Compare commits

..

7 Commits

Author SHA1 Message Date
Leonardo de Moura
31cd6bac1b chore: update comments 2025-10-22 17:43:09 -07:00
Leonardo de Moura
e5c6459887 chore: add checkSystem 2025-10-22 17:34:16 -07:00
Leonardo de Moura
acedf24747 chore: missing file 2025-10-22 17:24:43 -07:00
Leonardo de Moura
12df6ce4a3 feat: use parameter optimizer at finish? 2025-10-22 17:23:49 -07:00
Leonardo de Moura
73f6c29d8b chore: 2025-10-22 16:30:03 -07:00
Leonardo de Moura
a93800ac19 chore: move 2025-10-22 16:30:03 -07:00
Leonardo de Moura
5642496dbe feat: simple parameter minimizer 2025-10-22 16:30:03 -07:00
3315 changed files with 17084 additions and 56909 deletions

View File

@@ -1,34 +0,0 @@
To build Lean you should use `make -j -C build/release`.
To run a test you should use `cd tests/lean/run && ./test_single.sh example_test.lean`.
## New features
When asked to implement new features:
* begin by reviewing existing relevant code and tests
* write comprehensive tests first (expecting that these will initially fail)
* and then iterate on the implementation until the tests pass.
All new tests should go in `tests/lean/run/`. These tests don't have expected output; we just check there are no errors. You should use `#guard_msgs` to check for specific messages.
## Success Criteria
*Never* report success on a task unless you have verified both a clean build without errors, and that the relevant tests pass.
## Build System Safety
**NEVER manually delete build directories** (build/, stage0/, stage1/, etc.) even when builds fail.
- ONLY use the project's documented build command: `make -j -C build/release`
- If a build is broken, ask the user before attempting any manual cleanup
## LSP and IDE Diagnostics
After rebuilding, LSP diagnostics may be stale until the user interacts with files. Trust command-line test results over IDE diagnostics.
## Update prompting when the user is frustrated
If the user expresses frustration with you, stop and ask them to help update this `.claude/CLAUDE.md` file with missing guidance.
## Creating pull requests.
All PRs must have a first paragraph starting with "This PR". This paragraph is automatically incorporated into release notes. Read `lean4/doc/dev/commit_convention.md` when making PRs.

View File

@@ -213,7 +213,7 @@ jobs:
else
${{ matrix.tar || 'tar' }} cf - $dir | zstd -T0 --no-progress -o pack/$dir.tar.zst
fi
- uses: actions/upload-artifact@v5
- uses: actions/upload-artifact@v4
if: matrix.release
with:
name: build-${{ matrix.name }}

View File

@@ -106,54 +106,9 @@ jobs:
TAG_NAME="${GITHUB_REF##*/}"
echo "RELEASE_TAG=$TAG_NAME" >> "$GITHUB_OUTPUT"
- name: Validate CMakeLists.txt version matches tag
if: steps.set-release.outputs.RELEASE_TAG != ''
run: |
echo "Validating CMakeLists.txt version matches tag ${{ steps.set-release.outputs.RELEASE_TAG }}"
# Extract version values from CMakeLists.txt
CMAKE_MAJOR=$(grep -E "^set\(LEAN_VERSION_MAJOR " src/CMakeLists.txt | grep -oE '[0-9]+')
CMAKE_MINOR=$(grep -E "^set\(LEAN_VERSION_MINOR " src/CMakeLists.txt | grep -oE '[0-9]+')
CMAKE_PATCH=$(grep -E "^set\(LEAN_VERSION_PATCH " src/CMakeLists.txt | grep -oE '[0-9]+')
CMAKE_IS_RELEASE=$(grep -E "^set\(LEAN_VERSION_IS_RELEASE " src/CMakeLists.txt | grep -oE '[0-9]+')
# Expected values from tag parsing
TAG_MAJOR="${{ steps.set-release.outputs.LEAN_VERSION_MAJOR }}"
TAG_MINOR="${{ steps.set-release.outputs.LEAN_VERSION_MINOR }}"
TAG_PATCH="${{ steps.set-release.outputs.LEAN_VERSION_PATCH }}"
ERRORS=""
if [[ "$CMAKE_MAJOR" != "$TAG_MAJOR" ]]; then
ERRORS+="LEAN_VERSION_MAJOR: expected $TAG_MAJOR, found $CMAKE_MAJOR\n"
fi
if [[ "$CMAKE_MINOR" != "$TAG_MINOR" ]]; then
ERRORS+="LEAN_VERSION_MINOR: expected $TAG_MINOR, found $CMAKE_MINOR\n"
fi
if [[ "$CMAKE_PATCH" != "$TAG_PATCH" ]]; then
ERRORS+="LEAN_VERSION_PATCH: expected $TAG_PATCH, found $CMAKE_PATCH\n"
fi
if [[ "$CMAKE_IS_RELEASE" != "1" ]]; then
ERRORS+="LEAN_VERSION_IS_RELEASE: expected 1, found $CMAKE_IS_RELEASE\n"
fi
if [[ -n "$ERRORS" ]]; then
echo "::error::Version mismatch between tag and src/CMakeLists.txt"
echo ""
echo "Tag ${{ steps.set-release.outputs.RELEASE_TAG }} expects version $TAG_MAJOR.$TAG_MINOR.$TAG_PATCH"
echo "But src/CMakeLists.txt has mismatched values:"
echo -e "$ERRORS"
echo ""
echo "Fix src/CMakeLists.txt, delete the tag, and re-tag."
exit 1
fi
echo "Version validation passed: $TAG_MAJOR.$TAG_MINOR.$TAG_PATCH"
# 0: PRs without special label
# 1: PRs with `merge-ci` label, merge queue checks, master commits
# 2: nightlies
# 3: PRs with `release-ci` label, full releases
# 2: PRs with `release-ci` label, releases (incl. nightlies)
- name: Set check level
id: set-level
# We do not use github.event.pull_request.labels.*.name here because
@@ -163,16 +118,14 @@ jobs:
check_level=0
fast=false
if [[ -n "${{ steps.set-release.outputs.RELEASE_TAG }}" || -n "${{ steps.set-release-custom.outputs.RELEASE_TAG }}" ]]; then
check_level=3
elif [[ -n "${{ steps.set-nightly.outputs.nightly }}" ]]; then
if [[ -n "${{ steps.set-nightly.outputs.nightly }}" || -n "${{ steps.set-release.outputs.RELEASE_TAG }}" || -n "${{ steps.set-release-custom.outputs.RELEASE_TAG }}" ]]; then
check_level=2
elif [[ "${{ github.event_name }}" != "pull_request" ]]; then
check_level=1
else
labels="$(gh api repos/${{ github.repository_owner }}/${{ github.event.repository.name }}/pulls/${{ github.event.pull_request.number }} --jq '.labels')"
if echo "$labels" | grep -q "release-ci"; then
check_level=3
check_level=2
elif echo "$labels" | grep -q "merge-ci"; then
check_level=1
fi
@@ -247,8 +200,8 @@ jobs:
"test": true,
// NOTE: `test-speedcenter` currently seems to be broken on `ubuntu-latest`
"test-speedcenter": large && level >= 2,
// We are not warning-free yet on all platforms, start here
"CMAKE_OPTIONS": "-DLEAN_EXTRA_CXX_FLAGS=-Werror",
// made explicit until it can be assumed to have propagated to PRs
"CMAKE_OPTIONS": "-DUSE_LAKE=ON",
},
{
"name": "Linux Reldebug",
@@ -257,22 +210,17 @@ jobs:
"test": true,
"CMAKE_PRESET": "reldebug",
},
{
// TODO: suddenly started failing in CI
/*{
"name": "Linux fsanitize",
// Always run on large if available, more reliable regarding timeouts
"os": large ? "nscloud-ubuntu-22.04-amd64-8x16-with-cache" : "ubuntu-latest",
"os": "ubuntu-latest",
"enabled": level >= 2,
// do not fail nightlies on this for now
"secondary": level <= 2,
"test": true,
// turn off custom allocator & symbolic functions to make LSAN do its magic
"CMAKE_PRESET": "sanitize",
// `StackOverflow*` correctly triggers ubsan
// `reverse-ffi` fails to link in sanitizers
// `interactive` and `async_select_channel` fail nondeterministically, would need to
// be investigated.
"CTEST_OPTIONS": "-E 'StackOverflow|reverse-ffi|interactive|async_select_channel'"
},
// exclude seriously slow/problematic tests (laketests crash)
"CTEST_OPTIONS": "-E 'interactivetest|leanpkgtest|laketest|benchtest'"
},*/
{
"name": "macOS",
"os": "macos-15-intel",
@@ -304,7 +252,7 @@ jobs:
},
{
"name": "Windows",
"os": large && (fast || level >= 2) ? "namespace-profile-windows-amd64-4x16" : "windows-2022",
"os": large && (fast || level == 2) ? "namespace-profile-windows-amd64-4x16" : "windows-2022",
"release": true,
"enabled": level >= 2,
"test": true,
@@ -427,11 +375,11 @@ jobs:
runs-on: ubuntu-latest
needs: build
steps:
- uses: actions/download-artifact@v6
- uses: actions/download-artifact@v5
with:
path: artifacts
- name: Release
uses: softprops/action-gh-release@6da8fa9354ddfdc4aeace5fc48d7f679b5214090
uses: softprops/action-gh-release@6cbd405e2c4e67a21c47fa9e383d020e4e28b836
with:
files: artifacts/*/*
fail_on_unmatched_files: true
@@ -459,7 +407,7 @@ jobs:
# Doesn't seem to be working when additionally fetching from lean4-nightly
#filter: tree:0
token: ${{ secrets.PUSH_NIGHTLY_TOKEN }}
- uses: actions/download-artifact@v6
- uses: actions/download-artifact@v5
with:
path: artifacts
- name: Prepare Nightly Release
@@ -477,7 +425,7 @@ jobs:
echo -e "\n*Full commit log*\n" >> diff.md
git log --oneline "$last_tag"..HEAD | sed 's/^/* /' >> diff.md
- name: Release Nightly
uses: softprops/action-gh-release@6da8fa9354ddfdc4aeace5fc48d7f679b5214090
uses: softprops/action-gh-release@6cbd405e2c4e67a21c47fa9e383d020e4e28b836
with:
body_path: diff.md
prerelease: true

View File

@@ -71,7 +71,7 @@ jobs:
GH_TOKEN: ${{ secrets.PR_RELEASES_TOKEN }}
- name: Release (short format)
if: ${{ steps.workflow-info.outputs.pullRequestNumber != '' }}
uses: softprops/action-gh-release@6da8fa9354ddfdc4aeace5fc48d7f679b5214090
uses: softprops/action-gh-release@6cbd405e2c4e67a21c47fa9e383d020e4e28b836
with:
name: Release for PR ${{ steps.workflow-info.outputs.pullRequestNumber }}
# There are coredumps files here as well, but all in deeper subdirectories.
@@ -86,7 +86,7 @@ jobs:
- name: Release (SHA-suffixed format)
if: ${{ steps.workflow-info.outputs.pullRequestNumber != '' }}
uses: softprops/action-gh-release@6da8fa9354ddfdc4aeace5fc48d7f679b5214090
uses: softprops/action-gh-release@6cbd405e2c4e67a21c47fa9e383d020e4e28b836
with:
name: Release for PR ${{ steps.workflow-info.outputs.pullRequestNumber }} (${{ steps.workflow-info.outputs.sourceHeadSha }})
# There are coredumps files here as well, but all in deeper subdirectories.
@@ -426,7 +426,7 @@ jobs:
git switch -c lean-pr-testing-${{ steps.workflow-info.outputs.pullRequestNumber }} "$BASE"
echo "leanprover/lean4-pr-releases:pr-release-${{ steps.workflow-info.outputs.pullRequestNumber }}-${{ env.SHORT_SHA }}" > lean-toolchain
git add lean-toolchain
git commit --allow-empty -m "Update lean-toolchain for testing https://github.com/leanprover/lean4/pull/${{ steps.workflow-info.outputs.pullRequestNumber }}"
git commit -m "Update lean-toolchain for testing https://github.com/leanprover/lean4/pull/${{ steps.workflow-info.outputs.pullRequestNumber }}"
else
echo "Branch already exists, updating lean-toolchain."
git switch lean-pr-testing-${{ steps.workflow-info.outputs.pullRequestNumber }}
@@ -435,7 +435,7 @@ jobs:
git merge "$BASE" --strategy-option ours --no-commit --allow-unrelated-histories
echo "leanprover/lean4-pr-releases:pr-release-${{ steps.workflow-info.outputs.pullRequestNumber }}-${{ env.SHORT_SHA }}" > lean-toolchain
git add lean-toolchain
git commit --allow-empty -m "Update lean-toolchain for https://github.com/leanprover/lean4/pull/${{ steps.workflow-info.outputs.pullRequestNumber }}"
git commit -m "Update lean-toolchain for https://github.com/leanprover/lean4/pull/${{ steps.workflow-info.outputs.pullRequestNumber }}"
fi
- name: Push changes
@@ -496,7 +496,7 @@ jobs:
sed -i 's,require "leanprover-community" / "batteries" @ git ".\+",require "leanprover-community" / "batteries" @ git "lean-pr-testing-${{ steps.workflow-info.outputs.pullRequestNumber }}",' lakefile.lean
lake update batteries
git add lakefile.lean lake-manifest.json
git commit --allow-empty -m "Update lean-toolchain for testing https://github.com/leanprover/lean4/pull/${{ steps.workflow-info.outputs.pullRequestNumber }}"
git commit -m "Update lean-toolchain for testing https://github.com/leanprover/lean4/pull/${{ steps.workflow-info.outputs.pullRequestNumber }}"
else
echo "Branch already exists, updating lean-toolchain and bumping Batteries."
git switch lean-pr-testing-${{ steps.workflow-info.outputs.pullRequestNumber }}
@@ -507,7 +507,7 @@ jobs:
git add lean-toolchain
lake update batteries
git add lake-manifest.json
git commit --allow-empty -m "Update lean-toolchain for https://github.com/leanprover/lean4/pull/${{ steps.workflow-info.outputs.pullRequestNumber }}"
git commit -m "Update lean-toolchain for https://github.com/leanprover/lean4/pull/${{ steps.workflow-info.outputs.pullRequestNumber }}"
fi
- name: Push changes
@@ -558,7 +558,7 @@ jobs:
echo "leanprover/lean4-pr-releases:pr-release-${{ steps.workflow-info.outputs.pullRequestNumber }}-${{ env.SHORT_SHA }}" > lean-toolchain
git add lean-toolchain
git add lakefile.lean lake-manifest.json
git commit --allow-empty -m "Update lean-toolchain for testing https://github.com/leanprover/lean4/pull/${{ steps.workflow-info.outputs.pullRequestNumber }}"
git commit -m "Update lean-toolchain for testing https://github.com/leanprover/lean4/pull/${{ steps.workflow-info.outputs.pullRequestNumber }}"
else
echo "Branch already exists, updating lean-toolchain."
git switch lean-pr-testing-${{ steps.workflow-info.outputs.pullRequestNumber }}
@@ -568,7 +568,7 @@ jobs:
echo "leanprover/lean4-pr-releases:pr-release-${{ steps.workflow-info.outputs.pullRequestNumber }}-${{ env.SHORT_SHA }}" > lean-toolchain
git add lean-toolchain
git add lake-manifest.json
git commit --allow-empty -m "Update lean-toolchain for https://github.com/leanprover/lean4/pull/${{ steps.workflow-info.outputs.pullRequestNumber }}"
git commit -m "Update lean-toolchain for https://github.com/leanprover/lean4/pull/${{ steps.workflow-info.outputs.pullRequestNumber }}"
fi
- name: Push changes

View File

@@ -15,6 +15,6 @@ jobs:
script: |
const msg = context.payload.pull_request? context.payload.pull_request.title : context.payload.merge_group.head_commit.message;
console.log(`Message: ${msg}`)
if (!/^(feat|fix|doc|style|refactor|test|chore|perf): (?![A-Z][a-z]).*[^.]($|\n\n)/.test(msg)) {
if (!/^(feat|fix|doc|style|refactor|test|chore|perf): .*[^.]($|\n\n)/.test(msg)) {
core.setFailed('PR title does not follow the Commit Convention (https://leanprover.github.io/lean4/doc/dev/commit_convention.html).');
}

View File

@@ -41,7 +41,7 @@
"SMALL_ALLOCATOR": "OFF",
"USE_MIMALLOC": "OFF",
"BSYMBOLIC": "OFF",
"LEAN_TEST_VARS": "MAIN_STACK_SIZE=16000 LSAN_OPTIONS=max_leaks=10"
"LEAN_TEST_VARS": "MAIN_STACK_SIZE=16000"
},
"generator": "Unix Makefiles",
"binaryDir": "${sourceDir}/build/sanitize"

View File

@@ -72,9 +72,6 @@ update the archived C source code of the stage 0 compiler in `stage0/src`.
The github repository will automatically update stage0 on `master` once
`src/stdlib_flags.h` and `stage0/src/stdlib_flags.h` are out of sync.
To trigger this, modify `stage0/src/stdlib_flags.h` (e.g., by adding or changing
a comment). When `update-stage0` runs, it will overwrite `stage0/src/stdlib_flags.h`
with the contents of `src/stdlib_flags.h`, bringing them back in sync.
NOTE: A full rebuild of stage 1 will only be triggered when the *committed* contents of `stage0/` are changed.
Thus if you change files in it manually instead of through `update-stage0-commit` (see below) or fetching updates from git, you either need to commit those changes first or run `make -C build/release clean-stdlib`.

View File

@@ -129,7 +129,8 @@ For all other modules imported by `lean`, the initializer is run without `builti
Thus `[init]` functions are run iff their module is imported, regardless of whether they have native code available or not, while `[builtin_init]` functions are only run for native executable or plugins, regardless of whether their module is imported or not.
`lean` uses built-in initializers for e.g. registering basic parsers that should be available even without importing their module (which is necessary for bootstrapping).
The initializer for module `A.B` in a package `foo` is called `initialize_foo_A_B`. For modules in the Lean core (e.g., `Init.Prelude`), the initializer is called `initialize_Init_Prelude`. Module initializers will automatically initialize any imported modules. They are also idempotent (when run with the same `builtin` flag), but not thread-safe.
The initializer for module `A.B` is called `initialize_A_B` and will automatically initialize any imported modules.
Module initializers are idempotent (when run with the same `builtin` flag), but not thread-safe.
**Important for process-related functionality**: If your application needs to use process-related functions from libuv, such as `Std.Internal.IO.Process.getProcessTitle` and `Std.Internal.IO.Process.setProcessTitle`, you must call `lean_setup_args(argc, argv)` (which returns a potentially modified `argv` that must be used in place of the original) **before** calling `lean_initialize()` or `lean_initialize_runtime_module()`. This sets up process handling capabilities correctly, which is essential for certain system-level operations that Lean's runtime may depend on.

View File

@@ -94,8 +94,10 @@ theorem List.palindrome_of_eq_reverse (h : as.reverse = as) : Palindrome as := b
next => exact Palindrome.nil
next a => exact Palindrome.single a
next a b as ih =>
obtain rfl, h, - := by simpa using h
exact Palindrome.sandwich b (ih h)
have : a = b := by simp_all
subst this
have : as.reverse = as := by simp_all
exact Palindrome.sandwich a (ih this)
/-!
We now define a function that returns `true` iff `as` is a palindrome.

View File

@@ -1,54 +0,0 @@
This release introduces the Lean module system, which allows files to
control the visibility of their contents for other files. In previous
releases, this feature was available as a preview when the option
`experimental.module` was set to `true`; it is now a fully supported
feature of Lean.
# Benefits
Because modules reduce the amount of information exposed to other
code, they speed up rebuilds because irrelevant changes can be
ignored, they make it possible to be deliberate about API evolution by
hiding details that may change from clients, they help proofs be
checked faster by avoiding accidentally unfolding definitions, and
they lead to smaller executable files through improved dead code
elimination.
# Visibility
A source file is a module if it begins with the `module` keyword. By
default, declarations in a module are private; the `public` modifier
exports them. Proofs of theorems and bodies of definitions are private
by default even when their signatures are public; the bodies of
definitions can be made public by adding the `@[expose]`
attribute. Theorems and opaque constants never expose their bodies.
`public section` and `@[expose] section` change the default visibility
of declarations in the section.
# Imports
Modules may only import other modules. By default, `import` adds the
public information of the imported module to the private scope of the
current module. Adding the `public` modifier to an import places the
imported modules's public information in the public scope of the
current module, exposing it in turn to the current module's clients.
Within a package, `import all` can be used to import another module's
private scope into the current module; this can be used to separate
lemmas or tests from definition modules without exposing details to
downstream clients.
# Meta Code
Code used in metaprograms must be marked `meta`. This ensures that the
code is compiled and available for execution when it is needed during
elaboration. Meta code may only reference other meta code. A whole
module can be made available in the meta phase using `meta import`;
this allows code to be shared across phases by importing the module in
each phase. Code that is reachable from public metaprograms must be
imported via `public meta import`, while local metaprograms can use
plain `meta import` for their dependencies.
The module system is described in detail in [the Lean language reference](https://lean-reference-manual-review.netlify.app/find/?domain=Verso.Genre.Manual.section&name=files).

View File

@@ -0,0 +1,132 @@
/-
Copyright (c) 2025 Amazon.com, Inc. or its affiliates. All Rights Reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Leonardo de Moura
-/
import Lean
namespace Lean.Meta.Grind.Analyzer
/-!
A simple E-matching annotation analyzer.
For each theorem annotated as an E-matching candidate, it creates an artificial goal, executes `grind` and shows the
number of instances created.
For a theorem of the form `params -> type`, the artificial goal is of the form `params -> type -> False`.
-/
/--
`grind` configuration for the analyzer. We disable case-splits and lookahead,
increase the number of generations, and limit the number of instances generated.
-/
def config : Grind.Config := {
splits := 0
lookahead := false
mbtc := false
ematch := 20
instances := 100
gen := 10
}
structure Config where
/-- Minimum number of instantiations to trigger summary report -/
min : Nat := 10
/-- Minimum number of instantiations to trigger detailed report -/
detailed : Nat := 50
def mkParams : MetaM Params := do
let params Grind.mkParams config
let ematch getEMatchTheorems
let casesTypes Grind.getCasesTypes
return { params with ematch, casesTypes }
/-- Returns the total number of generated instances. -/
private def sum (cs : PHashMap Origin Nat) : Nat := Id.run do
let mut r := 0
for (_, c) in cs do
r := r + c
return r
private def thmsToMessageData (thms : PHashMap Origin Nat) : MetaM MessageData := do
let data := thms.toArray.filterMap fun (origin, c) =>
match origin with
| .decl declName => some (declName, c)
| _ => none
let data := data.qsort fun (d₁, c₁) (d₂, c₂) => if c₁ == c₂ then Name.lt d₁ d₂ else c₁ > c₂
let data data.mapM fun (declName, counter) =>
return .trace { cls := `thm } m!"{.ofConst (← mkConstWithLevelParams declName)} ↦ {counter}" #[]
return .trace { cls := `thm } "instances" data
/--
Analyzes theorem `declName`. That is, creates the artificial goal based on `declName` type,
and invokes `grind` on it.
-/
def analyzeEMatchTheorem (declName : Name) (c : Config) : MetaM Unit := do
let info getConstInfo declName
let mvarId forallTelescope info.type fun _ type => do
withLocalDeclD `h type fun _ => do
return ( mkFreshExprMVar (mkConst ``False)).mvarId!
let result Grind.main mvarId ( mkParams) (pure ())
let thms := result.counters.thm
let s := sum thms
if s > c.min then
IO.println s!"{declName} : {s}"
if s > c.detailed then
logInfo m!"{declName}\n{← thmsToMessageData thms}"
-- Not sure why this is failing: `down_pure` perhaps has an unnecessary universe parameter?
run_meta analyzeEMatchTheorem ``Std.Do.SPred.down_pure {}
/-- Analyzes all theorems in the standard library marked as E-matching theorems. -/
def analyzeEMatchTheorems (c : Config := {}) : MetaM Unit := do
let origins := ( getEMatchTheorems).getOrigins
let decls := origins.filterMap fun | .decl declName => some declName | _ => none
for declName in decls.mergeSort Name.lt do
try
analyzeEMatchTheorem declName c
catch e =>
logError m!"{declName} failed with {e.toMessageData}"
logInfo m!"Finished analyzing {decls.length} theorems"
/-- Macro for analyzing E-match theorems with unlimited heartbeats -/
macro "#analyzeEMatchTheorems" : command => `(
set_option maxHeartbeats 0 in
run_meta analyzeEMatchTheorems
)
#analyzeEMatchTheorems
-- -- We can analyze specific theorems using commands such as
set_option trace.grind.ematch.instance true
-- 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 {}

View File

@@ -131,11 +131,10 @@ structure State where
`transDeps[i]` is the (non-reflexive) transitive closure of `mods[i].imports`. More specifically,
* `j ∈ transDeps[i].pub` if `i -(public import)->+ j`
* `j ∈ transDeps[i].priv` if `i -(import ...)-> _ -(public import)->* j`
* `j ∈ transDeps[i].priv` if `i -(import all)->+ i'` and `j ∈ transDeps[i'].pub/priv`
* `j ∈ transDeps[i].metaPub` if `i -(public (meta)? import)->* _ -(public meta import)-> _ -(public (meta)? import)->* j`
* `j ∈ transDeps[i].metaPriv` if `i -(meta import ...)-> _ -(public (meta)? import)->* j`
* `j ∈ transDeps[i].metaPriv` if `i -(import ...)-> i'` and `j ∈ transDeps[i'].metaPub`
* `j ∈ transDeps[i].metaPriv` if `i -(import all)->+ i'` and `j ∈ transDeps[i'].metaPub/metaPriv`
* `j ∈ transDeps[i].priv` if `i -(import all)->+ -(public import ...)-> _ -(public import)->* j`
* `j ∈ transDeps[i].metaPub` if `i -(public (meta)? import)->* _ -(public meta import)-> _ -(public (meta)? import ...)->* j`
* `j ∈ transDeps[i].metaPriv` if `i -(meta import ...)-> _ -(public (meta)? import ...)->* j`
* `j ∈ transDeps[i].metaPriv` if `i -(import all)->+ -(public meta import ...)-> _ -(public (meta)? import ...)->* j`
-/
transDeps : Array Needs := #[]
/--
@@ -163,10 +162,10 @@ def addTransitiveImps (transImps : Needs) (imp : Import) (j : Nat) (impTransImps
-- `j ∈ transDeps[i].priv` if `i -(import ...)-> _ -(public import)->* j`
transImps := transImps.union .priv {j} |>.union .priv (impTransImps.get .pub)
if imp.importAll then
-- `j ∈ transDeps[i].priv` if `i -(import all)->+ i'` and `j ∈ transDeps[i'].pub/priv`
transImps := transImps.union .priv (impTransImps.get .pub impTransImps.get .priv)
-- `j ∈ transDeps[i].priv` if `i -(import all)->+ -(public import ...)-> _ -(public import)->* j`
transImps := transImps.union .priv (impTransImps.get .pub)
-- `j ∈ transDeps[i].metaPub` if `i -(public (meta)? import)->* _ -(public meta import)-> _ -(public (meta)? import)->* j`
-- `j ∈ transDeps[i].metaPub` if `i -(public (meta)? import)->* _ -(public meta import)-> _ -(public (meta)? import ...)->* j`
if imp.isExported then
transImps := transImps.union .metaPub (impTransImps.get .metaPub)
if imp.isMeta then
@@ -174,13 +173,10 @@ def addTransitiveImps (transImps : Needs) (imp : Import) (j : Nat) (impTransImps
if !imp.isExported then
if imp.isMeta then
-- `j ∈ transDeps[i].metaPriv` if `i -(meta import ...)-> _ -(public (meta)? import)->* j`
-- `j ∈ transDeps[i].metaPriv` if `i -(meta import ...)-> _ -(public (meta)? import ...)->* j`
transImps := transImps.union .metaPriv {j} |>.union .metaPriv (impTransImps.get .pub impTransImps.get .metaPub)
if imp.importAll then
-- `j ∈ transDeps[i].metaPriv` if `i -(import all)->+ i'` and `j ∈ transDeps[i'].metaPub/metaPriv`
transImps := transImps.union .metaPriv (impTransImps.get .metaPub impTransImps.get .metaPriv)
else
-- `j ∈ transDeps[i].metaPriv` if `i -(import ...)-> i'` and `j ∈ transDeps[i'].metaPub`
-- `j ∈ transDeps[i].metaPriv` if `i -(import all)->+ -(public meta import ...)-> _ -(public (meta)? import ...)->* j`
transImps := transImps.union .metaPriv (impTransImps.get .metaPub)
transImps
@@ -189,8 +185,7 @@ def addTransitiveImps (transImps : Needs) (imp : Import) (j : Nat) (impTransImps
def calcNeeds (env : Environment) (i : ModuleIdx) : Needs := Id.run do
let mut needs := default
for ci in env.header.moduleData[i]!.constants do
-- Added guard for cases like `structure` that are still exported even if private
let pubCI? := guard (!isPrivateName ci.name) *> (env.setExporting true).find? ci.name
let pubCI? := env.setExporting true |>.find? ci.name
let k := { isExported := pubCI?.isSome, isMeta := isMeta env ci.name }
needs := visitExpr k ci.type needs
if let some e := ci.value? (allowOpaque := true) then
@@ -221,8 +216,7 @@ def getExplanations (env : Environment) (i : ModuleIdx) :
Std.HashMap (ModuleIdx × NeedsKind) (Option (Name × Name)) := Id.run do
let mut deps := default
for ci in env.header.moduleData[i]!.constants do
-- Added guard for cases like `structure` that are still exported even if private
let pubCI? := guard (!isPrivateName ci.name) *> (env.setExporting true).find? ci.name
let pubCI? := env.setExporting true |>.find? ci.name
let k := { isExported := pubCI?.isSome, isMeta := isMeta env ci.name }
deps := visitExpr k ci.name ci.type deps
if let some e := ci.value? (allowOpaque := true) then
@@ -292,7 +286,7 @@ and `endPos` is the position of the end of the header.
-/
def parseHeaderFromString (text path : String) :
IO (System.FilePath × Parser.InputContext ×
TSyntax ``Parser.Module.header × String.Pos.Raw) := do
TSyntaxArray ``Parser.Module.import × String.Pos) := do
let inputCtx := Parser.mkInputContext text path
let (header, parserState, msgs) Parser.parseHeader inputCtx
if !msgs.toList.isEmpty then -- skip this file if there are parse errors
@@ -300,8 +294,8 @@ def parseHeaderFromString (text path : String) :
throw <| .userError "parse errors in file"
-- the insertion point for `add` is the first newline after the imports
let insertion := header.raw.getTailPos?.getD parserState.pos
let insertion := text.findAux (· == '\n') text.rawEndPos insertion + '\n'
pure (path, inputCtx, header, insertion)
let insertion := text.findAux (· == '\n') text.endPos insertion + 1
pure (path, inputCtx, .mk header.raw[2].getArgs, insertion)
/-- Parse a source file to extract the location of the import lines, for edits and error messages.
@@ -310,18 +304,13 @@ and `endPos` is the position of the end of the header.
-/
def parseHeader (srcSearchPath : SearchPath) (mod : Name) :
IO (System.FilePath × Parser.InputContext ×
TSyntax ``Parser.Module.header × String.Pos.Raw) := do
TSyntaxArray ``Parser.Module.import × String.Pos) := do
-- Parse the input file
let some path srcSearchPath.findModuleWithExt "lean" mod
| throw <| .userError s!"error: failed to find source file for {mod}"
let text IO.FS.readFile path
parseHeaderFromString text path.toString
def decodeHeader : TSyntax ``Parser.Module.header Option (TSyntax `module) × Option (TSyntax `prelude) × TSyntaxArray ``Parser.Module.import
| `(Parser.Module.header| $[module%$moduleTk?]? $[prelude%$preludeTk?]? $imports*) =>
(moduleTk?.map .mk, preludeTk?.map .mk, imports)
| _ => unreachable!
def decodeImport : TSyntax ``Parser.Module.import Import
| `(Parser.Module.import| $[public%$pubTk?]? $[meta%$metaTk?]? import $[all%$allTk?]? $id) =>
{ module := id.getId, isExported := pubTk?.isSome, isMeta := metaTk?.isSome, importAll := allTk?.isSome }
@@ -337,20 +326,11 @@ def decodeImport : TSyntax ``Parser.Module.import → Import
* `addOnly`: if true, only add missing imports, do not remove unused ones
-/
def visitModule (srcSearchPath : SearchPath)
(i : Nat) (needs : Needs) (preserve : Needs) (edits : Edits) (headerStx : TSyntax ``Parser.Module.header)
(i : Nat) (needs : Needs) (preserve : Needs) (edits : Edits)
(addOnly := false) (githubStyle := false) (explain := false) : StateT State IO Edits := do
let s get
-- Do transitive reduction of `needs` in `deps`.
let mut deps := needs
let (_, prelude?, imports) := decodeHeader headerStx
if prelude?.isNone then
deps := deps.union .pub {s.env.getModuleIdx? `Init |>.get!}
for imp in imports do
if addOnly || imp.raw.getTrailing?.any (·.toString.toSlice.contains "shake: keep") then
let imp := decodeImport imp
let j := s.env.getModuleIdx? imp.module |>.get!
let k := NeedsKind.ofImport imp
deps := deps.union k {j}
for j in [0:s.mods.size] do
let transDeps := s.transDeps[j]!
for k in NeedsKind.all do
@@ -374,8 +354,7 @@ def visitModule (srcSearchPath : SearchPath)
newDeps := addTransitiveImps newDeps imp j s.transDeps[j]!
else
let k := NeedsKind.ofImport imp
-- A private import should also be removed if the public version is needed
if !deps.has k j || !k.isExported && deps.has { k with isExported := true } j then
if !addOnly && !deps.has k j && !deps.has { k with isExported := false } j then
toRemove := toRemove.push imp
else
newDeps := addTransitiveImps newDeps imp j s.transDeps[j]!
@@ -406,8 +385,7 @@ def visitModule (srcSearchPath : SearchPath)
if githubStyle then
try
let (path, inputCtx, stx, endHeader) parseHeader srcSearchPath s.modNames[i]!
let (_, _, imports) := decodeHeader stx
let (path, inputCtx, imports, endHeader) parseHeader srcSearchPath s.modNames[i]!
for stx in imports do
if toRemove.any fun imp => imp == decodeImport stx then
let pos := inputCtx.fileMap.toPosition stx.raw.getPos?.get!
@@ -551,61 +529,51 @@ def main (args : List String) : IO UInt32 := do
let needs := s.mods.mapIdx fun i _ =>
Task.spawn fun _ => calcNeeds s.env i
-- Parse headers in parallel
let headers s.mods.mapIdxM fun i _ =>
BaseIO.asTask (parseHeader srcSearchPath s.modNames[i]! |>.toBaseIO)
if args.fix then
println! "The following changes will be made automatically:"
-- Check all selected modules
let mut edits : Edits :=
let mut revNeeds : Needs := default
for i in [0:s.mods.size], t in needs, header in headers do
match header.get with
| .ok (_, _, stx, _) =>
edits visitModule (addOnly := !pkg.isPrefixOf s.modNames[i]!)
srcSearchPath i t.get revNeeds edits stx args.githubStyle args.explain
if isExtraRevModUse s.env i then
revNeeds := revNeeds.union .priv {i}
| .error e =>
println! e.toString
for i in [0:s.mods.size], t in needs do
edits visitModule (addOnly := !pkg.isPrefixOf s.modNames[i]!) srcSearchPath i t.get revNeeds edits args.githubStyle args.explain
if isExtraRevModUse s.env i then
revNeeds := revNeeds.union .priv {i}
if !args.fix then
-- return error if any issues were found
return if edits.isEmpty then 0 else 1
-- Apply the edits to existing files
let mut count := 0
for mod in s.modNames, header? in headers do
let some (remove, add) := edits[mod]? | continue
let count edits.foldM (init := 0) fun count mod (remove, add) => do
let add : Array Import := add.qsortOrd
-- Parse the input file
let .ok (path, inputCtx, stx, insertion) := header?.get | continue
let (_, _, imports) := decodeHeader stx
let (path, inputCtx, imports, insertion)
try parseHeader srcSearchPath mod
catch e => println! e.toString; return count
let text := inputCtx.fileMap.source
-- Calculate the edit result
let mut pos : String.Pos.Raw := 0
let mut pos : String.Pos := 0
let mut out : String := ""
let mut seen : Std.HashSet Import := {}
for stx in imports do
let mod := decodeImport stx
if remove.contains mod || seen.contains mod then
out := out ++ String.Pos.Raw.extract text pos stx.raw.getPos?.get!
out := out ++ text.extract pos stx.raw.getPos?.get!
-- We use the end position of the syntax, but include whitespace up to the first newline
pos := text.findAux (· == '\n') text.rawEndPos stx.raw.getTailPos?.get! + '\n'
pos := text.findAux (· == '\n') text.rawEndPos stx.raw.getTailPos?.get! + 1
seen := seen.insert mod
out := out ++ String.Pos.Raw.extract text pos insertion
out := out ++ text.extract pos insertion
for mod in add do
if !seen.contains mod then
seen := seen.insert mod
out := out ++ s!"{mod}\n"
out := out ++ String.Pos.Raw.extract text insertion text.rawEndPos
out := out ++ text.extract insertion text.rawEndPos
IO.FS.writeFile path out
count := count + 1
return count + 1
-- Since we throw an error upon encountering issues, we can be sure that everything worked
-- if we reach this point of the script.

View File

@@ -60,7 +60,7 @@ if (arity == fixed + {n}) \{
for j in [n:max + 1] do
let fs := mkFsArgs (j - n)
let sep := if j = n then "" else ", "
emit s!" case {j}: \{ obj* r = FN{j}(f)({fs}{sep}{args}); lean_free_object(f); return r; }\n"
emit s!" case {j}: \{ obj* r = FN{j}(f)({fs}{sep}{args}); lean_free_small_object(f); return r; }\n"
emit " }
}
switch (arity) {\n"
@@ -162,7 +162,7 @@ static obj* fix_args(obj* f, unsigned n, obj*const* as) {
for (unsigned i = 0; i < fixed; i++, source++, target++) {
*target = *source;
}
lean_free_object(f);
lean_free_small_object(f);
}
for (unsigned i = 0; i < n; i++, as++, target++) {
*target = *as;

96
script/bench.sh Executable file
View File

@@ -0,0 +1,96 @@
#!/usr/bin/env bash
set -euxo pipefail
cmake --preset release 1>&2
# We benchmark against stage2/bin to test new optimizations.
timeout -s KILL 1h time make -C build/release -j$(nproc) stage3 1>&2
export PATH=$PWD/build/release/stage2/bin:$PATH
# The extra opts used to be passed to the Makefile during benchmarking only but with Lake it is
# easier to configure them statically.
cmake -B build/release/stage3 -S src -DLEAN_EXTRA_LAKEFILE_TOML='weakLeanArgs=["-Dprofiler=true", "-Dprofiler.threshold=9999999", "--stats"]' 1>&2
(
cd tests/bench
timeout -s KILL 1h time temci exec --config speedcenter.yaml --in speedcenter.exec.velcom.yaml 1>&2
temci report run_output.yaml --reporter codespeed2
)
if [ -d .git ]; then
DIR="$(git rev-parse @)"
BASE_URL="https://speed.lean-lang.org/lean4-out/$DIR"
{
cat <<'EOF'
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Lakeprof Report</title>
</head>
<h1>Lakeprof Report</h1>
<button type="button" id="btn_fetch">View build trace in Perfetto</button>
<script type="text/javascript">
const ORIGIN = 'https://ui.perfetto.dev';
const btnFetch = document.getElementById('btn_fetch');
async function fetchAndOpen(traceUrl) {
const resp = await fetch(traceUrl);
// Error checking is left as an exercise to the reader.
const blob = await resp.blob();
const arrayBuffer = await blob.arrayBuffer();
openTrace(arrayBuffer, traceUrl);
}
function openTrace(arrayBuffer, traceUrl) {
const win = window.open(ORIGIN);
if (!win) {
btnFetch.style.background = '#f3ca63';
btnFetch.onclick = () => openTrace(arrayBuffer);
btnFetch.innerText = 'Popups blocked, click here to open the trace file';
return;
}
const timer = setInterval(() => win.postMessage('PING', ORIGIN), 50);
const onMessageHandler = (evt) => {
if (evt.data !== 'PONG') return;
// We got a PONG, the UI is ready.
window.clearInterval(timer);
window.removeEventListener('message', onMessageHandler);
const reopenUrl = new URL(location.href);
reopenUrl.hash = `#reopen=${traceUrl}`;
win.postMessage({
perfetto: {
buffer: arrayBuffer,
title: 'Lake Build Trace',
url: reopenUrl.toString(),
}}, ORIGIN);
};
window.addEventListener('message', onMessageHandler);
}
// This is triggered when following the link from the Perfetto UI's sidebar.
if (location.hash.startsWith('#reopen=')) {
const traceUrl = location.hash.substr(8);
fetchAndOpen(traceUrl);
}
EOF
cat <<EOF
btnFetch.onclick = () => fetchAndOpen("$BASE_URL/lakeprof.trace_event");
</script>
EOF
echo "<pre><code>"
(cd src; lakeprof report -prc)
echo "</code></pre>"
echo "</body></html>"
} | tee index.html
curl -T index.html $BASE_URL/index.html
curl -T src/lakeprof.log $BASE_URL/lakeprof.log
curl -T src/lakeprof.trace_event $BASE_URL/lakeprof.trace_event
fi

View File

@@ -10,16 +10,6 @@ Tests language server memory use by repeatedly re-elaborate a given file.
NOTE: only works on Linux for now.
-/
def determineRSS (pid : UInt32) : IO Nat := do
let status IO.FS.readFile s!"/proc/{pid}/smaps_rollup"
let some rssLine := status.splitOn "\n" |>.find? (·.startsWith "Rss:")
| throw <| IO.userError "No RSS in proc status"
let rssLine := rssLine.dropPrefix "Rss:"
let rssLine := rssLine.dropWhile Char.isWhitespace
let some rssInKB := rssLine.takeWhile Char.isDigit |>.toNat?
| throw <| IO.userError "Cannot parse RSS"
return rssInKB
def main (args : List String) : IO Unit := do
let leanCmd :: file :: iters :: args := args | panic! "usage: script <lean> <file> <#iterations> <server-args>..."
let file IO.FS.realPath file
@@ -44,14 +34,11 @@ def main (args : List String) : IO Unit := do
let text IO.FS.readFile file
let (_, headerEndPos, _) Elab.parseImports text
let headerEndPos := FileMap.ofString text |>.leanPosToLspPos headerEndPos
let n := iters.toNat!
let mut lastRSS? : Option Nat := none
let mut totalRSSDelta : Int := 0
let mut requestNo : Nat := 1
let mut versionNo : Nat := 1
Ipc.writeNotification "textDocument/didOpen", {
textDocument := { uri := uri, languageId := "lean", version := 1, text := text } : DidOpenTextDocumentParams }
for i in [0:n] do
for i in [0:iters.toNat!] do
if i > 0 then
versionNo := versionNo + 1
let params : DidChangeTextDocumentParams := {
@@ -74,16 +61,9 @@ def main (args : List String) : IO Unit := do
IO.eprintln diag.message
requestNo := requestNo + 1
let rss determineRSS ( read).pid
-- The first `didChange` usually results in a significantly higher RSS increase than
-- the others, so we ignore it.
if i > 1 then
if let some lastRSS := lastRSS? then
totalRSSDelta := totalRSSDelta + ((rss : Int) - (lastRSS : Int))
lastRSS? := some rss
let avgRSSDelta := totalRSSDelta / (n - 2)
IO.println s!"avg-reelab-rss-delta: {avgRSSDelta}"
let status IO.FS.readFile s!"/proc/{(← read).pid}/status"
for line in status.splitOn "\n" |>.filter (·.startsWith "RssAnon") do
IO.eprintln line
let _ Ipc.collectDiagnostics requestNo uri versionNo
( Ipc.stdin).writeLspMessage (Message.notification "exit" none)

View File

@@ -1,89 +0,0 @@
import Lean.Data.Lsp
import Lean.Elab.Import
open Lean
open Lean.Lsp
open Lean.JsonRpc
/-!
Tests watchdog memory use by repeatedly re-elaborate a given file.
NOTE: only works on Linux for now.
-/
def determineRSS (pid : UInt32) : IO Nat := do
let status IO.FS.readFile s!"/proc/{pid}/smaps_rollup"
let some rssLine := status.splitOn "\n" |>.find? (·.startsWith "Rss:")
| throw <| IO.userError "No RSS in proc status"
let rssLine := rssLine.dropPrefix "Rss:"
let rssLine := rssLine.dropWhile Char.isWhitespace
let some rssInKB := rssLine.takeWhile Char.isDigit |>.toNat?
| throw <| IO.userError "Cannot parse RSS"
return rssInKB
def main (args : List String) : IO Unit := do
let leanCmd :: file :: iters :: args := args | panic! "usage: script <lean> <file> <#iterations> <server-args>..."
let file IO.FS.realPath file
let uri := s!"file://{file}"
Ipc.runWith leanCmd (#["--server", "-DstderrAsMessages=false"] ++ args ++ #[uri]) do
let capabilities := {
textDocument? := some {
completion? := some {
completionItem? := some {
insertReplaceSupport? := true
}
}
}
}
Ipc.writeRequest 0, "initialize", { capabilities : InitializeParams }
discard <| Ipc.readResponseAs 0 InitializeResult
Ipc.writeNotification "initialized", InitializedParams.mk
let text IO.FS.readFile file
let (_, headerEndPos, _) Elab.parseImports text
let headerEndPos := FileMap.ofString text |>.leanPosToLspPos headerEndPos
let n := iters.toNat!
let mut lastRSS? : Option Nat := none
let mut totalRSSDelta : Int := 0
let mut requestNo : Nat := 1
let mut versionNo : Nat := 1
Ipc.writeNotification "textDocument/didOpen", {
textDocument := { uri := uri, languageId := "lean", version := 1, text := text } : DidOpenTextDocumentParams }
for i in [0:iters.toNat!] do
if i > 0 then
versionNo := versionNo + 1
let params : DidChangeTextDocumentParams := {
textDocument := {
uri := uri
version? := versionNo
}
contentChanges := #[TextDocumentContentChangeEvent.rangeChange {
start := headerEndPos
«end» := headerEndPos
} " "]
}
let params := toJson params
Ipc.writeNotification "textDocument/didChange", params
requestNo := requestNo + 1
let diags Ipc.collectDiagnostics requestNo uri versionNo
if let some diags := diags then
for diag in diags.param.diagnostics do
IO.eprintln diag.message
requestNo := requestNo + 1
Ipc.waitForILeans requestNo uri versionNo
let rss determineRSS ( read).pid
-- The first `didChange` usually results in a significantly higher RSS increase than
-- the others, so we ignore it.
if i > 1 then
if let some lastRSS := lastRSS? then
totalRSSDelta := totalRSSDelta + ((rss : Int) - (lastRSS : Int))
lastRSS? := some rss
let avgRSSDelta := totalRSSDelta / (n - 2)
IO.println s!"avg-reelab-rss-delta: {avgRSSDelta}"
let _ Ipc.collectDiagnostics requestNo uri versionNo
Ipc.shutdown requestNo
discard <| Ipc.waitForExit

View File

@@ -58,11 +58,7 @@ OPTIONS=()
# We build cadical using the custom toolchain on Linux to avoid glibc versioning issues
echo -n " -DLEAN_STANDALONE=ON -DCADICAL_USE_CUSTOM_CXX=ON"
echo -n " -DCMAKE_CXX_COMPILER=$PWD/llvm-host/bin/clang++ -DLEAN_CXX_STDLIB='-Wl,-Bstatic -lc++ -lc++abi -Wl,-Bdynamic'"
# these should also be used for cadical, so do not use `LEAN_EXTRA_CXX_FLAGS` here
echo -n " -DCMAKE_CXX_FLAGS='--sysroot $PWD/llvm -idirafter $GLIBC_DEV/include ${EXTRA_FLAGS:-}'"
# the above does not include linker flags which will be added below based on context, so skip the
# generic check by cmake
echo -n " -DCMAKE_C_COMPILER_WORKS=1 -DCMAKE_CXX_COMPILER_WORKS=1"
echo -n " -DLEAN_EXTRA_CXX_FLAGS='--sysroot $PWD/llvm -idirafter $GLIBC_DEV/include ${EXTRA_FLAGS:-}'"
# use target compiler directly when not cross-compiling
if [[ -L llvm-host ]]; then
echo -n " -DCMAKE_C_COMPILER=$PWD/stage1/bin/clang"

View File

@@ -31,8 +31,6 @@ What this script does:
- Ensures tags are merged into stable branches (for non-RC releases)
- Verifies bump branches exist and are configured correctly
- Special handling for ProofWidgets4 release tags
- For mathlib4: runs verify_version_tags.py to validate the release tag
(checks git/GitHub consistency, toolchain, elan, cache, and build)
3. Optionally automates missing steps (when not in --dry-run mode):
- Creates missing release tags using push_repo_release_tag.py
@@ -501,57 +499,6 @@ def check_proofwidgets4_release(repo_url, target_toolchain, github_token):
print(f" You will need to create and push a tag v0.0.{next_version}")
return False
def run_mathlib_verify_version_tags(toolchain, verbose=False):
"""Run mathlib4's verify_version_tags.py script to validate the release tag.
This clones mathlib4 to a temp directory and runs the verification script.
Returns True if verification passes, False otherwise.
"""
import tempfile
print(f" ... Running mathlib4 verify_version_tags.py {toolchain}")
with tempfile.TemporaryDirectory() as tmpdir:
# Clone mathlib4 (shallow clone is sufficient for running the script)
clone_result = subprocess.run(
['git', 'clone', '--depth', '1', 'https://github.com/leanprover-community/mathlib4.git', tmpdir],
capture_output=True,
text=True
)
if clone_result.returncode != 0:
print(f" ❌ Failed to clone mathlib4: {clone_result.stderr.strip()[:200]}")
return False
# Run the verification script
script_path = os.path.join(tmpdir, 'scripts', 'verify_version_tags.py')
if not os.path.exists(script_path):
print(f" ❌ verify_version_tags.py not found in mathlib4 (expected at scripts/verify_version_tags.py)")
return False
# Run from the mathlib4 directory so git operations work
result = subprocess.run(
['python3', script_path, toolchain],
cwd=tmpdir,
capture_output=True,
text=True,
timeout=900 # 15 minutes timeout for cache download etc.
)
# Print output with indentation
if result.stdout:
for line in result.stdout.strip().split('\n'):
print(f" {line}")
if result.stderr:
for line in result.stderr.strip().split('\n'):
print(f" {line}")
if result.returncode != 0:
print(f" ❌ mathlib4 verify_version_tags.py failed")
return False
print(f" ✅ mathlib4 verify_version_tags.py passed")
return True
def main():
parser = argparse.ArgumentParser(description="Check release status of Lean4 repositories")
parser.add_argument("toolchain", help="The toolchain version to check (e.g., v4.6.0)")
@@ -816,12 +763,6 @@ def main():
repo_status[name] = False
continue
# For mathlib4, run verify_version_tags.py to validate the release tag
if name == "mathlib4":
if not run_mathlib_verify_version_tags(toolchain, verbose):
repo_status[name] = False
continue
repo_status[name] = success
# Final check for lean4 master branch

View File

@@ -10,7 +10,7 @@ endif()
include(ExternalProject)
project(LEAN CXX C)
set(LEAN_VERSION_MAJOR 4)
set(LEAN_VERSION_MINOR 27)
set(LEAN_VERSION_MINOR 26)
set(LEAN_VERSION_PATCH 0)
set(LEAN_VERSION_IS_RELEASE 0) # This number is 1 in the release revision, and 0 otherwise.
set(LEAN_SPECIAL_VERSION_DESC "" CACHE STRING "Additional version description like 'nightly-2018-03-11'")
@@ -42,7 +42,7 @@ if(LLD_PATH)
endif()
set(LEAN_EXTRA_LINKER_FLAGS ${LEAN_EXTRA_LINKER_FLAGS_DEFAULT} CACHE STRING "Additional flags used by the linker")
set(LEAN_EXTRA_CXX_FLAGS "" CACHE STRING "Additional flags used by the C++ compiler. Unlike `CMAKE_CXX_FLAGS`, these will not be used to build e.g. cadical.")
set(LEAN_EXTRA_CXX_FLAGS "" CACHE STRING "Additional flags used by the C++ compiler")
set(LEAN_TEST_VARS "LEAN_CC=${CMAKE_C_COMPILER}" CACHE STRING "Additional environment variables used when running tests")
if (NOT CMAKE_BUILD_TYPE)
@@ -191,7 +191,7 @@ endif()
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/Modules")
# Initialize CXXFLAGS.
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${LEAN_EXTRA_CXX_FLAGS} -DLEAN_BUILD_TYPE=\"${CMAKE_BUILD_TYPE}\" -DLEAN_EXPORTING")
set(CMAKE_CXX_FLAGS "${LEAN_EXTRA_CXX_FLAGS} -DLEAN_BUILD_TYPE=\"${CMAKE_BUILD_TYPE}\" -DLEAN_EXPORTING")
set(CMAKE_CXX_FLAGS_DEBUG "-DLEAN_DEBUG")
set(CMAKE_CXX_FLAGS_MINSIZEREL "-DNDEBUG")
set(CMAKE_CXX_FLAGS_RELEASE "-DNDEBUG")

View File

@@ -14,6 +14,7 @@ public import Init.ByCases
public import Init.RCases
public import Init.Core
public import Init.Control
public import Init.Data.Basic
public import Init.WF
public import Init.WFTactics
public import Init.Data

View File

@@ -44,10 +44,3 @@ theorem apply_ite (f : α → β) (P : Prop) [Decidable P] (x y : α) :
/-- A `dite` whose results do not actually depend on the condition may be reduced to an `ite`. -/
@[simp] theorem dite_eq_ite [Decidable P] :
(dite P (fun _ => a) (fun _ => b)) = ite P a b := rfl
-- Remark: dite and ite are "defally equal" when we ignore the proofs.
@[deprecated dite_eq_ite (since := "2025-10-29")]
theorem dif_eq_if (c : Prop) {h : Decidable c} {α : Sort u} (t : α) (e : α) : dite c (fun _ => t) (fun _ => e) = ite c t e :=
match h with
| isTrue _ => rfl
| isFalse _ => rfl

View File

@@ -181,6 +181,9 @@ theorem not_imp_iff_and_not : ¬(a → b) ↔ a ∧ ¬b := Decidable.not_imp_iff
theorem not_and_iff_not_or_not : ¬(a b) ¬a ¬b := Decidable.not_and_iff_not_or_not
@[deprecated not_and_iff_not_or_not (since := "2025-03-18")]
abbrev not_and_iff_or_not_not := @not_and_iff_not_or_not
theorem not_iff : ¬(a b) (¬a b) := Decidable.not_iff
@[simp] theorem imp_iff_left_iff : (b a b) a b := Decidable.imp_iff_left_iff
@@ -205,5 +208,3 @@ export Classical (imp_iff_right_iff imp_and_neg_imp_iff and_or_imp not_imp)
/-- Show that an element extracted from `P : ∃ a, p a` using `P.choose` satisfies `p`. -/
theorem Exists.choose_spec {p : α Prop} (P : a, p a) : p P.choose := Classical.choose_spec P
grind_pattern Exists.choose_spec => P.choose

View File

@@ -25,7 +25,7 @@ instances are provided for the same type.
instance (priority := 500) instForInOfForIn' [ForIn' m ρ α d] : ForIn m ρ α where
forIn x b f := forIn' x b fun a _ => f a
@[simp] theorem forIn'_eq_forIn [d : Membership α ρ] [ForIn' m ρ α d] {β} (x : ρ) (b : β)
@[simp] theorem forIn'_eq_forIn [d : Membership α ρ] [ForIn' m ρ α d] {β} [Monad m] (x : ρ) (b : β)
(f : (a : α) a x β m (ForInStep β)) (g : (a : α) β m (ForInStep β))
(h : a m b, f a m b = g a b) :
forIn' x b f = forIn x b g := by
@@ -40,11 +40,14 @@ instance (priority := 500) instForInOfForIn' [ForIn' m ρ α d] : ForIn m ρ α
simp [h]
rfl
@[wf_preprocess] theorem forIn_eq_forIn' [d : Membership α ρ] [ForIn' m ρ α d] {β}
@[wf_preprocess] theorem forIn_eq_forIn' [d : Membership α ρ] [ForIn' m ρ α d] {β} [Monad m]
(x : ρ) (b : β) (f : (a : α) β m (ForInStep β)) :
forIn x b f = forIn' x b (fun x h => binderNameHint x f <| binderNameHint h () <| f x) := by
rfl
@[deprecated forIn_eq_forIn' (since := "2025-04-04")]
abbrev forIn_eq_forin' := @forIn_eq_forIn'
/--
Extracts the value from a `ForInStep`, ignoring whether it is `ForInStep.done` or `ForInStep.yield`.
-/
@@ -403,7 +406,7 @@ class ForM (m : Type u → Type v) (γ : Type w₁) (α : outParam (Type w₂))
/--
Runs the monadic action `f` on each element of the collection `coll`.
-/
forM (coll : γ) (f : α m PUnit) : m PUnit
forM [Monad m] (coll : γ) (f : α m PUnit) : m PUnit
export ForM (forM)

View File

@@ -148,23 +148,6 @@ This is the inverse of `ExceptT.mk`.
@[always_inline, inline, expose]
def ExceptT.run {ε : Type u} {m : Type u Type v} {α : Type u} (x : ExceptT ε m α) : m (Except ε α) := x
/--
Use a monadic action that may throw an exception by providing explicit success and failure
continuations.
-/
@[always_inline, inline, expose]
def ExceptT.runK [Monad m] (x : ExceptT ε m α) (ok : α m β) (error : ε m β) : m β :=
x.run >>= (·.casesOn error ok)
/--
Returns the value of a computation, forgetting whether it was an exception or a success.
This corresponds to early return.
-/
@[always_inline, inline, expose]
def ExceptT.runCatch [Monad m] (x : ExceptT α m α) : m α :=
x.runK pure pure
namespace ExceptT
variable {ε : Type u} {m : Type u Type v} [Monad m]

View File

@@ -170,7 +170,6 @@ theorem bind_pure_unit [Monad m] [LawfulMonad m] {x : m PUnit} : (x >>= fun _ =>
theorem map_congr [Functor m] {x : m α} {f g : α β} (h : a, f a = g a) : (f <$> x : m β) = g <$> x := by
simp [funext h]
@[deprecated seq_eq_bind_map (since := "2025-10-26")]
theorem seq_eq_bind {α β : Type u} [Monad m] [LawfulMonad m] (mf : m (α β)) (x : m α) : mf <*> x = mf >>= fun f => f <$> x := by
rw [bind_map]
@@ -256,4 +255,20 @@ instance : LawfulMonad Id := by
@[simp] theorem run_seqLeft (x y : Id α) : (x <* y).run = x.run := rfl
@[simp] theorem run_seq (f : Id (α β)) (x : Id α) : (f <*> x).run = f.run x.run := rfl
-- These lemmas are bad as they abuse the defeq of `Id α` and `α`
@[deprecated run_map (since := "2025-03-05")] theorem map_eq (x : Id α) (f : α β) : f <$> x = f x := rfl
@[deprecated run_bind (since := "2025-03-05")] theorem bind_eq (x : Id α) (f : α id β) : x >>= f = f x := rfl
@[deprecated run_pure (since := "2025-03-05")] theorem pure_eq (a : α) : (pure a : Id α) = a := rfl
end Id
/-! # Option -/
instance : LawfulMonad Option := LawfulMonad.mk'
(id_map := fun x => by cases x <;> rfl)
(pure_bind := fun _ _ => rfl)
(bind_assoc := fun x _ _ => by cases x <;> rfl)
(bind_pure_comp := fun _ x => by cases x <;> rfl)
instance : LawfulApplicative Option := inferInstance
instance : LawfulFunctor Option := inferInstance

View File

@@ -189,12 +189,12 @@ instance [Monad m] [LawfulMonad m] : LawfulMonad (OptionT m) where
@[simp] theorem run_seq [Monad m] [LawfulMonad m] (f : OptionT m (α β)) (x : OptionT m α) :
(f <*> x).run = Option.elimM f.run (pure none) (fun f => Option.map f <$> x.run) := by
simp [seq_eq_bind_map, Option.elimM, Option.elim]
simp [seq_eq_bind, Option.elimM, Option.elim]
@[simp] theorem run_seqLeft [Monad m] [LawfulMonad m] (x : OptionT m α) (y : OptionT m β) :
(x <* y).run = Option.elimM x.run (pure none)
(fun x => Option.map (Function.const β x) <$> y.run) := by
simp [seqLeft_eq, seq_eq_bind_map, Option.elimM, OptionT.run_bind]
simp [seqLeft_eq, seq_eq_bind, Option.elimM, OptionT.run_bind]
@[simp] theorem run_seqRight [Monad m] [LawfulMonad m] (x : OptionT m α) (y : OptionT m β) :
(x *> y).run = Option.elimM x.run (pure none) (Function.const α y.run) := by
@@ -219,7 +219,7 @@ instance : LawfulMonad Option := LawfulMonad.mk'
(id_map := fun x => by cases x <;> rfl)
(pure_bind := fun _ _ => by rfl)
(bind_assoc := fun a _ _ => by cases a <;> rfl)
(bind_pure_comp := fun _ x => by cases x <;> rfl)
(bind_pure_comp := bind_pure_comp)
instance : LawfulApplicative Option := inferInstance
instance : LawfulFunctor Option := inferInstance

View File

@@ -23,7 +23,7 @@ theorem monadLift_map [LawfulMonad m] [LawfulMonad n] (f : α → β) (ma : m α
theorem monadLift_seq [LawfulMonad m] [LawfulMonad n] (mf : m (α β)) (ma : m α) :
monadLift (mf <*> ma) = monadLift mf <*> (monadLift ma : n α) := by
simp only [seq_eq_bind_map, monadLift_map, monadLift_bind]
simp only [seq_eq_bind, monadLift_map, monadLift_bind]
theorem monadLift_seqLeft [LawfulMonad m] [LawfulMonad n] (x : m α) (y : m β) :
monadLift (x <* y) = (monadLift x : n α) <* (monadLift y : n β) := by

View File

@@ -377,7 +377,7 @@ class ForIn (m : Type u₁ → Type u₂) (ρ : Type u) (α : outParam (Type v))
More information about the translation of `for` loops into `ForIn.forIn` is available in [the Lean
reference manual](lean-manual://section/monad-iteration-syntax).
-/
forIn {β} (xs : ρ) (b : β) (f : α β m (ForInStep β)) : m β
forIn {β} [Monad m] (xs : ρ) (b : β) (f : α β m (ForInStep β)) : m β
export ForIn (forIn)
@@ -405,7 +405,7 @@ class ForIn' (m : Type u₁ → Type u₂) (ρ : Type u) (α : outParam (Type v)
More information about the translation of `for` loops into `ForIn'.forIn'` is available in [the
Lean reference manual](lean-manual://section/monad-iteration-syntax).
-/
forIn' {β} (x : ρ) (b : β) (f : (a : α) a x β m (ForInStep β)) : m β
forIn' {β} [Monad m] (x : ρ) (b : β) (f : (a : α) a x β m (ForInStep β)) : m β
export ForIn' (forIn')
@@ -600,6 +600,17 @@ export LawfulSingleton (insert_empty_eq)
attribute [simp] insert_empty_eq
@[deprecated insert_empty_eq (since := "2025-03-12")]
theorem insert_emptyc_eq [EmptyCollection β] [Insert α β] [Singleton α β]
[LawfulSingleton α β] (x : α) : (insert x : β) = singleton x :=
insert_empty_eq _
@[deprecated insert_empty_eq (since := "2025-03-12")]
theorem LawfulSingleton.insert_emptyc_eq [EmptyCollection β] [Insert α β] [Singleton α β]
[LawfulSingleton α β] (x : α) : (insert x : β) = singleton x :=
insert_empty_eq _
/-- Type class used to implement the notation `{ a ∈ c | p a }` -/
class Sep (α : outParam <| Type u) (γ : Type v) where
/-- Computes `{ a ∈ c | p a }`. -/
@@ -1084,6 +1095,14 @@ theorem of_toBoolUsing_eq_true {p : Prop} {d : Decidable p} (h : toBoolUsing d =
theorem of_toBoolUsing_eq_false {p : Prop} {d : Decidable p} (h : toBoolUsing d = false) : ¬p :=
of_decide_eq_false h
set_option linter.missingDocs false in
@[deprecated of_toBoolUsing_eq_true (since := "2025-04-04")]
abbrev ofBoolUsing_eq_true := @of_toBoolUsing_eq_true
set_option linter.missingDocs false in
@[deprecated of_toBoolUsing_eq_false (since := "2025-04-04")]
abbrev ofBoolUsing_eq_false := @of_toBoolUsing_eq_false
instance : Decidable True :=
isTrue trivial
@@ -1146,7 +1165,6 @@ end
else isFalse (fun h => absurd (h hp) hq)
else isTrue (fun h => absurd h hp)
@[inline]
instance {p q} [Decidable p] [Decidable q] : Decidable (p q) :=
if hp : p then
if hq : q then
@@ -1188,13 +1206,17 @@ theorem dif_neg {c : Prop} {h : Decidable c} (hnc : ¬c) {α : Sort u} {t : c
| isTrue hc => absurd hc hnc
| isFalse _ => rfl
@[macro_inline]
-- Remark: dite and ite are "defally equal" when we ignore the proofs.
theorem dif_eq_if (c : Prop) {h : Decidable c} {α : Sort u} (t : α) (e : α) : dite c (fun _ => t) (fun _ => e) = ite c t e :=
match h with
| isTrue _ => rfl
| isFalse _ => rfl
instance {c t e : Prop} [dC : Decidable c] [dT : Decidable t] [dE : Decidable e] : Decidable (if c then t else e) :=
match dC with
| isTrue _ => dT
| isFalse _ => dE
@[inline]
instance {c : Prop} {t : c Prop} {e : ¬c Prop} [dC : Decidable c] [dT : h, Decidable (t h)] [dE : h, Decidable (e h)] : Decidable (if h : c then t h else e h) :=
match dC with
| isTrue hc => dT hc
@@ -1345,12 +1367,12 @@ namespace Subtype
theorem exists_of_subtype {α : Type u} {p : α Prop} : { x // p x } Exists (fun x => p x)
| a, h => a, h
variable {α : Sort u} {p : α Prop}
set_option linter.missingDocs false in
@[deprecated exists_of_subtype (since := "2025-04-04")]
abbrev existsOfSubtype := @exists_of_subtype
protected theorem ext : {a1 a2 : {x // p x}}, val a1 = val a2 a1 = a2
| _, _, _, _, rfl => rfl
variable {α : Type u} {p : α Prop}
@[deprecated Subtype.ext (since := "2025-10-26")]
protected theorem eq : {a1 a2 : {x // p x}}, val a1 = val a2 a1 = a2
| _, _, _, _, rfl => rfl
@@ -1365,9 +1387,9 @@ instance {α : Type u} {p : α → Prop} [BEq α] [ReflBEq α] : ReflBEq {x : α
rfl {x} := BEq.refl x.1
instance {α : Type u} {p : α Prop} [BEq α] [LawfulBEq α] : LawfulBEq {x : α // p x} where
eq_of_beq h := Subtype.ext (eq_of_beq h)
eq_of_beq h := Subtype.eq (eq_of_beq h)
instance {α : Sort u} {p : α Prop} [DecidableEq α] : DecidableEq {x : α // p x} :=
instance {α : Type u} {p : α Prop} [DecidableEq α] : DecidableEq {x : α // p x} :=
fun a, h₁ b, h₂ =>
if h : a = b then isTrue (by subst h; exact rfl)
else isFalse (fun h' => Subtype.noConfusion h' (fun h' => absurd h' h))
@@ -1468,8 +1490,6 @@ def Prod.map {α₁ : Type u₁} {α₂ : Type u₂} {β₁ : Type v₁} {β₂
@[simp] theorem Prod.map_apply (f : α β) (g : γ δ) (x) (y) :
Prod.map f g (x, y) = (f x, g y) := rfl
-- We add `@[grind =]` to these in `Init.Data.Prod`.
@[simp] theorem Prod.map_fst (f : α β) (g : γ δ) (x) : (Prod.map f g x).1 = f x.1 := rfl
@[simp] theorem Prod.map_snd (f : α β) (g : γ δ) (x) : (Prod.map f g x).2 = g x.2 := rfl
@@ -1486,24 +1506,20 @@ protected theorem PSigma.eta {α : Sort u} {β : α → Sort v} {a₁ a₂ : α}
/-! # Universe polymorphic unit -/
theorem PUnit.ext (a b : PUnit) : a = b := by
cases a; cases b; exact rfl
@[deprecated PUnit.ext (since := "2025-10-26")]
theorem PUnit.subsingleton (a b : PUnit) : a = b := by
cases a; cases b; exact rfl
theorem PUnit.eq_punit (a : PUnit) : a = :=
PUnit.ext a
PUnit.subsingleton a
instance : Subsingleton PUnit :=
Subsingleton.intro PUnit.ext
Subsingleton.intro PUnit.subsingleton
instance : Inhabited PUnit where
default :=
instance : DecidableEq PUnit :=
fun a b => isTrue (PUnit.ext a b)
fun a b => isTrue (PUnit.subsingleton a b)
/-! # Setoid -/
@@ -1590,7 +1606,7 @@ gen_injective_theorems% PSum
gen_injective_theorems% Sigma
gen_injective_theorems% String
gen_injective_theorems% String.Pos.Raw
gen_injective_theorems% Substring.Raw
gen_injective_theorems% Substring
gen_injective_theorems% Subtype
gen_injective_theorems% Sum
gen_injective_theorems% Task
@@ -2507,7 +2523,8 @@ class Antisymm (r : αα → Prop) : Prop where
/-- An antisymmetric relation `r` satisfies `r a b → r b a → a = b`. -/
antisymm (a b : α) : r a b r b a a = b
/-- `Asymm r` means that the binary relation `r` is asymmetric, that is, `r a b → ¬ r b a`. -/
/-- `Asymm r` means that the binary relation `r` is asymmetric, that is,
`r a b → ¬ r b a`. -/
class Asymm (r : α α Prop) : Prop where
/-- An asymmetric relation satisfies `r a b → ¬ r b a`. -/
asymm : a b, r a b ¬r b a
@@ -2517,19 +2534,16 @@ class Symm (r : αα → Prop) : Prop where
/-- A symmetric relation satisfies `r a b → r b a`. -/
symm : a b, r a b r b a
/-- `Total X r` means that the binary relation `r` on `X` is total, that is, `r a b` or `r b a`. -/
/-- `Total X r` means that the binary relation `r` on `X` is total, that is, that for any
`x y : X` we have `r x y` or `r y x`. -/
class Total (r : α α Prop) : Prop where
/-- A total relation satisfies `r a b` or `r b a`. -/
/-- A total relation satisfies `r a b r b a`. -/
total : a b, r a b r b a
/-- `Irrefl r` means the binary relation `r` is irreflexive, that is, `r x x` never holds. -/
/-- `Irrefl r` means the binary relation `r` is irreflexive, that is, `r x x` never
holds. -/
class Irrefl (r : α α Prop) : Prop where
/-- An irreflexive relation satisfies `¬ r a a`. -/
irrefl : a, ¬r a a
/-- `Trichotomous r` says that `r` is trichotomous, that is, `¬ r a b → ¬ r b a → a = b`. -/
class Trichotomous (r : α α Prop) : Prop where
/-- An trichotomous relation `r` satisfies `¬ r a b → ¬ r b a → a = b`. -/
trichotomous (a b : α) : ¬ r a b ¬ r b a a = b
end Std

View File

@@ -6,6 +6,7 @@ Authors: Leonardo de Moura
module
prelude
public import Init.Data.Basic
public import Init.Data.Nat
public import Init.Data.Bool
public import Init.Data.BitVec

View File

@@ -749,6 +749,9 @@ and simplifies these to the function directly taking the value.
(Array.replicate n x).unattach = Array.replicate n x.1 := by
simp [unattach]
@[deprecated unattach_replicate (since := "2025-03-18")]
abbrev unattach_mkArray := @unattach_replicate
/-! ### Well-founded recursion preprocessing setup -/
@[wf_preprocess] theorem map_wfParam {xs : Array α} {f : α β} :

View File

@@ -209,6 +209,20 @@ Examples:
def replicate {α : Type u} (n : Nat) (v : α) : Array α where
toList := List.replicate n v
/--
Creates an array that contains `n` repetitions of `v`.
The corresponding `List` function is `List.replicate`.
Examples:
* `Array.mkArray 2 true = #[true, true]`
* `Array.mkArray 3 () = #[(), (), ()]`
* `Array.mkArray 0 "anything" = #[]`
-/
@[extern "lean_mk_array", deprecated replicate (since := "2025-03-18")]
def mkArray {α : Type u} (n : Nat) (v : α) : Array α where
toList := List.replicate n v
/--
Swaps two elements of an array. The modification is performed in-place when the reference to the
array is unique.
@@ -226,7 +240,7 @@ def swap (xs : Array α) (i j : @& Nat) (hi : i < xs.size := by get_elem_tactic)
let xs' := xs.set i v₂
xs'.set j v₁ (Nat.lt_of_lt_of_eq hj (size_set _).symm)
@[simp, grind =] theorem size_swap {xs : Array α} {i j : Nat} {hi hj} : (xs.swap i j hi hj).size = xs.size := by
@[simp] theorem size_swap {xs : Array α} {i j : Nat} {hi hj} : (xs.swap i j hi hj).size = xs.size := by
change ((xs.set i xs[j]).set j xs[i]
(Nat.lt_of_lt_of_eq hj (size_set _).symm)).size = xs.size
rw [size_set, size_set]
@@ -242,7 +256,7 @@ Examples:
* `#["red", "green", "blue", "brown"].swapIfInBounds 0 4 = #["red", "green", "blue", "brown"]`
* `#["red", "green", "blue", "brown"].swapIfInBounds 9 2 = #["red", "green", "blue", "brown"]`
-/
@[extern "lean_array_swap", expose]
@[extern "lean_array_swap", grind]
def swapIfInBounds (xs : Array α) (i j : @& Nat) : Array α :=
if h₁ : i < xs.size then
if h₂ : j < xs.size then swap xs i j
@@ -448,7 +462,7 @@ Examples:
-/
abbrev take (xs : Array α) (i : Nat) : Array α := extract xs 0 i
@[simp, grind =] theorem take_eq_extract {xs : Array α} {i : Nat} : xs.take i = xs.extract 0 i := rfl
@[simp] theorem take_eq_extract {xs : Array α} {i : Nat} : xs.take i = xs.extract 0 i := rfl
/--
Removes the first `i` elements of `xs`. If `xs` has fewer than `i` elements, the new array is empty.
@@ -462,7 +476,7 @@ Examples:
-/
abbrev drop (xs : Array α) (i : Nat) : Array α := extract xs i xs.size
@[simp, grind =] theorem drop_eq_extract {xs : Array α} {i : Nat} : xs.drop i = xs.extract i xs.size := rfl
@[simp] theorem drop_eq_extract {xs : Array α} {i : Nat} : xs.drop i = xs.extract i xs.size := rfl
@[inline]
unsafe def modifyMUnsafe [Monad m] (xs : Array α) (i : Nat) (f : α m α) : m (Array α) := do
@@ -570,7 +584,7 @@ protected def forIn' {α : Type u} {β : Type v} {m : Type v → Type w} [Monad
| ForInStep.yield b => loop i (Nat.le_of_lt h') b
loop as.size (Nat.le_refl _) b
instance [Monad m] : ForIn' m (Array α) α inferInstance where
instance : ForIn' m (Array α) α inferInstance where
forIn' := Array.forIn'
-- No separate `ForIn` instance is required because it can be derived from `ForIn'`.
@@ -1001,7 +1015,7 @@ unless `start < stop`. By default, the entire array is used.
protected def forM {α : Type u} {m : Type v Type w} [Monad m] (f : α m PUnit) (as : Array α) (start := 0) (stop := as.size) : m PUnit :=
as.foldlM (fun _ => f) start stop
instance [Monad m] : ForM m (Array α) α where
instance : ForM m (Array α) α where
forM xs f := Array.forM f xs
-- We simplify `Array.forM` to `forM`.
@@ -1295,7 +1309,7 @@ decreasing_by simp_wf; decreasing_trivial_pre_omega
/--
Returns the index of the first element equal to `a`, or `none` if no element is equal
Returns the index of the first element equal to `a`, or the size of the array if no element is equal
to `a`. The index is returned as a `Fin`, which guarantees that it is in bounds.
Examples:
@@ -1704,7 +1718,7 @@ def popWhile (p : α → Bool) (as : Array α) : Array α :=
as
decreasing_by simp_wf; decreasing_trivial_pre_omega
@[simp, grind =] theorem popWhile_empty {p : α Bool} :
@[simp] theorem popWhile_empty {p : α Bool} :
popWhile p #[] = #[] := by
simp [popWhile]
@@ -1751,8 +1765,7 @@ termination_by xs.size - i
decreasing_by simp_wf; exact Nat.sub_succ_lt_self _ _ h
-- This is required in `Lean.Data.PersistentHashMap`.
@[simp, grind =]
theorem size_eraseIdx {xs : Array α} (i : Nat) (h) : (xs.eraseIdx i h).size = xs.size - 1 := by
@[simp] theorem size_eraseIdx {xs : Array α} (i : Nat) (h) : (xs.eraseIdx i h).size = xs.size - 1 := by
induction xs, i, h using Array.eraseIdx.induct with
| @case1 xs i h h' xs' ih =>
unfold eraseIdx
@@ -2134,3 +2147,5 @@ instance [ToString α] : ToString (Array α) where
toString xs := String.Internal.append "#" (toString xs.toList)
end Array
export Array (mkArray)

View File

@@ -31,7 +31,7 @@ theorem foldlM_toList.aux [Monad m]
· cases Nat.not_le_of_gt _ (Nat.zero_add _ H)
· rename_i i; rw [Nat.succ_add] at H
simp [foldlM_toList.aux (j := j+1) H]
rw (occs := [2]) [ List.getElem_cons_drop _]
rw (occs := [2]) [ List.getElem_cons_drop_succ_eq_drop _]
simp
· rw [List.drop_of_length_le (Nat.ge_of_not_lt _)]; simp
@@ -100,15 +100,9 @@ abbrev push_toList := @toList_push
@[simp, grind =] theorem empty_append {xs : Array α} : #[] ++ xs = xs := by
apply ext'; simp only [toList_append, List.nil_append]
@[simp] theorem append_assoc {xs ys zs : Array α} : xs ++ ys ++ zs = xs ++ (ys ++ zs) := by
@[simp, grind _=_] theorem append_assoc {xs ys zs : Array α} : xs ++ ys ++ zs = xs ++ (ys ++ zs) := by
apply ext'; simp only [toList_append, List.append_assoc]
grind_pattern append_assoc => (xs ++ ys) ++ zs where
xs =/= #[]; ys =/= #[]; zs =/= #[]
grind_pattern append_assoc => xs ++ (ys ++ zs) where
xs =/= #[]; ys =/= #[]; zs =/= #[]
@[simp] theorem appendList_eq_append {xs : Array α} {l : List α} : xs.appendList l = xs ++ l := rfl
@[simp, grind =] theorem toList_appendList {xs : Array α} {l : List α} :
@@ -116,4 +110,6 @@ grind_pattern append_assoc => xs ++ (ys ++ zs) where
rw [ appendList_eq_append]; unfold Array.appendList
induction l generalizing xs <;> simp [*]
end Array

View File

@@ -99,6 +99,9 @@ theorem countP_le_size : countP p xs ≤ xs.size := by
theorem countP_replicate {a : α} {n : Nat} : countP p (replicate n a) = if p a then n else 0 := by
simp [ List.toArray_replicate, List.countP_replicate]
@[deprecated countP_replicate (since := "2025-03-18")]
abbrev countP_mkArray := @countP_replicate
theorem boole_getElem_le_countP {xs : Array α} {i : Nat} (h : i < xs.size) :
(if p xs[i] then 1 else 0) xs.countP p := by
rcases xs with xs
@@ -259,9 +262,15 @@ theorem count_eq_size {xs : Array α} : count a xs = xs.size ↔ ∀ b ∈ xs, a
@[simp] theorem count_replicate_self {a : α} {n : Nat} : count a (replicate n a) = n := by
simp [ List.toArray_replicate]
@[deprecated count_replicate_self (since := "2025-03-18")]
abbrev count_mkArray_self := @count_replicate_self
theorem count_replicate {a b : α} {n : Nat} : count a (replicate n b) = if b == a then n else 0 := by
simp [ List.toArray_replicate, List.count_replicate]
@[deprecated count_replicate (since := "2025-03-18")]
abbrev count_mkArray := @count_replicate
theorem filter_beq {xs : Array α} (a : α) : xs.filter (· == a) = replicate (count a xs) a := by
rcases xs with xs
simp [List.filter_beq]
@@ -275,6 +284,9 @@ theorem replicate_count_eq_of_count_eq_size {xs : Array α} (h : count a xs = xs
rw [ toList_inj]
simp [List.replicate_count_eq_of_count_eq_length (by simpa using h)]
@[deprecated replicate_count_eq_of_count_eq_size (since := "2025-03-18")]
abbrev mkArray_count_eq_of_count_eq_size := @replicate_count_eq_of_count_eq_size
@[simp] theorem count_filter {xs : Array α} (h : p a) : count a (filter p xs) = count a xs := by
rcases xs with xs
simp [List.count_filter, h]

View File

@@ -89,41 +89,11 @@ theorem isEqv_self_beq [BEq α] [ReflBEq α] (xs : Array α) : Array.isEqv xs xs
theorem isEqv_self [DecidableEq α] (xs : Array α) : Array.isEqv xs xs (· = ·) = true := by
simp [isEqv, isEqvAux_self]
def instDecidableEqImpl [DecidableEq α] : DecidableEq (Array α) := fun xs ys =>
match h:isEqv xs ys (fun a b => a = b) with
| true => isTrue (eq_of_isEqv xs ys h)
| false => isFalse (by subst ·; rw [isEqv_self] at h; contradiction)
instance instDecidableEq [DecidableEq α] : DecidableEq (Array α) := fun xs ys =>
match xs with
| [] =>
match ys with
| [] => isTrue rfl
| _ :: _ => isFalse (Array.noConfusion · (List.noConfusion ·))
| a :: as =>
match ys with
| [] => isFalse (Array.noConfusion · (List.noConfusion ·))
| b :: bs => instDecidableEqImpl a :: as b :: bs
@[csimp]
theorem instDecidableEq_csimp : @instDecidableEq = @instDecidableEqImpl :=
Subsingleton.allEq _ _
/--
Equality with `#[]` is decidable even if the underlying type does not have decidable equality.
-/
instance instDecidableEqEmp (xs : Array α) : Decidable (xs = #[]) :=
match xs with
| [] => isTrue rfl
| _ :: _ => isFalse (Array.noConfusion · (List.noConfusion ·))
/--
Equality with `#[]` is decidable even if the underlying type does not have decidable equality.
-/
instance instDecidableEmpEq (ys : Array α) : Decidable (#[] = ys) :=
match ys with
| [] => isTrue rfl
| _ :: _ => isFalse (Array.noConfusion · (List.noConfusion ·))
instance [DecidableEq α] : DecidableEq (Array α) :=
fun xs ys =>
match h:isEqv xs ys (fun a b => a = b) with
| true => isTrue (eq_of_isEqv xs ys h)
| false => isFalse fun h' => by subst h'; rw [isEqv_self] at h; contradiction
theorem beq_eq_decide [BEq α] (xs ys : Array α) :
(xs == ys) = if h : xs.size = ys.size then

View File

@@ -139,16 +139,25 @@ theorem eraseP_replicate {n : Nat} {a : α} {p : α → Bool} :
simp only [ List.toArray_replicate, List.eraseP_toArray, List.eraseP_replicate]
split <;> simp
@[deprecated eraseP_replicate (since := "2025-03-18")]
abbrev eraseP_mkArray := @eraseP_replicate
@[simp] theorem eraseP_replicate_of_pos {n : Nat} {a : α} (h : p a) :
(replicate n a).eraseP p = replicate (n - 1) a := by
simp only [ List.toArray_replicate, List.eraseP_toArray]
simp [h]
@[deprecated eraseP_replicate_of_pos (since := "2025-03-18")]
abbrev eraseP_mkArray_of_pos := @eraseP_replicate_of_pos
@[simp] theorem eraseP_replicate_of_neg {n : Nat} {a : α} (h : ¬p a) :
(replicate n a).eraseP p = replicate n a := by
simp only [ List.toArray_replicate, List.eraseP_toArray]
simp [h]
@[deprecated eraseP_replicate_of_neg (since := "2025-03-18")]
abbrev eraseP_mkArray_of_neg := @eraseP_replicate_of_neg
theorem eraseP_eq_iff {p} {xs : Array α} :
xs.eraseP p = ys
(( a xs, ¬ p a) xs = ys)
@@ -269,6 +278,9 @@ theorem erase_replicate [LawfulBEq α] {n : Nat} {a b : α} :
simp only [List.erase_replicate, beq_iff_eq, List.toArray_replicate]
split <;> simp
@[deprecated erase_replicate (since := "2025-03-18")]
abbrev erase_mkArray := @erase_replicate
-- The arguments `a b` are explicit,
-- so they can be specified to prevent `simp` repeatedly applying the lemma.
@[grind =]
@@ -296,11 +308,17 @@ theorem erase_eq_iff [LawfulBEq α] {a : α} {xs : Array α} :
simp only [ List.toArray_replicate, List.erase_toArray]
simp
@[deprecated erase_replicate_self (since := "2025-03-18")]
abbrev erase_mkArray_self := @erase_replicate_self
@[simp] theorem erase_replicate_ne [LawfulBEq α] {a b : α} (h : !b == a) :
(replicate n a).erase b = replicate n a := by
rw [erase_of_not_mem]
simp_all
@[deprecated erase_replicate_ne (since := "2025-03-18")]
abbrev erase_mkArray_ne := @erase_replicate_ne
end erase
/-! ### eraseIdxIfInBounds -/
@@ -411,6 +429,9 @@ theorem eraseIdx_replicate {n : Nat} {a : α} {k : Nat} {h} :
simp only [ List.toArray_replicate, List.eraseIdx_toArray]
simp [List.eraseIdx_replicate, h]
@[deprecated eraseIdx_replicate (since := "2025-03-18")]
abbrev eraseIdx_mkArray := @eraseIdx_replicate
theorem mem_eraseIdx_iff_getElem {x : α} {xs : Array α} {k} {h} : x xs.eraseIdx k h i w, i k xs[i]'w = x := by
rcases xs with xs
simp [List.mem_eraseIdx_iff_getElem, *]

View File

@@ -200,7 +200,7 @@ theorem getElem?_extract_of_succ {as : Array α} {j : Nat} :
simp [getElem?_extract]
omega
@[simp] theorem extract_extract {as : Array α} {i j k l : Nat} :
@[simp, grind =] theorem extract_extract {as : Array α} {i j k l : Nat} :
(as.extract i j).extract k l = as.extract (i + k) (min (i + l) j) := by
ext m h₁ h₂
· simp
@@ -208,9 +208,6 @@ theorem getElem?_extract_of_succ {as : Array α} {j : Nat} :
· simp only [size_extract] at h₁ h₂
simp [Nat.add_assoc]
grind_pattern extract_extract => (as.extract i j).extract k l where
as =/= #[]
theorem extract_eq_empty_of_eq_empty {as : Array α} {i j : Nat} (h : as = #[]) :
as.extract i j = #[] := by
simp [h]
@@ -292,6 +289,9 @@ theorem extract_append_right {as bs : Array α} :
· simp only [size_extract, size_replicate] at h₁ h₂
simp only [getElem_extract, getElem_replicate]
@[deprecated extract_replicate (since := "2025-03-18")]
abbrev extract_mkArray := @extract_replicate
theorem extract_eq_extract_right {as : Array α} {i j j' : Nat} :
as.extract i j = as.extract i j' min (j - i) (as.size - i) = min (j' - i) (as.size - i) := by
rcases as with as
@@ -409,6 +409,8 @@ theorem popWhile_append {xs ys : Array α} :
rcases ys with ys
simp only [List.append_toArray, List.popWhile_toArray, List.reverse_append, List.dropWhile_append,
List.isEmpty_iff, List.isEmpty_toArray, List.isEmpty_reverse]
-- Why do these not fire with `simp`?
rw [List.popWhile_toArray, List.isEmpty_toArray, List.isEmpty_reverse]
split
· rfl
· simp
@@ -427,20 +429,32 @@ theorem popWhile_append {xs ys : Array α} :
(replicate n a).takeWhile p = (replicate n a).filter p := by
simp [ List.toArray_replicate]
@[deprecated takeWhile_replicate_eq_filter (since := "2025-03-18")]
abbrev takeWhile_mkArray_eq_filter := @takeWhile_replicate_eq_filter
theorem takeWhile_replicate {p : α Bool} :
(replicate n a).takeWhile p = if p a then replicate n a else #[] := by
simp [takeWhile_replicate_eq_filter, filter_replicate]
@[deprecated takeWhile_replicate (since := "2025-03-18")]
abbrev takeWhile_mkArray := @takeWhile_replicate
@[simp] theorem popWhile_replicate_eq_filter_not {p : α Bool} :
(replicate n a).popWhile p = (replicate n a).filter (fun a => !p a) := by
simp [ List.toArray_replicate, List.filter_reverse]
@[deprecated popWhile_replicate_eq_filter_not (since := "2025-03-18")]
abbrev popWhile_mkArray_eq_filter_not := @popWhile_replicate_eq_filter_not
theorem popWhile_replicate {p : α Bool} :
(replicate n a).popWhile p = if p a then #[] else replicate n a := by
simp only [popWhile_replicate_eq_filter_not, size_replicate, filter_replicate, Bool.not_eq_eq_eq_not,
Bool.not_true]
split <;> simp_all
@[deprecated popWhile_replicate (since := "2025-03-18")]
abbrev popWhile_mkArray := @popWhile_replicate
theorem extract_takeWhile {as : Array α} {i : Nat} :
(as.takeWhile p).extract 0 i = (as.extract 0 i).takeWhile p := by
rcases as with as

View File

@@ -129,19 +129,31 @@ theorem getElem_zero_flatten {xss : Array (Array α)} (h) :
theorem findSome?_replicate : findSome? f (replicate n a) = if n = 0 then none else f a := by
simp [ List.toArray_replicate, List.findSome?_replicate]
@[deprecated findSome?_replicate (since := "2025-03-18")]
abbrev findSome?_mkArray := @findSome?_replicate
@[simp] theorem findSome?_replicate_of_pos (h : 0 < n) : findSome? f (replicate n a) = f a := by
simp [findSome?_replicate, Nat.ne_of_gt h]
@[deprecated findSome?_replicate_of_pos (since := "2025-03-18")]
abbrev findSome?_mkArray_of_pos := @findSome?_replicate_of_pos
-- Argument is unused, but used to decide whether `simp` should unfold.
@[simp] theorem findSome?_replicate_of_isSome (_ : (f a).isSome) :
findSome? f (replicate n a) = if n = 0 then none else f a := by
simp [findSome?_replicate]
@[deprecated findSome?_replicate_of_isSome (since := "2025-03-18")]
abbrev findSome?_mkArray_of_isSome := @findSome?_replicate_of_isSome
@[simp] theorem findSome?_replicate_of_isNone (h : (f a).isNone) :
findSome? f (replicate n a) = none := by
rw [Option.isNone_iff_eq_none] at h
simp [findSome?_replicate, h]
@[deprecated findSome?_replicate_of_isNone (since := "2025-03-18")]
abbrev findSome?_mkArray_of_isNone := @findSome?_replicate_of_isNone
/-! ### find? -/
@[simp, grind =] theorem find?_empty : find? p #[] = none := rfl
@@ -306,10 +318,16 @@ theorem find?_replicate :
find? p (replicate n a) = if p a then some a else none := by
simp [find?_replicate, Nat.ne_of_gt h]
@[deprecated find?_replicate_of_size_pos (since := "2025-03-18")]
abbrev find?_mkArray_of_length_pos := @find?_replicate_of_size_pos
@[simp] theorem find?_replicate_of_pos (h : p a) :
find? p (replicate n a) = if n = 0 then none else some a := by
simp [find?_replicate, h]
@[deprecated find?_replicate_of_pos (since := "2025-03-18")]
abbrev find?_mkArray_of_pos := @find?_replicate_of_pos
@[simp] theorem find?_replicate_of_neg (h : ¬ p a) : find? p (replicate n a) = none := by
simp [find?_replicate, h]
@@ -565,6 +583,9 @@ theorem findIdx?_flatten {xss : Array (Array α)} {p : α → Bool} :
simp only [List.findIdx?_toArray]
simp
@[deprecated findIdx?_replicate (since := "2025-03-18")]
abbrev findIdx?_mkArray := @findIdx?_replicate
theorem findIdx?_eq_findSome?_zipIdx {xs : Array α} {p : α Bool} :
xs.findIdx? p = xs.zipIdx.findSome? fun a, i => if p a then some i else none := by
rcases xs with xs

View File

@@ -50,6 +50,6 @@ where
getLit_eq (xs : Array α) (i : Nat) (h₁ : xs.size = n) (h₂ : i < n) : xs.getLit i h₁ h₂ = getElem xs.toList i ((id (α := xs.toList.length = n) h₁) h₂) :=
rfl
go (i : Nat) (hi : i xs.size) : toListLitAux xs n hsz i hi (xs.toList.drop i) = xs.toList := by
induction i <;> simp only [List.drop, toListLitAux, getLit_eq, List.getElem_cons_drop, *]
induction i <;> simp only [List.drop, toListLitAux, getLit_eq, List.getElem_cons_drop_succ_eq_drop, *]
end Array

View File

@@ -245,13 +245,12 @@ theorem back_eq_of_push_eq {a b : α} {xs ys : Array α} (h : xs.push a = ys.pus
replace h := List.append_inj_right' h (by simp)
simpa using h
theorem push_eq_push {a b : α} {xs ys : Array α} : xs.push a = ys.push b a = b xs = ys := by
theorem pop_eq_of_push_eq {a b : α} {xs ys : Array α} (h : xs.push a = ys.push b) : xs = ys := by
cases xs
cases ys
simp [And.comm]
theorem pop_eq_of_push_eq {a b : α} {xs ys : Array α} (h : xs.push a = ys.push b) : xs = ys :=
(push_eq_push.1 h).2
simp at h
replace h := List.append_inj_left' h (by simp)
simp [h]
theorem push_inj_left {a : α} {xs ys : Array α} : xs.push a = ys.push a xs = ys :=
pop_eq_of_push_eq, fun h => by simp [h]
@@ -259,6 +258,15 @@ theorem push_inj_left {a : α} {xs ys : Array α} : xs.push a = ys.push a ↔ xs
theorem push_inj_right {a b : α} {xs : Array α} : xs.push a = xs.push b a = b :=
back_eq_of_push_eq, fun h => by simp [h]
theorem push_eq_push {a b : α} {xs ys : Array α} : xs.push a = ys.push b a = b xs = ys := by
constructor
· intro h
exact back_eq_of_push_eq h, pop_eq_of_push_eq h
· rintro rfl, rfl
rfl
theorem push_eq_append_singleton {as : Array α} {x : α} : as.push x = as ++ #[x] := rfl
theorem exists_push_of_ne_empty {xs : Array α} (h : xs #[]) :
(ys : Array α) (a : α), xs = ys.push a := by
rcases xs with xs
@@ -309,23 +317,41 @@ theorem singleton_inj : #[a] = #[b] ↔ a = b := by
@[simp, grind =] theorem size_replicate {n : Nat} {v : α} : (replicate n v).size = n :=
List.length_replicate ..
@[deprecated size_replicate (since := "2025-03-18")]
abbrev size_mkArray := @size_replicate
@[simp] theorem toList_replicate : (replicate n a).toList = List.replicate n a := by
simp only [replicate]
@[deprecated toList_replicate (since := "2025-03-18")]
abbrev toList_mkArray := @toList_replicate
@[simp, grind =] theorem replicate_zero : replicate 0 a = #[] := rfl
@[deprecated replicate_zero (since := "2025-03-18")]
abbrev mkArray_zero := @replicate_zero
@[grind =]
theorem replicate_succ : replicate (n + 1) a = (replicate n a).push a := by
apply toList_inj.1
simp [List.replicate_succ']
@[deprecated replicate_succ (since := "2025-03-18")]
abbrev mkArray_succ := @replicate_succ
@[simp, grind =] theorem getElem_replicate {n : Nat} {v : α} {i : Nat} (h : i < (replicate n v).size) :
(replicate n v)[i] = v := by simp [ getElem_toList]
@[deprecated getElem_replicate (since := "2025-03-18")]
abbrev getElem_mkArray := @getElem_replicate
@[grind =] theorem getElem?_replicate {n : Nat} {v : α} {i : Nat} :
(replicate n v)[i]? = if i < n then some v else none := by
simp [getElem?_def]
@[deprecated getElem?_replicate (since := "2025-03-18")]
abbrev getElem?_mkArray := @getElem?_replicate
/-! ### mem -/
@[grind ]
@@ -809,11 +835,6 @@ theorem contains_eq_true_of_mem [BEq α] [ReflBEq α] {a : α} {as : Array α} (
theorem elem_iff [BEq α] [LawfulBEq α] {a : α} {xs : Array α} :
elem a xs = true a xs := mem_of_contains_eq_true, contains_eq_true_of_mem
@[grind =]
theorem contains_iff_mem [BEq α] [LawfulBEq α] {a : α} {xs : Array α} :
xs.contains a = true a xs := mem_of_contains_eq_true, contains_eq_true_of_mem
@[deprecated contains_iff_mem (since := "2025-10-26")]
theorem contains_iff [BEq α] [LawfulBEq α] {a : α} {xs : Array α} :
xs.contains a = true a xs := mem_of_contains_eq_true, contains_eq_true_of_mem
@@ -1053,6 +1074,12 @@ theorem mem_or_eq_of_mem_setIfInBounds
cases xs
simp
@[deprecated beq_empty_eq (since := "2025-04-04")]
abbrev beq_empty_iff := @beq_empty_eq
@[deprecated empty_beq_eq (since := "2025-04-04")]
abbrev empty_beq_iff := @empty_beq_eq
@[simp, grind =] theorem push_beq_push [BEq α] {a b : α} {xs ys : Array α} :
(xs.push a == ys.push b) = (xs == ys && a == b) := by
cases xs
@@ -1073,6 +1100,9 @@ theorem size_eq_of_beq [BEq α] {xs ys : Array α} (h : xs == ys) : xs.size = ys
rw [Bool.eq_iff_iff]
simp +contextual
@[deprecated replicate_beq_replicate (since := "2025-03-18")]
abbrev mkArray_beq_mkArray := @replicate_beq_replicate
private theorem beq_of_beq_singleton [BEq α] {a b : α} : #[a] == #[b] a == b := by
intro h
have : isEqv #[a] #[b] BEq.beq = true := h
@@ -1136,7 +1166,7 @@ where
aux (i bs) :
mapM.map f xs i bs = (xs.toList.drop i).foldlM (fun bs a => bs.push <$> f a) bs := by
unfold mapM.map; split
· rw [ List.getElem_cons_drop _]
· rw [ List.getElem_cons_drop_succ_eq_drop _]
simp only [aux (i + 1), map_eq_pure_bind, List.foldlM_cons, bind_assoc,
pure_bind]
rfl
@@ -1628,15 +1658,12 @@ theorem filterMap_eq_filter {p : α → Bool} (w : stop = as.size) :
cases as
simp
@[grind =]
theorem filterMap_filterMap {f : α Option β} {g : β Option γ} {xs : Array α} :
filterMap g (filterMap f xs) = filterMap (fun x => (f x).bind g) xs := by
cases xs
simp [List.filterMap_filterMap]
grind_pattern filterMap_filterMap => filterMap g (filterMap f xs) where
f =/= some
g =/= some
@[grind =]
theorem map_filterMap {f : α Option β} {g : β γ} {xs : Array α} :
map g (filterMap f xs) = filterMap (fun x => (f x).map g) xs := by
@@ -1691,6 +1718,9 @@ theorem forall_none_of_filterMap_eq_empty (h : filterMap f xs = #[]) : ∀ x ∈
cases xs
simp
@[deprecated filterMap_eq_empty_iff (since := "2025-04-04")]
abbrev filterMap_eq_nil_iff := @filterMap_eq_empty_iff
theorem filterMap_eq_push_iff {f : α Option β} {xs : Array α} {ys : Array β} {b : β} :
filterMap f xs = ys.push b as a bs,
xs = as.push a ++ bs filterMap f as = ys f a = some b ( x, x bs f x = none) := by
@@ -1853,9 +1883,6 @@ theorem getElem_of_append {xs ys zs : Array α} (eq : xs = ys.push a ++ zs) (h :
theorem push_eq_append {a : α} {as : Array α} : as.push a = as ++ #[a] := rfl
@[deprecated push_eq_append (since := "2025-10-26")]
theorem push_eq_append_singleton {as : Array α} {x : α} : as.push x = as ++ #[x] := rfl
theorem append_inj {xs₁ xs₂ ys₁ ys₂ : Array α} (h : xs₁ ++ ys₁ = xs₂ ++ ys₂) (hl : xs₁.size = xs₂.size) :
xs₁ = xs₂ ys₁ = ys₂ := by
rcases xs₁ with s₁
@@ -2056,22 +2083,11 @@ theorem append_eq_map_iff {f : α → β} :
| nil => simp
| cons as => induction as.toList <;> simp [*]
@[simp] theorem flatten_toArray_map_toArray {L : List (List α)} :
@[simp] theorem flatten_toArray_map {L : List (List α)} :
(L.map List.toArray).toArray.flatten = L.flatten.toArray := by
apply ext'
simp [Function.comp_def]
@[deprecated flatten_toArray_map_toArray (since := "2025-10-26")]
theorem flatten_toArray_map {L : List (List α)} :
(L.map List.toArray).toArray.flatten = L.flatten.toArray := by
simp
@[grind =]
theorem flatten_map_toArray_toArray {L : List (List α)} :
(L.toArray.map List.toArray).flatten = L.flatten.toArray := by
simp
@[deprecated flatten_map_toArray_toArray (since := "2025-10-26")]
theorem flatten_map_toArray {L : List (List α)} :
(L.toArray.map List.toArray).flatten = L.flatten.toArray := by
simp
@@ -2118,33 +2134,32 @@ theorem forall_mem_flatten {p : α → Prop} {xss : Array (Array α)} :
theorem flatten_eq_flatMap {xss : Array (Array α)} : flatten xss = xss.flatMap id := by
induction xss using array₂_induction
rw [flatten_toArray_map_toArray, List.flatten_eq_flatMap]
rw [flatten_toArray_map, List.flatten_eq_flatMap]
simp [List.flatMap_map]
@[simp, grind _=_] theorem map_flatten {f : α β} {xss : Array (Array α)} :
(flatten xss).map f = (map (map f) xss).flatten := by
induction xss using array₂_induction with
| of xss =>
simp only [flatten_toArray_map_toArray, List.map_toArray, List.map_flatten, List.map_map,
simp only [flatten_toArray_map, List.map_toArray, List.map_flatten, List.map_map,
Function.comp_def]
rw [ Function.comp_def, List.map_map, flatten_toArray_map_toArray]
rw [ Function.comp_def, List.map_map, flatten_toArray_map]
@[simp, grind =] theorem filterMap_flatten {f : α Option β} {xss : Array (Array α)} {stop : Nat} (w : stop = xss.flatten.size) :
filterMap f (flatten xss) 0 stop = flatten (map (filterMap f) xss) := by
subst w
induction xss using array₂_induction
simp only [flatten_toArray_map_toArray, List.size_toArray, List.length_flatten,
List.filterMap_toArray', List.filterMap_flatten, List.map_toArray, List.map_map,
Function.comp_def]
rw [ Function.comp_def, List.map_map, flatten_toArray_map_toArray]
simp only [flatten_toArray_map, List.size_toArray, List.length_flatten, List.filterMap_toArray',
List.filterMap_flatten, List.map_toArray, List.map_map, Function.comp_def]
rw [ Function.comp_def, List.map_map, flatten_toArray_map]
@[simp, grind =] theorem filter_flatten {p : α Bool} {xss : Array (Array α)} {stop : Nat} (w : stop = xss.flatten.size) :
filter p (flatten xss) 0 stop = flatten (map (filter p) xss) := by
subst w
induction xss using array₂_induction
simp only [flatten_toArray_map_toArray, List.size_toArray, List.length_flatten,
List.filter_toArray', List.filter_flatten, List.map_toArray, List.map_map, Function.comp_def]
rw [ Function.comp_def, List.map_map, flatten_toArray_map_toArray]
simp only [flatten_toArray_map, List.size_toArray, List.length_flatten, List.filter_toArray',
List.filter_flatten, List.map_toArray, List.map_map, Function.comp_def]
rw [ Function.comp_def, List.map_map, flatten_toArray_map]
theorem flatten_filter_not_isEmpty {xss : Array (Array α)} :
flatten (xss.filter fun xs => !xs.isEmpty) = xss.flatten := by
@@ -2167,23 +2182,23 @@ theorem flatten_filter_ne_empty [DecidablePred fun xs : Array α => xs ≠ #[]]
induction xss using array₂_induction
rcases xs with l
have this : [l.toArray] = [l].map List.toArray := by simp
simp only [List.push_toArray, flatten_toArray_map_toArray, List.append_toArray]
rw [this, List.map_append, flatten_toArray_map_toArray]
simp only [List.push_toArray, flatten_toArray_map, List.append_toArray]
rw [this, List.map_append, flatten_toArray_map]
simp
theorem flatten_flatten {xss : Array (Array (Array α))} : flatten (flatten xss) = flatten (map flatten xss) := by
induction xss using array₃_induction with
| of xss =>
rw [flatten_toArray_map_toArray]
rw [flatten_toArray_map]
have : (xss.map (fun xs => xs.map List.toArray)).flatten = xss.flatten.map List.toArray := by
induction xss with
| nil => simp
| cons xs xss ih =>
simp only [List.map_cons, List.flatten_cons, ih, List.map_append]
rw [this, flatten_toArray_map_toArray, List.flatten_flatten, List.map_toArray, Array.map_map,
rw [this, flatten_toArray_map, List.flatten_flatten, List.map_toArray, Array.map_map,
List.map_toArray, map_map, Function.comp_def]
simp only [Function.comp_apply, flatten_toArray_map_toArray]
rw [List.map_toArray, Function.comp_def, List.map_map, flatten_toArray_map_toArray]
simp only [Function.comp_apply, flatten_toArray_map]
rw [List.map_toArray, Function.comp_def, List.map_map, flatten_toArray_map]
theorem flatten_eq_push_iff {xss : Array (Array α)} {ys : Array α} {y : α} :
xss.flatten = ys.push y
@@ -2192,13 +2207,13 @@ theorem flatten_eq_push_iff {xss : Array (Array α)} {ys : Array α} {y : α} :
induction xss using array₂_induction with
| of xs =>
rcases ys with ys
rw [flatten_toArray_map_toArray, List.push_toArray, mk.injEq, List.flatten_eq_append_iff]
rw [flatten_toArray_map, List.push_toArray, mk.injEq, List.flatten_eq_append_iff]
constructor
· rintro (as, bs, rfl, rfl, h | as, bs, c, cs, ds, rfl, rfl, h)
· rw [List.singleton_eq_flatten_iff] at h
obtain xs, ys, rfl, h₁, h₂ := h
exact ((as ++ xs).map List.toArray).toArray, #[], (ys.map List.toArray).toArray, by simp,
by simpa using h₂, by rw [flatten_toArray_map_toArray]; simpa
by simpa using h₂, by rw [flatten_toArray_map]; simpa
· rw [List.singleton_eq_append_iff] at h
obtain (h₁, h₂ | h₁, h₂) := h
· simp at h₁
@@ -2231,8 +2246,8 @@ theorem push_eq_flatten_iff {xss : Array (Array α)} {ys : Array α} {y : α} :
-- zs = cs ++ ds.flatten := by sorry
/-- Two arrays of arrays are equal iff their flattens coincide, as well as the sizes of the
arrays. -/
/-- Two arrays of subarrays are equal iff their flattens coincide, as well as the sizes of the
subarrays. -/
theorem eq_iff_flatten_eq {xss₁ xss₂ : Array (Array α)} :
xss₁ = xss₂ xss₁.flatten = xss₂.flatten map size xss₁ = map size xss₂ := by
cases xss₁ using array₂_induction with
@@ -2243,12 +2258,18 @@ theorem eq_iff_flatten_eq {xss₁ xss₂ : Array (Array α)} :
rw [List.map_inj_right]
simp +contextual
theorem flatten_toArray_map_toArray {xss : List (List α)} :
(xss.map List.toArray).toArray.flatten = xss.flatten.toArray := by
simp
/-! ### flatMap -/
theorem flatMap_def {xs : Array α} {f : α Array β} : xs.flatMap f = flatten (map f xs) := by
rcases xs with l
simp [flatten_toArray, Function.comp_def, List.flatMap_def]
@[simp, grind =] theorem flatMap_empty {β} {f : α Array β} : (#[] : Array α).flatMap f = #[] := rfl
theorem flatMap_toList {xs : Array α} {f : α List β} :
xs.toList.flatMap f = (xs.flatMap (fun a => (f a).toArray)).toList := by
rcases xs with l
@@ -2259,7 +2280,6 @@ theorem flatMap_toList {xs : Array α} {f : α → List β} :
rcases xs with l
simp
@[deprecated List.flatMap_toArray_cons (since := "2025-10-29")]
theorem flatMap_toArray_cons {β} {f : α Array β} {a : α} {as : List α} :
(a :: as).toArray.flatMap f = f a ++ as.toArray.flatMap f := by
simp [flatMap]
@@ -2270,7 +2290,6 @@ theorem flatMap_toArray_cons {β} {f : α → Array β} {a : α} {as : List α}
intro cs
induction as generalizing cs <;> simp_all
@[deprecated List.flatMap_toArray (since := "2025-10-29")]
theorem flatMap_toArray {β} {f : α Array β} {as : List α} :
as.toArray.flatMap f = (as.flatMap (fun a => (f a).toList)).toArray := by
simp
@@ -2371,44 +2390,77 @@ theorem flatMap_eq_foldl {f : α → Array β} {xs : Array α} :
@[simp] theorem replicate_one : replicate 1 a = #[a] := rfl
@[deprecated replicate_one (since := "2025-03-18")]
abbrev mkArray_one := @replicate_one
/-- Variant of `replicate_succ` that prepends `a` at the beginning of the array. -/
theorem replicate_succ' : replicate (n + 1) a = #[a] ++ replicate n a := by
apply Array.ext'
simp [List.replicate_succ]
@[deprecated replicate_succ' (since := "2025-03-18")]
abbrev mkArray_succ' := @replicate_succ'
@[simp, grind =] theorem mem_replicate {a b : α} {n} : b replicate n a n 0 b = a := by
unfold replicate
simp only [List.mem_toArray, List.mem_replicate]
@[deprecated mem_replicate (since := "2025-03-18")]
abbrev mem_mkArray := @mem_replicate
@[grind ] theorem eq_of_mem_replicate {a b : α} {n} (h : b replicate n a) : b = a := (mem_replicate.1 h).2
@[deprecated eq_of_mem_mkArray (since := "2025-03-18")]
abbrev eq_of_mem_mkArray := @eq_of_mem_replicate
theorem forall_mem_replicate {p : α Prop} {a : α} {n} :
( b, b replicate n a p b) n = 0 p a := by
cases n <;> simp [mem_replicate]
@[deprecated forall_mem_replicate (since := "2025-03-18")]
abbrev forall_mem_mkArray := @forall_mem_replicate
@[simp] theorem replicate_succ_ne_empty {n : Nat} {a : α} : replicate (n+1) a #[] := by
simp [replicate_succ]
@[deprecated replicate_succ_ne_empty (since := "2025-03-18")]
abbrev mkArray_succ_ne_empty := @replicate_succ_ne_empty
@[simp] theorem replicate_eq_empty_iff {n : Nat} {a : α} : replicate n a = #[] n = 0 := by
cases n <;> simp
@[deprecated replicate_eq_empty_iff (since := "2025-03-18")]
abbrev mkArray_eq_empty_iff := @replicate_eq_empty_iff
@[simp] theorem replicate_inj : replicate n a = replicate m b n = m (n = 0 a = b) := by
rw [ toList_inj]
simp
@[deprecated replicate_inj (since := "2025-03-18")]
abbrev mkArray_inj := @replicate_inj
theorem eq_replicate_of_mem {a : α} {xs : Array α} (h : (b) (_ : b xs), b = a) : xs = replicate xs.size a := by
rw [ toList_inj]
simpa using List.eq_replicate_of_mem (by simpa using h)
@[deprecated eq_replicate_of_mem (since := "2025-03-18")]
abbrev eq_mkArray_of_mem := @eq_replicate_of_mem
theorem eq_replicate_iff {a : α} {n} {xs : Array α} :
xs = replicate n a xs.size = n (b) (_ : b xs), b = a := by
rw [ toList_inj]
simpa using List.eq_replicate_iff (l := xs.toList)
@[deprecated eq_replicate_iff (since := "2025-03-18")]
abbrev eq_mkArray_iff := @eq_replicate_iff
theorem map_eq_replicate_iff {xs : Array α} {f : α β} {b : β} :
xs.map f = replicate xs.size b x xs, f x = b := by
simp [eq_replicate_iff]
@[deprecated map_eq_replicate_iff (since := "2025-03-18")]
abbrev map_eq_mkArray_iff := @map_eq_replicate_iff
@[simp] theorem map_const {xs : Array α} {b : β} : map (Function.const α b) xs = replicate xs.size b :=
map_eq_replicate_iff.mpr fun _ _ => rfl
@@ -2425,86 +2477,143 @@ theorem map_const' {xs : Array α} {b : β} : map (fun _ => b) xs = replicate xs
apply Array.ext'
simp
@[deprecated set_replicate_self (since := "2025-03-18")]
abbrev set_mkArray_self := @set_replicate_self
@[simp] theorem setIfInBounds_replicate_self : (replicate n a).setIfInBounds i a = replicate n a := by
apply Array.ext'
simp
@[deprecated setIfInBounds_replicate_self (since := "2025-03-18")]
abbrev setIfInBounds_mkArray_self := @setIfInBounds_replicate_self
@[simp] theorem replicate_append_replicate : replicate n a ++ replicate m a = replicate (n + m) a := by
apply Array.ext'
simp
@[deprecated replicate_append_replicate (since := "2025-03-18")]
abbrev mkArray_append_mkArray := @replicate_append_replicate
theorem append_eq_replicate_iff {xs ys : Array α} {a : α} :
xs ++ ys = replicate n a
xs.size + ys.size = n xs = replicate xs.size a ys = replicate ys.size a := by
simp [ toList_inj, List.append_eq_replicate_iff]
@[deprecated append_eq_replicate_iff (since := "2025-03-18")]
abbrev append_eq_mkArray_iff := @append_eq_replicate_iff
theorem replicate_eq_append_iff {xs ys : Array α} {a : α} :
replicate n a = xs ++ ys
xs.size + ys.size = n xs = replicate xs.size a ys = replicate ys.size a := by
rw [eq_comm, append_eq_replicate_iff]
@[deprecated replicate_eq_append_iff (since := "2025-03-18")]
abbrev replicate_eq_mkArray_iff := @replicate_eq_append_iff
@[simp] theorem map_replicate : (replicate n a).map f = replicate n (f a) := by
apply Array.ext'
simp
@[deprecated map_replicate (since := "2025-03-18")]
abbrev map_mkArray := @map_replicate
@[grind =] theorem filter_replicate (w : stop = n) :
(replicate n a).filter p 0 stop = if p a then replicate n a else #[] := by
apply Array.ext'
simp only [w]
split <;> simp_all
@[deprecated filter_replicate (since := "2025-03-18")]
abbrev filter_mkArray := @filter_replicate
@[simp] theorem filter_replicate_of_pos (w : stop = n) (h : p a) :
(replicate n a).filter p 0 stop = replicate n a := by
simp [filter_replicate, h, w]
@[deprecated filter_replicate_of_pos (since := "2025-03-18")]
abbrev filter_mkArray_of_pos := @filter_replicate_of_pos
@[simp] theorem filter_replicate_of_neg (w : stop = n) (h : ¬ p a) :
(replicate n a).filter p 0 stop = #[] := by
simp [filter_replicate, h, w]
@[deprecated filter_replicate_of_neg (since := "2025-03-18")]
abbrev filter_mkArray_of_neg := @filter_replicate_of_neg
theorem filterMap_replicate {f : α Option β} (w : stop = n := by simp) :
(replicate n a).filterMap f 0 stop = match f a with | none => #[] | .some b => replicate n b := by
apply Array.ext'
simp only [w, size_replicate, toList_filterMap', toList_replicate, List.filterMap_replicate]
split <;> simp_all
@[deprecated filterMap_replicate (since := "2025-03-18")]
abbrev filterMap_mkArray := @filterMap_replicate
-- This is not a useful `simp` lemma because `b` is unknown.
theorem filterMap_replicate_of_some {f : α Option β} (h : f a = some b) :
(replicate n a).filterMap f = replicate n b := by
simp [filterMap_replicate, h]
@[deprecated filterMap_replicate_of_some (since := "2025-03-18")]
abbrev filterMap_mkArray_of_some := @filterMap_replicate_of_some
@[simp] theorem filterMap_replicate_of_isSome {f : α Option β} (h : (f a).isSome) :
(replicate n a).filterMap f = replicate n (Option.get _ h) := by
match w : f a, h with
| some b, _ => simp [filterMap_replicate, w]
@[deprecated filterMap_replicate_of_isSome (since := "2025-03-18")]
abbrev filterMap_mkArray_of_isSome := @filterMap_replicate_of_isSome
@[simp] theorem filterMap_replicate_of_none {f : α Option β} (h : f a = none) :
(replicate n a).filterMap f = #[] := by
simp [filterMap_replicate, h]
@[deprecated filterMap_replicate_of_none (since := "2025-03-18")]
abbrev filterMap_mkArray_of_none := @filterMap_replicate_of_none
@[simp] theorem flatten_replicate_empty : (replicate n (#[] : Array α)).flatten = #[] := by
rw [ toList_inj]
simp
@[deprecated flatten_replicate_empty (since := "2025-03-18")]
abbrev flatten_mkArray_empty := @flatten_replicate_empty
@[simp] theorem flatten_replicate_singleton : (replicate n #[a]).flatten = replicate n a := by
rw [ toList_inj]
simp
@[deprecated flatten_replicate_singleton (since := "2025-03-18")]
abbrev flatten_mkArray_singleton := @flatten_replicate_singleton
@[simp] theorem flatten_replicate_replicate : (replicate n (replicate m a)).flatten = replicate (n * m) a := by
rw [ toList_inj]
simp
@[deprecated flatten_replicate_replicate (since := "2025-03-18")]
abbrev flatten_mkArray_replicate := @flatten_replicate_replicate
theorem flatMap_replicate {f : α Array β} : (replicate n a).flatMap f = (replicate n (f a)).flatten := by
rw [ toList_inj]
simp [List.flatMap_replicate]
@[deprecated flatMap_replicate (since := "2025-03-18")]
abbrev flatMap_mkArray := @flatMap_replicate
@[simp] theorem isEmpty_replicate : (replicate n a).isEmpty = decide (n = 0) := by
rw [ List.toArray_replicate, List.isEmpty_toArray]
simp
@[deprecated isEmpty_replicate (since := "2025-03-18")]
abbrev isEmpty_mkArray := @isEmpty_replicate
@[simp] theorem sum_replicate_nat {n : Nat} {a : Nat} : (replicate n a).sum = n * a := by
rw [ List.toArray_replicate, List.sum_toArray]
simp
@[deprecated sum_replicate_nat (since := "2025-03-18")]
abbrev sum_mkArray_nat := @sum_replicate_nat
/-! ### Preliminaries about `swap` needed for `reverse`. -/
@[grind =]
@@ -2546,8 +2655,8 @@ theorem getElem?_swap {xs : Array α} {i j : Nat} (hi hj) {k : Nat} : (xs.swap i
split <;> rename_i h₃
· simp only [ h₃, Nat.not_le.2 (Nat.lt_succ_self _), Nat.le_refl, false_and]
exact (List.getElem?_reverse' (Eq.trans (by simp +arith) h)).symm
simp only [Nat.succ_le_iff, Nat.lt_iff_le_and_ne.trans (and_iff_left h₃),
Nat.lt_succ_iff.symm.trans (Nat.lt_iff_le_and_ne.trans (and_iff_left (Ne.symm h₂)))]
simp only [Nat.succ_le, Nat.lt_iff_le_and_ne.trans (and_iff_left h₃),
Nat.lt_succ.symm.trans (Nat.lt_iff_le_and_ne.trans (and_iff_left (Ne.symm h₂)))]
· rw [H]; split <;> rename_i h₂
· cases Nat.le_antisymm (Nat.not_lt.1 h₁) (Nat.le_trans h₂.1 h₂.2)
cases Nat.le_antisymm h₂.1 h₂.2
@@ -2562,7 +2671,7 @@ theorem getElem?_swap {xs : Array α} {i j : Nat} (hi hj) {k : Nat} : (xs.swap i
split
· rfl
· rename_i h
simp only [ show k < _ + 1 _ from Nat.lt_succ_iff (n := xs.size - 1), this, Nat.zero_le,
simp only [ show k < _ + 1 _ from Nat.lt_succ (n := xs.size - 1), this, Nat.zero_le,
true_and, Nat.not_lt] at h
rw [List.getElem?_eq_none_iff.2 _, List.getElem?_eq_none_iff.2 (xs.toList.length_reverse _)]
@@ -2691,6 +2800,9 @@ theorem flatten_reverse {xss : Array (Array α)} :
rw [ toList_inj]
simp
@[deprecated reverse_replicate (since := "2025-03-18")]
abbrev reverse_mkArray := @reverse_replicate
/-! ### extract -/
theorem extract_loop_zero {xs ys : Array α} {start : Nat} : extract.loop xs 0 start ys = ys := by
@@ -2710,8 +2822,8 @@ theorem extract_loop_eq_aux {xs ys : Array α} {size start : Nat} :
| zero => rw [extract_loop_zero, extract_loop_zero, append_empty]
| succ size ih =>
if h : start < xs.size then
rw [extract_loop_succ (h := h), ih, push_eq_append]
rw [extract_loop_succ (h := h), ih (ys := #[].push _), push_eq_append, empty_append]
rw [extract_loop_succ (h := h), ih, push_eq_append_singleton]
rw [extract_loop_succ (h := h), ih (ys := #[].push _), push_eq_append_singleton, empty_append]
rw [append_assoc]
else
rw [extract_loop_of_ge (h := Nat.le_of_not_lt h)]
@@ -3328,16 +3440,6 @@ theorem foldr_filterMap {f : α → Option β} {g : β → γγ} {xs : Arra
(xs.filterMap f).foldr g init = xs.foldr (fun x y => match f x with | some b => g b y | none => y) init := by
simp [foldr_filterMap']
theorem foldl_flatMap {f : α Array β} {g : γ β γ} {xs : Array α} {init : γ} :
(xs.flatMap f).foldl g init = xs.foldl (fun acc x => (f x).foldl g acc) init := by
rcases xs with l
simp [List.foldl_flatMap]
theorem foldr_flatMap {f : α Array β} {g : β γ γ} {xs : Array α} {init : γ} :
(xs.flatMap f).foldr g init = xs.foldr (fun x acc => (f x).foldr g acc) init := by
rcases xs with l
simp [List.foldr_flatMap]
theorem foldl_map_hom' {g : α β} {f : α α α} {f' : β β β} {a : α} {xs : Array α}
{stop : Nat} (h : x y, f' (g x) (g y) = g (f x y)) (w : stop = xs.size) :
(xs.map g).foldl f' (g a) 0 stop = g (xs.foldl f a) := by
@@ -3555,6 +3657,11 @@ theorem mem_of_back? {xs : Array α} {a : α} (h : xs.back? = some a) : a ∈ xs
rcases ys with ys
simp only [List.append_toArray, List.back_toArray, List.getLast_append, List.isEmpty_iff,
List.isEmpty_toArray]
split
· rw [dif_pos]
simpa only [List.isEmpty_toArray]
· rw [dif_neg]
simpa only [List.isEmpty_toArray]
theorem back_append_right {xs ys : Array α} (h : 0 < ys.size) :
(xs ++ ys).back (by simp; omega) = ys.back h := by
@@ -3605,9 +3712,15 @@ theorem back?_replicate {a : α} {n : Nat} :
rw [replicate_eq_toArray_replicate]
simp only [List.back?_toArray, List.getLast?_replicate]
@[deprecated back?_replicate (since := "2025-03-18")]
abbrev back?_mkArray := @back?_replicate
@[simp] theorem back_replicate {xs : Array α} (w : 0 < n) : (replicate n xs).back (by simpa using w) = xs := by
simp [back_eq_getElem]
@[deprecated back_replicate (since := "2025-03-18")]
abbrev back_mkArray := @back_replicate
/-! ## Additional operations -/
/-! ### leftpad -/
@@ -3625,6 +3738,9 @@ theorem size_rightpad {n : Nat} {a : α} {xs : Array α} :
theorem elem_push_self [BEq α] [LawfulBEq α] {xs : Array α} {a : α} : (xs.push a).elem a = true := by simp
@[deprecated elem_push_self (since := "2025-04-04")]
abbrev elem_cons_self := @elem_push_self
theorem contains_eq_any_beq [BEq α] {xs : Array α} {a : α} : xs.contains a = xs.any (a == ·) := by
rcases xs with xs
simp [List.contains_eq_any_beq]
@@ -3638,6 +3754,11 @@ theorem contains_iff_exists_mem_beq [BEq α] {xs : Array α} {a : α} :
-- With `LawfulBEq α`, it would be better to use `contains_iff_mem` directly.
grind_pattern contains_iff_exists_mem_beq => xs.contains a
@[grind =]
theorem contains_iff_mem [BEq α] [LawfulBEq α] {xs : Array α} {a : α} :
xs.contains a a xs := by
simp
@[simp, grind =]
theorem contains_toList [BEq α] {xs : Array α} {x : α} :
xs.toList.contains x = xs.contains x := by
@@ -3697,6 +3818,9 @@ theorem pop_append {xs ys : Array α} :
@[simp, grind =] theorem pop_replicate {n : Nat} {a : α} : (replicate n a).pop = replicate (n - 1) a := by
ext <;> simp
@[deprecated pop_replicate (since := "2025-03-18")]
abbrev pop_mkArray := @pop_replicate
/-! ## Logic -/
/-! ### any / all -/
@@ -3926,10 +4050,16 @@ theorem all_filterMap {xs : Array α} {f : α → Option β} {p : β → Bool} :
(replicate n a).any f = if n = 0 then false else f a := by
induction n <;> simp_all [replicate_succ']
@[deprecated any_replicate (since := "2025-03-18")]
abbrev any_mkArray := @any_replicate
@[simp] theorem all_replicate {n : Nat} {a : α} :
(replicate n a).all f = if n = 0 then true else f a := by
induction n <;> simp_all +contextual [replicate_succ']
@[deprecated all_replicate (since := "2025-03-18")]
abbrev all_mkArray := @all_replicate
/-! ### modify -/
@[simp, grind =] theorem size_modify {xs : Array α} {i : Nat} {f : α α} : (xs.modify i f).size = xs.size := by
@@ -3966,29 +4096,28 @@ theorem getElem_modify_of_ne {xs : Array α} {i : Nat} (h : i ≠ j)
/-! ### swap -/
@[grind =]
theorem getElem_swap {xs : Array α} {i j : Nat} (hi hj) {k : Nat} (hk : k < (xs.swap i j hi hj).size) :
(xs.swap i j hi hj)[k] = if k = i then xs[j] else if k = j then xs[i] else xs[k]'(by simp_all) := by
simp only [swap_def, getElem_set, eq_comm (a := k)]
split <;> split <;> simp_all
@[simp] theorem getElem_swap_right {xs : Array α} {i j : Nat} {hi hj} :
(xs.swap i j hi hj)[j]'(by simpa using hj) = xs[i] := by
simp +contextual [getElem_swap]
simp [swap_def]
@[simp] theorem getElem_swap_left {xs : Array α} {i j : Nat} {hi hj} :
(xs.swap i j hi hj)[i]'(by simpa using hi) = xs[j] := by
simp [getElem_swap]
simp +contextual [swap_def, getElem_set]
@[simp] theorem getElem_swap_of_ne {xs : Array α} {i j : Nat} {hi hj}
{h : k < (xs.swap i j hi hj).size} (hi' : k i) (hj' : k j) :
(xs.swap i j hi hj)[k] = xs[k]'(by simp_all) := by
simp [getElem_swap, hi', hj']
@[simp] theorem getElem_swap_of_ne {xs : Array α} {i j : Nat} {hi hj} (hp : k < xs.size)
(hi' : k i) (hj' : k j) : (xs.swap i j hi hj)[k]'(xs.size_swap .. |>.symm hp) = xs[k] := by
simp [swap_def, getElem_set, hi'.symm, hj'.symm]
@[deprecated getElem_swap (since := "2025-10-10")]
theorem getElem_swap' {xs : Array α} {i j : Nat} {hi hj} {k : Nat} (hk : k < xs.size) :
(xs.swap i j hi hj)[k]'(by simp_all) = if k = i then xs[j] else if k = j then xs[i] else xs[k] :=
getElem_swap _ _ _
(xs.swap i j hi hj)[k]'(by simp_all) = if k = i then xs[j] else if k = j then xs[i] else xs[k] := by
split
· simp_all only [getElem_swap_left]
· split <;> simp_all
@[grind =]
theorem getElem_swap {xs : Array α} {i j : Nat} (hi hj) {k : Nat} (hk : k < (xs.swap i j hi hj).size) :
(xs.swap i j hi hj)[k] = if k = i then xs[j] else if k = j then xs[i] else xs[k]'(by simp_all) := by
apply getElem_swap'
@[simp] theorem swap_swap {xs : Array α} {i j : Nat} (hi hj) :
(xs.swap i j hi hj).swap i j ((xs.size_swap ..).symm hi) ((xs.size_swap ..).symm hj) = xs := by
@@ -4009,66 +4138,8 @@ theorem swap_comm {xs : Array α} {i j : Nat} (hi hj) : xs.swap i j hi hj = xs.s
· split <;> simp_all
· split <;> simp_all
/-! ### swapIfInBounds -/
@[grind =] theorem swapIfInBounds_def {xs : Array α} {i j : Nat} :
xs.swapIfInBounds i j = if h₁ : i < xs.size then
if h₂ : j < xs.size then swap xs i j else xs else xs := rfl
@[simp, grind =] theorem size_swapIfInBounds {xs : Array α} {i j : Nat} :
(xs.swapIfInBounds i j).size = xs.size := by
unfold swapIfInBounds; split <;> (try split) <;> simp [size_swap]
@[grind =] theorem getElem_swapIfInBounds {xs : Array α} {i j k : Nat}
(hk : k < (xs.swapIfInBounds i j).size) :
(xs.swapIfInBounds i j)[k] =
if h₁ : k = i j < xs.size then xs[j]'h₁.2 else if h₂ : k = j i < xs.size then xs[i]'h₂.2
else xs[k]'(by simp_all) := by
rw [size_swapIfInBounds] at hk
unfold swapIfInBounds
split <;> rename_i hi
· split <;> rename_i hj
· simp only [hi, hj, and_true]
exact getElem_swap _ _ _
· simp only [hi, hj, and_true, and_false, dite_false]
split <;> simp_all
· simp only [hi, and_false, dite_false]
split <;> simp_all
@[simp]
theorem getElem_swapIfInBounds_of_size_le_left {xs : Array α} {i j k : Nat} (hi : xs.size i)
(hk : k < (xs.swapIfInBounds i j).size) :
(xs.swapIfInBounds i j)[k] = xs[k]'(Nat.lt_of_lt_of_eq hk size_swapIfInBounds) := by
have h₁ : k i := Nat.ne_of_lt <| Nat.lt_of_lt_of_le hk <|
Nat.le_trans (Nat.le_of_eq (size_swapIfInBounds)) hi
have h₂ : ¬ (i < xs.size) := Nat.not_lt_of_le hi
simp [getElem_swapIfInBounds, h₁, h₂]
@[simp]
theorem getElem_swapIfInBounds_of_size_le_right {xs : Array α} {i j k : Nat} (hj : xs.size j)
(hk : k < (xs.swapIfInBounds i j).size) :
(xs.swapIfInBounds i j)[k] = xs[k]'(Nat.lt_of_lt_of_eq hk size_swapIfInBounds) := by
have h₁ : ¬ (j < xs.size) := Nat.not_lt_of_le hj
have h₂ : k j := Nat.ne_of_lt <| Nat.lt_of_lt_of_le hk <|
Nat.le_trans (Nat.le_of_eq (size_swapIfInBounds)) hj
simp [getElem_swapIfInBounds, h₁, h₂]
@[simp]
theorem getElem_swapIfInBounds_left {xs : Array α} {i j : Nat} (hj : j < xs.size)
(hi : i < (xs.swapIfInBounds i j).size) : (xs.swapIfInBounds i j)[i] = xs[j] := by
simp [getElem_swapIfInBounds, hj]
@[simp]
theorem getElem_swapIfInBounds_right {xs : Array α} {i j : Nat} (hi : i < xs.size)
(hj : j < (xs.swapIfInBounds i j).size) :
(xs.swapIfInBounds i j)[j] = xs[i] := by
simp +contextual [getElem_swapIfInBounds, hi]
@[simp]
theorem getElem_swapIfInBounds_of_ne_of_ne {xs : Array α} {i j k : Nat} (hi : k i) (hj : k j)
(hk : k < (xs.swapIfInBounds i j).size) :
(xs.swapIfInBounds i j)[k] = xs[k]'(Nat.lt_of_lt_of_eq hk size_swapIfInBounds) := by
simp [getElem_swapIfInBounds, hi, hj]
(xs.swapIfInBounds i j).size = xs.size := by unfold swapIfInBounds; split <;> (try split) <;> simp [size_swap]
/-! ### swapAt -/
@@ -4163,11 +4234,17 @@ theorem replace_extract {xs : Array α} {i : Nat} :
(replicate n a).replace a b = #[b] ++ replicate (n - 1) a := by
cases n <;> simp_all [replicate_succ', replace_append]
@[deprecated replace_replicate_self (since := "2025-03-18")]
abbrev replace_mkArray_self := @replace_replicate_self
@[simp] theorem replace_replicate_ne {a b c : α} (h : !b == a) :
(replicate n a).replace b c = replicate n a := by
rw [replace_of_not_mem]
simp_all
@[deprecated replace_replicate_ne (since := "2025-03-18")]
abbrev replace_mkArray_ne := @replace_replicate_ne
end replace
/-! ### toListRev -/
@@ -4330,15 +4407,14 @@ theorem size_uset {xs : Array α} {v : α} {i : USize} (h : i.toNat < xs.size) :
theorem getElem!_eq_getD [Inhabited α] {xs : Array α} {i} : xs[i]! = xs.getD i default := by
rfl
theorem getElem_eq_getD {xs : Array α} {i} {h : i < xs.size} (fallback : α) :
xs[i]'h = xs.getD i fallback := by
rw [getD_eq_getD_getElem?, getElem_eq_getElem?_get, Option.get_eq_getD]
/-! # mem -/
@[deprecated mem_toList_iff (since := "2025-05-26")]
theorem mem_toList {a : α} {xs : Array α} : a xs.toList a xs := mem_def.symm
@[deprecated not_mem_empty (since := "2025-03-25")]
theorem not_mem_nil (a : α) : ¬ a #[] := nofun
/-! # get lemmas -/
theorem lt_of_getElem {x : α} {xs : Array α} {i : Nat} {hidx : i < xs.size} (_ : xs[i] = x) :
@@ -4350,7 +4426,6 @@ theorem getElem_fin_eq_getElem_toList {xs : Array α} {i : Fin xs.size} : xs[i]
@[simp] theorem ugetElem_eq_getElem {xs : Array α} {i : USize} (h : i.toNat < xs.size) :
xs[i] = xs[i.toNat] := rfl
@[deprecated getElem?_eq_none (since := "2025-10-26")]
theorem getElem?_size_le {xs : Array α} {i : Nat} (h : xs.size i) : xs[i]? = none := by
simp [getElem?_neg, h]
@@ -4370,7 +4445,6 @@ theorem getElem?_push_lt {xs : Array α} {x : α} {i : Nat} (h : i < xs.size) :
(xs.push x)[i]? = some xs[i] := by
rw [getElem?_pos (xs.push x) i (size_push _ Nat.lt_succ_of_lt h), getElem_push_lt]
@[deprecated getElem?_push_size (since := "2025-10-26")]
theorem getElem?_push_eq {xs : Array α} {x : α} : (xs.push x)[xs.size]? = some x := by
rw [getElem?_pos (xs.push x) xs.size (size_push _ Nat.lt_succ_self xs.size), getElem_push_eq]
@@ -4389,6 +4463,12 @@ theorem getElem?_push_eq {xs : Array α} {x : α} : (xs.push x)[xs.size]? = some
cases xs
simp
/-! ### contains -/
@[deprecated contains_iff (since := "2025-04-07")]
abbrev contains_def [DecidableEq α] {a : α} {xs : Array α} : xs.contains a a xs :=
contains_iff
/-! ### isPrefixOf -/
@[simp, grind =] theorem isPrefixOf_toList [BEq α] {xs ys : Array α} :
@@ -4502,8 +4582,7 @@ theorem uset_toArray {l : List α} {i : USize} {a : α} {h : i.toNat < l.toArray
apply ext'
simp
@[deprecated Array.flatten_map_toArray_toArray (since := "2025-10-26")]
theorem flatten_toArray {L : List (List α)} :
@[simp, grind =] theorem flatten_toArray {L : List (List α)} :
(L.toArray.map List.toArray).flatten = L.flatten.toArray := by
apply ext'
simp

View File

@@ -34,18 +34,7 @@ grind_pattern _root_.List.le_toArray => l₁.toArray ≤ l₂.toArray
grind_pattern lt_toList => xs.toList < ys.toList
grind_pattern le_toList => xs.toList ys.toList
@[simp]
protected theorem not_lt [LT α] {xs ys : Array α} : ¬ xs < ys ys xs := Iff.rfl
@[deprecated Array.not_lt (since := "2025-10-26")]
protected theorem not_lt_iff_ge [LT α] {xs ys : Array α} : ¬ xs < ys ys xs := Iff.rfl
@[simp]
protected theorem not_le [LT α] {xs ys : Array α} :
¬ xs ys ys < xs :=
Classical.not_not
@[deprecated Array.not_le (since := "2025-10-26")]
protected theorem not_le_iff_gt [LT α] {xs ys : Array α} :
¬ xs ys ys < xs :=
Classical.not_not
@@ -75,11 +64,11 @@ private theorem cons_lex_cons [BEq α] {lt : αα → Bool} {a b : α} {xs
Nat.add_min_add_left, Nat.add_lt_add_iff_left, Std.Rco.forIn'_eq_forIn'_toList]
conv =>
lhs; congr; congr
rw [cons_lex_cons.forIn'_congr_aux Std.Rco.toList_eq_if_roo rfl (fun _ _ _ => rfl)]
rw [cons_lex_cons.forIn'_congr_aux Std.Rco.toList_eq_if rfl (fun _ _ _ => rfl)]
simp only [bind_pure_comp, map_pure]
rw [cons_lex_cons.forIn'_congr_aux (if_pos (by omega)) rfl (fun _ _ _ => rfl)]
simp only [Std.toList_roo_eq_toList_rco_of_isSome_succ? (lo := 0) (h := rfl),
Std.PRange.UpwardEnumerable.succ?, Nat.add_comm 1, Std.PRange.Nat.toList_rco_succ_succ,
simp only [Std.toList_Roo_eq_toList_Rco_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
@@ -151,7 +140,7 @@ protected theorem lt_of_le_of_lt [LE α] [LT α] [LawfulOrderLT α] [IsLinearOrd
@[deprecated Array.lt_of_le_of_lt (since := "2025-08-01")]
protected theorem lt_of_le_of_lt' [LT α]
[i₁ : Std.Asymm (· < · : α α Prop)]
[i₂ : Std.Trichotomous (· < · : α α Prop)]
[i₂ : Std.Antisymm (¬ · < · : α α Prop)]
[i₃ : Trans (¬ · < · : α α Prop) (¬ · < ·) (¬ · < ·)]
{xs ys zs : Array α} (h₁ : xs ys) (h₂ : ys < zs) : xs < zs :=
letI := LE.ofLT α
@@ -165,7 +154,7 @@ protected theorem le_trans [LE α] [LT α] [LawfulOrderLT α] [IsLinearOrder α]
@[deprecated Array.le_trans (since := "2025-08-01")]
protected theorem le_trans' [LT α]
[i₁ : Std.Asymm (· < · : α α Prop)]
[i₂ : Std.Trichotomous (· < · : α α Prop)]
[i₂ : Std.Antisymm (¬ · < · : α α Prop)]
[i₃ : Trans (¬ · < · : α α Prop) (¬ · < ·) (¬ · < ·)]
{xs ys zs : Array α} (h₁ : xs ys) (h₂ : ys zs) : xs zs :=
letI := LE.ofLT α
@@ -189,6 +178,12 @@ protected theorem le_total [LT α]
[i : Std.Asymm (· < · : α α Prop)] (xs ys : Array α) : xs ys ys xs :=
List.le_total xs.toList ys.toList
@[simp] protected theorem not_lt [LT α]
{xs ys : Array α} : ¬ xs < ys ys xs := Iff.rfl
@[simp] protected theorem not_le [LT α]
{xs ys : Array α} : ¬ ys xs xs < ys := Classical.not_not
protected theorem le_of_lt [LT α]
[i : Std.Asymm (· < · : α α Prop)]
{xs ys : Array α} (h : xs < ys) : xs ys :=
@@ -196,7 +191,7 @@ protected theorem le_of_lt [LT α]
protected theorem le_iff_lt_or_eq [LT α]
[Std.Irrefl (· < · : α α Prop)]
[Std.Trichotomous (· < · : α α Prop)]
[Std.Antisymm (¬ · < · : α α Prop)]
[Std.Asymm (· < · : α α Prop)]
{xs ys : Array α} : xs ys xs < ys xs = ys := by
simpa using List.le_iff_lt_or_eq (l₁ := xs.toList) (l₂ := ys.toList)
@@ -285,7 +280,7 @@ protected theorem lt_iff_exists [LT α] {xs ys : Array α} :
protected theorem le_iff_exists [LT α]
[Std.Asymm (· < · : α α Prop)]
[Std.Trichotomous (· < · : α α Prop)] {xs ys : Array α} :
[Std.Antisymm (¬ · < · : α α Prop)] {xs ys : Array α} :
xs ys
(xs = ys.take xs.size)
( (i : Nat) (h₁ : i < xs.size) (h₂ : i < ys.size),
@@ -304,7 +299,7 @@ theorem append_left_lt [LT α] {xs ys zs : Array α} (h : ys < zs) :
theorem append_left_le [LT α]
[Std.Asymm (· < · : α α Prop)]
[Std.Trichotomous (· < · : α α Prop)]
[Std.Antisymm (¬ · < · : α α Prop)]
{xs ys zs : Array α} (h : ys zs) :
xs ++ ys xs ++ zs := by
cases xs
@@ -327,9 +322,9 @@ protected theorem map_lt [LT α] [LT β]
protected theorem map_le [LT α] [LT β]
[Std.Asymm (· < · : α α Prop)]
[Std.Trichotomous (· < · : α α Prop)]
[Std.Antisymm (¬ · < · : α α Prop)]
[Std.Asymm (· < · : β β Prop)]
[Std.Trichotomous (· < · : β β Prop)]
[Std.Antisymm (¬ · < · : β β Prop)]
{xs ys : Array α} {f : α β} (w : x y, x < y f x < f y) (h : xs ys) :
map f xs map f ys := by
cases xs

View File

@@ -296,6 +296,9 @@ theorem mapFinIdx_eq_replicate_iff {xs : Array α} {f : (i : Nat) → α → (h
rw [ toList_inj]
simp [List.mapFinIdx_eq_replicate_iff]
@[deprecated mapFinIdx_eq_replicate_iff (since := "2025-03-18")]
abbrev mapFinIdx_eq_mkArray_iff := @mapFinIdx_eq_replicate_iff
@[simp, grind =] theorem mapFinIdx_reverse {xs : Array α} {f : (i : Nat) α (h : i < xs.reverse.size) β} :
xs.reverse.mapFinIdx f = (xs.mapFinIdx (fun i a h => f (xs.size - 1 - i) a (by simp; omega))).reverse := by
rcases xs with l
@@ -435,6 +438,9 @@ theorem mapIdx_eq_replicate_iff {xs : Array α} {f : Nat → α → β} {b : β}
rw [ toList_inj]
simp [List.mapIdx_eq_replicate_iff]
@[deprecated mapIdx_eq_replicate_iff (since := "2025-03-18")]
abbrev mapIdx_eq_mkArray_iff := @mapIdx_eq_replicate_iff
@[simp, grind =] theorem mapIdx_reverse {xs : Array α} {f : Nat α β} :
xs.reverse.mapIdx f = (mapIdx (fun i => f (xs.size - 1 - i)) xs).reverse := by
rcases xs with xs

View File

@@ -84,6 +84,9 @@ theorem Perm.size_eq {xs ys : Array α} (p : xs ~ ys) : xs.size = ys.size := by
simp only [perm_iff_toList_perm] at p
simpa using p.length_eq
@[deprecated Perm.size_eq (since := "2025-04-17")]
abbrev Perm.length_eq := @Perm.size_eq
theorem Perm.mem_iff {a : α} {xs ys : Array α} (p : xs ~ ys) : a xs a ys := by
rcases xs with xs
rcases ys with ys
@@ -104,7 +107,7 @@ grind_pattern Perm.append => xs ~ ys, as ~ bs, ys ++ bs
theorem Perm.push (x : α) {xs ys : Array α} (p : xs ~ ys) :
xs.push x ~ ys.push x := by
rw [push_eq_append]
rw [push_eq_append_singleton]
exact p.append .rfl
grind_pattern Perm.push => xs ~ ys, xs.push x

View File

@@ -166,6 +166,9 @@ theorem zipWith_eq_append_iff {f : α → β → γ} {as : Array α} {bs : Array
zipWith f (replicate m a) (replicate n b) = replicate (min m n) (f a b) := by
simp [ List.toArray_replicate]
@[deprecated zipWith_replicate (since := "2025-03-18")]
abbrev zipWith_mkArray := @zipWith_replicate
theorem map_uncurry_zip_eq_zipWith {f : α β γ} {as : Array α} {bs : Array β} :
map (Function.uncurry f) (as.zip bs) = zipWith f as bs := by
cases as
@@ -291,6 +294,9 @@ theorem zip_eq_append_iff {as : Array α} {bs : Array β} :
zip (replicate m a) (replicate n b) = replicate (min m n) (a, b) := by
simp [ List.toArray_replicate]
@[deprecated zip_replicate (since := "2025-03-18")]
abbrev zip_mkArray := @zip_replicate
theorem zip_eq_zip_take_min {as : Array α} {bs : Array β} :
zip as bs = zip (as.take (min as.size bs.size)) (bs.take (min as.size bs.size)) := by
cases as
@@ -342,6 +348,9 @@ theorem map_zipWithAll {δ : Type _} {f : α → β} {g : Option γ → Option
zipWithAll f (replicate n a) (replicate n b) = replicate n (f (some a) (some b)) := by
simp [ List.toArray_replicate]
@[deprecated zipWithAll_replicate (since := "2025-03-18")]
abbrev zipWithAll_mkArray := @zipWithAll_replicate
/-! ### zipWithM -/
@[simp, grind =]
@@ -399,4 +408,7 @@ theorem zip_of_prod {as : Array α} {bs : Array β} {xs : Array (α × β)} (hl
unzip (replicate n (a, b)) = (replicate n a, replicate n b) := by
ext1 <;> simp
@[deprecated unzip_replicate (since := "2025-03-18")]
abbrev unzip_mkArray := @unzip_replicate
end Array

10
src/Init/Data/Basic.lean Normal file
View File

@@ -0,0 +1,10 @@
/-
Copyright (c) 2016 Microsoft Corporation. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Leonardo de Moura
-/
module
prelude
public import Init.Data.UInt
public import Init.Data.String.Extra

View File

@@ -203,8 +203,8 @@ If `n` is `0`, then one digit is returned. Otherwise, `⌊(n + 3) / 4⌋` digits
-- `Internal` string functions by moving this definition out to a separate file that can live
-- downstream of `Init.Data.String.Basic`.
protected def toHex {n : Nat} (x : BitVec n) : String :=
let s := String.ofList (Nat.toDigits 16 x.toNat)
let t := String.ofList (List.replicate ((n+3) / 4 - String.Internal.length s) '0')
let s := (Nat.toDigits 16 x.toNat).asString
let t := (List.replicate ((n+3) / 4 - String.Internal.length s) '0').asString
String.Internal.append t s
/-- `BitVec` representation. -/

View File

@@ -635,11 +635,12 @@ theorem mulRec_eq_mul_signExtend_setWidth (x y : BitVec w) (s : Nat) :
simp only [mulRec_zero_eq, ofNat_eq_ofNat, Nat.reduceAdd]
by_cases y.getLsbD 0
case pos hy =>
simp only [hy, reduceIte, setWidth_one, ofBool_true, ofNat_eq_ofNat]
simp only [hy, reduceIte, setWidth_one_eq_ofBool_getLsb_zero,
ofBool_true, ofNat_eq_ofNat]
rw [setWidth_ofNat_one_eq_ofNat_one_of_lt (by omega)]
simp
case neg hy =>
simp [hy, setWidth_one]
simp [hy, setWidth_one_eq_ofBool_getLsb_zero]
case succ s' hs =>
rw [mulRec_succ_eq, hs]
have heq :
@@ -1024,7 +1025,7 @@ theorem lawful_divSubtractShift (qr : DivModState w) (h : qr.Poised args) :
case neg.hrWidth =>
simp only
have hdr' : d (qr.r.shiftConcat (n.getLsbD (qr.wn - 1))) :=
BitVec.not_lt.mp rltd
BitVec.not_lt_iff_le.mp rltd
have hr' : ((qr.r.shiftConcat (n.getLsbD (qr.wn - 1)))).toNat < 2 ^ (qr.wr + 1) := by
apply toNat_shiftConcat_lt_of_lt <;> bv_omega
rw [BitVec.toNat_sub_of_le hdr']
@@ -1032,7 +1033,7 @@ theorem lawful_divSubtractShift (qr : DivModState w) (h : qr.Poised args) :
case neg.hqWidth =>
apply toNat_shiftConcat_lt_of_lt <;> omega
case neg.hdiv =>
have rltd' := (BitVec.not_lt.mp rltd)
have rltd' := (BitVec.not_lt_iff_le.mp rltd)
simp only [qr.toNat_shiftRight_sub_one_eq h,
BitVec.toNat_sub_of_le rltd',
toNat_shiftConcat_eq_of_lt (qr.wr_lt_w h) h.hrWidth]
@@ -1406,7 +1407,7 @@ theorem eq_iff_eq_of_inv (f : α → BitVec w) (g : BitVec w → α) (h : ∀ x,
have := congrArg g h'
simpa [h] using this
@[deprecated BitVec.ne_intMin_of_msb_eq_false (since := "2025-10-26")]
@[simp]
theorem ne_intMin_of_lt_of_msb_false {x : BitVec w} (hw : 0 < w) (hx : x.msb = false) :
x intMin w := by
have := toNat_lt_of_msb_false hx
@@ -1511,7 +1512,7 @@ theorem sdiv_ne_intMin_of_ne_intMin {x y : BitVec w} (h : x ≠ intMin w) :
by_cases hx : x.msb <;> by_cases hy : y.msb
<;> simp only [hx, hy, neg_ne_intMin_inj]
<;> simp only [Bool.not_eq_true] at hx hy
<;> apply ne_intMin_of_msb_eq_false (by omega)
<;> apply ne_intMin_of_lt_of_msb_false (by omega)
<;> rw [msb_udiv]
<;> try simp only [hx, Bool.false_and]
· simp [h, ne_zero_of_msb_true, hx]
@@ -1623,7 +1624,7 @@ theorem toInt_sdiv_of_ne_or_ne (a b : BitVec w) (h : a ≠ intMin w b ≠ -1
· have ry := (intMin_udiv_eq_intMin_iff b).mp
simp only [hb1, imp_false] at ry
simp [msb_udiv, ha_intMin, hb1, ry, intMin_udiv_ne_zero_of_ne_zero, hb, hb0]
· have := @BitVec.ne_intMin_of_msb_eq_false w wpos ((-a) / b) (by simp [ha, ha0, ha_intMin])
· have := @BitVec.ne_intMin_of_lt_of_msb_false w ((-a) / b) wpos (by simp [ha, ha0, ha_intMin])
simp [msb_neg, h', this, ha, ha_intMin]
rw [toInt_eq_toNat_of_msb hb, toInt_eq_neg_toNat_neg_of_msb_true ha, Int.neg_tdiv,
Int.tdiv_eq_ediv_of_nonneg (by omega), sdiv_toInt_of_msb_true_of_msb_false]
@@ -1634,7 +1635,7 @@ theorem toInt_sdiv_of_ne_or_ne (a b : BitVec w) (h : a ≠ intMin w b ≠ -1
rw [toInt_udiv_of_msb ha, toInt_eq_toNat_of_msb ha]
rw [toInt_eq_neg_toNat_neg_of_msb_true hb, Int.tdiv_neg, Int.tdiv_eq_ediv_of_nonneg (by omega)]
· apply sdiv_ne_intMin_of_ne_intMin
apply ne_intMin_of_msb_eq_false (by omega) ha
apply ne_intMin_of_lt_of_msb_false (by omega) ha
· rw [sdiv, Int.tdiv_cases, udiv_eq, neg_eq, if_pos (toInt_nonneg_of_msb_false ha),
if_pos (toInt_nonneg_of_msb_false hb), ha, hb, toInt_udiv_of_msb ha,
toInt_eq_toNat_of_msb ha, toInt_eq_toNat_of_msb hb]
@@ -1926,7 +1927,7 @@ theorem toInt_sub_neg_umod {x y : BitVec w} (hxmsb : x.msb = true) (hymsb : y.ms
rw [Int.bmod_eq_of_le (by omega) (by omega)]
simp only [toInt_eq_toNat_of_msb hymsb, BitVec.toInt_eq_neg_toNat_neg_of_msb_true hxmsb,
Int.dvd_neg] at hdvd
simp only [hdvd, reduceIte, Int.natAbs_natCast]
simp only [hdvd, reduceIte, Int.natAbs_cast]
theorem srem_zero_of_dvd {x y : BitVec w} (h : y.toInt x.toInt) :
x.srem y = 0#w := by

View File

@@ -82,7 +82,7 @@ theorem iunfoldr_getLsbD' {f : Fin w → αα × Bool} (state : Nat → α)
intro i
simp only [getLsbD_cons]
have hj2 : j.val w := by simp
cases (Nat.lt_or_eq_of_le (Nat.lt_succ_iff.mp i.isLt)) with
cases (Nat.lt_or_eq_of_le (Nat.lt_succ.mp i.isLt)) with
| inl h3 => simp [(Nat.ne_of_lt h3)]
exact (ih hj2).1 i.val, h3
| inr h3 => simp [h3]

View File

@@ -34,6 +34,14 @@ namespace BitVec
simp only [Bool.and_eq_false_imp, decide_eq_true_eq]
omega
set_option linter.missingDocs false in
@[deprecated getLsbD_of_ge (since := "2025-04-04")]
abbrev getLsbD_ge := @getLsbD_of_ge
set_option linter.missingDocs false in
@[deprecated getMsbD_of_ge (since := "2025-04-04")]
abbrev getMsbD_ge := @getMsbD_of_ge
theorem lt_of_getLsbD {x : BitVec w} {i : Nat} : getLsbD x i = true i < w := by
if h : i < w then
simp [h]
@@ -64,7 +72,6 @@ theorem getElem?_eq_none_iff {l : BitVec w} : l[n]? = none ↔ w ≤ n := by
theorem none_eq_getElem?_iff {l : BitVec w} : none = l[n]? w n := by
simp
@[simp]
theorem getElem?_eq_none {l : BitVec w} (h : w n) : l[n]? = none := getElem?_eq_none_iff.mpr h
theorem getElem?_eq (l : BitVec w) (i : Nat) :
@@ -133,6 +140,9 @@ theorem two_pow_le_toNat_of_getElem_eq_true {i : Nat} {x : BitVec w}
rw [ getElem_eq_testBit_toNat x i hi]
exact hx
@[grind =] theorem msb_eq_getMsbD (x : BitVec w) : x.msb = x.getMsbD 0 := by
simp [BitVec.msb]
@[grind =] theorem getMsb_eq_getLsb (x : BitVec w) (i : Fin w) :
x.getMsb i = x.getLsb w - 1 - i, by omega := by
simp only [getMsb, getLsb]
@@ -159,13 +169,18 @@ theorem getLsbD_eq_getMsbD (x : BitVec w) (i : Nat) : x.getLsbD i = (decide (i <
apply getLsbD_of_ge
omega
@[deprecated getElem?_eq_none (since := "2025-10-29")]
theorem getElem?_of_ge (x : BitVec w) (i : Nat) (ge : w i) : x[i]? = none := by
@[simp] theorem getElem?_of_ge (x : BitVec w) (i : Nat) (ge : w i) : x[i]? = none := by
simp [ge]
@[simp] theorem getMsb?_of_ge (x : BitVec w) (i : Nat) (ge : w i) : getMsb? x i = none := by
simp [getMsb?_eq_getLsb?]; omega
set_option linter.missingDocs false in
@[deprecated getElem?_of_ge (since := "2025-04-04")] abbrev getLsb?_ge := @getElem?_of_ge
set_option linter.missingDocs false in
@[deprecated getMsb?_of_ge (since := "2025-04-04")] abbrev getMsb?_ge := @getMsb?_of_ge
theorem lt_of_getElem?_eq_some (x : BitVec w) (i : Nat) : x[i]? = some b i < w := by
cases h : x[i]? with
| none => simp
@@ -188,6 +203,18 @@ theorem lt_of_isSome_getMsb? (x : BitVec w) (i : Nat) : (getMsb? x i).isSome →
else
simp [Nat.ge_of_not_lt h]
set_option linter.missingDocs false in
@[deprecated lt_of_getElem?_eq_some (since := "2025-04-04")]
abbrev lt_of_getLsb?_eq_some := @lt_of_getElem?_eq_some
set_option linter.missingDocs false in
@[deprecated lt_of_isSome_getElem? (since := "2025-04-04")]
abbrev lt_of_getLsb?_isSome := @lt_of_isSome_getElem?
set_option linter.missingDocs false in
@[deprecated lt_of_isSome_getMsb? (since := "2025-04-04")]
abbrev lt_of_getMsb?_isSome := @lt_of_isSome_getMsb?
theorem getMsbD_eq_getMsb?_getD (x : BitVec w) (i : Nat) :
x.getMsbD i = (x.getMsb? i).getD false := by
rw [getMsbD_eq_getLsbD]
@@ -417,18 +444,12 @@ theorem getElem?_zero_ofNat_one : (BitVec.ofNat (w+1) 1)[0]? = some true := by
-- This does not need to be a `@[simp]` theorem as it is already handled by `getElem?_eq_getElem`.
theorem getElem?_zero_ofBool (b : Bool) : (ofBool b)[0]? = some b := by
simp only [ofBool, ofNat_eq_ofNat, cond_eq_ite]
simp only [ofBool, ofNat_eq_ofNat, cond_eq_if]
split <;> simp_all
@[simp, grind =]
theorem getElem_ofBool_zero {b : Bool} : (ofBool b)[0] = b := by
@[simp, grind =] theorem getElem_zero_ofBool (b : Bool) : (ofBool b)[0] = b := by
rw [getElem_eq_iff, getElem?_zero_ofBool]
@[deprecated getElem_ofBool_zero (since := "2025-10-29")]
theorem getElem_zero_ofBool (b : Bool) : (ofBool b)[0] = b := by
simp
theorem getElem?_succ_ofBool (b : Bool) (i : Nat) : (ofBool b)[i + 1]? = none := by
simp
@@ -439,6 +460,8 @@ theorem getLsbD_ofBool (b : Bool) (i : Nat) : (ofBool b).getLsbD i = ((i = 0) &&
· simp only [ofBool, ofNat_eq_ofNat, cond_true, getLsbD_ofNat, Bool.and_true]
by_cases hi : i = 0 <;> simp [hi] <;> omega
theorem getElem_ofBool_zero {b : Bool} : (ofBool b)[0] = b := by simp
@[simp]
theorem getElem_ofBool {b : Bool} {h : i < 1}: (ofBool b)[i] = b := by
simp [ getLsbD_eq_getElem]
@@ -521,10 +544,6 @@ theorem toNat_ge_of_msb_true {x : BitVec n} (p : BitVec.msb x = true) : x.toNat
@[grind _=_] theorem msb_eq_getMsbD_zero (x : BitVec w) : x.msb = x.getMsbD 0 := by
cases w <;> simp [getMsbD_eq_getLsbD, msb_eq_getLsbD_last]
@[deprecated msb_eq_getMsbD_zero (since := "2025-10-26")]
theorem msb_eq_getMsbD (x : BitVec w) : x.msb = x.getMsbD 0 := by
simp [BitVec.msb]
/-! ### cast -/
@[simp, grind =] theorem toFin_cast (h : w = v) (x : BitVec w) :
@@ -586,7 +605,7 @@ theorem toInt_eq_toNat_bmod (x : BitVec n) : x.toInt = Int.bmod x.toNat (2^n) :=
simp only [toInt_eq_toNat_cond]
split
next g =>
rw [Int.bmod_eq_emod_of_lt] <;> simp only [Int.natCast_emod, toNat_mod_cancel]
rw [Int.bmod_pos] <;> simp only [Int.natCast_emod, toNat_mod_cancel]
omega
next g =>
rw [Int.bmod_neg] <;> simp only [Int.natCast_emod, toNat_mod_cancel]
@@ -994,14 +1013,7 @@ theorem msb_setWidth' (x : BitVec w) (h : w ≤ v) : (x.setWidth' h).msb = (deci
theorem msb_setWidth'' (x : BitVec w) : (x.setWidth (k + 1)).msb = x.getLsbD k := by
simp [BitVec.msb, getMsbD]
/-- Truncating to width 1 produces a bitvector equal to the least significant bit. -/
theorem setWidth_one {x : BitVec w} :
x.setWidth 1 = ofBool (x.getLsbD 0) := by
ext i
simp [show i = 0 by omega]
/-- zero extending a bitvector to width 1 equals the boolean of the lsb. -/
@[deprecated setWidth_one (since := "2025-10-29")]
theorem setWidth_one_eq_ofBool_getLsb_zero (x : BitVec w) :
x.setWidth 1 = BitVec.ofBool (x.getLsbD 0) := by
ext i h
@@ -1017,6 +1029,12 @@ theorem setWidth_ofNat_one_eq_ofNat_one_of_lt {v w : Nat} (hv : 0 < v) :
have hv := (@Nat.testBit_one_eq_true_iff_self_eq_zero i)
by_cases h : Nat.testBit 1 i = true <;> simp_all
/-- Truncating to width 1 produces a bitvector equal to the least significant bit. -/
theorem setWidth_one {x : BitVec w} :
x.setWidth 1 = ofBool (x.getLsbD 0) := by
ext i
simp [show i = 0 by omega]
@[simp, grind =] theorem setWidth_ofNat_of_le (h : v w) (x : Nat) : setWidth v (BitVec.ofNat w x) = BitVec.ofNat v x := by
apply BitVec.eq_of_toNat_eq
simp only [toNat_setWidth, toNat_ofNat]
@@ -1056,7 +1074,7 @@ theorem toInt_setWidth' {m n : Nat} (p : m ≤ n) {x : BitVec m} :
@[simp, grind =] theorem toFin_setWidth' {m n : Nat} (p : m n) (x : BitVec m) :
(setWidth' p x).toFin = x.toFin.castLE (Nat.pow_le_pow_right (by omega) (by omega)) := by
ext
rw [setWidth'_eq, toFin_setWidth, Fin.val_ofNat, Fin.val_castLE, val_toFin,
rw [setWidth'_eq, toFin_setWidth, Fin.val_ofNat, Fin.coe_castLE, val_toFin,
Nat.mod_eq_of_lt (by apply BitVec.toNat_lt_twoPow_of_le p)]
theorem toNat_setWidth_of_le {w w' : Nat} {b : BitVec w} (h : w w') : (b.setWidth w').toNat = b.toNat := by
@@ -1190,7 +1208,7 @@ let x' = x.extractLsb' 7 5 = _ _ 9 8 7
@[simp] theorem getLsbD_extract (hi lo : Nat) (x : BitVec n) (i : Nat) :
getLsbD (extractLsb hi lo x) i = (i (hi-lo) && getLsbD x (lo+i)) := by
simp [getLsbD, Nat.lt_succ_iff]
simp [getLsbD, Nat.lt_succ]
@[simp] theorem getLsbD_extractLsb {hi lo : Nat} {x : BitVec n} {i : Nat} :
(extractLsb hi lo x).getLsbD i = (decide (i < hi - lo + 1) && x.getLsbD (lo + i)) := by
@@ -1646,11 +1664,11 @@ theorem not_def {x : BitVec v} : ~~~x = allOnes v ^^^ x := rfl
@[simp] theorem ofInt_negSucc_eq_not_ofNat {w n : Nat} :
BitVec.ofInt w (Int.negSucc n) = ~~~.ofNat w n := by
simp only [BitVec.ofInt, Int.toNat, Int.ofNat_eq_natCast, toNat_eq, toNat_ofNatLT, toNat_not,
simp only [BitVec.ofInt, Int.toNat, Int.ofNat_eq_coe, toNat_eq, toNat_ofNatLT, toNat_not,
toNat_ofNat]
cases h : Int.negSucc n % ((2 ^ w : Nat) : Int)
case ofNat =>
rw [Int.ofNat_eq_natCast, Int.negSucc_emod] at h
rw [Int.ofNat_eq_coe, Int.negSucc_emod] at h
· dsimp only
omega
· omega
@@ -1732,6 +1750,9 @@ theorem not_eq_comm {x y : BitVec w} : ~~~ x = y ↔ x = ~~~ y := by
rw [h]
simp
set_option linter.missingDocs false in
@[deprecated getMsbD_not (since := "2025-04-04")] abbrev getMsb_not := @getMsbD_not
@[simp] theorem msb_not {x : BitVec w} : (~~~x).msb = (decide (0 < w) && !x.msb) := by
simp [BitVec.msb]
@@ -2551,6 +2572,10 @@ theorem signExtend_eq_setWidth_of_le (x : BitVec w) {v : Nat} (hv : v ≤ w) :
ext i h
simp [getElem_signExtend, show i < w by omega]
@[deprecated signExtend_eq_setWidth_of_le (since := "2025-03-07")]
theorem signExtend_eq_setWidth_of_lt (x : BitVec w) {v : Nat} (hv : v w) :
x.signExtend v = x.setWidth v := signExtend_eq_setWidth_of_le x hv
/-- Sign extending to the same bitwidth is a no op. -/
@[simp] theorem signExtend_eq (x : BitVec w) : x.signExtend w = x := by
rw [signExtend_eq_setWidth_of_le _ (Nat.le_refl _), setWidth_eq]
@@ -3610,6 +3635,9 @@ theorem sub_eq_add_neg {n} (x y : BitVec n) : x - y = x + - y := by
simp only [toNat_sub, toNat_add, toNat_neg, Nat.add_mod_mod]
rw [Nat.add_comm]
set_option linter.missingDocs false in
@[deprecated sub_eq_add_neg (since := "2025-04-04")] abbrev sub_toAdd := @sub_eq_add_neg
theorem add_left_neg (x : BitVec w) : -x + x = 0#w := by
apply toInt_inj.mp
simp [toInt_neg, Int.add_left_neg]
@@ -3649,6 +3677,10 @@ theorem neg_one_eq_allOnes : -1#w = allOnes w := by
have r : (2^w - 1) < 2^w := by omega
simp [Nat.mod_eq_of_lt q, Nat.mod_eq_of_lt r]
set_option linter.missingDocs false in
@[deprecated neg_one_eq_allOnes (since := "2025-04-04")]
abbrev negOne_eq_allOnes := @neg_one_eq_allOnes
theorem neg_eq_not_add (x : BitVec w) : -x = ~~~x + 1#w := by
apply eq_of_toNat_eq
simp only [toNat_neg, toNat_add, toNat_not, toNat_ofNat, Nat.add_mod_mod]
@@ -4065,7 +4097,6 @@ protected theorem umod_lt (x : BitVec n) {y : BitVec n} : 0 < y → x % y < y :=
simp only [ofNat_eq_ofNat, lt_def, toNat_ofNat, Nat.zero_mod]
apply Nat.mod_lt
@[deprecated BitVec.not_lt (since := "2025-10-26")]
theorem not_lt_iff_le {x y : BitVec w} : (¬ x < y) y x := by
constructor <;>
(intro h; simp only [lt_def, Nat.not_lt, le_def] at h ; omega)
@@ -4082,7 +4113,7 @@ theorem not_lt_zero {x : BitVec w} : ¬x < 0#w := of_decide_eq_false rfl
theorem le_zero_iff {x : BitVec w} : x 0#w x = 0#w := by
constructor
· intro h
have : x 0 := BitVec.not_lt.mp not_lt_zero
have : x 0 := not_lt_iff_le.mp not_lt_zero
exact Eq.symm (BitVec.le_antisymm this h)
· simp_all
@@ -4105,7 +4136,7 @@ theorem not_allOnes_lt {x : BitVec w} : ¬allOnes w < x := by
theorem allOnes_le_iff {x : BitVec w} : allOnes w x x = allOnes w := by
constructor
· intro h
have : x allOnes w := BitVec.not_lt.mp not_allOnes_lt
have : x allOnes w := not_lt_iff_le.mp not_allOnes_lt
exact Eq.symm (BitVec.le_antisymm h this)
· simp_all
@@ -4651,6 +4682,9 @@ theorem zero_smod {x : BitVec w} : (0#w).smod x = 0#w := by
@[simp, grind =] theorem getLsbD_ofBoolListLE : (ofBoolListLE bs).getLsbD i = bs.getD i false := by
induction bs generalizing i <;> cases i <;> simp_all [ofBoolListLE]
set_option linter.missingDocs false in
@[deprecated getLsbD_ofBoolListLE (since := "2025-04-04")] abbrev getLsb_ofBoolListLE := @getLsbD_ofBoolListLE
@[simp, grind =] theorem getMsbD_ofBoolListLE :
(ofBoolListLE bs).getMsbD i = (decide (i < bs.length) && bs.getD (bs.length - 1 - i) false) := by
simp [getMsbD_eq_getLsbD]
@@ -4721,6 +4755,14 @@ theorem getLsbD_rotateLeftAux_of_ge {x : BitVec w} {r : Nat} {i : Nat} (hi : i
apply getLsbD_of_ge
omega
set_option linter.missingDocs false in
@[deprecated getLsbD_rotateLeftAux_of_lt (since := "2025-04-04")]
abbrev getLsbD_rotateLeftAux_of_le := @getLsbD_rotateLeftAux_of_lt
set_option linter.missingDocs false in
@[deprecated getLsbD_rotateLeftAux_of_ge (since := "2025-04-04")]
abbrev getLsbD_rotateLeftAux_of_geq := @getLsbD_rotateLeftAux_of_ge
/-- When `r < w`, we give a formula for `(x.rotateLeft r).getLsbD i`. -/
theorem getLsbD_rotateLeft_of_le {x : BitVec w} {r i : Nat} (hr: r < w) :
(x.rotateLeft r).getLsbD i =
@@ -4877,6 +4919,14 @@ theorem getLsbD_rotateRightAux_of_ge {x : BitVec w} {r : Nat} {i : Nat} (hi : i
apply getLsbD_of_ge
omega
set_option linter.missingDocs false in
@[deprecated getLsbD_rotateRightAux_of_lt (since := "2025-04-04")]
abbrev getLsbD_rotateRightAux_of_le := @getLsbD_rotateRightAux_of_lt
set_option linter.missingDocs false in
@[deprecated getLsbD_rotateRightAux_of_ge (since := "2025-04-04")]
abbrev getLsbD_rotateRightAux_of_geq := @getLsbD_rotateRightAux_of_ge
/-- `rotateRight` equals the bit fiddling definition of `rotateRightAux` when the rotation amount is
smaller than the bitwidth. -/
theorem rotateRight_eq_rotateRightAux_of_lt {x : BitVec w} {r : Nat} (hr : r < w) :

View File

@@ -111,11 +111,35 @@ Needed for confluence of term `(a && b) ↔ a` which reduces to `(a && b) = a` v
@[simp] theorem eq_self_and : {a b : Bool}, (a = (a && b)) (a b) := by decide
@[simp] theorem eq_and_self : {a b : Bool}, (b = (a && b)) (b a) := by decide
@[deprecated and_eq_left_iff_imp (since := "2025-04-04")]
abbrev and_iff_left_iff_imp := @and_eq_left_iff_imp
@[deprecated and_eq_right_iff_imp (since := "2025-04-04")]
abbrev and_iff_right_iff_imp := @and_eq_right_iff_imp
@[deprecated eq_self_and (since := "2025-04-04")]
abbrev iff_self_and := @eq_self_and
@[deprecated eq_and_self (since := "2025-04-04")]
abbrev iff_and_self := @eq_and_self
@[simp] theorem not_and_eq_left_iff_and : {a b : Bool}, ((!a && b) = a) !a !b := by decide
@[simp] theorem and_not_eq_right_iff_and : {a b : Bool}, ((a && !b) = b) !a !b := by decide
@[simp] theorem eq_not_self_and : {a b : Bool}, (a = (!a && b)) !a !b := by decide
@[simp] theorem eq_and_not_self : {a b : Bool}, (b = (a && !b)) !a !b := by decide
@[deprecated not_and_eq_left_iff_and (since := "2025-04-04")]
abbrev not_and_iff_left_iff_imp := @not_and_eq_left_iff_and
@[deprecated and_not_eq_right_iff_and (since := "2025-04-04")]
abbrev and_not_iff_right_iff_imp := @and_not_eq_right_iff_and
@[deprecated eq_not_self_and (since := "2025-04-04")]
abbrev iff_not_self_and := @eq_not_self_and
@[deprecated eq_and_not_self (since := "2025-04-04")]
abbrev iff_and_not_self := @eq_and_not_self
/-! ### or -/
@[simp] theorem or_self_left : (a b : Bool), (a || (a || b)) = (a || b) := by decide
@@ -145,11 +169,35 @@ Needed for confluence of term `(a || b) ↔ a` which reduces to `(a || b) = a` v
@[simp] theorem eq_self_or : {a b : Bool}, (a = (a || b)) (b a) := by decide
@[simp] theorem eq_or_self : {a b : Bool}, (b = (a || b)) (a b) := by decide
@[deprecated or_eq_left_iff_imp (since := "2025-04-04")]
abbrev or_iff_left_iff_imp := @or_eq_left_iff_imp
@[deprecated or_eq_right_iff_imp (since := "2025-04-04")]
abbrev or_iff_right_iff_imp := @or_eq_right_iff_imp
@[deprecated eq_self_or (since := "2025-04-04")]
abbrev iff_self_or := @eq_self_or
@[deprecated eq_or_self (since := "2025-04-04")]
abbrev iff_or_self := @eq_or_self
@[simp] theorem not_or_eq_left_iff_and : {a b : Bool}, ((!a || b) = a) a b := by decide
@[simp] theorem or_not_eq_right_iff_and : {a b : Bool}, ((a || !b) = b) a b := by decide
@[simp] theorem eq_not_self_or : {a b : Bool}, (a = (!a || b)) a b := by decide
@[simp] theorem eq_or_not_self : {a b : Bool}, (b = (a || !b)) a b := by decide
@[deprecated not_or_eq_left_iff_and (since := "2025-04-04")]
abbrev not_or_iff_left_iff_imp := @not_or_eq_left_iff_and
@[deprecated or_not_eq_right_iff_and (since := "2025-04-04")]
abbrev or_not_iff_right_iff_imp := @or_not_eq_right_iff_and
@[deprecated eq_not_self_or (since := "2025-04-04")]
abbrev iff_not_self_or := @eq_not_self_or
@[deprecated eq_or_not_self (since := "2025-04-04")]
abbrev iff_or_not_self := @eq_or_not_self
theorem or_comm : (x y : Bool), (x || y) = (y || x) := by decide
instance : Std.Commutative (· || ·) := or_comm
@@ -514,7 +562,6 @@ theorem exists_bool {p : Bool → Prop} : (∃ b, p b) ↔ p false p true :=
theorem cond_eq_ite {α} (b : Bool) (t e : α) : cond b t e = if b then t else e := by
cases b <;> simp
@[deprecated cond_eq_ite (since := "2025-10-29")]
theorem cond_eq_if : (bif b then x else y) = (if b then x else y) := cond_eq_ite b x y
@[simp] theorem cond_not (b : Bool) (t e : α) : cond (!b) t e = cond b e t := by
@@ -574,6 +621,11 @@ protected theorem cond_false {α : Sort u} {a b : α} : cond false a b = b := co
@[simp] theorem cond_then_self : (c b : Bool), cond c c b = (c || b) := by decide
@[simp] theorem cond_else_self : (c b : Bool), cond c b c = (c && b) := by decide
@[deprecated cond_then_not_self (since := "2025-04-04")] abbrev cond_true_not_same := @cond_then_not_self
@[deprecated cond_else_not_self (since := "2025-04-04")] abbrev cond_false_not_same := @cond_else_not_self
@[deprecated cond_then_self (since := "2025-04-04")] abbrev cond_true_same := @cond_then_self
@[deprecated cond_else_self (since := "2025-04-04")] abbrev cond_false_same := @cond_else_self
theorem cond_pos {b : Bool} {a a' : α} (h : b = true) : (bif b then a else a') = a := by
rw [h, cond_true]
@@ -613,7 +665,7 @@ theorem decide_beq_decide (p q : Prop) [dpq : Decidable (p ↔ q)] [dp : Decidab
end Bool
export Bool (cond_eq_if cond_eq_ite xor and or not)
export Bool (cond_eq_if xor and or not)
/-! ### decide -/

View File

@@ -24,6 +24,9 @@ attribute [ext] ByteArray
instance : DecidableEq ByteArray :=
fun _ _ => decidable_of_decidable_of_iff ByteArray.ext_iff.symm
@[deprecated emptyWithCapacity (since := "2025-03-12")]
abbrev mkEmpty := emptyWithCapacity
instance : Inhabited ByteArray where
default := empty
@@ -132,11 +135,6 @@ Copies the bytes with indices {name}`b` (inclusive) to {name}`e` (exclusive) to
def extract (a : ByteArray) (b e : Nat) : ByteArray :=
a.copySlice b empty 0 (e - b)
/--
Appends two byte arrays using fast array primitives instead of converting them into lists and back.
In compiled code, this function replaces calls to {name}`ByteArray.append`.
-/
@[inline]
protected def fastAppend (a : ByteArray) (b : ByteArray) : ByteArray :=
-- we assume that `append`s may be repeated, so use asymptotic growing; use `copySlice` directly to customize
@@ -248,7 +246,7 @@ protected def forIn {β : Type v} {m : Type v → Type w} [Monad m] (as : ByteAr
| ForInStep.yield b => loop i (Nat.le_of_lt h') b
loop as.size (Nat.le_refl _) b
instance [Monad m] : ForIn m ByteArray UInt8 where
instance : ForIn m ByteArray UInt8 where
forIn := ByteArray.forIn
/--

View File

@@ -10,8 +10,6 @@ public import Init.Data.ByteArray.Basic
public section
namespace ByteArray
-- At present the preferred normal form for empty byte arrays is `ByteArray.empty`
@[simp]
theorem emptyc_eq_empty : ( : ByteArray) = ByteArray.empty := rfl
@@ -20,10 +18,10 @@ theorem emptyc_eq_empty : (∅ : ByteArray) = ByteArray.empty := rfl
theorem emptyWithCapacity_eq_empty : ByteArray.emptyWithCapacity 0 = ByteArray.empty := rfl
@[simp]
theorem data_empty : ByteArray.empty.data = #[] := rfl
theorem ByteArray.data_empty : ByteArray.empty.data = #[] := rfl
@[simp]
theorem data_extract {a : ByteArray} {b e : Nat} :
theorem ByteArray.data_extract {a : ByteArray} {b e : Nat} :
(a.extract b e).data = a.data.extract b e := by
simp [extract, copySlice]
by_cases b e
@@ -31,39 +29,39 @@ theorem data_extract {a : ByteArray} {b e : Nat} :
· rw [Array.extract_eq_empty_of_le (by omega), Array.extract_eq_empty_of_le (by omega)]
@[simp]
theorem extract_zero_size {b : ByteArray} : b.extract 0 b.size = b := by
theorem ByteArray.extract_zero_size {b : ByteArray} : b.extract 0 b.size = b := by
ext1
simp
@[simp]
theorem extract_same {b : ByteArray} {i : Nat} : b.extract i i = ByteArray.empty := by
theorem ByteArray.extract_same {b : ByteArray} {i : Nat} : b.extract i i = ByteArray.empty := by
ext1
simp [Nat.min_le_left]
theorem fastAppend_eq_copySlice {a b : ByteArray} :
theorem ByteArray.fastAppend_eq_copySlice {a b : ByteArray} :
a.fastAppend b = b.copySlice 0 a a.size b.size false := rfl
@[simp]
theorem _root_.List.toByteArray_append {l l' : List UInt8} :
theorem List.toByteArray_append {l l' : List UInt8} :
(l ++ l').toByteArray = l.toByteArray ++ l'.toByteArray := by
simp [List.toByteArray_append']
@[simp]
theorem toList_data_append {l l' : ByteArray} :
theorem ByteArray.toList_data_append {l l' : ByteArray} :
(l ++ l').data.toList = l.data.toList ++ l'.data.toList := by
simp [ append_eq]
@[simp]
theorem data_append {l l' : ByteArray} :
theorem ByteArray.data_append {l l' : ByteArray} :
(l ++ l').data = l.data ++ l'.data := by
simp [ Array.toList_inj]
@[simp]
theorem size_empty : ByteArray.empty.size = 0 := by
theorem ByteArray.size_empty : ByteArray.empty.size = 0 := by
simp [ ByteArray.size_data]
@[simp]
theorem _root_.List.data_toByteArray {l : List UInt8} :
theorem List.data_toByteArray {l : List UInt8} :
l.toByteArray.data = l.toArray := by
rw [List.toByteArray]
suffices a b, (List.toByteArray.loop a b).data = b.data ++ a.toArray by
@@ -72,159 +70,153 @@ theorem _root_.List.data_toByteArray {l : List UInt8} :
fun_induction List.toByteArray.loop a b with simp_all
@[simp]
theorem _root_.List.size_toByteArray {l : List UInt8} :
theorem List.size_toByteArray {l : List UInt8} :
l.toByteArray.size = l.length := by
simp [ ByteArray.size_data]
@[simp]
theorem _root_.List.toByteArray_nil : List.toByteArray [] = ByteArray.empty := rfl
theorem List.toByteArray_nil : List.toByteArray [] = ByteArray.empty := rfl
@[simp]
theorem empty_append {b : ByteArray} : ByteArray.empty ++ b = b := by
theorem ByteArray.empty_append {b : ByteArray} : ByteArray.empty ++ b = b := by
ext1
simp
@[simp]
theorem append_empty {b : ByteArray} : b ++ ByteArray.empty = b := by
theorem ByteArray.append_empty {b : ByteArray} : b ++ ByteArray.empty = b := by
ext1
simp
@[simp, grind =]
theorem size_append {a b : ByteArray} : (a ++ b).size = a.size + b.size := by
theorem ByteArray.size_append {a b : ByteArray} : (a ++ b).size = a.size + b.size := by
simp [ size_data]
@[simp]
theorem size_eq_zero_iff {a : ByteArray} : a.size = 0 a = ByteArray.empty := by
theorem ByteArray.size_eq_zero_iff {a : ByteArray} : a.size = 0 a = ByteArray.empty := by
refine fun h => ?_, fun h => h ByteArray.size_empty
ext1
simp [ Array.size_eq_zero_iff, h]
theorem getElem_eq_getElem_data {a : ByteArray} {i : Nat} {h : i < a.size} :
theorem ByteArray.getElem_eq_getElem_data {a : ByteArray} {i : Nat} {h : i < a.size} :
a[i] = a.data[i]'(by simpa [ size_data]) := rfl
@[simp]
theorem getElem_append_left {i : Nat} {a b : ByteArray} {h : i < (a ++ b).size}
theorem ByteArray.getElem_append_left {i : Nat} {a b : ByteArray} {h : i < (a ++ b).size}
(hlt : i < a.size) : (a ++ b)[i] = a[i] := by
simp only [getElem_eq_getElem_data, data_append]
rw [Array.getElem_append_left (by simpa)]
theorem getElem_append_right {i : Nat} {a b : ByteArray} {h : i < (a ++ b).size}
theorem ByteArray.getElem_append_right {i : Nat} {a b : ByteArray} {h : i < (a ++ b).size}
(hle : a.size i) : (a ++ b)[i] = b[i - a.size]'(by simp_all; omega) := by
simp only [getElem_eq_getElem_data, data_append]
rw [Array.getElem_append_right (by simpa)]
simp
@[simp]
theorem _root_.List.getElem_toByteArray {l : List UInt8} {i : Nat} {h : i < l.toByteArray.size} :
theorem List.getElem_toByteArray {l : List UInt8} {i : Nat} {h : i < l.toByteArray.size} :
l.toByteArray[i]'h = l[i]'(by simp_all) := by
simp [ByteArray.getElem_eq_getElem_data]
theorem _root_.List.getElem_eq_getElem_toByteArray {l : List UInt8} {i : Nat} {h : i < l.length} :
theorem List.getElem_eq_getElem_toByteArray {l : List UInt8} {i : Nat} {h : i < l.length} :
l[i]'h = l.toByteArray[i]'(by simp_all) := by
simp
@[simp]
theorem size_extract {a : ByteArray} {b e : Nat} :
theorem ByteArray.size_extract {a : ByteArray} {b e : Nat} :
(a.extract b e).size = min e a.size - b := by
simp [ size_data]
@[simp]
theorem extract_eq_empty_iff {b : ByteArray} {i j : Nat} : b.extract i j = ByteArray.empty min j b.size i := by
theorem ByteArray.extract_eq_empty_iff {b : ByteArray} {i j : Nat} : b.extract i j = ByteArray.empty min j b.size i := by
rw [ size_eq_zero_iff, size_extract]
omega
@[simp]
theorem extract_add_left {b : ByteArray} {i j : Nat} : b.extract (i + j) i = ByteArray.empty := by
theorem ByteArray.extract_add_left {b : ByteArray} {i j : Nat} : b.extract (i + j) i = ByteArray.empty := by
simp only [extract_eq_empty_iff]
exact Nat.le_trans (Nat.min_le_left _ _) (by simp)
@[simp]
theorem append_eq_empty_iff {a b : ByteArray} :
theorem ByteArray.append_eq_empty_iff {a b : ByteArray} :
a ++ b = ByteArray.empty a = ByteArray.empty b = ByteArray.empty := by
simp [ size_eq_zero_iff, size_append]
@[simp]
theorem toByteArray_eq_empty {l : List UInt8} :
theorem List.toByteArray_eq_empty {l : List UInt8} :
l.toByteArray = ByteArray.empty l = [] := by
simp [ ByteArray.size_eq_zero_iff]
@[simp]
theorem append_right_inj {ys₁ ys₂ : ByteArray} (xs : ByteArray) :
theorem ByteArray.append_right_inj {ys₁ ys₂ : ByteArray} (xs : ByteArray) :
xs ++ ys₁ = xs ++ ys₂ ys₁ = ys₂ := by
simp [ByteArray.ext_iff, Array.append_right_inj]
@[simp]
theorem append_left_inj {xs₁ xs₂ : ByteArray} (ys : ByteArray) :
xs₁ ++ ys = xs₂ ++ ys xs₁ = xs₂ := by
simp [ByteArray.ext_iff, Array.append_left_inj]
@[simp]
theorem extract_append_extract {a : ByteArray} {i j k : Nat} :
theorem ByteArray.extract_append_extract {a : ByteArray} {i j k : Nat} :
a.extract i j ++ a.extract j k = a.extract (min i j) (max j k) := by
ext1
simp
theorem extract_eq_extract_append_extract {a : ByteArray} {i k : Nat} (j : Nat)
theorem ByteArray.extract_eq_extract_append_extract {a : ByteArray} {i k : Nat} (j : Nat)
(hi : i j) (hk : j k) :
a.extract i k = a.extract i j ++ a.extract j k := by
simp
rw [Nat.min_eq_left hi, Nat.max_eq_right hk]
theorem append_inj_left {xs₁ xs₂ ys₁ ys₂ : ByteArray} (h : xs₁ ++ ys₁ = xs₂ ++ ys₂) (hl : xs₁.size = xs₂.size) : xs₁ = xs₂ := by
theorem ByteArray.append_inj_left {xs₁ xs₂ ys₁ ys₂ : ByteArray} (h : xs₁ ++ ys₁ = xs₂ ++ ys₂) (hl : xs₁.size = xs₂.size) : xs₁ = xs₂ := by
simp only [ByteArray.ext_iff, ByteArray.size_data, ByteArray.data_append] at *
exact Array.append_inj_left h hl
theorem extract_append_eq_right {a b : ByteArray} {i j : Nat} (hi : i = a.size) (hj : j = a.size + b.size) :
theorem ByteArray.extract_append_eq_right {a b : ByteArray} {i j : Nat} (hi : i = a.size) (hj : j = a.size + b.size) :
(a ++ b).extract i j = b := by
subst hi hj
ext1
simp [ size_data]
theorem extract_append_eq_left {a b : ByteArray} {i : Nat} (hi : i = a.size) :
theorem ByteArray.extract_append_eq_left {a b : ByteArray} {i : Nat} (hi : i = a.size) :
(a ++ b).extract 0 i = a := by
subst hi
ext1
simp
theorem extract_append_size_left {a b : ByteArray} {i : Nat} :
theorem ByteArray.extract_append_size_left {a b : ByteArray} {i : Nat} :
(a ++ b).extract i a.size = a.extract i a.size := by
ext1
simp
theorem extract_append_size_add {a b : ByteArray} {i j : Nat} :
theorem ByteArray.extract_append_size_add {a b : ByteArray} {i j : Nat} :
(a ++ b).extract (a.size + i) (a.size + j) = b.extract i j := by
ext1
simp
theorem extract_append {as bs : ByteArray} {i j : Nat} :
theorem ByteArray.extract_append {as bs : ByteArray} {i j : Nat} :
(as ++ bs).extract i j = as.extract i j ++ bs.extract (i - as.size) (j - as.size) := by
ext1
simp
theorem extract_append_size_add' {a b : ByteArray} {i j k : Nat} (h : k = a.size) :
theorem ByteArray.extract_append_size_add' {a b : ByteArray} {i j k : Nat} (h : k = a.size) :
(a ++ b).extract (k + i) (k + j) = b.extract i j := by
cases h
rw [extract_append_size_add]
theorem extract_extract {a : ByteArray} {i j k l : Nat} :
theorem ByteArray.extract_extract {a : ByteArray} {i j k l : Nat} :
(a.extract i j).extract k l = a.extract (i + k) (min (i + l) j) := by
ext1
simp
theorem getElem_extract_aux {xs : ByteArray} {start stop : Nat} (h : i < (xs.extract start stop).size) :
theorem ByteArray.getElem_extract_aux {xs : ByteArray} {start stop : Nat} (h : i < (xs.extract start stop).size) :
start + i < xs.size := by
rw [size_extract] at h; apply Nat.add_lt_of_lt_sub'; apply Nat.lt_of_lt_of_le h
apply Nat.sub_le_sub_right; apply Nat.min_le_right
theorem getElem_extract {i : Nat} {b : ByteArray} {start stop : Nat}
theorem ByteArray.getElem_extract {i : Nat} {b : ByteArray} {start stop : Nat}
(h) : (b.extract start stop)[i]'h = b[start + i]'(getElem_extract_aux h) := by
simp [getElem_eq_getElem_data]
theorem extract_eq_extract_left {a : ByteArray} {i i' j : Nat} :
theorem ByteArray.extract_eq_extract_left {a : ByteArray} {i i' j : Nat} :
a.extract i j = a.extract i' j min j a.size - i = min j a.size - i' := by
simp [ByteArray.ext_iff, Array.extract_eq_extract_left]
theorem extract_add_one {a : ByteArray} {i : Nat} (ha : i + 1 a.size) :
theorem ByteArray.extract_add_one {a : ByteArray} {i : Nat} (ha : i + 1 a.size) :
a.extract i (i + 1) = [a[i]].toByteArray := by
ext
· simp
@@ -233,57 +225,50 @@ theorem extract_add_one {a : ByteArray} {i : Nat} (ha : i + 1 ≤ a.size) :
obtain rfl : j = 0 := by simpa using hj'
simp [ByteArray.getElem_eq_getElem_data]
theorem extract_add_two {a : ByteArray} {i : Nat} (ha : i + 2 a.size) :
theorem ByteArray.extract_add_two {a : ByteArray} {i : Nat} (ha : i + 2 a.size) :
a.extract i (i + 2) = [a[i], a[i + 1]].toByteArray := by
rw [extract_eq_extract_append_extract (i + 1) (by simp) (by omega),
extract_add_one (by omega), extract_add_one (by omega)]
simp [ List.toByteArray_append]
theorem extract_add_three {a : ByteArray} {i : Nat} (ha : i + 3 a.size) :
theorem ByteArray.extract_add_three {a : ByteArray} {i : Nat} (ha : i + 3 a.size) :
a.extract i (i + 3) = [a[i], a[i + 1], a[i + 2]].toByteArray := by
rw [extract_eq_extract_append_extract (i + 1) (by simp) (by omega),
extract_add_one (by omega), extract_add_two (by omega)]
simp [ List.toByteArray_append]
theorem extract_add_four {a : ByteArray} {i : Nat} (ha : i + 4 a.size) :
theorem ByteArray.extract_add_four {a : ByteArray} {i : Nat} (ha : i + 4 a.size) :
a.extract i (i + 4) = [a[i], a[i + 1], a[i + 2], a[i + 3]].toByteArray := by
rw [extract_eq_extract_append_extract (i + 1) (by simp) (by omega),
extract_add_one (by omega), extract_add_three (by omega)]
simp [ List.toByteArray_append]
theorem append_assoc {a b c : ByteArray} : a ++ b ++ c = a ++ (b ++ c) := by
theorem ByteArray.append_assoc {a b c : ByteArray} : a ++ b ++ c = a ++ (b ++ c) := by
ext1
simp
@[simp]
theorem toList_empty : ByteArray.empty.toList = [] := by
theorem ByteArray.toList_empty : ByteArray.empty.toList = [] := by
simp [ByteArray.toList, ByteArray.toList.loop]
theorem copySlice_eq_append {src : ByteArray} {srcOff : Nat} {dest : ByteArray} {destOff len : Nat} {exact : Bool} :
theorem ByteArray.copySlice_eq_append {src : ByteArray} {srcOff : Nat} {dest : ByteArray} {destOff len : Nat} {exact : Bool} :
ByteArray.copySlice src srcOff dest destOff len exact =
dest.extract 0 destOff ++ src.extract srcOff (srcOff +len) ++ dest.extract (destOff + min len (src.data.size - srcOff)) dest.data.size := by
ext1
simp [copySlice]
@[simp]
theorem data_set {as : ByteArray} {i : Nat} {h : i < as.size} {a : UInt8} :
theorem ByteArray.data_set {as : ByteArray} {i : Nat} {h : i < as.size} {a : UInt8} :
(as.set i a h).data = as.data.set i a (by simpa) := by
simp [set]
theorem set_eq_push_extract_append_extract {as : ByteArray} {i : Nat} (h : i < as.size) {a : UInt8} :
theorem ByteArray.set_eq_push_extract_append_extract {as : ByteArray} {i : Nat} (h : i < as.size) {a : UInt8} :
as.set i a h = (as.extract 0 i).push a ++ as.extract (i + 1) as.size := by
ext1
simpa using Array.set_eq_push_extract_append_extract _
@[simp]
theorem append_toByteArray_singleton {as : ByteArray} {a : UInt8} :
theorem ByteArray.append_toByteArray_singleton {as : ByteArray} {a : UInt8} :
as ++ [a].toByteArray = as.push a := by
ext1
simp
@[simp]
theorem extract_zero_max_size {a : ByteArray} {i : Nat} : a.extract 0 (max i a.size) = a := by
ext1
simp [Nat.le_max_right]
end ByteArray

View File

@@ -13,16 +13,12 @@ public section
namespace Char
@[deprecated Char.ext (since := "2025-10-26")]
protected theorem eq_of_val_eq : {a b : Char} a.val = b.val a = b
@[ext] protected theorem ext : {a b : Char} a.val = b.val a = b
| _,_, _,_, rfl => rfl
theorem le_def {a b : Char} : a b a.1 b.1 := .rfl
theorem lt_def {a b : Char} : a < b a.1 < b.1 := .rfl
@[deprecated lt_def (since := "2025-10-26")]
theorem lt_iff_val_lt_val {a b : Char} : a < b a.val < b.val := Iff.rfl
@[simp] protected theorem not_le {a b : Char} : ¬ a b b < a := UInt32.not_le
@[simp] protected theorem not_lt {a b : Char} : ¬ a < b b a := UInt32.not_lt
@[simp] protected theorem le_refl (a : Char) : a a := by simp [le_def]
@@ -55,12 +51,8 @@ instance leAntisymm : Std.Antisymm (· ≤ · : Char → Char → Prop) where
antisymm _ _ := Char.le_antisymm
-- This instance is useful while setting up instances for `String`.
instance ltTrichotomous : Std.Trichotomous (· < · : Char Char Prop) where
trichotomous _ _ h₁ h₂ := Char.le_antisymm (by simpa using h₂) (by simpa using h₁)
@[deprecated ltTrichotomous (since := "2025-10-27")]
def notLTAntisymm : Std.Antisymm (¬ · < · : Char Char Prop) where
antisymm := Char.ltTrichotomous.trichotomous
antisymm _ _ h₁ h₂ := Char.le_antisymm (by simpa using h₂) (by simpa using h₁)
instance ltAsymm : Std.Asymm (· < · : Char Char Prop) where
asymm _ _ := Char.lt_asymm
@@ -77,9 +69,4 @@ def notLTTotal : Std.Total (¬ · < · : Char → Char → Prop) where
rw [Char.ofNat, dif_pos]
rfl
@[simp]
theorem toUInt8_val {c : Char} : c.val.toUInt8 = c.toUInt8 := rfl
theorem toString_eq_singleton {c : Char} : c.toString = String.singleton c := rfl
end Char

View File

@@ -287,7 +287,7 @@ theorem toRat_add (x y : Dyadic) : toRat (x + y) = toRat x + toRat y := by
· 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_natCast, Int.add_shiftLeft, Int.shiftLeft_add,
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
@@ -438,13 +438,13 @@ theorem toDyadic_mkRat (a : Int) (b : Nat) (prec : Int) :
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_natCast, Int.toNat_natCast, Int.toNat_neg_natCast,
· 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_of_nonneg (by simp), Int.shiftLeft_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_of_nonneg (by simp),
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) :
@@ -463,7 +463,7 @@ theorem toRat_toDyadic (x : Rat) (prec : Int) :
rw [Rat.floor_def, Int.shiftLeft_eq, Nat.shiftLeft_eq]
match prec with
| .ofNat prec =>
simp only [Int.ofNat_eq_natCast, Int.toNat_natCast, Int.toNat_neg_natCast, Nat.pow_zero,
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']
@@ -472,7 +472,7 @@ theorem toRat_toDyadic (x : Rat) (prec : Int) :
Rat.den_ofNat, Nat.one_pow, Nat.mul_one]
split
· simp_all
· rw [Int.ediv_ediv_of_nonneg (Int.natCast_nonneg _)]
· rw [Int.ediv_ediv (Int.ofNat_zero_le _)]
congr 1
rw [Int.natCast_ediv, Int.mul_ediv_cancel']
rw [Int.natCast_dvd_natCast]
@@ -495,7 +495,7 @@ theorem toRat_toDyadic (x : Rat) (prec : Int) :
simp only [this, Int.mul_one]
split
· simp_all
· rw [Int.ediv_ediv_of_nonneg (Int.natCast_nonneg _)]
· rw [Int.ediv_ediv (Int.ofNat_zero_le _)]
congr 1
rw [Int.natCast_ediv, Int.mul_ediv_cancel']
· simp
@@ -682,11 +682,9 @@ instance : LE Dyadic where
instance : DecidableLT Dyadic := fun _ _ => inferInstanceAs (Decidable (_ = true))
instance : DecidableLE Dyadic := fun _ _ => inferInstanceAs (Decidable (_ = true))
@[simp]
theorem toRat_lt_toRat_iff {x y : Dyadic} : x.toRat < y.toRat x < y := blt_iff_toRat.symm
theorem lt_iff_toRat {x y : Dyadic} : x < y x.toRat < y.toRat := blt_iff_toRat
@[simp]
theorem toRat_le_toRat_iff {x y : Dyadic} : x.toRat y.toRat x y := ble_iff_toRat.symm
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
@@ -698,20 +696,20 @@ protected theorem not_lt {x y : Dyadic} : ¬x ≤ y ↔ y < x := by
@[simp]
protected theorem le_refl (x : Dyadic) : x x := by
rw [ toRat_le_toRat_iff]
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 [ toRat_le_toRat_iff] at h h'
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 [ toRat_le_toRat_iff] at h h'
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 [ toRat_le_toRat_iff, toRat_le_toRat_iff]
rw [le_iff_toRat, le_iff_toRat]
exact Rat.le_total
instance : Std.LawfulOrderLT Dyadic where

View File

@@ -52,8 +52,8 @@ instance : NoNatZeroDivisors Dyadic where
instance : OrderedRing Dyadic where
zero_lt_one := by decide
add_le_left_iff _ := by simp [ toRat_le_toRat_iff, Rat.add_le_add_right]
mul_lt_mul_of_pos_left {_ _ _} := by simpa [ toRat_lt_toRat_iff] using Rat.mul_lt_mul_of_pos_left
mul_lt_mul_of_pos_right {_ _ _} := by simpa [ toRat_lt_toRat_iff] using Rat.mul_lt_mul_of_pos_right
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

View File

@@ -27,7 +27,7 @@ def invAtPrec (x : Dyadic) (prec : Int) : Dyadic :=
/-- 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 [ toRat_le_toRat_iff]
rw [le_iff_toRat]
rw [toRat_mul]
rw [show (1 : Dyadic).toRat = (1 : Rat) from rfl]
unfold invAtPrec
@@ -39,19 +39,19 @@ theorem invAtPrec_mul_le_one {x : Dyadic} (hx : 0 < x) (prec : Int) :
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 [ toRat_lt_toRat_iff, toRat_zero] at hx
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 [ toRat_lt_toRat_iff, toRat_zero] at hx
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 [ toRat_lt_toRat_iff]
rw [lt_iff_toRat]
rw [toRat_mul]
rw [show (1 : Dyadic).toRat = (1 : Rat) from rfl]
unfold invAtPrec
@@ -64,12 +64,12 @@ theorem one_lt_invAtPrec_add_inc_mul {x : Dyadic} (hx : 0 < x) (prec : Int) :
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 [ toRat_lt_toRat_iff, toRat_zero] at hx
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 [ toRat_lt_toRat_iff, toRat_zero] at hx
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

View File

@@ -28,7 +28,7 @@ theorem roundDown_le {x : Dyadic} {prec : Int} : roundDown x prec ≤ x :=
match h : k - prec with
| .ofNat l =>
dsimp
rw [ofOdd_eq_ofIntWithPrec, toRat_le_toRat_iff]
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]
@@ -36,7 +36,7 @@ theorem roundDown_le {x : Dyadic} {prec : Int} : roundDown x prec ≤ x :=
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_natCast]
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]

View File

@@ -246,11 +246,6 @@ instance neg (n : Nat) : Neg (Fin n) :=
theorem neg_def (a : Fin n) : -a = (n - a) % n, Nat.mod_lt _ a.pos := rfl
-- Later we give another version called `Fin.val_neg` that splits on `a = 0`.
protected theorem val_neg' (a : Fin n) : ((-a : Fin n) : Nat) = (n - a) % n :=
rfl
@[deprecated Fin.val_neg' (since := "2025-11-21")]
protected theorem coe_neg (a : Fin n) : ((-a : Fin n) : Nat) = (n - a) % n :=
rfl

View File

@@ -16,25 +16,17 @@ open Std
namespace Fin
@[simp, grind =] theorem ofNat_zero (n : Nat) [NeZero n] : Fin.ofNat n 0 = 0 := rfl
@[simp] theorem ofNat_zero (n : Nat) [NeZero n] : Fin.ofNat n 0 = 0 := rfl
@[deprecated ofNat_zero (since := "2025-05-28")] abbrev ofNat'_zero := @ofNat_zero
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 val_mod (a m : Fin n) : (a % m).val = a.val % m.val := rfl
theorem mul_def (a b : Fin n) : a * b = Fin.mk ((a.val * b.val) % n) (Nat.mod_lt _ a.pos) := rfl
theorem val_mul (a b : Fin n) : (a * b).val = (a.val * b.val) % n := rfl
theorem sub_def (a b : Fin n) : a - b = Fin.mk (((n - b.val) + a.val) % n) (Nat.mod_lt _ a.pos) := rfl
@[grind =]
theorem val_sub (a b : Fin n) : (a - b).val = ((n - b.val) + a.val) % n := rfl
@[grind ]
theorem pos' : [Nonempty (Fin n)], 0 < n | i => i.pos
@[simp] theorem is_lt (a : Fin n) : (a : Nat) < n := a.2
@@ -46,8 +38,7 @@ theorem pos_iff_nonempty {n : Nat} : 0 < n ↔ Nonempty (Fin n) :=
@[simp] protected theorem eta (a : Fin n) (h : a < n) : (a, h : Fin n) = a := rfl
@[ext, grind ext]
protected theorem ext {a b : Fin n} (h : (a : Nat) = b) : a = b := eq_of_val_eq h
@[ext] protected theorem ext {a b : Fin n} (h : (a : Nat) = b) : a = b := eq_of_val_eq h
theorem val_ne_iff {a b : Fin n} : a.1 b.1 a b := not_congr val_inj
@@ -78,7 +69,7 @@ theorem mk_val (i : Fin n) : (⟨i, i.isLt⟩ : Fin n) = i := Fin.eta ..
@[deprecated val_ofNat (since := "2025-05-28")] abbrev val_ofNat' := @val_ofNat
@[simp, grind =] theorem ofNat_self {n : Nat} [NeZero n] : Fin.ofNat n n = 0 := by
@[simp] theorem ofNat_self {n : Nat} [NeZero n] : Fin.ofNat n n = 0 := by
ext
simp
congr
@@ -98,7 +89,7 @@ theorem mk_val (i : Fin n) : (⟨i, i.isLt⟩ : Fin n) = i := Fin.eta ..
@[simp] theorem div_val (a b : Fin n) : (a / b).val = a.val / b.val :=
rfl
@[simp, grind =] theorem modn_val (a : Fin n) (b : Nat) : (a.modn b).val = a.val % b :=
@[simp] theorem modn_val (a : Fin n) (b : Nat) : (a.modn b).val = a.val % b :=
rfl
@[simp] theorem val_eq_zero (a : Fin 1) : a.val = 0 :=
@@ -166,7 +157,6 @@ theorem le_def {a b : Fin n} : a ≤ b ↔ a.1 ≤ b.1 := .rfl
theorem lt_def {a b : Fin n} : a < b a.1 < b.1 := .rfl
@[deprecated lt_def (since := "2025-10-26")]
theorem lt_iff_val_lt_val {a b : Fin n} : a < b a.val < b.val := Iff.rfl
@[simp] protected theorem not_le {a b : Fin n} : ¬ a b b < a := Nat.not_le
@@ -268,15 +258,13 @@ instance : LawfulOrderLT (Fin n) where
lt_iff := by
simp [ Fin.not_le, Decidable.imp_iff_not_or, Std.Total.total]
@[simp] theorem val_rev (i : Fin n) : (rev i).val = n - (i + 1) := rfl
grind_pattern val_rev => i.rev
@[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]
@[simp] theorem rev_le_rev {i j : Fin n} : rev i rev j j i := by
simp only [le_def, val_rev, Nat.sub_le_sub_iff_left (Nat.succ_le_iff.2 j.is_lt)]
simp only [le_def, val_rev, Nat.sub_le_sub_iff_left (Nat.succ_le.2 j.is_lt)]
exact Nat.succ_le_succ_iff
@[simp] theorem rev_inj {i j : Fin n} : rev i = rev j i = j :=
@@ -295,8 +283,6 @@ theorem rev_eq {n a : Nat} (i : Fin (n + 1)) (h : n = a + i) :
@[simp] theorem val_last (n : Nat) : (last n).1 = n := rfl
grind_pattern val_last => last n
@[simp] theorem last_zero : (Fin.last 0 : Fin 1) = 0 := by
ext
simp
@@ -397,17 +383,14 @@ theorem add_one_pos (i : Fin (n + 1)) (h : i < Fin.last n) : (0 : Fin (n + 1)) <
rw [Fin.lt_def, val_add, val_zero, val_one, Nat.mod_eq_of_lt h]
exact Nat.zero_lt_succ _
@[deprecated zero_lt_one (since := "2025-10-26")]
theorem one_pos : (0 : Fin (n + 2)) < 1 := Nat.succ_pos 0
theorem zero_ne_one : (0 : Fin (n + 2)) 1 := Fin.ne_of_lt zero_lt_one
theorem zero_ne_one : (0 : Fin (n + 2)) 1 := Fin.ne_of_lt one_pos
/-! ### succ and casts into larger Fin types -/
@[simp] theorem val_succ (j : Fin n) : (j.succ : Nat) = j + 1 := rfl
grind_pattern val_succ => j.succ
@[simp] theorem succ_pos (a : Fin n) : (0 : Fin (n + 1)) < a.succ := by
simp [Fin.lt_def]
@@ -468,18 +451,12 @@ theorem one_lt_succ_succ (a : Fin n) : (1 : Fin (n + 2)) < a.succ.succ := by
theorem succ_succ_ne_one (a : Fin n) : Fin.succ (Fin.succ a) 1 :=
Fin.ne_of_gt (one_lt_succ_succ a)
@[simp, grind =] theorem val_castLT (i : Fin m) (h : i.1 < n) : (castLT i h : Nat) = i := rfl
@[deprecated val_castLT (since := "2025-11-21")]
theorem coe_castLT (i : Fin m) (h : i.1 < n) : (castLT i h : Nat) = i := rfl
@[simp] theorem coe_castLT (i : Fin m) (h : i.1 < n) : (castLT i h : Nat) = i := rfl
@[simp] theorem castLT_mk (i n m : Nat) (hn : i < n) (hm : i < m) : castLT i, hn hm = i, hm :=
rfl
@[simp, grind =] theorem val_castLE (h : n m) (i : Fin n) : (castLE h i : Nat) = i := rfl
@[deprecated val_castLE (since := "2025-11-21")]
theorem coe_castLE (h : n m) (i : Fin n) : (castLE h i : Nat) = i := rfl
@[simp, grind =] theorem coe_castLE (h : n m) (i : Fin n) : (castLE h i : Nat) = i := rfl
@[simp] theorem castLE_mk (i n m : Nat) (hn : i < n) (h : n m) :
castLE h i, hn = i, Nat.lt_of_lt_of_le hn h := rfl
@@ -491,16 +468,13 @@ theorem coe_castLE (h : n ≤ m) (i : Fin n) : (castLE h i : Nat) = i := rfl
@[simp] theorem castLE_castLE {k m n} (km : k m) (mn : m n) (i : Fin k) :
Fin.castLE mn (Fin.castLE km i) = Fin.castLE (Nat.le_trans km mn) i :=
Fin.ext (by simp only [val_castLE])
Fin.ext (by simp only [coe_castLE])
@[simp] theorem castLE_comp_castLE {k m n} (km : k m) (mn : m n) :
Fin.castLE mn Fin.castLE km = Fin.castLE (Nat.le_trans km mn) :=
funext (castLE_castLE km mn)
@[simp, grind =] theorem val_cast (h : n = m) (i : Fin n) : (i.cast h : Nat) = i := rfl
@[deprecated val_cast (since := "2025-11-21")]
theorem coe_cast (h : n = m) (i : Fin n) : (i.cast h : Nat) = i := rfl
@[simp] theorem coe_cast (h : n = m) (i : Fin n) : (i.cast h : Nat) = i := rfl
@[simp] theorem cast_castLE {k m n} (km : k m) (mn : m = n) (i : Fin k) :
Fin.cast mn (i.castLE km) = i.castLE (mn km) :=
@@ -513,7 +487,7 @@ theorem coe_cast (h : n = m) (i : Fin n) : (i.cast h : Nat) = i := rfl
@[simp] theorem cast_zero [NeZero n] [NeZero m] (h : n = m) : Fin.cast h 0 = 0 := rfl
@[simp] theorem cast_last {n' : Nat} {h : n + 1 = n' + 1} : (last n).cast h = last n' :=
Fin.ext (by rw [val_cast, val_last, val_last, Nat.succ.inj h])
Fin.ext (by rw [coe_cast, val_last, val_last, Nat.succ.inj h])
@[simp] theorem cast_mk (h : n = m) (i : Nat) (hn : i < n) : Fin.cast h i, hn = i, h hn := rfl
@@ -528,10 +502,7 @@ theorem coe_cast (h : n = m) (i : Fin n) : (i.cast h : Nat) = i := rfl
theorem castLE_of_eq {m n : Nat} (h : m = n) {h' : m n} : castLE h' = Fin.cast h := rfl
@[simp, grind =] theorem val_castAdd (m : Nat) (i : Fin n) : (castAdd m i : Nat) = i := rfl
@[deprecated val_castAdd (since := "2025-11-21")]
theorem coe_castAdd (m : Nat) (i : Fin n) : (castAdd m i : Nat) = i := rfl
@[simp] theorem coe_castAdd (m : Nat) (i : Fin n) : (castAdd m i : Nat) = i := rfl
@[simp] theorem castAdd_zero : (castAdd 0 : Fin n Fin (n + 0)) = Fin.cast rfl := rfl
@@ -567,18 +538,15 @@ the reverse direction. -/
theorem succ_cast_eq {n' : Nat} (i : Fin n) (h : n = n') :
(i.cast h).succ = i.succ.cast (by rw [h]) := rfl
@[simp, grind =] theorem val_castSucc (i : Fin n) : (i.castSucc : Nat) = i := rfl
@[simp] theorem coe_castSucc (i : Fin n) : (i.castSucc : Nat) = i := rfl
@[deprecated val_castSucc (since := "2025-11-21")]
theorem coe_castSucc (i : Fin n) : (i.castSucc : Nat) = i := rfl
@[simp] theorem castSucc_mk (n i : Nat) (h : i < n) : castSucc i, h = i, Nat.lt_succ_of_lt h := rfl
@[simp] theorem castSucc_mk (n i : Nat) (h : i < n) : castSucc i, h = i, Nat.lt.step h := rfl
@[simp] theorem cast_castSucc {n' : Nat} {h : n + 1 = n' + 1} {i : Fin n} :
i.castSucc.cast h = (i.cast (Nat.succ.inj h)).castSucc := rfl
theorem castSucc_lt_succ {i : Fin n} : i.castSucc < i.succ :=
lt_def.2 <| by simp only [val_castSucc, val_succ, Nat.lt_succ_self]
theorem castSucc_lt_succ (i : Fin n) : i.castSucc < i.succ :=
lt_def.2 <| by simp only [coe_castSucc, val_succ, Nat.lt_succ_self]
theorem le_castSucc_iff {i : Fin (n + 1)} {j : Fin n} : i j.castSucc i < j.succ := by
simpa only [lt_def, le_def] using Nat.add_one_le_add_one_iff.symm
@@ -617,12 +585,8 @@ theorem castSucc_pos [NeZero n] {i : Fin n} (h : 0 < i) : 0 < i.castSucc := by
theorem castSucc_ne_zero_iff [NeZero n] {a : Fin n} : a.castSucc 0 a 0 :=
not_congr <| castSucc_eq_zero_iff
@[simp, grind _=_]
theorem castSucc_succ (i : Fin n) : i.succ.castSucc = i.castSucc.succ := rfl
@[deprecated castSucc_succ (since := "2025-10-29")]
theorem castSucc_fin_succ (n : Nat) (j : Fin n) :
j.succ.castSucc = (j.castSucc).succ := by simp
j.succ.castSucc = (j.castSucc).succ := by simp [Fin.ext_iff]
@[simp]
theorem coeSucc_eq_succ {a : Fin n} : a.castSucc + 1 = a.succ := by
@@ -630,9 +594,8 @@ theorem coeSucc_eq_succ {a : Fin n} : a.castSucc + 1 = a.succ := by
· exact a.elim0
· simp [Fin.ext_iff, add_def, Nat.mod_eq_of_lt (Nat.succ_lt_succ a.is_lt)]
@[deprecated castSucc_lt_succ (since := "2025-10-29")]
theorem lt_succ {a : Fin n} : a.castSucc < a.succ := by
rw [castSucc, lt_def, val_castAdd, val_succ]; exact Nat.lt_succ_self a.val
rw [castSucc, lt_def, coe_castAdd, val_succ]; exact Nat.lt_succ_self a.val
theorem exists_castSucc_eq {n : Nat} {i : Fin (n + 1)} : ( j, castSucc j = i) i last n :=
fun j, hj => hj Fin.ne_of_lt j.castSucc_lt_last,
@@ -640,10 +603,7 @@ theorem exists_castSucc_eq {n : Nat} {i : Fin (n + 1)} : (∃ j, castSucc j = i)
theorem succ_castSucc {n : Nat} (i : Fin n) : i.castSucc.succ = i.succ.castSucc := rfl
@[simp, grind =] theorem val_addNat (m : Nat) (i : Fin n) : (addNat i m : Nat) = i + m := rfl
@[deprecated val_addNat (since := "2025-11-21")]
theorem coe_addNat (m : Nat) (i : Fin n) : (addNat i m : Nat) = i + m := rfl
@[simp] theorem coe_addNat (m : Nat) (i : Fin n) : (addNat i m : Nat) = i + m := rfl
@[simp] theorem addNat_zero (n : Nat) (i : Fin n) : addNat i 0 = i := by
ext
@@ -671,10 +631,7 @@ theorem cast_addNat_left {n n' m : Nat} (i : Fin n') (h : n' + m = n + m) :
(addNat i m').cast h = addNat i m :=
Fin.ext <| (congrArg ((· + ·) (i : Nat)) (Nat.add_left_cancel h) : _)
@[simp, grind =] theorem val_natAdd (n : Nat) {m : Nat} (i : Fin m) : (natAdd n i : Nat) = n + i := rfl
@[deprecated val_natAdd (since := "2025-11-21")]
theorem coe_natAdd (n : Nat) {m : Nat} (i : Fin m) : (natAdd n i : Nat) = n + i := rfl
@[simp] theorem coe_natAdd (n : Nat) {m : Nat} (i : Fin m) : (natAdd n i : Nat) = n + i := rfl
@[simp] theorem natAdd_mk (n i : Nat) (hi : i < m) :
natAdd n i, hi = n + i, Nat.add_lt_add_left hi n := rfl
@@ -731,7 +688,7 @@ theorem natAdd_castSucc {m n : Nat} {i : Fin m} : natAdd n (castSucc i) = castSu
omega
theorem rev_castAdd (k : Fin n) (m : Nat) : rev (castAdd m k) = addNat (rev k) m := Fin.ext <| by
rw [val_rev, val_castAdd, val_addNat, val_rev, Nat.sub_add_comm (Nat.succ_le_of_lt k.is_lt)]
rw [val_rev, coe_castAdd, coe_addNat, val_rev, Nat.sub_add_comm (Nat.succ_le_of_lt k.is_lt)]
theorem rev_addNat (k : Fin n) (m : Nat) : rev (addNat k m) = castAdd m (rev k) := by
rw [ rev_rev (castAdd ..), rev_castAdd, rev_rev]
@@ -740,6 +697,9 @@ theorem rev_castSucc (k : Fin n) : rev (castSucc k) = succ (rev k) := k.rev_cast
theorem rev_succ (k : Fin n) : rev (succ k) = castSucc (rev k) := k.rev_addNat 1
@[simp, grind _=_]
theorem castSucc_succ (i : Fin n) : i.succ.castSucc = i.castSucc.succ := rfl
@[simp, grind =]
theorem castLE_refl (h : n n) (i : Fin n) : i.castLE h = i := rfl
@@ -753,12 +713,7 @@ theorem castSucc_natAdd (n : Nat) (i : Fin k) :
/-! ### pred -/
@[simp] theorem val_pred (j : Fin (n + 1)) (h : j 0) : (j.pred h : Nat) = j - 1 := rfl
grind_pattern val_pred => j.pred h
@[deprecated val_pred (since := "2025-11-21")]
theorem coe_pred (j : Fin (n + 1)) (h : j 0) : (j.pred h : Nat) = j - 1 := rfl
@[simp] theorem coe_pred (j : Fin (n + 1)) (h : j 0) : (j.pred h : Nat) = j - 1 := rfl
@[simp] theorem succ_pred : (i : Fin (n + 1)) (h : i 0), (i.pred h).succ = i
| 0, _, hi => by simp only [mk_zero, ne_eq, not_true] at hi
@@ -776,7 +731,7 @@ theorem pred_eq_iff_eq_succ {n : Nat} {i : Fin (n + 1)} (hi : i ≠ 0) {j : Fin
theorem pred_mk_succ (i : Nat) (h : i < n + 1) :
Fin.pred i + 1, Nat.add_lt_add_right h 1 (ne_of_val_ne (Nat.ne_of_gt (mk_succ_pos i h))) =
i, h := by
simp only [Fin.ext_iff, val_pred, Nat.add_sub_cancel]
simp only [Fin.ext_iff, coe_pred, Nat.add_sub_cancel]
@[simp] theorem pred_mk_succ' (i : Nat) (h₁ : i + 1 < n + 1 + 1) (h₂) :
Fin.pred i + 1, h₁ h₂ = i, Nat.lt_of_succ_lt_succ h₁ := pred_mk_succ i _
@@ -799,17 +754,14 @@ theorem pred_mk {n : Nat} (i : Nat) (h : i < n + 1) (w) : Fin.pred ⟨i, h⟩ w
| i + 1, hi, j + 1, hj, ha, hb => by simp [Fin.ext_iff]
@[simp] theorem pred_one {n : Nat} :
Fin.pred (1 : Fin (n + 2)) (Ne.symm (Fin.ne_of_lt zero_lt_one)) = 0 := rfl
Fin.pred (1 : Fin (n + 2)) (Ne.symm (Fin.ne_of_lt one_pos)) = 0 := rfl
theorem pred_add_one (i : Fin (n + 2)) (h : (i : Nat) < n + 1) :
pred (i + 1) (Fin.ne_of_gt (add_one_pos _ (lt_def.2 h))) = castLT i h := by
rw [Fin.ext_iff, val_pred, val_castLT, val_add, val_one, Nat.mod_eq_of_lt, Nat.add_sub_cancel]
rw [Fin.ext_iff, coe_pred, coe_castLT, val_add, val_one, Nat.mod_eq_of_lt, Nat.add_sub_cancel]
exact Nat.add_lt_add_right h 1
@[simp, grind =] theorem val_subNat (i : Fin (n + m)) (h : m i) : (i.subNat m h : Nat) = i - m := rfl
@[deprecated val_subNat (since := "2025-11-21")]
theorem coe_subNat (i : Fin (n + m)) (h : m i) : (i.subNat m h : Nat) = i - m := rfl
@[simp] theorem coe_subNat (i : Fin (n + m)) (h : m i) : (i.subNat m h : Nat) = i - m := rfl
@[simp] theorem subNat_mk {i : Nat} (h₁ : i < n + m) (h₂ : m i) :
subNat m i, h₁ h₂ = i - m, Nat.sub_lt_right_of_lt_add h₂ h₁ := rfl
@@ -874,11 +826,11 @@ step. `Fin.succRec` is a version of this induction principle that takes the `Fin
(zero : n, motive (n + 1) 0) (succ : n i, motive n i motive (Nat.succ n) i.succ) :
motive n i := i.succRec zero succ
@[simp, grind =] theorem succRecOn_zero {motive : n, Fin n Sort _} {zero succ} (n) :
@[simp] theorem succRecOn_zero {motive : n, Fin n Sort _} {zero succ} (n) :
@Fin.succRecOn (n + 1) 0 motive zero succ = zero n := by
cases n <;> rfl
@[simp, grind =] theorem succRecOn_succ {motive : n, Fin n Sort _} {zero succ} {n} (i : Fin n) :
@[simp] theorem succRecOn_succ {motive : n, Fin n Sort _} {zero succ} {n} (i : Fin n) :
@Fin.succRecOn (n + 1) i.succ motive zero succ = succ n i (Fin.succRecOn i zero succ) := by
cases i; rfl
@@ -906,11 +858,11 @@ where
| 0, hi => by rwa [Fin.mk_zero]
| i+1, hi => succ i, Nat.lt_of_succ_lt_succ hi (go i (Nat.lt_of_succ_lt hi))
@[simp, grind =] theorem induction_zero {motive : Fin (n + 1) Sort _} (zero : motive 0)
@[simp] theorem induction_zero {motive : Fin (n + 1) Sort _} (zero : motive 0)
(hs : i : Fin n, motive (castSucc i) motive i.succ) :
(induction zero hs : i : Fin (n + 1), motive i) 0 = zero := rfl
@[simp, grind =] theorem induction_succ {motive : Fin (n + 1) Sort _} (zero : motive 0)
@[simp] theorem induction_succ {motive : Fin (n + 1) Sort _} (zero : motive 0)
(succ : i : Fin n, motive (castSucc i) motive i.succ) (i : Fin n) :
induction (motive := motive) zero succ i.succ = succ i (induction zero succ (castSucc i)) := rfl
@@ -942,13 +894,13 @@ The corresponding induction principle is `Fin.induction`.
(zero : motive 0) (succ : i : Fin n, motive i.succ) :
i : Fin (n + 1), motive i := induction zero fun i _ => succ i
@[simp, grind =] theorem cases_zero {n} {motive : Fin (n + 1) Sort _} {zero succ} :
@[simp] theorem cases_zero {n} {motive : Fin (n + 1) Sort _} {zero succ} :
@Fin.cases n motive zero succ 0 = zero := rfl
@[simp, grind =] theorem cases_succ {n} {motive : Fin (n + 1) Sort _} {zero succ} (i : Fin n) :
@[simp] theorem cases_succ {n} {motive : Fin (n + 1) Sort _} {zero succ} (i : Fin n) :
@Fin.cases n motive zero succ i.succ = succ i := rfl
@[simp, grind =] theorem cases_succ' {n} {motive : Fin (n + 1) Sort _} {zero succ}
@[simp] theorem cases_succ' {n} {motive : Fin (n + 1) Sort _} {zero succ}
{i : Nat} (h : i + 1 < n + 1) :
@Fin.cases n motive zero succ i.succ, h = succ i, Nat.lt_of_succ_lt_succ h := rfl
@@ -998,7 +950,7 @@ For the induction:
| j + 1 => go j (by omega) (by omega) (cast j, by omega x)
go _ _ (by omega) last
@[simp, grind =] theorem reverseInduction_last {n : Nat} {motive : Fin (n + 1) Sort _} {zero succ} :
@[simp] theorem reverseInduction_last {n : Nat} {motive : Fin (n + 1) Sort _} {zero succ} :
(reverseInduction zero succ (Fin.last n) : motive (Fin.last n)) = zero := by
rw [reverseInduction, reverseInduction.go]; simp
@@ -1015,7 +967,7 @@ private theorem reverseInduction_castSucc_aux {n : Nat} {motive : Fin (n + 1)
dsimp only
rw [ih _ _ (by omega), eq_comm, reverseInduction.go, dif_neg (by change i.1 + 1 _; omega)]
@[simp, grind =] theorem reverseInduction_castSucc {n : Nat} {motive : Fin (n + 1) Sort _} {zero succ}
@[simp] theorem reverseInduction_castSucc {n : Nat} {motive : Fin (n + 1) Sort _} {zero succ}
(i : Fin n) : reverseInduction (motive := motive) zero succ (castSucc i) =
succ i (reverseInduction zero succ i.succ) := by
rw [reverseInduction, reverseInduction_castSucc_aux _ _ _ i.isLt, reverseInduction]
@@ -1034,11 +986,11 @@ The corresponding induction principle is `Fin.reverseInduction`.
(cast : i : Fin n, motive (castSucc i)) (i : Fin (n + 1)) : motive i :=
reverseInduction last (fun i _ => cast i) i
@[simp, grind =] theorem lastCases_last {n : Nat} {motive : Fin (n + 1) Sort _} {last cast} :
@[simp] theorem lastCases_last {n : Nat} {motive : Fin (n + 1) Sort _} {last cast} :
(Fin.lastCases last cast (Fin.last n) : motive (Fin.last n)) = last :=
reverseInduction_last ..
@[simp, grind =] theorem lastCases_castSucc {n : Nat} {motive : Fin (n + 1) Sort _} {last cast}
@[simp] theorem lastCases_castSucc {n : Nat} {motive : Fin (n + 1) Sort _} {last cast}
(i : Fin n) : (Fin.lastCases last cast (Fin.castSucc i) : motive (Fin.castSucc i)) = cast i :=
reverseInduction_castSucc ..
@@ -1058,11 +1010,11 @@ as `Fin.natAdd m (j : Fin n)`.
if hi : (i : Nat) < m then (castAdd_castLT n i hi) (left (castLT i hi))
else (natAdd_subNat_cast (Nat.le_of_not_lt hi)) (right _)
@[simp, grind =] theorem addCases_left {m n : Nat} {motive : Fin (m + n) Sort _} {left right} (i : Fin m) :
@[simp] theorem addCases_left {m n : Nat} {motive : Fin (m + n) Sort _} {left right} (i : Fin m) :
addCases (motive := motive) left right (Fin.castAdd n i) = left i := by
rw [addCases, dif_pos (castAdd_lt _ _)]; rfl
@[simp, grind =]
@[simp]
theorem addCases_right {m n : Nat} {motive : Fin (m + n) Sort _} {left right} (i : Fin n) :
addCases (motive := motive) left right (natAdd m i) = right i := by
have : ¬(natAdd m i : Nat) < m := Nat.not_lt.2 (le_coe_natAdd ..)
@@ -1095,7 +1047,6 @@ theorem add_ofNat [NeZero n] (x : Fin n) (y : Nat) :
/-! ### sub -/
@[deprecated val_sub (since := "2025-11-21")]
protected theorem coe_sub (a b : Fin n) : ((a - b : Fin n) : Nat) = ((n - b) + a) % n := by
cases a; cases b; rfl
@@ -1147,7 +1098,6 @@ theorem coe_sub_iff_lt {a b : Fin n} : (↑(a - b) : Nat) = n + a - b ↔ a < b
/-! ### neg -/
@[grind =]
theorem val_neg {n : Nat} [NeZero n] (x : Fin n) :
(-x).val = if x = 0 then 0 else n - x.val := by
change (n - x) % n = _
@@ -1163,7 +1113,7 @@ protected theorem sub_eq_add_neg {n : Nat} (x y : Fin n) : x - y = x + -y := by
apply elim0 x
· replace h : NeZero n := h
ext
rw [Fin.val_sub, Fin.val_add, val_neg]
rw [Fin.coe_sub, Fin.val_add, val_neg]
split
· simp_all
· simp [Nat.add_comm]
@@ -1184,7 +1134,9 @@ theorem mul_ofNat [NeZero n] (x : Fin n) (y : Nat) :
@[deprecated mul_ofNat (since := "2025-05-28")] abbrev mul_ofNat' := @mul_ofNat
@[deprecated val_mul (since := "2025-10-26")]
theorem val_mul {n : Nat} : a b : Fin n, (a * b).val = a.val * b.val % n
| _, _, _, _ => rfl
theorem coe_mul {n : Nat} : a b : Fin n, ((a * b : Fin n) : Nat) = a * b % n
| _, _, _, _ => rfl

View File

@@ -29,6 +29,9 @@ attribute [ext] FloatArray
def emptyWithCapacity (c : @& Nat) : FloatArray :=
{ data := #[] }
@[deprecated emptyWithCapacity (since := "2025-03-12")]
abbrev mkEmpty := emptyWithCapacity
def empty : FloatArray :=
emptyWithCapacity 0
@@ -129,7 +132,7 @@ protected def forIn {β : Type v} {m : Type v → Type w} [Monad m] (as : FloatA
| ForInStep.yield b => loop i (Nat.le_of_lt h') b
loop as.size (Nat.le_refl _) b
instance [Monad m] : ForIn m FloatArray Float where
instance : ForIn m FloatArray Float where
forIn := FloatArray.forIn
/-- See comment at `forInUnsafe` -/

View File

@@ -7,7 +7,7 @@ module
prelude
public import Init.Data.Array.Basic
import Init.Data.String.Search
import Init.Data.String.Basic
public section
@@ -47,7 +47,7 @@ Converts a string to a pretty-printer document, replacing newlines in the string
`Std.Format.line`.
-/
def String.toFormat (s : String) : Std.Format :=
Std.Format.joinSep (s.split '\n').toList Std.Format.line
Std.Format.joinSep (s.splitOn "\n") Std.Format.line
instance : ToFormat String.Pos.Raw where
format p := format p.byteIdx

View File

@@ -80,10 +80,7 @@ protected theorem zero_ne_one : (0 : Int) ≠ 1 := nofun
/-! ## Coercions -/
@[simp] theorem ofNat_eq_natCast (n : Nat) : Int.ofNat n = n := rfl
@[deprecated ofNat_eq_natCast (since := "2025-10-29")]
theorem ofNat_eq_coe : Int.ofNat n = Nat.cast n := rfl
@[simp] theorem ofNat_eq_coe : Int.ofNat n = Nat.cast n := rfl
@[simp] theorem ofNat_zero : ((0 : Nat) : Int) = 0 := rfl
@@ -372,6 +369,9 @@ def toNat? : Int → Option Nat
| (n : Nat) => some n
| -[_+1] => none
@[deprecated toNat? (since := "2025-03-11"), inherit_doc toNat?]
abbrev toNat' := toNat?
/-! ## divisibility -/
/--
@@ -392,9 +392,9 @@ Examples:
* `(0 : Int) ^ 10 = 0`
* `(-7 : Int) ^ 3 = -343`
-/
protected def pow : Int Nat Int
| (m : Nat), n => Int.ofNat (m ^ n)
| m@-[_+1], n => if n % 2 = 0 then Int.ofNat (m.natAbs ^ n) else - Int.ofNat (m.natAbs ^ n)
protected def pow (m : Int) : Nat Int
| 0 => 1
| succ n => Int.pow m n * m
instance : NatPow Int where
pow := Int.pow

View File

@@ -24,17 +24,12 @@ theorem natCast_shiftRight (n s : Nat) : n >>> s = (n : Int) >>> s := rfl
theorem negSucc_shiftRight (m n : Nat) :
-[m+1] >>> n = -[m >>>n +1] := rfl
@[grind _=_]
theorem shiftRight_add (i : Int) (m n : Nat) :
i >>> (m + n) = i >>> m >>> n := by
simp only [shiftRight_eq, Int.shiftRight]
cases i <;> simp [Nat.shiftRight_add]
grind_pattern shiftRight_add => i >>> (m + n) where
i =/= 0
grind_pattern shiftRight_add => i >>> m >>> n where
i =/= 0
theorem shiftRight_eq_div_pow (m : Int) (n : Nat) :
m >>> n = m / ((2 ^ n) : Nat) := by
simp only [shiftRight_eq, Int.shiftRight, Nat.shiftRight_eq_div_pow]
@@ -52,10 +47,10 @@ theorem shiftRight_zero (n : Int) : n >>> 0 = n := by
simp [Int.shiftRight_eq_div_pow]
theorem le_shiftRight_of_nonpos {n : Int} {s : Nat} (h : n 0) : n n >>> s := by
simp only [Int.shiftRight_eq, Int.shiftRight, Int.ofNat_eq_natCast]
simp only [Int.shiftRight_eq, Int.shiftRight, Int.ofNat_eq_coe]
split
case _ _ _ m =>
simp only [ofNat_eq_natCast] at h
simp only [ofNat_eq_coe] at h
by_cases hm : m = 0
· simp [hm]
· omega
@@ -66,14 +61,14 @@ theorem le_shiftRight_of_nonpos {n : Int} {s : Nat} (h : n ≤ 0) : n ≤ n >>>
omega
theorem shiftRight_le_of_nonneg {n : Int} {s : Nat} (h : 0 n) : n >>> s n := by
simp only [Int.shiftRight_eq, Int.shiftRight, Int.ofNat_eq_natCast]
simp only [Int.shiftRight_eq, Int.shiftRight, Int.ofNat_eq_coe]
split
case _ _ _ m =>
simp only [Int.ofNat_eq_natCast] at h
simp only [Int.ofNat_eq_coe] at h
by_cases hm : m = 0
· simp [hm]
· have := Nat.shiftRight_le m s
rw [ofNat_eq_natCast]
rw [ofNat_eq_coe]
omega
case _ _ _ m =>
omega
@@ -113,7 +108,7 @@ 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_natCast]
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]

View File

@@ -9,4 +9,3 @@ prelude
public import Init.Data.Int.DivMod.Basic
public import Init.Data.Int.DivMod.Bootstrap
public import Init.Data.Int.DivMod.Lemmas
public import Init.Data.Int.DivMod.Pow

View File

@@ -118,6 +118,9 @@ instance : Mod Int where
@[simp, norm_cast] theorem natCast_ediv (m n : Nat) : ((m / n) : Int) = m / n := rfl
@[deprecated natCast_ediv (since := "2025-04-17")]
theorem ofNat_ediv (m n : Nat) : ((m / n) : Int) = m / n := natCast_ediv m n
theorem ofNat_ediv_ofNat {a b : Nat} : (a / b : Int) = (a / b : Nat) := rfl
@[norm_cast]
theorem negSucc_ediv_ofNat_succ {a b : Nat} : ((-[a+1]) / (b+1) : Int) = -[a / succ b +1] := rfl

View File

@@ -38,7 +38,7 @@ protected theorem dvd_trans : ∀ {a b c : Int}, a b → b c → a c
refine fun a, ae => ?_, fun k, e => k, by rw [e, Int.natCast_mul]
match Int.le_total a 0 with
| .inl h =>
have := ae.symm Int.mul_nonpos_of_nonneg_of_nonpos (natCast_nonneg _) h
have := ae.symm Int.mul_nonpos_of_nonneg_of_nonpos (ofNat_zero_le _) h
rw [Nat.le_antisymm (ofNat_le.1 this) (Nat.zero_le _)]
apply Nat.dvd_zero
| .inr h => match a, eq_ofNat_of_zero_le h with
@@ -92,6 +92,9 @@ theorem ofNat_dvd_left {n : Nat} {z : Int} : (↑n : Int) z ↔ n z.natA
@[simp, norm_cast] theorem natCast_emod (m n : Nat) : ((m % n) : Int) = m % n := rfl
@[deprecated natCast_emod (since := "2025-04-17")]
theorem ofNat_emod (m n : Nat) : ((m % n) : Int) = m % n := natCast_emod m n
/-! ### mod definitions -/
theorem emod_add_mul_ediv : a b : Int, a % b + b * (a / b) = a
@@ -206,7 +209,7 @@ theorem ediv_nonneg_iff_of_pos {a b : Int} (h : 0 < b) : 0 ≤ a / b ↔ 0 ≤ a
/-! ### emod -/
theorem emod_nonneg : (a : Int) {b : Int}, b 0 0 a % b
| ofNat _, _, _ => natCast_nonneg _
| ofNat _, _, _ => ofNat_zero_le _
| -[_+1], _, H => Int.sub_nonneg_of_le <| ofNat_le.2 <| Nat.mod_lt _ (natAbs_pos.2 H)
theorem emod_lt_of_pos (a : Int) {b : Int} (H : 0 < b) : a % b < b :=
@@ -230,6 +233,10 @@ theorem emod_lt_of_pos (a : Int) {b : Int} (H : 0 < b) : a % b < b :=
@[simp] theorem mul_add_emod_self_left (a b c : Int) : (a * b + c) % a = c % a := by
rw [Int.add_comm, add_mul_emod_self_left]
@[deprecated add_mul_emod_self_right (since := "2025-04-11")]
theorem add_mul_emod_self {a b c : Int} : (a + b * c) % c = a % c :=
add_mul_emod_self_right ..
@[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_mul_ediv] at this

View File

@@ -73,7 +73,7 @@ protected theorem dvd_iff_dvd_of_dvd_add {a b c : Int} (H : a b + c) : a
theorem le_of_dvd {a b : Int} (bpos : 0 < b) (H : a b) : a b :=
match a, b, eq_succ_of_zero_lt bpos, H with
| ofNat _, _, n, rfl, H => ofNat_le.2 <| Nat.le_of_dvd n.succ_pos <| ofNat_dvd.1 H
| -[_+1], _, _, rfl, _ => Int.le_trans (Int.le_of_lt <| negSucc_lt_zero _) (natCast_nonneg _)
| -[_+1], _, _, rfl, _ => Int.le_trans (Int.le_of_lt <| negSucc_lt_zero _) (ofNat_zero_le _)
theorem natAbs_dvd {a b : Int} : (a.natAbs : Int) b a b :=
match natAbs_eq a with
@@ -145,12 +145,6 @@ theorem dvd_of_mul_dvd_mul_left {a m n : Int} (ha : a ≠ 0) (h : a * m a *
theorem dvd_of_mul_dvd_mul_right {a m n : Int} (ha : a 0) (h : m * a n * a) : m n :=
dvd_of_mul_dvd_mul_left ha (by simpa [Int.mul_comm] using h)
theorem dvd_mul_of_dvd_right {a b c : Int} (h : a c) : a b * c :=
Int.dvd_trans h (Int.dvd_mul_left b c)
theorem dvd_mul_of_dvd_left {a b c : Int} (h : a b) : a b * c :=
Int.dvd_trans h (Int.dvd_mul_right b c)
@[norm_cast] theorem natCast_dvd_natCast {m n : Nat} : (m : Int) n m n where
mp := by
rintro a, h
@@ -220,8 +214,8 @@ theorem tdiv_eq_ediv {a b : Int} :
| ofNat a, -[b+1] => simp [tdiv_eq_ediv_of_nonneg]
| -[a+1], 0 => simp
| -[a+1], ofNat (succ b) =>
simp only [tdiv, Nat.succ_eq_add_one, ofNat_eq_natCast, Int.natCast_add, cast_ofNat_Int,
negSucc_not_nonneg, sign_natCast_add_one]
simp only [tdiv, Nat.succ_eq_add_one, ofNat_eq_coe, Int.natCast_add, cast_ofNat_Int,
negSucc_not_nonneg, sign_of_add_one]
simp only [negSucc_emod_ofNat_succ_eq_zero_iff]
norm_cast
simp only [Nat.succ_eq_add_one, false_or]
@@ -231,7 +225,7 @@ theorem tdiv_eq_ediv {a b : Int} :
· rw [neg_ofNat_eq_negSucc_add_one_iff]
exact Nat.succ_div_of_mod_ne_zero h
| -[a+1], -[b+1] =>
simp only [tdiv, ofNat_eq_natCast, negSucc_not_nonneg, false_or, sign_negSucc]
simp only [tdiv, ofNat_eq_coe, negSucc_not_nonneg, false_or, sign_negSucc]
norm_cast
simp only [negSucc_ediv_negSucc]
rw [Int.natCast_add, Int.natCast_one]
@@ -262,7 +256,7 @@ theorem fdiv_eq_ediv {a b : Int} :
| 0, -[b+1] => simp
| ofNat (a + 1), -[b+1] =>
simp only [fdiv, ofNat_ediv_negSucc, negSucc_not_nonneg, negSucc_dvd, false_or]
simp only [ofNat_eq_natCast, ofNat_dvd]
simp only [ofNat_eq_coe, ofNat_dvd]
norm_cast
rw [Nat.succ_div, negSucc_eq]
split <;> rename_i h
@@ -270,7 +264,7 @@ theorem fdiv_eq_ediv {a b : Int} :
· simp [Int.neg_add]
norm_cast
| -[a+1], -[b+1] =>
simp only [fdiv, ofNat_eq_natCast, negSucc_ediv_negSucc, negSucc_not_nonneg, dvd_negSucc, negSucc_dvd,
simp only [fdiv, ofNat_eq_coe, negSucc_ediv_negSucc, negSucc_not_nonneg, dvd_negSucc, negSucc_dvd,
false_or]
norm_cast
rw [Int.natCast_add, Int.natCast_one, Nat.succ_div]
@@ -516,29 +510,32 @@ theorem ediv_neg_of_neg_of_pos {a b : Int} (Ha : a < 0) (Hb : 0 < b) : a / b < 0
match a, b, eq_negSucc_of_lt_zero Ha, eq_succ_of_zero_lt Hb with
| _, _, _, rfl, _, rfl => negSucc_lt_zero _
@[deprecated ediv_neg_of_neg_of_pos (since := "2025-03-04")]
abbrev ediv_neg' := @ediv_neg_of_neg_of_pos
theorem negSucc_ediv (m : Nat) {b : Int} (H : 0 < b) : -[m+1] / b = -(ediv m b + 1) :=
match b, eq_succ_of_zero_lt H with
| _, _, rfl => rfl
theorem ediv_nonneg {a b : Int} (Ha : 0 a) (Hb : 0 b) : 0 a / b :=
match a, b, eq_ofNat_of_zero_le Ha, eq_ofNat_of_zero_le Hb with
| _, _, _, rfl, _, rfl => natCast_nonneg _
| _, _, _, rfl, _, rfl => ofNat_zero_le _
theorem ediv_nonneg_of_nonpos_of_nonpos {a b : Int} (Ha : a 0) (Hb : b 0) : 0 a / b := by
match a, b with
| ofNat a, b =>
match Int.le_antisymm Ha (natCast_nonneg a) with
match Int.le_antisymm Ha (ofNat_zero_le a) with
| h1 =>
rw [h1, zero_ediv]
exact Int.le_refl 0
| a, ofNat b =>
match Int.le_antisymm Hb (natCast_nonneg b) with
match Int.le_antisymm Hb (ofNat_zero_le b) with
| h1 =>
rw [h1, Int.ediv_zero]
exact Int.le_refl 0
| negSucc a, negSucc b =>
rw [Int.div_def, ediv]
exact le_add_one (ediv_nonneg (natCast_nonneg a) (Int.le_trans (natCast_nonneg b) (le.intro 1 rfl)))
exact le_add_one (ediv_nonneg (ofNat_zero_le a) (Int.le_trans (ofNat_zero_le b) (le.intro 1 rfl)))
theorem ediv_pos_of_neg_of_neg {a b : Int} (ha : a < 0) (hb : b < 0) : 0 < a / b := by
rw [Int.div_def]
@@ -548,6 +545,9 @@ theorem ediv_pos_of_neg_of_neg {a b : Int} (ha : a < 0) (hb : b < 0) : 0 < a / b
theorem ediv_nonpos_of_nonneg_of_nonpos {a b : Int} (Ha : 0 a) (Hb : b 0) : a / b 0 :=
Int.nonpos_of_neg_nonneg <| Int.ediv_neg .. Int.ediv_nonneg Ha (Int.neg_nonneg_of_nonpos Hb)
@[deprecated ediv_nonpos_of_nonneg_of_nonpos (since := "2025-03-04")]
abbrev ediv_nonpos := @ediv_nonpos_of_nonneg_of_nonpos
theorem ediv_eq_zero_of_lt {a b : Int} (H1 : 0 a) (H2 : a < b) : a / b = 0 :=
match a, b, eq_ofNat_of_zero_le H1, eq_succ_of_zero_lt (Int.lt_of_le_of_lt H1 H2) with
| _, _, _, rfl, _, rfl => congrArg Nat.cast <| Nat.div_eq_of_lt <| ofNat_lt.1 H2
@@ -565,7 +565,7 @@ theorem ediv_eq_one_of_neg_of_le {a b : Int} (H1 : a < 0) (H2 : b ≤ a) : a / b
match a, b, H1, H2 with
| negSucc a', ofNat n', H1, H2 => simp [Int.negSucc_eq] at H2; omega
| negSucc a', negSucc b', H1, H2 =>
rw [Int.div_def, ediv, ofNat_eq_natCast]
rw [Int.div_def, ediv, ofNat_eq_coe]
norm_cast
rw [Nat.succ_eq_add_one, Nat.add_eq_right, Nat.div_eq_zero_iff_lt (by omega)]
simp [Int.negSucc_eq] at H2
@@ -585,7 +585,7 @@ theorem neg_one_ediv (b : Int) : -1 / b = -b.sign :=
match b with
| ofNat 0 => by simp
| ofNat (b + 1) =>
ediv_eq_neg_one_of_neg_of_le (by decide) (by simp [ofNat_eq_natCast]; omega)
ediv_eq_neg_one_of_neg_of_le (by decide) (by simp [ofNat_eq_coe]; omega)
| negSucc b =>
ediv_eq_one_of_neg_of_le (by decide) (by omega)
@@ -652,7 +652,7 @@ theorem sign_ediv (a b : Int) : sign (a / b) = if 0 ≤ a ∧ a < b.natAbs then
| (a + 1 : Nat) =>
norm_cast
simp only [Nat.le_add_left, Nat.add_lt_add_iff_right, true_and, Int.natCast_add,
cast_ofNat_Int, sign_natCast_add_one, Int.mul_one]
cast_ofNat_Int, sign_of_add_one, Int.mul_one]
split
· rw [Nat.div_eq_of_lt (by omega)]
simp
@@ -678,15 +678,25 @@ theorem ofNat_mod_ofNat (m n : Nat) : (m % n : Int) = ↑(m % n) := rfl
@[simp] theorem add_neg_mul_emod_self_right (a b c : Int) : (a + -(b * c)) % c = a % c := by
rw [Int.neg_mul_eq_neg_mul, add_mul_emod_self_right]
@[deprecated add_neg_mul_emod_self_right (since := "2025-04-11")]
theorem add_neg_mul_emod_self {a b c : Int} : (a + -(b * c)) % c = a % c :=
add_neg_mul_emod_self_right ..
@[simp] theorem add_neg_mul_emod_self_left (a b c : Int) : (a + -(b * c)) % b = a % b := by
rw [Int.neg_mul_eq_mul_neg, add_mul_emod_self_left]
@[simp] theorem add_emod_right (a b : Int) : (a + b) % b = a % b := by
have := add_mul_emod_self_left a b 1; rwa [Int.mul_one] at this
@[deprecated add_emod_right (since := "2025-04-11")]
theorem add_emod_self {a b : Int} : (a + b) % b = a % b := add_emod_right ..
@[simp] theorem add_emod_left (a b : Int) : (a + b) % a = b % a := by
rw [Int.add_comm, add_emod_right]
@[deprecated add_emod_left (since := "2025-04-11")]
theorem add_emod_self_left {a b : Int} : (a + b) % a = b % a := add_emod_left ..
@[simp] theorem sub_mul_emod_self_right (a b c : Int) : (a - b * c) % c = a % c := by
simp [Int.sub_eq_add_neg]
@@ -927,6 +937,9 @@ where
| -[_+1], 0 => Nat.zero_le _
| -[_+1], succ _ => Nat.succ_le_succ (Nat.div_le_self _ _)
@[deprecated natAbs_ediv_le_natAbs (since := "2025-03-05")]
abbrev natAbs_div_le_natAbs := natAbs_ediv_le_natAbs
theorem ediv_le_self {a : Int} (b : Int) (Ha : 0 a) : a / b a := by
have := Int.le_trans le_natAbs (ofNat_le.2 <| natAbs_ediv_le_natAbs a b)
rwa [natAbs_of_nonneg Ha] at this
@@ -959,6 +972,14 @@ theorem emod_eq_iff {a b c : Int} (hb : b ≠ 0) : a % b = c ↔ 0 ≤ c ∧ c <
rw [ dvd_iff_emod_eq_zero, Int.dvd_neg]
exact Int.dvd_mul_right a b
@[deprecated mul_ediv_cancel (since := "2025-03-05")]
theorem neg_mul_ediv_cancel (a b : Int) (h : b 0) : -(a * b) / b = -a := by
rw [neg_ediv_of_dvd (Int.dvd_mul_left a b), mul_ediv_cancel _ h]
@[deprecated mul_ediv_cancel (since := "2025-03-05")]
theorem neg_mul_ediv_cancel_left (a b : Int) (h : a 0) : -(a * b) / a = -b := by
rw [neg_ediv_of_dvd (Int.dvd_mul_right a b), mul_ediv_cancel_left _ h]
@[simp] theorem ediv_one : a : Int, a / 1 = a
| (_:Nat) => congrArg Nat.cast (Nat.div_one _)
| -[_+1] => congrArg negSucc (Nat.div_one _)
@@ -972,6 +993,10 @@ theorem ediv_minus_one (a : Int) : a / (-1) = -a := by
theorem emod_minus_one (a : Int) : a % (-1) = 0 := by
simp
@[deprecated sub_emod_right (since := "2025-04-11")]
theorem emod_sub_cancel (x y : Int) : (x - y) % y = x % y :=
sub_emod_right ..
@[simp] theorem add_neg_emod_self (a b : Int) : (a + -b) % b = a % b := by
rw [Int.add_neg_eq_sub, sub_emod_right]
@@ -982,6 +1007,10 @@ theorem emod_minus_one (a : Int) : a % (-1) = 0 := by
theorem dvd_self_sub_of_emod_eq {a b : Int} : {c : Int} a % b = c b a - c
| _, rfl => dvd_self_sub_emod
@[deprecated dvd_self_sub_of_emod_eq (since := "2025-04-12")]
theorem dvd_sub_of_emod_eq {a b : Int} : {c : Int} a % b = c b a - c :=
dvd_self_sub_of_emod_eq
theorem dvd_sub_self_of_emod_eq {a b : Int} : {c : Int} a % b = c b c - a
| _, rfl => dvd_emod_sub_self
@@ -1069,7 +1098,7 @@ theorem emod_natAbs_of_neg {x : Int} (h : x < 0) {n : Nat} (w : n ≠ 0) :
match x, h with
| -(x + 1 : Nat), _ =>
rw [Int.natAbs_neg]
rw [Int.natAbs_natCast]
rw [Int.natAbs_cast]
rw [Int.neg_emod]
simp only [Int.dvd_neg]
simp only [Int.natCast_dvd_natCast]
@@ -1235,7 +1264,7 @@ private theorem ediv_ediv_of_pos {x y z : Int} (hy : 0 < y) (hz : 0 < z) :
· 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_of_nonneg {x y z : Int} (hy : 0 y) : x / y / z = x / (y * z) := by
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
@@ -1244,21 +1273,6 @@ theorem ediv_ediv_of_nonneg {x y z : Int} (hy : 0 ≤ y) : x / y / z = x / (y *
· simp [Int.negSucc_eq, Int.mul_neg, ediv_ediv_of_pos]
· simp at hy
theorem ediv_ediv {x y z : Int} : x / y / z = x / (y * z) - if y < 0 ¬ z x / y then z.sign else 0 := by
rcases y with y | y
· rw [ediv_ediv_of_nonneg (by simp), if_neg (by simp; omega)]
simp
· rw [Int.negSucc_eq, Int.ediv_neg, Int.neg_mul, Int.ediv_neg, Int.neg_ediv, ediv_ediv_of_nonneg (by omega)]
simp
theorem ediv_mul {x y z : Int} : x / (y * z) = x / y / z + if y < 0 ¬ z x / y then z.sign else 0 := by
have := ediv_ediv (x := x) (y := y) (z := z)
omega
theorem ediv_mul_of_nonneg {x y z : Int} (hy : 0 y) : x / (y * z) = x / y / z := by
have := ediv_ediv_of_nonneg (x := x) (y := y) (z := z) hy
omega
/-! ### tdiv -/
-- `tdiv` analogues of `ediv` lemmas from `Bootstrap.lean`
@@ -1292,7 +1306,7 @@ because these statements are all incorrect, and require awkward conditional off-
protected theorem tdiv_nonneg {a b : Int} (Ha : 0 a) (Hb : 0 b) : 0 a.tdiv b :=
match a, b, eq_ofNat_of_zero_le Ha, eq_ofNat_of_zero_le Hb with
| _, _, _, rfl, _, rfl => natCast_nonneg _
| _, _, _, rfl, _, rfl => ofNat_zero_le _
theorem tdiv_nonneg_of_nonpos_of_nonpos {a b : Int} (Ha : a 0) (Hb : b 0) : 0 a.tdiv b := by
rw [tdiv_eq_ediv]
@@ -1315,6 +1329,9 @@ theorem tdiv_nonneg_of_nonpos_of_nonpos {a b : Int} (Ha : a ≤ 0) (Hb : b ≤ 0
protected theorem tdiv_nonpos_of_nonneg_of_nonpos {a b : Int} (Ha : 0 a) (Hb : b 0) : a.tdiv b 0 :=
Int.nonpos_of_neg_nonneg <| Int.tdiv_neg .. Int.tdiv_nonneg Ha (Int.neg_nonneg_of_nonpos Hb)
@[deprecated Int.tdiv_nonpos_of_nonneg_of_nonpos (since := "2025-03-04")]
abbrev tdiv_nonpos := @Int.tdiv_nonpos_of_nonneg_of_nonpos
theorem tdiv_eq_zero_of_lt {a b : Int} (H1 : 0 a) (H2 : a < b) : a.tdiv b = 0 :=
match a, b, eq_ofNat_of_zero_le H1, eq_succ_of_zero_lt (Int.lt_of_le_of_lt H1 H2) with
| _, _, _, rfl, _, rfl => congrArg Nat.cast <| Nat.div_eq_of_lt <| ofNat_lt.1 H2
@@ -1410,7 +1427,7 @@ theorem tmod_lt_of_pos (a : Int) {b : Int} (H : 0 < b) : tmod a b < b :=
theorem lt_tmod_of_pos (a : Int) {b : Int} (H : 0 < b) : -b < tmod a b :=
match a, b, eq_succ_of_zero_lt H with
| ofNat _, _, n, rfl => by rw [ofNat_eq_natCast, Int.natCast_succ, ofNat_tmod]; omega
| ofNat _, _, n, rfl => by rw [ofNat_eq_coe, Int.natCast_succ, ofNat_tmod]; omega
| -[a+1], _, n, rfl => by
rw [negSucc_eq, neg_tmod, Int.natCast_add_one, Int.natCast_add_one, ofNat_tmod]
have : (a + 1) % (n + 1) < n + 1 := Nat.mod_lt _ (Nat.zero_lt_succ n)
@@ -1781,16 +1798,6 @@ theorem ediv_lt_ediv_iff_of_dvd_of_neg_of_neg {a b c d : Int} (hb : b < 0) (hd :
obtain x, rfl, y, rfl := hba, hdc
simp [*, Int.ne_of_lt, d.mul_assoc, b.mul_comm]
theorem ediv_lt_ediv_of_lt {a b c : Int} (h : a < b) (hcb : c b) (hc : 0 < c) :
a / c < b / c :=
Int.lt_ediv_of_mul_lt (Int.le_of_lt hc) hcb
(Int.lt_of_le_of_lt (Int.ediv_mul_le _ (Int.ne_of_gt hc)) h)
theorem ediv_lt_ediv_of_lt_of_neg {a b c : Int} (h : b < a) (hca : c a) (hc : c < 0) :
a / c < b / c :=
(Int.ediv_lt_iff_of_dvd_of_neg hc hca).2
(Int.lt_of_le_of_lt (Int.mul_ediv_self_le (Int.ne_of_lt hc)) h)
/-! ### `tdiv` and ordering -/
-- Theorems about `tdiv` and ordering, whose `ediv` analogues are in `Bootstrap.lean`.
@@ -1867,7 +1874,7 @@ theorem le_emod_self_add_one_iff {a b : Int} (h : 0 < b) : b ≤ a % b + 1 ↔ b
match b, h with
| .ofNat 1, h => simp
| .ofNat (b + 2), h =>
simp only [ofNat_eq_natCast, Int.natCast_add, cast_ofNat_Int] at *
simp only [ofNat_eq_coe, Int.natCast_add, cast_ofNat_Int] at *
constructor
· rw [dvd_iff_emod_eq_zero]
intro w
@@ -1883,12 +1890,16 @@ theorem le_emod_self_add_one_iff {a b : Int} (h : 0 < b) : b ≤ a % b + 1 ↔ b
sign_eq_one_of_pos (by omega), Int.mul_add]
omega
@[deprecated le_emod_self_add_one_iff (since := "2025-04-12")]
theorem le_mod_self_add_one_iff {a b : Int} (h : 0 < b) : b a % b + 1 b a + 1 :=
le_emod_self_add_one_iff h
theorem add_one_tdiv_of_pos {a b : Int} (h : 0 < b) :
(a + 1).tdiv b = a.tdiv b + if (0 < a + 1 b a + 1) (a < 0 b a) then 1 else 0 := by
match b, h with
| .ofNat 1, h => simp; omega
| .ofNat (b + 2), h =>
simp only [ofNat_eq_natCast]
simp only [ofNat_eq_coe]
rw [tdiv_eq_ediv, add_ediv (by omega), tdiv_eq_ediv]
simp only [Int.natCast_add, cast_ofNat_Int]
have : 1 / (b + 2 : Int) = 0 := by rw [one_ediv]; omega
@@ -2003,7 +2014,7 @@ theorem add_fdiv_of_dvd_left {a b c : Int} (H : c a) : (a + b).fdiv c = a.fd
theorem fdiv_nonneg {a b : Int} (Ha : 0 a) (Hb : 0 b) : 0 a.fdiv b :=
match a, b, eq_ofNat_of_zero_le Ha, eq_ofNat_of_zero_le Hb with
| _, _, _, rfl, _, rfl => ofNat_fdiv .. natCast_nonneg _
| _, _, _, rfl, _, rfl => ofNat_fdiv .. ofNat_zero_le _
theorem fdiv_nonneg_of_nonpos_of_nonpos {a b : Int} (Ha : a 0) (Hb : b 0) : 0 a.fdiv b := by
rw [fdiv_eq_ediv]
@@ -2018,6 +2029,9 @@ theorem fdiv_nonpos_of_nonneg_of_nonpos : ∀ {a b : Int}, 0 ≤ a → b ≤ 0
| 0, 0, _, _ | 0, -[_+1], _, _ | succ _, 0, _, _ | succ _, -[_+1], _, _ => by
simp [fdiv, negSucc_le_zero]
@[deprecated fdiv_nonpos_of_nonneg_of_nonpos (since := "2025-03-04")]
abbrev fdiv_nonpos := @fdiv_nonpos_of_nonneg_of_nonpos
theorem fdiv_neg_of_neg_of_pos : {a b : Int}, a < 0 0 < b a.fdiv b < 0
| -[_+1], succ _, _, _ => negSucc_lt_zero _
@@ -2052,8 +2066,8 @@ protected theorem fdiv_eq_of_eq_mul_right {a b c : Int}
(H1 : b 0) (H2 : a = b * c) : a.fdiv b = c := by rw [H2, Int.mul_fdiv_cancel_left _ H1]
protected theorem eq_fdiv_of_mul_eq_right {a b c : Int}
(H1 : a 0) (H2 : a * b = c) : b = c.fdiv a :=
(Int.fdiv_eq_of_eq_mul_right H1 H2.symm).symm
(H1 : a 0) (H2 : a * b = c) : b = c.tdiv a :=
(Int.tdiv_eq_of_eq_mul_right H1 H2.symm).symm
protected theorem fdiv_eq_of_eq_mul_left {a b c : Int}
(H1 : b 0) (H2 : a = c * b) : a.fdiv b = c :=
@@ -2090,20 +2104,20 @@ theorem neg_fdiv {a b : Int} : (-a).fdiv b = -(a.fdiv b) - if b = 0 b a
| ofNat (a + 1), 0 => simp
| ofNat (a + 1), ofNat (b + 1) =>
unfold fdiv
simp only [ofNat_eq_natCast, Int.natCast_add, cast_ofNat_Int, Nat.succ_eq_add_one]
simp only [ofNat_eq_coe, Int.natCast_add, cast_ofNat_Int, Nat.succ_eq_add_one]
rw [ negSucc_eq, negSucc_eq]
| ofNat (a + 1), -[b+1] =>
unfold fdiv
simp only [ofNat_eq_natCast, Int.natCast_add, cast_ofNat_Int, Nat.succ_eq_add_one]
simp only [ofNat_eq_coe, Int.natCast_add, cast_ofNat_Int, Nat.succ_eq_add_one]
rw [ negSucc_eq, neg_negSucc]
| -[a+1], 0 => simp
| -[a+1], ofNat (b + 1) =>
unfold fdiv
simp only [ofNat_eq_natCast, Int.natCast_add, cast_ofNat_Int, Nat.succ_eq_add_one]
simp only [ofNat_eq_coe, Int.natCast_add, cast_ofNat_Int, Nat.succ_eq_add_one]
rw [neg_negSucc, negSucc_eq]
| -[a+1], -[b+1] =>
unfold fdiv
simp only [ofNat_eq_natCast, natCast_ediv, Nat.succ_eq_add_one, Int.natCast_add, cast_ofNat_Int]
simp only [ofNat_eq_coe, natCast_ediv, Nat.succ_eq_add_one, Int.natCast_add, cast_ofNat_Int]
rw [neg_negSucc, neg_negSucc]
simp
@@ -2136,6 +2150,9 @@ theorem fmod_nonneg {a b : Int} (ha : 0 ≤ a) (hb : 0 ≤ b) : 0 ≤ a.fmod b :
theorem fmod_nonneg_of_pos (a : Int) {b : Int} (hb : 0 < b) : 0 a.fmod b :=
fmod_eq_emod_of_nonneg _ (Int.le_of_lt hb) emod_nonneg _ (Int.ne_of_lt hb).symm
@[deprecated fmod_nonneg_of_pos (since := "2025-03-04")]
abbrev fmod_nonneg' := @fmod_nonneg_of_pos
theorem fmod_lt_of_pos (a : Int) {b : Int} (H : 0 < b) : a.fmod b < b :=
fmod_eq_emod_of_nonneg _ (Int.le_of_lt H) emod_lt_of_pos a H
@@ -2145,6 +2162,10 @@ theorem fmod_lt_of_pos (a : Int) {b : Int} (H : 0 < b) : a.fmod b < b :=
rw [fmod_eq_emod, add_mul_emod_self_right, fmod_eq_emod]
simp
@[deprecated add_mul_fmod_self_right (since := "2025-04-11")]
theorem add_mul_fmod_self {a b c : Int} : (a + b * c).fmod c = a.fmod c :=
add_mul_fmod_self_right ..
@[simp] theorem add_mul_fmod_self_left (a b c : Int) : (a + b * c).fmod b = a.fmod b := by
rw [Int.mul_comm, Int.add_mul_fmod_self_right]
@@ -2392,7 +2413,7 @@ theorem natAbs_fdiv_le_natAbs (a b : Int) : natAbs (a.fdiv b) ≤ natAbs a := by
| 0, .negSucc b, h => simp at h
| .ofNat (a + 1), .negSucc 0, h => simp at h
| .ofNat (a + 1), .negSucc (b + 1), h =>
rw [negSucc_eq, ofNat_eq_natCast]
rw [negSucc_eq, ofNat_eq_coe]
norm_cast
rw [Int.ediv_neg, Int.sub_eq_add_neg, Int.neg_add, natAbs_neg]
norm_cast
@@ -2443,12 +2464,20 @@ theorem dvd_sub_self_of_fmod_eq {a b c : Int} (h : a.fmod b = c) :
@[simp] theorem fmod_one (a : Int) : a.fmod 1 = 0 := by
simp [fmod_def, Int.one_mul, Int.sub_self]
@[deprecated sub_fmod_right (since := "2025-04-12")]
theorem fmod_sub_cancel (x y : Int) : (x - y).fmod y = x.fmod y :=
sub_fmod_right _ _
@[simp] theorem add_neg_fmod_self (a b : Int) : (a + -b).fmod b = a.fmod b := by
rw [Int.add_neg_eq_sub, sub_fmod_right]
@[simp] theorem neg_add_fmod_self (a b : Int) : (-a + b).fmod a = b.fmod a := by
rw [Int.add_comm, add_neg_fmod_self]
@[deprecated dvd_self_sub_of_fmod_eq (since := "2025-04-12")]
theorem dvd_sub_of_fmod_eq {a b c : Int} (h : a.fmod b = c) : b a - c :=
dvd_self_sub_of_fmod_eq h
theorem fdiv_sign {a b : Int} : a.fdiv (sign b) = a * sign b := by
rw [fdiv_eq_ediv]
rcases sign_trichotomy b with h | h | h <;> simp [h]
@@ -2482,6 +2511,10 @@ theorem lt_mul_fdiv_self_add {x k : Int} (h : 0 < k) : x < k * (x.fdiv k) + k :=
theorem emod_bmod (x : Int) (n : Nat) : Int.bmod (x%n) n = Int.bmod x n := by
simp [bmod]
@[deprecated emod_bmod (since := "2025-04-11")]
theorem emod_bmod_congr (x : Int) (n : Nat) : Int.bmod (x%n) n = Int.bmod x n :=
emod_bmod ..
theorem bdiv_add_bmod (x : Int) (m : Nat) : m * bdiv x m + bmod x m = x := by
unfold bdiv bmod
split
@@ -2508,10 +2541,6 @@ theorem bmod_eq_self_sub_mul_bdiv (x : Int) (m : Nat) : bmod x m = x - m * bdiv
theorem bmod_eq_self_sub_bdiv_mul (x : Int) (m : Nat) : bmod x m = x - bdiv x m * m := by
rw [ Int.add_sub_cancel (bmod x m), bmod_add_bdiv']
theorem bmod_eq_emod_of_lt {x : Int} {m : Nat} (hx : x % m < (m + 1) / 2) : bmod x m = x % m := by
simp [bmod, hx]
@[deprecated Int.bmod_eq_emod_of_lt (since := "2025-10-29")]
theorem bmod_pos (x : Int) (m : Nat) (p : x % m < (m + 1) / 2) : bmod x m = x % m := by
simp [bmod_def, p]
@@ -2521,12 +2550,15 @@ theorem bmod_neg (x : Int) (m : Nat) (p : x % m ≥ (m + 1) / 2) : bmod x m = (x
theorem bmod_eq_emod (x : Int) (m : Nat) : bmod x m = x % m - if x % m (m + 1) / 2 then m else 0 := by
split
· rwa [bmod_neg]
· rw [bmod_eq_emod_of_lt] <;> simp_all
· rw [bmod_pos] <;> simp_all
@[simp]
theorem bmod_one (x : Int) : Int.bmod x 1 = 0 := by
simp [Int.bmod]
@[deprecated bmod_one (since := "2025-04-10")]
abbrev bmod_one_is_zero := @bmod_one
@[simp] theorem add_bmod_right (a : Int) (b : Nat) : (a + b).bmod b = a.bmod b := by
simp [bmod_def]
@@ -2569,36 +2601,76 @@ theorem bmod_one (x : Int) : Int.bmod x 1 = 0 := by
@[simp] theorem add_neg_mul_bmod_self_left (a : Int) (b : Nat) (c : Int) : (a + -(b * c)).bmod b = a.bmod b := by
simp [bmod_def]
@[deprecated add_bmod_right (since := "2025-04-10")]
theorem bmod_add_cancel {x : Int} {n : Nat} : Int.bmod (x + n) n = Int.bmod x n :=
add_bmod_right ..
@[deprecated add_mul_bmod_self_left (since := "2025-04-10")]
theorem bmod_add_mul_cancel (x : Int) (n : Nat) (k : Int) : Int.bmod (x + n * k) n = Int.bmod x n :=
add_mul_bmod_self_left ..
@[deprecated sub_bmod_right (since := "2025-04-10")]
theorem bmod_sub_cancel (x : Int) (n : Nat) : Int.bmod (x - n) n = Int.bmod x n :=
sub_bmod_right ..
@[deprecated sub_mul_bmod_self_left (since := "2025-04-10")]
theorem Int.bmod_sub_mul_cancel (x : Int) (n : Nat) (k : Int) : (x - n * k).bmod n = x.bmod n :=
sub_mul_bmod_self_left ..
@[simp]
theorem emod_add_bmod (x : Int) (n : Nat) : Int.bmod (x % n + y) n = Int.bmod (x + y) n := by
simp [Int.emod_def, Int.sub_eq_add_neg]
rw [Int.mul_neg, Int.add_right_comm, Int.add_mul_bmod_self_left]
@[deprecated emod_add_bmod (since := "2025-04-11")]
theorem emod_add_bmod_congr (x : Int) (n : Nat) : Int.bmod (x % n + y) n = Int.bmod (x + y) n :=
emod_add_bmod ..
@[simp]
theorem emod_sub_bmod (x : Int) (n : Nat) : Int.bmod (x % n - y) n = Int.bmod (x - y) n := by
simp only [emod_def, Int.sub_eq_add_neg]
rw [Int.mul_neg, Int.add_right_comm, Int.add_mul_bmod_self_left]
@[deprecated emod_sub_bmod (since := "2025-04-11")]
theorem emod_sub_bmod_congr (x : Int) (n : Nat) : Int.bmod (x % n - y) n = Int.bmod (x - y) n :=
emod_sub_bmod ..
@[simp]
theorem sub_emod_bmod (x : Int) (n : Nat) : Int.bmod (x - y % n) n = Int.bmod (x - y) n := by
simp only [emod_def]
rw [Int.sub_eq_add_neg, Int.neg_sub, Int.sub_eq_add_neg, Int.add_assoc, Int.add_right_comm,
Int.add_mul_bmod_self_left, Int.sub_eq_add_neg]
@[deprecated sub_emod_bmod (since := "2025-04-11")]
theorem sub_emod_bmod_congr (x : Int) (n : Nat) : Int.bmod (x - y % n) n = Int.bmod (x - y) n :=
sub_emod_bmod ..
@[simp]
theorem emod_mul_bmod (x : Int) (n : Nat) : Int.bmod (x % n * y) n = Int.bmod (x * y) n := by
simp [Int.emod_def, Int.sub_eq_add_neg]
rw [Int.mul_neg, Int.add_mul, Int.mul_assoc, Int.add_mul_bmod_self_left]
@[deprecated emod_mul_bmod (since := "2025-04-11")]
theorem emod_mul_bmod_congr (x : Int) (n : Nat) : Int.bmod (x % n * y) n = Int.bmod (x * y) n :=
emod_mul_bmod ..
@[simp]
theorem bmod_add_bmod : Int.bmod (Int.bmod x n + y) n = Int.bmod (x + y) n := by
have := (@add_mul_bmod_self_left (Int.bmod x n + y) n (bdiv x n)).symm
rwa [Int.add_right_comm, bmod_add_bdiv] at this
@[deprecated bmod_add_bmod (since := "2025-04-11")]
theorem bmod_add_bmod_congr : Int.bmod (Int.bmod x n + y) n = Int.bmod (x + y) n :=
bmod_add_bmod ..
@[simp]
theorem bmod_sub_bmod : Int.bmod (Int.bmod x n - y) n = Int.bmod (x - y) n :=
@bmod_add_bmod x n (-y)
@[deprecated bmod_sub_bmod (since := "2025-04-11")]
theorem bmod_sub_bmod_congr : Int.bmod (Int.bmod x n - y) n = Int.bmod (x - y) n :=
bmod_sub_bmod ..
theorem add_bmod_eq_add_bmod_right (i : Int)
(H : bmod x n = bmod y n) : bmod (x + i) n = bmod (y + i) n := by
rw [ bmod_add_bmod, @bmod_add_bmod y, H]
@@ -2758,6 +2830,9 @@ theorem bmod_eq_iff {a : Int} {b : Nat} {c : Int} (hb : 0 < b) :
have := bmod_lt (x := a) (m := b) hb
omega
theorem bmod_eq_emod_of_lt {x : Int} {m : Nat} (hx : x % m < (m + 1) / 2) : bmod x m = x % m := by
simp [bmod, hx]
theorem bmod_eq_neg {n : Nat} {m : Int} (hm : 0 m) (hn : n = 2 * m) : m.bmod n = -m := by
by_cases h : m = 0
· subst h; simp
@@ -2788,6 +2863,9 @@ theorem bmod_natAbs_add_one (x : Int) (w : x ≠ -1) : x.bmod (x.natAbs + 1) = -
· rw [sign_eq_one_iff_pos.2 hx]
exact by omega, by omega, -1, by omega
@[deprecated bmod_natAbs_add_one (since := "2025-04-04")]
abbrev bmod_natAbs_plus_one := @bmod_natAbs_add_one
theorem bmod_self_add_one {x : Nat} : (x : Int).bmod (x + 1) = if x = 0 then 0 else -1 := by
have := bmod_natAbs_add_one x (by omega)
simp only [natAbs_natCast] at this
@@ -2798,7 +2876,7 @@ theorem one_bmod_two : Int.bmod 1 2 = -1 := by simp
theorem one_bmod {b : Nat} (h : 3 b) : Int.bmod 1 b = 1 := by
have hb : 1 % (b : Int) = 1 := by rw [one_emod]; omega
rw [bmod_eq_emod_of_lt (by omega), hb]
rw [bmod_pos _ _ (by omega), hb]
theorem bmod_two_eq (x : Int) : x.bmod 2 = -1 x.bmod 2 = 0 := by
have := le_bmod (x := x) (m := 2) (by omega)
@@ -2908,6 +2986,11 @@ theorem bmod_eq_of_le {n : Int} {m : Nat} (hn' : -(m / 2) ≤ n) (hn : n < (m +
n.bmod m = n :=
(Nat.eq_zero_or_pos m).elim (by rintro rfl; simp) (fun hm => by simp_all [bmod_eq_iff])
@[deprecated bmod_eq_of_le (since := "2025-04-11")]
theorem bmod_eq_self_of_le {n : Int} {m : Nat} (hn' : -(m / 2) n) (hn : n < (m + 1) / 2) :
n.bmod m = n :=
bmod_eq_of_le hn' hn
theorem bmod_bmod_of_dvd {a : Int} {n m : Nat} (hnm : n m) :
(a.bmod m).bmod n = a.bmod n := by
rw [ Int.sub_eq_iff_eq_add.2 (bmod_add_bdiv a m).symm]
@@ -2918,6 +3001,11 @@ theorem bmod_eq_of_le_mul_two {x : Int} {y : Nat} (hle : -y ≤ x * 2) (hlt : x
x.bmod y = x := by
apply bmod_eq_of_le (by omega) (by omega)
@[deprecated bmod_eq_of_le_mul_two (since := "2025-04-11")]
theorem bmod_eq_self_of_le_mul_two {x : Int} {y : Nat} (hle : -y x * 2) (hlt : x * 2 < y) :
x.bmod y = x :=
bmod_eq_of_le_mul_two hle hlt
/- ### ediv -/
theorem ediv_lt_self_of_pos_of_ne_one {x y : Int} (hx : 0 < x) (hy : y 1) :
@@ -2936,7 +3024,7 @@ theorem ediv_nonneg_of_nonneg_of_nonneg {x y : Int} (hx : 0 ≤ x) (hy : 0 ≤ y
obtain xn, rfl := Int.eq_ofNat_of_zero_le (a := x) (by omega)
obtain yn, rfl := Int.eq_ofNat_of_zero_le (a := y) (by omega)
rw [ Int.natCast_ediv]
exact natCast_nonneg (xn / yn)
exact Int.ofNat_zero_le (xn / yn)
/-- When both x and y are negative we need stricter bounds on x and y
to establish the upper bound of x/y, i.e., x / y < x.natAbs.
@@ -2973,7 +3061,7 @@ theorem neg_self_le_ediv_of_nonneg_of_nonpos (x y : Int) (hx : 0 ≤ x) (hy : y
· obtain xn, rfl := Int.eq_ofNat_of_zero_le (a := x) (by omega)
obtain yn, rfl := Int.eq_negSucc_of_lt_zero (a := y) (by omega)
rw [show xn = ofNat xn by norm_cast, Int.ofNat_ediv_negSucc (a := xn)]
simp only [ofNat_eq_natCast, natCast_ediv, Int.natCast_add, cast_ofNat_Int, Int.neg_le_neg_iff]
simp only [ofNat_eq_coe, natCast_ediv, Int.natCast_add, cast_ofNat_Int, Int.neg_le_neg_iff]
norm_cast
apply Nat.le_trans (m := xn) (by exact Nat.div_le_self xn (yn + 1)) (by omega)

View File

@@ -1,35 +0,0 @@
/-
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.Int.DivMod.Lemmas
public import Init.Data.Int.Pow
/-!
# Lemmas about divisibility of powers
-/
namespace Int
theorem dvd_pow {a b : Int} {n : Nat} (hab : b a) : b ^ n a ^ n := by
rcases hab with c, rfl
rw [Int.mul_pow]
exact Int.dvd_mul_right (b ^ n) (c ^ n)
theorem ediv_pow {a b : Int} {n : Nat} (hab : b a) :
(a / b) ^ n = a ^ n / b ^ n := by
obtain c, rfl := hab
by_cases b = 0
· by_cases n = 0 <;> simp [*, Int.zero_pow]
· simp [Int.mul_pow, Int.pow_ne_zero, *]
theorem tdiv_pow {a b : Int} {n : Nat} (hab : b a) :
(a.tdiv b) ^ n = (a ^ n).tdiv (b ^ n) := by
rw [Int.tdiv_eq_ediv_of_dvd hab, ediv_pow hab, Int.tdiv_eq_ediv_of_dvd (dvd_pow hab)]
theorem fdiv_pow {a b : Int} {n : Nat} (hab : b a) :
(a.fdiv b) ^ n = (a ^ n).fdiv (b ^ n) := by
rw [Int.fdiv_eq_ediv_of_dvd hab, ediv_pow hab, Int.fdiv_eq_ediv_of_dvd (dvd_pow hab)]

View File

@@ -17,7 +17,7 @@ open Nat
/-! ## Definitions of basic functions -/
theorem subNatNat_of_sub_eq_zero {m n : Nat} (h : n - m = 0) : subNatNat m n = (m - n) := by
rw [subNatNat, h, ofNat_eq_natCast]
rw [subNatNat, h, ofNat_eq_coe]
theorem subNatNat_of_sub_eq_succ {m n k : Nat} (h : n - m = succ k) : subNatNat m n = -[k+1] := by
rw [subNatNat, h]
@@ -74,6 +74,9 @@ theorem negSucc_inj : negSucc m = negSucc n ↔ m = n := ⟨negSucc.inj, fun H =
theorem negSucc_eq (n : Nat) : -[n+1] = -((n : Int) + 1) := rfl
@[deprecated negSucc_eq (since := "2025-03-11")]
theorem negSucc_coe (n : Nat) : -[n+1] = -(n + 1) := rfl
@[simp] theorem negSucc_ne_zero (n : Nat) : -[n+1] 0 := nofun
@[simp] theorem zero_ne_negSucc (n : Nat) : 0 -[n+1] := nofun
@@ -129,7 +132,7 @@ theorem subNatNat_elim (m n : Nat) (motive : Nat → Nat → Int → Prop)
theorem subNatNat_add_left : subNatNat (m + n) m = n := by
unfold subNatNat
rw [Nat.sub_eq_zero_of_le (Nat.le_add_right ..), Nat.add_sub_cancel_left, ofNat_eq_natCast]
rw [Nat.sub_eq_zero_of_le (Nat.le_add_right ..), Nat.add_sub_cancel_left, ofNat_eq_coe]
theorem subNatNat_add_right : subNatNat m (m + n + 1) = negSucc n := by
simp [subNatNat, Nat.add_assoc, Nat.add_sub_cancel_left]
@@ -350,6 +353,10 @@ protected theorem add_sub_assoc (a b c : Int) : a + b - c = a + (b - c) := by
change ofNat (n - succ m) = subNatNat n (succ m)
rw [subNatNat, Nat.sub_eq_zero_of_le h]
@[deprecated negSucc_eq (since := "2025-03-11")]
theorem negSucc_coe' (n : Nat) : -[n+1] = -n - 1 := by
rw [Int.sub_eq_add_neg, Int.neg_add]; rfl
protected theorem subNatNat_eq_coe {m n : Nat} : subNatNat m n = m - n := by
apply subNatNat_elim m n fun m n i => i = m - n
· intro i n
@@ -552,7 +559,7 @@ protected theorem mul_eq_zero {a b : Int} : a * b = 0 ↔ a = 0 b = 0 := by
exact match a, b, h with
| .ofNat 0, _, _ => by simp
| _, .ofNat 0, _ => by simp
| .ofNat (_+1), .negSucc _, h => by cases h
| .ofNat (a+1), .negSucc b, h => by cases h
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
@@ -600,4 +607,6 @@ protected theorem natCast_zero : ((0 : Nat) : Int) = (0 : Int) := rfl
protected theorem natCast_one : ((1 : Nat) : Int) = (1 : Int) := rfl
@[simp, norm_cast] theorem natAbs_cast (n : Nat) : natAbs n = n := rfl
end Int

View File

@@ -27,28 +27,28 @@ namespace Int
natCast_nonneg _
@[simp] theorem neg_natCast_le_natCast (n m : Nat) : -(n : Int) (m : Int) :=
Int.le_trans (by simp) (natCast_nonneg m)
Int.le_trans (by simp) (ofNat_zero_le m)
@[simp] theorem neg_natCast_le_ofNat (n m : Nat) : -(n : Int) (no_index (OfNat.ofNat m)) :=
Int.le_trans (by simp) (natCast_nonneg m)
Int.le_trans (by simp) (ofNat_zero_le m)
@[simp] theorem neg_ofNat_le_ofNat (n m : Nat) : -(no_index (OfNat.ofNat n)) (no_index (OfNat.ofNat m)) :=
Int.le_trans (by simp) (natCast_nonneg m)
Int.le_trans (by simp) (ofNat_zero_le m)
@[simp] theorem neg_ofNat_le_natCast (n m : Nat) : -(no_index (OfNat.ofNat n)) (m : Int) :=
Int.le_trans (by simp) (natCast_nonneg m)
Int.le_trans (by simp) (ofNat_zero_le m)
theorem neg_lt_self_iff {n : Int} : -n < n 0 < n := by
omega
@[deprecated ofNat_add_ofNat (since := "2025-10-26")]
protected theorem ofNat_add_out (m n : Nat) : m + n = ((m + n) : Int) := rfl
@[deprecated ofNat_mul_ofNat (since := "2025-10-26")]
protected theorem ofNat_mul_out (m n : Nat) : m * n = ((m * n) : Int) := rfl
protected theorem ofNat_add_one_out (n : Nat) : n + (1 : Int) = (Nat.succ n) := rfl
@[simp] theorem ofNat_eq_natCast (n : Nat) : Int.ofNat n = n := rfl
@[norm_cast] theorem natCast_inj {m n : Nat} : (m : Int) = (n : Int) m = n := ofNat_inj
@[norm_cast]
@@ -62,6 +62,8 @@ theorem natCast_succ_pos (n : Nat) : 0 < (n.succ : Int) := natCast_pos.2 n.succ_
@[simp high] theorem natCast_nonpos_iff {n : Nat} : (n : Int) 0 n = 0 := by omega
@[simp] theorem sign_natCast_add_one (n : Nat) : sign (n + 1) = 1 := rfl
@[simp, norm_cast] theorem cast_id {n : Int} : Int.cast n = n := rfl
@[simp] theorem ble'_eq_true (a b : Int) : (Int.ble' a b = true) = (a b) := by
@@ -82,7 +84,7 @@ theorem natCast_succ_pos (n : Nat) : 0 < (n.succ : Int) := natCast_pos.2 n.succ_
symm
simp only [Int.toNat]
split <;> rename_i x a
· simp only [Int.ofNat_eq_natCast]
· simp only [Int.ofNat_eq_coe]
split <;> rename_i y b h
· simp at h
omega
@@ -116,8 +118,14 @@ theorem pos_iff_toNat_pos {n : Int} : 0 < n ↔ 0 < n.toNat := by
theorem natCast_toNat_eq_self {a : Int} : a.toNat = a 0 a := by omega
@[deprecated natCast_toNat_eq_self (since := "2025-04-16")]
theorem ofNat_toNat_eq_self {a : Int} : a.toNat = a 0 a := natCast_toNat_eq_self
theorem eq_natCast_toNat {a : Int} : a = a.toNat 0 a := by omega
@[deprecated eq_natCast_toNat (since := "2025-04-16")]
theorem eq_ofNat_toNat {a : Int} : a = a.toNat 0 a := eq_natCast_toNat
theorem toNat_le_toNat {n m : Int} (h : n m) : n.toNat m.toNat := by omega
theorem toNat_lt_toNat {n m : Int} (hn : 0 < m) : n.toNat < m.toNat n < m := by omega

View File

@@ -4,6 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE.
Authors: Leonardo de Moura
-/
module
prelude
public import Init.Data.Int.LemmasAux
public import Init.Data.Int.Cooper
@@ -11,7 +12,9 @@ import all Init.Data.Int.Gcd
public import Init.Data.AC
import all Init.Data.AC
import Init.LawfulBEqTactics
public section
namespace Int.Linear
/-! Helper definitions and theorems for constructing linear arithmetic proofs. -/
@@ -19,7 +22,8 @@ namespace Int.Linear
abbrev Var := Nat
abbrev Context := Lean.RArray Int
abbrev Var.denote (ctx : Context) (v : Var) : Int :=
@[expose]
def Var.denote (ctx : Context) (v : Var) : Int :=
ctx.get v
inductive Expr where
@@ -32,7 +36,8 @@ inductive Expr where
| mulR (a : Expr) (k : Int)
deriving Inhabited, @[expose] BEq
abbrev Expr.denote (ctx : Context) : Expr Int
@[expose]
def Expr.denote (ctx : Context) : Expr Int
| .add a b => denote ctx a + denote ctx b
| .sub a b => denote ctx a - denote ctx b
| .neg a => - denote ctx a
@@ -41,9 +46,6 @@ abbrev Expr.denote (ctx : Context) : Expr → Int
| .mulL k e => k * denote ctx e
| .mulR e k => denote ctx e * k
set_option allowUnsafeReducibility true
attribute [semireducible] Var.denote Expr.denote
inductive Poly where
| num (k : Int)
| add (k : Int) (v : Var) (p : Poly)
@@ -66,36 +68,35 @@ protected noncomputable def Poly.beq' (p₁ : Poly) : Poly → Bool :=
intro _ _; subst k₁ v₁
simp [ ih p₂, Bool.and'_eq_and]; rfl
abbrev Poly.denote (ctx : Context) (p : Poly) : Int :=
@[expose]
def Poly.denote (ctx : Context) (p : Poly) : Int :=
match p with
| .num k => k
| .add k v p => k * v.denote ctx + denote ctx p
noncomputable abbrev Poly.denote'.go (ctx : Context) (p : Poly) : Int Int :=
Poly.rec
(fun k r => Bool.rec
(r + k)
r
(Int.beq' k 0))
(fun k v _ ih r => Bool.rec
(ih (r + k * v.denote ctx))
(ih (r + v.denote ctx))
(Int.beq' k 1))
p
/--
Similar to `Poly.denote`, but produces a denotation better for `simp +arith`.
Remark: we used to convert `Poly` back into `Expr` to achieve that.
-/
noncomputable abbrev Poly.denote' (ctx : Context) (p : Poly) : Int :=
@[expose] noncomputable def Poly.denote' (ctx : Context) (p : Poly) : Int :=
Poly.rec (fun k => k)
(fun k v p _ => Bool.rec
(denote'.go ctx p (k * v.denote ctx))
(denote'.go ctx p (v.denote ctx))
(go p (k * v.denote ctx))
(go p (v.denote ctx))
(Int.beq' k 1))
p
attribute [semireducible] Poly.denote Poly.denote' Poly.denote'.go
where
go (p : Poly) : Int Int :=
Poly.rec
(fun k r => Bool.rec
(r + k)
r
(Int.beq' k 0))
(fun k v _ ih r => Bool.rec
(ih (r + k * v.denote ctx))
(ih (r + v.denote ctx))
(Int.beq' k 1))
p
@[simp] theorem Poly.denote'_go_eq_denote (ctx : Context) (p : Poly) (r : Int) : denote'.go ctx p r = p.denote ctx + r := by
induction p generalizing r
@@ -1090,7 +1091,7 @@ theorem eq_unsat_coeff (ctx : Context) (p : Poly) (k : Int) : eq_unsat_coeff_cer
induction p
next => rfl
next a y p ih =>
simp [coeff_k, coeff, cond_eq_ite]; split
simp [coeff_k, coeff, cond_eq_if]; split
next h => simp [h]
next h => rw [ Nat.beq_eq, Bool.not_eq_true] at h; simp [h, ih]; rfl

View File

@@ -62,6 +62,8 @@ protected theorem le_total (a b : Int) : a ≤ b b ≤ a :=
let k, (hk : m + k = n) := Nat.le.dest h
le.intro k (by rw [ hk]; rfl)
@[simp] theorem ofNat_zero_le (n : Nat) : 0 (n : Int) := ofNat_le.2 n.zero_le
theorem eq_ofNat_of_zero_le {a : Int} (h : 0 a) : n : Nat, a = n := by
have t := le.dest_sub h; rwa [Int.sub_zero] at t
@@ -86,12 +88,8 @@ theorem lt.dest {a b : Int} (h : a < b) : ∃ n : Nat, a + Nat.succ n = b :=
@[deprecated natCast_pos (since := "2025-05-13"), simp high]
theorem ofNat_pos {n : Nat} : 0 < (n : Int) 0 < n := ofNat_lt
@[simp]
theorem natCast_nonneg (n : Nat) : 0 (n : Int) := _
@[deprecated natCast_nonneg (since := "2025-10-26")]
theorem ofNat_zero_le (n : Nat) : 0 (n : Int) := ofNat_le.2 n.zero_le
@[deprecated natCast_nonneg (since := "2025-05-13")]
theorem ofNat_nonneg (n : Nat) : 0 (n : Int) := _
@@ -236,10 +234,13 @@ theorem eq_natAbs_of_nonneg {a : Int} (h : 0 ≤ a) : a = natAbs a := by
let n, e := eq_ofNat_of_zero_le h
rw [e]; rfl
@[deprecated eq_natAbs_of_nonneg (since := "2025-03-11")]
abbrev eq_natAbs_of_zero_le := @eq_natAbs_of_nonneg
theorem le_natAbs {a : Int} : a natAbs a :=
match Int.le_total 0 a with
| .inl h => by rw [eq_natAbs_of_nonneg h]; apply Int.le_refl
| .inr h => Int.le_trans h (natCast_nonneg _)
| .inr h => Int.le_trans h (ofNat_zero_le _)
@[simp] theorem negSucc_lt_zero (n : Nat) : -[n+1] < 0 :=
Int.not_le.1 fun h => let _, h := eq_ofNat_of_zero_le h; nomatch h
@@ -377,15 +378,6 @@ protected theorem le_iff_lt_add_one {a b : Int} : a ≤ b ↔ a < b + 1 := by
@[grind =] protected theorem max_def (n m : Int) : max n m = if n m then m else n := rfl
end Int
namespace Lean.Meta.Grind.Lia
scoped grind_pattern Int.min_def => min n m
scoped grind_pattern Int.max_def => max n m
end Lean.Meta.Grind.Lia
namespace Int
@[simp] protected theorem neg_min_neg (a b : Int) : min (-a) (-b) = -max a b := by
rw [Int.min_def, Int.max_def]
simp
@@ -476,10 +468,10 @@ protected theorem max_lt {a b c : Int} : max a b < c ↔ a < c ∧ b < c := by
simpa using Int.max_le (a := a + 1) (b := b + 1) (c := c)
@[simp] theorem ofNat_max_zero (n : Nat) : (max (n : Int) 0) = n := by
rw [Int.max_eq_left (natCast_nonneg n)]
rw [Int.max_eq_left (ofNat_zero_le n)]
@[simp] theorem zero_max_ofNat (n : Nat) : (max 0 (n : Int)) = n := by
rw [Int.max_eq_right (natCast_nonneg n)]
rw [Int.max_eq_right (ofNat_zero_le n)]
@[simp] theorem negSucc_max_zero (n : Nat) : (max (Int.negSucc n) 0) = 0 := by
rw [Int.max_eq_right (negSucc_le_zero _)]
@@ -562,8 +554,8 @@ protected theorem mul_le_mul_of_nonpos_left {a b c : Int}
@[simp, norm_cast] theorem natAbs_natCast (n : Nat) : natAbs n = n := rfl
@[deprecated natAbs_natCast (since := "2025-10-26")]
theorem natAbs_cast (n : Nat) : natAbs n = n := rfl
@[deprecated natAbs_natCast (since := "2025-04-16")]
theorem natAbs_ofNat (n : Nat) : natAbs n = n := natAbs_natCast n
/-
TODO: rename `natAbs_ofNat'` to `natAbs_ofNat` once the current deprecated alias
@@ -642,7 +634,7 @@ theorem eq_zero_of_dvd_of_natAbs_lt_natAbs {d n : Int} (h : d n) (h₁ : n.n
/-! ### toNat -/
theorem toNat_eq_max : a : Int, (toNat a : Int) = max a 0
| (n : Nat) => (Int.max_eq_left (natCast_nonneg n)).symm
| (n : Nat) => (Int.max_eq_left (ofNat_zero_le n)).symm
| -[n+1] => (Int.max_eq_right (Int.le_of_lt (negSucc_lt_zero n))).symm
@[simp] theorem toNat_zero : (0 : Int).toNat = 0 := rfl
@@ -654,11 +646,17 @@ theorem toNat_of_nonneg {a : Int} (h : 0 ≤ a) : (toNat a : Int) = a := by
@[simp] theorem toNat_natCast (n : Nat) : toNat n = n := rfl
@[deprecated toNat_natCast (since := "2025-04-16")]
theorem toNat_ofNat (n : Nat) : toNat n = n := rfl
@[simp] theorem toNat_negSucc (n : Nat) : (Int.negSucc n).toNat = 0 := by
simp [toNat]
@[simp] theorem toNat_natCast_add_one {n : Nat} : ((n : Int) + 1).toNat = n + 1 := rfl
@[deprecated toNat_natCast_add_one (since := "2025-04-16")]
theorem toNat_ofNat_add_one {n : Nat} : ((n : Int) + 1).toNat = n + 1 := toNat_natCast_add_one
@[simp] theorem ofNat_toNat (a : Int) : (a.toNat : Int) = max a 0 := by
match a with
| (n : Nat) => simp
@@ -719,6 +717,9 @@ theorem mem_toNat? : ∀ {a : Int} {n : Nat}, toNat? a = some n ↔ a = n
| (m : Nat), n => by simp [toNat?, Int.ofNat_inj]
| -[m+1], n => by constructor <;> nofun
@[deprecated mem_toNat? (since := "2025-03-11")]
abbrev mem_toNat' := @mem_toNat?
/-! ## Order properties of the integers -/
protected theorem le_of_not_le {a b : Int} : ¬ a b b a := (Int.le_total a b).resolve_left
@@ -727,7 +728,7 @@ protected theorem le_of_not_le {a b : Int} : ¬ a ≤ b → b ≤ a := (Int.le_t
simp only [Int.not_lt, iff_false]; constructor
theorem eq_negSucc_of_lt_zero : {a : Int}, a < 0 n : Nat, a = -[n+1]
| ofNat _, h => absurd h (Int.not_lt.2 (natCast_nonneg _))
| ofNat _, h => absurd h (Int.not_lt.2 (ofNat_zero_le _))
| -[n+1], _ => n, rfl
protected theorem lt_of_add_lt_add_left {a b c : Int} (h : a + b < a + c) : b < c := by
@@ -795,10 +796,10 @@ theorem add_one_le_iff {a b : Int} : a + 1 ≤ b ↔ a < b := .rfl
theorem lt_add_one_iff {a b : Int} : a < b + 1 a b := Int.add_le_add_iff_right _
@[simp] theorem succ_ofNat_pos (n : Nat) : 0 < (n : Int) + 1 :=
lt_add_one_iff.mpr (natCast_nonneg _)
lt_add_one_iff.mpr (ofNat_zero_le _)
theorem not_ofNat_neg (n : Nat) : ¬((n : Int) < 0) :=
Int.not_lt.mpr (natCast_nonneg ..)
Int.not_lt.mpr (ofNat_zero_le ..)
theorem le_add_one {a b : Int} (h : a b) : a b + 1 :=
Int.le_of_lt (Int.lt_add_one_iff.2 h)
@@ -1249,11 +1250,7 @@ protected theorem neg_of_mul_pos_right {a b : Int}
@[simp] theorem sign_one : sign 1 = 1 := rfl
theorem sign_neg_one : sign (-1) = -1 := rfl
@[simp] theorem sign_natCast_add_one (n : Nat) : sign (n + 1) = 1 := rfl
@[deprecated sign_natCast_add_one (since := "2025-10-26")]
theorem sign_of_add_one (x : Nat) : Int.sign (x + 1) = 1 := rfl
@[simp] theorem sign_of_add_one (x : Nat) : Int.sign (x + 1) = 1 := rfl
@[simp] theorem sign_negSucc (x : Nat) : Int.sign (Int.negSucc x) = -1 := rfl
theorem natAbs_sign (z : Int) : z.sign.natAbs = if z = 0 then 0 else 1 :=
@@ -1262,9 +1259,17 @@ theorem natAbs_sign (z : Int) : z.sign.natAbs = if z = 0 then 0 else 1 :=
theorem natAbs_sign_of_ne_zero {z : Int} (hz : z 0) : z.sign.natAbs = 1 := by
rw [Int.natAbs_sign, if_neg hz]
@[deprecated natAbs_sign_of_ne_zero (since := "2025-04-16")]
theorem natAbs_sign_of_nonzero {z : Int} (hz : z 0) : z.sign.natAbs = 1 :=
natAbs_sign_of_ne_zero hz
theorem sign_natCast_of_ne_zero {n : Nat} (hn : n 0) : Int.sign n = 1 :=
match n, Nat.exists_eq_succ_of_ne_zero hn with
| _, n, rfl => Int.sign_natCast_add_one n
| _, n, rfl => Int.sign_of_add_one n
@[deprecated sign_natCast_of_ne_zero (since := "2025-04-16")]
theorem sign_ofNat_of_nonzero {n : Nat} (hn : n 0) : Int.sign n = 1 :=
sign_natCast_of_ne_zero hn
@[simp] theorem sign_neg (z : Int) : Int.sign (-z) = -Int.sign z := by
match z with | 0 | succ _ | -[_+1] => rfl
@@ -1320,6 +1325,8 @@ theorem neg_of_sign_eq_neg_one : ∀ {a : Int}, sign a = -1 → a < 0
exact Int.le_add_one (natCast_nonneg _)
| .negSucc _ => simp +decide [sign]
@[deprecated sign_nonneg_iff (since := "2025-03-11")] abbrev sign_nonneg := @sign_nonneg_iff
@[simp] theorem sign_pos_iff : 0 < sign x 0 < x := by
match x with
| 0
@@ -1402,6 +1409,9 @@ theorem natAbs_add_of_nonpos {a b : Int} (ha : a ≤ 0) (hb : b ≤ 0) :
natAbs_add_of_nonneg (Int.neg_nonneg_of_nonpos ha) (Int.neg_nonneg_of_nonpos hb),
natAbs_neg (-a), natAbs_neg (-b)]
@[deprecated negSucc_eq (since := "2025-03-11")]
theorem negSucc_eq' (m : Nat) : -[m+1] = -m - 1 := by simp only [negSucc_eq, Int.neg_add]; rfl
theorem natAbs_lt_natAbs_of_nonneg_of_lt {a b : Int}
(w₁ : 0 a) (w₂ : a < b) : a.natAbs < b.natAbs :=
match a, b, eq_ofNat_of_zero_le w₁, eq_ofNat_of_zero_le (Int.le_trans w₁ (Int.le_of_lt w₂)) with
@@ -1410,6 +1420,9 @@ theorem natAbs_lt_natAbs_of_nonneg_of_lt {a b : Int}
theorem natAbs_eq_iff_mul_eq_zero : natAbs a = n (a - n) * (a + n) = 0 := by
rw [natAbs_eq_iff, Int.mul_eq_zero, Int.sub_neg, Int.sub_eq_zero, Int.sub_eq_zero]
@[deprecated natAbs_eq_iff_mul_eq_zero (since := "2025-03-11")]
abbrev eq_natAbs_iff_mul_eq_zero := @natAbs_eq_iff_mul_eq_zero
instance instIsLinearOrder : IsLinearOrder Int := by
apply IsLinearOrder.of_le
case le_antisymm => constructor; apply Int.le_antisymm

View File

@@ -14,20 +14,9 @@ namespace Int
/-! # pow -/
@[simp, norm_cast]
theorem natCast_pow (m n : Nat) : (m ^ n : Nat) = (m : Int) ^ n := rfl
theorem negSucc_pow (m n : Nat) : (-[m+1] : Int) ^ n = if n % 2 = 0 then Int.ofNat (m.succ ^ n) else Int.negOfNat (m.succ ^ n) := rfl
@[simp] protected theorem pow_zero (m : Int) : m ^ 0 = 1 := by cases m <;> simp [ natCast_pow, negSucc_pow]
protected theorem pow_succ (m : Int) (n : Nat) : m ^ n.succ = m ^ n * m := by
rcases m with _ | a
· rfl
· simp only [negSucc_pow, Nat.succ_mod_succ_eq_zero_iff, Nat.reduceAdd, Nat.mod_two_ne_zero,
Nat.pow_succ, ofNat_eq_natCast, @negOfNat_eq (_ * _), ite_not, apply_ite (· * -[a+1]),
ofNat_mul_negSucc, negOfNat_mul_negSucc]
@[simp] protected theorem pow_zero (b : Int) : b^0 = 1 := rfl
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]
@@ -43,46 +32,33 @@ protected theorem zero_pow {n : Nat} (h : n ≠ 0) : (0 : Int) ^ n = 0 := by
protected theorem one_pow {n : Nat} : (1 : Int) ^ n = 1 := by
induction n with simp_all [Int.pow_succ]
protected theorem mul_pow {a b : Int} {n : Nat} : (a * b) ^ n = a ^ n * b ^ n := by
induction n with
| zero => simp
| succ n ih =>
rw [Int.pow_succ, Int.pow_succ, Int.pow_succ, ih, Int.mul_assoc, Int.mul_assoc,
Int.mul_left_comm (b^n)]
protected theorem pow_one (a : Int) : a ^ 1 = a := by
rw [Int.pow_succ, Int.pow_zero, Int.one_mul]
protected theorem pow_mul {a : Int} {n m : Nat} : a ^ (n * m) = (a ^ n) ^ m := by
induction m with
| zero => simp
| succ m ih =>
rw [Int.pow_succ, Nat.mul_add_one, Int.pow_add, ih]
protected theorem pow_pos {n : Int} {m : Nat} : 0 < n 0 < n ^ m := by
induction m with
| zero => simp
| succ m ih =>
simp only [Int.pow_succ]
exact fun h => Int.mul_pos (ih h) h
| succ m ih => exact fun h => Int.mul_pos (ih h) h
protected theorem pow_nonneg {n : Int} {m : Nat} : 0 n 0 n ^ m := by
induction m with
| zero => simp
| succ m ih =>
simp only [Int.pow_succ]
exact fun h => Int.mul_nonneg (ih h) h
| succ m ih => exact fun h => Int.mul_nonneg (ih h) h
protected theorem pow_ne_zero {n : Int} {m : Nat} : n 0 n ^ m 0 := by
induction m with
| zero => simp
| succ m ih =>
simp only [Int.pow_succ]
exact fun h => Int.mul_ne_zero (ih h) h
| 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 _)
instance {n : Int} : NeZero (n^0) := by simp
-- This can't be removed until the next update-stage0
@[deprecated Nat.pow_pos (since := "2025-02-17")]
abbrev _root_.Nat.pos_pow_of_pos := @Nat.pow_pos
@[simp, norm_cast]
protected theorem natCast_pow (b n : Nat) : ((b^n : Nat) : Int) = (b : Int) ^ n := by
match n with
| 0 => rfl
| n + 1 =>
simp only [Nat.pow_succ, Int.pow_succ, Int.natCast_mul, Int.natCast_pow _ n]
@[simp]
protected theorem two_pow_pred_sub_two_pow {w : Nat} (h : 0 < w) :
@@ -105,7 +81,7 @@ theorem pow_lt_pow_of_lt {a : Int} {b c : Nat} (ha : 1 < a) (hbc : b < c):
omega
@[simp] theorem natAbs_pow (n : Int) : (k : Nat) (n ^ k).natAbs = n.natAbs ^ k
| 0 => by simp
| 0 => rfl
| k + 1 => by rw [Int.pow_succ, natAbs_mul, natAbs_pow, Nat.pow_succ]
theorem toNat_pow_of_nonneg {x : Int} (h : 0 x) (k : Nat) : (x ^ k).toNat = x.toNat ^ k := by
@@ -114,21 +90,4 @@ theorem toNat_pow_of_nonneg {x : Int} (h : 0 ≤ x) (k : Nat) : (x ^ k).toNat =
| succ k ih =>
rw [Int.pow_succ, Int.toNat_mul (Int.pow_nonneg h) h, ih, Nat.pow_succ]
protected theorem sq_nonnneg (m : Int) : 0 m ^ 2 := by
rw [Int.pow_succ, Int.pow_one]
cases m
· apply Int.mul_nonneg <;> simp
· apply Int.mul_nonneg_of_nonpos_of_nonpos <;> exact negSucc_le_zero _
protected theorem pow_nonneg_of_even {m : Int} {n : Nat} (h : n % 2 = 0) : 0 m ^ n := by
rw [ Nat.mod_add_div n 2, h, Nat.zero_add, Int.pow_mul]
apply Int.pow_nonneg
exact Int.sq_nonnneg m
protected theorem neg_pow {m : Int} {n : Nat} : (-m)^n = (-1)^(n % 2) * m^n := by
rw [Int.neg_eq_neg_one_mul, Int.mul_pow]
rw (occs := [1]) [ Nat.mod_add_div n 2]
rw [Int.pow_add, Int.pow_mul]
simp [Int.one_pow]
end Int

View File

@@ -9,7 +9,6 @@ prelude
public import Init.Data.Iterators.Basic
public import Init.Data.Iterators.PostconditionMonad
public import Init.Data.Iterators.Consumers
public import Init.Data.Iterators.Producers
public import Init.Data.Iterators.Combinators
public import Init.Data.Iterators.Lemmas
public import Init.Data.Iterators.ToIterator

View File

@@ -678,7 +678,6 @@ Given this typeclass, termination proofs for well-founded recursion over an iter
`it.finitelyManySteps` as a termination measure.
-/
class Finite (α : Type w) (m : Type w Type w') {β : Type w} [Iterator α m β] : Prop where
/-- The relation of plausible successors is well-founded. -/
wf : WellFounded (IterM.IsPlausibleSuccessorOf (α := α) (m := m))
theorem Finite.wf_of_id {α : Type w} {β : Type w} [Iterator α Id β] [Finite α Id] :
@@ -798,7 +797,6 @@ Given this typeclass, termination proofs for well-founded recursion over an iter
`it.finitelyManySkips` as a termination measure.
-/
class Productive (α m) {β} [Iterator α m β] : Prop where
/-- The relation of plausible successors during skips is well-founded. -/
wf : WellFounded (IterM.IsPlausibleSkipSuccessorOf (α := α) (m := m))
/--
@@ -819,24 +817,6 @@ def IterM.TerminationMeasures.Productive.Rel
TerminationMeasures.Productive α m TerminationMeasures.Productive α m Prop :=
Relation.TransGen <| InvImage IterM.IsPlausibleSkipSuccessorOf IterM.TerminationMeasures.Productive.it
theorem IterM.TerminationMeasures.Finite.Rel.of_productive
{α : Type w} {m : Type w Type w'} {β : Type w} [Iterator α m β] {a b : Finite α m} :
Productive.Rel a.it b.it Finite.Rel a b := by
generalize ha' : Productive.mk a.it = a'
generalize hb' : Productive.mk b.it = b'
have ha : a = a'.it := by simp [ ha']
have hb : b = b'.it := by simp [ hb']
rw [ha, hb]
clear ha hb ha' hb' a b
rw [Productive.Rel, Finite.Rel]
intro h
induction h
· rename_i ih
exact .single _, rfl, ih
· rename_i hab ih
refine .trans ih ?_
exact .single _, rfl, hab
instance {α : Type w} {m : Type w Type w'} {β : Type w} [Iterator α m β]
[Productive α m] : WellFoundedRelation (IterM.TerminationMeasures.Productive α m) where
rel := IterM.TerminationMeasures.Productive.Rel

View File

@@ -9,5 +9,4 @@ prelude
public import Init.Data.Iterators.Combinators.Monadic
public import Init.Data.Iterators.Combinators.FilterMap
public import Init.Data.Iterators.Combinators.FlatMap
public import Init.Data.Iterators.Combinators.Take
public import Init.Data.Iterators.Combinators.ULift

View File

@@ -8,5 +8,4 @@ module
prelude
public import Init.Data.Iterators.Combinators.Monadic.FilterMap
public import Init.Data.Iterators.Combinators.Monadic.FlatMap
public import Init.Data.Iterators.Combinators.Monadic.Take
public import Init.Data.Iterators.Combinators.Monadic.ULift

View File

@@ -106,6 +106,16 @@ instance Attach.instIteratorLoopPartial {α β : Type w} {m : Type w → Type w'
IteratorLoopPartial (Attach α m P) m n :=
.defaultImplementation
instance {α β : Type w} {m : Type w Type w'} [Monad m]
{P : β Prop} [Iterator α m β] [IteratorSize α m] :
IteratorSize (Attach α m P) m where
size it := IteratorSize.size it.internalState.inner
instance {α β : Type w} {m : Type w Type w'} [Monad m]
{P : β Prop} [Iterator α m β] [IteratorSizePartial α m] :
IteratorSizePartial (Attach α m P) m where
size it := IteratorSizePartial.size it.internalState.inner
end Types
/--

View File

@@ -604,4 +604,30 @@ def IterM.filter {α β : Type w} {m : Type w → Type w'} [Iterator α m β] [M
(f : β Bool) (it : IterM (α := α) m β) :=
(it.filterMap (fun b => if f b then some b else none) : IterM m β)
instance {α β γ : Type w} {m : Type w Type w'}
{n : Type w Type w''} [Monad n] [Iterator α m β] {lift : α : Type w m α n α}
{f : β PostconditionT n (Option γ)} [Finite α m] :
IteratorSize (FilterMap α m n lift f) n :=
.defaultImplementation
instance {α β γ : Type w} {m : Type w Type w'}
{n : Type w Type w''} [Monad n] [Iterator α m β] {lift : α : Type w m α n α}
{f : β PostconditionT n (Option γ)} :
IteratorSizePartial (FilterMap α m n lift f) n :=
.defaultImplementation
instance {α β γ : Type w} {m : Type w Type w'}
{n : Type w Type w''} [Monad n] [Iterator α m β]
{lift : α : Type w m α n α}
{f : β PostconditionT n γ} [IteratorSize α m] :
IteratorSize (Map α m n lift f) n where
size it := lift (IteratorSize.size it.internalState.inner)
instance {α β γ : Type w} {m : Type w Type w'}
{n : Type w Type w''} [Monad n] [Iterator α m β]
{lift : α : Type w m α n α}
{f : β PostconditionT n γ} [IteratorSizePartial α m] :
IteratorSizePartial (Map α m n lift f) n where
size it := lift (IteratorSizePartial.size it.internalState.inner)
end Std.Iterators

View File

@@ -1,223 +0,0 @@
/-
Copyright (c) 2025 Lean FRO, LLC. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Paul Reichert
-/
module
prelude
public import Init.Data.Nat.Lemmas
public import Init.Data.Iterators.Consumers.Monadic.Collect
public import Init.Data.Iterators.Consumers.Monadic.Loop
public import Init.Data.Iterators.Internal.Termination
@[expose] public section
/-!
This module provides the iterator combinator `IterM.take`.
-/
namespace Std.Iterators
variable {α : Type w} {m : Type w Type w'} {β : Type w}
/--
The internal state of the `IterM.take` iterator combinator.
-/
@[unbox]
structure Take (α : Type w) (m : Type w Type w') {β : Type w} [Iterator α m β] where
/--
Internal implementation detail of the iterator library.
Caution: For `take n`, `countdown` is `n + 1`.
If `countdown` is zero, the combinator only terminates when `inner` terminates.
-/
countdown : Nat
/-- Internal implementation detail of the iterator library -/
inner : IterM (α := α) m β
/--
Internal implementation detail of the iterator library.
This proof term ensures that a `take` always produces a finite iterator from a productive one.
-/
finite : countdown > 0 Finite α m
/--
Given an iterator `it` and a natural number `n`, `it.take n` is an iterator that outputs
up to the first `n` of `it`'s values in order and then terminates.
**Marble diagram:**
```text
it ---a----b---c--d-e--
it.take 3 ---a----b---c⊥
it ---a--
it.take 3 ---a--
```
**Termination properties:**
* `Finite` instance: only if `it` is productive
* `Productive` instance: only if `it` is productive
**Performance:**
This combinator incurs an additional O(1) cost with each output of `it`.
-/
@[always_inline, inline]
def IterM.take [Iterator α m β] (n : Nat) (it : IterM (α := α) m β) :=
toIterM (Take.mk (n + 1) it (Or.inl <| Nat.zero_lt_succ _)) m β
/--
This combinator is only useful for advanced use cases.
Given a finite iterator `it`, returns an iterator that behaves exactly like `it` but is of the same
type as `it.take n`.
**Marble diagram:**
```text
it ---a----b---c--d-e--
it.toTake ---a----b---c--d-e--
```
**Termination properties:**
* `Finite` instance: always
* `Productive` instance: always
**Performance:**
This combinator incurs an additional O(1) cost with each output of `it`.
-/
@[always_inline, inline]
def IterM.toTake [Iterator α m β] [Finite α m] (it : IterM (α := α) m β) :=
toIterM (Take.mk 0 it (Or.inr inferInstance)) m β
theorem IterM.take.surjective_of_zero_lt {α : Type w} {m : Type w Type w'} {β : Type w}
[Iterator α m β] (it : IterM (α := Take α m) m β) (h : 0 < it.internalState.countdown) :
(it₀ : IterM (α := α) m β) (k : Nat), it = it₀.take k := by
refine it.internalState.inner, it.internalState.countdown - 1, ?_
simp only [take, Nat.sub_add_cancel (m := 1) (n := it.internalState.countdown) (by omega)]
rfl
inductive Take.PlausibleStep [Iterator α m β] (it : IterM (α := Take α m) m β) :
(step : IterStep (IterM (α := Take α m) m β) β) Prop where
| yield : {it' out}, it.internalState.inner.IsPlausibleStep (.yield it' out)
(h : it.internalState.countdown 1) PlausibleStep it (.yield it.internalState.countdown - 1, it', it.internalState.finite.imp_left (by omega) out)
| skip : {it'}, it.internalState.inner.IsPlausibleStep (.skip it')
it.internalState.countdown 1 PlausibleStep it (.skip it.internalState.countdown, it', it.internalState.finite)
| done : it.internalState.inner.IsPlausibleStep .done PlausibleStep it .done
| depleted : it.internalState.countdown = 1
PlausibleStep it .done
@[always_inline, inline]
instance Take.instIterator [Monad m] [Iterator α m β] : Iterator (Take α m) m β where
IsPlausibleStep := Take.PlausibleStep
step it :=
if h : it.internalState.countdown = 1 then
pure <| .deflate <| .done (.depleted h)
else do
match ( it.internalState.inner.step).inflate with
| .yield it' out h' =>
pure <| .deflate <| .yield it.internalState.countdown - 1, it', (it.internalState.finite.imp_left (by omega)) out (.yield h' h)
| .skip it' h' => pure <| .deflate <| .skip it.internalState.countdown, it', it.internalState.finite (.skip h' h)
| .done h' => pure <| .deflate <| .done (.done h')
def Take.Rel (m : Type w Type w') [Monad m] [Iterator α m β] [Productive α m] :
IterM (α := Take α m) m β IterM (α := Take α m) m β Prop :=
open scoped Classical in
if _ : Finite α m then
InvImage (Prod.Lex Nat.lt_wfRel.rel IterM.TerminationMeasures.Finite.Rel)
(fun it => (it.internalState.countdown, it.internalState.inner.finitelyManySteps))
else
InvImage (Prod.Lex Nat.lt_wfRel.rel IterM.TerminationMeasures.Productive.Rel)
(fun it => (it.internalState.countdown, it.internalState.inner.finitelyManySkips))
theorem Take.rel_of_countdown [Monad m] [Iterator α m β] [Productive α m]
{it it' : IterM (α := Take α m) m β}
(h : it'.internalState.countdown < it.internalState.countdown) : Take.Rel m it' it := by
simp only [Rel]
split <;> exact Prod.Lex.left _ _ h
theorem Take.rel_of_inner [Monad m] [Iterator α m β] [Productive α m] {remaining : Nat}
{it it' : IterM (α := α) m β}
(h : it'.finitelyManySkips.Rel it.finitelyManySkips) :
Take.Rel m (it'.take remaining) (it.take remaining) := by
simp only [Rel]
split
· exact Prod.Lex.right _ (.of_productive h)
· exact Prod.Lex.right _ h
theorem Take.rel_of_zero_of_inner [Monad m] [Iterator α m β]
{it it' : IterM (α := Take α m) m β}
(h : it.internalState.countdown = 0) (h' : it'.internalState.countdown = 0)
(h'' : haveI := it.internalState.finite.resolve_left (by omega); it'.internalState.inner.finitelyManySteps.Rel it.internalState.inner.finitelyManySteps) :
haveI := it.internalState.finite.resolve_left (by omega)
Take.Rel m it' it := by
haveI := it.internalState.finite.resolve_left (by omega)
simp only [Rel, this, reduceDIte, InvImage, h, h']
exact Prod.Lex.right _ h''
private def Take.instFinitenessRelation [Monad m] [Iterator α m β]
[Productive α m] :
FinitenessRelation (Take α m) m where
rel := Take.Rel m
wf := by
rw [Rel]
split
all_goals
apply InvImage.wf
refine fun (a, b) => Prod.lexAccessible (WellFounded.apply ?_ a) (WellFounded.apply ?_) b
· exact WellFoundedRelation.wf
· exact WellFoundedRelation.wf
subrelation {it it'} h := by
obtain step, h, h' := h
cases h'
case yield it' out k h' h'' =>
cases h
cases it.internalState.finite
· apply rel_of_countdown
simp only
omega
· by_cases h : it.internalState.countdown = 0
· simp only [h, Nat.zero_le, Nat.sub_eq_zero_of_le]
apply rel_of_zero_of_inner h rfl
exact .single _, rfl, h'
· apply rel_of_countdown
simp only
omega
case skip it' out k h' h'' =>
cases h
by_cases h : it.internalState.countdown = 0
· simp only [h]
apply Take.rel_of_zero_of_inner h rfl
exact .single _, rfl, h'
· obtain it, k, rfl := IterM.take.surjective_of_zero_lt it (by omega)
apply Take.rel_of_inner
exact IterM.TerminationMeasures.Productive.rel_of_skip h'
case done _ =>
cases h
case depleted _ =>
cases h
instance Take.instFinite [Monad m] [Iterator α m β] [Productive α m] :
Finite (Take α m) m :=
by exact Finite.of_finitenessRelation instFinitenessRelation
instance Take.instIteratorCollect {n : Type w Type w'} [Monad m] [Monad n] [Iterator α m β] :
IteratorCollect (Take α m) m n :=
.defaultImplementation
instance Take.instIteratorCollectPartial {n : Type w Type w'} [Monad m] [Monad n] [Iterator α m β] :
IteratorCollectPartial (Take α m) m n :=
.defaultImplementation
instance Take.instIteratorLoop {n : Type x Type x'} [Monad m] [Monad n] [Iterator α m β] :
IteratorLoop (Take α m) m n :=
.defaultImplementation
instance Take.instIteratorLoopPartial [Monad m] [Monad n] [Iterator α m β] :
IteratorLoopPartial (Take α m) m n :=
.defaultImplementation
end Std.Iterators

View File

@@ -74,7 +74,7 @@ variable {α : Type u} {m : Type u → Type u'} {n : Type max u v → Type v'}
/--
Transforms a step of the base iterator into a step of the `uLift` iterator.
-/
@[always_inline, inline, expose]
@[always_inline, inline]
def Types.ULiftIterator.Monadic.modifyStep (step : IterStep (IterM (α := α) m β) β) :
IterStep (IterM (α := ULiftIterator.{v} α m n β lift) n (ULift.{v} β)) (ULift.{v} β) :=
match step with
@@ -140,6 +140,15 @@ instance Types.ULiftIterator.instIteratorCollectPartial {o} [Monad n] [Monad o]
IteratorCollectPartial (ULiftIterator α m n β lift) n o :=
.defaultImplementation
instance Types.ULiftIterator.instIteratorSize [Monad n] [Iterator α m β] [IteratorSize α m]
[Finite (ULiftIterator α m n β lift) n] :
IteratorSize (ULiftIterator α m n β lift) n :=
.defaultImplementation
instance Types.ULiftIterator.instIteratorSizePartial [Monad n] [Iterator α m β] [IteratorSize α m] :
IteratorSizePartial (ULiftIterator α m n β lift) n :=
.defaultImplementation
/--
Transforms an `m`-monadic iterator with values in `β` into an `n`-monadic iterator with
values in `ULift β`. Requires a `MonadLift m (ULiftT n)` instance.

View File

@@ -1,70 +0,0 @@
/-
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.Iterators.Combinators.Monadic.Take
@[expose] public section
namespace Std.Iterators
/--
Given an iterator `it` and a natural number `n`, `it.take n` is an iterator that outputs
up to the first `n` of `it`'s values in order and then terminates.
**Marble diagram:**
```text
it ---a----b---c--d-e--
it.take 3 ---a----b---c⊥
it ---a--
it.take 3 ---a--
```
**Termination properties:**
* `Finite` instance: only if `it` is productive
* `Productive` instance: only if `it` is productive
**Performance:**
This combinator incurs an additional O(1) cost with each output of `it`.
-/
@[always_inline, inline]
def Iter.take {α : Type w} {β : Type w} [Iterator α Id β] (n : Nat) (it : Iter (α := α) β) :
Iter (α := Take α Id) β :=
it.toIterM.take n |>.toIter
/--
This combinator is only useful for advanced use cases.
Given a finite iterator `it`, returns an iterator that behaves exactly like `it` but is of the same
type as `it.take n`.
**Marble diagram:**
```text
it ---a----b---c--d-e--
it.toTake ---a----b---c--d-e--
```
**Termination properties:**
* `Finite` instance: always
* `Productive` instance: always
**Performance:**
This combinator incurs an additional O(1) cost with each output of `it`.
-/
@[always_inline, inline]
def Iter.toTake {α : Type w} {β : Type w} [Iterator α Id β] [Finite α Id] (it : Iter (α := α) β) :
Iter (α := Take α Id) β :=
it.toIterM.toTake.toIter
end Std.Iterators

View File

@@ -9,8 +9,6 @@ prelude
public import Init.Data.Iterators.Consumers.Collect
public import Init.Data.Iterators.Consumers.Monadic.Loop
set_option linter.missingDocs true
public section
/-!
@@ -48,9 +46,6 @@ instance (α : Type w) (β : Type w) (n : Type x → Type x') [Monad n]
haveI : ForIn' n (Iter (α := α) β) β _ := Iter.instForIn'
instForInOfForIn'
/--
An implementation of `for h : ... in ... do ...` notation for partial iterators.
-/
@[always_inline, inline]
def Iter.Partial.instForIn' {α : Type w} {β : Type w} {n : Type x Type x'} [Monad n]
[Iterator α Id β] [IteratorLoopPartial α Id n] :
@@ -68,12 +63,12 @@ instance (α : Type w) (β : Type w) (n : Type x → Type x') [Monad n]
instForInOfForIn'
instance {m : Type x Type x'}
{α : Type w} {β : Type w} [Iterator α Id β] [Finite α Id] [IteratorLoop α Id m] [Monad m] :
{α : Type w} {β : Type w} [Iterator α Id β] [Finite α Id] [IteratorLoop α Id m] :
ForM m (Iter (α := α) β) β where
forM it f := forIn it PUnit.unit (fun out _ => do f out; return .yield .unit)
instance {m : Type x Type x'}
{α : Type w} {β : Type w} [Iterator α Id β] [Finite α Id] [IteratorLoopPartial α Id m] [Monad m] :
{α : Type w} {β : Type w} [Iterator α Id β] [Finite α Id] [IteratorLoopPartial α Id m] :
ForM m (Iter.Partial (α := α) β) β where
forM it f := forIn it PUnit.unit (fun out _ => do f out; return .yield .unit)
@@ -207,11 +202,6 @@ def Iter.all {α β : Type w}
(p : β Bool) (it : Iter (α := α) β) : Bool :=
(it.allM (fun x => pure (f := Id) (p x))).run
/--
Steps through the iterator until the monadic function `f` returns `some` for an element, at which
point iteration stops and the result of `f` is returned. If the iterator is completely consumed
without `f` returning `some`, then the result is `none`.
-/
@[inline]
def Iter.findSomeM? {α β : Type w} {γ : Type x} {m : Type x Type w'} [Monad m] [Iterator α Id β]
[IteratorLoop α Id m] [Finite α Id] (it : Iter (α := α) β) (f : β m (Option γ)) :
@@ -221,7 +211,7 @@ def Iter.findSomeM? {α β : Type w} {γ : Type x} {m : Type x → Type w'} [Mon
| none => return .yield none
| some fx => return .done (some fx))
@[inline, inherit_doc Iter.findSomeM?]
@[inline]
def Iter.Partial.findSomeM? {α β : Type w} {γ : Type x} {m : Type x Type w'} [Monad m]
[Iterator α Id β] [IteratorLoopPartial α Id m] (it : Iter.Partial (α := α) β)
(f : β m (Option γ)) :
@@ -231,100 +221,62 @@ def Iter.Partial.findSomeM? {α β : Type w} {γ : Type x} {m : Type x → Type
| none => return .yield none
| some fx => return .done (some fx))
/--
Steps through the iterator until `f` returns `some` for an element, at which point iteration stops
and the result of `f` is returned. If the iterator is completely consumed without `f` returning
`some`, then the result is `none`.
-/
@[inline]
def Iter.findSome? {α β : Type w} {γ : Type x} [Iterator α Id β]
[IteratorLoop α Id Id] [Finite α Id] (it : Iter (α := α) β) (f : β Option γ) :
Option γ :=
Id.run (it.findSomeM? (pure <| f ·))
@[inline, inherit_doc Iter.findSome?]
@[inline]
def Iter.Partial.findSome? {α β : Type w} {γ : Type x} [Iterator α Id β]
[IteratorLoopPartial α Id Id] (it : Iter.Partial (α := α) β) (f : β Option γ) :
Option γ :=
Id.run (it.findSomeM? (pure <| f ·))
/--
Steps through the iterator until an element satisfies the monadic predicate `f`, at which point
iteration stops and the element is returned. If no element satisfies `f`, then the result is
`none`.
-/
@[inline]
def Iter.findM? {α β : Type w} {m : Type w Type w'} [Monad m] [Iterator α Id β]
[IteratorLoop α Id m] [Finite α Id] (it : Iter (α := α) β) (f : β m (ULift Bool)) :
m (Option β) :=
it.findSomeM? (fun x => return if ( f x).down then some x else none)
@[inline, inherit_doc Iter.findM?]
@[inline]
def Iter.Partial.findM? {α β : Type w} {m : Type w Type w'} [Monad m] [Iterator α Id β]
[IteratorLoopPartial α Id m] (it : Iter.Partial (α := α) β) (f : β m (ULift Bool)) :
m (Option β) :=
it.findSomeM? (fun x => return if ( f x).down then some x else none)
/--
Steps through the iterator until an element satisfies `f`, at which point iteration stops and the
element is returned. If no element satisfies `f`, then the result is `none`.
-/
@[inline]
def Iter.find? {α β : Type w} [Iterator α Id β] [IteratorLoop α Id Id]
[Finite α Id] (it : Iter (α := α) β) (f : β Bool) : Option β :=
Id.run (it.findM? (pure <| .up <| f ·))
@[inline, inherit_doc Iter.find?]
@[inline]
def Iter.Partial.find? {α β : Type w} [Iterator α Id β] [IteratorLoopPartial α Id Id]
(it : Iter.Partial (α := α) β) (f : β Bool) : Option β :=
Id.run (it.findM? (pure <| .up <| f ·))
/--
Steps through the whole iterator, counting the number of outputs emitted.
**Performance**:
This function's runtime is linear in the number of steps taken by the iterator.
-/
@[always_inline, inline, expose]
def Iter.count {α : Type w} {β : Type w} [Iterator α Id β] [Finite α Id] [IteratorLoop α Id Id]
@[always_inline, inline, expose, inherit_doc IterM.size]
def Iter.size {α : Type w} {β : Type w} [Iterator α Id β] [IteratorSize α Id]
(it : Iter (α := α) β) : Nat :=
it.toIterM.count.run.down
(IteratorSize.size it.toIterM).run.down
/--
Steps through the whole iterator, counting the number of outputs emitted.
**Performance**:
This function's runtime is linear in the number of steps taken by the iterator.
-/
@[always_inline, inline, expose, deprecated Iter.count (since := "2025-10-29")]
def Iter.size {α : Type w} {β : Type w} [Iterator α Id β] [Finite α Id] [IteratorLoop α Id Id]
@[always_inline, inline, inherit_doc IterM.Partial.size]
def Iter.Partial.size {α : Type w} {β : Type w} [Iterator α Id β] [IteratorSizePartial α Id]
(it : Iter (α := α) β) : Nat :=
it.count
(IteratorSizePartial.size it.toIterM).run.down
/--
Steps through the whole iterator, counting the number of outputs emitted.
`LawfulIteratorSize α m` ensures that the `size` function of an iterator behaves as if it
iterated over the whole iterator, counting its elements and causing all the monadic side effects
of the iterations. This is a fairly strong condition for monadic iterators and it will be false
for many efficient implementations of `size` that compute the size without actually iterating.
**Performance**:
This function's runtime is linear in the number of steps taken by the iterator.
This class is experimental and users of the iterator API should not explicitly depend on it.
-/
@[always_inline, inline, expose]
def Iter.Partial.count {α : Type w} {β : Type w} [Iterator α Id β] [IteratorLoopPartial α Id Id]
(it : Iter.Partial (α := α) β) : Nat :=
it.it.toIterM.allowNontermination.count.run.down
/--
Steps through the whole iterator, counting the number of outputs emitted.
**Performance**:
This function's runtime is linear in the number of steps taken by the iterator.
-/
@[always_inline, inline, expose, deprecated Iter.Partial.count (since := "2025-10-29")]
def Iter.Partial.size {α : Type w} {β : Type w} [Iterator α Id β] [IteratorLoopPartial α Id Id]
(it : Iter.Partial (α := α) β) : Nat :=
it.count
class LawfulIteratorSize (α : Type w) {β : Type w} [Iterator α Id β] [Finite α Id]
[IteratorSize α Id] where
size_eq_size_toArray {it : Iter (α := α) β} : it.size =
haveI : IteratorCollect α Id Id := .defaultImplementation
it.toArray.size
end Std.Iterators

View File

@@ -88,6 +88,27 @@ class IteratorLoopPartial (α : Type w) (m : Type w → Type w') {β : Type w} [
(it : IterM (α := α) m β) γ
((b : β) it.IsPlausibleIndirectOutput b (c : γ) n (ForInStep γ)) n γ
/--
`IteratorSize α m` provides an implementation of the `IterM.size` function.
This class is experimental and users of the iterator API should not explicitly depend on it.
They can, however, assume that consumers that require an instance will work for all iterators
provided by the standard library.
-/
class IteratorSize (α : Type w) (m : Type w Type w') {β : Type w} [Iterator α m β] where
size : IterM (α := α) m β m (ULift Nat)
/--
`IteratorSizePartial α m` provides an implementation of the `IterM.Partial.size` function that
can be used as `it.allowTermination.size`.
This class is experimental and users of the iterator API should not explicitly depend on it.
They can, however, assume that consumers that require an instance will work for all iterators
provided by the standard library.
-/
class IteratorSizePartial (α : Type w) (m : Type w Type w') {β : Type w} [Iterator α m β] where
size : IterM (α := α) m β m (ULift Nat)
end Typeclasses
/-- Internal implementation detail of the iterator library. -/
@@ -247,10 +268,10 @@ This `ForIn'`-style loop construct traverses a finite iterator using an `Iterato
-/
@[always_inline, inline]
def IteratorLoop.finiteForIn' {m : Type w Type w'} {n : Type x Type x'}
{α : Type w} {β : Type w} [Iterator α m β] [Finite α m] [IteratorLoop α m n] [Monad n]
{α : Type w} {β : Type w} [Iterator α m β] [Finite α m] [IteratorLoop α m n]
(lift : γ δ, (γ n δ) m γ n δ) :
ForIn' n (IterM (α := α) m β) β fun it out => it.IsPlausibleIndirectOutput out where
forIn' {γ} it init f :=
forIn' {γ} [Monad n] it init f :=
IteratorLoop.forIn (α := α) (m := m) lift γ (fun _ _ _ => True)
wellFounded_of_finite
it init (fun out h acc => (·, .intro) <$> f out h acc)
@@ -288,13 +309,13 @@ instance {m : Type w → Type w'} {n : Type w → Type w''}
instForInOfForIn'
instance {m : Type w Type w'} {n : Type w Type w''}
{α : Type w} {β : Type w} [Iterator α m β] [Finite α m] [IteratorLoop α m n] [Monad n]
{α : Type w} {β : Type w} [Iterator α m β] [Finite α m] [IteratorLoop α m n]
[MonadLiftT m n] :
ForM n (IterM (α := α) m β) β where
forM it f := forIn it PUnit.unit (fun out _ => do f out; return .yield .unit)
instance {m : Type w Type w'} {n : Type w Type w''}
{α : Type w} {β : Type w} [Iterator α m β] [IteratorLoopPartial α m n] [Monad n]
{α : Type w} {β : Type w} [Iterator α m β] [Finite α m] [IteratorLoopPartial α m n]
[MonadLiftT m n] :
ForM n (IterM.Partial (α := α) m β) β where
forM it f := forIn it PUnit.unit (fun out _ => do f out; return .yield .unit)
@@ -612,58 +633,86 @@ def IterM.Partial.find? {α β : Type w} {m : Type w → Type w'} [Monad m] [Ite
m (Option β) :=
it.findM? (pure <| .up <| f ·)
section Count
section Size
/--
Steps through the whole iterator, counting the number of outputs emitted.
**Performance**:
This function's runtime is linear in the number of steps taken by the iterator.
This is the implementation of the default instance `IteratorSize.defaultImplementation`.
-/
@[always_inline, inline]
def IterM.count {α : Type w} {m : Type w Type w'} {β : Type w} [Iterator α m β] [Finite α m]
[IteratorLoop α m m]
[Monad m] (it : IterM (α := α) m β) : m (ULift Nat) :=
def IterM.DefaultConsumers.size {α : Type w} {m : Type w Type w'} [Monad m] {β : Type w}
[Iterator α m β] [IteratorLoop α m m] [Finite α m] (it : IterM (α := α) m β) :
m (ULift Nat) :=
it.fold (init := .up 0) fun acc _ => .up (acc.down + 1)
/--
Steps through the whole iterator, counting the number of outputs emitted.
**Performance**:
This function's runtime is linear in the number of steps taken by the iterator.
-/
@[always_inline, inline, deprecated IterM.count (since := "2025-10-29")]
def IterM.size {α : Type w} {m : Type w Type w'} {β : Type w} [Iterator α m β] [Finite α m]
[IteratorLoop α m m]
[Monad m] (it : IterM (α := α) m β) : m (ULift Nat) :=
it.count
/--
Steps through the whole iterator, counting the number of outputs emitted.
**Performance**:
This function's runtime is linear in the number of steps taken by the iterator.
This is the implementation of the default instance `IteratorSizePartial.defaultImplementation`.
-/
@[always_inline, inline]
def IterM.Partial.count {α : Type w} {m : Type w Type w'} {β : Type w} [Iterator α m β]
[IteratorLoopPartial α m m] [Monad m] (it : IterM.Partial (α := α) m β) : m (ULift Nat) :=
it.fold (init := .up 0) fun acc _ => .up (acc.down + 1)
def IterM.DefaultConsumers.sizePartial {α : Type w} {m : Type w Type w'} [Monad m] {β : Type w}
[Iterator α m β] [IteratorLoopPartial α m m] (it : IterM (α := α) m β) :
m (ULift Nat) :=
it.allowNontermination.fold (init := .up 0) fun acc _ => .up (acc.down + 1)
/--
Steps through the whole iterator, counting the number of outputs emitted.
This is the default implementation of the `IteratorSize` class.
It simply iterates using `IteratorLoop` and counts the elements.
For certain iterators, more efficient implementations are possible and should be used instead.
-/
@[always_inline, inline]
def IteratorSize.defaultImplementation {α β : Type w} {m : Type w Type w'} [Monad m]
[Iterator α m β] [Finite α m] [IteratorLoop α m m] :
IteratorSize α m where
size := IterM.DefaultConsumers.size
/--
This is the default implementation of the `IteratorSizePartial` class.
It simply iterates using `IteratorLoopPartial` and counts the elements.
For certain iterators, more efficient implementations are possible and should be used instead.
-/
@[always_inline, inline]
instance IteratorSizePartial.defaultImplementation {α β : Type w} {m : Type w Type w'} [Monad m]
[Iterator α m β] [IteratorLoopPartial α m m] :
IteratorSizePartial α m where
size := IterM.DefaultConsumers.sizePartial
/--
Computes how many elements the iterator returns. In monadic situations, it is unclear which effects
are caused by calling `size`, and if the monad is nondeterministic, it is also unclear what the
returned value should be. The reference implementation, `IteratorSize.defaultImplementation`,
simply iterates over the whole iterator monadically, counting the number of emitted values.
An `IteratorSize` instance is considered lawful if it is equal to the reference implementation.
**Performance**:
This function's runtime is linear in the number of steps taken by the iterator.
Default performance is linear in the number of steps taken by the iterator.
-/
@[always_inline, inline, deprecated IterM.Partial.count (since := "2025-10-29")]
def IterM.Partial.size {α : Type w} {m : Type w Type w'} {β : Type w} [Iterator α m β]
[IteratorLoopPartial α m m] [Monad m] (it : IterM.Partial (α := α) m β) : m (ULift Nat) :=
it.count
@[always_inline, inline]
def IterM.size {α : Type} {m : Type Type w'} {β : Type} [Iterator α m β] [Monad m]
(it : IterM (α := α) m β) [IteratorSize α m] : m Nat :=
ULift.down <$> IteratorSize.size it
end Count
/--
Computes how many elements the iterator emits.
With monadic iterators (`IterM`), it is unclear which effects
are caused by calling `size`, and if the monad is nondeterministic, it is also unclear what the
returned value should be. The reference implementation, `IteratorSize.defaultImplementation`,
simply iterates over the whole iterator monadically, counting the number of emitted values.
An `IteratorSize` instance is considered lawful if it is equal to the reference implementation.
This is the partial version of `size`. It does not require a proof of finiteness and might loop
forever. It is not possible to verify the behavior in Lean because it uses `partial`.
**Performance**:
Default performance is linear in the number of steps taken by the iterator.
-/
@[always_inline, inline]
def IterM.Partial.size {α : Type} {m : Type Type w'} {β : Type} [Iterator α m β] [Monad m]
(it : IterM.Partial (α := α) m β) [IteratorSizePartial α m] : m Nat :=
ULift.down <$> IteratorSizePartial.size it.it
end Size
end Std.Iterators

View File

@@ -55,7 +55,7 @@ theorem LawfulMonadLiftFunction.lift_map [LawfulMonad m] [LawfulMonad n]
theorem LawfulMonadLiftFunction.lift_seq [LawfulMonad m] [LawfulMonad n]
[LawfulMonadLiftFunction lift] (mf : m (α β)) (ma : m α) :
lift (mf <*> ma) = lift mf <*> (lift ma : n α) := by
simp only [seq_eq_bind_map, lift_map, lift_bind]
simp only [seq_eq_bind, lift_map, lift_bind]
theorem LawfulMonadLiftFunction.lift_seqLeft [LawfulMonad m] [LawfulMonad n]
[LawfulMonadLiftFunction lift] (x : m α) (y : m β) :

View File

@@ -8,4 +8,3 @@ module
prelude
public import Init.Data.Iterators.Lemmas.Consumers
public import Init.Data.Iterators.Lemmas.Combinators
public import Init.Data.Iterators.Lemmas.Producers

View File

@@ -10,5 +10,4 @@ public import Init.Data.Iterators.Lemmas.Combinators.Attach
public import Init.Data.Iterators.Lemmas.Combinators.Monadic
public import Init.Data.Iterators.Lemmas.Combinators.FilterMap
public import Init.Data.Iterators.Lemmas.Combinators.FlatMap
public import Init.Data.Iterators.Lemmas.Combinators.Take
public import Init.Data.Iterators.Lemmas.Combinators.ULift

View File

@@ -11,7 +11,6 @@ import all Init.Data.Iterators.Combinators.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.Iterators.Lemmas.Consumers.Loop
public import Init.Data.Array.Attach
public section
@@ -83,14 +82,4 @@ theorem Iter.toArray_attachWith [Iterator α Id β]
simpa only [Array.toList_inj]
simp [Iter.toList_toArray]
@[simp]
theorem Iter.count_attachWith [Iterator α Id β]
{it : Iter (α := α) β} {hP}
[Finite α Id] [IteratorLoop α Id Id]
[LawfulIteratorLoop α Id Id] :
(it.attachWith P hP).count = it.count := by
letI : IteratorCollect α Id Id := .defaultImplementation
rw [ Iter.length_toList_eq_count, toList_attachWith]
simp
end Std.Iterators

View File

@@ -467,17 +467,6 @@ theorem Iter.fold_map {α β γ : Type w} {δ : Type x}
end Fold
section Count
@[simp]
theorem Iter.count_map {α β β' : Type w} [Iterator α Id β]
[IteratorLoop α Id Id] [Finite α Id] [LawfulIteratorLoop α Id Id]
{it : Iter (α := α) β} {f : β β'} :
(it.map f).count = it.count := by
simp [map_eq_toIter_map_toIterM, count_eq_count_toIterM]
end Count
theorem Iter.anyM_filterMapM {α β β' : Type w} {m : Type w Type w'}
[Iterator α Id β] [Finite α Id] [Monad m] [LawfulMonad m]
{it : Iter (α := α) β} {f : β m (Option β')} {p : β' m (ULift Bool)} :

View File

@@ -9,5 +9,4 @@ prelude
public import Init.Data.Iterators.Lemmas.Combinators.Monadic.Attach
public import Init.Data.Iterators.Lemmas.Combinators.Monadic.FilterMap
public import Init.Data.Iterators.Lemmas.Combinators.Monadic.FlatMap
public import Init.Data.Iterators.Lemmas.Combinators.Monadic.Take
public import Init.Data.Iterators.Lemmas.Combinators.Monadic.ULift

View File

@@ -9,7 +9,6 @@ prelude
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 import Init.Data.Iterators.Lemmas.Consumers.Monadic.Loop
public section
@@ -60,14 +59,4 @@ theorem IterM.map_unattach_toArray_attachWith [Iterator α m β] [Monad m] [Mona
rw [ toArray_toList, toArray_toList, map_unattach_toList_attachWith (it := it) (hP := hP)]
simp [-map_unattach_toList_attachWith, -IterM.toArray_toList]
@[simp]
theorem IterM.count_attachWith [Iterator α m β] [Monad m] [Monad n]
{it : IterM (α := α) m β} {hP}
[Finite α m] [IteratorLoop α m m] [LawfulMonad m] [LawfulIteratorLoop α m m] :
(it.attachWith P hP).count = it.count := by
letI : IteratorCollect α m m := .defaultImplementation
rw [ up_length_toList_eq_count, up_length_toList_eq_count,
map_unattach_toList_attachWith (it := it) (P := P) (hP := hP)]
simp only [Functor.map_map, List.length_unattach]
end Std.Iterators

View File

@@ -895,23 +895,6 @@ theorem IterM.fold_map {α β γ δ : Type w} {m : Type w → Type w'}
end Fold
section Count
@[simp]
theorem IterM.count_map {α β β' : Type w} {m : Type w Type w'} [Iterator α m β] [Monad m]
[IteratorLoop α m m] [Finite α m] [LawfulMonad m] [LawfulIteratorLoop α m m]
{it : IterM (α := α) m β} {f : β β'} :
(it.map f).count = it.count := by
induction it using IterM.inductSteps with | step it ihy ihs
rw [count_eq_match_step, count_eq_match_step, step_map, bind_assoc]
apply bind_congr; intro step
cases step.inflate using PlausibleIterStep.casesOn
· simp [ihy _]
· simp [ihs _]
· simp
end Count
section AnyAll
theorem IterM.anyM_filterMapM {α β β' : Type w} {m : Type w Type w'} {n : Type w Type w''}

View File

@@ -1,77 +0,0 @@
/-
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.Iterators.Combinators.Monadic.Take
public import Init.Data.Iterators.Lemmas.Consumers.Monadic
@[expose] public section
namespace Std.Iterators
theorem Take.isPlausibleStep_take_yield [Monad m] [Iterator α m β] {n : Nat}
{it : IterM (α := α) m β} (h : it.IsPlausibleStep (.yield it' out)) :
(it.take (n + 1)).IsPlausibleStep (.yield (it'.take n) out) :=
(.yield h (by simp [IterM.take]))
theorem Take.isPlausibleStep_take_skip [Monad m] [Iterator α m β] {n : Nat}
{it : IterM (α := α) m β} (h : it.IsPlausibleStep (.skip it')) :
(it.take (n + 1)).IsPlausibleStep (.skip (it'.take (n + 1))) :=
(.skip h (by simp [IterM.take]))
theorem IterM.step_take {α m β} [Monad m] [Iterator α m β] {n : Nat}
{it : IterM (α := α) m β} :
(it.take n).step = (match n with
| 0 => pure <| .deflate <| .done (.depleted rfl)
| k + 1 => do
match ( it.step).inflate with
| .yield it' out h => pure <| .deflate <| .yield (it'.take k) out (Take.isPlausibleStep_take_yield h)
| .skip it' h => pure <| .deflate <| .skip (it'.take (k + 1)) (Take.isPlausibleStep_take_skip h)
| .done h => pure <| .deflate <| .done (.done h)) := by
simp only [take, step, Iterator.step, internalState_toIterM]
cases n
case zero => rfl
case succ k =>
apply bind_congr
intro step
cases step.inflate using PlausibleIterStep.casesOn <;> rfl
theorem IterM.toList_take_zero {α m β} [Monad m] [LawfulMonad m] [Iterator α m β]
[Finite (Take α m) m]
[IteratorCollect (Take α m) m m] [LawfulIteratorCollect (Take α m) m m]
{it : IterM (α := α) m β} :
(it.take 0).toList = pure [] := by
rw [toList_eq_match_step]
simp [step_take]
theorem IterM.step_toTake {α m β} [Monad m] [Iterator α m β] [Finite α m]
{it : IterM (α := α) m β} :
it.toTake.step = (do
match ( it.step).inflate with
| .yield it' out h => pure <| .deflate <| .yield it'.toTake out (.yield h Nat.zero_ne_one)
| .skip it' h => pure <| .deflate <| .skip it'.toTake (.skip h Nat.zero_ne_one)
| .done h => pure <| .deflate <| .done (.done h)) := by
simp only [toTake, step, Iterator.step, internalState_toIterM]
apply bind_congr
intro step
cases step.inflate using PlausibleIterStep.casesOn <;> rfl
@[simp]
theorem IterM.toList_toTake {α m β} [Monad m] [LawfulMonad m] [Iterator α m β] [Finite α m]
[IteratorCollect α m m] [LawfulIteratorCollect α m m]
{it : IterM (α := α) m β} :
it.toTake.toList = it.toList := by
induction it using IterM.inductSteps with | step it ihy ihs
rw [toList_eq_match_step, toList_eq_match_step]
simp only [step_toTake, bind_assoc]
apply bind_congr; intro step
cases step.inflate using PlausibleIterStep.casesOn
· simp [ihy _]
· simp [ihs _]
· simp
end Std.Iterators

View File

@@ -7,8 +7,8 @@ module
prelude
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 import Init.Data.Iterators.Lemmas.Consumers.Monadic.Loop
public section
@@ -20,13 +20,9 @@ variable {α : Type u} {m : Type u → Type u'} {n : Type max u v → Type v'}
theorem IterM.step_uLift [Iterator α m β] [Monad n] {it : IterM (α := α) m β}
[MonadLiftT m (ULiftT n)] :
(it.uLift n).step = (do
match ( (monadLift it.step : ULiftT n _).run).down.inflate with
| .yield it' out h => return .deflate (.yield (it'.uLift n) (.up out) _, h, rfl)
| .skip it' h => return .deflate (.skip (it'.uLift n) _, h, rfl)
| .done h => return .deflate (.done _, h, rfl)) := by
simp only [IterM.step, Iterator.step, IterM.uLift]
apply bind_congr; intro step
split <;> simp [Types.ULiftIterator.Monadic.modifyStep, *]
let step := ( (monadLift it.step : ULiftT n _).run).down
return .deflate Types.ULiftIterator.Monadic.modifyStep step.inflate.val, step.inflate.val, step.inflate.property, rfl) :=
rfl
@[simp]
theorem IterM.toList_uLift [Iterator α m β] [Monad m] [Monad n] {it : IterM (α := α) m β}
@@ -37,11 +33,14 @@ theorem IterM.toList_uLift [Iterator α m β] [Monad m] [Monad n] {it : IterM (
(fun l => l.down.map ULift.up) <$> (monadLift it.toList : ULiftT n _).run := by
induction it using IterM.inductSteps with | step it ihy ihs
rw [IterM.toList_eq_match_step, IterM.toList_eq_match_step, step_uLift]
simp only [bind_assoc, map_eq_pure_bind, monadLift_bind, ULiftT.run_bind]
apply bind_congr; intro step
simp only [bind_pure_comp, bind_map_left, liftM_bind, ULiftT.run_bind, map_bind]
apply bind_congr
intro step
simp [Types.ULiftIterator.Monadic.modifyStep]
cases step.down.inflate using PlausibleIterStep.casesOn
· simp [ihy _]
· simp [ihs _]
· simp only [uLift] at ihy
simp [ihy _]
· exact ihs _
· simp
@[simp]
@@ -64,20 +63,4 @@ theorem IterM.toArray_uLift [Iterator α m β] [Monad m] [Monad n] {it : IterM (
rw [ toArray_toList, toArray_toList, toList_uLift, monadLift_map]
simp
@[simp]
theorem IterM.count_uLift [Iterator α m β] [Monad m] [Monad n] {it : IterM (α := α) m β}
[MonadLiftT m (ULiftT n)] [Finite α m] [IteratorLoop α m m]
[LawfulMonad m] [LawfulMonad n] [LawfulIteratorLoop α m m]
[LawfulMonadLiftT m (ULiftT n)] :
(it.uLift n).count =
(.up ·.down.down) <$> (monadLift (n := ULiftT n) it.count).run := by
induction it using IterM.inductSteps with | step it ihy ihs
rw [count_eq_match_step, count_eq_match_step, monadLift_bind, map_eq_pure_bind, step_uLift]
simp only [bind_assoc, ULiftT.run_bind]
apply bind_congr; intro step
cases step.down.inflate using PlausibleIterStep.casesOn
· simp [ihy _]
· simp [ihs _]
· simp
end Std.Iterators

View File

@@ -10,7 +10,6 @@ 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
public import Init.Data.Iterators.Lemmas.Consumers.Loop
public section
@@ -23,16 +22,14 @@ theorem Iter.uLift_eq_toIter_uLift_toIterM {it : Iter (α := α) β} :
rfl
theorem Iter.step_uLift [Iterator α Id β] {it : Iter (α := α) β} :
it.uLift.step = match it.step with
| .yield it' out h => .yield it'.uLift (.up out) _, h, rfl
| .skip it' h => .skip it'.uLift _, h, rfl
| .done h => .done _, h, rfl := by
it.uLift.step =
Types.ULiftIterator.modifyStep it.step.val,
it.step.val.mapIterator Iter.toIterM, it.step.property,
by simp [Types.ULiftIterator.modifyStep] := by
rw [Subtype.ext_iff]
simp only [uLift_eq_toIter_uLift_toIterM, step, IterM.Step.toPure, toIterM_toIter,
IterM.step_uLift, toIter_toIterM]
simp only [monadLift, ULiftT.run_pure, PlausibleIterStep.yield, PlausibleIterStep.skip,
PlausibleIterStep.done, pure_bind]
cases it.toIterM.step.run.inflate using PlausibleIterStep.casesOn <;> simp
IterM.step_uLift, bind_pure_comp, Id.run_map, toIter_toIterM]
simp [Types.ULiftIterator.modifyStep, monadLift]
@[simp]
theorem Iter.toList_uLift [Iterator α Id β] {it : Iter (α := α) β}
@@ -58,12 +55,4 @@ theorem Iter.toArray_uLift [Iterator α Id β] {it : Iter (α := α) β}
rw [ toArray_toList, toArray_toList, toList_uLift]
simp [-toArray_toList]
@[simp]
theorem Iter.count_uLift [Iterator α Id β] {it : Iter (α := α) β}
[Finite α Id] [IteratorLoop α Id Id] [LawfulIteratorLoop α Id Id] :
it.uLift.count = it.count := by
simp only [monadLift, uLift_eq_toIter_uLift_toIterM, count_eq_count_toIterM, toIterM_toIter]
rw [IterM.count_uLift]
simp [monadLift]
end Std.Iterators

View File

@@ -68,7 +68,8 @@ theorem Iter.forIn_eq {α β : Type w} [Iterator α Id β] [Finite α Id]
rw [ h]
theorem Iter.forIn'_eq_forIn'_toIterM {α β : Type w} [Iterator α Id β]
[Finite α Id] {m : Type w Type w''} [Monad m] [LawfulMonad m] [IteratorLoop α Id m]
[Finite α Id] {m : Type w Type w''} [Monad m] [LawfulMonad m]
[IteratorLoop α Id m] [LawfulIteratorLoop α Id m]
{γ : Type w} {it : Iter (α := α) β} {init : γ}
{f : (out : β) _ γ m (ForInStep γ)} :
letI : ForIn' m (Iter (α := α) β) β _ := Iter.instForIn'
@@ -80,7 +81,7 @@ theorem Iter.forIn'_eq_forIn'_toIterM {α β : Type w} [Iterator α Id β]
theorem Iter.forIn_eq_forIn_toIterM {α β : Type w} [Iterator α Id β]
[Finite α Id] {m : Type w Type w''} [Monad m] [LawfulMonad m]
[IteratorLoop α Id m]
[IteratorLoop α Id m] [LawfulIteratorLoop α Id m]
{γ : Type w} {it : Iter (α := α) β} {init : γ}
{f : β γ m (ForInStep γ)} :
ForIn.forIn it init f =
@@ -330,7 +331,7 @@ theorem Iter.foldM_eq_forIn {α β : Type w} {γ : Type x} [Iterator α Id β] [
theorem Iter.foldM_eq_foldM_toIterM {α β : Type w} [Iterator α Id β]
[Finite α Id] {m : Type w Type w''} [Monad m] [LawfulMonad m]
[IteratorLoop α Id m]
[IteratorLoop α Id m] [LawfulIteratorLoop α Id m]
{γ : Type w} {it : Iter (α := α) β} {init : γ} {f : γ β m γ} :
it.foldM (init := init) f = it.toIterM.foldM (init := init) f := by
simp [foldM_eq_forIn, IterM.foldM_eq_forIn, forIn_eq_forIn_toIterM]
@@ -395,7 +396,7 @@ theorem Iter.fold_eq_foldM {α β : Type w} {γ : Type x} [Iterator α Id β]
simp [foldM_eq_forIn, fold_eq_forIn]
theorem Iter.fold_eq_fold_toIterM {α β : Type w} {γ : Type w} [Iterator α Id β]
[Finite α Id] [IteratorLoop α Id Id]
[Finite α Id] [IteratorLoop α Id Id] [LawfulIteratorLoop α Id Id]
{f : γ β γ} {init : γ} {it : Iter (α := α) β} :
it.fold (init := init) f = (it.toIterM.fold (init := init) f).run := by
rw [fold_eq_foldM, foldM_eq_foldM_toIterM, IterM.fold_eq_foldM]
@@ -421,9 +422,8 @@ theorem Iter.fold_eq_match_step {α β : Type w} {γ : Type x} [Iterator α Id
cases step using PlausibleIterStep.casesOn <;> simp
-- The argument `f : γ₁ → γ₂` is intentionally explicit, as it is sometimes not found by unification.
theorem Iter.fold_hom {γ₁ : Type x₁} {γ₂ : Type x₂} [Iterator α Id β] [Finite α Id]
[IteratorLoop α Id Id.{x₁}] [LawfulIteratorLoop α Id Id.{x₁}]
[IteratorLoop α Id Id.{x₂}] [LawfulIteratorLoop α Id Id.{x₂}]
theorem Iter.fold_hom [Iterator α Id β] [Finite α Id]
[IteratorLoop α Id Id] [LawfulIteratorLoop α Id Id]
{it : Iter (α := α) β}
(f : γ₁ γ₂) {g₁ : γ₁ β γ₁} {g₂ : γ₂ β γ₂} {init : γ₁}
(H : x y, g₂ (f x) y = f (g₁ x y)) :
@@ -469,72 +469,30 @@ theorem Iter.foldl_toArray {α β : Type w} {γ : Type x} [Iterator α Id β] [F
it.toArray.foldl (init := init) f = it.fold (init := init) f := by
rw [fold_eq_foldM, Array.foldl_eq_foldlM, Iter.foldlM_toArray]
theorem Iter.count_eq_count_toIterM {α β : Type w} [Iterator α Id β]
[Finite α Id] [IteratorLoop α Id Id.{w}] {it : Iter (α := α) β} :
it.count = it.toIterM.count.run.down :=
(rfl)
theorem Iter.count_eq_fold {α β : Type w} [Iterator α Id β]
[Finite α Id] [IteratorLoop α Id Id.{w}] [LawfulIteratorLoop α Id Id.{w}]
[IteratorLoop α Id Id.{0}] [LawfulIteratorLoop α Id Id.{0}]
@[simp]
theorem Iter.size_toArray_eq_size {α β : Type w} [Iterator α Id β] [Finite α Id]
[IteratorCollect α Id Id] [LawfulIteratorCollect α Id Id]
[IteratorSize α Id] [LawfulIteratorSize α]
{it : Iter (α := α) β} :
it.count = it.fold (γ := Nat) (init := 0) (fun acc _ => acc + 1) := by
rw [count_eq_count_toIterM, IterM.count_eq_fold, fold_eq_fold_toIterM]
rw [ fold_hom (f := ULift.down)]
simp
theorem Iter.count_eq_forIn {α β : Type w} [Iterator α Id β]
[Finite α Id] [IteratorLoop α Id Id.{w}] [LawfulIteratorLoop α Id Id.{w}]
[IteratorLoop α Id Id.{0}] [LawfulIteratorLoop α Id Id.{0}]
{it : Iter (α := α) β} :
it.count = (ForIn.forIn (m := Id) it 0 (fun _ acc => return .yield (acc + 1))).run := by
rw [count_eq_fold, forIn_pure_yield_eq_fold, Id.run_pure]
theorem Iter.count_eq_match_step {α β : Type w} [Iterator α Id β]
[Finite α Id] [IteratorLoop α Id Id] [LawfulIteratorLoop α Id Id]
{it : Iter (α := α) β} :
it.count = (match it.step.val with
| .yield it' _ => it'.count + 1
| .skip it' => it'.count
| .done => 0) := by
simp only [count_eq_count_toIterM]
rw [IterM.count_eq_match_step]
simp only [bind_pure_comp, id_map', Id.run_bind, Iter.step]
cases it.toIterM.step.run.inflate using PlausibleIterStep.casesOn <;> simp
it.toArray.size = it.size := by
simp only [toArray_eq_toArray_toIterM, LawfulIteratorCollect.toArray_eq]
simp [ toArray_eq_toArray_toIterM, LawfulIteratorSize.size_eq_size_toArray]
@[simp]
theorem Iter.size_toArray_eq_count {α β : Type w} [Iterator α Id β] [Finite α Id]
theorem Iter.length_toList_eq_size {α β : Type w} [Iterator α Id β] [Finite α Id]
[IteratorCollect α Id Id] [LawfulIteratorCollect α Id Id]
[IteratorLoop α Id Id] [LawfulIteratorLoop α Id Id]
[IteratorSize α Id] [LawfulIteratorSize α]
{it : Iter (α := α) β} :
it.toArray.size = it.count := by
simp only [toArray_eq_toArray_toIterM, count_eq_count_toIterM, Id.run_map,
IterM.up_size_toArray_eq_count]
@[deprecated Iter.size_toArray_eq_count (since := "2025-10-29")]
def Iter.size_toArray_eq_size := @size_toArray_eq_count
it.toList.length = it.size := by
rw [ toList_toArray, Array.length_toList, size_toArray_eq_size]
@[simp]
theorem Iter.length_toList_eq_count {α β : Type w} [Iterator α Id β] [Finite α Id]
theorem Iter.length_toListRev_eq_size {α β : Type w} [Iterator α Id β] [Finite α Id]
[IteratorCollect α Id Id] [LawfulIteratorCollect α Id Id]
[IteratorLoop α Id Id] [LawfulIteratorLoop α Id Id]
[IteratorSize α Id] [LawfulIteratorSize α]
{it : Iter (α := α) β} :
it.toList.length = it.count := by
rw [ toList_toArray, Array.length_toList, size_toArray_eq_count]
@[deprecated Iter.length_toList_eq_count (since := "2025-10-29")]
def Iter.length_toList_eq_size := @length_toList_eq_count
@[simp]
theorem Iter.length_toListRev_eq_count {α β : Type w} [Iterator α Id β] [Finite α Id]
[IteratorCollect α Id Id] [LawfulIteratorCollect α Id Id]
[IteratorLoop α Id Id] [LawfulIteratorLoop α Id Id]
{it : Iter (α := α) β} :
it.toListRev.length = it.count := by
rw [toListRev_eq, List.length_reverse, length_toList_eq_count]
@[deprecated Iter.length_toListRev_eq_count (since := "2025-10-29")]
def Iter.length_toListRev_eq_size := @length_toListRev_eq_count
it.toListRev.length = it.size := by
rw [toListRev_eq, List.length_reverse, length_toList_eq_size]
theorem Iter.anyM_eq_forIn {α β : Type w} {m : Type Type w'} [Iterator α Id β]
[Finite α Id] [Monad m] [LawfulMonad m] [IteratorLoop α Id m] [LawfulIteratorLoop α Id m]

View File

@@ -335,73 +335,6 @@ theorem IterM.drain_eq_map_toArray {α β : Type w} {m : Type w → Type w'} [It
it.drain = (fun _ => .unit) <$> it.toList := by
simp [IterM.drain_eq_map_toList]
theorem IterM.count_eq_fold {α β : Type w} {m : Type w Type w'} [Iterator α m β]
[Finite α m] [Monad m] [LawfulMonad m] [IteratorLoop α m m]
{it : IterM (α := α) m β} :
it.count = it.fold (init := .up 0) (fun acc _ => .up <| acc.down + 1) :=
(rfl)
theorem IterM.count_eq_forIn {α β : Type w} {m : Type w Type w'} [Iterator α m β]
[Finite α m] [Monad m] [LawfulMonad m] [IteratorLoop α m m]
{it : IterM (α := α) m β} :
it.count = ForIn.forIn it (.up 0) (fun _ acc => return .yield (.up (acc.down + 1))) :=
(rfl)
theorem IterM.count_eq_match_step {α β : Type w} {m : Type w Type w'} [Iterator α m β]
[Finite α m] [Monad m] [LawfulMonad m] [IteratorLoop α m m] [LawfulIteratorLoop α m m]
{it : IterM (α := α) m β} :
it.count = (do
match ( it.step).inflate.val with
| .yield it' _ => return .up (( it'.count).down + 1)
| .skip it' => return .up ( it'.count).down
| .done => return .up 0) := by
simp only [count_eq_fold]
have (acc : Nat) (it' : IterM (α := α) m β) :
it'.fold (init := ULift.up acc) (fun acc _ => .up (acc.down + 1)) =
(ULift.up <| ·.down + acc) <$>
it'.fold (init := ULift.up 0) (fun acc _ => .up (acc.down + 1)) := by
rw [ fold_hom]
· simp only [Nat.zero_add]; rfl
· simp only [ULift.up.injEq]; omega
rw [fold_eq_match_step]
apply bind_congr; intro step
cases step.inflate using PlausibleIterStep.casesOn
· simp only [Nat.zero_add, bind_pure_comp]
rw [this 1]
· simp
· simp
@[simp]
theorem IterM.up_size_toArray_eq_count {α β : Type w} [Iterator α m β] [Finite α m]
[Monad m] [LawfulMonad m]
[IteratorCollect α m m] [LawfulIteratorCollect α m m]
[IteratorLoop α m m] [LawfulIteratorLoop α m m]
{it : IterM (α := α) m β} :
(.up <| ·.size) <$> it.toArray = it.count := by
rw [toArray_eq_fold, count_eq_fold, fold_hom]
· simp only [List.size_toArray, List.length_nil]; rfl
· simp
@[simp]
theorem IterM.up_length_toList_eq_count {α β : Type w} [Iterator α m β] [Finite α m]
[Monad m] [LawfulMonad m]
[IteratorCollect α m m] [LawfulIteratorCollect α m m]
[IteratorLoop α m m] [LawfulIteratorLoop α m m]
{it : IterM (α := α) m β} :
(.up <| ·.length) <$> it.toList = it.count := by
rw [toList_eq_fold, count_eq_fold, fold_hom]
· simp only [List.length_nil]; rfl
· simp
@[simp]
theorem IterM.up_length_toListRev_eq_count {α β : Type w} [Iterator α m β] [Finite α m]
[Monad m] [LawfulMonad m]
[IteratorCollect α m m] [LawfulIteratorCollect α m m]
[IteratorLoop α m m] [LawfulIteratorLoop α m m]
{it : IterM (α := α) m β} :
(.up <| ·.length) <$> it.toListRev = it.count := by
simp only [toListRev_eq, Functor.map_map, List.length_reverse, up_length_toList_eq_count]
theorem IterM.anyM_eq_forIn {α β : Type w} {m : Type w Type w'} [Iterator α m β]
[Finite α m] [Monad m] [LawfulMonad m] [IteratorLoop α m m] [LawfulIteratorLoop α m m]
{it : IterM (α := α) m β} {p : β m (ULift Bool)} :

View File

@@ -1,10 +0,0 @@
/-
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.Iterators.Lemmas.Producers.Monadic
public import Init.Data.Iterators.Lemmas.Producers.List

View File

@@ -1,71 +0,0 @@
/-
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.Iterators.Lemmas.Consumers.Monadic
public import Init.Data.Iterators.Producers.Monadic.List
@[expose] public section
/-!
# Lemmas about list iterators
This module provides lemmas about the interactions of `List.iterM` with `IterM.step` and various
collectors.
-/
namespace Std.Iterators
open Std.Internal
variable {m : Type w Type w'} {n : Type w Type w''} [Monad m] {β : Type w}
@[simp]
theorem _root_.List.step_iterM_nil :
(([] : List β).iterM m).step = pure (.deflate .done, rfl) := by
simp only [IterM.step, Iterator.step]; rfl
@[simp]
theorem _root_.List.step_iterM_cons {x : β} {xs : List β} :
((x :: xs).iterM m).step = pure (.deflate .yield (xs.iterM m) x, rfl) := by
simp only [List.iterM, IterM.step, Iterator.step]; rfl
theorem _root_.List.step_iterM {l : List β} :
(l.iterM m).step = match l with
| [] => pure (.deflate .done, rfl)
| x :: xs => pure (.deflate .yield (xs.iterM m) x, rfl) := by
cases l <;> simp [List.step_iterM_cons, List.step_iterM_nil]
theorem ListIterator.toArrayMapped_iterM [Monad n] [LawfulMonad n]
{β : Type w} {γ : Type w} {lift : δ : Type w m δ n δ}
[LawfulMonadLiftFunction lift] {f : β n γ} {l : List β} :
IteratorCollect.toArrayMapped lift f (l.iterM m) (m := m) = List.toArray <$> l.mapM f := by
rw [LawfulIteratorCollect.toArrayMapped_eq]
induction l with
| nil =>
rw [IterM.DefaultConsumers.toArrayMapped_eq_match_step]
simp [List.step_iterM_nil, LawfulMonadLiftFunction.lift_pure]
| cons x xs ih =>
rw [IterM.DefaultConsumers.toArrayMapped_eq_match_step]
simp [List.step_iterM_cons, List.mapM_cons, pure_bind, ih, LawfulMonadLiftFunction.lift_pure]
@[simp]
theorem _root_.List.toArray_iterM [LawfulMonad m] {l : List β} :
(l.iterM m).toArray = pure l.toArray := by
simp only [IterM.toArray, ListIterator.toArrayMapped_iterM]
rw [List.mapM_pure, map_pure, List.map_id']
@[simp]
theorem _root_.List.toList_iterM [LawfulMonad m] {l : List β} :
(l.iterM m).toList = pure l := by
rw [ IterM.toList_toArray, List.toArray_iterM, map_pure, List.toList_toArray]
@[simp]
theorem _root_.List.toListRev_iterM [LawfulMonad m] {l : List β} :
(l.iterM m).toListRev = pure l.reverse := by
simp [IterM.toListRev_eq, List.toList_iterM]
end Std.Iterators

View File

@@ -1,10 +0,0 @@
/-
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.Iterators.Producers.Monadic
public import Init.Data.Iterators.Producers.List

View File

@@ -1,9 +0,0 @@
/-
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.Iterators.Producers.Monadic.List

Some files were not shown because too many files have changed in this diff Show More