mirror of
https://github.com/leanprover/lean4.git
synced 2026-04-14 08:04:07 +00:00
Compare commits
178 Commits
kmill_debu
...
grind_inv_
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2d1a86edf5 | ||
|
|
974c649e2e | ||
|
|
184f716da1 | ||
|
|
3f7f1c87f6 | ||
|
|
7ba0ae1f72 | ||
|
|
9923a8d9f8 | ||
|
|
de38a16fa9 | ||
|
|
c0238e396c | ||
|
|
c7cc398935 | ||
|
|
849bb770fd | ||
|
|
6cefbc4bb0 | ||
|
|
9b6a4a7588 | ||
|
|
47787dc1cb | ||
|
|
25ab3dd93d | ||
|
|
bbd45b13f4 | ||
|
|
85f168bbd0 | ||
|
|
89aed0931e | ||
|
|
92d24e1c40 | ||
|
|
c15ee8a9f0 | ||
|
|
320b02108b | ||
|
|
80df86dfdd | ||
|
|
fef390df08 | ||
|
|
37be918c50 | ||
|
|
2efbe4ac36 | ||
|
|
6d68aab56a | ||
|
|
ccb8568756 | ||
|
|
a4f6f391fe | ||
|
|
dac61c406f | ||
|
|
db35f98b26 | ||
|
|
e6f50b0181 | ||
|
|
2877196656 | ||
|
|
f748d1c4ef | ||
|
|
848832dd61 | ||
|
|
c5f2c192d6 | ||
|
|
96c42b95fa | ||
|
|
d826474b14 | ||
|
|
8d9d23b5bb | ||
|
|
c83237baf7 | ||
|
|
11f618ac49 | ||
|
|
708f715efb | ||
|
|
b0506ee835 | ||
|
|
f1737737f0 | ||
|
|
f3b1f054ef | ||
|
|
94ea5fb3fd | ||
|
|
5b9567b144 | ||
|
|
c4e5f57512 | ||
|
|
f376fd87d0 | ||
|
|
8e7e55f2d5 | ||
|
|
8789e5621b | ||
|
|
fbf096510d | ||
|
|
18cc1cec80 | ||
|
|
404b00a584 | ||
|
|
50ddf85b07 | ||
|
|
9107d27368 | ||
|
|
d51a5b920d | ||
|
|
eb013fb90d | ||
|
|
4c44fdb95f | ||
|
|
d63d1188cc | ||
|
|
a31d686ed1 | ||
|
|
a62dabeb56 | ||
|
|
d2eb1bc9f5 | ||
|
|
38608a672e | ||
|
|
86425f655a | ||
|
|
9757a7be53 | ||
|
|
3ce69e4edb | ||
|
|
2dda33ddb2 | ||
|
|
655a39ceb8 | ||
|
|
8d26a9e8b5 | ||
|
|
72e8970848 | ||
|
|
697ea0bc01 | ||
|
|
4d5fb31dfb | ||
|
|
43dc9f45d1 | ||
|
|
dc1ddda473 | ||
|
|
b5555052bd | ||
|
|
e4ca32174c | ||
|
|
d06fff0f13 | ||
|
|
e74e9694fe | ||
|
|
5bb7818355 | ||
|
|
5bc42bf5ca | ||
|
|
aaec0f584c | ||
|
|
db3fb47109 | ||
|
|
c83674bdff | ||
|
|
2652cc18b8 | ||
|
|
62e00fb5a0 | ||
|
|
2324c0939d | ||
|
|
425bebe99e | ||
|
|
a0613f4d12 | ||
|
|
298bd10f54 | ||
|
|
6810d31602 | ||
|
|
3e11f27ff4 | ||
|
|
a78a34bbd7 | ||
|
|
0803f1e77e | ||
|
|
9e47edd0df | ||
|
|
0f1174d097 | ||
|
|
f180eee7bf | ||
|
|
6a3fc281ad | ||
|
|
06e9f4735a | ||
|
|
0f5f2df11f | ||
|
|
aa0cf78d93 | ||
|
|
4f94972ff1 | ||
|
|
37dd26966b | ||
|
|
1feac1ae92 | ||
|
|
3ff195f7b2 | ||
|
|
5478dcf373 | ||
|
|
ad3e975178 | ||
|
|
cd9865b26b | ||
|
|
8c4db341dd | ||
|
|
a6a02fe6b9 | ||
|
|
741347281c | ||
|
|
a06e6e7f4d | ||
|
|
505d5c6013 | ||
|
|
13e8cb5a3a | ||
|
|
2107f45991 | ||
|
|
a72f9429ea | ||
|
|
321af0e02b | ||
|
|
1718ca21cd | ||
|
|
f4ce319f1b | ||
|
|
340c3da6ae | ||
|
|
afbf52896f | ||
|
|
afcf52e623 | ||
|
|
3c40ea2733 | ||
|
|
c95100e8fd | ||
|
|
be4651a772 | ||
|
|
797985e319 | ||
|
|
c9f08de7b3 | ||
|
|
9be2eab93d | ||
|
|
cc5ff2afb1 | ||
|
|
5651192fa2 | ||
|
|
5ccea92a09 | ||
|
|
3fc3f5d240 | ||
|
|
dca16fb58c | ||
|
|
20d66250df | ||
|
|
47632f27f6 | ||
|
|
dfdd682c01 | ||
|
|
8e828216e5 | ||
|
|
92037b5b1b | ||
|
|
a93e315e72 | ||
|
|
902484988e | ||
|
|
c9727c2d19 | ||
|
|
0d9b7fb6b8 | ||
|
|
db43de7b9d | ||
|
|
17f76f3bd7 | ||
|
|
6f69715f0a | ||
|
|
2b34d5b899 | ||
|
|
0881a8872b | ||
|
|
91a2de1e1e | ||
|
|
4a7def9e5f | ||
|
|
dc5766d27a | ||
|
|
a63d483258 | ||
|
|
1f9bba9d39 | ||
|
|
5daf65ec56 | ||
|
|
9d4665a0bf | ||
|
|
6df94385c5 | ||
|
|
82932ec86a | ||
|
|
3d7d35b588 | ||
|
|
fb23d7b45d | ||
|
|
f12177d01e | ||
|
|
68654c231b | ||
|
|
2adc21f28b | ||
|
|
0528696bbe | ||
|
|
51bba5338a | ||
|
|
561a4510b3 | ||
|
|
0e8838df3b | ||
|
|
385daa99a8 | ||
|
|
7595bc0791 | ||
|
|
9c6b698227 | ||
|
|
962ba9649c | ||
|
|
8c8a6021af | ||
|
|
584ed5f33e | ||
|
|
1523ed1cdb | ||
|
|
facc356a0a | ||
|
|
c4b3f303bb | ||
|
|
1448493489 | ||
|
|
f7a251b75f | ||
|
|
5aa706435a | ||
|
|
a581433d8b | ||
|
|
6683d1eb91 | ||
|
|
504d71f268 |
16
.github/workflows/build-template.yml
vendored
16
.github/workflows/build-template.yml
vendored
@@ -36,7 +36,7 @@ jobs:
|
||||
include: ${{fromJson(inputs.config)}}
|
||||
# complete all jobs
|
||||
fail-fast: false
|
||||
runs-on: ${{ matrix.os }}
|
||||
runs-on: ${{ endsWith(matrix.os, '-with-cache') && fromJSON(format('["{0}", "nscloud-git-mirror-1gb"]', matrix.os)) || matrix.os }}
|
||||
defaults:
|
||||
run:
|
||||
shell: ${{ matrix.shell || 'nix develop -c bash -euxo pipefail {0}' }}
|
||||
@@ -69,10 +69,16 @@ jobs:
|
||||
brew install ccache tree zstd coreutils gmp libuv
|
||||
if: runner.os == 'macOS'
|
||||
- name: Checkout
|
||||
if: (!endsWith(matrix.os, '-with-cache'))
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
# the default is to use a virtual merge commit between the PR and master: just use the PR
|
||||
ref: ${{ github.event.pull_request.head.sha }}
|
||||
- name: Namespace Checkout
|
||||
if: endsWith(matrix.os, '-with-cache')
|
||||
uses: namespacelabs/nscloud-checkout-action@v7
|
||||
with:
|
||||
ref: ${{ github.event.pull_request.head.sha }}
|
||||
- name: Open Nix shell once
|
||||
run: true
|
||||
if: runner.os == 'Linux'
|
||||
@@ -169,7 +175,9 @@ jobs:
|
||||
# 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'
|
||||
# Caching on cancellation created some mysterious issues perhaps related to improper build
|
||||
# shutdown
|
||||
if: steps.restore-cache.outputs.cache-hit != 'true' && !cancelled()
|
||||
uses: actions/cache/save@v4
|
||||
with:
|
||||
# NOTE: must be in sync with `restore` above
|
||||
@@ -215,13 +223,13 @@ jobs:
|
||||
path: pack/*
|
||||
- name: Lean stats
|
||||
run: |
|
||||
build/stage1/bin/lean --stats src/Lean.lean -Dexperimental.module=true
|
||||
build/$TARGET_STAGE/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
|
||||
time ctest --preset ${{ matrix.CMAKE_PRESET || 'release' }} --test-dir build/$TARGET_STAGE -j$NPROC --output-junit test-results.xml ${{ matrix.CTEST_OPTIONS }}
|
||||
if: (matrix.wasm || !matrix.cross) && (inputs.check-level >= 1 || matrix.test)
|
||||
- name: Test Summary
|
||||
uses: test-summary/action@v2
|
||||
|
||||
23
.github/workflows/ci.yml
vendored
23
.github/workflows/ci.yml
vendored
@@ -182,12 +182,10 @@ jobs:
|
||||
"binary-check": "ldd -v",
|
||||
// foreign code may be linked against more recent glibc
|
||||
"CTEST_OPTIONS": "-E 'foreign'",
|
||||
// not compatible with `prepare-llvm` currently
|
||||
"CMAKE_OPTIONS": "-DUSE_LAKE=OFF",
|
||||
},
|
||||
{
|
||||
"name": "Linux Lake",
|
||||
"os": large ? "nscloud-ubuntu-22.04-amd64-8x16" : "ubuntu-latest",
|
||||
"os": large ? "nscloud-ubuntu-22.04-amd64-8x16-with-cache" : "ubuntu-latest",
|
||||
"check-level": 0,
|
||||
"test": true,
|
||||
"check-rebootstrap": level >= 1,
|
||||
@@ -202,8 +200,6 @@ jobs:
|
||||
"os": "ubuntu-latest",
|
||||
"check-level": 2,
|
||||
"CMAKE_PRESET": "reldebug",
|
||||
// exclude seriously slow/stackoverflowing tests
|
||||
"CTEST_OPTIONS": "-E 'interactivetest|leanpkgtest|laketest|benchtest|bv_bitblast_stress|3807'"
|
||||
},
|
||||
// TODO: suddenly started failing in CI
|
||||
/*{
|
||||
@@ -225,8 +221,7 @@ jobs:
|
||||
"prepare-llvm": "../script/prepare-llvm-macos.sh lean-llvm*",
|
||||
"binary-check": "otool -L",
|
||||
"tar": "gtar", // https://github.com/actions/runner-images/issues/2619
|
||||
// not compatible with `prepare-llvm` currently
|
||||
"CMAKE_OPTIONS": "-DUSE_LAKE=OFF",
|
||||
"CTEST_OPTIONS": "-E 'leanlaketest_hello'", // started failing from unpack
|
||||
},
|
||||
{
|
||||
"name": "macOS aarch64",
|
||||
@@ -242,8 +237,6 @@ 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",
|
||||
@@ -252,13 +245,9 @@ jobs:
|
||||
"check-level": 2,
|
||||
"shell": "msys2 {0}",
|
||||
"CMAKE_OPTIONS": "-G \"Unix Makefiles\"",
|
||||
// for reasons unknown, interactivetests are flaky on Windows
|
||||
"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",
|
||||
// not compatible with `prepare-llvm` currently
|
||||
"CMAKE_OPTIONS": "-DUSE_LAKE=OFF",
|
||||
},
|
||||
{
|
||||
"name": "Linux aarch64",
|
||||
@@ -269,8 +258,6 @@ jobs:
|
||||
"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*",
|
||||
// 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
|
||||
//{
|
||||
@@ -299,6 +286,12 @@ jobs:
|
||||
// "CTEST_OPTIONS": "-R \"leantest_1007\\.lean|leantest_Format\\.lean|leanruntest\\_1037.lean|leanruntest_ac_rfl\\.lean|leanruntest_tempfile.lean\\.|leanruntest_libuv\\.lean\""
|
||||
// }
|
||||
];
|
||||
for (const job of matrix) {
|
||||
if (job["prepare-llvm"]) {
|
||||
// `USE_LAKE` is not compatible with `prepare-llvm` currently
|
||||
job["CMAKE_OPTIONS"] = (job["CMAKE_OPTIONS"] ? job["CMAKE_OPTIONS"] + " " : "") + "-DUSE_LAKE=OFF";
|
||||
}
|
||||
}
|
||||
console.log(`matrix:\n${JSON.stringify(matrix, null, 2)}`);
|
||||
matrix = matrix.filter((job) => level >= job["check-level"]);
|
||||
core.setOutput('matrix', matrix.filter((job) => !job["secondary"]));
|
||||
|
||||
2
.github/workflows/update-stage0.yml
vendored
2
.github/workflows/update-stage0.yml
vendored
@@ -19,6 +19,8 @@ concurrency:
|
||||
jobs:
|
||||
update-stage0:
|
||||
runs-on: nscloud-ubuntu-22.04-amd64-8x16
|
||||
env:
|
||||
CCACHE_DIR: ${{ github.workspace }}/.ccache
|
||||
steps:
|
||||
# This action should push to an otherwise protected branch, so it
|
||||
# uses a deploy key with write permissions, as suggested at
|
||||
|
||||
@@ -9,7 +9,7 @@ This is the repository for **Lean 4**.
|
||||
- [Documentation Overview](https://lean-lang.org/documentation/)
|
||||
- [Language Reference](https://lean-lang.org/doc/reference/latest/)
|
||||
- [Release notes](RELEASES.md) starting at v4.0.0-m3
|
||||
- [Examples](https://lean-lang.org/documentation/examples/)
|
||||
- [Examples](https://lean-lang.org/lean4/doc/examples.html)
|
||||
- [External Contribution Guidelines](CONTRIBUTING.md)
|
||||
|
||||
# Installation
|
||||
|
||||
@@ -75,7 +75,7 @@ The github repository will automatically update stage0 on `master` once
|
||||
|
||||
NOTE: A full rebuild of stage 1 will only be triggered when the *committed* contents of `stage0/` are changed.
|
||||
Thus if you change files in it manually instead of through `update-stage0-commit` (see below) or fetching updates from git, you either need to commit those changes first or run `make -C build/release clean-stdlib`.
|
||||
The same is true for further stages except that a rebuild of them is retriggered on any commited change, not just to a specific directory.
|
||||
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
|
||||
|
||||
@@ -8,7 +8,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.
|
||||
You can use any of the [supported editors](https://lean-lang.org/install/manual/) for editing the Lean source code.
|
||||
Please see below for specific instructions for VS Code.
|
||||
|
||||
### Dev setup using elan
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
These are instructions to set up a working development environment for those who wish to make changes to Lean itself. It is part of the [Development Guide](../dev/index.md).
|
||||
|
||||
We strongly suggest that new users instead follow the [Quickstart](../quickstart.md) to get started using Lean, since this sets up an environment that can automatically manage multiple Lean toolchain versions, which is necessary when working within the Lean ecosystem.
|
||||
We strongly suggest that new users instead follow the [Installation Instructions](https://lean-lang.org/install/) to get started using Lean, since this sets up an environment that can automatically manage multiple Lean toolchain versions, which is necessary when working within the Lean ecosystem.
|
||||
|
||||
Requirements
|
||||
------------
|
||||
|
||||
@@ -97,5 +97,36 @@ macro "#analyzeEMatchTheorems" : command => `(
|
||||
#analyzeEMatchTheorems
|
||||
|
||||
-- -- We can analyze specific theorems using commands such as
|
||||
set_option trace.grind.ematch.instance true in
|
||||
run_meta analyzeEMatchTheorem ``List.filterMap_some {}
|
||||
set_option trace.grind.ematch.instance true
|
||||
|
||||
-- 1. grind immediately sees `(#[] : Array α) = ([] : List α).toArray` but probably this should be hidden.
|
||||
-- 2. `Vector.toArray_empty` keys on `Array.mk []` rather than `#v[].toArray`
|
||||
-- I guess we could add `(#[].extract _ _).extract _ _` as a stop pattern.
|
||||
run_meta analyzeEMatchTheorem ``Array.extract_empty {}
|
||||
|
||||
-- Neither `Option.bind_some` nor `Option.bind_fun_some` fire, because the terms appear inside
|
||||
-- lambdas. So we get crazy things like:
|
||||
-- `fun x => ((some x).bind some).bind fun x => (some x).bind fun x => (some x).bind some`
|
||||
-- We could consider replacing `filterMap_some` with
|
||||
-- `filterMap g (filterMap f xs) = filterMap (f >=> g) xs`
|
||||
-- to avoid the lambda that `grind` struggles with, but this would require more API around the fish.
|
||||
run_meta analyzeEMatchTheorem ``Array.filterMap_some {}
|
||||
|
||||
-- Not entirely certain what is wrong here, but certainly
|
||||
-- `eq_empty_of_append_eq_empty` is firing too often.
|
||||
-- Ideally we could instantiate this is we fine `xs ++ ys` in the same equivalence class,
|
||||
-- note just as soon as we see `xs ++ ys`.
|
||||
-- I've tried removing this in https://github.com/leanprover/lean4/pull/10162
|
||||
run_meta analyzeEMatchTheorem ``Array.range'_succ {}
|
||||
|
||||
-- Perhaps the same story here.
|
||||
run_meta analyzeEMatchTheorem ``Array.range_succ {}
|
||||
|
||||
-- `zip_map_left` and `zip_map_right` are bad grind lemmas,
|
||||
-- checking if they can be removed in https://github.com/leanprover/lean4/pull/10163
|
||||
run_meta analyzeEMatchTheorem ``Array.zip_map {}
|
||||
|
||||
-- It seems crazy to me that as soon as we have `0 >>> n = 0`, we instantiate based on the
|
||||
-- pattern `0 >>> n >>> m` by substituting `0` into `0 >>> n` to produce the `0 >>> n >>> n`.
|
||||
-- I don't think any forbidden subterms can help us here. I don't know what to do. :-(
|
||||
run_meta analyzeEMatchTheorem ``Int.zero_shiftRight {}
|
||||
|
||||
@@ -469,6 +469,7 @@ elseif(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
|
||||
string(APPEND CMAKE_CXX_FLAGS " -ftls-model=initial-exec")
|
||||
string(APPEND INIT_SHARED_LINKER_FLAGS " -install_name @rpath/libInit_shared.dylib")
|
||||
string(APPEND LEANSHARED_1_LINKER_FLAGS " -install_name @rpath/libleanshared_1.dylib")
|
||||
string(APPEND LEANSHARED_2_LINKER_FLAGS " -install_name @rpath/libleanshared_2.dylib")
|
||||
string(APPEND LEANSHARED_LINKER_FLAGS " -install_name @rpath/libleanshared.dylib")
|
||||
string(APPEND LAKESHARED_LINKER_FLAGS " -Wl,-force_load,${CMAKE_BINARY_DIR}/lib/lean/libLake.a.export -install_name @rpath/libLake_shared.dylib")
|
||||
string(APPEND CMAKE_EXE_LINKER_FLAGS " -Wl,-rpath,@executable_path/../lib -Wl,-rpath,@executable_path/../lib/lean")
|
||||
@@ -502,7 +503,7 @@ endif()
|
||||
# are already loaded) and probably fail unless we set up LD_LIBRARY_PATH.
|
||||
if(${CMAKE_SYSTEM_NAME} MATCHES "Windows")
|
||||
# import libraries created by the stdlib.make targets
|
||||
string(APPEND LEANC_SHARED_LINKER_FLAGS " -lInit_shared -lleanshared_1 -lleanshared")
|
||||
string(APPEND LEANC_SHARED_LINKER_FLAGS " -lInit_shared -lleanshared_2 -lleanshared_1 -lleanshared")
|
||||
elseif("${CMAKE_SYSTEM_NAME}" MATCHES "Darwin")
|
||||
# The second flag is necessary to even *load* dylibs without resolved symbols, as can happen
|
||||
# if a Lake `extern_lib` depends on a symbols defined by the Lean library but is loaded even
|
||||
@@ -589,7 +590,7 @@ endif()
|
||||
|
||||
add_subdirectory(initialize)
|
||||
add_subdirectory(shell)
|
||||
# to be included in `leanshared` but not the smaller `leanshared_1` (as it would pull
|
||||
# to be included in `leanshared` but not the smaller `leanshared_*` (as it would pull
|
||||
# in the world)
|
||||
add_library(leaninitialize STATIC $<TARGET_OBJECTS:initialize>)
|
||||
set_target_properties(leaninitialize PROPERTIES
|
||||
@@ -714,6 +715,7 @@ if(${CMAKE_SYSTEM_NAME} MATCHES "Emscripten")
|
||||
)
|
||||
add_custom_target(leanshared ALL
|
||||
DEPENDS Init_shared leancpp
|
||||
COMMAND touch ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/libleanshared_2${CMAKE_SHARED_LIBRARY_SUFFIX}
|
||||
COMMAND touch ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/libleanshared_1${CMAKE_SHARED_LIBRARY_SUFFIX}
|
||||
COMMAND touch ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/libleanshared${CMAKE_SHARED_LIBRARY_SUFFIX}
|
||||
)
|
||||
@@ -734,7 +736,7 @@ else()
|
||||
COMMAND $(MAKE) -f ${CMAKE_BINARY_DIR}/stdlib.make leanshared
|
||||
VERBATIM)
|
||||
|
||||
string(APPEND CMAKE_EXE_LINKER_FLAGS " -lInit_shared -lleanshared_1 -lleanshared")
|
||||
string(APPEND CMAKE_EXE_LINKER_FLAGS " -lInit_shared -lleanshared_2 -lleanshared_1 -lleanshared")
|
||||
endif()
|
||||
|
||||
if(NOT ${CMAKE_SYSTEM_NAME} MATCHES "Emscripten")
|
||||
|
||||
@@ -7,8 +7,10 @@ module
|
||||
|
||||
prelude
|
||||
public import Init.Control.Lawful.Basic
|
||||
public import all Init.Control.Except
|
||||
public import all Init.Control.State
|
||||
public import Init.Control.Except
|
||||
import all Init.Control.Except
|
||||
public import Init.Control.State
|
||||
import all Init.Control.State
|
||||
public import Init.Control.StateRef
|
||||
public import Init.Ext
|
||||
|
||||
|
||||
@@ -6,12 +6,18 @@ Authors: Quang Dao, Paul Reichert
|
||||
module
|
||||
|
||||
prelude
|
||||
public import all Init.Control.Option
|
||||
public import all Init.Control.Except
|
||||
public import all Init.Control.ExceptCps
|
||||
public import all Init.Control.StateRef
|
||||
public import all Init.Control.StateCps
|
||||
public import all Init.Control.Id
|
||||
public import Init.Control.Option
|
||||
import all Init.Control.Option
|
||||
public import Init.Control.Except
|
||||
import all Init.Control.Except
|
||||
public import Init.Control.ExceptCps
|
||||
import all Init.Control.ExceptCps
|
||||
public import Init.Control.StateRef
|
||||
import all Init.Control.StateRef
|
||||
public import Init.Control.StateCps
|
||||
import all Init.Control.StateCps
|
||||
public import Init.Control.Id
|
||||
import all Init.Control.Id
|
||||
public import Init.Control.Lawful.MonadLift.Lemmas
|
||||
public import Init.Control.Lawful.Instances
|
||||
|
||||
|
||||
@@ -290,13 +290,17 @@ macro "right" : conv => `(conv| rhs)
|
||||
/-- `intro` traverses into binders. Synonym for `ext`. -/
|
||||
macro "intro" xs:(ppSpace colGt binderIdent)* : conv => `(conv| ext $xs*)
|
||||
|
||||
syntax enterArg := binderIdent <|> argArg
|
||||
syntax enterPattern := "in " (occs)? term
|
||||
|
||||
syntax enterArg := binderIdent <|> argArg <|> enterPattern
|
||||
|
||||
/-- `enter [arg, ...]` is a compact way to describe a path to a subterm.
|
||||
It is a shorthand for other conv tactics as follows:
|
||||
* `enter [i]` is equivalent to `arg i`.
|
||||
* `enter [@i]` is equivalent to `arg @i`.
|
||||
* `enter [x]` (where `x` is an identifier) is equivalent to `ext x`.
|
||||
* `enter [in e]` (where `e` is a term) is equivalent to `pattern e`.
|
||||
Occurrences can be specified with `enter [in (occs := ...) e]`.
|
||||
For example, given the target `f (g a (fun x => x b))`, `enter [1, 2, x, 1]`
|
||||
will traverse to the subterm `b`. -/
|
||||
syntax (name := enter) "enter" " [" withoutPosition(enterArg,+) "]" : conv
|
||||
|
||||
@@ -25,7 +25,7 @@ public import Init.Data.SInt
|
||||
public import Init.Data.Float
|
||||
public import Init.Data.Float32
|
||||
public import Init.Data.Option
|
||||
public import Init.Data.OrdRoot
|
||||
public import Init.Data.Ord
|
||||
public import Init.Data.Random
|
||||
public import Init.Data.ToString
|
||||
public import Init.Data.Range
|
||||
@@ -51,5 +51,6 @@ public import Init.Data.Range.Polymorphic
|
||||
public import Init.Data.Slice
|
||||
public import Init.Data.Order
|
||||
public import Init.Data.Rat
|
||||
public import Init.Data.Dyadic
|
||||
|
||||
public section
|
||||
|
||||
@@ -9,7 +9,8 @@ prelude
|
||||
public import Init.Data.Array.Mem
|
||||
public import Init.Data.Array.Lemmas
|
||||
public import Init.Data.Array.Count
|
||||
public import all Init.Data.List.Attach
|
||||
public import Init.Data.List.Attach
|
||||
import all Init.Data.List.Attach
|
||||
|
||||
public section
|
||||
|
||||
|
||||
@@ -10,11 +10,11 @@ public import Init.WFTactics
|
||||
public import Init.Data.Nat.Basic
|
||||
public import Init.Data.Fin.Basic
|
||||
public import Init.Data.UInt.BasicAux
|
||||
public import Init.Data.Repr
|
||||
public import Init.Data.ToString.Basic
|
||||
public import Init.GetElem
|
||||
public import all Init.Data.List.ToArrayImpl
|
||||
public import all Init.Data.Array.Set
|
||||
public import Init.Data.List.ToArrayImpl
|
||||
import all Init.Data.List.ToArrayImpl
|
||||
public import Init.Data.Array.Set
|
||||
import all Init.Data.Array.Set
|
||||
|
||||
public section
|
||||
|
||||
@@ -162,7 +162,7 @@ This is a low-level version of `Array.size` that directly queries the runtime sy
|
||||
representation of arrays. While this is not provable, `Array.usize` always returns the exact size of
|
||||
the array since the implementation only supports arrays of size less than `USize.size`.
|
||||
-/
|
||||
@[extern "lean_array_size", simp]
|
||||
@[extern "lean_array_size", simp, expose]
|
||||
def usize (xs : @& Array α) : USize := xs.size.toUSize
|
||||
|
||||
/--
|
||||
|
||||
@@ -6,7 +6,8 @@ Authors: Leonardo de Moura
|
||||
module
|
||||
|
||||
prelude
|
||||
public import all Init.Data.Array.Basic
|
||||
public import Init.Data.Array.Basic
|
||||
import all Init.Data.Array.Basic
|
||||
public import Init.Data.Nat.Linear
|
||||
public import Init.NotationExtra
|
||||
|
||||
|
||||
@@ -8,7 +8,8 @@ module
|
||||
|
||||
prelude
|
||||
public import Init.Data.List.TakeDrop
|
||||
public import all Init.Data.Array.Basic
|
||||
public import Init.Data.Array.Basic
|
||||
import all Init.Data.Array.Basic
|
||||
|
||||
public section
|
||||
|
||||
|
||||
@@ -6,7 +6,8 @@ Authors: Kim Morrison
|
||||
module
|
||||
|
||||
prelude
|
||||
public import all Init.Data.Array.Basic
|
||||
public import Init.Data.Array.Basic
|
||||
import all Init.Data.Array.Basic
|
||||
public import Init.Data.Array.Lemmas
|
||||
public import Init.Data.List.Nat.Count
|
||||
|
||||
|
||||
@@ -6,7 +6,8 @@ Authors: Leonardo de Moura
|
||||
module
|
||||
|
||||
prelude
|
||||
public import all Init.Data.Array.Basic
|
||||
public import Init.Data.Array.Basic
|
||||
import all Init.Data.Array.Basic
|
||||
public import Init.Data.BEq
|
||||
public import Init.Data.List.Nat.BEq
|
||||
public import Init.ByCases
|
||||
|
||||
@@ -6,7 +6,8 @@ Authors: Kim Morrison
|
||||
module
|
||||
|
||||
prelude
|
||||
public import all Init.Data.Array.Basic
|
||||
public import Init.Data.Array.Basic
|
||||
import all Init.Data.Array.Basic
|
||||
public import Init.Data.Array.Lemmas
|
||||
public import Init.Data.List.Nat.Erase
|
||||
public import Init.Data.List.Nat.Basic
|
||||
|
||||
@@ -7,7 +7,8 @@ module
|
||||
|
||||
prelude
|
||||
public import Init.Data.List.Nat.Find
|
||||
public import all Init.Data.Array.Basic
|
||||
public import Init.Data.Array.Basic
|
||||
import all Init.Data.Array.Basic
|
||||
public import Init.Data.Array.Lemmas
|
||||
public import Init.Data.Array.Attach
|
||||
public import Init.Data.Array.Range
|
||||
@@ -727,7 +728,7 @@ theorem isNone_findFinIdx? {xs : Array α} {p : α → Bool} :
|
||||
cases xs
|
||||
simp only [List.findFinIdx?_toArray, hf, List.findFinIdx?_subtype]
|
||||
rw [findFinIdx?_congr List.unattach_toArray]
|
||||
simp only [Option.map_map, Function.comp_def, Fin.cast_trans]
|
||||
simp only [Option.map_map, Function.comp_def, Fin.cast_cast]
|
||||
simp [Array.size]
|
||||
|
||||
/-! ### idxOf
|
||||
|
||||
@@ -70,8 +70,8 @@ private theorem cons_lex_cons [BEq α] {lt : α → α → Bool} {a b : α} {xs
|
||||
rw [cons_lex_cons.forIn'_congr_aux Std.PRange.toList_eq_match rfl (fun _ _ _ => rfl)]
|
||||
simp only [Std.PRange.SupportsUpperBound.IsSatisfied, bind_pure_comp, map_pure]
|
||||
rw [cons_lex_cons.forIn'_congr_aux (if_pos (by omega)) rfl (fun _ _ _ => rfl)]
|
||||
simp only [Std.PRange.toList_open_eq_toList_closed_of_isSome_succ? (lo := 0) (h := rfl),
|
||||
Std.PRange.UpwardEnumerable.succ?, Nat.add_comm 1, Std.PRange.Nat.ClosedOpen.toList_succ_succ,
|
||||
simp only [Std.PRange.toList_Rox_eq_toList_Rcx_of_isSome_succ? (lo := 0) (h := rfl),
|
||||
Std.PRange.UpwardEnumerable.succ?, Nat.add_comm 1, Std.PRange.Nat.toList_Rco_succ_succ,
|
||||
Option.get_some, List.forIn'_cons, List.size_toArray, List.length_cons, List.length_nil,
|
||||
Nat.lt_add_one, getElem_append_left, List.getElem_toArray, List.getElem_cons_zero]
|
||||
cases lt a b
|
||||
|
||||
@@ -6,11 +6,13 @@ Authors: Mario Carneiro, Kim Morrison
|
||||
module
|
||||
|
||||
prelude
|
||||
public import all Init.Data.Array.Basic
|
||||
public import Init.Data.Array.Basic
|
||||
import all Init.Data.Array.Basic
|
||||
public import Init.Data.Array.Lemmas
|
||||
public import Init.Data.Array.Attach
|
||||
public import Init.Data.Array.OfFn
|
||||
public import all Init.Data.List.MapIdx
|
||||
public import Init.Data.List.MapIdx
|
||||
import all Init.Data.List.MapIdx
|
||||
|
||||
public section
|
||||
|
||||
|
||||
@@ -6,8 +6,10 @@ Authors: Kim Morrison
|
||||
module
|
||||
|
||||
prelude
|
||||
public import all Init.Data.List.Control
|
||||
public import all Init.Data.Array.Basic
|
||||
public import Init.Data.List.Control
|
||||
import all Init.Data.List.Control
|
||||
public import Init.Data.Array.Basic
|
||||
import all Init.Data.Array.Basic
|
||||
public import Init.Data.Array.Lemmas
|
||||
public import Init.Data.Array.Attach
|
||||
public import Init.Data.List.Monadic
|
||||
|
||||
@@ -6,7 +6,8 @@ Authors: Kim Morrison
|
||||
module
|
||||
|
||||
prelude
|
||||
public import all Init.Data.Array.Basic
|
||||
public import Init.Data.Array.Basic
|
||||
import all Init.Data.Array.Basic
|
||||
public import Init.Data.Array.Lemmas
|
||||
public import Init.Data.Array.Monadic
|
||||
public import Init.Data.List.OfFn
|
||||
|
||||
@@ -7,7 +7,8 @@ module
|
||||
|
||||
prelude
|
||||
public import Init.Data.List.Nat.Perm
|
||||
public import all Init.Data.Array.Basic
|
||||
public import Init.Data.Array.Basic
|
||||
import all Init.Data.Array.Basic
|
||||
public import Init.Data.Array.Lemmas
|
||||
|
||||
public section
|
||||
|
||||
@@ -7,8 +7,10 @@ module
|
||||
|
||||
prelude
|
||||
public import Init.Data.Array.Lemmas
|
||||
public import all Init.Data.Array.Basic
|
||||
public import all Init.Data.Array.OfFn
|
||||
public import Init.Data.Array.Basic
|
||||
import all Init.Data.Array.Basic
|
||||
public import Init.Data.Array.OfFn
|
||||
import all Init.Data.Array.OfFn
|
||||
public import Init.Data.Array.MapIdx
|
||||
public import Init.Data.Array.Zip
|
||||
public import Init.Data.List.Nat.Range
|
||||
|
||||
@@ -8,7 +8,8 @@ module
|
||||
|
||||
prelude
|
||||
public import Init.Data.Array.Basic
|
||||
public import all Init.Data.Array.Subarray
|
||||
public import Init.Data.Array.Subarray
|
||||
import all Init.Data.Array.Subarray
|
||||
public import Init.Omega
|
||||
|
||||
public section
|
||||
|
||||
@@ -6,7 +6,8 @@ Authors: Markus Himmel
|
||||
module
|
||||
|
||||
prelude
|
||||
public import all Init.Data.Array.Basic
|
||||
public import Init.Data.Array.Basic
|
||||
import all Init.Data.Array.Basic
|
||||
public import Init.Data.Array.Lemmas
|
||||
public import Init.Data.List.Nat.TakeDrop
|
||||
|
||||
|
||||
@@ -6,7 +6,8 @@ Authors: Kim Morrison
|
||||
module
|
||||
|
||||
prelude
|
||||
public import all Init.Data.Array.Basic
|
||||
public import Init.Data.Array.Basic
|
||||
import all Init.Data.Array.Basic
|
||||
public import Init.Data.Array.TakeDrop
|
||||
public import Init.Data.List.Zip
|
||||
|
||||
@@ -230,11 +231,9 @@ theorem zip_map {f : α → γ} {g : β → δ} {as : Array α} {bs : Array β}
|
||||
cases bs
|
||||
simp [List.zip_map]
|
||||
|
||||
@[grind _=_]
|
||||
theorem zip_map_left {f : α → γ} {as : Array α} {bs : Array β} :
|
||||
zip (as.map f) bs = (zip as bs).map (Prod.map f id) := by rw [← zip_map, map_id]
|
||||
|
||||
@[grind _=_]
|
||||
theorem zip_map_right {f : β → γ} {as : Array α} {bs : Array β} :
|
||||
zip as (bs.map f) = (zip as bs).map (Prod.map id f) := by rw [← zip_map, map_id]
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ prelude
|
||||
public import Init.Data.Fin.Basic
|
||||
public import Init.Data.Nat.Bitwise.Lemmas
|
||||
public import Init.Data.Nat.Power2
|
||||
public import Init.Data.Int.Bitwise
|
||||
public import Init.Data.Int.Bitwise.Basic
|
||||
public import Init.Data.BitVec.BasicAux
|
||||
|
||||
@[expose] public section
|
||||
|
||||
@@ -6,11 +6,14 @@ Authors: Harun Khan, Abdalrhman M Mohamed, Joe Hendrix, Siddharth Bhat
|
||||
module
|
||||
|
||||
prelude
|
||||
public import all Init.Data.Nat.Bitwise.Basic
|
||||
public import Init.Data.Nat.Bitwise.Basic
|
||||
import all Init.Data.Nat.Bitwise.Basic
|
||||
public import Init.Data.Nat.Mod
|
||||
public import all Init.Data.Int.DivMod
|
||||
public import Init.Data.Int.DivMod
|
||||
import all Init.Data.Int.DivMod
|
||||
public import Init.Data.Int.LemmasAux
|
||||
public import all Init.Data.BitVec.Basic
|
||||
public import Init.Data.BitVec.Basic
|
||||
import all Init.Data.BitVec.Basic
|
||||
public import Init.Data.BitVec.Decidable
|
||||
public import Init.Data.BitVec.Lemmas
|
||||
public import Init.Data.BitVec.Folds
|
||||
@@ -2152,4 +2155,238 @@ theorem shiftLeft_add_eq_shiftLeft_or {x y : BitVec w} :
|
||||
(y <<< x) + x = (y <<< x) ||| x := by
|
||||
rw [BitVec.add_comm, add_shiftLeft_eq_or_shiftLeft, or_comm]
|
||||
|
||||
/- ### Fast Circuit For Unsigned Overflow Detection -/
|
||||
|
||||
/-!
|
||||
# Note [Fast Unsigned Multiplication Overflow Detection]
|
||||
|
||||
The fast unsigned multiplication overflow detection circuit is described in
|
||||
`Efficient integer multiplication overflow detection circuits` (https://ieeexplore.ieee.org/abstract/document/987767).
|
||||
With this circuit, the computation of the overflow flag for the unsigned multiplication of
|
||||
two bitvectors `x` and `y` with bitwidth `w` requires:
|
||||
· extending the operands by `1` bit and performing the multiplication with the extended operands,
|
||||
· computing the preliminary overflow flag, which describes whether `x` and `y` together have at most
|
||||
`w - 2` leading zeros.
|
||||
If the most significant bit of the extended operands' multiplication is `true` or if the
|
||||
preliminary overflow flag is `true`, overflow happens.
|
||||
In particular, the conditions check two different cases:
|
||||
· if the most significant bit of the extended operands' multiplication is `true`, the result of the
|
||||
multiplication 2 ^ w ≤ x.toNat * y.toNat < 2 ^ (w + 1),
|
||||
· if the preliminary flag is true, then 2 ^ (w + 1) ≤ x.toNat * y.toNat.
|
||||
|
||||
The computation of the preliminary overflow flag `resRec` relies on two quantities:
|
||||
· `uppcRec`: the unsigned parallel prefix circuit for the bits until a certain `i`,
|
||||
· `aandRec`: the conjunction between the parallel prefix circuit at of the first operand until a certain `i`
|
||||
and the `i`-th bit in the second operand.
|
||||
-/
|
||||
|
||||
/--
|
||||
`uppcRec` is the unsigned parallel prefix, `x.uppcRec s = true` iff `x.toNat` is greater or equal
|
||||
than `2 ^ (w - 1 - (s - 1))`.
|
||||
-/
|
||||
def uppcRec {w} (x : BitVec w) (s : Nat) (hs : s < w) : Bool :=
|
||||
match s with
|
||||
| 0 => x.msb
|
||||
| i + 1 => x[w - 1 - i] || uppcRec x i (by omega)
|
||||
|
||||
/-- The unsigned parallel prefix of `x` at `s` is `true` if and only if x interpreted
|
||||
as a natural number is greater or equal than `2 ^ (w - 1 - (s - 1))`. -/
|
||||
@[simp]
|
||||
theorem uppcRec_true_iff (x : BitVec w) (s : Nat) (h : s < w) :
|
||||
uppcRec x s h ↔ 2 ^ (w - 1 - (s - 1)) ≤ x.toNat := by
|
||||
rcases w with _|w
|
||||
· omega
|
||||
· induction s
|
||||
· case succ.zero =>
|
||||
simp only [uppcRec, msb_eq_true_iff_two_mul_ge, Nat.pow_add, Nat.pow_one,
|
||||
Nat.mul_comm (2 ^ w) 2, ge_iff_le, Nat.add_one_sub_one, zero_le, Nat.sub_eq_zero_of_le,
|
||||
Nat.sub_zero]
|
||||
apply Nat.mul_le_mul_left_iff (by omega)
|
||||
· case succ.succ s ihs =>
|
||||
simp only [uppcRec, or_eq_true, ihs, Nat.add_one_sub_one]
|
||||
have := Nat.pow_le_pow_of_le (a := 2) ( n := (w - s)) (m := (w - (s - 1))) (by omega) (by omega)
|
||||
constructor
|
||||
· intro h'
|
||||
rcases h' with h'|h'
|
||||
· apply ge_two_pow_of_testBit h'
|
||||
· omega
|
||||
· intro h'
|
||||
by_cases hbit: x[w - s]
|
||||
· simp [hbit]
|
||||
· have := BitVec.le_toNat_iff_getLsbD_eq_true (x := x) (i := w - s) (by omega)
|
||||
simp only [h', true_iff] at this
|
||||
obtain ⟨k, hk⟩ := this
|
||||
by_cases hwk : w - s + k < w + 1
|
||||
· by_cases hk' : 0 < k
|
||||
· have hle := ge_two_pow_of_testBit hk
|
||||
have hpowle := Nat.pow_le_pow_of_le (a := 2) ( n := (w - (s - 1))) (m := (w - s + k)) (by omega) (by omega)
|
||||
omega
|
||||
· rw [getLsbD_eq_getElem (by omega)] at hk
|
||||
simp [hbit, show k = 0 by omega] at hk
|
||||
· simp_all
|
||||
|
||||
/--
|
||||
Conjunction for fast umulOverflow circuit
|
||||
-/
|
||||
def aandRec (x y : BitVec w) (s : Nat) (hs : s < w) : Bool :=
|
||||
y[s] && uppcRec x s (by omega)
|
||||
|
||||
|
||||
/--
|
||||
Preliminary overflow flag for fast umulOverflow circuit as introduced in
|
||||
`Efficient integer multiplication overflow detection circuits` (https://ieeexplore.ieee.org/abstract/document/987767).
|
||||
-/
|
||||
def resRec (x y : BitVec w) (s : Nat) (hs : s < w) (hslt : 0 < s) : Bool :=
|
||||
match hs0 : s with
|
||||
| 0 => by omega
|
||||
| s' + 1 =>
|
||||
match hs' : s' with
|
||||
| 0 => aandRec x y 1 (by omega)
|
||||
| s'' + 1 =>
|
||||
(resRec x y s' (by omega) (by omega)) || (aandRec x y s (by omega))
|
||||
|
||||
/-- The preliminary overflow flag is true for a certain `s` if and only if the conjunction returns true at
|
||||
any `k` smaller than or equal to `s`. -/
|
||||
theorem resRec_true_iff (x y : BitVec w) (s : Nat) (hs : s < w) (hs' : 0 < s) :
|
||||
resRec x y s hs hs' = true ↔ ∃ (k : Nat), ∃ (h : k ≤ s), ∃ (_ : 0 < k), aandRec x y k (by omega) := by
|
||||
unfold resRec
|
||||
rcases s with _|s
|
||||
· omega
|
||||
· rcases s
|
||||
· case zero =>
|
||||
constructor
|
||||
· intro ha
|
||||
exists 1, by omega, by omega
|
||||
· intro hr
|
||||
obtain ⟨k, hk, hk', hk''⟩ := hr
|
||||
simp only [show k = 1 by omega] at hk''
|
||||
exact hk''
|
||||
· case succ s =>
|
||||
induction s
|
||||
· case zero =>
|
||||
unfold resRec
|
||||
simp only [Nat.zero_add, Nat.reduceAdd, or_eq_true]
|
||||
constructor
|
||||
· intro h
|
||||
rcases h with h|h
|
||||
· exists 1, by omega, by omega
|
||||
· exists 2, by omega, by omega
|
||||
· intro h
|
||||
obtain ⟨k, hk, hk', hk''⟩ := h
|
||||
have h : k = 1 ∨ k = 2 := by omega
|
||||
rcases h with h|h
|
||||
<;> simp only [h] at hk''
|
||||
<;> simp [hk'']
|
||||
· case succ s ihs =>
|
||||
specialize ihs (by omega) (by omega)
|
||||
unfold resRec
|
||||
simp only [or_eq_true, ihs]
|
||||
constructor
|
||||
· intro h
|
||||
rcases h with h|h
|
||||
· obtain ⟨k, hk, hk', hk''⟩ := h
|
||||
exists k, by omega, by omega
|
||||
· exists s + 1 + 1 + 1, by omega, by omega
|
||||
· intro h
|
||||
obtain ⟨k, hk, hk', hk''⟩ := h
|
||||
by_cases h' : x.aandRec y (s + 1 + 1 + 1) (by omega) = true
|
||||
· simp [h']
|
||||
· simp only [h', false_eq_true, _root_.or_false]
|
||||
by_cases h'' : k ≤ s + 1 + 1
|
||||
· exists k, h'', by omega
|
||||
· have : k = s + 1 + 1 + 1 := by omega
|
||||
simp_all
|
||||
|
||||
/-- If the sum of the leading zeroes of two bitvecs with bitwidth `w` is less than or equal to
|
||||
(`w - 2`), then the preliminary overflow flag is true and their unsigned multiplication overflows.
|
||||
The explanation is in `Efficient integer multiplication overflow detection circuits`
|
||||
https://ieeexplore.ieee.org/abstract/document/987767
|
||||
-/
|
||||
theorem resRec_of_clz_le {x y : BitVec w} (hw : 1 < w) (hx : x ≠ 0#w) (hy : y ≠ 0#w):
|
||||
(clz x).toNat + (clz y).toNat ≤ w - 2 → resRec x y (w - 1) (by omega) (by omega) := by
|
||||
intro h
|
||||
rw [resRec_true_iff]
|
||||
exists (w - 1 - y.clz.toNat), by omega, by omega
|
||||
simp only [aandRec]
|
||||
by_cases hw0 : w - 1 - y.clz.toNat = 0
|
||||
· have := clz_lt_iff_ne_zero.mpr (by omega)
|
||||
omega
|
||||
· simp only [and_eq_true, getLsbD_true_clz_of_ne_zero (x := y) (by omega) (by omega),
|
||||
getElem_of_getLsbD_eq_true, uppcRec_true_iff,
|
||||
show w - 1 - (w - 1 - y.clz.toNat - 1) = y.clz.toNat + 1 by omega, _root_.true_and]
|
||||
exact Nat.le_trans (Nat.pow_le_pow_of_le (a := 2) (n := y.clz.toNat + 1)
|
||||
(m := w - 1 - x.clz.toNat) (by omega) (by omega))
|
||||
(BitVec.two_pow_sub_clz_le_toNat_of_ne_zero (x := x) (by omega) (by omega))
|
||||
|
||||
/--
|
||||
Complete fast overflow detection circuit for unsigned multiplication.
|
||||
-/
|
||||
theorem fastUmulOverflow (x y : BitVec w) :
|
||||
umulOverflow x y = if hw : w ≤ 1 then false
|
||||
else (setWidth (w + 1) x * setWidth (w + 1) y)[w] || x.resRec y (w - 1) (by omega) (by omega) := by
|
||||
rcases w with _|_|w
|
||||
· simp [of_length_zero, umulOverflow]
|
||||
· have hx : x.toNat ≤ 1 := by omega
|
||||
have hy : y.toNat ≤ 1 := by omega
|
||||
have := Nat.mul_le_mul (n₁ := x.toNat) (m₁ := y.toNat) (n₂ := 1) (m₂ := 1) hx hy
|
||||
simp [umulOverflow]
|
||||
omega
|
||||
· by_cases h : umulOverflow x y
|
||||
· simp only [h, Nat.reduceLeDiff, reduceDIte, Nat.add_one_sub_one, true_eq, or_eq_true]
|
||||
simp only [umulOverflow, ge_iff_le, decide_eq_true_eq] at h
|
||||
by_cases h' : x.toNat * y.toNat < 2 ^ (w + 1 + 1 + 1)
|
||||
· have hlt := BitVec.getElem_eq_true_of_lt_of_le
|
||||
(x := (setWidth (w + 1 + 1 + 1) x * setWidth (w + 1 + 1 + 1) y))
|
||||
(k := w + 1 + 1) (by omega)
|
||||
simp only [toNat_mul, toNat_setWidth, Nat.lt_add_one, toNat_mod_cancel_of_lt,
|
||||
Nat.mod_eq_of_lt (a := x.toNat * y.toNat) (b := 2 ^ (w + 1 + 1 + 1)) (by omega), h', h,
|
||||
forall_const] at hlt
|
||||
simp [hlt]
|
||||
· by_cases hsw : (setWidth (w + 1 + 1 + 1) x * setWidth (w + 1 + 1 + 1) y)[w + 1 + 1] = true
|
||||
· simp [hsw]
|
||||
· simp only [hsw, false_eq_true, _root_.false_or]
|
||||
have := Nat.two_pow_pos (w := w + 1 + 1)
|
||||
have hltx := BitVec.toNat_lt_two_pow_sub_clz (x := x)
|
||||
have hlty := BitVec.toNat_lt_two_pow_sub_clz (x := y)
|
||||
have := Nat.mul_ne_zero_iff (m := y.toNat) (n := x.toNat)
|
||||
simp only [ne_eq, show ¬x.toNat * y.toNat = 0 by omega, not_false_eq_true,
|
||||
true_iff] at this
|
||||
obtain ⟨hxz,hyz⟩ := this
|
||||
apply resRec_of_clz_le (x := x) (y := y) (by omega) (by simp [toNat_eq]; exact hxz) (by simp [toNat_eq]; exact hyz)
|
||||
by_cases hzxy : x.clz.toNat + y.clz.toNat ≤ w
|
||||
· omega
|
||||
· by_cases heq : w + 1 - y.clz.toNat = 0
|
||||
· by_cases heq' : w + 1 + 1 - y.clz.toNat = 0
|
||||
· simp [heq', hyz] at hlty
|
||||
· simp only [show y.clz.toNat = w + 1 by omega, Nat.add_sub_cancel_left,
|
||||
Nat.pow_one] at hlty
|
||||
simp only [show y.toNat = 1 by omega, Nat.mul_one, Nat.not_lt] at h'
|
||||
omega
|
||||
· by_cases w + 1 < y.clz.toNat
|
||||
· omega
|
||||
· simp only [Nat.not_lt] at h'
|
||||
have := Nat.mul_lt_mul'' (a := x.toNat) (b := y.toNat) (c := 2 ^ (w + 1 + 1 - x.clz.toNat)) (d := 2 ^ (w + 1 + 1 - y.clz.toNat)) hltx hlty
|
||||
simp only [← Nat.pow_add] at this
|
||||
have := Nat.pow_le_pow_of_le (a := 2) (n := w + 1 + 1 - x.clz.toNat + (w + 1 + 1 - y.clz.toNat)) (m := w + 1 + 1 + 1)
|
||||
(by omega) (by omega)
|
||||
omega
|
||||
· simp only [h, Nat.reduceLeDiff, reduceDIte, Nat.add_one_sub_one, false_eq, or_eq_false_iff]
|
||||
simp only [umulOverflow, ge_iff_le, decide_eq_true_eq, Nat.not_le] at h
|
||||
and_intros
|
||||
· simp only [← getLsbD_eq_getElem, getLsbD_eq_getMsbD, Nat.lt_add_one, decide_true,
|
||||
Nat.add_one_sub_one, Nat.sub_self, ← msb_eq_getMsbD_zero, Bool.true_and,
|
||||
msb_eq_false_iff_two_mul_lt, toNat_mul, toNat_setWidth, toNat_mod_cancel_of_lt]
|
||||
rw [Nat.mod_eq_of_lt (by omega),Nat.pow_add (m := w + 1 + 1) (n := 1)]
|
||||
simp [Nat.mul_comm 2 (x.toNat * y.toNat), h]
|
||||
· apply Classical.byContradiction
|
||||
intro hcontra
|
||||
simp only [not_eq_false, resRec_true_iff, exists_prop, exists_and_left] at hcontra
|
||||
obtain ⟨k,hk,hk',hk''⟩ := hcontra
|
||||
simp only [aandRec, and_eq_true, uppcRec_true_iff, Nat.add_one_sub_one] at hk''
|
||||
obtain ⟨hky, hkx⟩ := hk''
|
||||
have hyle := two_pow_le_toNat_of_getElem_eq_true (x := y) (i := k) (by omega) hky
|
||||
have := Nat.mul_le_mul (n₁ := 2 ^ (w + 1 - (k - 1))) (m₁ := 2 ^ k) (n₂ := x.toNat) (m₂ := y.toNat) hkx hyle
|
||||
simp [← Nat.pow_add, show w + 1 - (k - 1) + k = w + 1 + 1 by omega] at this
|
||||
omega
|
||||
|
||||
end BitVec
|
||||
|
||||
@@ -6,7 +6,9 @@ Authors: Joe Hendrix, Harun Khan, Alex Keizer, Abdalrhman M Mohamed, Siddharth B
|
||||
module
|
||||
|
||||
prelude
|
||||
public import all Init.Data.BitVec.Basic
|
||||
public import Init.Data.BitVec.Basic
|
||||
import all Init.Data.BitVec.Basic
|
||||
import Init.Data.Int.Bitwise.Lemmas
|
||||
|
||||
public section
|
||||
|
||||
|
||||
@@ -6,7 +6,8 @@ Authors: Joe Hendrix, Harun Khan
|
||||
module
|
||||
|
||||
prelude
|
||||
public import all Init.Data.BitVec.Basic
|
||||
public import Init.Data.BitVec.Basic
|
||||
import all Init.Data.BitVec.Basic
|
||||
public import Init.Data.BitVec.Lemmas
|
||||
public import Init.Data.Nat.Lemmas
|
||||
public import Init.Data.Fin.Iterate
|
||||
|
||||
@@ -7,8 +7,10 @@ module
|
||||
|
||||
prelude
|
||||
public import Init.Data.Bool
|
||||
public import all Init.Data.BitVec.Basic
|
||||
public import all Init.Data.BitVec.BasicAux
|
||||
public import Init.Data.BitVec.Basic
|
||||
import all Init.Data.BitVec.Basic
|
||||
public import Init.Data.BitVec.BasicAux
|
||||
import all Init.Data.BitVec.BasicAux
|
||||
public import Init.Data.Fin.Lemmas
|
||||
public import Init.Data.Nat.Lemmas
|
||||
public import Init.Data.Nat.Div.Lemmas
|
||||
@@ -508,6 +510,18 @@ theorem getElem_ofBool {b : Bool} {h : i < 1}: (ofBool b)[i] = b := by
|
||||
@[simp] theorem zero_eq_one_iff (w : Nat) : (0#w = 1#w) ↔ (w = 0) := by
|
||||
rw [← one_eq_zero_iff, eq_comm]
|
||||
|
||||
/-- A bitvector is equal to 0#w if and only if all bits are `false` -/
|
||||
theorem zero_iff_eq_false {x: BitVec w} :
|
||||
x = 0#w ↔ ∀ i, x.getLsbD i = false := by
|
||||
rcases w with _|w
|
||||
· simp [of_length_zero]
|
||||
· constructor
|
||||
· intro hzero
|
||||
simp [hzero]
|
||||
· intro hfalse
|
||||
ext j hj
|
||||
simp [← getLsbD_eq_getElem, hfalse]
|
||||
|
||||
/-! ### msb -/
|
||||
|
||||
@[simp] theorem msb_zero : (0#w).msb = false := by simp [BitVec.msb, getMsbD]
|
||||
@@ -2192,8 +2206,7 @@ theorem sshiftRight_eq_of_msb_false {x : BitVec w} {s : Nat} (h : x.msb = false)
|
||||
apply BitVec.eq_of_toNat_eq
|
||||
rw [BitVec.sshiftRight_eq, BitVec.toInt_eq_toNat_cond]
|
||||
have hxbound : 2 * x.toNat < 2 ^ w := BitVec.msb_eq_false_iff_two_mul_lt.mp h
|
||||
simp only [hxbound, ↓reduceIte, Int.natCast_shiftRight, ofInt_natCast,
|
||||
toNat_ofNat, toNat_ushiftRight]
|
||||
simp only [hxbound, ↓reduceIte, toNat_ushiftRight]
|
||||
replace hxbound : x.toNat >>> s < 2 ^ w := by
|
||||
rw [Nat.shiftRight_eq_div_pow]
|
||||
exact Nat.lt_of_le_of_lt (Nat.div_le_self ..) x.isLt
|
||||
@@ -5766,40 +5779,6 @@ theorem msb_replicate {n w : Nat} {x : BitVec w} :
|
||||
simp only [BitVec.msb, getMsbD_replicate, Nat.zero_mod]
|
||||
cases n <;> cases w <;> simp
|
||||
|
||||
/-! ### Count leading zeros -/
|
||||
|
||||
theorem clzAuxRec_zero (x : BitVec w) :
|
||||
x.clzAuxRec 0 = if x.getLsbD 0 then BitVec.ofNat w (w - 1) else BitVec.ofNat w w := by rfl
|
||||
|
||||
theorem clzAuxRec_succ (x : BitVec w) :
|
||||
x.clzAuxRec (n + 1) = if x.getLsbD (n + 1) then BitVec.ofNat w (w - 1 - (n + 1)) else BitVec.clzAuxRec x n := by rfl
|
||||
|
||||
theorem clzAuxRec_eq_clzAuxRec_of_le (x : BitVec w) (h : w - 1 ≤ n) :
|
||||
x.clzAuxRec n = x.clzAuxRec (w - 1) := by
|
||||
let k := n - (w - 1)
|
||||
rw [show n = (w - 1) + k by omega]
|
||||
induction k
|
||||
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 =>
|
||||
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
|
||||
simp only [Classical.not_forall, Bool.not_eq_false]
|
||||
exists n + k + 1
|
||||
simp [show n < n + k + 1 by omega, hxn]
|
||||
contradiction
|
||||
· simp only [hxn, Bool.false_eq_true, ↓reduceIte]
|
||||
exact ihk
|
||||
|
||||
|
||||
/-! ### Inequalities (le / lt) -/
|
||||
|
||||
theorem ule_eq_not_ult (x y : BitVec w) : x.ule y = !y.ult x := by
|
||||
@@ -5848,6 +5827,362 @@ theorem sle_eq_ule {x y : BitVec w} : x.sle y = (x.msb != y.msb ^^ x.ule y) := b
|
||||
theorem sle_eq_ule_of_msb_eq {x y : BitVec w} (h : x.msb = y.msb) : x.sle y = x.ule y := by
|
||||
simp [BitVec.sle_eq_ule, h]
|
||||
|
||||
/-- A bitvector interpreted as a natural number is greater than or equal to `2 ^ i` if and only if
|
||||
there exists at least one bit with `true` value at position `i` or higher. -/
|
||||
theorem le_toNat_iff_getLsbD_eq_true {x : BitVec w} (hi : i < w ) :
|
||||
(2 ^ i ≤ x.toNat) ↔ (∃ k, x.getLsbD (i + k) = true) := by
|
||||
rcases w with _|w
|
||||
· simp [of_length_zero]
|
||||
· constructor
|
||||
· intro hle
|
||||
apply Classical.byContradiction
|
||||
intros hcontra
|
||||
let x' := setWidth (i + 1) x
|
||||
have hx' : setWidth (i + 1) x = x' := by rfl
|
||||
have hcast : w - i + (i + 1) = w + 1 := by omega
|
||||
simp only [not_exists, Bool.not_eq_true] at hcontra
|
||||
have hx'' : x = BitVec.cast hcast (0#(w - i) ++ x') := by
|
||||
ext j
|
||||
by_cases hj : j < i + 1
|
||||
· simp only [← hx', getElem_cast, getElem_append, hj, reduceDIte, getElem_setWidth]
|
||||
rw [getLsbD_eq_getElem]
|
||||
· simp only [getElem_cast, getElem_append, hj, reduceDIte, getElem_zero]
|
||||
let j' := j - i
|
||||
simp only [show j = i + j' by omega]
|
||||
apply hcontra
|
||||
have : x'.toNat < 2 ^ i := by
|
||||
apply Nat.lt_pow_two_of_testBit (n := i) x'.toNat
|
||||
intro j hj
|
||||
let j' := j - i
|
||||
specialize hcontra j'
|
||||
have : x'.getLsbD (i + j') = x.getLsbD (i + j') := by
|
||||
subst x'
|
||||
simp [hcontra]
|
||||
simp [show j = i + j' by omega, testBit_toNat, this, hcontra]
|
||||
have : x'.toNat = x.toNat := by
|
||||
have := BitVec.setWidth_eq_append (w := (w + 1)) (v := i + 1) (x := x')
|
||||
specialize this (by omega)
|
||||
rw [toNat_eq, toNat_setWidth, Nat.mod_eq_of_lt (by omega)] at this
|
||||
simp [hx'']
|
||||
omega
|
||||
· intro h
|
||||
obtain ⟨k, hk⟩ := h
|
||||
by_cases hk' : i + k < w + 1
|
||||
· have := Nat.ge_two_pow_of_testBit hk
|
||||
have := Nat.pow_le_pow_of_le (a := 2) (n := i) (m := i + k) (by omega) (by omega)
|
||||
omega
|
||||
· simp [show w + 1 ≤ i + k by omega] at hk
|
||||
|
||||
/-- A bitvector interpreted as a natural number is strictly smaller than `2 ^ i` if and only if
|
||||
all bits at position `i` or higher are false. -/
|
||||
theorem toNat_lt_iff_getLsbD_eq_false {x : BitVec w} (i : Nat) (hi : i < w) :
|
||||
x.toNat < 2 ^ i ↔ (∀ k, x.getLsbD (i + k) = false) := by
|
||||
constructor
|
||||
· intro h
|
||||
apply Classical.byContradiction
|
||||
intro hcontra
|
||||
simp only [Classical.not_forall, Bool.not_eq_false] at hcontra
|
||||
obtain ⟨k, hk⟩ := hcontra
|
||||
have hle := Nat.ge_two_pow_of_testBit hk
|
||||
by_cases hlt : i + k < w
|
||||
· have := Nat.pow_le_pow_of_le (a := 2) (n := i) (m := i + k) (by omega) (by omega)
|
||||
omega
|
||||
· simp [show w ≤ i + k by omega] at hk
|
||||
· intro h
|
||||
apply Classical.byContradiction
|
||||
intro hcontra
|
||||
simp [BitVec.le_toNat_iff_getLsbD_eq_true (x := x) (i := i) hi, h] at hcontra
|
||||
|
||||
/-- If a bitvector interpreted as a natural number is strictly smaller than `2 ^ (k + 1)` and greater than or
|
||||
equal to 2 ^ k, then the bit at position `k` must be `true` -/
|
||||
theorem getElem_eq_true_of_lt_of_le {x : BitVec w} (hk' : k < w) (hlt: x.toNat < 2 ^ (k + 1)) (hle : 2 ^ k ≤ x.toNat) :
|
||||
x[k] = true := by
|
||||
have := le_toNat_iff_getLsbD_eq_true (x := x) (i := k) hk'
|
||||
simp only [hle, true_iff] at this
|
||||
obtain ⟨k',hk'⟩ := this
|
||||
by_cases hkk' : k + k' < w
|
||||
· have := Nat.ge_two_pow_of_testBit hk'
|
||||
by_cases hzk' : k' = 0
|
||||
· simp [hzk'] at hk'; exact hk'
|
||||
· have := Nat.pow_lt_pow_of_lt (a := 2) (n := k) (m := k + k') (by omega) (by omega)
|
||||
have := Nat.pow_le_pow_of_le (a := 2) (n := k + 1) (m := k + k') (by omega) (by omega)
|
||||
omega
|
||||
· simp [show w ≤ k + k' by omega] at hk'
|
||||
|
||||
/-! ### Count leading zeros -/
|
||||
|
||||
theorem clzAuxRec_zero (x : BitVec w) :
|
||||
x.clzAuxRec 0 = if x.getLsbD 0 then BitVec.ofNat w (w - 1) else BitVec.ofNat w w := by rfl
|
||||
|
||||
theorem clzAuxRec_succ (x : BitVec w) :
|
||||
x.clzAuxRec (n + 1) = if x.getLsbD (n + 1) then BitVec.ofNat w (w - 1 - (n + 1)) else BitVec.clzAuxRec x n := by rfl
|
||||
|
||||
theorem clzAuxRec_eq_clzAuxRec_of_le {x : BitVec w} (h : w - 1 ≤ n) :
|
||||
x.clzAuxRec n = x.clzAuxRec (w - 1) := by
|
||||
let k := n - (w - 1)
|
||||
rw [show n = (w - 1) + k by omega]
|
||||
induction k
|
||||
· 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 =>
|
||||
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
|
||||
simp only [Classical.not_forall, Bool.not_eq_false]
|
||||
exists n + k + 1
|
||||
simp [show n < n + k + 1 by omega, hxn]
|
||||
contradiction
|
||||
· simp only [hxn, Bool.false_eq_true, ↓reduceIte]
|
||||
exact ihk
|
||||
|
||||
theorem clzAuxRec_le {x : BitVec w} (n : Nat) :
|
||||
clzAuxRec x n ≤ w := by
|
||||
have := Nat.lt_pow_self (a := 2) (n := w) (by omega)
|
||||
rcases w with _|w
|
||||
· simp [of_length_zero]
|
||||
· induction n
|
||||
· case zero =>
|
||||
simp only [clzAuxRec_zero]
|
||||
by_cases hx0 : x.getLsbD 0
|
||||
· simp only [hx0, Nat.add_one_sub_one, reduceIte, natCast_eq_ofNat, ofNat_le_ofNat,
|
||||
Nat.mod_two_pow_self, ge_iff_le, Nat.mod_eq_of_lt (a := w) (b := 2 ^ (w + 1)) (by omega)]
|
||||
omega
|
||||
· simp only [hx0, Bool.false_eq_true, reduceIte, natCast_eq_ofNat, BitVec.le_refl]
|
||||
· case succ n ihn =>
|
||||
simp only [clzAuxRec_succ, Nat.add_one_sub_one, natCast_eq_ofNat, ge_iff_le]
|
||||
by_cases hxn : x.getLsbD (n + 1)
|
||||
· simp [hxn, Nat.mod_eq_of_lt (a := w - (n + 1)) (b := 2 ^(w + 1)) (by omega)]
|
||||
omega
|
||||
· simp only [hxn, Bool.false_eq_true, reduceIte]
|
||||
exact ihn
|
||||
|
||||
theorem clzAuxRec_eq_iff_of_getLsbD_false {x : BitVec w} (h : ∀ i, n < i → x.getLsbD i = false) :
|
||||
x.clzAuxRec n = BitVec.ofNat w w ↔ ∀ j, j ≤ n → x.getLsbD j = false := by
|
||||
rcases w with _|w
|
||||
· simp [of_length_zero]
|
||||
· have := Nat.lt_pow_self (a := 2) (n := w + 1)
|
||||
induction n
|
||||
· case zero =>
|
||||
simp only [clzAuxRec_zero, Nat.zero_lt_succ, getLsbD_eq_getElem, Nat.add_one_sub_one,
|
||||
ite_eq_right_iff, Nat.le_zero_eq, forall_eq]
|
||||
by_cases hx0 : x.getLsbD 0
|
||||
· simp [hx0, toNat_eq, toNat_ofNat, Nat.mod_eq_of_lt (a := w) (b := 2 ^ (w + 1)) (by omega)]
|
||||
· simp only [Nat.zero_lt_succ, getLsbD_eq_getElem, Bool.not_eq_true] at hx0
|
||||
simp [hx0]
|
||||
· case succ n ihn =>
|
||||
simp only [clzAuxRec_succ, Nat.add_one_sub_one]
|
||||
by_cases hxn : x.getLsbD (n + 1)
|
||||
· simp only [hxn, reduceIte, toNat_eq, toNat_ofNat,
|
||||
Nat.mod_eq_of_lt (a := w - (n + 1)) (b := 2 ^ (w + 1)) (by omega), Nat.mod_two_pow_self,
|
||||
show ¬w - (n + 1) = w + 1 by omega, false_iff, Classical.not_forall,
|
||||
Bool.not_eq_false]
|
||||
exists n + 1, by omega
|
||||
· have : ∀ (i : Nat), n < i → x.getLsbD i = false := by
|
||||
intro i hi
|
||||
by_cases hi' : i = n + 1
|
||||
· simp [hi', hxn]
|
||||
· apply h; omega
|
||||
specialize ihn this
|
||||
simp only [Bool.not_eq_true] at ihn hxn
|
||||
simp only [hxn, Bool.false_eq_true, reduceIte, ihn]
|
||||
constructor
|
||||
<;> intro h' j hj
|
||||
<;> (by_cases hj' : j = n + 1; simp [hj', hxn]; (apply h'; omega))
|
||||
|
||||
theorem clz_le {x : BitVec w} :
|
||||
clz x ≤ w := by
|
||||
unfold clz
|
||||
rcases w with _|w
|
||||
· simp [of_length_zero]
|
||||
· exact clzAuxRec_le (n := w)
|
||||
|
||||
@[simp]
|
||||
theorem clz_eq_iff_eq_zero {x : BitVec w} :
|
||||
clz x = w ↔ x = 0#w := by
|
||||
rcases w with _|w
|
||||
· simp [clz, of_length_zero]
|
||||
· simp only [clz, Nat.add_one_sub_one, natCast_eq_ofNat, zero_iff_eq_false]
|
||||
rw [clzAuxRec_eq_iff_of_getLsbD_false (x := x) (n := w) (w := w + 1) (by intros i hi; simp [show w + 1 ≤ i by omega])]
|
||||
constructor
|
||||
· intro h i
|
||||
by_cases i ≤ w
|
||||
· apply h; omega
|
||||
· simp [show w + 1 ≤ i by omega]
|
||||
· intro h j hj
|
||||
apply h
|
||||
|
||||
theorem clzAuxRec_eq_zero_iff {x : BitVec w} (h : ∀ i, n < i → x.getLsbD i = false) (hw : 0 < w) :
|
||||
(x.clzAuxRec n).toNat = 0 ↔ x[w - 1] = true := by
|
||||
have := Nat.lt_pow_self (a := 2) (n := w)
|
||||
induction n
|
||||
· case zero =>
|
||||
simp only [clzAuxRec_zero]
|
||||
by_cases hw1 : w - 1 = 0
|
||||
· by_cases hx0 : x.getLsbD 0
|
||||
· simp [hw1, hx0]
|
||||
· simp [hw1, show ¬ w = 0 by omega, hx0, ← getLsbD_eq_getElem]
|
||||
· by_cases hx0 : x.getLsbD 0
|
||||
· simp only [hx0, ↓reduceIte, toNat_ofNat,
|
||||
Nat.mod_eq_of_lt (a := w - 1) (b := 2 ^ w) (by omega), show ¬w - 1 = 0 by omega, false_iff,
|
||||
Bool.not_eq_true]
|
||||
specialize h (w - 1) (by omega)
|
||||
exact h
|
||||
· simp [hx0, show ¬ w = 0 by omega]
|
||||
specialize h (w - 1) (by omega)
|
||||
exact h
|
||||
· case succ n ihn =>
|
||||
by_cases hxn : x.getLsbD (n + 1)
|
||||
· simp only [clzAuxRec_succ, hxn, reduceIte, toNat_ofNat]
|
||||
rw [Nat.mod_eq_of_lt (by omega)]
|
||||
by_cases hwn : w - 1 - (n + 1) = 0
|
||||
· have := lt_of_getLsbD hxn
|
||||
simp only [show w - 1 = n + 1 by omega, Nat.sub_self, true_iff]
|
||||
exact hxn
|
||||
· simp only [hwn, false_iff, Bool.not_eq_true]
|
||||
specialize h (w - 1) (by omega)
|
||||
exact h
|
||||
· simp only [clzAuxRec_succ, hxn, Bool.false_eq_true, reduceIte]
|
||||
apply ihn
|
||||
intro i hi
|
||||
by_cases hi : i = n + 1
|
||||
· simp [hi, hxn]
|
||||
· apply h; omega
|
||||
|
||||
theorem clz_eq_zero_iff {x : BitVec w} (hw : 0 < w) :
|
||||
(clz x).toNat = 0 ↔ 2 ^ (w - 1) ≤ x.toNat := by
|
||||
simp only [clz, clzAuxRec_eq_zero_iff (x := x) (n := w - 1) (by intro i hi; simp [show w ≤ i by omega]) hw]
|
||||
by_cases hxw : x[w - 1]
|
||||
· simp [hxw, two_pow_le_toNat_of_getElem_eq_true (x := x) (i := w - 1) (by omega) hxw]
|
||||
· simp only [hxw, Bool.false_eq_true, false_iff, Nat.not_le]
|
||||
simp only [← getLsbD_eq_getElem, ← msb_eq_getLsbD_last, Bool.not_eq_true] at hxw
|
||||
exact toNat_lt_of_msb_false hxw
|
||||
|
||||
/-- The number of leading zeroes is strictly less than the bitwidth iff the bitvector is nonzero. -/
|
||||
theorem clz_lt_iff_ne_zero {x : BitVec w} :
|
||||
clz x < w ↔ x ≠ 0#w := by
|
||||
have hle := clz_le (x := x)
|
||||
have heq := clz_eq_iff_eq_zero (x := x)
|
||||
constructor
|
||||
· intro h
|
||||
simp only [natCast_eq_ofNat, BitVec.ne_of_lt (x := x.clz) (y := BitVec.ofNat w w) h,
|
||||
false_iff] at heq
|
||||
simp only [ne_eq, heq, not_false_eq_true]
|
||||
· intro h
|
||||
simp only [natCast_eq_ofNat, h, iff_false] at heq
|
||||
apply BitVec.lt_of_le_ne (x := x.clz) (y := BitVec.ofNat w w) hle heq
|
||||
|
||||
theorem getLsbD_false_of_clzAuxRec {x : BitVec w} (h : ∀ i, n < i → x.getLsbD i = false) :
|
||||
∀ j, x.getLsbD (w - (x.clzAuxRec n).toNat + j) = false := by
|
||||
rcases w with _|w
|
||||
· simp
|
||||
· have := Nat.lt_pow_self (a := 2) (n := w + 1)
|
||||
induction n
|
||||
· case zero =>
|
||||
intro j
|
||||
simp only [clzAuxRec_zero, Nat.zero_lt_succ, getLsbD_eq_getElem, Nat.add_one_sub_one]
|
||||
by_cases hx0 : x[0]
|
||||
· specialize h (1 + j) (by omega)
|
||||
simp [h, hx0, Nat.mod_eq_of_lt (a := w) (b := 2 ^ (w + 1)) (by omega)]
|
||||
· simp only [hx0, Bool.false_eq_true, ↓reduceIte, toNat_ofNat, Nat.mod_two_pow_self,
|
||||
Nat.sub_self, Nat.zero_add]
|
||||
by_cases hj0 : j = 0
|
||||
· simp [hj0, hx0]
|
||||
· specialize h j (by omega)
|
||||
exact h
|
||||
· case succ n ihn =>
|
||||
intro j
|
||||
by_cases hxn : x.getLsbD (n + 1)
|
||||
· have := lt_of_getLsbD hxn
|
||||
specialize h (n + j + 1 + 1) (by omega)
|
||||
simp [h, clzAuxRec_succ, hxn, Nat.mod_eq_of_lt (a := w - (n + 1)) (b := 2 ^ (w + 1)) (by omega),
|
||||
show (w + 1 - (w - (n + 1)) + j) = n + j + 1 + 1 by omega]
|
||||
· simp only [clzAuxRec_succ, hxn, Bool.false_eq_true, reduceIte]
|
||||
apply ihn
|
||||
intro i hi
|
||||
by_cases hin : i = n + 1
|
||||
· simp [hin, hxn]
|
||||
· specialize h i (by omega)
|
||||
exact h
|
||||
|
||||
theorem getLsbD_true_of_eq_clzAuxRec_of_ne_zero {x : BitVec w} (hx : ¬ x = 0#w) (hn : ∀ i, n < i → x.getLsbD i = false) :
|
||||
x.getLsbD (w - 1 - (x.clzAuxRec n).toNat) = true := by
|
||||
rcases w with _|w
|
||||
· simp [of_length_zero] at hx
|
||||
· have := Nat.lt_pow_self (a := 2) (n := w + 1)
|
||||
induction n
|
||||
· case zero =>
|
||||
by_cases hx0 : x[0]
|
||||
· simp only [Nat.add_one_sub_one, clzAuxRec_zero, Nat.zero_lt_succ, getLsbD_eq_getElem, hx0,
|
||||
reduceIte, toNat_ofNat, Nat.mod_eq_of_lt (a := w) (b := 2 ^(w + 1)) (by omega), show w - w = 0 by omega]
|
||||
· simp only [zero_iff_eq_false, Classical.not_forall, Bool.not_eq_false] at hx
|
||||
obtain ⟨m,hm⟩ := hx
|
||||
specialize hn m
|
||||
by_cases hm0 : m = 0
|
||||
· simp [hm0, hx0] at hm
|
||||
· simp [show 0 < m by omega, hm] at hn
|
||||
· case succ n ihn =>
|
||||
by_cases hxn : x.getLsbD (n + 1)
|
||||
· have := lt_of_getLsbD hxn
|
||||
simp [clzAuxRec_succ, hxn, toNat_ofNat, Nat.mod_eq_of_lt (a := w - (n + 1)) (b := 2 ^ (w + 1)) (by omega),
|
||||
show w - (w - (n + 1)) = n + 1 by omega]
|
||||
· simp only [Nat.add_one_sub_one, clzAuxRec_succ, hxn, Bool.false_eq_true, reduceIte]
|
||||
simp only [Nat.add_one_sub_one] at ihn
|
||||
apply ihn
|
||||
intro j hj
|
||||
by_cases hjn : j = n + 1
|
||||
· simp [hjn, hxn]
|
||||
· specialize hn j (by omega)
|
||||
exact hn
|
||||
|
||||
theorem getLsbD_true_clz_of_ne_zero {x : BitVec w} (hw : 0 < w) (hx : x ≠ 0#w) :
|
||||
x.getLsbD (w - 1 - (clz x).toNat) = true := by
|
||||
unfold clz
|
||||
apply getLsbD_true_of_eq_clzAuxRec_of_ne_zero (x := x) (n := w - 1) (by omega)
|
||||
intro i hi
|
||||
simp [show w ≤ i by omega]
|
||||
|
||||
/-- A nonzero bitvector is lower-bounded by its leading zeroes. -/
|
||||
theorem two_pow_sub_clz_le_toNat_of_ne_zero {x : BitVec w} (hw : 0 < w) (hx : x ≠ 0#w) :
|
||||
2 ^ (w - 1 - (clz x).toNat) ≤ x.toNat := by
|
||||
by_cases hc0 : x.clz.toNat = 0
|
||||
· simp [hc0, ← clz_eq_zero_iff (x := x) hw]
|
||||
· have hclz := getLsbD_true_clz_of_ne_zero (x := x) hw hx
|
||||
rw [getLsbD_eq_getElem (by omega)] at hclz
|
||||
have hge := Nat.ge_two_pow_of_testBit hclz
|
||||
push_cast at hge
|
||||
exact hge
|
||||
|
||||
/-- A bitvector is upper bounded by the number of leading zeroes. -/
|
||||
theorem toNat_lt_two_pow_sub_clz {x : BitVec w} :
|
||||
x.toNat < 2 ^ (w - (clz x).toNat) := by
|
||||
rcases w with _|w
|
||||
· simp [of_length_zero]
|
||||
· unfold clz
|
||||
have hlt := toNat_lt_iff_getLsbD_eq_false (x := x)
|
||||
have hzero := clzAuxRec_eq_zero_iff (x := x) (n := w) (by intro i hi; simp [show w + 1 ≤ i by omega]) (by omega)
|
||||
simp only [Nat.add_one_sub_one] at hzero
|
||||
by_cases hxw : x[w]
|
||||
· simp only [hxw, iff_true] at hzero
|
||||
simp only [Nat.add_one_sub_one, hzero, Nat.sub_zero, gt_iff_lt]
|
||||
omega
|
||||
· simp only [hxw, Bool.false_eq_true, iff_false] at hzero
|
||||
rw [hlt]
|
||||
· intro k
|
||||
apply getLsbD_false_of_clzAuxRec (x := x) (n := w)
|
||||
intro i hi
|
||||
by_cases hiw : i = w
|
||||
· simp [hiw, hxw]
|
||||
· simp [show w + 1 ≤ i by omega]
|
||||
· simp; omega
|
||||
|
||||
|
||||
/-! ### Deprecations -/
|
||||
|
||||
set_option linter.missingDocs false
|
||||
|
||||
@@ -6,10 +6,10 @@ Author: Leonardo de Moura
|
||||
module
|
||||
|
||||
prelude
|
||||
public import Init.Data.Array.Basic
|
||||
public import Init.Data.Array.DecidableEq
|
||||
public import Init.Data.UInt.Basic
|
||||
public import all Init.Data.UInt.BasicAux
|
||||
public import Init.Data.UInt.BasicAux
|
||||
import all Init.Data.UInt.BasicAux
|
||||
public import Init.Data.Option.Basic
|
||||
|
||||
@[expose] public section
|
||||
|
||||
@@ -6,7 +6,8 @@ Authors: Leonardo de Moura
|
||||
module
|
||||
|
||||
prelude
|
||||
public import all Init.Data.Char.Basic
|
||||
public import Init.Data.Char.Basic
|
||||
import all Init.Data.Char.Basic
|
||||
public import Init.Data.UInt.Lemmas
|
||||
|
||||
public section
|
||||
|
||||
12
src/Init/Data/Dyadic.lean
Normal file
12
src/Init/Data/Dyadic.lean
Normal file
@@ -0,0 +1,12 @@
|
||||
/-
|
||||
Copyright (c) 2025 Lean FRO, LLC. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Kim Morrison
|
||||
-/
|
||||
module
|
||||
prelude
|
||||
|
||||
public import Init.Data.Dyadic.Basic
|
||||
public import Init.Data.Dyadic.Instances
|
||||
public import Init.Data.Dyadic.Round
|
||||
public import Init.Data.Dyadic.Inv
|
||||
747
src/Init/Data/Dyadic/Basic.lean
Normal file
747
src/Init/Data/Dyadic/Basic.lean
Normal file
@@ -0,0 +1,747 @@
|
||||
/-
|
||||
Copyright (c) 2025 Lean FRO, LLC. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Kim Morrison, Robin Arnez
|
||||
-/
|
||||
module
|
||||
|
||||
prelude
|
||||
public import Init.Data.Rat.Lemmas
|
||||
import Init.Data.Int.Bitwise.Lemmas
|
||||
import Init.Data.Int.DivMod.Lemmas
|
||||
|
||||
/-!
|
||||
# The dyadic rationals
|
||||
|
||||
Constructs the dyadic rationals as an ordered ring, equipped with a compatible embedding into the rationals.
|
||||
-/
|
||||
|
||||
set_option linter.missingDocs true
|
||||
|
||||
@[expose] public section
|
||||
|
||||
open Nat
|
||||
|
||||
namespace Int
|
||||
|
||||
/-- The number of trailing zeros in the binary representation of `i`. -/
|
||||
def trailingZeros (i : Int) : Nat :=
|
||||
if h : i = 0 then 0 else aux i.natAbs i h (Nat.le_refl _) 0
|
||||
where
|
||||
aux (k : Nat) (i : Int) (hi : i ≠ 0) (hk : i.natAbs ≤ k) (acc : Nat) : Nat :=
|
||||
match k, (by omega : k ≠ 0) with
|
||||
| k + 1, _ =>
|
||||
if h : i % 2 = 0 then aux k (i / 2) (by omega) (by omega) (acc + 1)
|
||||
else acc
|
||||
|
||||
-- TODO: check performance of `trailingZeros` in the kernel and VM.
|
||||
|
||||
private theorem trailingZeros_aux_irrel (hi : i ≠ 0) (hk : i.natAbs ≤ k) (hk' : i.natAbs ≤ k') :
|
||||
trailingZeros.aux k i hi hk acc = trailingZeros.aux k' i hi hk' acc := by
|
||||
fun_induction trailingZeros.aux k i hi hk acc generalizing k' <;>
|
||||
fun_cases trailingZeros.aux k' _ _ hk' _
|
||||
· rename_i ih _ _ _ _ _
|
||||
exact ih _
|
||||
· contradiction
|
||||
· contradiction
|
||||
· rfl
|
||||
|
||||
private theorem trailingZeros_aux_succ :
|
||||
trailingZeros.aux k i hi hk (acc + 1) = trailingZeros.aux k i hi hk acc + 1 := by
|
||||
fun_induction trailingZeros.aux k i hi hk acc <;> simp_all [trailingZeros.aux]
|
||||
|
||||
theorem trailingZeros_zero : trailingZeros 0 = 0 := rfl
|
||||
|
||||
theorem trailingZeros_two_mul_add_one (i : Int) :
|
||||
Int.trailingZeros (2 * i + 1) = 0 := by
|
||||
unfold trailingZeros trailingZeros.aux
|
||||
rw [dif_neg (by omega)]
|
||||
split <;> simp_all
|
||||
|
||||
theorem trailingZeros_eq_zero_of_mod_eq {i : Int} (h : i % 2 = 1) :
|
||||
Int.trailingZeros i = 0 := by
|
||||
unfold trailingZeros trailingZeros.aux
|
||||
rw [dif_neg (by omega)]
|
||||
split <;> simp_all
|
||||
|
||||
theorem trailingZeros_two_mul {i : Int} (h : i ≠ 0) :
|
||||
Int.trailingZeros (2 * i) = Int.trailingZeros i + 1 := by
|
||||
rw [Int.trailingZeros, dif_neg (Int.mul_ne_zero (by decide) h), Int.trailingZeros.aux.eq_def]
|
||||
simp only [ne_eq, mul_emod_right, ↓reduceDIte, Int.reduceEq, not_false_eq_true,
|
||||
mul_ediv_cancel_left, Nat.zero_add]
|
||||
split
|
||||
rw [trailingZeros, trailingZeros_aux_succ, dif_neg h]
|
||||
apply congrArg Nat.succ (trailingZeros_aux_irrel ..) <;> omega
|
||||
|
||||
theorem shiftRight_trailingZeros_mod_two {i : Int} (h : i ≠ 0) :
|
||||
(i >>> i.trailingZeros) % 2 = 1 := by
|
||||
rw (occs := .pos [2]) [← Int.emod_add_mul_ediv i 2]
|
||||
rcases i.emod_two_eq with h' | h' <;> rw [h']
|
||||
· rcases Int.dvd_of_emod_eq_zero h' with ⟨a, rfl⟩
|
||||
simp only [ne_eq, Int.mul_eq_zero, Int.reduceEq, false_or] at h
|
||||
rw [Int.zero_add, mul_ediv_cancel_left _ (by decide), trailingZeros_two_mul h, Nat.add_comm,
|
||||
shiftRight_add, shiftRight_eq_div_pow _ 1]
|
||||
simpa using shiftRight_trailingZeros_mod_two h
|
||||
· rwa [Int.add_comm, trailingZeros_two_mul_add_one, shiftRight_zero]
|
||||
termination_by i.natAbs
|
||||
|
||||
theorem two_pow_trailingZeros_dvd {i : Int} (h : i ≠ 0) :
|
||||
2 ^ i.trailingZeros ∣ i := by
|
||||
rcases i.emod_two_eq with h' | h'
|
||||
· rcases Int.dvd_of_emod_eq_zero h' with ⟨a, rfl⟩
|
||||
simp only [ne_eq, Int.mul_eq_zero, Int.reduceEq, false_or] at h
|
||||
rw [trailingZeros_two_mul h, Int.pow_succ']
|
||||
exact Int.mul_dvd_mul_left _ (two_pow_trailingZeros_dvd h)
|
||||
· rw (occs := .pos [1]) [← Int.emod_add_mul_ediv i 2, h', Int.add_comm, trailingZeros_two_mul_add_one]
|
||||
exact Int.one_dvd _
|
||||
termination_by i.natAbs
|
||||
|
||||
theorem trailingZeros_shiftLeft {x : Int} (hx : x ≠ 0) (n : Nat) :
|
||||
trailingZeros (x <<< n) = x.trailingZeros + n := by
|
||||
have : NeZero x := ⟨hx⟩
|
||||
induction n <;> simp [Int.shiftLeft_succ', trailingZeros_two_mul (NeZero.ne _), *, Nat.add_assoc]
|
||||
|
||||
@[simp]
|
||||
theorem trailingZeros_neg (x : Int) : trailingZeros (-x) = x.trailingZeros := by
|
||||
by_cases hx : x = 0
|
||||
· simp [hx]
|
||||
rcases x.emod_two_eq with h | h
|
||||
· rcases Int.dvd_of_emod_eq_zero h with ⟨a, rfl⟩
|
||||
simp only [Int.mul_ne_zero_iff, ne_eq, Int.reduceEq, not_false_eq_true, true_and] at hx
|
||||
rw [← Int.mul_neg, trailingZeros_two_mul hx, trailingZeros_two_mul (Int.neg_ne_zero.mpr hx)]
|
||||
rw [trailingZeros_neg]
|
||||
· simp [trailingZeros_eq_zero_of_mod_eq, h]
|
||||
termination_by x.natAbs
|
||||
|
||||
end Int
|
||||
|
||||
/--
|
||||
A dyadic rational is either zero or of the form `n * 2^(-k)` for some (unique) `n k : Int`
|
||||
where `n` is odd.
|
||||
-/
|
||||
inductive Dyadic where
|
||||
/-- The dyadic number `0`. -/
|
||||
| zero
|
||||
/-- The dyadic number `n * 2^(-k)` for some odd `n` and integer `k`. -/
|
||||
| ofOdd (n : Int) (k : Int) (hn : n % 2 = 1)
|
||||
deriving DecidableEq
|
||||
|
||||
namespace Dyadic
|
||||
|
||||
/-- Returns the dyadic number representation of `i * 2 ^ (-exp)`. -/
|
||||
def ofIntWithPrec (i : Int) (prec : Int) : Dyadic :=
|
||||
if h : i = 0 then .zero
|
||||
else .ofOdd (i >>> i.trailingZeros) (prec - i.trailingZeros) (Int.shiftRight_trailingZeros_mod_two h)
|
||||
|
||||
/-- Convert an integer to a dyadic number (which will necessarily have non-positive precision). -/
|
||||
def ofInt (i : Int) : Dyadic :=
|
||||
Dyadic.ofIntWithPrec i 0
|
||||
|
||||
instance (n : Nat) : OfNat Dyadic n where
|
||||
ofNat := Dyadic.ofInt n
|
||||
|
||||
instance : IntCast Dyadic := ⟨ofInt⟩
|
||||
instance : NatCast Dyadic := ⟨fun x => ofInt x⟩
|
||||
|
||||
/-- Add two dyadic numbers. -/
|
||||
protected def add (x y : Dyadic) : Dyadic :=
|
||||
match x, y with
|
||||
| .zero, y => y
|
||||
| x, .zero => x
|
||||
| .ofOdd n₁ k₁ hn₁, .ofOdd n₂ k₂ hn₂ =>
|
||||
match k₁ - k₂ with
|
||||
| 0 => .ofIntWithPrec (n₁ + n₂) k₁
|
||||
-- TODO: these `simp_all` calls where previously factored out into a `where finally` clause,
|
||||
-- but there is apparently a bad interaction with the module system.
|
||||
| (d@hd:(d' + 1) : Nat) => .ofOdd (n₁ + (n₂ <<< d)) k₁ (by simp_all [Int.shiftLeft_eq, Int.pow_succ, ← Int.mul_assoc])
|
||||
| -(d + 1 : Nat) => .ofOdd (n₁ <<< (d + 1) + n₂) k₂ (by simp_all [Int.shiftLeft_eq, Int.pow_succ, ← Int.mul_assoc])
|
||||
|
||||
instance : Add Dyadic := ⟨Dyadic.add⟩
|
||||
|
||||
/-- Multiply two dyadic numbers. -/
|
||||
protected def mul (x y : Dyadic) : Dyadic :=
|
||||
match x, y with
|
||||
| .zero, _ => .zero
|
||||
| _, .zero => .zero
|
||||
| .ofOdd n₁ k₁ hn₁, .ofOdd n₂ k₂ hn₂ =>
|
||||
.ofOdd (n₁ * n₂) (k₁ + k₂) (by rw [Int.mul_emod, hn₁, hn₂]; rfl)
|
||||
|
||||
instance : Mul Dyadic := ⟨Dyadic.mul⟩
|
||||
|
||||
/-- Multiply two dyadic numbers. -/
|
||||
protected def pow (x : Dyadic) (i : Nat) : Dyadic :=
|
||||
match x with
|
||||
| .zero => if i = 0 then 1 else 0
|
||||
| .ofOdd n k hn =>
|
||||
.ofOdd (n ^ i) (k * i) (by induction i <;> simp [Int.pow_succ, Int.mul_emod, *])
|
||||
|
||||
instance : Pow Dyadic Nat := ⟨Dyadic.pow⟩
|
||||
|
||||
/-- Negate a dyadic number. -/
|
||||
protected def neg (x : Dyadic) : Dyadic :=
|
||||
match x with
|
||||
| .zero => .zero
|
||||
| .ofOdd n k hn => .ofOdd (-n) k (by rwa [Int.neg_emod_two])
|
||||
|
||||
instance : Neg Dyadic := ⟨Dyadic.neg⟩
|
||||
|
||||
/-- Subtract two dyadic numbers. -/
|
||||
protected def sub (x y : Dyadic) : Dyadic := x + (- y)
|
||||
|
||||
instance : Sub Dyadic := ⟨Dyadic.sub⟩
|
||||
|
||||
/-- Shift a dyadic number left by `i` bits. -/
|
||||
protected def shiftLeft (x : Dyadic) (i : Int) : Dyadic :=
|
||||
match x with
|
||||
| .zero => .zero
|
||||
| .ofOdd n k hn => .ofOdd n (k - i) hn
|
||||
|
||||
/-- Shift a dyadic number right by `i` bits. -/
|
||||
protected def shiftRight (x : Dyadic) (i : Int) : Dyadic :=
|
||||
match x with
|
||||
| .zero => .zero
|
||||
| .ofOdd n k hn => .ofOdd n (k + i) hn
|
||||
|
||||
instance : HShiftLeft Dyadic Int Dyadic := ⟨Dyadic.shiftLeft⟩
|
||||
instance : HShiftRight Dyadic Int Dyadic := ⟨Dyadic.shiftRight⟩
|
||||
|
||||
instance : HShiftLeft Dyadic Nat Dyadic := ⟨fun x y => x <<< (y : Int)⟩
|
||||
instance : HShiftRight Dyadic Nat Dyadic := ⟨fun x y => x >>> (y : Int)⟩
|
||||
|
||||
-- TODO: move this
|
||||
theorem _root_.Int.natAbs_emod_two (i : Int) : i.natAbs % 2 = (i % 2).natAbs := by omega
|
||||
|
||||
/-- Convert a dyadic number to a rational number. -/
|
||||
def toRat (x : Dyadic) : Rat :=
|
||||
match x with
|
||||
| .zero => 0
|
||||
| .ofOdd n (k : Nat) hn =>
|
||||
have reduced : n.natAbs.Coprime (2 ^ k) := by
|
||||
apply Coprime.pow_right
|
||||
rw [coprime_iff_gcd_eq_one, Nat.gcd_comm, Nat.gcd_def]
|
||||
simp [hn, Int.natAbs_emod_two]
|
||||
⟨n, 2 ^ k, Nat.ne_of_gt (Nat.pow_pos (by decide)), reduced⟩
|
||||
| .ofOdd n (-((k : Nat) + 1)) hn =>
|
||||
(n * (2 ^ (k + 1) : Nat) : Int)
|
||||
|
||||
@[simp] protected theorem zero_eq : Dyadic.zero = 0 := rfl
|
||||
@[simp] protected theorem add_zero (x : Dyadic) : x + 0 = x := by cases x <;> rfl
|
||||
@[simp] protected theorem zero_add (x : Dyadic) : 0 + x = x := by cases x <;> rfl
|
||||
@[simp] protected theorem neg_zero : (-0 : Dyadic) = 0 := rfl
|
||||
@[simp] protected theorem mul_zero (x : Dyadic) : x * 0 = 0 := by cases x <;> rfl
|
||||
@[simp] protected theorem zero_mul (x : Dyadic) : 0 * x = 0 := by cases x <;> rfl
|
||||
|
||||
@[simp] theorem toRat_zero : toRat 0 = 0 := rfl
|
||||
|
||||
theorem _root_.Rat.mkRat_one (x : Int) : mkRat x 1 = x := by
|
||||
rw [← Rat.mk_den_one, Rat.mk_eq_mkRat]
|
||||
|
||||
theorem toRat_ofOdd_eq_mkRat :
|
||||
toRat (.ofOdd n k hn) = mkRat (n <<< (-k).toNat) (1 <<< k.toNat) := by
|
||||
cases k
|
||||
· simp [toRat, Rat.mk_eq_mkRat, Int.shiftLeft_eq, Nat.shiftLeft_eq]
|
||||
· simp [toRat, Int.neg_negSucc, Rat.mkRat_one, Int.shiftLeft_eq]
|
||||
|
||||
theorem toRat_ofIntWithPrec_eq_mkRat :
|
||||
toRat (.ofIntWithPrec n k) = mkRat (n <<< (-k).toNat) (1 <<< k.toNat) := by
|
||||
simp only [ofIntWithPrec]
|
||||
split
|
||||
· simp_all
|
||||
rw [toRat_ofOdd_eq_mkRat, Rat.mkRat_eq_iff (NeZero.ne _) (NeZero.ne _)]
|
||||
simp only [Int.natCast_shiftLeft, Int.cast_ofNat_Int, Int.shiftLeft_mul_shiftLeft, Int.mul_one]
|
||||
have : (-(k - n.trailingZeros) : Int).toNat + k.toNat =
|
||||
n.trailingZeros + ((-k).toNat + (k - n.trailingZeros).toNat) := by omega
|
||||
rw [this, Int.shiftLeft_add, Int.shiftRight_shiftLeft_cancel]
|
||||
exact Int.two_pow_trailingZeros_dvd ‹_›
|
||||
|
||||
theorem toRat_ofIntWithPrec_eq_mul_two_pow : toRat (.ofIntWithPrec n k) = n * 2 ^ (-k) := by
|
||||
rw [toRat_ofIntWithPrec_eq_mkRat, Rat.zpow_neg, Int.shiftLeft_eq, Nat.one_shiftLeft]
|
||||
rw [Rat.mkRat_eq_div, Rat.div_def]
|
||||
have : ((2 : Int) : Rat) ≠ 0 := by decide
|
||||
simp only [Rat.intCast_mul, Rat.intCast_pow, ← Rat.zpow_natCast, ← Rat.intCast_natCast,
|
||||
Int.natCast_pow, Int.cast_ofNat_Int, ← Rat.zpow_neg, Rat.mul_assoc, ne_eq,
|
||||
Rat.intCast_eq_zero_iff, Int.reduceEq, not_false_eq_true, ← Rat.zpow_add]
|
||||
rw [Int.add_neg_eq_sub, ← Int.neg_sub, Int.toNat_sub_toNat_neg]
|
||||
rfl
|
||||
|
||||
example : ((3 : Dyadic) >>> 2) + ((3 : Dyadic) >>> 2) = ((3 : Dyadic) >>> 1) := rfl -- 3/4 + 3/4 = 3/2
|
||||
example : ((7 : Dyadic) >>> 3) + ((1 : Dyadic) >>> 3) = 1 := rfl -- 7/8 + 1/8 = 1
|
||||
example : (12 : Dyadic) + ((3 : Dyadic) >>> 1) = (27 : Dyadic) >>> 1 := rfl -- 12 + 3/2 = 27/2 = (2 * 13 + 1)/2^1
|
||||
example : ((3 : Dyadic) >>> 1).add 12 = (27 : Dyadic) >>> 1 := rfl -- 3/2 + 12 = 27/2 = (2 * 13 + 1)/2^1
|
||||
example : (12 : Dyadic).add 12 = 24 := rfl -- 12 + 12 = 24
|
||||
|
||||
@[simp]
|
||||
theorem toRat_add (x y : Dyadic) : toRat (x + y) = toRat x + toRat y := by
|
||||
match x, y with
|
||||
| .zero, _ => simp [toRat, Rat.zero_add]
|
||||
| _, .zero => simp [toRat, Rat.add_zero]
|
||||
| .ofOdd n₁ k₁ hn₁, .ofOdd n₂ k₂ hn₂ =>
|
||||
change (Dyadic.add _ _).toRat = _
|
||||
rw [Dyadic.add, toRat_ofOdd_eq_mkRat, toRat_ofOdd_eq_mkRat]
|
||||
rw [Rat.mkRat_add_mkRat _ _ (NeZero.ne _) (NeZero.ne _)]
|
||||
split
|
||||
· rename_i h
|
||||
cases Int.sub_eq_zero.mp h
|
||||
rw [toRat_ofIntWithPrec_eq_mkRat, Rat.mkRat_eq_iff (NeZero.ne _) (NeZero.ne _)]
|
||||
simp [Int.shiftLeft_mul_shiftLeft, Int.add_shiftLeft, Int.add_mul, Nat.add_assoc]
|
||||
· rename_i h
|
||||
cases Int.sub_eq_iff_eq_add.mp h
|
||||
rw [toRat_ofOdd_eq_mkRat, Rat.mkRat_eq_iff (NeZero.ne _) (NeZero.ne _)]
|
||||
simp only [succ_eq_add_one, Int.ofNat_eq_coe, Int.add_shiftLeft, ← Int.shiftLeft_add,
|
||||
Int.natCast_mul, Int.natCast_shiftLeft, Int.shiftLeft_mul_shiftLeft, Int.add_mul]
|
||||
congr 2 <;> omega
|
||||
· rename_i h
|
||||
cases Int.sub_eq_iff_eq_add.mp h
|
||||
rw [toRat_ofOdd_eq_mkRat, Rat.mkRat_eq_iff (NeZero.ne _) (NeZero.ne _)]
|
||||
simp only [Int.add_shiftLeft, ← Int.shiftLeft_add, Int.natCast_mul, Int.natCast_shiftLeft,
|
||||
Int.cast_ofNat_Int, Int.shiftLeft_mul_shiftLeft, Int.mul_one, Int.add_mul]
|
||||
congr 2 <;> omega
|
||||
|
||||
@[simp]
|
||||
theorem toRat_neg (x : Dyadic) : toRat (-x) = - toRat x := by
|
||||
change x.neg.toRat = _
|
||||
cases x
|
||||
· rfl
|
||||
· simp [Dyadic.neg, Rat.neg_mkRat, Int.neg_shiftLeft, toRat_ofOdd_eq_mkRat]
|
||||
|
||||
@[simp]
|
||||
theorem toRat_sub (x y : Dyadic) : toRat (x - y) = toRat x - toRat y := by
|
||||
change toRat (x + -y) = _
|
||||
simp [Rat.sub_eq_add_neg]
|
||||
|
||||
@[simp]
|
||||
theorem toRat_mul (x y : Dyadic) : toRat (x * y) = toRat x * toRat y := by
|
||||
match x, y with
|
||||
| .zero, _ => simp
|
||||
| _, .zero => simp
|
||||
| .ofOdd n₁ k₁ hn₁, .ofOdd n₂ k₂ hn₂ =>
|
||||
change (Dyadic.mul _ _).toRat = _
|
||||
rw [Dyadic.mul, toRat_ofOdd_eq_mkRat, toRat_ofOdd_eq_mkRat, toRat_ofOdd_eq_mkRat,
|
||||
Rat.mkRat_mul_mkRat, Rat.mkRat_eq_iff (NeZero.ne _) (NeZero.ne _)]
|
||||
simp only [Int.natCast_mul, Int.natCast_shiftLeft, Int.cast_ofNat_Int,
|
||||
Int.shiftLeft_mul_shiftLeft, Int.mul_one]
|
||||
congr 1; omega
|
||||
|
||||
@[simp]
|
||||
protected theorem pow_zero (x : Dyadic) : x ^ 0 = 1 := by
|
||||
change x.pow 0 = 1
|
||||
cases x <;> simp [Dyadic.pow] <;> rfl
|
||||
|
||||
protected theorem pow_succ (x : Dyadic) (n : Nat) : x ^ (n + 1) = x ^ n * x := by
|
||||
change x.pow (n + 1) = x.pow n * x
|
||||
cases x
|
||||
· simp [Dyadic.pow]
|
||||
· change _ = Dyadic.mul _ _
|
||||
simp [Dyadic.pow, Dyadic.mul, Int.pow_succ, Int.mul_add]
|
||||
|
||||
@[simp]
|
||||
theorem toRat_pow (x : Dyadic) (n : Nat) : toRat (x ^ n) = toRat x ^ n := by
|
||||
induction n with
|
||||
| zero => simp; rfl
|
||||
| succ k ih => simp [Dyadic.pow_succ, Rat.pow_succ, ih]
|
||||
|
||||
@[simp]
|
||||
theorem toRat_intCast (x : Int) : (x : Dyadic).toRat = x := by
|
||||
change (ofInt x).toRat = x
|
||||
simp [ofInt, toRat_ofIntWithPrec_eq_mul_two_pow]
|
||||
|
||||
@[simp]
|
||||
theorem toRat_natCast (x : Nat) : (x : Dyadic).toRat = x := by
|
||||
change (ofInt x).toRat = x
|
||||
simp [ofInt, toRat_ofIntWithPrec_eq_mul_two_pow, Rat.intCast_natCast]
|
||||
|
||||
@[simp] theorem of_ne_zero : ofOdd n k hn ≠ 0 := Dyadic.noConfusion
|
||||
@[simp] theorem zero_ne_of : 0 ≠ ofOdd n k hn := Dyadic.noConfusion
|
||||
|
||||
@[simp]
|
||||
theorem toRat_eq_zero_iff {x : Dyadic} : x.toRat = 0 ↔ x = 0 := by
|
||||
refine ⟨fun h => ?_, fun h => h ▸ rfl⟩
|
||||
cases x
|
||||
· rfl
|
||||
· simp only [toRat_ofOdd_eq_mkRat, ne_eq, shiftLeft_eq_zero_iff, succ_ne_self, not_false_eq_true,
|
||||
Rat.mkRat_eq_zero, Int.shiftLeft_eq_zero_iff] at h
|
||||
cases h
|
||||
contradiction
|
||||
|
||||
theorem ofOdd_eq_ofIntWithPrec : ofOdd n k hn = ofIntWithPrec n k := by
|
||||
simp only [ofIntWithPrec, Dyadic.zero_eq, Int.trailingZeros_eq_zero_of_mod_eq hn,
|
||||
Int.shiftRight_zero, Int.cast_ofNat_Int, Int.sub_zero, right_eq_dite_iff, of_ne_zero, imp_false]
|
||||
intro rfl; contradiction
|
||||
|
||||
theorem toRat_ofOdd_eq_mul_two_pow : toRat (.ofOdd n k hn) = n * 2 ^ (-k) := by
|
||||
rw [ofOdd_eq_ofIntWithPrec, toRat_ofIntWithPrec_eq_mul_two_pow]
|
||||
|
||||
@[simp]
|
||||
theorem ofIntWithPrec_zero {i : Int} : ofIntWithPrec 0 i = 0 := rfl
|
||||
|
||||
@[simp]
|
||||
theorem neg_ofOdd : -ofOdd n k hn = ofOdd (-n) k (by simpa using hn) := rfl
|
||||
|
||||
@[simp]
|
||||
theorem neg_ofIntWithPrec {i prec : Int} : -ofIntWithPrec i prec = ofIntWithPrec (-i) prec := by
|
||||
rw [ofIntWithPrec, ofIntWithPrec]
|
||||
simp only [Dyadic.zero_eq, Int.neg_eq_zero, Int.trailingZeros_neg]
|
||||
split
|
||||
· rfl
|
||||
· obtain ⟨a, h⟩ := Int.two_pow_trailingZeros_dvd ‹_›
|
||||
rw [Int.mul_comm, ← Int.shiftLeft_eq] at h
|
||||
conv => enter [1, 1, 1, 1]; rw [h]
|
||||
conv => enter [2, 1, 1]; rw [h]
|
||||
simp only [Int.shiftLeft_shiftRight_cancel, neg_ofOdd, ← Int.neg_shiftLeft]
|
||||
|
||||
theorem ofIntWithPrec_shiftLeft_add {n : Nat} :
|
||||
ofIntWithPrec ((x : Int) <<< n) (i + n) = ofIntWithPrec x i := by
|
||||
rw [ofIntWithPrec, ofIntWithPrec]
|
||||
simp only [Int.shiftLeft_eq_zero_iff]
|
||||
split
|
||||
· rfl
|
||||
· simp [Int.trailingZeros_shiftLeft, *, Int.shiftLeft_shiftRight_eq_shiftRight_of_le,
|
||||
Int.add_comm x.trailingZeros n, ← Int.sub_sub]
|
||||
|
||||
/-- The "precision" of a dyadic number, i.e. in `n * 2^(-p)` with `n` odd the precision is `p`. -/
|
||||
-- TODO: If `WithBot` is upstreamed, replace this with `WithBot Int`.
|
||||
def precision : Dyadic → Option Int
|
||||
| .zero => none
|
||||
| .ofOdd _ p _ => some p
|
||||
|
||||
theorem precision_ofIntWithPrec_le {i : Int} (h : i ≠ 0) (prec : Int) :
|
||||
(ofIntWithPrec i prec).precision ≤ some prec := by
|
||||
simp [ofIntWithPrec, h, precision]
|
||||
omega
|
||||
|
||||
@[simp] theorem precision_zero : (0 : Dyadic).precision = none := rfl
|
||||
@[simp] theorem precision_neg {x : Dyadic} : (-x).precision = x.precision :=
|
||||
match x with
|
||||
| .zero => rfl
|
||||
| .ofOdd _ _ _ => rfl
|
||||
|
||||
end Dyadic
|
||||
|
||||
namespace Rat
|
||||
|
||||
open Dyadic
|
||||
|
||||
/--
|
||||
Convert a rational number `x` to the greatest dyadic number with precision at most `prec`
|
||||
which is less than or equal to `x`.
|
||||
-/
|
||||
def toDyadic (x : Rat) (prec : Int) : Dyadic :=
|
||||
match prec with
|
||||
| (n : Nat) => .ofIntWithPrec ((x.num <<< n) / x.den) prec
|
||||
| -(n + 1 : Nat) => .ofIntWithPrec (x.num / (x.den <<< (n + 1))) prec
|
||||
|
||||
theorem toDyadic_mkRat (a : Int) (b : Nat) (prec : Int) :
|
||||
Rat.toDyadic (mkRat a b) prec =
|
||||
.ofIntWithPrec ((a <<< prec.toNat) / (b <<< (-prec).toNat)) prec := by
|
||||
by_cases hb : b = 0
|
||||
· cases prec <;> simp [hb, Rat.toDyadic]
|
||||
rcases h : mkRat a b with ⟨n, d, hnz, hr⟩
|
||||
obtain ⟨m, hm, rfl, rfl⟩ := Rat.mkRat_num_den hb h
|
||||
cases prec
|
||||
· simp only [Rat.toDyadic, Int.ofNat_eq_coe, Int.toNat_natCast, Int.toNat_neg_natCast,
|
||||
shiftLeft_zero, Int.natCast_mul]
|
||||
rw [Int.mul_comm d, ← Int.ediv_ediv (by simp), ← Int.shiftLeft_mul,
|
||||
Int.mul_ediv_cancel _ (by simpa using hm)]
|
||||
· simp only [Rat.toDyadic, Int.natCast_shiftLeft, Int.negSucc_eq, ← Int.natCast_add_one,
|
||||
Int.toNat_neg_natCast, Int.shiftLeft_zero, Int.neg_neg, Int.toNat_natCast, Int.natCast_mul]
|
||||
rw [Int.mul_comm d, ← Int.mul_shiftLeft, ← Int.ediv_ediv (by simp),
|
||||
Int.mul_ediv_cancel _ (by simpa using hm)]
|
||||
|
||||
theorem toDyadic_eq_ofIntWithPrec (x : Rat) (prec : Int) :
|
||||
x.toDyadic prec = .ofIntWithPrec ((x.num <<< prec.toNat) / (x.den <<< (-prec).toNat)) prec := by
|
||||
conv => lhs; rw [← Rat.mkRat_self x]
|
||||
rw [Rat.toDyadic_mkRat]
|
||||
|
||||
/--
|
||||
Converting a rational to a dyadic at a given precision and then back to a rational
|
||||
gives the same result as taking the floor of the rational at precision `2 ^ prec`.
|
||||
-/
|
||||
theorem toRat_toDyadic (x : Rat) (prec : Int) :
|
||||
(x.toDyadic prec).toRat = (x * 2 ^ prec).floor / 2 ^ prec := by
|
||||
rw [Rat.toDyadic_eq_ofIntWithPrec, toRat_ofIntWithPrec_eq_mul_two_pow, Rat.zpow_neg, Rat.div_def]
|
||||
congr 2
|
||||
rw [Rat.floor_def, Int.shiftLeft_eq, Nat.shiftLeft_eq]
|
||||
match prec with
|
||||
| .ofNat prec =>
|
||||
simp only [Int.ofNat_eq_coe, Int.toNat_natCast, Int.toNat_neg_natCast, Nat.pow_zero,
|
||||
Nat.mul_one]
|
||||
have : (2 ^ prec : Rat) = ((2 ^ prec : Nat) : Rat) := by simp
|
||||
rw [Rat.zpow_natCast, this, Rat.mul_def']
|
||||
simp only [Rat.num_mkRat, Rat.den_mkRat]
|
||||
simp only [Rat.natCast_pow, Rat.natCast_ofNat, Rat.num_pow, Rat.num_ofNat, Rat.den_pow,
|
||||
Rat.den_ofNat, Nat.one_pow, Nat.mul_one]
|
||||
split
|
||||
· simp_all
|
||||
· rw [Int.ediv_ediv (Int.ofNat_zero_le _)]
|
||||
congr 1
|
||||
rw [Int.natCast_ediv, Int.mul_ediv_cancel']
|
||||
rw [Int.natCast_dvd_natCast]
|
||||
apply gcd_dvd_left
|
||||
| .negSucc prec =>
|
||||
simp only [Int.toNat_negSucc, Int.pow_zero, Int.mul_one, Int.neg_negSucc, Int.natCast_mul,
|
||||
Int.natCast_pow, Int.cast_ofNat_Int]
|
||||
have : (2 ^ ((prec : Int) + 1)) = ((2 ^ (prec + 1) : Nat) : Rat) := by simp; rfl
|
||||
rw [Int.negSucc_eq, Rat.zpow_neg, this, Rat.mul_def']
|
||||
simp only [Rat.num_mkRat, Rat.den_mkRat]
|
||||
simp only [natCast_pow, natCast_ofNat, den_inv, num_pow, num_ofNat, Int.natAbs_pow,
|
||||
Int.reduceAbs, num_inv, den_pow, den_ofNat, Nat.one_pow, Int.cast_ofNat_Int, Int.mul_one]
|
||||
have : ¬ (2 ^ (prec + 1) : Int) = 0 := NeZero.out
|
||||
simp only [if_neg this]
|
||||
have : (2 ^ (prec + 1) : Int).sign = 1 := by simpa using Int.pow_pos (by decide)
|
||||
simp only [this]
|
||||
have : x.den * 2 ^ (prec + 1) = 0 ↔ x.den = 0 := by
|
||||
rw [Nat.mul_eq_zero]
|
||||
simp_all
|
||||
simp only [this, Int.mul_one]
|
||||
split
|
||||
· simp_all
|
||||
· rw [Int.ediv_ediv (Int.ofNat_zero_le _)]
|
||||
congr 1
|
||||
rw [Int.natCast_ediv, Int.mul_ediv_cancel']
|
||||
· simp
|
||||
· rw [Int.natCast_dvd_natCast]
|
||||
apply gcd_dvd_left
|
||||
|
||||
theorem toRat_toDyadic_le {x : Rat} {prec : Int} : (x.toDyadic prec).toRat ≤ x := by
|
||||
rw [toRat_toDyadic]
|
||||
have : (x * 2 ^ prec).floor ≤ x * 2 ^ prec := Rat.floor_le _
|
||||
apply Rat.le_of_mul_le_mul_right (c := 2 ^ prec)
|
||||
rw [Rat.div_mul_cancel]
|
||||
exact this
|
||||
· apply Rat.ne_of_gt (Rat.zpow_pos (by decide))
|
||||
· exact Rat.zpow_pos (by decide)
|
||||
|
||||
theorem lt_toRat_toDyadic_add {x : Rat} {prec : Int} :
|
||||
x < (x.toDyadic prec + ofIntWithPrec 1 prec).toRat := by
|
||||
rw [toRat_add, toRat_toDyadic, toRat_ofIntWithPrec_eq_mul_two_pow]
|
||||
have := Rat.lt_floor_add_one (x * 2 ^ prec)
|
||||
rw [Rat.zpow_neg, Rat.div_def, ← Rat.add_mul]
|
||||
apply Rat.lt_of_mul_lt_mul_right (c := 2 ^ prec)
|
||||
rw [Rat.mul_assoc, Rat.inv_mul_cancel, Rat.mul_one]
|
||||
exact mod_cast this
|
||||
· apply Rat.ne_of_gt (Rat.zpow_pos (by decide))
|
||||
· exact Rat.zpow_nonneg (by decide)
|
||||
|
||||
-- TODO: `x.toDyadic prec` is the unique dyadic with the given precision satisfying the two inequalities above.
|
||||
|
||||
end Rat
|
||||
|
||||
namespace Dyadic
|
||||
|
||||
/--
|
||||
Rounds a dyadic rational `x` down to the greatest dyadic number with precision at most `prec`
|
||||
which is less than or equal to `x`.
|
||||
-/
|
||||
def roundDown (x : Dyadic) (prec : Int) : Dyadic :=
|
||||
match x with
|
||||
| .zero => .zero
|
||||
| .ofOdd n k _ =>
|
||||
match k - prec with
|
||||
| .ofNat l => .ofIntWithPrec (n >>> l) prec
|
||||
| .negSucc _ => x
|
||||
|
||||
theorem roundDown_eq_self_of_le {x : Dyadic} {prec : Int} (h : x.precision ≤ some prec) :
|
||||
roundDown x prec = x := by
|
||||
rcases x with _ | ⟨n, k, hn⟩
|
||||
· rfl
|
||||
· simp only [precision] at h
|
||||
obtain ⟨a, rfl⟩ := h.dest
|
||||
rcases a with _ | a
|
||||
· simp [roundDown, ofOdd_eq_ofIntWithPrec]
|
||||
· have : k - (k + (a + 1 : Nat)) = Int.negSucc a := by omega
|
||||
simp only [roundDown, this]
|
||||
|
||||
@[simp]
|
||||
theorem toDyadic_toRat (x : Dyadic) (prec : Int) :
|
||||
x.toRat.toDyadic prec = x.roundDown prec := by
|
||||
rcases x with _ | ⟨n, k, hn⟩
|
||||
· cases prec <;> simp [Rat.toDyadic, roundDown]
|
||||
· simp only [toRat_ofOdd_eq_mkRat, roundDown]
|
||||
rw [Rat.toDyadic_mkRat]
|
||||
simp only [← Int.shiftLeft_add, Int.natCast_shiftLeft, Int.cast_ofNat_Int]
|
||||
rw [Int.shiftLeft_eq' 1, Int.one_mul, ← Int.shiftRight_eq_div_pow]
|
||||
rw [Int.shiftLeft_shiftRight_eq, ← Int.toNat_sub, ← Int.toNat_sub, ← Int.neg_sub]
|
||||
have : ((k.toNat + (-prec).toNat : Nat) - ((-k).toNat + prec.toNat : Nat) : Int) = k - prec := by
|
||||
omega
|
||||
rw [this]
|
||||
cases h : k - prec
|
||||
· simp
|
||||
· simp only [Int.neg_negSucc, Int.natCast_add, Int.cast_ofNat_Int, Int.toNat_natCast_add_one,
|
||||
Int.toNat_negSucc, Int.shiftRight_zero]
|
||||
rw [Int.negSucc_eq, Int.eq_neg_comm, Int.neg_sub, eq_comm, Int.sub_eq_iff_eq_add] at h
|
||||
simp only [h, ← Int.natCast_add_one, Int.add_comm _ k, ofIntWithPrec_shiftLeft_add,
|
||||
ofOdd_eq_ofIntWithPrec]
|
||||
|
||||
theorem toRat_inj {x y : Dyadic} : x.toRat = y.toRat ↔ x = y := by
|
||||
refine ⟨fun h => ?_, fun h => h ▸ rfl⟩
|
||||
cases x <;> cases y
|
||||
· rfl
|
||||
· simp [eq_comm (a := (0 : Rat))] at h
|
||||
· simp at h
|
||||
· rename_i n₁ k₁ hn₁ n₂ k₂ hn₂
|
||||
replace h := congrArg (·.toDyadic (max k₁ k₂)) h
|
||||
simpa [toDyadic_toRat, roundDown_eq_self_of_le, precision, Int.le_max_left, Int.le_max_right]
|
||||
using h
|
||||
|
||||
theorem add_comm (x y : Dyadic) : x + y = y + x := by
|
||||
rw [← toRat_inj, toRat_add, toRat_add, Rat.add_comm]
|
||||
|
||||
theorem add_assoc (x y z : Dyadic) : (x + y) + z = x + (y + z) := by
|
||||
rw [← toRat_inj, toRat_add, toRat_add, toRat_add, toRat_add, Rat.add_assoc]
|
||||
|
||||
theorem mul_comm (x y : Dyadic) : x * y = y * x := by
|
||||
rw [← toRat_inj, toRat_mul, toRat_mul, Rat.mul_comm]
|
||||
|
||||
theorem mul_assoc (x y z : Dyadic) : (x * y) * z = x * (y * z) := by
|
||||
rw [← toRat_inj, toRat_mul, toRat_mul, toRat_mul, toRat_mul, Rat.mul_assoc]
|
||||
|
||||
theorem mul_one (x : Dyadic) : x * 1 = x := by
|
||||
rw [← toRat_inj, toRat_mul]
|
||||
exact Rat.mul_one x.toRat
|
||||
|
||||
theorem one_mul (x : Dyadic) : 1 * x = x := by
|
||||
rw [← toRat_inj, toRat_mul]
|
||||
exact Rat.one_mul x.toRat
|
||||
|
||||
theorem add_mul (x y z : Dyadic) : (x + y) * z = x * z + y * z := by
|
||||
simp [← toRat_inj, Rat.add_mul]
|
||||
|
||||
theorem mul_add (x y z : Dyadic) : x * (y + z) = x * y + x * z := by
|
||||
simp [← toRat_inj, Rat.mul_add]
|
||||
|
||||
theorem neg_add_cancel (x : Dyadic) : -x + x = 0 := by
|
||||
simp [← toRat_inj, Rat.neg_add_cancel]
|
||||
|
||||
theorem neg_mul (x y : Dyadic) : -x * y = -(x * y) := by
|
||||
simp [← toRat_inj, Rat.neg_mul]
|
||||
|
||||
/-- Determine if a dyadic rational is strictly less than another. -/
|
||||
def blt (x y : Dyadic) : Bool :=
|
||||
match x, y with
|
||||
| .zero, .zero => false
|
||||
| .zero, .ofOdd n₂ _ _ => 0 < n₂
|
||||
| .ofOdd n₁ _ _, .zero => n₁ < 0
|
||||
| .ofOdd n₁ k₁ _, .ofOdd n₂ k₂ _ =>
|
||||
match k₂ - k₁ with
|
||||
| (l : Nat) => (n₁ <<< l) < n₂
|
||||
| -((l+1 : Nat)) => n₁ < (n₂ <<< (l + 1))
|
||||
|
||||
/-- Determine if a dyadic rational is less than or equal to another. -/
|
||||
def ble (x y : Dyadic) : Bool :=
|
||||
match x, y with
|
||||
| .zero, .zero => true
|
||||
| .zero, .ofOdd n₂ _ _ => 0 ≤ n₂
|
||||
| .ofOdd n₁ _ _, .zero => n₁ ≤ 0
|
||||
| .ofOdd n₁ k₁ _, .ofOdd n₂ k₂ _ =>
|
||||
match k₂ - k₁ with
|
||||
| (l : Nat) => (n₁ <<< l) ≤ n₂
|
||||
| -((l+1 : Nat)) => n₁ ≤ (n₂ <<< (l + 1))
|
||||
|
||||
theorem blt_iff_toRat {x y : Dyadic} : blt x y ↔ x.toRat < y.toRat := by
|
||||
rcases x with _ | ⟨n₁, k₁, hn₁⟩ <;> rcases y with _ | ⟨n₂, k₂, hn₂⟩
|
||||
· decide
|
||||
· simp only [blt, decide_eq_true_eq, Dyadic.zero_eq, toRat_zero, toRat_ofOdd_eq_mul_two_pow,
|
||||
Rat.mul_pos_iff_of_pos_right (Rat.zpow_pos (by decide : (0 : Rat) < 2)), Rat.intCast_pos]
|
||||
· simp only [blt, decide_eq_true_eq, Dyadic.zero_eq, toRat_zero, toRat_ofOdd_eq_mul_two_pow,
|
||||
Rat.mul_neg_iff_of_pos_right (Rat.zpow_pos (by decide : (0 : Rat) < 2)), Rat.intCast_neg_iff]
|
||||
· simp only [blt, toRat_ofOdd_eq_mul_two_pow,
|
||||
← Rat.div_lt_iff (Rat.zpow_pos (by decide : (0 : Rat) < 2)), Rat.div_def, ← Rat.zpow_neg,
|
||||
Int.neg_neg, Rat.mul_assoc, ne_eq, Rat.ofNat_eq_ofNat, reduceCtorEq, not_false_eq_true,
|
||||
← Rat.zpow_add, Int.shiftLeft_eq]
|
||||
rw [Int.add_comm, Int.add_neg_eq_sub]
|
||||
split
|
||||
· simp [decide_eq_true_eq, ← Rat.intCast_lt_intCast, Rat.zpow_natCast, *]
|
||||
· simp only [decide_eq_true_eq, Int.negSucc_eq, *]
|
||||
rw [Rat.zpow_neg, ← Rat.div_def, Rat.div_lt_iff (Rat.zpow_pos (by decide))]
|
||||
simp [← Rat.intCast_lt_intCast, ← Rat.zpow_natCast, *]
|
||||
|
||||
theorem blt_eq_false_iff : blt x y = false ↔ ble y x = true := by
|
||||
cases x <;> cases y
|
||||
· simp [ble, blt]
|
||||
· simp [ble, blt]
|
||||
· simp [ble, blt]
|
||||
· rename_i n₁ k₁ hn₁ n₂ k₂ hn₂
|
||||
simp only [blt, ble]
|
||||
rw [← Int.neg_sub]
|
||||
rcases k₁ - k₂ with (_ | _) | _
|
||||
· simp
|
||||
· simp [← Int.negSucc_eq]
|
||||
· simp only [Int.neg_negSucc, decide_eq_false_iff_not, Int.not_lt,
|
||||
decide_eq_true_eq]
|
||||
|
||||
theorem ble_iff_toRat : ble x y ↔ x.toRat ≤ y.toRat := by
|
||||
rw [← blt_eq_false_iff, Bool.eq_false_iff]
|
||||
simp only [ne_eq, blt_iff_toRat, Rat.not_lt]
|
||||
|
||||
instance : LT Dyadic where
|
||||
lt x y := blt x y
|
||||
|
||||
instance : LE Dyadic where
|
||||
le x y := ble x y
|
||||
|
||||
instance : DecidableLT Dyadic := fun _ _ => inferInstanceAs (Decidable (_ = true))
|
||||
instance : DecidableLE Dyadic := fun _ _ => inferInstanceAs (Decidable (_ = true))
|
||||
|
||||
theorem lt_iff_toRat {x y : Dyadic} : x < y ↔ x.toRat < y.toRat := blt_iff_toRat
|
||||
|
||||
theorem le_iff_toRat {x y : Dyadic} : x ≤ y ↔ x.toRat ≤ y.toRat := ble_iff_toRat
|
||||
|
||||
@[simp]
|
||||
protected theorem not_le {x y : Dyadic} : ¬x < y ↔ y ≤ x := by
|
||||
simp only [· ≤ ·, · < ·, Bool.not_eq_true, blt_eq_false_iff]
|
||||
|
||||
@[simp]
|
||||
protected theorem not_lt {x y : Dyadic} : ¬x ≤ y ↔ y < x := by
|
||||
rw [← Dyadic.not_le, Decidable.not_not]
|
||||
|
||||
@[simp]
|
||||
protected theorem le_refl (x : Dyadic) : x ≤ x := by
|
||||
rw [le_iff_toRat]
|
||||
exact Rat.le_refl
|
||||
|
||||
protected theorem le_trans {x y z : Dyadic} (h : x ≤ y) (h' : y ≤ z) : x ≤ z := by
|
||||
rw [le_iff_toRat] at h h' ⊢
|
||||
exact Rat.le_trans h h'
|
||||
|
||||
protected theorem le_antisymm {x y : Dyadic} (h : x ≤ y) (h' : y ≤ x) : x = y := by
|
||||
rw [le_iff_toRat] at h h'
|
||||
rw [← toRat_inj]
|
||||
exact Rat.le_antisymm h h'
|
||||
|
||||
protected theorem le_total (x y : Dyadic) : x ≤ y ∨ y ≤ x := by
|
||||
rw [le_iff_toRat, le_iff_toRat]
|
||||
exact Rat.le_total
|
||||
|
||||
instance : Std.LawfulOrderLT Dyadic where
|
||||
lt_iff a b := by rw [← Dyadic.not_lt, iff_and_self]; exact (Dyadic.le_total _ _).resolve_left
|
||||
|
||||
instance : Std.IsPreorder Dyadic where
|
||||
le_refl := Dyadic.le_refl
|
||||
le_trans _ _ _ := Dyadic.le_trans
|
||||
|
||||
instance : Std.IsPartialOrder Dyadic where
|
||||
le_antisymm _ _ := Dyadic.le_antisymm
|
||||
|
||||
instance : Std.IsLinearPreorder Dyadic where
|
||||
le_total := Dyadic.le_total
|
||||
|
||||
instance : Std.IsLinearOrder Dyadic where
|
||||
|
||||
/-- `roundUp x prec` is the least dyadic number with precision at most `prec` which is greater than or equal to `x`. -/
|
||||
def roundUp (x : Dyadic) (prec : Int) : Dyadic :=
|
||||
match x with
|
||||
| .zero => .zero
|
||||
| .ofOdd n k _ =>
|
||||
match k - prec with
|
||||
| .ofNat l => .ofIntWithPrec (-((-n) >>> l)) prec
|
||||
| .negSucc _ => x
|
||||
|
||||
theorem roundUp_eq_neg_roundDown_neg (x : Dyadic) (prec : Int) :
|
||||
x.roundUp prec = -((-x).roundDown prec) := by
|
||||
rcases x with _ | ⟨n, k, hn⟩
|
||||
· rfl
|
||||
· change _ = -(ofOdd ..).roundDown prec
|
||||
rw [roundDown, roundUp]
|
||||
split <;> simp
|
||||
|
||||
end Dyadic
|
||||
60
src/Init/Data/Dyadic/Instances.lean
Normal file
60
src/Init/Data/Dyadic/Instances.lean
Normal file
@@ -0,0 +1,60 @@
|
||||
/-
|
||||
Copyright (c) 2025 Lean FRO, LLC. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Kim Morrison, Robin Arnez
|
||||
-/
|
||||
module
|
||||
|
||||
prelude
|
||||
public import Init.Data.Dyadic.Basic
|
||||
public import Init.Grind.Ring.Basic
|
||||
public import Init.Grind.Ordered.Ring
|
||||
|
||||
/-! # Internal `grind` algebra instances for `Dyadic`. -/
|
||||
|
||||
open Lean.Grind
|
||||
|
||||
namespace Dyadic
|
||||
|
||||
instance : CommRing Dyadic where
|
||||
nsmul := ⟨(· * ·)⟩
|
||||
zsmul := ⟨(· * ·)⟩
|
||||
add_zero := Dyadic.add_zero
|
||||
add_comm := Dyadic.add_comm
|
||||
add_assoc := Dyadic.add_assoc
|
||||
mul_assoc := Dyadic.mul_assoc
|
||||
mul_one := Dyadic.mul_one
|
||||
one_mul := Dyadic.one_mul
|
||||
zero_mul := Dyadic.zero_mul
|
||||
mul_zero := Dyadic.mul_zero
|
||||
mul_comm := Dyadic.mul_comm
|
||||
pow_zero := Dyadic.pow_zero
|
||||
pow_succ := Dyadic.pow_succ
|
||||
sub_eq_add_neg _ _ := rfl
|
||||
neg_add_cancel := Dyadic.neg_add_cancel
|
||||
neg_zsmul i a := by
|
||||
change ((-i : Int) : Dyadic) * a = -(i * a)
|
||||
simp [← toRat_inj, Rat.neg_mul]
|
||||
left_distrib := Dyadic.mul_add
|
||||
right_distrib := Dyadic.add_mul
|
||||
intCast_neg _ := by simp [← toRat_inj]
|
||||
ofNat_succ n := by
|
||||
change ((n + 1 : Int) : Dyadic) = ((n : Int) : Dyadic) + 1
|
||||
simp [← toRat_inj, Rat.intCast_add]; rfl
|
||||
|
||||
instance : IsCharP Dyadic 0 := IsCharP.mk' _ _
|
||||
(ofNat_eq_zero_iff := fun x => by change (x : Dyadic) = 0 ↔ _; simp [← toRat_inj])
|
||||
|
||||
instance : NoNatZeroDivisors Dyadic where
|
||||
no_nat_zero_divisors k a b h₁ h₂ := by
|
||||
change k * a = k * b at h₂
|
||||
simp only [← toRat_inj, toRat_mul, toRat_natCast] at h₂ ⊢
|
||||
simpa [← Rat.mul_assoc, Rat.inv_mul_cancel, h₁] using congrArg ((k : Rat)⁻¹ * ·) h₂
|
||||
|
||||
instance : OrderedRing Dyadic where
|
||||
zero_lt_one := by decide
|
||||
add_le_left_iff _ := by simp [le_iff_toRat, Rat.add_le_add_right]
|
||||
mul_lt_mul_of_pos_left {_ _ _} := by simpa [lt_iff_toRat] using Rat.mul_lt_mul_of_pos_left
|
||||
mul_lt_mul_of_pos_right {_ _ _} := by simpa [lt_iff_toRat] using Rat.mul_lt_mul_of_pos_right
|
||||
|
||||
end Dyadic
|
||||
80
src/Init/Data/Dyadic/Inv.lean
Normal file
80
src/Init/Data/Dyadic/Inv.lean
Normal file
@@ -0,0 +1,80 @@
|
||||
/-
|
||||
Copyright (c) 2025 Lean FRO, LLC. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Kim Morrison
|
||||
-/
|
||||
module
|
||||
prelude
|
||||
import Init.Data.Dyadic.Basic
|
||||
import Init.Data.Dyadic.Round
|
||||
import Init.Grind.Ordered.Ring
|
||||
|
||||
/-!
|
||||
# Inversion for dyadic numbers
|
||||
-/
|
||||
|
||||
namespace Dyadic
|
||||
|
||||
/--
|
||||
Inverts a dyadic number at a given (maximum) precision.
|
||||
Returns the greatest dyadic number with precision at most `prec` which is less than or equal to `1/x`.
|
||||
For `x = 0`, returns `0`.
|
||||
-/
|
||||
def invAtPrec (x : Dyadic) (prec : Int) : Dyadic :=
|
||||
match x with
|
||||
| .zero => .zero
|
||||
| _ => x.toRat.inv.toDyadic prec
|
||||
|
||||
/-- For a positive dyadic `x`, `invAtPrec x prec * x ≤ 1`. -/
|
||||
theorem invAtPrec_mul_le_one {x : Dyadic} (hx : 0 < x) (prec : Int) :
|
||||
invAtPrec x prec * x ≤ 1 := by
|
||||
rw [le_iff_toRat]
|
||||
rw [toRat_mul]
|
||||
rw [show (1 : Dyadic).toRat = (1 : Rat) from rfl]
|
||||
unfold invAtPrec
|
||||
cases x with
|
||||
| zero =>
|
||||
exfalso
|
||||
contradiction
|
||||
| ofOdd n k hn =>
|
||||
simp only
|
||||
have h_le : ((ofOdd n k hn).toRat.inv.toDyadic prec).toRat ≤ (ofOdd n k hn).toRat.inv := Rat.toRat_toDyadic_le
|
||||
have h_pos : 0 ≤ (ofOdd n k hn).toRat := by
|
||||
rw [lt_iff_toRat, toRat_zero] at hx
|
||||
exact Rat.le_of_lt hx
|
||||
calc ((ofOdd n k hn).toRat.inv.toDyadic prec).toRat * (ofOdd n k hn).toRat
|
||||
≤ (ofOdd n k hn).toRat.inv * (ofOdd n k hn).toRat := Rat.mul_le_mul_of_nonneg_right h_le h_pos
|
||||
_ = 1 := by
|
||||
apply Rat.inv_mul_cancel
|
||||
rw [lt_iff_toRat, toRat_zero] at hx
|
||||
exact Rat.ne_of_gt hx
|
||||
|
||||
/-- For a positive dyadic `x`, `1 < (invAtPrec x prec + 2^(-prec)) * x`. -/
|
||||
theorem one_lt_invAtPrec_add_inc_mul {x : Dyadic} (hx : 0 < x) (prec : Int) :
|
||||
1 < (invAtPrec x prec + ofIntWithPrec 1 prec) * x := by
|
||||
rw [lt_iff_toRat]
|
||||
rw [toRat_mul]
|
||||
rw [show (1 : Dyadic).toRat = (1 : Rat) from rfl]
|
||||
unfold invAtPrec
|
||||
cases x with
|
||||
| zero =>
|
||||
exfalso
|
||||
contradiction
|
||||
| ofOdd n k hn =>
|
||||
simp only
|
||||
have h_le : (ofOdd n k hn).toRat.inv < ((ofOdd n k hn).toRat.inv.toDyadic prec + ofIntWithPrec 1 prec).toRat :=
|
||||
Rat.lt_toRat_toDyadic_add
|
||||
have h_pos : 0 < (ofOdd n k hn).toRat := by
|
||||
rwa [lt_iff_toRat, toRat_zero] at hx
|
||||
calc
|
||||
1 = (ofOdd n k hn).toRat.inv * (ofOdd n k hn).toRat := by
|
||||
symm
|
||||
apply Rat.inv_mul_cancel
|
||||
rw [lt_iff_toRat, toRat_zero] at hx
|
||||
exact Rat.ne_of_gt hx
|
||||
_ < ((ofOdd n k hn).toRat.inv.toDyadic prec + ofIntWithPrec 1 prec).toRat * (ofOdd n k hn).toRat :=
|
||||
Rat.mul_lt_mul_of_pos_right h_le h_pos
|
||||
|
||||
-- TODO: `invAtPrec` is the unique dyadic with the given precision satisfying the two inequalities above.
|
||||
|
||||
end Dyadic
|
||||
77
src/Init/Data/Dyadic/Round.lean
Normal file
77
src/Init/Data/Dyadic/Round.lean
Normal file
@@ -0,0 +1,77 @@
|
||||
/-
|
||||
Copyright (c) 2025 Lean FRO, LLC. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Kim Morrison
|
||||
-/
|
||||
module
|
||||
|
||||
prelude
|
||||
public import Init.Data.Dyadic.Basic
|
||||
import all Init.Data.Dyadic.Instances
|
||||
import Init.Data.Int.Bitwise.Lemmas
|
||||
import Init.Grind.Ordered.Rat
|
||||
import Init.Grind.Ordered.Field
|
||||
|
||||
namespace Dyadic
|
||||
|
||||
/-!
|
||||
Theorems about `roundUp` and `roundDown`.
|
||||
-/
|
||||
|
||||
public section
|
||||
|
||||
theorem roundDown_le {x : Dyadic} {prec : Int} : roundDown x prec ≤ x :=
|
||||
match x with
|
||||
| .zero => Dyadic.le_refl _
|
||||
| .ofOdd n k _ => by
|
||||
unfold roundDown
|
||||
dsimp
|
||||
match h : k - prec with
|
||||
| .ofNat l =>
|
||||
dsimp
|
||||
rw [ofOdd_eq_ofIntWithPrec, le_iff_toRat]
|
||||
replace h : k = Int.ofNat l + prec := by omega
|
||||
subst h
|
||||
simp only [toRat_ofIntWithPrec_eq_mul_two_pow]
|
||||
rw [Int.neg_add, Rat.zpow_add (by decide), ← Rat.mul_assoc]
|
||||
refine Lean.Grind.OrderedRing.mul_le_mul_of_nonneg_right ?_ (Rat.zpow_nonneg (by decide))
|
||||
rw [Int.shiftRight_eq_div_pow]
|
||||
rw [← Lean.Grind.Field.IsOrdered.mul_le_mul_iff_of_pos_right (c := 2^(Int.ofNat l)) (Rat.zpow_pos (by decide))]
|
||||
simp only [Int.natCast_pow, Int.cast_ofNat_Int, Int.ofNat_eq_coe]
|
||||
rw [Rat.mul_assoc, ← Rat.zpow_add (by decide), Int.add_left_neg, Rat.zpow_zero, Rat.mul_one]
|
||||
have : (2 : Rat) ^ (l : Int) = (2 ^ l : Int) := by
|
||||
rw [Rat.zpow_natCast, Rat.intCast_pow, Rat.intCast_ofNat]
|
||||
rw [this, ← Rat.intCast_mul, Rat.intCast_le_intCast]
|
||||
exact Int.ediv_mul_le n (Int.pow_ne_zero (by decide))
|
||||
| .negSucc _ =>
|
||||
apply Dyadic.le_refl
|
||||
|
||||
theorem precision_roundDown {x : Dyadic} {prec : Int} : (roundDown x prec).precision ≤ some prec := by
|
||||
unfold roundDown
|
||||
match x with
|
||||
| zero => simp [precision]
|
||||
| ofOdd n k hn =>
|
||||
dsimp
|
||||
split
|
||||
· rename_i n' h
|
||||
by_cases h' : n >>> n' = 0
|
||||
· simp [h']
|
||||
· exact precision_ofIntWithPrec_le h' _
|
||||
· simp [precision]
|
||||
omega
|
||||
|
||||
-- This theorem would characterize `roundDown` in terms of the order and `precision`.
|
||||
-- theorem le_roundDown {x y : Dyadic} {prec : Int} (h : y.precision ≤ some prec) (h' : y ≤ x) :
|
||||
-- y ≤ x.roundDown prec := sorry
|
||||
|
||||
theorem le_roundUp {x : Dyadic} {prec : Int} : x ≤ roundUp x prec := by
|
||||
rw [roundUp_eq_neg_roundDown_neg, Lean.Grind.OrderedAdd.le_neg_iff]
|
||||
apply roundDown_le
|
||||
|
||||
theorem precision_roundUp {x : Dyadic} {prec : Int} : (roundUp x prec).precision ≤ some prec := by
|
||||
rw [roundUp_eq_neg_roundDown_neg, precision_neg]
|
||||
exact precision_roundDown
|
||||
|
||||
-- This theorem would characterize `roundUp` in terms of the order and `precision`.
|
||||
-- theorem roundUp_le {x y : Dyadic} {prec : Int} (h : y.precision ≤ some prec) (h' : x ≤ y) :
|
||||
-- x.roundUp prec ≤ y := sorry
|
||||
@@ -25,12 +25,12 @@ namespace Fin
|
||||
|
||||
@[deprecated ofNat_zero (since := "2025-05-28")] abbrev ofNat'_zero := @ofNat_zero
|
||||
|
||||
theorem mod_def (a m : Fin n) : a % m = Fin.mk (a % m) (Nat.lt_of_le_of_lt (Nat.mod_le _ _) a.2) :=
|
||||
theorem mod_def (a m : Fin n) : a % m = Fin.mk (a.val % m.val) (Nat.lt_of_le_of_lt (Nat.mod_le _ _) a.2) :=
|
||||
rfl
|
||||
|
||||
theorem mul_def (a b : Fin n) : a * b = Fin.mk ((a * b) % n) (Nat.mod_lt _ a.pos) := rfl
|
||||
theorem mul_def (a b : Fin n) : a * b = Fin.mk ((a.val * b.val) % n) (Nat.mod_lt _ a.pos) := rfl
|
||||
|
||||
theorem sub_def (a b : Fin n) : a - b = Fin.mk (((n - b) + a) % n) (Nat.mod_lt _ a.pos) := rfl
|
||||
theorem sub_def (a b : Fin n) : a - b = Fin.mk (((n - b.val) + a.val) % n) (Nat.mod_lt _ a.pos) := rfl
|
||||
|
||||
theorem pos' : ∀ [Nonempty (Fin n)], 0 < n | ⟨i⟩ => i.pos
|
||||
|
||||
@@ -81,7 +81,7 @@ theorem mk_val (i : Fin n) : (⟨i, i.isLt⟩ : Fin n) = i := Fin.eta ..
|
||||
|
||||
@[deprecated ofNat_self (since := "2025-05-28")] abbrev ofNat'_self := @ofNat_self
|
||||
|
||||
@[simp] theorem ofNat_val_eq_self [NeZero n] (x : Fin n) : (Fin.ofNat n x) = x := by
|
||||
@[simp] theorem ofNat_val_eq_self [NeZero n] (x : Fin n) : (Fin.ofNat n x.val) = x := by
|
||||
ext
|
||||
rw [val_ofNat, Nat.mod_eq_of_lt]
|
||||
exact x.2
|
||||
@@ -121,8 +121,6 @@ Non-trivial loops lead to undesirable and counterintuitive elaboration behavior.
|
||||
For example, for `x : Fin k` and `n : Nat`,
|
||||
it causes `x < n` to be elaborated as `x < ↑n` rather than `↑x < n`,
|
||||
silently introducing wraparound arithmetic.
|
||||
|
||||
Note: as of 2025-06-03, Mathlib has such a coercion for `Fin n` anyway!
|
||||
-/
|
||||
@[expose]
|
||||
def instNatCast (n : Nat) [NeZero n] : NatCast (Fin n) where
|
||||
@@ -265,7 +263,7 @@ 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, grind =] theorem val_rev (i : Fin n) : (rev i).val = n - (i + 1) := rfl
|
||||
|
||||
@[simp] theorem rev_rev (i : Fin n) : rev (rev i) = i := Fin.ext <| by
|
||||
rw [val_rev, val_rev, ← Nat.sub_sub, Nat.sub_sub_self (by exact i.2), Nat.add_sub_cancel]
|
||||
@@ -500,9 +498,11 @@ theorem succ_succ_ne_one (a : Fin n) : Fin.succ (Fin.succ a) ≠ 1 :=
|
||||
ext
|
||||
simp
|
||||
|
||||
@[simp] theorem cast_trans {k : Nat} (h : n = m) (h' : m = k) {i : Fin n} :
|
||||
@[simp, grind =] theorem cast_cast {k : Nat} (h : n = m) (h' : m = k) {i : Fin n} :
|
||||
(i.cast h).cast h' = i.cast (Eq.trans h h') := rfl
|
||||
|
||||
@[deprecated cast_cast (since := "2025-09-03")] abbrev cast_trans := @cast_cast
|
||||
|
||||
theorem castLE_of_eq {m n : Nat} (h : m = n) {h' : m ≤ n} : castLE h' = Fin.cast h := rfl
|
||||
|
||||
@[simp] theorem coe_castAdd (m : Nat) (i : Fin n) : (castAdd m i : Nat) = i := rfl
|
||||
@@ -531,7 +531,7 @@ theorem cast_castAdd_left {n n' m : Nat} (i : Fin n') (h : n' + m = n + m) :
|
||||
(i.castAdd m').cast h = i.castAdd m := rfl
|
||||
|
||||
theorem castAdd_castAdd {m n p : Nat} (i : Fin m) :
|
||||
(i.castAdd n).castAdd p = (i.castAdd (n + p)).cast (Nat.add_assoc ..).symm := rfl
|
||||
(i.castAdd n).castAdd p = (i.castAdd (n + p)).cast (Nat.add_assoc ..).symm := rfl
|
||||
|
||||
/-- The cast of the successor is the successor of the cast. See `Fin.succ_cast_eq` for rewriting in
|
||||
the reverse direction. -/
|
||||
|
||||
@@ -31,6 +31,7 @@ This file defines the `Int` type as well as
|
||||
Division and modulus operations are defined in `Init.Data.Int.DivMod.Basic`.
|
||||
-/
|
||||
|
||||
set_option genCtorIdx false in
|
||||
/--
|
||||
The integers.
|
||||
|
||||
@@ -320,6 +321,8 @@ def natAbs (m : @& Int) : Nat :=
|
||||
| ofNat m => m
|
||||
| -[m +1] => m.succ
|
||||
|
||||
attribute [gen_constructor_elims] Int
|
||||
|
||||
/-! ## sign -/
|
||||
|
||||
/--
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -7,7 +7,8 @@ module
|
||||
|
||||
prelude
|
||||
public import Init.Data.Nat.Bitwise.Lemmas
|
||||
public import all Init.Data.Int.Bitwise.Basic
|
||||
public import Init.Data.Int.Bitwise.Basic
|
||||
import all Init.Data.Int.Bitwise.Basic
|
||||
public import Init.Data.Int.DivMod.Lemmas
|
||||
|
||||
public section
|
||||
@@ -16,8 +17,8 @@ namespace Int
|
||||
|
||||
theorem shiftRight_eq (n : Int) (s : Nat) : n >>> s = Int.shiftRight n s := rfl
|
||||
|
||||
@[simp]
|
||||
theorem natCast_shiftRight (n s : Nat) : (n : Int) >>> s = n >>> s := rfl
|
||||
@[simp, norm_cast]
|
||||
theorem natCast_shiftRight (n s : Nat) : n >>> s = (n : Int) >>> s := rfl
|
||||
|
||||
@[simp]
|
||||
theorem negSucc_shiftRight (m n : Nat) :
|
||||
@@ -37,11 +38,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]
|
||||
|
||||
@@ -67,7 +68,7 @@ theorem shiftRight_le_of_nonneg {n : Int} {s : Nat} (h : 0 ≤ n) : n >>> s ≤
|
||||
by_cases hm : m = 0
|
||||
· simp [hm]
|
||||
· have := Nat.shiftRight_le m s
|
||||
simp
|
||||
rw [ofNat_eq_coe]
|
||||
omega
|
||||
case _ _ _ m =>
|
||||
omega
|
||||
@@ -88,4 +89,94 @@ 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, norm_cast]
|
||||
theorem natCast_shiftLeft (n s : Nat) : n <<< s = (n : Int) <<< s := rfl
|
||||
|
||||
@[simp, grind =]
|
||||
theorem zero_shiftLeft (n : Nat) : (0 : Int) <<< n = 0 := by
|
||||
change ((0 <<< n : Nat) : Int) = 0
|
||||
simp
|
||||
|
||||
@[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 only [Int.shiftLeft, Int.ofNat_eq_coe]
|
||||
rw [Nat.shiftLeft_succ, Nat.mul_comm, natCast_mul, ofNat_two]
|
||||
| Int.negSucc m =>
|
||||
dsimp only [Int.shiftLeft]
|
||||
rw [Nat.shiftLeft_succ, Nat.mul_comm, Int.negSucc_eq]
|
||||
have := Nat.le_shiftLeft (a := m + 1) (b := n)
|
||||
omega
|
||||
|
||||
theorem shiftLeft_succ' (m : Int) (n : Nat) : m <<< (n + 1) = 2 * (m <<< n) := by
|
||||
rw [shiftLeft_succ, Int.mul_comm]
|
||||
|
||||
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]
|
||||
|
||||
theorem shiftLeft_add (a : Int) (b c : Nat) : a <<< (b + c) = a <<< b <<< c := by
|
||||
simp [shiftLeft_eq, Int.pow_add, Int.mul_assoc]
|
||||
|
||||
@[simp]
|
||||
theorem shiftLeft_shiftRight_cancel (a : Int) (b : Nat) : a <<< b >>> b = a := by
|
||||
simp [shiftLeft_eq, shiftRight_eq_div_pow, mul_ediv_cancel _ (NeZero.ne _)]
|
||||
|
||||
theorem shiftLeft_shiftRight_eq_shiftLeft_of_le {b c : Nat} (h : c ≤ b) (a : Int) :
|
||||
a <<< b >>> c = a <<< (b - c) := by
|
||||
obtain ⟨b, rfl⟩ := h.dest
|
||||
simp [shiftLeft_eq, Int.pow_add, shiftRight_eq_div_pow, Int.mul_left_comm a,
|
||||
Int.mul_ediv_cancel_left _ (NeZero.ne _)]
|
||||
|
||||
theorem shiftLeft_shiftRight_eq_shiftRight_of_le {b c : Nat} (h : b ≤ c) (a : Int) :
|
||||
a <<< b >>> c = a >>> (c - b) := by
|
||||
obtain ⟨c, rfl⟩ := h.dest
|
||||
simp [shiftRight_add]
|
||||
|
||||
theorem shiftLeft_shiftRight_eq (a : Int) (b c : Nat) :
|
||||
a <<< b >>> c = a <<< (b - c) >>> (c - b) := by
|
||||
rcases Nat.le_total b c with h | h
|
||||
· simp [shiftLeft_shiftRight_eq_shiftRight_of_le h, Nat.sub_eq_zero_of_le h]
|
||||
· simp [shiftLeft_shiftRight_eq_shiftLeft_of_le h, Nat.sub_eq_zero_of_le h]
|
||||
|
||||
@[simp]
|
||||
theorem shiftRight_shiftLeft_cancel {a : Int} {b : Nat} (h : 2 ^ b ∣ a) : a >>> b <<< b = a := by
|
||||
simp [shiftLeft_eq, shiftRight_eq_div_pow, Int.ediv_mul_cancel h]
|
||||
|
||||
theorem add_shiftLeft (a b : Int) (n : Nat) : (a + b) <<< n = a <<< n + b <<< n := by
|
||||
simp [shiftLeft_eq, Int.add_mul]
|
||||
|
||||
theorem neg_shiftLeft (a : Int) (n : Nat) : (-a) <<< n = -a <<< n := by
|
||||
simp [Int.shiftLeft_eq, Int.neg_mul]
|
||||
|
||||
theorem shiftLeft_mul (a b : Int) (n : Nat) : a <<< n * b = (a * b) <<< n := by
|
||||
simp [shiftLeft_eq, Int.mul_right_comm]
|
||||
|
||||
theorem mul_shiftLeft (a b : Int) (n : Nat) : a * b <<< n = (a * b) <<< n := by
|
||||
simp [shiftLeft_eq, Int.mul_assoc]
|
||||
|
||||
theorem shiftLeft_mul_shiftLeft (a b : Int) (m n : Nat) :
|
||||
a <<< m * b <<< n = (a * b) <<< (m + n) := by
|
||||
simp [shiftLeft_mul, mul_shiftLeft, shiftLeft_add]
|
||||
|
||||
@[simp]
|
||||
theorem shiftLeft_eq_zero_iff {a : Int} {n : Nat} : a <<< n = 0 ↔ a = 0 := by
|
||||
simp [shiftLeft_eq, Int.mul_eq_zero, NeZero.ne]
|
||||
|
||||
instance {a : Int} {n : Nat} [NeZero a] : NeZero (a <<< n) :=
|
||||
⟨mt shiftLeft_eq_zero_iff.mp (NeZero.ne _)⟩
|
||||
|
||||
end Int
|
||||
|
||||
@@ -6,7 +6,8 @@ Authors: Leonardo de Moura, Jeremy Avigad, Mario Carneiro, Paul Reichert
|
||||
module
|
||||
|
||||
prelude
|
||||
public import all Init.Data.Ord.Basic
|
||||
public import Init.Data.Ord.Basic
|
||||
import all Init.Data.Ord.Basic
|
||||
public import Init.Data.Int.Order
|
||||
|
||||
public section
|
||||
|
||||
@@ -97,7 +97,7 @@ theorem ofNat_emod (m n : Nat) : (↑(m % n) : Int) = m % n := natCast_emod m n
|
||||
|
||||
/-! ### mod definitions -/
|
||||
|
||||
theorem emod_add_ediv : ∀ a b : Int, a % b + b * (a / b) = a
|
||||
theorem emod_add_mul_ediv : ∀ a b : Int, a % b + b * (a / b) = a
|
||||
| ofNat _, ofNat _ => congrArg ofNat <| Nat.mod_add_div ..
|
||||
| ofNat m, -[n+1] => by
|
||||
change (m % succ n + -↑(succ n) * -↑(m / succ n) : Int) = m
|
||||
@@ -111,19 +111,35 @@ where
|
||||
← Int.neg_neg (_-_), Int.neg_sub, Int.sub_sub_self, Int.add_right_comm]
|
||||
exact congrArg (fun x => -(ofNat x + 1)) (Nat.mod_add_div ..)
|
||||
|
||||
/-- Variant of `emod_add_ediv` with the multiplication written the other way around. -/
|
||||
theorem emod_add_ediv' (a b : Int) : a % b + a / b * b = a := by
|
||||
rw [Int.mul_comm]; exact emod_add_ediv ..
|
||||
@[deprecated emod_add_mul_ediv (since := "2025-09-01")]
|
||||
def emod_add_ediv := @emod_add_mul_ediv
|
||||
|
||||
theorem ediv_add_emod (a b : Int) : b * (a / b) + a % b = a := by
|
||||
rw [Int.add_comm]; exact emod_add_ediv ..
|
||||
theorem emod_add_ediv_mul (a b : Int) : a % b + a / b * b = a := by
|
||||
rw [Int.mul_comm]; exact emod_add_mul_ediv ..
|
||||
|
||||
/-- Variant of `ediv_add_emod` with the multiplication written the other way around. -/
|
||||
theorem ediv_add_emod' (a b : Int) : a / b * b + a % b = a := by
|
||||
rw [Int.mul_comm]; exact ediv_add_emod ..
|
||||
@[deprecated emod_add_ediv_mul (since := "2025-09-01")]
|
||||
def emod_add_ediv' := @emod_add_ediv_mul
|
||||
|
||||
theorem mul_ediv_add_emod (a b : Int) : b * (a / b) + a % b = a := by
|
||||
rw [Int.add_comm]; exact emod_add_mul_ediv ..
|
||||
|
||||
@[deprecated mul_ediv_add_emod (since := "2025-09-01")]
|
||||
def ediv_add_emod := @mul_ediv_add_emod
|
||||
|
||||
theorem ediv_mul_add_emod (a b : Int) : a / b * b + a % b = a := by
|
||||
rw [Int.mul_comm]; exact mul_ediv_add_emod ..
|
||||
|
||||
@[deprecated ediv_mul_add_emod (since := "2025-09-01")]
|
||||
def ediv_add_emod' := @ediv_mul_add_emod
|
||||
|
||||
theorem emod_def (a b : Int) : a % b = a - b * (a / b) := by
|
||||
rw [← Int.add_sub_cancel (a % b), emod_add_ediv]
|
||||
rw [← Int.add_sub_cancel (a % b), emod_add_mul_ediv]
|
||||
|
||||
theorem mul_ediv_self (a b : Int) : b * (a / b) = a - a % b := by
|
||||
rw [emod_def, Int.sub_sub_self]
|
||||
|
||||
theorem ediv_mul_self (a b : Int) : a / b * b = a - a % b := by
|
||||
rw [Int.mul_comm, emod_def, Int.sub_sub_self]
|
||||
|
||||
/-! ### `/` ediv -/
|
||||
|
||||
@@ -226,7 +242,7 @@ theorem add_mul_emod_self {a b c : Int} : (a + b * c) % c = a % c :=
|
||||
|
||||
@[simp] theorem emod_add_emod (m n k : Int) : (m % n + k) % n = (m + k) % n := by
|
||||
have := (add_mul_emod_self_left (m % n + k) n (m / n)).symm
|
||||
rwa [Int.add_right_comm, emod_add_ediv] at this
|
||||
rwa [Int.add_right_comm, emod_add_mul_ediv] at this
|
||||
|
||||
@[simp] theorem add_emod_emod (m n k : Int) : (m + n % k) % k = (m + n) % k := by
|
||||
rw [Int.add_comm, emod_add_emod, Int.add_comm]
|
||||
@@ -252,7 +268,7 @@ theorem emod_add_cancel_right {m n k : Int} (i) : (m + i) % n = (k + i) % n ↔
|
||||
|
||||
theorem mul_emod (a b n : Int) : (a * b) % n = (a % n) * (b % n) % n := by
|
||||
conv => lhs; rw [
|
||||
← emod_add_ediv a n, ← emod_add_ediv' b n, Int.add_mul, Int.mul_add, Int.mul_add,
|
||||
← emod_add_mul_ediv a n, ← emod_add_ediv_mul b n, Int.add_mul, Int.mul_add, Int.mul_add,
|
||||
Int.mul_assoc, Int.mul_assoc, ← Int.mul_add n _ _, add_mul_emod_self_left,
|
||||
← Int.mul_assoc, add_mul_emod_self_right]
|
||||
|
||||
@@ -261,7 +277,7 @@ theorem mul_emod (a b n : Int) : (a * b) % n = (a % n) * (b % n) % n := by
|
||||
|
||||
@[simp] theorem emod_emod_of_dvd (n : Int) {m k : Int}
|
||||
(h : m ∣ k) : (n % k) % m = n % m := by
|
||||
conv => rhs; rw [← emod_add_ediv n k]
|
||||
conv => rhs; rw [← emod_add_mul_ediv n k]
|
||||
match k, h with
|
||||
| _, ⟨t, rfl⟩ => rw [Int.mul_assoc, add_mul_emod_self_left]
|
||||
|
||||
@@ -275,7 +291,7 @@ theorem sub_emod (a b n : Int) : (a - b) % n = (a % n - b % n) % n := by
|
||||
/-! ### properties of `/` and `%` -/
|
||||
|
||||
theorem mul_ediv_cancel_of_emod_eq_zero {a b : Int} (H : a % b = 0) : b * (a / b) = a := by
|
||||
have := emod_add_ediv a b; rwa [H, Int.zero_add] at this
|
||||
have := emod_add_mul_ediv a b; rwa [H, Int.zero_add] at this
|
||||
|
||||
theorem ediv_mul_cancel_of_emod_eq_zero {a b : Int} (H : a % b = 0) : a / b * b = a := by
|
||||
rw [Int.mul_comm, mul_ediv_cancel_of_emod_eq_zero H]
|
||||
@@ -326,11 +342,11 @@ theorem emod_pos_of_not_dvd {a b : Int} (h : ¬ a ∣ b) : a = 0 ∨ 0 < b % a :
|
||||
theorem mul_ediv_self_le {x k : Int} (h : k ≠ 0) : k * (x / k) ≤ x :=
|
||||
calc k * (x / k)
|
||||
_ ≤ k * (x / k) + x % k := Int.le_add_of_nonneg_right (emod_nonneg x h)
|
||||
_ = x := ediv_add_emod _ _
|
||||
_ = x := mul_ediv_add_emod _ _
|
||||
|
||||
theorem lt_mul_ediv_self_add {x k : Int} (h : 0 < k) : x < k * (x / k) + k :=
|
||||
calc x
|
||||
_ = k * (x / k) + x % k := (ediv_add_emod _ _).symm
|
||||
_ = k * (x / k) + x % k := (mul_ediv_add_emod _ _).symm
|
||||
_ < k * (x / k) + k := Int.add_lt_add_left (emod_lt_of_pos x h) _
|
||||
|
||||
/-! ### bmod -/
|
||||
|
||||
@@ -26,6 +26,10 @@ namespace Int
|
||||
|
||||
@[simp high] theorem natCast_eq_zero {n : Nat} : (n : Int) = 0 ↔ n = 0 := by omega
|
||||
|
||||
instance {n : Nat} [NeZero n] : NeZero (n : Int) := ⟨mt Int.natCast_eq_zero.mp (NeZero.ne _)⟩
|
||||
instance {n : Nat} [NeZero n] : NeZero (no_index (OfNat.ofNat n) : Int) :=
|
||||
⟨mt Int.natCast_eq_zero.mp (NeZero.ne _)⟩
|
||||
|
||||
protected theorem exists_add_of_le {a b : Int} (h : a ≤ b) : ∃ (c : Nat), b = a + c :=
|
||||
⟨(b - a).toNat, by omega⟩
|
||||
|
||||
@@ -330,7 +334,7 @@ theorem fdiv_eq_ediv_of_dvd {a b : Int} (h : b ∣ a) : a.fdiv b = a / b := by
|
||||
|
||||
/-! ### mod definitions -/
|
||||
|
||||
theorem tmod_add_tdiv : ∀ a b : Int, tmod a b + b * (a.tdiv b) = a
|
||||
theorem tmod_add_mul_tdiv : ∀ a b : Int, tmod a b + b * (a.tdiv b) = a
|
||||
| ofNat _, ofNat _ => congrArg ofNat (Nat.mod_add_div ..)
|
||||
| ofNat m, -[n+1] => by
|
||||
change (m % succ n + -↑(succ n) * -↑(m / succ n) : Int) = m
|
||||
@@ -347,21 +351,37 @@ theorem tmod_add_tdiv : ∀ a b : Int, tmod a b + b * (a.tdiv b) = a
|
||||
rw [Int.neg_mul, ← Int.neg_add]
|
||||
exact congrArg (-ofNat ·) (Nat.mod_add_div ..)
|
||||
|
||||
theorem tdiv_add_tmod (a b : Int) : b * a.tdiv b + tmod a b = a := by
|
||||
rw [Int.add_comm]; apply tmod_add_tdiv ..
|
||||
@[deprecated tmod_add_mul_tdiv (since := "2025-09-01")]
|
||||
def tmod_add_tdiv := @tmod_add_mul_tdiv
|
||||
|
||||
/-- Variant of `tmod_add_tdiv` with the multiplication written the other way around. -/
|
||||
theorem tmod_add_tdiv' (m k : Int) : tmod m k + m.tdiv k * k = m := by
|
||||
rw [Int.mul_comm]; apply tmod_add_tdiv
|
||||
theorem mul_tdiv_add_tmod (a b : Int) : b * a.tdiv b + tmod a b = a := by
|
||||
rw [Int.add_comm]; apply tmod_add_mul_tdiv ..
|
||||
|
||||
/-- Variant of `tdiv_add_tmod` with the multiplication written the other way around. -/
|
||||
theorem tdiv_add_tmod' (m k : Int) : m.tdiv k * k + tmod m k = m := by
|
||||
rw [Int.mul_comm]; apply tdiv_add_tmod
|
||||
@[deprecated mul_tdiv_add_tmod (since := "2025-09-01")]
|
||||
def tdiv_add_tmod := @mul_tdiv_add_tmod
|
||||
|
||||
theorem tmod_add_tdiv_mul (m k : Int) : tmod m k + m.tdiv k * k = m := by
|
||||
rw [Int.mul_comm]; apply tmod_add_mul_tdiv
|
||||
|
||||
@[deprecated tmod_add_tdiv_mul (since := "2025-09-01")]
|
||||
def tmod_add_tdiv' := @tmod_add_mul_tdiv
|
||||
|
||||
theorem tdiv_mul_add_tmod (m k : Int) : m.tdiv k * k + tmod m k = m := by
|
||||
rw [Int.mul_comm]; apply mul_tdiv_add_tmod
|
||||
|
||||
@[deprecated tdiv_mul_add_tmod (since := "2025-09-01")]
|
||||
def tdiv_add_tmod' := @tdiv_mul_add_tmod
|
||||
|
||||
theorem tmod_def (a b : Int) : tmod a b = a - b * a.tdiv b := by
|
||||
rw [← Int.add_sub_cancel (tmod a b), tmod_add_tdiv]
|
||||
rw [← Int.add_sub_cancel (tmod a b), tmod_add_mul_tdiv]
|
||||
|
||||
theorem fmod_add_fdiv : ∀ a b : Int, a.fmod b + b * a.fdiv b = a
|
||||
theorem mul_tdiv_self (a b : Int) : b * (a.tdiv b) = a - a.tmod b := by
|
||||
rw [tmod_def, Int.sub_sub_self]
|
||||
|
||||
theorem tdiv_mul_self (a b : Int) : a.tdiv b * b = a - a.tmod b := by
|
||||
rw [Int.mul_comm, tmod_def, Int.sub_sub_self]
|
||||
|
||||
theorem fmod_add_mul_fdiv : ∀ a b : Int, a.fmod b + b * a.fdiv b = a
|
||||
| 0, ofNat _ | 0, -[_+1] => congrArg ofNat <| by simp
|
||||
| succ _, ofNat _ => congrArg ofNat <| Nat.mod_add_div ..
|
||||
| succ m, -[n+1] => by
|
||||
@@ -378,19 +398,35 @@ theorem fmod_add_fdiv : ∀ a b : Int, a.fmod b + b * a.fdiv b = a
|
||||
change -(↑(succ m % succ n) : Int) + -↑(succ n * (succ m / succ n)) = -↑(succ m)
|
||||
rw [← Int.neg_add]; exact congrArg (-ofNat ·) <| Nat.mod_add_div ..
|
||||
|
||||
/-- Variant of `fmod_add_fdiv` with the multiplication written the other way around. -/
|
||||
theorem fmod_add_fdiv' (a b : Int) : a.fmod b + (a.fdiv b) * b = a := by
|
||||
rw [Int.mul_comm]; exact fmod_add_fdiv ..
|
||||
@[deprecated fmod_add_mul_fdiv (since := "2025-09-01")]
|
||||
def fmod_add_fdiv := @fmod_add_mul_fdiv
|
||||
|
||||
theorem fdiv_add_fmod (a b : Int) : b * a.fdiv b + a.fmod b = a := by
|
||||
rw [Int.add_comm]; exact fmod_add_fdiv ..
|
||||
theorem fmod_add_fdiv_mul (a b : Int) : a.fmod b + (a.fdiv b) * b = a := by
|
||||
rw [Int.mul_comm]; exact fmod_add_mul_fdiv ..
|
||||
|
||||
/-- Variant of `fdiv_add_fmod` with the multiplication written the other way around. -/
|
||||
theorem fdiv_add_fmod' (a b : Int) : (a.fdiv b) * b + a.fmod b = a := by
|
||||
rw [Int.mul_comm]; exact fdiv_add_fmod ..
|
||||
@[deprecated fmod_add_fdiv_mul (since := "2025-09-01")]
|
||||
def fmod_add_fdiv' := @fmod_add_fdiv_mul
|
||||
|
||||
theorem mul_fdiv_add_fmod (a b : Int) : b * a.fdiv b + a.fmod b = a := by
|
||||
rw [Int.add_comm]; exact fmod_add_mul_fdiv ..
|
||||
|
||||
@[deprecated mul_fdiv_add_fmod (since := "2025-09-01")]
|
||||
def fdiv_add_fmod := @mul_fdiv_add_fmod
|
||||
|
||||
theorem fdiv_mul_add_fmod (a b : Int) : (a.fdiv b) * b + a.fmod b = a := by
|
||||
rw [Int.mul_comm]; exact mul_fdiv_add_fmod ..
|
||||
|
||||
@[deprecated mul_fdiv_add_fmod (since := "2025-09-01")]
|
||||
def fdiv_add_fmod' := @mul_fdiv_add_fmod
|
||||
|
||||
theorem fmod_def (a b : Int) : a.fmod b = a - b * a.fdiv b := by
|
||||
rw [← Int.add_sub_cancel (a.fmod b), fmod_add_fdiv]
|
||||
rw [← Int.add_sub_cancel (a.fmod b), fmod_add_mul_fdiv]
|
||||
|
||||
theorem mul_fdiv_self (a b : Int) : b * (a.fdiv b) = a - a.fmod b := by
|
||||
rw [fmod_def, Int.sub_sub_self]
|
||||
|
||||
theorem fdiv_mul_self (a b : Int) : a.fdiv b * b = a - a.fmod b := by
|
||||
rw [Int.mul_comm, fmod_def, Int.sub_sub_self]
|
||||
|
||||
/-! ### mod equivalences -/
|
||||
|
||||
@@ -769,7 +805,7 @@ protected theorem ediv_emod_unique {a b r q : Int} (h : 0 < b) :
|
||||
a / b = q ∧ a % b = r ↔ r + b * q = a ∧ 0 ≤ r ∧ r < b := by
|
||||
constructor
|
||||
· intro ⟨rfl, rfl⟩
|
||||
exact ⟨emod_add_ediv a b, emod_nonneg _ (Int.ne_of_gt h), emod_lt_of_pos _ h⟩
|
||||
exact ⟨emod_add_mul_ediv a b, emod_nonneg _ (Int.ne_of_gt h), emod_lt_of_pos _ h⟩
|
||||
· intro ⟨rfl, hz, hb⟩
|
||||
constructor
|
||||
· rw [Int.add_mul_ediv_left r q (Int.ne_of_gt h), ediv_eq_zero_of_lt hz hb]
|
||||
@@ -793,7 +829,7 @@ theorem neg_ediv {a b : Int} : (-a) / b = -(a / b) - if b ∣ a then 0 else b.si
|
||||
if hb : b = 0 then
|
||||
simp [hb]
|
||||
else
|
||||
conv => lhs; rw [← ediv_add_emod a b]
|
||||
conv => lhs; rw [← mul_ediv_add_emod a b]
|
||||
rw [Int.neg_add, ← Int.mul_neg, mul_add_ediv_left _ _ hb, Int.add_comm]
|
||||
split <;> rename_i h
|
||||
· rw [emod_eq_zero_of_dvd h]
|
||||
@@ -1083,6 +1119,10 @@ theorem emod_natAbs_of_neg {x : Int} (h : x < 0) {n : Nat} (w : n ≠ 0) :
|
||||
protected theorem ediv_mul_le (a : Int) {b : Int} (H : b ≠ 0) : a / b * b ≤ a :=
|
||||
Int.le_of_sub_nonneg <| by rw [Int.mul_comm, ← emod_def]; apply emod_nonneg _ H
|
||||
|
||||
protected theorem lt_ediv_mul (a : Int) {b : Int} (H : 0 < b) : a - b < a / b * b := by
|
||||
rw [ediv_mul_self, Int.sub_lt_sub_left_iff]
|
||||
exact emod_lt_of_pos a H
|
||||
|
||||
theorem le_of_mul_le_mul_left {a b c : Int} (w : a * b ≤ a * c) (h : 0 < a) : b ≤ c := by
|
||||
have w := Int.sub_nonneg_of_le w
|
||||
rw [← Int.mul_sub] at w
|
||||
@@ -1173,9 +1213,9 @@ theorem ediv_eq_iff_of_pos {k x y : Int} (h : 0 < k) : x / k = y ↔ y * k ≤ x
|
||||
theorem add_ediv_of_pos {a b c : Int} (h : 0 < c) :
|
||||
(a + b) / c = a / c + b / c + if c ≤ a % c + b % c then 1 else 0 := by
|
||||
have h' : c ≠ 0 := by omega
|
||||
conv => lhs; rw [← Int.ediv_add_emod a c]
|
||||
conv => lhs; rw [← Int.mul_ediv_add_emod a c]
|
||||
rw [Int.add_assoc, Int.mul_add_ediv_left _ _ h']
|
||||
conv => lhs; rw [← Int.ediv_add_emod b c]
|
||||
conv => lhs; rw [← Int.mul_ediv_add_emod b c]
|
||||
rw [Int.add_comm (a % c), Int.add_assoc, Int.mul_add_ediv_left _ _ h',
|
||||
← Int.add_assoc, Int.add_comm (b % c)]
|
||||
congr
|
||||
@@ -1206,7 +1246,7 @@ theorem not_dvd_iff_lt_mul_succ (m : Int) (hn : 0 < n) :
|
||||
¬n ∣ m ↔ (∃ k, n * k < m ∧ m < n * (k + 1)) := by
|
||||
refine ⟨fun h ↦ ?_, ?_⟩
|
||||
· rw [dvd_iff_emod_eq_zero, ← Ne] at h
|
||||
rw [← emod_add_ediv m n]
|
||||
rw [← emod_add_mul_ediv m n]
|
||||
refine ⟨m / n, Int.lt_add_of_pos_left _ ?_, ?_⟩
|
||||
· have := emod_nonneg m (Int.ne_of_gt hn)
|
||||
omega
|
||||
@@ -1218,6 +1258,26 @@ theorem not_dvd_iff_lt_mul_succ (m : Int) (hn : 0 < n) :
|
||||
rw [Int.lt_add_one_iff, ← Int.not_lt] at h2k
|
||||
exact h2k h1k
|
||||
|
||||
private theorem ediv_ediv_of_pos {x y z : Int} (hy : 0 < y) (hz : 0 < z) :
|
||||
x / y / z = x / (y * z) := by
|
||||
rw [eq_comm, Int.ediv_eq_iff_of_pos (Int.mul_pos hy hz)]
|
||||
constructor
|
||||
· rw [Int.mul_comm y, ← Int.mul_assoc]
|
||||
exact Int.le_trans
|
||||
(Int.mul_le_mul_of_nonneg_right (Int.ediv_mul_le _ (Int.ne_of_gt hz)) (Int.le_of_lt hy))
|
||||
(Int.ediv_mul_le x (Int.ne_of_gt hy))
|
||||
· rw [Int.mul_comm y, ← Int.mul_assoc, ← Int.add_mul, Int.mul_comm _ z]
|
||||
exact Int.lt_mul_of_ediv_lt hy (Int.lt_mul_ediv_self_add hz)
|
||||
|
||||
theorem ediv_ediv {x y z : Int} (hy : 0 ≤ y) : x / y / z = x / (y * z) := by
|
||||
rcases y with (_ | a) | a
|
||||
· simp
|
||||
· rcases z with (_ | b) | b
|
||||
· simp
|
||||
· simp [ediv_ediv_of_pos]
|
||||
· simp [Int.negSucc_eq, Int.mul_neg, ediv_ediv_of_pos]
|
||||
· simp at hy
|
||||
|
||||
/-! ### tdiv -/
|
||||
|
||||
-- `tdiv` analogues of `ediv` lemmas from `Bootstrap.lean`
|
||||
@@ -1461,7 +1521,7 @@ theorem sign_tmod (a b : Int) : sign (tmod a b) = if b ∣ a then 0 else sign a
|
||||
-- Analogues of statements about `ediv` and `emod` from `Bootstrap.lean`
|
||||
|
||||
theorem mul_tdiv_cancel_of_tmod_eq_zero {a b : Int} (H : a.tmod b = 0) : b * (a.tdiv b) = a := by
|
||||
have := tmod_add_tdiv a b; rwa [H, Int.zero_add] at this
|
||||
have := tmod_add_mul_tdiv a b; rwa [H, Int.zero_add] at this
|
||||
|
||||
theorem tdiv_mul_cancel_of_tmod_eq_zero {a b : Int} (H : a.tmod b = 0) : a.tdiv b * b = a := by
|
||||
rw [Int.mul_comm, mul_tdiv_cancel_of_tmod_eq_zero H]
|
||||
@@ -2186,7 +2246,7 @@ theorem fmod_add_cancel_right {m n k : Int} (i) : (m + i).fmod n = (k + i).fmod
|
||||
|
||||
theorem mul_fmod (a b n : Int) : (a * b).fmod n = (a.fmod n * b.fmod n).fmod n := by
|
||||
conv => lhs; rw [
|
||||
← fmod_add_fdiv a n, ← fmod_add_fdiv' b n, Int.add_mul, Int.mul_add, Int.mul_add,
|
||||
← fmod_add_mul_fdiv a n, ← fmod_add_fdiv_mul b n, Int.add_mul, Int.mul_add, Int.mul_add,
|
||||
Int.mul_assoc, Int.mul_assoc, ← Int.mul_add n _ _, add_mul_fmod_self_left,
|
||||
← Int.mul_assoc, add_mul_fmod_self_right]
|
||||
|
||||
@@ -2195,7 +2255,7 @@ theorem mul_fmod (a b n : Int) : (a * b).fmod n = (a.fmod n * b.fmod n).fmod n :
|
||||
|
||||
@[simp] theorem fmod_fmod_of_dvd (n : Int) {m k : Int}
|
||||
(h : m ∣ k) : (n.fmod k).fmod m = n.fmod m := by
|
||||
conv => rhs; rw [← fmod_add_fdiv n k]
|
||||
conv => rhs; rw [← fmod_add_mul_fdiv n k]
|
||||
match k, h with
|
||||
| _, ⟨t, rfl⟩ => rw [Int.mul_assoc, add_mul_fmod_self_left]
|
||||
|
||||
@@ -2225,7 +2285,7 @@ theorem fmod_eq_of_lt {a b : Int} (H1 : 0 ≤ a) (H2 : a < b) : a.fmod b = a :=
|
||||
-- Analogues of properties of `ediv` and `emod` from `Bootstrap.lean`
|
||||
|
||||
theorem mul_fdiv_cancel_of_fmod_eq_zero {a b : Int} (H : a.fmod b = 0) : b * (a.fdiv b) = a := by
|
||||
have := fmod_add_fdiv a b; rwa [H, Int.zero_add] at this
|
||||
have := fmod_add_mul_fdiv a b; rwa [H, Int.zero_add] at this
|
||||
|
||||
theorem fdiv_mul_cancel_of_fmod_eq_zero {a b : Int} (H : a.fmod b = 0) : (a.fdiv b) * b= a := by
|
||||
rw [Int.mul_comm, mul_fdiv_cancel_of_fmod_eq_zero H]
|
||||
@@ -2467,9 +2527,9 @@ theorem bdiv_add_bmod (x : Int) (m : Nat) : m * bdiv x m + bmod x m = x := by
|
||||
ite_self]
|
||||
· dsimp only
|
||||
split
|
||||
· exact ediv_add_emod x m
|
||||
· exact mul_ediv_add_emod x m
|
||||
· rw [Int.mul_add, Int.mul_one, Int.add_assoc, Int.add_comm m, Int.sub_add_cancel]
|
||||
exact ediv_add_emod x m
|
||||
exact mul_ediv_add_emod x m
|
||||
|
||||
theorem bmod_add_bdiv (x : Int) (m : Nat) : bmod x m + m * bdiv x m = x := by
|
||||
rw [Int.add_comm]; exact bdiv_add_bmod x m
|
||||
@@ -2726,7 +2786,7 @@ theorem le_bmod {x : Int} {m : Nat} (h : 0 < m) : - (m/2) ≤ Int.bmod x m := by
|
||||
· exact Int.ne_of_gt (natCast_pos.mpr h)
|
||||
· simp [Int.not_lt] at w
|
||||
refine Int.le_trans ?_ (Int.sub_le_sub_right w _)
|
||||
rw [← ediv_add_emod m 2]
|
||||
rw [← mul_ediv_add_emod m 2]
|
||||
generalize (m : Int) / 2 = q
|
||||
generalize h : (m : Int) % 2 = r at *
|
||||
rcases v with rfl | rfl
|
||||
@@ -2887,7 +2947,7 @@ theorem neg_bmod {a : Int} {b : Nat} :
|
||||
simp only [gt_iff_lt, Nat.zero_lt_succ, Nat.mul_pos_iff_of_pos_left, Int.natCast_mul,
|
||||
cast_ofNat_Int, Int.not_lt] at *
|
||||
rw [Int.mul_dvd_mul_iff_left (by omega)]
|
||||
have := ediv_add_emod a (2 * c)
|
||||
have := mul_ediv_add_emod a (2 * c)
|
||||
rw [(by omega : a % (2 * c) = c)] at this
|
||||
rw [← this]
|
||||
apply Int.dvd_add _ (by simp)
|
||||
|
||||
@@ -40,7 +40,7 @@ theorem ofNat_succ (n : Nat) : (succ n : Int) = n + 1 := rfl
|
||||
|
||||
theorem neg_ofNat_zero : -((0 : Nat) : Int) = 0 := rfl
|
||||
theorem neg_ofNat_succ (n : Nat) : -(succ n : Int) = -[n+1] := rfl
|
||||
theorem neg_negSucc (n : Nat) : -(-[n+1]) = succ n := rfl
|
||||
@[simp] theorem neg_negSucc (n : Nat) : -(-[n+1]) = ((n + 1 : Nat) : Int) := rfl
|
||||
|
||||
theorem negOfNat_eq : negOfNat n = -ofNat n := rfl
|
||||
|
||||
@@ -566,6 +566,9 @@ protected theorem mul_eq_zero {a b : Int} : a * b = 0 ↔ a = 0 ∨ b = 0 := by
|
||||
protected theorem mul_ne_zero {a b : Int} (a0 : a ≠ 0) (b0 : b ≠ 0) : a * b ≠ 0 :=
|
||||
Or.rec a0 b0 ∘ Int.mul_eq_zero.mp
|
||||
|
||||
instance {a b : Int} [NeZero a] [NeZero b] : NeZero (a * b) :=
|
||||
⟨Int.mul_ne_zero (NeZero.ne _) (NeZero.ne _)⟩
|
||||
|
||||
@[simp] protected theorem mul_ne_zero_iff {a b : Int} : a * b ≠ 0 ↔ a ≠ 0 ∧ b ≠ 0 := by
|
||||
rw [ne_eq, Int.mul_eq_zero, not_or, ne_eq]
|
||||
|
||||
|
||||
@@ -12,9 +12,11 @@ public import Init.Data.Int.Lemmas
|
||||
public import Init.Data.Int.LemmasAux
|
||||
public import Init.Data.Int.DivMod.Bootstrap
|
||||
public import Init.Data.Int.Cooper
|
||||
public import all Init.Data.Int.Gcd
|
||||
public import Init.Data.Int.Gcd
|
||||
import all Init.Data.Int.Gcd
|
||||
public import Init.Data.RArray
|
||||
public import all Init.Data.AC
|
||||
public import Init.Data.AC
|
||||
import all Init.Data.AC
|
||||
|
||||
public section
|
||||
|
||||
@@ -37,7 +39,7 @@ inductive Expr where
|
||||
| neg (a : Expr)
|
||||
| mulL (k : Int) (a : Expr)
|
||||
| mulR (a : Expr) (k : Int)
|
||||
deriving Inhabited, BEq
|
||||
deriving Inhabited, @[expose] BEq
|
||||
|
||||
@[expose]
|
||||
def Expr.denote (ctx : Context) : Expr → Int
|
||||
@@ -52,7 +54,7 @@ def Expr.denote (ctx : Context) : Expr → Int
|
||||
inductive Poly where
|
||||
| num (k : Int)
|
||||
| add (k : Int) (v : Var) (p : Poly)
|
||||
deriving BEq
|
||||
deriving @[expose] BEq
|
||||
|
||||
@[expose]
|
||||
protected noncomputable def Poly.beq' (p₁ : Poly) : Poly → Bool :=
|
||||
@@ -245,7 +247,7 @@ def cmod (a b : Int) : Int :=
|
||||
|
||||
theorem cdiv_add_cmod (a b : Int) : b*(cdiv a b) + cmod a b = a := by
|
||||
unfold cdiv cmod
|
||||
have := Int.ediv_add_emod (-a) b
|
||||
have := Int.mul_ediv_add_emod (-a) b
|
||||
have := congrArg (Neg.neg) this
|
||||
simp at this
|
||||
conv => rhs; rw[← this]
|
||||
@@ -270,7 +272,7 @@ private abbrev div_mul_cancel_of_mod_zero :=
|
||||
theorem cdiv_eq_div_of_divides {a b : Int} (h : a % b = 0) : a/b = cdiv a b := by
|
||||
replace h := div_mul_cancel_of_mod_zero h
|
||||
have hz : a % b = 0 := by
|
||||
have := Int.ediv_add_emod a b
|
||||
have := Int.mul_ediv_add_emod a b
|
||||
conv at this => rhs; rw [← Int.add_zero a]
|
||||
rw [Int.mul_comm, h] at this
|
||||
exact Int.add_left_cancel this
|
||||
@@ -1751,7 +1753,7 @@ theorem cooper_right_split_dvd (ctx : Context) (p₁ p₂ : Poly) (k : Nat) (b :
|
||||
intros; subst b p'; simp; assumption
|
||||
|
||||
private theorem one_emod_eq_one {a : Int} (h : a > 1) : 1 % a = 1 := by
|
||||
have aux₁ := Int.ediv_add_emod 1 a
|
||||
have aux₁ := Int.mul_ediv_add_emod 1 a
|
||||
have : 1 / a = 0 := Int.ediv_eq_zero_of_lt (by decide) h
|
||||
simp [this] at aux₁
|
||||
assumption
|
||||
@@ -1778,7 +1780,7 @@ private theorem ex_of_dvd {α β a b d x : Int}
|
||||
rw [Int.mul_emod, aux₁, Int.one_mul, Int.emod_emod] at this
|
||||
assumption
|
||||
have : x = (x / d)*d + (- α * b) % d := by
|
||||
conv => lhs; rw [← Int.ediv_add_emod x d]
|
||||
conv => lhs; rw [← Int.mul_ediv_add_emod x d]
|
||||
rw [Int.mul_comm, this]
|
||||
exists x / d
|
||||
|
||||
@@ -1861,7 +1863,7 @@ theorem cooper_unsat (ctx : Context) (p₁ p₂ p₃ : Poly) (d : Int) (α β :
|
||||
exact cooper_unsat' h₁ h₂ h₃ h₄ h₅ h₆
|
||||
|
||||
theorem ediv_emod (x y : Int) : -1 * x + y * (x / y) + x % y = 0 := by
|
||||
rw [Int.add_assoc, Int.ediv_add_emod x y, Int.add_comm]
|
||||
rw [Int.add_assoc, Int.mul_ediv_add_emod x y, Int.add_comm]
|
||||
simp
|
||||
rw [Int.add_neg_eq_sub, Int.sub_self]
|
||||
|
||||
@@ -2196,6 +2198,9 @@ theorem mod_eq (a b k : Int) (h : b = k) : a % b = a % k := by simp [*]
|
||||
theorem div_eq' (a b b' k : Int) (h₁ : b = b') (h₂ : k == a/b') : a / b = k := by simp_all
|
||||
theorem mod_eq' (a b b' k : Int) (h₁ : b = b') (h₂ : k == a%b') : a % b = k := by simp_all
|
||||
|
||||
theorem pow_eq (a : Int) (b : Nat) (a' b' k : Int) (h₁ : a = a') (h₂ : ↑b = b') (h₃ : k == a'^b'.toNat) : a^b = k := by
|
||||
simp [← h₁, ← h₂] at h₃; simp [h₃]
|
||||
|
||||
end Int.Linear
|
||||
|
||||
theorem Int.not_le_eq (a b : Int) : (¬a ≤ b) = (b + 1 ≤ a) := by
|
||||
|
||||
@@ -701,10 +701,13 @@ theorem toNat_sub_toNat_neg : ∀ n : Int, ↑n.toNat - ↑(-n).toNat = n
|
||||
| (_+1:Nat) => Nat.add_zero _
|
||||
| -[_+1] => Nat.zero_add _
|
||||
|
||||
@[simp] theorem toNat_neg_nat : ∀ n : Nat, (-(n : Int)).toNat = 0
|
||||
@[simp] theorem toNat_neg_natCast : ∀ n : Nat, (-(n : Int)).toNat = 0
|
||||
| 0 => rfl
|
||||
| _+1 => rfl
|
||||
|
||||
@[deprecated toNat_neg_natCast (since := "2025-08-29")]
|
||||
theorem toNat_neg_nat : ∀ n : Nat, (-(n : Int)).toNat = 0 := toNat_neg_natCast
|
||||
|
||||
/-! ### toNat? -/
|
||||
|
||||
theorem mem_toNat? : ∀ {a : Int} {n : Nat}, toNat? a = some n ↔ a = n
|
||||
|
||||
@@ -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]
|
||||
@@ -43,6 +48,8 @@ protected theorem pow_ne_zero {n : Int} {m : Nat} : n ≠ 0 → n ^ m ≠ 0 := b
|
||||
| zero => simp
|
||||
| succ m ih => exact fun h => Int.mul_ne_zero (ih h) h
|
||||
|
||||
instance {n : Int} {m : Nat} [NeZero n] : NeZero (n ^ m) := ⟨Int.pow_ne_zero (NeZero.ne _)⟩
|
||||
|
||||
@[deprecated Nat.pow_le_pow_left (since := "2025-02-17")]
|
||||
abbrev pow_le_pow_of_le_left := @Nat.pow_le_pow_left
|
||||
|
||||
|
||||
@@ -6,8 +6,10 @@ Authors: Paul Reichert
|
||||
module
|
||||
|
||||
prelude
|
||||
public import all Init.Data.Iterators.Combinators.Attach
|
||||
public import all Init.Data.Iterators.Combinators.Monadic.Attach
|
||||
public import Init.Data.Iterators.Combinators.Attach
|
||||
import all Init.Data.Iterators.Combinators.Attach
|
||||
public import Init.Data.Iterators.Combinators.Monadic.Attach
|
||||
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
|
||||
|
||||
@@ -6,7 +6,8 @@ Authors: Paul Reichert
|
||||
module
|
||||
|
||||
prelude
|
||||
public import all Init.Data.Iterators.Combinators.Monadic.Attach
|
||||
public import Init.Data.Iterators.Combinators.Monadic.Attach
|
||||
import all Init.Data.Iterators.Combinators.Monadic.Attach
|
||||
public import Init.Data.Iterators.Lemmas.Consumers.Monadic.Collect
|
||||
|
||||
public section
|
||||
|
||||
@@ -9,7 +9,8 @@ prelude
|
||||
public import Init.Data.Iterators.Internal.LawfulMonadLiftFunction
|
||||
public import Init.Data.Iterators.Combinators.Monadic.FilterMap
|
||||
public import Init.Data.Iterators.Lemmas.Consumers.Monadic
|
||||
public import all Init.Data.Iterators.Consumers.Monadic.Collect
|
||||
public import Init.Data.Iterators.Consumers.Monadic.Collect
|
||||
import all Init.Data.Iterators.Consumers.Monadic.Collect
|
||||
|
||||
public section
|
||||
|
||||
|
||||
@@ -6,7 +6,8 @@ Authors: Paul Reichert
|
||||
module
|
||||
|
||||
prelude
|
||||
public import all Init.Data.Iterators.Combinators.Monadic.ULift
|
||||
public import Init.Data.Iterators.Combinators.Monadic.ULift
|
||||
import all Init.Data.Iterators.Combinators.Monadic.ULift
|
||||
public import Init.Data.Iterators.Lemmas.Consumers.Monadic.Collect
|
||||
|
||||
public section
|
||||
|
||||
@@ -6,7 +6,8 @@ Authors: Paul Reichert
|
||||
module
|
||||
|
||||
prelude
|
||||
public import all Init.Data.Iterators.Combinators.ULift
|
||||
public import Init.Data.Iterators.Combinators.ULift
|
||||
import all Init.Data.Iterators.Combinators.ULift
|
||||
public import Init.Data.Iterators.Lemmas.Combinators.Monadic.ULift
|
||||
public import Init.Data.Iterators.Lemmas.Consumers.Collect
|
||||
|
||||
|
||||
@@ -8,8 +8,10 @@ module
|
||||
prelude
|
||||
public import Init.Data.Iterators.Lemmas.Basic
|
||||
public import Init.Data.Iterators.Lemmas.Consumers.Monadic.Collect
|
||||
public import all Init.Data.Iterators.Consumers.Access
|
||||
public import all Init.Data.Iterators.Consumers.Collect
|
||||
public import Init.Data.Iterators.Consumers.Access
|
||||
import all Init.Data.Iterators.Consumers.Access
|
||||
public import Init.Data.Iterators.Consumers.Collect
|
||||
import all Init.Data.Iterators.Consumers.Collect
|
||||
|
||||
public section
|
||||
|
||||
|
||||
@@ -8,9 +8,12 @@ module
|
||||
prelude
|
||||
public import Init.Control.Lawful.MonadLift.Instances
|
||||
public import Init.Data.Iterators.Lemmas.Consumers.Collect
|
||||
public import all Init.Data.Iterators.Lemmas.Consumers.Monadic.Loop
|
||||
public import all Init.Data.Iterators.Consumers.Loop
|
||||
public import all Init.Data.Iterators.Consumers.Monadic.Collect
|
||||
public import Init.Data.Iterators.Lemmas.Consumers.Monadic.Loop
|
||||
import all Init.Data.Iterators.Lemmas.Consumers.Monadic.Loop
|
||||
public import Init.Data.Iterators.Consumers.Loop
|
||||
import all Init.Data.Iterators.Consumers.Loop
|
||||
public import Init.Data.Iterators.Consumers.Monadic.Collect
|
||||
import all Init.Data.Iterators.Consumers.Monadic.Collect
|
||||
|
||||
public section
|
||||
|
||||
|
||||
@@ -8,7 +8,8 @@ module
|
||||
prelude
|
||||
public import Init.Data.Array.Lemmas
|
||||
public import Init.Data.Iterators.Lemmas.Monadic.Basic
|
||||
public import all Init.Data.Iterators.Consumers.Monadic.Collect
|
||||
public import Init.Data.Iterators.Consumers.Monadic.Collect
|
||||
import all Init.Data.Iterators.Consumers.Monadic.Collect
|
||||
|
||||
public section
|
||||
|
||||
|
||||
@@ -7,7 +7,8 @@ module
|
||||
|
||||
prelude
|
||||
public import Init.Data.Iterators.Lemmas.Consumers.Monadic.Collect
|
||||
public import all Init.Data.Iterators.Consumers.Monadic.Loop
|
||||
public import Init.Data.Iterators.Consumers.Monadic.Loop
|
||||
import all Init.Data.Iterators.Consumers.Monadic.Loop
|
||||
|
||||
public section
|
||||
|
||||
|
||||
@@ -6,7 +6,8 @@ Authors: Mario Carneiro
|
||||
module
|
||||
|
||||
prelude
|
||||
public import all Init.Data.List.Lemmas -- for dsimping with `getElem?_cons_succ`
|
||||
public import Init.Data.List.Lemmas -- for dsimping with `getElem?_cons_succ`
|
||||
import all Init.Data.List.Lemmas -- for dsimping with `getElem?_cons_succ`
|
||||
public import Init.Data.List.Count
|
||||
public import Init.Data.Subtype.Basic
|
||||
public import Init.BinderNameHint
|
||||
|
||||
@@ -6,7 +6,8 @@ Authors: François G. Dorais
|
||||
module
|
||||
|
||||
prelude
|
||||
public import all Init.Data.List.OfFn
|
||||
public import Init.Data.List.OfFn
|
||||
import all Init.Data.List.OfFn
|
||||
public import Init.Data.List.Monadic
|
||||
|
||||
public section
|
||||
|
||||
@@ -11,7 +11,8 @@ public import Init.Data.List.Lemmas
|
||||
public import Init.Data.List.Sublist
|
||||
public import Init.Data.List.Range
|
||||
public import Init.Data.List.Impl
|
||||
public import all Init.Data.List.Attach
|
||||
public import Init.Data.List.Attach
|
||||
import all Init.Data.List.Attach
|
||||
public import Init.Data.Fin.Lemmas
|
||||
|
||||
public section
|
||||
|
||||
@@ -9,8 +9,10 @@ module
|
||||
prelude
|
||||
public import Init.Data.Bool
|
||||
public import Init.Data.Option.Lemmas
|
||||
public import all Init.Data.List.BasicAux
|
||||
public import all Init.Data.List.Control
|
||||
public import Init.Data.List.BasicAux
|
||||
import all Init.Data.List.BasicAux
|
||||
public import Init.Data.List.Control
|
||||
import all Init.Data.List.Control
|
||||
public import Init.Control.Lawful.Basic
|
||||
public import Init.BinderPredicates
|
||||
|
||||
|
||||
@@ -272,7 +272,7 @@ theorem max?_eq_some_iff_legacy [Max α] [LE α] [anti : Std.Antisymm (· ≤ ·
|
||||
(max_le_iff : ∀ a b c : α, max b c ≤ a ↔ b ≤ a ∧ c ≤ a) {xs : List α} :
|
||||
xs.max? = some a ↔ a ∈ xs ∧ ∀ b ∈ xs, b ≤ a := by
|
||||
haveI : MaxEqOr α := ⟨max_eq_or⟩
|
||||
haveI : LawfulOrderMax α := .of_le (fun _ _ _ => max_le_iff _ _ _) max_eq_or
|
||||
haveI : 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
|
||||
|
||||
@@ -10,7 +10,8 @@ public import Init.Data.List.TakeDrop
|
||||
public import Init.Data.List.Attach
|
||||
public import Init.Data.List.OfFn
|
||||
public import Init.Data.Array.Bootstrap
|
||||
public import all Init.Data.List.Control
|
||||
public import Init.Data.List.Control
|
||||
import all Init.Data.List.Control
|
||||
|
||||
public section
|
||||
|
||||
|
||||
@@ -9,7 +9,8 @@ prelude
|
||||
public import Init.Data.List.Pairwise
|
||||
public import Init.Data.List.Erase
|
||||
public import Init.Data.List.Find
|
||||
public import all Init.Data.List.Attach
|
||||
public import Init.Data.List.Attach
|
||||
import all Init.Data.List.Attach
|
||||
|
||||
public section
|
||||
|
||||
|
||||
@@ -6,7 +6,8 @@ Authors: Kim Morrison
|
||||
module
|
||||
|
||||
prelude
|
||||
public import all Init.Data.List.Sort.Basic
|
||||
public import Init.Data.List.Sort.Basic
|
||||
import all Init.Data.List.Sort.Basic
|
||||
public import Init.Data.List.Sort.Lemmas
|
||||
|
||||
public section
|
||||
|
||||
@@ -7,7 +7,8 @@ module
|
||||
|
||||
prelude
|
||||
public import Init.Data.List.Perm
|
||||
public import all Init.Data.List.Sort.Basic
|
||||
public import Init.Data.List.Sort.Basic
|
||||
import all Init.Data.List.Sort.Basic
|
||||
public import Init.Data.List.Nat.Range
|
||||
public import Init.Data.Bool
|
||||
|
||||
|
||||
@@ -6,7 +6,8 @@ Authors: Parikshit Khanna, Jeremy Avigad, Leonardo de Moura, Floris van Doorn, M
|
||||
module
|
||||
|
||||
prelude
|
||||
public import all Init.Data.List.Basic
|
||||
public import Init.Data.List.Basic
|
||||
import all Init.Data.List.Basic
|
||||
public import Init.Data.List.Lemmas
|
||||
|
||||
public section
|
||||
|
||||
@@ -6,14 +6,17 @@ Authors: Mario Carneiro
|
||||
module
|
||||
|
||||
prelude
|
||||
public import all Init.Data.List.Control
|
||||
public import Init.Data.List.Control
|
||||
import all Init.Data.List.Control
|
||||
public import Init.Data.List.Impl
|
||||
public import Init.Data.List.Nat.Erase
|
||||
public import Init.Data.List.Monadic
|
||||
public import Init.Data.List.Nat.InsertIdx
|
||||
public import Init.Data.Array.Lex.Basic
|
||||
public import all Init.Data.Array.Basic
|
||||
public import all Init.Data.Array.Set
|
||||
public import Init.Data.Array.Basic
|
||||
import all Init.Data.Array.Basic
|
||||
public import Init.Data.Array.Set
|
||||
import all Init.Data.Array.Set
|
||||
|
||||
public section
|
||||
|
||||
|
||||
@@ -274,11 +274,9 @@ theorem zip_map {f : α → γ} {g : β → δ} :
|
||||
| _, [] => by simp only [map, zip_nil_right]
|
||||
| _ :: _, _ :: _ => by simp only [map, zip_cons_cons, zip_map, Prod.map]
|
||||
|
||||
@[grind _=_]
|
||||
theorem zip_map_left {f : α → γ} {l₁ : List α} {l₂ : List β} :
|
||||
zip (l₁.map f) l₂ = (zip l₁ l₂).map (Prod.map f id) := by rw [← zip_map, map_id]
|
||||
|
||||
@[grind _=_]
|
||||
theorem zip_map_right {f : β → γ} {l₁ : List α} {l₂ : List β} :
|
||||
zip l₁ (l₂.map f) = (zip l₁ l₂).map (Prod.map id f) := by rw [← zip_map, map_id]
|
||||
|
||||
|
||||
@@ -9,7 +9,8 @@ module
|
||||
prelude
|
||||
public import Init.Data.Bool
|
||||
public import Init.Data.Int.Pow
|
||||
public import all Init.Data.Nat.Bitwise.Basic
|
||||
public import Init.Data.Nat.Bitwise.Basic
|
||||
import all Init.Data.Nat.Bitwise.Basic
|
||||
public import Init.Data.Nat.Lemmas
|
||||
public import Init.Data.Nat.Simproc
|
||||
public import Init.TacticsExtra
|
||||
@@ -844,6 +845,12 @@ theorem shiftLeft_add_eq_or_of_lt {b : Nat} (b_lt : b < 2^i) (a : Nat) :
|
||||
rw [shiftLeft_eq, Nat.mul_comm]
|
||||
rw [two_pow_add_eq_or_of_lt b_lt]
|
||||
|
||||
@[simp]
|
||||
theorem shiftLeft_eq_zero_iff {a n : Nat} : a <<< n = 0 ↔ a = 0 := by
|
||||
simp [shiftLeft_eq, mul_eq_zero]
|
||||
|
||||
instance {a n : Nat} [NeZero a] : NeZero (a <<< n) := ⟨mt shiftLeft_eq_zero_iff.mp (NeZero.ne _)⟩
|
||||
|
||||
/-! ### le -/
|
||||
|
||||
theorem le_of_testBit {n m : Nat} (h : ∀ i, n.testBit i = true → m.testBit i = true) : n ≤ m := by
|
||||
|
||||
@@ -6,7 +6,8 @@ Authors: Leonardo de Moura, Jeremy Avigad, Mario Carneiro
|
||||
module
|
||||
|
||||
prelude
|
||||
public import all Init.Data.Ord.Basic
|
||||
public import Init.Data.Ord.Basic
|
||||
import all Init.Data.Ord.Basic
|
||||
|
||||
public section
|
||||
|
||||
|
||||
@@ -128,6 +128,12 @@ theorem fold_congr {α : Type u} {n m : Nat} (w : n = m)
|
||||
subst m
|
||||
rfl
|
||||
|
||||
theorem foldRev_congr {α : Type u} {n m : Nat} (w : n = m)
|
||||
(f : (i : Nat) → i < n → α → α) (init : α) :
|
||||
foldRev n f init = foldRev m (fun i h => f i (by omega)) init := by
|
||||
subst m
|
||||
rfl
|
||||
|
||||
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
|
||||
@@ -270,6 +276,16 @@ def dfoldRev (n : Nat) {α : (i : Nat) → (h : i ≤ n := by omega) → Type u}
|
||||
| succ n ih =>
|
||||
simp [ih, List.finRange_succ_last, List.foldl_map]
|
||||
|
||||
theorem fold_add
|
||||
{α n m} (f : (i : Nat) → i < n + m → α → α) (init : α) :
|
||||
fold (n + m) f init =
|
||||
fold m (fun i h => f (n + i) (by omega))
|
||||
(fold n (fun i h => f i (by omega)) init) := by
|
||||
induction m with
|
||||
| zero => simp; rfl
|
||||
| succ m ih =>
|
||||
simp [fold_congr (Nat.add_assoc n m 1).symm, ih]
|
||||
|
||||
/-! ### `foldRev` -/
|
||||
|
||||
@[simp] theorem foldRev_zero {α : Type u} (f : (i : Nat) → i < 0 → α → α) (init : α) :
|
||||
@@ -285,6 +301,17 @@ def dfoldRev (n : Nat) {α : (i : Nat) → (h : i ≤ n := by omega) → Type u}
|
||||
| zero => simp
|
||||
| succ n ih => simp [ih, List.finRange_succ_last, List.foldr_map]
|
||||
|
||||
theorem foldRev_add
|
||||
{α n m} (f : (i : Nat) → i < n + m → α → α) (init : α) :
|
||||
foldRev (n + m) f init =
|
||||
foldRev n (fun i h => f i (by omega))
|
||||
(foldRev m (fun i h => f (n + i) (by omega)) init) := by
|
||||
induction m generalizing init with
|
||||
| zero => simp; rfl
|
||||
| succ m ih =>
|
||||
rw [foldRev_congr (Nat.add_assoc n m 1).symm]
|
||||
simp [ih]
|
||||
|
||||
/-! ### `any` -/
|
||||
|
||||
@[simp] theorem any_zero {f : (i : Nat) → i < 0 → Bool} : any 0 f = false := by simp [any]
|
||||
|
||||
@@ -6,9 +6,11 @@ Authors: Leonardo de Moura, Jeremy Avigad, Mario Carneiro, Floris van Doorn
|
||||
module
|
||||
|
||||
prelude
|
||||
public import all Init.Data.Nat.Bitwise.Basic
|
||||
public import Init.Data.Nat.Bitwise.Basic
|
||||
import all Init.Data.Nat.Bitwise.Basic
|
||||
public import Init.Data.Nat.MinMax
|
||||
public import all Init.Data.Nat.Log2
|
||||
public import Init.Data.Nat.Log2
|
||||
import all Init.Data.Nat.Log2
|
||||
public import Init.Data.Nat.Power2
|
||||
public import Init.Data.Nat.Mod
|
||||
|
||||
@@ -1313,13 +1315,13 @@ theorem pow_eq_self_iff {a b : Nat} (ha : 1 < a) : a ^ b = a ↔ b = 1 := by
|
||||
|
||||
@[simp]
|
||||
theorem log2_zero : Nat.log2 0 = 0 := by
|
||||
simp [Nat.log2]
|
||||
simp [Nat.log2_def]
|
||||
|
||||
theorem le_log2 (h : n ≠ 0) : k ≤ n.log2 ↔ 2 ^ k ≤ n := by
|
||||
match k with
|
||||
| 0 => simp [show 1 ≤ n from Nat.pos_of_ne_zero h]
|
||||
| k+1 =>
|
||||
rw [log2]; split
|
||||
rw [log2_def]; split
|
||||
· have n0 : 0 < n / 2 := (Nat.le_div_iff_mul_le (by decide)).2 ‹_›
|
||||
simp only [Nat.add_le_add_iff_right, le_log2 (Nat.ne_of_gt n0),
|
||||
Nat.pow_succ]
|
||||
@@ -1331,6 +1333,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]
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/-
|
||||
Copyright (c) 2021 Microsoft Corporation. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Gabriel Ebner
|
||||
Authors: Gabriel Ebner, Robin Arnez
|
||||
-/
|
||||
module
|
||||
|
||||
@@ -37,11 +37,38 @@ Examples:
|
||||
-/
|
||||
@[extern "lean_nat_log2"]
|
||||
def log2 (n : @& Nat) : Nat :=
|
||||
if n ≥ 2 then log2 (n / 2) + 1 else 0
|
||||
decreasing_by exact log2_terminates _ ‹_›
|
||||
-- Lean "assembly"
|
||||
n.rec (fun _ => nat_lit 0) (fun _ ih n =>
|
||||
((nat_lit 2).ble n).rec (nat_lit 0) ((ih (n.div (nat_lit 2))).succ)) n
|
||||
|
||||
private theorem log2_rec_irrel {n k k' : Nat} (hk : n ≤ k) (hk' : n ≤ k') :
|
||||
(k.rec (fun _ => 0) (fun _ ih n => ((2).ble n).rec 0 ((ih (n / 2)).succ)) n : Nat) =
|
||||
k'.rec (fun _ => 0) (fun _ ih n => ((2).ble n).rec 0 ((ih (n / 2)).succ)) n := by
|
||||
induction k generalizing n k' with
|
||||
| zero => cases hk; cases k' <;> rfl
|
||||
| succ k ih =>
|
||||
cases k'
|
||||
· cases hk'; rfl
|
||||
· dsimp only
|
||||
cases h : ble 2 n
|
||||
· rfl
|
||||
· have hn : n / 2 < n := log2_terminates n (Nat.le_of_ble_eq_true h)
|
||||
exact congrArg Nat.succ (ih (Nat.le_of_lt_add_one (Nat.lt_of_lt_of_le hn hk))
|
||||
(Nat.le_of_lt_add_one (Nat.lt_of_lt_of_le hn hk')))
|
||||
|
||||
theorem log2_def (n : Nat) : n.log2 = if 2 ≤ n then (n / 2).log2 + 1 else 0 := by
|
||||
rw [Nat.log2, Nat.log2]
|
||||
cases n
|
||||
· rfl
|
||||
split
|
||||
· rename_i n h
|
||||
simp only [ble_eq_true_of_le h]
|
||||
exact congrArg Nat.succ
|
||||
(log2_rec_irrel (Nat.le_of_lt_add_one (log2_terminates _ h)) (Nat.le_refl _))
|
||||
· simp only [mt le_of_ble_eq_true ‹_›]
|
||||
|
||||
theorem log2_le_self (n : Nat) : Nat.log2 n ≤ n := by
|
||||
unfold Nat.log2; split
|
||||
rw [log2_def]; split
|
||||
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))
|
||||
|
||||
@@ -25,14 +25,14 @@ public instance : LawfulOrderLT Nat := by
|
||||
simp [Nat.lt_iff_le_and_ne]
|
||||
|
||||
public instance : LawfulOrderMin Nat := by
|
||||
apply LawfulOrderMin.of_le
|
||||
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_le
|
||||
apply LawfulOrderMax.of_max_le_iff
|
||||
· apply Nat.max_le
|
||||
· intro a b
|
||||
simp only [Nat.max_def]
|
||||
|
||||
@@ -8,7 +8,8 @@ module
|
||||
prelude
|
||||
public import Init.Data.Array.Lemmas
|
||||
public import Init.Data.Option.List
|
||||
public import all Init.Data.Option.Instances
|
||||
public import Init.Data.Option.Instances
|
||||
import all Init.Data.Option.Instances
|
||||
|
||||
public section
|
||||
|
||||
|
||||
@@ -6,8 +6,10 @@ Authors: Mario Carneiro
|
||||
module
|
||||
|
||||
prelude
|
||||
public import all Init.Data.Option.BasicAux
|
||||
public import all Init.Data.Option.Instances
|
||||
public import Init.Data.Option.BasicAux
|
||||
import all Init.Data.Option.BasicAux
|
||||
public import Init.Data.Option.Instances
|
||||
import all Init.Data.Option.Instances
|
||||
public import Init.Data.BEq
|
||||
public import Init.Classical
|
||||
public import Init.Ext
|
||||
@@ -795,7 +797,7 @@ 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 : α → β) : Option.elim none x f = x := rfl
|
||||
|
||||
@[simp, grind =] theorem elim_some (x : β) (f : α → β) (a : α) : (some a).elim x f = f a := rfl
|
||||
|
||||
|
||||
@@ -7,8 +7,10 @@ module
|
||||
|
||||
prelude
|
||||
public import Init.Data.List.Lemmas
|
||||
public import all Init.Data.List.Control
|
||||
public import all Init.Data.Option.Instances
|
||||
public import Init.Data.List.Control
|
||||
import all Init.Data.List.Control
|
||||
public import Init.Data.Option.Instances
|
||||
import all Init.Data.Option.Instances
|
||||
|
||||
public section
|
||||
|
||||
|
||||
@@ -7,7 +7,8 @@ module
|
||||
|
||||
prelude
|
||||
|
||||
public import all Init.Data.Option.Instances
|
||||
public import Init.Data.Option.Instances
|
||||
import all Init.Data.Option.Instances
|
||||
public import Init.Data.Option.Attach
|
||||
public import Init.Control.Lawful.Basic
|
||||
|
||||
|
||||
@@ -9,7 +9,8 @@ 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 import Init.Data.Vector.Basic
|
||||
import all Init.Data.Vector.Basic
|
||||
|
||||
public section
|
||||
|
||||
@@ -96,7 +97,7 @@ Ordering.lt
|
||||
| a => a
|
||||
|
||||
/-- Version of `Ordering.then'` for proof by reflection. -/
|
||||
noncomputable def then' (a b : Ordering) : Ordering :=
|
||||
@[expose] noncomputable def then' (a b : Ordering) : Ordering :=
|
||||
Ordering.rec a b a a
|
||||
|
||||
/--
|
||||
@@ -530,7 +531,7 @@ instance [Ord α] : Ord (Option α) where
|
||||
| some x, some y => compare x y
|
||||
|
||||
instance : Ord Ordering where
|
||||
compare := compareOn (·.toCtorIdx)
|
||||
compare := compareOn (·.ctorIdx)
|
||||
|
||||
namespace List
|
||||
|
||||
|
||||
@@ -17,6 +17,26 @@ This module provides utilities for the creation of order-related typeclass insta
|
||||
|
||||
section OfLE
|
||||
|
||||
/--
|
||||
Creates a `Min α` instance from `LE α` and `DecidableLE α` so that `min a b` is either `a` or `b`,
|
||||
preferring `a` over `b` when in doubt.
|
||||
|
||||
Has a `LawfulOrderLeftLeaningMin α` instance.
|
||||
-/
|
||||
@[inline]
|
||||
public def _root_.Min.leftLeaningOfLE (α : Type u) [LE α] [DecidableLE α] : Min α where
|
||||
min a b := if a ≤ b then a else b
|
||||
|
||||
/--
|
||||
Creates a `Max α` instance from `LE α` and `DecidableLE α` so that `max a b` is either `a` or `b`,
|
||||
preferring `a` over `b` when in doubt.
|
||||
|
||||
Has a `LawfulOrderLeftLeaningMax α` instance.
|
||||
-/
|
||||
@[inline]
|
||||
public def _root_.Max.leftLeaningOfLE (α : Type u) [LE α] [DecidableLE α] : Max α where
|
||||
max a b := if b ≤ a then a else b
|
||||
|
||||
/--
|
||||
This instance is only publicly defined in `Init.Data.Order.Lemmas`.
|
||||
-/
|
||||
@@ -95,12 +115,34 @@ instances.
|
||||
|
||||
The produced instance entails `LawfulOrderInf α` and `MinEqOr α`.
|
||||
-/
|
||||
public theorem LawfulOrderMin.of_le {α : Type u} [Min α] [LE α]
|
||||
(le_min_iff : ∀ a b c : α, a ≤ min b c ↔ a ≤ b ∧ a ≤ c)
|
||||
(min_eq_or : ∀ a b : α, min a b = a ∨ min a b = b) : LawfulOrderMin α where
|
||||
public theorem LawfulOrderMin.of_le_min_iff {α : Type u} [Min α] [LE α]
|
||||
(le_min_iff : ∀ a b c : α, a ≤ min b c ↔ a ≤ b ∧ a ≤ c := by exact LawfulOrderInf.le_min_iff)
|
||||
(min_eq_or : ∀ a b : α, min a b = a ∨ min a b = b := by exact MinEqOr.min_eq_or) :
|
||||
LawfulOrderMin α where
|
||||
toLawfulOrderInf := .of_le le_min_iff
|
||||
toMinEqOr := ⟨min_eq_or⟩
|
||||
|
||||
/--
|
||||
Returns a `LawfulOrderMin α` instance given that `max a b` returns either `a` or `b` and that
|
||||
it is less than or equal to both of them. The `≤` relation needs to be transitive.
|
||||
|
||||
The produced instance entails `LawfulOrderInf α` and `MinEqOr α`.
|
||||
-/
|
||||
public theorem LawfulOrderMin.of_min_le {α : Type u} [Min α] [LE α]
|
||||
[i : Trans (α := α) (· ≤ ·) (· ≤ ·) (· ≤ ·)]
|
||||
(min_le_left : ∀ a b : α, min a b ≤ a) (min_le_right : ∀ a b : α, min a b ≤ b)
|
||||
(min_eq_or : ∀ a b : α, min a b = a ∨ min a b = b := by exact MinEqOr.min_eq_or) :
|
||||
LawfulOrderMin α := by
|
||||
apply LawfulOrderMin.of_le_min_iff
|
||||
· simp [autoParam]
|
||||
intro a b c
|
||||
constructor
|
||||
· intro h
|
||||
exact ⟨i.trans h (min_le_left b c), i.trans h (min_le_right b c)⟩
|
||||
· intro h
|
||||
cases min_eq_or b c <;> simp [*]
|
||||
· exact min_eq_or
|
||||
|
||||
/--
|
||||
This lemma characterizes in terms of `LE α` when a `Max α` instance "behaves like a supremum
|
||||
operator".
|
||||
@@ -117,12 +159,34 @@ instances.
|
||||
|
||||
The produced instance entails `LawfulOrderSup α` and `MaxEqOr α`.
|
||||
-/
|
||||
public def LawfulOrderMax.of_le {α : Type u} [Max α] [LE α]
|
||||
(max_le_iff : ∀ a b c : α, max a b ≤ c ↔ a ≤ c ∧ b ≤ c)
|
||||
(max_eq_or : ∀ a b : α, max a b = a ∨ max a b = b) : LawfulOrderMax α where
|
||||
public def LawfulOrderMax.of_max_le_iff {α : Type u} [Max α] [LE α]
|
||||
(max_le_iff : ∀ a b c : α, max a b ≤ c ↔ a ≤ c ∧ b ≤ c := by exact LawfulOrderInf.le_min_iff)
|
||||
(max_eq_or : ∀ a b : α, max a b = a ∨ max a b = b := by exact MaxEqOr.max_eq_or) :
|
||||
LawfulOrderMax α where
|
||||
toLawfulOrderSup := .of_le max_le_iff
|
||||
toMaxEqOr := ⟨max_eq_or⟩
|
||||
|
||||
/--
|
||||
Returns a `LawfulOrderMax α` instance given that `max a b` returns either `a` or `b` and that
|
||||
it is larger than or equal to both of them. The `≤` relation needs to be transitive.
|
||||
|
||||
The produced instance entails `LawfulOrderSup α` and `MaxEqOr α`.
|
||||
-/
|
||||
public theorem LawfulOrderMax.of_le_max {α : Type u} [Max α] [LE α]
|
||||
[i : Trans (α := α) (· ≤ ·) (· ≤ ·) (· ≤ ·)]
|
||||
(left_le_max : ∀ a b : α, a ≤ max a b) (right_le_max : ∀ a b : α, b ≤ max a b)
|
||||
(max_eq_or : ∀ a b : α, max a b = a ∨ max a b = b := by exact MaxEqOr.max_eq_or) :
|
||||
LawfulOrderMax α := by
|
||||
apply LawfulOrderMax.of_max_le_iff
|
||||
· simp [autoParam]
|
||||
intro a b c
|
||||
constructor
|
||||
· intro h
|
||||
exact ⟨i.trans (left_le_max a b) h, i.trans (right_le_max a b) h⟩
|
||||
· intro h
|
||||
cases max_eq_or a b <;> simp [*]
|
||||
· exact max_eq_or
|
||||
|
||||
end OfLE
|
||||
|
||||
section OfLT
|
||||
@@ -132,7 +196,8 @@ Creates a *total* `LE α` instance from an `LT α` instance.
|
||||
|
||||
This only makes sense for asymmetric `LT α` instances (see `Std.Asymm`).
|
||||
-/
|
||||
public def LE.ofLT (α : Type u) [LT α] : LE α where
|
||||
@[inline]
|
||||
public def _root_.LE.ofLT (α : Type u) [LT α] : LE α where
|
||||
le a b := ¬ b < a
|
||||
|
||||
/--
|
||||
|
||||
@@ -8,6 +8,7 @@ module
|
||||
prelude
|
||||
public import Init.Data.Order.Classes
|
||||
public import Init.Data.Order.Factories
|
||||
import all Init.Data.Order.Factories
|
||||
import Init.SimpLemmas
|
||||
public import Init.Classical
|
||||
public import Init.Data.BEq
|
||||
@@ -95,6 +96,11 @@ public theorem not_gt_of_lt {α : Type u} [LT α] [i : Std.Asymm (α := α) (·
|
||||
(h : a < b) : ¬ b < a :=
|
||||
i.asymm a b h
|
||||
|
||||
public theorem le_of_lt {α : Type u} [LT α] [LE α] [LawfulOrderLT α] {a b : α} (h : a < b) :
|
||||
a ≤ b := by
|
||||
simp only [LawfulOrderLT.lt_iff] at h
|
||||
exact h.1
|
||||
|
||||
public instance {α : Type u} [LT α] [LE α] [LawfulOrderLT α] :
|
||||
Std.Asymm (α := α) (· < ·) where
|
||||
asymm a b := by
|
||||
@@ -141,6 +147,15 @@ public theorem lt_of_le_of_lt {α : Type u} [LE α] [LT α]
|
||||
· intro hca
|
||||
exact hbc.2.elim (le_trans hca hab)
|
||||
|
||||
public theorem lt_of_lt_of_le {α : Type u} [LE α] [LT α]
|
||||
[Trans (α := α) (· ≤ ·) (· ≤ ·) (· ≤ ·)] [LawfulOrderLT α] {a b c : α} (hab : a < b)
|
||||
(hbc : b ≤ c) : a < c := by
|
||||
simp only [lt_iff_le_and_not_ge] at hab ⊢
|
||||
apply And.intro
|
||||
· exact le_trans hab.1 hbc
|
||||
· intro hca
|
||||
exact hab.2.elim (le_trans hbc hca)
|
||||
|
||||
public theorem lt_of_le_of_ne {α : Type u} [LE α] [LT α]
|
||||
[Std.Antisymm (α := α) (· ≤ ·)] [LawfulOrderLT α] {a b : α}
|
||||
(hle : a ≤ b) (hne : a ≠ b) : a < b := by
|
||||
@@ -306,8 +321,50 @@ public instance {α : Type u} [LE α] [Min α] [IsLinearOrder α] [LawfulOrderIn
|
||||
· apply min_le_right
|
||||
· simp [le_min_iff, le_refl, le_of_not_ge hab]
|
||||
|
||||
end Min
|
||||
public theorem LawfulOrderLeftLeaningMin.of_eq {α : Type u} [LE α] [Min α] [DecidableLE α]
|
||||
(min_eq : ∀ a b : α, min a b = if a ≤ b then a else b) : LawfulOrderLeftLeaningMin α where
|
||||
min_eq_left a b := by simp +contextual [min_eq]
|
||||
min_eq_right a b := by simp +contextual [min_eq]
|
||||
|
||||
attribute [local instance] Min.leftLeaningOfLE
|
||||
public instance [LE α] [DecidableLE α] : LawfulOrderLeftLeaningMin α :=
|
||||
.of_eq (fun a b => by simp [min])
|
||||
|
||||
public instance {α : Type u} [LE α] [Min α] [LawfulOrderLeftLeaningMin α] :
|
||||
MinEqOr α where
|
||||
min_eq_or a b := by
|
||||
open scoped Classical in
|
||||
suffices min_eq : min a b = if a ≤ b then a else b by
|
||||
rw [min_eq]
|
||||
split <;> simp
|
||||
split <;> simp [*, LawfulOrderLeftLeaningMin.min_eq_left, LawfulOrderLeftLeaningMin.min_eq_right]
|
||||
|
||||
public instance {α : Type u} [LE α] [Min α] [IsLinearPreorder α] [LawfulOrderLeftLeaningMin α] :
|
||||
LawfulOrderMin α where
|
||||
toMinEqOr := inferInstance
|
||||
le_min_iff a b c := by
|
||||
open scoped Classical in
|
||||
suffices min_eq : min b c = if b ≤ c then b else c by
|
||||
rw [min_eq]
|
||||
split <;> rename_i hbc
|
||||
· simp only [iff_self_and]
|
||||
exact fun hab => le_trans hab hbc
|
||||
· simp only [iff_and_self]
|
||||
exact fun hac => le_trans hac (by simpa [hbc] using Std.le_total (a := b) (b := c))
|
||||
split <;> simp [*, LawfulOrderLeftLeaningMin.min_eq_left, LawfulOrderLeftLeaningMin.min_eq_right]
|
||||
|
||||
end Min
|
||||
end Std
|
||||
|
||||
namespace Classical.Order
|
||||
open Std
|
||||
|
||||
public noncomputable scoped instance instMin {α : Type u} [LE α] : Min α :=
|
||||
.leftLeaningOfLE α
|
||||
|
||||
end Classical.Order
|
||||
|
||||
namespace Std
|
||||
section Max
|
||||
|
||||
public theorem max_self {α : Type u} [Max α] [Std.IdempotentOp (max : α → α → α)] {a : α} :
|
||||
@@ -401,6 +458,45 @@ public instance {α : Type u} [LE α] [Max α] [IsLinearOrder α] [LawfulOrderSu
|
||||
· simp [max_le_iff, le_refl, le_of_not_ge hab]
|
||||
· apply right_le_max
|
||||
|
||||
end Max
|
||||
public theorem LawfulOrderLeftLeaningMax.of_eq {α : Type u} [LE α] [Max α] [DecidableLE α]
|
||||
(min_eq : ∀ a b : α, max a b = if b ≤ a then a else b) : LawfulOrderLeftLeaningMax α where
|
||||
max_eq_left a b := by simp +contextual [min_eq]
|
||||
max_eq_right a b := by simp +contextual [min_eq]
|
||||
|
||||
attribute [local instance] Max.leftLeaningOfLE
|
||||
public instance [LE α] [DecidableLE α] : LawfulOrderLeftLeaningMax α :=
|
||||
.of_eq (fun a b => by simp [max])
|
||||
|
||||
public instance {α : Type u} [LE α] [Max α] [LawfulOrderLeftLeaningMax α] :
|
||||
MaxEqOr α where
|
||||
max_eq_or a b := by
|
||||
open scoped Classical in
|
||||
suffices min_eq : max a b = if b ≤ a then a else b by
|
||||
rw [min_eq]
|
||||
split <;> simp
|
||||
split <;> simp [*, LawfulOrderLeftLeaningMax.max_eq_left, LawfulOrderLeftLeaningMax.max_eq_right]
|
||||
|
||||
public instance {α : Type u} [LE α] [Max α] [IsLinearPreorder α] [LawfulOrderLeftLeaningMax α] :
|
||||
LawfulOrderMax α where
|
||||
toMaxEqOr := inferInstance
|
||||
max_le_iff a b c := by
|
||||
open scoped Classical in
|
||||
suffices max_eq : max a b = if b ≤ a then a else b by
|
||||
rw [max_eq]
|
||||
split <;> rename_i hba
|
||||
· simp only [iff_self_and]
|
||||
exact fun hac => le_trans hba hac
|
||||
· simp only [iff_and_self]
|
||||
exact fun hbc => le_trans (by simpa [hba] using Std.le_total (a := b) (b := a)) hbc
|
||||
split <;> simp [*, LawfulOrderLeftLeaningMax.max_eq_left, LawfulOrderLeftLeaningMax.max_eq_right]
|
||||
|
||||
end Max
|
||||
end Std
|
||||
|
||||
namespace Classical.Order
|
||||
open Std
|
||||
|
||||
public noncomputable scoped instance instMax {α : Type u} [LE α] : Max α :=
|
||||
.leftLeaningOfLE α
|
||||
|
||||
end Classical.Order
|
||||
|
||||
@@ -37,6 +37,10 @@ namespace ReflCmp
|
||||
theorem cmp_eq_of_eq {α : Type u} {cmp : α → α → Ordering} [Std.ReflCmp cmp] {a b : α} : a = b → cmp a b = .eq := by
|
||||
intro h; subst a; apply compare_self
|
||||
|
||||
theorem ne_of_cmp_ne_eq {α : Type u} {cmp : α → α → Ordering} [Std.ReflCmp cmp] {a b : α} :
|
||||
cmp a b ≠ .eq → a ≠ b :=
|
||||
mt cmp_eq_of_eq
|
||||
|
||||
end ReflCmp
|
||||
|
||||
/-- A typeclasses for ordered types for which `compare a a = .eq` for all `a`. -/
|
||||
|
||||
@@ -67,20 +67,20 @@ public structure Packages.PreorderOfLEArgs (α : Type u) where
|
||||
extract_lets
|
||||
first
|
||||
| infer_instance
|
||||
| exact Classical.Order.instLT
|
||||
| exact _root_.Classical.Order.instLT
|
||||
beq :
|
||||
let := le; let := decidableLE
|
||||
BEq α := by
|
||||
extract_lets
|
||||
first
|
||||
| infer_instance
|
||||
| exact FactoryInstances.beqOfDecidableLE
|
||||
| exact _root_.Std.FactoryInstances.beqOfDecidableLE
|
||||
lt_iff :
|
||||
let := le; let := lt
|
||||
∀ a b : α, a < b ↔ a ≤ b ∧ ¬ b ≤ a := by
|
||||
extract_lets
|
||||
first
|
||||
| exact LawfulOrderLT.lt_iff
|
||||
| exact _root_.Std.LawfulOrderLT.lt_iff
|
||||
| fail "Failed to automatically prove that the `LE` and `LT` instances are compatible. \
|
||||
Please ensure that a `LawfulOrderLT` instance can be synthesized or \
|
||||
manually provide the field `lt_iff`."
|
||||
@@ -89,10 +89,10 @@ public structure Packages.PreorderOfLEArgs (α : Type u) where
|
||||
have := lt_iff
|
||||
DecidableLT α := by
|
||||
extract_lets
|
||||
haveI := @LawfulOrderLT.mk (lt_iff := by assumption) ..
|
||||
haveI := @_root_.Std.LawfulOrderLT.mk (lt_iff := by assumption) ..
|
||||
first
|
||||
| infer_instance
|
||||
| exact FactoryInstances.decidableLTOfLE
|
||||
| exact _root_.Std.FactoryInstances.decidableLTOfLE
|
||||
| fail "Failed to automatically derive that `LT` is decidable. \
|
||||
Please ensure that a `DecidableLT` instance can be synthesized or \
|
||||
manually provide the field `decidableLT`."
|
||||
@@ -101,7 +101,7 @@ public structure Packages.PreorderOfLEArgs (α : Type u) where
|
||||
∀ a b : α, a == b ↔ a ≤ b ∧ b ≤ a := by
|
||||
extract_lets
|
||||
first
|
||||
| exact LawfulOrderBEq.beq_iff_le_and_ge
|
||||
| exact _root_.Std.LawfulOrderBEq.beq_iff_le_and_ge
|
||||
| fail "Failed to automatically prove that the `LE` and `BEq` instances are compatible. \
|
||||
Please ensure that a `LawfulOrderBEq` instance can be synthesized or \
|
||||
manually provide the field `beq_iff_le_and_ge`."
|
||||
@@ -110,7 +110,7 @@ public structure Packages.PreorderOfLEArgs (α : Type u) where
|
||||
∀ a : α, a ≤ a := by
|
||||
extract_lets
|
||||
first
|
||||
| exact Std.Refl.refl (r := (· ≤ ·))
|
||||
| exact _root_.Std.Refl.refl (r := (· ≤ ·))
|
||||
| fail "Failed to automatically prove that the `LE` instance is reflexive. \
|
||||
Please ensure that a `Refl` instance can be synthesized or \
|
||||
manually provide the field `le_refl`."
|
||||
@@ -119,7 +119,7 @@ public structure Packages.PreorderOfLEArgs (α : Type u) where
|
||||
∀ a b c : α, a ≤ b → b ≤ c → a ≤ c := by
|
||||
extract_lets
|
||||
first
|
||||
| exact fun _ _ _ hab hbc => Trans.trans (r := (· ≤ ·)) (s := (· ≤ ·)) (t := (· ≤ ·)) hab hbc
|
||||
| exact fun _ _ _ hab hbc => _root_.Trans.trans (r := (· ≤ ·)) (s := (· ≤ ·)) (t := (· ≤ ·)) hab hbc
|
||||
| fail "Failed to automatically prove that the `LE` instance is transitive. \
|
||||
Please ensure that a `Trans` instance can be synthesized or \
|
||||
manually provide the field `le_trans`."
|
||||
@@ -202,7 +202,7 @@ public structure Packages.PartialOrderOfLEArgs (α : Type u) extends Packages.Pr
|
||||
∀ a b : α, a ≤ b → b ≤ a → a = b := by
|
||||
extract_lets
|
||||
first
|
||||
| exact Antisymm.antisymm
|
||||
| exact _root_.Std.Antisymm.antisymm
|
||||
| fail "Failed to automatically prove that the `LE` instance is antisymmetric. \
|
||||
Please ensure that a `Antisymm` instance can be synthesized or \
|
||||
manually provide the field `le_antisymm`."
|
||||
@@ -310,11 +310,11 @@ public structure Packages.LinearPreorderOfLEArgs (α : Type u) extends
|
||||
extract_lets
|
||||
first
|
||||
| infer_instance
|
||||
| exact FactoryInstances.instOrdOfDecidableLE
|
||||
| exact _root_.Std.FactoryInstances.instOrdOfDecidableLE
|
||||
le_total :
|
||||
∀ a b : α, a ≤ b ∨ b ≤ a := by
|
||||
first
|
||||
| exact Total.total
|
||||
| exact _root_.Std.Total.total
|
||||
| fail "Failed to automatically prove that the `LE` instance is total. \
|
||||
Please ensure that a `Total` instance can be synthesized or \
|
||||
manually provide the field `le_total`."
|
||||
@@ -324,7 +324,7 @@ public structure Packages.LinearPreorderOfLEArgs (α : Type u) extends
|
||||
∀ a b : α, (compare a b).isLE ↔ a ≤ b := by
|
||||
extract_lets
|
||||
first
|
||||
| exact LawfulOrderOrd.isLE_compare
|
||||
| exact _root_.Std.LawfulOrderOrd.isLE_compare
|
||||
| fail "Failed to automatically prove that `(compare a b).isLE` is equivalent to `a ≤ b`. \
|
||||
Please ensure that a `LawfulOrderOrd` instance can be synthesized or \
|
||||
manually provide the field `isLE_compare`."
|
||||
@@ -333,7 +333,7 @@ public structure Packages.LinearPreorderOfLEArgs (α : Type u) extends
|
||||
∀ a b : α, (compare a b).isGE ↔ b ≤ a := by
|
||||
extract_lets
|
||||
first
|
||||
| exact LawfulOrderOrd.isGE_compare
|
||||
| exact _root_.Std.LawfulOrderOrd.isGE_compare
|
||||
| fail "Failed to automatically prove that `(compare a b).isGE` is equivalent to `b ≤ a`. \
|
||||
Please ensure that a `LawfulOrderOrd` instance can be synthesized or \
|
||||
manually provide the field `isGE_compare`."
|
||||
@@ -390,26 +390,6 @@ public def LinearPreorderPackage.ofLE (α : Type u)
|
||||
isLE_compare := args.isLE_compare
|
||||
isGE_compare := args.isGE_compare
|
||||
|
||||
namespace FactoryInstances
|
||||
|
||||
public scoped instance instMinOfDecidableLE {α : Type u} [LE α] [DecidableLE α] : Min α where
|
||||
min a b := if a ≤ b then a else b
|
||||
|
||||
public scoped instance instMaxOfDecidableLE {α : Type u} [LE α] [DecidableLE α] : Max α where
|
||||
max a b := if b ≤ a then a else b
|
||||
|
||||
public instance instLawfulOrderLeftLeaningMinOfDecidableLE {α : Type u} [LE α] [DecidableLE α] :
|
||||
LawfulOrderLeftLeaningMin α where
|
||||
min_eq_left a b := by simp +contextual [min]
|
||||
min_eq_right a b := by simp +contextual [min]
|
||||
|
||||
public instance instLawfulOrderLeftLeaningMaxOfDecidableLE {α : Type u} [LE α] [DecidableLE α] :
|
||||
LawfulOrderLeftLeaningMax α where
|
||||
max_eq_left a b := by simp +contextual [max]
|
||||
max_eq_right a b := by simp +contextual [max]
|
||||
|
||||
end FactoryInstances
|
||||
|
||||
/--
|
||||
This class entails `LE α`, `LT α`, `BEq α`, `Ord α`, `Min α` and `Max α` instances as well as proofs
|
||||
that these operations represent the same linear order structure on `α`.
|
||||
@@ -431,20 +411,20 @@ public structure Packages.LinearOrderOfLEArgs (α : Type u) extends
|
||||
extract_lets
|
||||
first
|
||||
| infer_instance
|
||||
| exact FactoryInstances.instMinOfDecidableLE
|
||||
| exact _root_.Min.leftLeaningOfLE _
|
||||
max :
|
||||
let := le; let := decidableLE
|
||||
Max α := by
|
||||
extract_lets
|
||||
first
|
||||
| infer_instance
|
||||
| exact FactoryInstances.instMaxOfDecidableLE
|
||||
| exact _root_.Max.leftLeaningOfLE _
|
||||
min_eq :
|
||||
let := le; let := decidableLE; let := min
|
||||
∀ a b : α, Min.min a b = if a ≤ b then a else b := by
|
||||
extract_lets
|
||||
first
|
||||
| exact fun a b => Std.min_eq_if (a := a) (b := b)
|
||||
| exact fun a b => _root_.Std.min_eq_if (a := a) (b := b)
|
||||
| fail "Failed to automatically prove that `min` is left-leaning. \
|
||||
Please ensure that a `LawfulOrderLeftLeaningMin` instance can be synthesized or \
|
||||
manually provide the field `min_eq`."
|
||||
@@ -453,41 +433,11 @@ public structure Packages.LinearOrderOfLEArgs (α : Type u) extends
|
||||
∀ a b : α, Max.max a b = if b ≤ a then a else b := by
|
||||
extract_lets
|
||||
first
|
||||
| exact fun a b => Std.max_eq_if (a := a) (b := b)
|
||||
| exact fun a b => _root_.Std.max_eq_if (a := a) (b := b)
|
||||
| fail "Failed to automatically prove that `max` is left-leaning. \
|
||||
Please ensure that a `LawfulOrderLeftLeaningMax` instance can be synthesized or \
|
||||
manually provide the field `max_eq`."
|
||||
|
||||
public theorem IsLinearPreorder.lawfulOrderMin_of_min_eq {α : Type u} [LE α]
|
||||
[DecidableLE α] [Min α] [IsLinearPreorder α]
|
||||
(min_eq : ∀ a b : α, min a b = if a ≤ b then a else b) :
|
||||
LawfulOrderMin α where
|
||||
min_eq_or a b := by
|
||||
rw [min_eq]
|
||||
split <;> simp
|
||||
le_min_iff a b c := by
|
||||
simp only [min_eq]
|
||||
split <;> rename_i hbc
|
||||
· simp only [iff_self_and]
|
||||
exact fun hab => le_trans hab hbc
|
||||
· simp only [iff_and_self]
|
||||
exact fun hac => le_trans hac (by simpa [hbc] using Std.le_total (a := b) (b := c))
|
||||
|
||||
public theorem IsLinearPreorder.lawfulOrderMax_of_max_eq {α : Type u} [LE α]
|
||||
[DecidableLE α] [Max α] [IsLinearPreorder α]
|
||||
(max_eq : ∀ a b : α, max a b = if b ≤ a then a else b) :
|
||||
LawfulOrderMax α where
|
||||
max_eq_or a b := by
|
||||
rw [max_eq]
|
||||
split <;> simp
|
||||
max_le_iff a b c := by
|
||||
simp only [max_eq]
|
||||
split <;> rename_i hab
|
||||
· simp only [iff_self_and]
|
||||
exact fun hbc => le_trans hab hbc
|
||||
· simp only [iff_and_self]
|
||||
exact fun hac => le_trans (by simpa [hab] using Std.le_total (a := a) (b := b)) hac
|
||||
|
||||
/--
|
||||
Use this factory to conveniently define a linear order on a type `α` and all the associated
|
||||
operations and instances given an `LE α` instance.
|
||||
@@ -540,14 +490,16 @@ public def LinearOrderPackage.ofLE (α : Type u)
|
||||
le_antisymm := (PartialOrderPackage.ofLE α args.toPartialOrderOfLEArgs).le_antisymm
|
||||
toMin := args.min
|
||||
toMax := args.max
|
||||
toLawfulOrderMin :=
|
||||
toLawfulOrderMin := by
|
||||
letI := LinearPreorderPackage.ofLE α args.toLinearPreorderOfLEArgs
|
||||
letI := args.decidableLE; letI := args.min
|
||||
IsLinearPreorder.lawfulOrderMin_of_min_eq args.min_eq
|
||||
toLawfulOrderMax :=
|
||||
haveI : LawfulOrderLeftLeaningMin α := .of_eq args.min_eq
|
||||
infer_instance
|
||||
toLawfulOrderMax := by
|
||||
letI := LinearPreorderPackage.ofLE α args.toLinearPreorderOfLEArgs
|
||||
letI := args.decidableLE; letI := args.max
|
||||
IsLinearPreorder.lawfulOrderMax_of_max_eq args.max_eq
|
||||
haveI : LawfulOrderLeftLeaningMax α := .of_eq args.max_eq
|
||||
infer_instance
|
||||
|
||||
section LinearPreorder
|
||||
|
||||
@@ -586,8 +538,8 @@ public structure Packages.LinearPreorderOfOrdArgs (α : Type u) where
|
||||
extract_lets
|
||||
first
|
||||
| infer_instance
|
||||
| exact LE.ofOrd _
|
||||
lawful_le :
|
||||
| exact _root_.LE.ofOrd _
|
||||
lawfulOrderOrd :
|
||||
let := ord; let := transOrd; let := le
|
||||
LawfulOrderOrd α := by
|
||||
extract_lets
|
||||
@@ -595,14 +547,14 @@ public structure Packages.LinearPreorderOfOrdArgs (α : Type u) where
|
||||
| infer_instance
|
||||
| fail "Failed to automatically derive a `LawfulOrderOrd` instance. \
|
||||
Please ensure that the instance can be synthesized or \
|
||||
manually provide the field `lawful_le`."
|
||||
manually provide the field `lawfulOrderOrd`."
|
||||
decidableLE :
|
||||
let := ord; let := le; have := lawful_le
|
||||
let := ord; let := le; have := lawfulOrderOrd
|
||||
DecidableLE α := by
|
||||
extract_lets
|
||||
first
|
||||
| infer_instance
|
||||
| exact DecidableLE.ofOrd _
|
||||
| exact _root_.DecidableLE.ofOrd _
|
||||
| fail "Failed to automatically derive that `LE` is decidable.\
|
||||
Please ensure that a `DecidableLE` instance can be synthesized or \
|
||||
manually provide the field `decidableLE`."
|
||||
@@ -614,21 +566,21 @@ public structure Packages.LinearPreorderOfOrdArgs (α : Type u) where
|
||||
| infer_instance
|
||||
| exact LT.ofOrd _
|
||||
lt_iff :
|
||||
let := ord; let := le; have := lawful_le; let := lt
|
||||
let := ord; let := le; have := lawfulOrderOrd; let := lt
|
||||
∀ a b : α, a < b ↔ compare a b = .lt := by
|
||||
extract_lets
|
||||
first
|
||||
| exact fun _ _ => Std.compare_eq_lt.symm
|
||||
| exact fun _ _ => _root_.Std.compare_eq_lt.symm
|
||||
| fail "Failed to automatically derive that `LT` and `Ord` are compatible. \
|
||||
Please ensure that a `LawfulOrderLT` instance can be synthesized or \
|
||||
manually provide the field `lt_iff`."
|
||||
decidableLT :
|
||||
let := ord; let := lt; let := le; have := lawful_le; have := lt_iff
|
||||
let := ord; let := lt; let := le; have := lawfulOrderOrd; have := lt_iff
|
||||
DecidableLT α := by
|
||||
extract_lets
|
||||
first
|
||||
| infer_instance
|
||||
| exact DecidableLT.ofOrd _
|
||||
| exact _root_DecidableLT.ofOrd _
|
||||
| fail "Failed to automatically derive that `LT` is decidable. \
|
||||
Please ensure that a `DecidableLT` instance can be synthesized or \
|
||||
manually provide the field `decidableLT`."
|
||||
@@ -637,9 +589,9 @@ public structure Packages.LinearPreorderOfOrdArgs (α : Type u) where
|
||||
extract_lets
|
||||
first
|
||||
| infer_instance
|
||||
| exact BEq.ofOrd _
|
||||
| exact _root_.BEq.ofOrd _
|
||||
beq_iff :
|
||||
let := ord; let := le; have := lawful_le; let := beq
|
||||
let := ord; let := le; have := lawfulOrderOrd; let := beq
|
||||
∀ a b : α, a == b ↔ compare a b = .eq := by
|
||||
extract_lets
|
||||
first
|
||||
@@ -697,15 +649,15 @@ public def LinearPreorderPackage.ofOrd (α : Type u)
|
||||
letI := args.ord
|
||||
haveI := args.transOrd
|
||||
letI := args.le
|
||||
haveI := args.lawful_le
|
||||
haveI := args.lawfulOrderOrd
|
||||
{ toOrd := args.ord
|
||||
toLE := args.le
|
||||
toLT := args.lt
|
||||
toBEq := args.beq
|
||||
toLawfulOrderOrd := args.lawful_le
|
||||
toLawfulOrderOrd := args.lawfulOrderOrd
|
||||
lt_iff a b := by
|
||||
cases h : compare a b
|
||||
all_goals simp [h, ← args.lawful_le.isLE_compare a _, ← args.lawful_le.isGE_compare a _,
|
||||
all_goals simp [h, ← args.lawfulOrderOrd.isLE_compare a _, ← args.lawfulOrderOrd.isGE_compare a _,
|
||||
args.lt_iff]
|
||||
beq_iff_le_and_ge a b := by
|
||||
simp [args.beq_iff, Ordering.eq_eq_iff_isLE_and_isGE, isLE_compare,
|
||||
@@ -756,7 +708,7 @@ public structure Packages.LinearOrderOfOrdArgs (α : Type u) extends
|
||||
∀ a b : α, compare a b = .eq → a = b := by
|
||||
extract_lets
|
||||
first
|
||||
| exact LawfulEqOrd.eq_of_compare
|
||||
| exact fun _ _ => _root_.Std.LawfulEqOrd.eq_of_compare
|
||||
| fail "Failed to derive a `LawfulEqOrd` instance. \
|
||||
Please make sure that it can be synthesized or \
|
||||
manually provide the field `eq_of_compare`."
|
||||
@@ -766,29 +718,29 @@ public structure Packages.LinearOrderOfOrdArgs (α : Type u) extends
|
||||
extract_lets
|
||||
first
|
||||
| infer_instance
|
||||
| exact FactoryInstances.instMinOfOrd
|
||||
| exact _root_.Std.FactoryInstances.instMinOfOrd
|
||||
max :
|
||||
let := ord
|
||||
Max α := by
|
||||
extract_lets
|
||||
first
|
||||
| infer_instance
|
||||
| exact FactoryInstances.instMaxOfOrd
|
||||
| exact _root_.Std.FactoryInstances.instMaxOfOrd
|
||||
min_eq :
|
||||
let := ord; let := le; let := min; have := lawful_le
|
||||
let := ord; let := le; let := min; have := lawfulOrderOrd
|
||||
∀ a b : α, Min.min a b = if (compare a b).isLE then a else b := by
|
||||
extract_lets
|
||||
first
|
||||
| exact fun a b => Std.min_eq_if_isLE_compare (a := a) (b := b)
|
||||
| exact fun a b => _root_.Std.min_eq_if_isLE_compare (a := a) (b := b)
|
||||
| fail "Failed to automatically prove that `min` is left-leaning. \
|
||||
Please ensure that a `LawfulOrderLeftLeaningMin` instance can be synthesized or \
|
||||
manuelly provide the field `min_eq`."
|
||||
manually provide the field `min_eq`."
|
||||
max_eq :
|
||||
let := ord; let := le; let := max; have := lawful_le
|
||||
let := ord; let := le; let := max; have := lawfulOrderOrd
|
||||
∀ a b : α, Max.max a b = if (compare a b).isGE then a else b := by
|
||||
extract_lets
|
||||
first
|
||||
| exact fun a b => Std.max_eq_if_isGE_compare (a := a) (b := b)
|
||||
| exact fun a b => _root_.Std.max_eq_if_isGE_compare (a := a) (b := b)
|
||||
| fail "Failed to automatically prove that `max` is left-leaning. \
|
||||
Please ensure that a `LawfulOrderLeftLeaningMax` instance can be synthesized or \
|
||||
manually provide the field `max_eq`."
|
||||
@@ -847,10 +799,12 @@ public def LinearOrderPackage.ofOrd (α : Type u)
|
||||
{ toMin := args.min
|
||||
toMax := args.max,
|
||||
le_antisymm := Antisymm.antisymm
|
||||
toLawfulOrderMin := IsLinearPreorder.lawfulOrderMin_of_min_eq
|
||||
(by simpa [isLE_compare] using args.min_eq)
|
||||
toLawfulOrderMax := IsLinearPreorder.lawfulOrderMax_of_max_eq
|
||||
(by simpa [isGE_compare] using args.max_eq) }
|
||||
toLawfulOrderMin := by
|
||||
haveI : LawfulOrderLeftLeaningMin α := .of_eq (by simpa [isLE_compare] using args.min_eq)
|
||||
infer_instance
|
||||
toLawfulOrderMax := by
|
||||
haveI : LawfulOrderLeftLeaningMax α := .of_eq (by simpa [isGE_compare] using args.max_eq)
|
||||
infer_instance }
|
||||
|
||||
end LinearOrder
|
||||
|
||||
|
||||
@@ -6,7 +6,8 @@ Authors: Kim Morrison
|
||||
module
|
||||
|
||||
prelude
|
||||
public import all Init.Data.Range.Basic
|
||||
public import Init.Data.Range.Basic
|
||||
import all Init.Data.Range.Basic
|
||||
public import Init.Data.List.Range
|
||||
public import Init.Data.List.Monadic
|
||||
public import Init.Data.Nat.Div.Lemmas
|
||||
|
||||
@@ -11,6 +11,7 @@ public import Init.Data.Range.Polymorphic.Iterators
|
||||
public import Init.Data.Range.Polymorphic.Stream
|
||||
public import Init.Data.Range.Polymorphic.Lemmas
|
||||
public import Init.Data.Range.Polymorphic.Nat
|
||||
public import Init.Data.Range.Polymorphic.Int
|
||||
public import Init.Data.Range.Polymorphic.NatLemmas
|
||||
public import Init.Data.Range.Polymorphic.GetElemTactic
|
||||
|
||||
|
||||
@@ -26,10 +26,9 @@ class RangeSize (shape : BoundShape) (α : Type u) where
|
||||
This typeclass ensures that a `RangeSize` instance returns the correct size for all ranges.
|
||||
-/
|
||||
class LawfulRangeSize (su : BoundShape) (α : Type u) [UpwardEnumerable α]
|
||||
[SupportsUpperBound su α] [RangeSize su α]
|
||||
[LawfulUpwardEnumerable α] [HasFiniteRanges su α] where
|
||||
[SupportsUpperBound su α] [RangeSize su α] where
|
||||
/-- If the smallest value in the range is beyond the upper bound, the size is zero. -/
|
||||
size_eq_zero_of_not_satisfied (upperBound : Bound su α) (init : α)
|
||||
size_eq_zero_of_not_isSatisfied (upperBound : Bound su α) (init : α)
|
||||
(h : ¬ SupportsUpperBound.IsSatisfied upperBound init) :
|
||||
RangeSize.size upperBound init = 0
|
||||
/--
|
||||
@@ -43,11 +42,38 @@ class LawfulRangeSize (su : BoundShape) (α : Type u) [UpwardEnumerable α]
|
||||
/--
|
||||
If the smallest value in the range satisfies the upper bound and has a successor, the size is
|
||||
one larger than the size of the range starting at the successor. -/
|
||||
size_eq_succ_of_succ?_eq_some (upperBound : Bound su α) (init : α)
|
||||
size_eq_succ_of_succ?_eq_some (upperBound : Bound su α) (init a : α)
|
||||
(h : SupportsUpperBound.IsSatisfied upperBound init)
|
||||
(h' : UpwardEnumerable.succ? init = some a) :
|
||||
RangeSize.size upperBound init = RangeSize.size upperBound a + 1
|
||||
|
||||
theorem LawfulRangeSize.size_eq_zero_iff_not_isSatisfied {su : BoundShape} {α : Type u}
|
||||
[UpwardEnumerable α] [SupportsUpperBound su α] [RangeSize su α] [LawfulRangeSize su α]
|
||||
{bound : Bound su α} {init : α} :
|
||||
RangeSize.size bound init = 0 ↔ ¬ SupportsUpperBound.IsSatisfied bound init := by
|
||||
match h : decide (SupportsUpperBound.IsSatisfied bound init) with
|
||||
| true =>
|
||||
simp only [decide_eq_true_eq] at h
|
||||
match hs : UpwardEnumerable.succ? init with
|
||||
| none => simp [h, LawfulRangeSize.size_eq_one_of_succ?_eq_none (h := h) (h' := hs)]
|
||||
| some b => simp [h, LawfulRangeSize.size_eq_succ_of_succ?_eq_some (h := h) (h' := hs)]
|
||||
| false =>
|
||||
simp only [decide_eq_false_iff_not] at h
|
||||
simp [h, LawfulRangeSize.size_eq_zero_of_not_isSatisfied]
|
||||
|
||||
theorem LawfulRangeSize.size_pos_iff_isSatisfied {su : BoundShape} {α : Type u}
|
||||
[UpwardEnumerable α] [SupportsUpperBound su α] [RangeSize su α] [LawfulRangeSize su α]
|
||||
{bound : Bound su α} {init : α} :
|
||||
0 < RangeSize.size bound init ↔ SupportsUpperBound.IsSatisfied bound init := by
|
||||
have := size_eq_zero_iff_not_isSatisfied (bound := bound) (init := init)
|
||||
match h : decide (SupportsUpperBound.IsSatisfied bound init) with
|
||||
| true =>
|
||||
simp only [decide_eq_true_eq] at h
|
||||
simp_all [Nat.pos_iff_ne_zero]
|
||||
| false =>
|
||||
simp only [decide_eq_false_iff_not] at h
|
||||
simp_all
|
||||
|
||||
/--
|
||||
Checks whether the range contains any value.
|
||||
|
||||
|
||||
175
src/Init/Data/Range/Polymorphic/Instances.lean
Normal file
175
src/Init/Data/Range/Polymorphic/Instances.lean
Normal file
@@ -0,0 +1,175 @@
|
||||
/-
|
||||
Copyright (c) 2025 Lean FRO, LLC. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Paul Reichert
|
||||
-/
|
||||
module
|
||||
|
||||
prelude
|
||||
public import Init.Data.Order.Classes
|
||||
public import Init.Data.Range.Polymorphic.Basic
|
||||
import Init.Data.Nat.Lemmas
|
||||
import Init.Data.Order.Lemmas
|
||||
|
||||
/-!
|
||||
This module provides instances that reduce the amount of code necessary to make a type compatible
|
||||
with the polymorphic ranges. For an example of the required work, take a look at
|
||||
`Init.Data.Range.Polymorphic.Nat`.
|
||||
-/
|
||||
|
||||
public section
|
||||
|
||||
namespace Std.PRange
|
||||
|
||||
instance [LE α] [LT α] [UpwardEnumerable α] [LawfulUpwardEnumerable α]
|
||||
[LawfulUpwardEnumerableLE α] [LawfulOrderLT α] : LawfulUpwardEnumerableLT α where
|
||||
lt_iff a b := by
|
||||
simp only [LawfulOrderLT.lt_iff, UpwardEnumerable.le_iff]
|
||||
constructor
|
||||
· intro h
|
||||
obtain ⟨n, hn⟩ := h.1
|
||||
cases n
|
||||
· apply h.2.elim
|
||||
refine ⟨0, ?_⟩
|
||||
simpa [succMany?_zero] using hn.symm
|
||||
exact ⟨_, hn⟩
|
||||
· intro h
|
||||
constructor
|
||||
· match h with | ⟨_, hn⟩ => exact ⟨_, hn⟩
|
||||
· exact UpwardEnumerable.not_ge_of_lt h
|
||||
|
||||
instance [LE α] [DecidableLE α] [UpwardEnumerable α] [LawfulUpwardEnumerableLE α] :
|
||||
LawfulUpwardEnumerableLowerBound .closed α where
|
||||
isSatisfied_iff a l := by
|
||||
simp [SupportsLowerBound.IsSatisfied, init?, UpwardEnumerable.le_iff]
|
||||
|
||||
instance [LE α] [DecidableLE α] [UpwardEnumerable α] [LawfulUpwardEnumerableLE α]
|
||||
[Trans (α := α) (· ≤ ·) (· ≤ ·) (· ≤ ·)]:
|
||||
LawfulUpwardEnumerableUpperBound .closed α where
|
||||
isSatisfied_of_le u a b hub hab := by
|
||||
simp only [SupportsUpperBound.IsSatisfied, ← UpwardEnumerable.le_iff] at hub hab ⊢
|
||||
exact Trans.trans hab hub
|
||||
|
||||
instance [LT α] [DecidableLT α] [UpwardEnumerable α] [LawfulUpwardEnumerable α]
|
||||
[LawfulUpwardEnumerableLT α] :
|
||||
LawfulUpwardEnumerableLowerBound .open α where
|
||||
isSatisfied_iff a l := by
|
||||
simp only [SupportsLowerBound.IsSatisfied, init?, UpwardEnumerable.lt_iff]
|
||||
constructor
|
||||
· rintro ⟨n, hn⟩
|
||||
simp only [succMany?_succ?_eq_succ?_bind_succMany?] at hn
|
||||
cases h : succ? l
|
||||
· simp [h] at hn
|
||||
· exact ⟨_, rfl, n, by simpa [h] using hn⟩
|
||||
· rintro ⟨init, hi, n, hn⟩
|
||||
exact ⟨n, by simpa [succMany?_succ?_eq_succ?_bind_succMany?, hi] using hn⟩
|
||||
|
||||
instance [LT α] [DecidableLT α] [UpwardEnumerable α] [LawfulUpwardEnumerable α]
|
||||
[LawfulUpwardEnumerableLT α] :
|
||||
LawfulUpwardEnumerableUpperBound .open α where
|
||||
isSatisfied_of_le u a b hub hab := by
|
||||
simp only [SupportsUpperBound.IsSatisfied, UpwardEnumerable.lt_iff] at hub ⊢
|
||||
exact UpwardEnumerable.lt_of_le_of_lt hab hub
|
||||
|
||||
instance [UpwardEnumerable α] [Least? α] [LawfulUpwardEnumerableLeast? α] :
|
||||
LawfulUpwardEnumerableLowerBound .unbounded α where
|
||||
isSatisfied_iff a l := by
|
||||
simpa [SupportsLowerBound.IsSatisfied, init?] using UpwardEnumerable.least?_le
|
||||
|
||||
instance [LE α] [Total (α := α) (· ≤ ·)] [UpwardEnumerable α] [LawfulUpwardEnumerable α]
|
||||
[LawfulUpwardEnumerableLE α] :
|
||||
LinearlyUpwardEnumerable α where
|
||||
eq_of_succ?_eq a b hab := by
|
||||
cases Total.total (α := α) (r := (· ≤ ·)) a b <;> rename_i h <;>
|
||||
simp only [UpwardEnumerable.le_iff] at h
|
||||
· obtain ⟨n, hn⟩ := h
|
||||
cases n
|
||||
· simpa [succMany?_zero] using hn
|
||||
· exfalso
|
||||
rw [succMany?_succ?_eq_succ?_bind_succMany?, hab,
|
||||
← succMany?_succ?_eq_succ?_bind_succMany?] at hn
|
||||
exact UpwardEnumerable.lt_irrefl ⟨_, hn⟩
|
||||
· obtain ⟨n, hn⟩ := h
|
||||
cases n
|
||||
· simpa [succMany?_zero] using hn.symm
|
||||
· exfalso
|
||||
rw [succMany?_succ?_eq_succ?_bind_succMany?, hab.symm,
|
||||
← succMany?_succ?_eq_succ?_bind_succMany?] at hn
|
||||
exact UpwardEnumerable.lt_irrefl ⟨_, hn⟩
|
||||
|
||||
instance [UpwardEnumerable α] : LawfulUpwardEnumerableUpperBound .unbounded α where
|
||||
isSatisfied_of_le _ _ _ _ _ := .intro
|
||||
|
||||
/--
|
||||
Creates a `RangeSize .open α` from a `RangeSize .closed α` instance. If the latter is lawful
|
||||
and certain other conditions hold, then the former is also lawful by
|
||||
`LawfulRangeSize.open_of_closed`.
|
||||
-/
|
||||
@[inline]
|
||||
abbrev RangeSize.openOfClosed [RangeSize .closed α] : RangeSize .open α where
|
||||
size bound a := RangeSize.size (shape := .closed) bound a - 1
|
||||
|
||||
attribute [local instance] RangeSize.openOfClosed in
|
||||
instance LawfulRangeSize.open_of_closed [UpwardEnumerable α] [LE α] [DecidableLE α]
|
||||
[LT α] [DecidableLT α] [LawfulOrderLT α] [IsPartialOrder α]
|
||||
[LawfulUpwardEnumerable α] [LawfulUpwardEnumerableLE α]
|
||||
[RangeSize .closed α] [LawfulRangeSize .closed α] :
|
||||
LawfulRangeSize .open α where
|
||||
size_eq_zero_of_not_isSatisfied bound a h := by
|
||||
simp only [SupportsUpperBound.IsSatisfied] at h
|
||||
simp only [RangeSize.size]
|
||||
by_cases h' : a ≤ bound
|
||||
· match hs : succ? a with
|
||||
| none => rw [LawfulRangeSize.size_eq_one_of_succ?_eq_none (h := h') (h' := by omega)]
|
||||
| some b =>
|
||||
rw [LawfulRangeSize.size_eq_succ_of_succ?_eq_some (h := h') (h' := hs)]
|
||||
have : ¬ b ≤ bound := by
|
||||
intro hb
|
||||
have : a < b := by
|
||||
rw [UpwardEnumerable.lt_iff]
|
||||
exact ⟨0, by simpa [succMany?_one] using hs⟩
|
||||
exact h (lt_of_lt_of_le this hb)
|
||||
rw [LawfulRangeSize.size_eq_zero_of_not_isSatisfied (h := this)]
|
||||
· suffices RangeSize.size (shape := .closed) bound a = 0 by omega
|
||||
exact LawfulRangeSize.size_eq_zero_of_not_isSatisfied _ _ h'
|
||||
size_eq_one_of_succ?_eq_none bound a h h' := by
|
||||
exfalso
|
||||
simp only [SupportsUpperBound.IsSatisfied, UpwardEnumerable.lt_iff] at h
|
||||
obtain ⟨n, hn⟩ := h
|
||||
simp [succMany?_succ?_eq_succ?_bind_succMany?, h'] at hn
|
||||
size_eq_succ_of_succ?_eq_some bound a a' h h' := by
|
||||
simp only [SupportsUpperBound.IsSatisfied] at h
|
||||
simp only [RangeSize.size, Nat.pred_eq_succ_iff]
|
||||
rw [LawfulRangeSize.size_eq_succ_of_succ?_eq_some (h := le_of_lt h) (h' := h')]
|
||||
rw [← Nat.sub_add_comm]
|
||||
· omega
|
||||
· simp only [Nat.succ_le_iff, LawfulRangeSize.size_pos_iff_isSatisfied,
|
||||
SupportsUpperBound.IsSatisfied]
|
||||
rw [UpwardEnumerable.le_iff]
|
||||
rw [UpwardEnumerable.lt_iff] at h
|
||||
refine ⟨h.choose, ?_⟩
|
||||
simpa [succMany?_succ?_eq_succ?_bind_succMany?, h'] using h.choose_spec
|
||||
|
||||
instance LawfulRangeSize.instHasFiniteRanges [UpwardEnumerable α] [LawfulUpwardEnumerable α]
|
||||
[RangeSize su α] [SupportsUpperBound su α] [LawfulRangeSize su α] : HasFiniteRanges su α where
|
||||
finite init bound := by
|
||||
refine ⟨RangeSize.size bound init, ?_⟩
|
||||
generalize hn : RangeSize.size bound init = n
|
||||
induction n generalizing init with
|
||||
| zero =>
|
||||
simp only [LawfulRangeSize.size_eq_zero_iff_not_isSatisfied] at hn
|
||||
simp [succMany?_zero, hn]
|
||||
| succ =>
|
||||
rename_i n ih
|
||||
rw [succMany?_succ?_eq_succ?_bind_succMany?]
|
||||
match hs : succ? init with
|
||||
| none => simp
|
||||
| some a =>
|
||||
simp only [Option.bind_some]
|
||||
apply ih
|
||||
have : SupportsUpperBound.IsSatisfied bound init :=
|
||||
LawfulRangeSize.size_pos_iff_isSatisfied.mp (by omega)
|
||||
rw [LawfulRangeSize.size_eq_succ_of_succ?_eq_some (h := this) (h' := hs)] at hn
|
||||
omega
|
||||
|
||||
end Std.PRange
|
||||
56
src/Init/Data/Range/Polymorphic/Int.lean
Normal file
56
src/Init/Data/Range/Polymorphic/Int.lean
Normal file
@@ -0,0 +1,56 @@
|
||||
/-
|
||||
Copyright (c) 2025 Lean FRO, LLC. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Paul Reichert
|
||||
-/
|
||||
module
|
||||
|
||||
prelude
|
||||
public import Init.Data.Range.Polymorphic.Instances
|
||||
public import Init.Data.Order.Classes
|
||||
import Init.Omega
|
||||
|
||||
public section
|
||||
|
||||
namespace Std.PRange
|
||||
|
||||
instance : UpwardEnumerable Int where
|
||||
succ? x := some (x + 1)
|
||||
succMany? n x := some (x + n)
|
||||
|
||||
instance : LawfulUpwardEnumerable Int where
|
||||
ne_of_lt := by
|
||||
simp only [UpwardEnumerable.LT, UpwardEnumerable.succMany?, Option.some.injEq]
|
||||
omega
|
||||
succMany?_zero := by simp [UpwardEnumerable.succMany?]
|
||||
succMany?_succ := by
|
||||
simp only [UpwardEnumerable.succMany?, UpwardEnumerable.succ?,
|
||||
Option.bind_some, Option.some.injEq]
|
||||
omega
|
||||
|
||||
instance : InfinitelyUpwardEnumerable Int where
|
||||
isSome_succ? x := by simp [UpwardEnumerable.succ?]
|
||||
|
||||
instance : LawfulUpwardEnumerableLE Int where
|
||||
le_iff x y := by
|
||||
simp [UpwardEnumerable.LE, UpwardEnumerable.succMany?, Int.le_def, Int.nonneg_def,
|
||||
Int.sub_eq_iff_eq_add', eq_comm (a := y)]
|
||||
|
||||
instance : RangeSize .closed Int where
|
||||
size bound a := (bound + 1 - a).toNat
|
||||
|
||||
instance : RangeSize .open Int := RangeSize.openOfClosed
|
||||
|
||||
instance : LawfulRangeSize .closed Int where
|
||||
size_eq_zero_of_not_isSatisfied bound x := by
|
||||
simp only [SupportsUpperBound.IsSatisfied, RangeSize.size]
|
||||
omega
|
||||
size_eq_one_of_succ?_eq_none bound x := by
|
||||
simp [SupportsUpperBound.IsSatisfied, RangeSize.size, UpwardEnumerable.succ?]
|
||||
|
||||
size_eq_succ_of_succ?_eq_some bound init x := by
|
||||
simp only [SupportsUpperBound.IsSatisfied, UpwardEnumerable.succ?, RangeSize.size,
|
||||
Option.some.injEq]
|
||||
omega
|
||||
|
||||
end Std.PRange
|
||||
@@ -7,11 +7,15 @@ module
|
||||
|
||||
prelude
|
||||
public import Init.Data.Iterators
|
||||
public import Init.Data.Iterators.Lemmas.Consumers.Collect
|
||||
public import all Init.Data.Range.Polymorphic.Basic
|
||||
public import all Init.Data.Range.Polymorphic.RangeIterator
|
||||
public import all Init.Data.Range.Polymorphic.Iterators
|
||||
public import all Init.Data.Iterators.Consumers.Loop
|
||||
import Init.Data.Iterators.Lemmas.Consumers.Collect
|
||||
public import Init.Data.Range.Polymorphic.Basic
|
||||
import all Init.Data.Range.Polymorphic.Basic
|
||||
public import Init.Data.Range.Polymorphic.RangeIterator
|
||||
import all Init.Data.Range.Polymorphic.RangeIterator
|
||||
public import Init.Data.Range.Polymorphic.Iterators
|
||||
import all Init.Data.Range.Polymorphic.Iterators
|
||||
public import Init.Data.Iterators.Consumers.Loop
|
||||
import all Init.Data.Iterators.Consumers.Loop
|
||||
|
||||
public section
|
||||
|
||||
@@ -26,13 +30,13 @@ open Std.Iterators
|
||||
|
||||
variable {shape : RangeShape} {α : Type u}
|
||||
|
||||
private theorem Internal.iter_open_eq_iter_closed_of_isSome_succ? {su} [UpwardEnumerable α]
|
||||
private theorem Internal.iter_Rox_eq_iter_Rcx_of_isSome_succ? {su} [UpwardEnumerable α]
|
||||
[SupportsUpperBound su α] [HasFiniteRanges su α]
|
||||
[LawfulUpwardEnumerable α]
|
||||
{lo : Bound .open α} {hi} (h : (UpwardEnumerable.succ? lo).isSome) :
|
||||
Internal.iter (PRange.mk (shape := ⟨.open, su⟩) lo hi) =
|
||||
Internal.iter (PRange.mk (shape := ⟨.closed, su⟩) (UpwardEnumerable.succ? lo |>.get h) hi) := by
|
||||
simp [Internal.iter, BoundedUpwardEnumerable.init?]
|
||||
simp [Internal.iter, init?]
|
||||
|
||||
private theorem Internal.toList_eq_toList_iter {sl su} [UpwardEnumerable α]
|
||||
[BoundedUpwardEnumerable sl α] [SupportsUpperBound su α] [HasFiniteRanges su α]
|
||||
@@ -40,7 +44,7 @@ private theorem Internal.toList_eq_toList_iter {sl su} [UpwardEnumerable α]
|
||||
r.toList = (Internal.iter r).toList := by
|
||||
rfl
|
||||
|
||||
theorem RangeIterator.toList_eq_match {su} [UpwardEnumerable α]
|
||||
public theorem RangeIterator.toList_eq_match {su} [UpwardEnumerable α]
|
||||
[SupportsUpperBound su α] [HasFiniteRanges su α]
|
||||
[LawfulUpwardEnumerable α]
|
||||
{it : Iter (α := RangeIterator su α) α} :
|
||||
@@ -57,11 +61,11 @@ theorem RangeIterator.toList_eq_match {su} [UpwardEnumerable α]
|
||||
· simp [*]
|
||||
· split <;> rename_i heq' <;> simp [*]
|
||||
|
||||
theorem toList_eq_match {sl su} [UpwardEnumerable α] [BoundedUpwardEnumerable sl α]
|
||||
public theorem toList_eq_match {sl su} [UpwardEnumerable α] [BoundedUpwardEnumerable sl α]
|
||||
[SupportsUpperBound su α] [HasFiniteRanges su α]
|
||||
[LawfulUpwardEnumerable α]
|
||||
{r : PRange ⟨sl, su⟩ α} :
|
||||
r.toList = match BoundedUpwardEnumerable.init? r.lower with
|
||||
r.toList = match init? r.lower with
|
||||
| none => []
|
||||
| some a => if SupportsUpperBound.IsSatisfied r.upper a then
|
||||
a :: (PRange.mk (shape := ⟨.open, su⟩) a r.upper).toList
|
||||
@@ -69,26 +73,35 @@ theorem toList_eq_match {sl su} [UpwardEnumerable α] [BoundedUpwardEnumerable s
|
||||
[] := by
|
||||
rw [Internal.toList_eq_toList_iter, RangeIterator.toList_eq_match]; rfl
|
||||
|
||||
theorem toList_open_eq_toList_closed_of_isSome_succ? {su} [UpwardEnumerable α]
|
||||
public theorem toList_Rox_eq_toList_Rcx_of_isSome_succ? {su} [UpwardEnumerable α]
|
||||
[SupportsUpperBound su α] [HasFiniteRanges su α]
|
||||
[LawfulUpwardEnumerable α]
|
||||
{lo : Bound .open α} {hi} (h : (UpwardEnumerable.succ? lo).isSome) :
|
||||
(PRange.mk (shape := ⟨.open, su⟩) lo hi).toList =
|
||||
(PRange.mk (shape := ⟨.closed, su⟩) (UpwardEnumerable.succ? lo |>.get h) hi).toList := by
|
||||
simp [Internal.toList_eq_toList_iter, Internal.iter_open_eq_iter_closed_of_isSome_succ?, h]
|
||||
simp [Internal.toList_eq_toList_iter, Internal.iter_Rox_eq_iter_Rcx_of_isSome_succ?, h]
|
||||
|
||||
theorem toList_eq_nil_iff {sl su} [UpwardEnumerable α]
|
||||
@[deprecated toList_Rox_eq_toList_Rcx_of_isSome_succ? (since := "2025-08-22")]
|
||||
public theorem toList_open_eq_toList_closed_of_isSome_succ? {su} [UpwardEnumerable α]
|
||||
[SupportsUpperBound su α] [HasFiniteRanges su α]
|
||||
[LawfulUpwardEnumerable α]
|
||||
{lo : Bound .open α} {hi} (h : (UpwardEnumerable.succ? lo).isSome) :
|
||||
(PRange.mk (shape := ⟨.open, su⟩) lo hi).toList =
|
||||
(PRange.mk (shape := ⟨.closed, su⟩) (UpwardEnumerable.succ? lo |>.get h) hi).toList :=
|
||||
toList_Rox_eq_toList_Rcx_of_isSome_succ? h
|
||||
|
||||
public theorem toList_eq_nil_iff {sl su} [UpwardEnumerable α]
|
||||
[SupportsUpperBound su α] [HasFiniteRanges su α] [BoundedUpwardEnumerable sl α]
|
||||
[LawfulUpwardEnumerable α]
|
||||
{r : PRange ⟨sl, su⟩ α} :
|
||||
r.toList = [] ↔
|
||||
¬ (∃ a, BoundedUpwardEnumerable.init? r.lower = some a ∧ SupportsUpperBound.IsSatisfied r.upper a) := by
|
||||
¬ (∃ a, init? r.lower = some a ∧ SupportsUpperBound.IsSatisfied r.upper a) := by
|
||||
rw [Internal.toList_eq_toList_iter]
|
||||
rw [RangeIterator.toList_eq_match, Internal.iter]
|
||||
simp only
|
||||
split <;> rename_i heq <;> simp [heq]
|
||||
|
||||
theorem mem_toList_iff_mem {sl su} [UpwardEnumerable α]
|
||||
public theorem mem_toList_iff_mem {sl su} [UpwardEnumerable α]
|
||||
[SupportsUpperBound su α] [SupportsLowerBound sl α] [HasFiniteRanges su α]
|
||||
[BoundedUpwardEnumerable sl α] [LawfulUpwardEnumerable α]
|
||||
[LawfulUpwardEnumerableLowerBound sl α] [LawfulUpwardEnumerableUpperBound su α]
|
||||
@@ -97,17 +110,24 @@ theorem mem_toList_iff_mem {sl su} [UpwardEnumerable α]
|
||||
rw [Internal.toList_eq_toList_iter, Iter.mem_toList_iff_isPlausibleIndirectOutput,
|
||||
Internal.isPlausibleIndirectOutput_iter_iff]
|
||||
|
||||
theorem BoundedUpwardEnumerable.Closed.init?_succ [UpwardEnumerable α]
|
||||
public theorem BoundedUpwardEnumerable.init?_succ?_closed [UpwardEnumerable α]
|
||||
[LawfulUpwardEnumerable α] {lower lower' : Bound .closed α}
|
||||
(h : UpwardEnumerable.succ? lower = some lower') :
|
||||
BoundedUpwardEnumerable.init? lower' = (BoundedUpwardEnumerable.init? lower).bind UpwardEnumerable.succ? := by
|
||||
init? lower' = (init? lower).bind UpwardEnumerable.succ? := by
|
||||
cases h : init? lower <;> rename_i ilower <;> cases h' : init? lower' <;> rename_i ilower'
|
||||
· simp
|
||||
· simp [init?] at h
|
||||
· simp [init?] at h'
|
||||
· simp_all [init?]
|
||||
|
||||
theorem pairwise_toList_upwardEnumerableLt {sl su} [UpwardEnumerable α]
|
||||
@[deprecated BoundedUpwardEnumerable.init?_succ?_closed (since := "2025-08-22")]
|
||||
public theorem BoundedUpwardEnumerable.Closed.init?_succ [UpwardEnumerable α]
|
||||
[LawfulUpwardEnumerable α] {lower lower' : Bound .closed α}
|
||||
(h : UpwardEnumerable.succ? lower = some lower') :
|
||||
init? lower' = (init? lower).bind UpwardEnumerable.succ? :=
|
||||
init?_succ?_closed h
|
||||
|
||||
public theorem pairwise_toList_upwardEnumerableLt {sl su} [UpwardEnumerable α]
|
||||
[SupportsUpperBound su α] [SupportsLowerBound sl α] [HasFiniteRanges su α]
|
||||
[BoundedUpwardEnumerable sl α] [LawfulUpwardEnumerable α]
|
||||
[LawfulUpwardEnumerableLowerBound sl α] [LawfulUpwardEnumerableUpperBound su α]
|
||||
@@ -126,14 +146,14 @@ theorem pairwise_toList_upwardEnumerableLt {sl su} [UpwardEnumerable α]
|
||||
simp only at ha
|
||||
have : UpwardEnumerable.LT a ha.choose := by
|
||||
refine ⟨0, ?_⟩
|
||||
simp only [UpwardEnumerable.succMany?_succ, UpwardEnumerable.succMany?_zero,
|
||||
simp only [succMany?_succ?, succMany?_zero,
|
||||
Option.bind_some]
|
||||
exact ha.choose_spec.1
|
||||
exact UpwardEnumerable.lt_of_lt_of_le this ha.choose_spec.2
|
||||
· apply ihy (out := a)
|
||||
simp_all [RangeIterator.isPlausibleStep_iff, RangeIterator.step]
|
||||
|
||||
theorem pairwise_toList_ne {sl su} [UpwardEnumerable α]
|
||||
public theorem pairwise_toList_ne {sl su} [UpwardEnumerable α]
|
||||
[SupportsUpperBound su α] [SupportsLowerBound sl α] [HasFiniteRanges su α]
|
||||
[BoundedUpwardEnumerable sl α] [LawfulUpwardEnumerable α]
|
||||
[LawfulUpwardEnumerableLowerBound sl α] [LawfulUpwardEnumerableUpperBound su α]
|
||||
@@ -141,7 +161,7 @@ theorem pairwise_toList_ne {sl su} [UpwardEnumerable α]
|
||||
r.toList.Pairwise (fun a b => a ≠ b) :=
|
||||
List.Pairwise.imp (fun hlt => UpwardEnumerable.ne_of_lt hlt) pairwise_toList_upwardEnumerableLt
|
||||
|
||||
theorem pairwise_toList_lt {sl su} [LT α] [UpwardEnumerable α]
|
||||
public theorem pairwise_toList_lt {sl su} [LT α] [UpwardEnumerable α]
|
||||
[SupportsUpperBound su α] [SupportsLowerBound sl α] [HasFiniteRanges su α]
|
||||
[BoundedUpwardEnumerable sl α] [LawfulUpwardEnumerable α] [LawfulUpwardEnumerableLT α]
|
||||
[LawfulUpwardEnumerableLowerBound sl α] [LawfulUpwardEnumerableUpperBound su α]
|
||||
@@ -150,7 +170,7 @@ theorem pairwise_toList_lt {sl su} [LT α] [UpwardEnumerable α]
|
||||
List.Pairwise.imp
|
||||
(fun hlt => (LawfulUpwardEnumerableLT.lt_iff ..).mpr hlt) pairwise_toList_upwardEnumerableLt
|
||||
|
||||
theorem pairwise_toList_le {sl su} [LE α] [UpwardEnumerable α]
|
||||
public theorem pairwise_toList_le {sl su} [LE α] [UpwardEnumerable α]
|
||||
[SupportsUpperBound su α] [SupportsLowerBound sl α] [HasFiniteRanges su α]
|
||||
[BoundedUpwardEnumerable sl α] [LawfulUpwardEnumerable α] [LawfulUpwardEnumerableLE α]
|
||||
[LawfulUpwardEnumerableLowerBound sl α] [LawfulUpwardEnumerableUpperBound su α]
|
||||
@@ -158,38 +178,44 @@ theorem pairwise_toList_le {sl su} [LE α] [UpwardEnumerable α]
|
||||
r.toList.Pairwise (fun a b => a ≤ b) :=
|
||||
pairwise_toList_upwardEnumerableLt
|
||||
|> List.Pairwise.imp UpwardEnumerable.le_of_lt
|
||||
|> List.Pairwise.imp (fun hle => (LawfulUpwardEnumerableLE.le_iff ..).mpr hle)
|
||||
|> List.Pairwise.imp (fun hle => (UpwardEnumerable.le_iff ..).mpr hle)
|
||||
|
||||
theorem ClosedOpen.mem_succ_iff [UpwardEnumerable α]
|
||||
public theorem mem_Rco_succ_succ_iff [UpwardEnumerable α]
|
||||
[LinearlyUpwardEnumerable α] [InfinitelyUpwardEnumerable α] [SupportsUpperBound .open α]
|
||||
[SupportsLowerBound .closed α] [LawfulUpwardEnumerableLowerBound .closed α]
|
||||
[HasFiniteRanges .open α] [LawfulUpwardEnumerable α] [LawfulOpenUpperBound α]
|
||||
{lower : Bound .closed α} {upper : Bound .open α} {a : α} :
|
||||
a ∈ PRange.mk (shape := ⟨.closed, .open⟩) (UpwardEnumerable.succ lower) (UpwardEnumerable.succ upper) ↔
|
||||
∃ a', a = UpwardEnumerable.succ a' ∧ a' ∈ PRange.mk (shape := ⟨.closed, .open⟩) lower upper := by
|
||||
(a ∈ (succ lower)...(succ upper)) ↔ ∃ a', a = succ a' ∧ a' ∈ lower...upper := by
|
||||
simp [Membership.mem, LawfulUpwardEnumerableLowerBound.isSatisfied_iff,
|
||||
BoundedUpwardEnumerable.init?, LawfulOpenUpperBound.isSatisfied_iff_le]
|
||||
init?, LawfulOpenUpperBound.isSatisfied_iff_le]
|
||||
rw [← Option.some_get (InfinitelyUpwardEnumerable.isSome_succ? _)]
|
||||
simp only [Option.some.injEq, ← UpwardEnumerable.succ.eq_def]
|
||||
simp
|
||||
constructor
|
||||
· rintro ⟨⟨n, hn⟩, h⟩
|
||||
rw [UpwardEnumerable.succMany?_eq_some_iff_succMany, ← UpwardEnumerable.succMany_one,
|
||||
← UpwardEnumerable.succMany_add, Nat.add_comm, UpwardEnumerable.succMany_add,
|
||||
UpwardEnumerable.succMany_one] at hn
|
||||
rw [succMany?_eq_some_iff_succMany, ← succMany_one, ← succMany_add, Nat.add_comm, succMany_add,
|
||||
succMany_one] at hn
|
||||
rw [← hn]
|
||||
refine ⟨UpwardEnumerable.succMany n lower, rfl, ?_, ?_⟩
|
||||
· exact ⟨n, by simp [UpwardEnumerable.succMany_eq_get]⟩
|
||||
refine ⟨succMany n lower, rfl, ?_, ?_⟩
|
||||
· exact ⟨n, by simp [succMany_eq_get]⟩
|
||||
· obtain ⟨m, hm⟩ := h
|
||||
refine ⟨m, ?_⟩
|
||||
rw [UpwardEnumerable.succMany?_eq_some_iff_succMany] at hm ⊢
|
||||
rwa [← hn, ← UpwardEnumerable.succMany_one, ← UpwardEnumerable.succMany_add, Nat.add_comm,
|
||||
UpwardEnumerable.succMany_add, UpwardEnumerable.succMany_one,
|
||||
UpwardEnumerable.succ_eq_succ_iff] at hm
|
||||
rw [succMany?_eq_some_iff_succMany] at hm ⊢
|
||||
rwa [← hn, ← succMany_one, ← succMany_add, Nat.add_comm, succMany_add, succMany_one,
|
||||
succ_eq_succ_iff] at hm
|
||||
· rintro ⟨a', rfl, hl, hu⟩
|
||||
simp [UpwardEnumerable.succ_le_succ_iff, UpwardEnumerable.succ_lt_succ_iff]
|
||||
exact ⟨hl, hu⟩
|
||||
|
||||
@[deprecated mem_Rco_succ_succ_iff (since := "2025-08-22")]
|
||||
public theorem ClosedOpen.mem_succ_iff [UpwardEnumerable α]
|
||||
[LinearlyUpwardEnumerable α] [InfinitelyUpwardEnumerable α] [SupportsUpperBound .open α]
|
||||
[SupportsLowerBound .closed α] [LawfulUpwardEnumerableLowerBound .closed α]
|
||||
[HasFiniteRanges .open α] [LawfulUpwardEnumerable α] [LawfulOpenUpperBound α]
|
||||
{lower : Bound .closed α} {upper : Bound .open α} {a : α} :
|
||||
(a ∈ (succ lower)...(succ upper)) ↔ ∃ a', a = succ a' ∧ a' ∈ lower...upper :=
|
||||
mem_Rco_succ_succ_iff
|
||||
|
||||
private theorem eq_of_pairwise_lt_of_mem_iff_mem {lt : α → α → Prop} [asymm : Asymm lt]
|
||||
{l l' : List α} (hl : l.Pairwise lt) (hl' : l'.Pairwise lt)
|
||||
(h : ∀ a, a ∈ l ↔ a ∈ l') : l = l' := by
|
||||
@@ -242,13 +268,13 @@ private theorem eq_of_pairwise_lt_of_mem_iff_mem {lt : α → α → Prop} [asym
|
||||
have hgt := hl.1 y ‹_›
|
||||
cases Asymm.asymm _ _ hlt hgt
|
||||
|
||||
theorem ClosedOpen.toList_succ_succ_eq_map [UpwardEnumerable α] [SupportsLowerBound .closed α]
|
||||
public theorem toList_Rco_succ_succ_eq_map [UpwardEnumerable α] [SupportsLowerBound .closed α]
|
||||
[LinearlyUpwardEnumerable α] [InfinitelyUpwardEnumerable α] [SupportsUpperBound .open α]
|
||||
[HasFiniteRanges .open α] [LawfulUpwardEnumerable α] [LawfulOpenUpperBound α]
|
||||
[LawfulUpwardEnumerableLowerBound .closed α] [LawfulUpwardEnumerableUpperBound .open α]
|
||||
{lower : Bound .closed α} {upper : Bound .open α} :
|
||||
(PRange.mk (shape := ⟨.closed, .open⟩) (UpwardEnumerable.succ lower) (UpwardEnumerable.succ upper)).toList =
|
||||
(PRange.mk (shape := ⟨.closed, .open⟩) lower upper).toList.map UpwardEnumerable.succ := by
|
||||
((succ lower)...(succ upper)).toList =
|
||||
(lower...upper).toList.map succ := by
|
||||
apply eq_of_pairwise_lt_of_mem_iff_mem (lt := UpwardEnumerable.LT) (asymm := ?_)
|
||||
· apply pairwise_toList_upwardEnumerableLt
|
||||
· apply List.Pairwise.map (R := UpwardEnumerable.LT) (S := UpwardEnumerable.LT)
|
||||
@@ -257,7 +283,7 @@ theorem ClosedOpen.toList_succ_succ_eq_map [UpwardEnumerable α] [SupportsLowerB
|
||||
· apply pairwise_toList_upwardEnumerableLt
|
||||
· simp only [List.mem_map, mem_toList_iff_mem]
|
||||
intro a
|
||||
rw [mem_succ_iff]
|
||||
rw [mem_Rco_succ_succ_iff]
|
||||
constructor
|
||||
· rintro ⟨a, rfl, h⟩
|
||||
exact ⟨a, h, rfl⟩
|
||||
@@ -265,6 +291,16 @@ theorem ClosedOpen.toList_succ_succ_eq_map [UpwardEnumerable α] [SupportsLowerB
|
||||
exact ⟨_, h'.symm, h⟩
|
||||
· exact ⟨fun _ _ => UpwardEnumerable.not_gt_of_lt⟩
|
||||
|
||||
@[deprecated toList_Rco_succ_succ_eq_map (since := "2025-08-22")]
|
||||
public theorem ClosedOpen.toList_succ_succ_eq_map [UpwardEnumerable α] [SupportsLowerBound .closed α]
|
||||
[LinearlyUpwardEnumerable α] [InfinitelyUpwardEnumerable α] [SupportsUpperBound .open α]
|
||||
[HasFiniteRanges .open α] [LawfulUpwardEnumerable α] [LawfulOpenUpperBound α]
|
||||
[LawfulUpwardEnumerableLowerBound .closed α] [LawfulUpwardEnumerableUpperBound .open α]
|
||||
{lower : Bound .closed α} {upper : Bound .open α} :
|
||||
((succ lower)...(succ upper)).toList =
|
||||
(lower...upper).toList.map succ :=
|
||||
toList_Rco_succ_succ_eq_map
|
||||
|
||||
private theorem Internal.forIn'_eq_forIn'_iter [UpwardEnumerable α]
|
||||
[SupportsUpperBound su α] [SupportsLowerBound sl α] [HasFiniteRanges su α]
|
||||
[BoundedUpwardEnumerable sl α] [LawfulUpwardEnumerable α]
|
||||
@@ -276,7 +312,7 @@ private theorem Internal.forIn'_eq_forIn'_iter [UpwardEnumerable α]
|
||||
ForIn'.forIn' (Internal.iter r) init (fun a ha acc => f a (Internal.isPlausibleIndirectOutput_iter_iff.mp ha) acc) := by
|
||||
rfl
|
||||
|
||||
theorem forIn'_eq_forIn'_toList [UpwardEnumerable α]
|
||||
public theorem forIn'_eq_forIn'_toList [UpwardEnumerable α]
|
||||
[SupportsUpperBound su α] [SupportsLowerBound sl α] [HasFiniteRanges su α]
|
||||
[BoundedUpwardEnumerable sl α] [LawfulUpwardEnumerable α]
|
||||
[LawfulUpwardEnumerableLowerBound sl α] [LawfulUpwardEnumerableUpperBound su α]
|
||||
@@ -288,7 +324,7 @@ theorem forIn'_eq_forIn'_toList [UpwardEnumerable α]
|
||||
simp [Internal.forIn'_eq_forIn'_iter, Internal.toList_eq_toList_iter,
|
||||
Iter.forIn'_eq_forIn'_toList]
|
||||
|
||||
theorem forIn'_toList_eq_forIn' [UpwardEnumerable α]
|
||||
public theorem forIn'_toList_eq_forIn' [UpwardEnumerable α]
|
||||
[SupportsUpperBound su α] [SupportsLowerBound sl α] [HasFiniteRanges su α]
|
||||
[BoundedUpwardEnumerable sl α] [LawfulUpwardEnumerable α]
|
||||
[LawfulUpwardEnumerableLowerBound sl α] [LawfulUpwardEnumerableUpperBound su α]
|
||||
@@ -299,7 +335,7 @@ theorem forIn'_toList_eq_forIn' [UpwardEnumerable α]
|
||||
ForIn'.forIn' r init (fun a ha acc => f a (mem_toList_iff_mem.mpr ha) acc) := by
|
||||
simp [forIn'_eq_forIn'_toList]
|
||||
|
||||
theorem mem_of_mem_open [UpwardEnumerable α]
|
||||
public theorem mem_of_mem_open [UpwardEnumerable α]
|
||||
[SupportsUpperBound su α] [SupportsLowerBound sl α] [HasFiniteRanges su α]
|
||||
[BoundedUpwardEnumerable sl α] [LawfulUpwardEnumerable α]
|
||||
[LawfulUpwardEnumerableLowerBound sl α] [LawfulUpwardEnumerableUpperBound su α]
|
||||
@@ -310,22 +346,21 @@ theorem mem_of_mem_open [UpwardEnumerable α]
|
||||
a ∈ r := by
|
||||
refine ⟨?_, hmem.2⟩
|
||||
have := hmem.1
|
||||
simp only [LawfulUpwardEnumerableLowerBound.isSatisfied_iff,
|
||||
BoundedUpwardEnumerable.init?] at this hrb ⊢
|
||||
simp only [LawfulUpwardEnumerableLowerBound.isSatisfied_iff, init?] at this hrb ⊢
|
||||
obtain ⟨init, hi⟩ := hrb
|
||||
obtain ⟨b', hb'⟩ := this
|
||||
refine ⟨init, hi.1, UpwardEnumerable.le_trans hi.2 (UpwardEnumerable.le_trans ?_ hb'.2)⟩
|
||||
exact UpwardEnumerable.le_of_succ?_eq hb'.1
|
||||
|
||||
theorem SupportsLowerBound.isSatisfied_init? {sl} [UpwardEnumerable α]
|
||||
public theorem SupportsLowerBound.isSatisfied_init? {sl} [UpwardEnumerable α]
|
||||
[SupportsLowerBound sl α] [BoundedUpwardEnumerable sl α] [LawfulUpwardEnumerable α]
|
||||
[LawfulUpwardEnumerableLowerBound sl α]
|
||||
{bound : Bound sl α} {a : α} (h : BoundedUpwardEnumerable.init? bound = some a) :
|
||||
{bound : Bound sl α} {a : α} (h : init? bound = some a) :
|
||||
SupportsLowerBound.IsSatisfied bound a := by
|
||||
simp only [LawfulUpwardEnumerableLowerBound.isSatisfied_iff]
|
||||
exact ⟨a, h, UpwardEnumerable.le_refl _⟩
|
||||
|
||||
theorem forIn'_eq_match {sl su} [UpwardEnumerable α]
|
||||
public theorem forIn'_eq_match {sl su} [UpwardEnumerable α]
|
||||
[SupportsUpperBound su α] [SupportsLowerBound sl α] [HasFiniteRanges su α]
|
||||
[BoundedUpwardEnumerable sl α] [LawfulUpwardEnumerable α]
|
||||
[LawfulUpwardEnumerableLowerBound sl α] [LawfulUpwardEnumerableUpperBound su α]
|
||||
@@ -333,7 +368,7 @@ theorem forIn'_eq_match {sl su} [UpwardEnumerable α]
|
||||
{r : PRange ⟨sl, su⟩ α}
|
||||
{γ : Type u} {init : γ} {m : Type u → Type w} [Monad m] [LawfulMonad m]
|
||||
{f : (a : α) → _ → γ → m (ForInStep γ)} :
|
||||
ForIn'.forIn' r init f = match hi : BoundedUpwardEnumerable.init? r.lower with
|
||||
ForIn'.forIn' r init f = match hi : init? r.lower with
|
||||
| none => pure init
|
||||
| some a => if hu : SupportsUpperBound.IsSatisfied r.upper a then do
|
||||
match ← f a ⟨SupportsLowerBound.isSatisfied_init? hi, hu⟩ init with
|
||||
@@ -358,7 +393,7 @@ theorem forIn'_eq_match {sl su} [UpwardEnumerable α]
|
||||
· simp
|
||||
· simp
|
||||
|
||||
instance {su} [UpwardEnumerable α] [SupportsUpperBound su α] [RangeSize su α]
|
||||
public instance {su} [UpwardEnumerable α] [SupportsUpperBound su α] [RangeSize su α]
|
||||
[LawfulUpwardEnumerable α] [HasFiniteRanges su α] [LawfulRangeSize su α] :
|
||||
LawfulIteratorSize (RangeIterator su α) where
|
||||
size_eq_size_toArray {it} := by
|
||||
@@ -376,7 +411,7 @@ instance {su} [UpwardEnumerable α] [SupportsUpperBound su α] [RangeSize su α]
|
||||
cases hn : UpwardEnumerable.succ? next
|
||||
· have := LawfulRangeSize.size_eq_one_of_succ?_eq_none _ _ h hn
|
||||
simp [*] at this
|
||||
· have := LawfulRangeSize.size_eq_succ_of_succ?_eq_some _ _ h hn
|
||||
· have := LawfulRangeSize.size_eq_succ_of_succ?_eq_some _ _ _ h hn
|
||||
simp [*] at this
|
||||
· simp [h]
|
||||
· rename_i ih
|
||||
@@ -389,14 +424,14 @@ instance {su} [UpwardEnumerable α] [SupportsUpperBound su α] [RangeSize su α]
|
||||
simp only [RangeIterator.step, Array.size_empty]
|
||||
simp_all [LawfulRangeSize.size_eq_one_of_succ?_eq_none _ _ h' hn]
|
||||
· rename_i next'
|
||||
have := LawfulRangeSize.size_eq_succ_of_succ?_eq_some _ _ h' hn
|
||||
have := LawfulRangeSize.size_eq_succ_of_succ?_eq_some _ _ _ h' hn
|
||||
simp only [this, Nat.add_right_cancel_iff] at h
|
||||
specialize ih (it := ⟨⟨some next', it.internalState.upperBound⟩⟩) next' rfl h
|
||||
rw [ih, Nat.add_comm]
|
||||
· have := LawfulRangeSize.size_eq_zero_of_not_satisfied _ _ h'
|
||||
· have := LawfulRangeSize.size_eq_zero_of_not_isSatisfied _ _ h'
|
||||
simp [*] at this
|
||||
|
||||
theorem isEmpty_iff_forall_not_mem {sl su} [UpwardEnumerable α] [LawfulUpwardEnumerable α]
|
||||
public theorem isEmpty_iff_forall_not_mem {sl su} [UpwardEnumerable α] [LawfulUpwardEnumerable α]
|
||||
[BoundedUpwardEnumerable sl α] [SupportsLowerBound sl α] [SupportsUpperBound su α]
|
||||
[LawfulUpwardEnumerableLowerBound sl α] [LawfulUpwardEnumerableUpperBound su α]
|
||||
{r : PRange ⟨sl, su⟩ α} :
|
||||
@@ -418,6 +453,6 @@ theorem isEmpty_iff_forall_not_mem {sl su} [UpwardEnumerable α] [LawfulUpwardEn
|
||||
intro hu
|
||||
have hl := SupportsLowerBound.isSatisfied_init? (bound := r.lower)
|
||||
(Option.some_get hi).symm
|
||||
exact h ((BoundedUpwardEnumerable.init? r.lower).get hi) ⟨hl, hu⟩
|
||||
exact h ((init? r.lower).get hi) ⟨hl, hu⟩
|
||||
|
||||
end Std.PRange
|
||||
|
||||
@@ -6,8 +6,11 @@ Authors: Paul Reichert
|
||||
module
|
||||
|
||||
prelude
|
||||
public import Init.Data.Nat.Lemmas
|
||||
public import Init.Data.Range.Polymorphic.Basic
|
||||
import Init.Data.Nat.Lemmas
|
||||
public import Init.Data.Nat.Order
|
||||
public import Init.Data.Range.Polymorphic.Instances
|
||||
public import Init.Data.Order.Classes
|
||||
import Init.Data.Order.Lemmas
|
||||
|
||||
public section
|
||||
|
||||
@@ -20,6 +23,10 @@ instance : UpwardEnumerable Nat where
|
||||
instance : Least? Nat where
|
||||
least? := some 0
|
||||
|
||||
instance : LawfulUpwardEnumerableLeast? Nat where
|
||||
least?_le a := by
|
||||
simpa [Least?.least?] using ⟨a, by simp [UpwardEnumerable.succMany?]⟩
|
||||
|
||||
instance : LawfulUpwardEnumerableLE Nat where
|
||||
le_iff a b := by
|
||||
constructor
|
||||
@@ -30,101 +37,32 @@ instance : LawfulUpwardEnumerableLE Nat where
|
||||
rw [← hn]
|
||||
exact Nat.le_add_right _ _
|
||||
|
||||
instance : LawfulUpwardEnumerableLT Nat where
|
||||
lt_iff a b := by
|
||||
constructor
|
||||
· intro h
|
||||
refine ⟨b - a - 1, ?_⟩
|
||||
simp [UpwardEnumerable.succMany?]
|
||||
rw [Nat.sub_add_cancel, Nat.add_sub_cancel']
|
||||
· exact Nat.le_of_lt h
|
||||
· rwa [Nat.lt_iff_add_one_le, ← Nat.le_sub_iff_add_le'] at h
|
||||
exact Nat.le_trans (Nat.le_succ _) h
|
||||
· rintro ⟨n, hn⟩
|
||||
simp only [UpwardEnumerable.succMany?, Option.some.injEq] at hn
|
||||
rw [← hn]
|
||||
apply Nat.lt_add_of_pos_right
|
||||
apply Nat.zero_lt_succ
|
||||
|
||||
instance : LawfulUpwardEnumerable Nat where
|
||||
succMany?_zero := by simp [UpwardEnumerable.succMany?]
|
||||
succMany?_succ := by simp [UpwardEnumerable.succMany?, UpwardEnumerable.succ?, Nat.add_assoc]
|
||||
ne_of_lt a b hlt := by
|
||||
rw [← LawfulUpwardEnumerableLT.lt_iff] at hlt
|
||||
exact Nat.ne_of_lt hlt
|
||||
have hn := hlt.choose_spec
|
||||
simp only [UpwardEnumerable.succMany?, Option.some.injEq] at hn
|
||||
omega
|
||||
|
||||
instance : LawfulUpwardEnumerableLowerBound .closed Nat where
|
||||
isSatisfied_iff a l := by
|
||||
simp [← LawfulUpwardEnumerableLE.le_iff, BoundedUpwardEnumerable.init?,
|
||||
SupportsLowerBound.IsSatisfied]
|
||||
|
||||
instance : LawfulUpwardEnumerableUpperBound .closed Nat where
|
||||
isSatisfied_of_le u a b hub hab := by
|
||||
rw [← LawfulUpwardEnumerableLE.le_iff] at hab
|
||||
exact Nat.le_trans hab hub
|
||||
|
||||
instance : LawfulUpwardEnumerableLowerBound .open Nat where
|
||||
isSatisfied_iff a l := by
|
||||
simp [← LawfulUpwardEnumerableLE.le_iff, BoundedUpwardEnumerable.init?,
|
||||
SupportsLowerBound.IsSatisfied, UpwardEnumerable.succ?, Nat.lt_iff_add_one_le]
|
||||
|
||||
instance : LawfulUpwardEnumerableUpperBound .open Nat where
|
||||
isSatisfied_of_le u a b hub hab := by
|
||||
rw [← LawfulUpwardEnumerableLE.le_iff] at hab
|
||||
exact Nat.lt_of_le_of_lt hab hub
|
||||
|
||||
instance : LawfulUpwardEnumerableLowerBound .unbounded Nat where
|
||||
isSatisfied_iff a l := by
|
||||
simp [← LawfulUpwardEnumerableLE.le_iff, BoundedUpwardEnumerable.init?,
|
||||
SupportsLowerBound.IsSatisfied, Least?.least?]
|
||||
|
||||
instance : LawfulUpwardEnumerableUpperBound .unbounded Nat where
|
||||
isSatisfied_of_le _ _ _ _ _ := .intro
|
||||
|
||||
instance : LinearlyUpwardEnumerable Nat where
|
||||
eq_of_succ?_eq a b := by simp [UpwardEnumerable.succ?]
|
||||
instance : LawfulUpwardEnumerableLT Nat := inferInstance
|
||||
instance : LawfulUpwardEnumerableLowerBound .closed Nat := inferInstance
|
||||
instance : LawfulUpwardEnumerableUpperBound .closed Nat := inferInstance
|
||||
instance : LawfulUpwardEnumerableLowerBound .open Nat := inferInstance
|
||||
instance : LawfulUpwardEnumerableUpperBound .open Nat := inferInstance
|
||||
instance : LawfulUpwardEnumerableLowerBound .unbounded Nat := inferInstance
|
||||
instance : LawfulUpwardEnumerableUpperBound .unbounded Nat := inferInstance
|
||||
|
||||
instance : InfinitelyUpwardEnumerable Nat where
|
||||
isSome_succ? a := by simp [UpwardEnumerable.succ?]
|
||||
|
||||
private def rangeRev (k : Nat) :=
|
||||
match k with
|
||||
| 0 => []
|
||||
| k + 1 => k :: rangeRev k
|
||||
|
||||
private theorem mem_rangeRev {k l : Nat} (h : l < k) : l ∈ rangeRev k := by
|
||||
induction k
|
||||
case zero => cases h
|
||||
case succ k ih =>
|
||||
rw [rangeRev]
|
||||
by_cases hl : l = k
|
||||
· simp [hl]
|
||||
· apply List.mem_cons_of_mem
|
||||
exact ih (Nat.lt_of_le_of_ne (Nat.le_of_lt_succ h) hl)
|
||||
|
||||
@[no_expose]
|
||||
instance : HasFiniteRanges .closed Nat where
|
||||
mem_of_satisfiesUpperBound upperBound := by
|
||||
refine ⟨rangeRev (upperBound + 1), fun a h => ?_⟩
|
||||
simp only [SupportsUpperBound.IsSatisfied] at h
|
||||
exact mem_rangeRev (Nat.lt_succ_of_le h)
|
||||
|
||||
@[no_expose]
|
||||
instance : HasFiniteRanges .open Nat where
|
||||
mem_of_satisfiesUpperBound upperBound := by
|
||||
refine ⟨rangeRev (upperBound + 1), fun a h => ?_⟩
|
||||
simp only [SupportsUpperBound.IsSatisfied] at h
|
||||
apply mem_rangeRev
|
||||
exact Nat.lt_succ_of_lt h
|
||||
|
||||
instance : RangeSize .closed Nat where
|
||||
size bound a := bound + 1 - a
|
||||
|
||||
instance : RangeSize .open Nat where
|
||||
size bound a := bound - a
|
||||
instance : RangeSize .open Nat := .openOfClosed
|
||||
|
||||
instance : LawfulRangeSize .closed Nat where
|
||||
size_eq_zero_of_not_satisfied upperBound init hu := by
|
||||
size_eq_zero_of_not_isSatisfied upperBound init hu := by
|
||||
simp only [SupportsUpperBound.IsSatisfied, RangeSize.size] at hu ⊢
|
||||
omega
|
||||
size_eq_one_of_succ?_eq_none upperBound init hu h := by
|
||||
@@ -135,17 +73,16 @@ instance : LawfulRangeSize .closed Nat where
|
||||
Option.some.injEq] at hu h ⊢
|
||||
omega
|
||||
|
||||
instance : LawfulRangeSize .open Nat where
|
||||
size_eq_zero_of_not_satisfied upperBound init hu := by
|
||||
simp only [SupportsUpperBound.IsSatisfied, RangeSize.size] at hu ⊢
|
||||
omega
|
||||
size_eq_one_of_succ?_eq_none upperBound init hu h := by
|
||||
simp only [UpwardEnumerable.succ?] at h
|
||||
cases h
|
||||
size_eq_succ_of_succ?_eq_some upperBound init hu h := by
|
||||
simp only [SupportsUpperBound.IsSatisfied, RangeSize.size, UpwardEnumerable.succ?,
|
||||
Option.some.injEq] at hu h ⊢
|
||||
omega
|
||||
instance : LawfulRangeSize .open Nat := inferInstance
|
||||
instance : HasFiniteRanges .closed Nat := inferInstance
|
||||
instance : HasFiniteRanges .open Nat := inferInstance
|
||||
instance : LinearlyUpwardEnumerable Nat := by
|
||||
exact instLinearlyUpwardEnumerableOfTotalLeOfLawfulUpwardEnumerableOfLawfulUpwardEnumerableLE
|
||||
|
||||
/-!
|
||||
The following instances are used for the implementation of array slices a.k.a. `Subarray`.
|
||||
See also `Init.Data.Slice.Array`.
|
||||
-/
|
||||
|
||||
instance : ClosedOpenIntersection ⟨.open, .open⟩ Nat where
|
||||
intersection r s := PRange.mk (max (r.lower + 1) s.lower) (min r.upper s.upper)
|
||||
|
||||
@@ -13,13 +13,16 @@ public section
|
||||
|
||||
namespace Std.PRange.Nat
|
||||
|
||||
theorem succ_eq {n : Nat} : UpwardEnumerable.succ n = n + 1 :=
|
||||
theorem succ_eq {n : Nat} : succ n = n + 1 :=
|
||||
rfl
|
||||
|
||||
theorem ClosedOpen.toList_succ_succ {m n : Nat} :
|
||||
((m+1)...(n+1)).toList =
|
||||
(m...n).toList.map (· + 1) := by
|
||||
theorem toList_Rco_succ_succ {m n : Nat} :
|
||||
((m+1)...(n+1)).toList = (m...n).toList.map (· + 1) := by
|
||||
simp only [← succ_eq]
|
||||
rw [Std.PRange.ClosedOpen.toList_succ_succ_eq_map]
|
||||
rw [Std.PRange.toList_Rco_succ_succ_eq_map]
|
||||
|
||||
@[deprecated toList_Rco_succ_succ (since := "2025-08-22")]
|
||||
theorem ClosedOpen.toList_succ_succ {m n : Nat} :
|
||||
((m+1)...(n+1)).toList = (m...n).toList.map (· + 1) := toList_Rco_succ_succ
|
||||
|
||||
end Std.PRange.Nat
|
||||
|
||||
@@ -53,14 +53,16 @@ A range of elements of some type `α`. It is characterized by its upper and lowe
|
||||
may be inclusive, exclusive or absent.
|
||||
|
||||
* `a...=b` is the range of elements greater than or equal to `a` and less than or equal to `b`.
|
||||
* `a<...=b` is the range of elements greater than `a` and less than or equal to `b`.
|
||||
* `a...b` or `a...<b` is the range of elements greater than or equal to `a` and less than `b`.
|
||||
* `a...*` is the range of elements greater than or equal to `a`.
|
||||
* `a<...=b` is the range of elements greater than `a` and less than or equal to `b`.
|
||||
* `a<...b` or `a<...<b` is the range of elements greater than `a` and less than `b`.
|
||||
* `a<...*` is the range of elements greater than `a`.
|
||||
* `*...=b` is the range of elements less than or equal to `b`.
|
||||
* `*...b` or `*...<b` is the range of elements less than `b`.
|
||||
* `a...*` is the range of elements greater than or equal to `a`.
|
||||
* `a<...*` is the range of elements greater than `a`.
|
||||
* `*...*` contains all elements of `α`.
|
||||
|
||||
The recommended spelling for these ranges can be found in the `PRange.mk` constructor's docstring.
|
||||
-/
|
||||
structure _root_.Std.PRange (shape : RangeShape) (α : Type u) where
|
||||
/-- The lower bound of the range. -/
|
||||
@@ -68,6 +70,14 @@ structure _root_.Std.PRange (shape : RangeShape) (α : Type u) where
|
||||
/-- The upper bound of the range. -/
|
||||
upper : Bound shape.upper α
|
||||
|
||||
/--
|
||||
Creates a new range. For more information about ranges, see `Std.PRange`.
|
||||
|
||||
The implicit `shape` parameter specifies the shape of the explicitly given
|
||||
lower and upper bounds.
|
||||
-/
|
||||
add_decl_doc _root_.Std.PRange.mk
|
||||
|
||||
/-- `a...*` is the range of elements greater than or equal to `a`. See also `Std.PRange`. -/
|
||||
syntax:max (term "...*") : term
|
||||
/-- `*...*` is the range that is unbounded in both directions. See also `Std.PRange`. -/
|
||||
@@ -125,6 +135,27 @@ macro_rules
|
||||
| `($a<...<$b) => ``(PRange.mk (shape := RangeShape.mk BoundShape.open BoundShape.open) $a $b)
|
||||
| `($a<...$b) => ``(PRange.mk (shape := RangeShape.mk BoundShape.open BoundShape.open) $a $b)
|
||||
|
||||
recommended_spelling "Rcc" for "a...=b" in [PRange.mk, «term_...=_»]
|
||||
recommended_spelling "Rco" for "a...b" in [PRange.mk, «term_..._», «term_...<_»]
|
||||
recommended_spelling "Rco" for "a...<b" in [«term_...<_»]
|
||||
recommended_spelling "Rci" for "a...*" in [PRange.mk, «term_...*»]
|
||||
recommended_spelling "Roc" for "a<...=b" in [PRange.mk, «term_<...=_»]
|
||||
recommended_spelling "Roo" for "a<...b" in [PRange.mk, «term_<..._», «term_<...<_»]
|
||||
recommended_spelling "Roo" for "a<...<b" in [«term_<...<_»]
|
||||
recommended_spelling "Roi" for "a<...*" in [PRange.mk, «term_<...*»]
|
||||
recommended_spelling "Ric" for "*...=b" in [PRange.mk, «term*...=_»]
|
||||
recommended_spelling "Rio" for "*...b" in [PRange.mk, «term*..._», «term*...<_»]
|
||||
recommended_spelling "Rio" for "*...<b" in [«term*...<_»]
|
||||
recommended_spelling "Rii" for "*...*" in [PRange.mk, «term*...*»]
|
||||
|
||||
recommended_spelling "Rcx" for "PRange.mk .closed ub" in [PRange.mk]
|
||||
recommended_spelling "Rox" for "PRange.mk .open ub" in [PRange.mk]
|
||||
recommended_spelling "Rix" for "PRange.mk .unbounded ub" in [PRange.mk]
|
||||
recommended_spelling "Rxc" for "PRange.mk lb .closed" in [PRange.mk]
|
||||
recommended_spelling "Rxo" for "PRange.mk lb .open" in [PRange.mk]
|
||||
recommended_spelling "Rxi" for "PRange.mk lb .unbounded" in [PRange.mk]
|
||||
recommended_spelling "Rxx" for "PRange.mk lb ub" in [PRange.mk]
|
||||
|
||||
/--
|
||||
This typeclass provides decidable lower bound checks of the given shape.
|
||||
|
||||
@@ -138,6 +169,8 @@ class SupportsLowerBound (shape : BoundShape) (α : Type u) where
|
||||
IsSatisfied : Bound shape α → α → Prop
|
||||
decidableSatisfiesLowerBound : DecidableRel IsSatisfied := by infer_instance
|
||||
|
||||
attribute [simp] SupportsLowerBound.IsSatisfied
|
||||
|
||||
instance : SupportsLowerBound .unbounded α where
|
||||
IsSatisfied _ _ := True
|
||||
|
||||
@@ -154,6 +187,8 @@ class SupportsUpperBound (shape : BoundShape) (α : Type u) where
|
||||
IsSatisfied : Bound shape α → α → Prop
|
||||
decidableSatisfiesUpperBound : DecidableRel IsSatisfied := by infer_instance
|
||||
|
||||
attribute [simp] SupportsUpperBound.IsSatisfied
|
||||
|
||||
instance {α} : SupportsUpperBound .unbounded α where
|
||||
IsSatisfied _ _ := True
|
||||
|
||||
@@ -175,9 +210,9 @@ instance {sl su α a} [SupportsLowerBound sl α] [SupportsUpperBound su α] (r :
|
||||
This typeclass ensures that ranges with the given shape of upper bounds are always finite.
|
||||
This is a prerequisite for many functions and instances, such as `PRange.toList` or `ForIn'`.
|
||||
-/
|
||||
class HasFiniteRanges (shape α) [SupportsUpperBound shape α] : Prop where
|
||||
mem_of_satisfiesUpperBound (u : Bound shape α) :
|
||||
∃ enumeration : List α, (a : α) → SupportsUpperBound.IsSatisfied u a → a ∈ enumeration
|
||||
class HasFiniteRanges (shape α) [UpwardEnumerable α] [SupportsUpperBound shape α] : Prop where
|
||||
finite (init : α) (u : Bound shape α) :
|
||||
∃ n, (UpwardEnumerable.succMany? n init).elim True (¬ SupportsUpperBound.IsSatisfied u ·)
|
||||
|
||||
/--
|
||||
This typeclass will usually be used together with `UpwardEnumerable α`. It provides the starting
|
||||
@@ -192,6 +227,9 @@ Instances are automatically generated in the following cases:
|
||||
class BoundedUpwardEnumerable (lowerBoundShape : BoundShape) (α : Type u) where
|
||||
init? : Bound lowerBoundShape α → Option α
|
||||
|
||||
attribute [simp] BoundedUpwardEnumerable.init?
|
||||
export BoundedUpwardEnumerable (init?)
|
||||
|
||||
/--
|
||||
This typeclass ensures that the lower bound predicate from `SupportsLowerBound sl α`
|
||||
can be characterized in terms of `UpwardEnumerable α` and `BoundedUpwardEnumerable sl α`.
|
||||
@@ -200,11 +238,10 @@ class LawfulUpwardEnumerableLowerBound (sl α) [UpwardEnumerable α]
|
||||
[SupportsLowerBound sl α] [BoundedUpwardEnumerable sl α] where
|
||||
/--
|
||||
An element `a` satisfies the lower bound `l` if and only if it is
|
||||
`BoundedUpwardEnumerable.init? l` or one of its transitive successors.
|
||||
`init? l` or one of its transitive successors.
|
||||
-/
|
||||
isSatisfied_iff (a : α) (l : Bound sl α) :
|
||||
SupportsLowerBound.IsSatisfied l a ↔
|
||||
∃ init, BoundedUpwardEnumerable.init? l = some init ∧ UpwardEnumerable.LE init a
|
||||
SupportsLowerBound.IsSatisfied l a ↔ ∃ init, init? l = some init ∧ UpwardEnumerable.LE init a
|
||||
|
||||
/--
|
||||
This typeclass ensures that if `b` is a transitive successor of `a` and `b` satisfies an upper bound
|
||||
|
||||
@@ -232,36 +232,49 @@ private def List.length_filter_strict_mono {l : List α} {P Q : α → Bool} {a
|
||||
private def RangeIterator.instFinitenessRelation [UpwardEnumerable α] [SupportsUpperBound su α]
|
||||
[LawfulUpwardEnumerable α] [HasFiniteRanges su α] :
|
||||
FinitenessRelation (RangeIterator su α) Id where
|
||||
rel :=
|
||||
open Classical in
|
||||
InvImage WellFoundedRelation.rel
|
||||
(fun it => (HasFiniteRanges.mem_of_satisfiesUpperBound it.internalState.upperBound).choose
|
||||
|>.filter (∃ a, it.internalState.next = some a ∧ UpwardEnumerable.LE a ·)
|
||||
|>.length)
|
||||
wf := InvImage.wf _ WellFoundedRelation.wf
|
||||
subrelation {it it'} h := by
|
||||
simp_wf
|
||||
rw [Monadic.isPlausibleSuccessorOf_iff] at h
|
||||
obtain ⟨a, hn, hu, hn', hu'⟩ := h
|
||||
rw [hu']
|
||||
apply List.length_filter_strict_mono (a := a)
|
||||
· intro u h
|
||||
simp only [decide_eq_true_eq] at ⊢ h
|
||||
obtain ⟨a', ha', hle⟩ := h
|
||||
refine ⟨a, hn, UpwardEnumerable.le_trans ⟨1, ?_⟩ hle⟩
|
||||
rw [ha'] at hn'
|
||||
rw [UpwardEnumerable.succMany?_succ, LawfulUpwardEnumerable.succMany?_zero,
|
||||
Option.bind_some, hn']
|
||||
· exact (HasFiniteRanges.mem_of_satisfiesUpperBound _).choose_spec _ hu
|
||||
· intro h
|
||||
simp only [decide_eq_true_eq] at h
|
||||
obtain ⟨x, hx, h⟩ := h
|
||||
rw [hx] at hn'
|
||||
have hlt : UpwardEnumerable.LT a x :=
|
||||
⟨0, by simp [UpwardEnumerable.succMany?_succ, UpwardEnumerable.succMany?_zero, hn']⟩
|
||||
exact UpwardEnumerable.not_gt_of_le h hlt
|
||||
· simp only [decide_eq_true_eq]
|
||||
exact ⟨a, hn, UpwardEnumerable.le_refl _⟩
|
||||
rel it' it := it'.IsPlausibleSuccessorOf it
|
||||
wf := by
|
||||
constructor
|
||||
intro it
|
||||
have hnone : ∀ bound, Acc (fun it' it : IterM (α := RangeIterator su α) Id α => it'.IsPlausibleSuccessorOf it)
|
||||
⟨⟨none, bound⟩⟩ := by
|
||||
intro bound
|
||||
constructor
|
||||
intro it' ⟨step, hs₁, hs₂⟩
|
||||
simp only [IterM.IsPlausibleStep, Iterator.IsPlausibleStep, Monadic.step] at hs₂
|
||||
simp [hs₂, IterStep.successor] at hs₁
|
||||
simp only [IterM.IsPlausibleSuccessorOf, IterM.IsPlausibleStep, Iterator.IsPlausibleStep,
|
||||
Monadic.step, exists_eq_right] at hnone ⊢
|
||||
match it with
|
||||
| ⟨⟨none, _⟩⟩ => apply hnone
|
||||
| ⟨⟨some init, bound⟩⟩ =>
|
||||
obtain ⟨n, hn⟩ := HasFiniteRanges.finite init bound
|
||||
induction n generalizing init with
|
||||
| zero =>
|
||||
simp only [succMany?_zero, Option.elim_some] at hn
|
||||
constructor
|
||||
simp [hn, IterStep.successor]
|
||||
| succ n ih =>
|
||||
constructor
|
||||
rintro it'
|
||||
simp only [succMany?_succ?_eq_succ?_bind_succMany?] at hn
|
||||
match hs : succ? init with
|
||||
| none =>
|
||||
simp only [hs]
|
||||
intro h
|
||||
split at h
|
||||
· cases h
|
||||
apply hnone
|
||||
· cases h
|
||||
| some a =>
|
||||
intro h
|
||||
simp only [hs] at h hn
|
||||
specialize ih _ hn
|
||||
split at h
|
||||
· cases h
|
||||
exact ih
|
||||
· cases h
|
||||
subrelation := id
|
||||
|
||||
@[no_expose]
|
||||
instance RangeIterator.instFinite {su} [UpwardEnumerable α] [SupportsUpperBound su α]
|
||||
@@ -303,7 +316,7 @@ instance RangeIterator.instIteratorAccess {su} [UpwardEnumerable α] [SupportsUp
|
||||
· split <;> rename_i heq
|
||||
· apply IterM.IsPlausibleNthOutputStep.done
|
||||
simp only [Monadic.isPlausibleStep_iff, Monadic.step]
|
||||
simp only [Option.bind_eq_none_iff, UpwardEnumerable.succMany?_zero, reduceCtorEq,
|
||||
simp only [Option.bind_eq_none_iff, succMany?_zero, reduceCtorEq,
|
||||
imp_false] at heq
|
||||
cases heq' : it.internalState.next
|
||||
· simp
|
||||
@@ -312,7 +325,7 @@ instance RangeIterator.instIteratorAccess {su} [UpwardEnumerable α] [SupportsUp
|
||||
exact heq _ rfl
|
||||
· cases heq' : it.internalState.next
|
||||
· simp [heq'] at heq
|
||||
simp only [heq', Option.bind_some, UpwardEnumerable.succMany?_zero, Option.some.injEq] at heq
|
||||
simp only [heq', Option.bind_some, succMany?_zero, Option.some.injEq] at heq
|
||||
cases heq
|
||||
split <;> rename_i heq''
|
||||
· apply IterM.IsPlausibleNthOutputStep.zero_yield
|
||||
@@ -325,7 +338,7 @@ instance RangeIterator.instIteratorAccess {su} [UpwardEnumerable α] [SupportsUp
|
||||
· apply IterM.IsPlausibleNthOutputStep.done
|
||||
simp only [Monadic.isPlausibleStep_iff, Monadic.step, heq']
|
||||
· rename_i out
|
||||
simp only [heq', Option.bind_some, LawfulUpwardEnumerable.succMany?_succ_eq_succ?_bind_succMany?] at heq
|
||||
simp only [heq', Option.bind_some, succMany?_succ?_eq_succ?_bind_succMany?] at heq
|
||||
specialize ih ⟨⟨UpwardEnumerable.succ? out, it.internalState.upperBound⟩⟩
|
||||
simp only [heq] at ih
|
||||
by_cases heq'' : SupportsUpperBound.IsSatisfied it.internalState.upperBound out
|
||||
@@ -341,7 +354,7 @@ instance RangeIterator.instIteratorAccess {su} [UpwardEnumerable α] [SupportsUp
|
||||
rename_i out
|
||||
simp only [heq', Option.bind_some] at heq
|
||||
have hle : UpwardEnumerable.LE out _ := ⟨n + 1, heq⟩
|
||||
simp only [LawfulUpwardEnumerable.succMany?_succ_eq_succ?_bind_succMany?] at heq
|
||||
simp only [succMany?_succ?_eq_succ?_bind_succMany?] at heq
|
||||
specialize ih ⟨⟨UpwardEnumerable.succ? out, it.internalState.upperBound⟩⟩
|
||||
simp only [heq] at ih
|
||||
by_cases hout : SupportsUpperBound.IsSatisfied it.internalState.upperBound out
|
||||
@@ -365,7 +378,7 @@ theorem RangeIterator.Monadic.isPlausibleIndirectOutput_iff {su α}
|
||||
[LawfulUpwardEnumerable α] [LawfulUpwardEnumerableUpperBound su α]
|
||||
{it : IterM (α := RangeIterator su α) Id α} {out : α} :
|
||||
it.IsPlausibleIndirectOutput out ↔
|
||||
∃ n, it.internalState.next.bind (UpwardEnumerable.succMany? n ·) = some out ∧
|
||||
∃ n, it.internalState.next.bind (succMany? n ·) = some out ∧
|
||||
SupportsUpperBound.IsSatisfied it.internalState.upperBound out := by
|
||||
constructor
|
||||
· intro h
|
||||
@@ -378,7 +391,7 @@ theorem RangeIterator.Monadic.isPlausibleIndirectOutput_iff {su α}
|
||||
obtain ⟨n, hn⟩ := ih
|
||||
obtain ⟨a, ha, h₁, h₂, h₃⟩ := h
|
||||
refine ⟨n + 1, ?_⟩
|
||||
simp [ha, ← h₃, hn.2, LawfulUpwardEnumerable.succMany?_succ_eq_succ?_bind_succMany?, h₂, hn]
|
||||
simp [ha, ← h₃, hn.2, succMany?_succ?_eq_succ?_bind_succMany?, h₂, hn]
|
||||
· rintro ⟨n, hn, hu⟩
|
||||
induction n generalizing it
|
||||
case zero =>
|
||||
@@ -391,8 +404,8 @@ theorem RangeIterator.Monadic.isPlausibleIndirectOutput_iff {su α}
|
||||
rename_i a
|
||||
simp only [hn', Option.bind_some] at hn
|
||||
have hle : UpwardEnumerable.LE a out := ⟨_, hn⟩
|
||||
rw [LawfulUpwardEnumerable.succMany?_succ_eq_succ?_bind_succMany?] at hn
|
||||
cases hn' : UpwardEnumerable.succ? a
|
||||
rw [succMany?_succ?_eq_succ?_bind_succMany?] at hn
|
||||
cases hn' : succ? a
|
||||
· simp only [hn', Option.bind_none, reduceCtorEq] at hn
|
||||
rename_i a'
|
||||
simp only [hn', Option.bind_some] at hn
|
||||
@@ -409,7 +422,7 @@ theorem RangeIterator.isPlausibleIndirectOutput_iff {su α}
|
||||
[LawfulUpwardEnumerable α] [LawfulUpwardEnumerableUpperBound su α]
|
||||
{it : Iter (α := RangeIterator su α) α} {out : α} :
|
||||
it.IsPlausibleIndirectOutput out ↔
|
||||
∃ n, it.internalState.next.bind (UpwardEnumerable.succMany? n ·) = some out ∧
|
||||
∃ n, it.internalState.next.bind (succMany? n ·) = some out ∧
|
||||
SupportsUpperBound.IsSatisfied it.internalState.upperBound out := by
|
||||
simp only [Iter.isPlausibleIndirectOutput_iff_isPlausibleIndirectOutput_toIterM,
|
||||
Monadic.isPlausibleIndirectOutput_iff, Iter.toIterM]
|
||||
@@ -463,7 +476,7 @@ instance RangeIterator.instIteratorLoop {su} [UpwardEnumerable α] [SupportsUppe
|
||||
exact UpwardEnumerable.le_refl _
|
||||
case hle' =>
|
||||
refine UpwardEnumerable.le_trans hl ⟨1, ?_⟩
|
||||
simp [UpwardEnumerable.succMany?_one, hs]
|
||||
simp [succMany?_one, hs]
|
||||
|
||||
partial instance RepeatIterator.instIteratorLoopPartial {su} [UpwardEnumerable α]
|
||||
[SupportsUpperBound su α] [LawfulUpwardEnumerable α] [LawfulUpwardEnumerableUpperBound su α]
|
||||
@@ -483,7 +496,7 @@ partial instance RepeatIterator.instIteratorLoopPartial {su} [UpwardEnumerable
|
||||
(next : α) (hl : UpwardEnumerable.LE least next) (hu : SupportsUpperBound.IsSatisfied upperBound next) : n γ := do
|
||||
match ← f next hl hu acc with
|
||||
| .yield acc' =>
|
||||
match hs : UpwardEnumerable.succ? next with
|
||||
match hs : succ? next with
|
||||
| some next' =>
|
||||
if hu : SupportsUpperBound.IsSatisfied upperBound next' then
|
||||
loop γ upperBound least acc' f next' ?hle' hu
|
||||
@@ -500,10 +513,10 @@ partial instance RepeatIterator.instIteratorLoopPartial {su} [UpwardEnumerable
|
||||
exact UpwardEnumerable.le_refl _
|
||||
case hle' =>
|
||||
refine UpwardEnumerable.le_trans hl ⟨1, ?_⟩
|
||||
simp [UpwardEnumerable.succMany?_one, hs]
|
||||
simp [succMany?_one, hs]
|
||||
|
||||
theorem RangeIterator.instIteratorLoop.loop_eq {su} [UpwardEnumerable α] [SupportsUpperBound su α]
|
||||
[LawfulUpwardEnumerable α] [LawfulUpwardEnumerableUpperBound su α]
|
||||
theorem RangeIterator.instIteratorLoop.loop_eq {su} [UpwardEnumerable α]
|
||||
[SupportsUpperBound su α] [LawfulUpwardEnumerable α] [LawfulUpwardEnumerableUpperBound su α]
|
||||
{n : Type u → Type w} [Monad n] [LawfulMonad n] {γ : Type u}
|
||||
{lift} [Internal.LawfulMonadLiftBindFunction lift]
|
||||
{PlausibleForInStep} {upperBound} {next} {hl} {hu} {f} {acc} {wf} :
|
||||
@@ -511,16 +524,18 @@ theorem RangeIterator.instIteratorLoop.loop_eq {su} [UpwardEnumerable α] [Suppo
|
||||
(do
|
||||
match ← f next hl hu acc with
|
||||
| ⟨.yield c, _⟩ =>
|
||||
letI it' : IterM (α := RangeIterator su α) Id α := ⟨⟨UpwardEnumerable.succ? next, upperBound⟩⟩
|
||||
letI it' : IterM (α := RangeIterator su α) Id α := ⟨⟨succ? next, upperBound⟩⟩
|
||||
IterM.DefaultConsumers.forIn' (m := Id) lift γ
|
||||
PlausibleForInStep wf it' c it'.IsPlausibleIndirectOutput (fun _ => id)
|
||||
(fun b h c => f b
|
||||
(by
|
||||
refine UpwardEnumerable.le_trans hl ?_
|
||||
simp only [RangeIterator.Monadic.isPlausibleIndirectOutput_iff, it',
|
||||
← LawfulUpwardEnumerable.succMany?_succ_eq_succ?_bind_succMany?] at h
|
||||
← succMany?_succ?_eq_succ?_bind_succMany?] at h
|
||||
exact ⟨h.choose + 1, h.choose_spec.1⟩)
|
||||
(by simp only [RangeIterator.Monadic.isPlausibleIndirectOutput_iff, it'] at h; exact h.choose_spec.2) c)
|
||||
(by
|
||||
simp only [RangeIterator.Monadic.isPlausibleIndirectOutput_iff, it'] at h
|
||||
exact h.choose_spec.2) c)
|
||||
| ⟨.done c, _⟩ => return c) := by
|
||||
rw [loop]
|
||||
apply bind_congr
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user