Compare commits

..

5 Commits

Author SHA1 Message Date
Leonardo de Moura
404a5b7351 fix: isRfl must ignore contextDependent; add unit tests
isRfl was using `matches .rfl` which only matched when ALL fields
have default values. With the new contextDependent field, .rfl false true
(cd=true) no longer matched, causing Theorems.rewrite to incorrectly
return cd .rfl results instead of continuing to the next theorem.

Fix: match `.rfl false _` (done=false, ignore cd).

Add unit tests for mkEqTransResult, andThen, orElse cd propagation.
2026-03-19 15:54:29 -04:00
Leonardo de Moura
96d15f5d48 test: add dependent forall test for contextDependent cache
Exercises `simpForall'` with `withFreshTransientCache` — the body
`n + 2 = 2 + n` is simplified context-dependently inside the binder.
The binder type `Nat` hits persistent cache on second traversal.
2026-03-19 15:41:33 -04:00
Leonardo de Moura
0a8121e609 test: add test for failed cd discharger propagation
When  fails (no matching hypothesis), it returns
`.failed true`. This cd propagates through the rewrite result, so
`n + 2` lands in the transient cache even though no rewrite occurred.
2026-03-19 15:35:05 -04:00
Leonardo de Moura
399f9a6717 test: add systematic contextDependent cache tests
Tests cover:
1. Ground evaluation → persistent cache hit
2. Conditional rewrite with dischargeAssumption → transient only
3. Congruence with mixed cd/non-cd sub-results → cd propagates
4. Arrow/implication → cd propagates through domain simplification
5. Lambda/funext → cd propagates through body under binder
6. Control flow (ite) → cd propagates through condition
2026-03-19 15:29:39 -04:00
Leonardo de Moura
81180ba129 feat: add contextDependent to Sym.simp Result with two-tier cache
Replace the coarse `wellBehavedMethods` flag with per-result
`contextDependent : Bool` tracking. Split the simp cache into
`persistentCache` (context-independent results, survives binder entry)
and `transientCache` (context-dependent results, cleared on binder entry).

Propagate `contextDependent` through all combinators (congruence,
transitivity, control flow, arrows, rewriting). The invariant:
when combining sub-results, `cd` is the disjunction of all sub-results'
flags — including `.rfl` results, since `simp` might take a completely
different code path in another local context.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 15:13:38 -04:00
2414 changed files with 10561 additions and 26203 deletions

View File

@@ -7,11 +7,6 @@ To build Lean you should use `make -j$(nproc) -C build/release`.
The build uses `ccache`, and in a sandbox `ccache` may complain about read-only file systems.
Use `CCACHE_READONLY` and `CCACHE_TEMPDIR` instead of disabling ccache completely.
To rebuild individual modules without a full build, use Lake directly:
```
cd src && lake build Init.Prelude
```
## Running Tests
See `tests/README.md` for full documentation. Quick reference:
@@ -21,32 +16,19 @@ See `tests/README.md` for full documentation. Quick reference:
CTEST_PARALLEL_LEVEL="$(nproc)" CTEST_OUTPUT_ON_FAILURE=1 \
make -C build/release -j "$(nproc)" test
# Specific test by name (supports regex via ctest -R; double-quote special chars like |)
# Specific test by name (supports regex via ctest -R)
CTEST_PARALLEL_LEVEL="$(nproc)" CTEST_OUTPUT_ON_FAILURE=1 \
make -C build/release -j "$(nproc)" test ARGS="-R 'grind_ematch'"
# Multiple tests matching a pattern
CTEST_PARALLEL_LEVEL="$(nproc)" CTEST_OUTPUT_ON_FAILURE=1 \
make -C build/release -j "$(nproc)" test ARGS="-R 'treemap|phashmap'"
make -C build/release -j "$(nproc)" test ARGS='-R grind_ematch'
# Rerun only previously failed tests
CTEST_PARALLEL_LEVEL="$(nproc)" CTEST_OUTPUT_ON_FAILURE=1 \
make -C build/release -j "$(nproc)" test ARGS='--rerun-failed'
# Run a test manually without ctest (test pile: pass filename relative to the pile dir)
tests/with_stage1_test_env.sh tests/elab_bench/run_bench.sh cbv_decide.lean
tests/with_stage1_test_env.sh tests/elab/run_test.sh grind_indexmap.lean
# Single test from tests/foo/bar/ (quick check during development)
CTEST_PARALLEL_LEVEL="$(nproc)" CTEST_OUTPUT_ON_FAILURE=1 \
make -C build/release -j "$(nproc)" test ARGS=-R testname'
```
## Benchmark vs Test Problem Sizes
Benchmarks are also run as tests. Use the `TEST_BENCH` environment variable (unset in tests, set to `1` in benchmarks) to scale problem sizes:
- In `compile_bench` `.init.sh` files: check `$TEST_BENCH` and set `TEST_ARGS` accordingly
- In `elab_bench` Lean files: use `(← IO.getEnv "TEST_BENCH") == some "1"` to switch between small (test) and large (bench) inputs
See `tests/README.md` for the full benchmark writing guide.
## Testing stage 2
When requested to test stage 2, build it as follows:
@@ -61,11 +43,6 @@ make -C build/release/stage2 clean-stdlib
```
must be run manually before building.
To rebuild individual stage 2 modules without a full `make stage2`, use Lake directly:
```
cd build/release/stage2 && lake build Init.Prelude
```
## New features
When asked to implement new features:

View File

@@ -157,16 +157,6 @@ Note: `gh pr checks --watch` exits as soon as ALL checks complete (pass or fail)
fail while others are still running, `--watch` will continue until everything settles, then exit
with a non-zero code. So a background `--watch` finishing = all checks done; check which failed.
## Mathlib Bump Branches
Mathlib `bump/v4.X.0` branches live on the **fork** `leanprover-community/mathlib4-nightly-testing`,
NOT on `leanprover-community/mathlib4`.
## Never Force-Update Remote Refs Without Confirmation
Never force-update an existing remote branch or tag via `git push --force` or the GitHub API
without explicit user confirmation.
## Error Handling
**CRITICAL**: If something goes wrong or a command fails:

View File

@@ -33,7 +33,7 @@ jobs:
include: ${{fromJson(inputs.config)}}
# complete all jobs
fail-fast: false
runs-on: ${{ endsWith(matrix.os, '-with-cache') && fromJSON(format('["{0}", "nscloud-git-mirror-5gb"]', matrix.os)) || matrix.os }}
runs-on: ${{ endsWith(matrix.os, '-with-cache') && fromJSON(format('["{0}", "nscloud-git-mirror-1gb"]', matrix.os)) || matrix.os }}
defaults:
run:
shell: ${{ matrix.shell || 'nix develop -c bash -euxo pipefail {0}' }}
@@ -78,7 +78,7 @@ jobs:
# (needs to be after "Install *" to use the right shell)
- name: CI Merge Checkout
run: |
git fetch --depth=${{ matrix.name == 'Linux Lake (Cached)' && '10' || '1' }} origin ${{ github.sha }}
git fetch --depth=1 origin ${{ github.sha }}
git checkout FETCH_HEAD flake.nix flake.lock script/prepare-* tests/elab/importStructure.lean
if: github.event_name == 'pull_request'
# (needs to be after "Checkout" so files don't get overridden)
@@ -125,7 +125,7 @@ jobs:
else
echo "TARGET_STAGE=stage1" >> $GITHUB_ENV
fi
- name: Configure Build
- name: Build
run: |
ulimit -c unlimited # coredumps
[ -d build ] || mkdir build
@@ -162,21 +162,7 @@ jobs:
fi
# contortion to support empty OPTIONS with old macOS bash
cmake .. --preset ${{ matrix.CMAKE_PRESET || 'release' }} -B . ${{ matrix.CMAKE_OPTIONS }} ${OPTIONS[@]+"${OPTIONS[@]}"} -DLEAN_INSTALL_PREFIX=$PWD/..
- name: Build Stage 0 & Configure Stage 1
run: |
ulimit -c unlimited # coredumps
time make -C build stage1-configure -j$NPROC
- name: Download Lake Cache
if: matrix.name == 'Linux Lake (Cached)'
run: |
cd src
../build/stage0/bin/lake cache get --repo=${{ github.repository }}
timeout-minutes: 20 # prevent excessive hanging from network issues
continue-on-error: true
- name: Build Target Stage
run: |
ulimit -c unlimited # coredumps
time make -C build $TARGET_STAGE -j$NPROC
time make $TARGET_STAGE -j$NPROC
# Should be done as early as possible and in particular *before* "Check rebootstrap" which
# changes the state of stage1/
- name: Save Cache
@@ -195,21 +181,6 @@ jobs:
build/stage1/**/*.c
build/stage1/**/*.c.o*' || '' }}
key: ${{ steps.restore-cache.outputs.cache-primary-key }}
- name: Upload Lake Cache
# Caching on cancellation created some mysterious issues perhaps related to improper build
# shutdown. Also, since this needs access to secrets, it cannot be run on forks.
if: matrix.name == 'Linux Lake' && !cancelled() && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository)
run: |
curl --version
cd src
time ../build/stage0/bin/lake build -o ../build/lake-mappings.jsonl
time ../build/stage0/bin/lake cache put ../build/lake-mappings.jsonl --repo=${{ github.repository }}
env:
LAKE_CACHE_KEY: ${{ secrets.LAKE_CACHE_KEY }}
LAKE_CACHE_ARTIFACT_ENDPOINT: ${{ vars.LAKE_CACHE_ENDPOINT }}/a1
LAKE_CACHE_REVISION_ENDPOINT: ${{ vars.LAKE_CACHE_ENDPOINT }}/r1
timeout-minutes: 20 # prevent excessive hanging from network issues
continue-on-error: true
- name: Install
run: |
make -C build/$TARGET_STAGE install
@@ -276,10 +247,10 @@ jobs:
- name: Check rebootstrap
run: |
set -e
git config user.email "stage0@lean-fro.org"
git config user.name "update-stage0"
# clean rebuild in case of Makefile changes/Lake does not detect uncommited stage 0
# changes yet
make -C build update-stage0
git commit --allow-empty -m "chore: update-stage0"
make -C build/stage1 clean-stdlib
time make -C build -j$NPROC
time ctest --preset ${{ matrix.CMAKE_PRESET || 'release' }} --test-dir build/stage1 -j$NPROC
if: matrix.check-rebootstrap

View File

@@ -1,29 +0,0 @@
name: Check for empty PR
on:
merge_group:
pull_request:
jobs:
check-empty-pr:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
with:
ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.sha }}
fetch-depth: 0
filter: tree:0
- name: Check for empty diff
run: |
if [[ "${{ github.event_name }}" == "pull_request" ]]; then
base=$(git merge-base "origin/${{ github.base_ref }}" HEAD)
else
base=$(git rev-parse HEAD^1)
fi
if git diff --quiet "$base" HEAD --; then
echo "This PR introduces no changes compared to its base branch." | tee "$GITHUB_STEP_SUMMARY"
echo "It may be a duplicate of an already-merged PR." | tee -a "$GITHUB_STEP_SUMMARY"
exit 1
fi
shell: bash

View File

@@ -61,35 +61,20 @@ jobs:
git remote add nightly https://foo:'${{ secrets.PUSH_NIGHTLY_TOKEN }}'@github.com/${{ github.repository_owner }}/lean4-nightly.git
git fetch nightly --tags
if [[ '${{ github.event_name }}' == 'workflow_dispatch' ]]; then
# Manual re-release: retry today's nightly, or create a revision if it already exists
TODAY_NIGHTLY="nightly-$(date -u +%F)"
if git rev-parse "refs/tags/${TODAY_NIGHTLY}" >/dev/null 2>&1; then
# Today's nightly already exists, create a revision
REV=1
while git rev-parse "refs/tags/${TODAY_NIGHTLY}-rev${REV}" >/dev/null 2>&1; do
REV=$((REV + 1))
done
LEAN_VERSION_STRING="${TODAY_NIGHTLY}-rev${REV}"
else
# Today's nightly doesn't exist yet (e.g. scheduled run failed), create it
LEAN_VERSION_STRING="${TODAY_NIGHTLY}"
fi
# Manual re-release: create a revision of the most recent nightly
BASE_NIGHTLY=$(git tag -l 'nightly-*' | sort -rV | head -1)
# Strip any existing -revK suffix to get the base date tag
BASE_NIGHTLY="${BASE_NIGHTLY%%-rev*}"
REV=1
while git rev-parse "refs/tags/${BASE_NIGHTLY}-rev${REV}" >/dev/null 2>&1; do
REV=$((REV + 1))
done
LEAN_VERSION_STRING="${BASE_NIGHTLY}-rev${REV}"
echo "nightly=$LEAN_VERSION_STRING" >> "$GITHUB_OUTPUT"
else
# Scheduled: do nothing if commit already has a different tag (e.g. a release tag)
# Scheduled: do nothing if commit already has a different tag
LEAN_VERSION_STRING="nightly-$(date -u +%F)"
HEAD_TAG="$(git name-rev --name-only --tags --no-undefined HEAD 2> /dev/null || true)"
if [[ -n "$HEAD_TAG" && "$HEAD_TAG" != "$LEAN_VERSION_STRING" ]]; then
echo "HEAD already tagged as ${HEAD_TAG}, skipping nightly"
elif git rev-parse "refs/tags/${LEAN_VERSION_STRING}" >/dev/null 2>&1; then
# Today's nightly already exists (e.g. from a manual release), create a revision
REV=1
while git rev-parse "refs/tags/${LEAN_VERSION_STRING}-rev${REV}" >/dev/null 2>&1; do
REV=$((REV + 1))
done
LEAN_VERSION_STRING="${LEAN_VERSION_STRING}-rev${REV}"
echo "nightly=$LEAN_VERSION_STRING" >> "$GITHUB_OUTPUT"
else
if [[ "$(git name-rev --name-only --tags --no-undefined HEAD 2> /dev/null || echo "$LEAN_VERSION_STRING")" == "$LEAN_VERSION_STRING" ]]; then
echo "nightly=$LEAN_VERSION_STRING" >> "$GITHUB_OUTPUT"
fi
fi
@@ -143,7 +128,7 @@ jobs:
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 -m 1 -E "^set\(LEAN_VERSION_IS_RELEASE " src/CMakeLists.txt | grep -oE '[0-9]+' | head -1)
CMAKE_IS_RELEASE=$(grep -m 1 -E "^set\(LEAN_VERSION_IS_RELEASE " src/CMakeLists.txt | sed -nE 's/^set\(LEAN_VERSION_IS_RELEASE ([0-9]+)\).*/\1/p')
# Expected values from tag parsing
TAG_MAJOR="${{ steps.set-release.outputs.LEAN_VERSION_MAJOR }}"
@@ -255,7 +240,7 @@ jobs:
// portable release build: use channel with older glibc (2.26)
"name": "Linux release",
// usually not a bottleneck so make exclusive to `fast-ci`
"os": large && fast ? "nscloud-ubuntu-24.04-amd64-8x16-with-cache" : "ubuntu-latest",
"os": large && fast ? "nscloud-ubuntu-22.04-amd64-8x16-with-cache" : "ubuntu-latest",
"release": true,
// Special handling for release jobs. We want:
// 1. To run it in PRs so developers get PR toolchains (so secondary without tests is sufficient)
@@ -276,7 +261,7 @@ jobs:
},
{
"name": "Linux Lake",
"os": large ? "nscloud-ubuntu-24.04-amd64-8x16-with-cache" : "ubuntu-latest",
"os": large ? "nscloud-ubuntu-22.04-amd64-8x16-with-cache" : "ubuntu-latest",
"enabled": true,
"check-rebootstrap": level >= 1,
"check-stage3": level >= 2,
@@ -284,19 +269,7 @@ jobs:
// NOTE: `test-bench` currently seems to be broken on `ubuntu-latest`
"test-bench": large && level >= 2,
// We are not warning-free yet on all platforms, start here
"CMAKE_OPTIONS": "-DLEAN_EXTRA_CXX_FLAGS=-Werror -DUSE_LAKE_CACHE=ON",
},
{
"name": "Linux Lake (Cached)",
"os": large ? "nscloud-ubuntu-24.04-amd64-8x16-with-cache" : "ubuntu-latest",
"enabled": true,
"check-rebootstrap": level >= 1,
"check-stage3": level >= 2,
"test": true,
"secondary": true,
// NOTE: `test-bench` currently seems to be broken on `ubuntu-latest`
"test-bench": large && level >= 2,
"CMAKE_OPTIONS": "-DLEAN_EXTRA_CXX_FLAGS=-Werror -DUSE_LAKE_CACHE=ON",
"CMAKE_OPTIONS": "-DLEAN_EXTRA_CXX_FLAGS=-Werror",
},
{
"name": "Linux Reldebug",
@@ -310,7 +283,7 @@ jobs:
{
"name": "Linux fsanitize",
// Always run on large if available, more reliable regarding timeouts
"os": large ? "nscloud-ubuntu-24.04-amd64-16x32-with-cache" : "ubuntu-latest",
"os": large ? "nscloud-ubuntu-22.04-amd64-16x32-with-cache" : "ubuntu-latest",
"enabled": level >= 2,
// do not fail nightlies on this for now
"secondary": level <= 2,

View File

@@ -6,6 +6,6 @@ vscode:
- leanprover.lean4
tasks:
- name: Build
init: cmake --preset dev
- name: Release build
init: cmake --preset release
command: make -C build/release -j$(nproc || sysctl -n hw.logicalcpu)

9
.vscode/tasks.json vendored
View File

@@ -11,15 +11,6 @@
"isDefault": true
}
},
{
"label": "build stage2",
"type": "shell",
"command": "make -C build/release stage2 -j$(nproc 2>/dev/null || sysctl -n hw.logicalcpu 2>/dev/null || echo 4)",
"problemMatcher": [],
"group": {
"kind": "build"
}
},
{
"label": "build-old",
"type": "shell",

View File

@@ -1,6 +1,4 @@
cmake_minimum_required(VERSION 3.21)
include(ExternalProject)
include(FetchContent)
if(NOT CMAKE_GENERATOR MATCHES "Makefiles")
message(FATAL_ERROR "Only makefile generators are supported")
@@ -36,6 +34,7 @@ foreach(var ${vars})
endif()
endforeach()
include(ExternalProject)
project(LEAN CXX C)
if(NOT (DEFINED STAGE0_CMAKE_EXECUTABLE_SUFFIX))
@@ -115,22 +114,21 @@ if(NOT CMAKE_SYSTEM_NAME MATCHES "Emscripten")
)
endif()
endif()
list(APPEND STAGE0_ARGS -DLEANTAR=${LEANTAR})
list(APPEND CL_ARGS -DCADICAL=${CADICAL} -DLEANTAR=${LEANTAR})
endif()
if(USE_MIMALLOC)
FetchContent_Declare(
ExternalProject_Add(
mimalloc
PREFIX mimalloc
GIT_REPOSITORY https://github.com/microsoft/mimalloc
GIT_TAG v2.2.3
# Unnecessarily deep directory structure, but it saves us from a complicated
# stage0 update for now. If we ever update the other dependencies like
# cadical, it might be worth reorganizing the directory structure.
SOURCE_DIR
"${CMAKE_BINARY_DIR}/mimalloc/src/mimalloc"
# just download, we compile it as part of each stage as it is small
CONFIGURE_COMMAND ""
BUILD_COMMAND ""
INSTALL_COMMAND ""
)
FetchContent_MakeAvailable(mimalloc)
list(APPEND EXTRA_DEPENDS mimalloc)
endif()
if(NOT STAGE1_PREV_STAGE)

View File

@@ -8,26 +8,16 @@
"configurePresets": [
{
"name": "release",
"displayName": "Release build config",
"displayName": "Default development optimized build config",
"generator": "Unix Makefiles",
"binaryDir": "${sourceDir}/build/release"
},
{
"name": "dev",
"displayName": "Default development optimized build config",
"cacheVariables": {
"STRIP_BINARIES": "OFF"
},
"generator": "Unix Makefiles",
"binaryDir": "${sourceDir}/build/dev"
},
{
"name": "debug",
"displayName": "Debug build config",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Debug",
"LEAN_EXTRA_CXX_FLAGS": "-DLEAN_DEFAULT_THREAD_STACK_SIZE=16*1024*1024",
"STRIP_BINARIES": "OFF"
"CMAKE_BUILD_TYPE": "Debug"
},
"generator": "Unix Makefiles",
"binaryDir": "${sourceDir}/build/debug"
@@ -36,8 +26,7 @@
"name": "reldebug",
"displayName": "Release with assertions enabled",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "RelWithAssert",
"STRIP_BINARIES": "OFF"
"CMAKE_BUILD_TYPE": "RelWithAssert"
},
"generator": "Unix Makefiles",
"binaryDir": "${sourceDir}/build/reldebug"
@@ -49,7 +38,6 @@
"LEAN_EXTRA_CXX_FLAGS": "-fsanitize=address,undefined -DLEAN_DEFAULT_THREAD_STACK_SIZE=16*1024*1024",
"LEANC_EXTRA_CC_FLAGS": "-fsanitize=address,undefined",
"LEAN_EXTRA_LINKER_FLAGS": "-fsanitize=address,undefined -fsanitize-link-c++-runtime",
"STRIP_BINARIES": "OFF",
"SMALL_ALLOCATOR": "OFF",
"USE_MIMALLOC": "OFF",
"BSYMBOLIC": "OFF",
@@ -70,10 +58,6 @@
"name": "release",
"configurePreset": "release"
},
{
"name": "dev",
"configurePreset": "dev"
},
{
"name": "debug",
"configurePreset": "debug"
@@ -97,11 +81,6 @@
"configurePreset": "release",
"output": {"outputOnFailure": true, "shortProgress": true}
},
{
"name": "dev",
"configurePreset": "dev",
"output": {"outputOnFailure": true, "shortProgress": true}
},
{
"name": "debug",
"configurePreset": "debug",

View File

@@ -1,4 +1,3 @@
30
interp.lean:146:4: warning: declaration uses `sorry`
interp.lean:146:0: warning: declaration uses `sorry`
3628800

View File

@@ -30,9 +30,6 @@ cd lean4
cmake --preset release
make -C build/release -j$(nproc || sysctl -n hw.logicalcpu)
```
For development, `cmake --preset dev` is recommended instead.
You can replace `$(nproc || sysctl -n hw.logicalcpu)` with the desired parallelism amount.
The above commands will compile the Lean library and binaries into the

View File

@@ -67,5 +67,5 @@
oldGlibc = devShellWithDist pkgsDist-old;
oldGlibcAArch = devShellWithDist pkgsDist-old-aarch;
};
}) ["x86_64-linux" "aarch64-linux" "aarch64-darwin"]);
}) ["x86_64-linux" "aarch64-linux"]);
}

View File

@@ -236,7 +236,7 @@ def parse_version(version_str):
def is_version_gte(version1, version2):
"""Check if version1 >= version2, including proper handling of release candidates."""
# Check if version1 is a nightly toolchain
if version1.startswith("leanprover/lean4:nightly-") or version1.startswith("leanprover/lean4-nightly:"):
if version1.startswith("leanprover/lean4:nightly-"):
return False
return parse_version(version1) >= parse_version(version2)
@@ -311,16 +311,16 @@ def check_cmake_version(repo_url, branch, version_major, version_minor, github_t
print(f" ❌ Could not retrieve {cmake_file_path} from {branch}")
return False
expected_patterns = [
(f"LEAN_VERSION_MAJOR", rf"^set\(LEAN_VERSION_MAJOR\s+{version_major}[\s)]", f"set(LEAN_VERSION_MAJOR {version_major} ...)"),
(f"LEAN_VERSION_MINOR", rf"^set\(LEAN_VERSION_MINOR\s+{version_minor}[\s)]", f"set(LEAN_VERSION_MINOR {version_minor} ...)"),
(f"LEAN_VERSION_PATCH", rf"^set\(LEAN_VERSION_PATCH\s+0[\s)]", f"set(LEAN_VERSION_PATCH 0 ...)"),
(f"LEAN_VERSION_IS_RELEASE", rf"^set\(LEAN_VERSION_IS_RELEASE\s+1[\s)]", f"set(LEAN_VERSION_IS_RELEASE 1 ...)"),
expected_lines = [
f"set(LEAN_VERSION_MAJOR {version_major})",
f"set(LEAN_VERSION_MINOR {version_minor})",
f"set(LEAN_VERSION_PATCH 0)",
f"set(LEAN_VERSION_IS_RELEASE 1)"
]
for name, pattern, display in expected_patterns:
if not any(re.match(pattern, l.strip()) for l in content.splitlines()):
print(f" ❌ Missing or incorrect line in {cmake_file_path}: {display}")
for line in expected_lines:
if not any(l.strip().startswith(line) for l in content.splitlines()):
print(f" ❌ Missing or incorrect line in {cmake_file_path}: {line}")
return False
print(f" ✅ CMake version settings are correct in {cmake_file_path}")
@@ -343,11 +343,11 @@ def check_stage0_version(repo_url, branch, version_major, version_minor, github_
for line in content.splitlines():
stripped = line.strip()
if stripped.startswith("set(LEAN_VERSION_MAJOR "):
actual = stripped.split()[1].rstrip(")")
actual = stripped.split()[-1].rstrip(")")
if actual != str(version_major):
errors.append(f"LEAN_VERSION_MAJOR: expected {version_major}, found {actual}")
elif stripped.startswith("set(LEAN_VERSION_MINOR "):
actual = stripped.split()[1].rstrip(")")
actual = stripped.split()[-1].rstrip(")")
if actual != str(version_minor):
errors.append(f"LEAN_VERSION_MINOR: expected {version_minor}, found {actual}")

View File

@@ -14,6 +14,13 @@ repositories:
bump-branch: true
dependencies: []
- name: lean4checker
url: https://github.com/leanprover/lean4checker
toolchain-tag: true
stable-branch: true
branch: master
dependencies: []
- name: quote4
url: https://github.com/leanprover-community/quote4
toolchain-tag: true

View File

@@ -8,7 +8,7 @@ endif()
include(ExternalProject)
project(LEAN CXX C)
set(LEAN_VERSION_MAJOR 4 CACHE STRING "")
set(LEAN_VERSION_MINOR 31 CACHE STRING "")
set(LEAN_VERSION_MINOR 30 CACHE STRING "")
set(LEAN_VERSION_PATCH 0 CACHE STRING "")
set(LEAN_VERSION_IS_RELEASE 0 CACHE STRING "") # 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'")
@@ -80,7 +80,6 @@ option(CCACHE "use ccache" ON)
option(SPLIT_STACK "SPLIT_STACK" OFF)
# When OFF we disable LLVM support
option(LLVM "LLVM" OFF)
option(STRIP_BINARIES "Strip produced binaries" ON)
# When ON we include githash in the version string
option(USE_GITHASH "GIT_HASH" ON)
@@ -615,38 +614,6 @@ else()
OUTPUT_VARIABLE GIT_SHA1
OUTPUT_STRIP_TRAILING_WHITESPACE
)
# Fallback for jj workspaces where git cannot find .git directly.
# Use `jj git root` to find the backing git repo, then `jj log` to
# resolve the current workspace's commit (git HEAD points to the root
# workspace, not the current one).
if("${GIT_SHA1}" STREQUAL "")
find_program(JJ_EXECUTABLE jj)
if(JJ_EXECUTABLE)
execute_process(
COMMAND "${JJ_EXECUTABLE}" git root
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
OUTPUT_VARIABLE _jj_git_dir
OUTPUT_STRIP_TRAILING_WHITESPACE
ERROR_QUIET
RESULT_VARIABLE _jj_git_root_result
)
execute_process(
COMMAND "${JJ_EXECUTABLE}" log -r @ --no-graph -T "commit_id"
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
OUTPUT_VARIABLE _jj_commit
OUTPUT_STRIP_TRAILING_WHITESPACE
ERROR_QUIET
RESULT_VARIABLE _jj_rev_result
)
if(_jj_git_root_result EQUAL 0 AND _jj_rev_result EQUAL 0)
execute_process(
COMMAND git --git-dir "${_jj_git_dir}" ls-tree "${_jj_commit}" stage0 --object-only
OUTPUT_VARIABLE GIT_SHA1
OUTPUT_STRIP_TRAILING_WHITESPACE
)
endif()
endif()
endif()
message(STATUS "stage0 sha1: ${GIT_SHA1}")
# Now that we've prepared the information for the next stage, we can forget that we will use
# Lake in the future as we won't use it in this stage
@@ -795,7 +762,7 @@ if(STAGE GREATER 0 AND CADICAL AND INSTALL_CADICAL)
add_dependencies(leancpp copy-cadical)
endif()
if(LEANTAR AND INSTALL_LEANTAR)
if(STAGE GREATER 0 AND LEANTAR AND INSTALL_LEANTAR)
add_custom_target(
copy-leantar
COMMAND cmake -E copy_if_different "${LEANTAR}" "${CMAKE_BINARY_DIR}/bin/leantar${CMAKE_EXECUTABLE_SUFFIX}"
@@ -830,14 +797,7 @@ if(LLVM AND STAGE GREATER 0)
set(EXTRA_LEANMAKE_OPTS "LLVM=1")
endif()
set(
STDLIBS
Init
Std
Lean
Leanc
LeanIR
)
set(STDLIBS Init Std Lean Leanc)
if(NOT CMAKE_SYSTEM_NAME MATCHES "Emscripten")
list(APPEND STDLIBS Lake LeanChecker)
endif()
@@ -944,13 +904,9 @@ if(PREV_STAGE)
add_custom_target(update-stage0-commit COMMAND git commit -m "chore: update stage0" DEPENDS update-stage0)
endif()
if(NOT CMAKE_SYSTEM_NAME MATCHES "Emscripten")
add_custom_target(leanir ALL DEPENDS leanshared COMMAND $(MAKE) -f ${CMAKE_BINARY_DIR}/stdlib.make leanir VERBATIM)
endif()
# use Bash version for building, use Lean version in bin/ for tests & distribution
configure_file("${LEAN_SOURCE_DIR}/bin/leanc.in" "${CMAKE_BINARY_DIR}/leanc.sh" @ONLY)
if(STAGE GREATER 0 AND NOT CMAKE_SYSTEM_NAME MATCHES "Emscripten")
if(STAGE GREATER 0 AND EXISTS "${LEAN_SOURCE_DIR}/Leanc.lean" AND NOT CMAKE_SYSTEM_NAME MATCHES "Emscripten")
configure_file("${LEAN_SOURCE_DIR}/Leanc.lean" "${CMAKE_BINARY_DIR}/leanc/Leanc.lean" @ONLY)
add_custom_target(
leanc
@@ -970,7 +926,7 @@ if(STAGE GREATER 0 AND CADICAL AND INSTALL_CADICAL)
install(PROGRAMS "${CADICAL}" DESTINATION bin)
endif()
if(LEANTAR AND INSTALL_LEANTAR)
if(STAGE GREATER 0 AND LEANTAR AND INSTALL_LEANTAR)
install(PROGRAMS "${LEANTAR}" DESTINATION bin)
endif()

View File

@@ -37,7 +37,7 @@ set_option linter.unusedVariables false in -- `s` unused
Use a monadic action that may throw an exception by providing explicit success and failure
continuations.
-/
@[always_inline, inline, expose]
@[always_inline, inline]
def runK {ε α : Type u} (x : ExceptCpsT ε m α) (s : ε) (ok : α m β) (error : ε m β) : m β :=
x _ ok error
@@ -83,8 +83,6 @@ of `True`.
-/
instance : MonadAttach (ExceptCpsT ε m) := .trivial
@[simp] theorem throw_bind [Monad m] (e : ε) (f : α ExceptCpsT ε m β) : (throw e >>= f : ExceptCpsT ε m β) = throw e := rfl
@[simp] theorem run_pure [Monad m] : run (pure x : ExceptCpsT ε m α) = pure (Except.ok x) := rfl
@[simp] theorem run_lift {α ε : Type u} [Monad m] (x : m α) : run (ExceptCpsT.lift x : ExceptCpsT ε m α) = (x >>= fun a => pure (Except.ok a) : m (Except ε α)) := rfl
@@ -93,20 +91,7 @@ instance : MonadAttach (ExceptCpsT ε m) := .trivial
@[simp] theorem run_bind_lift [Monad m] (x : m α) (f : α ExceptCpsT ε m β) : run (ExceptCpsT.lift x >>= f : ExceptCpsT ε m β) = x >>= fun a => run (f a) := rfl
@[deprecated throw_bind (since := "2026-03-13")]
theorem run_bind_throw [Monad m] (e : ε) (f : α ExceptCpsT ε m β) : run (throw e >>= f : ExceptCpsT ε m β) = run (throw e) := rfl
@[simp] theorem runK_pure :
runK (pure x : ExceptCpsT ε m α) s ok error = ok x := rfl
@[simp] theorem runK_lift {α ε : Type u} [Monad m] (x : m α) (s : ε) (ok : α m β) (error : ε m β) :
runK (ExceptCpsT.lift x : ExceptCpsT ε m α) s ok error = x >>= ok := rfl
@[simp] theorem runK_throw [Monad m] :
runK (throw e : ExceptCpsT ε m β) s ok error = error e := rfl
@[simp] theorem runK_bind_lift [Monad m] (x : m α) (f : α ExceptCpsT ε m β) :
runK (ExceptCpsT.lift x >>= f : ExceptCpsT ε m β) s ok error = x >>= fun a => runK (f a) s ok error := rfl
@[simp] theorem run_bind_throw [Monad m] (e : ε) (f : α ExceptCpsT ε m β) : run (throw e >>= f : ExceptCpsT ε m β) = run (throw e) := rfl
@[simp] theorem runCatch_pure [Monad m] : runCatch (pure x : ExceptCpsT α m α) = pure x := rfl
@@ -117,7 +102,6 @@ theorem run_bind_throw [Monad m] (e : ε) (f : α → ExceptCpsT ε m β) : run
@[simp] theorem runCatch_bind_lift [Monad m] (x : m α) (f : α ExceptCpsT β m β) : runCatch (ExceptCpsT.lift x >>= f : ExceptCpsT β m β) = x >>= fun a => runCatch (f a) := rfl
@[deprecated throw_bind (since := "2026-03-13")]
theorem runCatch_bind_throw [Monad m] (e : β) (f : α ExceptCpsT β m β) : runCatch (throw e >>= f : ExceptCpsT β m β) = pure e := rfl
@[simp] theorem runCatch_bind_throw [Monad m] (e : β) (f : α ExceptCpsT β m β) : runCatch (throw e >>= f : ExceptCpsT β m β) = pure e := rfl
end ExceptCpsT

View File

@@ -72,11 +72,11 @@ public instance [Monad m] [LawfulMonad m] [MonadAttach m] [LawfulMonadAttach m]
public instance [Monad m] [MonadAttach m] [LawfulMonad m] [WeaklyLawfulMonadAttach m] :
WeaklyLawfulMonadAttach (StateRefT' ω σ m) :=
inferInstanceAs (WeaklyLawfulMonadAttach (ReaderT (ST.Ref ω σ) m))
inferInstanceAs (WeaklyLawfulMonadAttach (ReaderT _ _))
public instance [Monad m] [MonadAttach m] [LawfulMonad m] [LawfulMonadAttach m] :
LawfulMonadAttach (StateRefT' ω σ m) :=
inferInstanceAs (LawfulMonadAttach (ReaderT (ST.Ref ω σ) m))
inferInstanceAs (LawfulMonadAttach (ReaderT _ _))
section

View File

@@ -103,11 +103,11 @@ namespace StateRefT'
instance {ω σ : Type} {m : Type Type} [Monad m] : LawfulMonadLift m (StateRefT' ω σ m) where
monadLift_pure _ := by
simp only [MonadLift.monadLift, pure]
unfold StateRefT'.lift instMonad._aux_5 ReaderT.pure
unfold StateRefT'.lift ReaderT.pure
simp only
monadLift_bind _ _ := by
simp only [MonadLift.monadLift, bind]
unfold StateRefT'.lift instMonad._aux_13 ReaderT.bind
unfold StateRefT'.lift ReaderT.bind
simp only
end StateRefT'

View File

@@ -60,6 +60,9 @@ with functions defined via well-founded recursion or partial fixpoints.
The proofs produced by `cbv` only use the three standard axioms.
In particular, they do not require trust in the correctness of the code
generator.
This tactic is experimental and its behavior is likely to change in upcoming
releases of Lean.
-/
syntax (name := cbv) "cbv" : conv

View File

@@ -172,8 +172,6 @@ instance thunkCoe : CoeTail α (Thunk α) where
-- Since coercions are expanded eagerly, `a` is evaluated lazily.
coe a := fun _ => a
instance [Inhabited α] : Inhabited (Thunk α) := .pure default
/-- A variation on `Eq.ndrec` with the equality argument first. -/
abbrev Eq.ndrecOn.{u1, u2} {α : Sort u2} {a : α} {motive : α Sort u1} {b : α} (h : a = b) (m : motive a) : motive b :=
Eq.ndrec m h

View File

@@ -98,7 +98,7 @@ well-founded recursion mechanism to prove that the function terminates.
@[simp] theorem pmap_push {P : α Prop} (f : a, P a β) (a : α) (xs : Array α) (h : b xs.push a, P b) :
pmap f (xs.push a) h =
(pmap f xs (fun a m => by simp [forall_or_eq_imp] at h; exact h.1 _ m)).push (f a (h a (by simp))) := by
(pmap f xs (fun a m => by simp at h; exact h.1 _ m)).push (f a (h a (by simp))) := by
simp [pmap]
@[simp] theorem attach_empty : (#[] : Array α).attach = #[] := rfl
@@ -153,7 +153,7 @@ theorem attachWith_congr {xs ys : Array α} (w : xs = ys) {P : α → Prop} {H :
@[simp] theorem attachWith_push {a : α} {xs : Array α} {P : α Prop} {H : x xs.push a, P x} :
(xs.push a).attachWith P H =
(xs.attachWith P (fun x h => by simp [forall_or_eq_imp] at H; exact H.1 _ h)).push a, H a (by simp) := by
(xs.attachWith P (fun x h => by simp at H; exact H.1 _ h)).push a, H a (by simp) := by
cases xs
simp

View File

@@ -559,9 +559,9 @@ def modifyOp (xs : Array α) (idx : Nat) (f : αα) : Array α :=
xs.modify idx f
/--
We claim this unsafe implementation is correct because an array cannot have more than `USize.size` elements in our runtime.
We claim this unsafe implementation is correct because an array cannot have more than `usizeSz` elements in our runtime.
This kind of low level trick can be removed with a little bit of compiler support. For example, if the compiler simplifies `as.size < USize.size` to true. -/
This kind of low level trick can be removed with a little bit of compiler support. For example, if the compiler simplifies `as.size < usizeSz` to true. -/
@[inline] unsafe def forIn'Unsafe {α : Type u} {β : Type v} {m : Type v Type w} [Monad m] (as : Array α) (b : β) (f : (a : α) a as β m (ForInStep β)) : m β :=
let sz := as.usize
let rec @[specialize] loop (i : USize) (b : β) : m β := do

View File

@@ -113,7 +113,7 @@ public theorem _root_.List.min?_toArray [Min α] {l : List α} :
· simp [List.min_toArray, List.min_eq_get_min?, - List.get_min?]
· simp_all
@[simp, grind =, cbv_eval ]
@[simp, grind =]
public theorem min?_toList [Min α] {xs : Array α} :
xs.toList.min? = xs.min? := by
cases xs; simp
@@ -153,7 +153,7 @@ public theorem _root_.List.max?_toArray [Max α] {l : List α} :
· simp [List.max_toArray, List.max_eq_get_max?, - List.get_max?]
· simp_all
@[simp, grind =, cbv_eval ]
@[simp, grind =]
public theorem max?_toList [Max α] {xs : Array α} :
xs.toList.max? = xs.max? := by
cases xs; simp

View File

@@ -134,7 +134,6 @@ theorem Array.toList_mergeSort {xs : Array α} {le : αα → Bool} :
(xs.mergeSort le).toList = xs.toList.mergeSort le := by
rw [Array.mergeSort, Subarray.toList_mergeSort, Array.toList_mkSlice_rii]
@[cbv_eval]
theorem Array.mergeSort_eq_toArray_mergeSort_toList {xs : Array α} {le : α α Bool} :
xs.mergeSort le = (xs.toList.mergeSort le).toArray := by
simp [ toList_mergeSort]

View File

@@ -36,8 +36,6 @@ theorem BEq.symm [BEq α] [Std.Symm (α := α) (· == ·)] {a b : α} : a == b
theorem BEq.comm [BEq α] [PartialEquivBEq α] {a b : α} : (a == b) = (b == a) :=
Bool.eq_iff_iff.2 BEq.symm, BEq.symm
theorem bne_eq [BEq α] {a b : α} : (a != b) = !(a == b) := rfl
theorem bne_comm [BEq α] [PartialEquivBEq α] {a b : α} : (a != b) = (b != a) := by
rw [bne, BEq.comm, bne]
@@ -66,8 +64,3 @@ theorem BEq.neq_of_beq_of_neq [BEq α] [PartialEquivBEq α] {a b c : α} :
instance (priority := low) [BEq α] [LawfulBEq α] : EquivBEq α where
symm h := beq_iff_eq.2 <| Eq.symm <| beq_iff_eq.1 h
trans hab hbc := beq_iff_eq.2 <| (beq_iff_eq.1 hab).trans <| beq_iff_eq.1 hbc
theorem equivBEq_of_iff_apply_eq [BEq α] (f : α β) (hf : a b, a == b f a = f b) : EquivBEq α where
rfl := by simp [hf]
symm := by simp [hf, eq_comm]
trans hab hbc := (hf _ _).2 (Eq.trans ((hf _ _).1 hab) ((hf _ _).1 hbc))

View File

@@ -20,20 +20,12 @@ universe u
namespace ByteArray
@[extern "lean_sarray_dec_eq"]
def beq (lhs rhs : @& ByteArray) : Bool :=
lhs.data == rhs.data
instance : BEq ByteArray where
beq := beq
deriving instance BEq for ByteArray
attribute [ext] ByteArray
@[extern "lean_sarray_dec_eq"]
def decEq (lhs rhs : @& ByteArray) : Decidable (lhs = rhs) :=
decidable_of_decidable_of_iff ByteArray.ext_iff.symm
instance : DecidableEq ByteArray := decEq
instance : DecidableEq ByteArray :=
fun _ _ => decidable_of_decidable_of_iff ByteArray.ext_iff.symm
instance : Inhabited ByteArray where
default := empty

View File

@@ -86,20 +86,4 @@ theorem toUInt8_val {c : Char} : c.val.toUInt8 = c.toUInt8 := rfl
@[simp]
theorem toString_eq_singleton {c : Char} : c.toString = String.singleton c := rfl
@[simp]
theorem toNat_val {c : Char} : c.val.toNat = c.toNat := rfl
theorem val_inj {c d : Char} : c.val = d.val c = d :=
Char.ext_iff.symm
theorem toNat_inj {c d : Char} : c.toNat = d.toNat c = d := by
simp [ toNat_val, val_inj, UInt32.toNat_inj]
theorem isDigit_iff_toNat {c : Char} : c.isDigit '0'.toNat c.toNat c.toNat '9'.toNat := by
simp [isDigit, UInt32.le_iff_toNat_le]
@[simp]
theorem toNat_mk {val : UInt32} {h} : (Char.mk val h).toNat = val.toNat := by
simp [ toNat_val]
end Char

View File

@@ -217,7 +217,7 @@ theorem succ?_eq {c : Char} : c.succ? = (c.ordinal.addNat? 1).map Char.ofOrdinal
Nat.reduceLeDiff, UInt32.left_eq_add]
grind [UInt32.lt_iff_toNat_lt]
· grind
· simp [coe_ordinal, -toNat_val]
· simp [coe_ordinal]
grind [UInt32.lt_iff_toNat_lt]
| case2 =>
rw [Fin.addNat?_eq_some]

View File

@@ -527,14 +527,6 @@ theorem castLE_of_eq {m n : Nat} (h : m = n) {h' : m ≤ n} : castLE h' = Fin.ca
@[simp, grind =] theorem val_castAdd (m : Nat) (i : Fin n) : (castAdd m i : Nat) = i := rfl
/-
**Note**
The current pattern inference heuristic includes the implicit term `n + m` as pattern of the pattern,
but arithmetic is problematic in patterns because it is an interpreted symbol. For example,
we will fail to match `@val n (castNat 0 i)`. Thus, we mark the implicit subterm with `no_index`
-/
grind_pattern val_castAdd => @val (no_index _) (castAdd m i)
@[deprecated val_castAdd (since := "2025-11-21")]
theorem coe_castAdd (m : Nat) (i : Fin n) : (castAdd m i : Nat) = i := rfl
@@ -645,15 +637,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] theorem val_addNat (m : Nat) (i : Fin n) : (addNat i m : Nat) = i + m := rfl
/-
**Note**
The current pattern inference heuristic includes the implicit term `n + m` as pattern of the pattern,
but arithmetic is problematic in patterns because it is an interpreted symbol. For example,
we will fail to match `@val n (addNat i 0)`. Thus, we mark the implicit subterm with `no_index`
-/
grind_pattern val_addNat => @val (no_index _) (addNat i m)
@[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

View File

@@ -18,4 +18,3 @@ public import Init.Data.Int.Pow
public import Init.Data.Int.Cooper
public import Init.Data.Int.Linear
public import Init.Data.Int.OfNat
public import Init.Data.Int.ToString

View File

@@ -1,24 +0,0 @@
/-
Copyright (c) 2016 Microsoft Corporation. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Author: Leonardo de Moura
-/
module
prelude
public import Init.Data.Repr
public import Init.Data.String.Defs
namespace Int
/--
Returns the decimal string representation of an integer.
-/
public protected def repr : Int String
| ofNat m => Nat.repr m
| negSucc m => "-" ++ Nat.repr (Nat.succ m)
public instance : Repr Int where
reprPrec i prec := if i < 0 then Repr.addAppParen i.repr prec else i.repr
end Int

View File

@@ -1,23 +0,0 @@
/-
Copyright (c) 2026 Lean FRO, LLC. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Julia Markus Himmel
-/
module
prelude
public import Init.Data.ToString.Extra
import all Init.Data.Int.Repr
import Init.Data.Int.Order
import Init.Data.Int.LemmasAux
namespace Int
public theorem repr_eq_if {a : Int} :
a.repr = if 0 a then a.toNat.repr else "-" ++ (-a).toNat.repr := by
cases a <;> simp [Int.repr]
@[simp]
public theorem toString_eq_repr {a : Int} : toString a = a.repr := (rfl)
end Int

View File

@@ -37,7 +37,7 @@ The standard library does not provide a `Productive` instance for this case.
This combinator incurs an additional O(1) cost with each output of `it₁` and `it₂`.
-/
@[cbv_opaque, inline, expose]
@[inline, expose]
def Iter.append {α₁ : Type w} {α₂ : Type w} {β : Type w}
[Iterator α₁ Id β] [Iterator α₂ Id β]
(it₁ : Iter (α := α₁) β) (it₂ : Iter (α := α₂) β) :

View File

@@ -13,7 +13,7 @@ public section
namespace Std
open Std.Iterators
@[cbv_opaque, always_inline, inline, expose, inherit_doc IterM.attachWith]
@[always_inline, inline, expose, inherit_doc IterM.attachWith]
def Iter.attachWith {α β : Type w}
[Iterator α Id β]
(it : Iter (α := α) β) (P : β Prop) (h : out, it.IsPlausibleIndirectOutput out P out) :

View File

@@ -282,17 +282,17 @@ def Iter.mapM {α β γ : Type w} [Iterator α Id β] {m : Type w → Type w'}
[Monad m] [MonadAttach m] (f : β m γ) (it : Iter (α := α) β) :=
(letI : MonadLift Id m := pure; it.toIterM.mapM f : IterM m γ)
@[cbv_opaque, always_inline, inline, inherit_doc IterM.filterMap, expose]
@[always_inline, inline, inherit_doc IterM.filterMap, expose]
def Iter.filterMap {α : Type w} {β : Type w} {γ : Type w} [Iterator α Id β]
(f : β Option γ) (it : Iter (α := α) β) :=
((it.toIterM.filterMap f).toIter : Iter γ)
@[cbv_opaque, always_inline, inline, inherit_doc IterM.filter, expose]
@[always_inline, inline, inherit_doc IterM.filter, expose]
def Iter.filter {α : Type w} {β : Type w} [Iterator α Id β]
(f : β Bool) (it : Iter (α := α) β) :=
((it.toIterM.filter f).toIter : Iter β)
@[cbv_opaque, always_inline, inline, inherit_doc IterM.map, expose]
@[always_inline, inline, inherit_doc IterM.map, expose]
def Iter.map {α : Type w} {β : Type w} {γ : Type w} [Iterator α Id β]
(f : β γ) (it : Iter (α := α) β) :=
((it.toIterM.map f).toIter : Iter γ)

View File

@@ -44,7 +44,7 @@ public def Iter.flatMapAfter {α : Type w} {β : Type w} {α₂ : Type w}
(f : β Iter (α := α₂) γ) (it₁ : Iter (α := α) β) (it₂ : Option (Iter (α := α₂) γ)) :=
((it₁.toIterM.flatMapAfter (fun b => (f b).toIterM) (Iter.toIterM <$> it₂)).toIter : Iter γ)
@[cbv_opaque, always_inline, expose, inherit_doc IterM.flatMap]
@[always_inline, expose, inherit_doc IterM.flatMap]
public def Iter.flatMap {α : Type w} {β : Type w} {α₂ : Type w}
{γ : Type w} [Iterator α Id β] [Iterator α₂ Id γ]
(f : β Iter (α := α₂) γ) (it : Iter (α := α) β) :=

View File

@@ -168,13 +168,6 @@ instance Map.instIterator {α β γ : Type w} {m : Type w → Type w'} {n : Type
Iterator (Map α m n lift f) n γ :=
inferInstanceAs <| Iterator (FilterMap α m n lift _) n γ
theorem Map.instIterator_eq_filterMapInstIterator {α β γ : Type w} {m : Type w Type w'}
{n : Type w Type w''} [Monad n]
[Iterator α m β] {lift : α : Type w m α n α} {f : β PostconditionT n γ} :
Map.instIterator (α := α) (β := β) (γ := γ) (m := m) (n := n) (lift := lift) (f := f) =
FilterMap.instIterator :=
rfl
private def FilterMap.instFinitenessRelation {α β γ : 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] :

View File

@@ -36,7 +36,7 @@ it.take 3 ---a--⊥
This combinator incurs an additional O(1) cost with each output of `it`.
-/
@[cbv_opaque, always_inline, inline]
@[always_inline, inline]
def Iter.take {α : Type w} {β : Type w} [Iterator α Id β] (n : Nat) (it : Iter (α := α) β) :
Iter (α := Take α Id) β :=
it.toIterM.take n |>.toIter

View File

@@ -44,7 +44,7 @@ it.uLift n ---.up a----.up b---.up c--.up d---⊥
* `Finite`: only if the original iterator is finite
* `Productive`: only if the original iterator is productive
-/
@[cbv_opaque, always_inline, inline, expose]
@[always_inline, inline, expose]
def Iter.uLift (it : Iter (α := α) β) :
Iter (α := Types.ULiftIterator.{v} α Id Id β (fun _ => monadLift)) (ULift β) :=
(it.toIterM.uLift Id).toIter

View File

@@ -32,7 +32,7 @@ Traverses the given iterator and stores the emitted values in an array.
If the iterator is not finite, this function might run forever. The variant
`it.ensureTermination.toArray` always terminates after finitely many steps.
-/
@[cbv_opaque, always_inline, inline]
@[always_inline, inline]
def Iter.toArray {α : Type w} {β : Type w}
[Iterator α Id β] (it : Iter (α := α) β) : Array β :=
it.toIterM.toArray.run
@@ -66,7 +66,7 @@ lists are prepend-only, this `toListRev` is usually more efficient that `toList`
If the iterator is not finite, this function might run forever. The variant
`it.ensureTermination.toListRev` always terminates after finitely many steps.
-/
@[always_inline, inline, cbv_opaque]
@[always_inline, inline]
def Iter.toListRev {α : Type w} {β : Type w}
[Iterator α Id β] (it : Iter (α := α) β) : List β :=
it.toIterM.toListRev.run
@@ -101,7 +101,7 @@ lists are prepend-only, `toListRev` is usually more efficient that `toList`.
If the iterator is not finite, this function might run forever. The variant
`it.ensureTermination.toList` always terminates after finitely many steps.
-/
@[cbv_opaque, always_inline, inline]
@[always_inline, inline]
def Iter.toList {α : Type w} {β : Type w}
[Iterator α Id β] (it : Iter (α := α) β) : List β :=
it.toIterM.toList.run

View File

@@ -226,7 +226,7 @@ any element emitted by the iterator {name}`it`.
{lit}`O(|xs|)`. Short-circuits upon encountering the first match. The elements in {name}`it` are
examined in order of iteration.
-/
@[inline, cbv_opaque]
@[inline]
def Iter.any {α β : Type w}
[Iterator α Id β] [IteratorLoop α Id Id]
(p : β Bool) (it : Iter (α := α) β) : Bool :=
@@ -292,7 +292,7 @@ all element emitted by the iterator {name}`it`.
{lit}`O(|xs|)`. Short-circuits upon encountering the first match. The elements in {name}`it` are
examined in order of iteration.
-/
@[inline, cbv_opaque]
@[inline]
def Iter.all {α β : Type w}
[Iterator α Id β] [IteratorLoop α Id Id]
(p : β Bool) (it : Iter (α := α) β) : Bool :=
@@ -644,7 +644,7 @@ Examples:
* `[7, 6].iter.first? = some 7`
* `[].iter.first? = none`
-/
@[inline, cbv_opaque]
@[inline]
def Iter.first? {α β : Type w} [Iterator α Id β] [IteratorLoop α Id Id]
(it : Iter (α := α) β) : Option β :=
it.toIterM.first?.run

View File

@@ -56,7 +56,7 @@ theorem Iter.Intermediate.step_appendSnd {α₁ α₂ β : Type w}
simp only [Iter.step, appendSnd, toIterM_toIter, IterM.Intermediate.step_appendSnd, Id.run_bind]
cases it₂.toIterM.step.run.inflate using PlausibleIterStep.casesOn <;> simp
@[cbv_eval, simp]
@[simp]
theorem Iter.toList_append {α₁ α₂ β : Type w}
[Iterator α₁ Id β] [Iterator α₂ Id β] [Finite α₁ Id] [Finite α₂ Id]
{it₁ : Iter (α := α₁) β} {it₂ : Iter (α := α₂) β} :
@@ -70,7 +70,7 @@ theorem Iter.toListRev_append {α₁ α₂ β : Type w}
(it₁.append it₂).toListRev = it₂.toListRev ++ it₁.toListRev := by
simp [append_eq_toIter_append_toIterM, toListRev_eq_toListRev_toIterM]
@[cbv_eval, simp]
@[simp]
theorem Iter.toArray_append {α₁ α₂ β : Type w}
[Iterator α₁ Id β] [Iterator α₂ Id β] [Finite α₁ Id] [Finite α₂ Id]
{it₁ : Iter (α := α₁) β} {it₂ : Iter (α := α₂) β} :

View File

@@ -34,7 +34,7 @@ theorem Iter.unattach_toList_attachWith [Iterator α Id β]
Id.run_map (f := List.unattach), IterM.map_unattach_toList_attachWith,
Iter.toList_eq_toList_toIterM]
@[cbv_eval, simp]
@[simp]
theorem Iter.toList_attachWith [Iterator α Id β]
{it : Iter (α := α) β} {hP}
[Finite α Id] :
@@ -68,7 +68,7 @@ theorem Iter.unattach_toArray_attachWith [Iterator α Id β]
(it.attachWith P hP).toListRev.unattach = it.toListRev := by
simp [toListRev_eq]
@[cbv_eval, simp]
@[simp]
theorem Iter.toArray_attachWith [Iterator α Id β]
{it : Iter (α := α) β} {hP}
[Finite α Id] :

View File

@@ -297,7 +297,7 @@ def Iter.val_step_filter {f : β → Bool} :
· simp
· simp
@[cbv_eval, simp]
@[simp]
theorem Iter.toList_filterMap [Finite α Id]
{f : β Option γ} :
(it.filterMap f).toList = it.toList.filterMap f := by
@@ -315,12 +315,12 @@ theorem Iter.toList_mapM [Monad m] [MonadAttach m] [LawfulMonad m] [WeaklyLawful
(it.mapM f).toList = it.toList.mapM f := by
simp [Iter.mapM_eq_toIter_mapM_toIterM, IterM.toList_mapM, Iter.toList_eq_toList_toIterM]
@[cbv_eval, simp]
@[simp]
theorem Iter.toList_map [Finite α Id] {f : β γ} :
(it.map f).toList = it.toList.map f := by
simp [map_eq_toIter_map_toIterM, IterM.toList_map, Iter.toList_eq_toList_toIterM]
@[cbv_eval, simp]
@[simp]
theorem Iter.toList_filter [Finite α Id] {f : β Bool} :
(it.filter f).toList = it.toList.filter f := by
simp [filter_eq_toIter_filter_toIterM, IterM.toList_filter, Iter.toList_eq_toList_toIterM]
@@ -369,7 +369,7 @@ theorem Iter.toListRev_filter [Finite α Id]
(it.filter f).toListRev = it.toListRev.filter f := by
simp [filter_eq_toIter_filter_toIterM, IterM.toListRev_filter, Iter.toListRev_eq_toListRev_toIterM]
@[cbv_eval, simp]
@[simp]
theorem Iter.toArray_filterMap [Finite α Id]
{f : β Option γ} :
(it.filterMap f).toArray = it.toArray.filterMap f := by
@@ -387,13 +387,13 @@ theorem Iter.toArray_mapM [Monad m] [MonadAttach m] [LawfulMonad m] [WeaklyLawfu
(it.mapM f).toArray = it.toArray.mapM f := by
simp [Iter.mapM_eq_toIter_mapM_toIterM, IterM.toArray_mapM, Iter.toArray_eq_toArray_toIterM]
@[cbv_eval, simp]
@[simp]
theorem Iter.toArray_map [Finite α Id] {f : β γ} :
(it.map f).toArray = it.toArray.map f := by
simp [map_eq_toIter_map_toIterM, IterM.toArray_map, Iter.toArray_eq_toArray_toIterM]
@[cbv_eval, simp]
theorem Iter.toArray_filter [Finite α Id] {f : β Bool} :
@[simp]
theorem Iter.toArray_filter[Finite α Id] {f : β Bool} :
(it.filter f).toArray = it.toArray.filter f := by
simp [filter_eq_toIter_filter_toIterM, IterM.toArray_filter, Iter.toArray_eq_toArray_toIterM]

View File

@@ -254,7 +254,6 @@ public theorem Iter.toArray_flatMapAfter {α α₂ β γ : Type w} [Iterator α
unfold Iter.toArray
cases it₂ <;> simp [map, IterM.toArray_map_eq_toArray_mapM, - IterM.toArray_map]
@[cbv_eval]
public theorem Iter.toList_flatMap {α α₂ β γ : Type w} [Iterator α Id β] [Iterator α₂ Id γ]
[Finite α Id] [Finite α₂ Id]
[Iterator α Id β] [Iterator α₂ Id γ] [Finite α Id] [Finite α₂ Id]
@@ -262,7 +261,6 @@ public theorem Iter.toList_flatMap {α α₂ β γ : Type w} [Iterator α Id β]
(it₁.flatMap f).toList = (it₁.map fun b => (f b).toList).toList.flatten := by
simp [flatMap, toList_flatMapAfter]
@[cbv_eval]
public theorem Iter.toArray_flatMap {α α₂ β γ : Type w} [Iterator α Id β] [Iterator α₂ Id γ]
[Finite α Id] [Finite α₂ Id]
[Iterator α Id β] [Iterator α₂ Id γ] [Finite α Id] [Finite α₂ Id]

View File

@@ -699,16 +699,18 @@ theorem IterM.toList_map {α β β' : Type w} {m : Type w → Type w'} [Monad m]
(it : IterM (α := α) m β) :
(it.map f).toList = (fun x => x.map f) <$> it.toList := by
rw [ List.filterMap_eq_map, toList_filterMap]
simp only [map, mapWithPostcondition, InternalCombinators.map, filterMap,
filterMapWithPostcondition, InternalCombinators.filterMap]
unfold Map
let t := type_of% (it.map f)
let t' := type_of% (it.filterMap (some f))
congr
· simp
· rw [Map.instIterator_eq_filterMapInstIterator]
· simp [Map]
· simp [Map.instIterator, inferInstanceAs]
congr
simp
· simp
· simp
· simp only [map, mapWithPostcondition, InternalCombinators.map, Function.comp_apply, filterMap,
filterMapWithPostcondition, InternalCombinators.filterMap]
congr
· simp [Map]
· simp
@[simp]
theorem IterM.toList_filter {α : Type w} {m : Type w Type w'} [Monad m] [LawfulMonad m]
@@ -1308,8 +1310,7 @@ theorem IterM.forIn_mapWithPostcondition
haveI : MonadLift n o := monadLift
forIn (it.mapWithPostcondition f) init g =
forIn it init (fun out acc => do g ( (f out).run) acc) := by
unfold mapWithPostcondition InternalCombinators.map Map.instIteratorLoop Map
rw [Map.instIterator_eq_filterMapInstIterator]
unfold mapWithPostcondition InternalCombinators.map Map.instIterator Map.instIteratorLoop Map
rw [ InternalCombinators.filterMap, filterMapWithPostcondition, forIn_filterMapWithPostcondition]
simp

View File

@@ -67,7 +67,7 @@ theorem Iter.atIdxSlow?_take {α β}
simp only [atIdxSlow?_eq_match (it := it.take k), step_take, h']
cases k <;> cases l <;> simp
@[cbv_eval, simp]
@[simp]
theorem Iter.toList_take_of_finite {α β} [Iterator α Id β] {n : Nat}
[Finite α Id] {it : Iter (α := α) β} :
(it.take n).toList = it.toList.take n := by
@@ -89,7 +89,7 @@ theorem Iter.toListRev_take_of_finite {α β} [Iterator α Id β] {n : Nat}
(it.take n).toListRev = it.toListRev.drop (it.toList.length - n) := by
rw [toListRev_eq, toList_take_of_finite, List.reverse_take, toListRev_eq]
@[cbv_eval, simp]
@[simp]
theorem Iter.toArray_take_of_finite {α β} [Iterator α Id β] {n : Nat}
[Finite α Id] {it : Iter (α := α) β} :
(it.take n).toArray = it.toArray.take n := by

View File

@@ -38,7 +38,7 @@ theorem Iter.step_uLift [Iterator α Id β] {it : Iter (α := α) β} :
PlausibleIterStep.done, pure_bind]
cases it.toIterM.step.run.inflate using PlausibleIterStep.casesOn <;> simp
@[cbv_eval, simp]
@[simp]
theorem Iter.toList_uLift [Iterator α Id β] {it : Iter (α := α) β}
[Finite α Id] :
it.uLift.toList = it.toList.map ULift.up := by
@@ -52,7 +52,7 @@ theorem Iter.toListRev_uLift [Iterator α Id β] {it : Iter (α := α) β}
it.uLift.toListRev = it.toListRev.map ULift.up := by
rw [toListRev_eq, toListRev_eq, toList_uLift, List.map_reverse]
@[cbv_eval, simp]
@[simp]
theorem Iter.toArray_uLift [Iterator α Id β] {it : Iter (α := α) β}
[Finite α Id] :
it.uLift.toArray = it.toArray.map ULift.up := by

View File

@@ -88,7 +88,7 @@ theorem Iter.toList_toArray_ensureTermination {α β} [Iterator α Id β] [Finit
it.ensureTermination.toArray.toList = it.toList := by
simp
@[cbv_eval , simp]
@[simp]
theorem Iter.toArray_toList {α β} [Iterator α Id β] [Finite α Id]
{it : Iter (α := α) β} :
it.toList.toArray = it.toArray := by
@@ -110,7 +110,6 @@ theorem Iter.reverse_toListRev_ensureTermination [Iterator α Id β] [Finite α
it.ensureTermination.toListRev.reverse = it.toList := by
simp
@[cbv_eval]
theorem Iter.toListRev_eq {α β} [Iterator α Id β] [Finite α Id]
{it : Iter (α := α) β} :
it.toListRev = it.toList.reverse := by

View File

@@ -449,7 +449,7 @@ theorem Iter.toArray_eq_fold {α β : Type w} [Iterator α Id β]
rw [ fold_hom (List.toArray)]
simp
@[cbv_eval , simp]
@[simp]
theorem Iter.foldl_toList {α β : Type w} {γ : Type x} [Iterator α Id β] [Finite α Id]
[IteratorLoop α Id Id] [LawfulIteratorLoop α Id Id]
{f : γ β γ} {init : γ} {it : Iter (α := α) β} :
@@ -637,7 +637,6 @@ theorem Iter.any_eq_forIn {α β : Type w} [Iterator α Id β]
return .yield false)).run := by
simp [any_eq_anyM, anyM_eq_forIn]
@[cbv_eval ]
theorem Iter.any_toList {α β : Type w} [Iterator α Id β]
[Finite α Id] [IteratorLoop α Id Id] [LawfulIteratorLoop α Id Id]
{it : Iter (α := α) β} {p : β Bool} :
@@ -728,7 +727,6 @@ theorem Iter.all_eq_forIn {α β : Type w} [Iterator α Id β]
return .done false)).run := by
simp [all_eq_allM, allM_eq_forIn]
@[cbv_eval ]
theorem Iter.all_toList {α β : Type w} [Iterator α Id β]
[Finite α Id] [IteratorLoop α Id Id] [LawfulIteratorLoop α Id Id]
{it : Iter (α := α) β} {p : β Bool} :
@@ -956,7 +954,7 @@ theorem Iter.first?_eq_match_step {α β : Type w} [Iterator α Id β] [Iterator
generalize it.toIterM.step.run.inflate = s
rcases s with _|_|_, _ <;> simp [Iter.first?_eq_first?_toIterM]
@[simp, grind =, cbv_eval ]
@[simp, grind =]
theorem Iter.head?_toList {α β : Type w} [Iterator α Id β] [IteratorLoop α Id Id]
[Finite α Id] [LawfulIteratorLoop α Id Id] {it : Iter (α := α) β} :
it.toList.head? = it.first? := by

View File

@@ -33,12 +33,12 @@ theorem List.step_iter_cons {x : β} {xs : List β} :
((x :: xs).iter).step = .yield xs.iter x, rfl := by
simp [List.iter, List.iterM, IterM.toIter, Iter.step_eq]
@[cbv_eval, simp, grind =]
@[simp, grind =]
theorem List.toArray_iter {l : List β} :
l.iter.toArray = l.toArray := by
simp [List.iter, List.toArray_iterM, Iter.toArray_eq_toArray_toIterM]
@[cbv_eval, simp, grind =]
@[simp, grind =]
theorem List.toList_iter {l : List β} :
l.iter.toList = l := by
simp [List.iter, List.toList_iterM]

View File

@@ -29,7 +29,7 @@ The monadic version of this iterator is `List.iterM`.
* `Finite` instance: always
* `Productive` instance: always
-/
@[cbv_opaque, always_inline, inline]
@[always_inline, inline]
def List.iter {α : Type w} (l : List α) :
Iter (α := ListIterator α) α :=
((l.iterM Id).toIter : Iter α)

View File

@@ -46,7 +46,7 @@ The non-monadic version of this iterator is `List.iter`.
* `Finite` instance: always
* `Productive` instance: always
-/
@[cbv_opaque, always_inline, inline]
@[always_inline, inline]
def _root_.List.iterM {α : Type w} (l : List α) (m : Type w Type w') [Pure m] :
IterM (α := ListIterator α) m α :=
{ list := l }

View File

@@ -1246,24 +1246,6 @@ def IsInfix (l₁ : List α) (l₂ : List α) : Prop := Exists fun s => Exists f
/-- not `isInfix` -/
recommended_spelling "infix" for "<:+:" in [IsInfix, «term_<:+:_»]
/--
Checks whether the first list is a contiguous sub-list of the second.
The relation `List.IsInfixOf` expresses this property with respect to logical equality.
Examples:
* `[2, 3].isInfixOf_internal [1, 2, 3, 4] = true`
* `[2, 3].isInfixOf_internal [1, 3, 2, 4] = false`
* `[2, 3].isInfixOf_internal [2, 3] = true`
* `[2, 3].isInfixOf_internal [1] = false`
Used internally by the `cbv` tactic.
-/
def isInfixOf_internal [BEq α] (l₁ l₂ : List α) : Bool :=
l₁.isPrefixOf l₂ || match l₂ with
| [] => false
| _ :: l₂ => isInfixOf_internal l₁ l₂
/-! ### splitAt -/
/--

View File

@@ -877,11 +877,6 @@ theorem getLast_eq_iff_getLast?_eq_some {xs : List α} (h) :
theorem getLast?_cons {a : α} : (a::l).getLast? = some (l.getLast?.getD a) := by
cases l <;> simp [getLast?, getLast]
theorem getLast?_cons_of_ne_nil {x : α} {xs : List α} (h : xs []) : (x::xs).getLast? = xs.getLast? := by
cases xs with
| nil => contradiction
| cons => simp [getLast?_cons]
@[simp] theorem getLast?_cons_cons : (a :: b :: l).getLast? = (b :: l).getLast? := by
simp [getLast?_cons]
@@ -1288,13 +1283,6 @@ theorem filter_eq_self {l} : filter p l = l ↔ ∀ a ∈ l, p a := by
cases h : p a <;> simp [*]
intro h; exact Nat.lt_irrefl _ (h length_filter_le p l)
theorem filter_bne_eq_self_of_not_mem [BEq α] [LawfulBEq α] {a : α} {l : List α} (h : a l) :
l.filter (· != a) = l := by
rw [List.filter_eq_self]
intro c hc
simp only [bne_iff_ne, ne_eq]
exact fun heq => absurd (heq hc) h
@[simp]
theorem length_filter_eq_length_iff {l} : (filter p l).length = l.length a l, p a := by
induction l with
@@ -1348,16 +1336,6 @@ theorem foldl_filter {p : α → Bool} {f : β → α → β} {l : List α} {ini
simp only [filter_cons, foldl_cons]
split <;> simp [ih]
theorem foldl_ite_left {P : α Prop} [DecidablePred P] {l : List α} {f : β α β} {init : β} :
(l.foldl (init := init) fun sofar a => if P a then f sofar a else sofar) = (l.filter P).foldl (init := init) f := by
simp [List.foldl_filter]
theorem foldl_ite_right {P : α Prop} [DecidablePred P] {l : List α} {f : β α β} {init : β} :
(l.foldl (init := init) fun sofar a => if P a then sofar else f sofar a) =
(l.filter (fun a => ¬ P a)).foldl (init := init) f := by
simp +singlePass only [ ite_not]
rw [foldl_ite_left]
theorem foldr_filter {p : α Bool} {f : α β β} {l : List α} {init : β} :
(l.filter p).foldr f init = l.foldr (fun x y => if p x then f x y else y) init := by
induction l generalizing init with

View File

@@ -481,13 +481,13 @@ protected theorem maxIdxOn_nil_eq_iff_false [LE β] [DecidableLE β] {f : α
@[simp]
protected theorem maxIdxOn_singleton [LE β] [DecidableLE β] {x : α} {f : α β} :
[x].maxIdxOn f (of_decide_eq_false rfl) = 0 :=
letI : LE β := (inferInstance : LE β).opposite
letI : LE β := (inferInstanceAs (LE β)).opposite
List.minIdxOn_singleton
@[simp]
protected theorem maxIdxOn_lt_length [LE β] [DecidableLE β] {f : α β} {xs : List α}
(h : xs []) : xs.maxIdxOn f h < xs.length :=
letI : LE β := (inferInstance : LE β).opposite
letI : LE β := (inferInstanceAs (LE β)).opposite
List.minIdxOn_lt_length h
protected theorem maxIdxOn_le_of_apply_getElem_le_apply_maxOn [LE β] [DecidableLE β] [IsLinearPreorder β]
@@ -495,7 +495,7 @@ protected theorem maxIdxOn_le_of_apply_getElem_le_apply_maxOn [LE β] [Decidable
{k : Nat} (hi : k < xs.length) (hle : f (xs.maxOn f h) f xs[k]) :
xs.maxIdxOn f h k := by
simp only [List.maxIdxOn_eq_minIdxOn, List.maxOn_eq_minOn] at hle
letI : LE β := (inferInstance : LE β).opposite
letI : LE β := (inferInstanceAs (LE β)).opposite
exact List.minIdxOn_le_of_apply_getElem_le_apply_minOn h hi (by simpa [LE.le_opposite_iff] using hle)
protected theorem apply_maxOn_lt_apply_getElem_of_lt_maxIdxOn [LE β] [DecidableLE β] [LT β] [IsLinearPreorder β]
@@ -513,7 +513,7 @@ protected theorem getElem_maxIdxOn [LE β] [DecidableLE β] [IsLinearPreorder β
{f : α β} {xs : List α} (h : xs []) :
xs[xs.maxIdxOn f h] = xs.maxOn f h := by
simp only [List.maxIdxOn_eq_minIdxOn, List.maxOn_eq_minOn]
letI : LE β := (inferInstance : LE β).opposite
letI : LE β := (inferInstanceAs (LE β)).opposite
exact List.getElem_minIdxOn h
protected theorem le_maxIdxOn_of_apply_getElem_lt_apply_getElem [LE β] [DecidableLE β] [LT β]
@@ -562,14 +562,14 @@ protected theorem maxIdxOn_cons
else if f (xs.maxOn f h) f x then 0
else (xs.maxIdxOn f h) + 1 := by
simp only [List.maxIdxOn_eq_minIdxOn, List.maxOn_eq_minOn]
letI : LE β := (inferInstance : LE β).opposite
letI : LE β := (inferInstanceAs (LE β)).opposite
simpa [LE.le_opposite_iff] using List.minIdxOn_cons (f := f)
protected theorem maxIdxOn_eq_zero_iff [LE β] [DecidableLE β] [IsLinearPreorder β]
{xs : List α} {f : α β} (h : xs []) :
xs.maxIdxOn f h = 0 x xs, f x f (xs.head h) := by
simp only [List.maxIdxOn_eq_minIdxOn]
letI : LE β := (inferInstance : LE β).opposite
letI : LE β := (inferInstanceAs (LE β)).opposite
simpa [LE.le_opposite_iff] using List.minIdxOn_eq_zero_iff h (f := f)
protected theorem maxIdxOn_append [LE β] [DecidableLE β] [IsLinearPreorder β]
@@ -580,26 +580,26 @@ protected theorem maxIdxOn_append [LE β] [DecidableLE β] [IsLinearPreorder β]
else
xs.length + ys.maxIdxOn f hys := by
simp only [List.maxIdxOn_eq_minIdxOn, List.maxOn_eq_minOn]
letI : LE β := (inferInstance : LE β).opposite
letI : LE β := (inferInstanceAs (LE β)).opposite
simpa [LE.le_opposite_iff] using List.minIdxOn_append hxs hys (f := f)
protected theorem left_le_maxIdxOn_append [LE β] [DecidableLE β] [IsLinearPreorder β]
{xs ys : List α} {f : α β} (h : xs []) :
xs.maxIdxOn f h (xs ++ ys).maxIdxOn f (by simp [h]) :=
letI : LE β := (inferInstance : LE β).opposite
letI : LE β := (inferInstanceAs (LE β)).opposite
List.left_le_minIdxOn_append h
protected theorem maxIdxOn_take_le [LE β] [DecidableLE β] [IsLinearPreorder β]
{xs : List α} {f : α β} {i : Nat} (h : xs.take i []) :
(xs.take i).maxIdxOn f h xs.maxIdxOn f (List.ne_nil_of_take_ne_nil h) :=
letI : LE β := (inferInstance : LE β).opposite
letI : LE β := (inferInstanceAs (LE β)).opposite
List.minIdxOn_take_le h
@[simp]
protected theorem maxIdxOn_replicate [LE β] [DecidableLE β] [Refl (α := β) (· ·)]
{n : Nat} {a : α} {f : α β} (h : replicate n a []) :
(replicate n a).maxIdxOn f h = 0 :=
letI : LE β := (inferInstance : LE β).opposite
letI : LE β := (inferInstanceAs (LE β)).opposite
List.minIdxOn_replicate h
@[simp]

View File

@@ -297,13 +297,13 @@ protected theorem maxOn_cons
(x :: xs).maxOn f (by exact of_decide_eq_false rfl) =
if h : xs = [] then x else maxOn f x (xs.maxOn f h) := by
simp only [maxOn_eq_minOn]
letI : LE β := (inferInstance : LE β).opposite
letI : LE β := (inferInstanceAs (LE β)).opposite
exact List.minOn_cons (f := f)
protected theorem maxOn_cons_cons [LE β] [DecidableLE β] {a b : α} {l : List α} {f : α β} :
(a :: b :: l).maxOn f (by simp) = (maxOn f a b :: l).maxOn f (by simp) := by
simp only [List.maxOn_eq_minOn, maxOn_eq_minOn]
letI : LE β := (inferInstance : LE β).opposite
letI : LE β := (inferInstanceAs (LE β)).opposite
exact List.minOn_cons_cons
@[simp]
@@ -334,51 +334,51 @@ protected theorem maxOn_id [Max α] [LE α] [DecidableLE α] [LawfulOrderLeftLea
{xs : List α} (h : xs []) :
xs.maxOn id h = xs.max h := by
simp only [List.maxOn_eq_minOn]
letI : LE α := (inferInstance : LE α).opposite
letI : Min α := (inferInstance : Max α).oppositeMin
letI : LE α := (inferInstanceAs (LE α)).opposite
letI : Min α := (inferInstanceAs (Max α)).oppositeMin
simpa only [List.max_eq_min] using List.minOn_id h
@[simp]
protected theorem maxOn_mem [LE β] [DecidableLE β] {xs : List α}
{f : α β} {h : xs []} : xs.maxOn f h xs :=
letI : LE β := (inferInstance : LE β).opposite
letI : LE β := (inferInstanceAs (LE β)).opposite
List.minOn_mem (f := f)
protected theorem le_apply_maxOn_of_mem [LE β] [DecidableLE β] [IsLinearPreorder β]
{xs : List α} {f : α β} {y : α} (hx : y xs) :
f y f (xs.maxOn f (List.ne_nil_of_mem hx)) := by
rw [List.maxOn_eq_minOn]
letI : LE β := (inferInstance : LE β).opposite
letI : LE β := (inferInstanceAs (LE β)).opposite
simpa [LE.le_opposite_iff] using List.apply_minOn_le_of_mem (f := f) hx
protected theorem apply_maxOn_le_iff [LE β] [DecidableLE β] [IsLinearPreorder β] {xs : List α}
{f : α β} (h : xs []) {b : β} :
f (xs.maxOn f h) b x xs, f x b := by
rw [List.maxOn_eq_minOn]
letI : LE β := (inferInstance : LE β).opposite
letI : LE β := (inferInstanceAs (LE β)).opposite
simpa [LE.le_opposite_iff] using List.le_apply_minOn_iff (f := f) h
protected theorem le_apply_maxOn_iff [LE β] [DecidableLE β] [IsLinearPreorder β] {xs : List α}
{f : α β} (h : xs []) {b : β} :
b f (xs.maxOn f h) x xs, b f x := by
rw [List.maxOn_eq_minOn]
letI : LE β := (inferInstance : LE β).opposite
letI : LE β := (inferInstanceAs (LE β)).opposite
simpa [LE.le_opposite_iff] using List.apply_minOn_le_iff (f := f) h
protected theorem apply_maxOn_lt_iff
[LE β] [DecidableLE β] [LT β] [IsLinearPreorder β] [LawfulOrderLT β]
{xs : List α} {f : α β} (h : xs []) {b : β} :
f (xs.maxOn f h) < b x xs, f x < b := by
letI : LE β := (inferInstance : LE β).opposite
letI : LT β := (inferInstance : LT β).opposite
letI : LE β := (inferInstanceAs (LE β)).opposite
letI : LT β := (inferInstanceAs (LT β)).opposite
simpa [LT.lt_opposite_iff] using List.lt_apply_minOn_iff (f := f) h
protected theorem lt_apply_maxOn_iff
[LE β] [DecidableLE β] [LT β] [IsLinearPreorder β] [LawfulOrderLT β]
{xs : List α} {f : α β} (h : xs []) {b : β} :
b < f (xs.maxOn f h) x xs, b < f x := by
letI : LE β := (inferInstance : LE β).opposite
letI : LT β := (inferInstance : LT β).opposite
letI : LE β := (inferInstanceAs (LE β)).opposite
letI : LT β := (inferInstanceAs (LT β)).opposite
simpa [LT.lt_opposite_iff] using List.apply_minOn_lt_iff (f := f) h
protected theorem apply_maxOn_le_apply_maxOn_of_subset [LE β] [DecidableLE β]
@@ -386,14 +386,14 @@ protected theorem apply_maxOn_le_apply_maxOn_of_subset [LE β] [DecidableLE β]
haveI : xs [] := by intro h; rw [h] at hxs; simp_all [subset_nil]
f (ys.maxOn f hys) f (xs.maxOn f this) := by
rw [List.maxOn_eq_minOn]
letI : LE β := (inferInstance : LE β).opposite
letI : LE β := (inferInstanceAs (LE β)).opposite
simpa [LE.le_opposite_iff] using List.apply_minOn_le_apply_minOn_of_subset (f := f) hxs hys
protected theorem apply_maxOn_take_le [LE β] [DecidableLE β] [IsLinearPreorder β]
{xs : List α} {f : α β} {i : Nat} (h : xs.take i []) :
f ((xs.take i).maxOn f h) f (xs.maxOn f (List.ne_nil_of_take_ne_nil h)) := by
rw [List.maxOn_eq_minOn]
letI : LE β := (inferInstance : LE β).opposite
letI : LE β := (inferInstanceAs (LE β)).opposite
simpa [LE.le_opposite_iff] using List.le_apply_minOn_take (f := f) h
protected theorem le_apply_maxOn_append_left [LE β] [DecidableLE β] [IsLinearPreorder β]
@@ -401,7 +401,7 @@ protected theorem le_apply_maxOn_append_left [LE β] [DecidableLE β] [IsLinearP
f (xs.maxOn f h)
f ((xs ++ ys).maxOn f (append_ne_nil_of_left_ne_nil h ys)) := by
rw [List.maxOn_eq_minOn]
letI : LE β := (inferInstance : LE β).opposite
letI : LE β := (inferInstanceAs (LE β)).opposite
simpa [LE.le_opposite_iff] using List.apply_minOn_append_le_left (f := f) h
protected theorem le_apply_maxOn_append_right [LE β] [DecidableLE β] [IsLinearPreorder β]
@@ -409,7 +409,7 @@ protected theorem le_apply_maxOn_append_right [LE β] [DecidableLE β] [IsLinear
f (ys.maxOn f h)
f ((xs ++ ys).maxOn f (append_ne_nil_of_right_ne_nil xs h)) := by
rw [List.maxOn_eq_minOn]
letI : LE β := (inferInstance : LE β).opposite
letI : LE β := (inferInstanceAs (LE β)).opposite
simpa [LE.le_opposite_iff] using List.apply_minOn_append_le_right (f := f) h
@[simp]
@@ -417,21 +417,21 @@ protected theorem maxOn_append [LE β] [DecidableLE β] [IsLinearPreorder β] {x
{f : α β} (hxs : xs []) (hys : ys []) :
(xs ++ ys).maxOn f (by simp [hxs]) = maxOn f (xs.maxOn f hxs) (ys.maxOn f hys) := by
simp only [List.maxOn_eq_minOn, maxOn_eq_minOn]
letI : LE β := (inferInstance : LE β).opposite
letI : LE β := (inferInstanceAs (LE β)).opposite
simpa [LE.le_opposite_iff] using List.minOn_append (f := f) hxs hys
protected theorem maxOn_eq_head [LE β] [DecidableLE β] [IsLinearPreorder β] {xs : List α}
{f : α β} (h : xs []) (h' : x xs, f x f (xs.head h)) :
xs.maxOn f h = xs.head h := by
rw [List.maxOn_eq_minOn]
letI : LE β := (inferInstance : LE β).opposite
letI : LE β := (inferInstanceAs (LE β)).opposite
simpa [LE.le_opposite_iff] using List.minOn_eq_head (f := f) h (by simpa [LE.le_opposite_iff] using h')
protected theorem max_map
[LE β] [DecidableLE β] [Max β] [IsLinearPreorder β] [LawfulOrderLeftLeaningMax β] {xs : List α}
{f : α β} (h : xs []) : (xs.map f).max (by simpa) = f (xs.maxOn f h) := by
letI : LE β := (inferInstance : LE β).opposite
letI : Min β := (inferInstance : Max β).oppositeMin
letI : LE β := (inferInstanceAs (LE β)).opposite
letI : Min β := (inferInstanceAs (Max β)).oppositeMin
simpa [List.max_eq_min] using List.min_map (f := f) h
protected theorem maxOn_eq_max [Max α] [LE α] [DecidableLE α] [LawfulOrderLeftLeaningMax α]
@@ -458,7 +458,7 @@ protected theorem max_map_eq_max [Max α] [LE α] [DecidableLE α] [LawfulOrderL
protected theorem maxOn_replicate [LE β] [DecidableLE β] [IsLinearPreorder β]
{n : Nat} {a : α} {f : α β} (h : replicate n a []) :
(replicate n a).maxOn f h = a :=
letI : LE β := (inferInstance : LE β).opposite
letI : LE β := (inferInstanceAs (LE β)).opposite
List.minOn_replicate (f := f) h
/-! # minOn? -/
@@ -579,7 +579,7 @@ protected theorem maxOn?_nil [LE β] [DecidableLE β] {f : α → β} :
protected theorem maxOn?_cons_eq_some_maxOn
[LE β] [DecidableLE β] {f : α β} {x : α} {xs : List α} :
(x :: xs).maxOn? f = some ((x :: xs).maxOn f (fun h => nomatch h)) :=
letI : LE β := (inferInstance : LE β).opposite
letI : LE β := (inferInstanceAs (LE β)).opposite
List.minOn?_cons_eq_some_minOn
protected theorem maxOn?_cons
@@ -588,7 +588,7 @@ protected theorem maxOn?_cons
have : maxOn f x = (letI : LE β := LE.opposite inferInstance; minOn f x) := by
ext; simp only [maxOn_eq_minOn]
simp only [List.maxOn?_eq_minOn?, this]
letI : LE β := (inferInstance : LE β).opposite
letI : LE β := (inferInstanceAs (LE β)).opposite
exact List.minOn?_cons
@[simp]
@@ -599,8 +599,8 @@ protected theorem maxOn?_singleton [LE β] [DecidableLE β] {x : α} {f : α
@[simp]
protected theorem maxOn?_id [Max α] [LE α] [DecidableLE α] [LawfulOrderLeftLeaningMax α]
{xs : List α} : xs.maxOn? id = xs.max? := by
letI : LE α := (inferInstance : LE α).opposite
letI : Min α := (inferInstance : Max α).oppositeMin
letI : LE α := (inferInstanceAs (LE α)).opposite
letI : Min α := (inferInstanceAs (Max α)).oppositeMin
simpa only [List.maxOn?_eq_minOn?, List.max?_eq_min?] using List.minOn?_id (α := α)
protected theorem maxOn?_eq_if
@@ -610,7 +610,7 @@ protected theorem maxOn?_eq_if
some (xs.maxOn f h)
else
none :=
letI : LE β := (inferInstance : LE β).opposite
letI : LE β := (inferInstanceAs (LE β)).opposite
List.minOn?_eq_if
@[simp]
@@ -620,55 +620,55 @@ protected theorem isSome_maxOn?_iff [LE β] [DecidableLE β] {f : α → β} {xs
protected theorem maxOn_eq_get_maxOn? [LE β] [DecidableLE β] {f : α β} {xs : List α}
(h : xs []) : xs.maxOn f h = (xs.maxOn? f).get (List.isSome_maxOn?_iff.mpr h) :=
letI : LE β := (inferInstance : LE β).opposite
letI : LE β := (inferInstanceAs (LE β)).opposite
List.minOn_eq_get_minOn? (f := f) h
protected theorem maxOn?_eq_some_maxOn [LE β] [DecidableLE β] {f : α β} {xs : List α}
(h : xs []) : xs.maxOn? f = some (xs.maxOn f h) :=
letI : LE β := (inferInstance : LE β).opposite
letI : LE β := (inferInstanceAs (LE β)).opposite
List.minOn?_eq_some_minOn (f := f) h
@[simp]
protected theorem get_maxOn? [LE β] [DecidableLE β] {f : α β} {xs : List α}
(h : xs []) : (xs.maxOn? f).get (List.isSome_maxOn?_iff.mpr h) = xs.maxOn f h :=
letI : LE β := (inferInstance : LE β).opposite
letI : LE β := (inferInstanceAs (LE β)).opposite
List.get_minOn? (f := f) h
protected theorem maxOn_eq_of_maxOn?_eq_some
[LE β] [DecidableLE β] {f : α β} {xs : List α} {x : α} (h : xs.maxOn? f = some x) :
xs.maxOn f (List.isSome_maxOn?_iff.mp (Option.isSome_of_eq_some h)) = x :=
letI : LE β := (inferInstance : LE β).opposite
letI : LE β := (inferInstanceAs (LE β)).opposite
List.minOn_eq_of_minOn?_eq_some (f := f) h
protected theorem isSome_maxOn?_of_mem
[LE β] [DecidableLE β] {f : α β} {xs : List α} {x : α} (h : x xs) :
(xs.maxOn? f).isSome :=
letI : LE β := (inferInstance : LE β).opposite
letI : LE β := (inferInstanceAs (LE β)).opposite
List.isSome_minOn?_of_mem (f := f) h
protected theorem le_apply_get_maxOn?_of_mem
[LE β] [DecidableLE β] [IsLinearPreorder β] {f : α β} {xs : List α} {x : α} (h : x xs) :
f x f ((xs.maxOn? f).get (List.isSome_maxOn?_of_mem h)) := by
simp only [List.maxOn?_eq_minOn?]
letI : LE β := (inferInstance : LE β).opposite
letI : LE β := (inferInstanceAs (LE β)).opposite
simpa [LE.le_opposite_iff] using List.apply_get_minOn?_le_of_mem (f := f) h
protected theorem maxOn?_mem [LE β] [DecidableLE β] {xs : List α}
{f : α β} (h : xs.maxOn? f = some a) : a xs :=
letI : LE β := (inferInstance : LE β).opposite
letI : LE β := (inferInstanceAs (LE β)).opposite
List.minOn?_mem (f := f) h
protected theorem maxOn?_replicate [LE β] [DecidableLE β] [IsLinearPreorder β]
{n : Nat} {a : α} {f : α β} :
(replicate n a).maxOn? f = if n = 0 then none else some a :=
letI : LE β := (inferInstance : LE β).opposite
letI : LE β := (inferInstanceAs (LE β)).opposite
List.minOn?_replicate
@[simp]
protected theorem maxOn?_replicate_of_pos [LE β] [DecidableLE β] [IsLinearPreorder β]
{n : Nat} {a : α} {f : α β} (h : 0 < n) :
(replicate n a).maxOn? f = some a :=
letI : LE β := (inferInstance : LE β).opposite
letI : LE β := (inferInstanceAs (LE β)).opposite
List.minOn?_replicate_of_pos (f := f) h
@[simp]
@@ -678,7 +678,7 @@ protected theorem maxOn?_append [LE β] [DecidableLE β] [IsLinearPreorder β]
have : maxOn f = (letI : LE β := LE.opposite inferInstance; minOn f) := by
ext; simp only [maxOn_eq_minOn]
simp only [List.maxOn?_eq_minOn?, this]
letI : LE β := (inferInstance : LE β).opposite
letI : LE β := (inferInstanceAs (LE β)).opposite
exact List.minOn?_append xs ys f
end List

View File

@@ -706,11 +706,6 @@ theorem infix_refl (l : List α) : l <:+: l := prefix_rfl.isInfix
grind_pattern suffix_cons => _ <:+ a :: l
@[simp]
theorem suffix_cons_append {a : α} {l₁ l₂ : List α} : l₂ <:+ a :: (l₁ ++ l₂) := by
rw [ List.cons_append]
exact List.suffix_append (a :: l₁) l₂
theorem infix_cons : l₁ <:+: l₂ l₁ <:+: a :: l₂ := fun l₁', l₂', h => a :: l₁', l₂', h rfl
theorem infix_concat : l₁ <:+: l₂ l₁ <:+: concat l₂ a := fun l₁', l₂', h =>
@@ -1297,31 +1292,6 @@ instance [DecidableEq α] (l₁ l₂ : List α) : Decidable (l₁ <+: l₂) :=
instance [DecidableEq α] (l₁ l₂ : List α) : Decidable (l₁ <:+ l₂) :=
decidable_of_iff (l₁.isSuffixOf l₂) isSuffixOf_iff_suffix
/-
Used internally by the `cbv` tactic.
-/
theorem isInfixOf_internal_iff_isInfix [BEq α] [LawfulBEq α] {l₁ l₂ : List α} :
l₁.isInfixOf_internal l₂ l₁ <:+: l₂ := by
induction l₂ with
| nil => simp [isInfixOf_internal, IsInfix]
| cons a l₂ ih =>
simp only [isInfixOf_internal, Bool.or_eq_true]
constructor
· rintro (h | h)
· exact (isPrefixOf_iff_prefix.mp h).isInfix
· exact infix_cons <| ih.mp h
· intro s, t, h
match s with
| [] => left; exact isPrefixOf_iff_prefix.mpr t, h
| a' :: s' =>
right; exact ih.mpr s', t, List.cons.inj h |>.2
/-
Used internally by the `cbv` tactic.
-/
instance [DecidableEq α] (l₁ l₂ : List α) : Decidable (l₁ <:+: l₂) :=
decidable_of_iff (l₁.isInfixOf_internal l₂) isInfixOf_internal_iff_isInfix
theorem prefix_iff_eq_append : l₁ <+: l₂ l₁ ++ drop (length l₁) l₂ = l₂ :=
by rintro r, rfl; rw [drop_left], fun e => _, e
@@ -1329,121 +1299,6 @@ theorem prefix_iff_eq_take : l₁ <+: l₂ ↔ l₁ = take (length l₁) l₂ :=
fun h => append_cancel_right <| (prefix_iff_eq_append.1 h).trans (take_append_drop _ _).symm,
fun e => e.symm take_prefix _ _
theorem prefix_iff_exists_append_eq {l₁ l₂ : List α} : l₁ <+: l₂ l₃, l₁ ++ l₃ = l₂ :=
Iff.rfl
theorem prefix_iff_exists_eq_append {l₁ l₂ : List α} : l₁ <+: l₂ l₃, l₂ = l₁ ++ l₃ := by
simp [prefix_iff_exists_append_eq, eq_comm]
-- See `Init.Data.List.Nat.Sublist` for `suffix_iff_eq_append`, `prefix_take_iff`, and `suffix_iff_eq_drop`.
theorem suffix_iff_exists_append_eq {l₁ l₂ : List α} : l₁ <:+ l₂ l₃, l₃ ++ l₁ = l₂ :=
Iff.rfl
theorem suffix_iff_exists_eq_append {l₁ l₂ : List α} : l₁ <:+ l₂ l₃, l₂ = l₃ ++ l₁ := by
simp [suffix_iff_exists_append_eq, eq_comm]
theorem suffix_append_self_iff {l₁ l₂ l₃ : List α} : l₁ ++ l₃ <:+ l₂ ++ l₃ l₁ <:+ l₂ := by
constructor
· rintro t, h
exact t, List.append_cancel_right (by rwa [ List.append_assoc] at h)
· rintro t, h
exact t, by rw [ List.append_assoc, h]
theorem prefix_self_append_iff {l₁ l₂ l₃ : List α} : l₃ ++ l₁ <+: l₃ ++ l₂ l₁ <+: l₂ := by
constructor
· rintro t, h
exact t, List.append_cancel_left (by rwa [List.append_assoc] at h)
· rintro t, h
exact t, by rw [List.append_assoc, h]
theorem suffix_append_inj_of_length_eq {l₁ l₂ s₁ s₂ : List α} (hs : s₁.length = s₂.length) :
l₁ ++ s₁ <:+ l₂ ++ s₂ l₁ <:+ l₂ s₁ = s₂ := by
simp only [suffix_iff_exists_eq_append]
refine ?_, ?_
· rintro l₃, h
rw [ List.append_assoc] at h
obtain rfl, rfl := List.append_inj' h hs.symm
refine l₃, by simp, by simp
· rintro l₃, rfl, rfl
refine l₃, by simp
theorem prefix_append_inj_of_length_eq {l₁ l₂ s₁ s₂ : List α} (hs : s₁.length = s₂.length) :
s₁ ++ l₁ <+: s₂ ++ l₂ s₁ = s₂ l₁ <+: l₂ := by
constructor
· rintro t, h
rw [List.append_assoc] at h
obtain rfl, rfl := List.append_inj h.symm hs.symm
exact rfl, t, rfl
· rintro rfl, t, rfl
exact t, by simp
theorem singleton_suffix_iff_getLast?_eq_some {a : α} {l : List α} : [a] <:+ l l.getLast? = some a := by
rw [suffix_iff_exists_eq_append, getLast?_eq_some_iff]
theorem singleton_prefix_iff_head?_eq_some {a : α} {l : List α} : [a] <+: l l.head? = some a := by
simp [prefix_iff_exists_eq_append, head?_eq_some_iff]
theorem singleton_prefix_cons_iff {a b : α} {l : List α} : [a] <+: b :: l a = b := by
simp
@[simp]
theorem singleton_suffix_append_singleton_iff {a b : α} {l : List α} :
[a] <:+ l ++ [b] a = b := by
refine fun h => Eq.symm ?_, by rintro rfl; simp
simpa [List.suffix_iff_exists_eq_append] using h
@[simp]
theorem singleton_suffix_cons_append_singleton_iff {a b c : α} {l : List α} :
[a] <:+ b :: (l ++ [c]) a = c := by
rw [ List.cons_append]
exact singleton_suffix_append_singleton_iff
theorem infix_append_iff {α : Type u} {l xs ys : List α} : l <:+: xs ++ ys
l <:+: xs l <:+: ys ( l₁ l₂, l = l₁ ++ l₂ l₁ <:+ xs l₂ <+: ys) := by
constructor
· rintro s, t, ht
rcases List.append_eq_append_iff.mp ht with as, hxs, _ | bs, hsl, hys
· exact Or.inl s, as, hxs.symm
· rcases List.append_eq_append_iff.mp hsl with cs, hxs', hl | ds, _, hbs
· exact Or.inr (Or.inr cs, bs, hl,
List.suffix_iff_exists_eq_append.mpr s, hxs',
List.prefix_iff_exists_eq_append.mpr t, hys)
· exact Or.inr (Or.inl ds, t, by rw [hys, hbs])
· rintro (s, t, ht | s, t, ht | l₁, l₂, rfl, hl₁, hl₂)
· exact s, t ++ ys, by rw [ List.append_assoc, ht]
· exact xs ++ s, t, by
rw [List.append_assoc] at ht
rw [List.append_assoc (xs ++ s), List.append_assoc xs, ht]
· rw [List.suffix_iff_exists_eq_append] at hl₁
rw [List.prefix_iff_exists_eq_append] at hl₂
obtain s, hxs := hl₁
obtain t, hys := hl₂
exact s, t, by rw [ List.append_assoc s l₁, List.append_assoc (s ++ l₁), hxs, hys]
theorem infix_append_iff_ne_nil {α : Type u} {l xs ys : List α} : l <:+: xs ++ ys
l <:+: xs l <:+: ys ( l₁ l₂, l₁ [] l₂ [] l = l₁ ++ l₂ l₁ <:+ xs l₂ <+: ys) := by
rw [List.infix_append_iff]
constructor
· rintro (h | h | l₁, l₂, hl, hl₁, hl₂)
· exact Or.inl h
· exact Or.inr (Or.inl h)
· cases l₁ with
| nil =>
simp only [List.nil_append] at hl
subst hl
exact Or.inr (Or.inl hl₂.isInfix)
| cons hd tl =>
cases l₂ with
| nil =>
simp only [List.append_nil] at hl
subst hl
exact Or.inl hl₁.isInfix
| cons hd' tl' =>
exact Or.inr (Or.inr _, _, List.cons_ne_nil _ _, List.cons_ne_nil _ _, hl, hl₁, hl₂)
· rintro (h | h | l₁, l₂, -, -, hl, hl₁, hl₂)
· exact Or.inl h
· exact Or.inr (Or.inl h)
· exact Or.inr (Or.inr l₁, l₂, hl, hl₁, hl₂)
end List

View File

@@ -297,14 +297,6 @@ theorem dropWhile_cons :
(a :: l).dropWhile p = a :: l := by
simp [dropWhile_cons, h]
theorem dropWhile_beq_eq_self_of_head?_ne [BEq α] [LawfulBEq α] {a : α} {l : List α}
(h : l.head? some a) : l.dropWhile (· == a) = l := by
cases l with
| nil => simp
| cons hd tl =>
rw [List.dropWhile_cons_of_neg]
simpa [beq_iff_eq] using h
theorem head?_takeWhile {p : α Bool} {l : List α} : (l.takeWhile p).head? = l.head?.filter p := by
cases l with
| nil => rfl

View File

@@ -867,7 +867,7 @@ theorem and_le_right {n m : Nat} : n &&& m ≤ m :=
le_of_testBit (by simp)
theorem left_le_or {n m : Nat} : n n ||| m :=
le_of_testBit (by simp [imp_or_left_iff_true])
le_of_testBit (by simp)
theorem right_le_or {n m : Nat} : m n ||| m :=
le_of_testBit (by simp [imp_or_right_iff_true])
le_of_testBit (by simp)

View File

@@ -253,16 +253,4 @@ theorem ext_div_mod {n a b : Nat} (h0 : a / n = b / n) (h1 : a % n = b % n) : a
theorem ext_div_mod_iff (n a b : Nat) : a = b a / n = b / n a % n = b % n :=
fun h => h rfl, h rfl, fun h0, h1 => ext_div_mod h0 h1
/-- An induction principle mirroring the base-`b` representation of the number. -/
theorem base_induction {P : Nat Prop} {n : Nat} (b : Nat) (hb : 1 < b) (single : m, m < b P m)
(digit : m k, k < b 0 < m P m P (b * m + k)) : P n := by
induction n using Nat.strongRecOn with | ind n ih
rcases Nat.lt_or_ge n b with hn | hn
· exact single _ hn
· have := div_add_mod n b
rw [ this]
apply digit _ _ (mod_lt _ (by omega)) _ (ih _ _)
· exact Nat.div_pos_iff.mpr by omega, hn
· exact div_lt_self (by omega) (by omega)
end Nat

View File

@@ -19,7 +19,6 @@ import Init.Data.Nat.Bitwise
import Init.Data.Nat.Simproc
import Init.WFTactics
import Init.Data.Char.Lemmas
import Init.Data.Nat.Div.Lemmas
public section
@@ -95,14 +94,6 @@ protected theorem digitChar_ne {n : Nat} (c : Char)
match n with
| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | _ + 16 => simp [digitChar] at h
theorem toNat_digitChar_of_lt_ten {n : Nat} (hn : n < 10) : n.digitChar.toNat = 48 + n :=
match n with
| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 => by simp [digitChar]
| _ + 10 => by omega
theorem toNat_digitChar_sub_48_of_lt_ten {n : Nat} (hn : n < 10) : n.digitChar.toNat - 48 = n := by
simp [toNat_digitChar_of_lt_ten hn]
private theorem isDigit_of_mem_toDigitsCore
(hc : c cs c.isDigit) (hb₁ : 0 < b) (hb₂ : b 10) (h : c toDigitsCore b fuel n cs) :
c.isDigit := by
@@ -119,11 +110,6 @@ private theorem isDigit_of_mem_toDigitsCore
theorem isDigit_of_mem_toDigits (hb₁ : 0 < b) (hb₂ : b 10) (hc : c toDigits b n) : c.isDigit :=
isDigit_of_mem_toDigitsCore (fun _ => by contradiction) hb₁ hb₂ hc
@[simp]
theorem underscore_not_in_toDigits {n : Nat} : ¬'_' Nat.toDigits 10 n := by
intro h
simpa using isDigit_of_mem_toDigits (by decide) (by decide) h
private theorem toDigitsCore_of_lt_base (hb : n < b) (hf : n < fuel) :
toDigitsCore b fuel n cs = n.digitChar :: cs := by
unfold toDigitsCore
@@ -200,11 +186,6 @@ theorem length_toDigits_pos {b n : Nat} :
· rw [toDigitsCore_eq_toDigitsCore_nil_append]
simp
@[simp]
theorem toDigits_ne_nil {n b : Nat} : Nat.toDigits b n [] := by
rw [ List.length_pos_iff]
exact Nat.length_toDigits_pos
theorem length_toDigits_le_iff {n k : Nat} (hb : 1 < b) (h : 0 < k) :
(Nat.toDigits b n).length k n < b ^ k := by
match k with
@@ -230,14 +211,6 @@ theorem repr_eq_ofList_toDigits {n : Nat} :
n.repr = .ofList (toDigits 10 n) :=
(rfl)
@[simp]
theorem toList_repr {n : Nat} : n.repr.toList = Nat.toDigits 10 n := by
simp [repr_eq_ofList_toDigits]
@[simp]
theorem repr_ne_empty {n : Nat} : n.repr "" := by
simp [ String.toList_inj]
theorem toString_eq_ofList_toDigits {n : Nat} :
toString n = .ofList (toDigits 10 n) :=
(rfl)
@@ -278,59 +251,4 @@ theorem length_repr_le_iff {n k : Nat} (h : 0 < k) :
n.repr.length k n < 10 ^ k := by
simpa [repr_eq_ofList_toDigits] using length_toDigits_le_iff (by omega) h
/--
Transforms a list of characters into a natural number, *assuming that all characters are in the
range from `'0'` to `'9'`*.
-/
def ofDigitChars (b : Nat) (l : List Char) (init : Nat) : Nat :=
l.foldl (init := init) (fun sofar c => b * sofar + (c.toNat - '0'.toNat))
theorem ofDigitChars_eq_foldl {b : Nat} {l : List Char} {init : Nat} :
ofDigitChars b l init = l.foldl (init := init) (fun sofar c => b * sofar + (c.toNat - '0'.toNat)) :=
(rfl)
@[simp]
theorem ofDigitChars_nil {init : Nat} : ofDigitChars b [] init = init := by
simp [ofDigitChars]
theorem ofDigitChars_cons {c : Char} {cs : List Char} {init : Nat} :
ofDigitChars b (c::cs) init = ofDigitChars b cs (b * init + (c.toNat - '0'.toNat)) := by
simp [ofDigitChars]
theorem ofDigitChars_cons_digitChar_of_lt_ten {n : Nat} (hn : n < 10) {cs : List Char} {init : Nat} :
ofDigitChars b (n.digitChar :: cs) init = ofDigitChars b cs (b * init + n) := by
simp [ofDigitChars_cons, Nat.toNat_digitChar_sub_48_of_lt_ten hn]
theorem ofDigitChars_eq_ofDigitChars_zero {l : List Char} {init : Nat} :
ofDigitChars 10 l init = 10 ^ l.length * init + ofDigitChars 10 l 0 := by
induction l generalizing init with
| nil => simp [ofDigitChars]
| cons hd tl ih =>
simp only [ofDigitChars, Char.isValue, Char.reduceToNat, List.foldl_cons, List.length_cons,
Nat.mul_zero, Nat.zero_add] at ih
rw [ih, ih (init := hd.toNat - 48), Nat.pow_succ, Nat.mul_add, Nat.mul_assoc, Nat.add_assoc]
theorem ofDigitChars_append {l m : List Char} (init : Nat) :
ofDigitChars b (l ++ m) init = ofDigitChars b m (ofDigitChars b l init) := by
simp [ofDigitChars]
@[simp]
theorem ofDigitChars_replicate_zero {n : Nat} : ofDigitChars b (List.replicate n '0') init = b ^ n * init := by
induction n generalizing init with
| zero => simp
| succ n ih => simp [List.replicate_succ, ofDigitChars_cons, ih, Nat.pow_succ, Nat.mul_assoc]
theorem ofDigitChars_toDigits {b n : Nat} (hb' : 1 < b) (hb : b 10) : ofDigitChars b (toDigits b n) 0 = n := by
induction n using base_induction b hb' with
| single m hm =>
simp [Nat.toDigits_of_lt_base hm, ofDigitChars_cons_digitChar_of_lt_ten (by omega : m < 10)]
| digit m k hk hm ih =>
rw [ Nat.toDigits_append_toDigits hb' hm hk,
ofDigitChars_append, ih, Nat.toDigits_of_lt_base hk,
ofDigitChars_cons_digitChar_of_lt_ten (Nat.lt_of_lt_of_le hk hb), ofDigitChars_nil]
@[simp]
theorem ofDigitChars_ten_toDigits {n : Nat} : ofDigitChars 10 (toDigits 10 n) 0 = n :=
ofDigitChars_toDigits (by decide) (by decide)
end Nat

View File

@@ -9,7 +9,7 @@ prelude
public import Init.Data.Order.Ord
public import Init.Data.String.Basic
import Init.Data.Char.Lemmas
import Init.Data.String.Lemmas.StringOrder
import Init.Data.String.Lemmas
public section

View File

@@ -243,10 +243,6 @@ public theorem lt_iff_le_and_ne [LE α] [LT α] [LawfulOrderLT α] [IsPartialOrd
a < b a b a b := by
simpa [le_iff_lt_or_eq, or_and_right] using Std.ne_of_lt
public theorem lt_trichotomy [LT α] [Std.Trichotomous (α := α) (· < ·)] (a b : α) :
a < b a = b b < a :=
Trichotomous.rel_or_eq_or_rel_swap
end LT
end Std

View File

@@ -39,8 +39,8 @@ public theorem minOn_id [Min α] [LE α] [DecidableLE α] [LawfulOrderLeftLeanin
public theorem maxOn_id [Max α] [LE α] [DecidableLE α] [LawfulOrderLeftLeaningMax α] {x y : α} :
maxOn id x y = max x y := by
letI : LE α := (inferInstance : LE α).opposite
letI : Min α := (inferInstance : Max α).oppositeMin
letI : LE α := (inferInstanceAs (LE α)).opposite
letI : Min α := (inferInstanceAs (Max α)).oppositeMin
simp [maxOn, minOn_id, Max.min_oppositeMin, this]
public theorem minOn_eq_or [LE β] [DecidableLE β] {f : α β} {x y : α} :
@@ -168,32 +168,32 @@ public theorem maxOn_eq_right_of_lt
[LE β] [DecidableLE β] [LT β] [Total (α := β) (· ·)] [LawfulOrderLT β]
{f : α β} {x y : α} (h : f x < f y) :
maxOn f x y = y :=
letI : LE β := (inferInstance : LE β).opposite
letI : LT β := (inferInstance : LT β).opposite
letI : LE β := (inferInstanceAs (LE β)).opposite
letI : LT β := (inferInstanceAs (LT β)).opposite
minOn_eq_right_of_lt (h := by simpa [LT.lt_opposite_iff] using h) ..
public theorem left_le_apply_maxOn [le : LE β] [DecidableLE β] [IsLinearPreorder β] {f : α β}
{x y : α} : f x f (maxOn f x y) := by
rw [maxOn_eq_minOn]
letI : LE β := (inferInstance : LE β).opposite
letI : LE β := (inferInstanceAs (LE β)).opposite
simpa only [LE.le_opposite_iff] using apply_minOn_le_left (f := f) ..
public theorem right_le_apply_maxOn [LE β] [DecidableLE β] [IsLinearPreorder β] {f : α β}
{x y : α} : f y f (maxOn f x y) := by
rw [maxOn_eq_minOn]
letI : LE β := (inferInstance : LE β).opposite
letI : LE β := (inferInstanceAs (LE β)).opposite
simpa only [LE.le_opposite_iff] using apply_minOn_le_right (f := f)
public theorem apply_maxOn_le_iff [LE β] [DecidableLE β] [IsLinearPreorder β] {f : α β}
{x y : α} {b : β} :
f (maxOn f x y) b f x b f y b := by
rw [maxOn_eq_minOn]
letI : LE β := (inferInstance : LE β).opposite
letI : LE β := (inferInstanceAs (LE β)).opposite
simpa only [LE.le_opposite_iff] using le_apply_minOn_iff (f := f)
public theorem maxOn_assoc [LE β] [DecidableLE β] [IsLinearPreorder β] {f : α β}
{x y z : α} : maxOn f (maxOn f x y) z = maxOn f x (maxOn f y z) :=
letI : LE β := (inferInstance : LE β).opposite
letI : LE β := (inferInstanceAs (LE β)).opposite
minOn_assoc (f := f)
public instance [LE β] [DecidableLE β] [IsLinearPreorder β] {f : α β} :
@@ -203,8 +203,8 @@ public instance [LE β] [DecidableLE β] [IsLinearPreorder β] {f : α → β} :
public theorem max_apply [LE β] [DecidableLE β] [Max β] [LawfulOrderLeftLeaningMax β]
{f : α β} {x y : α} : max (f x) (f y) = f (maxOn f x y) := by
letI : LE β := (inferInstance : LE β).opposite
letI : Min β := (inferInstance : Max β).oppositeMin
letI : LE β := (inferInstanceAs (LE β)).opposite
letI : Min β := (inferInstanceAs (Max β)).oppositeMin
simpa [Max.min_oppositeMin] using min_apply (f := f)
public theorem apply_maxOn [LE β] [DecidableLE β] [Max β] [LawfulOrderLeftLeaningMax β]

View File

@@ -44,7 +44,7 @@ def min' [LE α] [DecidableLE α] (a b : α) : α :=
open scoped Std.OppositeOrderInstances in
def max' [LE α] [DecidableLE α] (a b : α) : α :=
letI : LE α := (inferInstance : LE α).opposite
letI : LE α := (inferInstanceAs (LE α)).opposite
-- `DecidableLE` for the opposite order is derived automatically via `OppositeOrderInstances`
min' a b
```

View File

@@ -411,7 +411,6 @@ private theorem Rii.Internal.toArray_eq_toArray_iter [Least? α]
r.toArray = (Internal.iter r).toArray := by
rfl
@[cbv_eval]
public theorem Rxc.Iterator.toList_eq_match [LE α] [DecidableLE α]
[UpwardEnumerable α] [Rxc.IsAlwaysFinite α] [LawfulUpwardEnumerable α]
[LawfulUpwardEnumerableLE α]
@@ -429,7 +428,6 @@ public theorem Rxc.Iterator.toList_eq_match [LE α] [DecidableLE α]
· simp [*]
· split <;> rename_i heq' <;> simp [*]
@[cbv_eval]
public theorem Rxc.Iterator.toArray_eq_match [LE α] [DecidableLE α]
[UpwardEnumerable α] [Rxc.IsAlwaysFinite α] [LawfulUpwardEnumerable α]
[LawfulUpwardEnumerableLE α]
@@ -445,7 +443,6 @@ public theorem Rxc.Iterator.toArray_eq_match [LE α] [DecidableLE α]
· rfl
· split <;> simp
@[cbv_eval]
public theorem Rxo.Iterator.toList_eq_match [LT α] [DecidableLT α]
[UpwardEnumerable α] [Rxo.IsAlwaysFinite α] [LawfulUpwardEnumerable α]
[LawfulUpwardEnumerableLT α]
@@ -462,7 +459,6 @@ public theorem Rxo.Iterator.toList_eq_match [LT α] [DecidableLT α]
· simp [*]
· split <;> rename_i heq' <;> simp [*]
@[cbv_eval]
public theorem Rxo.Iterator.toArray_eq_match [LT α] [DecidableLT α]
[UpwardEnumerable α] [Rxo.IsAlwaysFinite α] [LawfulUpwardEnumerable α]
[LawfulUpwardEnumerableLT α]
@@ -495,7 +491,6 @@ public theorem Rxc.Iterator.toList_eq_toList_rxoIterator [LE α] [DecidableLE α
· simpa [UpwardEnumerable.lt_iff, UpwardEnumerable.le_iff, UpwardEnumerable.lt_succ_iff] using h
· simpa [UpwardEnumerable.lt_iff, UpwardEnumerable.le_iff, UpwardEnumerable.lt_succ_iff] using h
@[cbv_eval]
public theorem Rxi.Iterator.toList_eq_match
[UpwardEnumerable α] [Rxi.IsAlwaysFinite α] [LawfulUpwardEnumerable α]
{it : Iter (α := Rxi.Iterator α) α} :
@@ -507,7 +502,6 @@ public theorem Rxi.Iterator.toList_eq_match
simp only [Iter.toList_eq_match_step (it := it), Rxi.Iterator.step_eq_step, Rxi.Iterator.step]
split <;> rename_i heq <;> simp [*]
@[cbv_eval]
public theorem Rxi.Iterator.toArray_eq_match
[UpwardEnumerable α] [Rxi.IsAlwaysFinite α] [LawfulUpwardEnumerable α]
{it : Iter (α := Rxi.Iterator α) α} :
@@ -614,7 +608,6 @@ namespace Rcc
variable {r : Rcc α}
@[cbv_eval]
public theorem toList_eq_if_roc [LE α] [DecidableLE α] [UpwardEnumerable α]
[LawfulUpwardEnumerable α] [LawfulUpwardEnumerableLE α] [Rxc.IsAlwaysFinite α] :
r.toList = if r.lower r.upper then
@@ -762,7 +755,6 @@ public theorem ClosedOpen.toList_succ_succ_eq_map [LE α] [DecidableLE α] [Upwa
(lo...=hi).toList.map succ :=
Rcc.toList_succ_succ_eq_map
@[cbv_eval]
public theorem forIn'_eq_forIn'_toList [LE α] [DecidableLE α] [UpwardEnumerable α]
[LawfulUpwardEnumerableLE α] [Rxc.IsAlwaysFinite α] [LawfulUpwardEnumerable α]
{γ : Type u} {init : γ} {m : Type u Type w} [Monad m] [LawfulMonad m]
@@ -852,7 +844,6 @@ namespace Rco
variable {r : Rco α}
@[cbv_eval]
public theorem toList_eq_if_roo [UpwardEnumerable α] [LT α] [DecidableLT α]
[LawfulUpwardEnumerable α] [Rxo.IsAlwaysFinite α] [LawfulUpwardEnumerableLT α] :
r.toList = if r.lower < r.upper then
@@ -1020,7 +1011,6 @@ public theorem toArray_succ_succ_eq_map [LE α] [DecidableLE α] [LT α] [Decida
(lo...hi).toArray.map succ := by
simp [ toArray_toList, toList_succ_succ_eq_map]
@[cbv_eval]
public theorem forIn'_eq_forIn'_toList [LE α] [LT α] [DecidableLT α]
[UpwardEnumerable α] [LawfulUpwardEnumerableLE α] [LawfulUpwardEnumerableLT α]
[Rxo.IsAlwaysFinite α] [LawfulUpwardEnumerable α]
@@ -1234,7 +1224,6 @@ public theorem toArray_succ_succ_eq_map [LE α] [DecidableLE α]
((succ lo)...*).toArray = (lo...*).toArray.map succ := by
simp [ toArray_toList, toList_succ_succ_eq_map]
@[cbv_eval]
public theorem forIn'_eq_forIn'_toList [LE α]
[UpwardEnumerable α] [LawfulUpwardEnumerableLE α]
[Rxi.IsAlwaysFinite α] [LawfulUpwardEnumerable α]
@@ -1341,7 +1330,6 @@ public theorem toArray_eq_match [LE α] [DecidableLE α] [UpwardEnumerable α]
rw [Internal.toArray_eq_toArray_iter, Rxc.Iterator.toArray_eq_match (it := Internal.iter r)]
simp [Internal.iter, Internal.toArray_eq_toArray_iter]
@[cbv_eval]
public theorem toList_eq_match_rcc [LE α] [DecidableLE α] [UpwardEnumerable α]
[LawfulUpwardEnumerable α] [LawfulUpwardEnumerableLE α] [Rxc.IsAlwaysFinite α] :
r.toList = match UpwardEnumerable.succ? r.lower with
@@ -1485,7 +1473,6 @@ public theorem toArray_succ_succ_eq_map [LE α] [DecidableLE α] [LT α] [Decida
(lo<...=hi).toArray.map succ := by
simp [ toArray_toList, toList_succ_succ_eq_map]
@[cbv_eval]
public theorem forIn'_eq_forIn'_toList [LE α] [DecidableLE α] [LT α]
[UpwardEnumerable α] [LawfulUpwardEnumerableLE α] [LawfulUpwardEnumerableLT α]
[Rxc.IsAlwaysFinite α] [LawfulUpwardEnumerable α] {γ : Type u} {init : γ} {m : Type u Type w}
@@ -1585,7 +1572,6 @@ public theorem toArray_eq_match [LE α] [LT α] [DecidableLT α] [UpwardEnumerab
#[] := by
rw [Internal.toArray_eq_toArray_iter, Rxo.Iterator.toArray_eq_match]; rfl
@[cbv_eval]
public theorem toList_eq_match_rco [UpwardEnumerable α] [LT α] [DecidableLT α]
[LawfulUpwardEnumerable α] [LawfulUpwardEnumerableLT α] [Rxo.IsAlwaysFinite α] :
r.toList = match UpwardEnumerable.succ? r.lower with
@@ -1719,7 +1705,6 @@ public theorem toArray_succ_succ_eq_map [LT α] [DecidableLT α]
(lo<...hi).toArray.map succ := by
simp [ toArray_toList, toList_succ_succ_eq_map]
@[cbv_eval]
public theorem forIn'_eq_forIn'_toList [LT α] [DecidableLT α]
[UpwardEnumerable α] [LawfulUpwardEnumerableLT α]
[Rxo.IsAlwaysFinite α] [LawfulUpwardEnumerable α]
@@ -1954,7 +1939,6 @@ public theorem toArray_succ_succ_eq_map [LT α] [DecidableLT α]
((succ lo)<...*).toArray = (lo<...*).toArray.map succ := by
simp [ toArray_toList, toList_succ_succ_eq_map]
@[cbv_eval]
public theorem forIn'_eq_forIn'_toList [LT α]
[UpwardEnumerable α] [LawfulUpwardEnumerableLT α]
[Rxi.IsAlwaysFinite α] [LawfulUpwardEnumerable α]
@@ -2055,7 +2039,6 @@ public theorem toList_toArray [Least? α] [LE α] [DecidableLE α] [UpwardEnumer
r.toArray.toList = r.toList := by
simp [Internal.toList_eq_toList_iter, Internal.toArray_eq_toArray_iter]
@[cbv_eval]
public theorem toList_eq_match_rcc [LE α] [DecidableLE α] [Least? α] [UpwardEnumerable α]
[LawfulUpwardEnumerable α] [LawfulUpwardEnumerableLE α]
[Rxc.IsAlwaysFinite α] :
@@ -2248,7 +2231,6 @@ public theorem toArray_succ_eq_map [LE α] [DecidableLE α] [Least? α]
#[UpwardEnumerable.least (hn := r.upper)] ++ (*...=hi).toArray.map succ := by
simp [ toArray_toList, toList_succ_eq_map]
@[cbv_eval]
public theorem forIn'_eq_forIn'_toList [LE α] [DecidableLE α] [Least? α]
[UpwardEnumerable α] [LawfulUpwardEnumerableLE α] [LawfulUpwardEnumerableLeast? α]
[Rxc.IsAlwaysFinite α] [LawfulUpwardEnumerable α] {γ : Type u} {init : γ} {m : Type u Type w}
@@ -2358,7 +2340,6 @@ public theorem toList_toArray [Least? α] [LT α] [DecidableLT α] [UpwardEnumer
r.toArray.toList = r.toList := by
simp [Internal.toList_eq_toList_iter, Internal.toArray_eq_toArray_iter]
@[cbv_eval]
public theorem toList_eq_match_rco [LT α] [DecidableLT α] [Least? α] [UpwardEnumerable α]
[LawfulUpwardEnumerable α] [LawfulUpwardEnumerableLT α]
[Rxo.IsAlwaysFinite α] :
@@ -2569,7 +2550,6 @@ public theorem toArray_succ_eq_map [LT α] [DecidableLT α] [Least? α]
#[UpwardEnumerable.least (hn := r.upper)] ++ (*...hi).toArray.map succ := by
simp [ toArray_toList, toList_succ_eq_map]
@[cbv_eval]
public theorem forIn'_eq_forIn'_toList [LT α] [DecidableLT α] [Least? α]
[UpwardEnumerable α] [LawfulUpwardEnumerableLT α] [LawfulUpwardEnumerableLeast? α]
[Rxo.IsAlwaysFinite α] [LawfulUpwardEnumerable α] {γ : Type u} {init : γ} {m : Type u Type w}
@@ -2808,7 +2788,6 @@ public theorem pairwise_toList_le [LE α] [Least? α]
|> List.Pairwise.imp UpwardEnumerable.le_of_lt
|> List.Pairwise.imp (fun hle => (UpwardEnumerable.le_iff ..).mpr hle)
@[cbv_eval]
public theorem forIn'_eq_forIn'_toList [Least? α]
[UpwardEnumerable α] [LawfulUpwardEnumerableLeast? α]
[Rxi.IsAlwaysFinite α] [LawfulUpwardEnumerable α] {γ : Type u} {init : γ} {m : Type u Type w}

View File

@@ -354,6 +354,16 @@ end Nat
instance : Repr Nat where
reprPrec n _ := Nat.repr n
/--
Returns the decimal string representation of an integer.
-/
protected def Int.repr : Int String
| ofNat m => Nat.repr m
| negSucc m => String.Internal.append "-" (Nat.repr (succ m))
instance : Repr Int where
reprPrec i prec := if i < 0 then Repr.addAppParen i.repr prec else i.repr
def hexDigitRepr (n : Nat) : String :=
String.singleton <| Nat.digitChar n

View File

@@ -126,7 +126,7 @@ public theorem forIn_toList {α : Type u} {s : Subarray α}
ForIn.forIn s.toList init f = ForIn.forIn s init f :=
Slice.forIn_toList
@[cbv_eval, grind =]
@[grind =]
public theorem forIn_eq_forIn_toList {α : Type u} {s : Subarray α}
{m : Type v Type w} [Monad m] [LawfulMonad m] {γ : Type v} {init : γ}
{f : α γ m (ForInStep γ)} :
@@ -193,7 +193,6 @@ public theorem Array.toSubarray_eq_toSubarray_of_min_eq_min {xs : Array α}
simp [*]; omega
· simp
@[cbv_eval]
public theorem Array.toSubarray_eq_min {xs : Array α} {lo hi : Nat} :
xs.toSubarray lo hi = xs, min lo (min hi xs.size), min hi xs.size, Nat.min_le_right _ _,
Nat.min_le_right _ _ := by
@@ -244,7 +243,6 @@ private theorem Std.Internal.List.extract_eq_drop_take' {l : List α} {start sto
List.length_take, ge_iff_le, h₁]
omega
@[cbv_eval]
public theorem Subarray.toList_eq_drop_take {xs : Subarray α} :
xs.toList = (xs.array.toList.take xs.stop).drop xs.start := by
rw [Subarray.toList_eq, Array.toList_extract, Std.Internal.List.extract_eq_drop_take']

View File

@@ -852,10 +852,6 @@ theorem Slice.rawEndPos_copy {s : Slice} : s.copy.rawEndPos = s.rawEndPos := by
theorem copy_toSlice {s : String} : s.toSlice.copy = s := by
simp [ toByteArray_inj, Slice.toByteArray_copy, size_toByteArray]
@[simp]
theorem copy_comp_toSlice : String.Slice.copy String.toSlice = id := by
ext; simp
theorem Slice.getUTF8Byte_eq_getUTF8Byte_copy {s : Slice} {p : Pos.Raw} {h : p < s.rawEndPos} :
s.getUTF8Byte p h = s.copy.getUTF8Byte p (by simpa) := by
simp [getUTF8Byte, String.getUTF8Byte, toByteArray_copy, ByteArray.getElem_extract]
@@ -1270,11 +1266,9 @@ theorem Pos.toSlice_comp_ofToSlice {s : String} :
theorem Pos.ofToSlice_comp_toSlice {s : String} :
Pos.ofToSlice (toSlice (s := s)) = id := by ext; simp
@[simp]
theorem Pos.toSlice_inj {s : String} {p q : s.Pos} : p.toSlice = q.toSlice p = q :=
fun h => by simpa using congrArg Pos.ofToSlice h, (· rfl)
@[simp]
theorem Pos.ofToSlice_inj {s : String} {p q : s.toSlice.Pos} : ofToSlice p = ofToSlice q p = q :=
fun h => by simpa using congrArg Pos.toSlice h, (· rfl)
@@ -1386,11 +1380,6 @@ theorem Slice.copy_eq_copy_sliceTo {s : Slice} {pos : s.Pos} :
rw [Nat.max_eq_right]
exact pos.offset_str_le_offset_endExclusive
@[simp]
theorem Slice.sliceTo_append_sliceFrom {s : Slice} {pos : s.Pos} :
(s.sliceTo pos).copy ++ (s.sliceFrom pos).copy = s.copy :=
copy_eq_copy_sliceTo.symm
/-- Given a slice `s` and a position on `s.copy`, obtain the corresponding position on `s`. -/
@[inline]
def Pos.ofCopy {s : Slice} (pos : s.copy.Pos) : s.Pos where
@@ -1698,7 +1687,7 @@ def Pos.next {s : @& String} (pos : @& s.Pos) (h : pos ≠ s.endPos) : s.Pos :=
@[simp]
theorem Pos.ofToSlice_next_toSlice {s : String} {pos : s.Pos} {h} :
ofToSlice (Slice.Pos.next pos.toSlice h) = pos.next (ne_of_apply_ne Pos.toSlice (by simpa using h)) :=
ofToSlice (Slice.Pos.next pos.toSlice h) = pos.next (ne_of_apply_ne Pos.toSlice (by simpa)) :=
rfl
@[simp]
@@ -1750,31 +1739,6 @@ theorem Slice.Pos.offset_cast {s t : Slice} {pos : s.Pos} {h : s.copy = t.copy}
theorem Slice.Pos.cast_rfl {s : Slice} {pos : s.Pos} : pos.cast rfl = pos :=
Slice.Pos.ext (by simp)
@[simp]
theorem Slice.Pos.cast_cast {s t u : Slice} {hst : s.copy = t.copy} {htu : t.copy = u.copy}
{pos : s.Pos} : (pos.cast hst).cast htu = pos.cast (hst.trans htu) :=
Slice.Pos.ext (by simp)
@[simp]
theorem Slice.Pos.cast_inj {s t : Slice} {hst : s.copy = t.copy} {p q : s.Pos} : p.cast hst = q.cast hst p = q := by
simp [Slice.Pos.ext_iff]
@[simp]
theorem Slice.Pos.cast_startPos {s t : Slice} {hst : s.copy = t.copy} : s.startPos.cast hst = t.startPos :=
Slice.Pos.ext (by simp)
@[simp]
theorem Slice.Pos.cast_eq_startPos {s t : Slice} {p : s.Pos} {hst : s.copy = t.copy} : p.cast hst = t.startPos p = s.startPos := by
rw [ cast_startPos (hst := hst), Pos.cast_inj]
@[simp]
theorem Slice.Pos.cast_endPos {s t : Slice} {hst : s.copy = t.copy} : s.endPos.cast hst = t.endPos :=
Slice.Pos.ext (by simp [ rawEndPos_copy, hst])
@[simp]
theorem Slice.Pos.cast_eq_endPos {s t : Slice} {p : s.Pos} {hst : s.copy = t.copy} : p.cast hst = t.endPos p = s.endPos := by
rw [ cast_endPos (hst := hst), Pos.cast_inj]
@[simp]
theorem Slice.Pos.cast_le_cast_iff {s t : Slice} {pos pos' : s.Pos} {h : s.copy = t.copy} :
pos.cast h pos'.cast h pos pos' := by
@@ -1785,22 +1749,6 @@ theorem Slice.Pos.cast_lt_cast_iff {s t : Slice} {pos pos' : s.Pos} {h : s.copy
pos.cast h < pos'.cast h pos < pos' := by
simp [Slice.Pos.lt_iff]
theorem Slice.Pos.cast_le_iff {s t : Slice} {pos : s.Pos} {pos' : t.Pos} {h : s.copy = t.copy} :
pos.cast h pos' pos pos'.cast h.symm := by
simp [Slice.Pos.le_iff]
theorem Slice.Pos.le_cast_iff {s t : Slice} {pos : t.Pos} {pos' : s.Pos} {h : s.copy = t.copy} :
pos pos'.cast h pos.cast h.symm pos' := by
simp [Slice.Pos.le_iff]
theorem Slice.Pos.cast_lt_iff {s t : Slice} {pos : s.Pos} {pos' : t.Pos} {h : s.copy = t.copy} :
pos.cast h < pos' pos < pos'.cast h.symm := by
simp [Slice.Pos.lt_iff]
theorem Slice.Pos.lt_cast_iff {s t : Slice} {pos : t.Pos} {pos' : s.Pos} {h : s.copy = t.copy} :
pos < pos'.cast h pos.cast h.symm < pos' := by
simp [Slice.Pos.lt_iff]
/-- Constructs a valid position on `t` from a valid position on `s` and a proof that `s = t`. -/
@[inline]
def Pos.cast {s t : String} (pos : s.Pos) (h : s = t) : t.Pos where
@@ -1815,31 +1763,6 @@ theorem Pos.offset_cast {s t : String} {pos : s.Pos} {h : s = t} :
theorem Pos.cast_rfl {s : String} {pos : s.Pos} : pos.cast rfl = pos :=
Pos.ext (by simp)
@[simp]
theorem Pos.cast_cast {s t u : String} {hst : s = t} {htu : t = u}
{pos : s.Pos} : (pos.cast hst).cast htu = pos.cast (hst.trans htu) :=
Pos.ext (by simp)
@[simp]
theorem Pos.cast_inj {s t : String} {hst : s = t} {p q : s.Pos} : p.cast hst = q.cast hst p = q := by
simp [Pos.ext_iff]
@[simp]
theorem Pos.cast_startPos {s t : String} {hst : s = t} : s.startPos.cast hst = t.startPos := by
subst hst; simp
@[simp]
theorem Pos.cast_eq_startPos {s t : String} {hst : s = t} {p : s.Pos} : p.cast hst = t.startPos p = s.startPos := by
rw [ Pos.cast_startPos (hst := hst), Pos.cast_inj]
@[simp]
theorem Pos.cast_endPos {s t : String} {hst : s = t} : s.endPos.cast hst = t.endPos := by
subst hst; simp
@[simp]
theorem Pos.cast_eq_endPos {s t : String} {hst : s = t} {p : s.Pos} : p.cast hst = t.endPos p = s.endPos := by
rw [ Pos.cast_endPos (hst := hst), Pos.cast_inj]
@[simp]
theorem Pos.cast_le_cast_iff {s t : String} {pos pos' : s.Pos} {h : s = t} :
pos.cast h pos'.cast h pos pos' := by
@@ -1850,22 +1773,6 @@ theorem Pos.cast_lt_cast_iff {s t : String} {pos pos' : s.Pos} {h : s = t} :
pos.cast h < pos'.cast h pos < pos' := by
cases h; simp
theorem Pos.cast_le_iff {s t : String} {pos : s.Pos} {pos' : t.Pos} {h : s = t} :
pos.cast h pos' pos pos'.cast h.symm := by
simp [Pos.le_iff]
theorem Pos.le_cast_iff {s t : String} {pos : t.Pos} {pos' : s.Pos} {h : s = t} :
pos pos'.cast h pos.cast h.symm pos' := by
simp [Pos.le_iff]
theorem Pos.cast_lt_iff {s t : String} {pos : s.Pos} {pos' : t.Pos} {h : s = t} :
pos.cast h < pos' pos < pos'.cast h.symm := by
simp [Pos.lt_iff]
theorem Pos.lt_cast_iff {s t : String} {pos : t.Pos} {pos' : s.Pos} {h : s = t} :
pos < pos'.cast h pos.cast h.symm < pos' := by
simp [Pos.lt_iff]
theorem Pos.copy_toSlice_eq_cast {s : String} (p : s.Pos) :
p.toSlice.copy = p.cast copy_toSlice.symm :=
Pos.ext (by simp)
@@ -2015,7 +1922,7 @@ theorem Pos.toSlice_next {s : String} {p : s.Pos} {h} :
simp [next, -ofToSlice_next_toSlice]
theorem Pos.next_toSlice {s : String} {p : s.Pos} {h} :
p.toSlice.next h = (p.next (ne_of_apply_ne Pos.toSlice (by simpa using h))).toSlice := by
p.toSlice.next h = (p.next (ne_of_apply_ne Pos.toSlice (by simpa))).toSlice := by
simp [Pos.toSlice_next]
theorem Pos.byteIdx_lt_utf8ByteSize {s : String} (p : s.Pos) (h : p s.endPos) :
@@ -2141,10 +2048,6 @@ theorem Pos.le_ofToSlice_iff {s : String} {p : s.Pos} {q : s.toSlice.Pos} :
theorem Pos.toSlice_lt_toSlice_iff {s : String} {p q : s.Pos} :
p.toSlice < q.toSlice p < q := Iff.rfl
@[simp]
theorem Pos.toSlice_le_toSlice_iff {s : String} {p q : s.Pos} :
p.toSlice q.toSlice p q := Iff.rfl
theorem Pos.next_le_of_lt {s : String} {p q : s.Pos} {h} : p < q p.next h q := by
rw [next, Pos.ofToSlice_le_iff, Pos.toSlice_lt_toSlice_iff]
exact Slice.Pos.next_le_of_lt

View File

@@ -64,7 +64,7 @@ public theorem Char.utf8Size_eq (c : Char) : c.utf8Size = 1 c.utf8Size = 2
match c.utf8Size, c.utf8Size_pos, c.utf8Size_le_four with
| 1, _, _ | 2, _, _ | 3, _, _ | 4, _, _ => simp
theorem Char.toNat_le {c : Char} : c.toNat 0x10ffff := by
theorem Char.toNat_val_le {c : Char} : c.val.toNat 0x10ffff := by
have := c.valid
simp [UInt32.isValidChar, Nat.isValidChar] at this
omega
@@ -193,10 +193,10 @@ theorem helper₄ (s : Nat) (c : BitVec w₀) (v : BitVec w') (w : Nat) :
-- TODO: possibly it makes sense to factor out this proof
theorem String.toBitVec_getElem_utf8EncodeChar_zero_of_utf8Size_eq_one {c : Char} (h : c.utf8Size = 1) :
((String.utf8EncodeChar c)[0]'(by simp [h])).toBitVec = 0#1 ++ c.val.toBitVec.extractLsb' 0 7 := by
have h₀ : c.toNat < 128 := by
suffices c.toNat 127 by omega
have h₀ : c.val.toNat < 128 := by
suffices c.val.toNat 127 by omega
simpa [Char.utf8Size_eq_one_iff, UInt32.le_iff_toNat_le] using h
have h₁ : c.toNat < 256 := by omega
have h₁ : c.val.toNat < 256 := by omega
rw [ BitVec.toNat_inj, BitVec.toNat_append]
simp [-Char.toUInt8_val, utf8EncodeChar_eq_singleton h, Nat.mod_eq_of_lt h₀, Nat.mod_eq_of_lt h₁]
@@ -977,9 +977,9 @@ theorem assemble₄_eq_some_iff_utf8EncodeChar_eq {w x y z : UInt8} {c : Char} :
BitVec.extractLsb'_append_extractLsb'_eq_extractLsb' (by simp),
BitVec.extractLsb'_append_extractLsb'_eq_extractLsb' (by simp),
BitVec.setWidth_eq_extractLsb' (by simp), BitVec.setWidth_setWidth_eq_self]
have := c.toNat_le
have := c.toNat_val_le
simp only [Nat.reduceAdd, BitVec.lt_def, UInt32.toNat_toBitVec, BitVec.toNat_twoPow,
Nat.reducePow, Nat.reduceMod, gt_iff_lt, Char.toNat_val]
Nat.reducePow, Nat.reduceMod, gt_iff_lt]
omega
theorem verify₄_eq_isSome_assemble₄ {w x y z : UInt8} :

View File

@@ -187,9 +187,6 @@ theorem append_right_inj (s : String) {t₁ t₂ : String} :
theorem append_assoc {s₁ s₂ s₃ : String} : s₁ ++ s₂ ++ s₃ = s₁ ++ (s₂ ++ s₃) := by
simp [ toByteArray_inj, ByteArray.append_assoc]
instance : Std.Associative (α := String) (· ++ ·) where
assoc _ _ _ := append_assoc
@[simp]
theorem utf8ByteSize_eq_zero_iff {s : String} : s.utf8ByteSize = 0 s = "" := by
refine fun h => ?_, fun h => h utf8ByteSize_empty

View File

@@ -6,5 +6,29 @@ Authors: Markus Himmel
module
prelude
public import Init.Data.String.Iter.Basic
public import Init.Data.String.Iter.Intercalate
public import Init.Data.Iterators.Combinators.FilterMap
public import Init.Data.Iterators.Consumers.Collect
set_option doc.verso true
namespace Std
/--
Convenience function for turning an iterator into a list of strings, provided the output of the
iterator implements {name}`ToString`.
-/
@[inline]
public abbrev Iter.toStringList {α β : Type} [Iterator α Id β] [ToString β]
(it : Iter (α := α) β) : List String :=
it.map toString |>.toList
/--
Convenience function for turning an iterator into an array of strings, provided the output of the
iterator implements {name}`ToString`.
-/
@[inline]
public abbrev Iter.toStringArray {α β : Type} [Iterator α Id β] [ToString β]
(it : Iter (α := α) β) : Array String :=
it.map toString |>.toArray
end Std

View File

@@ -1,34 +0,0 @@
/-
Copyright (c) 2026 Lean FRO, LLC. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Markus Himmel
-/
module
prelude
public import Init.Data.Iterators.Combinators.FilterMap
public import Init.Data.Iterators.Consumers.Collect
set_option doc.verso true
namespace Std
/--
Convenience function for turning an iterator into a list of strings, provided the output of the
iterator implements {name}`ToString`.
-/
@[inline]
public abbrev Iter.toStringList {α β : Type} [Iterator α Id β] [ToString β]
(it : Iter (α := α) β) : List String :=
it.map toString |>.toList
/--
Convenience function for turning an iterator into an array of strings, provided the output of the
iterator implements {name}`ToString`.
-/
@[inline]
public abbrev Iter.toStringArray {α β : Type} [Iterator α Id β] [ToString β]
(it : Iter (α := α) β) : Array String :=
it.map toString |>.toArray
end Std

View File

@@ -1,37 +0,0 @@
/-
Copyright (c) 2026 Lean FRO, LLC. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Julia Markus Himmel
-/
module
prelude
public import Init.Data.Iterators.Combinators.Monadic.FilterMap
public import Init.Data.String.Basic
import Init.Data.String.Slice
set_option doc.verso true
namespace Std
/--
Appends all the elements in the iterator, in order.
-/
@[inline]
public def Iter.joinString {α β : Type} [Iterator α Id β] [ToString β]
(it : Std.Iter (α := α) β) : String :=
(it.map toString).fold (init := "") (· ++ ·)
/--
Appends the elements of the iterator into a string, placing the separator {name}`s` between them.
-/
@[inline]
public def Iter.intercalateString {α β : Type} [Iterator α Id β] [ToString β]
(s : String.Slice) (it : Std.Iter (α := α) β) : String :=
it.map toString
|>.fold (init := none) (fun
| none, sl => some sl
| some str, sl => some (str ++ s ++ sl))
|>.getD ""
end Std

View File

@@ -27,7 +27,6 @@ deriving Inhabited
/--
Creates an iterator over the valid positions within {name}`s`, starting at {name}`p`.
-/
@[cbv_opaque]
def positionsFrom {s : Slice} (p : s.Pos) :
Std.Iter (α := PosIterator s) { p : s.Pos // p s.endPos } :=
{ internalState := { currPos := p } }
@@ -100,7 +99,7 @@ Examples:
* {lean}`"abc".toSlice.chars.toList = ['a', 'b', 'c']`
* {lean}`"ab∀c".toSlice.chars.toList = ['a', 'b', '∀', 'c']`
-/
@[cbv_opaque, expose, inline]
@[expose, inline]
def chars (s : Slice) :=
Std.Iter.map (fun pos, h => pos.get h) (positions s)
@@ -189,7 +188,7 @@ Example:
* {lean}`"abc".toSlice.revChars.toList = ['c', 'b', 'a']`
* {lean}`"ab∀c".toSlice.revChars.toList = ['c', '∀', 'b', 'a']`
-/
@[cbv_opaque, expose, inline]
@[expose, inline]
def revChars (s : Slice) :=
Std.Iter.map (fun pos, h => pos.get h) (revPositions s)
@@ -348,7 +347,7 @@ Examples:
* {lean}`"coffee tea and water".toSlice.foldl (fun n c => if c.isWhitespace then n + 1 else n) 0 = 3`
* {lean}`"coffee tea water".toSlice.foldl (·.push ·) "" = "coffee tea water"`
-/
@[cbv_opaque, inline]
@[inline]
def foldl {α : Type u} (f : α Char α) (init : α) (s : Slice) : α :=
Std.Iter.fold f init (chars s)
@@ -399,7 +398,7 @@ Examples:
* {lean}`"abc".chars.toList = ['a', 'b', 'c']`
* {lean}`"ab∀c".chars.toList = ['a', 'b', '∀', 'c']`
-/
@[cbv_opaque, inline]
@[inline]
def chars (s : String) :=
(s.toSlice.chars : Std.Iter Char)
@@ -433,7 +432,7 @@ Example:
* {lean}`"abc".revChars.toList = ['c', 'b', 'a']`
* {lean}`"ab∀c".revChars.toList = ['c', '∀', 'b', 'a']`
-/
@[cbv_opaque, inline]
@[inline]
def revChars (s : String) :=
(s.toSlice.revChars : Std.Iter Char)
@@ -463,32 +462,4 @@ def revBytes (s : String) :=
instance {m : Type u Type v} [Monad m] : ForIn m String Char where
forIn s b f := ForIn.forIn s.toSlice b f
/--
Folds a function over a string from the start, accumulating a value starting with {name}`init`. The
accumulated value is combined with each character in order, using {name}`f`.
Examples:
* {lean}`"coffee tea water".foldl (fun n c => if c.isWhitespace then n + 1 else n) 0 = 2`
* {lean}`"coffee tea and water".foldl (fun n c => if c.isWhitespace then n + 1 else n) 0 = 3`
* {lean}`"coffee tea water".foldl (·.push ·) "" = "coffee tea water"`
-/
@[inline] def foldl {α : Type u} (f : α Char α) (init : α) (s : String) : α :=
s.toSlice.foldl f init
@[export lean_string_foldl]
def Internal.foldlImpl (f : String Char String) (init : String) (s : String) : String :=
String.foldl f init s
/--
Folds a function over a string from the right, accumulating a value starting with {lean}`init`. The
accumulated value is combined with each character in reverse order, using {lean}`f`.
Examples:
* {lean}`"coffee tea water".foldr (fun c n => if c.isWhitespace then n + 1 else n) 0 = 2`
* {lean}`"coffee tea and water".foldr (fun c n => if c.isWhitespace then n + 1 else n) 0 = 3`
* {lean}`"coffee tea water".foldr (fun c s => s.push c) "" = "retaw aet eeffoc"`
-/
@[inline] def foldr {α : Type u} (f : Char α α) (init : α) (s : String) : α :=
s.toSlice.foldr f init
end String

View File

@@ -17,7 +17,49 @@ public import Init.Data.String.Lemmas.Pattern
public import Init.Data.String.Lemmas.Slice
public import Init.Data.String.Lemmas.Iterate
public import Init.Data.String.Lemmas.Intercalate
public import Init.Data.String.Lemmas.Iter
public import Init.Data.String.Lemmas.Hashable
public import Init.Data.String.Lemmas.TakeDrop
public import Init.Data.String.Lemmas.StringOrder
import Init.Data.Order.Lemmas
public import Init.Data.String.Basic
import Init.Data.Char.Lemmas
import Init.Data.Char.Order
import Init.Data.List.Lex
public section
open Std
namespace String
@[deprecated toList_inj (since := "2025-10-30")]
protected theorem data_eq_of_eq {a b : String} (h : a = b) : a.toList = b.toList :=
h rfl
@[deprecated toList_inj (since := "2025-10-30")]
protected theorem ne_of_data_ne {a b : String} (h : a.toList b.toList) : a b := by
simpa [ toList_inj]
@[simp] protected theorem not_le {a b : String} : ¬ a b b < a := Decidable.not_not
@[simp] protected theorem not_lt {a b : String} : ¬ a < b b a := Iff.rfl
@[simp] protected theorem le_refl (a : String) : a a := List.le_refl _
@[simp] protected theorem lt_irrefl (a : String) : ¬ a < a := List.lt_irrefl _
attribute [local instance] Char.notLTTrans Char.ltTrichotomous Char.ltAsymm
protected theorem le_trans {a b c : String} : a b b c a c := List.le_trans
protected theorem lt_trans {a b c : String} : a < b b < c a < c := List.lt_trans
protected theorem le_total (a b : String) : a b b a := List.le_total _ _
protected theorem le_antisymm {a b : String} : a b b a a = b := fun h₁ h₂ => String.ext (List.le_antisymm (as := a.toList) (bs := b.toList) h₁ h₂)
protected theorem lt_asymm {a b : String} (h : a < b) : ¬ b < a := List.lt_asymm h
protected theorem ne_of_lt {a b : String} (h : a < b) : a b := by
have := String.lt_irrefl a
intro h; subst h; contradiction
instance instIsLinearOrder : IsLinearOrder String := by
apply IsLinearOrder.of_le
case le_antisymm => constructor; apply String.le_antisymm
case le_trans => constructor; apply String.le_trans
case le_total => constructor; apply String.le_total
instance : LawfulOrderLT String where
lt_iff a b := by
simp [ String.not_le, Decidable.imp_iff_not_or, Std.Total.total]
end String

View File

@@ -7,7 +7,6 @@ module
prelude
public import Init.Data.String.Basic
import all Init.Data.String.Basic
import Init.Data.ByteArray.Lemmas
import Init.Data.Nat.MinMax
@@ -22,10 +21,6 @@ public section
namespace String
@[simp]
theorem singleton_inj {c d : Char} : singleton c = singleton d c = d := by
simp [ toList_inj]
@[simp]
theorem singleton_append_inj : singleton c ++ s = singleton d ++ t c = d s = t := by
simp [ toList_inj]
@@ -61,11 +56,6 @@ theorem singleton_ne_empty {c : Char} : singleton c ≠ "" := by
theorem empty_ne_singleton {c : Char} : "" singleton c := by
simp
@[simp]
theorem ofList_cons {c : Char} {l : List Char} :
String.ofList (c :: l) = String.singleton c ++ String.ofList l := by
simp [ toList_inj]
@[simp]
theorem Slice.Pos.copy_inj {s : Slice} {p₁ p₂ : s.Pos} : p₁.copy = p₂.copy p₁ = p₂ := by
simp [String.Pos.ext_iff, Pos.ext_iff]
@@ -88,7 +78,7 @@ theorem getUTF8Byte_toSlice {s : String} {p : String.Pos.Raw} {h} :
@[simp]
theorem Pos.byte_toSlice {s : String} {p : s.Pos} {h} :
p.toSlice.byte h = p.byte (ne_of_apply_ne Pos.toSlice (by simpa using h)) := by
p.toSlice.byte h = p.byte (ne_of_apply_ne Pos.toSlice (by simpa)) := by
simp [byte]
theorem Pos.byte_eq_byte_toSlice {s : String} {p : s.Pos} {h} :
@@ -191,78 +181,6 @@ theorem sliceTo_slice {s : String} {p₁ p₂ h p} :
(s.slice p₁ p₂ h).sliceTo p = s.slice p₁ (Pos.ofSlice p) Pos.le_ofSlice := by
ext <;> simp
@[simp]
theorem Slice.sliceFrom_startPos {s : Slice} : s.sliceFrom s.startPos = s := by
ext <;> simp
@[simp]
theorem Slice.sliceFrom_eq_self_iff {s : Slice} {p : s.Pos} : s.sliceFrom p = s p = s.startPos := by
refine ?_, by rintro rfl; simp
rcases s with str, startInclusive, endExclusive, h
simp [sliceFrom, Slice.startPos, String.Pos.ext_iff, Pos.Raw.ext_iff, Slice.Pos.ext_iff]
@[simp]
theorem Slice.sliceTo_endPos {s : Slice} : s.sliceTo s.endPos = s := by
ext <;> simp
@[simp]
theorem Slice.sliceTo_eq_self_iff {s : Slice} {p : s.Pos} : s.sliceTo p = s p = s.endPos := by
refine ?_, by rintro rfl; simp
rcases s with str, startInclusive, endExclusive, h
simp [sliceTo, Slice.endPos, String.Pos.ext_iff, Pos.Raw.ext_iff, Slice.Pos.ext_iff,
utf8ByteSize_eq]
omega
@[simp]
theorem Slice.slice_startPos {s : Slice} {p : s.Pos} :
s.slice s.startPos p (Pos.startPos_le _) = s.sliceTo p := by
ext <;> simp
@[simp]
theorem Slice.slice_eq_self_iff {s : Slice} {p₁ p₂ : s.Pos} {h} :
s.slice p₁ p₂ h = s p₁ = s.startPos p₂ = s.endPos := by
refine ?_, by rintro rfl, rfl; simp
rcases s with str, startInclusive, endExclusive, h
simp [slice, Slice.endPos, String.Pos.ext_iff, Pos.Raw.ext_iff, Slice.Pos.ext_iff,
utf8ByteSize_eq]
omega
@[simp]
theorem Slice.slice_endPos {s : Slice} {p : s.Pos} :
s.slice p s.endPos (Pos.le_endPos _) = s.sliceFrom p := by
ext <;> simp
@[simp]
theorem sliceFrom_startPos {s : String} : s.sliceFrom s.startPos = s := by
ext <;> simp
@[simp]
theorem sliceFrom_eq_toSlice_iff {s : String} {p : s.Pos} : s.sliceFrom p = s.toSlice p = s.startPos := by
simp [ sliceFrom_toSlice]
@[simp]
theorem sliceTo_endPos {s : String} : s.sliceTo s.endPos = s := by
ext <;> simp
@[simp]
theorem sliceTo_eq_toSlice_iff {s : String} {p : s.Pos} : s.sliceTo p = s.toSlice p = s.endPos := by
simp [ sliceTo_toSlice]
@[simp]
theorem slice_startPos {s : String} {p : s.Pos} :
s.slice s.startPos p (Pos.startPos_le _) = s.sliceTo p := by
ext <;> simp
@[simp]
theorem slice_endPos {s : String} {p : s.Pos} :
s.slice p s.endPos (Pos.le_endPos _) = s.sliceFrom p := by
ext <;> simp
@[simp]
theorem slice_eq_toSlice_iff {s : String} {p₁ p₂ : s.Pos} {h} :
s.slice p₁ p₂ h = s.toSlice p₁ = s.startPos p₂ = s.endPos := by
simp [ slice_toSlice]
end Iterate
theorem Slice.copy_eq_copy_slice {s : Slice} {pos₁ pos₂ : s.Pos} {h} :
@@ -310,81 +228,4 @@ theorem Pos.get_ofToSlice {s : String} {p : (s.toSlice).Pos} {h} :
@[simp]
theorem push_empty {c : Char} : "".push c = singleton c := rfl
namespace Slice.Pos
@[simp]
theorem nextn_zero {s : Slice} {p : s.Pos} : p.nextn 0 = p := by
simp [nextn]
theorem nextn_add_one {s : Slice} {p : s.Pos} :
p.nextn (n + 1) = if h : p = s.endPos then p else (p.next h).nextn n := by
simp [nextn]
@[simp]
theorem nextn_endPos {s : Slice} : s.endPos.nextn n = s.endPos := by
cases n <;> simp [nextn_add_one]
end Slice.Pos
namespace Pos
theorem nextn_eq_nextn_toSlice {s : String} {p : s.Pos} : p.nextn n = Pos.ofToSlice (p.toSlice.nextn n) :=
(rfl)
@[simp]
theorem nextn_zero {s : String} {p : s.Pos} : p.nextn 0 = p := by
simp [nextn_eq_nextn_toSlice]
theorem nextn_add_one {s : String} {p : s.Pos} :
p.nextn (n + 1) = if h : p = s.endPos then p else (p.next h).nextn n := by
simp only [nextn_eq_nextn_toSlice, Slice.Pos.nextn_add_one, endPos_toSlice, toSlice_inj]
split <;> simp [Pos.next_toSlice]
theorem nextn_toSlice {s : String} {p : s.Pos} : p.toSlice.nextn n = (p.nextn n).toSlice := by
induction n generalizing p with simp_all [nextn_add_one, Slice.Pos.nextn_add_one, apply_dite Pos.toSlice, next_toSlice]
theorem toSlice_nextn {s : String} {p : s.Pos} : (p.nextn n).toSlice = p.toSlice.nextn n :=
nextn_toSlice.symm
@[simp]
theorem nextn_endPos {s : String} : s.endPos.nextn n = s.endPos := by
cases n <;> simp [nextn_add_one]
end Pos
@[simp]
theorem Slice.Pos.cast_toSlice_copy {s : Slice} {pos : s.Pos} :
pos.copy.toSlice.cast (by simp) = pos := by
ext; simp
@[simp]
theorem Slice.Pos.sliceFrom_eq_startPos {s : Slice} {p : s.Pos} :
(Pos.sliceFrom p p (Pos.le_refl _)) = Slice.startPos _ := by
simp [ Pos.ofSliceFrom_inj]
@[simp]
theorem Slice.Pos.sliceFrom_endPos {s : Slice} {p : s.Pos} :
(Pos.sliceFrom p s.endPos (Pos.le_endPos _)) = Slice.endPos _ := by
simp [ Pos.ofSliceFrom_inj]
@[simp]
theorem Slice.Pos.sliceTo_startPos {s : Slice} {p : s.Pos} :
(Pos.sliceTo p s.startPos (Pos.startPos_le _)) = Slice.startPos _ := by
simp [ Pos.ofSliceTo_inj]
@[simp]
theorem Slice.Pos.sliceTo_eq_endPos {s : Slice} {p : s.Pos} :
(Pos.sliceTo p p (Pos.le_refl _)) = Slice.endPos _ := by
simp [ Pos.ofSliceTo_inj]
@[simp]
theorem Slice.Pos.slice_eq_startPos {s : Slice} {p₀ p₁ : s.Pos} {h} :
(Pos.slice p₀ p₀ p₁ (Pos.le_refl _) h) = Slice.startPos _ := by
simp [ Pos.ofSlice_inj]
@[simp]
theorem Slice.Pos.slice_eq_endPos {s : Slice} {p₀ p₁ : s.Pos} {h} :
(Pos.slice p₁ p₀ p₁ h (Pos.le_refl _)) = Slice.endPos _ := by
simp [ Pos.ofSlice_inj]
end String

View File

@@ -11,8 +11,6 @@ import all Init.Data.String.FindPos
import Init.Data.String.OrderInstances
import Init.Data.String.Lemmas.Order
import Init.Data.Order.Lemmas
import Init.Data.Option.Lemmas
import Init.ByCases
public section
@@ -201,10 +199,6 @@ theorem Pos.prev_eq_iff {s : Slice} {p q : s.Pos} {h} :
theorem Pos.prev_lt {s : Slice} {p : s.Pos} {h} : p.prev h < p := by
simp
@[simp]
theorem Pos.prev_le {s : Slice} {p : s.Pos} {h} : p.prev h p :=
Std.le_of_lt (by simp)
@[simp]
theorem Pos.prev_ne_endPos {s : Slice} {p : s.Pos} {h} : p.prev h s.endPos :=
ne_endPos_of_lt prev_lt
@@ -215,29 +209,6 @@ theorem Pos.prevn_le {s : Slice} {p : s.Pos} {n : Nat} : p.prevn n ≤ p := by
| case2 p n h ih => exact Std.le_of_lt (by simpa using ih)
| case3 => simp
theorem Pos.ofSliceTo_prev {s : Slice} {p₀ : s.Pos} {p : (s.sliceTo p₀).Pos} {h} :
Pos.ofSliceTo (p.prev h) = (Pos.ofSliceTo p).prev (by simpa [ Pos.ofSliceTo_inj] using h) := by
rw [eq_comm, Pos.prev_eq_iff]
simp only [Pos.ofSliceTo_lt_ofSliceTo_iff, Pos.le_ofSliceTo_iff]
simp [Pos.lt_ofSliceTo_iff]
theorem Pos.prev_ofSliceTo {s : Slice} {p₀ : s.Pos} {p : (s.sliceTo p₀).Pos} {h} :
(Pos.ofSliceTo p).prev h = Pos.ofSliceTo (p.prev (by simpa [ Pos.ofSliceTo_inj])) := by
simp [ofSliceTo_prev]
theorem Pos.ofSliceFrom_prev {s : Slice} {p₀ : s.Pos} {p : (s.sliceFrom p₀).Pos} {h} :
Pos.ofSliceFrom (p.prev h) = (Pos.ofSliceFrom p).prev (by exact ofSliceFrom_ne_startPos h) := by
rw [eq_comm, Pos.prev_eq_iff]
simp only [Pos.ofSliceFrom_lt_ofSliceFrom_iff, Pos.le_ofSliceFrom_iff]
simp [Pos.lt_ofSliceFrom_iff]
theorem Pos.ofSlice_prev {s : Slice} {p₀ p₁ : s.Pos} {h}
{p : (s.slice p₀ p₁ h).Pos} {h'} :
Pos.ofSlice (p.prev h') = (Pos.ofSlice p).prev (by exact ofSlice_ne_startPos h') := by
rw [eq_comm, Pos.prev_eq_iff]
simp only [ofSlice_lt_ofSlice_iff, le_ofSlice_iff]
simpa +contextual [ ofSlice_lt_ofSlice_iff] using fun q hq => Std.le_of_lt (Std.lt_of_lt_of_le hq ofSlice_le)
@[simp]
theorem Pos.prev_next {s : Slice} {p : s.Pos} {h} : (p.next h).prev (by simp) = p :=
prev_eq_iff.2 (by simp)
@@ -246,23 +217,6 @@ theorem Pos.prev_next {s : Slice} {p : s.Pos} {h} : (p.next h).prev (by simp) =
theorem Pos.next_prev {s : Slice} {p : s.Pos} {h} : (p.prev h).next (by simp) = p :=
next_eq_iff.2 (by simp)
theorem Pos.prev?_eq_dif {s : Slice} {p : s.Pos} : p.prev? = if h : p = s.startPos then none else some (p.prev h) :=
(rfl)
theorem Pos.prev?_eq_some_prev {s : Slice} {p : s.Pos} (h : p s.startPos) : p.prev? = some (p.prev h) := by
simp [Pos.prev?, h]
@[simp]
theorem Pos.prev?_eq_none_iff {s : Slice} {p : s.Pos} : p.prev? = none p = s.startPos := by
simp [Pos.prev?]
theorem Pos.prev?_eq_none {s : Slice} {p : s.Pos} (h : p = s.startPos) : p.prev? = none :=
prev?_eq_none_iff.2 h
@[simp]
theorem Pos.prev?_startPos {s : Slice} : s.startPos.prev? = none := by
simp
end Slice
@[simp]
@@ -466,10 +420,6 @@ theorem Pos.prev_eq_iff {s : String} {p q : s.Pos} {h} :
theorem Pos.prev_lt {s : String} {p : s.Pos} {h} : p.prev h < p := by
simp
@[simp]
theorem Pos.prev_le {s : String} {p : s.Pos} {h} : p.prev h p :=
Std.le_of_lt (by simp)
@[simp]
theorem Pos.prev_ne_endPos {s : String} {p : s.Pos} {h} : p.prev h s.endPos :=
ne_endPos_of_lt prev_lt
@@ -478,45 +428,14 @@ theorem Pos.toSlice_prev {s : String} {p : s.Pos} {h} :
(p.prev h).toSlice = p.toSlice.prev (by simpa [toSlice_inj]) := by
simp [prev]
theorem Pos.ofToSlice_prev {s : String} {p : s.toSlice.Pos} {h} :
Pos.ofToSlice (p.prev h) = (Pos.ofToSlice p).prev (by simpa [ toSlice_inj]) := by
simp [prev]
theorem Pos.prev_toSlice {s : String} {p : s.Pos} {h} :
p.toSlice.prev h = (p.prev (by simpa [ toSlice_inj])).toSlice := by
simp [prev]
theorem Pos.prev_ofToSlice {s : String} {p : s.toSlice.Pos} {h} :
(Pos.ofToSlice p).prev h = Pos.ofToSlice (p.prev (by simpa [ ofToSlice_inj])) := by
simp [prev]
theorem Pos.prevn_le {s : String} {p : s.Pos} {n : Nat} :
p.prevn n p := by
simpa [Pos.le_iff, offset_toSlice] using Slice.Pos.prevn_le
theorem Pos.ofSliceTo_prev {s : String} {p₀ : s.Pos} {p : (s.sliceTo p₀).Pos} {h} :
Pos.ofSliceTo (p.prev h) = (Pos.ofSliceTo p).prev (by simpa [ Pos.ofSliceTo_inj] using h) := by
rw [eq_comm, Pos.prev_eq_iff]
simp only [Pos.ofSliceTo_lt_ofSliceTo_iff, Pos.le_ofSliceTo_iff]
simp [Pos.lt_ofSliceTo_iff]
theorem Pos.prev_ofSliceTo {s : String} {p₀ : s.Pos} {p : (s.sliceTo p₀).Pos} {h} :
(Pos.ofSliceTo p).prev h = Pos.ofSliceTo (p.prev (by simpa [ Pos.ofSliceTo_inj])) := by
simp [ofSliceTo_prev]
theorem Pos.ofSliceFrom_prev {s : String} {p₀ : s.Pos} {p : (s.sliceFrom p₀).Pos} {h} :
Pos.ofSliceFrom (p.prev h) = (Pos.ofSliceFrom p).prev (by exact ofSliceFrom_ne_startPos h) := by
rw [eq_comm, Pos.prev_eq_iff]
simp only [Pos.ofSliceFrom_lt_ofSliceFrom_iff, Pos.le_ofSliceFrom_iff]
simp [Pos.lt_ofSliceFrom_iff]
theorem Pos.ofSlice_prev {s : String} {p₀ p₁ : s.Pos} {h}
{p : (s.slice p₀ p₁ h).Pos} {h'} :
Pos.ofSlice (p.prev h') = (Pos.ofSlice p).prev (by exact ofSlice_ne_startPos h') := by
rw [eq_comm, Pos.prev_eq_iff]
simp only [ofSlice_lt_ofSlice_iff, le_ofSlice_iff]
simpa +contextual [ ofSlice_lt_ofSlice_iff] using fun q hq => Std.le_of_lt (Std.lt_of_lt_of_le hq ofSlice_le)
@[simp]
theorem Pos.prev_next {s : String} {p : s.Pos} {h} : (p.next h).prev (by simp) = p :=
prev_eq_iff.2 (by simp)
@@ -525,71 +444,4 @@ theorem Pos.prev_next {s : String} {p : s.Pos} {h} : (p.next h).prev (by simp) =
theorem Pos.next_prev {s : String} {p : s.Pos} {h} : (p.prev h).next (by simp) = p :=
next_eq_iff.2 (by simp)
theorem Pos.prev?_eq_prev?_toSlice {s : String} {p : s.Pos} : p.prev? = p.toSlice.prev?.map Pos.ofToSlice :=
(rfl)
theorem Pos.prev?_toSlice {s : String} {p : s.Pos} : p.toSlice.prev? = p.prev?.map Pos.toSlice := by
simp [prev?_eq_prev?_toSlice]
theorem Pos.prev?_eq_dif {s : String} {p : s.Pos} : p.prev? = if h : p = s.startPos then none else some (p.prev h) := by
simp [prev?_eq_prev?_toSlice, Slice.Pos.prev?_eq_dif, apply_dite (Option.map Pos.ofToSlice),
ofToSlice_prev]
theorem Pos.prev?_eq_some_prev {s : String} {p : s.Pos} (h : p s.startPos) : p.prev? = some (p.prev h) := by
simp [prev?_eq_prev?_toSlice, Slice.Pos.prev?_eq_some_prev (by simpa : p.toSlice s.toSlice.startPos),
ofToSlice_prev]
@[simp]
theorem Pos.prev?_eq_none_iff {s : String} {p : s.Pos} : p.prev? = none p = s.startPos := by
simp [prev?_eq_prev?_toSlice]
theorem Pos.prev?_eq_none {s : String} {p : s.Pos} (h : p = s.startPos) : p.prev? = none :=
prev?_eq_none_iff.2 h
@[simp]
theorem Pos.prev?_startPos {s : String} : s.startPos.prev? = none := by
simp
namespace Slice.Pos
@[simp]
theorem prevn_zero {s : Slice} {p : s.Pos} : p.prevn 0 = p := by
simp [prevn]
theorem prevn_add_one {s : Slice} {p : s.Pos} :
p.prevn (n + 1) = if h : p = s.startPos then p else (p.prev h).prevn n := by
simp [prevn]
@[simp]
theorem prevn_startPos {s : Slice} : s.startPos.prevn n = s.startPos := by
cases n <;> simp [prevn_add_one]
end Slice.Pos
namespace Pos
theorem prevn_eq_prevn_toSlice {s : String} {p : s.Pos} : p.prevn n = Pos.ofToSlice (p.toSlice.prevn n) :=
(rfl)
@[simp]
theorem prevn_zero {s : String} {p : s.Pos} : p.prevn 0 = p := by
simp [prevn_eq_prevn_toSlice]
theorem prevn_add_one {s : String} {p : s.Pos} :
p.prevn (n + 1) = if h : p = s.startPos then p else (p.prev h).prevn n := by
simp only [prevn_eq_prevn_toSlice, Slice.Pos.prevn_add_one, startPos_toSlice, toSlice_inj]
split <;> simp [Pos.prev_toSlice]
theorem prevn_toSlice {s : String} {p : s.Pos} : p.toSlice.prevn n = (p.prevn n).toSlice := by
induction n generalizing p with simp_all [prevn_add_one, Slice.Pos.prevn_add_one, apply_dite Pos.toSlice, prev_toSlice]
theorem toSlice_prevn {s : String} {p : s.Pos} : (p.prevn n).toSlice = p.toSlice.prevn n :=
prevn_toSlice.symm
@[simp]
theorem prevn_startPos {s : String} : s.startPos.prevn n = s.startPos := by
cases n <;> simp [prevn_add_one]
end Pos
end String

View File

@@ -1,25 +0,0 @@
/-
Copyright (c) 2026 Lean FRO, LLC. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Julia Markus Himmel
-/
module
prelude
public import Init.Data.String.Slice
public import Init.Data.LawfulHashable
import all Init.Data.String.Slice
import Init.Data.String.Lemmas.Slice
namespace String
public theorem hash_eq {s : String} : hash s = String.hash s := rfl
namespace Slice
public theorem hash_eq {s : String.Slice} : hash s = String.hash s.copy := (rfl)
public instance : LawfulHashable String.Slice where
hash_eq a b hab := by simp [hash_eq, beq_eq_true_iff.1 hab]
end String.Slice

View File

@@ -10,7 +10,6 @@ public import Init.Data.String.Defs
import all Init.Data.String.Defs
public import Init.Data.String.Slice
import all Init.Data.String.Slice
import Init.ByCases
public section
@@ -43,16 +42,6 @@ theorem intercalate_cons_of_ne_nil {s t : String} {l : List String} (h : l ≠ [
match l, h with
| u::l, _ => by simp
theorem intercalate_append_of_ne_nil {l m : List String} {s : String} (hl : l []) (hm : m []) :
s.intercalate (l ++ m) = s.intercalate l ++ s ++ s.intercalate m := by
induction l with
| nil => simp_all
| cons hd tl ih =>
rw [List.cons_append, intercalate_cons_of_ne_nil (by simp_all)]
by_cases ht : tl = []
· simp_all
· simp [ih ht, intercalate_cons_of_ne_nil ht, String.append_assoc]
@[simp]
theorem toList_intercalate {s : String} {l : List String} :
(s.intercalate l).toList = s.toList.intercalate (l.map String.toList) := by
@@ -60,32 +49,6 @@ theorem toList_intercalate {s : String} {l : List String} :
| nil => simp
| cons hd tl ih => cases tl <;> simp_all
theorem join_eq_foldl : join l = l.foldl (fun r s => r ++ s) "" :=
(rfl)
@[simp]
theorem join_nil : join [] = "" := by
simp [join]
@[simp]
theorem join_cons : join (s :: l) = s ++ join l := by
simp only [join, List.foldl_cons, empty_append]
conv => lhs; rw [ String.append_empty (s := s)]
rw [List.foldl_assoc]
@[simp]
theorem toList_join {l : List String} : (String.join l).toList = l.flatMap String.toList := by
induction l <;> simp_all
@[simp]
theorem join_append {l m : List String} : String.join (l ++ m) = String.join l ++ String.join m := by
simp [ toList_inj]
@[simp]
theorem length_join {l : List String} : (String.join l).length = (l.map String.length).sum := by
simp only [ length_toList, toList_join, List.length_flatMap]
simp
namespace Slice
@[simp]
@@ -102,10 +65,6 @@ theorem intercalate_eq {s : Slice} {l : List Slice} :
| nil => simp [intercalate]
| cons hd tl ih => cases tl <;> simp_all [intercalate, intercalate.go, intercalateGo_append]
@[simp]
theorem join_eq {l : List Slice} : join l = String.join (l.map copy) := by
simp [join, String.join, List.foldl_map]
end Slice
end String

View File

@@ -204,7 +204,7 @@ theorem Slice.copy_sliceTo_startPos {s : Slice} : (s.sliceTo s.startPos).copy =
simp
@[simp]
theorem Slice.copy_sliceFrom_endPos {s : Slice} : (s.sliceFrom s.endPos).copy = "" := by
theorem Slice.copy_sliceFrom_startPos {s : Slice} : (s.sliceFrom s.endPos).copy = "" := by
simp
end CopyEqEmpty

View File

@@ -1,50 +0,0 @@
/-
Copyright (c) 2026 Lean FRO, LLC. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Julia Markus Himmel
-/
module
prelude
public import Init.Data.String.Iter.Intercalate
public import Init.Data.String.Slice
import all Init.Data.String.Iter.Intercalate
import all Init.Data.String.Defs
import Init.Data.String.Lemmas.Intercalate
import Init.Data.Iterators.Lemmas.Consumers.Loop
import Init.Data.Iterators.Lemmas.Combinators.FilterMap
namespace Std.Iter
@[simp]
public theorem joinString_eq {α β : Type} [Std.Iterator α Id β] [Std.Iterators.Finite α Id]
[ToString β] {it : Std.Iter (α := α) β} :
it.joinString = String.join (it.toList.map toString) := by
rw [joinString, String.join, foldl_toList, toList_map]
@[simp]
public theorem intercalateString_eq {α β : Type} [Std.Iterator α Id β] [Std.Iterators.Finite α Id]
[ToString β] {s : String.Slice} {it : Std.Iter (α := α) β} :
it.intercalateString s = s.copy.intercalate (it.toList.map toString) := by
simp only [intercalateString, String.appendSlice_eq, foldl_toList, toList_map]
generalize s.copy = s
suffices (l m : List String),
(l.foldl (init := if m = [] then none else some (s.intercalate m))
(fun | none, sl => some sl | some str, sl => some (str ++ s ++ sl))).getD ""
= s.intercalate (m ++ l) by
simpa [-foldl_toList] using this (it.toList.map toString) []
intro l m
induction l generalizing m with
| nil => cases m <;> simp
| cons hd tl ih =>
rw [List.append_cons, ih, List.foldl_cons]
congr
simp only [List.append_eq_nil_iff, List.cons_ne_self, and_false, reduceIte]
match m with
| [] => simp
| x::xs =>
simp only [reduceCtorEq, reduceIte, List.cons_append, Option.some.injEq]
rw [ List.cons_append, String.intercalate_append_of_ne_nil (by simp) (by simp),
String.intercalate_singleton]
end Std.Iter

View File

@@ -76,7 +76,7 @@ theorem Model.map_get_positionsFrom_startPos {s : Slice} :
(Model.positionsFrom s.startPos).map (fun p => p.1.get p.2) = s.copy.toList :=
Model.map_get_positionsFrom_of_splits (splits_startPos s)
@[cbv_eval, simp]
@[simp]
theorem toList_positionsFrom {s : Slice} {p : s.Pos} :
(s.positionsFrom p).toList = Model.positionsFrom p := by
rw [positionsFrom]
@@ -91,7 +91,7 @@ theorem toList_positionsFrom {s : Slice} {p : s.Pos} :
theorem toList_positions {s : Slice} : s.positions.toList = Model.positionsFrom s.startPos := by
simp [positions]
@[cbv_eval, simp]
@[simp]
theorem toList_chars {s : Slice} : s.chars.toList = s.copy.toList := by
simp [chars, Model.map_get_positionsFrom_startPos]
@@ -177,30 +177,19 @@ theorem toList_revPositionsFrom {s : Slice} {p : s.Pos} :
theorem toList_revPositions {s : Slice} : s.revPositions.toList = Model.revPositionsFrom s.endPos := by
simp [revPositions]
@[cbv_eval, simp]
@[simp]
theorem toList_revChars {s : Slice} : s.revChars.toList = s.copy.toList.reverse := by
simp [revChars, Model.map_get_revPositionsFrom_endPos]
theorem forIn_eq_forIn_chars {m : Type u Type v} [Monad m] {s : Slice} {b} {f : Char β m (ForInStep β)} :
ForIn.forIn s b f = ForIn.forIn s.chars b f := rfl
@[cbv_eval, simp]
@[simp]
theorem forIn_eq_forIn_toList {m : Type u Type v} [Monad m] [LawfulMonad m] {s : Slice} {b}
{f : Char β m (ForInStep β)} :
ForIn.forIn s b f = ForIn.forIn s.copy.toList b f := by
rw [forIn_eq_forIn_chars, Std.Iter.forIn_toList, toList_chars]
@[cbv_eval, simp]
theorem foldl_eq_foldl_toList {α : Type u} {f : α Char α} {init : α} {s : Slice} :
s.foldl f init = s.copy.toList.foldl f init := by
rw [foldl, Std.Iter.foldl_toList, toList_chars]
@[simp]
theorem foldr_eq_foldr_toList {α : Type u} {f : Char α α} {init : α} {s : Slice} :
s.foldr f init = s.copy.toList.foldr f init := by
rw [foldr, Std.Iter.foldl_toList, toList_revChars, List.foldl_reverse]
congr
end Slice
/--
@@ -262,11 +251,10 @@ theorem toList_positionsFrom {s : String} {p : s.Pos} :
(s.positionsFrom p).toList = Model.positionsFrom p := by
simp [positionsFrom, Internal.ofToSliceWithProof, Model.positionsFrom_eq_map]
@[cbv_eval]
theorem toList_positions {s : String} : s.positions.toList = Model.positionsFrom s.startPos := by
simp [positions]
@[cbv_eval, simp]
@[simp]
theorem toList_chars {s : String} : s.chars.toList = s.toList := by
simp [chars]
@@ -354,7 +342,7 @@ theorem toList_revPositions {s : String} :
s.revPositions.toList = Model.revPositionsFrom s.endPos := by
simp [revPositions]
@[cbv_eval, simp]
@[simp]
theorem toList_revChars {s : String} : s.revChars.toList = s.toList.reverse := by
simp [revChars]
@@ -367,14 +355,4 @@ theorem forIn_eq_forIn_toList {m : Type u → Type v} [Monad m] [LawfulMonad m]
ForIn.forIn s b f = ForIn.forIn s.toList b f := by
rw [forIn_eq_forIn_chars, Std.Iter.forIn_toList, toList_chars]
@[simp]
theorem foldl_eq_foldl_toList {α : Type u} {f : α Char α} {init : α} {s : String} :
s.foldl f init = s.toList.foldl f init := by
simp [foldl]
@[simp]
theorem foldr_eq_foldr_toList {α : Type u} {f : Char α α} {init : α} {s : String} :
s.foldr f init = s.toList.foldr f init := by
simp [foldr]
end String

View File

@@ -49,14 +49,6 @@ theorem toList_mapAux {f : Char → Char} {s : String} {p : s.Pos}
theorem toList_map {f : Char Char} {s : String} : (s.map f).toList = s.toList.map f := by
simp [map, toList_mapAux s.splits_startPos]
/-
Used internally by the `cbv` tactic.
-/
@[cbv_eval]
theorem map_eq_internal {f : Char Char} {s : String} : s.map f = .ofList (s.toList.map f) := by
apply String.toList_injective
simp only [toList_map, toList_ofList]
@[simp]
theorem length_map {f : Char Char} {s : String} : (s.map f).length = s.length := by
simp [ length_toList]

View File

@@ -11,7 +11,6 @@ import Init.Data.String.OrderInstances
import Init.Data.String.Lemmas.Basic
import Init.Data.Order.Lemmas
import Init.Omega
import Init.ByCases
public section
@@ -71,7 +70,7 @@ theorem Pos.le_startPos {s : String} (p : s.Pos) : p ≤ s.startPos ↔ p = s.st
fun h => Std.le_antisymm h (startPos_le _), by simp +contextual
@[simp]
theorem Pos.startPos_lt_iff {s : String} (p : s.Pos) : s.startPos < p p s.startPos := by
theorem Pos.startPos_lt_iff {s : String} {p : s.Pos} : s.startPos < p p s.startPos := by
simp [ le_startPos, Std.not_le]
@[simp]
@@ -236,10 +235,6 @@ theorem Slice.Pos.ofSliceFrom_next {s : Slice} {p₀ : s.Pos} {p : (s.sliceFrom
Pos.next_le_iff_lt, true_and]
simp [Pos.ofSliceFrom_lt_iff]
theorem Slice.Pos.next_ofSliceFrom {s : Slice} {p₀ : s.Pos} {p : (s.sliceFrom p₀).Pos} {h} :
(Pos.ofSliceFrom p).next h = Pos.ofSliceFrom (p.next (by simpa [ Pos.ofSliceFrom_inj])) := by
simp [ofSliceFrom_next]
theorem Pos.ofSliceFrom_next {s : String} {p₀ : s.Pos} {p : (s.sliceFrom p₀).Pos} {h} :
Pos.ofSliceFrom (p.next h) = (Pos.ofSliceFrom p).next (by simpa [ Pos.ofSliceFrom_inj] using h) := by
rw [eq_comm, Pos.next_eq_iff]
@@ -247,10 +242,6 @@ theorem Pos.ofSliceFrom_next {s : String} {p₀ : s.Pos} {p : (s.sliceFrom p₀)
Slice.Pos.next_le_iff_lt, true_and]
simp [Pos.ofSliceFrom_lt_iff]
theorem Pos.next_ofSliceFrom {s : String} {p₀ : s.Pos} {p : (s.sliceFrom p₀).Pos} {h} :
(Pos.ofSliceFrom p).next h = Pos.ofSliceFrom (p.next (by simpa [ Pos.ofSliceFrom_inj])) := by
simp [Pos.ofSliceFrom_next]
theorem Slice.Pos.le_ofSliceTo_iff {s : Slice} {p₀ : s.Pos} {p : (s.sliceTo p₀).Pos} {q : s.Pos} :
q Pos.ofSliceTo p h, Slice.Pos.sliceTo p₀ q h p := by
refine fun h => Slice.Pos.le_trans h Pos.ofSliceTo_le, ?_, fun h, h' => ?_
@@ -368,41 +359,11 @@ theorem Slice.Pos.ofSliceTo_ne_endPos {s : Slice} {p₀ : s.Pos} {p : (s.sliceTo
refine (lt_endPos_iff _).1 (Std.lt_of_lt_of_le ?_ (le_endPos p₀))
simpa [ lt_endPos_iff, ofSliceTo_lt_ofSliceTo_iff] using h
theorem Slice.Pos.ne_endPos_of_sliceTo_ne_endPos {s : Slice} {p p₀ : s.Pos} {h₀}
(h : Pos.sliceTo p₀ p h₀ Slice.endPos _) : p s.endPos := by
rw [ Pos.ofSliceTo_sliceTo (h := h₀)]
apply Pos.ofSliceTo_ne_endPos h
theorem Slice.Pos.ofSliceFrom_ne_startPos {s : Slice} {p₀ : s.Pos} {p : (s.sliceFrom p₀).Pos}
(h : p (s.sliceFrom p₀).startPos) : Pos.ofSliceFrom p s.startPos := by
refine (startPos_lt_iff _).1 (Std.lt_of_le_of_lt (startPos_le p₀) ?_)
simpa [ startPos_lt_iff, ofSliceFrom_lt_ofSliceFrom_iff] using h
theorem Slice.Pos.ne_startPos_of_sliceFrom_ne_startPos {s : Slice} {p p₀ : s.Pos} {h₀}
(h : Pos.sliceFrom p₀ p h₀ Slice.startPos _) : p s.startPos := by
rw [ Pos.ofSliceFrom_sliceFrom (h := h₀)]
apply Pos.ofSliceFrom_ne_startPos h
theorem Pos.ofSliceTo_ne_endPos {s : String} {p₀ : s.Pos} {p : (s.sliceTo p₀).Pos}
(h : p (s.sliceTo p₀).endPos) : Pos.ofSliceTo p s.endPos := by
refine (lt_endPos_iff _).1 (Std.lt_of_lt_of_le ?_ (le_endPos p₀))
simpa [ Slice.Pos.lt_endPos_iff, ofSliceTo_lt_ofSliceTo_iff] using h
theorem Pos.ne_endPos_of_sliceTo_ne_endPos {s : String} {p p₀ : s.Pos} {h₀}
(h : Pos.sliceTo p₀ p h₀ Slice.endPos _) : p s.endPos := by
rw [ Pos.ofSliceTo_sliceTo (h := h₀)]
apply Pos.ofSliceTo_ne_endPos h
theorem Pos.ofSliceFrom_ne_startPos {s : String} {p₀ : s.Pos} {p : (s.sliceFrom p₀).Pos}
(h : p (s.sliceFrom p₀).startPos) : Pos.ofSliceFrom p s.startPos := by
refine (startPos_lt_iff _).1 (Std.lt_of_le_of_lt (startPos_le p₀) ?_)
simpa [ Slice.Pos.startPos_lt_iff, ofSliceFrom_lt_ofSliceFrom_iff] using h
theorem Pos.ne_startPos_of_sliceFrom_ne_startPos {s : String} {p p₀ : s.Pos} {h₀}
(h : Pos.sliceFrom p₀ p h₀ Slice.startPos _) : p s.startPos := by
rw [ Pos.ofSliceFrom_sliceFrom (h := h₀)]
apply Pos.ofSliceFrom_ne_startPos h
theorem Slice.Pos.ofSliceTo_next {s : Slice} {p₀ : s.Pos} {p : (s.sliceTo p₀).Pos} {h} :
Pos.ofSliceTo (p.next h) = (Pos.ofSliceTo p).next (ofSliceTo_ne_endPos h) := by
rw [eq_comm, Pos.next_eq_iff]
@@ -445,130 +406,16 @@ theorem Pos.slice_le_slice_iff {s : String} {p₀ p₁ : s.Pos} {q r : s.Pos}
simp [Slice.Pos.le_iff, Pos.le_iff, Pos.Raw.le_iff] at h₁ h₁'
omega
theorem Slice.Pos.le_ofSlice_iff {s : Slice} {p₀ p₁ : s.Pos} {h} {p : (s.slice p₀ p₁ h).Pos} {q : s.Pos} :
q Pos.ofSlice p h₁, h₀, Slice.Pos.slice q p₀ p₁ h₀ h₁ p := by
refine fun h => Std.le_trans h ofSlice_le, fun h' => ?_, fun h₁, h => ?_
· simp only [ Slice.Pos.slice_ofSlice (pos := p), slice_le_slice_iff]
simpa
· by_cases h₀ : p₀ q
· simpa only [ Slice.Pos.ofSlice_slice (h₁ := h₀) (h₂ := h₁), ofSlice_le_ofSlice_iff] using h h₀
· exact Std.le_of_lt (Std.lt_of_lt_of_le (Std.not_le.1 h₀) le_ofSlice)
theorem Slice.Pos.ofSlice_lt_iff {s : Slice} {p₀ p₁ : s.Pos} {h} {p : (s.slice p₀ p₁ h).Pos} {q : s.Pos} :
Pos.ofSlice p < q h₁, h₀, p < Slice.Pos.slice q p₀ p₁ h₀ h₁ := by
simp [ Std.not_le, le_ofSlice_iff]
theorem Slice.Pos.lt_ofSlice_iff {s : Slice} {p₀ p₁ : s.Pos} {h} {p : (s.slice p₀ p₁ h).Pos} {q : s.Pos} :
q < Pos.ofSlice p h₁, h₀, Slice.Pos.slice q p₀ p₁ h₀ h₁ < p := by
refine fun h => Std.le_of_lt (Std.lt_of_lt_of_le h ofSlice_le), fun h' => ?_, fun h₁, h => ?_
· simp only [ Slice.Pos.slice_ofSlice (pos := p), slice_lt_slice_iff]
simpa
· by_cases h₀ : p₀ q
· simpa only [ Slice.Pos.ofSlice_slice (h₁ := h₀) (h₂ := h₁), ofSlice_lt_ofSlice_iff] using h h₀
· exact Std.lt_of_lt_of_le (Std.not_le.1 h₀) le_ofSlice
theorem Slice.Pos.ofSlice_le_iff {s : Slice} {p₀ p₁ : s.Pos} {h} {p : (s.slice p₀ p₁ h).Pos} {q : s.Pos} :
Pos.ofSlice p q h₁, h₀, p Slice.Pos.slice q p₀ p₁ h₀ h₁ := by
simp [ Std.not_lt, lt_ofSlice_iff]
theorem Pos.le_ofSlice_iff {s : String} {p₀ p₁ : s.Pos} {h} {p : (s.slice p₀ p₁ h).Pos} {q : s.Pos} :
q Pos.ofSlice p h₁, h₀, Pos.slice q p₀ p₁ h₀ h₁ p := by
refine fun h => Std.le_trans h ofSlice_le, fun h' => ?_, fun h₁, h => ?_
· simp only [ Pos.slice_ofSlice (pos := p), slice_le_slice_iff]
simpa
· by_cases h₀ : p₀ q
· simpa only [ Pos.ofSlice_slice (h₁ := h₀) (h₂ := h₁), ofSlice_le_ofSlice_iff] using h h₀
· exact Std.le_of_lt (Std.lt_of_lt_of_le (Std.not_le.1 h₀) le_ofSlice)
theorem Pos.ofSlice_lt_iff {s : String} {p₀ p₁ : s.Pos} {h} {p : (s.slice p₀ p₁ h).Pos} {q : s.Pos} :
Pos.ofSlice p < q h₁, h₀, p < Pos.slice q p₀ p₁ h₀ h₁ := by
simp [ Std.not_le, le_ofSlice_iff]
theorem Pos.lt_ofSlice_iff {s : String} {p₀ p₁ : s.Pos} {h} {p : (s.slice p₀ p₁ h).Pos} {q : s.Pos} :
q < Pos.ofSlice p h₁, h₀, Pos.slice q p₀ p₁ h₀ h₁ < p := by
refine fun h => Std.le_of_lt (Std.lt_of_lt_of_le h ofSlice_le), fun h' => ?_, fun h₁, h => ?_
· simp only [ Pos.slice_ofSlice (pos := p), slice_lt_slice_iff]
simpa
· by_cases h₀ : p₀ q
· simpa only [ Pos.ofSlice_slice (h₁ := h₀) (h₂ := h₁), ofSlice_lt_ofSlice_iff] using h h₀
· exact Std.lt_of_lt_of_le (Std.not_le.1 h₀) le_ofSlice
theorem Pos.ofSlice_le_iff {s : String} {p₀ p₁ : s.Pos} {h} {p : (s.slice p₀ p₁ h).Pos} {q : s.Pos} :
Pos.ofSlice p q h₁, h₀, p Pos.slice q p₀ p₁ h₀ h₁ := by
simp [ Std.not_lt, lt_ofSlice_iff]
theorem Slice.Pos.slice_le_iff {s : Slice} {p₀ p₁ : s.Pos} {h} {p : (s.slice p₀ p₁ h).Pos} {q : s.Pos} {h₀ h₁} :
Slice.Pos.slice q p₀ p₁ h₀ h₁ p q Pos.ofSlice p := by
simp [le_ofSlice_iff, h₀, h₁]
theorem Slice.Pos.lt_slice_iff {s : Slice} {p₀ p₁ : s.Pos} {h} {p : (s.slice p₀ p₁ h).Pos} {q : s.Pos} {h₀ h₁} :
p < Slice.Pos.slice q p₀ p₁ h₀ h₁ Pos.ofSlice p < q := by
simp [ofSlice_lt_iff, h₀, h₁]
theorem Slice.Pos.slice_lt_iff {s : Slice} {p₀ p₁ : s.Pos} {h} {p : (s.slice p₀ p₁ h).Pos} {q : s.Pos} {h₀ h₁} :
Slice.Pos.slice q p₀ p₁ h₀ h₁ < p q < Pos.ofSlice p := by
simp [lt_ofSlice_iff, h₀, h₁]
theorem Slice.Pos.le_slice_iff {s : Slice} {p₀ p₁ : s.Pos} {h} {p : (s.slice p₀ p₁ h).Pos} {q : s.Pos} {h₀ h₁} :
p Slice.Pos.slice q p₀ p₁ h₀ h₁ Pos.ofSlice p q := by
simp [ofSlice_le_iff, h₀, h₁]
theorem Pos.slice_le_iff {s : String} {p₀ p₁ : s.Pos} {h} {p : (s.slice p₀ p₁ h).Pos} {q : s.Pos} {h₀ h₁} :
Pos.slice q p₀ p₁ h₀ h₁ p q Pos.ofSlice p := by
simp [le_ofSlice_iff, h₀, h₁]
theorem Pos.lt_slice_iff {s : String} {p₀ p₁ : s.Pos} {h} {p : (s.slice p₀ p₁ h).Pos} {q : s.Pos} {h₀ h₁} :
p < Pos.slice q p₀ p₁ h₀ h₁ Pos.ofSlice p < q := by
simp [ofSlice_lt_iff, h₀, h₁]
theorem Pos.slice_lt_iff {s : String} {p₀ p₁ : s.Pos} {h} {p : (s.slice p₀ p₁ h).Pos} {q : s.Pos} {h₀ h₁} :
Pos.slice q p₀ p₁ h₀ h₁ < p q < Pos.ofSlice p := by
simp [lt_ofSlice_iff, h₀, h₁]
theorem Pos.le_slice_iff {s : String} {p₀ p₁ : s.Pos} {h} {p : (s.slice p₀ p₁ h).Pos} {q : s.Pos} {h₀ h₁} :
p Pos.slice q p₀ p₁ h₀ h₁ Pos.ofSlice p q := by
simp [ofSlice_le_iff, h₀, h₁]
theorem Slice.Pos.ofSlice_ne_endPos {s : Slice} {p₀ p₁ : s.Pos} {h} {p : (s.slice p₀ p₁ h).Pos}
(h : p (s.slice p₀ p₁ h).endPos) : Pos.ofSlice p s.endPos := by
refine (lt_endPos_iff _).1 (Std.lt_of_lt_of_le ?_ (le_endPos p₁))
simpa [ lt_endPos_iff, ofSlice_lt_ofSlice_iff] using h
theorem Slice.Pos.ne_endPos_of_slice_ne_endPos {s : Slice} {p p₀ p₁ : s.Pos} {h₁ h₂}
(h : Pos.slice p p₀ p₁ h₁ h₂ Slice.endPos _) : p s.endPos := by
rw [ Pos.ofSlice_slice (h₁ := h₁) (h₂ := h₂)]
apply Pos.ofSlice_ne_endPos h
theorem Slice.Pos.ofSlice_ne_startPos {s : Slice} {p₀ p₁ : s.Pos} {h} {p : (s.slice p₀ p₁ h).Pos}
(h : p (s.slice p₀ p₁ h).startPos) : Pos.ofSlice p s.startPos := by
refine (startPos_lt_iff _).1 (Std.lt_of_le_of_lt (startPos_le p₀) ?_)
simpa [ startPos_lt_iff, ofSlice_lt_ofSlice_iff] using h
theorem Slice.Pos.ne_startPos_of_slice_ne_startPos {s : Slice} {p p₀ p₁ : s.Pos} {h₁ h₂}
(h : Pos.slice p p₀ p₁ h₁ h₂ Slice.startPos _) : p s.startPos := by
rw [ Pos.ofSlice_slice (h₁ := h₁) (h₂ := h₂)]
apply Pos.ofSlice_ne_startPos h
theorem Pos.ofSlice_ne_endPos {s : String} {p₀ p₁ : s.Pos} {h} {p : (s.slice p₀ p₁ h).Pos}
(h : p (s.slice p₀ p₁ h).endPos) : Pos.ofSlice p s.endPos := by
refine (lt_endPos_iff _).1 (Std.lt_of_lt_of_le ?_ (le_endPos p₁))
simpa [ Slice.Pos.lt_endPos_iff, ofSlice_lt_ofSlice_iff] using h
theorem Pos.ne_endPos_of_slice_ne_endPos {s : String} {p p₀ p₁ : s.Pos} {h₁ h₂}
(h : Pos.slice p p₀ p₁ h₁ h₂ Slice.endPos _) : p s.endPos := by
rw [ Pos.ofSlice_slice (h₁ := h₁) (h₂ := h₂)]
apply Pos.ofSlice_ne_endPos h
theorem Pos.ofSlice_ne_startPos {s : String} {p₀ p₁ : s.Pos} {h} {p : (s.slice p₀ p₁ h).Pos}
(h : p (s.slice p₀ p₁ h).startPos) : Pos.ofSlice p s.startPos := by
refine (startPos_lt_iff _).1 (Std.lt_of_le_of_lt (startPos_le p₀) ?_)
simpa [ Slice.Pos.startPos_lt_iff, ofSlice_lt_ofSlice_iff] using h
theorem Pos.ne_startPos_of_slice_ne_startPos {s : String} {p p₀ p₁ : s.Pos} {h₁ h₂}
(h : Pos.slice p p₀ p₁ h₁ h₂ Slice.startPos _) : p s.startPos := by
rw [ Pos.ofSlice_slice (h₁ := h₁) (h₂ := h₂)]
apply Pos.ofSlice_ne_startPos h
@[simp]
theorem Slice.Pos.offset_le_rawEndPos {s : Slice} {p : s.Pos} :
p.offset s.rawEndPos :=
@@ -621,37 +468,21 @@ theorem Slice.Pos.get_eq_get_ofSliceTo {s : Slice} {p₀ : s.Pos} {pos : (s.slic
pos.get h = (ofSliceTo pos).get (ofSliceTo_ne_endPos h) := by
simp [Slice.Pos.get]
theorem Slice.Pos.get_sliceTo {s : Slice} {p₀ p : s.Pos} {h h'} :
(Pos.sliceTo p₀ p h).get h' = p.get (ne_endPos_of_sliceTo_ne_endPos h') := by
simp [get_eq_get_ofSliceTo]
theorem Pos.get_eq_get_ofSliceTo {s : String} {p₀ : s.Pos}
{pos : (s.sliceTo p₀).Pos} {h} :
pos.get h = (ofSliceTo pos).get (ofSliceTo_ne_endPos h) := by
simp [Pos.get, Slice.Pos.get]
theorem Pos.get_sliceTo {s : String} {p₀ p : s.Pos} {h h'} :
(Pos.sliceTo p₀ p h).get h' = p.get (ne_endPos_of_sliceTo_ne_endPos h') := by
simp [get_eq_get_ofSliceTo]
theorem Slice.Pos.get_eq_get_ofSlice {s : Slice} {p₀ p₁ : s.Pos} {h}
{pos : (s.slice p₀ p₁ h).Pos} {h'} :
pos.get h' = (ofSlice pos).get (ofSlice_ne_endPos h') := by
simp [Slice.Pos.get, Nat.add_assoc]
theorem Slice.Pos.get_slice {s : Slice} {p p₀ p₁ : s.Pos} {h₁ h₂ h} :
(Pos.slice p p₀ p₁ h₁ h₂).get h = p.get (ne_endPos_of_slice_ne_endPos h) := by
simp [get_eq_get_ofSlice]
theorem Pos.get_eq_get_ofSlice {s : String} {p₀ p₁ : s.Pos} {h}
{pos : (s.slice p₀ p₁ h).Pos} {h'} :
pos.get h' = (ofSlice pos).get (ofSlice_ne_endPos h') := by
simp [Pos.get, Slice.Pos.get]
theorem Pos.get_slice {s : String} {p p₀ p₁ : s.Pos} {h₁ h₂ h} :
(Pos.slice p p₀ p₁ h₁ h₂).get h = p.get (ne_endPos_of_slice_ne_endPos h) := by
simp [get_eq_get_ofSlice]
theorem Slice.Pos.ofSlice_next {s : Slice} {p₀ p₁ : s.Pos} {h}
{p : (s.slice p₀ p₁ h).Pos} {h'} :
Pos.ofSlice (p.next h') = (Pos.ofSlice p).next (ofSlice_ne_endPos h') := by

View File

@@ -13,4 +13,3 @@ public import Init.Data.String.Lemmas.Pattern.Char
public import Init.Data.String.Lemmas.Pattern.String
public import Init.Data.String.Lemmas.Pattern.Split
public import Init.Data.String.Lemmas.Pattern.Find
public import Init.Data.String.Lemmas.Pattern.TakeDrop

File diff suppressed because it is too large Load Diff

View File

@@ -20,44 +20,28 @@ import Init.Data.String.Lemmas.Order
import Init.Data.Order.Lemmas
import Init.Data.String.OrderInstances
import Init.Omega
import Init.Data.String.Lemmas.FindPos
public section
namespace String.Slice.Pattern.Model.Char
instance {c : Char} : PatternModel c where
instance {c : Char} : ForwardPatternModel c where
Matches s := s = String.singleton c
not_matches_empty := by simp
instance {c : Char} : StrictPatternModel c where
not_matches_empty := by simp [PatternModel.Matches]
instance {c : Char} : NoPrefixPatternModel c :=
.of_length_eq (by simp +contextual [PatternModel.Matches])
instance {c : Char} : NoSuffixPatternModel c :=
.of_length_eq (by simp +contextual [PatternModel.Matches])
instance {c : Char} : NoPrefixForwardPatternModel c :=
.of_length_eq (by simp +contextual [ForwardPatternModel.Matches])
theorem isMatch_iff {c : Char} {s : Slice} {pos : s.Pos} :
IsMatch c pos
(h : s.startPos s.endPos), pos = s.startPos.next h s.startPos.get h = c := by
simp only [Model.isMatch_iff, PatternModel.Matches, copy_sliceTo_eq_iff_exists_splits]
simp only [Model.isMatch_iff, ForwardPatternModel.Matches, sliceTo_copy_eq_iff_exists_splits]
refine ?_, ?_
· simp only [splits_singleton_iff]
exact fun t₂, h, h₁, h₂, h₃ => h, h₁, h₂
· rintro h, rfl, rfl
exact _, Slice.splits_next_startPos
theorem isRevMatch_iff {c : Char} {s : Slice} {pos : s.Pos} :
IsRevMatch c pos
(h : s.endPos s.startPos), pos = s.endPos.prev h (s.endPos.prev h).get (by simp) = c := by
simp only [Model.isRevMatch_iff, PatternModel.Matches, copy_sliceFrom_eq_iff_exists_splits]
refine ?_, ?_
· simp only [splits_singleton_right_iff]
exact fun t₂, h, h₁, h₂, h₃ => h, h₁, h₂
· rintro h, rfl, rfl
exact _, Slice.splits_prev_endPos
theorem isLongestMatch_iff {c : Char} {s : Slice} {pos : s.Pos} :
IsLongestMatch c pos
(h : s.startPos s.endPos), pos = s.startPos.next h s.startPos.get h = c := by
@@ -68,46 +52,21 @@ theorem isLongestMatchAt_iff {c : Char} {s : Slice} {pos pos' : s.Pos} :
simp +contextual [Model.isLongestMatchAt_iff, isLongestMatch_iff, Pos.ofSliceFrom_inj,
Pos.get_eq_get_ofSliceFrom, Pos.ofSliceFrom_next]
theorem isLongestRevMatch_iff {c : Char} {s : Slice} {pos : s.Pos} :
IsLongestRevMatch c pos
(h : s.endPos s.startPos), pos = s.endPos.prev h (s.endPos.prev h).get (by simp) = c := by
rw [isLongestRevMatch_iff_isRevMatch, isRevMatch_iff]
theorem isLongestRevMatchAt_iff {c : Char} {s : Slice} {pos pos' : s.Pos} :
IsLongestRevMatchAt c pos pos' h, pos = pos'.prev h (pos'.prev h).get (by simp) = c := by
simp +contextual [Model.isLongestRevMatchAt_iff, isLongestRevMatch_iff, Pos.ofSliceTo_inj,
Pos.get_eq_get_ofSliceTo, Pos.ofSliceTo_prev]
theorem isLongestMatchAt_of_get_eq {c : Char} {s : Slice} {pos : s.Pos} {h : pos s.endPos}
(hc : pos.get h = c) : IsLongestMatchAt c pos (pos.next h) :=
isLongestMatchAt_iff.2 h, by simp [hc]
theorem isLongestRevMatchAt_of_get_eq {c : Char} {s : Slice} {pos : s.Pos} {h : pos s.startPos}
(hc : (pos.prev h).get (by simp) = c) : IsLongestRevMatchAt c (pos.prev h) pos :=
isLongestRevMatchAt_iff.2 h, by simp [hc]
instance {c : Char} : LawfulForwardPatternModel c where
skipPrefix?_eq_some_iff {s} pos := by
simp [isLongestMatch_iff, ForwardPattern.skipPrefix?, and_comm, eq_comm (b := pos)]
instance {c : Char} : LawfulBackwardPatternModel c where
skipSuffix?_eq_some_iff {s} pos := by
simp [isLongestRevMatch_iff, BackwardPattern.skipSuffix?, and_comm, eq_comm (b := pos)]
dropPrefix?_eq_some_iff {s} pos := by
simp [isLongestMatch_iff, ForwardPattern.dropPrefix?, and_comm, eq_comm (b := pos)]
theorem toSearcher_eq {c : Char} {s : Slice} :
ToForwardSearcher.toSearcher c s = ToForwardSearcher.toSearcher (· == c) s := (rfl)
theorem toBackwardSearcher_eq {c : Char} {s : Slice} :
ToBackwardSearcher.toSearcher c s = ToBackwardSearcher.toSearcher (· == c) s := (rfl)
theorem matchesAt_iff {c : Char} {s : Slice} {pos : s.Pos} :
MatchesAt c pos (h : pos s.endPos), pos.get h = c := by
simp [matchesAt_iff_exists_isLongestMatchAt, isLongestMatchAt_iff, exists_comm]
theorem revMatchesAt_iff {c : Char} {s : Slice} {pos : s.Pos} :
RevMatchesAt c pos (h : pos s.startPos), (pos.prev h).get (by simp) = c := by
simp [revMatchesAt_iff_exists_isLongestRevMatchAt, isLongestRevMatchAt_iff, exists_comm]
theorem matchesAt_iff_splits {c : Char} {s : Slice} {pos : s.Pos} :
MatchesAt c pos t₁ t₂, pos.Splits t₁ (singleton c ++ t₂) := by
rw [matchesAt_iff]
@@ -118,131 +77,37 @@ theorem matchesAt_iff_splits {c : Char} {s : Slice} {pos : s.Pos} :
have hne := hs.ne_endPos_of_singleton
exact hne, (singleton_append_inj.mp (hs.eq_right (pos.splits_next_right hne))).1.symm
theorem revMatchesAt_iff_splits {c : Char} {s : Slice} {pos : s.Pos} :
RevMatchesAt c pos t₁ t₂, pos.Splits (t₁ ++ singleton c) t₂ := by
rw [revMatchesAt_iff]
refine ?_, ?_
· rintro h, rfl
exact _, _, pos.splits_prev_right h
· rintro t₁, t₂, hs
have hne := hs.ne_startPos_of_singleton
refine hne, ?_
have := hs.eq_left (pos.splits_prev_right hne)
simp only [append_singleton, push_inj] at this
exact this.2.symm
theorem not_matchesAt_of_get_ne {c : Char} {s : Slice} {pos : s.Pos} {h : pos s.endPos}
(hc : pos.get h c) : ¬ MatchesAt c pos := by
simp [matchesAt_iff, hc]
theorem not_revMatchesAt_of_get_ne {c : Char} {s : Slice} {pos : s.Pos} {h : pos s.startPos}
(hc : (pos.prev h).get (by simp) c) : ¬ RevMatchesAt c pos := by
simp [revMatchesAt_iff, hc]
theorem matchAt?_eq {s : Slice} {pos : s.Pos} {c : Char} :
matchAt? c pos =
if h₀ : (h : pos s.endPos), pos.get h = c then some (pos.next h₀.1) else none := by
split <;> simp_all [isLongestMatchAt_iff, matchesAt_iff]
theorem revMatchAt?_eq {s : Slice} {pos : s.Pos} {c : Char} :
revMatchAt? c pos =
if h₀ : (h : pos s.startPos), (pos.prev h).get (by simp) = c then some (pos.prev h₀.1) else none := by
split <;> simp_all [isLongestRevMatchAt_iff, revMatchesAt_iff]
theorem isMatch_iff_isMatch_beq {c : Char} {s : Slice} {pos : s.Pos} :
IsMatch c pos IsMatch (· == c) pos := by
simp [isMatch_iff, CharPred.isMatch_iff, beq_iff_eq]
theorem isRevMatch_iff_isRevMatch_beq {c : Char} {s : Slice} {pos : s.Pos} :
IsRevMatch c pos IsRevMatch (· == c) pos := by
simp [isRevMatch_iff, CharPred.isRevMatch_iff, beq_iff_eq]
theorem isLongestMatch_iff_isLongestMatch_beq {c : Char} {s : Slice} {pos : s.Pos} :
IsLongestMatch c pos IsLongestMatch (· == c) pos := by
simp [isLongestMatch_iff_isMatch, isMatch_iff_isMatch_beq]
theorem isLongestRevMatch_iff_isLongestRevMatch_beq {c : Char} {s : Slice} {pos : s.Pos} :
IsLongestRevMatch c pos IsLongestRevMatch (· == c) pos := by
simp [isLongestRevMatch_iff_isRevMatch, isRevMatch_iff_isRevMatch_beq]
theorem isLongestMatchAt_iff_isLongestMatchAt_beq {c : Char} {s : Slice}
{pos pos' : s.Pos} :
IsLongestMatchAt c pos pos' IsLongestMatchAt (· == c) pos pos' := by
simp [Model.isLongestMatchAt_iff, isLongestMatch_iff_isLongestMatch_beq]
theorem isLongestMatchAtChain_iff_isLongestMatchAtChain_beq {c : Char} {s : Slice} {pos pos' : s.Pos} :
IsLongestMatchAtChain c pos pos' IsLongestMatchAtChain (· == c) pos pos' := by
refine fun h => ?_, fun h => ?_
· induction h with
| nil => simp
| cons p₁ p₂ p₃ h₁ h₂ ih => exact .cons _ _ _ (isLongestMatchAt_iff_isLongestMatchAt_beq.1 h₁) ih
· induction h with
| nil => simp
| cons p₁ p₂ p₃ h₁ h₂ ih => exact .cons _ _ _ (isLongestMatchAt_iff_isLongestMatchAt_beq.2 h₁) ih
theorem isLongestMatchAtChain_iff {c : Char} {s : Slice} {pos pos' : s.Pos} :
IsLongestMatchAtChain c pos pos' pos pos' pos'', pos pos'' (h : pos'' < pos') pos''.get (Pos.ne_endPos_of_lt h) = c := by
simp [isLongestMatchAtChain_iff_isLongestMatchAtChain_beq, CharPred.isLongestMatchAtChain_iff]
theorem isLongestMatchAtChain_iff_toList {c : Char} {s : Slice} {pos pos' : s.Pos} :
IsLongestMatchAtChain c pos pos'
(h : pos pos'), (s.slice pos pos' h).copy.toList = List.replicate (s.slice pos pos' h).copy.length c := by
simp [isLongestMatchAtChain_iff_isLongestMatchAtChain_beq, CharPred.isLongestMatchAtChain_iff_toList,
List.eq_replicate_iff]
theorem isLongestMatchAtChain_startPos_endPos_iff_toList {c : Char} {s : Slice} :
IsLongestMatchAtChain c s.startPos s.endPos s.copy.toList = List.replicate s.copy.length c := by
simp [isLongestMatchAtChain_iff_isLongestMatchAtChain_beq,
CharPred.isLongestMatchAtChain_startPos_endPos_iff_toList, List.eq_replicate_iff]
theorem isLongestRevMatchAt_iff_isLongestRevMatchAt_beq {c : Char} {s : Slice}
{pos pos' : s.Pos} :
IsLongestRevMatchAt c pos pos' IsLongestRevMatchAt (· == c) pos pos' := by
simp [Model.isLongestRevMatchAt_iff, isLongestRevMatch_iff_isLongestRevMatch_beq]
theorem isLongestRevMatchAtChain_iff_isLongestRevMatchAtChain_beq {c : Char} {s : Slice} {pos pos' : s.Pos} :
IsLongestRevMatchAtChain c pos pos' IsLongestRevMatchAtChain (· == c) pos pos' := by
refine fun h => ?_, fun h => ?_
· induction h with
| nil => simp
| cons p₂ p₃ _ hmatch ih => exact .cons _ _ _ ih (isLongestRevMatchAt_iff_isLongestRevMatchAt_beq.1 hmatch)
· induction h with
| nil => simp
| cons p₂ p₃ _ hmatch ih => exact .cons _ _ _ ih (isLongestRevMatchAt_iff_isLongestRevMatchAt_beq.2 hmatch)
theorem isLongestRevMatchAtChain_iff {c : Char} {s : Slice} {pos pos' : s.Pos} :
IsLongestRevMatchAtChain c pos pos' pos pos' pos'', pos pos'' (h : pos'' < pos') pos''.get (Pos.ne_endPos_of_lt h) = c := by
simp [isLongestRevMatchAtChain_iff_isLongestRevMatchAtChain_beq, CharPred.isLongestRevMatchAtChain_iff]
theorem isLongestRevMatchAtChain_iff_toList {c : Char} {s : Slice} {pos pos' : s.Pos} :
IsLongestRevMatchAtChain c pos pos'
(h : pos pos'), (s.slice pos pos' h).copy.toList = List.replicate (s.slice pos pos' h).copy.length c := by
simp [isLongestRevMatchAtChain_iff_isLongestRevMatchAtChain_beq, CharPred.isLongestRevMatchAtChain_iff_toList,
List.eq_replicate_iff]
theorem isLongestRevMatchAtChain_startPos_endPos_iff_toList {c : Char} {s : Slice} :
IsLongestRevMatchAtChain c s.startPos s.endPos s.copy.toList = List.replicate s.copy.length c := by
simp [isLongestRevMatchAtChain_iff_isLongestRevMatchAtChain_beq,
CharPred.isLongestRevMatchAtChain_startPos_endPos_iff_toList, List.eq_replicate_iff]
theorem matchesAt_iff_matchesAt_beq {c : Char} {s : Slice} {pos : s.Pos} :
MatchesAt c pos MatchesAt (· == c) pos := by
simp [matchesAt_iff_exists_isLongestMatchAt, isLongestMatchAt_iff_isLongestMatchAt_beq]
theorem revMatchesAt_iff_revMatchesAt_beq {c : Char} {s : Slice} {pos : s.Pos} :
RevMatchesAt c pos RevMatchesAt (· == c) pos := by
simp [revMatchesAt_iff_exists_isLongestRevMatchAt, isLongestRevMatchAt_iff_isLongestRevMatchAt_beq]
theorem matchAt?_eq_matchAt?_beq {c : Char} {s : Slice} {pos : s.Pos} :
matchAt? c pos = matchAt? (· == c) pos := by
refine Option.ext (fun pos' => ?_)
simp [matchAt?_eq_some_iff, isLongestMatchAt_iff_isLongestMatchAt_beq]
theorem revMatchAt?_eq_revMatchAt?_beq {c : Char} {s : Slice} {pos : s.Pos} :
revMatchAt? c pos = revMatchAt? (· == c) pos := by
refine Option.ext (fun pos' => ?_)
simp [revMatchAt?_eq_some_iff, isLongestRevMatchAt_iff_isLongestRevMatchAt_beq]
theorem isValidSearchFrom_iff_isValidSearchFrom_beq {c : Char} {s : Slice} {p : s.Pos}
{l : List (SearchStep s)} : IsValidSearchFrom c p l IsValidSearchFrom (· == c) p l := by
refine fun h => ?_, fun h => ?_
@@ -255,28 +120,11 @@ theorem isValidSearchFrom_iff_isValidSearchFrom_beq {c : Char} {s : Slice} {p :
| matched => simp_all [IsValidSearchFrom.matched, isLongestMatchAt_iff_isLongestMatchAt_beq]
| mismatched => simp_all [IsValidSearchFrom.mismatched, matchesAt_iff_matchesAt_beq]
theorem isValidRevSearchFrom_iff_isValidRevSearchFrom_beq {c : Char} {s : Slice} {p : s.Pos}
{l : List (SearchStep s)} : IsValidRevSearchFrom c p l IsValidRevSearchFrom (· == c) p l := by
refine fun h => ?_, fun h => ?_
· induction h with
| startPos => simpa using IsValidRevSearchFrom.startPos
| matched => simp_all [IsValidRevSearchFrom.matched, isLongestRevMatchAt_iff_isLongestRevMatchAt_beq]
| mismatched => simp_all [IsValidRevSearchFrom.mismatched, revMatchesAt_iff_revMatchesAt_beq]
· induction h with
| startPos => simpa using IsValidRevSearchFrom.startPos
| matched => simp_all [IsValidRevSearchFrom.matched, isLongestRevMatchAt_iff_isLongestRevMatchAt_beq]
| mismatched => simp_all [IsValidRevSearchFrom.mismatched, revMatchesAt_iff_revMatchesAt_beq]
instance {c : Char} : LawfulToForwardSearcherModel c where
isValidSearchFrom_toList s := by
simpa [toSearcher_eq, isValidSearchFrom_iff_isValidSearchFrom_beq] using
LawfulToForwardSearcherModel.isValidSearchFrom_toList (pat := (· == c)) (s := s)
instance {c : Char} : LawfulToBackwardSearcherModel c where
isValidRevSearchFrom_toList s := by
simpa [toBackwardSearcher_eq, isValidRevSearchFrom_iff_isValidRevSearchFrom_beq] using
LawfulToBackwardSearcherModel.isValidRevSearchFrom_toList (pat := (· == c)) (s := s)
end Pattern.Model.Char
theorem startsWith_char_eq_startsWith_beq {c : Char} {s : Slice} :
@@ -288,43 +136,46 @@ theorem dropPrefix?_char_eq_dropPrefix?_beq {c : Char} {s : Slice} :
theorem dropPrefix_char_eq_dropPrefix_beq {c : Char} {s : Slice} :
s.dropPrefix c = s.dropPrefix (· == c) := (rfl)
theorem skipPrefix?_char_eq_skipPrefix?_beq {c : Char} {s : Slice} :
s.skipPrefix? c = s.skipPrefix? (· == c) := (rfl)
theorem Pattern.ForwardPattern.dropPrefix?_char_eq_dropPrefix?_beq {c : Char} {s : Slice} :
dropPrefix? c s = dropPrefix? (· == c) s := (rfl)
theorem Pattern.ForwardPattern.skipPrefix?_char_eq_skipPrefix?_beq {c : Char} {s : Slice} :
skipPrefix? c s = skipPrefix? (· == c) s := (rfl)
theorem Pos.skip?_char_eq_skip?_beq {c : Char} {s : Slice} {pos : s.Pos} :
pos.skip? c = pos.skip? (· == c) := (rfl)
theorem Pos.skipWhile_char_eq_skipWhile_beq {c : Char} {s : Slice} (curr : s.Pos) :
Pos.skipWhile curr c = Pos.skipWhile curr (· == c) := by
fun_induction Pos.skipWhile curr c with
private theorem dropWhileGo_eq {c : Char} {s : Slice} (curr : s.Pos) :
dropWhile.go s c curr = dropWhile.go s (· == c) curr := by
fun_induction dropWhile.go s c curr with
| case1 pos nextCurr h₁ h₂ ih =>
conv => rhs; rw [Pos.skipWhile]
simp [ Pos.skip?_char_eq_skip?_beq, h₁, h₂, ih]
conv => rhs; rw [dropWhile.go]
simp [ Pattern.ForwardPattern.dropPrefix?_char_eq_dropPrefix?_beq, h₁, h₂, ih]
| case2 pos nextCurr h ih =>
conv => rhs; rw [Pos.skipWhile]
simp [ Pos.skip?_char_eq_skip?_beq, h, ih]
conv => rhs; rw [dropWhile.go]
simp [ Pattern.ForwardPattern.dropPrefix?_char_eq_dropPrefix?_beq, h, ih]
| case3 pos h =>
conv => rhs; rw [Pos.skipWhile]
simp [ Pos.skip?_char_eq_skip?_beq, h]
theorem skipPrefixWhile_char_eq_skipPrefixWhile_beq {c : Char} {s : Slice} :
s.skipPrefixWhile c = s.skipPrefixWhile (· == c) :=
Pos.skipWhile_char_eq_skipWhile_beq s.startPos
conv => rhs; rw [dropWhile.go]
simp [ Pattern.ForwardPattern.dropPrefix?_char_eq_dropPrefix?_beq]
theorem dropWhile_char_eq_dropWhile_beq {c : Char} {s : Slice} :
s.dropWhile c = s.dropWhile (· == c) := by
simp only [dropWhile]; exact congrArg _ skipPrefixWhile_char_eq_skipPrefixWhile_beq
simpa only [dropWhile] using dropWhileGo_eq s.startPos
private theorem takeWhileGo_eq {c : Char} {s : Slice} (curr : s.Pos) :
takeWhile.go s c curr = takeWhile.go s (· == c) curr := by
fun_induction takeWhile.go s c curr with
| case1 pos nextCurr h₁ h₂ ih =>
conv => rhs; rw [takeWhile.go]
simp [ Pattern.ForwardPattern.dropPrefix?_char_eq_dropPrefix?_beq, h₁, h₂, ih]
| case2 pos nextCurr h ih =>
conv => rhs; rw [takeWhile.go]
simp [ Pattern.ForwardPattern.dropPrefix?_char_eq_dropPrefix?_beq, h, ih]
| case3 pos h =>
conv => rhs; rw [takeWhile.go]
simp [ Pattern.ForwardPattern.dropPrefix?_char_eq_dropPrefix?_beq]
theorem takeWhile_char_eq_takeWhile_beq {c : Char} {s : Slice} :
s.takeWhile c = s.takeWhile (· == c) := by
simp only [takeWhile]; exact congrArg _ skipPrefixWhile_char_eq_skipPrefixWhile_beq
simp only [takeWhile]; exact takeWhileGo_eq s.startPos
theorem all_char_eq_all_beq {c : Char} {s : Slice} :
s.all c = s.all (· == c) := by
simp only [all, skipPrefixWhile_char_eq_skipPrefixWhile_beq]
simp only [all, dropWhile_char_eq_dropWhile_beq]
theorem find?_char_eq_find?_beq {c : Char} {s : Slice} :
s.find? c = s.find? (· == c) :=
@@ -341,56 +192,47 @@ theorem contains_char_eq_contains_beq {c : Char} {s : Slice} :
theorem endsWith_char_eq_endsWith_beq {c : Char} {s : Slice} :
s.endsWith c = s.endsWith (· == c) := (rfl)
theorem skipSuffix?_char_eq_skipSuffix?_beq {c : Char} {s : Slice} :
s.skipSuffix? c = s.skipSuffix? (· == c) := (rfl)
theorem dropSuffix?_char_eq_dropSuffix?_beq {c : Char} {s : Slice} :
s.dropSuffix? c = s.dropSuffix? (· == c) := (rfl)
theorem dropSuffix_char_eq_dropSuffix_beq {c : Char} {s : Slice} :
s.dropSuffix c = s.dropSuffix (· == c) := (rfl)
theorem Pattern.BackwardPattern.skipSuffix?_char_eq_skipSuffix?_beq {c : Char} {s : Slice} :
skipSuffix? c s = skipSuffix? (· == c) s := (rfl)
theorem Pattern.BackwardPattern.dropSuffix?_char_eq_dropSuffix?_beq {c : Char} {s : Slice} :
dropSuffix? c s = dropSuffix? (· == c) s := (rfl)
theorem Pos.revSkip?_char_eq_revSkip?_beq {c : Char} {s : Slice} {pos : s.Pos} :
pos.revSkip? c = pos.revSkip? (· == c) := (rfl)
theorem Pos.revSkipWhile_char_eq_revSkipWhile_beq {c : Char} {s : Slice} (curr : s.Pos) :
Pos.revSkipWhile curr c = Pos.revSkipWhile curr (· == c) := by
fun_induction Pos.revSkipWhile curr c with
private theorem dropEndWhileGo_eq {c : Char} {s : Slice} (curr : s.Pos) :
dropEndWhile.go s c curr = dropEndWhile.go s (· == c) curr := by
fun_induction dropEndWhile.go s c curr with
| case1 pos nextCurr h₁ h₂ ih =>
conv => rhs; rw [Pos.revSkipWhile]
simp [ Pos.revSkip?_char_eq_revSkip?_beq, h₁, h₂, ih]
conv => rhs; rw [dropEndWhile.go]
simp [ Pattern.BackwardPattern.dropSuffix?_char_eq_dropSuffix?_beq, h₁, h₂, ih]
| case2 pos nextCurr h ih =>
conv => rhs; rw [Pos.revSkipWhile]
simp [ Pos.revSkip?_char_eq_revSkip?_beq, h, ih]
conv => rhs; rw [dropEndWhile.go]
simp [ Pattern.BackwardPattern.dropSuffix?_char_eq_dropSuffix?_beq, h, ih]
| case3 pos h =>
conv => rhs; rw [Pos.revSkipWhile]
simp [ Pos.revSkip?_char_eq_revSkip?_beq, h]
theorem skipSuffixWhile_char_eq_skipSuffixWhile_beq {c : Char} {s : Slice} :
s.skipSuffixWhile c = s.skipSuffixWhile (· == c) :=
Pos.revSkipWhile_char_eq_revSkipWhile_beq s.endPos
conv => rhs; rw [dropEndWhile.go]
simp [ Pattern.BackwardPattern.dropSuffix?_char_eq_dropSuffix?_beq]
theorem dropEndWhile_char_eq_dropEndWhile_beq {c : Char} {s : Slice} :
s.dropEndWhile c = s.dropEndWhile (· == c) := by
simp only [dropEndWhile]; exact congrArg _ skipSuffixWhile_char_eq_skipSuffixWhile_beq
simpa only [dropEndWhile] using dropEndWhileGo_eq s.endPos
private theorem takeEndWhileGo_eq {c : Char} {s : Slice} (curr : s.Pos) :
takeEndWhile.go s c curr = takeEndWhile.go s (· == c) curr := by
fun_induction takeEndWhile.go s c curr with
| case1 pos nextCurr h₁ h₂ ih =>
conv => rhs; rw [takeEndWhile.go]
simp [ Pattern.BackwardPattern.dropSuffix?_char_eq_dropSuffix?_beq, h₁, h₂, ih]
| case2 pos nextCurr h ih =>
conv => rhs; rw [takeEndWhile.go]
simp [ Pattern.BackwardPattern.dropSuffix?_char_eq_dropSuffix?_beq, h, ih]
| case3 pos h =>
conv => rhs; rw [takeEndWhile.go]
simp [ Pattern.BackwardPattern.dropSuffix?_char_eq_dropSuffix?_beq]
theorem takeEndWhile_char_eq_takeEndWhile_beq {c : Char} {s : Slice} :
s.takeEndWhile c = s.takeEndWhile (· == c) := by
simp only [takeEndWhile]; exact congrArg _ skipSuffixWhile_char_eq_skipSuffixWhile_beq
theorem revFind?_char_eq_revFind?_beq {c : Char} {s : Slice} :
s.revFind? c = s.revFind? (· == c) :=
(rfl)
theorem Pos.revFind?_char_eq_revFind?_beq {c : Char} {s : Slice} {p : s.Pos} :
p.revFind? c = p.revFind? (· == c) :=
(rfl)
theorem revAll_char_eq_revAll_beq {c : Char} {s : Slice} :
s.revAll c = s.revAll (· == c) := by
simp [revAll, skipSuffixWhile_char_eq_skipSuffixWhile_beq]
simpa only [takeEndWhile] using takeEndWhileGo_eq s.endPos
end String.Slice

View File

@@ -23,8 +23,8 @@ open Std String.Slice Pattern Pattern.Model
namespace String.Slice
theorem Pattern.Model.find?_eq_some_iff {ρ : Type} (pat : ρ) [PatternModel pat] [StrictPatternModel pat]
{σ : Slice Type} [ s, Iterator (σ s) Id (SearchStep s)] [ s, Iterators.Finite (σ s) Id]
theorem Pattern.Model.find?_eq_some_iff {ρ : Type} (pat : ρ) [ForwardPatternModel pat] {σ : Slice Type}
[ s, Iterator (σ s) Id (SearchStep s)] [ s, Iterators.Finite (σ s) Id]
[ s, IteratorLoop (σ s) Id Id] [ s, LawfulIteratorLoop (σ s) Id Id]
[ToForwardSearcher pat σ] [LawfulToForwardSearcherModel pat] {s : Slice} {pos : s.Pos} :
s.find? pat = some pos MatchesAt pat pos ( pos', pos' < pos ¬ MatchesAt pat pos') := by
@@ -40,8 +40,8 @@ theorem Pattern.Model.find?_eq_some_iff {ρ : Type} (pat : ρ) [PatternModel pat
| matched h₁ _ _ => have := h₁.matchesAt; grind
| mismatched => grind
theorem Pattern.Model.find?_eq_none_iff {ρ : Type} (pat : ρ) [PatternModel pat] [StrictPatternModel pat]
{σ : Slice Type} [ s, Iterator (σ s) Id (SearchStep s)] [ s, Iterators.Finite (σ s) Id]
theorem Pattern.Model.find?_eq_none_iff {ρ : Type} (pat : ρ) [ForwardPatternModel pat] {σ : Slice Type}
[ s, Iterator (σ s) Id (SearchStep s)] [ s, Iterators.Finite (σ s) Id]
[ s, IteratorLoop (σ s) Id Id] [ s, LawfulIteratorLoop (σ s) Id Id]
[ToForwardSearcher pat σ] [LawfulToForwardSearcherModel pat] {s : Slice} :
s.find? pat = none (pos : s.Pos), ¬ MatchesAt pat pos := by
@@ -65,15 +65,15 @@ theorem find?_eq_none_iff {ρ : Type} (pat : ρ) {σ : Slice → Type}
[ToForwardSearcher pat σ] {s : Slice} : s.find? pat = none s.contains pat = false := by
rw [ Option.isNone_iff_eq_none, Option.isSome_eq_false_iff, isSome_find?]
theorem Pattern.Model.contains_eq_false_iff {ρ : Type} (pat : ρ) [PatternModel pat] [StrictPatternModel pat]
{σ : Slice Type} [ s, Iterator (σ s) Id (SearchStep s)] [ s, Iterators.Finite (σ s) Id]
theorem Pattern.Model.contains_eq_false_iff {ρ : Type} (pat : ρ) [ForwardPatternModel pat] {σ : Slice Type}
[ s, Iterator (σ s) Id (SearchStep s)] [ s, Iterators.Finite (σ s) Id]
[ s, IteratorLoop (σ s) Id Id] [ s, LawfulIteratorLoop (σ s) Id Id]
[ToForwardSearcher pat σ] [LawfulToForwardSearcherModel pat] {s : Slice} :
s.contains pat = false (pos : s.Pos), ¬ MatchesAt pat pos := by
rw [ find?_eq_none_iff, Slice.find?_eq_none_iff]
theorem Pattern.Model.contains_eq_true_iff {ρ : Type} (pat : ρ) [PatternModel pat] [StrictPatternModel pat]
{σ : Slice Type} [ s, Iterator (σ s) Id (SearchStep s)] [ s, Iterators.Finite (σ s) Id]
theorem Pattern.Model.contains_eq_true_iff {ρ : Type} (pat : ρ) [ForwardPatternModel pat] {σ : Slice Type}
[ s, Iterator (σ s) Id (SearchStep s)] [ s, Iterators.Finite (σ s) Id]
[ s, IteratorLoop (σ s) Id Id] [ s, LawfulIteratorLoop (σ s) Id Id]
[ToForwardSearcher pat σ] [LawfulToForwardSearcherModel pat] {s : Slice} :
s.contains pat (pos : s.Pos), MatchesAt pat pos := by
@@ -85,7 +85,7 @@ theorem Pos.find?_eq_find?_sliceFrom {ρ : Type} {pat : ρ} {σ : Slice → Type
p.find? pat = ((s.sliceFrom p).find? pat).map Pos.ofSliceFrom :=
(rfl)
theorem Pattern.Model.posFind?_eq_some_iff {ρ : Type} {pat : ρ} [PatternModel pat] [StrictPatternModel pat] {σ : Slice Type}
theorem Pattern.Model.posFind?_eq_some_iff {ρ : Type} {pat : ρ} [ForwardPatternModel pat] {σ : Slice Type}
[ s, Iterator (σ s) Id (SearchStep s)] [ s, Iterators.Finite (σ s) Id]
[ s, IteratorLoop (σ s) Id Id] [ s, LawfulIteratorLoop (σ s) Id Id]
[ToForwardSearcher pat σ] [LawfulToForwardSearcherModel pat] {s : Slice} {pos pos' : s.Pos} :
@@ -100,8 +100,8 @@ theorem Pattern.Model.posFind?_eq_some_iff {ρ : Type} {pat : ρ} [PatternModel
refine Pos.sliceFrom _ _ h₁, by simpa using h₂, fun p hp₁ hp₂ => ?_, by simp
exact h₃ (Pos.ofSliceFrom p) Slice.Pos.le_ofSliceFrom (Pos.lt_sliceFrom_iff.1 hp₁) hp₂
theorem Pattern.Model.posFind?_eq_none_iff {ρ : Type} {pat : ρ} [PatternModel pat] [StrictPatternModel pat]
{σ : Slice Type} [ s, Iterator (σ s) Id (SearchStep s)] [ s, Iterators.Finite (σ s) Id]
theorem Pattern.Model.posFind?_eq_none_iff {ρ : Type} {pat : ρ} [ForwardPatternModel pat] {σ : Slice Type}
[ s, Iterator (σ s) Id (SearchStep s)] [ s, Iterators.Finite (σ s) Id]
[ s, IteratorLoop (σ s) Id Id] [ s, LawfulIteratorLoop (σ s) Id Id]
[ToForwardSearcher pat σ] [LawfulToForwardSearcherModel pat] {s : Slice} {pos : s.Pos} :
pos.find? pat = none pos', pos pos' ¬ MatchesAt pat pos' := by

View File

@@ -183,7 +183,7 @@ theorem find?_char_eq_some_iff_splits {c : Char} {s : String} {pos : s.Pos} :
· rintro t, u, hsplit, hnotin
exact pos.toSlice, t, u, Pos.splits_toSlice_iff.mpr hsplit, hnotin, by simp
@[cbv_eval, simp]
@[simp]
theorem contains_char_eq {c : Char} {s : String} : s.contains c = decide (c s.toList) := by
simp [contains_eq_contains_toSlice, Slice.contains_char_eq, copy_toSlice]

View File

@@ -58,7 +58,7 @@ theorem find?_prop_eq_some_iff_splits {p : Char → Prop} [DecidablePred p] {s :
simp only [find?_prop_eq_find?_decide, find?_bool_eq_some_iff_splits, decide_eq_true_eq,
decide_eq_false_iff_not]
@[cbv_eval, simp]
@[simp]
theorem contains_bool_eq {p : Char Bool} {s : Slice} : s.contains p = s.copy.toList.any p := by
rw [Bool.eq_iff_iff, Pattern.Model.contains_eq_true_iff]
simp only [Pattern.Model.CharPred.matchesAt_iff, ne_eq, List.any_eq_true,

View File

@@ -49,10 +49,9 @@ theorem contains_slice_iff {t s : Slice} :
by_cases ht : t.isEmpty
· simp [contains_eq_true_of_isEmpty ht s, copy_eq_empty_iff.mpr ht, String.toList_empty]
· simp only [Bool.not_eq_true] at ht
have := Pattern.Model.ForwardSliceSearcher.strictPatternModel ht
have := Pattern.Model.ForwardSliceSearcher.lawfulToForwardSearcherModel ht
simp only [Pattern.Model.contains_eq_true_iff,
Pattern.Model.ForwardSliceSearcher.exists_matchesAt_iff_eq_append, isInfix_toList_iff]
Pattern.Model.ForwardSliceSearcher.exists_matchesAt_iff_eq_append ht, isInfix_toList_iff]
@[simp]
theorem contains_string_iff {t : String} {s : Slice} :
@@ -91,12 +90,4 @@ theorem contains_string_eq_false_iff {t s : String} :
s.contains t = false ¬(t.toList <:+: s.toList) :=
Bool.eq_false_iff.trans (not_congr contains_string_iff)
/-
Used internally by the `cbv` tactic.
-/
@[cbv_eval]
theorem contains_string_eq_internal {t s : String} :
s.contains t = t.toList.isInfixOf_internal s.toList := by
rw [Bool.eq_iff_iff, contains_string_iff, List.isInfixOf_internal_iff_isInfix]
end String

View File

@@ -18,321 +18,125 @@ import Init.Data.String.Lemmas.Basic
import Init.Data.String.Lemmas.Order
import Init.Data.Order.Lemmas
import Init.Data.String.OrderInstances
import Init.Data.String.Lemmas.Iterate
import Init.Omega
import Init.Data.String.Lemmas.FindPos
public section
namespace String.Slice.Pattern.Model.CharPred
instance {p : Char Bool} : PatternModel p where
instance {p : Char Bool} : ForwardPatternModel p where
Matches s := c, s = singleton c p c
not_matches_empty := by
simp
instance {p : Char Bool} : StrictPatternModel p where
not_matches_empty := by simp [PatternModel.Matches]
instance {p : Char Bool} : NoPrefixPatternModel p :=
.of_length_eq (by simp +contextual [PatternModel.Matches])
instance {p : Char Bool} : NoSuffixPatternModel p :=
.of_length_eq (by simp +contextual [PatternModel.Matches])
instance {p : Char Bool} : NoPrefixForwardPatternModel p :=
.of_length_eq (by simp +contextual [ForwardPatternModel.Matches])
theorem isMatch_iff {p : Char Bool} {s : Slice} {pos : s.Pos} :
IsMatch p pos
(h : s.startPos s.endPos), pos = s.startPos.next h p (s.startPos.get h) := by
simp only [Model.isMatch_iff, PatternModel.Matches, copy_sliceTo_eq_iff_exists_splits]
simp only [Model.isMatch_iff, ForwardPatternModel.Matches, sliceTo_copy_eq_iff_exists_splits]
refine ?_, ?_
· simp only [splits_singleton_iff]
refine fun c, t₂, h, h₁, h₂, h₃, hc => h, h₁, h₂ hc
· rintro h, rfl, h'
exact s.startPos.get h, _, Slice.splits_next_startPos, h'
theorem isRevMatch_iff {p : Char Bool} {s : Slice} {pos : s.Pos} :
IsRevMatch p pos
(h : s.endPos s.startPos), pos = s.endPos.prev h p ((s.endPos.prev h).get (by simp)) := by
simp only [Model.isRevMatch_iff, PatternModel.Matches, copy_sliceFrom_eq_iff_exists_splits]
refine ?_, ?_
· simp only [splits_singleton_right_iff]
refine fun c, t₂, h, h₁, h₂, h₃, hc => h, h₁, h₂ hc
· rintro h, rfl, h'
exact (s.endPos.prev h).get (by simp), _, Slice.splits_prev_endPos, h'
theorem isLongestMatch_iff {p : Char Bool} {s : Slice} {pos : s.Pos} :
IsLongestMatch p pos
(h : s.startPos s.endPos), pos = s.startPos.next h p (s.startPos.get h) := by
rw [isLongestMatch_iff_isMatch, isMatch_iff]
theorem isLongestRevMatch_iff {p : Char Bool} {s : Slice} {pos : s.Pos} :
IsLongestRevMatch p pos
(h : s.endPos s.startPos), pos = s.endPos.prev h p ((s.endPos.prev h).get (by simp)) := by
rw [isLongestRevMatch_iff_isRevMatch, isRevMatch_iff]
theorem isLongestMatchAt_iff {p : Char Bool} {s : Slice} {pos pos' : s.Pos} :
IsLongestMatchAt p pos pos' h, pos' = pos.next h p (pos.get h) := by
simp +contextual [Model.isLongestMatchAt_iff, isLongestMatch_iff, Pos.ofSliceFrom_inj,
Pos.get_eq_get_ofSliceFrom, Pos.ofSliceFrom_next]
theorem isLongestMatchAtChain_iff {p : Char Bool} {s : Slice} {pos pos' : s.Pos} :
IsLongestMatchAtChain p pos pos' pos pos' pos'', pos pos'' (h : pos'' < pos') p (pos''.get (Pos.ne_endPos_of_lt h)) := by
induction pos using WellFounded.induction Pos.wellFounded_gt with | h pos ih
obtain (h|rfl|h) := Std.lt_trichotomy pos pos'
· refine fun h => ?_, fun h₁, h₂ => ?_
· cases h with
| nil => exact (Std.lt_irrefl h).elim
| cons _ mid _ h₁ h₂ =>
obtain h₀, rfl, h₁' := isLongestMatchAt_iff.1 h₁
refine Std.le_of_lt h, fun pos'' hp₁ hp₂ => ?_
obtain (hh|rfl) := Std.le_iff_lt_or_eq.1 hp₁
· exact ((ih (pos.next (Pos.ne_endPos_of_lt h)) Pos.lt_next).1 h₂).2 _ (by simpa) hp₂
· exact h₁'
· refine .cons _ (pos.next (Pos.ne_endPos_of_lt h)) _ ?_ ((ih _ Pos.lt_next).2 ?_)
· exact isLongestMatchAt_iff.2 Pos.ne_endPos_of_lt h, rfl, h₂ _ (by simp) h
· exact by simpa, fun pos'' hp₁ hp₂ => h₂ _ (Std.le_trans Pos.le_next hp₁) hp₂
· simpa using fun _ h₁ h₂ => (Std.lt_irrefl (Std.lt_of_le_of_lt h₁ h₂)).elim
· simpa [Std.not_le.2 h] using fun h' => (Std.not_le.2 h h'.le).elim
theorem isLongestMatchAtChain_iff_toList {p : Char Bool} {s : Slice} {pos pos' : s.Pos} :
IsLongestMatchAtChain p pos pos' (h : pos pos'), c, c (s.slice pos pos' h).copy.toList p c := by
simp only [isLongestMatchAtChain_iff, mem_toList_copy_iff_exists_get, Pos.get_eq_get_ofSlice,
forall_exists_index]
refine fun h₁, h₂ => h₁, fun c p' hp => ?_, fun h₁, h₂ => h₁, fun p' hp₁ hp₂ => ?_
· rintro rfl
exact h₂ _ Pos.le_ofSlice (by simp [Pos.ofSlice_lt_iff, h₁, hp])
· refine h₂ _ (Pos.slice p' _ _ hp₁ (Std.le_of_lt hp₂)) ?_ (by simp)
rwa [ Pos.lt_endPos_iff, Pos.slice_eq_endPos (h := h₁), Pos.slice_lt_slice_iff]
theorem isLongestMatchAtChain_startPos_endPos_iff_toList {p : Char Bool} {s : Slice} :
IsLongestMatchAtChain p s.startPos s.endPos c, c s.copy.toList p c := by
simp [isLongestMatchAtChain_iff_toList]
theorem isLongestRevMatchAt_iff {p : Char Bool} {s : Slice} {pos pos' : s.Pos} :
IsLongestRevMatchAt p pos pos' h, pos = pos'.prev h p ((pos'.prev h).get (by simp)) := by
simp +contextual [Model.isLongestRevMatchAt_iff, isLongestRevMatch_iff, Pos.ofSliceTo_inj,
Pos.get_eq_get_ofSliceTo, Pos.ofSliceTo_prev]
theorem isLongestMatchAt_of_get {p : Char Bool} {s : Slice} {pos : s.Pos} {h : pos s.endPos}
(hc : p (pos.get h)) : IsLongestMatchAt p pos (pos.next h) :=
isLongestMatchAt_iff.2 h, by simp [hc]
theorem isLongestRevMatchAt_of_get {p : Char Bool} {s : Slice} {pos : s.Pos} {h : pos s.startPos}
(hc : p ((pos.prev h).get (by simp))) : IsLongestRevMatchAt p (pos.prev h) pos :=
isLongestRevMatchAt_iff.2 h, by simp [hc]
theorem isLongestRevMatchAtChain_iff {p : Char Bool} {s : Slice} {pos pos' : s.Pos} :
IsLongestRevMatchAtChain p pos pos' pos pos' pos'', pos pos'' (h : pos'' < pos') p (pos''.get (Pos.ne_endPos_of_lt h)) := by
induction pos' using WellFounded.induction Pos.wellFounded_lt with | h pos' ih
obtain (h|rfl|h) := Std.lt_trichotomy pos pos'
· refine fun h => ?_, fun h₁, h₂ => ?_
· cases h with
| nil => exact (Std.lt_irrefl h).elim
| cons _ _ hchain hmatch =>
obtain hne, hmid, hp := isLongestRevMatchAt_iff.1 hmatch
refine Std.le_of_lt h, fun pos'' hp₁ hp₂ => ?_
rcases Std.le_iff_lt_or_eq.1 (Pos.le_prev_iff_lt.2 hp₂) with hh | heq
· exact ((ih _ Pos.prev_lt).1 (hmid hchain)).2 _ hp₁ hh
· exact heq hp
· have hne : pos' s.startPos := Slice.Pos.ne_startPos_of_lt h
refine .cons _ (pos'.prev hne) _ ((ih _ Pos.prev_lt).2 ?_)
(isLongestRevMatchAt_of_get (h₂ _ (Pos.le_prev_iff_lt.2 h) Pos.prev_lt))
exact Pos.le_prev_iff_lt.2 h, fun pos'' hp₁ hp₂ =>
h₂ _ hp₁ (Std.lt_trans hp₂ Pos.prev_lt)
· simpa using fun _ h₁ h₂ => (Std.lt_irrefl (Std.lt_of_le_of_lt h₁ h₂)).elim
· simpa [Std.not_le.2 h] using fun h' => (Std.not_le.2 h h'.le).elim
theorem isLongestRevMatchAtChain_iff_toList {p : Char Bool} {s : Slice} {pos pos' : s.Pos} :
IsLongestRevMatchAtChain p pos pos' (h : pos pos'), c, c (s.slice pos pos' h).copy.toList p c :=
isLongestRevMatchAtChain_iff.trans (isLongestMatchAtChain_iff.symm.trans isLongestMatchAtChain_iff_toList)
theorem isLongestRevMatchAtChain_startPos_endPos_iff_toList {p : Char Bool} {s : Slice} :
IsLongestRevMatchAtChain p s.startPos s.endPos c, c s.copy.toList p c := by
simp [isLongestRevMatchAtChain_iff_toList]
instance {p : Char Bool} : LawfulForwardPatternModel p where
skipPrefix?_eq_some_iff {s} pos := by
simp [isLongestMatch_iff, ForwardPattern.skipPrefix?, and_comm, eq_comm (b := pos)]
instance {p : Char Bool} : LawfulBackwardPatternModel p where
skipSuffix?_eq_some_iff {s} pos := by
simp [isLongestRevMatch_iff, BackwardPattern.skipSuffix?, and_comm, eq_comm (b := pos)]
dropPrefix?_eq_some_iff {s} pos := by
simp [isLongestMatch_iff, ForwardPattern.dropPrefix?, and_comm, eq_comm (b := pos)]
instance {p : Char Bool} : LawfulToForwardSearcherModel p :=
.defaultImplementation
instance {p : Char Bool} : LawfulToBackwardSearcherModel p :=
.defaultImplementation
theorem matchesAt_iff {p : Char Bool} {s : Slice} {pos : s.Pos} :
MatchesAt p pos (h : pos s.endPos), p (pos.get h) := by
simp [matchesAt_iff_exists_isLongestMatchAt, isLongestMatchAt_iff, exists_comm]
theorem revMatchesAt_iff {p : Char Bool} {s : Slice} {pos : s.Pos} :
RevMatchesAt p pos (h : pos s.startPos), p ((pos.prev h).get (by simp)) := by
simp [revMatchesAt_iff_exists_isLongestRevMatchAt, isLongestRevMatchAt_iff, exists_comm]
theorem not_matchesAt_of_get {p : Char Bool} {s : Slice} {pos : s.Pos} {h : pos s.endPos}
(hc : p (pos.get h) = false) : ¬ MatchesAt p pos := by
simp [matchesAt_iff, hc]
theorem not_revMatchesAt_of_get {p : Char Bool} {s : Slice} {pos : s.Pos} {h : pos s.startPos}
(hc : p ((pos.prev h).get (by simp)) = false) : ¬ RevMatchesAt p pos := by
simp [revMatchesAt_iff, hc]
theorem matchAt?_eq {s : Slice} {pos : s.Pos} {p : Char Bool} :
matchAt? p pos =
if h₀ : (h : pos s.endPos), p (pos.get h) then some (pos.next h₀.1) else none := by
split <;> simp_all [isLongestMatchAt_iff, matchesAt_iff]
theorem revMatchAt?_eq {s : Slice} {pos : s.Pos} {p : Char Bool} :
revMatchAt? p pos =
if h₀ : (h : pos s.startPos), p ((pos.prev h).get (by simp)) then some (pos.prev h₀.1) else none := by
split <;> simp_all [isLongestRevMatchAt_iff, revMatchesAt_iff]
namespace Decidable
instance {p : Char Prop} [DecidablePred p] : PatternModel p where
Matches := PatternModel.Matches (decide <| p ·)
instance {p : Char Prop} [DecidablePred p] : ForwardPatternModel p where
Matches := ForwardPatternModel.Matches (decide <| p ·)
not_matches_empty := ForwardPatternModel.not_matches_empty (pat := (decide <| p ·))
instance {p : Char Prop} [DecidablePred p] : StrictPatternModel p where
not_matches_empty := StrictPatternModel.not_matches_empty (pat := (decide <| p ·))
instance {p : Char Prop} [DecidablePred p] : NoPrefixPatternModel p where
eq_empty := NoPrefixPatternModel.eq_empty (pat := (decide <| p ·))
instance {p : Char Prop} [DecidablePred p] : NoSuffixPatternModel p where
eq_empty := NoSuffixPatternModel.eq_empty (pat := (decide <| p ·))
instance {p : Char Prop} [DecidablePred p] : NoPrefixForwardPatternModel p where
eq_empty := NoPrefixForwardPatternModel.eq_empty (pat := (decide <| p ·))
theorem isMatch_iff_isMatch_decide {p : Char Prop} [DecidablePred p] {s : Slice} {pos : s.Pos} :
IsMatch p pos IsMatch (decide <| p ·) pos :=
fun h => h, fun h => h
theorem isRevMatch_iff_isRevMatch_decide {p : Char Prop} [DecidablePred p] {s : Slice} {pos : s.Pos} :
IsRevMatch p pos IsRevMatch (decide <| p ·) pos :=
fun h => h, fun h => h
theorem isMatch_iff {p : Char Prop} [DecidablePred p] {s : Slice} {pos : s.Pos} :
IsMatch p pos
(h : s.startPos s.endPos), pos = s.startPos.next h p (s.startPos.get h) := by
simp [isMatch_iff_isMatch_decide, CharPred.isMatch_iff]
theorem isRevMatch_iff {p : Char Prop} [DecidablePred p] {s : Slice} {pos : s.Pos} :
IsRevMatch p pos
(h : s.endPos s.startPos), pos = s.endPos.prev h p ((s.endPos.prev h).get (by simp)) := by
simp [isRevMatch_iff_isRevMatch_decide, CharPred.isRevMatch_iff]
theorem isLongestMatch_iff {p : Char Prop} [DecidablePred p] {s : Slice} {pos : s.Pos} :
IsLongestMatch p pos
(h : s.startPos s.endPos), pos = s.startPos.next h p (s.startPos.get h) := by
rw [isLongestMatch_iff_isMatch, isMatch_iff]
theorem isLongestRevMatch_iff {p : Char Prop} [DecidablePred p] {s : Slice} {pos : s.Pos} :
IsLongestRevMatch p pos
(h : s.endPos s.startPos), pos = s.endPos.prev h p ((s.endPos.prev h).get (by simp)) := by
simp [isLongestRevMatch_iff_isRevMatch, isRevMatch_iff]
theorem isLongestMatch_iff_isLongestMatch_decide {p : Char Prop} [DecidablePred p] {s : Slice}
{pos : s.Pos} : IsLongestMatch p pos IsLongestMatch (decide <| p ·) pos := by
simp [isLongestMatch_iff_isMatch, isMatch_iff_isMatch_decide]
theorem isLongestRevMatch_iff_isLongestRevMatch_decide {p : Char Prop} [DecidablePred p] {s : Slice}
{pos : s.Pos} : IsLongestRevMatch p pos IsLongestRevMatch (decide <| p ·) pos := by
simp [isLongestRevMatch_iff_isRevMatch, isRevMatch_iff_isRevMatch_decide]
theorem isLongestMatchAt_iff_isLongestMatchAt_decide {p : Char Prop} [DecidablePred p]
{s : Slice} {pos pos' : s.Pos} :
IsLongestMatchAt p pos pos' IsLongestMatchAt (decide <| p ·) pos pos' := by
simp [Model.isLongestMatchAt_iff, isLongestMatch_iff_isLongestMatch_decide]
theorem isLongestRevMatchAt_iff_isLongestRevMatchAt_decide {p : Char Prop} [DecidablePred p]
{s : Slice} {pos pos' : s.Pos} :
IsLongestRevMatchAt p pos pos' IsLongestRevMatchAt (decide <| p ·) pos pos' := by
simp [Model.isLongestRevMatchAt_iff, isLongestRevMatch_iff_isLongestRevMatch_decide]
theorem isLongestMatchAtChain_iff_isLongestMatchAtChain_decide {p : Char Prop} [DecidablePred p]
{s : Slice} {pos pos' : s.Pos} :
IsLongestMatchAtChain p pos pos' IsLongestMatchAtChain (decide <| p ·) pos pos' := by
constructor
· intro h; induction h with
| nil => exact .nil _
| cons _ mid _ hmatch hchain ih =>
exact .cons _ mid _ (isLongestMatchAt_iff_isLongestMatchAt_decide.1 hmatch) ih
· intro h; induction h with
| nil => exact .nil _
| cons _ mid _ hmatch hchain ih =>
exact .cons _ mid _ (isLongestMatchAt_iff_isLongestMatchAt_decide.2 hmatch) ih
theorem isLongestRevMatchAtChain_iff_isLongestRevMatchAtChain_decide {p : Char Prop} [DecidablePred p]
{s : Slice} {pos pos' : s.Pos} :
IsLongestRevMatchAtChain p pos pos' IsLongestRevMatchAtChain (decide <| p ·) pos pos' := by
constructor
· intro h; induction h with
| nil => exact .nil _
| cons _ _ hchain hmatch ih =>
exact .cons _ _ _ ih (isLongestRevMatchAt_iff_isLongestRevMatchAt_decide.1 hmatch)
· intro h; induction h with
| nil => exact .nil _
| cons _ _ hchain hmatch ih =>
exact .cons _ _ _ ih (isLongestRevMatchAt_iff_isLongestRevMatchAt_decide.2 hmatch)
theorem isLongestMatchAt_iff {p : Char Prop} [DecidablePred p] {s : Slice}
{pos pos' : s.Pos} :
IsLongestMatchAt p pos pos' h, pos' = pos.next h p (pos.get h) := by
simp [isLongestMatchAt_iff_isLongestMatchAt_decide, CharPred.isLongestMatchAt_iff]
theorem isLongestRevMatchAt_iff {p : Char Prop} [DecidablePred p] {s : Slice}
{pos pos' : s.Pos} :
IsLongestRevMatchAt p pos pos' h, pos = pos'.prev h p ((pos'.prev h).get (by simp)) := by
simp [isLongestRevMatchAt_iff_isLongestRevMatchAt_decide, CharPred.isLongestRevMatchAt_iff]
theorem isLongestMatchAt_of_get {p : Char Prop} [DecidablePred p] {s : Slice} {pos : s.Pos}
{h : pos s.endPos} (hc : p (pos.get h)) : IsLongestMatchAt p pos (pos.next h) :=
isLongestMatchAt_iff.2 h, by simp [hc]
theorem isLongestRevMatchAt_of_get {p : Char Prop} [DecidablePred p] {s : Slice} {pos : s.Pos}
{h : pos s.startPos} (hc : p ((pos.prev h).get (by simp))) :
IsLongestRevMatchAt p (pos.prev h) pos :=
isLongestRevMatchAt_iff.2 h, by simp [hc]
theorem matchesAt_iff_matchesAt_decide {p : Char Prop} [DecidablePred p] {s : Slice}
{pos : s.Pos} : MatchesAt p pos MatchesAt (decide <| p ·) pos := by
simp [matchesAt_iff_exists_isLongestMatchAt, isLongestMatchAt_iff_isLongestMatchAt_decide]
theorem revMatchesAt_iff_revMatchesAt_decide {p : Char Prop} [DecidablePred p] {s : Slice}
{pos : s.Pos} : RevMatchesAt p pos RevMatchesAt (decide <| p ·) pos := by
simp [revMatchesAt_iff_exists_isLongestRevMatchAt, isLongestRevMatchAt_iff_isLongestRevMatchAt_decide]
theorem matchAt?_eq_matchAt?_decide {p : Char Prop} [DecidablePred p] {s : Slice}
{pos : s.Pos} : matchAt? p pos = matchAt? (decide <| p ·) pos := by
ext endPos
simp [isLongestMatchAt_iff_isLongestMatchAt_decide]
theorem revMatchAt?_eq_revMatchAt?_decide {p : Char Prop} [DecidablePred p] {s : Slice}
{pos : s.Pos} : revMatchAt? p pos = revMatchAt? (decide <| p ·) pos := by
ext startPos
simp [isLongestRevMatchAt_iff_isLongestRevMatchAt_decide]
theorem skipPrefix?_eq_skipPrefix?_decide {p : Char Prop} [DecidablePred p] :
ForwardPattern.skipPrefix? p = ForwardPattern.skipPrefix? (decide <| p ·) := rfl
theorem skipSuffix?_eq_skipSuffix?_decide {p : Char Prop} [DecidablePred p] :
BackwardPattern.skipSuffix? p = BackwardPattern.skipSuffix? (decide <| p ·) := rfl
theorem dropPrefix?_eq_dropPrefix?_decide {p : Char Prop} [DecidablePred p] :
ForwardPattern.dropPrefix? p = ForwardPattern.dropPrefix? (decide <| p ·) := rfl
instance {p : Char Prop} [DecidablePred p] : LawfulForwardPatternModel p where
skipPrefix?_eq_some_iff {s} pos := by
rw [skipPrefix?_eq_skipPrefix?_decide, isLongestMatch_iff_isLongestMatch_decide]
exact LawfulForwardPatternModel.skipPrefix?_eq_some_iff ..
instance {p : Char Prop} [DecidablePred p] : LawfulBackwardPatternModel p where
skipSuffix?_eq_some_iff {s} pos := by
rw [skipSuffix?_eq_skipSuffix?_decide, isLongestRevMatch_iff_isLongestRevMatch_decide]
exact LawfulBackwardPatternModel.skipSuffix?_eq_some_iff ..
dropPrefix?_eq_some_iff {s} pos := by
rw [dropPrefix?_eq_dropPrefix?_decide, isLongestMatch_iff_isLongestMatch_decide]
exact LawfulForwardPatternModel.dropPrefix?_eq_some_iff ..
theorem toSearcher_eq {p : Char Prop} [DecidablePred p] {s : Slice} :
ToForwardSearcher.toSearcher p s = ToForwardSearcher.toSearcher (decide <| p ·) s := (rfl)
theorem toBackwardSearcher_eq {p : Char Prop} [DecidablePred p] {s : Slice} :
ToBackwardSearcher.toSearcher p s = ToBackwardSearcher.toSearcher (decide <| p ·) s := (rfl)
theorem isValidSearchFrom_iff_isValidSearchFrom_decide {p : Char Prop} [DecidablePred p]
{s : Slice} {pos : s.Pos} {l : List (SearchStep s)} :
IsValidSearchFrom p pos l IsValidSearchFrom (decide <| p ·) pos l := by
@@ -346,55 +150,24 @@ theorem isValidSearchFrom_iff_isValidSearchFrom_decide {p : Char → Prop} [Deci
| matched => simp_all [IsValidSearchFrom.matched, isLongestMatchAt_iff_isLongestMatchAt_decide]
| mismatched => simp_all [IsValidSearchFrom.mismatched, matchesAt_iff_matchesAt_decide]
theorem isValidRevSearchFrom_iff_isValidRevSearchFrom_decide {p : Char Prop} [DecidablePred p]
{s : Slice} {pos : s.Pos} {l : List (SearchStep s)} :
IsValidRevSearchFrom p pos l IsValidRevSearchFrom (decide <| p ·) pos l := by
refine fun h => ?_, fun h => ?_
· induction h with
| startPos => simpa using IsValidRevSearchFrom.startPos
| matched => simp_all [IsValidRevSearchFrom.matched, isLongestRevMatchAt_iff_isLongestRevMatchAt_decide]
| mismatched => simp_all [IsValidRevSearchFrom.mismatched, revMatchesAt_iff_revMatchesAt_decide]
· induction h with
| startPos => simpa using IsValidRevSearchFrom.startPos
| matched => simp_all [IsValidRevSearchFrom.matched, isLongestRevMatchAt_iff_isLongestRevMatchAt_decide]
| mismatched => simp_all [IsValidRevSearchFrom.mismatched, revMatchesAt_iff_revMatchesAt_decide]
instance {p : Char Prop} [DecidablePred p] : LawfulToForwardSearcherModel p where
isValidSearchFrom_toList s := by
simpa [toSearcher_eq, isValidSearchFrom_iff_isValidSearchFrom_decide] using
LawfulToForwardSearcherModel.isValidSearchFrom_toList (pat := (decide <| p ·)) (s := s)
instance {p : Char Prop} [DecidablePred p] : LawfulToBackwardSearcherModel p where
isValidRevSearchFrom_toList s := by
simpa [toBackwardSearcher_eq, isValidRevSearchFrom_iff_isValidRevSearchFrom_decide] using
LawfulToBackwardSearcherModel.isValidRevSearchFrom_toList (pat := (decide <| p ·)) (s := s)
theorem matchesAt_iff {p : Char Prop} [DecidablePred p] {s : Slice} {pos : s.Pos} :
MatchesAt p pos (h : pos s.endPos), p (pos.get h) := by
simp [matchesAt_iff_exists_isLongestMatchAt, isLongestMatchAt_iff, exists_comm]
theorem revMatchesAt_iff {p : Char Prop} [DecidablePred p] {s : Slice} {pos : s.Pos} :
RevMatchesAt p pos (h : pos s.startPos), p ((pos.prev h).get (by simp)) := by
simp [revMatchesAt_iff_exists_isLongestRevMatchAt, isLongestRevMatchAt_iff, exists_comm]
theorem not_matchesAt_of_get {p : Char Prop} [DecidablePred p] {s : Slice} {pos : s.Pos}
{h : pos s.endPos} (hc : ¬ p (pos.get h)) : ¬ MatchesAt p pos := by
simp [matchesAt_iff, hc]
theorem not_revMatchesAt_of_get {p : Char Prop} [DecidablePred p] {s : Slice} {pos : s.Pos}
{h : pos s.startPos} (hc : ¬ p ((pos.prev h).get (by simp))) : ¬ RevMatchesAt p pos := by
simp [revMatchesAt_iff, hc]
theorem matchAt?_eq {s : Slice} {pos : s.Pos} {p : Char Prop} [DecidablePred p] :
matchAt? p pos =
if h₀ : (h : pos s.endPos), p (pos.get h) then some (pos.next h₀.1) else none := by
split <;> simp_all [isLongestMatchAt_iff, matchesAt_iff]
theorem revMatchAt?_eq {s : Slice} {pos : s.Pos} {p : Char Prop} [DecidablePred p] :
revMatchAt? p pos =
if h₀ : (h : pos s.startPos), p ((pos.prev h).get (by simp)) then some (pos.prev h₀.1) else none := by
split <;> simp_all [isLongestRevMatchAt_iff, revMatchesAt_iff]
end Decidable
end Pattern.Model.CharPred
@@ -408,46 +181,47 @@ theorem dropPrefix?_prop_eq_dropPrefix?_decide {p : Char → Prop} [DecidablePre
theorem dropPrefix_prop_eq_dropPrefix_decide {p : Char Prop} [DecidablePred p] {s : Slice} :
s.dropPrefix p = s.dropPrefix (decide <| p ·) := (rfl)
theorem skipPrefix?_prop_eq_skipPrefix?_decide {p : Char Prop} [DecidablePred p] {s : Slice} :
s.skipPrefix? p = s.skipPrefix? (decide <| p ·) := (rfl)
theorem Pos.skip?_prop_eq_skip?_decide {p : Char Prop} [DecidablePred p] {s : Slice} {pos : s.Pos} :
pos.skip? p = pos.skip? (decide <| p ·) := (rfl)
theorem Pattern.ForwardPattern.skipPrefix?_prop_eq_skipPrefix?_decide
theorem Pattern.ForwardPattern.dropPrefix?_prop_eq_dropPrefix?_decide
{p : Char Prop} [DecidablePred p] {s : Slice} :
skipPrefix? p s = skipPrefix? (decide <| p ·) s := (rfl)
dropPrefix? p s = dropPrefix? (decide <| p ·) s := (rfl)
theorem Pos.skipWhile_prop_eq_skipWhile_decide {p : Char Prop} [DecidablePred p] {s : Slice}
(curr : s.Pos) :
Pos.skipWhile curr p = Pos.skipWhile curr (decide <| p ·) := by
fun_induction Pos.skipWhile curr p with
private theorem dropWhileGo_eq {p : Char Prop} [DecidablePred p] {s : Slice} (curr : s.Pos) :
dropWhile.go s p curr = dropWhile.go s (decide <| p ·) curr := by
fun_induction dropWhile.go s p curr with
| case1 pos nextCurr h₁ h₂ ih =>
conv => rhs; rw [Pos.skipWhile]
simp [ Pos.skip?_prop_eq_skip?_decide, h₁, h₂, ih]
conv => rhs; rw [dropWhile.go]
simp [ Pattern.ForwardPattern.dropPrefix?_prop_eq_dropPrefix?_decide, h₁, h₂, ih]
| case2 pos nextCurr h ih =>
conv => rhs; rw [Pos.skipWhile]
simp [ Pos.skip?_prop_eq_skip?_decide, h, ih]
conv => rhs; rw [dropWhile.go]
simp [ Pattern.ForwardPattern.dropPrefix?_prop_eq_dropPrefix?_decide, h, ih]
| case3 pos h =>
conv => rhs; rw [Pos.skipWhile]
simp [ Pos.skip?_prop_eq_skip?_decide, h]
theorem skipPrefixWhile_prop_eq_skipPrefixWhile_decide {p : Char Prop} [DecidablePred p]
{s : Slice} :
s.skipPrefixWhile p = s.skipPrefixWhile (decide <| p ·) :=
Pos.skipWhile_prop_eq_skipWhile_decide s.startPos
conv => rhs; rw [dropWhile.go]
simp [ Pattern.ForwardPattern.dropPrefix?_prop_eq_dropPrefix?_decide]
theorem dropWhile_prop_eq_dropWhile_decide {p : Char Prop} [DecidablePred p] {s : Slice} :
s.dropWhile p = s.dropWhile (decide <| p ·) := by
simp only [dropWhile]; exact congrArg _ skipPrefixWhile_prop_eq_skipPrefixWhile_decide
simpa only [dropWhile] using dropWhileGo_eq s.startPos
private theorem takeWhileGo_eq {p : Char Prop} [DecidablePred p] {s : Slice} (curr : s.Pos) :
takeWhile.go s p curr = takeWhile.go s (decide <| p ·) curr := by
fun_induction takeWhile.go s p curr with
| case1 pos nextCurr h₁ h₂ ih =>
conv => rhs; rw [takeWhile.go]
simp [ Pattern.ForwardPattern.dropPrefix?_prop_eq_dropPrefix?_decide, h₁, h₂, ih]
| case2 pos nextCurr h ih =>
conv => rhs; rw [takeWhile.go]
simp [ Pattern.ForwardPattern.dropPrefix?_prop_eq_dropPrefix?_decide, h, ih]
| case3 pos h =>
conv => rhs; rw [takeWhile.go]
simp [ Pattern.ForwardPattern.dropPrefix?_prop_eq_dropPrefix?_decide]
theorem takeWhile_prop_eq_takeWhile_decide {p : Char Prop} [DecidablePred p] {s : Slice} :
s.takeWhile p = s.takeWhile (decide <| p ·) := by
simp only [takeWhile]; exact congrArg _ skipPrefixWhile_prop_eq_skipPrefixWhile_decide
simp only [takeWhile]; exact takeWhileGo_eq s.startPos
theorem all_prop_eq_all_decide {p : Char Prop} [DecidablePred p] {s : Slice} :
s.all p = s.all (decide <| p ·) := by
simp only [all, skipPrefixWhile_prop_eq_skipPrefixWhile_decide]
simp only [all, dropWhile_prop_eq_dropWhile_decide]
theorem find?_prop_eq_find?_decide {p : Char Prop} [DecidablePred p] {s : Slice} :
s.find? p = s.find? (decide <| p ·) :=
@@ -465,53 +239,52 @@ theorem contains_prop_eq_contains_decide {p : Char → Prop} [DecidablePred p] {
theorem endsWith_prop_eq_endsWith_decide {p : Char Prop} [DecidablePred p] {s : Slice} :
s.endsWith p = s.endsWith (decide <| p ·) := (rfl)
theorem skipSuffix?_prop_eq_skipSuffix?_decide {p : Char Prop} [DecidablePred p] {s : Slice} :
s.skipSuffix? p = s.skipSuffix? (decide <| p ·) := (rfl)
theorem dropSuffix?_prop_eq_dropSuffix?_decide {p : Char Prop} [DecidablePred p] {s : Slice} :
s.dropSuffix? p = s.dropSuffix? (decide <| p ·) := (rfl)
theorem dropSuffix_prop_eq_dropSuffix_decide {p : Char Prop} [DecidablePred p] {s : Slice} :
s.dropSuffix p = s.dropSuffix (decide <| p ·) := (rfl)
theorem Pattern.BackwardPattern.skipSuffix?_prop_eq_skipSuffix?_decide
theorem Pattern.BackwardPattern.dropSuffix?_prop_eq_dropSuffix?_decide
{p : Char Prop} [DecidablePred p] {s : Slice} :
skipSuffix? p s = skipSuffix? (decide <| p ·) s := (rfl)
dropSuffix? p s = dropSuffix? (decide <| p ·) s := (rfl)
theorem Pos.revSkip?_prop_eq_revSkip?_decide {p : Char Prop} [DecidablePred p] {s : Slice} {pos : s.Pos} :
pos.revSkip? p = pos.revSkip? (decide <| p ·) := (rfl)
theorem Pos.revSkipWhile_prop_eq_revSkipWhile_decide {p : Char Prop} [DecidablePred p]
{s : Slice} (curr : s.Pos) :
Pos.revSkipWhile curr p = Pos.revSkipWhile curr (decide <| p ·) := by
fun_induction Pos.revSkipWhile curr p with
private theorem dropEndWhileGo_eq {p : Char Prop} [DecidablePred p] {s : Slice}
(curr : s.Pos) :
dropEndWhile.go s p curr = dropEndWhile.go s (decide <| p ·) curr := by
fun_induction dropEndWhile.go s p curr with
| case1 pos nextCurr h₁ h₂ ih =>
conv => rhs; rw [Pos.revSkipWhile]
simp [ Pos.revSkip?_prop_eq_revSkip?_decide, h₁, h₂, ih]
conv => rhs; rw [dropEndWhile.go]
simp [ Pattern.BackwardPattern.dropSuffix?_prop_eq_dropSuffix?_decide, h₁, h₂, ih]
| case2 pos nextCurr h ih =>
conv => rhs; rw [Pos.revSkipWhile]
simp [ Pos.revSkip?_prop_eq_revSkip?_decide, h, ih]
conv => rhs; rw [dropEndWhile.go]
simp [ Pattern.BackwardPattern.dropSuffix?_prop_eq_dropSuffix?_decide, h, ih]
| case3 pos h =>
conv => rhs; rw [Pos.revSkipWhile]
simp [ Pos.revSkip?_prop_eq_revSkip?_decide, h]
theorem skipSuffixWhile_prop_eq_skipSuffixWhile_decide {p : Char Prop} [DecidablePred p]
{s : Slice} :
s.skipSuffixWhile p = s.skipSuffixWhile (decide <| p ·) :=
Pos.revSkipWhile_prop_eq_revSkipWhile_decide s.endPos
conv => rhs; rw [dropEndWhile.go]
simp [ Pattern.BackwardPattern.dropSuffix?_prop_eq_dropSuffix?_decide]
theorem dropEndWhile_prop_eq_dropEndWhile_decide {p : Char Prop} [DecidablePred p]
{s : Slice} :
s.dropEndWhile p = s.dropEndWhile (decide <| p ·) := by
simp only [dropEndWhile]; exact congrArg _ skipSuffixWhile_prop_eq_skipSuffixWhile_decide
simpa only [dropEndWhile] using dropEndWhileGo_eq s.endPos
private theorem takeEndWhileGo_eq {p : Char Prop} [DecidablePred p] {s : Slice}
(curr : s.Pos) :
takeEndWhile.go s p curr = takeEndWhile.go s (decide <| p ·) curr := by
fun_induction takeEndWhile.go s p curr with
| case1 pos nextCurr h₁ h₂ ih =>
conv => rhs; rw [takeEndWhile.go]
simp [ Pattern.BackwardPattern.dropSuffix?_prop_eq_dropSuffix?_decide, h₁, h₂, ih]
| case2 pos nextCurr h ih =>
conv => rhs; rw [takeEndWhile.go]
simp [ Pattern.BackwardPattern.dropSuffix?_prop_eq_dropSuffix?_decide, h, ih]
| case3 pos h =>
conv => rhs; rw [takeEndWhile.go]
simp [ Pattern.BackwardPattern.dropSuffix?_prop_eq_dropSuffix?_decide]
theorem takeEndWhile_prop_eq_takeEndWhile_decide {p : Char Prop} [DecidablePred p]
{s : Slice} :
s.takeEndWhile p = s.takeEndWhile (decide <| p ·) := by
simp only [takeEndWhile]; exact congrArg _ skipSuffixWhile_prop_eq_skipSuffixWhile_decide
theorem revAll_prop_eq_revAll_decide {p : Char Prop} [DecidablePred p] {s : Slice} :
s.revAll p = s.revAll (decide <| p ·) := by
simp only [revAll, skipSuffixWhile_prop_eq_skipSuffixWhile_decide]
simpa only [takeEndWhile] using takeEndWhileGo_eq s.endPos
end String.Slice

View File

@@ -28,15 +28,14 @@ set_option doc.verso true
# Verification of {name}`String.Slice.splitToSubslice`
This PR verifies the {name}`String.Slice.splitToSubslice` function by relating it to a model
implementation based on the {name}`String.Slice.Pattern.Model.PatternModel` class.
implementation based on the {name}`String.Slice.Pattern.Model.ForwardPatternModel` class.
This gives a low-level correctness proof from which higher-level API lemmas can be derived.
-/
namespace String.Slice.Pattern.Model
@[cbv_opaque]
public protected noncomputable def split {ρ : Type} (pat : ρ) [PatternModel pat] [StrictPatternModel pat] {s : Slice}
public protected noncomputable def split {ρ : Type} (pat : ρ) [ForwardPatternModel pat] {s : Slice}
(firstRejected curr : s.Pos) (hle : firstRejected curr) : List s.Subslice :=
if h : curr = s.endPos then
[s.subslice _ _ hle]
@@ -49,12 +48,12 @@ public protected noncomputable def split {ρ : Type} (pat : ρ) [PatternModel pa
termination_by curr
@[simp]
public theorem split_endPos {ρ : Type} {pat : ρ} [PatternModel pat] [StrictPatternModel pat] {s : Slice}
public theorem split_endPos {ρ : Type} {pat : ρ} [ForwardPatternModel pat] {s : Slice}
{firstRejected : s.Pos} :
Model.split (s := s) pat firstRejected s.endPos (by simp) = [s.subslice firstRejected s.endPos (by simp)] := by
simp [Model.split]
public theorem split_eq_of_isLongestMatchAt {ρ : Type} {pat : ρ} [PatternModel pat] [StrictPatternModel pat]
public theorem split_eq_of_isLongestMatchAt {ρ : Type} {pat : ρ} [ForwardPatternModel pat]
{s : Slice} {firstRejected start stop : s.Pos} {hle} (h : IsLongestMatchAt pat start stop) :
Model.split pat firstRejected start hle =
s.subslice _ _ hle :: Model.split pat stop stop (by exact Std.le_refl _) := by
@@ -63,7 +62,7 @@ public theorem split_eq_of_isLongestMatchAt {ρ : Type} {pat : ρ} [PatternModel
· congr <;> exact (matchAt?_eq_some_iff.1 _).eq h
· simp [matchAt?_eq_some_iff.2 _] at *
public theorem split_eq_of_not_matchesAt {ρ : Type} {pat : ρ} [PatternModel pat] [StrictPatternModel pat]
public theorem split_eq_of_not_matchesAt {ρ : Type} {pat : ρ} [ForwardPatternModel pat]
{s : Slice} {firstRejected start} (stop : s.Pos) (h₀ : start stop) {hle}
(h : p, start p p < stop ¬ MatchesAt pat p) :
Model.split pat firstRejected start hle =
@@ -80,7 +79,7 @@ public theorem split_eq_of_not_matchesAt {ρ : Type} {pat : ρ} [PatternModel pa
· obtain rfl : start = stop := Std.le_antisymm h₀ (Std.not_lt.1 h')
simp
public theorem split_eq_next_of_not_matchesAt {ρ : Type} {pat : ρ} [PatternModel pat] [StrictPatternModel pat]
public theorem split_eq_next_of_not_matchesAt {ρ : Type} {pat : ρ} [ForwardPatternModel pat]
{s : Slice} {firstRejected start} {hle} (hs : start s.endPos) (h : ¬ MatchesAt pat start) :
Model.split pat firstRejected start hle =
Model.split pat firstRejected (start.next hs) (by exact Std.le_trans hle (by simp)) := by
@@ -103,7 +102,7 @@ def splitFromSteps {s : Slice} (currPos : s.Pos) (l : List (SearchStep s)) : Lis
| .matched p q :: l => s.subslice! currPos p :: splitFromSteps q l
theorem IsValidSearchFrom.splitFromSteps_eq_extend_split {ρ : Type} (pat : ρ)
[PatternModel pat] [StrictPatternModel pat] (l : List (SearchStep s)) (pos pos' : s.Pos) (h₀ : pos pos')
[ForwardPatternModel pat] (l : List (SearchStep s)) (pos pos' : s.Pos) (h₀ : pos pos')
(h' : p, pos p p < pos' ¬ MatchesAt pat p)
(h : IsValidSearchFrom pat pos' l) :
splitFromSteps pos l = Model.split pat pos pos' h₀ := by
@@ -154,8 +153,7 @@ end Model
open Model
@[cbv_eval]
public theorem toList_splitToSubslice_eq_modelSplit {ρ : Type} (pat : ρ) [PatternModel pat] [StrictPatternModel pat]
public theorem toList_splitToSubslice_eq_modelSplit {ρ : Type} (pat : ρ) [ForwardPatternModel pat]
{σ : Slice Type} [ToForwardSearcher pat σ] [ s, Std.Iterator (σ s) Id (SearchStep s)]
[ s, Std.Iterators.Finite (σ s) Id] [LawfulToForwardSearcherModel pat] (s : Slice) :
(s.splitToSubslice pat).toList = Model.split pat s.startPos s.startPos (by exact Std.le_refl _) := by
@@ -168,7 +166,7 @@ end Pattern
open Pattern
public theorem toList_splitToSubslice_of_isEmpty {ρ : Type} (pat : ρ)
[Model.PatternModel pat] [Model.StrictPatternModel pat] {σ : Slice Type}
[Model.ForwardPatternModel pat] {σ : Slice Type}
[ToForwardSearcher pat σ] [ s, Std.Iterator (σ s) Id (SearchStep s)]
[ s, Std.Iterators.Finite (σ s) Id] [Model.LawfulToForwardSearcherModel pat] {s : Slice}
(h : s.isEmpty = true) :
@@ -182,7 +180,7 @@ public theorem toList_split_eq_splitToSubslice {ρ : Type} (pat : ρ) {σ : Slic
simp [split, Std.Iter.toList_map]
public theorem toList_split_of_isEmpty {ρ : Type} (pat : ρ)
[Model.PatternModel pat] [Model.StrictPatternModel pat] {σ : Slice Type}
[Model.ForwardPatternModel pat] {σ : Slice Type}
[ToForwardSearcher pat σ] [ s, Std.Iterator (σ s) Id (SearchStep s)]
[ s, Std.Iterators.Finite (σ s) Id] [Model.LawfulToForwardSearcherModel pat] {s : Slice}
(h : s.isEmpty = true) :
@@ -200,7 +198,7 @@ public theorem split_eq_split_toSlice {ρ : Type} {pat : ρ} {σ : Slice → Typ
@[simp]
public theorem toList_split_empty {ρ : Type} (pat : ρ)
[Model.PatternModel pat] [Model.StrictPatternModel pat] {σ : Slice Type}
[Model.ForwardPatternModel pat] {σ : Slice Type}
[ToForwardSearcher pat σ] [ s, Std.Iterator (σ s) Id (SearchStep s)]
[ s, Std.Iterators.Finite (σ s) Id] [Model.LawfulToForwardSearcherModel pat] :
("".split pat).toList.map Slice.copy = [""] := by

View File

@@ -23,7 +23,6 @@ import Init.Data.String.OrderInstances
import Init.Data.String.Lemmas.Order
import Init.Data.String.Lemmas.Intercalate
import Init.Data.List.SplitOn.Lemmas
import Init.Data.String.Lemmas.Slice
public section
@@ -31,7 +30,6 @@ namespace String.Slice
open Pattern.Model Pattern.Model.Char
@[cbv_eval]
theorem Pattern.Model.split_char_eq_split_beq {c : Char} {s : Slice}
(f curr : s.Pos) (hle : f curr) :
Model.split c f curr hle = Model.split (· == c) f curr hle := by
@@ -71,11 +69,6 @@ theorem Slice.toList_split_intercalate {c : Char} {l : List Slice} (hl : ∀ s
· simp_all
· rw [List.splitOn_intercalate] <;> simp_all
theorem Slice.toList_split_intercalate_beq {c : Char} {l : List Slice} (hl : s l, c s.copy.toList) :
((Slice.intercalate (String.singleton c) l).split c).toList ==
if l = [] then ["".toSlice] else l := by
split <;> simp_all [toList_split_intercalate hl, beq_list_iff]
theorem toList_split_intercalate {c : Char} {l : List String} (hl : s l, c s.toList) :
((String.intercalate (String.singleton c) l).split c).toList.map (·.copy) =
if l = [] then [""] else l := by
@@ -84,9 +77,4 @@ theorem toList_split_intercalate {c : Char} {l : List String} (hl : ∀ s ∈ l,
· simp_all
· rw [List.splitOn_intercalate] <;> simp_all
theorem toList_split_intercalate_beq {c : Char} {l : List String} (hl : s l, c s.toList) :
((String.intercalate (String.singleton c) l).split c).toList ==
if l = [] then ["".toSlice] else l.map String.toSlice := by
split <;> simp_all [toList_split_intercalate hl, Slice.beq_list_iff]
end String

View File

@@ -58,33 +58,12 @@ theorem toList_split_bool {s : Slice} {p : Char → Bool} :
(s.split p).toList.map Slice.copy = (s.copy.toList.splitOnP p).map String.ofList := by
simp [toList_split_eq_splitToSubslice, toList_splitToSubslice_bool]
/-
Used internally by the `cbv` tactic.
-/
@[cbv_eval]
theorem Pattern.Model.split_bool_eq_internal {p : Char Bool} {s : Slice} (f curr : s.Pos) (hle : f curr) :
Model.split p f curr hle =
if h : curr = s.endPos then [s.subslice _ _ hle]
else if p (curr.get h) then
s.subslice _ _ hle :: Model.split p (curr.next h) (curr.next h) (by simp [Std.le_refl])
else Model.split p f (curr.next h) (by simp [Std.le_trans hle _]) := by
by_cases h : curr = s.endPos
· simp only [h, split_endPos, subslice_endPos, reduceDIte]
· simp only [h, reduceDIte]
by_cases hp : p (curr.get h)
· simp only [hp, reduceIte]
exact split_eq_of_isLongestMatchAt (isLongestMatchAt_of_get hp)
· rw [Bool.not_eq_true] at hp
simp only [hp, Bool.false_eq_true, reduceIte]
exact split_eq_next_of_not_matchesAt h (not_matchesAt_of_get hp)
end
section
open Pattern.Model Pattern.Model.CharPred.Decidable
@[cbv_eval]
theorem Pattern.Model.split_eq_split_decide {p : Char Prop} [DecidablePred p] {s : Slice}
(f curr : s.Pos) (hle : f curr) :
Model.split p f curr hle = Model.split (decide <| p ·) f curr hle := by

View File

@@ -10,9 +10,6 @@ public import Init.Data.String.Pattern.String
public import Init.Data.String.Lemmas.Pattern.Basic
import Init.Data.String.Lemmas.IsEmpty
import Init.Data.String.Lemmas.Basic
import Init.Data.String.Lemmas.Intercalate
import Init.Data.String.OrderInstances
import Init.Data.String.Lemmas.Splits
import Init.Data.ByteArray.Lemmas
import Init.Omega
@@ -22,135 +19,46 @@ namespace String.Slice.Pattern.Model
namespace ForwardSliceSearcher
instance {pat : Slice} : PatternModel pat where
Matches s := s = pat.copy
instance {pat : Slice} : ForwardPatternModel pat where
/-
See the docstring of `ForwardPatternModel` for an explanation about why we disallow matching the
empty string.
theorem strictPatternModel {pat : Slice} (hpat : pat.isEmpty = false) : StrictPatternModel pat where
not_matches_empty := by simpa [PatternModel.Matches]
Requiring `s ≠ ""` is a trick that allows us to give a `ForwardPatternModel` instance
unconditionally, without forcing `pat.copy` to be non-empty (which would make it very awkward
to state theorems about the instance). It does not change anything about the fact that all lemmas
about this instance require `pat.isEmpty = false`.
-/
Matches s := s "" s = pat.copy
not_matches_empty := by simp
instance {pat : Slice} : NoPrefixPatternModel pat :=
.of_length_eq (by simp +contextual [PatternModel.Matches])
instance {pat : Slice} : NoPrefixForwardPatternModel pat :=
.of_length_eq (by simp +contextual [ForwardPatternModel.Matches])
instance {pat : Slice} : NoSuffixPatternModel pat :=
.of_length_eq (by simp +contextual [PatternModel.Matches])
theorem isMatch_iff {pat s : Slice} {pos : s.Pos} :
theorem isMatch_iff {pat s : Slice} {pos : s.Pos} (h : pat.isEmpty = false) :
IsMatch pat pos (s.sliceTo pos).copy = pat.copy := by
simp [Model.isMatch_iff, PatternModel.Matches]
simp only [Model.isMatch_iff, ForwardPatternModel.Matches, ne_eq, copy_eq_empty_iff,
Bool.not_eq_true, and_iff_right_iff_imp]
intro h'
rw [ isEmpty_copy (s := s.sliceTo pos), h', isEmpty_copy, h]
theorem isRevMatch_iff {pat s : Slice} {pos : s.Pos} :
IsRevMatch pat pos (s.sliceFrom pos).copy = pat.copy := by
simp [Model.isRevMatch_iff, PatternModel.Matches]
theorem isLongestMatch_iff {pat s : Slice} {pos : s.Pos} :
theorem isLongestMatch_iff {pat s : Slice} {pos : s.Pos} (h : pat.isEmpty = false) :
IsLongestMatch pat pos (s.sliceTo pos).copy = pat.copy := by
rw [isLongestMatch_iff_isMatch, isMatch_iff]
rw [isLongestMatch_iff_isMatch, isMatch_iff h]
theorem isLongestRevMatch_iff {pat s : Slice} {pos : s.Pos} :
IsLongestRevMatch pat pos (s.sliceFrom pos).copy = pat.copy := by
rw [isLongestRevMatch_iff_isRevMatch, isRevMatch_iff]
theorem isLongestMatchAt_iff {pat s : Slice} {pos₁ pos₂ : s.Pos} :
theorem isLongestMatchAt_iff {pat s : Slice} {pos pos₂ : s.Pos} (h : pat.isEmpty = false) :
IsLongestMatchAt pat pos₁ pos₂ h, (s.slice pos₁ pos₂ h).copy = pat.copy := by
simp [Model.isLongestMatchAt_iff, isLongestMatch_iff]
simp [Model.isLongestMatchAt_iff, isLongestMatch_iff h]
theorem isLongestMatchAtChain_iff {pat s : Slice} {pos₁ pos₂ : s.Pos} :
IsLongestMatchAtChain pat pos₁ pos₂
h n, (s.slice pos₁ pos₂ h).copy = String.join (List.replicate n pat.copy) := by
refine fun h => h.le, ?_, fun h, n, h' => ?_
· induction h with
| nil => simpa using 0, by simp
| cons p₁ p₂ p₃ h₁ h₂ ih =>
rw [isLongestMatchAt_iff] at h₁
obtain n, ih := ih
obtain h₀, h₁ := h₁
have : (s.slice p₁ p₃ (Std.le_trans h₀ h₂.le)).copy = (s.slice p₁ p₂ h₀).copy ++ (s.slice p₂ p₃ h₂.le).copy := by
simp [(Slice.Pos.slice p₂ _ _ h₀ h₂.le).splits.eq_append]
refine n + 1, ?_
rw [this, h₁, ih]
simp [ String.join_cons, List.replicate_succ]
· induction n generalizing pos₁ pos₂ with
| zero => simp_all
| succ n ih =>
rw [List.replicate_succ, String.join_cons] at h'
refine .cons _ (Pos.ofSlice (Pos.ofEqAppend h')) _ ?_ (ih ?_ Pos.ofSlice_le ?_)
· simpa [isLongestMatchAt_iff] using (Pos.splits_ofEqAppend h').copy_sliceTo_eq
· simpa [sliceFrom_slice (Pos.splits_ofEqAppend h').copy_sliceFrom_eq] using n, rfl
· simpa using (Pos.splits_ofEqAppend h').copy_sliceFrom_eq
theorem isLongestMatchAtChain_startPos_endPos_iff {pat s : Slice} :
IsLongestMatchAtChain pat s.startPos s.endPos
n, s.copy = String.join (List.replicate n pat.copy) := by
simp [isLongestMatchAtChain_iff]
theorem isLongestRevMatchAt_iff {pat s : Slice} {pos₁ pos₂ : s.Pos} :
IsLongestRevMatchAt pat pos₁ pos₂ h, (s.slice pos₁ pos₂ h).copy = pat.copy := by
simp [Model.isLongestRevMatchAt_iff, isLongestRevMatch_iff]
theorem isLongestRevMatchAtChain_iff {pat s : Slice} {pos₁ pos₂ : s.Pos} :
IsLongestRevMatchAtChain pat pos₁ pos₂
h n, (s.slice pos₁ pos₂ h).copy = String.join (List.replicate n pat.copy) := by
refine fun h => h.le, ?_, fun h, n, h' => ?_
· induction h with
| nil => simpa using 0, by simp
| cons p₂ p₃ h₁ h₂ ih =>
rw [isLongestRevMatchAt_iff] at h₂
obtain n, ih := ih
obtain h₀, h₂ := h₂
have : (s.slice pos₁ p₃ (Std.le_trans h₁.le h₀)).copy = (s.slice pos₁ p₂ h₁.le).copy ++ (s.slice p₂ p₃ h₀).copy := by
simp [(Slice.Pos.slice p₂ _ _ (IsLongestRevMatchAtChain.le _) h₀).splits.eq_append]
refine n + 1, ?_
rw [this, h₂, ih]
simp [ List.replicate_append_replicate]
· induction n generalizing pos₁ pos₂ with
| zero => simp_all
| succ n ih =>
have h'' : (s.slice pos₁ pos₂ h).copy = String.join (List.replicate n pat.copy) ++ pat.copy := by
rw [h', List.replicate_succ', String.join_append]; simp
refine .cons _ (Pos.ofSlice (Pos.ofEqAppend h'')) _ (ih ?_ Pos.le_ofSlice ?_) ?_
· simpa [sliceTo_slice (Pos.splits_ofEqAppend h'').copy_sliceTo_eq] using n, rfl
· simpa using (Pos.splits_ofEqAppend h'').copy_sliceTo_eq
· simpa [isLongestRevMatchAt_iff] using (Pos.splits_ofEqAppend h'').copy_sliceFrom_eq
theorem isLongestRevMatchAtChain_startPos_endPos_iff {pat s : Slice} :
IsLongestRevMatchAtChain pat s.startPos s.endPos
n, s.copy = String.join (List.replicate n pat.copy) := by
simp [isLongestRevMatchAtChain_iff]
theorem isLongestMatchAt_iff_splits {pat s : Slice} {pos₁ pos₂ : s.Pos} :
theorem isLongestMatchAt_iff_splits {pat s : Slice} {pos₁ pos₂ : s.Pos} (h : pat.isEmpty = false) :
IsLongestMatchAt pat pos₁ pos₂ t₁ t₂, pos₁.Splits t₁ (pat.copy ++ t₂)
pos₂.Splits (t₁ ++ pat.copy) t₂ := by
simp only [isLongestMatchAt_iff, copy_slice_eq_iff_splits]
theorem isLongestRevMatchAt_iff_splits {pat s : Slice} {pos₁ pos₂ : s.Pos} :
IsLongestRevMatchAt pat pos₁ pos₂ t₁ t₂, pos₁.Splits t₁ (pat.copy ++ t₂)
pos₂.Splits (t₁ ++ pat.copy) t₂ := by
simp only [isLongestRevMatchAt_iff, copy_slice_eq_iff_splits]
theorem isLongestMatch_iff_splits {pat s : Slice} {pos : s.Pos} :
IsLongestMatch pat pos t, pos.Splits pat.copy t := by
rw [isLongestMatch_iff, copy_sliceTo_eq_iff_exists_splits]
theorem isLongestRevMatch_iff_splits {pat s : Slice} {pos : s.Pos} :
IsLongestRevMatch pat pos t, pos.Splits t pat.copy := by
rw [isLongestRevMatch_iff, copy_sliceFrom_eq_iff_exists_splits]
simp only [isLongestMatchAt_iff h, copy_slice_eq_iff_splits]
theorem isLongestMatchAt_iff_extract {pat s : Slice} {pos₁ pos₂ : s.Pos} (h : pat.isEmpty = false) :
IsLongestMatchAt pat pos₁ pos₂
s.copy.toByteArray.extract pos₁.offset.byteIdx pos₂.offset.byteIdx = pat.copy.toByteArray := by
rw [isLongestMatchAt_iff]
refine fun h, h' => ?_, fun h' => ?_
· simp [ h', toByteArray_copy_slice]
· rw [ Slice.toByteArray_copy_ne_empty_iff, h', ne_eq, ByteArray.extract_eq_empty_iff] at h
exact by simp [Pos.le_iff, Pos.Raw.le_iff]; omega,
by simp [ h', toByteArray_inj, toByteArray_copy_slice]
theorem isLongestRevMatchAt_iff_extract {pat s : Slice} {pos₁ pos₂ : s.Pos}
(h : pat.isEmpty = false) :
IsLongestRevMatchAt pat pos₁ pos₂
s.copy.toByteArray.extract pos₁.offset.byteIdx pos₂.offset.byteIdx =
pat.copy.toByteArray := by
rw [isLongestRevMatchAt_iff]
rw [isLongestMatchAt_iff h]
refine fun h, h' => ?_, fun h' => ?_
· simp [ h', toByteArray_copy_slice]
· rw [ Slice.toByteArray_copy_ne_empty_iff, h', ne_eq, ByteArray.extract_eq_empty_iff] at h
@@ -167,32 +75,15 @@ theorem offset_of_isLongestMatchAt {pat s : Slice} {pos₁ pos₂ : s.Pos} (h :
suffices pos₂.offset.byteIdx s.utf8ByteSize by omega
simpa [Pos.le_iff, Pos.Raw.le_iff] using pos₂.le_endPos
theorem offset_of_isLongestRevMatchAt {pat s : Slice} {pos pos₂ : s.Pos}
(h : pat.isEmpty = false) (h' : IsLongestRevMatchAt pat pos₁ pos₂) :
pos₂.offset = pos₁.offset.increaseBy pat.utf8ByteSize := by
simp only [Pos.Raw.ext_iff, Pos.Raw.byteIdx_increaseBy]
rw [isLongestRevMatchAt_iff_extract h] at h'
rw [ Slice.toByteArray_copy_ne_empty_iff, h', ne_eq, ByteArray.extract_eq_empty_iff] at h
replace h' := congrArg ByteArray.size h'
simp only [ByteArray.size_extract, size_toByteArray, utf8ByteSize_copy] at h'
suffices pos₂.offset.byteIdx s.utf8ByteSize by omega
simpa [Pos.le_iff, Pos.Raw.le_iff] using pos₂.le_endPos
theorem matchesAt_iff_splits {pat s : Slice} {pos : s.Pos} :
theorem matchesAt_iff_splits {pat s : Slice} {pos : s.Pos} (h : pat.isEmpty = false) :
MatchesAt pat pos t₁ t₂, pos.Splits t₁ (pat.copy ++ t₂) := by
simp only [matchesAt_iff_exists_isLongestMatchAt, isLongestMatchAt_iff_splits]
simp only [matchesAt_iff_exists_isLongestMatchAt, isLongestMatchAt_iff_splits h]
exact fun e, t₁, t₂, ht₁, ht₂ => t₁, t₂, ht₁,
fun t₁, t₂, ht => ht.rotateRight, t₁, t₂, ht, ht.splits_rotateRight
theorem revMatchesAt_iff_splits {pat s : Slice} {pos : s.Pos} :
RevMatchesAt pat pos t₁ t₂, pos.Splits (t₁ ++ pat.copy) t₂ := by
simp only [revMatchesAt_iff_exists_isLongestRevMatchAt, isLongestRevMatchAt_iff_splits]
exact fun e, t₁, t₂, ht₁, ht₂ => t₁, t₂, ht₂,
fun t₁, t₂, ht => ht.rotateLeft, t₁, t₂, ht.splits_rotateLeft, ht
theorem exists_matchesAt_iff_eq_append {pat s : Slice} :
theorem exists_matchesAt_iff_eq_append {pat s : Slice} (h : pat.isEmpty = false) :
( (pos : s.Pos), MatchesAt pat pos) t₁ t₂, s.copy = t₁ ++ pat.copy ++ t₂ := by
simp only [matchesAt_iff_splits]
simp only [matchesAt_iff_splits h]
constructor
· rintro pos, t₁, t₂, hsplit
exact t₁, t₂, by rw [hsplit.eq_append, append_assoc]
@@ -202,18 +93,6 @@ theorem exists_matchesAt_iff_eq_append {pat s : Slice} :
t₁, pat.copy ++ t₂, by rw [ append_assoc]; exact heq, rfl
exact s.pos _ hvalid, t₁, t₂, by rw [ append_assoc]; exact heq, by simp
theorem exists_revMatchesAt_iff_eq_append {pat s : Slice} :
( (pos : s.Pos), RevMatchesAt pat pos) t₁ t₂, s.copy = t₁ ++ pat.copy ++ t₂ := by
simp only [revMatchesAt_iff_splits]
constructor
· rintro pos, t₁, t₂, hsplit
exact t₁, t₂, by rw [hsplit.eq_append, append_assoc]
· rintro t₁, t₂, heq
have hvalid : (t₁ ++ pat.copy).rawEndPos.IsValidForSlice s :=
Pos.Raw.isValidForSlice_iff_exists_append.mpr
t₁ ++ pat.copy, t₂, heq, rfl
exact s.pos _ hvalid, t₁, t₂, heq, by simp
theorem matchesAt_iff_isLongestMatchAt {pat s : Slice} {pos : s.Pos} (h : pat.isEmpty = false) :
MatchesAt pat pos (h : (pos.offset.increaseBy pat.utf8ByteSize).IsValidForSlice s),
IsLongestMatchAt pat pos (s.pos _ h) := by
@@ -223,25 +102,6 @@ theorem matchesAt_iff_isLongestMatchAt {pat s : Slice} {pos : s.Pos} (h : pat.is
obtain rfl : p = s.pos _ this := by simpa [Pos.ext_iff] using offset_of_isLongestMatchAt h h'
exact h'
theorem revMatchesAt_iff_isLongestRevMatchAt {pat s : Slice} {pos : s.Pos}
(h : pat.isEmpty = false) :
RevMatchesAt pat pos
(h : (pos.offset.decreaseBy pat.utf8ByteSize).IsValidForSlice s),
IsLongestRevMatchAt pat (s.pos _ h) pos := by
refine fun p, h' => ?_, fun _, h => _, h
have hoff := offset_of_isLongestRevMatchAt h h'
have hvalid : (pos.offset.decreaseBy pat.utf8ByteSize).IsValidForSlice s := by
rw [show pos.offset.decreaseBy pat.utf8ByteSize = p.offset from by
simp [Pos.Raw.ext_iff, Pos.Raw.byteIdx_decreaseBy, Pos.Raw.byteIdx_increaseBy] at hoff
omega]
exact p.isValidForSlice
refine hvalid, ?_
obtain rfl : p = s.pos _ hvalid := by
simp only [Pos.ext_iff, offset_pos]
simp [Pos.Raw.ext_iff, Pos.Raw.byteIdx_decreaseBy, Pos.Raw.byteIdx_increaseBy] at hoff
omega
exact h'
theorem matchesAt_iff_getElem {pat s : Slice} {pos : s.Pos} (h : pat.isEmpty = false) :
MatchesAt pat pos
(h : pos.offset.byteIdx + pat.copy.toByteArray.size s.copy.toByteArray.size),
@@ -280,194 +140,81 @@ end ForwardSliceSearcher
namespace ForwardStringSearcher
instance {pat : String} : PatternModel pat where
Matches s := s = pat
instance {pat : String} : ForwardPatternModel pat where
Matches s := s "" s = pat
not_matches_empty := by simp
theorem strictPatternModel {pat : String} (h : pat "") : StrictPatternModel pat where
not_matches_empty := by simpa [PatternModel.Matches]
instance {pat : String} : NoPrefixPatternModel pat :=
.of_length_eq (by simp +contextual [PatternModel.Matches])
instance {pat : String} : NoSuffixPatternModel pat :=
.of_length_eq (by simp +contextual [PatternModel.Matches])
instance {pat : String} : NoPrefixForwardPatternModel pat :=
.of_length_eq (by simp +contextual [ForwardPatternModel.Matches])
theorem isMatch_iff_slice {pat : String} {s : Slice} {pos : s.Pos} :
IsMatch (ρ := String) pat pos IsMatch (ρ := Slice) pat.toSlice pos := by
simp only [Model.isMatch_iff, PatternModel.Matches, copy_toSlice]
theorem isRevMatch_iff_slice {pat : String} {s : Slice} {pos : s.Pos} :
IsRevMatch (ρ := String) pat pos IsRevMatch (ρ := Slice) pat.toSlice pos := by
simp only [Model.isRevMatch_iff, PatternModel.Matches, copy_toSlice]
simp only [Model.isMatch_iff, ForwardPatternModel.Matches, copy_toSlice]
theorem isLongestMatch_iff_isLongestMatch_toSlice {pat : String} {s : Slice} {pos : s.Pos} :
IsLongestMatch (ρ := String) pat pos IsLongestMatch (ρ := Slice) pat.toSlice pos where
mp h := isMatch_iff_slice.1 h.isMatch, fun p hp hm => h.not_isMatch p hp (isMatch_iff_slice.2 hm)
mpr h := isMatch_iff_slice.2 h.isMatch, fun p hp hm => h.not_isMatch p hp (isMatch_iff_slice.1 hm)
theorem isLongestRevMatch_iff_isLongestRevMatch_toSlice {pat : String} {s : Slice} {pos : s.Pos} :
IsLongestRevMatch (ρ := String) pat pos IsLongestRevMatch (ρ := Slice) pat.toSlice pos where
mp h := isRevMatch_iff_slice.1 h.isRevMatch,
fun p hp hm => h.not_isRevMatch p hp (isRevMatch_iff_slice.2 hm)
mpr h := isRevMatch_iff_slice.2 h.isRevMatch,
fun p hp hm => h.not_isRevMatch p hp (isRevMatch_iff_slice.1 hm)
theorem isLongestMatchAt_iff_isLongestMatchAt_toSlice {pat : String} {s : Slice} {pos₁ pos₂ : s.Pos} :
IsLongestMatchAt (ρ := String) pat pos₁ pos₂
IsLongestMatchAt (ρ := Slice) pat.toSlice pos₁ pos₂ := by
simp [Model.isLongestMatchAt_iff, isLongestMatch_iff_isLongestMatch_toSlice]
theorem isLongestMatchAtChain_iff_isLongestMatchAtChain_toSlice {pat : String} {s : Slice} {pos₁ pos₂ : s.Pos} :
IsLongestMatchAtChain pat pos₁ pos₂
IsLongestMatchAtChain pat.toSlice pos₁ pos₂ := by
refine fun h => ?_, fun h => ?_
· induction h with
| nil => simp
| cons p₁ p₂ p₃ h₁ h₂ ih =>
exact .cons _ _ _ (isLongestMatchAt_iff_isLongestMatchAt_toSlice.1 h₁) ih
· induction h with
| nil => simp
| cons p₁ p₂ p₃ h₁ h₂ ih =>
exact .cons _ _ _ (isLongestMatchAt_iff_isLongestMatchAt_toSlice.2 h₁) ih
theorem isLongestMatchAtChain_iff {pat : String} {s : Slice} {pos₁ pos₂ : s.Pos} :
IsLongestMatchAtChain pat pos₁ pos₂
h n, (s.slice pos₁ pos₂ h).copy = String.join (List.replicate n pat) := by
simp [isLongestMatchAtChain_iff_isLongestMatchAtChain_toSlice,
ForwardSliceSearcher.isLongestMatchAtChain_iff]
theorem isLongestMatchAtChain_startPos_endPos_iff {pat : String} {s : Slice} :
IsLongestMatchAtChain pat s.startPos s.endPos
n, s.copy = String.join (List.replicate n pat) := by
simp [isLongestMatchAtChain_iff]
theorem isLongestRevMatchAt_iff_isLongestRevMatchAt_toSlice {pat : String} {s : Slice}
{pos₁ pos₂ : s.Pos} :
IsLongestRevMatchAt (ρ := String) pat pos₁ pos₂
IsLongestRevMatchAt (ρ := Slice) pat.toSlice pos₁ pos₂ := by
simp [Model.isLongestRevMatchAt_iff, isLongestRevMatch_iff_isLongestRevMatch_toSlice]
theorem isLongestRevMatchAtChain_iff_isLongestRevMatchAtChain_toSlice {pat : String} {s : Slice} {pos₁ pos₂ : s.Pos} :
IsLongestRevMatchAtChain pat pos₁ pos₂
IsLongestRevMatchAtChain pat.toSlice pos₁ pos₂ := by
refine fun h => ?_, fun h => ?_
· induction h with
| nil => simp
| cons p₂ p₃ _ hmatch ih =>
exact .cons _ _ _ ih (isLongestRevMatchAt_iff_isLongestRevMatchAt_toSlice.1 hmatch)
· induction h with
| nil => simp
| cons p₂ p₃ _ hmatch ih =>
exact .cons _ _ _ ih (isLongestRevMatchAt_iff_isLongestRevMatchAt_toSlice.2 hmatch)
theorem isLongestRevMatchAtChain_iff {pat : String} {s : Slice} {pos₁ pos₂ : s.Pos} :
IsLongestRevMatchAtChain pat pos₁ pos₂
h n, (s.slice pos₁ pos₂ h).copy = String.join (List.replicate n pat) := by
simp [isLongestRevMatchAtChain_iff_isLongestRevMatchAtChain_toSlice,
ForwardSliceSearcher.isLongestRevMatchAtChain_iff]
theorem isLongestRevMatchAtChain_startPos_endPos_iff {pat : String} {s : Slice} :
IsLongestRevMatchAtChain pat s.startPos s.endPos
n, s.copy = String.join (List.replicate n pat) := by
simp [isLongestRevMatchAtChain_iff]
theorem matchesAt_iff_toSlice {pat : String} {s : Slice} {pos : s.Pos} :
MatchesAt (ρ := String) pat pos MatchesAt (ρ := Slice) pat.toSlice pos := by
simp [matchesAt_iff_exists_isLongestMatchAt, isLongestMatchAt_iff_isLongestMatchAt_toSlice]
theorem revMatchesAt_iff_toSlice {pat : String} {s : Slice} {pos : s.Pos} :
RevMatchesAt (ρ := String) pat pos RevMatchesAt (ρ := Slice) pat.toSlice pos := by
simp [revMatchesAt_iff_exists_isLongestRevMatchAt,
isLongestRevMatchAt_iff_isLongestRevMatchAt_toSlice]
private theorem toSlice_isEmpty (h : pat "") : pat.toSlice.isEmpty = false := by
rwa [isEmpty_toSlice, isEmpty_eq_false_iff]
theorem isMatch_iff {pat : String} {s : Slice} {pos : s.Pos} :
theorem isMatch_iff {pat : String} {s : Slice} {pos : s.Pos} (h : pat "") :
IsMatch pat pos (s.sliceTo pos).copy = pat := by
rw [isMatch_iff_slice, ForwardSliceSearcher.isMatch_iff]
rw [isMatch_iff_slice, ForwardSliceSearcher.isMatch_iff (toSlice_isEmpty h)]
simp
theorem isRevMatch_iff {pat : String} {s : Slice} {pos : s.Pos} :
IsRevMatch pat pos (s.sliceFrom pos).copy = pat := by
rw [isRevMatch_iff_slice, ForwardSliceSearcher.isRevMatch_iff]
simp
theorem isLongestMatch_iff {pat : String} {s : Slice} {pos : s.Pos} :
theorem isLongestMatch_iff {pat : String} {s : Slice} {pos : s.Pos} (h : pat "") :
IsLongestMatch pat pos (s.sliceTo pos).copy = pat := by
rw [isLongestMatch_iff_isMatch, isMatch_iff]
rw [isLongestMatch_iff_isMatch, isMatch_iff h]
theorem isLongestRevMatch_iff {pat : String} {s : Slice} {pos : s.Pos} :
IsLongestRevMatch pat pos (s.sliceFrom pos).copy = pat := by
rw [isLongestRevMatch_iff_isRevMatch, isRevMatch_iff]
theorem isLongestMatchAt_iff {pat : String} {s : Slice} {pos₁ pos₂ : s.Pos} :
theorem isLongestMatchAt_iff {pat : String} {s : Slice} {pos pos₂ : s.Pos} (h : pat "") :
IsLongestMatchAt pat pos₁ pos₂ h, (s.slice pos₁ pos₂ h).copy = pat := by
rw [isLongestMatchAt_iff_isLongestMatchAt_toSlice,
ForwardSliceSearcher.isLongestMatchAt_iff]
ForwardSliceSearcher.isLongestMatchAt_iff (toSlice_isEmpty h)]
simp
theorem isLongestRevMatchAt_iff {pat : String} {s : Slice} {pos₁ pos₂ : s.Pos} :
IsLongestRevMatchAt pat pos₁ pos₂ h, (s.slice pos₁ pos₂ h).copy = pat := by
rw [isLongestRevMatchAt_iff_isLongestRevMatchAt_toSlice,
ForwardSliceSearcher.isLongestRevMatchAt_iff]
simp
theorem isLongestMatchAt_iff_splits {pat : String} {s : Slice} {pos₁ pos₂ : s.Pos} :
IsLongestMatchAt pat pos₁ pos₂
t₁ t₂, pos₁.Splits t₁ (pat ++ t₂) pos₂.Splits (t₁ ++ pat) t₂ := by
rw [isLongestMatchAt_iff_isLongestMatchAt_toSlice,
ForwardSliceSearcher.isLongestMatchAt_iff_splits]
simp
theorem isLongestRevMatchAt_iff_splits {pat : String} {s : Slice} {pos₁ pos₂ : s.Pos} :
IsLongestRevMatchAt pat pos₁ pos₂
t₁ t₂, pos₁.Splits t₁ (pat ++ t₂) pos₂.Splits (t₁ ++ pat) t₂ := by
rw [isLongestRevMatchAt_iff_isLongestRevMatchAt_toSlice,
ForwardSliceSearcher.isLongestRevMatchAt_iff_splits]
simp
theorem isLongestMatchAt_iff_extract {pat : String} {s : Slice} {pos₁ pos₂ : s.Pos} (h : pat "") :
IsLongestMatchAt pat pos₁ pos₂
s.copy.toByteArray.extract pos₁.offset.byteIdx pos₂.offset.byteIdx = pat.toByteArray := by
rw [isLongestMatchAt_iff_isLongestMatchAt_toSlice,
ForwardSliceSearcher.isLongestMatchAt_iff_extract (by simpa)]
simp
theorem isLongestRevMatchAt_iff_extract {pat : String} {s : Slice} {pos₁ pos₂ : s.Pos}
theorem isLongestMatchAt_iff_splits {pat : String} {s : Slice} {pos₁ pos₂ : s.Pos}
(h : pat "") :
IsLongestRevMatchAt pat pos₁ pos₂
IsLongestMatchAt pat pos₁ pos₂
t₁ t₂, pos₁.Splits t₁ (pat ++ t₂) pos₂.Splits (t₁ ++ pat) t₂ := by
rw [isLongestMatchAt_iff_isLongestMatchAt_toSlice,
ForwardSliceSearcher.isLongestMatchAt_iff_splits (toSlice_isEmpty h)]
simp
theorem isLongestMatchAt_iff_extract {pat : String} {s : Slice} {pos₁ pos₂ : s.Pos}
(h : pat "") :
IsLongestMatchAt pat pos₁ pos₂
s.copy.toByteArray.extract pos₁.offset.byteIdx pos₂.offset.byteIdx = pat.toByteArray := by
rw [isLongestRevMatchAt_iff_isLongestRevMatchAt_toSlice,
ForwardSliceSearcher.isLongestRevMatchAt_iff_extract (by simpa)]
rw [isLongestMatchAt_iff_isLongestMatchAt_toSlice,
ForwardSliceSearcher.isLongestMatchAt_iff_extract (toSlice_isEmpty h)]
simp
theorem offset_of_isLongestMatchAt {pat : String} {s : Slice} {pos₁ pos₂ : s.Pos}
(h : pat "") (h' : IsLongestMatchAt pat pos₁ pos₂) :
pos₂.offset = pos₁.offset.increaseBy pat.utf8ByteSize := by
rw [show pat.utf8ByteSize = pat.toSlice.utf8ByteSize from utf8ByteSize_toSlice.symm]
exact ForwardSliceSearcher.offset_of_isLongestMatchAt (by simpa)
exact ForwardSliceSearcher.offset_of_isLongestMatchAt (toSlice_isEmpty h)
(isLongestMatchAt_iff_isLongestMatchAt_toSlice.1 h')
theorem offset_of_isLongestRevMatchAt {pat : String} {s : Slice} {pos pos₂ : s.Pos}
(h : pat "") (h' : IsLongestRevMatchAt pat pos₁ pos₂) :
pos₂.offset = pos₁.offset.increaseBy pat.utf8ByteSize := by
rw [show pat.utf8ByteSize = pat.toSlice.utf8ByteSize from utf8ByteSize_toSlice.symm]
exact ForwardSliceSearcher.offset_of_isLongestRevMatchAt (by simpa)
(isLongestRevMatchAt_iff_isLongestRevMatchAt_toSlice.1 h')
theorem matchesAt_iff_splits {pat : String} {s : Slice} {pos : s.Pos} :
theorem matchesAt_iff_splits {pat : String} {s : Slice} {pos : s.Pos} (h : pat "") :
MatchesAt pat pos t₁ t₂, pos.Splits t₁ (pat ++ t₂) := by
rw [matchesAt_iff_toSlice,
ForwardSliceSearcher.matchesAt_iff_splits]
ForwardSliceSearcher.matchesAt_iff_splits (toSlice_isEmpty h)]
simp
theorem revMatchesAt_iff_splits {pat : String} {s : Slice} {pos : s.Pos} :
RevMatchesAt pat pos t₁ t₂, pos.Splits (t₁ ++ pat) t₂ := by
rw [revMatchesAt_iff_toSlice,
ForwardSliceSearcher.revMatchesAt_iff_splits]
simp
theorem exists_matchesAt_iff_eq_append {pat : String} {s : Slice} :
theorem exists_matchesAt_iff_eq_append {pat : String} {s : Slice} (h : pat "") :
( (pos : s.Pos), MatchesAt pat pos) t₁ t₂, s.copy = t₁ ++ pat ++ t₂ := by
simp only [matchesAt_iff_splits]
simp only [matchesAt_iff_splits h]
constructor
· rintro pos, t₁, t₂, hsplit
exact t₁, t₂, by rw [hsplit.eq_append, append_assoc]
@@ -477,58 +224,35 @@ theorem exists_matchesAt_iff_eq_append {pat : String} {s : Slice} :
t₁, pat ++ t₂, by rw [ append_assoc]; exact heq, rfl
exact s.pos _ hvalid, t₁, t₂, by rw [ append_assoc]; exact heq, by simp
theorem exists_revMatchesAt_iff_eq_append {pat : String} {s : Slice} :
( (pos : s.Pos), RevMatchesAt pat pos) t₁ t₂, s.copy = t₁ ++ pat ++ t₂ := by
rw [show ( (pos : s.Pos), RevMatchesAt (ρ := String) pat pos)
( (pos : s.Pos), RevMatchesAt (ρ := Slice) pat.toSlice pos) from by
simp [revMatchesAt_iff_toSlice],
ForwardSliceSearcher.exists_revMatchesAt_iff_eq_append]
simp
theorem matchesAt_iff_isLongestMatchAt {pat : String} {s : Slice} {pos : s.Pos}
(h : pat "") :
MatchesAt pat pos (h : (pos.offset.increaseBy pat.utf8ByteSize).IsValidForSlice s),
IsLongestMatchAt pat pos (s.pos _ h) := by
have key := ForwardSliceSearcher.matchesAt_iff_isLongestMatchAt (pat := pat.toSlice)
(by simpa) (pos := pos)
(toSlice_isEmpty h) (pos := pos)
simp only [utf8ByteSize_toSlice, isLongestMatchAt_iff_isLongestMatchAt_toSlice] at key
rwa [matchesAt_iff_toSlice]
theorem revMatchesAt_iff_isLongestRevMatchAt {pat : String} {s : Slice} {pos : s.Pos}
(h : pat "") :
RevMatchesAt pat pos
(h : (pos.offset.decreaseBy pat.utf8ByteSize).IsValidForSlice s),
IsLongestRevMatchAt pat (s.pos _ h) pos := by
have key := ForwardSliceSearcher.revMatchesAt_iff_isLongestRevMatchAt (pat := pat.toSlice)
(by simpa) (pos := pos)
simp only [utf8ByteSize_toSlice, isLongestRevMatchAt_iff_isLongestRevMatchAt_toSlice] at key
rwa [revMatchesAt_iff_toSlice]
theorem matchesAt_iff_getElem {pat : String} {s : Slice} {pos : s.Pos} (h : pat "") :
MatchesAt pat pos
(h : pos.offset.byteIdx + pat.toByteArray.size s.copy.toByteArray.size),
(j), (hj : j < pat.toByteArray.size)
pat.toByteArray[j] = s.copy.toByteArray[pos.offset.byteIdx + j] := by
have key := ForwardSliceSearcher.matchesAt_iff_getElem (pat := pat.toSlice)
(by simpa) (pos := pos)
(toSlice_isEmpty h) (pos := pos)
simp only [copy_toSlice] at key
rwa [matchesAt_iff_toSlice]
theorem le_of_matchesAt {pat : String} {s : Slice} {pos : s.Pos} (h : pat "")
(h' : MatchesAt pat pos) : pos.offset.increaseBy pat.utf8ByteSize s.rawEndPos := by
rw [show pat.utf8ByteSize = pat.toSlice.utf8ByteSize from utf8ByteSize_toSlice.symm]
exact ForwardSliceSearcher.le_of_matchesAt (by simpa)
exact ForwardSliceSearcher.le_of_matchesAt (toSlice_isEmpty h)
(matchesAt_iff_toSlice.1 h')
theorem matchesAt_iff_matchesAt_toSlice {pat : String} {s : Slice}
{pos : s.Pos} : MatchesAt pat pos MatchesAt pat.toSlice pos := by
simp [matchesAt_iff_exists_isLongestMatchAt, isLongestMatchAt_iff_isLongestMatchAt_toSlice]
theorem revMatchesAt_iff_revMatchesAt_toSlice {pat : String} {s : Slice}
{pos : s.Pos} : RevMatchesAt pat pos RevMatchesAt pat.toSlice pos := by
simp [revMatchesAt_iff_exists_isLongestRevMatchAt,
isLongestRevMatchAt_iff_isLongestRevMatchAt_toSlice]
theorem toSearcher_eq {pat : String} {s : Slice} :
ToForwardSearcher.toSearcher pat s = ToForwardSearcher.toSearcher pat.toSlice s := (rfl)
@@ -545,21 +269,6 @@ theorem isValidSearchFrom_iff_isValidSearchFrom_toSlice {pat : String}
| matched => simp_all [IsValidSearchFrom.matched, isLongestMatchAt_iff_isLongestMatchAt_toSlice]
| mismatched => simp_all [IsValidSearchFrom.mismatched, matchesAt_iff_matchesAt_toSlice]
theorem isValidRevSearchFrom_iff_isValidRevSearchFrom_toSlice {pat : String}
{s : Slice} {pos : s.Pos} {l : List (SearchStep s)} :
IsValidRevSearchFrom pat pos l IsValidRevSearchFrom pat.toSlice pos l := by
refine fun h => ?_, fun h => ?_
· induction h with
| startPos => simpa using IsValidRevSearchFrom.startPos
| matched => simp_all [IsValidRevSearchFrom.matched,
isLongestRevMatchAt_iff_isLongestRevMatchAt_toSlice]
| mismatched => simp_all [IsValidRevSearchFrom.mismatched, revMatchesAt_iff_revMatchesAt_toSlice]
· induction h with
| startPos => simpa using IsValidRevSearchFrom.startPos
| matched => simp_all [IsValidRevSearchFrom.matched,
isLongestRevMatchAt_iff_isLongestRevMatchAt_toSlice]
| mismatched => simp_all [IsValidRevSearchFrom.mismatched, revMatchesAt_iff_revMatchesAt_toSlice]
end ForwardStringSearcher
end String.Slice.Pattern.Model

View File

@@ -39,9 +39,9 @@ theorem startsWith_iff {pat s : Slice} : startsWith pat s ↔ ∃ t, s.copy = pa
· rintro t, rfl
simp [-size_toByteArray, ByteArray.extract_append]
theorem skipPrefix?_eq_some_iff {pat s : Slice} {pos : s.Pos} :
skipPrefix? pat s = some pos (s.sliceTo pos).copy = pat.copy := by
fun_cases skipPrefix? with
theorem dropPrefix?_eq_some_iff {pat s : Slice} {pos : s.Pos} :
dropPrefix? pat s = some pos (s.sliceTo pos).copy = pat.copy := by
fun_cases dropPrefix? with
| case1 h =>
simp only [offset_startPos, Pos.Raw.offsetBy_zero, Option.some.injEq]
obtain t, ht := startsWith_iff.1 h
@@ -56,19 +56,10 @@ theorem skipPrefix?_eq_some_iff {pat s : Slice} {pos : s.Pos} :
simp only [reduceCtorEq, false_iff]
intro heq
have := h (s.sliceFrom pos).copy
simp [ heq, -sliceTo_append_sliceFrom, pos.splits.eq_append] at this
simp [ heq, pos.splits.eq_append] at this
theorem isSome_skipPrefix? {pat s : Slice} : (skipPrefix? pat s).isSome = startsWith pat s := by
fun_cases skipPrefix? <;> simp_all
public theorem startsWith_of_isEmpty {pat s : Slice} (hpat : pat.isEmpty = true) :
ForwardPattern.startsWith pat s = true := by
suffices pat.copy = "" by simp [ForwardPattern.startsWith, startsWith_iff, this]
simpa
public theorem skipPrefix?_of_isEmpty {pat s : Slice} (hpat : pat.isEmpty = true) :
ForwardPattern.skipPrefix? pat s = some s.startPos := by
simpa [ForwardPattern.skipPrefix?, skipPrefix?_eq_some_iff]
theorem isSome_dropPrefix? {pat s : Slice} : (dropPrefix? pat s).isSome = startsWith pat s := by
fun_cases dropPrefix? <;> simp_all
end ForwardSliceSearcher
@@ -76,11 +67,12 @@ namespace Model.ForwardSliceSearcher
open Pattern.ForwardSliceSearcher
public instance {pat : Slice} : LawfulForwardPatternModel pat where
skipPrefixOfNonempty?_eq _ := rfl
startsWith_eq _ := isSome_skipPrefix?.symm
skipPrefix?_eq_some_iff pos := by
simp [ForwardPattern.skipPrefix?, skipPrefix?_eq_some_iff, isLongestMatch_iff]
public theorem lawfulForwardPatternModel {pat : Slice} (hpat : pat.isEmpty = false) :
LawfulForwardPatternModel pat where
dropPrefixOfNonempty?_eq h := rfl
startsWith_eq s := isSome_dropPrefix?.symm
dropPrefix?_eq_some_iff pos := by
simp [ForwardPattern.dropPrefix?, dropPrefix?_eq_some_iff, isLongestMatch_iff hpat]
end Model.ForwardSliceSearcher
@@ -88,107 +80,15 @@ namespace Model.ForwardStringSearcher
open Pattern.ForwardSliceSearcher
public instance {pat : String} : LawfulForwardPatternModel pat where
skipPrefixOfNonempty?_eq _ := rfl
startsWith_eq _ := isSome_skipPrefix?.symm
skipPrefix?_eq_some_iff pos := by
simp [ForwardPattern.skipPrefix?, skipPrefix?_eq_some_iff, isLongestMatch_iff]
public theorem lawfulForwardPatternModel {pat : String} (hpat : pat "") :
LawfulForwardPatternModel pat where
dropPrefixOfNonempty?_eq h := rfl
startsWith_eq s := isSome_dropPrefix?.symm
dropPrefix?_eq_some_iff pos := by
simp [ForwardPattern.dropPrefix?, dropPrefix?_eq_some_iff, isLongestMatch_iff hpat]
end Model.ForwardStringSearcher
namespace BackwardSliceSearcher
theorem endsWith_iff {pat s : Slice} : endsWith pat s t, s.copy = t ++ pat.copy := by
rw [endsWith]
simp [Internal.memcmpSlice_eq_true_iff, utf8ByteSize_eq_size_toByteArray_copy, -size_toByteArray]
generalize pat.copy = pat
generalize s.copy = s
refine fun h₁, h₂ => ?_, ?_
· rw [Nat.sub_add_cancel h₁] at h₂
suffices (s.rawEndPos.unoffsetBy pat.rawEndPos).IsValid s by
have h₃ : (s.sliceFrom (s.pos _ this)).copy = pat := by
rw [ toByteArray_inj, (s.pos _ this).splits.toByteArray_right_eq]
simpa [offset_pos, Pos.Raw.byteIdx_unoffsetBy, byteIdx_rawEndPos]
have := (s.pos _ this).splits
rw [h₃] at this
exact _, this.eq_append
rw [Pos.Raw.isValid_iff_isValidUTF8_extract_utf8ByteSize]
refine by simp [Pos.Raw.le_iff, Pos.Raw.byteIdx_unoffsetBy], ?_
simp only [size_toByteArray] at h₂
simpa [Pos.Raw.byteIdx_unoffsetBy, byteIdx_rawEndPos, h₂] using pat.isValidUTF8
· rintro t, rfl
exact by simp, by rw [Nat.sub_add_cancel (by simp)]; exact
ByteArray.extract_append_eq_right (by simp) (by simp)
theorem skipSuffix?_eq_some_iff {pat s : Slice} {pos : s.Pos} :
skipSuffix? pat s = some pos (s.sliceFrom pos).copy = pat.copy := by
fun_cases skipSuffix? with
| case1 h =>
simp only [Option.some.injEq]
obtain t, ht := endsWith_iff.1 h
have hpc : pat.copy.utf8ByteSize = pat.utf8ByteSize := Slice.utf8ByteSize_copy
have hsz : s.utf8ByteSize = t.utf8ByteSize + pat.utf8ByteSize := by
have := congrArg String.utf8ByteSize ht
simp only [utf8ByteSize_append, Slice.utf8ByteSize_copy] at this
exact this
have hoff : (s.endPos.offset.unoffsetBy pat.rawEndPos) = t.rawEndPos := by
ext
simp only [offset_endPos, Pos.Raw.byteIdx_unoffsetBy, byteIdx_rawEndPos,
String.byteIdx_rawEndPos]
omega
have hval : (s.endPos.offset.unoffsetBy pat.rawEndPos).IsValidForSlice s :=
Pos.Raw.isValidForSlice_iff_exists_append.mpr t, pat.copy, ht, hoff
have hsp : (s.pos _ hval).Splits t pat.copy := ht, hoff
rw [Slice.pos!_eq_pos hval]
exact (· hsp.copy_sliceFrom_eq),
fun h => hsp.pos_eq_of_eq_right (h pos.splits)
| case2 h =>
simp only [endsWith_iff, not_exists] at h
simp only [reduceCtorEq, false_iff]
intro heq
have := h (s.sliceTo pos).copy
simp [ heq, -sliceTo_append_sliceFrom, pos.splits.eq_append] at this
theorem isSome_skipSuffix? {pat s : Slice} : (skipSuffix? pat s).isSome = endsWith pat s := by
fun_cases skipSuffix? <;> simp_all
public theorem endsWith_of_isEmpty {pat s : Slice} (hpat : pat.isEmpty = true) :
BackwardPattern.endsWith pat s = true := by
suffices pat.copy = "" by simp [BackwardPattern.endsWith, endsWith_iff, this]
simpa
public theorem skipSuffix?_of_isEmpty {pat s : Slice} (hpat : pat.isEmpty = true) :
BackwardPattern.skipSuffix? pat s = some s.endPos := by
simpa [BackwardPattern.skipSuffix?, skipSuffix?_eq_some_iff]
end BackwardSliceSearcher
namespace Model.BackwardSliceSearcher
open Pattern.BackwardSliceSearcher
public instance {pat : Slice} : LawfulBackwardPatternModel pat where
skipSuffixOfNonempty?_eq _ := rfl
endsWith_eq _ := isSome_skipSuffix?.symm
skipSuffix?_eq_some_iff pos := by
simp [BackwardPattern.skipSuffix?, skipSuffix?_eq_some_iff,
ForwardSliceSearcher.isLongestRevMatch_iff]
end Model.BackwardSliceSearcher
namespace Model.BackwardStringSearcher
open Pattern.BackwardSliceSearcher
public instance {pat : String} : LawfulBackwardPatternModel pat where
skipSuffixOfNonempty?_eq _ := rfl
endsWith_eq _ := isSome_skipSuffix?.symm
skipSuffix?_eq_some_iff pos := by
simp [BackwardPattern.skipSuffix?, skipSuffix?_eq_some_iff,
ForwardStringSearcher.isLongestRevMatch_iff]
end Model.BackwardStringSearcher
end Pattern
public theorem startsWith_string_eq_startsWith_toSlice {pat : String} {s : Slice} :
@@ -200,93 +100,93 @@ public theorem dropPrefix?_string_eq_dropPrefix?_toSlice {pat : String} {s : Sli
public theorem dropPrefix_string_eq_dropPrefix_toSlice {pat : String} {s : Slice} :
s.dropPrefix pat = s.dropPrefix pat.toSlice := (rfl)
public theorem skipPrefix?_string_eq_skipPrefix?_toSlice {pat : String} {s : Slice} :
s.skipPrefix? pat = s.skipPrefix? pat.toSlice := (rfl)
public theorem Pattern.ForwardPattern.skipPrefix?_string_eq_skipPrefix?_toSlice
public theorem Pattern.ForwardPattern.dropPrefix?_string_eq_dropPrefix?_toSlice
{pat : String} {s : Slice} :
skipPrefix? pat s = skipPrefix? pat.toSlice s := (rfl)
dropPrefix? pat s = dropPrefix? pat.toSlice s := (rfl)
public theorem Pos.skip?_string_eq_skip?_toSlice {pat : String} {s : Slice} {pos : s.Pos} :
pos.skip? pat = pos.skip? pat.toSlice := (rfl)
public theorem Pos.skipWhile_string_eq_skipWhile_toSlice {pat : String} {s : Slice}
(curr : s.Pos) :
Pos.skipWhile curr pat = Pos.skipWhile curr pat.toSlice := by
fun_induction Pos.skipWhile curr pat with
private theorem dropWhileGo_string_eq {pat : String} {s : Slice} (curr : s.Pos) :
dropWhile.go s pat curr = dropWhile.go s pat.toSlice curr := by
fun_induction dropWhile.go s pat curr with
| case1 pos nextCurr h₁ h₂ ih =>
conv => rhs; rw [Pos.skipWhile]
simp [ Pos.skip?_string_eq_skip?_toSlice, h₁, h₂, ih]
conv => rhs; rw [dropWhile.go]
simp [ Pattern.ForwardPattern.dropPrefix?_string_eq_dropPrefix?_toSlice, h₁, h₂, ih]
| case2 pos nextCurr h ih =>
conv => rhs; rw [Pos.skipWhile]
simp [ Pos.skip?_string_eq_skip?_toSlice, h, ih]
conv => rhs; rw [dropWhile.go]
simp [ Pattern.ForwardPattern.dropPrefix?_string_eq_dropPrefix?_toSlice, h, ih]
| case3 pos h =>
conv => rhs; rw [Pos.skipWhile]
simp [ Pos.skip?_string_eq_skip?_toSlice, h]
public theorem skipPrefixWhile_string_eq_skipPrefixWhile_toSlice {pat : String} {s : Slice} :
s.skipPrefixWhile pat = s.skipPrefixWhile pat.toSlice :=
Pos.skipWhile_string_eq_skipWhile_toSlice s.startPos
conv => rhs; rw [dropWhile.go]
simp [ Pattern.ForwardPattern.dropPrefix?_string_eq_dropPrefix?_toSlice]
public theorem dropWhile_string_eq_dropWhile_toSlice {pat : String} {s : Slice} :
s.dropWhile pat = s.dropWhile pat.toSlice := by
simp only [dropWhile]; exact congrArg _ skipPrefixWhile_string_eq_skipPrefixWhile_toSlice
simpa only [dropWhile] using dropWhileGo_string_eq s.startPos
private theorem takeWhileGo_string_eq {pat : String} {s : Slice} (curr : s.Pos) :
takeWhile.go s pat curr = takeWhile.go s pat.toSlice curr := by
fun_induction takeWhile.go s pat curr with
| case1 pos nextCurr h₁ h₂ ih =>
conv => rhs; rw [takeWhile.go]
simp [ Pattern.ForwardPattern.dropPrefix?_string_eq_dropPrefix?_toSlice, h₁, h₂, ih]
| case2 pos nextCurr h ih =>
conv => rhs; rw [takeWhile.go]
simp [ Pattern.ForwardPattern.dropPrefix?_string_eq_dropPrefix?_toSlice, h, ih]
| case3 pos h =>
conv => rhs; rw [takeWhile.go]
simp [ Pattern.ForwardPattern.dropPrefix?_string_eq_dropPrefix?_toSlice]
public theorem takeWhile_string_eq_takeWhile_toSlice {pat : String} {s : Slice} :
s.takeWhile pat = s.takeWhile pat.toSlice := by
simp only [takeWhile]; exact congrArg _ skipPrefixWhile_string_eq_skipPrefixWhile_toSlice
simp only [takeWhile]; exact takeWhileGo_string_eq s.startPos
public theorem all_string_eq_all_toSlice {pat : String} {s : Slice} :
s.all pat = s.all pat.toSlice := by
simp only [all, skipPrefixWhile_string_eq_skipPrefixWhile_toSlice]
simp only [all, dropWhile_string_eq_dropWhile_toSlice]
public theorem endsWith_string_eq_endsWith_toSlice {pat : String} {s : Slice} :
s.endsWith pat = s.endsWith pat.toSlice := (rfl)
public theorem skipSuffix?_string_eq_skipSuffix?_toSlice {pat : String} {s : Slice} :
s.skipSuffix? pat = s.skipSuffix? pat.toSlice := (rfl)
public theorem dropSuffix?_string_eq_dropSuffix?_toSlice {pat : String} {s : Slice} :
s.dropSuffix? pat = s.dropSuffix? pat.toSlice := (rfl)
public theorem dropSuffix_string_eq_dropSuffix_toSlice {pat : String} {s : Slice} :
s.dropSuffix pat = s.dropSuffix pat.toSlice := (rfl)
public theorem Pattern.BackwardPattern.skipSuffix?_string_eq_skipSuffix?_toSlice
public theorem Pattern.BackwardPattern.dropSuffix?_string_eq_dropSuffix?_toSlice
{pat : String} {s : Slice} :
skipSuffix? pat s = skipSuffix? pat.toSlice s := (rfl)
dropSuffix? pat s = dropSuffix? pat.toSlice s := (rfl)
public theorem Pos.revSkip?_string_eq_revSkip?_toSlice {pat : String} {s : Slice} {pos : s.Pos} :
pos.revSkip? pat = pos.revSkip? pat.toSlice := (rfl)
public theorem Pos.revSkipWhile_string_eq_revSkipWhile_toSlice {pat : String} {s : Slice}
(curr : s.Pos) :
Pos.revSkipWhile curr pat = Pos.revSkipWhile curr pat.toSlice := by
fun_induction Pos.revSkipWhile curr pat with
private theorem dropEndWhileGo_string_eq {pat : String} {s : Slice} (curr : s.Pos) :
dropEndWhile.go s pat curr = dropEndWhile.go s pat.toSlice curr := by
fun_induction dropEndWhile.go s pat curr with
| case1 pos nextCurr h₁ h₂ ih =>
conv => rhs; rw [Pos.revSkipWhile]
simp [ Pos.revSkip?_string_eq_revSkip?_toSlice, h₁, h₂, ih]
conv => rhs; rw [dropEndWhile.go]
simp [ Pattern.BackwardPattern.dropSuffix?_string_eq_dropSuffix?_toSlice, h₁, h₂, ih]
| case2 pos nextCurr h ih =>
conv => rhs; rw [Pos.revSkipWhile]
simp [ Pos.revSkip?_string_eq_revSkip?_toSlice, h, ih]
conv => rhs; rw [dropEndWhile.go]
simp [ Pattern.BackwardPattern.dropSuffix?_string_eq_dropSuffix?_toSlice, h, ih]
| case3 pos h =>
conv => rhs; rw [Pos.revSkipWhile]
simp [ Pos.revSkip?_string_eq_revSkip?_toSlice, h]
public theorem skipSuffixWhile_string_eq_skipSuffixWhile_toSlice {pat : String} {s : Slice} :
s.skipSuffixWhile pat = s.skipSuffixWhile pat.toSlice :=
Pos.revSkipWhile_string_eq_revSkipWhile_toSlice s.endPos
conv => rhs; rw [dropEndWhile.go]
simp [ Pattern.BackwardPattern.dropSuffix?_string_eq_dropSuffix?_toSlice]
public theorem dropEndWhile_string_eq_dropEndWhile_toSlice {pat : String} {s : Slice} :
s.dropEndWhile pat = s.dropEndWhile pat.toSlice := by
simp only [dropEndWhile]; exact congrArg _ skipSuffixWhile_string_eq_skipSuffixWhile_toSlice
simpa only [dropEndWhile] using dropEndWhileGo_string_eq s.endPos
private theorem takeEndWhileGo_string_eq {pat : String} {s : Slice} (curr : s.Pos) :
takeEndWhile.go s pat curr = takeEndWhile.go s pat.toSlice curr := by
fun_induction takeEndWhile.go s pat curr with
| case1 pos nextCurr h₁ h₂ ih =>
conv => rhs; rw [takeEndWhile.go]
simp [ Pattern.BackwardPattern.dropSuffix?_string_eq_dropSuffix?_toSlice, h₁, h₂, ih]
| case2 pos nextCurr h ih =>
conv => rhs; rw [takeEndWhile.go]
simp [ Pattern.BackwardPattern.dropSuffix?_string_eq_dropSuffix?_toSlice, h, ih]
| case3 pos h =>
conv => rhs; rw [takeEndWhile.go]
simp [ Pattern.BackwardPattern.dropSuffix?_string_eq_dropSuffix?_toSlice]
public theorem takeEndWhile_string_eq_takeEndWhile_toSlice {pat : String} {s : Slice} :
s.takeEndWhile pat = s.takeEndWhile pat.toSlice := by
simp only [takeEndWhile]; exact congrArg _ skipSuffixWhile_string_eq_skipSuffixWhile_toSlice
public theorem revAll_string_eq_revAll_toSlice {pat : String} {s : Slice} :
s.revAll pat = s.revAll pat.toSlice := by
simp [revAll, skipSuffixWhile_string_eq_skipSuffixWhile_toSlice]
simpa only [takeEndWhile] using takeEndWhileGo_string_eq s.endPos
end String.Slice

View File

@@ -1,12 +0,0 @@
/-
Copyright (c) 2026 Lean FRO, LLC. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Markus Himmel
-/
module
prelude
public import Init.Data.String.Lemmas.Pattern.TakeDrop.Basic
public import Init.Data.String.Lemmas.Pattern.TakeDrop.Char
public import Init.Data.String.Lemmas.Pattern.TakeDrop.Pred
public import Init.Data.String.Lemmas.Pattern.TakeDrop.String

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