mirror of
https://github.com/leanprover/lean4.git
synced 2026-03-20 11:54:07 +00:00
Compare commits
1 Commits
grind_patt
...
hbv/string
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
70d1229b2c |
@@ -1,34 +1,14 @@
|
||||
To build Lean you should use `make -j -C build/release`.
|
||||
|
||||
To run a test you should use `cd tests/lean/run && ./test_single.sh example_test.lean`.
|
||||
|
||||
## New features
|
||||
|
||||
When asked to implement new features:
|
||||
* begin by reviewing existing relevant code and tests
|
||||
* write comprehensive tests first (expecting that these will initially fail)
|
||||
* and then iterate on the implementation until the tests pass.
|
||||
|
||||
All new tests should go in `tests/lean/run/`. These tests don't have expected output; we just check there are no errors. You should use `#guard_msgs` to check for specific messages.
|
||||
To build Lean you should use `make -j$(nproc) -C build/release`.
|
||||
|
||||
## Success Criteria
|
||||
To run a test you should use `cd tests/lean/run && ./test_single.sh example_test.lean`.
|
||||
|
||||
*Never* report success on a task unless you have verified both a clean build without errors, and that the relevant tests pass.
|
||||
*Never* report success on a task unless you have verified both a clean build without errors, and that the relevant tests pass. You have to keep working until you have verified both of these.
|
||||
|
||||
## Build System Safety
|
||||
All new tests should go in `tests/lean/run/`. Note that these tests don't have expected output, and just run on a success or failure basis. So you should use `#guard_msgs` to check for specific messages.
|
||||
|
||||
**NEVER manually delete build directories** (build/, stage0/, stage1/, etc.) even when builds fail.
|
||||
- ONLY use the project's documented build command: `make -j -C build/release`
|
||||
- If a build is broken, ask the user before attempting any manual cleanup
|
||||
|
||||
## LSP and IDE Diagnostics
|
||||
|
||||
After rebuilding, LSP diagnostics may be stale until the user interacts with files. Trust command-line test results over IDE diagnostics.
|
||||
|
||||
## Update prompting when the user is frustrated
|
||||
|
||||
If the user expresses frustration with you, stop and ask them to help update this `.claude/CLAUDE.md` file with missing guidance.
|
||||
|
||||
## Creating pull requests.
|
||||
|
||||
All PRs must have a first paragraph starting with "This PR". This paragraph is automatically incorporated into release notes. Read `lean4/doc/dev/commit_convention.md` when making PRs.
|
||||
If you are not following best practices specific to this repository and the user expresses frustration, stop and ask them to help update this `.claude/CLAUDE.md` file with the missing guidance.
|
||||
72
.github/workflows/ci.yml
vendored
72
.github/workflows/ci.yml
vendored
@@ -106,54 +106,9 @@ jobs:
|
||||
TAG_NAME="${GITHUB_REF##*/}"
|
||||
echo "RELEASE_TAG=$TAG_NAME" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Validate CMakeLists.txt version matches tag
|
||||
if: steps.set-release.outputs.RELEASE_TAG != ''
|
||||
run: |
|
||||
echo "Validating CMakeLists.txt version matches tag ${{ steps.set-release.outputs.RELEASE_TAG }}"
|
||||
|
||||
# Extract version values from CMakeLists.txt
|
||||
CMAKE_MAJOR=$(grep -E "^set\(LEAN_VERSION_MAJOR " src/CMakeLists.txt | grep -oE '[0-9]+')
|
||||
CMAKE_MINOR=$(grep -E "^set\(LEAN_VERSION_MINOR " src/CMakeLists.txt | grep -oE '[0-9]+')
|
||||
CMAKE_PATCH=$(grep -E "^set\(LEAN_VERSION_PATCH " src/CMakeLists.txt | grep -oE '[0-9]+')
|
||||
CMAKE_IS_RELEASE=$(grep -E "^set\(LEAN_VERSION_IS_RELEASE " src/CMakeLists.txt | grep -oE '[0-9]+')
|
||||
|
||||
# Expected values from tag parsing
|
||||
TAG_MAJOR="${{ steps.set-release.outputs.LEAN_VERSION_MAJOR }}"
|
||||
TAG_MINOR="${{ steps.set-release.outputs.LEAN_VERSION_MINOR }}"
|
||||
TAG_PATCH="${{ steps.set-release.outputs.LEAN_VERSION_PATCH }}"
|
||||
|
||||
ERRORS=""
|
||||
|
||||
if [[ "$CMAKE_MAJOR" != "$TAG_MAJOR" ]]; then
|
||||
ERRORS+="LEAN_VERSION_MAJOR: expected $TAG_MAJOR, found $CMAKE_MAJOR\n"
|
||||
fi
|
||||
if [[ "$CMAKE_MINOR" != "$TAG_MINOR" ]]; then
|
||||
ERRORS+="LEAN_VERSION_MINOR: expected $TAG_MINOR, found $CMAKE_MINOR\n"
|
||||
fi
|
||||
if [[ "$CMAKE_PATCH" != "$TAG_PATCH" ]]; then
|
||||
ERRORS+="LEAN_VERSION_PATCH: expected $TAG_PATCH, found $CMAKE_PATCH\n"
|
||||
fi
|
||||
if [[ "$CMAKE_IS_RELEASE" != "1" ]]; then
|
||||
ERRORS+="LEAN_VERSION_IS_RELEASE: expected 1, found $CMAKE_IS_RELEASE\n"
|
||||
fi
|
||||
|
||||
if [[ -n "$ERRORS" ]]; then
|
||||
echo "::error::Version mismatch between tag and src/CMakeLists.txt"
|
||||
echo ""
|
||||
echo "Tag ${{ steps.set-release.outputs.RELEASE_TAG }} expects version $TAG_MAJOR.$TAG_MINOR.$TAG_PATCH"
|
||||
echo "But src/CMakeLists.txt has mismatched values:"
|
||||
echo -e "$ERRORS"
|
||||
echo ""
|
||||
echo "Fix src/CMakeLists.txt, delete the tag, and re-tag."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Version validation passed: $TAG_MAJOR.$TAG_MINOR.$TAG_PATCH"
|
||||
|
||||
# 0: PRs without special label
|
||||
# 1: PRs with `merge-ci` label, merge queue checks, master commits
|
||||
# 2: nightlies
|
||||
# 3: PRs with `release-ci` label, full releases
|
||||
# 2: PRs with `release-ci` label, releases (incl. nightlies)
|
||||
- name: Set check level
|
||||
id: set-level
|
||||
# We do not use github.event.pull_request.labels.*.name here because
|
||||
@@ -163,16 +118,14 @@ jobs:
|
||||
check_level=0
|
||||
fast=false
|
||||
|
||||
if [[ -n "${{ steps.set-release.outputs.RELEASE_TAG }}" || -n "${{ steps.set-release-custom.outputs.RELEASE_TAG }}" ]]; then
|
||||
check_level=3
|
||||
elif [[ -n "${{ steps.set-nightly.outputs.nightly }}" ]]; then
|
||||
if [[ -n "${{ steps.set-nightly.outputs.nightly }}" || -n "${{ steps.set-release.outputs.RELEASE_TAG }}" || -n "${{ steps.set-release-custom.outputs.RELEASE_TAG }}" ]]; then
|
||||
check_level=2
|
||||
elif [[ "${{ github.event_name }}" != "pull_request" ]]; then
|
||||
check_level=1
|
||||
else
|
||||
labels="$(gh api repos/${{ github.repository_owner }}/${{ github.event.repository.name }}/pulls/${{ github.event.pull_request.number }} --jq '.labels')"
|
||||
if echo "$labels" | grep -q "release-ci"; then
|
||||
check_level=3
|
||||
check_level=2
|
||||
elif echo "$labels" | grep -q "merge-ci"; then
|
||||
check_level=1
|
||||
fi
|
||||
@@ -257,22 +210,17 @@ jobs:
|
||||
"test": true,
|
||||
"CMAKE_PRESET": "reldebug",
|
||||
},
|
||||
{
|
||||
// TODO: suddenly started failing in CI
|
||||
/*{
|
||||
"name": "Linux fsanitize",
|
||||
// Always run on large if available, more reliable regarding timeouts
|
||||
"os": large ? "nscloud-ubuntu-22.04-amd64-8x16-with-cache" : "ubuntu-latest",
|
||||
"os": "ubuntu-latest",
|
||||
"enabled": level >= 2,
|
||||
// do not fail nightlies on this for now
|
||||
"secondary": level <= 2,
|
||||
"test": true,
|
||||
// turn off custom allocator & symbolic functions to make LSAN do its magic
|
||||
"CMAKE_PRESET": "sanitize",
|
||||
// `StackOverflow*` correctly triggers ubsan
|
||||
// `reverse-ffi` fails to link in sanitizers
|
||||
// `interactive` and `async_select_channel` fail nondeterministically, would need to
|
||||
// be investigated.
|
||||
"CTEST_OPTIONS": "-E 'StackOverflow|reverse-ffi|interactive|async_select_channel'"
|
||||
},
|
||||
// exclude seriously slow/problematic tests (laketests crash)
|
||||
"CTEST_OPTIONS": "-E 'interactivetest|leanpkgtest|laketest|benchtest'"
|
||||
},*/
|
||||
{
|
||||
"name": "macOS",
|
||||
"os": "macos-15-intel",
|
||||
@@ -304,7 +252,7 @@ jobs:
|
||||
},
|
||||
{
|
||||
"name": "Windows",
|
||||
"os": large && (fast || level >= 2) ? "namespace-profile-windows-amd64-4x16" : "windows-2022",
|
||||
"os": large && (fast || level == 2) ? "namespace-profile-windows-amd64-4x16" : "windows-2022",
|
||||
"release": true,
|
||||
"enabled": level >= 2,
|
||||
"test": true,
|
||||
|
||||
@@ -41,7 +41,7 @@
|
||||
"SMALL_ALLOCATOR": "OFF",
|
||||
"USE_MIMALLOC": "OFF",
|
||||
"BSYMBOLIC": "OFF",
|
||||
"LEAN_TEST_VARS": "MAIN_STACK_SIZE=16000 LSAN_OPTIONS=max_leaks=10"
|
||||
"LEAN_TEST_VARS": "MAIN_STACK_SIZE=16000"
|
||||
},
|
||||
"generator": "Unix Makefiles",
|
||||
"binaryDir": "${sourceDir}/build/sanitize"
|
||||
|
||||
@@ -72,9 +72,6 @@ update the archived C source code of the stage 0 compiler in `stage0/src`.
|
||||
|
||||
The github repository will automatically update stage0 on `master` once
|
||||
`src/stdlib_flags.h` and `stage0/src/stdlib_flags.h` are out of sync.
|
||||
To trigger this, modify `stage0/src/stdlib_flags.h` (e.g., by adding or changing
|
||||
a comment). When `update-stage0` runs, it will overwrite `stage0/src/stdlib_flags.h`
|
||||
with the contents of `src/stdlib_flags.h`, bringing them back in sync.
|
||||
|
||||
NOTE: A full rebuild of stage 1 will only be triggered when the *committed* contents of `stage0/` are changed.
|
||||
Thus if you change files in it manually instead of through `update-stage0-commit` (see below) or fetching updates from git, you either need to commit those changes first or run `make -C build/release clean-stdlib`.
|
||||
|
||||
@@ -1,54 +0,0 @@
|
||||
This release introduces the Lean module system, which allows files to
|
||||
control the visibility of their contents for other files. In previous
|
||||
releases, this feature was available as a preview when the option
|
||||
`experimental.module` was set to `true`; it is now a fully supported
|
||||
feature of Lean.
|
||||
|
||||
# Benefits
|
||||
|
||||
Because modules reduce the amount of information exposed to other
|
||||
code, they speed up rebuilds because irrelevant changes can be
|
||||
ignored, they make it possible to be deliberate about API evolution by
|
||||
hiding details that may change from clients, they help proofs be
|
||||
checked faster by avoiding accidentally unfolding definitions, and
|
||||
they lead to smaller executable files through improved dead code
|
||||
elimination.
|
||||
|
||||
# Visibility
|
||||
|
||||
A source file is a module if it begins with the `module` keyword. By
|
||||
default, declarations in a module are private; the `public` modifier
|
||||
exports them. Proofs of theorems and bodies of definitions are private
|
||||
by default even when their signatures are public; the bodies of
|
||||
definitions can be made public by adding the `@[expose]`
|
||||
attribute. Theorems and opaque constants never expose their bodies.
|
||||
|
||||
`public section` and `@[expose] section` change the default visibility
|
||||
of declarations in the section.
|
||||
|
||||
# Imports
|
||||
|
||||
Modules may only import other modules. By default, `import` adds the
|
||||
public information of the imported module to the private scope of the
|
||||
current module. Adding the `public` modifier to an import places the
|
||||
imported modules's public information in the public scope of the
|
||||
current module, exposing it in turn to the current module's clients.
|
||||
|
||||
Within a package, `import all` can be used to import another module's
|
||||
private scope into the current module; this can be used to separate
|
||||
lemmas or tests from definition modules without exposing details to
|
||||
downstream clients.
|
||||
|
||||
# Meta Code
|
||||
|
||||
Code used in metaprograms must be marked `meta`. This ensures that the
|
||||
code is compiled and available for execution when it is needed during
|
||||
elaboration. Meta code may only reference other meta code. A whole
|
||||
module can be made available in the meta phase using `meta import`;
|
||||
this allows code to be shared across phases by importing the module in
|
||||
each phase. Code that is reachable from public metaprograms must be
|
||||
imported via `public meta import`, while local metaprograms can use
|
||||
plain `meta import` for their dependencies.
|
||||
|
||||
|
||||
The module system is described in detail in [the Lean language reference](https://lean-reference-manual-review.netlify.app/find/?domain=Verso.Genre.Manual.section&name=files).
|
||||
@@ -300,7 +300,7 @@ def parseHeaderFromString (text path : String) :
|
||||
throw <| .userError "parse errors in file"
|
||||
-- the insertion point for `add` is the first newline after the imports
|
||||
let insertion := header.raw.getTailPos?.getD parserState.pos
|
||||
let insertion := text.findAux (· == '\n') text.rawEndPos insertion + '\n'
|
||||
let insertion := text.findAux (· == '\n') text.endPos insertion + '\n'
|
||||
pure (path, inputCtx, header, insertion)
|
||||
|
||||
/-- Parse a source file to extract the location of the import lines, for edits and error messages.
|
||||
@@ -593,16 +593,16 @@ def main (args : List String) : IO UInt32 := do
|
||||
for stx in imports do
|
||||
let mod := decodeImport stx
|
||||
if remove.contains mod || seen.contains mod then
|
||||
out := out ++ String.Pos.Raw.extract text pos stx.raw.getPos?.get!
|
||||
out := out ++ text.extract pos stx.raw.getPos?.get!
|
||||
-- We use the end position of the syntax, but include whitespace up to the first newline
|
||||
pos := text.findAux (· == '\n') text.rawEndPos stx.raw.getTailPos?.get! + '\n'
|
||||
seen := seen.insert mod
|
||||
out := out ++ String.Pos.Raw.extract text pos insertion
|
||||
out := out ++ text.extract pos insertion
|
||||
for mod in add do
|
||||
if !seen.contains mod then
|
||||
seen := seen.insert mod
|
||||
out := out ++ s!"{mod}\n"
|
||||
out := out ++ String.Pos.Raw.extract text insertion text.rawEndPos
|
||||
out := out ++ text.extract insertion text.rawEndPos
|
||||
|
||||
IO.FS.writeFile path out
|
||||
count := count + 1
|
||||
|
||||
96
script/bench.sh
Executable file
96
script/bench.sh
Executable file
@@ -0,0 +1,96 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euxo pipefail
|
||||
|
||||
cmake --preset release 1>&2
|
||||
|
||||
# We benchmark against stage2/bin to test new optimizations.
|
||||
timeout -s KILL 1h time make -C build/release -j$(nproc) stage3 1>&2
|
||||
export PATH=$PWD/build/release/stage2/bin:$PATH
|
||||
|
||||
# The extra opts used to be passed to the Makefile during benchmarking only but with Lake it is
|
||||
# easier to configure them statically.
|
||||
cmake -B build/release/stage3 -S src -DLEAN_EXTRA_LAKEFILE_TOML='weakLeanArgs=["-Dprofiler=true", "-Dprofiler.threshold=9999999", "--stats"]' 1>&2
|
||||
|
||||
(
|
||||
cd tests/bench
|
||||
timeout -s KILL 1h time temci exec --config speedcenter.yaml --in speedcenter.exec.velcom.yaml 1>&2
|
||||
temci report run_output.yaml --reporter codespeed2
|
||||
)
|
||||
|
||||
if [ -d .git ]; then
|
||||
DIR="$(git rev-parse @)"
|
||||
BASE_URL="https://speed.lean-lang.org/lean4-out/$DIR"
|
||||
{
|
||||
cat <<'EOF'
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Lakeprof Report</title>
|
||||
</head>
|
||||
<h1>Lakeprof Report</h1>
|
||||
<button type="button" id="btn_fetch">View build trace in Perfetto</button>
|
||||
<script type="text/javascript">
|
||||
const ORIGIN = 'https://ui.perfetto.dev';
|
||||
|
||||
const btnFetch = document.getElementById('btn_fetch');
|
||||
|
||||
async function fetchAndOpen(traceUrl) {
|
||||
const resp = await fetch(traceUrl);
|
||||
// Error checking is left as an exercise to the reader.
|
||||
const blob = await resp.blob();
|
||||
const arrayBuffer = await blob.arrayBuffer();
|
||||
openTrace(arrayBuffer, traceUrl);
|
||||
}
|
||||
|
||||
function openTrace(arrayBuffer, traceUrl) {
|
||||
const win = window.open(ORIGIN);
|
||||
if (!win) {
|
||||
btnFetch.style.background = '#f3ca63';
|
||||
btnFetch.onclick = () => openTrace(arrayBuffer);
|
||||
btnFetch.innerText = 'Popups blocked, click here to open the trace file';
|
||||
return;
|
||||
}
|
||||
|
||||
const timer = setInterval(() => win.postMessage('PING', ORIGIN), 50);
|
||||
|
||||
const onMessageHandler = (evt) => {
|
||||
if (evt.data !== 'PONG') return;
|
||||
|
||||
// We got a PONG, the UI is ready.
|
||||
window.clearInterval(timer);
|
||||
window.removeEventListener('message', onMessageHandler);
|
||||
|
||||
const reopenUrl = new URL(location.href);
|
||||
reopenUrl.hash = `#reopen=${traceUrl}`;
|
||||
win.postMessage({
|
||||
perfetto: {
|
||||
buffer: arrayBuffer,
|
||||
title: 'Lake Build Trace',
|
||||
url: reopenUrl.toString(),
|
||||
}}, ORIGIN);
|
||||
};
|
||||
|
||||
window.addEventListener('message', onMessageHandler);
|
||||
}
|
||||
|
||||
// This is triggered when following the link from the Perfetto UI's sidebar.
|
||||
if (location.hash.startsWith('#reopen=')) {
|
||||
const traceUrl = location.hash.substr(8);
|
||||
fetchAndOpen(traceUrl);
|
||||
}
|
||||
EOF
|
||||
cat <<EOF
|
||||
btnFetch.onclick = () => fetchAndOpen("$BASE_URL/lakeprof.trace_event");
|
||||
</script>
|
||||
EOF
|
||||
echo "<pre><code>"
|
||||
(cd src; lakeprof report -prc)
|
||||
echo "</code></pre>"
|
||||
echo "</body></html>"
|
||||
} | tee index.html
|
||||
|
||||
curl -T index.html $BASE_URL/index.html
|
||||
curl -T src/lakeprof.log $BASE_URL/lakeprof.log
|
||||
curl -T src/lakeprof.trace_event $BASE_URL/lakeprof.trace_event
|
||||
fi
|
||||
@@ -10,16 +10,6 @@ Tests language server memory use by repeatedly re-elaborate a given file.
|
||||
NOTE: only works on Linux for now.
|
||||
-/
|
||||
|
||||
def determineRSS (pid : UInt32) : IO Nat := do
|
||||
let status ← IO.FS.readFile s!"/proc/{pid}/smaps_rollup"
|
||||
let some rssLine := status.splitOn "\n" |>.find? (·.startsWith "Rss:")
|
||||
| throw <| IO.userError "No RSS in proc status"
|
||||
let rssLine := rssLine.dropPrefix "Rss:"
|
||||
let rssLine := rssLine.dropWhile Char.isWhitespace
|
||||
let some rssInKB := rssLine.takeWhile Char.isDigit |>.toNat?
|
||||
| throw <| IO.userError "Cannot parse RSS"
|
||||
return rssInKB
|
||||
|
||||
def main (args : List String) : IO Unit := do
|
||||
let leanCmd :: file :: iters :: args := args | panic! "usage: script <lean> <file> <#iterations> <server-args>..."
|
||||
let file ← IO.FS.realPath file
|
||||
@@ -44,14 +34,11 @@ def main (args : List String) : IO Unit := do
|
||||
let text ← IO.FS.readFile file
|
||||
let (_, headerEndPos, _) ← Elab.parseImports text
|
||||
let headerEndPos := FileMap.ofString text |>.leanPosToLspPos headerEndPos
|
||||
let n := iters.toNat!
|
||||
let mut lastRSS? : Option Nat := none
|
||||
let mut totalRSSDelta : Int := 0
|
||||
let mut requestNo : Nat := 1
|
||||
let mut versionNo : Nat := 1
|
||||
Ipc.writeNotification ⟨"textDocument/didOpen", {
|
||||
textDocument := { uri := uri, languageId := "lean", version := 1, text := text } : DidOpenTextDocumentParams }⟩
|
||||
for i in [0:n] do
|
||||
for i in [0:iters.toNat!] do
|
||||
if i > 0 then
|
||||
versionNo := versionNo + 1
|
||||
let params : DidChangeTextDocumentParams := {
|
||||
@@ -74,16 +61,9 @@ def main (args : List String) : IO Unit := do
|
||||
IO.eprintln diag.message
|
||||
requestNo := requestNo + 1
|
||||
|
||||
let rss ← determineRSS (← read).pid
|
||||
-- The first `didChange` usually results in a significantly higher RSS increase than
|
||||
-- the others, so we ignore it.
|
||||
if i > 1 then
|
||||
if let some lastRSS := lastRSS? then
|
||||
totalRSSDelta := totalRSSDelta + ((rss : Int) - (lastRSS : Int))
|
||||
lastRSS? := some rss
|
||||
|
||||
let avgRSSDelta := totalRSSDelta / (n - 2)
|
||||
IO.println s!"avg-reelab-rss-delta: {avgRSSDelta}"
|
||||
let status ← IO.FS.readFile s!"/proc/{(← read).pid}/status"
|
||||
for line in status.splitOn "\n" |>.filter (·.startsWith "RssAnon") do
|
||||
IO.eprintln line
|
||||
|
||||
let _ ← Ipc.collectDiagnostics requestNo uri versionNo
|
||||
(← Ipc.stdin).writeLspMessage (Message.notification "exit" none)
|
||||
|
||||
@@ -1,89 +0,0 @@
|
||||
import Lean.Data.Lsp
|
||||
import Lean.Elab.Import
|
||||
open Lean
|
||||
open Lean.Lsp
|
||||
open Lean.JsonRpc
|
||||
|
||||
/-!
|
||||
Tests watchdog memory use by repeatedly re-elaborate a given file.
|
||||
|
||||
NOTE: only works on Linux for now.
|
||||
-/
|
||||
|
||||
def determineRSS (pid : UInt32) : IO Nat := do
|
||||
let status ← IO.FS.readFile s!"/proc/{pid}/smaps_rollup"
|
||||
let some rssLine := status.splitOn "\n" |>.find? (·.startsWith "Rss:")
|
||||
| throw <| IO.userError "No RSS in proc status"
|
||||
let rssLine := rssLine.dropPrefix "Rss:"
|
||||
let rssLine := rssLine.dropWhile Char.isWhitespace
|
||||
let some rssInKB := rssLine.takeWhile Char.isDigit |>.toNat?
|
||||
| throw <| IO.userError "Cannot parse RSS"
|
||||
return rssInKB
|
||||
|
||||
def main (args : List String) : IO Unit := do
|
||||
let leanCmd :: file :: iters :: args := args | panic! "usage: script <lean> <file> <#iterations> <server-args>..."
|
||||
let file ← IO.FS.realPath file
|
||||
let uri := s!"file://{file}"
|
||||
Ipc.runWith leanCmd (#["--server", "-DstderrAsMessages=false"] ++ args ++ #[uri]) do
|
||||
let capabilities := {
|
||||
textDocument? := some {
|
||||
completion? := some {
|
||||
completionItem? := some {
|
||||
insertReplaceSupport? := true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Ipc.writeRequest ⟨0, "initialize", { capabilities : InitializeParams }⟩
|
||||
discard <| Ipc.readResponseAs 0 InitializeResult
|
||||
Ipc.writeNotification ⟨"initialized", InitializedParams.mk⟩
|
||||
|
||||
let text ← IO.FS.readFile file
|
||||
let (_, headerEndPos, _) ← Elab.parseImports text
|
||||
let headerEndPos := FileMap.ofString text |>.leanPosToLspPos headerEndPos
|
||||
let n := iters.toNat!
|
||||
let mut lastRSS? : Option Nat := none
|
||||
let mut totalRSSDelta : Int := 0
|
||||
let mut requestNo : Nat := 1
|
||||
let mut versionNo : Nat := 1
|
||||
Ipc.writeNotification ⟨"textDocument/didOpen", {
|
||||
textDocument := { uri := uri, languageId := "lean", version := 1, text := text } : DidOpenTextDocumentParams }⟩
|
||||
for i in [0:iters.toNat!] do
|
||||
if i > 0 then
|
||||
versionNo := versionNo + 1
|
||||
let params : DidChangeTextDocumentParams := {
|
||||
textDocument := {
|
||||
uri := uri
|
||||
version? := versionNo
|
||||
}
|
||||
contentChanges := #[TextDocumentContentChangeEvent.rangeChange {
|
||||
start := headerEndPos
|
||||
«end» := headerEndPos
|
||||
} " "]
|
||||
}
|
||||
let params := toJson params
|
||||
Ipc.writeNotification ⟨"textDocument/didChange", params⟩
|
||||
requestNo := requestNo + 1
|
||||
|
||||
let diags ← Ipc.collectDiagnostics requestNo uri versionNo
|
||||
if let some diags := diags then
|
||||
for diag in diags.param.diagnostics do
|
||||
IO.eprintln diag.message
|
||||
requestNo := requestNo + 1
|
||||
|
||||
Ipc.waitForILeans requestNo uri versionNo
|
||||
|
||||
let rss ← determineRSS (← read).pid
|
||||
-- The first `didChange` usually results in a significantly higher RSS increase than
|
||||
-- the others, so we ignore it.
|
||||
if i > 1 then
|
||||
if let some lastRSS := lastRSS? then
|
||||
totalRSSDelta := totalRSSDelta + ((rss : Int) - (lastRSS : Int))
|
||||
lastRSS? := some rss
|
||||
|
||||
let avgRSSDelta := totalRSSDelta / (n - 2)
|
||||
IO.println s!"avg-reelab-rss-delta: {avgRSSDelta}"
|
||||
|
||||
let _ ← Ipc.collectDiagnostics requestNo uri versionNo
|
||||
Ipc.shutdown requestNo
|
||||
discard <| Ipc.waitForExit
|
||||
@@ -58,11 +58,7 @@ OPTIONS=()
|
||||
# We build cadical using the custom toolchain on Linux to avoid glibc versioning issues
|
||||
echo -n " -DLEAN_STANDALONE=ON -DCADICAL_USE_CUSTOM_CXX=ON"
|
||||
echo -n " -DCMAKE_CXX_COMPILER=$PWD/llvm-host/bin/clang++ -DLEAN_CXX_STDLIB='-Wl,-Bstatic -lc++ -lc++abi -Wl,-Bdynamic'"
|
||||
# these should also be used for cadical, so do not use `LEAN_EXTRA_CXX_FLAGS` here
|
||||
echo -n " -DCMAKE_CXX_FLAGS='--sysroot $PWD/llvm -idirafter $GLIBC_DEV/include ${EXTRA_FLAGS:-}'"
|
||||
# the above does not include linker flags which will be added below based on context, so skip the
|
||||
# generic check by cmake
|
||||
echo -n " -DCMAKE_C_COMPILER_WORKS=1 -DCMAKE_CXX_COMPILER_WORKS=1"
|
||||
echo -n " -DLEAN_EXTRA_CXX_FLAGS='--sysroot $PWD/llvm -idirafter $GLIBC_DEV/include ${EXTRA_FLAGS:-}'"
|
||||
# use target compiler directly when not cross-compiling
|
||||
if [[ -L llvm-host ]]; then
|
||||
echo -n " -DCMAKE_C_COMPILER=$PWD/stage1/bin/clang"
|
||||
|
||||
@@ -31,8 +31,6 @@ What this script does:
|
||||
- Ensures tags are merged into stable branches (for non-RC releases)
|
||||
- Verifies bump branches exist and are configured correctly
|
||||
- Special handling for ProofWidgets4 release tags
|
||||
- For mathlib4: runs verify_version_tags.py to validate the release tag
|
||||
(checks git/GitHub consistency, toolchain, elan, cache, and build)
|
||||
|
||||
3. Optionally automates missing steps (when not in --dry-run mode):
|
||||
- Creates missing release tags using push_repo_release_tag.py
|
||||
@@ -501,57 +499,6 @@ def check_proofwidgets4_release(repo_url, target_toolchain, github_token):
|
||||
print(f" You will need to create and push a tag v0.0.{next_version}")
|
||||
return False
|
||||
|
||||
def run_mathlib_verify_version_tags(toolchain, verbose=False):
|
||||
"""Run mathlib4's verify_version_tags.py script to validate the release tag.
|
||||
|
||||
This clones mathlib4 to a temp directory and runs the verification script.
|
||||
Returns True if verification passes, False otherwise.
|
||||
"""
|
||||
import tempfile
|
||||
|
||||
print(f" ... Running mathlib4 verify_version_tags.py {toolchain}")
|
||||
|
||||
with tempfile.TemporaryDirectory() as tmpdir:
|
||||
# Clone mathlib4 (shallow clone is sufficient for running the script)
|
||||
clone_result = subprocess.run(
|
||||
['git', 'clone', '--depth', '1', 'https://github.com/leanprover-community/mathlib4.git', tmpdir],
|
||||
capture_output=True,
|
||||
text=True
|
||||
)
|
||||
if clone_result.returncode != 0:
|
||||
print(f" ❌ Failed to clone mathlib4: {clone_result.stderr.strip()[:200]}")
|
||||
return False
|
||||
|
||||
# Run the verification script
|
||||
script_path = os.path.join(tmpdir, 'scripts', 'verify_version_tags.py')
|
||||
if not os.path.exists(script_path):
|
||||
print(f" ❌ verify_version_tags.py not found in mathlib4 (expected at scripts/verify_version_tags.py)")
|
||||
return False
|
||||
|
||||
# Run from the mathlib4 directory so git operations work
|
||||
result = subprocess.run(
|
||||
['python3', script_path, toolchain],
|
||||
cwd=tmpdir,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
timeout=900 # 15 minutes timeout for cache download etc.
|
||||
)
|
||||
|
||||
# Print output with indentation
|
||||
if result.stdout:
|
||||
for line in result.stdout.strip().split('\n'):
|
||||
print(f" {line}")
|
||||
if result.stderr:
|
||||
for line in result.stderr.strip().split('\n'):
|
||||
print(f" {line}")
|
||||
|
||||
if result.returncode != 0:
|
||||
print(f" ❌ mathlib4 verify_version_tags.py failed")
|
||||
return False
|
||||
|
||||
print(f" ✅ mathlib4 verify_version_tags.py passed")
|
||||
return True
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description="Check release status of Lean4 repositories")
|
||||
parser.add_argument("toolchain", help="The toolchain version to check (e.g., v4.6.0)")
|
||||
@@ -816,12 +763,6 @@ def main():
|
||||
repo_status[name] = False
|
||||
continue
|
||||
|
||||
# For mathlib4, run verify_version_tags.py to validate the release tag
|
||||
if name == "mathlib4":
|
||||
if not run_mathlib_verify_version_tags(toolchain, verbose):
|
||||
repo_status[name] = False
|
||||
continue
|
||||
|
||||
repo_status[name] = success
|
||||
|
||||
# Final check for lean4 master branch
|
||||
|
||||
@@ -42,7 +42,7 @@ if(LLD_PATH)
|
||||
endif()
|
||||
|
||||
set(LEAN_EXTRA_LINKER_FLAGS ${LEAN_EXTRA_LINKER_FLAGS_DEFAULT} CACHE STRING "Additional flags used by the linker")
|
||||
set(LEAN_EXTRA_CXX_FLAGS "" CACHE STRING "Additional flags used by the C++ compiler. Unlike `CMAKE_CXX_FLAGS`, these will not be used to build e.g. cadical.")
|
||||
set(LEAN_EXTRA_CXX_FLAGS "" CACHE STRING "Additional flags used by the C++ compiler")
|
||||
set(LEAN_TEST_VARS "LEAN_CC=${CMAKE_C_COMPILER}" CACHE STRING "Additional environment variables used when running tests")
|
||||
|
||||
if (NOT CMAKE_BUILD_TYPE)
|
||||
@@ -191,7 +191,7 @@ endif()
|
||||
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/Modules")
|
||||
|
||||
# Initialize CXXFLAGS.
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${LEAN_EXTRA_CXX_FLAGS} -DLEAN_BUILD_TYPE=\"${CMAKE_BUILD_TYPE}\" -DLEAN_EXPORTING")
|
||||
set(CMAKE_CXX_FLAGS "${LEAN_EXTRA_CXX_FLAGS} -DLEAN_BUILD_TYPE=\"${CMAKE_BUILD_TYPE}\" -DLEAN_EXPORTING")
|
||||
set(CMAKE_CXX_FLAGS_DEBUG "-DLEAN_DEBUG")
|
||||
set(CMAKE_CXX_FLAGS_MINSIZEREL "-DNDEBUG")
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "-DNDEBUG")
|
||||
|
||||
@@ -205,5 +205,3 @@ export Classical (imp_iff_right_iff imp_and_neg_imp_iff and_or_imp not_imp)
|
||||
|
||||
/-- Show that an element extracted from `P : ∃ a, p a` using `P.choose` satisfies `p`. -/
|
||||
theorem Exists.choose_spec {p : α → Prop} (P : ∃ a, p a) : p P.choose := Classical.choose_spec P
|
||||
|
||||
grind_pattern Exists.choose_spec => P.choose
|
||||
|
||||
@@ -25,7 +25,7 @@ instances are provided for the same type.
|
||||
instance (priority := 500) instForInOfForIn' [ForIn' m ρ α d] : ForIn m ρ α where
|
||||
forIn x b f := forIn' x b fun a _ => f a
|
||||
|
||||
@[simp] theorem forIn'_eq_forIn [d : Membership α ρ] [ForIn' m ρ α d] {β} (x : ρ) (b : β)
|
||||
@[simp] theorem forIn'_eq_forIn [d : Membership α ρ] [ForIn' m ρ α d] {β} [Monad m] (x : ρ) (b : β)
|
||||
(f : (a : α) → a ∈ x → β → m (ForInStep β)) (g : (a : α) → β → m (ForInStep β))
|
||||
(h : ∀ a m b, f a m b = g a b) :
|
||||
forIn' x b f = forIn x b g := by
|
||||
@@ -40,7 +40,7 @@ instance (priority := 500) instForInOfForIn' [ForIn' m ρ α d] : ForIn m ρ α
|
||||
simp [h]
|
||||
rfl
|
||||
|
||||
@[wf_preprocess] theorem forIn_eq_forIn' [d : Membership α ρ] [ForIn' m ρ α d] {β}
|
||||
@[wf_preprocess] theorem forIn_eq_forIn' [d : Membership α ρ] [ForIn' m ρ α d] {β} [Monad m]
|
||||
(x : ρ) (b : β) (f : (a : α) → β → m (ForInStep β)) :
|
||||
forIn x b f = forIn' x b (fun x h => binderNameHint x f <| binderNameHint h () <| f x) := by
|
||||
rfl
|
||||
@@ -403,7 +403,7 @@ class ForM (m : Type u → Type v) (γ : Type w₁) (α : outParam (Type w₂))
|
||||
/--
|
||||
Runs the monadic action `f` on each element of the collection `coll`.
|
||||
-/
|
||||
forM (coll : γ) (f : α → m PUnit) : m PUnit
|
||||
forM [Monad m] (coll : γ) (f : α → m PUnit) : m PUnit
|
||||
|
||||
export ForM (forM)
|
||||
|
||||
|
||||
@@ -377,7 +377,7 @@ class ForIn (m : Type u₁ → Type u₂) (ρ : Type u) (α : outParam (Type v))
|
||||
More information about the translation of `for` loops into `ForIn.forIn` is available in [the Lean
|
||||
reference manual](lean-manual://section/monad-iteration-syntax).
|
||||
-/
|
||||
forIn {β} (xs : ρ) (b : β) (f : α → β → m (ForInStep β)) : m β
|
||||
forIn {β} [Monad m] (xs : ρ) (b : β) (f : α → β → m (ForInStep β)) : m β
|
||||
|
||||
export ForIn (forIn)
|
||||
|
||||
@@ -405,7 +405,7 @@ class ForIn' (m : Type u₁ → Type u₂) (ρ : Type u) (α : outParam (Type v)
|
||||
More information about the translation of `for` loops into `ForIn'.forIn'` is available in [the
|
||||
Lean reference manual](lean-manual://section/monad-iteration-syntax).
|
||||
-/
|
||||
forIn' {β} (x : ρ) (b : β) (f : (a : α) → a ∈ x → β → m (ForInStep β)) : m β
|
||||
forIn' {β} [Monad m] (x : ρ) (b : β) (f : (a : α) → a ∈ x → β → m (ForInStep β)) : m β
|
||||
|
||||
export ForIn' (forIn')
|
||||
|
||||
|
||||
@@ -242,7 +242,7 @@ Examples:
|
||||
* `#["red", "green", "blue", "brown"].swapIfInBounds 0 4 = #["red", "green", "blue", "brown"]`
|
||||
* `#["red", "green", "blue", "brown"].swapIfInBounds 9 2 = #["red", "green", "blue", "brown"]`
|
||||
-/
|
||||
@[extern "lean_array_swap", expose]
|
||||
@[extern "lean_array_swap", grind]
|
||||
def swapIfInBounds (xs : Array α) (i j : @& Nat) : Array α :=
|
||||
if h₁ : i < xs.size then
|
||||
if h₂ : j < xs.size then swap xs i j
|
||||
@@ -570,7 +570,7 @@ protected def forIn' {α : Type u} {β : Type v} {m : Type v → Type w} [Monad
|
||||
| ForInStep.yield b => loop i (Nat.le_of_lt h') b
|
||||
loop as.size (Nat.le_refl _) b
|
||||
|
||||
instance [Monad m] : ForIn' m (Array α) α inferInstance where
|
||||
instance : ForIn' m (Array α) α inferInstance where
|
||||
forIn' := Array.forIn'
|
||||
|
||||
-- No separate `ForIn` instance is required because it can be derived from `ForIn'`.
|
||||
@@ -1001,7 +1001,7 @@ unless `start < stop`. By default, the entire array is used.
|
||||
protected def forM {α : Type u} {m : Type v → Type w} [Monad m] (f : α → m PUnit) (as : Array α) (start := 0) (stop := as.size) : m PUnit :=
|
||||
as.foldlM (fun _ => f) ⟨⟩ start stop
|
||||
|
||||
instance [Monad m] : ForM m (Array α) α where
|
||||
instance : ForM m (Array α) α where
|
||||
forM xs f := Array.forM f xs
|
||||
|
||||
-- We simplify `Array.forM` to `forM`.
|
||||
|
||||
@@ -89,41 +89,11 @@ theorem isEqv_self_beq [BEq α] [ReflBEq α] (xs : Array α) : Array.isEqv xs xs
|
||||
theorem isEqv_self [DecidableEq α] (xs : Array α) : Array.isEqv xs xs (· = ·) = true := by
|
||||
simp [isEqv, isEqvAux_self]
|
||||
|
||||
def instDecidableEqImpl [DecidableEq α] : DecidableEq (Array α) := fun xs ys =>
|
||||
match h:isEqv xs ys (fun a b => a = b) with
|
||||
| true => isTrue (eq_of_isEqv xs ys h)
|
||||
| false => isFalse (by subst ·; rw [isEqv_self] at h; contradiction)
|
||||
|
||||
instance instDecidableEq [DecidableEq α] : DecidableEq (Array α) := fun xs ys =>
|
||||
match xs with
|
||||
| ⟨[]⟩ =>
|
||||
match ys with
|
||||
| ⟨[]⟩ => isTrue rfl
|
||||
| ⟨_ :: _⟩ => isFalse (Array.noConfusion · (List.noConfusion ·))
|
||||
| ⟨a :: as⟩ =>
|
||||
match ys with
|
||||
| ⟨[]⟩ => isFalse (Array.noConfusion · (List.noConfusion ·))
|
||||
| ⟨b :: bs⟩ => instDecidableEqImpl ⟨a :: as⟩ ⟨b :: bs⟩
|
||||
|
||||
@[csimp]
|
||||
theorem instDecidableEq_csimp : @instDecidableEq = @instDecidableEqImpl :=
|
||||
Subsingleton.allEq _ _
|
||||
|
||||
/--
|
||||
Equality with `#[]` is decidable even if the underlying type does not have decidable equality.
|
||||
-/
|
||||
instance instDecidableEqEmp (xs : Array α) : Decidable (xs = #[]) :=
|
||||
match xs with
|
||||
| ⟨[]⟩ => isTrue rfl
|
||||
| ⟨_ :: _⟩ => isFalse (Array.noConfusion · (List.noConfusion ·))
|
||||
|
||||
/--
|
||||
Equality with `#[]` is decidable even if the underlying type does not have decidable equality.
|
||||
-/
|
||||
instance instDecidableEmpEq (ys : Array α) : Decidable (#[] = ys) :=
|
||||
match ys with
|
||||
| ⟨[]⟩ => isTrue rfl
|
||||
| ⟨_ :: _⟩ => isFalse (Array.noConfusion · (List.noConfusion ·))
|
||||
instance [DecidableEq α] : DecidableEq (Array α) :=
|
||||
fun xs ys =>
|
||||
match h:isEqv xs ys (fun a b => a = b) with
|
||||
| true => isTrue (eq_of_isEqv xs ys h)
|
||||
| false => isFalse fun h' => by subst h'; rw [isEqv_self] at h; contradiction
|
||||
|
||||
theorem beq_eq_decide [BEq α] (xs ys : Array α) :
|
||||
(xs == ys) = if h : xs.size = ys.size then
|
||||
|
||||
@@ -409,6 +409,8 @@ theorem popWhile_append {xs ys : Array α} :
|
||||
rcases ys with ⟨ys⟩
|
||||
simp only [List.append_toArray, List.popWhile_toArray, List.reverse_append, List.dropWhile_append,
|
||||
List.isEmpty_iff, List.isEmpty_toArray, List.isEmpty_reverse]
|
||||
-- Why do these not fire with `simp`?
|
||||
rw [List.popWhile_toArray, List.isEmpty_toArray, List.isEmpty_reverse]
|
||||
split
|
||||
· rfl
|
||||
· simp
|
||||
|
||||
@@ -3555,6 +3555,11 @@ theorem mem_of_back? {xs : Array α} {a : α} (h : xs.back? = some a) : a ∈ xs
|
||||
rcases ys with ⟨ys⟩
|
||||
simp only [List.append_toArray, List.back_toArray, List.getLast_append, List.isEmpty_iff,
|
||||
List.isEmpty_toArray]
|
||||
split
|
||||
· rw [dif_pos]
|
||||
simpa only [List.isEmpty_toArray]
|
||||
· rw [dif_neg]
|
||||
simpa only [List.isEmpty_toArray]
|
||||
|
||||
theorem back_append_right {xs ys : Array α} (h : 0 < ys.size) :
|
||||
(xs ++ ys).back (by simp; omega) = ys.back h := by
|
||||
@@ -3966,29 +3971,28 @@ theorem getElem_modify_of_ne {xs : Array α} {i : Nat} (h : i ≠ j)
|
||||
|
||||
/-! ### swap -/
|
||||
|
||||
@[grind =]
|
||||
theorem getElem_swap {xs : Array α} {i j : Nat} (hi hj) {k : Nat} (hk : k < (xs.swap i j hi hj).size) :
|
||||
(xs.swap i j hi hj)[k] = if k = i then xs[j] else if k = j then xs[i] else xs[k]'(by simp_all) := by
|
||||
simp only [swap_def, getElem_set, eq_comm (a := k)]
|
||||
split <;> split <;> simp_all
|
||||
|
||||
@[simp] theorem getElem_swap_right {xs : Array α} {i j : Nat} {hi hj} :
|
||||
(xs.swap i j hi hj)[j]'(by simpa using hj) = xs[i] := by
|
||||
simp +contextual [getElem_swap]
|
||||
simp [swap_def]
|
||||
|
||||
@[simp] theorem getElem_swap_left {xs : Array α} {i j : Nat} {hi hj} :
|
||||
(xs.swap i j hi hj)[i]'(by simpa using hi) = xs[j] := by
|
||||
simp [getElem_swap]
|
||||
simp +contextual [swap_def, getElem_set]
|
||||
|
||||
@[simp] theorem getElem_swap_of_ne {xs : Array α} {i j : Nat} {hi hj}
|
||||
{h : k < (xs.swap i j hi hj).size} (hi' : k ≠ i) (hj' : k ≠ j) :
|
||||
(xs.swap i j hi hj)[k] = xs[k]'(by simp_all) := by
|
||||
simp [getElem_swap, hi', hj']
|
||||
@[simp] theorem getElem_swap_of_ne {xs : Array α} {i j : Nat} {hi hj} (hp : k < xs.size)
|
||||
(hi' : k ≠ i) (hj' : k ≠ j) : (xs.swap i j hi hj)[k]'(xs.size_swap .. |>.symm ▸ hp) = xs[k] := by
|
||||
simp [swap_def, getElem_set, hi'.symm, hj'.symm]
|
||||
|
||||
@[deprecated getElem_swap (since := "2025-10-10")]
|
||||
theorem getElem_swap' {xs : Array α} {i j : Nat} {hi hj} {k : Nat} (hk : k < xs.size) :
|
||||
(xs.swap i j hi hj)[k]'(by simp_all) = if k = i then xs[j] else if k = j then xs[i] else xs[k] :=
|
||||
getElem_swap _ _ _
|
||||
(xs.swap i j hi hj)[k]'(by simp_all) = if k = i then xs[j] else if k = j then xs[i] else xs[k] := by
|
||||
split
|
||||
· simp_all only [getElem_swap_left]
|
||||
· split <;> simp_all
|
||||
|
||||
@[grind =]
|
||||
theorem getElem_swap {xs : Array α} {i j : Nat} (hi hj) {k : Nat} (hk : k < (xs.swap i j hi hj).size) :
|
||||
(xs.swap i j hi hj)[k] = if k = i then xs[j] else if k = j then xs[i] else xs[k]'(by simp_all) := by
|
||||
apply getElem_swap'
|
||||
|
||||
@[simp] theorem swap_swap {xs : Array α} {i j : Nat} (hi hj) :
|
||||
(xs.swap i j hi hj).swap i j ((xs.size_swap ..).symm ▸ hi) ((xs.size_swap ..).symm ▸ hj) = xs := by
|
||||
@@ -4009,66 +4013,8 @@ theorem swap_comm {xs : Array α} {i j : Nat} (hi hj) : xs.swap i j hi hj = xs.s
|
||||
· split <;> simp_all
|
||||
· split <;> simp_all
|
||||
|
||||
/-! ### swapIfInBounds -/
|
||||
|
||||
@[grind =] theorem swapIfInBounds_def {xs : Array α} {i j : Nat} :
|
||||
xs.swapIfInBounds i j = if h₁ : i < xs.size then
|
||||
if h₂ : j < xs.size then swap xs i j else xs else xs := rfl
|
||||
|
||||
@[simp, grind =] theorem size_swapIfInBounds {xs : Array α} {i j : Nat} :
|
||||
(xs.swapIfInBounds i j).size = xs.size := by
|
||||
unfold swapIfInBounds; split <;> (try split) <;> simp [size_swap]
|
||||
|
||||
@[grind =] theorem getElem_swapIfInBounds {xs : Array α} {i j k : Nat}
|
||||
(hk : k < (xs.swapIfInBounds i j).size) :
|
||||
(xs.swapIfInBounds i j)[k] =
|
||||
if h₁ : k = i ∧ j < xs.size then xs[j]'h₁.2 else if h₂ : k = j ∧ i < xs.size then xs[i]'h₂.2
|
||||
else xs[k]'(by simp_all) := by
|
||||
rw [size_swapIfInBounds] at hk
|
||||
unfold swapIfInBounds
|
||||
split <;> rename_i hi
|
||||
· split <;> rename_i hj
|
||||
· simp only [hi, hj, and_true]
|
||||
exact getElem_swap _ _ _
|
||||
· simp only [hi, hj, and_true, and_false, dite_false]
|
||||
split <;> simp_all
|
||||
· simp only [hi, and_false, dite_false]
|
||||
split <;> simp_all
|
||||
|
||||
@[simp]
|
||||
theorem getElem_swapIfInBounds_of_size_le_left {xs : Array α} {i j k : Nat} (hi : xs.size ≤ i)
|
||||
(hk : k < (xs.swapIfInBounds i j).size) :
|
||||
(xs.swapIfInBounds i j)[k] = xs[k]'(Nat.lt_of_lt_of_eq hk size_swapIfInBounds) := by
|
||||
have h₁ : k ≠ i := Nat.ne_of_lt <| Nat.lt_of_lt_of_le hk <|
|
||||
Nat.le_trans (Nat.le_of_eq (size_swapIfInBounds)) hi
|
||||
have h₂ : ¬ (i < xs.size) := Nat.not_lt_of_le hi
|
||||
simp [getElem_swapIfInBounds, h₁, h₂]
|
||||
|
||||
@[simp]
|
||||
theorem getElem_swapIfInBounds_of_size_le_right {xs : Array α} {i j k : Nat} (hj : xs.size ≤ j)
|
||||
(hk : k < (xs.swapIfInBounds i j).size) :
|
||||
(xs.swapIfInBounds i j)[k] = xs[k]'(Nat.lt_of_lt_of_eq hk size_swapIfInBounds) := by
|
||||
have h₁ : ¬ (j < xs.size) := Nat.not_lt_of_le hj
|
||||
have h₂ : k ≠ j := Nat.ne_of_lt <| Nat.lt_of_lt_of_le hk <|
|
||||
Nat.le_trans (Nat.le_of_eq (size_swapIfInBounds)) hj
|
||||
simp [getElem_swapIfInBounds, h₁, h₂]
|
||||
|
||||
@[simp]
|
||||
theorem getElem_swapIfInBounds_left {xs : Array α} {i j : Nat} (hj : j < xs.size)
|
||||
(hi : i < (xs.swapIfInBounds i j).size) : (xs.swapIfInBounds i j)[i] = xs[j] := by
|
||||
simp [getElem_swapIfInBounds, hj]
|
||||
|
||||
@[simp]
|
||||
theorem getElem_swapIfInBounds_right {xs : Array α} {i j : Nat} (hi : i < xs.size)
|
||||
(hj : j < (xs.swapIfInBounds i j).size) :
|
||||
(xs.swapIfInBounds i j)[j] = xs[i] := by
|
||||
simp +contextual [getElem_swapIfInBounds, hi]
|
||||
|
||||
@[simp]
|
||||
theorem getElem_swapIfInBounds_of_ne_of_ne {xs : Array α} {i j k : Nat} (hi : k ≠ i) (hj : k ≠ j)
|
||||
(hk : k < (xs.swapIfInBounds i j).size) :
|
||||
(xs.swapIfInBounds i j)[k] = xs[k]'(Nat.lt_of_lt_of_eq hk size_swapIfInBounds) := by
|
||||
simp [getElem_swapIfInBounds, hi, hj]
|
||||
(xs.swapIfInBounds i j).size = xs.size := by unfold swapIfInBounds; split <;> (try split) <;> simp [size_swap]
|
||||
|
||||
/-! ### swapAt -/
|
||||
|
||||
@@ -4330,10 +4276,6 @@ theorem size_uset {xs : Array α} {v : α} {i : USize} (h : i.toNat < xs.size) :
|
||||
theorem getElem!_eq_getD [Inhabited α] {xs : Array α} {i} : xs[i]! = xs.getD i default := by
|
||||
rfl
|
||||
|
||||
theorem getElem_eq_getD {xs : Array α} {i} {h : i < xs.size} (fallback : α) :
|
||||
xs[i]'h = xs.getD i fallback := by
|
||||
rw [getD_eq_getD_getElem?, getElem_eq_getElem?_get, Option.get_eq_getD]
|
||||
|
||||
/-! # mem -/
|
||||
|
||||
@[deprecated mem_toList_iff (since := "2025-05-26")]
|
||||
|
||||
@@ -1056,7 +1056,7 @@ theorem toInt_setWidth' {m n : Nat} (p : m ≤ n) {x : BitVec m} :
|
||||
@[simp, grind =] theorem toFin_setWidth' {m n : Nat} (p : m ≤ n) (x : BitVec m) :
|
||||
(setWidth' p x).toFin = x.toFin.castLE (Nat.pow_le_pow_right (by omega) (by omega)) := by
|
||||
ext
|
||||
rw [setWidth'_eq, toFin_setWidth, Fin.val_ofNat, Fin.val_castLE, val_toFin,
|
||||
rw [setWidth'_eq, toFin_setWidth, Fin.val_ofNat, Fin.coe_castLE, val_toFin,
|
||||
Nat.mod_eq_of_lt (by apply BitVec.toNat_lt_twoPow_of_le p)]
|
||||
|
||||
theorem toNat_setWidth_of_le {w w' : Nat} {b : BitVec w} (h : w ≤ w') : (b.setWidth w').toNat = b.toNat := by
|
||||
|
||||
@@ -132,11 +132,6 @@ Copies the bytes with indices {name}`b` (inclusive) to {name}`e` (exclusive) to
|
||||
def extract (a : ByteArray) (b e : Nat) : ByteArray :=
|
||||
a.copySlice b empty 0 (e - b)
|
||||
|
||||
/--
|
||||
Appends two byte arrays using fast array primitives instead of converting them into lists and back.
|
||||
|
||||
In compiled code, this function replaces calls to {name}`ByteArray.append`.
|
||||
-/
|
||||
@[inline]
|
||||
protected def fastAppend (a : ByteArray) (b : ByteArray) : ByteArray :=
|
||||
-- we assume that `append`s may be repeated, so use asymptotic growing; use `copySlice` directly to customize
|
||||
@@ -248,7 +243,7 @@ protected def forIn {β : Type v} {m : Type v → Type w} [Monad m] (as : ByteAr
|
||||
| ForInStep.yield b => loop i (Nat.le_of_lt h') b
|
||||
loop as.size (Nat.le_refl _) b
|
||||
|
||||
instance [Monad m] : ForIn m ByteArray UInt8 where
|
||||
instance : ForIn m ByteArray UInt8 where
|
||||
forIn := ByteArray.forIn
|
||||
|
||||
/--
|
||||
|
||||
@@ -246,11 +246,6 @@ instance neg (n : Nat) : Neg (Fin n) :=
|
||||
|
||||
theorem neg_def (a : Fin n) : -a = ⟨(n - a) % n, Nat.mod_lt _ a.pos⟩ := rfl
|
||||
|
||||
-- Later we give another version called `Fin.val_neg` that splits on `a = 0`.
|
||||
protected theorem val_neg' (a : Fin n) : ((-a : Fin n) : Nat) = (n - a) % n :=
|
||||
rfl
|
||||
|
||||
@[deprecated Fin.val_neg' (since := "2025-11-21")]
|
||||
protected theorem coe_neg (a : Fin n) : ((-a : Fin n) : Nat) = (n - a) % n :=
|
||||
rfl
|
||||
|
||||
|
||||
@@ -16,25 +16,17 @@ open Std
|
||||
|
||||
namespace Fin
|
||||
|
||||
@[simp, grind =] theorem ofNat_zero (n : Nat) [NeZero n] : Fin.ofNat n 0 = 0 := rfl
|
||||
@[simp] theorem ofNat_zero (n : Nat) [NeZero n] : Fin.ofNat n 0 = 0 := rfl
|
||||
|
||||
@[deprecated ofNat_zero (since := "2025-05-28")] abbrev ofNat'_zero := @ofNat_zero
|
||||
|
||||
theorem mod_def (a m : Fin n) : a % m = Fin.mk (a.val % m.val) (Nat.lt_of_le_of_lt (Nat.mod_le _ _) a.2) :=
|
||||
rfl
|
||||
|
||||
theorem val_mod (a m : Fin n) : (a % m).val = a.val % m.val := rfl
|
||||
|
||||
theorem mul_def (a b : Fin n) : a * b = Fin.mk ((a.val * b.val) % n) (Nat.mod_lt _ a.pos) := rfl
|
||||
|
||||
theorem val_mul (a b : Fin n) : (a * b).val = (a.val * b.val) % n := rfl
|
||||
|
||||
theorem sub_def (a b : Fin n) : a - b = Fin.mk (((n - b.val) + a.val) % n) (Nat.mod_lt _ a.pos) := rfl
|
||||
|
||||
@[grind =]
|
||||
theorem val_sub (a b : Fin n) : (a - b).val = ((n - b.val) + a.val) % n := rfl
|
||||
|
||||
@[grind →]
|
||||
theorem pos' : ∀ [Nonempty (Fin n)], 0 < n | ⟨i⟩ => i.pos
|
||||
|
||||
@[simp] theorem is_lt (a : Fin n) : (a : Nat) < n := a.2
|
||||
@@ -46,8 +38,7 @@ theorem pos_iff_nonempty {n : Nat} : 0 < n ↔ Nonempty (Fin n) :=
|
||||
|
||||
@[simp] protected theorem eta (a : Fin n) (h : a < n) : (⟨a, h⟩ : Fin n) = a := rfl
|
||||
|
||||
@[ext, grind ext]
|
||||
protected theorem ext {a b : Fin n} (h : (a : Nat) = b) : a = b := eq_of_val_eq h
|
||||
@[ext] protected theorem ext {a b : Fin n} (h : (a : Nat) = b) : a = b := eq_of_val_eq h
|
||||
|
||||
theorem val_ne_iff {a b : Fin n} : a.1 ≠ b.1 ↔ a ≠ b := not_congr val_inj
|
||||
|
||||
@@ -78,7 +69,7 @@ theorem mk_val (i : Fin n) : (⟨i, i.isLt⟩ : Fin n) = i := Fin.eta ..
|
||||
|
||||
@[deprecated val_ofNat (since := "2025-05-28")] abbrev val_ofNat' := @val_ofNat
|
||||
|
||||
@[simp, grind =] theorem ofNat_self {n : Nat} [NeZero n] : Fin.ofNat n n = 0 := by
|
||||
@[simp] theorem ofNat_self {n : Nat} [NeZero n] : Fin.ofNat n n = 0 := by
|
||||
ext
|
||||
simp
|
||||
congr
|
||||
@@ -98,7 +89,7 @@ theorem mk_val (i : Fin n) : (⟨i, i.isLt⟩ : Fin n) = i := Fin.eta ..
|
||||
@[simp] theorem div_val (a b : Fin n) : (a / b).val = a.val / b.val :=
|
||||
rfl
|
||||
|
||||
@[simp, grind =] theorem modn_val (a : Fin n) (b : Nat) : (a.modn b).val = a.val % b :=
|
||||
@[simp] theorem modn_val (a : Fin n) (b : Nat) : (a.modn b).val = a.val % b :=
|
||||
rfl
|
||||
|
||||
@[simp] theorem val_eq_zero (a : Fin 1) : a.val = 0 :=
|
||||
@@ -268,9 +259,7 @@ instance : LawfulOrderLT (Fin n) where
|
||||
lt_iff := by
|
||||
simp [← Fin.not_le, Decidable.imp_iff_not_or, Std.Total.total]
|
||||
|
||||
@[simp] theorem val_rev (i : Fin n) : (rev i).val = n - (i + 1) := rfl
|
||||
|
||||
grind_pattern val_rev => i.rev
|
||||
@[simp, grind =] theorem val_rev (i : Fin n) : (rev i).val = n - (i + 1) := rfl
|
||||
|
||||
@[simp] theorem rev_rev (i : Fin n) : rev (rev i) = i := Fin.ext <| by
|
||||
rw [val_rev, val_rev, ← Nat.sub_sub, Nat.sub_sub_self (by exact i.2), Nat.add_sub_cancel]
|
||||
@@ -295,8 +284,6 @@ theorem rev_eq {n a : Nat} (i : Fin (n + 1)) (h : n = a + i) :
|
||||
|
||||
@[simp] theorem val_last (n : Nat) : (last n).1 = n := rfl
|
||||
|
||||
grind_pattern val_last => last n
|
||||
|
||||
@[simp] theorem last_zero : (Fin.last 0 : Fin 1) = 0 := by
|
||||
ext
|
||||
simp
|
||||
@@ -406,8 +393,6 @@ theorem zero_ne_one : (0 : Fin (n + 2)) ≠ 1 := Fin.ne_of_lt zero_lt_one
|
||||
|
||||
@[simp] theorem val_succ (j : Fin n) : (j.succ : Nat) = j + 1 := rfl
|
||||
|
||||
grind_pattern val_succ => j.succ
|
||||
|
||||
@[simp] theorem succ_pos (a : Fin n) : (0 : Fin (n + 1)) < a.succ := by
|
||||
simp [Fin.lt_def]
|
||||
|
||||
@@ -468,18 +453,12 @@ theorem one_lt_succ_succ (a : Fin n) : (1 : Fin (n + 2)) < a.succ.succ := by
|
||||
theorem succ_succ_ne_one (a : Fin n) : Fin.succ (Fin.succ a) ≠ 1 :=
|
||||
Fin.ne_of_gt (one_lt_succ_succ a)
|
||||
|
||||
@[simp, grind =] theorem val_castLT (i : Fin m) (h : i.1 < n) : (castLT i h : Nat) = i := rfl
|
||||
|
||||
@[deprecated val_castLT (since := "2025-11-21")]
|
||||
theorem coe_castLT (i : Fin m) (h : i.1 < n) : (castLT i h : Nat) = i := rfl
|
||||
@[simp] theorem coe_castLT (i : Fin m) (h : i.1 < n) : (castLT i h : Nat) = i := rfl
|
||||
|
||||
@[simp] theorem castLT_mk (i n m : Nat) (hn : i < n) (hm : i < m) : castLT ⟨i, hn⟩ hm = ⟨i, hm⟩ :=
|
||||
rfl
|
||||
|
||||
@[simp, grind =] theorem val_castLE (h : n ≤ m) (i : Fin n) : (castLE h i : Nat) = i := rfl
|
||||
|
||||
@[deprecated val_castLE (since := "2025-11-21")]
|
||||
theorem coe_castLE (h : n ≤ m) (i : Fin n) : (castLE h i : Nat) = i := rfl
|
||||
@[simp, grind =] theorem coe_castLE (h : n ≤ m) (i : Fin n) : (castLE h i : Nat) = i := rfl
|
||||
|
||||
@[simp] theorem castLE_mk (i n m : Nat) (hn : i < n) (h : n ≤ m) :
|
||||
castLE h ⟨i, hn⟩ = ⟨i, Nat.lt_of_lt_of_le hn h⟩ := rfl
|
||||
@@ -491,16 +470,13 @@ theorem coe_castLE (h : n ≤ m) (i : Fin n) : (castLE h i : Nat) = i := rfl
|
||||
|
||||
@[simp] theorem castLE_castLE {k m n} (km : k ≤ m) (mn : m ≤ n) (i : Fin k) :
|
||||
Fin.castLE mn (Fin.castLE km i) = Fin.castLE (Nat.le_trans km mn) i :=
|
||||
Fin.ext (by simp only [val_castLE])
|
||||
Fin.ext (by simp only [coe_castLE])
|
||||
|
||||
@[simp] theorem castLE_comp_castLE {k m n} (km : k ≤ m) (mn : m ≤ n) :
|
||||
Fin.castLE mn ∘ Fin.castLE km = Fin.castLE (Nat.le_trans km mn) :=
|
||||
funext (castLE_castLE km mn)
|
||||
|
||||
@[simp, grind =] theorem val_cast (h : n = m) (i : Fin n) : (i.cast h : Nat) = i := rfl
|
||||
|
||||
@[deprecated val_cast (since := "2025-11-21")]
|
||||
theorem coe_cast (h : n = m) (i : Fin n) : (i.cast h : Nat) = i := rfl
|
||||
@[simp] theorem coe_cast (h : n = m) (i : Fin n) : (i.cast h : Nat) = i := rfl
|
||||
|
||||
@[simp] theorem cast_castLE {k m n} (km : k ≤ m) (mn : m = n) (i : Fin k) :
|
||||
Fin.cast mn (i.castLE km) = i.castLE (mn ▸ km) :=
|
||||
@@ -513,7 +489,7 @@ theorem coe_cast (h : n = m) (i : Fin n) : (i.cast h : Nat) = i := rfl
|
||||
@[simp] theorem cast_zero [NeZero n] [NeZero m] (h : n = m) : Fin.cast h 0 = 0 := rfl
|
||||
|
||||
@[simp] theorem cast_last {n' : Nat} {h : n + 1 = n' + 1} : (last n).cast h = last n' :=
|
||||
Fin.ext (by rw [val_cast, val_last, val_last, Nat.succ.inj h])
|
||||
Fin.ext (by rw [coe_cast, val_last, val_last, Nat.succ.inj h])
|
||||
|
||||
@[simp] theorem cast_mk (h : n = m) (i : Nat) (hn : i < n) : Fin.cast h ⟨i, hn⟩ = ⟨i, h ▸ hn⟩ := rfl
|
||||
|
||||
@@ -528,10 +504,7 @@ theorem coe_cast (h : n = m) (i : Fin n) : (i.cast h : Nat) = i := rfl
|
||||
|
||||
theorem castLE_of_eq {m n : Nat} (h : m = n) {h' : m ≤ n} : castLE h' = Fin.cast h := rfl
|
||||
|
||||
@[simp, grind =] theorem val_castAdd (m : Nat) (i : Fin n) : (castAdd m i : Nat) = i := rfl
|
||||
|
||||
@[deprecated val_castAdd (since := "2025-11-21")]
|
||||
theorem coe_castAdd (m : Nat) (i : Fin n) : (castAdd m i : Nat) = i := rfl
|
||||
@[simp] theorem coe_castAdd (m : Nat) (i : Fin n) : (castAdd m i : Nat) = i := rfl
|
||||
|
||||
@[simp] theorem castAdd_zero : (castAdd 0 : Fin n → Fin (n + 0)) = Fin.cast rfl := rfl
|
||||
|
||||
@@ -567,10 +540,7 @@ the reverse direction. -/
|
||||
theorem succ_cast_eq {n' : Nat} (i : Fin n) (h : n = n') :
|
||||
(i.cast h).succ = i.succ.cast (by rw [h]) := rfl
|
||||
|
||||
@[simp, grind =] theorem val_castSucc (i : Fin n) : (i.castSucc : Nat) = i := rfl
|
||||
|
||||
@[deprecated val_castSucc (since := "2025-11-21")]
|
||||
theorem coe_castSucc (i : Fin n) : (i.castSucc : Nat) = i := rfl
|
||||
@[simp] theorem coe_castSucc (i : Fin n) : (i.castSucc : Nat) = i := rfl
|
||||
|
||||
@[simp] theorem castSucc_mk (n i : Nat) (h : i < n) : castSucc ⟨i, h⟩ = ⟨i, Nat.lt_succ_of_lt h⟩ := rfl
|
||||
|
||||
@@ -578,7 +548,7 @@ theorem coe_castSucc (i : Fin n) : (i.castSucc : Nat) = i := rfl
|
||||
i.castSucc.cast h = (i.cast (Nat.succ.inj h)).castSucc := rfl
|
||||
|
||||
theorem castSucc_lt_succ {i : Fin n} : i.castSucc < i.succ :=
|
||||
lt_def.2 <| by simp only [val_castSucc, val_succ, Nat.lt_succ_self]
|
||||
lt_def.2 <| by simp only [coe_castSucc, val_succ, Nat.lt_succ_self]
|
||||
|
||||
theorem le_castSucc_iff {i : Fin (n + 1)} {j : Fin n} : i ≤ j.castSucc ↔ i < j.succ := by
|
||||
simpa only [lt_def, le_def] using Nat.add_one_le_add_one_iff.symm
|
||||
@@ -632,7 +602,7 @@ theorem coeSucc_eq_succ {a : Fin n} : a.castSucc + 1 = a.succ := by
|
||||
|
||||
@[deprecated castSucc_lt_succ (since := "2025-10-29")]
|
||||
theorem lt_succ {a : Fin n} : a.castSucc < a.succ := by
|
||||
rw [castSucc, lt_def, val_castAdd, val_succ]; exact Nat.lt_succ_self a.val
|
||||
rw [castSucc, lt_def, coe_castAdd, val_succ]; exact Nat.lt_succ_self a.val
|
||||
|
||||
theorem exists_castSucc_eq {n : Nat} {i : Fin (n + 1)} : (∃ j, castSucc j = i) ↔ i ≠ last n :=
|
||||
⟨fun ⟨j, hj⟩ => hj ▸ Fin.ne_of_lt j.castSucc_lt_last,
|
||||
@@ -640,10 +610,7 @@ theorem exists_castSucc_eq {n : Nat} {i : Fin (n + 1)} : (∃ j, castSucc j = i)
|
||||
|
||||
theorem succ_castSucc {n : Nat} (i : Fin n) : i.castSucc.succ = i.succ.castSucc := rfl
|
||||
|
||||
@[simp, grind =] theorem val_addNat (m : Nat) (i : Fin n) : (addNat i m : Nat) = i + m := rfl
|
||||
|
||||
@[deprecated val_addNat (since := "2025-11-21")]
|
||||
theorem coe_addNat (m : Nat) (i : Fin n) : (addNat i m : Nat) = i + m := rfl
|
||||
@[simp] theorem coe_addNat (m : Nat) (i : Fin n) : (addNat i m : Nat) = i + m := rfl
|
||||
|
||||
@[simp] theorem addNat_zero (n : Nat) (i : Fin n) : addNat i 0 = i := by
|
||||
ext
|
||||
@@ -671,10 +638,7 @@ theorem cast_addNat_left {n n' m : Nat} (i : Fin n') (h : n' + m = n + m) :
|
||||
(addNat i m').cast h = addNat i m :=
|
||||
Fin.ext <| (congrArg ((· + ·) (i : Nat)) (Nat.add_left_cancel h) : _)
|
||||
|
||||
@[simp, grind =] theorem val_natAdd (n : Nat) {m : Nat} (i : Fin m) : (natAdd n i : Nat) = n + i := rfl
|
||||
|
||||
@[deprecated val_natAdd (since := "2025-11-21")]
|
||||
theorem coe_natAdd (n : Nat) {m : Nat} (i : Fin m) : (natAdd n i : Nat) = n + i := rfl
|
||||
@[simp] theorem coe_natAdd (n : Nat) {m : Nat} (i : Fin m) : (natAdd n i : Nat) = n + i := rfl
|
||||
|
||||
@[simp] theorem natAdd_mk (n i : Nat) (hi : i < m) :
|
||||
natAdd n ⟨i, hi⟩ = ⟨n + i, Nat.add_lt_add_left hi n⟩ := rfl
|
||||
@@ -731,7 +695,7 @@ theorem natAdd_castSucc {m n : Nat} {i : Fin m} : natAdd n (castSucc i) = castSu
|
||||
omega
|
||||
|
||||
theorem rev_castAdd (k : Fin n) (m : Nat) : rev (castAdd m k) = addNat (rev k) m := Fin.ext <| by
|
||||
rw [val_rev, val_castAdd, val_addNat, val_rev, Nat.sub_add_comm (Nat.succ_le_of_lt k.is_lt)]
|
||||
rw [val_rev, coe_castAdd, coe_addNat, val_rev, Nat.sub_add_comm (Nat.succ_le_of_lt k.is_lt)]
|
||||
|
||||
theorem rev_addNat (k : Fin n) (m : Nat) : rev (addNat k m) = castAdd m (rev k) := by
|
||||
rw [← rev_rev (castAdd ..), rev_castAdd, rev_rev]
|
||||
@@ -753,12 +717,7 @@ theorem castSucc_natAdd (n : Nat) (i : Fin k) :
|
||||
|
||||
/-! ### pred -/
|
||||
|
||||
@[simp] theorem val_pred (j : Fin (n + 1)) (h : j ≠ 0) : (j.pred h : Nat) = j - 1 := rfl
|
||||
|
||||
grind_pattern val_pred => j.pred h
|
||||
|
||||
@[deprecated val_pred (since := "2025-11-21")]
|
||||
theorem coe_pred (j : Fin (n + 1)) (h : j ≠ 0) : (j.pred h : Nat) = j - 1 := rfl
|
||||
@[simp] theorem coe_pred (j : Fin (n + 1)) (h : j ≠ 0) : (j.pred h : Nat) = j - 1 := rfl
|
||||
|
||||
@[simp] theorem succ_pred : ∀ (i : Fin (n + 1)) (h : i ≠ 0), (i.pred h).succ = i
|
||||
| ⟨0, _⟩, hi => by simp only [mk_zero, ne_eq, not_true] at hi
|
||||
@@ -776,7 +735,7 @@ theorem pred_eq_iff_eq_succ {n : Nat} {i : Fin (n + 1)} (hi : i ≠ 0) {j : Fin
|
||||
theorem pred_mk_succ (i : Nat) (h : i < n + 1) :
|
||||
Fin.pred ⟨i + 1, Nat.add_lt_add_right h 1⟩ (ne_of_val_ne (Nat.ne_of_gt (mk_succ_pos i h))) =
|
||||
⟨i, h⟩ := by
|
||||
simp only [Fin.ext_iff, val_pred, Nat.add_sub_cancel]
|
||||
simp only [Fin.ext_iff, coe_pred, Nat.add_sub_cancel]
|
||||
|
||||
@[simp] theorem pred_mk_succ' (i : Nat) (h₁ : i + 1 < n + 1 + 1) (h₂) :
|
||||
Fin.pred ⟨i + 1, h₁⟩ h₂ = ⟨i, Nat.lt_of_succ_lt_succ h₁⟩ := pred_mk_succ i _
|
||||
@@ -803,13 +762,10 @@ theorem pred_mk {n : Nat} (i : Nat) (h : i < n + 1) (w) : Fin.pred ⟨i, h⟩ w
|
||||
|
||||
theorem pred_add_one (i : Fin (n + 2)) (h : (i : Nat) < n + 1) :
|
||||
pred (i + 1) (Fin.ne_of_gt (add_one_pos _ (lt_def.2 h))) = castLT i h := by
|
||||
rw [Fin.ext_iff, val_pred, val_castLT, val_add, val_one, Nat.mod_eq_of_lt, Nat.add_sub_cancel]
|
||||
rw [Fin.ext_iff, coe_pred, coe_castLT, val_add, val_one, Nat.mod_eq_of_lt, Nat.add_sub_cancel]
|
||||
exact Nat.add_lt_add_right h 1
|
||||
|
||||
@[simp, grind =] theorem val_subNat (i : Fin (n + m)) (h : m ≤ i) : (i.subNat m h : Nat) = i - m := rfl
|
||||
|
||||
@[deprecated val_subNat (since := "2025-11-21")]
|
||||
theorem coe_subNat (i : Fin (n + m)) (h : m ≤ i) : (i.subNat m h : Nat) = i - m := rfl
|
||||
@[simp] theorem coe_subNat (i : Fin (n + m)) (h : m ≤ i) : (i.subNat m h : Nat) = i - m := rfl
|
||||
|
||||
@[simp] theorem subNat_mk {i : Nat} (h₁ : i < n + m) (h₂ : m ≤ i) :
|
||||
subNat m ⟨i, h₁⟩ h₂ = ⟨i - m, Nat.sub_lt_right_of_lt_add h₂ h₁⟩ := rfl
|
||||
@@ -874,11 +830,11 @@ step. `Fin.succRec` is a version of this induction principle that takes the `Fin
|
||||
(zero : ∀ n, motive (n + 1) 0) (succ : ∀ n i, motive n i → motive (Nat.succ n) i.succ) :
|
||||
motive n i := i.succRec zero succ
|
||||
|
||||
@[simp, grind =] theorem succRecOn_zero {motive : ∀ n, Fin n → Sort _} {zero succ} (n) :
|
||||
@[simp] theorem succRecOn_zero {motive : ∀ n, Fin n → Sort _} {zero succ} (n) :
|
||||
@Fin.succRecOn (n + 1) 0 motive zero succ = zero n := by
|
||||
cases n <;> rfl
|
||||
|
||||
@[simp, grind =] theorem succRecOn_succ {motive : ∀ n, Fin n → Sort _} {zero succ} {n} (i : Fin n) :
|
||||
@[simp] theorem succRecOn_succ {motive : ∀ n, Fin n → Sort _} {zero succ} {n} (i : Fin n) :
|
||||
@Fin.succRecOn (n + 1) i.succ motive zero succ = succ n i (Fin.succRecOn i zero succ) := by
|
||||
cases i; rfl
|
||||
|
||||
@@ -906,11 +862,11 @@ where
|
||||
| 0, hi => by rwa [Fin.mk_zero]
|
||||
| i+1, hi => succ ⟨i, Nat.lt_of_succ_lt_succ hi⟩ (go i (Nat.lt_of_succ_lt hi))
|
||||
|
||||
@[simp, grind =] theorem induction_zero {motive : Fin (n + 1) → Sort _} (zero : motive 0)
|
||||
@[simp] theorem induction_zero {motive : Fin (n + 1) → Sort _} (zero : motive 0)
|
||||
(hs : ∀ i : Fin n, motive (castSucc i) → motive i.succ) :
|
||||
(induction zero hs : ∀ i : Fin (n + 1), motive i) 0 = zero := rfl
|
||||
|
||||
@[simp, grind =] theorem induction_succ {motive : Fin (n + 1) → Sort _} (zero : motive 0)
|
||||
@[simp] theorem induction_succ {motive : Fin (n + 1) → Sort _} (zero : motive 0)
|
||||
(succ : ∀ i : Fin n, motive (castSucc i) → motive i.succ) (i : Fin n) :
|
||||
induction (motive := motive) zero succ i.succ = succ i (induction zero succ (castSucc i)) := rfl
|
||||
|
||||
@@ -942,13 +898,13 @@ The corresponding induction principle is `Fin.induction`.
|
||||
(zero : motive 0) (succ : ∀ i : Fin n, motive i.succ) :
|
||||
∀ i : Fin (n + 1), motive i := induction zero fun i _ => succ i
|
||||
|
||||
@[simp, grind =] theorem cases_zero {n} {motive : Fin (n + 1) → Sort _} {zero succ} :
|
||||
@[simp] theorem cases_zero {n} {motive : Fin (n + 1) → Sort _} {zero succ} :
|
||||
@Fin.cases n motive zero succ 0 = zero := rfl
|
||||
|
||||
@[simp, grind =] theorem cases_succ {n} {motive : Fin (n + 1) → Sort _} {zero succ} (i : Fin n) :
|
||||
@[simp] theorem cases_succ {n} {motive : Fin (n + 1) → Sort _} {zero succ} (i : Fin n) :
|
||||
@Fin.cases n motive zero succ i.succ = succ i := rfl
|
||||
|
||||
@[simp, grind =] theorem cases_succ' {n} {motive : Fin (n + 1) → Sort _} {zero succ}
|
||||
@[simp] theorem cases_succ' {n} {motive : Fin (n + 1) → Sort _} {zero succ}
|
||||
{i : Nat} (h : i + 1 < n + 1) :
|
||||
@Fin.cases n motive zero succ ⟨i.succ, h⟩ = succ ⟨i, Nat.lt_of_succ_lt_succ h⟩ := rfl
|
||||
|
||||
@@ -998,7 +954,7 @@ For the induction:
|
||||
| j + 1 => go j (by omega) (by omega) (cast ⟨j, by omega⟩ x)
|
||||
go _ _ (by omega) last
|
||||
|
||||
@[simp, grind =] theorem reverseInduction_last {n : Nat} {motive : Fin (n + 1) → Sort _} {zero succ} :
|
||||
@[simp] theorem reverseInduction_last {n : Nat} {motive : Fin (n + 1) → Sort _} {zero succ} :
|
||||
(reverseInduction zero succ (Fin.last n) : motive (Fin.last n)) = zero := by
|
||||
rw [reverseInduction, reverseInduction.go]; simp
|
||||
|
||||
@@ -1015,7 +971,7 @@ private theorem reverseInduction_castSucc_aux {n : Nat} {motive : Fin (n + 1)
|
||||
dsimp only
|
||||
rw [ih _ _ (by omega), eq_comm, reverseInduction.go, dif_neg (by change i.1 + 1 ≠ _; omega)]
|
||||
|
||||
@[simp, grind =] theorem reverseInduction_castSucc {n : Nat} {motive : Fin (n + 1) → Sort _} {zero succ}
|
||||
@[simp] theorem reverseInduction_castSucc {n : Nat} {motive : Fin (n + 1) → Sort _} {zero succ}
|
||||
(i : Fin n) : reverseInduction (motive := motive) zero succ (castSucc i) =
|
||||
succ i (reverseInduction zero succ i.succ) := by
|
||||
rw [reverseInduction, reverseInduction_castSucc_aux _ _ _ i.isLt, reverseInduction]
|
||||
@@ -1034,11 +990,11 @@ The corresponding induction principle is `Fin.reverseInduction`.
|
||||
(cast : ∀ i : Fin n, motive (castSucc i)) (i : Fin (n + 1)) : motive i :=
|
||||
reverseInduction last (fun i _ => cast i) i
|
||||
|
||||
@[simp, grind =] theorem lastCases_last {n : Nat} {motive : Fin (n + 1) → Sort _} {last cast} :
|
||||
@[simp] theorem lastCases_last {n : Nat} {motive : Fin (n + 1) → Sort _} {last cast} :
|
||||
(Fin.lastCases last cast (Fin.last n) : motive (Fin.last n)) = last :=
|
||||
reverseInduction_last ..
|
||||
|
||||
@[simp, grind =] theorem lastCases_castSucc {n : Nat} {motive : Fin (n + 1) → Sort _} {last cast}
|
||||
@[simp] theorem lastCases_castSucc {n : Nat} {motive : Fin (n + 1) → Sort _} {last cast}
|
||||
(i : Fin n) : (Fin.lastCases last cast (Fin.castSucc i) : motive (Fin.castSucc i)) = cast i :=
|
||||
reverseInduction_castSucc ..
|
||||
|
||||
@@ -1058,11 +1014,11 @@ as `Fin.natAdd m (j : Fin n)`.
|
||||
if hi : (i : Nat) < m then (castAdd_castLT n i hi) ▸ (left (castLT i hi))
|
||||
else (natAdd_subNat_cast (Nat.le_of_not_lt hi)) ▸ (right _)
|
||||
|
||||
@[simp, grind =] theorem addCases_left {m n : Nat} {motive : Fin (m + n) → Sort _} {left right} (i : Fin m) :
|
||||
@[simp] theorem addCases_left {m n : Nat} {motive : Fin (m + n) → Sort _} {left right} (i : Fin m) :
|
||||
addCases (motive := motive) left right (Fin.castAdd n i) = left i := by
|
||||
rw [addCases, dif_pos (castAdd_lt _ _)]; rfl
|
||||
|
||||
@[simp, grind =]
|
||||
@[simp]
|
||||
theorem addCases_right {m n : Nat} {motive : Fin (m + n) → Sort _} {left right} (i : Fin n) :
|
||||
addCases (motive := motive) left right (natAdd m i) = right i := by
|
||||
have : ¬(natAdd m i : Nat) < m := Nat.not_lt.2 (le_coe_natAdd ..)
|
||||
@@ -1095,7 +1051,6 @@ theorem add_ofNat [NeZero n] (x : Fin n) (y : Nat) :
|
||||
|
||||
/-! ### sub -/
|
||||
|
||||
@[deprecated val_sub (since := "2025-11-21")]
|
||||
protected theorem coe_sub (a b : Fin n) : ((a - b : Fin n) : Nat) = ((n - b) + a) % n := by
|
||||
cases a; cases b; rfl
|
||||
|
||||
@@ -1147,7 +1102,6 @@ theorem coe_sub_iff_lt {a b : Fin n} : (↑(a - b) : Nat) = n + a - b ↔ a < b
|
||||
|
||||
/-! ### neg -/
|
||||
|
||||
@[grind =]
|
||||
theorem val_neg {n : Nat} [NeZero n] (x : Fin n) :
|
||||
(-x).val = if x = 0 then 0 else n - x.val := by
|
||||
change (n - ↑x) % n = _
|
||||
@@ -1163,7 +1117,7 @@ protected theorem sub_eq_add_neg {n : Nat} (x y : Fin n) : x - y = x + -y := by
|
||||
apply elim0 x
|
||||
· replace h : NeZero n := ⟨h⟩
|
||||
ext
|
||||
rw [Fin.val_sub, Fin.val_add, val_neg]
|
||||
rw [Fin.coe_sub, Fin.val_add, val_neg]
|
||||
split
|
||||
· simp_all
|
||||
· simp [Nat.add_comm]
|
||||
@@ -1184,6 +1138,9 @@ theorem mul_ofNat [NeZero n] (x : Fin n) (y : Nat) :
|
||||
|
||||
@[deprecated mul_ofNat (since := "2025-05-28")] abbrev mul_ofNat' := @mul_ofNat
|
||||
|
||||
theorem val_mul {n : Nat} : ∀ a b : Fin n, (a * b).val = a.val * b.val % n
|
||||
| ⟨_, _⟩, ⟨_, _⟩ => rfl
|
||||
|
||||
@[deprecated val_mul (since := "2025-10-26")]
|
||||
theorem coe_mul {n : Nat} : ∀ a b : Fin n, ((a * b : Fin n) : Nat) = a * b % n
|
||||
| ⟨_, _⟩, ⟨_, _⟩ => rfl
|
||||
|
||||
@@ -129,7 +129,7 @@ protected def forIn {β : Type v} {m : Type v → Type w} [Monad m] (as : FloatA
|
||||
| ForInStep.yield b => loop i (Nat.le_of_lt h') b
|
||||
loop as.size (Nat.le_refl _) b
|
||||
|
||||
instance [Monad m] : ForIn m FloatArray Float where
|
||||
instance : ForIn m FloatArray Float where
|
||||
forIn := FloatArray.forIn
|
||||
|
||||
/-- See comment at `forInUnsafe` -/
|
||||
|
||||
@@ -7,7 +7,7 @@ module
|
||||
|
||||
prelude
|
||||
public import Init.Data.Array.Basic
|
||||
import Init.Data.String.Search
|
||||
import Init.Data.String.Basic
|
||||
|
||||
public section
|
||||
|
||||
@@ -47,7 +47,7 @@ Converts a string to a pretty-printer document, replacing newlines in the string
|
||||
`Std.Format.line`.
|
||||
-/
|
||||
def String.toFormat (s : String) : Std.Format :=
|
||||
Std.Format.joinSep (s.split '\n').toList Std.Format.line
|
||||
Std.Format.joinSep (s.splitOn "\n") Std.Format.line
|
||||
|
||||
instance : ToFormat String.Pos.Raw where
|
||||
format p := format p.byteIdx
|
||||
|
||||
@@ -1781,16 +1781,6 @@ theorem ediv_lt_ediv_iff_of_dvd_of_neg_of_neg {a b c d : Int} (hb : b < 0) (hd :
|
||||
obtain ⟨⟨x, rfl⟩, y, rfl⟩ := hba, hdc
|
||||
simp [*, Int.ne_of_lt, d.mul_assoc, b.mul_comm]
|
||||
|
||||
theorem ediv_lt_ediv_of_lt {a b c : Int} (h : a < b) (hcb : c ∣ b) (hc : 0 < c) :
|
||||
a / c < b / c :=
|
||||
Int.lt_ediv_of_mul_lt (Int.le_of_lt hc) hcb
|
||||
(Int.lt_of_le_of_lt (Int.ediv_mul_le _ (Int.ne_of_gt hc)) h)
|
||||
|
||||
theorem ediv_lt_ediv_of_lt_of_neg {a b c : Int} (h : b < a) (hca : c ∣ a) (hc : c < 0) :
|
||||
a / c < b / c :=
|
||||
(Int.ediv_lt_iff_of_dvd_of_neg hc hca).2
|
||||
(Int.lt_of_le_of_lt (Int.mul_ediv_self_le (Int.ne_of_lt hc)) h)
|
||||
|
||||
/-! ### `tdiv` and ordering -/
|
||||
|
||||
-- Theorems about `tdiv` and ordering, whose `ediv` analogues are in `Bootstrap.lean`.
|
||||
|
||||
@@ -377,15 +377,6 @@ protected theorem le_iff_lt_add_one {a b : Int} : a ≤ b ↔ a < b + 1 := by
|
||||
|
||||
@[grind =] protected theorem max_def (n m : Int) : max n m = if n ≤ m then m else n := rfl
|
||||
|
||||
end Int
|
||||
namespace Lean.Meta.Grind.Lia
|
||||
|
||||
scoped grind_pattern Int.min_def => min n m
|
||||
scoped grind_pattern Int.max_def => max n m
|
||||
|
||||
end Lean.Meta.Grind.Lia
|
||||
namespace Int
|
||||
|
||||
@[simp] protected theorem neg_min_neg (a b : Int) : min (-a) (-b) = -max a b := by
|
||||
rw [Int.min_def, Int.max_def]
|
||||
simp
|
||||
|
||||
@@ -678,7 +678,6 @@ Given this typeclass, termination proofs for well-founded recursion over an iter
|
||||
`it.finitelyManySteps` as a termination measure.
|
||||
-/
|
||||
class Finite (α : Type w) (m : Type w → Type w') {β : Type w} [Iterator α m β] : Prop where
|
||||
/-- The relation of plausible successors is well-founded. -/
|
||||
wf : WellFounded (IterM.IsPlausibleSuccessorOf (α := α) (m := m))
|
||||
|
||||
theorem Finite.wf_of_id {α : Type w} {β : Type w} [Iterator α Id β] [Finite α Id] :
|
||||
@@ -798,7 +797,6 @@ Given this typeclass, termination proofs for well-founded recursion over an iter
|
||||
`it.finitelyManySkips` as a termination measure.
|
||||
-/
|
||||
class Productive (α m) {β} [Iterator α m β] : Prop where
|
||||
/-- The relation of plausible successors during skips is well-founded. -/
|
||||
wf : WellFounded (IterM.IsPlausibleSkipSuccessorOf (α := α) (m := m))
|
||||
|
||||
/--
|
||||
|
||||
@@ -9,8 +9,6 @@ prelude
|
||||
public import Init.Data.Iterators.Consumers.Collect
|
||||
public import Init.Data.Iterators.Consumers.Monadic.Loop
|
||||
|
||||
set_option linter.missingDocs true
|
||||
|
||||
public section
|
||||
|
||||
/-!
|
||||
@@ -48,9 +46,6 @@ instance (α : Type w) (β : Type w) (n : Type x → Type x') [Monad n]
|
||||
haveI : ForIn' n (Iter (α := α) β) β _ := Iter.instForIn'
|
||||
instForInOfForIn'
|
||||
|
||||
/--
|
||||
An implementation of `for h : ... in ... do ...` notation for partial iterators.
|
||||
-/
|
||||
@[always_inline, inline]
|
||||
def Iter.Partial.instForIn' {α : Type w} {β : Type w} {n : Type x → Type x'} [Monad n]
|
||||
[Iterator α Id β] [IteratorLoopPartial α Id n] :
|
||||
@@ -68,12 +63,12 @@ instance (α : Type w) (β : Type w) (n : Type x → Type x') [Monad n]
|
||||
instForInOfForIn'
|
||||
|
||||
instance {m : Type x → Type x'}
|
||||
{α : Type w} {β : Type w} [Iterator α Id β] [Finite α Id] [IteratorLoop α Id m] [Monad m] :
|
||||
{α : Type w} {β : Type w} [Iterator α Id β] [Finite α Id] [IteratorLoop α Id m] :
|
||||
ForM m (Iter (α := α) β) β where
|
||||
forM it f := forIn it PUnit.unit (fun out _ => do f out; return .yield .unit)
|
||||
|
||||
instance {m : Type x → Type x'}
|
||||
{α : Type w} {β : Type w} [Iterator α Id β] [Finite α Id] [IteratorLoopPartial α Id m] [Monad m] :
|
||||
{α : Type w} {β : Type w} [Iterator α Id β] [Finite α Id] [IteratorLoopPartial α Id m] :
|
||||
ForM m (Iter.Partial (α := α) β) β where
|
||||
forM it f := forIn it PUnit.unit (fun out _ => do f out; return .yield .unit)
|
||||
|
||||
@@ -207,11 +202,6 @@ def Iter.all {α β : Type w}
|
||||
(p : β → Bool) (it : Iter (α := α) β) : Bool :=
|
||||
(it.allM (fun x => pure (f := Id) (p x))).run
|
||||
|
||||
/--
|
||||
Steps through the iterator until the monadic function `f` returns `some` for an element, at which
|
||||
point iteration stops and the result of `f` is returned. If the iterator is completely consumed
|
||||
without `f` returning `some`, then the result is `none`.
|
||||
-/
|
||||
@[inline]
|
||||
def Iter.findSomeM? {α β : Type w} {γ : Type x} {m : Type x → Type w'} [Monad m] [Iterator α Id β]
|
||||
[IteratorLoop α Id m] [Finite α Id] (it : Iter (α := α) β) (f : β → m (Option γ)) :
|
||||
@@ -221,7 +211,7 @@ def Iter.findSomeM? {α β : Type w} {γ : Type x} {m : Type x → Type w'} [Mon
|
||||
| none => return .yield none
|
||||
| some fx => return .done (some fx))
|
||||
|
||||
@[inline, inherit_doc Iter.findSomeM?]
|
||||
@[inline]
|
||||
def Iter.Partial.findSomeM? {α β : Type w} {γ : Type x} {m : Type x → Type w'} [Monad m]
|
||||
[Iterator α Id β] [IteratorLoopPartial α Id m] (it : Iter.Partial (α := α) β)
|
||||
(f : β → m (Option γ)) :
|
||||
@@ -231,50 +221,36 @@ def Iter.Partial.findSomeM? {α β : Type w} {γ : Type x} {m : Type x → Type
|
||||
| none => return .yield none
|
||||
| some fx => return .done (some fx))
|
||||
|
||||
/--
|
||||
Steps through the iterator until `f` returns `some` for an element, at which point iteration stops
|
||||
and the result of `f` is returned. If the iterator is completely consumed without `f` returning
|
||||
`some`, then the result is `none`.
|
||||
-/
|
||||
@[inline]
|
||||
def Iter.findSome? {α β : Type w} {γ : Type x} [Iterator α Id β]
|
||||
[IteratorLoop α Id Id] [Finite α Id] (it : Iter (α := α) β) (f : β → Option γ) :
|
||||
Option γ :=
|
||||
Id.run (it.findSomeM? (pure <| f ·))
|
||||
|
||||
@[inline, inherit_doc Iter.findSome?]
|
||||
@[inline]
|
||||
def Iter.Partial.findSome? {α β : Type w} {γ : Type x} [Iterator α Id β]
|
||||
[IteratorLoopPartial α Id Id] (it : Iter.Partial (α := α) β) (f : β → Option γ) :
|
||||
Option γ :=
|
||||
Id.run (it.findSomeM? (pure <| f ·))
|
||||
|
||||
/--
|
||||
Steps through the iterator until an element satisfies the monadic predicate `f`, at which point
|
||||
iteration stops and the element is returned. If no element satisfies `f`, then the result is
|
||||
`none`.
|
||||
-/
|
||||
@[inline]
|
||||
def Iter.findM? {α β : Type w} {m : Type w → Type w'} [Monad m] [Iterator α Id β]
|
||||
[IteratorLoop α Id m] [Finite α Id] (it : Iter (α := α) β) (f : β → m (ULift Bool)) :
|
||||
m (Option β) :=
|
||||
it.findSomeM? (fun x => return if (← f x).down then some x else none)
|
||||
|
||||
@[inline, inherit_doc Iter.findM?]
|
||||
@[inline]
|
||||
def Iter.Partial.findM? {α β : Type w} {m : Type w → Type w'} [Monad m] [Iterator α Id β]
|
||||
[IteratorLoopPartial α Id m] (it : Iter.Partial (α := α) β) (f : β → m (ULift Bool)) :
|
||||
m (Option β) :=
|
||||
it.findSomeM? (fun x => return if (← f x).down then some x else none)
|
||||
|
||||
/--
|
||||
Steps through the iterator until an element satisfies `f`, at which point iteration stops and the
|
||||
element is returned. If no element satisfies `f`, then the result is `none`.
|
||||
-/
|
||||
@[inline]
|
||||
def Iter.find? {α β : Type w} [Iterator α Id β] [IteratorLoop α Id Id]
|
||||
[Finite α Id] (it : Iter (α := α) β) (f : β → Bool) : Option β :=
|
||||
Id.run (it.findM? (pure <| .up <| f ·))
|
||||
|
||||
@[inline, inherit_doc Iter.find?]
|
||||
@[inline]
|
||||
def Iter.Partial.find? {α β : Type w} [Iterator α Id β] [IteratorLoopPartial α Id Id]
|
||||
(it : Iter.Partial (α := α) β) (f : β → Bool) : Option β :=
|
||||
Id.run (it.findM? (pure <| .up <| f ·))
|
||||
|
||||
@@ -247,10 +247,10 @@ This `ForIn'`-style loop construct traverses a finite iterator using an `Iterato
|
||||
-/
|
||||
@[always_inline, inline]
|
||||
def IteratorLoop.finiteForIn' {m : Type w → Type w'} {n : Type x → Type x'}
|
||||
{α : Type w} {β : Type w} [Iterator α m β] [Finite α m] [IteratorLoop α m n] [Monad n]
|
||||
{α : Type w} {β : Type w} [Iterator α m β] [Finite α m] [IteratorLoop α m n]
|
||||
(lift : ∀ γ δ, (γ → n δ) → m γ → n δ) :
|
||||
ForIn' n (IterM (α := α) m β) β ⟨fun it out => it.IsPlausibleIndirectOutput out⟩ where
|
||||
forIn' {γ} it init f :=
|
||||
forIn' {γ} [Monad n] it init f :=
|
||||
IteratorLoop.forIn (α := α) (m := m) lift γ (fun _ _ _ => True)
|
||||
wellFounded_of_finite
|
||||
it init (fun out h acc => (⟨·, .intro⟩) <$> f out h acc)
|
||||
@@ -288,13 +288,13 @@ instance {m : Type w → Type w'} {n : Type w → Type w''}
|
||||
instForInOfForIn'
|
||||
|
||||
instance {m : Type w → Type w'} {n : Type w → Type w''}
|
||||
{α : Type w} {β : Type w} [Iterator α m β] [Finite α m] [IteratorLoop α m n] [Monad n]
|
||||
{α : Type w} {β : Type w} [Iterator α m β] [Finite α m] [IteratorLoop α m n]
|
||||
[MonadLiftT m n] :
|
||||
ForM n (IterM (α := α) m β) β where
|
||||
forM it f := forIn it PUnit.unit (fun out _ => do f out; return .yield .unit)
|
||||
|
||||
instance {m : Type w → Type w'} {n : Type w → Type w''}
|
||||
{α : Type w} {β : Type w} [Iterator α m β] [IteratorLoopPartial α m n] [Monad n]
|
||||
{α : Type w} {β : Type w} [Iterator α m β] [IteratorLoopPartial α m n]
|
||||
[MonadLiftT m n] :
|
||||
ForM n (IterM.Partial (α := α) m β) β where
|
||||
forM it f := forIn it PUnit.unit (fun out _ => do f out; return .yield .unit)
|
||||
|
||||
@@ -19,45 +19,110 @@ open Std.Iterators
|
||||
|
||||
namespace Std.Iterators
|
||||
|
||||
/-- This typeclass provides an iterator for elements of type `γ`. -/
|
||||
class ToIterator (γ : Type u) (m : Type w → Type w') (α β : outParam (Type w)) where
|
||||
iterMInternal (x : γ) : IterM (α := α) m β
|
||||
/--
|
||||
This typeclass provides an iterator for the given element `x : γ`. Usually, instances are provided
|
||||
for all elements of a type `γ`.
|
||||
-/
|
||||
class ToIterator {γ : Type u} (x : γ) (m : Type w → Type w') (β : outParam (Type w)) where
|
||||
State : Type w
|
||||
iterMInternal : IterM (α := State) m β
|
||||
|
||||
/-- Converts `x` into a monadic iterator. -/
|
||||
@[always_inline, inline, expose]
|
||||
def ToIterator.iterM (x : γ) [ToIterator γ m α β] : IterM (α := α) m β :=
|
||||
def ToIterator.iterM (x : γ) [ToIterator x m β] : IterM (α := ToIterator.State x m) m β :=
|
||||
ToIterator.iterMInternal (x := x)
|
||||
|
||||
/-- Converts `x` into a pure iterator. -/
|
||||
@[always_inline, inline, expose]
|
||||
def ToIterator.iter [ToIterator γ Id α β] (x : γ) : Iter (α := α) β :=
|
||||
def ToIterator.iter (x : γ) [ToIterator x Id β] : Iter (α := ToIterator.State x Id) β :=
|
||||
ToIterator.iterM x |>.toIter
|
||||
|
||||
/-- Creates a monadic `ToIterator` instance. -/
|
||||
@[always_inline, inline, expose]
|
||||
def ToIterator.ofM (α : Type w)
|
||||
(iterM : γ → IterM (α := α) m β) :
|
||||
ToIterator γ m α β where
|
||||
iterMInternal x := iterM x
|
||||
def ToIterator.ofM {x : γ} (State : Type w)
|
||||
(iterM : IterM (α := State) m β) :
|
||||
ToIterator x m β where
|
||||
State := State
|
||||
iterMInternal := iterM
|
||||
|
||||
/-- Creates a pure `ToIterator` instance. -/
|
||||
@[always_inline, inline, expose]
|
||||
def ToIterator.of (α : Type w)
|
||||
(iter : γ → Iter (α := α) β) :
|
||||
ToIterator γ Id α β where
|
||||
iterMInternal x := iter x |>.toIterM
|
||||
def ToIterator.of {x : γ} (State : Type w)
|
||||
(iter : Iter (α := State) β) :
|
||||
ToIterator x Id β where
|
||||
State := State
|
||||
iterMInternal := iter.toIterM
|
||||
|
||||
/-- Replaces `ToIterator.iterM` with its definition. -/
|
||||
theorem ToIterator.iterM_eq {γ : Type u} {α β : Type v}
|
||||
{it : γ → IterM (α := α) Id β} {x} :
|
||||
letI : ToIterator γ Id α β := .ofM α it
|
||||
ToIterator.iterM x = it x :=
|
||||
theorem ToIterator.iterM_eq {γ : Type u} {x : γ} {State : Type v} {β : Type v} {it} :
|
||||
letI : ToIterator x Id β := .ofM State it
|
||||
ToIterator.iterM x = it :=
|
||||
rfl
|
||||
|
||||
/-- Replaces `ToIterator.iter` with its definition. -/
|
||||
theorem ToIterator.iter_eq {γ : Type u} {x : γ} {α β : Type v} {it} :
|
||||
letI : ToIterator γ Id α β := .ofM α it
|
||||
ToIterator.iter x = (it x).toIter :=
|
||||
theorem ToIterator.iter_eq {γ : Type u} {x : γ} {State : Type v} {β : Type v} {it} :
|
||||
letI : ToIterator x Id β := .ofM State it
|
||||
ToIterator.iter x = it.toIter :=
|
||||
rfl
|
||||
|
||||
/-!
|
||||
## Instance forwarding
|
||||
|
||||
If the type defined as `ToIterator.State` implements an iterator typeclass, then this typeclass
|
||||
should also be available when the type is syntactically visible as `ToIteratorState`. The following
|
||||
instances are responsible for this forwarding.
|
||||
-/
|
||||
|
||||
instance {x : γ} {State : Type w} {iter}
|
||||
[Iterator State m β] :
|
||||
letI i : ToIterator x m β := .ofM State iter
|
||||
Iterator (α := i.State) m β :=
|
||||
inferInstanceAs <| Iterator State m β
|
||||
|
||||
instance {x : γ} {State : Type w} {iter}
|
||||
[Iterator (α := State) m β] [Finite State m] :
|
||||
letI i : ToIterator x m β := .ofM State iter
|
||||
Finite (α := i.State) m :=
|
||||
inferInstanceAs <| Finite (α := State) m
|
||||
|
||||
instance {x : γ} {State : Type w} {iter}
|
||||
[Iterator (α := State) m β] [IteratorCollect State m n] :
|
||||
letI i : ToIterator x m β := .ofM State iter
|
||||
IteratorCollect (α := i.State) m n :=
|
||||
inferInstanceAs <| IteratorCollect (α := State) m n
|
||||
|
||||
instance {x : γ} {State : Type w} {iter} [Monad m] [Monad n]
|
||||
[Iterator (α := State) m β] [IteratorCollect State m n] [LawfulIteratorCollect State m n] :
|
||||
letI i : ToIterator x m β := .ofM State iter
|
||||
LawfulIteratorCollect (α := i.State) m n :=
|
||||
inferInstanceAs <| LawfulIteratorCollect (α := State) m n
|
||||
|
||||
instance {x : γ} {State : Type w} {iter}
|
||||
[Iterator (α := State) m β] [IteratorCollectPartial State m n] :
|
||||
letI i : ToIterator x m β := .ofM State iter
|
||||
IteratorCollectPartial (α := i.State) m n :=
|
||||
inferInstanceAs <| IteratorCollectPartial (α := State) m n
|
||||
|
||||
instance {x : γ} {State : Type w} {iter}
|
||||
[Iterator (α := State) m β] [IteratorLoop State m n] :
|
||||
letI i : ToIterator x m β := .ofM State iter
|
||||
IteratorLoop (α := i.State) m n :=
|
||||
inferInstanceAs <| IteratorLoop (α := State) m n
|
||||
|
||||
instance {x : γ} {State : Type w} {iter} [Monad m] [Monad n]
|
||||
[Iterator (α := State) m β] [IteratorLoop State m n] [LawfulIteratorLoop State m n]:
|
||||
letI i : ToIterator x m β := .ofM State iter
|
||||
LawfulIteratorLoop (α := i.State) m n :=
|
||||
inferInstanceAs <| LawfulIteratorLoop (α := State) m n
|
||||
|
||||
instance {x : γ} {State : Type w} {iter}
|
||||
[Iterator (α := State) m β] [IteratorLoopPartial State m n] :
|
||||
letI i : ToIterator x m β := .ofM State iter
|
||||
IteratorLoopPartial (α := i.State) m n :=
|
||||
inferInstanceAs <| IteratorLoopPartial (α := State) m n
|
||||
|
||||
@[simp]
|
||||
theorem ToIterator.state_eq {x : γ} {State : Type w} {iter} :
|
||||
haveI : ToIterator x Id β := .of State iter
|
||||
ToIterator.State x Id = State :=
|
||||
rfl
|
||||
|
||||
end Std.Iterators
|
||||
|
||||
@@ -471,7 +471,7 @@ theorem findM?_eq_findSomeM? [Monad m] [LawfulMonad m] {p : α → m Bool} {as :
|
||||
loop as' b this
|
||||
loop as init ⟨[], rfl⟩
|
||||
|
||||
instance [Monad m] : ForIn' m (List α) α inferInstance where
|
||||
instance : ForIn' m (List α) α inferInstance where
|
||||
forIn' := List.forIn'
|
||||
|
||||
-- No separate `ForIn` instance is required because it can be derived from `ForIn'`.
|
||||
@@ -485,7 +485,7 @@ instance [Monad m] : ForIn' m (List α) α inferInstance where
|
||||
@[simp, grind =] theorem forIn_nil [Monad m] {f : α → β → m (ForInStep β)} {b : β} : forIn [] b f = pure b :=
|
||||
rfl
|
||||
|
||||
instance [Monad m] : ForM m (List α) α where
|
||||
instance : ForM m (List α) α where
|
||||
forM := List.forM
|
||||
|
||||
-- We simplify `List.forM` to `forM`.
|
||||
|
||||
@@ -13,9 +13,6 @@ import all Init.Data.List.BasicAux
|
||||
public import Init.Data.List.Control
|
||||
import all Init.Data.List.Control
|
||||
public import Init.BinderPredicates
|
||||
import Init.Grind.Annotated
|
||||
|
||||
grind_annotated "2025-01-24"
|
||||
|
||||
public section
|
||||
|
||||
@@ -254,10 +251,6 @@ theorem getElem_eq_getElem?_get {l : List α} {i : Nat} (h : i < l.length) :
|
||||
l[i] = l[i]?.get (by simp [h]) := by
|
||||
simp
|
||||
|
||||
theorem getElem_eq_getD {l : List α} {i : Nat} {h : i < l.length} (fallback : α) :
|
||||
l[i] = l.getD i fallback := by
|
||||
rw [getElem_eq_getElem?_get, List.getD, Option.get_eq_getD]
|
||||
|
||||
theorem getD_getElem? {l : List α} {i : Nat} {d : α} :
|
||||
l[i]?.getD d = if p : i < l.length then l[i]'p else d := by
|
||||
if h : i < l.length then
|
||||
@@ -305,12 +298,6 @@ theorem ext_getElem {l₁ l₂ : List α} (hl : length l₁ = length l₂)
|
||||
have h₁ := Nat.le_of_not_lt h₁
|
||||
rw [getElem?_eq_none h₁, getElem?_eq_none]; rwa [← hl]
|
||||
|
||||
theorem ext_getElem_iff {l₁ l₂ : List α} :
|
||||
l₁ = l₂ ↔ l₁.length = l₂.length ∧ ∀ (i : Nat) (h₁ : i < l₁.length) (h₂ : i < l₂.length), l₁[i]'h₁ = l₂[i]'h₂ := by
|
||||
constructor
|
||||
· simp +contextual
|
||||
· exact fun h => ext_getElem h.1 h.2
|
||||
|
||||
@[simp] theorem getElem_concat_length {l : List α} {a : α} {i : Nat} (h : i = l.length) (w) :
|
||||
(l ++ [a])[i]'w = a := by
|
||||
subst h; simp
|
||||
|
||||
@@ -374,22 +374,6 @@ theorem drop_take : ∀ {i j : Nat} {l : List α}, drop i (take j l) = take (j -
|
||||
rw [drop_take]
|
||||
simp
|
||||
|
||||
@[simp]
|
||||
theorem drop_eq_drop_iff :
|
||||
∀ {l : List α} {i j : Nat}, l.drop i = l.drop j ↔ min i l.length = min j l.length
|
||||
| [], i, j => by simp
|
||||
| _ :: xs, 0, 0 => by simp
|
||||
| x :: xs, i + 1, 0 => by
|
||||
rw [List.ext_getElem_iff]
|
||||
simp [succ_min_succ, show ¬ xs.length - i = xs.length + 1 by omega]
|
||||
| x :: xs, 0, j + 1 => by
|
||||
rw [List.ext_getElem_iff]
|
||||
simp [succ_min_succ, show ¬ xs.length + 1 = xs.length - j by omega]
|
||||
| x :: xs, i + 1, j + 1 => by simp [succ_min_succ, drop_eq_drop_iff]
|
||||
|
||||
theorem drop_eq_drop_min {l : List α} {i : Nat} : l.drop i = l.drop (min i l.length) := by
|
||||
simp
|
||||
|
||||
theorem take_reverse {α} {xs : List α} {i : Nat} :
|
||||
xs.reverse.take i = (xs.drop (xs.length - i)).reverse := by
|
||||
by_cases h : i ≤ xs.length
|
||||
|
||||
@@ -15,40 +15,7 @@ public section
|
||||
|
||||
namespace Option
|
||||
|
||||
instance instDecidableEq {α} [inst : DecidableEq α] : DecidableEq (Option α) := fun a b =>
|
||||
/-
|
||||
Structured for compatibility with the decidable-equality-with-none instances.
|
||||
-/
|
||||
match a with
|
||||
| none => match b with
|
||||
| none => .isTrue rfl
|
||||
| some _ => .isFalse Option.noConfusion
|
||||
| some a => match b with
|
||||
| none => .isFalse Option.noConfusion
|
||||
| some b => match inst a b with
|
||||
| .isTrue h => .isTrue (h ▸ rfl)
|
||||
| .isFalse n => .isFalse (Option.noConfusion · n)
|
||||
|
||||
/--
|
||||
Equality with `none` is decidable even if the wrapped type does not have decidable equality.
|
||||
-/
|
||||
instance decidableEqNone (o : Option α) : Decidable (o = none) :=
|
||||
/- We use a `match` instead of transferring from `isNone_iff_eq_none` for
|
||||
compatibility with the `DecidableEq` instance. -/
|
||||
match o with
|
||||
| none => .isTrue rfl
|
||||
| some _ => .isFalse Option.noConfusion
|
||||
|
||||
/--
|
||||
Equality with `none` is decidable even if the wrapped type does not have decidable equality.
|
||||
-/
|
||||
instance decidableNoneEq (o : Option α) : Decidable (none = o) :=
|
||||
/- We use a `match` instead of transferring from `isNone_iff_eq_none` for
|
||||
compatibility with the `DecidableEq` instance. -/
|
||||
match o with
|
||||
| none => .isTrue rfl
|
||||
| some _ => .isFalse Option.noConfusion
|
||||
|
||||
deriving instance DecidableEq for Option
|
||||
deriving instance BEq for Option
|
||||
|
||||
@[simp, grind =] theorem getD_none : getD none a = a := rfl
|
||||
|
||||
@@ -35,6 +35,17 @@ instance [DecidableEq α] (j : α) (o : Option α) : Decidable (j ∈ o) :=
|
||||
|
||||
theorem some_inj {a b : α} : some a = some b ↔ a = b := by simp; rfl
|
||||
|
||||
/--
|
||||
Equality with `none` is decidable even if the wrapped type does not have decidable equality.
|
||||
|
||||
This is not an instance because it is not definitionally equal to the standard instance of
|
||||
`DecidableEq (Option α)`, which can cause problems. It can be locally bound if needed.
|
||||
|
||||
Try to use the Boolean comparisons `Option.isNone` or `Option.isSome` instead.
|
||||
-/
|
||||
@[inline] def decidableEqNone {o : Option α} : Decidable (o = none) :=
|
||||
decidable_of_decidable_of_iff isNone_iff_eq_none
|
||||
|
||||
instance decidableForallMem {p : α → Prop} [DecidablePred p] :
|
||||
∀ o : Option α, Decidable (∀ a, a ∈ o → p a)
|
||||
| none => isTrue nofun
|
||||
@@ -168,10 +179,10 @@ Examples:
|
||||
| none , _ => pure ⟨⟩
|
||||
| some a, f => f a
|
||||
|
||||
instance [Monad m] : ForM m (Option α) α :=
|
||||
instance : ForM m (Option α) α :=
|
||||
⟨Option.forM⟩
|
||||
|
||||
instance [Monad m] : ForIn' m (Option α) α inferInstance where
|
||||
instance : ForIn' m (Option α) α inferInstance where
|
||||
forIn' x init f := do
|
||||
match x with
|
||||
| none => return init
|
||||
|
||||
@@ -631,7 +631,7 @@ instance [Ord α] : DecidableRel (@LT.lt α ltOfOrd) := fun a b =>
|
||||
decidable_of_bool (compare a b).isLT Ordering.isLT_iff_eq_lt
|
||||
|
||||
/--
|
||||
Constructs an `LE` instance from an `Ord` instance that asserts that the result of `compare`
|
||||
Constructs an `LT` instance from an `Ord` instance that asserts that the result of `compare`
|
||||
satisfies `Ordering.isLE`.
|
||||
-/
|
||||
@[expose] def leOfOrd [Ord α] : LE α where
|
||||
|
||||
@@ -43,7 +43,7 @@ universe u v
|
||||
have := range.step_pos
|
||||
loop init range.start (by simp)
|
||||
|
||||
instance [Monad m] : ForIn' m Range Nat inferInstance where
|
||||
instance : ForIn' m Range Nat inferInstance where
|
||||
forIn' := Range.forIn'
|
||||
|
||||
-- No separate `ForIn` instance is required because it can be derived from `ForIn'`.
|
||||
@@ -59,7 +59,7 @@ instance [Monad m] : ForIn' m Range Nat inferInstance where
|
||||
have := range.step_pos
|
||||
loop range.start
|
||||
|
||||
instance [Monad m] : ForM m Range Nat where
|
||||
instance : ForM m Range Nat where
|
||||
forM := Range.forM
|
||||
|
||||
syntax:max "[" withoutPosition(":" term) "]" : term
|
||||
|
||||
@@ -2846,7 +2846,6 @@ public theorem size_eq_if_rcc [LE α] [DecidableLE α] [UpwardEnumerable α]
|
||||
· split <;> simp [*]
|
||||
· rfl
|
||||
|
||||
@[simp]
|
||||
public theorem length_toList [LE α] [DecidableLE α] [UpwardEnumerable α]
|
||||
[Rxc.HasSize α] [LawfulUpwardEnumerable α] [LawfulUpwardEnumerableLE α]
|
||||
[Rxc.IsAlwaysFinite α] [Rxc.LawfulHasSize α] :
|
||||
@@ -2865,7 +2864,6 @@ public theorem length_toList [LE α] [DecidableLE α] [UpwardEnumerable α]
|
||||
simp [h, ← ih _ h]
|
||||
· simp
|
||||
|
||||
@[simp]
|
||||
public theorem size_toArray [LE α] [DecidableLE α] [UpwardEnumerable α]
|
||||
[Rxc.HasSize α] [LawfulUpwardEnumerable α] [LawfulUpwardEnumerableLE α]
|
||||
[Rxc.IsAlwaysFinite α] [Rxc.LawfulHasSize α] :
|
||||
@@ -2990,7 +2988,6 @@ public theorem size_eq_match_roc [LE α] [DecidableLE α] [UpwardEnumerable α]
|
||||
rw [size_eq_match_rcc]
|
||||
simp [Rcc.size_eq_if_roc]
|
||||
|
||||
@[simp]
|
||||
public theorem length_toList [LE α] [DecidableLE α] [UpwardEnumerable α]
|
||||
[Rxc.HasSize α] [LawfulUpwardEnumerable α] [LawfulUpwardEnumerableLE α]
|
||||
[Rxc.IsAlwaysFinite α] [Rxc.LawfulHasSize α] :
|
||||
@@ -2998,7 +2995,6 @@ public theorem length_toList [LE α] [DecidableLE α] [UpwardEnumerable α]
|
||||
simp only [toList_eq_match_rcc, size_eq_match_rcc]
|
||||
split <;> simp [Rcc.length_toList]
|
||||
|
||||
@[simp]
|
||||
public theorem size_toArray [LE α] [DecidableLE α] [UpwardEnumerable α]
|
||||
[Rxc.HasSize α] [LawfulUpwardEnumerable α] [LawfulUpwardEnumerableLE α]
|
||||
[Rxc.IsAlwaysFinite α] [Rxc.LawfulHasSize α] :
|
||||
@@ -3098,7 +3094,6 @@ public theorem size_eq_match_roc [Least? α] [LE α] [DecidableLE α] [UpwardEnu
|
||||
rw [size_eq_match_rcc]
|
||||
simp [Rcc.size_eq_if_roc]
|
||||
|
||||
@[simp]
|
||||
public theorem length_toList [Least? α] [LE α] [DecidableLE α] [UpwardEnumerable α]
|
||||
[Rxc.HasSize α] [LawfulUpwardEnumerable α] [LawfulUpwardEnumerableLE α]
|
||||
[Rxc.IsAlwaysFinite α] [Rxc.LawfulHasSize α] :
|
||||
@@ -3106,7 +3101,6 @@ public theorem length_toList [Least? α] [LE α] [DecidableLE α] [UpwardEnumera
|
||||
rw [toList_eq_match_rcc, size_eq_match_rcc]
|
||||
split <;> simp [Rcc.length_toList]
|
||||
|
||||
@[simp]
|
||||
public theorem size_toArray [Least? α] [LE α] [DecidableLE α] [UpwardEnumerable α]
|
||||
[Rxc.HasSize α] [LawfulUpwardEnumerable α] [LawfulUpwardEnumerableLE α]
|
||||
[Rxc.IsAlwaysFinite α] [Rxc.LawfulHasSize α] :
|
||||
@@ -3229,7 +3223,6 @@ public theorem size_eq_if_rcc [LT α] [DecidableLT α] [UpwardEnumerable α]
|
||||
· split <;> simp [*]
|
||||
· rfl
|
||||
|
||||
@[simp]
|
||||
public theorem length_toList [LT α] [DecidableLT α] [UpwardEnumerable α]
|
||||
[Rxo.HasSize α] [LawfulUpwardEnumerable α] [LawfulUpwardEnumerableLT α]
|
||||
[Rxo.IsAlwaysFinite α] [Rxo.LawfulHasSize α] :
|
||||
@@ -3248,7 +3241,6 @@ public theorem length_toList [LT α] [DecidableLT α] [UpwardEnumerable α]
|
||||
simp [h, ← ih _ h]
|
||||
· simp
|
||||
|
||||
@[simp]
|
||||
public theorem size_toArray [LT α] [DecidableLT α] [UpwardEnumerable α]
|
||||
[Rxo.HasSize α] [LawfulUpwardEnumerable α] [LawfulUpwardEnumerableLT α]
|
||||
[Rxo.IsAlwaysFinite α] [Rxo.LawfulHasSize α] :
|
||||
@@ -3374,7 +3366,6 @@ public theorem size_eq_match_roc [LT α] [DecidableLT α] [UpwardEnumerable α]
|
||||
rw [size_eq_match_rcc]
|
||||
simp [Rco.size_eq_if_roo]
|
||||
|
||||
@[simp]
|
||||
public theorem length_toList [LT α] [DecidableLT α] [UpwardEnumerable α]
|
||||
[Rxo.HasSize α] [LawfulUpwardEnumerable α] [LawfulUpwardEnumerableLT α]
|
||||
[Rxo.IsAlwaysFinite α] [Rxo.LawfulHasSize α] :
|
||||
@@ -3382,7 +3373,6 @@ public theorem length_toList [LT α] [DecidableLT α] [UpwardEnumerable α]
|
||||
simp only [toList_eq_match_rco, size_eq_match_rcc]
|
||||
split <;> simp [Rco.length_toList]
|
||||
|
||||
@[simp]
|
||||
public theorem size_toArray [LT α] [DecidableLT α] [UpwardEnumerable α]
|
||||
[Rxo.HasSize α] [LawfulUpwardEnumerable α] [LawfulUpwardEnumerableLT α]
|
||||
[Rxo.IsAlwaysFinite α] [Rxo.LawfulHasSize α] :
|
||||
@@ -3482,7 +3472,6 @@ public theorem size_eq_match_roc [Least? α] [LT α] [DecidableLT α] [UpwardEnu
|
||||
rw [size_eq_match_rcc]
|
||||
simp [Rco.size_eq_if_roo]
|
||||
|
||||
@[simp]
|
||||
public theorem length_toList [Least? α] [LT α] [DecidableLT α] [UpwardEnumerable α]
|
||||
[Rxo.HasSize α] [LawfulUpwardEnumerable α] [LawfulUpwardEnumerableLT α]
|
||||
[Rxo.IsAlwaysFinite α] [Rxo.LawfulHasSize α] :
|
||||
@@ -3490,7 +3479,6 @@ public theorem length_toList [Least? α] [LT α] [DecidableLT α] [UpwardEnumera
|
||||
rw [toList_eq_match_rco, size_eq_match_rcc]
|
||||
split <;> simp [Rco.length_toList]
|
||||
|
||||
@[simp]
|
||||
public theorem size_toArray [Least? α] [LT α] [DecidableLT α] [UpwardEnumerable α]
|
||||
[Rxo.HasSize α] [LawfulUpwardEnumerable α] [LawfulUpwardEnumerableLT α]
|
||||
[Rxo.IsAlwaysFinite α] [Rxo.LawfulHasSize α] :
|
||||
@@ -3602,7 +3590,6 @@ public theorem size_eq_match_rci [UpwardEnumerable α] [Rxi.HasSize α] [LawfulU
|
||||
simp only [Rci.size]
|
||||
split <;> simp [*]
|
||||
|
||||
@[simp]
|
||||
public theorem length_toList [UpwardEnumerable α] [Rxi.HasSize α] [LawfulUpwardEnumerable α]
|
||||
[Rxi.IsAlwaysFinite α] [Rxi.LawfulHasSize α] :
|
||||
r.toList.length = r.size := by
|
||||
@@ -3618,7 +3605,6 @@ public theorem length_toList [UpwardEnumerable α] [Rxi.HasSize α] [LawfulUpwar
|
||||
· simp only [Nat.add_right_cancel_iff, *] at h
|
||||
simp [ih _ h, h]
|
||||
|
||||
@[simp]
|
||||
public theorem size_toArray [UpwardEnumerable α] [Rxi.HasSize α] [LawfulUpwardEnumerable α]
|
||||
[Rxi.IsAlwaysFinite α] [Rxi.LawfulHasSize α] :
|
||||
r.toArray.size = r.size := by
|
||||
@@ -3725,14 +3711,12 @@ public theorem size_eq_match_roi [UpwardEnumerable α] [Rxi.HasSize α] [LawfulU
|
||||
rw [size_eq_match_rci]
|
||||
simp [Rci.size_eq_size_roi]
|
||||
|
||||
@[simp]
|
||||
public theorem length_toList [UpwardEnumerable α] [Rxi.HasSize α] [LawfulUpwardEnumerable α]
|
||||
[Rxi.IsAlwaysFinite α] [Rxi.LawfulHasSize α] :
|
||||
r.toList.length = r.size := by
|
||||
simp only [toList_eq_match_rci, size_eq_match_rci]
|
||||
split <;> simp [Rci.length_toList]
|
||||
|
||||
@[simp]
|
||||
public theorem size_toArray [UpwardEnumerable α] [Rxi.HasSize α] [LawfulUpwardEnumerable α]
|
||||
[Rxi.IsAlwaysFinite α] [Rxi.LawfulHasSize α] :
|
||||
r.toArray.size = r.size := by
|
||||
@@ -3825,7 +3809,6 @@ public theorem size_eq_match_roi [Least? α] [UpwardEnumerable α] [Rxi.HasSize
|
||||
rw [size_eq_match_rci]
|
||||
simp [Rci.size_eq_size_roi]
|
||||
|
||||
@[simp]
|
||||
public theorem length_toList [Least? α] [UpwardEnumerable α]
|
||||
[Rxi.HasSize α] [LawfulUpwardEnumerable α]
|
||||
[Rxi.IsAlwaysFinite α] [Rxi.LawfulHasSize α] :
|
||||
@@ -3833,7 +3816,6 @@ public theorem length_toList [Least? α] [UpwardEnumerable α]
|
||||
rw [toList_eq_match_rci, size_eq_match_rci]
|
||||
split <;> simp [Rci.length_toList]
|
||||
|
||||
@[simp]
|
||||
public theorem size_toArray [Least? α] [UpwardEnumerable α]
|
||||
[Rxi.HasSize α] [LawfulUpwardEnumerable α]
|
||||
[Rxi.IsAlwaysFinite α] [Rxi.LawfulHasSize α] :
|
||||
|
||||
@@ -9,7 +9,6 @@ prelude
|
||||
public import Init.Data.Range.Polymorphic.UpwardEnumerable
|
||||
|
||||
set_option doc.verso true
|
||||
set_option linter.missingDocs true
|
||||
|
||||
public section
|
||||
|
||||
@@ -24,13 +23,7 @@ A range of elements of {given}`α` with closed lower and upper bounds.
|
||||
equal to {given}`b : α`. This is notation for {lean}`Rcc.mk a b`.
|
||||
-/
|
||||
structure Rcc (α : Type u) where
|
||||
/--
|
||||
The lower bound of the range. {name (full := Rcc.lower)}`lower` is included in the range.
|
||||
-/
|
||||
lower : α
|
||||
/--
|
||||
The upper bound of the range. {name (full := Rcc.upper)}`upper` is included in the range.
|
||||
-/
|
||||
upper : α
|
||||
|
||||
/--
|
||||
@@ -40,13 +33,7 @@ A range of elements of {given}`α` with a closed lower bound and an open upper b
|
||||
less than {given}`b : α`. This is notation for {lean}`Rco.mk a b`.
|
||||
-/
|
||||
structure Rco (α : Type u) where
|
||||
/--
|
||||
The lower bound of the range. {name (full := Rco.lower)}`lower` is included in the range.
|
||||
-/
|
||||
lower : α
|
||||
/--
|
||||
The upper bound of the range. {name (full := Rco.upper)}`upper` is not included in the range.
|
||||
-/
|
||||
upper : α
|
||||
|
||||
/--
|
||||
@@ -56,9 +43,6 @@ An upward-unbounded range of elements of {given}`α` with a closed lower bound.
|
||||
This is notation for {lean}`Rci.mk a`.
|
||||
-/
|
||||
structure Rci (α : Type u) where
|
||||
/--
|
||||
The lower bound of the range. {name (full := Rci.lower)}`lower` is included in the range.
|
||||
-/
|
||||
lower : α
|
||||
|
||||
/--
|
||||
@@ -68,13 +52,7 @@ A range of elements of {given}`α` with an open lower bound and a closed upper b
|
||||
{given}`b : α`. This is notation for {lean}`Roc.mk a b`.
|
||||
-/
|
||||
structure Roc (α : Type u) where
|
||||
/--
|
||||
The lower bound of the range. {name (full := Roc.lower)}`lower` is not included in the range.
|
||||
-/
|
||||
lower : α
|
||||
/--
|
||||
The upper bound of the range. {name (full := Roc.upper)}`upper` is included in the range.
|
||||
-/
|
||||
upper : α
|
||||
|
||||
/--
|
||||
@@ -84,13 +62,7 @@ A range of elements of {given}`α` with an open lower and upper bounds.
|
||||
{given}`b : α`. This is notation for {lean}`Roo.mk a b`.
|
||||
-/
|
||||
structure Roo (α : Type u) where
|
||||
/--
|
||||
The lower bound of the range. {name (full := Roo.lower)}`lower` is not included in the range.
|
||||
-/
|
||||
lower : α
|
||||
/--
|
||||
The upper bound of the range. {name (full := Roo.upper)}`upper` is not included in the range.
|
||||
-/
|
||||
upper : α
|
||||
|
||||
/--
|
||||
@@ -100,9 +72,6 @@ An upward-unbounded range of elements of {given}`α` with an open lower bound.
|
||||
This is notation for {lean}`Roi.mk a`.
|
||||
-/
|
||||
structure Roi (α : Type u) where
|
||||
/--
|
||||
The lower bound of the range. {name (full := Roi.lower)}`lower` is not included in the range.
|
||||
-/
|
||||
lower : α
|
||||
|
||||
/--
|
||||
@@ -112,9 +81,6 @@ A downward-unbounded range of elements of {given}`α` with a closed upper bound.
|
||||
This is notation for {lean}`Ric.mk b`.
|
||||
-/
|
||||
structure Ric (α : Type u) where
|
||||
/--
|
||||
The upper bound of the range. {name (full := Ric.upper)}`upper` is included in the range.
|
||||
-/
|
||||
upper : α
|
||||
|
||||
/--
|
||||
@@ -124,9 +90,6 @@ A downward-unbounded range of elements of {given}`α` with an open upper bound.
|
||||
This is notation for {lean}`Rio.mk b`.
|
||||
-/
|
||||
structure Rio (α : Type u) where
|
||||
/--
|
||||
The upper bound of the range. {name (full := Rio.upper)}`upper` is not included in the range.
|
||||
-/
|
||||
upper : α
|
||||
|
||||
/--
|
||||
@@ -199,10 +162,6 @@ This is a prerequisite for many functions and instances, such as
|
||||
{name (scope := "Init.Data.Range.Polymorphic.Iterators")}`Rcc.toList` or {name}`ForIn'`.
|
||||
-/
|
||||
class Rxc.IsAlwaysFinite (α : Type u) [UpwardEnumerable α] [LE α] : Prop where
|
||||
/--
|
||||
For every pair of elements {name}`init` and {name}`hi`, there exists a chain of successors that
|
||||
results in an element that either has no successors or is greater than {name}`hi`.
|
||||
-/
|
||||
finite (init : α) (hi : α) :
|
||||
∃ n, (UpwardEnumerable.succMany? n init).elim True (¬ · ≤ hi)
|
||||
|
||||
@@ -213,10 +172,6 @@ This is a prerequisite for many functions and instances, such as
|
||||
{name (scope := "Init.Data.Range.Polymorphic.Iterators")}`Rco.toList` or {name}`ForIn'`.
|
||||
-/
|
||||
class Rxo.IsAlwaysFinite (α : Type u) [UpwardEnumerable α] [LT α] : Prop where
|
||||
/--
|
||||
For every pair of elements {name}`init` and {name}`hi`, there exists a chain of successors that
|
||||
results in an element that either has no successors or is greater than {name}`hi`.
|
||||
-/
|
||||
finite (init : α) (hi : α) :
|
||||
∃ n, (UpwardEnumerable.succMany? n init).elim True (¬ · < hi)
|
||||
|
||||
@@ -227,10 +182,6 @@ This is a prerequisite for many functions and instances, such as
|
||||
{name (scope := "Init.Data.Range.Polymorphic.Iterators")}`Rci.toList` or {name}`ForIn'`.
|
||||
-/
|
||||
class Rxi.IsAlwaysFinite (α : Type u) [UpwardEnumerable α] : Prop where
|
||||
/--
|
||||
For every elements {name}`init`, there exists a chain of successors that
|
||||
results in an element that has no successors.
|
||||
-/
|
||||
finite (init : α) : ∃ n, UpwardEnumerable.succMany? n init = none
|
||||
|
||||
namespace Rcc
|
||||
@@ -340,7 +291,6 @@ This type class allows taking the intersection of a closed range with a
|
||||
left-closed right-open range, resulting in another left-closed right-open range.
|
||||
-/
|
||||
class Rcc.HasRcoIntersection (α : Type w) where
|
||||
/-- The intersection operator. -/
|
||||
intersection : Rcc α → Rco α → Rco α
|
||||
|
||||
/--
|
||||
@@ -349,9 +299,6 @@ of two ranges contains exactly those elements that are contained in both ranges.
|
||||
-/
|
||||
class Rcc.LawfulRcoIntersection (α : Type w) [LT α] [LE α]
|
||||
[HasRcoIntersection α] where
|
||||
/--
|
||||
Every element of the intersection is an element of both original ranges.
|
||||
-/
|
||||
mem_intersection_iff {a : α} {r : Rcc α} {s : Rco α} :
|
||||
a ∈ HasRcoIntersection.intersection r s ↔ a ∈ r ∧ a ∈ s
|
||||
|
||||
@@ -360,7 +307,6 @@ This type class allows taking the intersection of two left-closed right-open ran
|
||||
another left-closed right-open range.
|
||||
-/
|
||||
class Rco.HasRcoIntersection (α : Type w) where
|
||||
/-- The intersection operator. -/
|
||||
intersection : Rco α → Rco α → Rco α
|
||||
|
||||
/--
|
||||
@@ -369,9 +315,6 @@ of two ranges contains exactly those elements that are contained in both ranges.
|
||||
-/
|
||||
class Rco.LawfulRcoIntersection (α : Type w) [LT α] [LE α]
|
||||
[HasRcoIntersection α] where
|
||||
/--
|
||||
Every element of the intersection is an element of both original ranges.
|
||||
-/
|
||||
mem_intersection_iff {a : α} {r : Rco α} {s : Rco α} :
|
||||
a ∈ HasRcoIntersection.intersection r s ↔ a ∈ r ∧ a ∈ s
|
||||
|
||||
@@ -380,7 +323,6 @@ This type class allows taking the intersection of a left-closed right-unbounded
|
||||
left-closed right-open range, resulting in another left-closed right-open range.
|
||||
-/
|
||||
class Rci.HasRcoIntersection (α : Type w) where
|
||||
/-- The intersection operator. -/
|
||||
intersection : Rci α → Rco α → Rco α
|
||||
|
||||
/--
|
||||
@@ -389,9 +331,6 @@ of two ranges contains exactly those elements that are contained in both ranges.
|
||||
-/
|
||||
class Rci.LawfulRcoIntersection (α : Type w) [LT α] [LE α]
|
||||
[HasRcoIntersection α] where
|
||||
/--
|
||||
Every element of the intersection is an element of both original ranges.
|
||||
-/
|
||||
mem_intersection_iff {a : α} {r : Rci α} {s : Rco α} :
|
||||
a ∈ HasRcoIntersection.intersection r s ↔ a ∈ r ∧ a ∈ s
|
||||
|
||||
@@ -400,7 +339,6 @@ This type class allows taking the intersection of a left-open right-closed range
|
||||
left-closed right-open range, resulting in another left-closed right-open range.
|
||||
-/
|
||||
class Roc.HasRcoIntersection (α : Type w) where
|
||||
/-- The intersection operator. -/
|
||||
intersection : Roc α → Rco α → Rco α
|
||||
|
||||
/--
|
||||
@@ -409,9 +347,6 @@ of two ranges contains exactly those elements that are contained in both ranges.
|
||||
-/
|
||||
class Roc.LawfulRcoIntersection (α : Type w) [LT α] [LE α]
|
||||
[HasRcoIntersection α] where
|
||||
/--
|
||||
Every element of the intersection is an element of both original ranges.
|
||||
-/
|
||||
mem_intersection_iff {a : α} {r : Roc α} {s : Rco α} :
|
||||
a ∈ HasRcoIntersection.intersection r s ↔ a ∈ r ∧ a ∈ s
|
||||
|
||||
@@ -420,7 +355,6 @@ This type class allows taking the intersection of an open range with a
|
||||
left-closed right-open range, resulting in another left-closed right-open range.
|
||||
-/
|
||||
class Roo.HasRcoIntersection (α : Type w) where
|
||||
/-- The intersection operator. -/
|
||||
intersection : Roo α → Rco α → Rco α
|
||||
|
||||
/--
|
||||
@@ -429,9 +363,6 @@ of two ranges contains exactly those elements that are contained in both ranges.
|
||||
-/
|
||||
class Roo.LawfulRcoIntersection (α : Type w) [LT α] [LE α]
|
||||
[HasRcoIntersection α] where
|
||||
/--
|
||||
Every element of the intersection is an element of both original ranges.
|
||||
-/
|
||||
mem_intersection_iff {a : α} {r : Roo α} {s : Rco α} :
|
||||
a ∈ HasRcoIntersection.intersection r s ↔ a ∈ r ∧ a ∈ s
|
||||
|
||||
@@ -440,7 +371,6 @@ This type class allows taking the intersection of a left-open right-unbounded ra
|
||||
left-closed right-open range, resulting in another left-closed right-open range.
|
||||
-/
|
||||
class Roi.HasRcoIntersection (α : Type w) where
|
||||
/-- The intersection operator. -/
|
||||
intersection : Roi α → Rco α → Rco α
|
||||
|
||||
/--
|
||||
@@ -449,9 +379,6 @@ of two ranges contains exactly those elements that are contained in both ranges.
|
||||
-/
|
||||
class Roi.LawfulRcoIntersection (α : Type w) [LT α] [LE α]
|
||||
[HasRcoIntersection α] where
|
||||
/--
|
||||
Every element of the intersection is an element of both original ranges.
|
||||
-/
|
||||
mem_intersection_iff {a : α} {r : Roi α} {s : Rco α} :
|
||||
a ∈ HasRcoIntersection.intersection r s ↔ a ∈ r ∧ a ∈ s
|
||||
|
||||
@@ -460,7 +387,6 @@ This type class allows taking the intersection of a left-unbounded right-closed
|
||||
left-closed right-open range, resulting in another left-closed right-open range.
|
||||
-/
|
||||
class Ric.HasRcoIntersection (α : Type w) where
|
||||
/-- The intersection operator. -/
|
||||
intersection : Ric α → Rco α → Rco α
|
||||
|
||||
/--
|
||||
@@ -469,9 +395,6 @@ of two ranges contains exactly those elements that are contained in both ranges.
|
||||
-/
|
||||
class Ric.LawfulRcoIntersection (α : Type w) [LT α] [LE α]
|
||||
[HasRcoIntersection α] where
|
||||
/--
|
||||
Every element of the intersection is an element of both original ranges.
|
||||
-/
|
||||
mem_intersection_iff {a : α} {r : Ric α} {s : Rco α} :
|
||||
a ∈ HasRcoIntersection.intersection r s ↔ a ∈ r ∧ a ∈ s
|
||||
|
||||
@@ -480,7 +403,6 @@ This type class allows taking the intersection of a left-unbounded right-open ra
|
||||
left-closed right-open range, resulting in another left-closed right-open range.
|
||||
-/
|
||||
class Rio.HasRcoIntersection (α : Type w) where
|
||||
/-- The intersection operator. -/
|
||||
intersection : Rio α → Rco α → Rco α
|
||||
|
||||
/--
|
||||
@@ -489,9 +411,6 @@ of two ranges contains exactly those elements that are contained in both ranges.
|
||||
-/
|
||||
class Rio.LawfulRcoIntersection (α : Type w) [LT α] [LE α]
|
||||
[HasRcoIntersection α] where
|
||||
/--
|
||||
Every element of the intersection is an element of both original ranges.
|
||||
-/
|
||||
mem_intersection_iff {a : α} {r : Rio α} {s : Rco α} :
|
||||
a ∈ HasRcoIntersection.intersection r s ↔ a ∈ r ∧ a ∈ s
|
||||
|
||||
|
||||
@@ -295,15 +295,6 @@ theorem add_def (a b : Rat) :
|
||||
theorem add_def' (a b : Rat) : a + b = mkRat (a.num * b.den + b.num * a.den) (a.den * b.den) := by
|
||||
rw [add_def, normalize_eq_mkRat]
|
||||
|
||||
theorem num_add (a b : Rat) : (a + b).num =
|
||||
(a.num * ↑b.den + b.num * ↑a.den) /
|
||||
↑((a.num * ↑b.den + b.num * ↑a.den).natAbs.gcd (a.den * b.den)) := by
|
||||
rw [add_def, num_normalize]
|
||||
|
||||
theorem den_add (a b : Rat) : (a + b).den =
|
||||
a.den * b.den / (a.num * ↑b.den + b.num * ↑a.den).natAbs.gcd (a.den * b.den) := by
|
||||
rw [add_def, den_normalize]
|
||||
|
||||
@[local simp]
|
||||
protected theorem add_zero (a : Rat) : a + 0 = a := by simp [add_def', mkRat_self]
|
||||
@[local simp]
|
||||
@@ -415,13 +406,6 @@ theorem mul_def (a b : Rat) :
|
||||
theorem mul_def' (a b : Rat) : a * b = mkRat (a.num * b.num) (a.den * b.den) := by
|
||||
rw [mul_def, normalize_eq_mkRat]
|
||||
|
||||
theorem num_mul (a b : Rat) :
|
||||
(a * b).num = a.num * b.num / ↑((a.num * b.num).natAbs.gcd (a.den * b.den)) := by
|
||||
rw [mul_def, num_normalize]
|
||||
theorem den_mul (a b : Rat) :
|
||||
(a * b).den = a.den * b.den / (a.num * b.num).natAbs.gcd (a.den * b.den) := by
|
||||
rw [mul_def, den_normalize]
|
||||
|
||||
protected theorem mul_comm (a b : Rat) : a * b = b * a := by
|
||||
simp [mul_def, normalize_eq_mkRat, Int.mul_comm, Nat.mul_comm]
|
||||
|
||||
|
||||
@@ -23,82 +23,45 @@ variable {α : Type u}
|
||||
|
||||
instance : Rcc.Sliceable (Array α) Nat (Subarray α) where
|
||||
mkSlice xs range :=
|
||||
xs.toSubarray range.lower (range.upper + 1)
|
||||
let halfOpenRange := Rcc.HasRcoIntersection.intersection range 0...<xs.size
|
||||
(xs.toSubarray halfOpenRange.lower halfOpenRange.upper)
|
||||
|
||||
instance : Rco.Sliceable (Array α) Nat (Subarray α) where
|
||||
mkSlice xs range :=
|
||||
xs.toSubarray range.lower range.upper
|
||||
let halfOpenRange := Rco.HasRcoIntersection.intersection range 0...<xs.size
|
||||
(xs.toSubarray halfOpenRange.lower halfOpenRange.upper)
|
||||
|
||||
instance : Rci.Sliceable (Array α) Nat (Subarray α) where
|
||||
mkSlice xs range :=
|
||||
let halfOpenRange := Rci.HasRcoIntersection.intersection range 0...<xs.size
|
||||
xs.toSubarray halfOpenRange.lower halfOpenRange.upper
|
||||
(xs.toSubarray halfOpenRange.lower halfOpenRange.upper)
|
||||
|
||||
instance : Roc.Sliceable (Array α) Nat (Subarray α) where
|
||||
mkSlice xs range :=
|
||||
xs.toSubarray (range.lower + 1) (range.upper + 1)
|
||||
let halfOpenRange := Roc.HasRcoIntersection.intersection range 0...<xs.size
|
||||
(xs.toSubarray halfOpenRange.lower halfOpenRange.upper)
|
||||
|
||||
instance : Roo.Sliceable (Array α) Nat (Subarray α) where
|
||||
mkSlice xs range :=
|
||||
xs.toSubarray (range.lower + 1) range.upper
|
||||
let halfOpenRange := Roo.HasRcoIntersection.intersection range 0...<xs.size
|
||||
(xs.toSubarray halfOpenRange.lower halfOpenRange.upper)
|
||||
|
||||
instance : Roi.Sliceable (Array α) Nat (Subarray α) where
|
||||
mkSlice xs range :=
|
||||
let halfOpenRange := Roi.HasRcoIntersection.intersection range 0...<xs.size
|
||||
xs.toSubarray halfOpenRange.lower halfOpenRange.upper
|
||||
(xs.toSubarray halfOpenRange.lower halfOpenRange.upper)
|
||||
|
||||
instance : Ric.Sliceable (Array α) Nat (Subarray α) where
|
||||
mkSlice xs range :=
|
||||
xs.toSubarray 0 (range.upper + 1)
|
||||
let halfOpenRange := Ric.HasRcoIntersection.intersection range 0...<xs.size
|
||||
(xs.toSubarray halfOpenRange.lower halfOpenRange.upper)
|
||||
|
||||
instance : Rio.Sliceable (Array α) Nat (Subarray α) where
|
||||
mkSlice xs range :=
|
||||
xs.toSubarray 0 range.upper
|
||||
let halfOpenRange := Rio.HasRcoIntersection.intersection range 0...<xs.size
|
||||
(xs.toSubarray halfOpenRange.lower halfOpenRange.upper)
|
||||
|
||||
instance : Rii.Sliceable (Array α) Nat (Subarray α) where
|
||||
mkSlice xs _ :=
|
||||
xs.toSubarray 0 xs.size
|
||||
|
||||
instance : Rcc.Sliceable (Subarray α) Nat (Subarray α) where
|
||||
mkSlice xs range :=
|
||||
let halfOpenRange := Rcc.HasRcoIntersection.intersection range 0...<xs.size
|
||||
xs.array[(halfOpenRange.lower + xs.start)...(halfOpenRange.upper + xs.start)]
|
||||
|
||||
instance : Rco.Sliceable (Subarray α) Nat (Subarray α) where
|
||||
mkSlice xs range :=
|
||||
let halfOpenRange := Rco.HasRcoIntersection.intersection range 0...<xs.size
|
||||
xs.array[(halfOpenRange.lower + xs.start)...(halfOpenRange.upper + xs.start)]
|
||||
|
||||
instance : Rci.Sliceable (Subarray α) Nat (Subarray α) where
|
||||
mkSlice xs range :=
|
||||
let halfOpenRange := Rci.HasRcoIntersection.intersection range 0...<xs.size
|
||||
xs.array[(halfOpenRange.lower + xs.start)...(halfOpenRange.upper + xs.start)]
|
||||
|
||||
instance : Roc.Sliceable (Subarray α) Nat (Subarray α) where
|
||||
mkSlice xs range :=
|
||||
let halfOpenRange := Roc.HasRcoIntersection.intersection range 0...<xs.size
|
||||
xs.array[(halfOpenRange.lower + xs.start)...(halfOpenRange.upper + xs.start)]
|
||||
|
||||
instance : Roo.Sliceable (Subarray α) Nat (Subarray α) where
|
||||
mkSlice xs range :=
|
||||
let halfOpenRange := Roo.HasRcoIntersection.intersection range 0...<xs.size
|
||||
xs.array[(halfOpenRange.lower + xs.start)...(halfOpenRange.upper + xs.start)]
|
||||
|
||||
instance : Roi.Sliceable (Subarray α) Nat (Subarray α) where
|
||||
mkSlice xs range :=
|
||||
let halfOpenRange := Roi.HasRcoIntersection.intersection range 0...<xs.size
|
||||
xs.array[(halfOpenRange.lower + xs.start)...(halfOpenRange.upper + xs.start)]
|
||||
|
||||
instance : Ric.Sliceable (Subarray α) Nat (Subarray α) where
|
||||
mkSlice xs range :=
|
||||
let halfOpenRange := Ric.HasRcoIntersection.intersection range 0...<xs.size
|
||||
xs.array[(halfOpenRange.lower + xs.start)...(halfOpenRange.upper + xs.start)]
|
||||
|
||||
instance : Rio.Sliceable (Subarray α) Nat (Subarray α) where
|
||||
mkSlice xs range :=
|
||||
let halfOpenRange := Rio.HasRcoIntersection.intersection range 0...<xs.size
|
||||
xs.array[(halfOpenRange.lower + xs.start)...(halfOpenRange.upper + xs.start)]
|
||||
|
||||
instance : Rii.Sliceable (Subarray α) Nat (Subarray α) where
|
||||
mkSlice xs _ :=
|
||||
xs
|
||||
let halfOpenRange := 0...<xs.size
|
||||
(xs.toSubarray halfOpenRange.lower halfOpenRange.upper)
|
||||
|
||||
@@ -26,55 +26,38 @@ open Std Slice PRange Iterators
|
||||
|
||||
variable {shape : RangeShape} {α : Type u}
|
||||
|
||||
@[unbox]
|
||||
structure SubarrayIterator (α : Type u) where
|
||||
xs : Subarray α
|
||||
|
||||
@[inline, expose]
|
||||
def SubarrayIterator.step :
|
||||
IterM (α := SubarrayIterator α) Id α → IterStep (IterM (α := SubarrayIterator α) m α) α
|
||||
| ⟨⟨xs⟩⟩ =>
|
||||
if h : xs.start < xs.stop then
|
||||
have := xs.start_le_stop; have := xs.stop_le_array_size
|
||||
.yield ⟨⟨xs.array, xs.start + 1, xs.stop, by omega, xs.stop_le_array_size⟩⟩ xs.array[xs.start]
|
||||
else
|
||||
.done
|
||||
|
||||
instance : Iterator (SubarrayIterator α) Id α where
|
||||
IsPlausibleStep it step := step = SubarrayIterator.step it
|
||||
step it := pure <| .deflate ⟨SubarrayIterator.step it, rfl⟩
|
||||
|
||||
private def SubarrayIterator.instFinitelessRelation : FinitenessRelation (SubarrayIterator α) Id where
|
||||
rel := InvImage WellFoundedRelation.rel (fun it => it.internalState.xs.stop - it.internalState.xs.start)
|
||||
wf := InvImage.wf _ WellFoundedRelation.wf
|
||||
subrelation {it it'} h := by
|
||||
simp [IterM.IsPlausibleSuccessorOf, IterM.IsPlausibleStep, Iterator.IsPlausibleStep, step] at h
|
||||
split at h
|
||||
· cases h
|
||||
simp only [InvImage, Subarray.stop, Subarray.start, WellFoundedRelation.rel, InvImage,
|
||||
Nat.lt_wfRel, sizeOf_nat]
|
||||
exact Nat.sub_succ_lt_self _ _ ‹_›
|
||||
· cases h
|
||||
|
||||
instance SubarrayIterator.instFinite : Finite (SubarrayIterator α) Id :=
|
||||
.of_finitenessRelation instFinitelessRelation
|
||||
|
||||
instance [Monad m] : IteratorCollect (SubarrayIterator α) Id m := .defaultImplementation
|
||||
instance [Monad m] : IteratorCollectPartial (SubarrayIterator α) Id m := .defaultImplementation
|
||||
instance [Monad m] : IteratorLoop (SubarrayIterator α) Id m := .defaultImplementation
|
||||
instance [Monad m] : IteratorLoopPartial (SubarrayIterator α) Id m := .defaultImplementation
|
||||
|
||||
@[inline, expose]
|
||||
def Subarray.instToIterator :=
|
||||
ToIterator.of (γ := Slice (Internal.SubarrayData α)) (β := α) (SubarrayIterator α) (⟨⟨·⟩⟩)
|
||||
attribute [instance] Subarray.instToIterator
|
||||
instance {s : Slice (Internal.SubarrayData α)} : ToIterator s Id α :=
|
||||
.of _
|
||||
(Rco.Internal.iter (s.internalRepresentation.start...<s.internalRepresentation.stop)
|
||||
|>.attachWith (· < s.internalRepresentation.array.size) ?h
|
||||
|>.uLift
|
||||
|>.map fun | .up i => s.internalRepresentation.array[i.1])
|
||||
where finally
|
||||
case h =>
|
||||
simp only [Rco.Internal.isPlausibleIndirectOutput_iter_iff, Membership.mem, and_imp]
|
||||
intro out _ h
|
||||
have := s.internalRepresentation.stop_le_array_size
|
||||
omega
|
||||
|
||||
universe v w
|
||||
|
||||
@[no_expose] instance {s : Slice (Internal.SubarrayData α)} : Iterator (ToIterator.State s Id) Id α := inferInstance
|
||||
@[no_expose] instance {s : Slice (Internal.SubarrayData α)} : Finite (ToIterator.State s Id) Id := inferInstance
|
||||
@[no_expose] instance {s : Slice (Internal.SubarrayData α)} : IteratorCollect (ToIterator.State s Id) Id Id := inferInstance
|
||||
@[no_expose] instance {s : Slice (Internal.SubarrayData α)} : LawfulIteratorCollect (ToIterator.State s Id) Id Id := inferInstance
|
||||
@[no_expose] instance {s : Slice (Internal.SubarrayData α)} : IteratorCollectPartial (ToIterator.State s Id) Id Id := inferInstance
|
||||
@[no_expose] instance {s : Slice (Internal.SubarrayData α)} {m : Type v → Type w} [Monad m] :
|
||||
IteratorLoop (ToIterator.State s Id) Id m := inferInstance
|
||||
@[no_expose] instance {s : Slice (Internal.SubarrayData α)} {m : Type v → Type w} [Monad m] :
|
||||
LawfulIteratorLoop (ToIterator.State s Id) Id m := inferInstance
|
||||
@[no_expose] instance {s : Slice (Internal.SubarrayData α)} {m : Type v → Type w} [Monad m] :
|
||||
IteratorLoopPartial (ToIterator.State s Id) Id m := inferInstance
|
||||
|
||||
instance : SliceSize (Internal.SubarrayData α) where
|
||||
size s := s.internalRepresentation.stop - s.internalRepresentation.start
|
||||
|
||||
instance {α : Type u} {m : Type v → Type w} [Monad m] : ForIn m (Subarray α) α :=
|
||||
instance {α : Type u} {m : Type v → Type w} [Monad m] :
|
||||
ForIn m (Subarray α) α :=
|
||||
inferInstance
|
||||
|
||||
/-!
|
||||
|
||||
@@ -13,100 +13,43 @@ public import Init.Data.Slice.Array.Iterator
|
||||
import all Init.Data.Slice.Array.Iterator
|
||||
import all Init.Data.Slice.Operations
|
||||
import all Init.Data.Range.Polymorphic.Iterators
|
||||
public import Init.Data.Range.Polymorphic.Lemmas
|
||||
import all Init.Data.Range.Polymorphic.Lemmas
|
||||
public import Init.Data.Slice.Lemmas
|
||||
public import Init.Data.Iterators.Lemmas
|
||||
import Init.Data.Slice.List.Lemmas
|
||||
import Init.Data.Range.Polymorphic.NatLemmas
|
||||
|
||||
open Std Std.Iterators Std.PRange Std.Slice
|
||||
|
||||
namespace SubarrayIterator
|
||||
|
||||
theorem step_eq {it : Iter (α := SubarrayIterator α) α} :
|
||||
it.step = if h : it.1.xs.start < it.1.xs.stop then
|
||||
haveI := it.1.xs.start_le_stop
|
||||
haveI := it.1.xs.stop_le_array_size
|
||||
⟨.yield ⟨⟨it.1.xs.array, it.1.xs.start + 1, it.1.xs.stop, by omega, by assumption⟩⟩
|
||||
(it.1.xs.array[it.1.xs.start]'(by omega)),
|
||||
(by
|
||||
simp_all [Iter.IsPlausibleStep, IterM.IsPlausibleStep, Iterator.IsPlausibleStep,
|
||||
SubarrayIterator.step, Iter.toIterM])⟩
|
||||
else
|
||||
⟨.done, (by
|
||||
simpa [Iter.IsPlausibleStep, IterM.IsPlausibleStep, Iterator.IsPlausibleStep,
|
||||
SubarrayIterator.step] using h)⟩ := by
|
||||
simp only [Iter.step, IterM.Step.toPure, Iter.toIter_toIterM, IterStep.mapIterator, IterM.step,
|
||||
Iterator.step, SubarrayIterator.step, Id.run_pure, Shrink.inflate_deflate]
|
||||
by_cases h : it.internalState.xs.start < it.internalState.xs.stop
|
||||
· simp only [h, ↓reduceDIte]
|
||||
split
|
||||
· rfl
|
||||
· rename_i h'
|
||||
exact h'.elim h
|
||||
· simp only [h, ↓reduceDIte]
|
||||
split
|
||||
· rename_i h'
|
||||
exact h.elim h'
|
||||
· rfl
|
||||
|
||||
theorem val_step_eq {it : Iter (α := SubarrayIterator α) α} :
|
||||
it.step.val = if h : it.1.xs.start < it.1.xs.stop then
|
||||
haveI := it.1.xs.start_le_stop
|
||||
haveI := it.1.xs.stop_le_array_size
|
||||
.yield ⟨⟨it.1.xs.array, it.1.xs.start + 1, it.1.xs.stop, by omega, by assumption⟩⟩
|
||||
it.1.xs.array[it.1.xs.start]
|
||||
else
|
||||
.done := by
|
||||
simp only [step_eq]
|
||||
split <;> simp
|
||||
|
||||
theorem toList_eq {α : Type u} {it : Iter (α := SubarrayIterator α) α} :
|
||||
it.toList =
|
||||
(it.internalState.xs.array.toList.take it.internalState.xs.stop).drop it.internalState.xs.start := by
|
||||
induction it using Iter.inductSteps with | step it ihy ihs
|
||||
rw [Iter.toList_eq_match_step, SubarrayIterator.val_step_eq]
|
||||
by_cases h : it.internalState.xs.start < it.internalState.xs.stop
|
||||
· simp [h]
|
||||
have := it.1.xs.start_le_stop
|
||||
have := it.1.xs.stop_le_array_size
|
||||
rw [ihy (out := it.internalState.xs.array[it.internalState.xs.start])]
|
||||
· simp only [Subarray.start]
|
||||
rw (occs := [2]) [List.drop_eq_getElem_cons]; rotate_left
|
||||
· rw [List.length_take]
|
||||
simp [it.internalState.xs.stop_le_array_size]
|
||||
exact h
|
||||
· simp [Subarray.array, Subarray.stop]
|
||||
· simp only [Iter.IsPlausibleStep, IterM.IsPlausibleStep, Iterator.IsPlausibleStep,
|
||||
IterStep.mapIterator_yield, SubarrayIterator.step]
|
||||
rw [dif_pos]; rotate_left; exact h
|
||||
rfl
|
||||
· rw [dif_neg]; rotate_left; exact h
|
||||
simp_all [it.internalState.xs.stop_le_array_size]
|
||||
|
||||
theorem count_eq {α : Type u} {it : Iter (α := SubarrayIterator α) α} :
|
||||
it.count = it.internalState.xs.stop - it.internalState.xs.start := by
|
||||
simp [← Iter.length_toList_eq_count, toList_eq, it.internalState.xs.stop_le_array_size]
|
||||
|
||||
end SubarrayIterator
|
||||
|
||||
namespace Subarray
|
||||
|
||||
theorem internalIter_eq {α : Type u} {s : Subarray α} :
|
||||
Internal.iter s = ⟨⟨s⟩⟩ :=
|
||||
rfl
|
||||
Internal.iter s = (Rco.Internal.iter (s.start...<s.stop)
|
||||
|>.attachWith (· < s.array.size)
|
||||
(fun out h => h
|
||||
|> Rco.Internal.isPlausibleIndirectOutput_iter_iff.mp
|
||||
|> Rco.lt_upper_of_mem
|
||||
|> (Nat.lt_of_lt_of_le · s.stop_le_array_size))
|
||||
|>.uLift
|
||||
|>.map fun | .up i => s.array[i.1]) := by
|
||||
simp [Internal.iter, ToIterator.iter_eq, Subarray.start, Subarray.stop, Subarray.array]
|
||||
|
||||
theorem toList_internalIter {α : Type u} {s : Subarray α} :
|
||||
(Internal.iter s).toList =
|
||||
(s.array.toList.take s.stop).drop s.start := by
|
||||
simp [SubarrayIterator.toList_eq, Internal.iter_eq_toIteratorIter, ToIterator.iter_eq]
|
||||
((s.start...s.stop).toList
|
||||
|>.attachWith (· < s.array.size)
|
||||
(fun out h => h
|
||||
|> Rco.mem_toList_iff_mem.mp
|
||||
|> Rco.lt_upper_of_mem
|
||||
|> (Nat.lt_of_lt_of_le · s.stop_le_array_size))
|
||||
|>.map fun i => s.array[i.1]) := by
|
||||
rw [internalIter_eq, Iter.toList_map, Iter.toList_uLift, Iter.toList_attachWith]
|
||||
simp [Rco.toList]
|
||||
|
||||
public instance : LawfulSliceSize (Internal.SubarrayData α) where
|
||||
lawful s := by
|
||||
simp [SliceSize.size, ToIterator.iter_eq, Iter.toIter_toIterM,
|
||||
← Iter.length_toList_eq_count, SubarrayIterator.toList_eq,
|
||||
s.internalRepresentation.stop_le_array_size, start, stop, array]
|
||||
← Iter.size_toArray_eq_count, ← Rco.Internal.toArray_eq_toArray_iter,
|
||||
Rco.size_toArray, Rco.size, Rxo.HasSize.size, Rxc.HasSize.size]
|
||||
omega
|
||||
|
||||
public theorem toArray_eq_sliceToArray {α : Type u} {s : Subarray α} :
|
||||
s.toArray = Slice.toArray s := by
|
||||
@@ -127,631 +70,3 @@ public theorem forIn_toArray {α : Type u} {s : Subarray α}
|
||||
Slice.forIn_toArray
|
||||
|
||||
end Subarray
|
||||
|
||||
public theorem Array.toSubarray_eq_toSubarray_of_min_eq_min {xs : Array α}
|
||||
{start stop stop' : Nat} (h : min stop xs.size = min stop' xs.size) :
|
||||
xs.toSubarray start stop = xs.toSubarray start stop' := by
|
||||
simp only [Array.toSubarray]
|
||||
split
|
||||
· split
|
||||
· have h₁ : start ≤ xs.size := by omega
|
||||
have h₂ : start ≤ stop' := by omega
|
||||
simp only [dif_pos h₁, dif_pos h₂]
|
||||
split
|
||||
· simp_all
|
||||
· simp_all [Nat.min_eq_right (Nat.le_of_lt _)]
|
||||
· simp only [Nat.min_eq_left, *] at h
|
||||
split
|
||||
· simp only [Nat.min_eq_left, *] at h
|
||||
simp only [h, right_eq_dite_iff, Slice.mk.injEq, Internal.SubarrayData.mk.injEq, and_true,
|
||||
true_and]
|
||||
omega
|
||||
· simp only [ge_iff_le, not_false_eq_true, Nat.min_eq_right (Nat.le_of_not_ge _), *] at h
|
||||
simp [h]
|
||||
omega
|
||||
· split
|
||||
· split
|
||||
· simp only [not_false_eq_true, Nat.min_eq_right (Nat.le_of_not_ge _),
|
||||
Nat.min_eq_left, Nat.not_le, *] at *
|
||||
simp [*]; omega
|
||||
· simp
|
||||
· simp [Nat.min_eq_right (Nat.le_of_not_ge _), *] at h
|
||||
split
|
||||
· simp only [Nat.min_eq_left, *] at h
|
||||
simp [*]; omega
|
||||
· simp
|
||||
|
||||
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
|
||||
simp only [Array.toSubarray]
|
||||
split <;> split <;> simp [Nat.min_eq_right (Nat.le_of_not_ge _), *]
|
||||
|
||||
@[simp]
|
||||
public theorem Array.array_toSubarray {xs : Array α} {lo hi : Nat} :
|
||||
(xs.toSubarray lo hi).array = xs := by
|
||||
simp [toSubarray_eq_min, Subarray.array]
|
||||
|
||||
@[simp]
|
||||
public theorem Array.start_toSubarray {xs : Array α} {lo hi : Nat} :
|
||||
(xs.toSubarray lo hi).start = min lo (min hi xs.size) := by
|
||||
simp [toSubarray_eq_min, Subarray.start]
|
||||
|
||||
@[simp]
|
||||
public theorem Array.stop_toSubarray {xs : Array α} {lo hi : Nat} :
|
||||
(xs.toSubarray lo hi).stop = min hi xs.size := by
|
||||
simp [toSubarray_eq_min, Subarray.stop]
|
||||
|
||||
theorem Subarray.toList_eq {xs : Subarray α} :
|
||||
xs.toList = (xs.array.extract xs.start xs.stop).toList := by
|
||||
let aslice := xs
|
||||
obtain ⟨⟨array, start, stop, h₁, h₂⟩⟩ := xs
|
||||
let lslice : ListSlice α := ⟨array.toList.drop start, some (stop - start)⟩
|
||||
simp only [Subarray.start, Subarray.stop, Subarray.array]
|
||||
change aslice.toList = _
|
||||
have : aslice.toList = lslice.toList := by
|
||||
rw [ListSlice.toList_eq]
|
||||
simp only [aslice, lslice, Std.Slice.toList, toList_internalIter]
|
||||
apply List.ext_getElem
|
||||
· have : stop - start ≤ array.size - start := by omega
|
||||
simp [Subarray.start, Subarray.stop, *, Subarray.array]
|
||||
· intros
|
||||
simp [Subarray.array, Subarray.start, Subarray.stop]
|
||||
simp [this, ListSlice.toList_eq, lslice]
|
||||
|
||||
public theorem Subarray.size_eq {xs : Subarray α} :
|
||||
xs.size = xs.stop - xs.start := by
|
||||
simp [Subarray.size]
|
||||
|
||||
@[simp]
|
||||
public theorem Subarray.toArray_toList {xs : Subarray α} :
|
||||
xs.toList.toArray = xs.toArray := by
|
||||
simp [Std.Slice.toList, Subarray.toArray, Array.ofSubarray, Std.Slice.toArray]
|
||||
|
||||
@[simp]
|
||||
public theorem Subarray.toList_toArray {xs : Subarray α} :
|
||||
xs.toArray.toList = xs.toList := by
|
||||
simp [Std.Slice.toList, Subarray.toArray, Array.ofSubarray, Std.Slice.toArray]
|
||||
|
||||
@[simp]
|
||||
public theorem Subarray.length_toList {xs : Subarray α} :
|
||||
xs.toList.length = xs.size := by
|
||||
have : xs.start ≤ xs.stop := xs.internalRepresentation.start_le_stop
|
||||
have : xs.stop ≤ xs.array.size := xs.internalRepresentation.stop_le_array_size
|
||||
simp [Subarray.toList_eq, Subarray.size]; omega
|
||||
|
||||
@[simp]
|
||||
public theorem Subarray.size_toArray {xs : Subarray α} :
|
||||
xs.toArray.size = xs.size := by
|
||||
simp [← Subarray.toArray_toList, Subarray.size, Slice.size, SliceSize.size, start, stop]
|
||||
|
||||
namespace Array
|
||||
|
||||
@[simp]
|
||||
public theorem array_mkSlice_rco {xs : Array α} {lo hi : Nat} :
|
||||
xs[lo...hi].array = xs := by
|
||||
simp [Std.Rco.Sliceable.mkSlice, Array.toSubarray, apply_dite, Subarray.array]
|
||||
|
||||
@[simp]
|
||||
public theorem start_mkSlice_rco {xs : Array α} {lo hi : Nat} :
|
||||
xs[lo...hi].start = min lo (min hi xs.size) := by
|
||||
simp [Std.Rco.Sliceable.mkSlice]
|
||||
|
||||
@[simp]
|
||||
public theorem stop_mkSlice_rco {xs : Array α} {lo hi : Nat} :
|
||||
xs[lo...hi].stop = min hi xs.size := by
|
||||
simp [Std.Rco.Sliceable.mkSlice]
|
||||
|
||||
public theorem mkSlice_rco_eq_mkSlice_rco_min {xs : Array α} {lo hi : Nat} :
|
||||
xs[lo...hi] = xs[(min lo (min hi xs.size))...(min hi xs.size)] := by
|
||||
simp [Std.Rco.Sliceable.mkSlice, Array.toSubarray_eq_min]
|
||||
|
||||
@[simp]
|
||||
public theorem toList_mkSlice_rco {xs : Array α} {lo hi : Nat} :
|
||||
xs[lo...hi].toList = (xs.toList.take hi).drop lo := by
|
||||
rw [List.take_eq_take_min, List.drop_eq_drop_min]
|
||||
simp [Std.Rco.Sliceable.mkSlice, Subarray.toList_eq, List.take_drop,
|
||||
Nat.add_sub_of_le (Nat.min_le_right _ _)]
|
||||
|
||||
@[simp]
|
||||
public theorem toArray_mkSlice_rco {xs : Array α} {lo hi : Nat} :
|
||||
xs[lo...hi].toArray = xs.extract lo hi := by
|
||||
simp only [← Subarray.toArray_toList, toList_mkSlice_rco]
|
||||
rw [show xs = xs.toList.toArray by simp, List.extract_toArray, List.extract_eq_drop_take]
|
||||
simp only [List.take_drop, mk.injEq]
|
||||
by_cases h : lo ≤ hi
|
||||
· congr 1
|
||||
rw [List.take_eq_take_iff, Nat.add_sub_cancel' h]
|
||||
· rw [List.drop_eq_nil_of_le, List.drop_eq_nil_of_le]
|
||||
· simp; omega
|
||||
· simp; omega
|
||||
|
||||
@[simp]
|
||||
public theorem size_mkSlice_rco {xs : Array α} {lo hi : Nat} :
|
||||
xs[lo...hi].size = min hi xs.size - lo := by
|
||||
simp [← Subarray.length_toList]
|
||||
|
||||
@[simp]
|
||||
public theorem mkSlice_rcc_eq_mkSlice_rco {xs : Array α} {lo hi : Nat} :
|
||||
xs[lo...=hi] = xs[lo...(hi + 1)] := by
|
||||
simp [Std.Rcc.Sliceable.mkSlice, Std.Rco.Sliceable.mkSlice]
|
||||
|
||||
public theorem mkSlice_rcc_eq_mkSlice_rco_min {xs : Array α} {lo hi : Nat} :
|
||||
xs[lo...=hi] = xs[(min lo (min (hi + 1) xs.size))...(min (hi + 1) xs.size)] := by
|
||||
simp [mkSlice_rco_eq_mkSlice_rco_min]
|
||||
|
||||
@[simp]
|
||||
public theorem array_mkSlice_rcc {xs : Array α} {lo hi : Nat} :
|
||||
xs[lo...=hi].array = xs := by
|
||||
simp [Std.Rcc.Sliceable.mkSlice, Array.toSubarray, apply_dite, Subarray.array]
|
||||
|
||||
@[simp]
|
||||
public theorem start_mkSlice_rcc {xs : Array α} {lo hi : Nat} :
|
||||
xs[lo...=hi].start = min lo (min (hi + 1) xs.size) := by
|
||||
simp [Std.Rco.Sliceable.mkSlice]
|
||||
|
||||
@[simp]
|
||||
public theorem stop_mkSlice_rcc {xs : Array α} {lo hi : Nat} :
|
||||
xs[lo...=hi].stop = min (hi + 1) xs.size := by
|
||||
simp [Std.Rco.Sliceable.mkSlice]
|
||||
|
||||
@[simp]
|
||||
public theorem toList_mkSlice_rcc {xs : Array α} {lo hi : Nat} :
|
||||
xs[lo...=hi].toList = (xs.toList.take (hi + 1)).drop lo := by
|
||||
simp
|
||||
|
||||
@[simp]
|
||||
public theorem toArray_mkSlice_rcc {xs : Array α} {lo hi : Nat} :
|
||||
xs[lo...=hi].toArray = xs.extract lo (hi + 1) := by
|
||||
simp
|
||||
|
||||
@[simp]
|
||||
public theorem size_mkSlice_rcc {xs : Array α} {lo hi : Nat} :
|
||||
xs[lo...=hi].size = min (hi + 1) xs.size - lo := by
|
||||
simp [← Subarray.length_toList]
|
||||
|
||||
@[simp]
|
||||
public theorem array_mkSlice_rci {xs : Array α} {lo : Nat} :
|
||||
xs[lo...*].array = xs := by
|
||||
simp [Std.Rci.Sliceable.mkSlice, Array.toSubarray, apply_dite, Subarray.array]
|
||||
|
||||
@[simp]
|
||||
public theorem start_mkSlice_rci {xs : Array α} {lo : Nat} :
|
||||
xs[lo...*].start = min lo xs.size := by
|
||||
simp [Std.Rci.Sliceable.mkSlice, Std.Rci.HasRcoIntersection.intersection]
|
||||
|
||||
@[simp]
|
||||
public theorem stop_mkSlice_rci {xs : Array α} {lo : Nat} :
|
||||
xs[lo...*].stop = xs.size := by
|
||||
simp [Std.Rci.Sliceable.mkSlice, Std.Rci.HasRcoIntersection.intersection]
|
||||
|
||||
@[simp]
|
||||
public theorem mkSlice_rci_eq_mkSlice_rco {xs : Array α} {lo : Nat} :
|
||||
xs[lo...*] = xs[lo...xs.size] := by
|
||||
simp [Std.Rci.Sliceable.mkSlice, Std.Rco.Sliceable.mkSlice, Std.Rci.HasRcoIntersection.intersection]
|
||||
|
||||
public theorem mkSlice_rci_eq_mkSlice_rco_min {xs : Array α} {lo : Nat} :
|
||||
xs[lo...*] = xs[(min lo xs.size)...xs.size] := by
|
||||
simp [mkSlice_rco_eq_mkSlice_rco_min]
|
||||
|
||||
@[simp]
|
||||
public theorem toList_mkSlice_rci {xs : Array α} {lo : Nat} :
|
||||
xs[lo...*].toList = xs.toList.drop lo := by
|
||||
rw [mkSlice_rci_eq_mkSlice_rco, toList_mkSlice_rco, ← Array.length_toList, List.take_length]
|
||||
|
||||
@[simp]
|
||||
public theorem toArray_mkSlice_rci {xs : Array α} {lo : Nat} :
|
||||
xs[lo...*].toArray = xs.extract lo := by
|
||||
simp
|
||||
|
||||
@[simp]
|
||||
public theorem size_mkSlice_rci {xs : Array α} {lo : Nat} :
|
||||
xs[lo...*].size = xs.size - lo := by
|
||||
simp [← Subarray.length_toList]
|
||||
|
||||
@[simp]
|
||||
public theorem array_mkSlice_roo {xs : Array α} {lo hi : Nat} :
|
||||
xs[lo<...hi].array = xs := by
|
||||
simp [Std.Roo.Sliceable.mkSlice, Array.toSubarray, apply_dite, Subarray.array]
|
||||
|
||||
@[simp]
|
||||
public theorem start_mkSlice_roo {xs : Array α} {lo hi : Nat} :
|
||||
xs[lo<...hi].start = min (lo + 1) (min hi xs.size) := by
|
||||
simp [Std.Roo.Sliceable.mkSlice]
|
||||
|
||||
@[simp]
|
||||
public theorem stop_mkSlice_roo {xs : Array α} {lo hi : Nat} :
|
||||
xs[lo<...hi].stop = min hi xs.size := by
|
||||
simp [Std.Roo.Sliceable.mkSlice]
|
||||
|
||||
@[simp]
|
||||
public theorem mkSlice_roo_eq_mkSlice_rco {xs : Array α} {lo hi : Nat} :
|
||||
xs[lo<...hi] = xs[(lo + 1)...hi] := by
|
||||
simp [Std.Roo.Sliceable.mkSlice, Std.Rco.Sliceable.mkSlice]
|
||||
|
||||
public theorem mkSlice_roo_eq_mkSlice_roo_min {xs : Array α} {lo hi : Nat} :
|
||||
xs[lo<...hi] = xs[(min (lo + 1) (min hi xs.size))...(min hi xs.size)] := by
|
||||
simp [mkSlice_rco_eq_mkSlice_rco_min]
|
||||
|
||||
@[simp]
|
||||
public theorem toList_mkSlice_roo {xs : Array α} {lo hi : Nat} :
|
||||
xs[lo<...hi].toList = (xs.toList.take hi).drop (lo + 1) := by
|
||||
simp
|
||||
|
||||
@[simp]
|
||||
public theorem toArray_mkSlice_roo {xs : Array α} {lo hi : Nat} :
|
||||
xs[lo<...hi].toArray = xs.extract (lo + 1) hi := by
|
||||
simp
|
||||
|
||||
@[simp]
|
||||
public theorem size_mkSlice_roo {xs : Array α} {lo hi : Nat} :
|
||||
xs[lo<...hi].size = min hi xs.size - (lo + 1) := by
|
||||
simp [← Subarray.length_toList]
|
||||
|
||||
@[simp]
|
||||
public theorem array_mkSlice_roc {xs : Array α} {lo hi : Nat} :
|
||||
xs[lo<...=hi].array = xs := by
|
||||
simp [Std.Roc.Sliceable.mkSlice, Array.toSubarray, apply_dite, Subarray.array]
|
||||
|
||||
@[simp]
|
||||
public theorem start_mkSlice_roc {xs : Array α} {lo hi : Nat} :
|
||||
xs[lo<...=hi].start = min (lo + 1) (min (hi + 1) xs.size) := by
|
||||
simp [Std.Roc.Sliceable.mkSlice]
|
||||
|
||||
@[simp]
|
||||
public theorem stop_mkSlice_roc {xs : Array α} {lo hi : Nat} :
|
||||
xs[lo<...=hi].stop = min (hi + 1) xs.size := by
|
||||
simp [Std.Roc.Sliceable.mkSlice]
|
||||
|
||||
@[simp]
|
||||
public theorem mkSlice_roc_eq_mkSlice_roo {xs : Array α} {lo hi : Nat} :
|
||||
xs[lo<...=hi] = xs[lo<...(hi + 1)] := by
|
||||
simp [Std.Roc.Sliceable.mkSlice, Std.Roo.Sliceable.mkSlice]
|
||||
|
||||
public theorem mkSlice_roc_eq_mkSlice_roo_min {xs : Array α} {lo hi : Nat} :
|
||||
xs[lo<...=hi] = xs[(min (lo + 1) (min (hi + 1) xs.size))...(min (hi + 1) xs.size)] := by
|
||||
simp [mkSlice_rco_eq_mkSlice_rco_min]
|
||||
|
||||
@[simp]
|
||||
public theorem toList_mkSlice_roc {xs : Array α} {lo hi : Nat} :
|
||||
xs[lo<...=hi].toList = (xs.toList.take (hi + 1)).drop (lo + 1) := by
|
||||
simp
|
||||
|
||||
@[simp]
|
||||
public theorem toArray_mkSlice_roc {xs : Array α} {lo hi : Nat} :
|
||||
xs[lo<...=hi].toArray = xs.extract (lo + 1) (hi + 1) := by
|
||||
simp
|
||||
|
||||
@[simp]
|
||||
public theorem size_mkSlice_roc {xs : Array α} {lo hi : Nat} :
|
||||
xs[lo<...=hi].size = min (hi + 1) xs.size - (lo + 1) := by
|
||||
simp [← Subarray.length_toList]
|
||||
|
||||
@[simp]
|
||||
public theorem array_mkSlice_roi {xs : Array α} {lo : Nat} :
|
||||
xs[lo<...*].array = xs := by
|
||||
simp [Std.Roi.Sliceable.mkSlice, Array.toSubarray, apply_dite, Subarray.array]
|
||||
|
||||
@[simp]
|
||||
public theorem start_mkSlice_roi {xs : Array α} {lo : Nat} :
|
||||
xs[lo<...*].start = min (lo + 1) xs.size := by
|
||||
simp [Std.Roi.Sliceable.mkSlice, Std.Roi.HasRcoIntersection.intersection]
|
||||
|
||||
@[simp]
|
||||
public theorem stop_mkSlice_roi {xs : Array α} {lo : Nat} :
|
||||
xs[lo...*].stop = xs.size := by
|
||||
simp [Std.Rco.Sliceable.mkSlice]
|
||||
|
||||
@[simp]
|
||||
public theorem mkSlice_roi_eq_mkSlice_rci {xs : Array α} {lo : Nat} :
|
||||
xs[lo<...*] = xs[(lo + 1)...*] := by
|
||||
simp [Std.Roi.Sliceable.mkSlice, Std.Roi.HasRcoIntersection.intersection,
|
||||
Std.Rci.Sliceable.mkSlice, Std.Rci.HasRcoIntersection.intersection]
|
||||
|
||||
public theorem mkSlice_roi_eq_mkSlice_roo {xs : Array α} {lo : Nat} :
|
||||
xs[lo<...*] = xs[lo<...xs.size] := by
|
||||
simp [mkSlice_rci_eq_mkSlice_rco]
|
||||
|
||||
public theorem mkSlice_roi_eq_mkSlice_roo_min {xs : Array α} {lo : Nat} :
|
||||
xs[lo<...*] = xs[(min (lo + 1) xs.size)...xs.size] := by
|
||||
simp [mkSlice_rco_eq_mkSlice_rco_min]
|
||||
|
||||
@[simp]
|
||||
public theorem toList_mkSlice_roi {xs : Array α} {lo : Nat} :
|
||||
xs[lo<...*].toList = xs.toList.drop (lo + 1) := by
|
||||
rw [mkSlice_roi_eq_mkSlice_rci, toList_mkSlice_rci]
|
||||
|
||||
@[simp]
|
||||
public theorem toArray_mkSlice_roi {xs : Array α} {lo : Nat} :
|
||||
xs[lo<...*].toArray = xs.drop (lo + 1) := by
|
||||
simp
|
||||
|
||||
@[simp]
|
||||
public theorem size_mkSlice_roi {xs : Array α} {lo : Nat} :
|
||||
xs[lo<...*].size = xs.size - (lo + 1) := by
|
||||
simp [← Subarray.length_toList]
|
||||
|
||||
@[simp]
|
||||
public theorem array_mkSlice_rio {xs : Array α} {hi : Nat} :
|
||||
xs[*...hi].array = xs := by
|
||||
simp [Std.Rio.Sliceable.mkSlice, Array.toSubarray, apply_dite, Subarray.array]
|
||||
|
||||
@[simp]
|
||||
public theorem start_mkSlice_rio {xs : Array α} {hi : Nat} :
|
||||
xs[*...hi].start = 0 := by
|
||||
simp [Std.Rio.Sliceable.mkSlice]
|
||||
|
||||
@[simp]
|
||||
public theorem stop_mkSlice_rio {xs : Array α} {hi : Nat} :
|
||||
xs[*...hi].stop = min hi xs.size := by
|
||||
simp [Std.Rio.Sliceable.mkSlice]
|
||||
|
||||
@[simp]
|
||||
public theorem mkSlice_rio_eq_mkSlice_rco {xs : Array α} {hi : Nat} :
|
||||
xs[*...hi] = xs[0...hi] := by
|
||||
simp [Std.Rio.Sliceable.mkSlice, Std.Rco.Sliceable.mkSlice]
|
||||
|
||||
public theorem mkSlice_rio_eq_mkSlice_rio_min {xs : Array α} {hi : Nat} :
|
||||
xs[*...hi] = xs[*...(min hi xs.size)] := by
|
||||
simp [mkSlice_rco_eq_mkSlice_rco_min]
|
||||
|
||||
@[simp]
|
||||
public theorem toList_mkSlice_rio {xs : Array α} {hi : Nat} :
|
||||
xs[*...hi].toList = xs.toList.take hi := by
|
||||
simp
|
||||
|
||||
@[simp]
|
||||
public theorem toArray_mkSlice_rio {xs : Array α} {hi : Nat} :
|
||||
xs[*...hi].toArray = xs.extract 0 hi := by
|
||||
simp
|
||||
|
||||
@[simp]
|
||||
public theorem size_mkSlice_rio {xs : Array α} {hi : Nat} :
|
||||
xs[*...hi].size = min hi xs.size := by
|
||||
simp [← Subarray.length_toList]
|
||||
|
||||
@[simp]
|
||||
public theorem array_mkSlice_ric {xs : Array α} {hi : Nat} :
|
||||
xs[*...=hi].array = xs := by
|
||||
simp [Std.Ric.Sliceable.mkSlice, Array.toSubarray, apply_dite, Subarray.array]
|
||||
|
||||
@[simp]
|
||||
public theorem start_mkSlice_ric {xs : Array α} {hi : Nat} :
|
||||
xs[*...=hi].start = 0 := by
|
||||
simp [Std.Ric.Sliceable.mkSlice]
|
||||
|
||||
@[simp]
|
||||
public theorem stop_mkSlice_ric {xs : Array α} {hi : Nat} :
|
||||
xs[*...=hi].stop = min (hi + 1) xs.size := by
|
||||
simp [Std.Ric.Sliceable.mkSlice]
|
||||
|
||||
@[simp]
|
||||
public theorem mkSlice_ric_eq_mkSlice_rio {xs : Array α} {hi : Nat} :
|
||||
xs[*...=hi] = xs[*...(hi + 1)] := by
|
||||
simp [Std.Ric.Sliceable.mkSlice, Std.Rio.Sliceable.mkSlice]
|
||||
|
||||
public theorem mkSlice_ric_eq_mkSlice_rio_min {xs : Array α} {hi : Nat} :
|
||||
xs[*...=hi] = xs[*...(min (hi + 1) xs.size)] := by
|
||||
simp [mkSlice_rco_eq_mkSlice_rco_min]
|
||||
|
||||
@[simp]
|
||||
public theorem toList_mkSlice_ric {xs : Array α} {hi : Nat} :
|
||||
xs[*...=hi].toList = xs.toList.take (hi + 1) := by
|
||||
simp
|
||||
|
||||
@[simp]
|
||||
public theorem toArray_mkSlice_ric {xs : Array α} {hi : Nat} :
|
||||
xs[*...=hi].toArray = xs.extract 0 (hi + 1) := by
|
||||
simp
|
||||
|
||||
@[simp]
|
||||
public theorem size_mkSlice_ric {xs : Array α} {hi : Nat} :
|
||||
xs[*...=hi].size = min (hi + 1) xs.size := by
|
||||
simp [← Subarray.length_toList]
|
||||
|
||||
@[simp]
|
||||
public theorem mkSlice_rii_eq_mkSlice_rci {xs : Array α} :
|
||||
xs[*...*] = xs[0...*] := by
|
||||
simp [Std.Rii.Sliceable.mkSlice, Std.Rci.Sliceable.mkSlice,
|
||||
Std.Rci.HasRcoIntersection.intersection]
|
||||
|
||||
public theorem mkSlice_rii_eq_mkSlice_rio {xs : Array α} :
|
||||
xs[*...*] = xs[*...xs.size] := by
|
||||
simp [mkSlice_rci_eq_mkSlice_rco]
|
||||
|
||||
public theorem mkSlice_rii_eq_mkSlice_rio_min {xs : Array α} :
|
||||
xs[*...*] = xs[*...xs.size] := by
|
||||
simp [mkSlice_rco_eq_mkSlice_rco_min]
|
||||
|
||||
@[simp]
|
||||
public theorem toList_mkSlice_rii {xs : Array α} :
|
||||
xs[*...*].toList = xs.toList := by
|
||||
rw [mkSlice_rii_eq_mkSlice_rci, toList_mkSlice_rci, List.drop_zero]
|
||||
|
||||
@[simp]
|
||||
public theorem toArray_mkSlice_rii {xs : Array α} :
|
||||
xs[*...*].toArray = xs := by
|
||||
simp
|
||||
|
||||
@[simp]
|
||||
public theorem size_mkSlice_rii {xs : Array α} :
|
||||
xs[*...*].size = xs.size := by
|
||||
simp [← Subarray.length_toList]
|
||||
|
||||
@[simp]
|
||||
public theorem array_mkSlice_rii {xs : Array α} :
|
||||
xs[*...*].array = xs := by
|
||||
simp
|
||||
|
||||
@[simp]
|
||||
public theorem start_mkSlice_rii {xs : Array α} :
|
||||
xs[*...*].start = 0 := by
|
||||
simp
|
||||
|
||||
@[simp]
|
||||
public theorem stop_mkSlice_rii {xs : Array α} :
|
||||
xs[*...*].stop = xs.size := by
|
||||
simp [Std.Rii.Sliceable.mkSlice]
|
||||
|
||||
end Array
|
||||
|
||||
section SubarraySlices
|
||||
|
||||
namespace Subarray
|
||||
|
||||
@[simp]
|
||||
public theorem toList_mkSlice_rco {xs : Subarray α} {lo hi : Nat} :
|
||||
xs[lo...hi].toList = (xs.toList.take hi).drop lo := by
|
||||
simp only [Std.Rco.Sliceable.mkSlice, Std.Rco.HasRcoIntersection.intersection, toList_eq,
|
||||
Array.start_toSubarray, Array.stop_toSubarray, Array.toList_extract, List.take_drop,
|
||||
List.take_take]
|
||||
rw [Nat.add_sub_cancel' (by omega)]
|
||||
simp [Subarray.size, ← Array.length_toList, ← List.take_eq_take_min, Nat.add_comm xs.start]
|
||||
|
||||
@[simp]
|
||||
public theorem toArray_mkSlice_rco {xs : Subarray α} {lo hi : Nat} :
|
||||
xs[lo...hi].toArray = xs.toArray.extract lo hi := by
|
||||
simp [← Subarray.toArray_toList, List.drop_take]
|
||||
|
||||
@[simp]
|
||||
public theorem mkSlice_rcc_eq_mkSlice_rco {xs : Subarray α} {lo hi : Nat} :
|
||||
xs[lo...=hi] = xs[lo...(hi + 1)] := by
|
||||
simp [Std.Rcc.Sliceable.mkSlice, Std.Rco.Sliceable.mkSlice,
|
||||
Std.Rcc.HasRcoIntersection.intersection, Std.Rco.HasRcoIntersection.intersection]
|
||||
|
||||
@[simp]
|
||||
public theorem toList_mkSlice_rcc {xs : Subarray α} {lo hi : Nat} :
|
||||
xs[lo...=hi].toList = (xs.toList.take (hi + 1)).drop lo := by
|
||||
simp
|
||||
|
||||
@[simp]
|
||||
public theorem toArray_mkSlice_rcc {xs : Subarray α} {lo hi : Nat} :
|
||||
xs[lo...=hi].toArray = xs.toArray.extract lo (hi + 1) := by
|
||||
simp
|
||||
|
||||
@[simp]
|
||||
public theorem mkSlice_rci_eq_mkSlice_rco {xs : Subarray α} {lo : Nat} :
|
||||
xs[lo...*] = xs[lo...xs.size] := by
|
||||
simp [Std.Rci.Sliceable.mkSlice, Std.Rco.Sliceable.mkSlice,
|
||||
Std.Rci.HasRcoIntersection.intersection, Std.Rco.HasRcoIntersection.intersection]
|
||||
|
||||
@[simp]
|
||||
public theorem toList_mkSlice_rci {xs : Subarray α} {lo : Nat} :
|
||||
xs[lo...*].toList = xs.toList.drop lo := by
|
||||
rw [mkSlice_rci_eq_mkSlice_rco, toList_mkSlice_rco, ← Subarray.length_toList, List.take_length]
|
||||
|
||||
@[simp]
|
||||
public theorem toArray_mkSlice_rci {xs : Subarray α} {lo : Nat} :
|
||||
xs[lo...*].toArray = xs.toArray.extract lo := by
|
||||
simp
|
||||
|
||||
@[simp]
|
||||
public theorem mkSlice_roc_eq_mkSlice_roo {xs : Subarray α} {lo hi : Nat} :
|
||||
xs[lo<...=hi] = xs[lo<...(hi + 1)] := by
|
||||
simp [Std.Roc.Sliceable.mkSlice, Std.Roo.Sliceable.mkSlice,
|
||||
Std.Roc.HasRcoIntersection.intersection, Std.Roo.HasRcoIntersection.intersection]
|
||||
|
||||
@[simp]
|
||||
public theorem mkSlice_roo_eq_mkSlice_rco {xs : Subarray α} {lo hi : Nat} :
|
||||
xs[lo<...hi] = xs[(lo + 1)...hi] := by
|
||||
simp [Std.Roo.Sliceable.mkSlice, Std.Rco.Sliceable.mkSlice,
|
||||
Std.Roo.HasRcoIntersection.intersection, Std.Rco.HasRcoIntersection.intersection]
|
||||
|
||||
@[simp]
|
||||
public theorem toList_mkSlice_roo {xs : Subarray α} {lo hi : Nat} :
|
||||
xs[lo<...hi].toList = (xs.toList.take hi).drop (lo + 1) := by
|
||||
simp
|
||||
|
||||
@[simp]
|
||||
public theorem toArray_mkSlice_roo {xs : Subarray α} {lo hi : Nat} :
|
||||
xs[lo<...hi].toArray = xs.toArray.extract (lo + 1) hi := by
|
||||
simp
|
||||
|
||||
@[simp]
|
||||
public theorem mkSlice_roc_eq_mkSlice_rcc {xs : Subarray α} {lo hi : Nat} :
|
||||
xs[lo<...=hi] = xs[(lo + 1)...=hi] := by
|
||||
simp [Std.Roc.Sliceable.mkSlice, Std.Rco.Sliceable.mkSlice,
|
||||
Std.Roc.HasRcoIntersection.intersection, Std.Rco.HasRcoIntersection.intersection]
|
||||
|
||||
@[simp]
|
||||
public theorem toList_mkSlice_roc {xs : Subarray α} {lo hi : Nat} :
|
||||
xs[lo<...=hi].toList = (xs.toList.take (hi + 1)).drop (lo + 1) := by
|
||||
simp
|
||||
|
||||
@[simp]
|
||||
public theorem toArray_mkSlice_roc {xs : Subarray α} {lo hi : Nat} :
|
||||
xs[lo<...=hi].toArray = xs.toArray.extract (lo + 1) (hi + 1) := by
|
||||
simp
|
||||
|
||||
@[simp]
|
||||
public theorem mkSlice_roi_eq_mkSlice_rci {xs : Subarray α} {lo : Nat} :
|
||||
xs[lo<...*] = xs[(lo + 1)...*] := by
|
||||
simp [Std.Roi.Sliceable.mkSlice, Std.Rci.Sliceable.mkSlice,
|
||||
Std.Roi.HasRcoIntersection.intersection, Std.Rci.HasRcoIntersection.intersection]
|
||||
|
||||
@[simp]
|
||||
public theorem toList_mkSlice_roi {xs : Subarray α} {lo : Nat} :
|
||||
xs[lo<...*].toList = xs.toList.drop (lo + 1) := by
|
||||
rw [mkSlice_roi_eq_mkSlice_rci, toList_mkSlice_rci]
|
||||
|
||||
@[simp]
|
||||
public theorem toArray_mkSlice_roi {xs : Subarray α} {lo : Nat} :
|
||||
xs[lo<...*].toArray = xs.toArray.extract (lo + 1) := by
|
||||
simp
|
||||
|
||||
@[simp]
|
||||
public theorem mkSlice_ric_eq_mkSlice_rio {xs : Subarray α} {hi : Nat} :
|
||||
xs[*...=hi] = xs[*...(hi + 1)] := by
|
||||
simp [Std.Ric.Sliceable.mkSlice, Std.Rio.Sliceable.mkSlice,
|
||||
Std.Ric.HasRcoIntersection.intersection, Std.Rio.HasRcoIntersection.intersection]
|
||||
|
||||
@[simp]
|
||||
public theorem mkSlice_rio_eq_mkSlice_rco {xs : Subarray α} {hi : Nat} :
|
||||
xs[*...hi] = xs[0...hi] := by
|
||||
simp [Std.Rio.Sliceable.mkSlice, Std.Rco.Sliceable.mkSlice,
|
||||
Std.Rio.HasRcoIntersection.intersection, Std.Rco.HasRcoIntersection.intersection]
|
||||
|
||||
@[simp]
|
||||
public theorem toList_mkSlice_rio {xs : Subarray α} {hi : Nat} :
|
||||
xs[*...hi].toList = xs.toList.take hi := by
|
||||
simp
|
||||
|
||||
@[simp]
|
||||
public theorem toArray_mkSlice_rio {xs : Subarray α} {hi : Nat} :
|
||||
xs[*...hi].toArray = xs.toArray.extract 0 hi := by
|
||||
simp
|
||||
|
||||
@[simp]
|
||||
public theorem mkSlice_ric_eq_mkSlice_rcc {xs : Subarray α} {hi : Nat} :
|
||||
xs[*...=hi] = xs[0...=hi] := by
|
||||
simp [Std.Ric.Sliceable.mkSlice, Std.Rco.Sliceable.mkSlice,
|
||||
Std.Ric.HasRcoIntersection.intersection, Std.Rco.HasRcoIntersection.intersection]
|
||||
|
||||
@[simp]
|
||||
public theorem toList_mkSlice_ric {xs : Subarray α} {hi : Nat} :
|
||||
xs[*...=hi].toList = xs.toList.take (hi + 1) := by
|
||||
simp
|
||||
|
||||
@[simp]
|
||||
public theorem toArray_mkSlice_ric {xs : Subarray α} {hi : Nat} :
|
||||
xs[*...=hi].toArray = xs.toArray.extract 0 (hi + 1) := by
|
||||
simp
|
||||
|
||||
@[simp]
|
||||
public theorem mkSlice_rii {xs : Subarray α} :
|
||||
xs[*...*] = xs := by
|
||||
simp [Std.Rii.Sliceable.mkSlice]
|
||||
|
||||
@[simp]
|
||||
public theorem toList_mkSlice_rii {xs : Subarray α} :
|
||||
xs[*...*].toList = xs.toList := by
|
||||
rw [mkSlice_rii]
|
||||
|
||||
@[simp]
|
||||
public theorem toArray_mkSlice_rii {xs : Subarray α} :
|
||||
xs[*...*].toArray = xs.toArray := by
|
||||
rw [mkSlice_rii]
|
||||
|
||||
end Subarray
|
||||
|
||||
end SubarraySlices
|
||||
|
||||
@@ -18,20 +18,20 @@ namespace Std.Slice
|
||||
|
||||
open Std.Iterators
|
||||
|
||||
variable {γ : Type u} {α β : Type v}
|
||||
variable {γ : Type u} {β : Type v}
|
||||
|
||||
theorem Internal.iter_eq_toIteratorIter {γ : Type u}
|
||||
[ToIterator (Slice γ) Id α β] {s : Slice γ} :
|
||||
theorem Internal.iter_eq_toIteratorIter {γ : Type u} {s : Slice γ}
|
||||
[ToIterator s Id β] :
|
||||
Internal.iter s = ToIterator.iter s :=
|
||||
(rfl)
|
||||
|
||||
theorem forIn_internalIter {γ : Type u} {β : Type v}
|
||||
{m : Type w → Type x} [Monad m] {δ : Type w}
|
||||
[ToIterator (Slice γ) Id α β]
|
||||
[Iterator α Id β]
|
||||
[IteratorLoop α Id m]
|
||||
[LawfulIteratorLoop α Id m]
|
||||
[Finite α Id] {s : Slice γ}
|
||||
[∀ s : Slice γ, ToIterator s Id β]
|
||||
[∀ s : Slice γ, Iterator (ToIterator.State s Id) Id β]
|
||||
[∀ s : Slice γ, IteratorLoop (ToIterator.State s Id) Id m]
|
||||
[∀ s : Slice γ, LawfulIteratorLoop (ToIterator.State s Id) Id m]
|
||||
[∀ s : Slice γ, Finite (ToIterator.State s Id) Id] {s : Slice γ}
|
||||
{init : δ} {f : β → δ → m (ForInStep δ)} :
|
||||
ForIn.forIn (Internal.iter s) init f = ForIn.forIn s init f :=
|
||||
(rfl)
|
||||
@@ -39,13 +39,13 @@ theorem forIn_internalIter {γ : Type u} {β : Type v}
|
||||
@[simp]
|
||||
public theorem forIn_toList {γ : Type u} {β : Type v}
|
||||
{m : Type w → Type x} [Monad m] [LawfulMonad m] {δ : Type w}
|
||||
[ToIterator (Slice γ) Id α β]
|
||||
[Iterator α Id β]
|
||||
[IteratorLoop α Id m]
|
||||
[LawfulIteratorLoop α Id m]
|
||||
[IteratorCollect α Id Id]
|
||||
[LawfulIteratorCollect α Id Id]
|
||||
[Finite α Id] {s : Slice γ}
|
||||
[∀ s : Slice γ, ToIterator s Id β]
|
||||
[∀ s : Slice γ, Iterator (ToIterator.State s Id) Id β]
|
||||
[∀ s : Slice γ, IteratorLoop (ToIterator.State s Id) Id m]
|
||||
[∀ s : Slice γ, LawfulIteratorLoop (ToIterator.State s Id) Id m]
|
||||
[∀ s : Slice γ, IteratorCollect (ToIterator.State s Id) Id Id]
|
||||
[∀ s : Slice γ, LawfulIteratorCollect (ToIterator.State s Id) Id Id]
|
||||
[∀ s : Slice γ, Finite (ToIterator.State s Id) Id] {s : Slice γ}
|
||||
{init : δ} {f : β → δ → m (ForInStep δ)} :
|
||||
ForIn.forIn s.toList init f = ForIn.forIn s init f := by
|
||||
rw [← forIn_internalIter, ← Iter.forIn_toList, Slice.toList]
|
||||
@@ -53,68 +53,70 @@ public theorem forIn_toList {γ : Type u} {β : Type v}
|
||||
@[simp]
|
||||
public theorem forIn_toArray {γ : Type u} {β : Type v}
|
||||
{m : Type w → Type x} [Monad m] [LawfulMonad m] {δ : Type w}
|
||||
[ToIterator (Slice γ) Id α β]
|
||||
[Iterator α Id β]
|
||||
[IteratorLoop α Id m]
|
||||
[LawfulIteratorLoop α Id m]
|
||||
[IteratorCollect α Id Id]
|
||||
[LawfulIteratorCollect α Id Id]
|
||||
[Finite α Id] {s : Slice γ}
|
||||
[∀ s : Slice γ, ToIterator s Id β]
|
||||
[∀ s : Slice γ, Iterator (ToIterator.State s Id) Id β]
|
||||
[∀ s : Slice γ, IteratorLoop (ToIterator.State s Id) Id m]
|
||||
[∀ s : Slice γ, LawfulIteratorLoop (ToIterator.State s Id) Id m]
|
||||
[∀ s : Slice γ, IteratorCollect (ToIterator.State s Id) Id Id]
|
||||
[∀ s : Slice γ, LawfulIteratorCollect (ToIterator.State s Id) Id Id]
|
||||
[∀ s : Slice γ, Finite (ToIterator.State s Id) Id] {s : Slice γ}
|
||||
{init : δ} {f : β → δ → m (ForInStep δ)} :
|
||||
ForIn.forIn s.toArray init f = ForIn.forIn s init f := by
|
||||
rw [← forIn_internalIter, ← Iter.forIn_toArray, Slice.toArray]
|
||||
|
||||
theorem Internal.size_eq_count_iter [ToIterator (Slice γ) Id α β]
|
||||
[Iterator α Id β] [Finite α Id]
|
||||
[IteratorLoop α Id Id] [LawfulIteratorLoop α Id Id]
|
||||
{s : Slice γ} [SliceSize γ] [LawfulSliceSize γ] :
|
||||
theorem Internal.size_eq_count_iter [∀ s : Slice γ, ToIterator s Id β]
|
||||
[∀ s : Slice γ, Iterator (ToIterator.State s Id) Id β] {s : Slice γ}
|
||||
[Finite (ToIterator.State s Id) Id]
|
||||
[IteratorLoop (ToIterator.State s Id) Id Id] [LawfulIteratorLoop (ToIterator.State s Id) Id Id]
|
||||
[SliceSize γ] [LawfulSliceSize γ] :
|
||||
s.size = (Internal.iter s).count := by
|
||||
letI : IteratorCollect α Id Id := .defaultImplementation
|
||||
letI : IteratorCollect (ToIterator.State s Id) Id Id := .defaultImplementation
|
||||
simp only [Slice.size, iter, LawfulSliceSize.lawful, ← Iter.length_toList_eq_count]
|
||||
|
||||
theorem Internal.toArray_eq_toArray_iter {s : Slice γ} [ToIterator (Slice γ) Id α β]
|
||||
[Iterator α Id β] [IteratorCollect α Id Id]
|
||||
[Finite α Id] :
|
||||
theorem Internal.toArray_eq_toArray_iter {s : Slice γ} [ToIterator s Id β]
|
||||
[Iterator (ToIterator.State s Id) Id β] [IteratorCollect (ToIterator.State s Id) Id Id]
|
||||
[Finite (ToIterator.State s Id) Id] :
|
||||
s.toArray = (Internal.iter s).toArray :=
|
||||
(rfl)
|
||||
|
||||
theorem Internal.toList_eq_toList_iter {s : Slice γ} [ToIterator (Slice γ) Id α β]
|
||||
[Iterator α Id β] [IteratorCollect α Id Id]
|
||||
[Finite α Id] :
|
||||
theorem Internal.toList_eq_toList_iter {s : Slice γ} [ToIterator s Id β]
|
||||
[Iterator (ToIterator.State s Id) Id β] [IteratorCollect (ToIterator.State s Id) Id Id]
|
||||
[Finite (ToIterator.State s Id) Id] :
|
||||
s.toList = (Internal.iter s).toList :=
|
||||
(rfl)
|
||||
|
||||
theorem Internal.toListRev_eq_toListRev_iter {s : Slice γ} [ToIterator (Slice γ) Id α β]
|
||||
[Iterator α Id β] [Finite α Id] :
|
||||
theorem Internal.toListRev_eq_toListRev_iter {s : Slice γ} [ToIterator s Id β]
|
||||
[Iterator (ToIterator.State s Id) Id β] [Finite (ToIterator.State s Id) Id] :
|
||||
s.toListRev = (Internal.iter s).toListRev :=
|
||||
(rfl)
|
||||
|
||||
@[simp]
|
||||
theorem size_toArray_eq_size [ToIterator (Slice γ) Id α β]
|
||||
[Iterator α Id β] [SliceSize γ] [LawfulSliceSize γ]
|
||||
[IteratorCollect α Id Id] [Finite α Id]
|
||||
[LawfulIteratorCollect α Id Id] {s : Slice γ} :
|
||||
theorem size_toArray_eq_size [∀ s : Slice γ, ToIterator s Id β]
|
||||
[∀ s : Slice γ, Iterator (ToIterator.State s Id) Id β] {s : Slice γ}
|
||||
[SliceSize γ] [LawfulSliceSize γ]
|
||||
[IteratorCollect (ToIterator.State s Id) Id Id] [Finite (ToIterator.State s Id) Id]
|
||||
[LawfulIteratorCollect (ToIterator.State s Id) Id Id] :
|
||||
s.toArray.size = s.size := by
|
||||
letI : IteratorLoop α Id Id := .defaultImplementation
|
||||
letI : IteratorLoop (ToIterator.State s Id) Id Id := .defaultImplementation
|
||||
rw [Internal.size_eq_count_iter, Internal.toArray_eq_toArray_iter, Iter.size_toArray_eq_count]
|
||||
|
||||
@[simp]
|
||||
theorem length_toList_eq_size [ToIterator (Slice γ) Id α β]
|
||||
[Iterator α Id β] {s : Slice γ}
|
||||
[SliceSize γ] [LawfulSliceSize γ] [IteratorCollect α Id Id]
|
||||
[Finite α Id] [LawfulIteratorCollect α Id Id] :
|
||||
theorem length_toList_eq_size [∀ s : Slice γ, ToIterator s Id β]
|
||||
[∀ s : Slice γ, Iterator (ToIterator.State s Id) Id β] {s : Slice γ}
|
||||
[SliceSize γ] [LawfulSliceSize γ] [IteratorCollect (ToIterator.State s Id) Id Id]
|
||||
[Finite (ToIterator.State s Id) Id] [LawfulIteratorCollect (ToIterator.State s Id) Id Id] :
|
||||
s.toList.length = s.size := by
|
||||
letI : IteratorLoop α Id Id := .defaultImplementation
|
||||
letI : IteratorLoop (ToIterator.State s Id) Id Id := .defaultImplementation
|
||||
rw [Internal.size_eq_count_iter, Internal.toList_eq_toList_iter, Iter.length_toList_eq_count]
|
||||
|
||||
@[simp]
|
||||
theorem length_toListRev_eq_size [ToIterator (Slice γ) Id α β]
|
||||
[Iterator α Id β] {s : Slice γ}
|
||||
[IteratorLoop α Id Id.{v}] [SliceSize γ] [LawfulSliceSize γ]
|
||||
[Finite α Id]
|
||||
[LawfulIteratorLoop α Id Id] :
|
||||
theorem length_toListRev_eq_size [∀ s : Slice γ, ToIterator s Id β]
|
||||
[∀ s : Slice γ, Iterator (ToIterator.State s Id) Id β] {s : Slice γ}
|
||||
[IteratorLoop (ToIterator.State s Id) Id Id.{v}] [SliceSize γ] [LawfulSliceSize γ]
|
||||
[Finite (ToIterator.State s Id) Id]
|
||||
[LawfulIteratorLoop (ToIterator.State s Id) Id Id] :
|
||||
s.toListRev.length = s.size := by
|
||||
letI : IteratorCollect α Id Id := .defaultImplementation
|
||||
letI : IteratorCollect (ToIterator.State s Id) Id Id := .defaultImplementation
|
||||
rw [Internal.size_eq_count_iter, Internal.toListRev_eq_toListRev_iter,
|
||||
Iter.length_toListRev_eq_count]
|
||||
|
||||
|
||||
@@ -49,7 +49,7 @@ Additionally, the starting index is clamped to the ending index.
|
||||
This function is linear in `start` because it stores `as.drop start` in the slice.
|
||||
-/
|
||||
public def List.toSlice (as : List α) (start : Nat) (stop : Nat) : ListSlice α :=
|
||||
if start < stop then
|
||||
if start ≤ stop then
|
||||
⟨{ list := as.drop start, stop := some (stop - start) }⟩
|
||||
else
|
||||
⟨{ list := [], stop := some 0 }⟩
|
||||
@@ -66,94 +66,36 @@ public def List.toUnboundedSlice (as : List α) (start : Nat) : ListSlice α :=
|
||||
|
||||
public instance : Rcc.Sliceable (List α) Nat (ListSlice α) where
|
||||
mkSlice xs range :=
|
||||
xs.toSlice range.lower (range.upper + 1)
|
||||
(xs.toSlice range.lower (range.upper + 1))
|
||||
|
||||
public instance : Rco.Sliceable (List α) Nat (ListSlice α) where
|
||||
mkSlice xs range :=
|
||||
xs.toSlice range.lower range.upper
|
||||
(xs.toSlice range.lower range.upper)
|
||||
|
||||
public instance : Rci.Sliceable (List α) Nat (ListSlice α) where
|
||||
mkSlice xs range :=
|
||||
xs.toUnboundedSlice range.lower
|
||||
(xs.toUnboundedSlice range.lower)
|
||||
|
||||
public instance : Roc.Sliceable (List α) Nat (ListSlice α) where
|
||||
mkSlice xs range :=
|
||||
xs.toSlice (range.lower + 1) (range.upper + 1)
|
||||
(xs.toSlice (range.lower + 1) (range.upper + 1))
|
||||
|
||||
public instance : Roo.Sliceable (List α) Nat (ListSlice α) where
|
||||
mkSlice xs range :=
|
||||
xs.toSlice (range.lower + 1) range.upper
|
||||
(xs.toSlice (range.lower + 1) range.upper)
|
||||
|
||||
public instance : Roi.Sliceable (List α) Nat (ListSlice α) where
|
||||
mkSlice xs range :=
|
||||
xs.toUnboundedSlice (range.lower + 1)
|
||||
(xs.toUnboundedSlice (range.lower + 1))
|
||||
|
||||
public instance : Ric.Sliceable (List α) Nat (ListSlice α) where
|
||||
mkSlice xs range :=
|
||||
xs.toSlice 0 (range.upper + 1)
|
||||
(xs.toSlice 0 (range.upper + 1))
|
||||
|
||||
public instance : Rio.Sliceable (List α) Nat (ListSlice α) where
|
||||
mkSlice xs range :=
|
||||
xs.toSlice 0 range.upper
|
||||
(xs.toSlice 0 range.upper)
|
||||
|
||||
public instance : Rii.Sliceable (List α) Nat (ListSlice α) where
|
||||
mkSlice xs _ :=
|
||||
xs.toUnboundedSlice 0
|
||||
|
||||
public instance : Rcc.Sliceable (ListSlice α) Nat (ListSlice α) where
|
||||
mkSlice xs range :=
|
||||
let stop := match xs.internalRepresentation.stop with
|
||||
| none => range.upper + 1
|
||||
| some stop => min stop (range.upper + 1)
|
||||
xs.internalRepresentation.list[range.lower...stop]
|
||||
|
||||
public instance : Rco.Sliceable (ListSlice α) Nat (ListSlice α) where
|
||||
mkSlice xs range :=
|
||||
let stop := match xs.internalRepresentation.stop with
|
||||
| none => range.upper
|
||||
| some stop => min stop range.upper
|
||||
xs.internalRepresentation.list[range.lower...stop]
|
||||
|
||||
public instance : Rci.Sliceable (ListSlice α) Nat (ListSlice α) where
|
||||
mkSlice xs range :=
|
||||
match xs.internalRepresentation.stop with
|
||||
| none => xs.internalRepresentation.list[range.lower...*]
|
||||
| some stop => xs.internalRepresentation.list[range.lower...stop]
|
||||
|
||||
public instance : Roc.Sliceable (ListSlice α) Nat (ListSlice α) where
|
||||
mkSlice xs range :=
|
||||
let stop := match xs.internalRepresentation.stop with
|
||||
| none => range.upper + 1
|
||||
| some stop => min stop (range.upper + 1)
|
||||
xs.internalRepresentation.list[range.lower<...stop]
|
||||
|
||||
public instance : Roo.Sliceable (ListSlice α) Nat (ListSlice α) where
|
||||
mkSlice xs range :=
|
||||
let stop := match xs.internalRepresentation.stop with
|
||||
| none => range.upper
|
||||
| some stop => min stop range.upper
|
||||
xs.internalRepresentation.list[range.lower<...stop]
|
||||
|
||||
public instance : Roi.Sliceable (ListSlice α) Nat (ListSlice α) where
|
||||
mkSlice xs range :=
|
||||
match xs.internalRepresentation.stop with
|
||||
| none => xs.internalRepresentation.list[range.lower<...*]
|
||||
| some stop => xs.internalRepresentation.list[range.lower<...stop]
|
||||
|
||||
public instance : Ric.Sliceable (ListSlice α) Nat (ListSlice α) where
|
||||
mkSlice xs range :=
|
||||
let stop := match xs.internalRepresentation.stop with
|
||||
| none => range.upper + 1
|
||||
| some stop => min stop (range.upper + 1)
|
||||
xs.internalRepresentation.list[*...stop]
|
||||
|
||||
public instance : Rio.Sliceable (ListSlice α) Nat (ListSlice α) where
|
||||
mkSlice xs range :=
|
||||
let stop := match xs.internalRepresentation.stop with
|
||||
| none => range.upper
|
||||
| some stop => min stop range.upper
|
||||
xs.internalRepresentation.list[*...stop]
|
||||
|
||||
public instance : Rii.Sliceable (ListSlice α) Nat (ListSlice α) where
|
||||
mkSlice xs _ :=
|
||||
xs
|
||||
(xs.toUnboundedSlice 0)
|
||||
|
||||
@@ -22,27 +22,40 @@ This module implements an iterator for list slices.
|
||||
|
||||
open Std Slice PRange Iterators
|
||||
|
||||
variable {α : Type u}
|
||||
variable {shape : RangeShape} {α : Type u}
|
||||
|
||||
@[inline, expose]
|
||||
def ListSlice.instToIterator :=
|
||||
ToIterator.of (γ := Slice (Internal.ListSliceData α)) _ (fun s => match s.internalRepresentation.stop with
|
||||
instance {s : ListSlice α} : ToIterator s Id α :=
|
||||
.of _ (match s.internalRepresentation.stop with
|
||||
| some n => s.internalRepresentation.list.iter.take n
|
||||
| none => s.internalRepresentation.list.iter.toTake)
|
||||
attribute [instance] ListSlice.instToIterator
|
||||
|
||||
universe v w
|
||||
|
||||
@[no_expose] instance {s : ListSlice α} : Iterator (ToIterator.State s Id) Id α := inferInstance
|
||||
@[no_expose] instance {s : ListSlice α} : Finite (ToIterator.State s Id) Id := inferInstance
|
||||
@[no_expose] instance {s : ListSlice α} : IteratorCollect (ToIterator.State s Id) Id Id := inferInstance
|
||||
@[no_expose] instance {s : ListSlice α} : IteratorCollectPartial (ToIterator.State s Id) Id Id := inferInstance
|
||||
@[no_expose] instance {s : ListSlice α} {m : Type v → Type w} [Monad m] :
|
||||
IteratorLoop (ToIterator.State s Id) Id m := inferInstance
|
||||
@[no_expose] instance {s : ListSlice α} {m : Type v → Type w} [Monad m] :
|
||||
IteratorLoopPartial (ToIterator.State s Id) Id m := inferInstance
|
||||
|
||||
instance : SliceSize (Internal.ListSliceData α) where
|
||||
size s := (Internal.iter s).count
|
||||
|
||||
@[no_expose]
|
||||
instance {α : Type u} {m : Type v → Type w} [Monad m] :
|
||||
instance {α : Type u} {m : Type v → Type w} :
|
||||
ForIn m (ListSlice α) α where
|
||||
forIn xs init f := forIn (Internal.iter xs) init f
|
||||
|
||||
namespace List
|
||||
|
||||
/-- Allocates a new list that contains the contents of the slice. -/
|
||||
def ofSlice (s : ListSlice α) : List α :=
|
||||
s.toList
|
||||
|
||||
docs_to_verso ofSlice
|
||||
|
||||
instance : Append (ListSlice α) where
|
||||
append x y :=
|
||||
let a := x.toList ++ y.toList
|
||||
@@ -60,3 +73,7 @@ instance [ToString α] : ToString (ListSlice α) where
|
||||
toString s := toString s.toArray
|
||||
|
||||
end List
|
||||
|
||||
@[inherit_doc List.ofSlice]
|
||||
def ListSlice.toList (s : ListSlice α) : List α :=
|
||||
List.ofSlice s
|
||||
|
||||
@@ -17,9 +17,7 @@ public import Init.Data.Iterators.Lemmas
|
||||
|
||||
open Std.Iterators Std.PRange
|
||||
|
||||
namespace ListSlice
|
||||
|
||||
open Std.Slice
|
||||
namespace Std.Slice.List
|
||||
|
||||
theorem internalIter_eq {α : Type u} {s : ListSlice α} :
|
||||
Internal.iter s = match s.internalRepresentation.stop with
|
||||
@@ -42,355 +40,4 @@ public instance : LawfulSliceSize (Internal.ListSliceData α) where
|
||||
lawful s := by
|
||||
simp [← internalIter_eq_toIteratorIter, SliceSize.size]
|
||||
|
||||
public theorem toList_eq {xs : ListSlice α} :
|
||||
xs.toList = match xs.internalRepresentation.stop with
|
||||
| some stop => xs.internalRepresentation.list.take stop
|
||||
| none => xs.internalRepresentation.list := by
|
||||
simp only [Std.Slice.toList, toList_internalIter]
|
||||
rfl
|
||||
|
||||
public theorem toArray_toList {xs : ListSlice α} :
|
||||
xs.toList.toArray = xs.toArray := by
|
||||
simp [Std.Slice.toArray, Std.Slice.toList]
|
||||
|
||||
public theorem toList_toArray {xs : ListSlice α} :
|
||||
xs.toArray.toList = xs.toList := by
|
||||
simp [Std.Slice.toArray, Std.Slice.toList]
|
||||
|
||||
@[simp]
|
||||
public theorem length_toList {xs : ListSlice α} :
|
||||
xs.toList.length = xs.size := by
|
||||
simp [ListSlice.toList_eq, Std.Slice.size, Std.Slice.SliceSize.size, ← Iter.length_toList_eq_count,
|
||||
toList_internalIter]; rfl
|
||||
|
||||
@[simp]
|
||||
public theorem size_toArray {xs : ListSlice α} :
|
||||
xs.toArray.size = xs.size := by
|
||||
simp [← ListSlice.toArray_toList]
|
||||
|
||||
end ListSlice
|
||||
|
||||
namespace List
|
||||
|
||||
@[simp]
|
||||
public theorem toList_mkSlice_rco {xs : List α} {lo hi : Nat} :
|
||||
xs[lo...hi].toList = (xs.take hi).drop lo := by
|
||||
rw [List.take_eq_take_min, List.drop_eq_drop_min]
|
||||
simp only [Std.Rco.Sliceable.mkSlice, toSlice, ListSlice.toList_eq]
|
||||
by_cases h : lo < hi
|
||||
· have : lo ≤ hi := by omega
|
||||
simp [h, List.take_drop, Nat.add_sub_cancel' ‹_›, ← List.take_eq_take_min]
|
||||
· have : min hi xs.length ≤ lo := by omega
|
||||
simp [h, Nat.min_eq_right this]
|
||||
|
||||
@[simp]
|
||||
public theorem toArray_mkSlice_rco {xs : List α} {lo hi : Nat} :
|
||||
xs[lo...hi].toArray = ((xs.take hi).drop lo).toArray := by
|
||||
simp [← ListSlice.toArray_toList]
|
||||
|
||||
@[simp]
|
||||
public theorem size_mkSlice_rco {xs : List α} {lo hi : Nat} :
|
||||
xs[lo...hi].size = min hi xs.length - lo := by
|
||||
simp [← ListSlice.length_toList]
|
||||
|
||||
@[simp]
|
||||
public theorem mkSlice_rcc_eq_mkSlice_rco {xs : List α} {lo hi : Nat} :
|
||||
xs[lo...=hi] = xs[lo...(hi + 1)] := by
|
||||
simp [Std.Rcc.Sliceable.mkSlice, Std.Rco.Sliceable.mkSlice]
|
||||
|
||||
@[simp]
|
||||
public theorem toList_mkSlice_rcc {xs : List α} {lo hi : Nat} :
|
||||
xs[lo...=hi].toList = (xs.take (hi + 1)).drop lo := by
|
||||
simp
|
||||
|
||||
@[simp]
|
||||
public theorem toArray_mkSlice_rcc {xs : List α} {lo hi : Nat} :
|
||||
xs[lo...=hi].toArray = ((xs.take (hi + 1)).drop lo).toArray := by
|
||||
simp [← ListSlice.toArray_toList]
|
||||
|
||||
@[simp]
|
||||
public theorem size_mkSlice_rcc {xs : List α} {lo hi : Nat} :
|
||||
xs[lo...=hi].size = min (hi + 1) xs.length - lo := by
|
||||
simp [← ListSlice.length_toList]
|
||||
|
||||
@[simp]
|
||||
public theorem toList_mkSlice_rci {xs : List α} {lo : Nat} :
|
||||
xs[lo...*].toList = xs.drop lo := by
|
||||
rw [List.drop_eq_drop_min]
|
||||
simp [ListSlice.toList_eq, Std.Rci.Sliceable.mkSlice, List.toUnboundedSlice]
|
||||
|
||||
@[simp]
|
||||
public theorem toArray_mkSlice_rci {xs : List α} {lo : Nat} :
|
||||
xs[lo...*].toArray = (xs.drop lo).toArray := by
|
||||
simp [← ListSlice.toArray_toList]
|
||||
|
||||
@[simp]
|
||||
public theorem size_mkSlice_rci {xs : List α} {lo : Nat} :
|
||||
xs[lo...*].size = xs.length - lo := by
|
||||
simp [← ListSlice.length_toList]
|
||||
|
||||
@[simp]
|
||||
public theorem mkSlice_roo_eq_mkSlice_rco {xs : List α} {lo hi : Nat} :
|
||||
xs[lo<...hi] = xs[(lo + 1)...hi] := by
|
||||
simp [Std.Roo.Sliceable.mkSlice, Std.Rco.Sliceable.mkSlice]
|
||||
|
||||
@[simp]
|
||||
public theorem toList_mkSlice_roo {xs : List α} {lo hi : Nat} :
|
||||
xs[lo<...hi].toList = (xs.take hi).drop (lo + 1) := by
|
||||
simp
|
||||
|
||||
@[simp]
|
||||
public theorem toArray_mkSlice_roo {xs : List α} {lo hi : Nat} :
|
||||
xs[lo<...hi].toArray = ((xs.take hi).drop (lo + 1)).toArray := by
|
||||
simp [← ListSlice.toArray_toList]
|
||||
|
||||
@[simp]
|
||||
public theorem size_mkSlice_roo {xs : List α} {lo hi : Nat} :
|
||||
xs[lo<...hi].size = min hi xs.length - (lo + 1) := by
|
||||
simp [← ListSlice.length_toList]
|
||||
|
||||
@[simp]
|
||||
public theorem mkSlice_roc_eq_mkSlice_roo {xs : List α} {lo hi : Nat} :
|
||||
xs[lo<...=hi] = xs[lo<...(hi + 1)] := by
|
||||
simp [Std.Roc.Sliceable.mkSlice, Std.Roo.Sliceable.mkSlice]
|
||||
|
||||
@[simp]
|
||||
public theorem toList_mkSlice_roc {xs : List α} {lo hi : Nat} :
|
||||
xs[lo<...=hi].toList = (xs.take (hi + 1)).drop (lo + 1) := by
|
||||
simp
|
||||
|
||||
@[simp]
|
||||
public theorem toArray_mkSlice_roc {xs : List α} {lo hi : Nat} :
|
||||
xs[lo<...=hi].toArray = ((xs.take (hi + 1)).drop (lo + 1)).toArray := by
|
||||
simp [← ListSlice.toArray_toList]
|
||||
|
||||
@[simp]
|
||||
public theorem size_mkSlice_roc {xs : List α} {lo hi : Nat} :
|
||||
xs[lo<...=hi].size = min (hi + 1) xs.length - (lo + 1) := by
|
||||
simp [← ListSlice.length_toList]
|
||||
|
||||
@[simp]
|
||||
public theorem mkSlice_roi_eq_mkSlice_rci {xs : List α} {lo : Nat} :
|
||||
xs[lo<...*] = xs[(lo + 1)...*] := by
|
||||
simp [Std.Roi.Sliceable.mkSlice, Std.Rci.Sliceable.mkSlice]
|
||||
|
||||
@[simp]
|
||||
public theorem toList_mkSlice_roi {xs : List α} {lo : Nat} :
|
||||
xs[lo<...*].toList = xs.drop (lo + 1) := by
|
||||
simp
|
||||
|
||||
@[simp]
|
||||
public theorem toArray_mkSlice_roi {xs : List α} {lo : Nat} :
|
||||
xs[lo<...*].toArray = (xs.drop (lo + 1)).toArray := by
|
||||
simp [← ListSlice.toArray_toList]
|
||||
|
||||
@[simp]
|
||||
public theorem size_mkSlice_roi {xs : List α} {lo : Nat} :
|
||||
xs[lo<...*].size = xs.length - (lo + 1) := by
|
||||
simp [← ListSlice.length_toList]
|
||||
|
||||
@[simp]
|
||||
public theorem mkSlice_rio_eq_mkSlice_rco {xs : List α} {hi : Nat} :
|
||||
xs[*...hi] = xs[0...hi] := by
|
||||
simp [Std.Rio.Sliceable.mkSlice, Std.Rco.Sliceable.mkSlice]
|
||||
|
||||
@[simp]
|
||||
public theorem toList_mkSlice_rio {xs : List α} {hi : Nat} :
|
||||
xs[*...hi].toList = xs.take hi := by
|
||||
simp
|
||||
|
||||
@[simp]
|
||||
public theorem toArray_mkSlice_rio {xs : List α} {hi : Nat} :
|
||||
xs[*...hi].toArray = (xs.take hi).toArray := by
|
||||
simp [← ListSlice.toArray_toList]
|
||||
|
||||
@[simp]
|
||||
public theorem size_mkSlice_rio {xs : List α} {hi : Nat} :
|
||||
xs[*...hi].size = min hi xs.length := by
|
||||
simp [← ListSlice.length_toList]
|
||||
|
||||
@[simp]
|
||||
public theorem mkSlice_ric_eq_mkSlice_rio {xs : List α} {hi : Nat} :
|
||||
xs[*...=hi] = xs[*...(hi + 1)] := by
|
||||
simp [Std.Ric.Sliceable.mkSlice, Std.Rio.Sliceable.mkSlice]
|
||||
|
||||
@[simp]
|
||||
public theorem toList_mkSlice_ric {xs : List α} {hi : Nat} :
|
||||
xs[*...=hi].toList = xs.take (hi + 1) := by
|
||||
simp
|
||||
|
||||
@[simp]
|
||||
public theorem toArray_mkSlice_ric {xs : List α} {hi : Nat} :
|
||||
xs[*...=hi].toArray = (xs.take (hi + 1)).toArray := by
|
||||
simp [← ListSlice.toArray_toList]
|
||||
|
||||
@[simp]
|
||||
public theorem size_mkSlice_ric {xs : List α} {hi : Nat} :
|
||||
xs[*...=hi].size = min (hi + 1) xs.length := by
|
||||
simp [← ListSlice.length_toList]
|
||||
|
||||
@[simp]
|
||||
public theorem mkSlice_rii_eq_mkSlice_rci {xs : List α} :
|
||||
xs[*...*] = xs[0...*] := by
|
||||
simp [Std.Rii.Sliceable.mkSlice, Std.Rci.Sliceable.mkSlice]
|
||||
|
||||
@[simp]
|
||||
public theorem toList_mkSlice_rii {xs : List α} :
|
||||
xs[*...*].toList = xs := by
|
||||
simp
|
||||
|
||||
@[simp]
|
||||
public theorem toArray_mkSlice_rii {xs : List α} :
|
||||
xs[*...*].toArray = xs.toArray := by
|
||||
simp [← ListSlice.toArray_toList]
|
||||
|
||||
@[simp]
|
||||
public theorem size_mkSlice_rii {xs : List α} :
|
||||
xs[*...*].size = xs.length := by
|
||||
simp [← ListSlice.length_toList]
|
||||
|
||||
end List
|
||||
|
||||
section ListSubslices
|
||||
|
||||
namespace ListSlice
|
||||
|
||||
@[simp]
|
||||
public theorem toList_mkSlice_rco {xs : ListSlice α} {lo hi : Nat} :
|
||||
xs[lo...hi].toList = (xs.toList.take hi).drop lo := by
|
||||
simp only [instSliceableListSliceNat_1, List.toList_mkSlice_rco, ListSlice.toList_eq (xs := xs)]
|
||||
obtain ⟨⟨xs, stop⟩⟩ := xs
|
||||
cases stop
|
||||
· simp
|
||||
· simp [List.take_take, Nat.min_comm]
|
||||
|
||||
@[simp]
|
||||
public theorem toArray_mkSlice_rco {xs : ListSlice α} {lo hi : Nat} :
|
||||
xs[lo...hi].toArray = xs.toArray.extract lo hi := by
|
||||
simp [← toArray_toList, List.drop_take]
|
||||
|
||||
@[simp]
|
||||
public theorem mkSlice_rcc_eq_mkSlice_rco {xs : ListSlice α} {lo hi : Nat} :
|
||||
xs[lo...=hi] = xs[lo...(hi + 1)] := by
|
||||
simp [Std.Rcc.Sliceable.mkSlice, Std.Rco.Sliceable.mkSlice]
|
||||
|
||||
@[simp]
|
||||
public theorem toList_mkSlice_rcc {xs : ListSlice α} {lo hi : Nat} :
|
||||
xs[lo...=hi].toList = (xs.toList.take (hi + 1)).drop lo := by
|
||||
simp
|
||||
|
||||
@[simp]
|
||||
public theorem toArray_mkSlice_rcc {xs : ListSlice α} {lo hi : Nat} :
|
||||
xs[lo...=hi].toArray = xs.toArray.extract lo (hi + 1) := by
|
||||
simp [← ListSlice.toArray_toList, List.drop_take]
|
||||
|
||||
@[simp]
|
||||
public theorem toList_mkSlice_rci {xs : ListSlice α} {lo : Nat} :
|
||||
xs[lo...*].toList = xs.toList.drop lo := by
|
||||
simp only [instSliceableListSliceNat_2, ListSlice.toList_eq (xs := xs)]
|
||||
obtain ⟨⟨xs, stop⟩⟩ := xs
|
||||
simp only
|
||||
split <;> simp
|
||||
|
||||
@[simp]
|
||||
public theorem toArray_mkSlice_rci {xs : ListSlice α} {lo : Nat} :
|
||||
xs[lo...*].toArray = xs.toArray.extract lo := by
|
||||
simp only [← toArray_toList, toList_mkSlice_rci]
|
||||
rw (occs := [1]) [← List.take_length (l := List.drop lo xs.toList)]
|
||||
simp
|
||||
|
||||
@[simp]
|
||||
public theorem mkSlice_roo_eq_mkSlice_rco {xs : ListSlice α} {lo hi : Nat} :
|
||||
xs[lo<...hi] = xs[(lo + 1)...hi] := by
|
||||
simp [Std.Roo.Sliceable.mkSlice, Std.Rco.Sliceable.mkSlice]
|
||||
|
||||
@[simp]
|
||||
public theorem toList_mkSlice_roo {xs : ListSlice α} {lo hi : Nat} :
|
||||
xs[lo<...hi].toList = (xs.toList.take hi).drop (lo + 1) := by
|
||||
simp
|
||||
|
||||
@[simp]
|
||||
public theorem toArray_mkSlice_roo {xs : ListSlice α} {lo hi : Nat} :
|
||||
xs[lo<...hi].toArray = xs.toArray.extract (lo + 1) hi := by
|
||||
simp [← toArray_toList, List.drop_take]
|
||||
|
||||
@[simp]
|
||||
public theorem mkSlice_roc_eq_mkSlice_roo {xs : ListSlice α} {lo hi : Nat} :
|
||||
xs[lo<...=hi] = xs[lo<...(hi + 1)] := by
|
||||
simp [Std.Roc.Sliceable.mkSlice, Std.Roo.Sliceable.mkSlice]
|
||||
|
||||
@[simp]
|
||||
public theorem mkSlice_roc_eq_mkSlice_rcc {xs : ListSlice α} {lo hi : Nat} :
|
||||
xs[lo<...=hi] = xs[(lo + 1)...=hi] := by
|
||||
simp [Std.Roc.Sliceable.mkSlice, Std.Rco.Sliceable.mkSlice]
|
||||
|
||||
@[simp]
|
||||
public theorem toList_mkSlice_roc {xs : ListSlice α} {lo hi : Nat} :
|
||||
xs[lo<...=hi].toList = (xs.toList.take (hi + 1)).drop (lo + 1) := by
|
||||
simp
|
||||
|
||||
@[simp]
|
||||
public theorem toArray_mkSlice_roc {xs : ListSlice α} {lo hi : Nat} :
|
||||
xs[lo<...=hi].toArray = xs.toArray.extract (lo + 1) (hi + 1) := by
|
||||
simp [← toArray_toList, List.drop_take]
|
||||
|
||||
@[simp]
|
||||
public theorem mkSlice_roi_eq_mkSlice_rci {xs : ListSlice α} {lo : Nat} :
|
||||
xs[lo<...*] = xs[(lo + 1)...*] := by
|
||||
simp [Std.Roi.Sliceable.mkSlice, Std.Rci.Sliceable.mkSlice]
|
||||
|
||||
@[simp]
|
||||
public theorem toList_mkSlice_roi {xs : ListSlice α} {lo : Nat} :
|
||||
xs[lo<...*].toList = xs.toList.drop (lo + 1) := by
|
||||
simp
|
||||
|
||||
@[simp]
|
||||
public theorem toArray_mkSlice_roi {xs : ListSlice α} {lo : Nat} :
|
||||
xs[lo<...*].toArray = xs.toArray.extract (lo + 1) := by
|
||||
simp only [← toArray_toList, toList_mkSlice_roi]
|
||||
rw (occs := [1]) [← List.take_length (l := List.drop (lo + 1) xs.toList)]
|
||||
simp
|
||||
|
||||
@[simp]
|
||||
public theorem mkSlice_rio_eq_mkSlice_rco {xs : ListSlice α} {hi : Nat} :
|
||||
xs[*...hi] = xs[0...hi] := by
|
||||
simp [Std.Rio.Sliceable.mkSlice, Std.Rco.Sliceable.mkSlice]
|
||||
|
||||
@[simp]
|
||||
public theorem toList_mkSlice_rio {xs : ListSlice α} {hi : Nat} :
|
||||
xs[*...hi].toList = xs.toList.take hi := by
|
||||
simp
|
||||
|
||||
@[simp]
|
||||
public theorem toArray_mkSlice_rio {xs : ListSlice α} {hi : Nat} :
|
||||
xs[*...hi].toArray = xs.toArray.extract 0 hi := by
|
||||
simp [← toArray_toList]
|
||||
|
||||
@[simp]
|
||||
public theorem mkSlice_ric_eq_mkSlice_rio {xs : ListSlice α} {hi : Nat} :
|
||||
xs[*...=hi] = xs[*...(hi + 1)] := by
|
||||
simp [Std.Ric.Sliceable.mkSlice, Std.Rio.Sliceable.mkSlice]
|
||||
|
||||
@[simp]
|
||||
public theorem mkSlice_ric_eq_mkSlice_rcc {xs : ListSlice α} {hi : Nat} :
|
||||
xs[*...=hi] = xs[0...=hi] := by
|
||||
simp [Std.Ric.Sliceable.mkSlice, Std.Rco.Sliceable.mkSlice]
|
||||
|
||||
@[simp]
|
||||
public theorem toList_mkSlice_ric {xs : ListSlice α} {hi : Nat} :
|
||||
xs[*...=hi].toList = xs.toList.take (hi + 1) := by
|
||||
simp
|
||||
|
||||
@[simp]
|
||||
public theorem toArray_mkSlice_ric {xs : ListSlice α} {hi : Nat} :
|
||||
xs[*...=hi].toArray = xs.toArray.extract 0 (hi + 1) := by
|
||||
simp [← toArray_toList]
|
||||
|
||||
@[simp]
|
||||
public theorem mkSlice_rii {xs : ListSlice α} :
|
||||
xs[*...*] = xs := by
|
||||
simp [Std.Rii.Sliceable.mkSlice]
|
||||
|
||||
end ListSlice
|
||||
|
||||
end ListSubslices
|
||||
end Std.Slice.List
|
||||
|
||||
@@ -16,36 +16,37 @@ open Std.Iterators
|
||||
|
||||
namespace Std.Slice
|
||||
|
||||
instance [ToIterator γ m α β] : ToIterator (Slice γ) m α β where
|
||||
iterMInternal x := ToIterator.iterMInternal x.internalRepresentation
|
||||
instance {x : γ} [ToIterator x m β] : ToIterator (Slice.mk x) m β where
|
||||
State := ToIterator.State x m
|
||||
iterMInternal := ToIterator.iterMInternal
|
||||
|
||||
/--
|
||||
Internal function to obtain an iterator from a slice. Users should import `Std.Data.Iterators`
|
||||
and use `Std.Slice.iter` instead.
|
||||
-/
|
||||
@[always_inline, inline]
|
||||
def Internal.iter [ToIterator (Slice γ) Id α β] (s : Slice γ) :=
|
||||
def Internal.iter (s : Slice γ) [ToIterator s Id β] :=
|
||||
ToIterator.iter s
|
||||
|
||||
/--
|
||||
This type class provides support for the `Slice.size` function.
|
||||
-/
|
||||
class SliceSize (γ : Type u) where
|
||||
class SliceSize (α : Type u) where
|
||||
/-- Computes the slice of a `Slice`. Use `Slice.size` instead. -/
|
||||
size (slice : Slice γ) : Nat
|
||||
size (slice : Slice α) : Nat
|
||||
|
||||
/--
|
||||
This type class states that the slice's iterator emits exactly `Slice.size` elements before
|
||||
terminating.
|
||||
-/
|
||||
class LawfulSliceSize (γ : Type u) [SliceSize γ] [ToIterator (Slice γ) Id α β]
|
||||
[Iterator α Id β] where
|
||||
class LawfulSliceSize (α : Type u) [SliceSize α] [∀ s : Slice α, ToIterator s Id β]
|
||||
[∀ s : Slice α, Iterator (ToIterator.State s Id) Id β] where
|
||||
/-- The iterator for every `Slice α` is finite. -/
|
||||
[finite : Finite α Id]
|
||||
/-- The iterator of a slice `s` of type `Slice γ` emits exactly `SliceSize.size s` elements. -/
|
||||
[finite : ∀ s : Slice α, Finite (ToIterator.State s Id) Id]
|
||||
/-- The iterator of a slice `s` of type `Slice α` emits exactly `SliceSize.size s` elements. -/
|
||||
lawful :
|
||||
letI : IteratorLoop α Id Id := .defaultImplementation
|
||||
∀ s : Slice γ, SliceSize.size s = (ToIterator.iter (γ := Slice γ) s).count
|
||||
letI (s : Slice α) : IteratorLoop (ToIterator.State s Id) Id Id := .defaultImplementation
|
||||
∀ s : Slice α, SliceSize.size s = (ToIterator.iter s).count
|
||||
|
||||
/--
|
||||
Returns the number of elements with distinct indices in the given slice.
|
||||
@@ -58,27 +59,26 @@ def size (s : Slice γ) [SliceSize γ] :=
|
||||
|
||||
/-- Allocates a new array that contains the elements of the slice. -/
|
||||
@[always_inline, inline]
|
||||
def toArray [ToIterator (Slice γ) Id α β] [Iterator α Id β]
|
||||
[IteratorCollect α Id Id] [Finite α Id] (s : Slice γ) : Array β :=
|
||||
def toArray (s : Slice γ) [ToIterator s Id β] [Iterator (ToIterator.State s Id) Id β]
|
||||
[IteratorCollect (ToIterator.State s Id) Id Id] [Finite (ToIterator.State s Id) Id] : Array β :=
|
||||
Internal.iter s |>.toArray
|
||||
|
||||
/-- Allocates a new list that contains the elements of the slice. -/
|
||||
@[always_inline, inline]
|
||||
def toList [ToIterator (Slice γ) Id α β] [Iterator α Id β]
|
||||
[IteratorCollect α Id Id] [Finite α Id]
|
||||
(s : Slice γ) : List β :=
|
||||
def toList (s : Slice γ) [ToIterator s Id β] [Iterator (ToIterator.State s Id) Id β]
|
||||
[IteratorCollect (ToIterator.State s Id) Id Id] [Finite (ToIterator.State s Id) Id] : List β :=
|
||||
Internal.iter s |>.toList
|
||||
|
||||
/-- Allocates a new list that contains the elements of the slice in reverse order. -/
|
||||
@[always_inline, inline]
|
||||
def toListRev [ToIterator (Slice γ) Id α β] [Iterator α Id β]
|
||||
[Finite α Id] (s : Slice γ) : List β :=
|
||||
def toListRev (s : Slice γ) [ToIterator s Id β] [Iterator (ToIterator.State s Id) Id β]
|
||||
[Finite (ToIterator.State s Id) Id] : List β :=
|
||||
Internal.iter s |>.toListRev
|
||||
|
||||
instance {γ : Type u} {β : Type v} [Monad m] [ToIterator (Slice γ) Id α β]
|
||||
[Iterator α Id β]
|
||||
[IteratorLoop α Id m]
|
||||
[Finite α Id] :
|
||||
instance {γ : Type u} {β : Type v} [∀ s : Slice γ, ToIterator s Id β]
|
||||
[∀ s : Slice γ, Iterator (ToIterator.State s Id) Id β]
|
||||
[∀ s : Slice γ, IteratorLoop (ToIterator.State s Id) Id m]
|
||||
[∀ s : Slice γ, Finite (ToIterator.State s Id) Id] :
|
||||
ForIn m (Slice γ) β where
|
||||
forIn s init f :=
|
||||
forIn (Internal.iter s) init f
|
||||
@@ -110,9 +110,8 @@ none
|
||||
@[always_inline, inline]
|
||||
def foldlM {γ : Type u} {β : Type v}
|
||||
{δ : Type w} {m : Type w → Type w'} [Monad m] (f : δ → β → m δ) (init : δ)
|
||||
[ToIterator (Slice γ) Id α β] [Iterator α Id β]
|
||||
[IteratorLoop α Id m] [Finite α Id]
|
||||
(s : Slice γ) : m δ :=
|
||||
(s : Slice γ) [ToIterator s Id β] [Iterator (ToIterator.State s Id) Id β]
|
||||
[IteratorLoop (ToIterator.State s Id) Id m] [Finite (ToIterator.State s Id) Id] : m δ :=
|
||||
Internal.iter s |>.foldM f init
|
||||
|
||||
/--
|
||||
@@ -126,9 +125,8 @@ Examples for the special case of subarrays:
|
||||
@[always_inline, inline]
|
||||
def foldl {γ : Type u} {β : Type v}
|
||||
{δ : Type w} (f : δ → β → δ) (init : δ)
|
||||
[ToIterator (Slice γ) Id α β] [Iterator α Id β]
|
||||
[IteratorLoop α Id Id] [Finite α Id]
|
||||
(s : Slice γ) : δ :=
|
||||
(s : Slice γ) [ToIterator s Id β] [Iterator (ToIterator.State s Id) Id β]
|
||||
[IteratorLoop (ToIterator.State s Id) Id Id] [Finite (ToIterator.State s Id) Id] : δ :=
|
||||
Internal.iter s |>.fold f init
|
||||
|
||||
end Std.Slice
|
||||
|
||||
@@ -66,7 +66,7 @@ protected partial def Stream.forIn [Stream ρ α] [Monad m] (s : ρ) (b : β) (f
|
||||
| none => return b
|
||||
visit s b
|
||||
|
||||
instance (priority := low) [Monad m] [Stream ρ α] : ForIn m ρ α where
|
||||
instance (priority := low) [Stream ρ α] : ForIn m ρ α where
|
||||
forIn := Stream.forIn
|
||||
|
||||
instance : ToStream (List α) (List α) where
|
||||
|
||||
@@ -13,6 +13,7 @@ public import Init.Data.String.Defs
|
||||
public import Init.Data.String.Extra
|
||||
public import Init.Data.String.Iterator
|
||||
public import Init.Data.String.Lemmas
|
||||
public import Init.Data.String.Repr
|
||||
public import Init.Data.String.Bootstrap
|
||||
public import Init.Data.String.Slice
|
||||
public import Init.Data.String.Pattern
|
||||
@@ -24,5 +25,3 @@ public import Init.Data.String.Modify
|
||||
public import Init.Data.String.Termination
|
||||
public import Init.Data.String.ToSlice
|
||||
public import Init.Data.String.Search
|
||||
public import Init.Data.String.Legacy
|
||||
public import Init.Data.String.Grind
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -13,6 +13,9 @@ public section
|
||||
|
||||
namespace String
|
||||
|
||||
@[deprecated Pos.Raw (since := "2025-09-30")]
|
||||
abbrev Pos := Pos.Raw
|
||||
|
||||
instance : OfNat String.Pos.Raw (nat_lit 0) where
|
||||
ofNat := {}
|
||||
|
||||
|
||||
@@ -74,11 +74,11 @@ Encodes a string in UTF-8 as an array of bytes.
|
||||
-/
|
||||
@[extern "lean_string_to_utf8"]
|
||||
def String.toUTF8 (a : @& String) : ByteArray :=
|
||||
a.toByteArray
|
||||
a.bytes
|
||||
|
||||
@[simp] theorem String.toUTF8_eq_toByteArray {s : String} : s.toUTF8 = s.toByteArray := (rfl)
|
||||
@[simp] theorem String.toUTF8_eq_bytes {s : String} : s.toUTF8 = s.bytes := (rfl)
|
||||
|
||||
@[simp] theorem String.toByteArray_empty : "".toByteArray = ByteArray.empty := (rfl)
|
||||
@[simp] theorem String.bytes_empty : "".bytes = ByteArray.empty := (rfl)
|
||||
|
||||
/--
|
||||
Appends two strings. Usually accessed via the `++` operator.
|
||||
@@ -92,33 +92,33 @@ Examples:
|
||||
-/
|
||||
@[extern "lean_string_append", expose]
|
||||
def String.append (s : String) (t : @& String) : String where
|
||||
toByteArray := s.toByteArray ++ t.toByteArray
|
||||
bytes := s.bytes ++ t.bytes
|
||||
isValidUTF8 := s.isValidUTF8.append t.isValidUTF8
|
||||
|
||||
instance : Append String where
|
||||
append s t := s.append t
|
||||
|
||||
@[simp]
|
||||
theorem String.toByteArray_append {s t : String} : (s ++ t).toByteArray = s.toByteArray ++ t.toByteArray := (rfl)
|
||||
theorem String.bytes_append {s t : String} : (s ++ t).bytes = s.bytes ++ t.bytes := (rfl)
|
||||
|
||||
theorem String.toByteArray_inj {s t : String} : s.toByteArray = t.toByteArray ↔ s = t := by
|
||||
theorem String.bytes_inj {s t : String} : s.bytes = t.bytes ↔ s = t := by
|
||||
refine ⟨fun h => ?_, (· ▸ rfl)⟩
|
||||
rcases s with ⟨s⟩
|
||||
rcases t with ⟨t⟩
|
||||
subst h
|
||||
rfl
|
||||
|
||||
@[simp] theorem String.toByteArray_ofList {l : List Char} : (String.ofList l).toByteArray = l.utf8Encode := by
|
||||
@[simp] theorem String.bytes_ofList {l : List Char} : (String.ofList l).bytes = l.utf8Encode := by
|
||||
simp [String.ofList]
|
||||
|
||||
@[deprecated String.toByteArray_ofList (since := "2025-10-30")]
|
||||
theorem List.toByteArray_asString {l : List Char} : (String.ofList l).toByteArray = l.utf8Encode :=
|
||||
String.toByteArray_ofList
|
||||
@[deprecated String.bytes_ofList (since := "2025-10-30")]
|
||||
theorem List.bytes_asString {l : List Char} : (String.ofList l).bytes = l.utf8Encode :=
|
||||
String.bytes_ofList
|
||||
|
||||
theorem String.exists_eq_ofList (s : String) :
|
||||
∃ l : List Char, s = String.ofList l := by
|
||||
rcases s with ⟨_, ⟨l, rfl⟩⟩
|
||||
refine ⟨l, by simp [← String.toByteArray_inj]⟩
|
||||
refine ⟨l, by simp [← String.bytes_inj]⟩
|
||||
|
||||
@[deprecated String.exists_eq_ofList (since := "2025-10-30")]
|
||||
theorem String.exists_eq_asString (s : String) :
|
||||
@@ -134,14 +134,18 @@ theorem String.utf8ByteSize_append {s t : String} :
|
||||
simp [utf8ByteSize]
|
||||
|
||||
@[simp]
|
||||
theorem String.size_toByteArray {s : String} : s.toByteArray.size = s.utf8ByteSize := rfl
|
||||
theorem String.size_bytes {s : String} : s.bytes.size = s.utf8ByteSize := rfl
|
||||
|
||||
@[simp]
|
||||
theorem String.toByteArray_push {s : String} {c : Char} : (s.push c).toByteArray = s.toByteArray ++ [c].utf8Encode := by
|
||||
theorem String.bytes_push {s : String} {c : Char} : (s.push c).bytes = s.bytes ++ [c].utf8Encode := by
|
||||
simp [push]
|
||||
|
||||
namespace String
|
||||
|
||||
@[deprecated rawEndPos (since := "2025-10-20")]
|
||||
def endPos (s : String) : String.Pos.Raw :=
|
||||
s.rawEndPos
|
||||
|
||||
/-- The start position of the string, as a `String.Pos.Raw.` -/
|
||||
def rawStartPos (_s : String) : String.Pos.Raw :=
|
||||
0
|
||||
@@ -160,11 +164,11 @@ theorem utf8ByteSize_ofByteArray {b : ByteArray} {h} :
|
||||
(String.ofByteArray b h).utf8ByteSize = b.size := rfl
|
||||
|
||||
@[simp]
|
||||
theorem toByteArray_singleton {c : Char} : (String.singleton c).toByteArray = [c].utf8Encode := by
|
||||
theorem bytes_singleton {c : Char} : (String.singleton c).bytes = [c].utf8Encode := by
|
||||
simp [singleton]
|
||||
|
||||
theorem singleton_eq_ofList {c : Char} : String.singleton c = String.ofList [c] := by
|
||||
simp [← String.toByteArray_inj]
|
||||
simp [← String.bytes_inj]
|
||||
|
||||
@[deprecated singleton_eq_ofList (since := "2025-10-30")]
|
||||
theorem singleton_eq_asString {c : Char} : String.singleton c = String.ofList [c] :=
|
||||
@@ -172,20 +176,20 @@ theorem singleton_eq_asString {c : Char} : String.singleton c = String.ofList [c
|
||||
|
||||
@[simp]
|
||||
theorem append_singleton {s : String} {c : Char} : s ++ singleton c = s.push c := by
|
||||
simp [← toByteArray_inj]
|
||||
simp [← bytes_inj]
|
||||
|
||||
@[simp]
|
||||
theorem append_left_inj {s₁ s₂ : String} (t : String) :
|
||||
s₁ ++ t = s₂ ++ t ↔ s₁ = s₂ := by
|
||||
simp [← toByteArray_inj]
|
||||
simp [← bytes_inj]
|
||||
|
||||
theorem append_assoc {s₁ s₂ s₃ : String} : s₁ ++ s₂ ++ s₃ = s₁ ++ (s₂ ++ s₃) := by
|
||||
simp [← toByteArray_inj, ByteArray.append_assoc]
|
||||
simp [← bytes_inj, ByteArray.append_assoc]
|
||||
|
||||
@[simp]
|
||||
theorem utf8ByteSize_eq_zero_iff {s : String} : s.utf8ByteSize = 0 ↔ s = "" := by
|
||||
refine ⟨fun h => ?_, fun h => h ▸ utf8ByteSize_empty⟩
|
||||
simpa [← toByteArray_inj, ← ByteArray.size_eq_zero_iff] using h
|
||||
simpa [← bytes_inj, ← ByteArray.size_eq_zero_iff] using h
|
||||
|
||||
theorem rawEndPos_eq_zero_iff {b : String} : b.rawEndPos = 0 ↔ b = "" := by
|
||||
simp
|
||||
@@ -296,14 +300,14 @@ Examples:
|
||||
-/
|
||||
structure Pos.Raw.IsValid (s : String) (off : String.Pos.Raw) : Prop where private mk ::
|
||||
le_rawEndPos : off ≤ s.rawEndPos
|
||||
isValidUTF8_extract_zero : (s.toByteArray.extract 0 off.byteIdx).IsValidUTF8
|
||||
isValidUTF8_extract_zero : (s.bytes.extract 0 off.byteIdx).IsValidUTF8
|
||||
|
||||
theorem Pos.Raw.IsValid.le_utf8ByteSize {s : String} {off : String.Pos.Raw} (h : off.IsValid s) :
|
||||
off.byteIdx ≤ s.utf8ByteSize := by
|
||||
simpa [Pos.Raw.le_iff] using h.le_rawEndPos
|
||||
|
||||
theorem Pos.Raw.isValid_iff_isValidUTF8_extract_zero {s : String} {p : Pos.Raw} :
|
||||
p.IsValid s ↔ p ≤ s.rawEndPos ∧ (s.toByteArray.extract 0 p.byteIdx).IsValidUTF8 :=
|
||||
p.IsValid s ↔ p ≤ s.rawEndPos ∧ (s.bytes.extract 0 p.byteIdx).IsValidUTF8 :=
|
||||
⟨fun ⟨h₁, h₂⟩ => ⟨h₁, h₂⟩, fun ⟨h₁, h₂⟩ => ⟨h₁, h₂⟩⟩
|
||||
|
||||
@[deprecated le_rawEndPos (since := "2025-10-20")]
|
||||
@@ -319,7 +323,7 @@ theorem Pos.Raw.isValid_zero {s : String} : (0 : Pos.Raw).IsValid s where
|
||||
@[simp]
|
||||
theorem Pos.Raw.isValid_rawEndPos {s : String} : s.rawEndPos.IsValid s where
|
||||
le_rawEndPos := by simp
|
||||
isValidUTF8_extract_zero := by simp [← size_toByteArray, s.isValidUTF8]
|
||||
isValidUTF8_extract_zero := by simp [← size_bytes, s.isValidUTF8]
|
||||
|
||||
theorem Pos.Raw.isValid_of_eq_rawEndPos {s : String} {p : Pos.Raw} (h : p = s.rawEndPos) :
|
||||
p.IsValid s := by
|
||||
@@ -337,55 +341,55 @@ theorem Pos.Raw.isValid_empty_iff {p : Pos.Raw} : p.IsValid "" ↔ p = 0 := by
|
||||
simp
|
||||
|
||||
/--
|
||||
A `Pos s` is a byte offset in `s` together with a proof that this position is at a UTF-8
|
||||
A `ValidPos s` is a byte offset in `s` together with a proof that this position is at a UTF-8
|
||||
character boundary.
|
||||
-/
|
||||
@[ext]
|
||||
structure Pos (s : String) where
|
||||
/-- The underlying byte offset of the `Pos`. -/
|
||||
structure ValidPos (s : String) where
|
||||
/-- The underlying byte offset of the `ValidPos`. -/
|
||||
offset : Pos.Raw
|
||||
/-- The proof that `offset` is valid for the string `s`. -/
|
||||
isValid : offset.IsValid s
|
||||
deriving @[expose] DecidableEq
|
||||
|
||||
/-- The start position of `s`, as an `s.Pos`. -/
|
||||
/-- The start position of `s`, as an `s.ValidPos`. -/
|
||||
@[inline, expose]
|
||||
def startPos (s : String) : s.Pos where
|
||||
def startValidPos (s : String) : s.ValidPos where
|
||||
offset := 0
|
||||
isValid := by simp
|
||||
|
||||
@[simp]
|
||||
theorem offset_startPos {s : String} : s.startPos.offset = 0 := (rfl)
|
||||
theorem offset_startValidPos {s : String} : s.startValidPos.offset = 0 := (rfl)
|
||||
|
||||
instance {s : String} : Inhabited s.Pos where
|
||||
default := s.startPos
|
||||
instance {s : String} : Inhabited s.ValidPos where
|
||||
default := s.startValidPos
|
||||
|
||||
/-- The past-the-end position of `s`, as an `s.Pos`. -/
|
||||
/-- The past-the-end position of `s`, as an `s.ValidPos`. -/
|
||||
@[inline, expose]
|
||||
def endPos (s : String) : s.Pos where
|
||||
def endValidPos (s : String) : s.ValidPos where
|
||||
offset := s.rawEndPos
|
||||
isValid := by simp
|
||||
|
||||
@[simp]
|
||||
theorem offset_endPos {s : String} : s.endPos.offset = s.rawEndPos := (rfl)
|
||||
theorem offset_endValidPos {s : String} : s.endValidPos.offset = s.rawEndPos := (rfl)
|
||||
|
||||
instance {s : String} : LE s.Pos where
|
||||
instance {s : String} : LE s.ValidPos where
|
||||
le l r := l.offset ≤ r.offset
|
||||
|
||||
instance {s : String} : LT s.Pos where
|
||||
instance {s : String} : LT s.ValidPos where
|
||||
lt l r := l.offset < r.offset
|
||||
|
||||
theorem Pos.le_iff {s : String} {l r : s.Pos} : l ≤ r ↔ l.offset ≤ r.offset :=
|
||||
theorem ValidPos.le_iff {s : String} {l r : s.ValidPos} : l ≤ r ↔ l.offset ≤ r.offset :=
|
||||
Iff.rfl
|
||||
|
||||
theorem Pos.lt_iff {s : String} {l r : s.Pos} : l < r ↔ l.offset < r.offset :=
|
||||
theorem ValidPos.lt_iff {s : String} {l r : s.ValidPos} : l < r ↔ l.offset < r.offset :=
|
||||
Iff.rfl
|
||||
|
||||
instance {s : String} (l r : s.Pos) : Decidable (l ≤ r) :=
|
||||
decidable_of_iff' _ Pos.le_iff
|
||||
instance {s : String} (l r : s.ValidPos) : Decidable (l ≤ r) :=
|
||||
decidable_of_iff' _ ValidPos.le_iff
|
||||
|
||||
instance {s : String} (l r : s.Pos) : Decidable (l < r) :=
|
||||
decidable_of_iff' _ Pos.lt_iff
|
||||
instance {s : String} (l r : s.ValidPos) : Decidable (l < r) :=
|
||||
decidable_of_iff' _ ValidPos.lt_iff
|
||||
|
||||
/--
|
||||
A region or slice of some underlying string.
|
||||
@@ -402,14 +406,14 @@ structure Slice where
|
||||
/-- The underlying strings. -/
|
||||
str : String
|
||||
/-- The byte position of the start of the string slice. -/
|
||||
startInclusive : str.Pos
|
||||
startInclusive : str.ValidPos
|
||||
/-- The byte position of the end of the string slice. -/
|
||||
endExclusive : str.Pos
|
||||
endExclusive : str.ValidPos
|
||||
/-- The slice is not degenerate (but it may be empty). -/
|
||||
startInclusive_le_endExclusive : startInclusive ≤ endExclusive
|
||||
|
||||
instance : Inhabited Slice where
|
||||
default := ⟨"", "".startPos, "".startPos, by simp [Pos.le_iff]⟩
|
||||
default := ⟨"", "".startValidPos, "".startValidPos, by simp [ValidPos.le_iff]⟩
|
||||
|
||||
/--
|
||||
Returns a slice that contains the entire string.
|
||||
@@ -417,18 +421,15 @@ Returns a slice that contains the entire string.
|
||||
@[inline, expose] -- expose for the defeq `s.toSlice.str = s`.
|
||||
def toSlice (s : String) : Slice where
|
||||
str := s
|
||||
startInclusive := s.startPos
|
||||
endExclusive := s.endPos
|
||||
startInclusive_le_endExclusive := by simp [Pos.le_iff, Pos.Raw.le_iff]
|
||||
|
||||
instance : Coe String String.Slice where
|
||||
coe := String.toSlice
|
||||
startInclusive := s.startValidPos
|
||||
endExclusive := s.endValidPos
|
||||
startInclusive_le_endExclusive := by simp [ValidPos.le_iff, Pos.Raw.le_iff]
|
||||
|
||||
@[simp]
|
||||
theorem startInclusive_toSlice {s : String} : s.toSlice.startInclusive = s.startPos := rfl
|
||||
theorem startInclusive_toSlice {s : String} : s.toSlice.startInclusive = s.startValidPos := rfl
|
||||
|
||||
@[simp]
|
||||
theorem endExclusive_toSlice {s : String} : s.toSlice.endExclusive = s.endPos := rfl
|
||||
theorem endExclusive_toSlice {s : String} : s.toSlice.endExclusive = s.endValidPos := rfl
|
||||
|
||||
@[simp]
|
||||
theorem str_toSlice {s : String} : s.toSlice.str = s := rfl
|
||||
@@ -531,7 +532,7 @@ instance {s : Slice} : Inhabited s.Pos where
|
||||
theorem Slice.offset_startInclusive_add_self {s : Slice} :
|
||||
s.startInclusive.offset + s = s.endExclusive.offset := by
|
||||
have := s.startInclusive_le_endExclusive
|
||||
simp_all [String.Pos.Raw.ext_iff, Pos.le_iff, Pos.Raw.le_iff, utf8ByteSize_eq]
|
||||
simp_all [String.Pos.Raw.ext_iff, ValidPos.le_iff, Pos.Raw.le_iff, utf8ByteSize_eq]
|
||||
|
||||
@[simp]
|
||||
theorem Pos.Raw.offsetBy_rawEndPos_left {p : Pos.Raw} {s : String} :
|
||||
@@ -590,18 +591,18 @@ instance {s : Slice} (l r : s.Pos) : Decidable (l < r) :=
|
||||
decidable_of_iff' _ Slice.Pos.lt_iff
|
||||
|
||||
/--
|
||||
`pos.IsAtEnd` is just shorthand for `pos = s.endPos` that is easier to write if `s` is long.
|
||||
`pos.IsAtEnd` is just shorthand for `pos = s.endValidPos` that is easier to write if `s` is long.
|
||||
-/
|
||||
abbrev Pos.IsAtEnd {s : String} (pos : s.Pos) : Prop :=
|
||||
pos = s.endPos
|
||||
abbrev ValidPos.IsAtEnd {s : String} (pos : s.ValidPos) : Prop :=
|
||||
pos = s.endValidPos
|
||||
|
||||
@[simp]
|
||||
theorem Pos.isAtEnd_iff {s : String} {pos : s.Pos} :
|
||||
pos.IsAtEnd ↔ pos = s.endPos := Iff.rfl
|
||||
theorem ValidPos.isAtEnd_iff {s : String} {pos : s.ValidPos} :
|
||||
pos.IsAtEnd ↔ pos = s.endValidPos := Iff.rfl
|
||||
|
||||
@[inline]
|
||||
instance {s : String} {pos : s.Pos} : Decidable pos.IsAtEnd :=
|
||||
decidable_of_iff _ Pos.isAtEnd_iff
|
||||
instance {s : String} {pos : s.ValidPos} : Decidable pos.IsAtEnd :=
|
||||
decidable_of_iff _ ValidPos.isAtEnd_iff
|
||||
|
||||
/--
|
||||
`pos.IsAtEnd` is just shorthand for `pos = s.endPos` that is easier to write if `s` is long.
|
||||
@@ -638,20 +639,4 @@ def toSubstring (s : String) : Substring.Raw :=
|
||||
def toSubstring' (s : String) : Substring.Raw :=
|
||||
s.toRawSubstring'
|
||||
|
||||
@[deprecated String.Pos (since := "2025-11-24")]
|
||||
abbrev ValidPos (s : String) : Type :=
|
||||
s.Pos
|
||||
|
||||
@[deprecated String.startPos (since := "2025-11-24")]
|
||||
abbrev startValidPos (s : String) : s.Pos :=
|
||||
s.startPos
|
||||
|
||||
@[deprecated String.endPos (since := "2025-11-24")]
|
||||
abbrev endValidPos (s : String) : s.Pos :=
|
||||
s.endPos
|
||||
|
||||
@[deprecated String.toByteArray (since := "2025-11-24")]
|
||||
abbrev String.bytes (s : String) : ByteArray :=
|
||||
s.toByteArray
|
||||
|
||||
end String
|
||||
|
||||
@@ -17,6 +17,27 @@ public section
|
||||
|
||||
namespace String
|
||||
|
||||
/--
|
||||
Interprets a string as the decimal representation of a natural number, returning it. Panics if the
|
||||
string does not contain a decimal natural number.
|
||||
|
||||
A string can be interpreted as a decimal natural number if it is not empty and all the characters in
|
||||
it are digits.
|
||||
|
||||
Use `String.isNat` to check whether `String.toNat!` would return a value. `String.toNat?` is a safer
|
||||
alternative that returns `none` instead of panicking when the string is not a natural number.
|
||||
|
||||
Examples:
|
||||
* `"0".toNat! = 0`
|
||||
* `"5".toNat! = 5`
|
||||
* `"587".toNat! = 587`
|
||||
-/
|
||||
def toNat! (s : String) : Nat :=
|
||||
if s.isNat then
|
||||
s.foldl (fun n c => n*10 + (c.toNat - '0'.toNat)) 0
|
||||
else
|
||||
panic! "Nat expected"
|
||||
|
||||
@[deprecated ByteArray.utf8DecodeChar? (since := "2025-10-01")]
|
||||
abbrev utf8DecodeChar? (a : ByteArray) (i : Nat) : Option Char :=
|
||||
a.utf8DecodeChar? i
|
||||
@@ -29,28 +50,28 @@ abbrev validateUTF8 (a : ByteArray) : Bool :=
|
||||
a.validateUTF8
|
||||
|
||||
private def findLeadingSpacesSize (s : String) : Nat :=
|
||||
let it := s.startPos
|
||||
let it := it.find? (· == '\n') |>.bind String.Pos.next?
|
||||
let it := s.startValidPos
|
||||
let it := it.find? (· == '\n') |>.bind String.ValidPos.next?
|
||||
match it with
|
||||
| some it => consumeSpaces it 0 s.length
|
||||
| none => 0
|
||||
where
|
||||
consumeSpaces {s : String} (it : s.Pos) (curr min : Nat) : Nat :=
|
||||
consumeSpaces {s : String} (it : s.ValidPos) (curr min : Nat) : Nat :=
|
||||
if h : it.IsAtEnd then min
|
||||
else if it.get h == ' ' || it.get h == '\t' then consumeSpaces (it.next h) (curr + 1) min
|
||||
else if it.get h == '\n' then findNextLine (it.next h) min
|
||||
else findNextLine (it.next h) (Nat.min curr min)
|
||||
termination_by it
|
||||
findNextLine {s : String} (it : s.Pos) (min : Nat) : Nat :=
|
||||
findNextLine {s : String} (it : s.ValidPos) (min : Nat) : Nat :=
|
||||
if h : it.IsAtEnd then min
|
||||
else if it.get h == '\n' then consumeSpaces (it.next h) 0 min
|
||||
else findNextLine (it.next h) min
|
||||
termination_by it
|
||||
|
||||
private def removeNumLeadingSpaces (n : Nat) (s : String) : String :=
|
||||
consumeSpaces n s.startPos ""
|
||||
consumeSpaces n s.startValidPos ""
|
||||
where
|
||||
consumeSpaces (n : Nat) {s : String} (it : s.Pos) (r : String) : String :=
|
||||
consumeSpaces (n : Nat) {s : String} (it : s.ValidPos) (r : String) : String :=
|
||||
match n with
|
||||
| 0 => saveLine it r
|
||||
| n+1 =>
|
||||
@@ -58,7 +79,7 @@ where
|
||||
else if it.get h == ' ' || it.get h == '\t' then consumeSpaces n (it.next h) r
|
||||
else saveLine it r
|
||||
termination_by (it, 1)
|
||||
saveLine {s : String} (it : s.Pos) (r : String) : String :=
|
||||
saveLine {s : String} (it : s.ValidPos) (r : String) : String :=
|
||||
if h : it.IsAtEnd then r
|
||||
else if it.get h == '\n' then consumeSpaces n (it.next h) (r.push '\n')
|
||||
else saveLine (it.next h) (r.push (it.get h))
|
||||
|
||||
@@ -1,112 +0,0 @@
|
||||
/-
|
||||
Copyright (c) 2025 Lean FRO, LLC. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Author: Markus Himmel
|
||||
-/
|
||||
module
|
||||
|
||||
prelude
|
||||
public import Init.Data.String.Defs
|
||||
public import Init.Grind.ToInt
|
||||
|
||||
public section
|
||||
|
||||
/-!
|
||||
# Register string positions with `grind`.
|
||||
-/
|
||||
|
||||
namespace String
|
||||
|
||||
namespace Internal
|
||||
|
||||
scoped macro "order" : tactic => `(tactic| {
|
||||
simp [Pos.Raw.lt_iff, Pos.Raw.le_iff, String.Pos.lt_iff, String.Pos.le_iff, Slice.Pos.lt_iff,
|
||||
Slice.Pos.le_iff, Pos.Raw.ext_iff, String.Pos.ext_iff, Slice.Pos.ext_iff] at *;
|
||||
try omega })
|
||||
|
||||
end Internal
|
||||
|
||||
open Internal
|
||||
|
||||
namespace Pos.Raw
|
||||
|
||||
instance : Lean.Grind.ToInt String.Pos.Raw (.ci 0) where
|
||||
toInt p := p.byteIdx
|
||||
toInt_inj p q := by simp [Pos.Raw.ext_iff, ← Int.ofNat_inj]
|
||||
toInt_mem := by simp
|
||||
|
||||
@[simp]
|
||||
theorem toInt_eq {p : Pos.Raw} : Lean.Grind.ToInt.toInt p = p.byteIdx := rfl
|
||||
|
||||
instance : Lean.Grind.ToInt.LE String.Pos.Raw (.ci 0) where
|
||||
le_iff := by simp [Pos.Raw.le_iff]
|
||||
|
||||
instance : Lean.Grind.ToInt.LT String.Pos.Raw (.ci 0) where
|
||||
lt_iff := by simp [Pos.Raw.lt_iff]
|
||||
|
||||
instance : Std.LawfulOrderLT String.Pos.Raw where
|
||||
lt_iff := by order
|
||||
|
||||
instance : Std.IsLinearOrder String.Pos.Raw where
|
||||
le_refl := by order
|
||||
le_trans := by order
|
||||
le_antisymm := by order
|
||||
le_total := by order
|
||||
|
||||
end Pos.Raw
|
||||
|
||||
namespace Pos
|
||||
|
||||
instance {s : String} : Lean.Grind.ToInt s.Pos (.co 0 (s.utf8ByteSize + 1)) where
|
||||
toInt p := p.offset.byteIdx
|
||||
toInt_inj p q := by simp [Pos.ext_iff, Pos.Raw.ext_iff, ← Int.ofNat_inj]
|
||||
toInt_mem p := by have := p.isValid.le_utf8ByteSize; simp; omega
|
||||
|
||||
@[simp]
|
||||
theorem toInt_eq {s : String} {p : s.Pos} : Lean.Grind.ToInt.toInt p = p.offset.byteIdx := rfl
|
||||
|
||||
instance {s : String} : Lean.Grind.ToInt.LE s.Pos (.co 0 (s.utf8ByteSize + 1)) where
|
||||
le_iff := by simp [Pos.le_iff, Pos.Raw.le_iff]
|
||||
|
||||
instance {s : String} : Lean.Grind.ToInt.LT s.Pos (.co 0 (s.utf8ByteSize + 1)) where
|
||||
lt_iff := by simp [Pos.lt_iff, Pos.Raw.lt_iff]
|
||||
|
||||
instance {s : String} : Std.LawfulOrderLT s.Pos where
|
||||
lt_iff := by order
|
||||
|
||||
instance {s : String} : Std.IsLinearOrder s.Pos where
|
||||
le_refl := by order
|
||||
le_trans := by order
|
||||
le_antisymm := by order
|
||||
le_total := by order
|
||||
|
||||
end Pos
|
||||
|
||||
namespace Slice.Pos
|
||||
|
||||
instance {s : Slice} : Lean.Grind.ToInt s.Pos (.co 0 (s.utf8ByteSize + 1)) where
|
||||
toInt p := p.offset.byteIdx
|
||||
toInt_inj p q := by simp [Pos.ext_iff, Pos.Raw.ext_iff, ← Int.ofNat_inj]
|
||||
toInt_mem p := by have := p.isValidForSlice.le_utf8ByteSize; simp; omega
|
||||
|
||||
@[simp]
|
||||
theorem toInt_eq {s : Slice} {p : s.Pos} : Lean.Grind.ToInt.toInt p = p.offset.byteIdx := rfl
|
||||
|
||||
instance {s : Slice} : Lean.Grind.ToInt.LE s.Pos (.co 0 (s.utf8ByteSize + 1)) where
|
||||
le_iff := by simp [Pos.le_iff, Pos.Raw.le_iff]
|
||||
|
||||
instance {s : Slice} : Lean.Grind.ToInt.LT s.Pos (.co 0 (s.utf8ByteSize + 1)) where
|
||||
lt_iff := by simp [Pos.lt_iff, Pos.Raw.lt_iff]
|
||||
|
||||
instance {s : Slice} : Std.LawfulOrderLT s.Pos where
|
||||
lt_iff := by order
|
||||
|
||||
instance {s : Slice} : Std.IsLinearOrder s.Pos where
|
||||
le_refl := by order
|
||||
le_trans := by order
|
||||
le_antisymm := by order
|
||||
le_total := by order
|
||||
|
||||
end Slice.Pos
|
||||
|
||||
end String
|
||||
@@ -25,9 +25,9 @@ An iterator over the characters (Unicode code points) in a `String`. Typically c
|
||||
`String.iter`.
|
||||
|
||||
This is a no-longer-supported legacy API that will be removed in a future release. You should use
|
||||
`String.Pos` instead, which is similar, but safer. To iterate over a string `s`, start with
|
||||
`p : s.startPos`, advance it using `p.next`, access the current character using `p.get` and
|
||||
check if the position is at the end using `p = s.endPos` or `p.IsAtEnd`.
|
||||
`String.ValidPos` instead, which is similar, but safer. To iterate over a string `s`, start with
|
||||
`p : s.startValidPos`, advance it using `p.next`, access the current character using `p.get` and
|
||||
check if the position is at the end using `p = s.endValidPos` or `p.IsAtEnd`.
|
||||
|
||||
String iterators pair a string with a valid byte index. This allows efficient character-by-character
|
||||
processing of strings while avoiding the need to manually ensure that byte indices are used with the
|
||||
@@ -57,9 +57,9 @@ structure Iterator where
|
||||
/-- Creates an iterator at the beginning of the string.
|
||||
|
||||
This is a no-longer-supported legacy API that will be removed in a future release. You should use
|
||||
`String.Pos` instead, which is similar, but safer. To iterate over a string `s`, start with
|
||||
`p : s.startPos`, advance it using `p.next`, access the current character using `p.get` and
|
||||
check if the position is at the end using `p = s.endPos` or `p.IsAtEnd`.
|
||||
`String.ValidPos` instead, which is similar, but safer. To iterate over a string `s`, start with
|
||||
`p : s.startValidPos`, advance it using `p.next`, access the current character using `p.get` and
|
||||
check if the position is at the end using `p = s.endValidPos` or `p.IsAtEnd`.
|
||||
-/
|
||||
@[inline] def mkIterator (s : String) : Iterator :=
|
||||
⟨s, 0⟩
|
||||
@@ -95,9 +95,9 @@ def pos := Iterator.i
|
||||
Gets the character at the iterator's current position.
|
||||
|
||||
This is a no-longer-supported legacy API that will be removed in a future release. You should use
|
||||
`String.Pos` instead, which is similar, but safer. To iterate over a string `s`, start with
|
||||
`p : s.startPos`, advance it using `p.next`, access the current character using `p.get` and
|
||||
check if the position is at the end using `p = s.endPos` or `p.IsAtEnd`.
|
||||
`String.ValidPos` instead, which is similar, but safer. To iterate over a string `s`, start with
|
||||
`p : s.startValidPos`, advance it using `p.next`, access the current character using `p.get` and
|
||||
check if the position is at the end using `p = s.endValidPos` or `p.IsAtEnd`.
|
||||
|
||||
A run-time bounds check is performed. Use `String.Iterator.curr'` to avoid redundant bounds checks.
|
||||
|
||||
@@ -110,9 +110,9 @@ If the position is invalid, returns `(default : Char)`.
|
||||
Moves the iterator's position forward by one character, unconditionally.
|
||||
|
||||
This is a no-longer-supported legacy API that will be removed in a future release. You should use
|
||||
`String.Pos` instead, which is similar, but safer. To iterate over a string `s`, start with
|
||||
`p : s.startPos`, advance it using `p.next`, access the current character using `p.get` and
|
||||
check if the position is at the end using `p = s.endPos` or `p.IsAtEnd`.
|
||||
`String.ValidPos` instead, which is similar, but safer. To iterate over a string `s`, start with
|
||||
`p : s.startValidPos`, advance it using `p.next`, access the current character using `p.get` and
|
||||
check if the position is at the end using `p = s.endValidPos` or `p.IsAtEnd`.
|
||||
|
||||
It is only valid to call this function if the iterator is not at the end of the string (i.e.
|
||||
if `Iterator.atEnd` is `false`); otherwise, the resulting iterator will be invalid.
|
||||
|
||||
@@ -1,115 +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, Mario Carneiro
|
||||
-/
|
||||
module
|
||||
|
||||
prelude
|
||||
public import Init.Data.String.Basic
|
||||
|
||||
/-!
|
||||
# Legacy string functions
|
||||
|
||||
This file contains `String` functions which have since been replaced by different functions and
|
||||
will be deprecated in the future.
|
||||
-/
|
||||
|
||||
public section
|
||||
|
||||
namespace String
|
||||
|
||||
@[specialize] def splitAux (s : String) (p : Char → Bool) (b : Pos.Raw) (i : Pos.Raw) (r : List String) : List String :=
|
||||
if h : i.atEnd s then
|
||||
let r := (b.extract s i)::r
|
||||
r.reverse
|
||||
else
|
||||
have := Nat.sub_lt_sub_left (Nat.gt_of_not_le (mt decide_eq_true h)) (Pos.Raw.lt_next s _)
|
||||
if p (i.get s) then
|
||||
let i' := i.next s
|
||||
splitAux s p i' i' (b.extract s i :: r)
|
||||
else
|
||||
splitAux s p b (i.next s) r
|
||||
termination_by s.rawEndPos.1 - i.1
|
||||
|
||||
/--
|
||||
Splits a string at each character for which `p` returns `true`.
|
||||
|
||||
The characters that satisfy `p` are not included in any of the resulting strings. If multiple
|
||||
characters in a row satisfy `p`, then the resulting list will contain empty strings.
|
||||
|
||||
This is a legacy function. Use `String.split` instead.
|
||||
|
||||
Examples:
|
||||
* `"coffee tea water".split (·.isWhitespace) = ["coffee", "tea", "water"]`
|
||||
* `"coffee tea water".split (·.isWhitespace) = ["coffee", "", "tea", "", "water"]`
|
||||
* `"fun x =>\n x + 1\n".split (· == '\n') = ["fun x =>", " x + 1", ""]`
|
||||
-/
|
||||
@[inline] def splitToList (s : String) (p : Char → Bool) : List String :=
|
||||
splitAux s p 0 0 []
|
||||
|
||||
/--
|
||||
Auxiliary for `splitOn`. Preconditions:
|
||||
* `sep` is not empty
|
||||
* `b <= i` are indexes into `s`
|
||||
* `j` is an index into `sep`, and not at the end
|
||||
|
||||
It represents the state where we have currently parsed some split parts into `r` (in reverse order),
|
||||
`b` is the beginning of the string / the end of the previous match of `sep`, and the first `j` bytes
|
||||
of `sep` match the bytes `i-j .. i` of `s`.
|
||||
-/
|
||||
def splitOnAux (s sep : String) (b : Pos.Raw) (i : Pos.Raw) (j : Pos.Raw) (r : List String) : List String :=
|
||||
if i.atEnd s then
|
||||
let r := (b.extract s i)::r
|
||||
r.reverse
|
||||
else
|
||||
if i.get s == j.get sep then
|
||||
let i := i.next s
|
||||
let j := j.next sep
|
||||
if j.atEnd sep then
|
||||
splitOnAux s sep i i 0 (b.extract s (i.unoffsetBy j)::r)
|
||||
else
|
||||
splitOnAux s sep b i j r
|
||||
else
|
||||
splitOnAux s sep b ((i.unoffsetBy j).next s) 0 r
|
||||
termination_by (s.rawEndPos.1 - (j.byteDistance i), sep.rawEndPos.1 - j.1)
|
||||
decreasing_by
|
||||
focus
|
||||
rename_i h _ _
|
||||
left; exact Nat.sub_lt_sub_left
|
||||
(Nat.lt_of_le_of_lt (Nat.sub_le ..) (Nat.gt_of_not_le (mt decide_eq_true h)))
|
||||
(Nat.lt_of_le_of_lt (Nat.sub_le ..) (Pos.Raw.lt_next s _))
|
||||
focus
|
||||
rename_i i₀ j₀ _ eq h'
|
||||
rw [show (j₀.next sep).byteDistance (i₀.next s) = j₀.byteDistance i₀ by
|
||||
change (_ + Char.utf8Size _) - (_ + Char.utf8Size _) = _
|
||||
rw [(beq_iff_eq ..).1 eq, Nat.add_sub_add_right]; rfl]
|
||||
right; exact Nat.sub_lt_sub_left
|
||||
(Nat.lt_of_le_of_lt (Nat.le_add_right ..) (Nat.gt_of_not_le (mt decide_eq_true h')))
|
||||
(Pos.Raw.lt_next sep _)
|
||||
focus
|
||||
rename_i h _
|
||||
left; exact Nat.sub_lt_sub_left
|
||||
(Nat.lt_of_le_of_lt (Nat.sub_le ..) (Nat.gt_of_not_le (mt decide_eq_true h)))
|
||||
(Pos.Raw.lt_next s _)
|
||||
|
||||
/--
|
||||
Splits a string `s` on occurrences of the separator string `sep`. The default separator is `" "`.
|
||||
|
||||
When `sep` is empty, the result is `[s]`. When `sep` occurs in overlapping patterns, the first match
|
||||
is taken. There will always be exactly `n+1` elements in the returned list if there were `n`
|
||||
non-overlapping matches of `sep` in the string. The separators are not included in the returned
|
||||
substrings.
|
||||
|
||||
This is a legacy function. Use `String.split` instead.
|
||||
|
||||
Examples:
|
||||
* `"here is some text ".splitOn = ["here", "is", "some", "text", ""]`
|
||||
* `"here is some text ".splitOn "some" = ["here is ", " text "]`
|
||||
* `"here is some text ".splitOn "" = ["here is some text "]`
|
||||
* `"ababacabac".splitOn "aba" = ["", "bac", "c"]`
|
||||
-/
|
||||
@[inline] def splitOn (s : String) (sep : String := " ") : List String :=
|
||||
if sep == "" then [s] else splitOnAux s sep 0 0 0 []
|
||||
|
||||
end String
|
||||
@@ -8,7 +8,6 @@ module
|
||||
prelude
|
||||
public import Init.Data.String.Lemmas.Splits
|
||||
public import Init.Data.String.Lemmas.Modify
|
||||
public import Init.Data.String.Lemmas.Search
|
||||
public import Init.Data.Char.Order
|
||||
public import Init.Data.Char.Lemmas
|
||||
public import Init.Data.List.Lex
|
||||
|
||||
@@ -41,18 +41,6 @@ theorem singleton_ne_empty {c : Char} : singleton c ≠ "" := by
|
||||
|
||||
@[simp]
|
||||
theorem Slice.Pos.toCopy_inj {s : Slice} {p₁ p₂ : s.Pos} : p₁.toCopy = p₂.toCopy ↔ p₁ = p₂ := by
|
||||
simp [String.Pos.ext_iff, Pos.ext_iff]
|
||||
|
||||
@[simp]
|
||||
theorem Pos.startPos_le {s : String} (p : s.Pos) : s.startPos ≤ p := by
|
||||
simp [Pos.le_iff, Pos.Raw.le_iff]
|
||||
|
||||
@[simp]
|
||||
theorem Slice.Pos.startPos_le {s : Slice} (p : s.Pos) : s.startPos ≤ p := by
|
||||
simp [Pos.le_iff, Pos.Raw.le_iff]
|
||||
|
||||
@[simp]
|
||||
theorem Slice.Pos.le_endPos {s : Slice} (p : s.Pos) : p ≤ s.endPos :=
|
||||
p.isValidForSlice.le_rawEndPos
|
||||
simp [Pos.ext_iff, ValidPos.ext_iff]
|
||||
|
||||
end String
|
||||
|
||||
@@ -22,22 +22,22 @@ public section
|
||||
|
||||
namespace String
|
||||
|
||||
/-- You might want to invoke `Pos.Splits.exists_eq_singleton_append` to be able to apply this. -/
|
||||
theorem Pos.Splits.pastSet {s : String} {p : s.Pos} {t₁ t₂ : String}
|
||||
/-- You might want to invoke `ValidPos.Splits.exists_eq_singleton_append` to be able to apply this. -/
|
||||
theorem ValidPos.Splits.pastSet {s : String} {p : s.ValidPos} {t₁ t₂ : String}
|
||||
{c d : Char} (h : p.Splits t₁ (singleton c ++ t₂)) :
|
||||
(p.pastSet d h.ne_endPos_of_singleton).Splits (t₁ ++ singleton d) t₂ := by
|
||||
generalize h.ne_endPos_of_singleton = hp
|
||||
(p.pastSet d h.ne_endValidPos_of_singleton).Splits (t₁ ++ singleton d) t₂ := by
|
||||
generalize h.ne_endValidPos_of_singleton = hp
|
||||
obtain ⟨rfl, rfl, rfl⟩ := by simpa using h.eq (p.splits_next_right hp)
|
||||
apply splits_pastSet
|
||||
|
||||
/-- You might want to invoke `Pos.Splits.exists_eq_singleton_append` to be able to apply this. -/
|
||||
theorem Pos.Splits.pastModify {s : String} {p : s.Pos} {t₁ t₂ : String}
|
||||
/-- You might want to invoke `ValidPos.Splits.exists_eq_singleton_append` to be able to apply this. -/
|
||||
theorem ValidPos.Splits.pastModify {s : String} {p : s.ValidPos} {t₁ t₂ : String}
|
||||
{c : Char} (h : p.Splits t₁ (singleton c ++ t₂)) :
|
||||
(p.pastModify f h.ne_endPos_of_singleton).Splits
|
||||
(t₁ ++ singleton (f (p.get h.ne_endPos_of_singleton))) t₂ :=
|
||||
(p.pastModify f h.ne_endValidPos_of_singleton).Splits
|
||||
(t₁ ++ singleton (f (p.get h.ne_endValidPos_of_singleton))) t₂ :=
|
||||
h.pastSet
|
||||
|
||||
theorem toList_mapAux {f : Char → Char} {s : String} {p : s.Pos}
|
||||
theorem toList_mapAux {f : Char → Char} {s : String} {p : s.ValidPos}
|
||||
(h : p.Splits t₁ t₂) : (mapAux f s p).toList = t₁.toList ++ t₂.toList.map f := by
|
||||
fun_induction mapAux generalizing t₁ t₂ with
|
||||
| case1 s => simp_all
|
||||
@@ -47,7 +47,7 @@ theorem toList_mapAux {f : Char → Char} {s : String} {p : s.Pos}
|
||||
|
||||
@[simp]
|
||||
theorem toList_map {f : Char → Char} {s : String} : (s.map f).toList = s.toList.map f := by
|
||||
simp [map, toList_mapAux s.splits_startPos]
|
||||
simp [map, toList_mapAux s.splits_startValidPos]
|
||||
|
||||
@[simp]
|
||||
theorem length_map {f : Char → Char} {s : String} : (s.map f).length = s.length := by
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
/-
|
||||
Copyright (c) 2025 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.Search
|
||||
import all Init.Data.String.Search
|
||||
|
||||
public section
|
||||
|
||||
namespace String
|
||||
open String.Slice Pattern
|
||||
|
||||
variable {ρ : Type} {σ : Slice → Type}
|
||||
variable [∀ s, Std.Iterators.Iterator (σ s) Id (SearchStep s)]
|
||||
variable [∀ s, Std.Iterators.Finite (σ s) Id]
|
||||
variable [∀ s, Std.Iterators.IteratorLoop (σ s) Id Id]
|
||||
|
||||
@[simp]
|
||||
theorem Slice.Pos.le_find {s : Slice} (pos : s.Pos) (pattern : ρ) [ToForwardSearcher pattern σ] :
|
||||
pos ≤ pos.find pattern := by
|
||||
simp [Slice.Pos.find]
|
||||
|
||||
@[simp]
|
||||
theorem Pos.le_find {s : String} (pos : s.Pos) (pattern : ρ) [ToForwardSearcher pattern σ] :
|
||||
pos ≤ pos.find pattern := by
|
||||
simp [Pos.find, ← toSlice_le]
|
||||
|
||||
end String
|
||||
@@ -11,7 +11,7 @@ import Init.Data.ByteArray.Lemmas
|
||||
import Init.Data.String.Lemmas.Basic
|
||||
|
||||
/-!
|
||||
# `Splits` predicates on `String.Pos` and `String.Slice.Pos`.
|
||||
# `Splits` predicates on `String.ValidPos` and `String.Slice.Pos`.
|
||||
|
||||
We introduce the predicate `p.Splits t₁ t₂` for a position `p` on a string or slice `s`, which means
|
||||
that `s = t₁ ++ t₂` with `p` lying between the two parts. This is a useful primitive when verifying
|
||||
@@ -26,7 +26,7 @@ namespace String
|
||||
We say that `p` splits `s` into `t₁` and `t₂` if `s = t₁ ++ t₂` and `p` is the position between `t₁`
|
||||
and `t₂`.
|
||||
-/
|
||||
structure Pos.Splits {s : String} (p : s.Pos) (t₁ t₂ : String) : Prop where
|
||||
structure ValidPos.Splits {s : String} (p : s.ValidPos) (t₁ t₂ : String) : Prop where
|
||||
eq_append : s = t₁ ++ t₂
|
||||
offset_eq_rawEndPos : p.offset = t₁.rawEndPos
|
||||
|
||||
@@ -39,11 +39,11 @@ structure Slice.Pos.Splits {s : Slice} (p : s.Pos) (t₁ t₂ : String) : Prop w
|
||||
offset_eq_rawEndPos : p.offset = t₁.rawEndPos
|
||||
|
||||
@[simp]
|
||||
theorem Pos.splits_cast_iff {s₁ s₂ : String} {h : s₁ = s₂} {p : s₁.Pos} {t₁ t₂ : String} :
|
||||
theorem ValidPos.splits_cast_iff {s₁ s₂ : String} {h : s₁ = s₂} {p : s₁.ValidPos} {t₁ t₂ : String} :
|
||||
(p.cast h).Splits t₁ t₂ ↔ p.Splits t₁ t₂ := by
|
||||
subst h; simp
|
||||
|
||||
theorem Pos.Splits.cast {s₁ s₂ : String} {p : s₁.Pos} {t₁ t₂ : String} (h : s₁ = s₂) :
|
||||
theorem ValidPos.Splits.cast {s₁ s₂ : String} {p : s₁.ValidPos} {t₁ t₂ : String} (h : s₁ = s₂) :
|
||||
p.Splits t₁ t₂ → (p.cast h).Splits t₁ t₂ :=
|
||||
splits_cast_iff.mpr
|
||||
|
||||
@@ -72,41 +72,41 @@ theorem Slice.Pos.splits_toCopy_iff {s : Slice} {p : s.Pos} {t₁ t₂ : String}
|
||||
⟨splits_of_splits_toCopy, (·.toCopy)⟩
|
||||
|
||||
@[simp]
|
||||
theorem Pos.splits_toSlice_iff {s : String} {p : s.Pos} {t₁ t₂ : String} :
|
||||
theorem ValidPos.splits_toSlice_iff {s : String} {p : s.ValidPos} {t₁ t₂ : String} :
|
||||
p.toSlice.Splits t₁ t₂ ↔ p.Splits t₁ t₂ := by
|
||||
rw [← Slice.Pos.splits_toCopy_iff, p.toCopy_toSlice_eq_cast, splits_cast_iff]
|
||||
|
||||
theorem Pos.Splits.toSlice {s : String} {p : s.Pos} {t₁ t₂ : String}
|
||||
theorem ValidPos.Splits.toSlice {s : String} {p : s.ValidPos} {t₁ t₂ : String}
|
||||
(h : p.Splits t₁ t₂) : p.toSlice.Splits t₁ t₂ :=
|
||||
splits_toSlice_iff.mpr h
|
||||
|
||||
theorem Pos.splits {s : String} (p : s.Pos) :
|
||||
p.Splits (s.sliceTo p).copy (s.sliceFrom p).copy where
|
||||
eq_append := by simp [← toByteArray_inj, Slice.toByteArray_copy, ← size_toByteArray]
|
||||
theorem ValidPos.splits {s : String} (p : s.ValidPos) :
|
||||
p.Splits (s.replaceEnd p).copy (s.replaceStart p).copy where
|
||||
eq_append := by simp [← bytes_inj, Slice.bytes_copy, ← size_bytes]
|
||||
offset_eq_rawEndPos := by simp
|
||||
|
||||
theorem Slice.Pos.splits {s : Slice} (p : s.Pos) :
|
||||
p.Splits (s.sliceTo p).copy (s.sliceFrom p).copy where
|
||||
eq_append := copy_eq_copy_sliceTo
|
||||
p.Splits (s.replaceEnd p).copy (s.replaceStart p).copy where
|
||||
eq_append := copy_eq_copy_replaceEnd
|
||||
offset_eq_rawEndPos := by simp
|
||||
|
||||
theorem Pos.Splits.toByteArray_left_eq {s : String} {p : s.Pos} {t₁ t₂}
|
||||
(h : p.Splits t₁ t₂) : t₁.toByteArray = s.toByteArray.extract 0 p.offset.byteIdx := by
|
||||
theorem ValidPos.Splits.bytes_left_eq {s : String} {p : s.ValidPos} {t₁ t₂}
|
||||
(h : p.Splits t₁ t₂) : t₁.bytes = s.bytes.extract 0 p.offset.byteIdx := by
|
||||
simp [h.eq_append, h.offset_eq_rawEndPos, ByteArray.extract_append_eq_left]
|
||||
|
||||
theorem Pos.Splits.toByteArray_right_eq {s : String} {p : s.Pos} {t₁ t₂}
|
||||
(h : p.Splits t₁ t₂) : t₂.toByteArray = s.toByteArray.extract p.offset.byteIdx s.utf8ByteSize := by
|
||||
theorem ValidPos.Splits.bytes_right_eq {s : String} {p : s.ValidPos} {t₁ t₂}
|
||||
(h : p.Splits t₁ t₂) : t₂.bytes = s.bytes.extract p.offset.byteIdx s.utf8ByteSize := by
|
||||
simp [h.eq_append, h.offset_eq_rawEndPos, ByteArray.extract_append_eq_right]
|
||||
|
||||
theorem Pos.Splits.eq_left {s : String} {p : s.Pos} {t₁ t₂ t₃ t₄}
|
||||
theorem ValidPos.Splits.eq_left {s : String} {p : s.ValidPos} {t₁ t₂ t₃ t₄}
|
||||
(h₁ : p.Splits t₁ t₂) (h₂ : p.Splits t₃ t₄) : t₁ = t₃ := by
|
||||
rw [← String.toByteArray_inj, h₁.toByteArray_left_eq, h₂.toByteArray_left_eq]
|
||||
rw [← String.bytes_inj, h₁.bytes_left_eq, h₂.bytes_left_eq]
|
||||
|
||||
theorem Pos.Splits.eq_right {s : String} {p : s.Pos} {t₁ t₂ t₃ t₄}
|
||||
theorem ValidPos.Splits.eq_right {s : String} {p : s.ValidPos} {t₁ t₂ t₃ t₄}
|
||||
(h₁ : p.Splits t₁ t₂) (h₂ : p.Splits t₃ t₄) : t₂ = t₄ := by
|
||||
rw [← String.toByteArray_inj, h₁.toByteArray_right_eq, h₂.toByteArray_right_eq]
|
||||
rw [← String.bytes_inj, h₁.bytes_right_eq, h₂.bytes_right_eq]
|
||||
|
||||
theorem Pos.Splits.eq {s : String} {p : s.Pos} {t₁ t₂ t₃ t₄}
|
||||
theorem ValidPos.Splits.eq {s : String} {p : s.ValidPos} {t₁ t₂ t₃ t₄}
|
||||
(h₁ : p.Splits t₁ t₂) (h₂ : p.Splits t₃ t₄) : t₁ = t₃ ∧ t₂ = t₄ :=
|
||||
⟨h₁.eq_left h₂, h₁.eq_right h₂⟩
|
||||
|
||||
@@ -123,35 +123,35 @@ theorem Slice.Pos.Splits.eq {s : Slice} {p : s.Pos} {t₁ t₂ t₃ t₄}
|
||||
(splits_toCopy_iff.2 h₁).eq (splits_toCopy_iff.2 h₂)
|
||||
|
||||
@[simp]
|
||||
theorem splits_endPos (s : String) : s.endPos.Splits s "" where
|
||||
theorem splits_endValidPos (s : String) : s.endValidPos.Splits s "" where
|
||||
eq_append := by simp
|
||||
offset_eq_rawEndPos := by simp
|
||||
|
||||
@[simp]
|
||||
theorem splits_endPos_iff {s : String} :
|
||||
s.endPos.Splits t₁ t₂ ↔ t₁ = s ∧ t₂ = "" :=
|
||||
⟨fun h => ⟨h.eq_left s.splits_endPos, h.eq_right s.splits_endPos⟩,
|
||||
by rintro ⟨rfl, rfl⟩; exact t₁.splits_endPos⟩
|
||||
theorem splits_endValidPos_iff {s : String} :
|
||||
s.endValidPos.Splits t₁ t₂ ↔ t₁ = s ∧ t₂ = "" :=
|
||||
⟨fun h => ⟨h.eq_left s.splits_endValidPos, h.eq_right s.splits_endValidPos⟩,
|
||||
by rintro ⟨rfl, rfl⟩; exact t₁.splits_endValidPos⟩
|
||||
|
||||
theorem Pos.Splits.eq_endPos_iff {s : String} {p : s.Pos} (h : p.Splits t₁ t₂) :
|
||||
p = s.endPos ↔ t₂ = "" :=
|
||||
⟨fun h' => h.eq_right (h' ▸ s.splits_endPos),
|
||||
by rintro rfl; simp [Pos.ext_iff, h.offset_eq_rawEndPos, h.eq_append]⟩
|
||||
theorem ValidPos.Splits.eq_endValidPos_iff {s : String} {p : s.ValidPos} (h : p.Splits t₁ t₂) :
|
||||
p = s.endValidPos ↔ t₂ = "" :=
|
||||
⟨fun h' => h.eq_right (h' ▸ s.splits_endValidPos),
|
||||
by rintro rfl; simp [ValidPos.ext_iff, h.offset_eq_rawEndPos, h.eq_append]⟩
|
||||
|
||||
theorem splits_startPos (s : String) : s.startPos.Splits "" s where
|
||||
theorem splits_startValidPos (s : String) : s.startValidPos.Splits "" s where
|
||||
eq_append := by simp
|
||||
offset_eq_rawEndPos := by simp
|
||||
|
||||
@[simp]
|
||||
theorem splits_startPos_iff {s : String} :
|
||||
s.startPos.Splits t₁ t₂ ↔ t₁ = "" ∧ t₂ = s :=
|
||||
⟨fun h => ⟨h.eq_left s.splits_startPos, h.eq_right s.splits_startPos⟩,
|
||||
by rintro ⟨rfl, rfl⟩; exact t₂.splits_startPos⟩
|
||||
theorem splits_startValidPos_iff {s : String} :
|
||||
s.startValidPos.Splits t₁ t₂ ↔ t₁ = "" ∧ t₂ = s :=
|
||||
⟨fun h => ⟨h.eq_left s.splits_startValidPos, h.eq_right s.splits_startValidPos⟩,
|
||||
by rintro ⟨rfl, rfl⟩; exact t₂.splits_startValidPos⟩
|
||||
|
||||
theorem Pos.Splits.eq_startPos_iff {s : String} {p : s.Pos} (h : p.Splits t₁ t₂) :
|
||||
p = s.startPos ↔ t₁ = "" :=
|
||||
⟨fun h' => h.eq_left (h' ▸ s.splits_startPos),
|
||||
by rintro rfl; simp [Pos.ext_iff, h.offset_eq_rawEndPos]⟩
|
||||
theorem ValidPos.Splits.eq_startValidPos_iff {s : String} {p : s.ValidPos} (h : p.Splits t₁ t₂) :
|
||||
p = s.startValidPos ↔ t₁ = "" :=
|
||||
⟨fun h' => h.eq_left (h' ▸ s.splits_startValidPos),
|
||||
by rintro rfl; simp [ValidPos.ext_iff, h.offset_eq_rawEndPos]⟩
|
||||
|
||||
@[simp]
|
||||
theorem Slice.splits_endPos (s : Slice) : s.endPos.Splits s.copy "" where
|
||||
@@ -161,11 +161,11 @@ theorem Slice.splits_endPos (s : Slice) : s.endPos.Splits s.copy "" where
|
||||
@[simp]
|
||||
theorem Slice.splits_endPos_iff {s : Slice} :
|
||||
s.endPos.Splits t₁ t₂ ↔ t₁ = s.copy ∧ t₂ = "" := by
|
||||
rw [← Pos.splits_toCopy_iff, ← endPos_copy, String.splits_endPos_iff]
|
||||
rw [← Pos.splits_toCopy_iff, ← endValidPos_copy, splits_endValidPos_iff]
|
||||
|
||||
theorem Slice.Pos.Splits.eq_endPos_iff {s : Slice} {p : s.Pos} (h : p.Splits t₁ t₂) :
|
||||
p = s.endPos ↔ t₂ = "" := by
|
||||
rw [← toCopy_inj, ← endPos_copy, h.toCopy.eq_endPos_iff]
|
||||
rw [← toCopy_inj, ← endValidPos_copy, h.toCopy.eq_endValidPos_iff]
|
||||
|
||||
@[simp]
|
||||
theorem Slice.splits_startPos (s : Slice) : s.startPos.Splits "" s.copy where
|
||||
@@ -175,55 +175,55 @@ theorem Slice.splits_startPos (s : Slice) : s.startPos.Splits "" s.copy where
|
||||
@[simp]
|
||||
theorem Slice.splits_startPos_iff {s : Slice} :
|
||||
s.startPos.Splits t₁ t₂ ↔ t₁ = "" ∧ t₂ = s.copy := by
|
||||
rw [← Pos.splits_toCopy_iff, ← startPos_copy, String.splits_startPos_iff]
|
||||
rw [← Pos.splits_toCopy_iff, ← startValidPos_copy, splits_startValidPos_iff]
|
||||
|
||||
theorem Slice.Pos.Splits.eq_startPos_iff {s : Slice} {p : s.Pos} (h : p.Splits t₁ t₂) :
|
||||
p = s.startPos ↔ t₁ = "" := by
|
||||
rw [← toCopy_inj, ← startPos_copy, h.toCopy.eq_startPos_iff]
|
||||
rw [← toCopy_inj, ← startValidPos_copy, h.toCopy.eq_startValidPos_iff]
|
||||
|
||||
theorem Pos.splits_next_right {s : String} (p : s.Pos) (hp : p ≠ s.endPos) :
|
||||
p.Splits (s.sliceTo p).copy (singleton (p.get hp) ++ (s.sliceFrom (p.next hp)).copy) where
|
||||
eq_append := by simpa [← append_assoc] using p.eq_copy_sliceTo_append_get hp
|
||||
theorem ValidPos.splits_next_right {s : String} (p : s.ValidPos) (hp : p ≠ s.endValidPos) :
|
||||
p.Splits (s.replaceEnd p).copy (singleton (p.get hp) ++ (s.replaceStart (p.next hp)).copy) where
|
||||
eq_append := by simpa [← append_assoc] using p.eq_copy_replaceEnd_append_get hp
|
||||
offset_eq_rawEndPos := by simp
|
||||
|
||||
theorem Pos.splits_next {s : String} (p : s.Pos) (hp : p ≠ s.endPos) :
|
||||
(p.next hp).Splits ((s.sliceTo p).copy ++ singleton (p.get hp)) (s.sliceFrom (p.next hp)).copy where
|
||||
eq_append := p.eq_copy_sliceTo_append_get hp
|
||||
theorem ValidPos.splits_next {s : String} (p : s.ValidPos) (hp : p ≠ s.endValidPos) :
|
||||
(p.next hp).Splits ((s.replaceEnd p).copy ++ singleton (p.get hp)) (s.replaceStart (p.next hp)).copy where
|
||||
eq_append := p.eq_copy_replaceEnd_append_get hp
|
||||
offset_eq_rawEndPos := by simp
|
||||
|
||||
theorem Slice.Pos.splits_next_right {s : Slice} (p : s.Pos) (hp : p ≠ s.endPos) :
|
||||
p.Splits (s.sliceTo p).copy (singleton (p.get hp) ++ (s.sliceFrom (p.next hp)).copy) where
|
||||
eq_append := by simpa [← append_assoc] using p.copy_eq_copy_sliceTo_append_get hp
|
||||
p.Splits (s.replaceEnd p).copy (singleton (p.get hp) ++ (s.replaceStart (p.next hp)).copy) where
|
||||
eq_append := by simpa [← append_assoc] using p.copy_eq_copy_replaceEnd_append_get hp
|
||||
offset_eq_rawEndPos := by simp
|
||||
|
||||
theorem Slice.Pos.splits_next {s : Slice} (p : s.Pos) (hp : p ≠ s.endPos) :
|
||||
(p.next hp).Splits ((s.sliceTo p).copy ++ singleton (p.get hp)) (s.sliceFrom (p.next hp)).copy where
|
||||
eq_append := p.copy_eq_copy_sliceTo_append_get hp
|
||||
(p.next hp).Splits ((s.replaceEnd p).copy ++ singleton (p.get hp)) (s.replaceStart (p.next hp)).copy where
|
||||
eq_append := p.copy_eq_copy_replaceEnd_append_get hp
|
||||
offset_eq_rawEndPos := by simp
|
||||
|
||||
theorem Pos.Splits.exists_eq_singleton_append {s : String} {p : s.Pos}
|
||||
(hp : p ≠ s.endPos) (h : p.Splits t₁ t₂) : ∃ t₂', t₂ = singleton (p.get hp) ++ t₂' :=
|
||||
⟨(s.sliceFrom (p.next hp)).copy, h.eq_right (p.splits_next_right hp)⟩
|
||||
theorem ValidPos.Splits.exists_eq_singleton_append {s : String} {p : s.ValidPos}
|
||||
(hp : p ≠ s.endValidPos) (h : p.Splits t₁ t₂) : ∃ t₂', t₂ = singleton (p.get hp) ++ t₂' :=
|
||||
⟨(s.replaceStart (p.next hp)).copy, h.eq_right (p.splits_next_right hp)⟩
|
||||
|
||||
theorem Pos.Splits.exists_eq_append_singleton {s : String} {p : s.Pos}
|
||||
(hp : p ≠ s.endPos) (h : (p.next hp).Splits t₁ t₂) : ∃ t₁', t₁ = t₁' ++ singleton (p.get hp) :=
|
||||
⟨(s.sliceTo p).copy, h.eq_left (p.splits_next hp)⟩
|
||||
theorem ValidPos.Splits.exists_eq_append_singleton {s : String} {p : s.ValidPos}
|
||||
(hp : p ≠ s.endValidPos) (h : (p.next hp).Splits t₁ t₂) : ∃ t₁', t₁ = t₁' ++ singleton (p.get hp) :=
|
||||
⟨(s.replaceEnd p).copy, h.eq_left (p.splits_next hp)⟩
|
||||
|
||||
theorem Slice.Pos.Splits.exists_eq_singleton_append {s : Slice} {p : s.Pos}
|
||||
(hp : p ≠ s.endPos) (h : p.Splits t₁ t₂) : ∃ t₂', t₂ = singleton (p.get hp) ++ t₂' :=
|
||||
⟨(s.sliceFrom (p.next hp)).copy, h.eq_right (p.splits_next_right hp)⟩
|
||||
⟨(s.replaceStart (p.next hp)).copy, h.eq_right (p.splits_next_right hp)⟩
|
||||
|
||||
theorem Slice.Pos.Splits.exists_eq_append_singleton {s : Slice} {p : s.Pos}
|
||||
(hp : p ≠ s.endPos) (h : (p.next hp).Splits t₁ t₂) : ∃ t₁', t₁ = t₁' ++ singleton (p.get hp) :=
|
||||
⟨(s.sliceTo p).copy, h.eq_left (p.splits_next hp)⟩
|
||||
⟨(s.replaceEnd p).copy, h.eq_left (p.splits_next hp)⟩
|
||||
|
||||
theorem Pos.Splits.ne_endPos_of_singleton {s : String} {p : s.Pos}
|
||||
(h : p.Splits t₁ (singleton c ++ t₂)) : p ≠ s.endPos := by
|
||||
simp [h.eq_endPos_iff]
|
||||
theorem ValidPos.Splits.ne_endValidPos_of_singleton {s : String} {p : s.ValidPos}
|
||||
(h : p.Splits t₁ (singleton c ++ t₂)) : p ≠ s.endValidPos := by
|
||||
simp [h.eq_endValidPos_iff]
|
||||
|
||||
theorem Pos.Splits.ne_startPos_of_singleton {s : String} {p : s.Pos}
|
||||
(h : p.Splits (t₁ ++ singleton c) t₂) : p ≠ s.startPos := by
|
||||
simp [h.eq_startPos_iff]
|
||||
theorem ValidPos.Splits.ne_startValidPos_of_singleton {s : String} {p : s.ValidPos}
|
||||
(h : p.Splits (t₁ ++ singleton c) t₂) : p ≠ s.startValidPos := by
|
||||
simp [h.eq_startValidPos_iff]
|
||||
|
||||
theorem Slice.Pos.Splits.ne_endPos_of_singleton {s : Slice} {p : s.Pos}
|
||||
(h : p.Splits t₁ (singleton c ++ t₂)) : p ≠ s.endPos := by
|
||||
@@ -233,10 +233,10 @@ theorem Slice.Pos.Splits.ne_startPos_of_singleton {s : Slice} {p : s.Pos}
|
||||
(h : p.Splits (t₁ ++ singleton c) t₂) : p ≠ s.startPos := by
|
||||
simp [h.eq_startPos_iff]
|
||||
|
||||
/-- You might want to invoke `Pos.Splits.exists_eq_singleton_append` to be able to apply this. -/
|
||||
theorem Pos.Splits.next {s : String} {p : s.Pos}
|
||||
(h : p.Splits t₁ (singleton c ++ t₂)) : (p.next h.ne_endPos_of_singleton).Splits (t₁ ++ singleton c) t₂ := by
|
||||
generalize h.ne_endPos_of_singleton = hp
|
||||
/-- You might want to invoke `ValidPos.Splits.exists_eq_singleton_append` to be able to apply this. -/
|
||||
theorem ValidPos.Splits.next {s : String} {p : s.ValidPos}
|
||||
(h : p.Splits t₁ (singleton c ++ t₂)) : (p.next h.ne_endValidPos_of_singleton).Splits (t₁ ++ singleton c) t₂ := by
|
||||
generalize h.ne_endValidPos_of_singleton = hp
|
||||
obtain ⟨rfl, rfl, rfl⟩ := by simpa using h.eq (splits_next_right p hp)
|
||||
exact splits_next p hp
|
||||
|
||||
|
||||
@@ -33,69 +33,69 @@ Examples:
|
||||
* `("L∃∀N".pos ⟨4⟩ (by decide)).set 'X' (by decide) = "L∃XN"`
|
||||
-/
|
||||
@[extern "lean_string_utf8_set", expose]
|
||||
def Pos.set {s : String} (p : s.Pos) (c : Char) (hp : p ≠ s.endPos) : String :=
|
||||
def ValidPos.set {s : String} (p : s.ValidPos) (c : Char) (hp : p ≠ s.endValidPos) : String :=
|
||||
if hc : c.utf8Size = 1 ∧ (p.byte hp).utf8ByteSize isUTF8FirstByte_byte = 1 then
|
||||
.ofByteArray (s.toByteArray.set p.offset.byteIdx c.toUInt8 (p.byteIdx_lt_utf8ByteSize hp)) (by
|
||||
.ofByteArray (s.bytes.set p.offset.byteIdx c.toUInt8 (p.byteIdx_lt_utf8ByteSize hp)) (by
|
||||
rw [ByteArray.set_eq_push_extract_append_extract, ← hc.2, utf8ByteSize_byte,
|
||||
← Pos.byteIdx_offset_next]
|
||||
← ValidPos.byteIdx_offset_next]
|
||||
refine ByteArray.IsValidUTF8.append ?_ (p.next hp).isValid.isValidUTF8_extract_utf8ByteSize
|
||||
exact p.isValid.isValidUTF8_extract_zero.push hc.1)
|
||||
else
|
||||
(s.sliceTo p).copy ++ singleton c ++ (s.sliceFrom (p.next hp)).copy
|
||||
(s.replaceEnd p).copy ++ singleton c ++ (s.replaceStart (p.next hp)).copy
|
||||
|
||||
theorem Pos.set_eq_append {s : String} {p : s.Pos} {c : Char} {hp} :
|
||||
p.set c hp = (s.sliceTo p).copy ++ singleton c ++ (s.sliceFrom (p.next hp)).copy := by
|
||||
theorem ValidPos.set_eq_append {s : String} {p : s.ValidPos} {c : Char} {hp} :
|
||||
p.set c hp = (s.replaceEnd p).copy ++ singleton c ++ (s.replaceStart (p.next hp)).copy := by
|
||||
rw [set]
|
||||
split
|
||||
· rename_i h
|
||||
simp [← toByteArray_inj, ByteArray.set_eq_push_extract_append_extract, Slice.toByteArray_copy,
|
||||
simp [← bytes_inj, ByteArray.set_eq_push_extract_append_extract, Slice.bytes_copy,
|
||||
List.utf8Encode_singleton, String.utf8EncodeChar_eq_singleton h.1, utf8ByteSize_byte ▸ h.2]
|
||||
· rfl
|
||||
|
||||
theorem Pos.Raw.IsValid.set_of_le {s : String} {p : s.Pos} {c : Char} {hp : p ≠ s.endPos}
|
||||
theorem Pos.Raw.IsValid.set_of_le {s : String} {p : s.ValidPos} {c : Char} {hp : p ≠ s.endValidPos}
|
||||
{q : Pos.Raw} (hq : q.IsValid s) (hpq : q ≤ p.offset) : q.IsValid (p.set c hp) := by
|
||||
rw [Pos.set_eq_append, String.append_assoc]
|
||||
rw [ValidPos.set_eq_append, String.append_assoc]
|
||||
apply append_right
|
||||
rw [isValid_copy_iff, isValidForSlice_stringSliceTo]
|
||||
rw [isValid_copy_iff, isValidForSlice_stringReplaceEnd]
|
||||
exact ⟨hpq, hq⟩
|
||||
|
||||
/-- Given a valid position in a string, obtain the corresponding position after setting a character on
|
||||
that string, provided that the position was before the changed position. -/
|
||||
@[inline]
|
||||
def Pos.toSetOfLE {s : String} (q p : s.Pos) (c : Char) (hp : p ≠ s.endPos)
|
||||
(hpq : q ≤ p) : (p.set c hp).Pos where
|
||||
def ValidPos.toSetOfLE {s : String} (q p : s.ValidPos) (c : Char) (hp : p ≠ s.endValidPos)
|
||||
(hpq : q ≤ p) : (p.set c hp).ValidPos where
|
||||
offset := q.offset
|
||||
isValid := q.isValid.set_of_le hpq
|
||||
|
||||
@[simp]
|
||||
theorem Pos.offset_toSetOfLE {s : String} {q p : s.Pos} {c : Char} {hp : p ≠ s.endPos}
|
||||
theorem ValidPos.offset_toSetOfLE {s : String} {q p : s.ValidPos} {c : Char} {hp : p ≠ s.endValidPos}
|
||||
{hpq : q ≤ p} : (q.toSetOfLE p c hp hpq).offset = q.offset := (rfl)
|
||||
|
||||
theorem Pos.Raw.isValid_add_char_set {s : String} {p : s.Pos} {c : Char} {hp} :
|
||||
theorem Pos.Raw.isValid_add_char_set {s : String} {p : s.ValidPos} {c : Char} {hp} :
|
||||
(p.offset + c).IsValid (p.set c hp) :=
|
||||
Pos.set_eq_append ▸ IsValid.append_right (isValid_of_eq_rawEndPos (by simp)) _
|
||||
ValidPos.set_eq_append ▸ IsValid.append_right (isValid_of_eq_rawEndPos (by simp)) _
|
||||
|
||||
/-- The position just after the position that changed in a `Pos.set` call. -/
|
||||
/-- The position just after the position that changed in a `ValidPos.set` call. -/
|
||||
@[inline]
|
||||
def Pos.pastSet {s : String} (p : s.Pos) (c : Char) (hp) : (p.set c hp).Pos where
|
||||
def ValidPos.pastSet {s : String} (p : s.ValidPos) (c : Char) (hp) : (p.set c hp).ValidPos where
|
||||
offset := p.offset + c
|
||||
isValid := Pos.Raw.isValid_add_char_set
|
||||
|
||||
@[simp]
|
||||
theorem Pos.offset_pastSet {s : String} {p : s.Pos} {c : Char} {hp} :
|
||||
theorem ValidPos.offset_pastSet {s : String} {p : s.ValidPos} {c : Char} {hp} :
|
||||
(p.pastSet c hp).offset = p.offset + c := (rfl)
|
||||
|
||||
@[inline]
|
||||
def Pos.appendRight {s : String} (p : s.Pos) (t : String) : (s ++ t).Pos where
|
||||
def ValidPos.appendRight {s : String} (p : s.ValidPos) (t : String) : (s ++ t).ValidPos where
|
||||
offset := p.offset
|
||||
isValid := p.isValid.append_right t
|
||||
|
||||
theorem Pos.splits_pastSet {s : String} {p : s.Pos} {c : Char} {hp} :
|
||||
(p.pastSet c hp).Splits ((s.sliceTo p).copy ++ singleton c) (s.sliceFrom (p.next hp)).copy where
|
||||
theorem ValidPos.splits_pastSet {s : String} {p : s.ValidPos} {c : Char} {hp} :
|
||||
(p.pastSet c hp).Splits ((s.replaceEnd p).copy ++ singleton c) (s.replaceStart (p.next hp)).copy where
|
||||
eq_append := set_eq_append
|
||||
offset_eq_rawEndPos := by simp
|
||||
|
||||
theorem remainingBytes_pastSet {s : String} {p : s.Pos} {c : Char} {hp} :
|
||||
theorem remainingBytes_pastSet {s : String} {p : s.ValidPos} {c : Char} {hp} :
|
||||
(p.pastSet c hp).remainingBytes = (p.next hp).remainingBytes := by
|
||||
rw [(p.next hp).splits.remainingBytes_eq, p.splits_pastSet.remainingBytes_eq]
|
||||
|
||||
@@ -110,34 +110,34 @@ Examples:
|
||||
* `("abc".pos ⟨1⟩ (by decide)).modify Char.toUpper (by decide) = "aBc"`
|
||||
-/
|
||||
@[inline]
|
||||
def Pos.modify {s : String} (p : s.Pos) (f : Char → Char) (hp : p ≠ s.endPos) :
|
||||
def ValidPos.modify {s : String} (p : s.ValidPos) (f : Char → Char) (hp : p ≠ s.endValidPos) :
|
||||
String :=
|
||||
p.set (f <| p.get hp) hp
|
||||
|
||||
theorem Pos.Raw.IsValid.modify_of_le {s : String} {p : s.Pos} {f : Char → Char}
|
||||
{hp : p ≠ s.endPos} {q : Pos.Raw} (hq : q.IsValid s) (hpq : q ≤ p.offset) :
|
||||
theorem Pos.Raw.IsValid.modify_of_le {s : String} {p : s.ValidPos} {f : Char → Char}
|
||||
{hp : p ≠ s.endValidPos} {q : Pos.Raw} (hq : q.IsValid s) (hpq : q ≤ p.offset) :
|
||||
q.IsValid (p.modify f hp) :=
|
||||
set_of_le hq hpq
|
||||
|
||||
/-- Given a valid position in a string, obtain the corresponding position after modifying a character
|
||||
in that string, provided that the position was before the changed position. -/
|
||||
@[inline]
|
||||
def Pos.toModifyOfLE {s : String} (q p : s.Pos) (f : Char → Char)
|
||||
(hp : p ≠ s.endPos) (hpq : q ≤ p) : (p.modify f hp).Pos where
|
||||
def ValidPos.toModifyOfLE {s : String} (q p : s.ValidPos) (f : Char → Char)
|
||||
(hp : p ≠ s.endValidPos) (hpq : q ≤ p) : (p.modify f hp).ValidPos where
|
||||
offset := q.offset
|
||||
isValid := q.isValid.modify_of_le hpq
|
||||
|
||||
@[simp]
|
||||
theorem Pos.offset_toModifyOfLE {s : String} {q p : s.Pos} {f : Char → Char}
|
||||
{hp : p ≠ s.endPos} {hpq : q ≤ p} : (q.toModifyOfLE p f hp hpq).offset = q.offset := (rfl)
|
||||
theorem ValidPos.offset_toModifyOfLE {s : String} {q p : s.ValidPos} {f : Char → Char}
|
||||
{hp : p ≠ s.endValidPos} {hpq : q ≤ p} : (q.toModifyOfLE p f hp hpq).offset = q.offset := (rfl)
|
||||
|
||||
/-- The position just after the position that was modified in a `Pos.modify` call. -/
|
||||
/-- The position just after the position that was modified in a `ValidPos.modify` call. -/
|
||||
@[inline]
|
||||
def Pos.pastModify {s : String} (p : s.Pos) (f : Char → Char)
|
||||
(hp : p ≠ s.endPos) : (p.modify f hp).Pos :=
|
||||
def ValidPos.pastModify {s : String} (p : s.ValidPos) (f : Char → Char)
|
||||
(hp : p ≠ s.endValidPos) : (p.modify f hp).ValidPos :=
|
||||
p.pastSet _ _
|
||||
|
||||
theorem remainingBytes_pastModify {s : String} {p : s.Pos} {f : Char → Char} {hp} :
|
||||
theorem remainingBytes_pastModify {s : String} {p : s.ValidPos} {f : Char → Char} {hp} :
|
||||
(p.pastModify f hp).remainingBytes = (p.next hp).remainingBytes :=
|
||||
remainingBytes_pastSet
|
||||
|
||||
@@ -148,8 +148,8 @@ invalid, the string is returned unchanged.
|
||||
If both the replacement character and the replaced character are 7-bit ASCII characters and the
|
||||
string is not shared, then it is updated in-place and not copied.
|
||||
|
||||
This is a legacy function. The recommended alternative is `String.Pos.set`, combined with
|
||||
`String.pos` or another means of obtaining a `String.Pos`.
|
||||
This is a legacy function. The recommended alternative is `String.ValidPos.set`, combined with
|
||||
`String.pos` or another means of obtaining a `String.ValidPos`.
|
||||
|
||||
Examples:
|
||||
* `"abc".set ⟨1⟩ 'B' = "aBc"`
|
||||
@@ -173,8 +173,8 @@ character. If `p` is an invalid position, the string is returned unchanged.
|
||||
If both the replacement character and the replaced character are 7-bit ASCII characters and the
|
||||
string is not shared, then it is updated in-place and not copied.
|
||||
|
||||
This is a legacy function. The recommended alternative is `String.Pos.set`, combined with
|
||||
`String.pos` or another means of obtaining a `String.Pos`.
|
||||
This is a legacy function. The recommended alternative is `String.ValidPos.set`, combined with
|
||||
`String.pos` or another means of obtaining a `String.ValidPos`.
|
||||
|
||||
Examples:
|
||||
* `"abc".modify ⟨1⟩ Char.toUpper = "aBc"`
|
||||
@@ -188,14 +188,14 @@ def Pos.Raw.modify (s : String) (i : Pos.Raw) (f : Char → Char) : String :=
|
||||
def modify (s : String) (i : Pos.Raw) (f : Char → Char) : String :=
|
||||
i.set s (f (i.get s))
|
||||
|
||||
@[specialize] def mapAux (f : Char → Char) (s : String) (p : s.Pos) : String :=
|
||||
if h : p = s.endPos then
|
||||
@[specialize] def mapAux (f : Char → Char) (s : String) (p : s.ValidPos) : String :=
|
||||
if h : p = s.endValidPos then
|
||||
s
|
||||
else
|
||||
mapAux f (p.modify f h) (p.pastModify f h)
|
||||
termination_by p.remainingBytes
|
||||
decreasing_by
|
||||
simp [remainingBytes_pastModify, ← Pos.lt_iff_remainingBytes_lt]
|
||||
simp [remainingBytes_pastModify, ← ValidPos.lt_iff_remainingBytes_lt]
|
||||
|
||||
/--
|
||||
Applies the function `f` to every character in a string, returning a string that contains the
|
||||
@@ -206,7 +206,7 @@ Examples:
|
||||
* `"".map Char.toUpper = ""`
|
||||
-/
|
||||
@[inline] def map (f : Char → Char) (s : String) : String :=
|
||||
mapAux f s s.startPos
|
||||
mapAux f s s.startValidPos
|
||||
|
||||
/--
|
||||
Replaces each character in `s` with the result of applying `Char.toUpper` to it.
|
||||
|
||||
@@ -44,13 +44,13 @@ deriving Inhabited, BEq
|
||||
Provides a conversion from a pattern to an iterator of {name}`SearchStep` that searches for matches
|
||||
of the pattern from the start towards the end of a {name}`Slice`.
|
||||
-/
|
||||
class ToForwardSearcher {ρ : Type} (pat : ρ) (σ : outParam (Slice → Type)) where
|
||||
class ToForwardSearcher (ρ : Type) (σ : outParam (Slice → Type)) where
|
||||
/--
|
||||
Builds an iterator of {name}`SearchStep` corresponding to matches of {name}`pat` along the slice
|
||||
{name}`s`. The {name}`SearchStep`s returned by this iterator must contain ranges that are
|
||||
adjacent, non-overlapping and cover all of {name}`s`.
|
||||
-/
|
||||
toSearcher : (s : Slice) → Std.Iter (α := σ s) (SearchStep s)
|
||||
toSearcher : (s : Slice) → (pat : ρ) → Std.Iter (α := σ s) (SearchStep s)
|
||||
|
||||
/--
|
||||
Provides simple pattern matching capabilities from the start of a {name}`Slice`.
|
||||
@@ -61,16 +61,16 @@ need to specialize in this fashion, then
|
||||
{name (scope := "Init.Data.String.Pattern.Basic")}`ForwardPattern.defaultImplementation` can be used
|
||||
to automatically derive an instance.
|
||||
-/
|
||||
class ForwardPattern {ρ : Type} (pat : ρ) where
|
||||
class ForwardPattern (ρ : Type) where
|
||||
/--
|
||||
Checks whether the slice starts with the pattern.
|
||||
-/
|
||||
startsWith : Slice → Bool
|
||||
startsWith : Slice → ρ → Bool
|
||||
/--
|
||||
Checks whether the slice starts with the pattern. If it does, the slice is returned with the
|
||||
prefix removed; otherwise the result is {name}`none`.
|
||||
-/
|
||||
dropPrefix? : (s : Slice) → Option s.Pos
|
||||
dropPrefix? : (s : Slice) → ρ → Option s.Pos
|
||||
|
||||
namespace Internal
|
||||
|
||||
@@ -112,12 +112,12 @@ def memcmpSlice (lhs rhs : Slice) (lstart : String.Pos.Raw) (rstart : String.Pos
|
||||
(by
|
||||
have := lhs.startInclusive_le_endExclusive
|
||||
have := lhs.endExclusive.isValid.le_utf8ByteSize
|
||||
simp [String.Pos.le_iff, Pos.Raw.le_iff, Slice.utf8ByteSize_eq] at *
|
||||
simp [ValidPos.le_iff, Pos.Raw.le_iff, Slice.utf8ByteSize_eq] at *
|
||||
omega)
|
||||
(by
|
||||
have := rhs.startInclusive_le_endExclusive
|
||||
have := rhs.endExclusive.isValid.le_utf8ByteSize
|
||||
simp [String.Pos.le_iff, Pos.Raw.le_iff, Slice.utf8ByteSize_eq] at *
|
||||
simp [ValidPos.le_iff, Pos.Raw.le_iff, Slice.utf8ByteSize_eq] at *
|
||||
omega)
|
||||
|
||||
end Internal
|
||||
@@ -126,26 +126,26 @@ namespace ForwardPattern
|
||||
|
||||
variable {ρ : Type} {σ : Slice → Type}
|
||||
variable [∀ s, Std.Iterators.Iterator (σ s) Id (SearchStep s)]
|
||||
variable (pat : ρ) [ToForwardSearcher pat σ]
|
||||
variable [ToForwardSearcher ρ σ]
|
||||
|
||||
@[specialize pat]
|
||||
def defaultStartsWith (s : Slice) : Bool :=
|
||||
let searcher := ToForwardSearcher.toSearcher pat s
|
||||
def defaultStartsWith (s : Slice) (pat : ρ) : Bool :=
|
||||
let searcher := ToForwardSearcher.toSearcher s pat
|
||||
match searcher.step with
|
||||
| .yield _ (.matched start ..) _ => s.startPos = start
|
||||
| _ => false
|
||||
|
||||
@[specialize pat]
|
||||
def defaultDropPrefix? (s : Slice) : Option s.Pos :=
|
||||
let searcher := ToForwardSearcher.toSearcher pat s
|
||||
def defaultDropPrefix? (s : Slice) (pat : ρ) : Option s.Pos :=
|
||||
let searcher := ToForwardSearcher.toSearcher s pat
|
||||
match searcher.step with
|
||||
| .yield _ (.matched _ endPos) _ => some endPos
|
||||
| _ => none
|
||||
|
||||
@[always_inline, inline]
|
||||
def defaultImplementation {pat : ρ} [ToForwardSearcher pat σ] : ForwardPattern pat where
|
||||
startsWith := defaultStartsWith pat
|
||||
dropPrefix? := defaultDropPrefix? pat
|
||||
def defaultImplementation : ForwardPattern ρ where
|
||||
startsWith := defaultStartsWith
|
||||
dropPrefix? := defaultDropPrefix?
|
||||
|
||||
end ForwardPattern
|
||||
|
||||
@@ -153,13 +153,13 @@ end ForwardPattern
|
||||
Provides a conversion from a pattern to an iterator of {name}`SearchStep` searching for matches of
|
||||
the pattern from the end towards the start of a {name}`Slice`.
|
||||
-/
|
||||
class ToBackwardSearcher {ρ : Type} (pat : ρ) (σ : outParam (Slice → Type)) where
|
||||
class ToBackwardSearcher (ρ : Type) (σ : outParam (Slice → Type)) where
|
||||
/--
|
||||
Build an iterator of {name}`SearchStep` corresponding to matches of {lean}`pat` along the slice
|
||||
{name}`s`. The {name}`SearchStep`s returned by this iterator must contain ranges that are
|
||||
adjacent, non-overlapping and cover all of {name}`s`.
|
||||
-/
|
||||
toSearcher : (s : Slice) → Std.Iter (α := σ s) (SearchStep s)
|
||||
toSearcher : (s : Slice) → (pat : ρ) → Std.Iter (α := σ s) (SearchStep s)
|
||||
|
||||
/--
|
||||
Provides simple pattern matching capabilities from the end of a {name}`Slice`.
|
||||
@@ -170,41 +170,41 @@ need to specialize in this fashion, then
|
||||
{name (scope := "Init.Data.String.Pattern.Basic")}`BackwardPattern.defaultImplementation` can be
|
||||
used to automatically derive an instance.
|
||||
-/
|
||||
class BackwardPattern {ρ : Type} (pat : ρ) where
|
||||
class BackwardPattern (ρ : Type) where
|
||||
/--
|
||||
Checks whether the slice ends with the pattern.
|
||||
-/
|
||||
endsWith : Slice → Bool
|
||||
endsWith : Slice → ρ → Bool
|
||||
/--
|
||||
Checks whether the slice ends with the pattern. If it does, the slice is returned with the
|
||||
suffix removed; otherwise the result is {name}`none`.
|
||||
-/
|
||||
dropSuffix? : (s : Slice) → Option s.Pos
|
||||
dropSuffix? : (s : Slice) → ρ → Option s.Pos
|
||||
|
||||
namespace ToBackwardSearcher
|
||||
|
||||
variable {ρ : Type} {σ : Slice → Type}
|
||||
variable [∀ s, Std.Iterators.Iterator (σ s) Id (SearchStep s)]
|
||||
variable (pat : ρ) [ToBackwardSearcher pat σ]
|
||||
variable [ToBackwardSearcher ρ σ]
|
||||
|
||||
@[specialize pat]
|
||||
def defaultEndsWith (s : Slice) : Bool :=
|
||||
let searcher := ToBackwardSearcher.toSearcher pat s
|
||||
def defaultEndsWith (s : Slice) (pat : ρ) : Bool :=
|
||||
let searcher := ToBackwardSearcher.toSearcher s pat
|
||||
match searcher.step with
|
||||
| .yield _ (.matched _ endPos) _ => s.endPos = endPos
|
||||
| _ => false
|
||||
|
||||
@[specialize pat]
|
||||
def defaultDropSuffix? (s : Slice) : Option s.Pos :=
|
||||
let searcher := ToBackwardSearcher.toSearcher pat s
|
||||
def defaultDropSuffix? (s : Slice) (pat : ρ) : Option s.Pos :=
|
||||
let searcher := ToBackwardSearcher.toSearcher s pat
|
||||
match searcher.step with
|
||||
| .yield _ (.matched startPos _) _ => some startPos
|
||||
| _ => none
|
||||
|
||||
@[always_inline, inline]
|
||||
def defaultImplementation {pat : ρ} [ToBackwardSearcher pat σ] : BackwardPattern pat where
|
||||
endsWith := defaultEndsWith pat
|
||||
dropSuffix? := defaultDropSuffix? pat
|
||||
def defaultImplementation : BackwardPattern ρ where
|
||||
endsWith := defaultEndsWith
|
||||
dropSuffix? := defaultDropSuffix?
|
||||
|
||||
end ToBackwardSearcher
|
||||
|
||||
|
||||
@@ -21,44 +21,46 @@ public section
|
||||
|
||||
namespace String.Slice.Pattern
|
||||
|
||||
structure ForwardCharSearcher (needle : Char) (s : Slice) where
|
||||
structure ForwardCharSearcher (s : Slice) where
|
||||
currPos : s.Pos
|
||||
needle : Char
|
||||
deriving Inhabited
|
||||
|
||||
namespace ForwardCharSearcher
|
||||
|
||||
@[inline]
|
||||
def iter (c : Char) (s : Slice) : Std.Iter (α := ForwardCharSearcher c s) (SearchStep s) :=
|
||||
{ internalState := { currPos := s.startPos }}
|
||||
def iter (s : Slice) (c : Char) : Std.Iter (α := ForwardCharSearcher s) (SearchStep s) :=
|
||||
{ internalState := { currPos := s.startPos, needle := c }}
|
||||
|
||||
instance (s : Slice) : Std.Iterators.Iterator (ForwardCharSearcher c s) Id (SearchStep s) where
|
||||
instance (s : Slice) : Std.Iterators.Iterator (ForwardCharSearcher s) Id (SearchStep s) where
|
||||
IsPlausibleStep it
|
||||
| .yield it' out =>
|
||||
it.internalState.needle = it'.internalState.needle ∧
|
||||
∃ h1 : it.internalState.currPos ≠ s.endPos,
|
||||
it'.internalState.currPos = it.internalState.currPos.next h1 ∧
|
||||
match out with
|
||||
| .matched startPos endPos =>
|
||||
it.internalState.currPos = startPos ∧
|
||||
it'.internalState.currPos = endPos ∧
|
||||
it.internalState.currPos.get h1 = c
|
||||
it.internalState.currPos.get h1 = it.internalState.needle
|
||||
| .rejected startPos endPos =>
|
||||
it.internalState.currPos = startPos ∧
|
||||
it'.internalState.currPos = endPos ∧
|
||||
it.internalState.currPos.get h1 ≠ c
|
||||
it.internalState.currPos.get h1 ≠ it.internalState.needle
|
||||
| .skip _ => False
|
||||
| .done => it.internalState.currPos = s.endPos
|
||||
step := fun ⟨⟨currPos⟩⟩ =>
|
||||
step := fun ⟨currPos, needle⟩ =>
|
||||
if h1 : currPos = s.endPos then
|
||||
pure (.deflate ⟨.done, by simp [h1]⟩)
|
||||
else
|
||||
let nextPos := currPos.next h1
|
||||
let nextIt := ⟨⟨nextPos⟩⟩
|
||||
if h2 : currPos.get h1 = c then
|
||||
let nextIt := ⟨nextPos, needle⟩
|
||||
if h2 : currPos.get h1 = needle then
|
||||
pure (.deflate ⟨.yield nextIt (.matched currPos nextPos), by simp [h1, h2, nextIt, nextPos]⟩)
|
||||
else
|
||||
pure (.deflate ⟨.yield nextIt (.rejected currPos nextPos), by simp [h1, h2, nextIt, nextPos]⟩)
|
||||
|
||||
def finitenessRelation : Std.Iterators.FinitenessRelation (ForwardCharSearcher s c) Id where
|
||||
def finitenessRelation : Std.Iterators.FinitenessRelation (ForwardCharSearcher s) Id where
|
||||
rel := InvImage WellFoundedRelation.rel (fun it => it.internalState.currPos)
|
||||
wf := InvImage.wf _ WellFoundedRelation.wf
|
||||
subrelation {it it'} h := by
|
||||
@@ -66,21 +68,21 @@ def finitenessRelation : Std.Iterators.FinitenessRelation (ForwardCharSearcher s
|
||||
obtain ⟨step, h, h'⟩ := h
|
||||
cases step
|
||||
· cases h
|
||||
obtain ⟨_, h2, _⟩ := h'
|
||||
obtain ⟨_, h1, h2, _⟩ := h'
|
||||
simp [h2]
|
||||
· cases h'
|
||||
· cases h
|
||||
|
||||
instance : Std.Iterators.Finite (ForwardCharSearcher s c) Id :=
|
||||
instance : Std.Iterators.Finite (ForwardCharSearcher s) Id :=
|
||||
.of_finitenessRelation finitenessRelation
|
||||
|
||||
instance : Std.Iterators.IteratorLoop (ForwardCharSearcher s c) Id Id :=
|
||||
instance : Std.Iterators.IteratorLoop (ForwardCharSearcher s) Id Id :=
|
||||
.defaultImplementation
|
||||
|
||||
instance {c : Char} : ToForwardSearcher c (ForwardCharSearcher c) where
|
||||
toSearcher := iter c
|
||||
instance : ToForwardSearcher Char ForwardCharSearcher where
|
||||
toSearcher := iter
|
||||
|
||||
instance {c : Char} : ForwardPattern c := .defaultImplementation
|
||||
instance : ForwardPattern Char := .defaultImplementation
|
||||
|
||||
end ForwardCharSearcher
|
||||
|
||||
@@ -92,7 +94,7 @@ deriving Inhabited
|
||||
namespace BackwardCharSearcher
|
||||
|
||||
@[inline]
|
||||
def iter (c : Char) (s : Slice) : Std.Iter (α := BackwardCharSearcher s) (SearchStep s) :=
|
||||
def iter (s : Slice) (c : Char) : Std.Iter (α := BackwardCharSearcher s) (SearchStep s) :=
|
||||
{ internalState := { currPos := s.endPos, needle := c }}
|
||||
|
||||
instance (s : Slice) : Std.Iterators.Iterator (BackwardCharSearcher s) Id (SearchStep s) where
|
||||
@@ -142,10 +144,10 @@ instance : Std.Iterators.Finite (BackwardCharSearcher s) Id :=
|
||||
instance : Std.Iterators.IteratorLoop (BackwardCharSearcher s) Id Id :=
|
||||
.defaultImplementation
|
||||
|
||||
instance {c : Char} : ToBackwardSearcher c BackwardCharSearcher where
|
||||
toSearcher := iter c
|
||||
instance : ToBackwardSearcher Char BackwardCharSearcher where
|
||||
toSearcher := iter
|
||||
|
||||
instance {c : Char} : BackwardPattern c := ToBackwardSearcher.defaultImplementation
|
||||
instance : BackwardPattern Char := ToBackwardSearcher.defaultImplementation
|
||||
|
||||
end BackwardCharSearcher
|
||||
|
||||
|
||||
@@ -22,45 +22,47 @@ public section
|
||||
|
||||
namespace String.Slice.Pattern
|
||||
|
||||
structure ForwardCharPredSearcher (p : Char → Bool) (s : Slice) where
|
||||
structure ForwardCharPredSearcher (s : Slice) where
|
||||
currPos : s.Pos
|
||||
needle : Char → Bool
|
||||
deriving Inhabited
|
||||
|
||||
namespace ForwardCharPredSearcher
|
||||
|
||||
@[inline]
|
||||
def iter (p : Char → Bool) (s : Slice) : Std.Iter (α := ForwardCharPredSearcher p s) (SearchStep s) :=
|
||||
{ internalState := { currPos := s.startPos }}
|
||||
def iter (s : Slice) (p : Char → Bool) : Std.Iter (α := ForwardCharPredSearcher s) (SearchStep s) :=
|
||||
{ internalState := { currPos := s.startPos, needle := p }}
|
||||
|
||||
instance (s : Slice) : Std.Iterators.Iterator (ForwardCharPredSearcher p s) Id (SearchStep s) where
|
||||
instance (s : Slice) : Std.Iterators.Iterator (ForwardCharPredSearcher s) Id (SearchStep s) where
|
||||
IsPlausibleStep it
|
||||
| .yield it' out =>
|
||||
it.internalState.needle = it'.internalState.needle ∧
|
||||
∃ h1 : it.internalState.currPos ≠ s.endPos,
|
||||
it'.internalState.currPos = it.internalState.currPos.next h1 ∧
|
||||
match out with
|
||||
| .matched startPos endPos =>
|
||||
it.internalState.currPos = startPos ∧
|
||||
it'.internalState.currPos = endPos ∧
|
||||
p (it.internalState.currPos.get h1)
|
||||
it.internalState.needle (it.internalState.currPos.get h1)
|
||||
| .rejected startPos endPos =>
|
||||
it.internalState.currPos = startPos ∧
|
||||
it'.internalState.currPos = endPos ∧
|
||||
¬ p (it.internalState.currPos.get h1)
|
||||
¬ it.internalState.needle (it.internalState.currPos.get h1)
|
||||
| .skip _ => False
|
||||
| .done => it.internalState.currPos = s.endPos
|
||||
step := fun ⟨⟨currPos⟩⟩ =>
|
||||
step := fun ⟨currPos, needle⟩ =>
|
||||
if h1 : currPos = s.endPos then
|
||||
pure (.deflate ⟨.done, by simp [h1]⟩)
|
||||
else
|
||||
let nextPos := currPos.next h1
|
||||
let nextIt := ⟨⟨nextPos⟩⟩
|
||||
if h2 : p <| currPos.get h1 then
|
||||
let nextIt := ⟨nextPos, needle⟩
|
||||
if h2 : needle <| currPos.get h1 then
|
||||
pure (.deflate ⟨.yield nextIt (.matched currPos nextPos), by simp [h1, h2, nextPos, nextIt]⟩)
|
||||
else
|
||||
pure (.deflate ⟨.yield nextIt (.rejected currPos nextPos), by simp [h1, h2, nextPos, nextIt]⟩)
|
||||
|
||||
|
||||
def finitenessRelation : Std.Iterators.FinitenessRelation (ForwardCharPredSearcher p s) Id where
|
||||
def finitenessRelation : Std.Iterators.FinitenessRelation (ForwardCharPredSearcher s) Id where
|
||||
rel := InvImage WellFoundedRelation.rel (fun it => it.internalState.currPos)
|
||||
wf := InvImage.wf _ WellFoundedRelation.wf
|
||||
subrelation {it it'} h := by
|
||||
@@ -68,27 +70,21 @@ def finitenessRelation : Std.Iterators.FinitenessRelation (ForwardCharPredSearch
|
||||
obtain ⟨step, h, h'⟩ := h
|
||||
cases step
|
||||
· cases h
|
||||
obtain ⟨_, h2, _⟩ := h'
|
||||
obtain ⟨_, h1, h2, _⟩ := h'
|
||||
simp [h2]
|
||||
· cases h'
|
||||
· cases h
|
||||
|
||||
instance : Std.Iterators.Finite (ForwardCharPredSearcher p s) Id :=
|
||||
instance : Std.Iterators.Finite (ForwardCharPredSearcher s) Id :=
|
||||
.of_finitenessRelation finitenessRelation
|
||||
|
||||
instance : Std.Iterators.IteratorLoop (ForwardCharPredSearcher p s) Id Id :=
|
||||
instance : Std.Iterators.IteratorLoop (ForwardCharPredSearcher s) Id Id :=
|
||||
.defaultImplementation
|
||||
|
||||
instance {p : Char → Bool} : ToForwardSearcher p (ForwardCharPredSearcher p) where
|
||||
toSearcher := iter p
|
||||
instance : ToForwardSearcher (Char → Bool) ForwardCharPredSearcher where
|
||||
toSearcher := iter
|
||||
|
||||
instance {p : Char → Bool} : ForwardPattern p := .defaultImplementation
|
||||
|
||||
instance {p : Char → Prop} [DecidablePred p] : ToForwardSearcher p (ForwardCharPredSearcher p) where
|
||||
toSearcher := iter (decide <| p ·)
|
||||
|
||||
instance {p : Char → Prop} [DecidablePred p] : ForwardPattern p :=
|
||||
.defaultImplementation
|
||||
instance : ForwardPattern (Char → Bool) := .defaultImplementation
|
||||
|
||||
end ForwardCharPredSearcher
|
||||
|
||||
@@ -100,7 +96,7 @@ deriving Inhabited
|
||||
namespace BackwardCharPredSearcher
|
||||
|
||||
@[inline]
|
||||
def iter (c : Char → Bool) (s : Slice) : Std.Iter (α := BackwardCharPredSearcher s) (SearchStep s) :=
|
||||
def iter (s : Slice) (c : Char → Bool) : Std.Iter (α := BackwardCharPredSearcher s) (SearchStep s) :=
|
||||
{ internalState := { currPos := s.endPos, needle := c }}
|
||||
|
||||
instance (s : Slice) : Std.Iterators.Iterator (BackwardCharPredSearcher s) Id (SearchStep s) where
|
||||
@@ -153,16 +149,10 @@ instance : Std.Iterators.Finite (BackwardCharPredSearcher s) Id :=
|
||||
instance : Std.Iterators.IteratorLoop (BackwardCharPredSearcher s) Id Id :=
|
||||
.defaultImplementation
|
||||
|
||||
instance {p : Char → Bool} : ToBackwardSearcher p BackwardCharPredSearcher where
|
||||
toSearcher := iter p
|
||||
instance : ToBackwardSearcher (Char → Bool) BackwardCharPredSearcher where
|
||||
toSearcher := iter
|
||||
|
||||
instance {p : Char → Bool} : BackwardPattern p := ToBackwardSearcher.defaultImplementation
|
||||
|
||||
instance {p : Char → Prop} [DecidablePred p] : ToBackwardSearcher p BackwardCharPredSearcher where
|
||||
toSearcher := iter (decide <| p ·)
|
||||
|
||||
instance {p : Char → Prop} [DecidablePred p] : BackwardPattern p :=
|
||||
ToBackwardSearcher.defaultImplementation
|
||||
instance : BackwardPattern (Char → Bool) := ToBackwardSearcher.defaultImplementation
|
||||
|
||||
end BackwardCharPredSearcher
|
||||
|
||||
|
||||
@@ -84,7 +84,7 @@ inductive _root_.String.Slice.Pattern.ForwardSliceSearcher (s : Slice) where
|
||||
deriving Inhabited
|
||||
|
||||
@[inline]
|
||||
def iter (pat : Slice) (s : Slice) : Std.Iter (α := ForwardSliceSearcher s) (SearchStep s) :=
|
||||
def iter (s : Slice) (pat : Slice) : Std.Iter (α := ForwardSliceSearcher s) (SearchStep s) :=
|
||||
if h : pat.utf8ByteSize = 0 then
|
||||
{ internalState := .emptyBefore s.startPos }
|
||||
else
|
||||
@@ -259,11 +259,11 @@ instance : Std.Iterators.IteratorCollect (ForwardSliceSearcher s) Id Id :=
|
||||
instance : Std.Iterators.IteratorLoop (ForwardSliceSearcher s) Id Id :=
|
||||
.defaultImplementation
|
||||
|
||||
instance {pat : Slice} : ToForwardSearcher pat ForwardSliceSearcher where
|
||||
toSearcher := iter pat
|
||||
instance : ToForwardSearcher Slice ForwardSliceSearcher where
|
||||
toSearcher := iter
|
||||
|
||||
@[inline]
|
||||
def startsWith (pat : Slice) (s : Slice) : Bool :=
|
||||
def startsWith (s : Slice) (pat : Slice) : Bool :=
|
||||
if h : pat.utf8ByteSize ≤ s.utf8ByteSize then
|
||||
have hs := by
|
||||
simp [Pos.Raw.le_iff] at h ⊢
|
||||
@@ -275,29 +275,29 @@ def startsWith (pat : Slice) (s : Slice) : Bool :=
|
||||
false
|
||||
|
||||
@[inline]
|
||||
def dropPrefix? (pat : Slice) (s : Slice) : Option s.Pos :=
|
||||
if startsWith pat s then
|
||||
def dropPrefix? (s : Slice) (pat : Slice) : Option s.Pos :=
|
||||
if startsWith s pat then
|
||||
some <| s.pos! <| pat.rawEndPos.offsetBy s.startPos.offset
|
||||
else
|
||||
none
|
||||
|
||||
instance {pat : Slice} : ForwardPattern pat where
|
||||
startsWith := startsWith pat
|
||||
dropPrefix? := dropPrefix? pat
|
||||
instance : ForwardPattern Slice where
|
||||
startsWith := startsWith
|
||||
dropPrefix? := dropPrefix?
|
||||
|
||||
instance {pat : String} : ToForwardSearcher pat ForwardSliceSearcher where
|
||||
toSearcher := iter pat.toSlice
|
||||
instance : ToForwardSearcher String ForwardSliceSearcher where
|
||||
toSearcher slice pat := iter slice pat.toSlice
|
||||
|
||||
instance {pat : String} : ForwardPattern pat where
|
||||
startsWith := startsWith pat.toSlice
|
||||
dropPrefix? := dropPrefix? pat.toSlice
|
||||
instance : ForwardPattern String where
|
||||
startsWith s pat := startsWith s pat.toSlice
|
||||
dropPrefix? s pat := dropPrefix? s pat.toSlice
|
||||
|
||||
end ForwardSliceSearcher
|
||||
|
||||
namespace BackwardSliceSearcher
|
||||
|
||||
@[inline]
|
||||
def endsWith (pat : Slice) (s : Slice) : Bool :=
|
||||
def endsWith (s : Slice) (pat : Slice) : Bool :=
|
||||
if h : pat.utf8ByteSize ≤ s.utf8ByteSize then
|
||||
let sStart := s.endPos.offset.unoffsetBy pat.rawEndPos
|
||||
let patStart := pat.startPos.offset
|
||||
@@ -311,19 +311,19 @@ def endsWith (pat : Slice) (s : Slice) : Bool :=
|
||||
false
|
||||
|
||||
@[inline]
|
||||
def dropSuffix? (pat : Slice) (s : Slice) : Option s.Pos :=
|
||||
if endsWith pat s then
|
||||
def dropSuffix? (s : Slice) (pat : Slice) : Option s.Pos :=
|
||||
if endsWith s pat then
|
||||
some <| s.pos! <| s.endPos.offset.unoffsetBy pat.rawEndPos
|
||||
else
|
||||
none
|
||||
|
||||
instance {pat : Slice} : BackwardPattern pat where
|
||||
endsWith := endsWith pat
|
||||
dropSuffix? := dropSuffix? pat
|
||||
instance : BackwardPattern Slice where
|
||||
endsWith := endsWith
|
||||
dropSuffix? := dropSuffix?
|
||||
|
||||
instance {pat : String} : BackwardPattern pat where
|
||||
endsWith := endsWith pat.toSlice
|
||||
dropSuffix? := dropSuffix? pat.toSlice
|
||||
instance : BackwardPattern String where
|
||||
endsWith s pat := endsWith s pat.toSlice
|
||||
dropSuffix? s pat := dropSuffix? s pat.toSlice
|
||||
|
||||
end BackwardSliceSearcher
|
||||
|
||||
|
||||
@@ -108,7 +108,7 @@ At runtime, this function is implemented by efficient, constant-time code.
|
||||
-/
|
||||
@[extern "lean_string_get_byte_fast", expose]
|
||||
def getUTF8Byte (s : @& String) (p : Pos.Raw) (h : p < s.rawEndPos) : UInt8 :=
|
||||
s.toByteArray[p.byteIdx]
|
||||
s.bytes[p.byteIdx]
|
||||
|
||||
@[deprecated getUTF8Byte (since := "2025-10-01"), extern "lean_string_get_byte_fast", expose]
|
||||
abbrev getUtf8Byte (s : String) (p : Pos.Raw) (h : p < s.rawEndPos) : UInt8 :=
|
||||
@@ -216,7 +216,7 @@ theorem Pos.Raw.increaseBy_charUtf8Size {p : Pos.Raw} {c : Char} :
|
||||
p.increaseBy c.utf8Size = p + c := by
|
||||
simp [Pos.Raw.ext_iff]
|
||||
|
||||
/-- Increases the byte offset of the position by `1`. Not to be confused with `Pos.next`. -/
|
||||
/-- Increases the byte offset of the position by `1`. Not to be confused with `ValidPos.next`. -/
|
||||
@[inline, expose]
|
||||
def Pos.Raw.inc (p : Pos.Raw) : Pos.Raw :=
|
||||
⟨p.byteIdx + 1⟩
|
||||
@@ -224,7 +224,7 @@ def Pos.Raw.inc (p : Pos.Raw) : Pos.Raw :=
|
||||
@[simp]
|
||||
theorem Pos.Raw.byteIdx_inc {p : Pos.Raw} : p.inc.byteIdx = p.byteIdx + 1 := (rfl)
|
||||
|
||||
/-- Decreases the byte offset of the position by `1`. Not to be confused with `Pos.prev`. -/
|
||||
/-- Decreases the byte offset of the position by `1`. Not to be confused with `ValidPos.prev`. -/
|
||||
@[inline, expose]
|
||||
def Pos.Raw.dec (p : Pos.Raw) : Pos.Raw :=
|
||||
⟨p.byteIdx - 1⟩
|
||||
|
||||
88
src/Init/Data/String/Repr.lean
Normal file
88
src/Init/Data/String/Repr.lean
Normal file
@@ -0,0 +1,88 @@
|
||||
/-
|
||||
Copyright (c) 2016 Microsoft Corporation. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Author: Leonardo de Moura, Mario Carneiro
|
||||
-/
|
||||
module
|
||||
|
||||
prelude
|
||||
public import Init.Data.String.Substring
|
||||
|
||||
public section
|
||||
|
||||
/--
|
||||
Interprets a string as the decimal representation of an integer, returning it. Returns `none` if
|
||||
the string does not contain a decimal integer.
|
||||
|
||||
A string can be interpreted as a decimal integer if it only consists of at least one decimal digit
|
||||
and optionally `-` in front. Leading `+` characters are not allowed.
|
||||
|
||||
Use `String.isInt` to check whether `String.toInt?` would return `some`. `String.toInt!` is an
|
||||
alternative that panics instead of returning `none` when the string is not an integer.
|
||||
|
||||
Examples:
|
||||
* `"".toInt? = none`
|
||||
* `"-".toInt? = none`
|
||||
* `"0".toInt? = some 0`
|
||||
* `"5".toInt? = some 5`
|
||||
* `"-5".toInt? = some (-5)`
|
||||
* `"587".toInt? = some 587`
|
||||
* `"-587".toInt? = some (-587)`
|
||||
* `" 5".toInt? = none`
|
||||
* `"2-3".toInt? = none`
|
||||
* `"0xff".toInt? = none`
|
||||
-/
|
||||
def String.toInt? (s : String) : Option Int := do
|
||||
if s.front = '-' then do
|
||||
let v ← (s.toRawSubstring.drop 1).toNat?;
|
||||
pure <| - Int.ofNat v
|
||||
else
|
||||
Int.ofNat <$> s.toNat?
|
||||
|
||||
/--
|
||||
Checks whether the string can be interpreted as the decimal representation of an integer.
|
||||
|
||||
A string can be interpreted as a decimal integer if it only consists of at least one decimal digit
|
||||
and optionally `-` in front. Leading `+` characters are not allowed.
|
||||
|
||||
Use `String.toInt?` or `String.toInt!` to convert such a string to an integer.
|
||||
|
||||
Examples:
|
||||
* `"".isInt = false`
|
||||
* `"-".isInt = false`
|
||||
* `"0".isInt = true`
|
||||
* `"-0".isInt = true`
|
||||
* `"5".isInt = true`
|
||||
* `"587".isInt = true`
|
||||
* `"-587".isInt = true`
|
||||
* `"+587".isInt = false`
|
||||
* `" 5".isInt = false`
|
||||
* `"2-3".isInt = false`
|
||||
* `"0xff".isInt = false`
|
||||
-/
|
||||
def String.isInt (s : String) : Bool :=
|
||||
if s.front = '-' then
|
||||
(s.toRawSubstring.drop 1).isNat
|
||||
else
|
||||
s.isNat
|
||||
|
||||
/--
|
||||
Interprets a string as the decimal representation of an integer, returning it. Panics if the string
|
||||
does not contain a decimal integer.
|
||||
|
||||
A string can be interpreted as a decimal integer if it only consists of at least one decimal digit
|
||||
and optionally `-` in front. Leading `+` characters are not allowed.
|
||||
|
||||
Use `String.isInt` to check whether `String.toInt!` would return a value. `String.toInt?` is a safer
|
||||
alternative that returns `none` instead of panicking when the string is not an integer.
|
||||
|
||||
Examples:
|
||||
* `"0".toInt! = 0`
|
||||
* `"5".toInt! = 5`
|
||||
* `"587".toInt! = 587`
|
||||
* `"-587".toInt! = -587`
|
||||
-/
|
||||
def String.toInt! (s : String) : Int :=
|
||||
match s.toInt? with
|
||||
| some v => v
|
||||
| none => panic "Int expected"
|
||||
@@ -47,7 +47,7 @@ Examples:
|
||||
* {lean}`"abc".replace "" "k" = "kakbkck"`
|
||||
-/
|
||||
@[inline]
|
||||
def replace [ToSlice α] (s : String) (pattern : ρ) [ToForwardSearcher pattern σ]
|
||||
def replace [ToForwardSearcher ρ σ] [ToSlice α] (s : String) (pattern : ρ)
|
||||
(replacement : α) : String :=
|
||||
s.toSlice.replace pattern replacement
|
||||
|
||||
@@ -62,24 +62,9 @@ Examples:
|
||||
* {lean}`("tea".toSlice.pos ⟨1⟩ (by decide)).find? (fun (c : Char) => c == 't') == none`
|
||||
-/
|
||||
@[inline]
|
||||
def Slice.Pos.find? {s : Slice} (pos : s.Pos) (pattern : ρ) [ToForwardSearcher pattern σ] :
|
||||
def Slice.Pos.find? [ToForwardSearcher ρ σ] {s : Slice} (pos : s.Pos) (pattern : ρ) :
|
||||
Option s.Pos :=
|
||||
((s.sliceFrom pos).find? pattern).map ofSliceFrom
|
||||
|
||||
/--
|
||||
Finds the position of the first match of the pattern {name}`pattern` in after the position
|
||||
{name}`pos`. If there is no match {lean}`s.endPos` is returned.
|
||||
|
||||
This function is generic over all currently supported patterns.
|
||||
|
||||
Examples:
|
||||
* {lean}`("coffee tea water".toSlice.startPos.find Char.isWhitespace).get! == ' '`
|
||||
* {lean}`("tea".toSlice.pos ⟨1⟩ (by decide)).find (fun (c : Char) => c == 't') == "tea".toSlice.endPos`
|
||||
-/
|
||||
@[inline]
|
||||
def Slice.Pos.find {s : Slice} (pos : s.Pos) (pattern : ρ) [ToForwardSearcher pattern σ] :
|
||||
s.Pos :=
|
||||
ofSliceFrom ((s.sliceFrom pos).find pattern)
|
||||
((s.replaceStart pos).find? pattern).map ofReplaceStart
|
||||
|
||||
/--
|
||||
Finds the position of the first match of the pattern {name}`pattern` in after the position
|
||||
@@ -88,28 +73,13 @@ Finds the position of the first match of the pattern {name}`pattern` in after th
|
||||
This function is generic over all currently supported patterns.
|
||||
|
||||
Examples:
|
||||
* {lean}`("coffee tea water".startPos.find? Char.isWhitespace).map (·.get!) == some ' '`
|
||||
* {lean}`("coffee tea water".startValidPos.find? Char.isWhitespace).map (·.get!) == some ' '`
|
||||
* {lean}`("tea".pos ⟨1⟩ (by decide)).find? (fun (c : Char) => c == 't') == none`
|
||||
-/
|
||||
@[inline]
|
||||
def Pos.find? {s : String} (pos : s.Pos) (pattern : ρ)
|
||||
[ToForwardSearcher pattern σ] : Option s.Pos :=
|
||||
(pos.toSlice.find? pattern).map Pos.ofToSlice
|
||||
|
||||
/--
|
||||
Finds the position of the first match of the pattern {name}`pattern` in after the position
|
||||
{name}`pos`. If there is no match {lean}`s.endPos` is returned.
|
||||
|
||||
This function is generic over all currently supported patterns.
|
||||
|
||||
Examples:
|
||||
* {lean}`("coffee tea water".startPos.find Char.isWhitespace).get! == ' '`
|
||||
* {lean}`("tea".pos ⟨1⟩ (by decide)).find (fun (c : Char) => c == 't') == "tea".endPos`
|
||||
-/
|
||||
@[inline]
|
||||
def Pos.find {s : String} (pos : s.Pos) (pattern : ρ) [ToForwardSearcher pattern σ] :
|
||||
s.Pos :=
|
||||
ofToSlice (pos.toSlice.find pattern)
|
||||
def ValidPos.find? [ToForwardSearcher ρ σ] {s : String} (pos : s.ValidPos)
|
||||
(pattern : ρ) : Option s.ValidPos :=
|
||||
(pos.toSlice.find? pattern).map (·.ofSlice)
|
||||
|
||||
/--
|
||||
Finds the position of the first match of the pattern {name}`pattern` in a string {name}`s`. If
|
||||
@@ -123,515 +93,8 @@ Examples:
|
||||
* {lean}`("coffee tea water".find? "tea").map (·.get!) == some 't'`
|
||||
-/
|
||||
@[inline]
|
||||
def find? (s : String) (pattern : ρ) [ToForwardSearcher pattern σ] : Option s.Pos :=
|
||||
s.startPos.find? pattern
|
||||
|
||||
/--
|
||||
Finds the position of the first match of the pattern {name}`pattern` in a slice {name}`s`. If there
|
||||
is no match {lean}`s.endPos` is returned.
|
||||
|
||||
This function is generic over all currently supported patterns.
|
||||
|
||||
Examples:
|
||||
* {lean}`("coffee tea water".find Char.isWhitespace).get! == ' '`
|
||||
* {lean}`"tea".find (fun (c : Char) => c == 'X') == "tea".endPos`
|
||||
* {lean}`("coffee tea water".find "tea").get! == 't'`
|
||||
-/
|
||||
@[inline]
|
||||
def find (s : String) (pattern : ρ) [ToForwardSearcher pattern σ] : s.Pos :=
|
||||
s.startPos.find pattern
|
||||
|
||||
/--
|
||||
Finds the position of the first match of the pattern {name}`pattern` in a slice {name}`s` that is
|
||||
strictly before {name}`pos`. If there is no such match {lean}`none` is returned.
|
||||
|
||||
This function is generic over all currently supported patterns except
|
||||
{name}`String`/{name}`String.Slice`.
|
||||
|
||||
Examples:
|
||||
* {lean}`(("abc".toSlice.endPos.prev (by decide)).revFind? Char.isAlpha).map (·.get!) == some 'b'`
|
||||
* {lean}`"abc".toSlice.startPos.revFind? Char.isAlpha == none`
|
||||
|
||||
-/
|
||||
@[inline]
|
||||
def Slice.Pos.revFind? {s : Slice} (pos : s.Pos) (pattern : ρ) [ToBackwardSearcher pattern σ] :
|
||||
Option s.Pos :=
|
||||
((s.sliceTo pos).revFind? pattern).map ofSliceTo
|
||||
|
||||
/--
|
||||
Finds the position of the first match of the pattern {name}`pattern` in a slice {name}`s` that is
|
||||
strictly before {name}`pos`. If there is no such match {lean}`none` is returned.
|
||||
|
||||
This function is generic over all currently supported patterns except
|
||||
{name}`String`/{name}`String.Slice`.
|
||||
|
||||
Examples:
|
||||
* {lean}`(("ab1c".endPos.prev (by decide)).revFind? Char.isAlpha).map (·.get!) == some 'b'`
|
||||
* {lean}`"abc".startPos.revFind? Char.isAlpha == none`
|
||||
-/
|
||||
@[inline]
|
||||
def Pos.revFind? {s : String} (pos : s.Pos) (pattern : ρ) [ToBackwardSearcher pattern σ] :
|
||||
Option s.Pos :=
|
||||
(pos.toSlice.revFind? pattern).map Pos.ofToSlice
|
||||
|
||||
/--
|
||||
Finds the position of the first match of the pattern {name}`pattern` in a string, starting
|
||||
from the end of the slice and traversing towards the start. If there is no match {name}`none` is
|
||||
returned.
|
||||
|
||||
This function is generic over all currently supported patterns except
|
||||
{name}`String`/{name}`String.Slice`.
|
||||
|
||||
Examples:
|
||||
* {lean}`("coffee tea water".toSlice.revFind? Char.isWhitespace).map (·.get!) == some ' '`
|
||||
* {lean}`"tea".toSlice.revFind? (fun (c : Char) => c == 'X') == none`
|
||||
-/
|
||||
@[inline]
|
||||
def revFind? (s : String) (pattern : ρ) [ToBackwardSearcher pattern σ] : Option s.Pos :=
|
||||
s.endPos.revFind? pattern
|
||||
|
||||
@[export lean_string_posof]
|
||||
def Internal.posOfImpl (s : String) (c : Char) : Pos.Raw :=
|
||||
(s.find c).offset
|
||||
|
||||
@[deprecated String.Pos.find (since := "2025-11-19")]
|
||||
def findAux (s : String) (p : Char → Bool) (stopPos : Pos.Raw) (pos : Pos.Raw) : Pos.Raw :=
|
||||
if h : pos ≤ stopPos ∧ pos.IsValid s ∧ stopPos.IsValid s then
|
||||
(String.Slice.mk s (s.pos pos h.2.1) (s.pos stopPos h.2.2)
|
||||
(by simp [Pos.le_iff, h.1])).find p |>.str.offset
|
||||
else stopPos
|
||||
|
||||
@[deprecated String.Pos.find (since := "2025-11-19")]
|
||||
def posOfAux (s : String) (c : Char) (stopPos : Pos.Raw) (pos : Pos.Raw) : Pos.Raw :=
|
||||
if h : pos ≤ stopPos ∧ pos.IsValid s ∧ stopPos.IsValid s then
|
||||
(String.Slice.mk s (s.pos pos h.2.1) (s.pos stopPos h.2.2)
|
||||
(by simp [Pos.le_iff, h.1])).find c |>.str.offset
|
||||
else stopPos
|
||||
|
||||
@[deprecated String.find (since := "2025-11-19")]
|
||||
def posOf (s : String) (c : Char) : Pos.Raw :=
|
||||
(s.find c).offset
|
||||
|
||||
@[deprecated String.Pos.revFind? (since := "2025-11-19")]
|
||||
def revPosOfAux (s : String) (c : Char) (pos : Pos.Raw) : Option Pos.Raw :=
|
||||
s.pos? pos |>.bind (·.revFind? c) |>.map (·.offset)
|
||||
|
||||
@[deprecated String.revFind? (since := "2025-11-19")]
|
||||
def revPosOf (s : String) (c : Char) : Option Pos.Raw :=
|
||||
s.revFind? c |>.map (·.offset)
|
||||
|
||||
@[deprecated String.Pos.revFind? (since := "2025-11-19")]
|
||||
def revFindAux (s : String) (p : Char → Bool) (pos : Pos.Raw) : Option Pos.Raw :=
|
||||
s.pos? pos |>.bind (·.revFind? p) |>.map (·.offset)
|
||||
|
||||
@[deprecated String.revFind? (since := "2025-11-19")]
|
||||
def revFind (s : String) (p : Char → Bool) : Option Pos.Raw :=
|
||||
s.revFind? p |>.map (·.offset)
|
||||
|
||||
/--
|
||||
Returns the position of the beginning of the line that contains the position {name}`pos`.
|
||||
|
||||
Lines are ended by {lean}`'\n'`, and the returned position is either {lean}`0 : String.Pos.Raw` or
|
||||
immediately after a {lean}`'\n'` character.
|
||||
-/
|
||||
@[deprecated String.Pos.revFind? (since := "2025-11-19")]
|
||||
def findLineStart (s : String) (pos : String.Pos.Raw) : String.Pos.Raw :=
|
||||
s.pos? pos |>.bind (·.revFind? '\n') |>.map (·.offset) |>.getD s.startPos.offset
|
||||
|
||||
/--
|
||||
Splits a string at each subslice that matches the pattern {name}`pat`.
|
||||
|
||||
The subslices that matched the pattern are not included in any of the resulting subslices. If
|
||||
multiple subslices in a row match the pattern, the resulting list will contain empty strings.
|
||||
|
||||
This function is generic over all currently supported patterns.
|
||||
|
||||
Examples:
|
||||
* {lean}`("coffee tea water".split Char.isWhitespace).toList == ["coffee".toSlice, "tea".toSlice, "water".toSlice]`
|
||||
* {lean}`("coffee tea water".split ' ').toList == ["coffee".toSlice, "tea".toSlice, "water".toSlice]`
|
||||
* {lean}`("coffee tea water".split " tea ").toList == ["coffee".toSlice, "water".toSlice]`
|
||||
* {lean}`("ababababa".split "aba").toList == ["coffee".toSlice, "water".toSlice]`
|
||||
* {lean}`("baaab".split "aa").toList == ["b".toSlice, "ab".toSlice]`
|
||||
-/
|
||||
@[inline]
|
||||
def split (s : String) (pat : ρ) [ToForwardSearcher pat σ] :=
|
||||
(s.toSlice.split pat : Std.Iter String.Slice)
|
||||
|
||||
/--
|
||||
Splits a string at each subslice that matches the pattern {name}`pat`. Unlike {name}`split` the
|
||||
matched subslices are included at the end of each subslice.
|
||||
|
||||
This function is generic over all currently supported patterns.
|
||||
|
||||
Examples:
|
||||
* {lean}`("coffee tea water".splitInclusive Char.isWhitespace).toList == ["coffee ".toSlice, "tea ".toSlice, "water".toSlice]`
|
||||
* {lean}`("coffee tea water".splitInclusive ' ').toList == ["coffee ".toSlice, "tea ".toSlice, "water".toSlice]`
|
||||
* {lean}`("coffee tea water".splitInclusive " tea ").toList == ["coffee tea ".toSlice, "water".toSlice]`
|
||||
* {lean}`("baaab".splitInclusive "aa").toList == ["baa".toSlice, "ab".toSlice]`
|
||||
-/
|
||||
@[inline]
|
||||
def splitInclusive (s : String) (pat : ρ) [ToForwardSearcher pat σ] :=
|
||||
(s.toSlice.splitInclusive pat : Std.Iter String.Slice)
|
||||
|
||||
@[deprecated String.Slice.foldl (since := "2025-11-20")]
|
||||
def foldlAux {α : Type u} (f : α → Char → α) (s : String) (stopPos : Pos.Raw) (i : Pos.Raw) (a : α) : α :=
|
||||
s.slice! (s.pos! i) (s.pos! stopPos) |>.foldl f a
|
||||
|
||||
/--
|
||||
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
|
||||
|
||||
@[deprecated String.Slice.foldr (since := "2025-11-25")]
|
||||
def foldrAux {α : Type u} (f : Char → α → α) (a : α) (s : String) (i begPos : Pos.Raw) : α :=
|
||||
s.slice! (s.pos! begPos) (s.pos! i) |>.foldr f a
|
||||
|
||||
/--
|
||||
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
|
||||
|
||||
@[deprecated String.Slice.any (since := "2025-11-25")]
|
||||
def anyAux (s : String) (stopPos : Pos.Raw) (p : Char → Bool) (i : Pos.Raw) : Bool :=
|
||||
s.slice! (s.pos! i) (s.pos! stopPos) |>.any p
|
||||
|
||||
|
||||
/--
|
||||
Checks whether a string has a match of the pattern {name}`pat` anywhere.
|
||||
|
||||
This function is generic over all currently supported patterns.
|
||||
|
||||
Examples:
|
||||
* {lean}`"coffee tea water".contains Char.isWhitespace = true`
|
||||
* {lean}`"tea".contains (fun (c : Char) => c == 'X') = false`
|
||||
* {lean}`"coffee tea water".contains "tea" = true`
|
||||
-/
|
||||
@[inline] def contains (s : String) (pat : ρ) [ToForwardSearcher pat σ] : Bool :=
|
||||
s.toSlice.contains pat
|
||||
|
||||
@[export lean_string_contains]
|
||||
def Internal.containsImpl (s : String) (c : Char) : Bool :=
|
||||
String.contains s c
|
||||
|
||||
@[inline, inherit_doc contains] def any (s : String) (pat : ρ) [ToForwardSearcher pat σ] : Bool :=
|
||||
s.contains pat
|
||||
|
||||
@[export lean_string_any]
|
||||
def Internal.anyImpl (s : String) (p : Char → Bool) :=
|
||||
String.any s p
|
||||
|
||||
/--
|
||||
Checks whether a slice only consists of matches of the pattern {name}`pat`.
|
||||
|
||||
Short-circuits at the first pattern mis-match.
|
||||
|
||||
This function is generic over all currently supported patterns.
|
||||
|
||||
Examples:
|
||||
* {lean}`"brown".all Char.isLower = true`
|
||||
* {lean}`"brown and orange".all Char.isLower = false`
|
||||
* {lean}`"aaaaaa".all 'a' = true`
|
||||
* {lean}`"aaaaaa".all "aa" = true`
|
||||
* {lean}`"aaaaaaa".all "aa" = false`
|
||||
-/
|
||||
@[inline] def all (s : String) (pat : ρ) [ForwardPattern pat] : Bool :=
|
||||
s.toSlice.all pat
|
||||
|
||||
/--
|
||||
Checks whether the string can be interpreted as the decimal representation of a natural number.
|
||||
|
||||
A slice can be interpreted as a decimal natural number if it is not empty and all the characters in
|
||||
it are digits.
|
||||
|
||||
Use {name (scope := "Init.Data.String.Search")}`toNat?` or
|
||||
{name (scope := "Init.Data.String.Search")}`toNat!` to convert such a slice to a natural number.
|
||||
|
||||
Examples:
|
||||
* {lean}`"".isNat = false`
|
||||
* {lean}`"0".isNat = true`
|
||||
* {lean}`"5".isNat = true`
|
||||
* {lean}`"05".isNat = true`
|
||||
* {lean}`"587".isNat = true`
|
||||
* {lean}`"-587".isNat = false`
|
||||
* {lean}`" 5".isNat = false`
|
||||
* {lean}`"2+3".isNat = false`
|
||||
* {lean}`"0xff".isNat = false`
|
||||
-/
|
||||
@[inline] def isNat (s : String) : Bool :=
|
||||
s.toSlice.isNat
|
||||
|
||||
/--
|
||||
Interprets a string as the decimal representation of a natural number, returning it. Returns
|
||||
{name}`none` if the slice does not contain a decimal natural number.
|
||||
|
||||
A slice can be interpreted as a decimal natural number if it is not empty and all the characters in
|
||||
it are digits.
|
||||
|
||||
Use {name}`isNat` to check whether {name}`toNat?` would return {name}`some`.
|
||||
{name (scope := "Init.Data.String.Search")}`toNat!` is an alternative that panics instead of
|
||||
returning {name}`none` when the slice is not a natural number.
|
||||
|
||||
Examples:
|
||||
* {lean}`"".toNat? = none`
|
||||
* {lean}`"0".toNat? = some 0`
|
||||
* {lean}`"5".toNat? = some 5`
|
||||
* {lean}`"587".toNat? = some 587`
|
||||
* {lean}`"-587".toNat? = none`
|
||||
* {lean}`" 5".toNat? = none`
|
||||
* {lean}`"2+3".toNat? = none`
|
||||
* {lean}`"0xff".toNat? = none`
|
||||
-/
|
||||
@[inline] def toNat? (s : String) : Option Nat :=
|
||||
s.toSlice.toNat?
|
||||
|
||||
/--
|
||||
Interprets a string as the decimal representation of a natural number, returning it. Panics if the
|
||||
slice does not contain a decimal natural number.
|
||||
|
||||
A slice can be interpreted as a decimal natural number if it is not empty and all the characters in
|
||||
it are digits.
|
||||
|
||||
Use {name}`isNat` to check whether {name}`toNat!` would return a value. {name}`toNat?` is a safer
|
||||
alternative that returns {name}`none` instead of panicking when the string is not a natural number.
|
||||
|
||||
Examples:
|
||||
* {lean}`"0".toNat! = 0`
|
||||
* {lean}`"5".toNat! = 5`
|
||||
* {lean}`"587".toNat! = 587`
|
||||
-/
|
||||
@[inline] def toNat! (s : String) : Nat :=
|
||||
s.toSlice.toNat!
|
||||
|
||||
/--
|
||||
Interprets a string as the decimal representation of an integer, returning it. Returns {lean}`none`
|
||||
if the string does not contain a decimal integer.
|
||||
|
||||
A string can be interpreted as a decimal integer if it only consists of at least one decimal digit
|
||||
and optionally {lit}`-` in front. Leading `+` characters are not allowed.
|
||||
|
||||
Use {name (scope := "Init.Data.String.Search")}`String.isInt` to check whether {name}`String.toInt?`
|
||||
would return {lean}`some`. {name (scope := "Init.Data.String.Search")}`String.toInt!` is an
|
||||
alternative that panics instead of returning {lean}`none` when the string is not an integer.
|
||||
|
||||
Examples:
|
||||
* {lean}`"".toInt? = none`
|
||||
* {lean}`"-".toInt? = none`
|
||||
* {lean}`"0".toInt? = some 0`
|
||||
* {lean}`"5".toInt? = some 5`
|
||||
* {lean}`"-5".toInt? = some (-5)`
|
||||
* {lean}`"587".toInt? = some 587`
|
||||
* {lean}`"-587".toInt? = some (-587)`
|
||||
* {lean}`" 5".toInt? = none`
|
||||
* {lean}`"2-3".toInt? = none`
|
||||
* {lean}`"0xff".toInt? = none`
|
||||
-/
|
||||
@[inline] def toInt? (s : String) : Option Int :=
|
||||
s.toSlice.toInt?
|
||||
|
||||
/--
|
||||
Checks whether the string can be interpreted as the decimal representation of an integer.
|
||||
|
||||
A string can be interpreted as a decimal integer if it only consists of at least one decimal digit
|
||||
and optionally {lit}`-` in front. Leading `+` characters are not allowed.
|
||||
|
||||
Use {name}`String.toInt?` or {name (scope := "Init.Data.String.Search")}`String.toInt!` to convert
|
||||
such a string to an integer.
|
||||
|
||||
Examples:
|
||||
* {lean}`"".isInt = false`
|
||||
* {lean}`"-".isInt = false`
|
||||
* {lean}`"0".isInt = true`
|
||||
* {lean}`"-0".isInt = true`
|
||||
* {lean}`"5".isInt = true`
|
||||
* {lean}`"587".isInt = true`
|
||||
* {lean}`"-587".isInt = true`
|
||||
* {lean}`"+587".isInt = false`
|
||||
* {lean}`" 5".isInt = false`
|
||||
* {lean}`"2-3".isInt = false`
|
||||
* {lean}`"0xff".isInt = false`
|
||||
-/
|
||||
@[inline] def isInt (s : String) : Bool :=
|
||||
s.toSlice.isInt
|
||||
|
||||
/--
|
||||
Interprets a string as the decimal representation of an integer, returning it. Panics if the string
|
||||
does not contain a decimal integer.
|
||||
|
||||
A string can be interpreted as a decimal integer if it only consists of at least one decimal digit
|
||||
and optionally {lit}`-` in front. Leading `+` characters are not allowed.
|
||||
|
||||
Use {name}`String.isInt` to check whether {name}`String.toInt!` would return a value.
|
||||
{name}`String.toInt?` is a safer alternative that returns {lean}`none` instead of panicking when the
|
||||
string is not an integer.
|
||||
|
||||
Examples:
|
||||
* {lean}`"0".toInt! = 0`
|
||||
* {lean}`"5".toInt! = 5`
|
||||
* {lean}`"587".toInt! = 587`
|
||||
* {lean}`"-587".toInt! = -587`
|
||||
-/
|
||||
@[inline] def toInt! (s : String) : Int :=
|
||||
s.toSlice.toInt!
|
||||
|
||||
|
||||
/--
|
||||
Returns the first character in {name}`s`. If {name}`s` is empty, returns {name}`none`.
|
||||
|
||||
Examples:
|
||||
* {lean}`"abc".front? = some 'a'`
|
||||
* {lean}`"".front? = none`
|
||||
-/
|
||||
@[inline]
|
||||
def front? (s : String) : Option Char :=
|
||||
s.toSlice.front?
|
||||
|
||||
/--
|
||||
Returns the first character in {name}`s`. If {lean}`s = ""`, returns {lean}`(default : Char)`.
|
||||
|
||||
Examples:
|
||||
* {lean}`"abc".front = 'a'`
|
||||
* {lean}`"".front = (default : Char)`
|
||||
-/
|
||||
@[inline, expose] def front (s : String) : Char :=
|
||||
s.toSlice.front
|
||||
|
||||
@[export lean_string_front]
|
||||
def Internal.frontImpl (s : String) : Char :=
|
||||
String.front s
|
||||
|
||||
/--
|
||||
Returns the last character in {name}`s`. If {name}`s` is empty, returns {name}`none`.
|
||||
|
||||
Examples:
|
||||
* {lean}`"abc".back? = some 'c'`
|
||||
* {lean}`"".back? = none`
|
||||
-/
|
||||
@[inline]
|
||||
def back? (s : String) : Option Char :=
|
||||
s.toSlice.back?
|
||||
|
||||
|
||||
/--
|
||||
Returns the last character in {name}`s`. If {lean}`s = ""`, returns {lean}`(default : Char)`.
|
||||
|
||||
Examples:
|
||||
* {lean}`"abc".back = 'c'`
|
||||
* {lean}`"".back = (default : Char)`
|
||||
-/
|
||||
@[inline, expose] def back (s : String) : Char :=
|
||||
s.toSlice.back
|
||||
|
||||
theorem Pos.ofToSlice_ne_endPos {s : String} {p : s.toSlice.Pos}
|
||||
(h : p ≠ s.toSlice.endPos) : ofToSlice p ≠ s.endPos := by
|
||||
rwa [ne_eq, ← Pos.toSlice_inj, Slice.Pos.toSlice_ofToSlice, ← endPos_toSlice]
|
||||
|
||||
@[inline]
|
||||
def Internal.toSliceWithProof {s : String} :
|
||||
{ p : s.toSlice.Pos // p ≠ s.toSlice.endPos } → { p : s.Pos // p ≠ s.endPos } :=
|
||||
fun ⟨p, h⟩ => ⟨Pos.ofToSlice p, Pos.ofToSlice_ne_endPos h⟩
|
||||
|
||||
/--
|
||||
Creates an iterator over all valid positions within {name}`s`.
|
||||
|
||||
Examples
|
||||
* {lean}`("abc".positions.map (fun ⟨p, h⟩ => p.get h) |>.toList) = ['a', 'b', 'c']`
|
||||
* {lean}`("abc".positions.map (·.val.offset.byteIdx) |>.toList) = [0, 1, 2]`
|
||||
* {lean}`("ab∀c".positions.map (fun ⟨p, h⟩ => p.get h) |>.toList) = ['a', 'b', '∀', 'c']`
|
||||
* {lean}`("ab∀c".positions.map (·.val.offset.byteIdx) |>.toList) = [0, 1, 2, 5]`
|
||||
-/
|
||||
@[inline]
|
||||
def positions (s : String) :=
|
||||
(s.toSlice.positions.map Internal.toSliceWithProof : Std.Iter { p : s.Pos // p ≠ s.endPos })
|
||||
|
||||
/--
|
||||
Creates an iterator over all characters (Unicode code points) in {name}`s`.
|
||||
|
||||
Examples:
|
||||
* {lean}`"abc".chars.toList = ['a', 'b', 'c']`
|
||||
* {lean}`"ab∀c".chars.toList = ['a', 'b', '∀', 'c']`
|
||||
-/
|
||||
@[inline]
|
||||
def chars (s : String) :=
|
||||
(s.toSlice.chars : Std.Iter Char)
|
||||
|
||||
/--
|
||||
Creates an iterator over all valid positions within {name}`s`, starting from the last valid
|
||||
position and iterating towards the first one.
|
||||
|
||||
Examples
|
||||
* {lean}`("abc".revPositions.map (fun ⟨p, h⟩ => p.get h) |>.toList) = ['c', 'b', 'a']`
|
||||
* {lean}`("abc".revPositions.map (·.val.offset.byteIdx) |>.toList) = [2, 1, 0]`
|
||||
* {lean}`("ab∀c".revPositions.map (fun ⟨p, h⟩ => p.get h) |>.toList) = ['c', '∀', 'b', 'a']`
|
||||
* {lean}`("ab∀c".toSlice.revPositions.map (·.val.offset.byteIdx) |>.toList) = [5, 2, 1, 0]`
|
||||
-/
|
||||
@[inline]
|
||||
def revPositions (s : String) :=
|
||||
(s.toSlice.revPositions.map Internal.toSliceWithProof : Std.Iter { p : s.Pos // p ≠ s.endPos })
|
||||
|
||||
/--
|
||||
Creates an iterator over all characters (Unicode code points) in {name}`s`, starting from the end
|
||||
of the slice and iterating towards the start.
|
||||
|
||||
Example:
|
||||
* {lean}`"abc".revChars.toList = ['c', 'b', 'a']`
|
||||
* {lean}`"ab∀c".revChars.toList = ['c', '∀', 'b', 'a']`
|
||||
-/
|
||||
@[inline]
|
||||
def revChars (s : String) :=
|
||||
(s.toSlice.revChars : Std.Iter Char)
|
||||
|
||||
/--
|
||||
Creates an iterator over all bytes in {name}`s`.
|
||||
|
||||
Examples:
|
||||
* {lean}`"abc".byteIterator.toList = [97, 98, 99]`
|
||||
* {lean}`"ab∀c".byteIterator.toList = [97, 98, 226, 136, 128, 99]`
|
||||
-/
|
||||
@[inline]
|
||||
def byteIterator (s : String) :=
|
||||
(s.toSlice.bytes : Std.Iter UInt8)
|
||||
|
||||
/--
|
||||
Creates an iterator over all bytes in {name}`s`, starting from the last one and iterating towards
|
||||
the first one.
|
||||
|
||||
Examples:
|
||||
* {lean}`"abc".revBytes.toList = [99, 98, 97]`
|
||||
* {lean}`"ab∀c".revBytes.toList = [99, 128, 136, 226, 98, 97]`
|
||||
-/
|
||||
@[inline]
|
||||
def revBytes (s : String) :=
|
||||
(s.toSlice.revBytes : Std.Iter UInt8)
|
||||
|
||||
/--
|
||||
Creates an iterator over all lines in {name}`s` with the line ending characters `\r\n` or `\n` being
|
||||
stripped.
|
||||
|
||||
Examples:
|
||||
* {lean}`"foo\r\nbar\n\nbaz\n".lines.toList == ["foo".toSlice, "bar".toSlice, "".toSlice, "baz".toSlice]`
|
||||
* {lean}`"foo\r\nbar\n\nbaz".lines.toList == ["foo".toSlice, "bar".toSlice, "".toSlice, "baz".toSlice]`
|
||||
* {lean}`"foo\r\nbar\n\nbaz\r".lines.toList == ["foo".toSlice, "bar".toSlice, "".toSlice, "baz\r".toSlice]`
|
||||
-/
|
||||
def lines (s : String) :=
|
||||
s.toSlice.lines
|
||||
def find? [ToForwardSearcher ρ σ] (s : String) (pattern : ρ) : Option s.ValidPos :=
|
||||
s.startValidPos.find? pattern
|
||||
|
||||
end
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/-
|
||||
Copyright (c) 2025 Lean FRO, LLC. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Henrik Böving, Markus Himmel
|
||||
Authors: Henrik Böving
|
||||
-/
|
||||
module
|
||||
|
||||
@@ -117,21 +117,21 @@ Examples:
|
||||
* {lean}`"red green blue".toSlice.startsWith Char.isLower = true`
|
||||
-/
|
||||
@[inline]
|
||||
def startsWith (s : Slice) (pat : ρ) [ForwardPattern pat] : Bool :=
|
||||
ForwardPattern.startsWith pat s
|
||||
def startsWith [ForwardPattern ρ] (s : Slice) (pat : ρ) : Bool :=
|
||||
ForwardPattern.startsWith s pat
|
||||
|
||||
inductive SplitIterator {ρ : Type} (pat : ρ) (s : Slice) [ToForwardSearcher pat σ] where
|
||||
inductive SplitIterator (ρ : Type) (s : Slice) [ToForwardSearcher ρ σ] where
|
||||
| operating (currPos : s.Pos) (searcher : Std.Iter (α := σ s) (SearchStep s))
|
||||
| atEnd
|
||||
deriving Inhabited
|
||||
|
||||
namespace SplitIterator
|
||||
|
||||
variable {pat : ρ} [ToForwardSearcher pat σ]
|
||||
variable [ToForwardSearcher ρ σ]
|
||||
|
||||
inductive PlausibleStep
|
||||
|
||||
instance : Std.Iterators.Iterator (SplitIterator pat s) Id Slice where
|
||||
instance : Std.Iterators.Iterator (SplitIterator ρ s) Id Slice where
|
||||
IsPlausibleStep
|
||||
| ⟨.operating _ s⟩, .yield ⟨.operating _ s'⟩ _ => s'.IsPlausibleSuccessorOf s
|
||||
| ⟨.operating _ s⟩, .yield ⟨.atEnd ..⟩ _ => True
|
||||
@@ -145,7 +145,7 @@ instance : Std.Iterators.Iterator (SplitIterator pat s) Id Slice where
|
||||
| ⟨.operating currPos searcher⟩ =>
|
||||
match h : searcher.step with
|
||||
| ⟨.yield searcher' (.matched startPos endPos), hps⟩ =>
|
||||
let slice := s.slice! currPos startPos
|
||||
let slice := s.replaceStartEnd! currPos startPos
|
||||
let nextIt := ⟨.operating endPos searcher'⟩
|
||||
pure (.deflate ⟨.yield nextIt slice, by simp [nextIt, hps.isPlausibleSuccessor_of_yield]⟩)
|
||||
| ⟨.yield searcher' (.rejected ..), hps⟩ =>
|
||||
@@ -155,16 +155,16 @@ instance : Std.Iterators.Iterator (SplitIterator pat s) Id Slice where
|
||||
pure (.deflate ⟨.skip ⟨.operating currPos searcher'⟩,
|
||||
by simp [hps.isPlausibleSuccessor_of_skip]⟩)
|
||||
| ⟨.done, _⟩ =>
|
||||
let slice := s.sliceFrom currPos
|
||||
let slice := s.replaceStart currPos
|
||||
pure (.deflate ⟨.yield ⟨.atEnd⟩ slice, by simp⟩)
|
||||
| ⟨.atEnd⟩ => pure (.deflate ⟨.done, by simp⟩)
|
||||
|
||||
private def toOption : SplitIterator pat s → Option (Std.Iter (α := σ s) (SearchStep s))
|
||||
private def toOption : SplitIterator ρ s → Option (Std.Iter (α := σ s) (SearchStep s))
|
||||
| .operating _ s => some s
|
||||
| .atEnd => none
|
||||
|
||||
private def finitenessRelation [Std.Iterators.Finite (σ s) Id] :
|
||||
Std.Iterators.FinitenessRelation (SplitIterator pat s) Id where
|
||||
Std.Iterators.FinitenessRelation (SplitIterator ρ s) Id where
|
||||
rel := InvImage (Option.lt Std.Iterators.Iter.IsPlausibleSuccessorOf)
|
||||
(SplitIterator.toOption ∘ Std.Iterators.IterM.internalState)
|
||||
wf := InvImage.wf _ (Option.wellFounded_lt Std.Iterators.Finite.wf_of_id)
|
||||
@@ -182,19 +182,19 @@ private def finitenessRelation [Std.Iterators.Finite (σ s) Id] :
|
||||
| ⟨.atEnd⟩, _ => simp
|
||||
|
||||
@[no_expose]
|
||||
instance [Std.Iterators.Finite (σ s) Id] : Std.Iterators.Finite (SplitIterator pat s) Id :=
|
||||
instance [Std.Iterators.Finite (σ s) Id] : Std.Iterators.Finite (SplitIterator ρ s) Id :=
|
||||
.of_finitenessRelation finitenessRelation
|
||||
|
||||
instance [Monad n] : Std.Iterators.IteratorCollect (SplitIterator pat s) Id n :=
|
||||
instance [Monad n] : Std.Iterators.IteratorCollect (SplitIterator ρ s) Id n :=
|
||||
.defaultImplementation
|
||||
|
||||
instance [Monad n] : Std.Iterators.IteratorCollectPartial (SplitIterator pat s) Id n :=
|
||||
instance [Monad n] : Std.Iterators.IteratorCollectPartial (SplitIterator ρ s) Id n :=
|
||||
.defaultImplementation
|
||||
|
||||
instance [Monad n] : Std.Iterators.IteratorLoop (SplitIterator pat s) Id n :=
|
||||
instance [Monad n] : Std.Iterators.IteratorLoop (SplitIterator ρ s) Id n :=
|
||||
.defaultImplementation
|
||||
|
||||
instance [Monad n] : Std.Iterators.IteratorLoopPartial (SplitIterator pat s) Id n :=
|
||||
instance [Monad n] : Std.Iterators.IteratorLoopPartial (SplitIterator ρ s) Id n :=
|
||||
.defaultImplementation
|
||||
|
||||
end SplitIterator
|
||||
@@ -215,19 +215,19 @@ Examples:
|
||||
* {lean}`("baaab".toSlice.split "aa").toList == ["b".toSlice, "ab".toSlice]`
|
||||
-/
|
||||
@[specialize pat]
|
||||
def split (s : Slice) (pat : ρ) [ToForwardSearcher pat σ] : Std.Iter (α := SplitIterator pat s) Slice :=
|
||||
{ internalState := .operating s.startPos (ToForwardSearcher.toSearcher pat s) }
|
||||
def split [ToForwardSearcher ρ σ] (s : Slice) (pat : ρ) : Std.Iter (α := SplitIterator ρ s) Slice :=
|
||||
{ internalState := .operating s.startPos (ToForwardSearcher.toSearcher s pat) }
|
||||
|
||||
inductive SplitInclusiveIterator {ρ : Type} (pat : ρ) (s : Slice) [ToForwardSearcher pat σ] where
|
||||
inductive SplitInclusiveIterator (ρ : Type) (s : Slice) [ToForwardSearcher ρ σ] where
|
||||
| operating (currPos : s.Pos) (searcher : Std.Iter (α := σ s) (SearchStep s))
|
||||
| atEnd
|
||||
deriving Inhabited
|
||||
|
||||
namespace SplitInclusiveIterator
|
||||
|
||||
variable {pat : ρ} [ToForwardSearcher pat σ]
|
||||
variable [ToForwardSearcher ρ σ]
|
||||
|
||||
instance : Std.Iterators.Iterator (SplitInclusiveIterator pat s) Id Slice where
|
||||
instance : Std.Iterators.Iterator (SplitInclusiveIterator ρ s) Id Slice where
|
||||
IsPlausibleStep
|
||||
| ⟨.operating _ s⟩, .yield ⟨.operating _ s'⟩ _ => s'.IsPlausibleSuccessorOf s
|
||||
| ⟨.operating _ s⟩, .yield ⟨.atEnd ..⟩ _ => True
|
||||
@@ -241,7 +241,7 @@ instance : Std.Iterators.Iterator (SplitInclusiveIterator pat s) Id Slice where
|
||||
| ⟨.operating currPos searcher⟩ =>
|
||||
match h : searcher.step with
|
||||
| ⟨.yield searcher' (.matched _ endPos), hps⟩ =>
|
||||
let slice := s.slice! currPos endPos
|
||||
let slice := s.replaceStartEnd! currPos endPos
|
||||
let nextIt := ⟨.operating endPos searcher'⟩
|
||||
pure (.deflate ⟨.yield nextIt slice,
|
||||
by simp [nextIt, hps.isPlausibleSuccessor_of_yield]⟩)
|
||||
@@ -253,18 +253,18 @@ instance : Std.Iterators.Iterator (SplitInclusiveIterator pat s) Id Slice where
|
||||
by simp [hps.isPlausibleSuccessor_of_skip]⟩)
|
||||
| ⟨.done, _⟩ =>
|
||||
if currPos != s.endPos then
|
||||
let slice := s.sliceFrom currPos
|
||||
let slice := s.replaceStart currPos
|
||||
pure (.deflate ⟨.yield ⟨.atEnd⟩ slice, by simp⟩)
|
||||
else
|
||||
pure (.deflate ⟨.done, by simp⟩)
|
||||
| ⟨.atEnd⟩ => pure (.deflate ⟨.done, by simp⟩)
|
||||
|
||||
private def toOption : SplitInclusiveIterator pat s → Option (Std.Iter (α := σ s) (SearchStep s))
|
||||
private def toOption : SplitInclusiveIterator ρ s → Option (Std.Iter (α := σ s) (SearchStep s))
|
||||
| .operating _ s => some s
|
||||
| .atEnd => none
|
||||
|
||||
private def finitenessRelation [Std.Iterators.Finite (σ s) Id] :
|
||||
Std.Iterators.FinitenessRelation (SplitInclusiveIterator pat s) Id where
|
||||
Std.Iterators.FinitenessRelation (SplitInclusiveIterator ρ s) Id where
|
||||
rel := InvImage (Option.lt Std.Iterators.Iter.IsPlausibleSuccessorOf)
|
||||
(SplitInclusiveIterator.toOption ∘ Std.Iterators.IterM.internalState)
|
||||
wf := InvImage.wf _ (Option.wellFounded_lt Std.Iterators.Finite.wf_of_id)
|
||||
@@ -283,23 +283,23 @@ private def finitenessRelation [Std.Iterators.Finite (σ s) Id] :
|
||||
|
||||
@[no_expose]
|
||||
instance [Std.Iterators.Finite (σ s) Id] :
|
||||
Std.Iterators.Finite (SplitInclusiveIterator pat s) Id :=
|
||||
Std.Iterators.Finite (SplitInclusiveIterator ρ s) Id :=
|
||||
.of_finitenessRelation finitenessRelation
|
||||
|
||||
instance [Monad n] {s} :
|
||||
Std.Iterators.IteratorCollect (SplitInclusiveIterator pat s) Id n :=
|
||||
Std.Iterators.IteratorCollect (SplitInclusiveIterator ρ s) Id n :=
|
||||
.defaultImplementation
|
||||
|
||||
instance [Monad n] {s} :
|
||||
Std.Iterators.IteratorCollectPartial (SplitInclusiveIterator pat s) Id n :=
|
||||
Std.Iterators.IteratorCollectPartial (SplitInclusiveIterator ρ s) Id n :=
|
||||
.defaultImplementation
|
||||
|
||||
instance [Monad n] {s} :
|
||||
Std.Iterators.IteratorLoop (SplitInclusiveIterator pat s) Id n :=
|
||||
Std.Iterators.IteratorLoop (SplitInclusiveIterator ρ s) Id n :=
|
||||
.defaultImplementation
|
||||
|
||||
instance [Monad n] {s} :
|
||||
Std.Iterators.IteratorLoopPartial (SplitInclusiveIterator pat s) Id n :=
|
||||
Std.Iterators.IteratorLoopPartial (SplitInclusiveIterator ρ s) Id n :=
|
||||
.defaultImplementation
|
||||
|
||||
end SplitInclusiveIterator
|
||||
@@ -317,9 +317,9 @@ Examples:
|
||||
* {lean}`("baaab".toSlice.splitInclusive "aa").toList == ["baa".toSlice, "ab".toSlice]`
|
||||
-/
|
||||
@[specialize pat]
|
||||
def splitInclusive (s : Slice) (pat : ρ) [ToForwardSearcher pat σ] :
|
||||
Std.Iter (α := SplitInclusiveIterator pat s) Slice :=
|
||||
{ internalState := .operating s.startPos (ToForwardSearcher.toSearcher pat s) }
|
||||
def splitInclusive [ToForwardSearcher ρ σ] (s : Slice) (pat : ρ) :
|
||||
Std.Iter (α := SplitInclusiveIterator ρ s) Slice :=
|
||||
{ internalState := .operating s.startPos (ToForwardSearcher.toSearcher s pat) }
|
||||
|
||||
/--
|
||||
If {name}`pat` matches a prefix of {name}`s`, returns the remainder. Returns {name}`none` otherwise.
|
||||
@@ -336,8 +336,8 @@ Examples:
|
||||
* {lean}`"red green blue".toSlice.dropPrefix? Char.isLower == some "ed green blue".toSlice`
|
||||
-/
|
||||
@[inline]
|
||||
def dropPrefix? (s : Slice) (pat : ρ) [ForwardPattern pat] : Option Slice :=
|
||||
(ForwardPattern.dropPrefix? pat s).map s.sliceFrom
|
||||
def dropPrefix? [ForwardPattern ρ] (s : Slice) (pat : ρ) : Option Slice :=
|
||||
(ForwardPattern.dropPrefix? s pat).map s.replaceStart
|
||||
|
||||
/--
|
||||
If {name}`pat` matches a prefix of {name}`s`, returns the remainder. Returns {name}`s` unmodified
|
||||
@@ -354,7 +354,7 @@ Examples:
|
||||
* {lean}`"red green blue".toSlice.dropPrefix Char.isLower == "ed green blue".toSlice`
|
||||
-/
|
||||
@[specialize pat]
|
||||
def dropPrefix (s : Slice) (pat : ρ) [ForwardPattern pat] : Slice :=
|
||||
def dropPrefix [ForwardPattern ρ] (s : Slice) (pat : ρ) : Slice :=
|
||||
dropPrefix? s pat |>.getD s
|
||||
|
||||
/--
|
||||
@@ -373,11 +373,11 @@ Examples:
|
||||
* {lean}`"aaaaa".toSlice.replace "aa" "b" = "bba"`
|
||||
* {lean}`"abc".toSlice.replace "" "k" = "kakbkck"`
|
||||
-/
|
||||
def replace [ToSlice α] (s : Slice) (pattern : ρ) [ToForwardSearcher pattern σ] (replacement : α) :
|
||||
def replace [ToForwardSearcher ρ σ] [ToSlice α] (s : Slice) (pattern : ρ) (replacement : α) :
|
||||
String :=
|
||||
(ToForwardSearcher.toSearcher pattern s).fold (init := "") (fun
|
||||
(ToForwardSearcher.toSearcher s pattern).fold (init := "") (fun
|
||||
| sofar, .matched .. => sofar ++ ToSlice.toSlice replacement
|
||||
| sofar, .rejected start stop => sofar ++ s.slice! start stop)
|
||||
| sofar, .rejected start stop => sofar ++ s.replaceStartEnd! start stop)
|
||||
|
||||
/--
|
||||
Removes the specified number of characters (Unicode code points) from the start of the slice.
|
||||
@@ -391,7 +391,7 @@ Examples:
|
||||
-/
|
||||
@[inline]
|
||||
def drop (s : Slice) (n : Nat) : Slice :=
|
||||
s.sliceFrom (s.startPos.nextn n)
|
||||
s.replaceStart (s.startPos.nextn n)
|
||||
|
||||
/--
|
||||
Creates a new slice that contains the longest prefix of {name}`s` for which {name}`pat` matched
|
||||
@@ -404,18 +404,18 @@ Examples:
|
||||
* {lean}`"red green blue".toSlice.dropWhile (fun (_ : Char) => true) == "".toSlice`
|
||||
-/
|
||||
@[inline]
|
||||
def dropWhile (s : Slice) (pat : ρ) [ForwardPattern pat] : Slice :=
|
||||
def dropWhile [ForwardPattern ρ] (s : Slice) (pat : ρ) : Slice :=
|
||||
go s.startPos
|
||||
where
|
||||
@[specialize pat]
|
||||
go (curr : s.Pos) : Slice :=
|
||||
if let some nextCurr := ForwardPattern.dropPrefix? pat (s.sliceFrom curr) then
|
||||
if curr < Pos.ofSliceFrom nextCurr then
|
||||
go (Pos.ofSliceFrom nextCurr)
|
||||
if let some nextCurr := ForwardPattern.dropPrefix? (s.replaceStart curr) pat then
|
||||
if curr < Pos.ofReplaceStart nextCurr then
|
||||
go (Pos.ofReplaceStart nextCurr)
|
||||
else
|
||||
s.sliceFrom curr
|
||||
s.replaceStart curr
|
||||
else
|
||||
s.sliceFrom curr
|
||||
s.replaceStart curr
|
||||
termination_by curr
|
||||
|
||||
/--
|
||||
@@ -449,7 +449,7 @@ Examples:
|
||||
-/
|
||||
@[inline]
|
||||
def take (s : Slice) (n : Nat) : Slice :=
|
||||
s.sliceTo (s.startPos.nextn n)
|
||||
s.replaceEnd (s.startPos.nextn n)
|
||||
|
||||
/--
|
||||
Creates a new slice that contains the longest prefix of {name}`s` for which {name}`pat` matched
|
||||
@@ -464,18 +464,18 @@ Examples:
|
||||
* {lean}`"red green blue".toSlice.takeWhile (fun (_ : Char) => true) == "red green blue".toSlice`
|
||||
-/
|
||||
@[inline]
|
||||
def takeWhile (s : Slice) (pat : ρ) [ForwardPattern pat] : Slice :=
|
||||
def takeWhile [ForwardPattern ρ] (s : Slice) (pat : ρ) : Slice :=
|
||||
go s.startPos
|
||||
where
|
||||
@[specialize pat]
|
||||
go (curr : s.Pos) : Slice :=
|
||||
if let some nextCurr := ForwardPattern.dropPrefix? pat (s.sliceFrom curr) then
|
||||
if curr < Pos.ofSliceFrom nextCurr then
|
||||
go (Pos.ofSliceFrom nextCurr)
|
||||
if let some nextCurr := ForwardPattern.dropPrefix? (s.replaceStart curr) pat then
|
||||
if curr < Pos.ofReplaceStart nextCurr then
|
||||
go (Pos.ofReplaceStart nextCurr)
|
||||
else
|
||||
s.sliceTo curr
|
||||
s.replaceEnd curr
|
||||
else
|
||||
s.sliceTo curr
|
||||
s.replaceEnd curr
|
||||
termination_by curr
|
||||
|
||||
/--
|
||||
@@ -489,26 +489,11 @@ Examples:
|
||||
* {lean}`"tea".toSlice.find? (fun (c : Char) => c == 'X') == none`
|
||||
* {lean}`("coffee tea water".toSlice.find? "tea").map (·.get!) == some 't'`
|
||||
-/
|
||||
@[inline]
|
||||
def find? (s : Slice) (pat : ρ) [ToForwardSearcher pat σ] : Option s.Pos :=
|
||||
let searcher := ToForwardSearcher.toSearcher pat s
|
||||
@[specialize pat]
|
||||
def find? [ToForwardSearcher ρ σ] (s : Slice) (pat : ρ) : Option s.Pos :=
|
||||
let searcher := ToForwardSearcher.toSearcher s pat
|
||||
searcher.findSome? (fun | .matched startPos _ => some startPos | .rejected .. => none)
|
||||
|
||||
/--
|
||||
Finds the position of the first match of the pattern {name}`pat` in a slice {name}`s`. If there
|
||||
is no match {lean}`s.endPos` is returned.
|
||||
|
||||
This function is generic over all currently supported patterns.
|
||||
|
||||
Examples:
|
||||
* {lean}`("coffee tea water".toSlice.find Char.isWhitespace).get! == ' '`
|
||||
* {lean}`"tea".toSlice.find (fun (c : Char) => c == 'X') == "tea".toSlice.endPos`
|
||||
* {lean}`("coffee tea water".toSlice.find "tea").get! == 't'`
|
||||
-/
|
||||
@[inline]
|
||||
def find (s : Slice) (pat : ρ) [ToForwardSearcher pat σ] : s.Pos :=
|
||||
s.find? pat |>.getD s.endPos
|
||||
|
||||
/--
|
||||
Checks whether a slice has a match of the pattern {name}`pat` anywhere.
|
||||
|
||||
@@ -520,16 +505,12 @@ Examples:
|
||||
* {lean}`"coffee tea water".toSlice.contains "tea" = true`
|
||||
-/
|
||||
@[specialize pat]
|
||||
def contains (s : Slice) (pat : ρ) [ToForwardSearcher pat σ] : Bool :=
|
||||
let searcher := ToForwardSearcher.toSearcher pat s
|
||||
def contains [ToForwardSearcher ρ σ] (s : Slice) (pat : ρ) : Bool :=
|
||||
let searcher := ToForwardSearcher.toSearcher s pat
|
||||
searcher.any (· matches .matched ..)
|
||||
|
||||
@[inline, inherit_doc contains]
|
||||
def any (s : Slice) (pat : ρ) [ToForwardSearcher pat σ] : Bool :=
|
||||
s.contains pat
|
||||
|
||||
/--
|
||||
Checks whether a slice only consists of matches of the pattern {name}`pat`.
|
||||
Checks whether a slice only consists of matches of the pattern {name}`pat` anywhere.
|
||||
|
||||
Short-circuits at the first pattern mis-match.
|
||||
|
||||
@@ -543,7 +524,7 @@ Examples:
|
||||
* {lean}`"aaaaaaa".toSlice.all "aa" = false`
|
||||
-/
|
||||
@[inline]
|
||||
def all (s : Slice) (pat : ρ) [ForwardPattern pat] : Bool :=
|
||||
def all [ForwardPattern ρ] (s : Slice) (pat : ρ) : Bool :=
|
||||
s.dropWhile pat |>.isEmpty
|
||||
|
||||
end ForwardPatternUsers
|
||||
@@ -568,10 +549,10 @@ Examples:
|
||||
* {lean}`"red green blue".toSlice.endsWith Char.isLower = true`
|
||||
-/
|
||||
@[inline]
|
||||
def endsWith (s : Slice) (pat : ρ) [BackwardPattern pat] : Bool :=
|
||||
BackwardPattern.endsWith pat s
|
||||
def endsWith [BackwardPattern ρ] (s : Slice) (pat : ρ) : Bool :=
|
||||
BackwardPattern.endsWith s pat
|
||||
|
||||
inductive RevSplitIterator {ρ : Type} (pat : ρ) (s : Slice) [ToBackwardSearcher pat σ] where
|
||||
inductive RevSplitIterator (ρ : Type) (s : Slice) [ToBackwardSearcher ρ σ] where
|
||||
| operating (currPos : s.Pos) (searcher : Std.Iter (α := σ s) (SearchStep s))
|
||||
| atEnd
|
||||
deriving Inhabited
|
||||
@@ -594,7 +575,7 @@ instance [Pure m] : Std.Iterators.Iterator (RevSplitIterator ρ s) m Slice where
|
||||
| ⟨.operating currPos searcher⟩ =>
|
||||
match h : searcher.step with
|
||||
| ⟨.yield searcher' (.matched startPos endPos), hps⟩ =>
|
||||
let slice := s.slice! endPos currPos
|
||||
let slice := s.replaceStartEnd! endPos currPos
|
||||
let nextIt := ⟨.operating startPos searcher'⟩
|
||||
pure (.deflate ⟨.yield nextIt slice, by simp [nextIt, hps.isPlausibleSuccessor_of_yield]⟩)
|
||||
| ⟨.yield searcher' (.rejected ..), hps⟩ =>
|
||||
@@ -605,7 +586,7 @@ instance [Pure m] : Std.Iterators.Iterator (RevSplitIterator ρ s) m Slice where
|
||||
by simp [hps.isPlausibleSuccessor_of_skip]⟩)
|
||||
| ⟨.done, _⟩ =>
|
||||
if currPos ≠ s.startPos then
|
||||
let slice := s.sliceTo currPos
|
||||
let slice := s.replaceEnd currPos
|
||||
pure (.deflate ⟨.yield ⟨.atEnd⟩ slice, by simp⟩)
|
||||
else
|
||||
pure (.deflate ⟨.done, by simp⟩)
|
||||
@@ -667,9 +648,9 @@ Examples:
|
||||
* {lean}`("coffee tea water".toSlice.revSplit ' ').toList == ["water".toSlice, "tea".toSlice, "coffee".toSlice]`
|
||||
-/
|
||||
@[specialize pat]
|
||||
def revSplit (s : Slice) (pat : ρ) [ToBackwardSearcher pat σ] :
|
||||
Std.Iter (α := RevSplitIterator pat s) Slice :=
|
||||
{ internalState := .operating s.endPos (ToBackwardSearcher.toSearcher pat s) }
|
||||
def revSplit [ToBackwardSearcher ρ σ] (s : Slice) (pat : ρ) :
|
||||
Std.Iter (α := RevSplitIterator ρ s) Slice :=
|
||||
{ internalState := .operating s.endPos (ToBackwardSearcher.toSearcher s pat) }
|
||||
|
||||
/--
|
||||
If {name}`pat` matches a suffix of {name}`s`, returns the remainder. Returns {name}`none` otherwise.
|
||||
@@ -686,8 +667,8 @@ Examples:
|
||||
* {lean}`"red green blue".toSlice.dropSuffix? Char.isLower == some "red green blu".toSlice`
|
||||
-/
|
||||
@[inline]
|
||||
def dropSuffix? (s : Slice) (pat : ρ) [BackwardPattern pat] : Option Slice :=
|
||||
(BackwardPattern.dropSuffix? pat s).map s.sliceTo
|
||||
def dropSuffix? [BackwardPattern ρ] (s : Slice) (pat : ρ) : Option Slice :=
|
||||
(BackwardPattern.dropSuffix? s pat).map s.replaceEnd
|
||||
|
||||
/--
|
||||
If {name}`pat` matches a suffix of {name}`s`, returns the remainder. Returns {name}`s` unmodified
|
||||
@@ -705,7 +686,7 @@ Examples:
|
||||
* {lean}`"red green blue".toSlice.dropSuffix Char.isLower == "red green blu".toSlice`
|
||||
-/
|
||||
@[specialize pat]
|
||||
def dropSuffix (s : Slice) (pat : ρ) [BackwardPattern pat] : Slice :=
|
||||
def dropSuffix [BackwardPattern ρ] (s : Slice) (pat : ρ) : Slice :=
|
||||
dropSuffix? s pat |>.getD s
|
||||
|
||||
/--
|
||||
@@ -720,7 +701,7 @@ Examples:
|
||||
-/
|
||||
@[inline]
|
||||
def dropEnd (s : Slice) (n : Nat) : Slice :=
|
||||
s.sliceTo (s.endPos.prevn n)
|
||||
s.replaceEnd (s.endPos.prevn n)
|
||||
|
||||
/--
|
||||
Creates a new slice that contains the longest suffix of {name}`s` for which {name}`pat` matched
|
||||
@@ -732,18 +713,18 @@ Examples:
|
||||
* {lean}`"red green blue".toSlice.dropEndWhile (fun (_ : Char) => true) == "".toSlice`
|
||||
-/
|
||||
@[inline]
|
||||
def dropEndWhile (s : Slice) (pat : ρ) [BackwardPattern pat] : Slice :=
|
||||
def dropEndWhile [BackwardPattern ρ] (s : Slice) (pat : ρ) : Slice :=
|
||||
go s.endPos
|
||||
where
|
||||
@[specialize pat]
|
||||
go (curr : s.Pos) : Slice :=
|
||||
if let some nextCurr := BackwardPattern.dropSuffix? pat (s.sliceTo curr) then
|
||||
if Pos.ofSliceTo nextCurr < curr then
|
||||
go (Pos.ofSliceTo nextCurr)
|
||||
if let some nextCurr := BackwardPattern.dropSuffix? (s.replaceEnd curr) pat then
|
||||
if Pos.ofReplaceEnd nextCurr < curr then
|
||||
go (Pos.ofReplaceEnd nextCurr)
|
||||
else
|
||||
s.sliceTo curr
|
||||
s.replaceEnd curr
|
||||
else
|
||||
s.sliceTo curr
|
||||
s.replaceEnd curr
|
||||
termination_by curr.down
|
||||
|
||||
/--
|
||||
@@ -777,7 +758,7 @@ Examples:
|
||||
-/
|
||||
@[inline]
|
||||
def takeEnd (s : Slice) (n : Nat) : Slice :=
|
||||
s.sliceFrom (s.endPos.prevn n)
|
||||
s.replaceStart (s.endPos.prevn n)
|
||||
|
||||
/--
|
||||
Creates a new slice that contains the suffix prefix of {name}`s` for which {name}`pat` matched
|
||||
@@ -791,22 +772,22 @@ Examples:
|
||||
* {lean}`"red green blue".toSlice.takeEndWhile (fun (_ : Char) => true) == "red green blue".toSlice`
|
||||
-/
|
||||
@[inline]
|
||||
def takeEndWhile (s : Slice) (pat : ρ) [BackwardPattern pat] : Slice :=
|
||||
def takeEndWhile [BackwardPattern ρ] (s : Slice) (pat : ρ) : Slice :=
|
||||
go s.endPos
|
||||
where
|
||||
@[specialize pat]
|
||||
go (curr : s.Pos) : Slice :=
|
||||
if let some nextCurr := BackwardPattern.dropSuffix? pat (s.sliceTo curr) then
|
||||
if Pos.ofSliceTo nextCurr < curr then
|
||||
go (Pos.ofSliceTo nextCurr)
|
||||
if let some nextCurr := BackwardPattern.dropSuffix? (s.replaceEnd curr) pat then
|
||||
if Pos.ofReplaceEnd nextCurr < curr then
|
||||
go (Pos.ofReplaceEnd nextCurr)
|
||||
else
|
||||
s.sliceFrom curr
|
||||
s.replaceStart curr
|
||||
else
|
||||
s.sliceFrom curr
|
||||
s.replaceStart curr
|
||||
termination_by curr.down
|
||||
|
||||
/--
|
||||
Finds the position of the first match of the pattern {name}`pat` in a slice, starting
|
||||
Finds the position of the first match of the pattern {name}`pat` in a slice {name}`true`, starting
|
||||
from the end of the slice and traversing towards the start. If there is no match {name}`none` is
|
||||
returned.
|
||||
|
||||
@@ -814,12 +795,13 @@ This function is generic over all currently supported patterns except
|
||||
{name}`String`/{name}`String.Slice`.
|
||||
|
||||
Examples:
|
||||
* {lean}`("coffee tea water".toSlice.revFind? Char.isWhitespace).map (·.get!) == some ' '`
|
||||
* {lean}`"tea".toSlice.revFind? (fun (c : Char) => c == 'X') == none`
|
||||
* {lean}`("coffee tea water".toSlice.find? Char.isWhitespace).map (·.get!) == some ' '`
|
||||
* {lean}`"tea".toSlice.find? (fun (c : Char) => c == 'X') == none`
|
||||
* {lean}`("coffee tea water".toSlice.find? "tea").map (·.get!) == some 't'`
|
||||
-/
|
||||
@[specialize pat]
|
||||
def revFind? (s : Slice) (pat : ρ) [ToBackwardSearcher pat σ] : Option s.Pos :=
|
||||
let searcher := ToBackwardSearcher.toSearcher pat s
|
||||
def revFind? [ToBackwardSearcher ρ σ] (s : Slice) (pat : ρ) : Option s.Pos :=
|
||||
let searcher := ToBackwardSearcher.toSearcher s pat
|
||||
searcher.findSome? (fun | .matched startPos _ => some startPos | .rejected .. => none)
|
||||
|
||||
end BackwardPatternUsers
|
||||
@@ -945,10 +927,6 @@ Examples:
|
||||
def chars (s : Slice) :=
|
||||
Std.Iterators.Iter.map (fun ⟨pos, h⟩ => pos.get h) (positions s)
|
||||
|
||||
@[deprecated "There is no constant-time length function on slices. Use `s.positions.count` instead, or `isEmpty` if you only need to know whether the slice is empty." (since := "2025-11-20")]
|
||||
def length (s : Slice) : Nat :=
|
||||
s.positions.count
|
||||
|
||||
structure RevPosIterator (s : Slice) where
|
||||
currPos : s.Pos
|
||||
deriving Inhabited
|
||||
@@ -1318,13 +1296,13 @@ def toNat! (s : Slice) : Nat :=
|
||||
panic! "Nat expected"
|
||||
|
||||
/--
|
||||
Returns the first character in {name}`s`. If {name}`s` is empty, returns {name}`none`.
|
||||
Returns the first character in {name}`s`. If {name}`s` is empty, {name}`none`.
|
||||
|
||||
Examples:
|
||||
* {lean}`"abc".toSlice.front? = some 'a'`
|
||||
* {lean}`"".toSlice.front? = none`
|
||||
-/
|
||||
@[inline, expose]
|
||||
@[inline]
|
||||
def front? (s : Slice) : Option Char :=
|
||||
s.startPos.get?
|
||||
|
||||
@@ -1335,89 +1313,10 @@ Examples:
|
||||
* {lean}`"abc".toSlice.front = 'a'`
|
||||
* {lean}`"".toSlice.front = (default : Char)`
|
||||
-/
|
||||
@[inline, expose]
|
||||
@[inline]
|
||||
def front (s : Slice) : Char :=
|
||||
s.front?.getD default
|
||||
|
||||
/--
|
||||
Checks whether the slice can be interpreted as the decimal representation of an integer.
|
||||
|
||||
A slice can be interpreted as a decimal integer if it only consists of at least one decimal digit
|
||||
and optionally {lit}`-` in front. Leading {lit}`+` characters are not allowed.
|
||||
|
||||
Use {name (scope := "Init.Data.String.Slice")}`String.Slice.toInt?` or {name (scope := "Init.Data.String.Slice")}`String.toInt!` to convert such a string to an integer.
|
||||
|
||||
Examples:
|
||||
* {lean}`"".toSlice.isInt = false`
|
||||
* {lean}`"-".toSlice.isInt = false`
|
||||
* {lean}`"0".toSlice.isInt = true`
|
||||
* {lean}`"-0".toSlice.isInt = true`
|
||||
* {lean}`"5".toSlice.isInt = true`
|
||||
* {lean}`"587".toSlice.isInt = true`
|
||||
* {lean}`"-587".toSlice.isInt = true`
|
||||
* {lean}`"+587".toSlice.isInt = false`
|
||||
* {lean}`" 5".toSlice.isInt = false`
|
||||
* {lean}`"2-3".toSlice.isInt = false`
|
||||
* {lean}`"0xff".toSlice.isInt = false`
|
||||
-/
|
||||
def isInt (s : Slice) : Bool :=
|
||||
if s.front = '-' then
|
||||
(s.drop 1).isNat
|
||||
else
|
||||
s.isNat
|
||||
|
||||
/--
|
||||
Interprets a slice as the decimal representation of an integer, returning it. Returns {lean}`none` if
|
||||
the string does not contain a decimal integer.
|
||||
|
||||
A string can be interpreted as a decimal integer if it only consists of at least one decimal digit
|
||||
and optionally {lit}`-` in front. Leading {lit}`+` characters are not allowed.
|
||||
|
||||
Use {name}`Slice.isInt` to check whether {name}`Slice.toInt?` would return {lean}`some`.
|
||||
{name (scope := "Init.Data.String.Slice")}`Slice.toInt!` is an alternative that panics instead of
|
||||
returning {lean}`none` when the string is not an integer.
|
||||
|
||||
Examples:
|
||||
* {lean}`"".toSlice.toInt? = none`
|
||||
* {lean}`"-".toSlice.toInt? = none`
|
||||
* {lean}`"0".toSlice.toInt? = some 0`
|
||||
* {lean}`"5".toSlice.toInt? = some 5`
|
||||
* {lean}`"-5".toSlice.toInt? = some (-5)`
|
||||
* {lean}`"587".toSlice.toInt? = some 587`
|
||||
* {lean}`"-587".toSlice.toInt? = some (-587)`
|
||||
* {lean}`" 5".toSlice.toInt? = none`
|
||||
* {lean}`"2-3".toSlice.toInt? = none`
|
||||
* {lean}`"0xff".toSlice.toInt? = none`
|
||||
-/
|
||||
def toInt? (s : Slice) : Option Int :=
|
||||
if s.front = '-' then
|
||||
Int.negOfNat <$> (s.drop 1).toNat?
|
||||
else
|
||||
Int.ofNat <$> s.toNat?
|
||||
|
||||
/--
|
||||
Interprets a string as the decimal representation of an integer, returning it. Panics if the string
|
||||
does not contain a decimal integer.
|
||||
|
||||
A string can be interpreted as a decimal integer if it only consists of at least one decimal digit
|
||||
and optionally {lit}`-` in front. Leading `+` characters are not allowed.
|
||||
|
||||
Use {name}`Slice.isInt` to check whether {name}`Slice.toInt!` would return a value.
|
||||
{name}`Slice.toInt?` is a safer alternative that returns {lean}`none` instead of panicking when the
|
||||
string is not an integer.
|
||||
|
||||
Examples:
|
||||
* {lean}`"0".toSlice.toInt! = 0`
|
||||
* {lean}`"5".toSlice.toInt! = 5`
|
||||
* {lean}`"587".toSlice.toInt! = 587`
|
||||
* {lean}`"-587".toSlice.toInt! = -587`
|
||||
-/
|
||||
@[inline]
|
||||
def toInt! (s : Slice) : Int :=
|
||||
match s.toInt? with
|
||||
| some v => v
|
||||
| none => panic "Int expected"
|
||||
|
||||
/--
|
||||
Returns the last character in {name}`s`. If {name}`s` is empty, returns {name}`none`.
|
||||
|
||||
@@ -1425,7 +1324,7 @@ Examples:
|
||||
* {lean}`"abc".toSlice.back? = some 'c'`
|
||||
* {lean}`"".toSlice.back? = none`
|
||||
-/
|
||||
@[inline, expose]
|
||||
@[inline]
|
||||
def back? (s : Slice) : Option Char :=
|
||||
s.endPos.prev? |>.bind (·.get?)
|
||||
|
||||
@@ -1436,7 +1335,7 @@ Examples:
|
||||
* {lean}`"abc".toSlice.back = 'c'`
|
||||
* {lean}`"".toSlice.back = (default : Char)`
|
||||
-/
|
||||
@[inline, expose]
|
||||
@[inline]
|
||||
def back (s : Slice) : Char :=
|
||||
s.back?.getD default
|
||||
|
||||
@@ -1472,20 +1371,4 @@ hierarchical, and the string is split at the dots ({lean}`'.'`).
|
||||
def toName (s : Slice) : Lean.Name :=
|
||||
s.toString.toName
|
||||
|
||||
instance : Std.ToFormat String.Slice where
|
||||
format s := Std.ToFormat.format s.copy
|
||||
|
||||
end String.Slice
|
||||
|
||||
/-- Converts a {lean}`Std.Iter String.Slice` to a {lean}`List String`. -/
|
||||
@[inline]
|
||||
def Std.Iterators.Iter.toStringList {α : Type} [Std.Iterators.Iterator α Id String.Slice]
|
||||
[Std.Iterators.Finite α Id] [Std.Iterators.IteratorCollect α Id Id]
|
||||
(i : Std.Iter (α := α) String.Slice) : List String :=
|
||||
i.map String.Slice.copy |>.toList
|
||||
|
||||
/-- Converts a {lean}`Std.Iter String.Slice` to an {lean}`Array String`. -/
|
||||
def Std.Iterators.Iter.toStringArray {α : Type} [Std.Iterators.Iterator α Id String.Slice]
|
||||
[Std.Iterators.Finite α Id] [Std.Iterators.IteratorCollect α Id Id]
|
||||
(i : Std.Iter (α := α) String.Slice) : Array String :=
|
||||
i.map String.Slice.copy |>.toArray
|
||||
|
||||
@@ -6,7 +6,7 @@ Author: Leonardo de Moura, Mario Carneiro
|
||||
module
|
||||
|
||||
prelude
|
||||
public import Init.Data.String.Slice
|
||||
public import Init.Data.String.Basic
|
||||
|
||||
/-!
|
||||
# The `Substring` type
|
||||
@@ -19,26 +19,6 @@ public section
|
||||
|
||||
namespace Substring.Raw
|
||||
|
||||
/--
|
||||
Converts a `String.Slice` into a `Substring.Raw`.
|
||||
-/
|
||||
@[inline]
|
||||
def ofSlice (s : String.Slice) : Substring.Raw where
|
||||
str := s.str
|
||||
startPos := s.startInclusive.offset
|
||||
stopPos := s.endExclusive.offset
|
||||
|
||||
/--
|
||||
Converts a `Substring.Raw` into a `String.Slice`, returning `none` if the substring is invalid.
|
||||
-/
|
||||
@[inline]
|
||||
def toSlice? (s : Substring.Raw) : Option String.Slice :=
|
||||
if h : s.startPos.IsValid s.str ∧ s.stopPos.IsValid s.str ∧ s.startPos ≤ s.stopPos then
|
||||
some (String.Slice.mk s.str (s.str.pos s.startPos h.1) (s.str.pos s.stopPos h.2.1)
|
||||
(by simp [String.Pos.le_iff, h.2.2]))
|
||||
else
|
||||
none
|
||||
|
||||
/--
|
||||
Checks whether a substring is empty.
|
||||
|
||||
@@ -51,7 +31,7 @@ A substring is empty if its start and end positions are the same.
|
||||
def Internal.isEmptyImpl (ss : Substring.Raw) : Bool :=
|
||||
Substring.Raw.isEmpty ss
|
||||
|
||||
/--{}
|
||||
/--
|
||||
Copies the region of the underlying string pointed to by a substring into a fresh string.
|
||||
-/
|
||||
@[inline] def toString : Substring.Raw → String
|
||||
@@ -155,7 +135,8 @@ Returns the substring-relative position of the first occurrence of `c` in `s`, o
|
||||
doesn't occur.
|
||||
-/
|
||||
@[inline] def posOf (s : Substring.Raw) (c : Char) : String.Pos.Raw :=
|
||||
s.toSlice?.map (·.find c |>.offset) |>.getD ⟨s.bsize⟩
|
||||
match s with
|
||||
| ⟨s, b, e⟩ => { byteIdx := (String.posOfAux s c e b).byteIdx - b.byteIdx }
|
||||
|
||||
/--
|
||||
Removes the specified number of characters (Unicode code points) from the beginning of a substring
|
||||
@@ -260,14 +241,16 @@ Folds a function over a substring from the left, accumulating a value starting w
|
||||
accumulated value is combined with each character in order, using `f`.
|
||||
-/
|
||||
@[inline] def foldl {α : Type u} (f : α → Char → α) (init : α) (s : Substring.Raw) : α :=
|
||||
s.toSlice?.get!.foldl f init
|
||||
match s with
|
||||
| ⟨s, b, e⟩ => String.foldlAux f s e b init
|
||||
|
||||
/--
|
||||
Folds a function over a substring from the right, accumulating a value starting with `init`. The
|
||||
accumulated value is combined with each character in reverse order, using `f`.
|
||||
-/
|
||||
@[inline] def foldr {α : Type u} (f : Char → α → α) (init : α) (s : Substring.Raw) : α :=
|
||||
s.toSlice?.get!.foldr f init
|
||||
match s with
|
||||
| ⟨s, b, e⟩ => String.foldrAux f init s e b
|
||||
|
||||
/--
|
||||
Checks whether the Boolean predicate `p` returns `true` for any character in a substring.
|
||||
@@ -275,7 +258,8 @@ Checks whether the Boolean predicate `p` returns `true` for any character in a s
|
||||
Short-circuits at the first character for which `p` returns `true`.
|
||||
-/
|
||||
@[inline] def any (s : Substring.Raw) (p : Char → Bool) : Bool :=
|
||||
s.toSlice?.get!.any p
|
||||
match s with
|
||||
| ⟨s, b, e⟩ => String.anyAux s e p b
|
||||
|
||||
/--
|
||||
Checks whether the Boolean predicate `p` returns `true` for every character in a substring.
|
||||
@@ -283,7 +267,7 @@ Checks whether the Boolean predicate `p` returns `true` for every character in a
|
||||
Short-circuits at the first character for which `p` returns `false`.
|
||||
-/
|
||||
@[inline] def all (s : Substring.Raw) (p : Char → Bool) : Bool :=
|
||||
s.toSlice?.get!.all p
|
||||
!s.any (fun c => !p c)
|
||||
|
||||
@[export lean_substring_all]
|
||||
def Internal.allImpl (s : Substring.Raw) (p : Char → Bool) : Bool :=
|
||||
|
||||
@@ -69,10 +69,6 @@ Examples:
|
||||
def dropRight (s : String) (n : Nat) : String :=
|
||||
(s.dropEnd n).copy
|
||||
|
||||
@[deprecated Slice.dropEnd (since := "2025-11-20")]
|
||||
def Slice.dropRight (s : Slice) (n : Nat) : Slice :=
|
||||
s.dropEnd n
|
||||
|
||||
@[export lean_string_dropright]
|
||||
def Internal.dropRightImpl (s : String) (n : Nat) : String :=
|
||||
(String.dropEnd s n).copy
|
||||
@@ -119,10 +115,6 @@ Examples:
|
||||
def takeRight (s : String) (n : Nat) : String :=
|
||||
(s.takeEnd n).toString
|
||||
|
||||
@[deprecated Slice.takeEnd (since := "2025-11-20")]
|
||||
def Slice.takeRight (s : Slice) (n : Nat) : Slice :=
|
||||
s.takeEnd n
|
||||
|
||||
/--
|
||||
Creates a string slice that contains the longest prefix of {name}`s` in which {name}`pat` matched
|
||||
(potentially repeatedly).
|
||||
@@ -138,7 +130,7 @@ Examples:
|
||||
* {lean}`"red red green blue".takeWhile "red " == "red red ".toSlice`
|
||||
* {lean}`"red green blue".takeWhile (fun (_ : Char) => true) == "red green blue".toSlice`
|
||||
-/
|
||||
@[inline] def takeWhile (s : String) (pat : ρ) [ForwardPattern pat] : String.Slice :=
|
||||
@[inline] def takeWhile [ForwardPattern ρ] (s : String) (pat : ρ) : String.Slice :=
|
||||
s.toSlice.takeWhile pat
|
||||
|
||||
/--
|
||||
@@ -156,7 +148,7 @@ Examples:
|
||||
* {lean}`"red red green blue".dropWhile "red " == "green blue".toSlice`
|
||||
* {lean}`"red green blue".dropWhile (fun (_ : Char) => true) == "".toSlice`
|
||||
-/
|
||||
@[inline] def dropWhile (s : String) (pat : ρ) [ForwardPattern pat] : String.Slice :=
|
||||
@[inline] def dropWhile [ForwardPattern ρ] (s : String) (pat : ρ) : String.Slice :=
|
||||
s.toSlice.dropWhile pat
|
||||
|
||||
/--
|
||||
@@ -173,17 +165,13 @@ Examples:
|
||||
* {lean}`"red green blue".takeEndWhile 'e' == "e".toSlice`
|
||||
* {lean}`"red green blue".takeEndWhile (fun (_ : Char) => true) == "red green blue".toSlice`
|
||||
-/
|
||||
@[inline] def takeEndWhile (s : String) (pat : ρ) [BackwardPattern pat] : String.Slice :=
|
||||
@[inline] def takeEndWhile [BackwardPattern ρ] (s : String) (pat : ρ) : String.Slice :=
|
||||
s.toSlice.takeEndWhile pat
|
||||
|
||||
@[deprecated String.takeEndWhile (since := "2025-11-17")]
|
||||
def takeRightWhile (s : String) (p : Char → Bool) : String :=
|
||||
(s.takeEndWhile p).toString
|
||||
|
||||
@[deprecated Slice.takeEndWhile (since := "2025-11-20")]
|
||||
def Slice.takeRightWhile (s : Slice) (p : Char → Bool) : Slice :=
|
||||
s.takeEndWhile p
|
||||
|
||||
/--
|
||||
Creates a new string by removing the longest suffix from {name}`s` in which {name}`pat` matches
|
||||
(potentially repeatedly).
|
||||
@@ -198,17 +186,13 @@ Examples:
|
||||
* {lean}`"red green blue".dropEndWhile 'e' == "red green blu".toSlice`
|
||||
* {lean}`"red green blue".dropEndWhile (fun (_ : Char) => true) == "".toSlice`
|
||||
-/
|
||||
@[inline] def dropEndWhile (s : String) (pat : ρ) [BackwardPattern pat] : String.Slice :=
|
||||
@[inline] def dropEndWhile [BackwardPattern ρ] (s : String) (pat : ρ) : String.Slice :=
|
||||
s.toSlice.dropEndWhile pat
|
||||
|
||||
@[deprecated String.dropEndWhile (since := "2025-11-17")]
|
||||
def dropRightWhile (s : String) (p : Char → Bool) : String :=
|
||||
(s.dropEndWhile p).toString
|
||||
|
||||
@[deprecated Slice.dropEndWhile (since := "2025-11-20")]
|
||||
def Slice.dropRightWhile (s : Slice) (p : Char → Bool) : Slice :=
|
||||
s.dropEndWhile p
|
||||
|
||||
/--
|
||||
Checks whether the first string ({name}`s`) begins with the pattern ({name}`pat`).
|
||||
|
||||
@@ -222,7 +206,7 @@ Examples:
|
||||
* {lean}`"red green blue".startsWith 'r' = true`
|
||||
* {lean}`"red green blue".startsWith Char.isLower = true`
|
||||
-/
|
||||
@[inline] def startsWith (s : String) (pat : ρ) [ForwardPattern pat] : Bool :=
|
||||
@[inline] def startsWith [ForwardPattern ρ] (s : String) (pat : ρ) : Bool :=
|
||||
s.toSlice.startsWith pat
|
||||
|
||||
/--
|
||||
@@ -256,7 +240,7 @@ Examples:
|
||||
* {lean}`"red green blue".endsWith 'e' = true`
|
||||
* {lean}`"red green blue".endsWith Char.isLower = true`
|
||||
-/
|
||||
@[inline] def endsWith (s : String) (pat : ρ) [BackwardPattern pat] : Bool :=
|
||||
@[inline] def endsWith [BackwardPattern ρ] (s : String) (pat : ρ) : Bool :=
|
||||
s.toSlice.endsWith pat
|
||||
|
||||
/--
|
||||
@@ -279,10 +263,6 @@ Examples:
|
||||
def trimRight (s : String) : String :=
|
||||
s.trimAsciiEnd.copy
|
||||
|
||||
@[deprecated Slice.trimAsciiEnd (since := "2025-11-20")]
|
||||
def Slice.trimRight (s : Slice) : Slice :=
|
||||
s.trimAsciiEnd
|
||||
|
||||
/--
|
||||
Removes leading whitespace from a string by returning a slice whose start position is the first
|
||||
non-whitespace character, or the end position if there is no non-whitespace character.
|
||||
@@ -303,10 +283,6 @@ Examples:
|
||||
def trimLeft (s : String) : String :=
|
||||
s.trimAsciiStart.copy
|
||||
|
||||
@[deprecated Slice.trimAsciiStart (since := "2025-11-20")]
|
||||
def Slice.trimLeft (s : Slice) : Slice :=
|
||||
s.trimAsciiStart
|
||||
|
||||
/--
|
||||
Removes leading and trailing whitespace from a string.
|
||||
|
||||
@@ -326,10 +302,6 @@ Examples:
|
||||
def trim (s : String) : String :=
|
||||
s.trimAscii.copy
|
||||
|
||||
@[deprecated Slice.trimAscii (since := "2025-11-20")]
|
||||
def Slice.trim (s : Slice) : Slice :=
|
||||
s.trimAscii
|
||||
|
||||
@[export lean_string_trim]
|
||||
def Internal.trimImpl (s : String) : String :=
|
||||
(String.trimAscii s).copy
|
||||
@@ -389,7 +361,7 @@ Examples:
|
||||
* {lean}`"red green blue".dropPrefix? 'r' == some "ed green blue".toSlice`
|
||||
* {lean}`"red green blue".dropPrefix? Char.isLower == some "ed green blue".toSlice`
|
||||
-/
|
||||
def dropPrefix? (s : String) (pat : ρ) [ForwardPattern pat] : Option String.Slice :=
|
||||
def dropPrefix? [ForwardPattern ρ] (s : String) (pat : ρ) : Option String.Slice :=
|
||||
s.toSlice.dropPrefix? pat
|
||||
|
||||
/--
|
||||
@@ -409,7 +381,7 @@ Examples:
|
||||
* {lean}`"red green blue".dropSuffix? 'e' == some "red green blu".toSlice`
|
||||
* {lean}`"red green blue".dropSuffix? Char.isLower == some "red green blu".toSlice`
|
||||
-/
|
||||
def dropSuffix? (s : String) (pat : ρ) [BackwardPattern pat] : Option String.Slice :=
|
||||
def dropSuffix? [BackwardPattern ρ] (s : String) (pat : ρ) : Option String.Slice :=
|
||||
s.toSlice.dropSuffix? pat
|
||||
|
||||
/--
|
||||
@@ -429,17 +401,13 @@ Examples:
|
||||
* {lean}`"red green blue".dropPrefix 'r' == "ed green blue".toSlice`
|
||||
* {lean}`"red green blue".dropPrefix Char.isLower == "ed green blue".toSlice`
|
||||
-/
|
||||
def dropPrefix (s : String) (pat : ρ) [ForwardPattern pat] : String.Slice :=
|
||||
def dropPrefix [ForwardPattern ρ] (s : String) (pat : ρ) : String.Slice :=
|
||||
s.toSlice.dropPrefix pat
|
||||
|
||||
@[deprecated String.dropPrefix (since := "2025-11-17")]
|
||||
def stripPrefix (s pre : String) : String :=
|
||||
(s.dropPrefix pre).toString
|
||||
|
||||
@[deprecated Slice.dropPrefix (since := "2025-11-20")]
|
||||
def Slice.stripPrefix (s pre : Slice) : Slice :=
|
||||
s.dropPrefix pre
|
||||
|
||||
/--
|
||||
If {name}`pat` matches a suffix of {name}`s`, returns the remainder. Returns {name}`s` unmodified
|
||||
otherwise.
|
||||
@@ -457,15 +425,11 @@ Examples:
|
||||
* {lean}`"red green blue".dropSuffix 'e' == "red green blu".toSlice`
|
||||
* {lean}`"red green blue".dropSuffix Char.isLower == "red green blu".toSlice`
|
||||
-/
|
||||
def dropSuffix (s : String) (pat : ρ) [BackwardPattern pat] : String.Slice :=
|
||||
def dropSuffix [BackwardPattern ρ] (s : String) (pat : ρ) : String.Slice :=
|
||||
s.toSlice.dropSuffix pat
|
||||
|
||||
@[deprecated String.dropSuffix (since := "2025-11-17")]
|
||||
def stripSuffix (s : String) (suff : String) : String :=
|
||||
(s.dropSuffix suff).toString
|
||||
|
||||
@[deprecated Slice.dropSuffix (since := "2025-11-20")]
|
||||
def Slice.stripSuffix (s : Slice) (suff : Slice) : Slice :=
|
||||
s.dropSuffix suff
|
||||
|
||||
end String
|
||||
|
||||
@@ -113,119 +113,125 @@ theorem prev_prev_lt {s : Slice} {p : s.Pos} {h h'} : (p.prev h).prev h' < p :=
|
||||
|
||||
end Slice.Pos
|
||||
|
||||
namespace Pos
|
||||
namespace ValidPos
|
||||
|
||||
/-- The number of bytes between `p` and the end position. This number decreases as `p` advances. -/
|
||||
def remainingBytes {s : String} (p : s.Pos) : Nat :=
|
||||
def remainingBytes {s : String} (p : s.ValidPos) : Nat :=
|
||||
p.toSlice.remainingBytes
|
||||
|
||||
@[simp]
|
||||
theorem remainingBytes_toSlice {s : String} {p : s.Pos} :
|
||||
theorem remainingBytes_toSlice {s : String} {p : s.ValidPos} :
|
||||
p.toSlice.remainingBytes = p.remainingBytes := (rfl)
|
||||
|
||||
theorem remainingBytes_eq_byteDistance {s : String} {p : s.Pos} :
|
||||
p.remainingBytes = p.offset.byteDistance s.endPos.offset := (rfl)
|
||||
theorem remainingBytes_eq_byteDistance {s : String} {p : s.ValidPos} :
|
||||
p.remainingBytes = p.offset.byteDistance s.endValidPos.offset := (rfl)
|
||||
|
||||
theorem remainingBytes_eq {s : String} {p : s.Pos} :
|
||||
theorem remainingBytes_eq {s : String} {p : s.ValidPos} :
|
||||
p.remainingBytes = s.utf8ByteSize - p.offset.byteIdx := by
|
||||
simp [remainingBytes_eq_byteDistance, Pos.Raw.byteDistance_eq]
|
||||
|
||||
theorem remainingBytes_inj {s : String} {p q : s.Pos} :
|
||||
theorem remainingBytes_inj {s : String} {p q : s.ValidPos} :
|
||||
p.remainingBytes = q.remainingBytes ↔ p = q := by
|
||||
simp [← remainingBytes_toSlice, Pos.toSlice_inj, Slice.Pos.remainingBytes_inj]
|
||||
simp [← remainingBytes_toSlice, ValidPos.toSlice_inj, Slice.Pos.remainingBytes_inj]
|
||||
|
||||
theorem le_iff_remainingBytes_le {s : String} (p q : s.Pos) :
|
||||
theorem le_iff_remainingBytes_le {s : String} (p q : s.ValidPos) :
|
||||
p ≤ q ↔ q.remainingBytes ≤ p.remainingBytes := by
|
||||
simp [← remainingBytes_toSlice, ← Slice.Pos.le_iff_remainingBytes_le]
|
||||
|
||||
theorem lt_iff_remainingBytes_lt {s : String} (p q : s.Pos) :
|
||||
theorem lt_iff_remainingBytes_lt {s : String} (p q : s.ValidPos) :
|
||||
p < q ↔ q.remainingBytes < p.remainingBytes := by
|
||||
simp [← remainingBytes_toSlice, ← Slice.Pos.lt_iff_remainingBytes_lt]
|
||||
|
||||
theorem wellFounded_lt {s : String} : WellFounded (fun (p : s.Pos) q => p < q) := by
|
||||
theorem wellFounded_lt {s : String} : WellFounded (fun (p : s.ValidPos) q => p < q) := by
|
||||
simpa [lt_iff, Pos.Raw.lt_iff] using
|
||||
InvImage.wf (Pos.Raw.byteIdx ∘ Pos.offset) Nat.lt_wfRel.wf
|
||||
InvImage.wf (Pos.Raw.byteIdx ∘ ValidPos.offset) Nat.lt_wfRel.wf
|
||||
|
||||
theorem wellFounded_gt {s : String} : WellFounded (fun (p : s.Pos) q => q < p) := by
|
||||
theorem wellFounded_gt {s : String} : WellFounded (fun (p : s.ValidPos) q => q < p) := by
|
||||
simpa [lt_iff_remainingBytes_lt] using
|
||||
InvImage.wf Pos.remainingBytes Nat.lt_wfRel.wf
|
||||
InvImage.wf ValidPos.remainingBytes Nat.lt_wfRel.wf
|
||||
|
||||
instance {s : String} : WellFoundedRelation s.Pos where
|
||||
instance {s : String} : WellFoundedRelation s.ValidPos where
|
||||
rel p q := q < p
|
||||
wf := Pos.wellFounded_gt
|
||||
wf := ValidPos.wellFounded_gt
|
||||
|
||||
/-- Type alias for `String.Pos` representing that the given position is expected to decrease
|
||||
/-- Type alias for `String.ValidPos` representing that the given position is expected to decrease
|
||||
in recursive calls. -/
|
||||
structure Down (s : String) : Type where
|
||||
inner : s.Pos
|
||||
inner : s.ValidPos
|
||||
|
||||
/-- Use `termination_by pos.down` to signify that in a recursive call, the parameter `pos` is
|
||||
expected to decrease. -/
|
||||
def down {s : String} (p : s.Pos) : Pos.Down s where
|
||||
def down {s : String} (p : s.ValidPos) : ValidPos.Down s where
|
||||
inner := p
|
||||
|
||||
@[simp]
|
||||
theorem inner_down {s : String} {p : s.Pos} : p.down.inner = p := (rfl)
|
||||
theorem inner_down {s : String} {p : s.ValidPos} : p.down.inner = p := (rfl)
|
||||
|
||||
instance {s : String} : WellFoundedRelation (Pos.Down s) where
|
||||
instance {s : String} : WellFoundedRelation (ValidPos.Down s) where
|
||||
rel p q := p.inner < q.inner
|
||||
wf := InvImage.wf Pos.Down.inner Pos.wellFounded_lt
|
||||
wf := InvImage.wf ValidPos.Down.inner ValidPos.wellFounded_lt
|
||||
|
||||
theorem map_toSlice_next? {s : String} {p : s.Pos} :
|
||||
p.next?.map Pos.toSlice = p.toSlice.next? := by
|
||||
theorem map_toSlice_next? {s : String} {p : s.ValidPos} :
|
||||
p.next?.map ValidPos.toSlice = p.toSlice.next? := by
|
||||
simp [next?]
|
||||
|
||||
theorem map_toSlice_prev? {s : String} {p : s.Pos} :
|
||||
p.prev?.map Pos.toSlice = p.toSlice.prev? := by
|
||||
theorem map_toSlice_prev? {s : String} {p : s.ValidPos} :
|
||||
p.prev?.map ValidPos.toSlice = p.toSlice.prev? := by
|
||||
simp [prev?]
|
||||
|
||||
theorem ne_endPos_of_next?_eq_some {s : String} {p q : s.Pos}
|
||||
(h : p.next? = some q) : p ≠ s.endPos :=
|
||||
ne_of_apply_ne Pos.toSlice (Slice.Pos.ne_endPos_of_next?_eq_some
|
||||
(by simpa only [Pos.map_toSlice_next?, Option.map_some] using congrArg (·.map toSlice) h))
|
||||
theorem ne_endValidPos_of_next?_eq_some {s : String} {p q : s.ValidPos}
|
||||
(h : p.next? = some q) : p ≠ s.endValidPos :=
|
||||
ne_of_apply_ne ValidPos.toSlice (Slice.Pos.ne_endPos_of_next?_eq_some
|
||||
(by simpa only [ValidPos.map_toSlice_next?, Option.map_some] using congrArg (·.map toSlice) h))
|
||||
|
||||
theorem eq_next_of_next?_eq_some {s : String} {p q : s.Pos} (h : p.next? = some q) :
|
||||
q = p.next (ne_endPos_of_next?_eq_some h) := by
|
||||
theorem eq_next_of_next?_eq_some {s : String} {p q : s.ValidPos} (h : p.next? = some q) :
|
||||
q = p.next (ne_endValidPos_of_next?_eq_some h) := by
|
||||
simpa only [← toSlice_inj, toSlice_next] using Slice.Pos.eq_next_of_next?_eq_some
|
||||
(by simpa [Pos.map_toSlice_next?] using congrArg (·.map toSlice) h)
|
||||
(by simpa [ValidPos.map_toSlice_next?] using congrArg (·.map toSlice) h)
|
||||
|
||||
theorem ne_startPos_of_prev?_eq_some {s : String} {p q : s.Pos}
|
||||
(h : p.prev? = some q) : p ≠ s.startPos :=
|
||||
ne_of_apply_ne Pos.toSlice (Slice.Pos.ne_startPos_of_prev?_eq_some
|
||||
(by simpa only [Pos.map_toSlice_prev?, Option.map_some] using congrArg (·.map toSlice) h))
|
||||
theorem ne_startValidPos_of_prev?_eq_some {s : String} {p q : s.ValidPos}
|
||||
(h : p.prev? = some q) : p ≠ s.startValidPos :=
|
||||
ne_of_apply_ne ValidPos.toSlice (Slice.Pos.ne_startPos_of_prev?_eq_some
|
||||
(by simpa only [ValidPos.map_toSlice_prev?, Option.map_some] using congrArg (·.map toSlice) h))
|
||||
|
||||
theorem eq_prev_of_prev?_eq_some {s : String} {p q : s.Pos} (h : p.prev? = some q) :
|
||||
q = p.prev (ne_startPos_of_prev?_eq_some h) := by
|
||||
theorem eq_prev_of_prev?_eq_some {s : String} {p q : s.ValidPos} (h : p.prev? = some q) :
|
||||
q = p.prev (ne_startValidPos_of_prev?_eq_some h) := by
|
||||
simpa only [← toSlice_inj, toSlice_prev] using Slice.Pos.eq_prev_of_prev?_eq_some
|
||||
(by simpa [Pos.map_toSlice_prev?] using congrArg (·.map toSlice) h)
|
||||
(by simpa [ValidPos.map_toSlice_prev?] using congrArg (·.map toSlice) h)
|
||||
|
||||
@[simp]
|
||||
theorem le_refl {s : String} (p : s.Pos) : p ≤ p := by
|
||||
simp [Pos.le_iff]
|
||||
theorem le_refl {s : String} (p : s.ValidPos) : p ≤ p := by
|
||||
simp [ValidPos.le_iff]
|
||||
|
||||
theorem lt_trans {s : String} {p q r : s.Pos} : p < q → q < r → p < r := by
|
||||
simpa [Pos.lt_iff, Pos.Raw.lt_iff] using Nat.lt_trans
|
||||
theorem lt_trans {s : String} {p q r : s.ValidPos} : p < q → q < r → p < r := by
|
||||
simpa [ValidPos.lt_iff, Pos.Raw.lt_iff] using Nat.lt_trans
|
||||
|
||||
theorem le_trans {s : String} {p q r : s.ValidPos} : p ≤ q → q ≤ r → p ≤ r := by
|
||||
simpa [ValidPos.le_iff, Pos.Raw.le_iff] using Nat.le_trans
|
||||
|
||||
theorem le_of_lt {s : String} {p q : s.ValidPos} : p < q → p ≤ q := by
|
||||
simpa [ValidPos.le_iff, ValidPos.lt_iff, Pos.Raw.le_iff, Pos.Raw.lt_iff] using Nat.le_of_lt
|
||||
|
||||
@[simp]
|
||||
theorem lt_next_next {s : String} {p : s.Pos} {h h'} : p < (p.next h).next h' :=
|
||||
theorem lt_next_next {s : String} {p : s.ValidPos} {h h'} : p < (p.next h).next h' :=
|
||||
lt_trans p.lt_next (p.next h).lt_next
|
||||
|
||||
@[simp]
|
||||
theorem prev_prev_lt {s : String} {p : s.Pos} {h h'} : (p.prev h).prev h' < p :=
|
||||
theorem prev_prev_lt {s : String} {p : s.ValidPos} {h h'} : (p.prev h).prev h' < p :=
|
||||
lt_trans (p.prev h).prev_lt p.prev_lt
|
||||
|
||||
theorem Splits.remainingBytes_eq {s : String} {p : s.Pos} {t₁ t₂}
|
||||
theorem Splits.remainingBytes_eq {s : String} {p : s.ValidPos} {t₁ t₂}
|
||||
(h : p.Splits t₁ t₂) : p.remainingBytes = t₂.utf8ByteSize := by
|
||||
simp [Pos.remainingBytes_eq, h.eq_append, h.offset_eq_rawEndPos]
|
||||
simp [ValidPos.remainingBytes_eq, h.eq_append, h.offset_eq_rawEndPos]
|
||||
|
||||
end Pos
|
||||
end ValidPos
|
||||
|
||||
namespace Slice.Pos
|
||||
|
||||
@[simp]
|
||||
theorem remainingBytes_toCopy {s : Slice} {p : s.Pos} :
|
||||
p.toCopy.remainingBytes = p.remainingBytes := by
|
||||
simp [remainingBytes_eq, String.Pos.remainingBytes_eq, Slice.utf8ByteSize_eq]
|
||||
simp [remainingBytes_eq, ValidPos.remainingBytes_eq, Slice.utf8ByteSize_eq]
|
||||
|
||||
theorem Splits.remainingBytes_eq {s : Slice} {p : s.Pos} {t₁ t₂} (h : p.Splits t₁ t₂) :
|
||||
p.remainingBytes = t₂.utf8ByteSize := by
|
||||
@@ -244,14 +250,14 @@ macro_rules | `(tactic| decreasing_trivial) => `(tactic|
|
||||
Slice.Pos.eq_prev_of_prev?_eq_some (by assumption),
|
||||
]) <;> done)
|
||||
macro_rules | `(tactic| decreasing_trivial) => `(tactic|
|
||||
(with_reducible change (_ : String.Pos _) < _
|
||||
(with_reducible change (_ : String.ValidPos _) < _
|
||||
simp [
|
||||
Pos.eq_next_of_next?_eq_some (by assumption),
|
||||
ValidPos.eq_next_of_next?_eq_some (by assumption),
|
||||
]) <;> done)
|
||||
macro_rules | `(tactic| decreasing_trivial) => `(tactic|
|
||||
(with_reducible change (_ : String.Pos _) < _
|
||||
(with_reducible change (_ : String.ValidPos _) < _
|
||||
simp [
|
||||
Pos.eq_prev_of_prev?_eq_some (by assumption),
|
||||
ValidPos.eq_prev_of_prev?_eq_some (by assumption),
|
||||
]) <;> done)
|
||||
|
||||
end String
|
||||
|
||||
@@ -8,7 +8,6 @@ module
|
||||
prelude
|
||||
public import Init.Data.String.Substring
|
||||
import Init.Data.String.TakeDrop
|
||||
import Init.Data.String.Search
|
||||
|
||||
/-!
|
||||
Here we give the. implementation of `Name.toString`. There is also a private implementation in
|
||||
|
||||
@@ -525,12 +525,12 @@ and do not provide separate verification theorems.
|
||||
@[simp] theorem mem_toArray_iff (a : α) (xs : Vector α n) : a ∈ xs.toArray ↔ a ∈ xs :=
|
||||
⟨fun h => ⟨h⟩, fun ⟨h⟩ => h⟩
|
||||
|
||||
instance [Monad m] : ForIn' m (Vector α n) α inferInstance where
|
||||
instance : ForIn' m (Vector α n) α inferInstance where
|
||||
forIn' xs b f := Array.forIn' xs.toArray b (fun a h b => f a (by simpa using h) b)
|
||||
|
||||
/-! ### ForM instance -/
|
||||
|
||||
instance [Monad m] : ForM m (Vector α n) α where
|
||||
instance : ForM m (Vector α n) α where
|
||||
forM := Vector.forM
|
||||
|
||||
-- We simplify `Vector.forM` to `forM`.
|
||||
|
||||
@@ -2535,6 +2535,11 @@ theorem back?_eq_some_iff {xs : Vector α n} {a : α} :
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
rcases ys with ⟨ys, rfl⟩
|
||||
simp [Array.back_append]
|
||||
split <;> rename_i h
|
||||
· rw [dif_pos]
|
||||
simp_all
|
||||
· rw [dif_neg]
|
||||
rwa [Array.isEmpty_iff_size_eq_zero] at h
|
||||
|
||||
theorem back_append_right {xs : Vector α n} {ys : Vector α m} [NeZero m] :
|
||||
(xs ++ ys).back = ys.back := by
|
||||
|
||||
@@ -116,7 +116,7 @@ macro:max x:term noWs "[" i:term "]" noWs "?" : term => `(getElem? $x $i)
|
||||
|
||||
/--
|
||||
The syntax `arr[i]!` gets the `i`'th element of the collection `arr` and
|
||||
panics if `i` is out of bounds.
|
||||
panics `i` is out of bounds.
|
||||
-/
|
||||
macro:max x:term noWs "[" i:term "]" noWs "!" : term => `(getElem! $x $i)
|
||||
|
||||
|
||||
@@ -26,5 +26,3 @@ public import Init.Grind.Injective
|
||||
public import Init.Grind.Order
|
||||
public import Init.Grind.Interactive
|
||||
public import Init.Grind.Lint
|
||||
public import Init.Grind.Annotated
|
||||
public import Init.Grind.FieldNormNum
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
/-
|
||||
Copyright (c) 2025 Lean FRO, LLC. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Kim Morrison
|
||||
-/
|
||||
module
|
||||
prelude
|
||||
public import Init.Tactics
|
||||
|
||||
public section
|
||||
namespace Lean.Parser.Command
|
||||
|
||||
/--
|
||||
`grind_annotated "YYYY-MM-DD"` marks the current file as having been manually annotated for `grind`.
|
||||
|
||||
When the LibrarySuggestion framework is called with `caller := "grind"` (as happens when using
|
||||
`grind +suggestions`), theorems from grind-annotated files are excluded from premise selection.
|
||||
This is because these files have already been manually reviewed and annotated with appropriate
|
||||
`@[grind]` attributes.
|
||||
|
||||
The date argument (in YYYY-MM-DD format) records when the file was annotated. This is currently
|
||||
informational only, but may be used in the future to detect files that have been significantly
|
||||
modified since annotation and may need re-review.
|
||||
|
||||
Example:
|
||||
```
|
||||
grind_annotated "2025-01-15"
|
||||
```
|
||||
|
||||
This command should typically appear near the top of a file, after imports.
|
||||
-/
|
||||
syntax (name := grindAnnotated) "grind_annotated" str : command
|
||||
|
||||
end Lean.Parser.Command
|
||||
@@ -188,16 +188,6 @@ where the term `f` contains at least one constant symbol.
|
||||
-/
|
||||
syntax grindInj := &"inj"
|
||||
/--
|
||||
The `funCC` modifier marks global functions that support **function-valued congruence closure**.
|
||||
Given an application `f a₁ a₂ … aₙ`, when `funCC := true`,
|
||||
`grind` generates and tracks equalities for all partial applications:
|
||||
- `f a₁`
|
||||
- `f a₁ a₂`
|
||||
- `…`
|
||||
- `f a₁ a₂ … aₙ`
|
||||
-/
|
||||
syntax grindFunCC := &"funCC"
|
||||
/--
|
||||
`symbol <prio>` sets the priority of a constant for `grind`’s pattern-selection
|
||||
procedure. `grind` prefers patterns that contain higher-priority symbols.
|
||||
Example:
|
||||
@@ -224,7 +214,7 @@ syntax grindMod :=
|
||||
grindEqBoth <|> grindEqRhs <|> grindEq <|> grindEqBwd <|> grindBwd
|
||||
<|> grindFwd <|> grindRL <|> grindLR <|> grindUsr <|> grindCasesEager
|
||||
<|> grindCases <|> grindIntro <|> grindExt <|> grindGen <|> grindSym <|> grindInj
|
||||
<|> grindFunCC <|> grindDef
|
||||
<|> grindDef
|
||||
|
||||
/--
|
||||
Marks a theorem or definition for use by the `grind` tactic.
|
||||
|
||||
@@ -172,36 +172,6 @@ structure Config where
|
||||
and then reintroduces them while simplifying and applying eager `cases`.
|
||||
-/
|
||||
revert := false
|
||||
/--
|
||||
When `true`, it enables **function-valued congruence closure**.
|
||||
`grind` treats equalities of partially applied functions as first-class equalities
|
||||
and propagates them through further applications.
|
||||
Given an application `f a₁ a₂ … aₙ`, when `funCC := true` *and* function equality is enabled for `f`,
|
||||
`grind` generates and tracks equalities for all partial applications:
|
||||
- `f a₁`
|
||||
- `f a₁ a₂`
|
||||
- `…`
|
||||
- `f a₁ a₂ … aₙ`
|
||||
|
||||
This allows equalities such as `f a₁ = g` to propagate to
|
||||
`f a₁ a₂ = g a₂`.
|
||||
|
||||
**When is function equality enabled for a symbol?**
|
||||
Function equality is automatically enabled in the following cases:
|
||||
1. **`f` is not a constant.** (For example, a lambda expression, a local variable, or a function parameter.)
|
||||
2. **`f` is a structure field projection**, *provided the structure is not a `class`.*
|
||||
3. **`f` is a constant marked with the attribute:** `@[grind funCC]`
|
||||
|
||||
If none of the above conditions apply, function equality is disabled for `f`, and congruence
|
||||
closure behaves almost like it does in SMT solvers for first-order logic.
|
||||
Here is an example, `grind` can solve when `funCC := true`
|
||||
```
|
||||
example (a b : Nat) (g : Nat → Nat) (f : Nat → Nat → Nat) (h : f a = g) :
|
||||
f a b = g b := by
|
||||
grind
|
||||
```
|
||||
-/
|
||||
funCC := true
|
||||
deriving Inhabited, BEq
|
||||
|
||||
/--
|
||||
|
||||
@@ -1,219 +0,0 @@
|
||||
/-
|
||||
Copyright (c) 2025 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Leonardo de Moura
|
||||
-/
|
||||
module
|
||||
prelude
|
||||
public import Init.Grind.Ring.Field
|
||||
public import Init.Data.Rat.Basic
|
||||
import Init.Data.Rat.Lemmas
|
||||
public section
|
||||
namespace Lean.Grind.Field.NormNum
|
||||
|
||||
attribute [local instance] Semiring.natCast Ring.intCast
|
||||
|
||||
abbrev ofRat {α} [Field α] (r : Rat) : α :=
|
||||
(r.num : α)/(r.den : α)
|
||||
|
||||
attribute [local simp]
|
||||
Field.inv_one Semiring.natCast_zero Semiring.natCast_one Ring.intCast_zero Ring.intCast_one Semiring.one_mul Semiring.mul_one
|
||||
Semiring.pow_zero Field.inv_one Field.inv_zero
|
||||
|
||||
private theorem dvd_helper₁ {z : Int} {n : Nat} : ↑(z.natAbs.gcd n : Int) ∣ z :=
|
||||
Rat.normalize.dvd_num rfl
|
||||
private theorem dvd_helper₂ {z : Int} {n : Nat} : z.natAbs.gcd n ∣ n :=
|
||||
Nat.gcd_dvd_right z.natAbs n
|
||||
|
||||
private theorem nonzero_helper {α} [Field α] {z : Int} {n m : Nat} (hn : (n : α) ≠ 0) (hm : (m : α) ≠ 0) :
|
||||
(z.natAbs.gcd (n * m) : α) ≠ 0 := by
|
||||
intro h
|
||||
have : z.natAbs.gcd (n * m) ∣ (n * m) := Nat.gcd_dvd_right z.natAbs (n * m)
|
||||
obtain ⟨k, hk⟩ := this
|
||||
replace hk := congrArg (fun x : Nat => (x : α)) hk
|
||||
dsimp at hk
|
||||
rw [Semiring.natCast_mul, Semiring.natCast_mul, h, Semiring.zero_mul] at hk
|
||||
replace hk := Field.of_mul_eq_zero hk
|
||||
simp_all
|
||||
|
||||
theorem ofRat_add' {α} [Field α] {a b : Rat} (ha : (a.den : α) ≠ 0) (hb : (b.den : α) ≠ 0) :
|
||||
(ofRat (a + b) : α) = ofRat a + ofRat b := by
|
||||
rw [ofRat, ofRat, ofRat, Rat.num_add, Rat.den_add]
|
||||
rw [Field.intCast_div_of_dvd dvd_helper₁ (by simpa [Ring.intCast_natCast] using (nonzero_helper ha hb))]
|
||||
rw [Field.natCast_div_of_dvd dvd_helper₂ (nonzero_helper ha hb)]
|
||||
rw [Ring.intCast_natCast, Field.div_div_right]
|
||||
rw [Field.div_mul_cancel (nonzero_helper ha hb)]
|
||||
rw [Field.add_div hb, Field.div_mul, Field.div_add ha]
|
||||
rw [Ring.intCast_add, Ring.intCast_mul, Ring.intCast_mul, Ring.intCast_natCast,
|
||||
Ring.intCast_natCast, CommSemiring.mul_comm (a.den : α), Field.div_div_left,
|
||||
Semiring.natCast_mul]
|
||||
theorem ofRat_mul' {α} [Field α] {a b : Rat} (ha : (a.den : α) ≠ 0) (hb : (b.den : α) ≠ 0) : (ofRat (a * b) : α) = ofRat a * ofRat b := by
|
||||
rw [ofRat, ofRat, ofRat, Rat.num_mul, Rat.den_mul]
|
||||
rw [Field.intCast_div_of_dvd dvd_helper₁ (by simpa [Ring.intCast_natCast] using (nonzero_helper ha hb))]
|
||||
rw [Field.natCast_div_of_dvd dvd_helper₂ (nonzero_helper ha hb)]
|
||||
rw [Ring.intCast_natCast, Field.div_div_right]
|
||||
rw [Field.div_mul_cancel (nonzero_helper ha hb)]
|
||||
rw [Field.div_mul, Field.mul_div, Field.div_div_left, Ring.intCast_mul, Semiring.natCast_mul,
|
||||
CommSemiring.mul_comm (b.den : α)]
|
||||
|
||||
-- Note: false without `IsCharP α 0` (consider `a = b = 1/2` in `ℤ/2ℤ`):
|
||||
theorem ofRat_add {α} [Field α] [IsCharP α 0] (a b : Rat) :
|
||||
(ofRat (a + b) : α) = ofRat a + ofRat b :=
|
||||
ofRat_add' (natCast_ne_zero a.den_nz) (natCast_ne_zero b.den_nz)
|
||||
-- Note: false without `IsCharP α 0` (consider `a = 2/3` and `b = 1/2` in `ℤ/2ℤ`):
|
||||
theorem ofRat_mul {α} [Field α] [IsCharP α 0] (a b : Rat) : (ofRat (a * b) : α) = ofRat a * ofRat b :=
|
||||
ofRat_mul' (natCast_ne_zero a.den_nz) (natCast_ne_zero b.den_nz)
|
||||
|
||||
theorem ofRat_inv {α} [Field α] (a : Rat) : (ofRat (a⁻¹) : α) = (ofRat a)⁻¹ := by
|
||||
simp [ofRat]; split
|
||||
next h => simp [h, Field.div_eq_mul_inv]
|
||||
next =>
|
||||
simp [Field.div_eq_mul_inv, Field.inv_mul, Field.inv_inv, Ring.intCast_mul, Ring.intCast_natCast]
|
||||
generalize a.num = n
|
||||
generalize a.den = d
|
||||
conv => rhs; rw [← Int.sign_mul_natAbs n]
|
||||
simp [Ring.intCast_mul, Ring.intCast_natCast, Field.inv_mul]
|
||||
have : (Int.cast n.sign : α) = (Int.cast n.sign : α)⁻¹ := by
|
||||
cases Int.sign_trichotomy n
|
||||
next h => simp [h]
|
||||
next h => cases h <;> simp [*, Ring.intCast_neg, Field.inv_neg]
|
||||
rw [← this, Semiring.mul_assoc, Semiring.mul_assoc]
|
||||
congr 1
|
||||
rw [CommSemiring.mul_comm]
|
||||
|
||||
theorem ofRat_div' {α} [Field α] {a b : Rat} (ha : (a.den : α) ≠ 0) (hb : (b.num : α) ≠ 0) :
|
||||
(ofRat (a / b) : α) = ofRat a / ofRat b := by
|
||||
replace hb : ((b⁻¹).den : α) ≠ 0 := by
|
||||
simp only [Rat.den_inv, Rat.num_eq_zero, ne_eq]
|
||||
rw [if_neg (by intro h; simp_all)]
|
||||
rw [← Ring.intCast_natCast]
|
||||
by_cases h : 0 ≤ b.num
|
||||
· have : (b.num.natAbs : Int) = b.num := Int.natAbs_of_nonneg h
|
||||
rwa [this]
|
||||
· have : (b.num.natAbs : Int) = -b.num := Int.ofNat_natAbs_of_nonpos (by omega)
|
||||
rw [this, Ring.intCast_neg]
|
||||
rwa [AddCommGroup.neg_eq_iff, AddCommGroup.neg_zero]
|
||||
rw [Rat.div_def, ofRat_mul' ha hb, ofRat_inv, Field.div_eq_mul_inv (ofRat a)]
|
||||
|
||||
theorem ofRat_div {α} [Field α] [IsCharP α 0] (a b : Rat) : (ofRat (a / b) : α) = ofRat a / ofRat b := by
|
||||
rw [Rat.div_def, ofRat_mul, ofRat_inv, Field.div_eq_mul_inv (ofRat a)]
|
||||
|
||||
theorem ofRat_neg {α} [Field α] (a : Rat) : (ofRat (-a) : α) = -ofRat a := by
|
||||
simp [ofRat, Field.div_eq_mul_inv, Ring.intCast_neg, Ring.neg_mul]
|
||||
|
||||
theorem ofRat_sub' {α} [Field α] {a b : Rat} (ha : (a.den : α) ≠ 0) (hb : (b.den : α) ≠ 0) :
|
||||
(ofRat (a - b) : α) = ofRat a - ofRat b := by
|
||||
replace hb : ((-b).den : α) ≠ 0 := by simpa
|
||||
rw [Rat.sub_eq_add_neg, ofRat_add' ha hb, ofRat_neg, Ring.sub_eq_add_neg]
|
||||
|
||||
theorem ofRat_sub {α} [Field α] [IsCharP α 0] (a b : Rat) :
|
||||
(ofRat (a - b) : α) = ofRat a - ofRat b := by
|
||||
rw [Rat.sub_eq_add_neg, ofRat_add, ofRat_neg, Ring.sub_eq_add_neg]
|
||||
|
||||
theorem ofRat_npow' {α} [Field α] {a : Rat} (ha : (a.den : α) ≠ 0) (n : Nat) : (ofRat (a^n) : α) = ofRat a ^ n := by
|
||||
have h : ∀ n : Nat, ((a^n).den : α) ≠ 0 := by
|
||||
intro n
|
||||
rw [Rat.den_pow, ne_eq, Semiring.natCast_pow]
|
||||
intro h
|
||||
induction n with
|
||||
| zero =>
|
||||
rw [Semiring.pow_zero] at h
|
||||
exact Field.zero_ne_one h.symm
|
||||
| succ n ih' =>
|
||||
rw [Semiring.pow_succ] at h
|
||||
replace h := Field.of_mul_eq_zero h
|
||||
rcases h with h | h
|
||||
· exact ih' h
|
||||
· exact ha h
|
||||
induction n
|
||||
next => simp [Field.div_eq_mul_inv, ofRat]
|
||||
next n ih =>
|
||||
rw [Rat.pow_succ, ofRat_mul' (h _) ha, ih, Semiring.pow_succ]
|
||||
|
||||
theorem ofRat_npow {α} [Field α] [IsCharP α 0] (a : Rat) (n : Nat) : (ofRat (a^n) : α) = ofRat a ^ n := by
|
||||
induction n
|
||||
next => simp [Field.div_eq_mul_inv, ofRat]
|
||||
next n ih => rw [Rat.pow_succ, ofRat_mul, ih, Semiring.pow_succ]
|
||||
|
||||
theorem ofRat_zpow' {α} [Field α] {a : Rat} (ha : (a.den : α) ≠ 0) (n : Int) : (ofRat (a^n) : α) = ofRat a ^ n := by
|
||||
cases n
|
||||
next => rw [Int.ofNat_eq_natCast, Rat.zpow_natCast, Field.zpow_natCast, ofRat_npow' ha]
|
||||
next =>
|
||||
rw [Int.negSucc_eq, Rat.zpow_neg, Field.zpow_neg, ofRat_inv]
|
||||
congr 1
|
||||
have : (1 : Int) = (1 : Nat) := rfl
|
||||
rw [this, ← Int.natCast_add, Rat.zpow_natCast, Field.zpow_natCast, ofRat_npow' ha]
|
||||
|
||||
theorem ofRat_zpow {α} [Field α] [IsCharP α 0] (a : Rat) (n : Int) : (ofRat (a^n) : α) = ofRat a ^ n := by
|
||||
cases n
|
||||
next => rw [Int.ofNat_eq_natCast, Rat.zpow_natCast, Field.zpow_natCast, ofRat_npow]
|
||||
next =>
|
||||
rw [Int.negSucc_eq, Rat.zpow_neg, Field.zpow_neg, ofRat_inv]
|
||||
congr 1
|
||||
have : (1 : Int) = (1 : Nat) := rfl
|
||||
rw [this, ← Int.natCast_add, Rat.zpow_natCast, Field.zpow_natCast, ofRat_npow]
|
||||
|
||||
theorem natCast_eq {α} [Field α] (n : Nat) : (NatCast.natCast n : α) = ofRat n := by
|
||||
simp [ofRat, Ring.intCast_natCast, Semiring.natCast_one, Field.div_eq_mul_inv,
|
||||
Field.inv_one, Semiring.mul_one]
|
||||
|
||||
theorem ofNat_eq {α} [Field α] (n : Nat) : (OfNat.ofNat n : α) = ofRat n := by
|
||||
rw [Semiring.ofNat_eq_natCast]
|
||||
apply natCast_eq
|
||||
|
||||
theorem intCast_eq {α} [Field α] (n : Int) : (IntCast.intCast n : α) = ofRat n := by
|
||||
simp [ofRat, Semiring.natCast_one, Field.div_eq_mul_inv, Field.inv_one, Semiring.mul_one]
|
||||
|
||||
theorem add_eq {α} [Field α] [IsCharP α 0] (a b : α) (v₁ v₂ v : Rat)
|
||||
: v == v₁ + v₂ → a = ofRat v₁ → b = ofRat v₂ → a + b = ofRat v := by
|
||||
simp; intros; subst v a b; rw [ofRat_add]
|
||||
|
||||
theorem sub_eq {α} [Field α] [IsCharP α 0] (a b : α) (v₁ v₂ v : Rat)
|
||||
: v == v₁ - v₂ → a = ofRat v₁ → b = ofRat v₂ → a - b = ofRat v := by
|
||||
simp; intros; subst v a b; rw [ofRat_sub]
|
||||
|
||||
theorem mul_eq {α} [Field α] [IsCharP α 0] (a b : α) (v₁ v₂ v : Rat)
|
||||
: v == v₁ * v₂ → a = ofRat v₁ → b = ofRat v₂ → a * b = ofRat v := by
|
||||
simp; intros; subst v a b; rw [ofRat_mul]
|
||||
|
||||
theorem div_eq {α} [Field α] [IsCharP α 0] (a b : α) (v₁ v₂ v : Rat)
|
||||
: v == v₁ / v₂ → a = ofRat v₁ → b = ofRat v₂ → a / b = ofRat v := by
|
||||
simp; intros; subst v a b; rw [ofRat_div]
|
||||
|
||||
theorem inv_eq {α} [Field α] (a : α) (v₁ v : Rat)
|
||||
: v == v₁⁻¹ → a = ofRat v₁ → a⁻¹ = ofRat v := by
|
||||
simp; intros; subst v a; rw [ofRat_inv]
|
||||
|
||||
theorem neg_eq {α} [Field α] (a : α) (v₁ v : Rat)
|
||||
: v == -v₁ → a = ofRat v₁ → -a = ofRat v := by
|
||||
simp; intros; subst v a; rw [ofRat_neg]
|
||||
|
||||
theorem npow_eq {α} [Field α] [IsCharP α 0] (a : α) (n : Nat) (v₁ v : Rat)
|
||||
: v == v₁^n → a = ofRat v₁ → a ^ n = ofRat v := by
|
||||
simp; intros; subst v a; rw [ofRat_npow]
|
||||
|
||||
theorem zpow_eq {α} [Field α] [IsCharP α 0] (a : α) (n : Int) (v₁ v : Rat)
|
||||
: v == v₁^n → a = ofRat v₁ → a ^ n = ofRat v := by
|
||||
simp; intros; subst v a; rw [ofRat_zpow]
|
||||
|
||||
theorem eq_int {α} [Field α] (a : α) (v : Rat) (n : Int)
|
||||
: n == v.num && v.den == 1 → a = ofRat v → a = IntCast.intCast n := by
|
||||
simp; cases v; simp [ofRat]
|
||||
next den _ _ =>
|
||||
intros; subst den n a
|
||||
simp [Semiring.natCast_one, Field.div_eq_mul_inv, Field.inv_one, Semiring.mul_one]
|
||||
|
||||
theorem eq_inv {α} [Field α] (a : α) (v : Rat) (d : Nat)
|
||||
: v.num == 1 && v.den == d → a = ofRat v → a = (NatCast.natCast d : α)⁻¹ := by
|
||||
simp; cases v; simp [ofRat]
|
||||
next num _ _ _ =>
|
||||
intros; subst num d a
|
||||
simp [Ring.intCast_one, Field.div_eq_mul_inv, Semiring.one_mul]
|
||||
|
||||
theorem eq_mul_inv {α} [Field α] (a : α) (v : Rat) (n : Int) (d : Nat)
|
||||
: v.num == n && v.den == d → a = ofRat v → a = (IntCast.intCast n : α) * (NatCast.natCast d : α)⁻¹ := by
|
||||
cases v; simp [ofRat]
|
||||
intros; subst d n a
|
||||
simp [Field.div_eq_mul_inv]
|
||||
|
||||
end Lean.Grind.Field.NormNum
|
||||
@@ -11,19 +11,19 @@ namespace Lean.Parser.Tactic
|
||||
|
||||
syntax anchor := "#" noWs hexnum
|
||||
|
||||
syntax grindLemma := ppGroup((Attr.grindMod ppSpace)? term)
|
||||
syntax grindLemma := ppGroup((Attr.grindMod ppSpace)? ident)
|
||||
/--
|
||||
The `!` modifier instructs `grind` to consider only minimal indexable subexpressions
|
||||
when selecting patterns.
|
||||
-/
|
||||
syntax grindLemmaMin := ppGroup("!" (Attr.grindMod ppSpace)? term)
|
||||
syntax grindLemmaMin := ppGroup("!" (Attr.grindMod ppSpace)? ident)
|
||||
|
||||
syntax grindErase := "-" ident
|
||||
/--
|
||||
The `!` modifier instructs `grind` to consider only minimal indexable subexpressions
|
||||
when selecting patterns.
|
||||
-/
|
||||
syntax grindParam := grindErase <|> grindLemmaMin <|> grindLemma <|> anchor
|
||||
syntax grindParam := grindErase <|> grindLemma <|> grindLemmaMin <|> anchor
|
||||
|
||||
namespace Grind
|
||||
declare_syntax_cat grind_filter (behavior := both)
|
||||
@@ -72,9 +72,7 @@ syntax (name := linarith) "linarith" : grind
|
||||
/-- The `sorry` tactic is a temporary placeholder for an incomplete tactic proof. -/
|
||||
syntax (name := «sorry») "sorry" : grind
|
||||
|
||||
syntax thmNs := &"namespace" ident
|
||||
|
||||
syntax thm := anchor <|> thmNs <|> grindLemmaMin <|> grindLemma
|
||||
syntax thm := anchor <|> grindLemma <|> grindLemmaMin
|
||||
|
||||
/--
|
||||
Instantiates theorems using E-matching.
|
||||
|
||||
@@ -77,16 +77,11 @@ syntax (name := grindLintMute) "#grind_lint" ppSpace &"mute" ident+ : command
|
||||
`#grind_lint skip thm₁ …` marks the given theorem(s) to be skipped entirely by `#grind_lint check`.
|
||||
Skipped theorems are neither analyzed nor reported, but may still be used for
|
||||
instantiation when analyzing other theorems.
|
||||
|
||||
`#grind_lint skip suffix name₁ …` marks all theorems with the given suffix(es) to be skipped.
|
||||
For example, `#grind_lint skip suffix foo` will skip `bar.foo`, `qux.foo`, etc.
|
||||
|
||||
Examples:
|
||||
Example:
|
||||
```
|
||||
#grind_lint skip Array.range_succ
|
||||
#grind_lint skip suffix append
|
||||
```
|
||||
-/
|
||||
syntax (name := grindLintSkip) "#grind_lint" ppSpace &"skip" (ppSpace &"suffix")? ident+ : command
|
||||
syntax (name := grindLintSkip) "#grind_lint" ppSpace &"skip" ident+ : command
|
||||
|
||||
end Lean.Grind
|
||||
|
||||
@@ -8,7 +8,6 @@ prelude
|
||||
public import Init.Data.Int.Linear
|
||||
public import Init.Grind.Ring.Field
|
||||
public import Init.Data.Rat.Lemmas
|
||||
public import Init.Grind.Ring.OfScientific
|
||||
public section
|
||||
|
||||
namespace Lean.Grind
|
||||
@@ -208,9 +207,7 @@ init_grind_norm
|
||||
Ring.intCast_mul
|
||||
Ring.intCast_pow
|
||||
Ring.intCast_sub
|
||||
-- OfScientific
|
||||
LawfulOfScientific.ofScientific_def
|
||||
-- Rationals
|
||||
Rat.zpow_neg
|
||||
Rat.ofScientific_def_eq_if Rat.zpow_neg
|
||||
|
||||
end Lean.Grind
|
||||
|
||||
@@ -236,21 +236,20 @@ instance [Ring R] [LE R] [LT R] [LawfulOrderLT R] [IsPreorder R] [OrderedRing R]
|
||||
|
||||
end Preorder
|
||||
|
||||
theorem mul_pos [LE R] [LT R] [IsPreorder R] [OrderedRing R] {a b : R} (h₁ : 0 < a) (h₂ : 0 < b) : 0 < a * b := by
|
||||
simpa [Semiring.zero_mul] using mul_lt_mul_of_pos_right h₁ h₂
|
||||
|
||||
theorem zero_le_one [LE R] [LT R] [LawfulOrderLT R] [IsPreorder R] [OrderedRing R] : (0 : R) ≤ 1 :=
|
||||
Preorder.le_of_lt zero_lt_one
|
||||
|
||||
theorem not_one_lt_zero [LE R] [LT R] [LawfulOrderLT R] [IsPreorder R] [OrderedRing R] : ¬ ((1 : R) < 0) :=
|
||||
fun h => Preorder.lt_irrefl (0 : R) (Preorder.lt_trans zero_lt_one h)
|
||||
|
||||
section PartialOrder
|
||||
|
||||
variable [LE R] [LT R] [IsPartialOrder R] [OrderedRing R]
|
||||
|
||||
theorem mul_pos {a b : R} (h₁ : 0 < a) (h₂ : 0 < b) : 0 < a * b := by
|
||||
simpa [Semiring.zero_mul] using mul_lt_mul_of_pos_right h₁ h₂
|
||||
|
||||
variable [LawfulOrderLT R]
|
||||
|
||||
theorem zero_le_one : (0 : R) ≤ 1 := Preorder.le_of_lt zero_lt_one
|
||||
|
||||
theorem not_one_lt_zero : ¬ ((1 : R) < 0) :=
|
||||
fun h => Preorder.lt_irrefl (0 : R) (Preorder.lt_trans zero_lt_one h)
|
||||
|
||||
theorem mul_le_mul_of_nonneg_left {a b c : R} (h : a ≤ b) (h' : 0 ≤ c) : c * a ≤ c * b := by
|
||||
rw [PartialOrder.le_iff_lt_or_eq] at h'
|
||||
cases h' with
|
||||
|
||||
@@ -82,10 +82,6 @@ class Semiring (α : Type u) extends Add α, Mul α where
|
||||
ofNat_succ : ∀ a : Nat, OfNat.ofNat (α := α) (a + 1) = OfNat.ofNat a + 1 := by intros; rfl
|
||||
/-- Numerals are consistently defined with respect to the canonical map from natural numbers. -/
|
||||
ofNat_eq_natCast : ∀ n : Nat, OfNat.ofNat (α := α) n = Nat.cast n := by intros; rfl
|
||||
/--
|
||||
Multiplying by a numeral is consistently defined with respect to the canonical map from natural
|
||||
numbers.
|
||||
-/
|
||||
nsmul_eq_natCast_mul : ∀ n : Nat, ∀ a : α, n • a = Nat.cast n * a := by intros; rfl
|
||||
|
||||
/--
|
||||
@@ -208,11 +204,6 @@ theorem pow_add (a : α) (k₁ k₂ : Nat) : a ^ (k₁ + k₂) = a^k₁ * a^k₂
|
||||
theorem pow_add_congr (a r : α) (k k₁ k₂ : Nat) : k = k₁ + k₂ → a^k₁ * a^k₂ = r → a ^ k = r := by
|
||||
intros; subst k r; rw [pow_add]
|
||||
|
||||
theorem one_pow (n : Nat) : (1 : α) ^ n = 1 := by
|
||||
induction n
|
||||
next => simp [pow_zero]
|
||||
next => simp [pow_succ, *, mul_one]
|
||||
|
||||
theorem natCast_pow (x : Nat) (k : Nat) : ((x ^ k : Nat) : α) = (x : α) ^ k := by
|
||||
induction k
|
||||
next => simp [pow_zero, Nat.pow_zero, natCast_one]
|
||||
@@ -385,11 +376,6 @@ variable {α : Type u} [CommSemiring α]
|
||||
theorem mul_left_comm (a b c : α) : a * (b * c) = b * (a * c) := by
|
||||
rw [← mul_assoc, ← mul_assoc, mul_comm a]
|
||||
|
||||
theorem mul_pow (a b : α) (n : Nat) : (a*b)^n = a^n * b^n := by
|
||||
induction n
|
||||
next => simp [pow_zero, mul_one]
|
||||
next n ih => simp [pow_succ, ih, mul_comm, mul_assoc, mul_left_comm]
|
||||
|
||||
end CommSemiring
|
||||
|
||||
open Semiring hiding add_comm add_assoc add_zero
|
||||
|
||||
@@ -656,29 +656,6 @@ noncomputable def Expr.toPoly_k (e : Expr) : Poly :=
|
||||
(k.beq 0))
|
||||
e
|
||||
|
||||
def Mon.degreeOf (m : Mon) (x : Var) : Nat :=
|
||||
match m with
|
||||
| .unit => 0
|
||||
| .mult pw m => bif pw.x == x then pw.k else degreeOf m x
|
||||
|
||||
def Mon.cancelVar (m : Mon) (x : Var) : Mon :=
|
||||
match m with
|
||||
| .unit => .unit
|
||||
| .mult pw m => bif pw.x == x then m else .mult pw (cancelVar m x)
|
||||
|
||||
def Poly.cancelVar' (c : Int) (x : Var) (p : Poly) (acc : Poly) : Poly :=
|
||||
match p with
|
||||
| .num k => acc.addConst k
|
||||
| .add k m p =>
|
||||
let n := m.degreeOf x
|
||||
bif n > 0 && c^n ∣ k then
|
||||
cancelVar' c x p (acc.insert (k / (c^n)) (m.cancelVar x))
|
||||
else
|
||||
cancelVar' c x p (acc.insert k m)
|
||||
|
||||
def Poly.cancelVar (c : Int) (x : Var) (p : Poly) : Poly :=
|
||||
cancelVar' c x p (.num 0)
|
||||
|
||||
@[simp] theorem Expr.toPoly_k_eq_toPoly (e : Expr) : e.toPoly_k = e.toPoly := by
|
||||
induction e <;> simp only [toPoly, toPoly_k]
|
||||
next a ih => rw [Poly.mulConst_k_eq_mulConst]; congr
|
||||
@@ -1198,72 +1175,6 @@ theorem Expr.eq_of_toPoly_nc_eq {α} [Ring α] (ctx : Context α) (a b : Expr) (
|
||||
simp [denote_toPoly_nc] at h
|
||||
assumption
|
||||
|
||||
section
|
||||
attribute [local simp] Semiring.pow_zero Semiring.mul_one Semiring.one_mul cond_eq_ite
|
||||
|
||||
theorem Mon.denote_cancelVar [CommSemiring α] (ctx : Context α) (m : Mon) (x : Var)
|
||||
: m.denote ctx = x.denote ctx ^ (m.degreeOf x) * (m.cancelVar x).denote ctx := by
|
||||
fun_induction cancelVar <;> simp [degreeOf]
|
||||
next h =>
|
||||
simp at h; simp [*, denote, Power.denote_eq]
|
||||
next h ih =>
|
||||
simp at h; simp [*, denote, Semiring.mul_assoc, CommSemiring.mul_comm, CommSemiring.mul_left_comm]
|
||||
|
||||
theorem Poly.denote_cancelVar' {α} [CommRing α] (ctx : Context α) (p : Poly) (c : Int) (x : Var) (acc : Poly)
|
||||
: c ≠ 0 → c * x.denote ctx = 1 → (p.cancelVar' c x acc).denote ctx = p.denote ctx + acc.denote ctx := by
|
||||
intro h₁ h₂
|
||||
fun_induction cancelVar'
|
||||
next acc k => simp [denote_addConst, denote, Semiring.add_comm]
|
||||
next h ih =>
|
||||
simp [ih, denote_insert, denote]
|
||||
conv => rhs; rw [Mon.denote_cancelVar (x := x)]
|
||||
simp [← Semiring.add_assoc]
|
||||
congr 1
|
||||
rw [Semiring.add_comm, Ring.zsmul_eq_intCast_mul,]
|
||||
congr 1
|
||||
simp +zetaDelta [Int.dvd_def] at h
|
||||
have ⟨d, h⟩ := h.2
|
||||
simp +zetaDelta [h]
|
||||
rw [Int.mul_ediv_cancel_left _ (Int.pow_ne_zero h₁)]
|
||||
rw [Ring.intCast_mul]
|
||||
conv => rhs; lhs; rw [CommSemiring.mul_comm]
|
||||
rw [Semiring.mul_assoc, Ring.intCast_pow]
|
||||
congr 1
|
||||
rw [← Semiring.mul_assoc, ← CommSemiring.mul_pow, h₂, Semiring.one_pow, Semiring.one_mul]
|
||||
next ih =>
|
||||
simp [ih, denote_insert, denote, Ring.zsmul_eq_intCast_mul, Semiring.add_assoc,
|
||||
Semiring.add_comm, add_left_comm]
|
||||
|
||||
theorem Poly.denote_cancelVar {α} [CommRing α] (ctx : Context α) (p : Poly) (c : Int) (x : Var)
|
||||
: c ≠ 0 → c * x.denote ctx = 1 → (p.cancelVar c x).denote ctx = p.denote ctx := by
|
||||
intro h₁ h₂
|
||||
have := denote_cancelVar' ctx p c x (.num 0) h₁ h₂
|
||||
rw [cancelVar, this, denote, Ring.intCast_zero, Semiring.add_zero]
|
||||
|
||||
noncomputable def cancel_var_cert (c : Int) (x : Var) (p₁ p₂ : Poly) : Bool :=
|
||||
c != 0 && p₂.beq' (p₁.cancelVar c x)
|
||||
|
||||
theorem eq_cancel_var {α} [CommRing α] (ctx : Context α) (c : Int) (x : Var) (p₁ p₂ : Poly)
|
||||
: cancel_var_cert c x p₁ p₂ → c * x.denote ctx = 1 → p₁.denote ctx = 0 → p₂.denote ctx = 0 := by
|
||||
simp [cancel_var_cert]; intros h₁ _ h₂ _; subst p₂
|
||||
simp [Poly.denote_cancelVar ctx p₁ c x h₁ h₂]; assumption
|
||||
|
||||
theorem diseq_cancel_var {α} [CommRing α] (ctx : Context α) (c : Int) (x : Var) (p₁ p₂ : Poly)
|
||||
: cancel_var_cert c x p₁ p₂ → c * x.denote ctx = 1 → p₁.denote ctx ≠ 0 → p₂.denote ctx ≠ 0 := by
|
||||
simp [cancel_var_cert]; intros h₁ _ h₂ _; subst p₂
|
||||
simp [Poly.denote_cancelVar ctx p₁ c x h₁ h₂]; assumption
|
||||
|
||||
theorem le_cancel_var {α} [CommRing α] [LE α] (ctx : Context α) (c : Int) (x : Var) (p₁ p₂ : Poly)
|
||||
: cancel_var_cert c x p₁ p₂ → c * x.denote ctx = 1 → p₁.denote ctx ≤ 0 → p₂.denote ctx ≤ 0 := by
|
||||
simp [cancel_var_cert]; intros h₁ _ h₂ _; subst p₂
|
||||
simp [Poly.denote_cancelVar ctx p₁ c x h₁ h₂]; assumption
|
||||
|
||||
theorem lt_cancel_var {α} [CommRing α] [LT α] (ctx : Context α) (c : Int) (x : Var) (p₁ p₂ : Poly)
|
||||
: cancel_var_cert c x p₁ p₂ → c * x.denote ctx = 1 → p₁.denote ctx < 0 → p₂.denote ctx < 0 := by
|
||||
simp [cancel_var_cert]; intros h₁ _ h₂ _; subst p₂
|
||||
simp [Poly.denote_cancelVar ctx p₁ c x h₁ h₂]; assumption
|
||||
|
||||
end
|
||||
/-!
|
||||
Theorems for justifying the procedure for commutative rings with a characteristic in `grind`.
|
||||
-/
|
||||
@@ -1482,34 +1393,15 @@ theorem simp {α} [CommRing α] (ctx : Context α) (k₁ : Int) (p₁ : Poly) (k
|
||||
noncomputable def mul_cert (p₁ : Poly) (k : Int) (p : Poly) : Bool :=
|
||||
p₁.mulConst_k k |>.beq' p
|
||||
|
||||
theorem mul {α} [CommRing α] (ctx : Context α) (p₁ : Poly) (k : Int) (p : Poly)
|
||||
def mul {α} [CommRing α] (ctx : Context α) (p₁ : Poly) (k : Int) (p : Poly)
|
||||
: mul_cert p₁ k p → p₁.denote ctx = 0 → p.denote ctx = 0 := by
|
||||
simp [mul_cert]; intro _ h; subst p
|
||||
simp [Poly.denote_mulConst, *, mul_zero]
|
||||
|
||||
theorem eq_mul {α} [CommRing α] (ctx : Context α) (p₁ : Poly) (k : Int) (p : Poly)
|
||||
: mul_cert p₁ k p → p₁.denote ctx = 0 → p.denote ctx = 0 := by
|
||||
apply mul
|
||||
|
||||
noncomputable def mul_ne_cert (p₁ : Poly) (k : Int) (p : Poly) : Bool :=
|
||||
k != 0 && (p₁.mulConst_k k |>.beq' p)
|
||||
|
||||
theorem diseq_mul {α} [CommRing α] [NoNatZeroDivisors α] (ctx : Context α) (p₁ : Poly) (k : Int) (p : Poly)
|
||||
: mul_ne_cert p₁ k p → p₁.denote ctx ≠ 0 → p.denote ctx ≠ 0 := by
|
||||
simp [mul_ne_cert]; intro h₁ _ h₂; subst p
|
||||
simp [Poly.denote_mulConst]; intro h₃
|
||||
rw [← zsmul_eq_intCast_mul] at h₃
|
||||
have := no_int_zero_divisors h₁ h₃
|
||||
contradiction
|
||||
|
||||
theorem inv {α} [CommRing α] (ctx : Context α) (p₁ : Poly) (p : Poly)
|
||||
: mul_cert p₁ (-1) p → p₁.denote ctx = 0 → p.denote ctx = 0 :=
|
||||
mul ctx p₁ (-1) p
|
||||
|
||||
noncomputable def div_cert (p₁ : Poly) (k : Int) (p : Poly) : Bool :=
|
||||
!Int.beq' k 0 |>.and' (p.mulConst_k k |>.beq' p₁)
|
||||
|
||||
theorem div {α} [CommRing α] (ctx : Context α) [NoNatZeroDivisors α] (p₁ : Poly) (k : Int) (p : Poly)
|
||||
def div {α} [CommRing α] (ctx : Context α) [NoNatZeroDivisors α] (p₁ : Poly) (k : Int) (p : Poly)
|
||||
: div_cert p₁ k p → p₁.denote ctx = 0 → p.denote ctx = 0 := by
|
||||
simp [div_cert]; intro hnz _ h; subst p₁
|
||||
simp [Poly.denote_mulConst, ← zsmul_eq_intCast_mul] at h
|
||||
@@ -1683,79 +1575,60 @@ theorem Poly.denoteAsIntModule_eq_denote {α} [CommRing α] (ctx : Context α) (
|
||||
open Stepwise
|
||||
|
||||
theorem eq_norm {α} [CommRing α] (ctx : Context α) (lhs rhs : Expr) (p : Poly)
|
||||
: core_cert lhs rhs p → lhs.denote ctx = rhs.denote ctx → p.denote ctx = 0 := by
|
||||
apply core
|
||||
|
||||
theorem eq_int_module {α} [CommRing α] (ctx : Context α) (p : Poly)
|
||||
: p.denote ctx = 0 → p.denoteAsIntModule ctx = 0 := by
|
||||
simp [Poly.denoteAsIntModule_eq_denote]
|
||||
: core_cert lhs rhs p → lhs.denote ctx = rhs.denote ctx → p.denoteAsIntModule ctx = 0 := by
|
||||
rw [Poly.denoteAsIntModule_eq_denote]; apply core
|
||||
|
||||
theorem diseq_norm {α} [CommRing α] (ctx : Context α) (lhs rhs : Expr) (p : Poly)
|
||||
: core_cert lhs rhs p → lhs.denote ctx ≠ rhs.denote ctx → p.denote ctx ≠ 0 := by
|
||||
simp [core_cert]; intro _ h; subst p; simp [Expr.denote_toPoly, Expr.denote]
|
||||
: core_cert lhs rhs p → lhs.denote ctx ≠ rhs.denote ctx → p.denoteAsIntModule ctx ≠ 0 := by
|
||||
simp [core_cert, Poly.denoteAsIntModule_eq_denote]; intro _ h; subst p; simp [Expr.denote_toPoly, Expr.denote]
|
||||
intro h; rw [sub_eq_zero_iff] at h; contradiction
|
||||
|
||||
theorem diseq_int_module {α} [CommRing α] (ctx : Context α) (p : Poly)
|
||||
: p.denote ctx ≠ 0 → p.denoteAsIntModule ctx ≠ 0 := by
|
||||
simp [Poly.denoteAsIntModule_eq_denote]
|
||||
|
||||
open OrderedAdd
|
||||
|
||||
theorem le_norm {α} [CommRing α] [LE α] [LT α] [IsPreorder α] [OrderedRing α] (ctx : Context α) (lhs rhs : Expr) (p : Poly)
|
||||
: core_cert lhs rhs p → lhs.denote ctx ≤ rhs.denote ctx → p.denote ctx ≤ 0 := by
|
||||
simp [core_cert]; intro _ h; subst p; simp [Expr.denote_toPoly, Expr.denote]
|
||||
: core_cert lhs rhs p → lhs.denote ctx ≤ rhs.denote ctx → p.denoteAsIntModule ctx ≤ 0 := by
|
||||
simp [core_cert, Poly.denoteAsIntModule_eq_denote]; intro _ h; subst p; simp [Expr.denote_toPoly, Expr.denote]
|
||||
replace h := add_le_left h ((-1) * rhs.denote ctx)
|
||||
rw [neg_mul, ← sub_eq_add_neg, one_mul, ← sub_eq_add_neg, sub_self] at h
|
||||
assumption
|
||||
|
||||
theorem le_int_module {α} [CommRing α] [LE α] (ctx : Context α) (p : Poly)
|
||||
: p.denote ctx ≤ 0 → p.denoteAsIntModule ctx ≤ 0 := by
|
||||
simp [Poly.denoteAsIntModule_eq_denote]
|
||||
|
||||
noncomputable def mul_ineq_cert (p₁ : Poly) (k : Int) (p : Poly) : Bool :=
|
||||
k > 0 && (p₁.mulConst_k k |>.beq' p)
|
||||
|
||||
theorem le_mul {α} [CommRing α] [LE α] [LT α] [IsPreorder α] [OrderedRing α] (ctx : Context α) (p₁ : Poly) (k : Int) (p : Poly)
|
||||
: mul_ineq_cert p₁ k p → p₁.denote ctx ≤ 0 → p.denote ctx ≤ 0 := by
|
||||
simp [mul_ineq_cert]; intro h₁ _ h₂; subst p; simp [Poly.denote_mulConst]
|
||||
replace h₂ := zsmul_nonpos (Int.le_of_lt h₁) h₂
|
||||
simp [Ring.zsmul_eq_intCast_mul] at h₂
|
||||
assumption
|
||||
|
||||
theorem lt_norm {α} [CommRing α] [LE α] [LT α] [LawfulOrderLT α] [IsPreorder α] [OrderedRing α] (ctx : Context α) (lhs rhs : Expr) (p : Poly)
|
||||
: core_cert lhs rhs p → lhs.denote ctx < rhs.denote ctx → p.denote ctx < 0 := by
|
||||
simp [core_cert]; intro _ h; subst p; simp [Expr.denote_toPoly, Expr.denote]
|
||||
: core_cert lhs rhs p → lhs.denote ctx < rhs.denote ctx → p.denoteAsIntModule ctx < 0 := by
|
||||
simp [core_cert, Poly.denoteAsIntModule_eq_denote]; intro _ h; subst p; simp [Expr.denote_toPoly, Expr.denote]
|
||||
replace h := add_lt_left h ((-1) * rhs.denote ctx)
|
||||
rw [neg_mul, ← sub_eq_add_neg, one_mul, ← sub_eq_add_neg, sub_self] at h
|
||||
assumption
|
||||
|
||||
theorem lt_int_module {α} [CommRing α] [LT α] (ctx : Context α) (p : Poly)
|
||||
: p.denote ctx < 0 → p.denoteAsIntModule ctx < 0 := by
|
||||
simp [Poly.denoteAsIntModule_eq_denote]
|
||||
|
||||
theorem lt_mul {α} [CommRing α] [LE α] [LT α] [LawfulOrderLT α] [IsPreorder α] [OrderedRing α] (ctx : Context α) (p₁ : Poly) (k : Int) (p : Poly)
|
||||
: mul_ineq_cert p₁ k p → p₁.denote ctx < 0 → p.denote ctx < 0 := by
|
||||
simp [mul_ineq_cert]; intro h₁ _ h₂; subst p; simp [Poly.denote_mulConst]
|
||||
replace h₂ := zsmul_neg_iff k h₂ |>.mpr h₁
|
||||
simp [Ring.zsmul_eq_intCast_mul] at h₂
|
||||
assumption
|
||||
|
||||
theorem not_le_norm {α} [CommRing α] [LE α] [LT α] [LawfulOrderLT α] [IsLinearOrder α] [OrderedRing α] (ctx : Context α) (lhs rhs : Expr) (p : Poly)
|
||||
: core_cert rhs lhs p → ¬ lhs.denote ctx ≤ rhs.denote ctx → p.denote ctx < 0 := by
|
||||
simp [core_cert]; intro _ h₁; subst p; simp [Expr.denote_toPoly, Expr.denote]
|
||||
: core_cert rhs lhs p → ¬ lhs.denote ctx ≤ rhs.denote ctx → p.denoteAsIntModule ctx < 0 := by
|
||||
simp [core_cert, Poly.denoteAsIntModule_eq_denote]; intro _ h₁; subst p; simp [Expr.denote_toPoly, Expr.denote]
|
||||
replace h₁ := LinearOrder.lt_of_not_le h₁
|
||||
replace h₁ := add_lt_left h₁ (-lhs.denote ctx)
|
||||
simp [← sub_eq_add_neg, sub_self] at h₁
|
||||
assumption
|
||||
|
||||
theorem not_lt_norm {α} [CommRing α] [LE α] [LT α] [LawfulOrderLT α] [IsLinearOrder α] [OrderedRing α] (ctx : Context α) (lhs rhs : Expr) (p : Poly)
|
||||
: core_cert rhs lhs p → ¬ lhs.denote ctx < rhs.denote ctx → p.denote ctx ≤ 0 := by
|
||||
simp [core_cert]; intro _ h₁; subst p; simp [Expr.denote_toPoly, Expr.denote]
|
||||
: core_cert rhs lhs p → ¬ lhs.denote ctx < rhs.denote ctx → p.denoteAsIntModule ctx ≤ 0 := by
|
||||
simp [core_cert, Poly.denoteAsIntModule_eq_denote]; intro _ h₁; subst p; simp [Expr.denote_toPoly, Expr.denote]
|
||||
replace h₁ := LinearOrder.le_of_not_lt h₁
|
||||
replace h₁ := add_le_left h₁ (-lhs.denote ctx)
|
||||
simp [← sub_eq_add_neg, sub_self] at h₁
|
||||
assumption
|
||||
|
||||
theorem not_le_norm' {α} [CommRing α] [LE α] [LT α] [IsPreorder α] [OrderedRing α] (ctx : Context α) (lhs rhs : Expr) (p : Poly)
|
||||
: core_cert lhs rhs p → ¬ lhs.denote ctx ≤ rhs.denote ctx → ¬ p.denoteAsIntModule ctx ≤ 0 := by
|
||||
simp [core_cert, Poly.denoteAsIntModule_eq_denote]; intro _ h₁; subst p; simp [Expr.denote_toPoly, Expr.denote]; intro h
|
||||
replace h : rhs.denote ctx + (lhs.denote ctx - rhs.denote ctx) ≤ _ := add_le_right (rhs.denote ctx) h
|
||||
rw [sub_eq_add_neg, add_left_comm, ← sub_eq_add_neg, sub_self] at h; simp [add_zero] at h
|
||||
contradiction
|
||||
|
||||
theorem not_lt_norm' {α} [CommRing α] [LE α] [LT α] [LawfulOrderLT α] [IsPreorder α] [OrderedRing α] (ctx : Context α) (lhs rhs : Expr) (p : Poly)
|
||||
: core_cert lhs rhs p → ¬ lhs.denote ctx < rhs.denote ctx → ¬ p.denoteAsIntModule ctx < 0 := by
|
||||
simp [core_cert, Poly.denoteAsIntModule_eq_denote]; intro _ h₁; subst p; simp [Expr.denote_toPoly, Expr.denote]; intro h
|
||||
replace h : rhs.denote ctx + (lhs.denote ctx - rhs.denote ctx) < _ := add_lt_right (rhs.denote ctx) h
|
||||
rw [sub_eq_add_neg, add_left_comm, ← sub_eq_add_neg, sub_self] at h; simp [add_zero] at h
|
||||
contradiction
|
||||
|
||||
theorem inv_int_eq [Field α] [IsCharP α 0] (b : Int) : b != 0 → (denoteInt b : α) * (denoteInt b)⁻¹ = 1 := by
|
||||
simp; intro h
|
||||
have : (denoteInt b : α) ≠ 0 := by
|
||||
@@ -1763,13 +1636,6 @@ theorem inv_int_eq [Field α] [IsCharP α 0] (b : Int) : b != 0 → (denoteInt b
|
||||
have := IsCharP.intCast_eq_zero_iff (α := α) 0 b; simp [*] at this
|
||||
rw [Field.mul_inv_cancel this]
|
||||
|
||||
theorem intCast_eq_denoteInt [Field α] (b : Int) : (IntCast.intCast b : α) = denoteInt b := by
|
||||
simp [denoteInt_eq]
|
||||
|
||||
theorem inv_int_eq' [Field α] [IsCharP α 0] (b : Int) : b != 0 → (IntCast.intCast b : α) * (denoteInt b)⁻¹ = 1 := by
|
||||
rw [intCast_eq_denoteInt]
|
||||
apply inv_int_eq
|
||||
|
||||
theorem inv_int_eqC {α c} [Field α] [IsCharP α c] (b : Int) : b % c != 0 → (denoteInt b : α) * (denoteInt b)⁻¹ = 1 := by
|
||||
simp; intro h
|
||||
have : (denoteInt b : α) ≠ 0 := by
|
||||
|
||||
@@ -16,7 +16,6 @@ namespace Lean.Grind
|
||||
A field is a commutative ring with inverses for all non-zero elements.
|
||||
-/
|
||||
class Field (α : Type u) extends CommRing α, Inv α, Div α where
|
||||
/-- An exponentiation operator. -/
|
||||
[zpow : HPow α Int α]
|
||||
/-- Division is multiplication by the inverse. -/
|
||||
div_eq_mul_inv : ∀ a b : α, a / b = a * b⁻¹
|
||||
@@ -95,7 +94,7 @@ theorem inv_eq_zero_iff {a : α} : a⁻¹ = 0 ↔ a = 0 := by
|
||||
theorem zero_eq_inv_iff {a : α} : 0 = a⁻¹ ↔ 0 = a := by
|
||||
rw [eq_comm, inv_eq_zero_iff, eq_comm]
|
||||
|
||||
theorem of_mul_eq_zero {a b : α} : a * b = 0 → a = 0 ∨ b = 0 := by
|
||||
theorem of_mul_eq_zero {a b : α} : a*b = 0 → a = 0 ∨ b = 0 := by
|
||||
cases (Classical.em (a = 0)); · simp [*, Semiring.zero_mul]
|
||||
cases (Classical.em (b = 0)); · simp [*, Semiring.mul_zero]
|
||||
rename_i h₁ h₂
|
||||
@@ -170,52 +169,6 @@ theorem zpow_add {a : α} (h : a ≠ 0) (m n : Int) : a ^ (m + n) = a ^ m * a ^
|
||||
| zero => simp [Int.add_neg_one, zpow_sub_one h, zpow_neg_one]
|
||||
| succ n ih => rw [Int.natCast_add_one, Int.neg_add, Int.add_neg_one, ← Int.add_sub_assoc, zpow_sub_one h, zpow_sub_one h, ih, Semiring.mul_assoc]
|
||||
|
||||
theorem div_zero {x : α} : x / 0 = 0 := by rw [div_eq_mul_inv, inv_zero, Semiring.mul_zero]
|
||||
|
||||
theorem mul_div {x y z : α} : x * (y / z) = (x * y) / z := by
|
||||
rw [div_eq_mul_inv, div_eq_mul_inv, Semiring.mul_assoc]
|
||||
theorem div_mul {x y z : α} : x / y * z = x * z / y := by
|
||||
rw [div_eq_mul_inv, div_eq_mul_inv, Semiring.mul_assoc, CommSemiring.mul_comm y⁻¹,
|
||||
Semiring.mul_assoc]
|
||||
theorem div_add {x y z : α} (hy : y ≠ 0) : x / y + z = (x + y * z) / y := by
|
||||
rw [div_eq_mul_inv, div_eq_mul_inv, Semiring.right_distrib, CommSemiring.mul_comm y,
|
||||
Semiring.mul_assoc, Field.mul_inv_cancel hy, Semiring.mul_one]
|
||||
theorem add_div {x y z : α} (hz : z ≠ 0) : x + y / z = (x * z + y) / z := by
|
||||
rw [div_eq_mul_inv, div_eq_mul_inv, Semiring.right_distrib, Semiring.mul_assoc,
|
||||
Field.mul_inv_cancel hz, Semiring.mul_one]
|
||||
|
||||
theorem div_div_right {x y z : α} : x / (y / z) = x * z / y := by
|
||||
rw [div_eq_mul_inv, div_eq_mul_inv, div_eq_mul_inv, inv_mul, inv_inv, CommSemiring.mul_comm y⁻¹,
|
||||
Semiring.mul_assoc]
|
||||
theorem div_div_left {x y z : α} : (x / y) / z = x / (y * z) := by
|
||||
rw [div_eq_mul_inv, div_eq_mul_inv, div_eq_mul_inv, inv_mul, Semiring.mul_assoc]
|
||||
theorem div_mul_cancel {x y : α} (h : y ≠ 0) : x / y * y = x := by
|
||||
rw [div_eq_mul_inv, Semiring.mul_assoc, Field.inv_mul_cancel h, Semiring.mul_one]
|
||||
|
||||
attribute [local instance] Semiring.natCast in
|
||||
theorem natCast_ne_zero [IsCharP α 0] {n : Nat} (h : n ≠ 0) : (n : α) ≠ 0 := by
|
||||
simpa [IsCharP.natCast_eq_zero_iff]
|
||||
|
||||
attribute [local instance] Ring.intCast in
|
||||
theorem intCast_div_of_dvd {x y : Int} (h : y ∣ x) (w : (y : α) ≠ 0) :
|
||||
((x / y : Int) : α) = ((x : α) / (y : α)) := by
|
||||
obtain ⟨z, rfl⟩ := h
|
||||
by_cases hy : y = 0
|
||||
· simp_all [Ring.intCast_zero]
|
||||
· rw [Int.mul_ediv_cancel_left _ hy]
|
||||
rw [Ring.intCast_mul, CommSemiring.mul_comm, div_eq_mul_inv, Semiring.mul_assoc,
|
||||
mul_inv_cancel w, Semiring.mul_one]
|
||||
|
||||
attribute [local instance] Semiring.natCast in
|
||||
theorem natCast_div_of_dvd {x y : Nat} (h : y ∣ x) (w : (y : α) ≠ 0) :
|
||||
((x / y : Nat) : α) = ((x : α) / (y : α)) := by
|
||||
obtain ⟨z, rfl⟩ := h
|
||||
by_cases hy : y = 0
|
||||
· simp_all [Semiring.natCast_zero]
|
||||
· rw [Nat.mul_div_cancel_left _ (by omega)]
|
||||
rw [Semiring.natCast_mul, CommSemiring.mul_comm, div_eq_mul_inv, Semiring.mul_assoc,
|
||||
mul_inv_cancel w, Semiring.mul_one]
|
||||
|
||||
-- This is expensive as an instance. Let's see what breaks without it.
|
||||
def noNatZeroDivisors.ofIsCharPZero [IsCharP α 0] : NoNatZeroDivisors α := NoNatZeroDivisors.mk' <| by
|
||||
intro a b h w
|
||||
|
||||
@@ -299,19 +299,9 @@ syntax (name := grindTrace)
|
||||
|
||||
It is a implemented as a thin wrapper around the `grind` tactic, enabling only the `cutsat` solver.
|
||||
Please use `grind` instead if you need additional capabilities.
|
||||
|
||||
**Deprecated**: Use `lia` instead.
|
||||
-/
|
||||
syntax (name := cutsat) "cutsat" optConfig : tactic
|
||||
|
||||
/--
|
||||
`lia` solves linear integer arithmetic goals.
|
||||
|
||||
It is a implemented as a thin wrapper around the `grind` tactic, enabling only the `cutsat` solver.
|
||||
Please use `grind` instead if you need additional capabilities.
|
||||
-/
|
||||
syntax (name := lia) "lia" optConfig : tactic
|
||||
|
||||
/--
|
||||
`grobner` solves goals that can be phrased as polynomial equations (with further polynomial equations as hypotheses)
|
||||
over commutative (semi)rings, using the Grobner basis algorithm.
|
||||
|
||||
@@ -108,7 +108,7 @@ instance : ToInt (Fin n) (.co 0 n) where
|
||||
toInt_inj x y w := Fin.eq_of_val_eq (Int.ofNat_inj.mp w)
|
||||
toInt_mem := by simp
|
||||
|
||||
@[simp, grind =] theorem toInt_fin (x : Fin n) : ToInt.toInt x = (x.val : Int) := rfl
|
||||
@[simp] theorem toInt_fin (x : Fin n) : ToInt.toInt x = (x.val : Int) := rfl
|
||||
|
||||
instance [NeZero n] : ToInt.Zero (Fin n) (.co 0 n) where
|
||||
toInt_zero := rfl
|
||||
@@ -116,9 +116,6 @@ instance [NeZero n] : ToInt.Zero (Fin n) (.co 0 n) where
|
||||
instance [NeZero n] : ToInt.OfNat (Fin n) (.co 0 n) where
|
||||
toInt_ofNat x := by simp; rfl
|
||||
|
||||
theorem ofNat_FinZero (n : Nat) [NeZero n] : ToInt.toInt (OfNat.ofNat 0 : Fin n) = 0 := by
|
||||
rw [ToInt.toInt, instToIntFinCoOfNatIntCast, Fin.instOfNat, Fin.ofNat]; simp
|
||||
|
||||
instance : ToInt.Add (Fin n) (.co 0 n) where
|
||||
toInt_add x y := by rfl
|
||||
|
||||
|
||||
@@ -631,8 +631,6 @@ structure Subtype {α : Sort u} (p : α → Prop) where
|
||||
-/
|
||||
property : p val
|
||||
|
||||
grind_pattern Subtype.property => self.val
|
||||
|
||||
set_option linter.unusedVariables.funArgs false in
|
||||
/--
|
||||
Gadget for optional parameter support.
|
||||
@@ -2264,7 +2262,6 @@ structure Fin (n : Nat) where
|
||||
isLt : LT.lt val n
|
||||
|
||||
attribute [coe] Fin.val
|
||||
grind_pattern Fin.isLt => self.val
|
||||
|
||||
theorem Fin.eq_of_val_eq {n} : ∀ {i j : Fin n}, Eq i.val j.val → Eq i j
|
||||
| ⟨_, _⟩, ⟨_, _⟩, rfl => rfl
|
||||
@@ -2923,40 +2920,7 @@ protected def List.hasDecEq {α : Type u} [DecidableEq α] : (a b : List α) →
|
||||
| isFalse nabs => isFalse (fun h => List.noConfusion h (fun _ habs => absurd habs nabs))
|
||||
| isFalse nab => isFalse (fun h => List.noConfusion h (fun hab _ => absurd hab nab))
|
||||
|
||||
instance {α : Type u} [DecidableEq α] : DecidableEq (List α) := fun xs ys =>
|
||||
/-
|
||||
The first match step is expanded to make this instance
|
||||
maximally-definitionally-equivalent to the compare-with-empty-list cases.
|
||||
-/
|
||||
match xs with
|
||||
| .nil => match ys with
|
||||
| .nil => isTrue rfl
|
||||
| .cons _ _ => isFalse List.noConfusion
|
||||
| .cons a as => match ys with
|
||||
| .nil => isFalse List.noConfusion
|
||||
| .cons b bs =>
|
||||
match decEq a b with
|
||||
| isTrue hab =>
|
||||
match List.hasDecEq as bs with
|
||||
| isTrue habs => isTrue (hab ▸ habs ▸ rfl)
|
||||
| isFalse nabs => isFalse (List.noConfusion · (fun _ habs => absurd habs nabs))
|
||||
| isFalse nab => isFalse (List.noConfusion · (fun hab _ => absurd hab nab))
|
||||
|
||||
/--
|
||||
Equality with `List.nil` is decidable even if the underlying type does not have decidable equality.
|
||||
-/
|
||||
instance List.instDecidableNilEq (a : List α) : Decidable (Eq List.nil a) :=
|
||||
match a with
|
||||
| .nil => isTrue rfl
|
||||
| .cons _ _ => isFalse List.noConfusion
|
||||
|
||||
/--
|
||||
Equality with `List.nil` is decidable even if the underlying type does not have decidable equality.
|
||||
-/
|
||||
instance List.instDecidableEqNil (a : List α) : Decidable (Eq a List.nil) :=
|
||||
match a with
|
||||
| .nil => isTrue rfl
|
||||
| .cons _ _ => isFalse List.noConfusion
|
||||
instance {α : Type u} [DecidableEq α] : DecidableEq (List α) := List.hasDecEq
|
||||
|
||||
/--
|
||||
The length of a list.
|
||||
@@ -3449,11 +3413,11 @@ structure String where ofByteArray ::
|
||||
/-- The bytes of the UTF-8 encoding of the string. Since strings have a special representation in
|
||||
the runtime, this function actually takes linear time and space at runtime. For efficient access
|
||||
to the string's bytes, use `String.utf8ByteSize` and `String.getUTF8Byte`. -/
|
||||
toByteArray : ByteArray
|
||||
bytes : ByteArray
|
||||
/-- The bytes of the string form valid UTF-8. -/
|
||||
isValidUTF8 : ByteArray.IsValidUTF8 toByteArray
|
||||
isValidUTF8 : ByteArray.IsValidUTF8 bytes
|
||||
|
||||
attribute [extern "lean_string_to_utf8"] String.toByteArray
|
||||
attribute [extern "lean_string_to_utf8"] String.bytes
|
||||
attribute [extern "lean_string_from_utf8_unchecked"] String.ofByteArray
|
||||
|
||||
/--
|
||||
@@ -3468,7 +3432,7 @@ def String.decEq (s₁ s₂ : @& String) : Decidable (Eq s₁ s₂) :=
|
||||
| ⟨⟨⟨s₁⟩⟩, _⟩, ⟨⟨⟨s₂⟩⟩, _⟩ =>
|
||||
dite (Eq s₁ s₂) (fun h => match s₁, s₂, h with | _, _, Eq.refl _ => isTrue rfl)
|
||||
(fun h => isFalse
|
||||
(fun h' => h (congrArg (fun s => Array.toList (ByteArray.data (String.toByteArray s))) h')))
|
||||
(fun h' => h (congrArg (fun s => Array.toList (ByteArray.data (String.bytes s))) h')))
|
||||
|
||||
instance : DecidableEq String := String.decEq
|
||||
|
||||
@@ -3482,7 +3446,7 @@ be translated internally to byte positions, which takes linear time.
|
||||
A byte position `p` is *valid* for a string `s` if `0 ≤ p ≤ s.rawEndPos` and `p` lies on a UTF-8
|
||||
character boundary, see `String.Pos.IsValid`.
|
||||
|
||||
There is another type, `String.Pos`, which bundles the validity predicate. Using `String.Pos`
|
||||
There is another type, `String.ValidPos`, which bundles the validity predicate. Using `String.ValidPos`
|
||||
instead of `String.Pos.Raw` is recommended because it will lead to less error handling and fewer edge cases.
|
||||
-/
|
||||
structure String.Pos.Raw where
|
||||
@@ -3534,7 +3498,7 @@ At runtime, this function takes constant time because the byte length of strings
|
||||
-/
|
||||
@[extern "lean_string_utf8_byte_size"]
|
||||
def String.utf8ByteSize (s : @& String) : Nat :=
|
||||
s.toByteArray.size
|
||||
s.bytes.size
|
||||
|
||||
/--
|
||||
A UTF-8 byte position that points at the end of a string, just after the last character.
|
||||
|
||||
@@ -8,7 +8,6 @@ module
|
||||
prelude
|
||||
public import Init.Data.String.Basic
|
||||
import Init.Data.String.Modify
|
||||
import Init.Data.String.Search
|
||||
|
||||
public section
|
||||
|
||||
@@ -93,7 +92,7 @@ An absolute path starts at the root directory or a drive letter. Accessing files
|
||||
path does not depend on the current working directory.
|
||||
-/
|
||||
def isAbsolute (p : FilePath) : Bool :=
|
||||
pathSeparators.contains p.toString.front || (isWindows && p.toString.length > 1 && p.toString.startPos.next?.bind (·.get?) == some ':')
|
||||
pathSeparators.contains p.toString.front || (isWindows && p.toString.length > 1 && p.toString.startValidPos.next?.bind (·.get?) == some ':')
|
||||
|
||||
/--
|
||||
A relative path is one that depends on the current working directory for interpretation. Relative
|
||||
@@ -122,7 +121,7 @@ instance : HDiv FilePath String FilePath where
|
||||
hDiv p sub := FilePath.join p ⟨sub⟩
|
||||
|
||||
private def posOfLastSep (p : FilePath) : Option String.Pos.Raw :=
|
||||
p.toString.revFind? pathSeparators.contains |>.map String.Pos.offset
|
||||
p.toString.revFind pathSeparators.contains
|
||||
|
||||
/--
|
||||
Returns the parent directory of a path, if there is one.
|
||||
@@ -173,7 +172,7 @@ Examples:
|
||||
-/
|
||||
def fileStem (p : FilePath) : Option String :=
|
||||
p.fileName.map fun fname =>
|
||||
match fname.revFind? '.' |>.map String.Pos.offset with
|
||||
match fname.revPosOf '.' with
|
||||
| some ⟨0⟩ => fname
|
||||
| some pos => String.Pos.Raw.extract fname 0 pos
|
||||
| none => fname
|
||||
@@ -192,7 +191,7 @@ Examples:
|
||||
-/
|
||||
def extension (p : FilePath) : Option String :=
|
||||
p.fileName.bind fun fname =>
|
||||
match fname.revFind? '.' |>.map String.Pos.offset with
|
||||
match fname.revPosOf '.' with
|
||||
| some 0 => none
|
||||
| some pos => some <| String.Pos.Raw.extract fname (pos + '.') fname.rawEndPos
|
||||
| none => none
|
||||
@@ -243,7 +242,7 @@ def withExtension (p : FilePath) (ext : String) : FilePath :=
|
||||
Splits a path into a list of individual file names at the platform-specific path separator.
|
||||
-/
|
||||
def components (p : FilePath) : List String :=
|
||||
p.normalize |>.toString.split pathSeparator.toString |>.toStringList
|
||||
p.normalize |>.toString.splitOn pathSeparator.toString
|
||||
|
||||
end FilePath
|
||||
|
||||
@@ -274,7 +273,7 @@ Separates the entries in the `$PATH` (or `%PATH%`) environment variable by the c
|
||||
platform-dependent separator character.
|
||||
-/
|
||||
def parse (s : String) : SearchPath :=
|
||||
s.split SearchPath.separator |>.map (FilePath.mk ∘ String.Slice.copy) |>.toList
|
||||
s.splitToList (fun c => SearchPath.separator == c) |>.map FilePath.mk
|
||||
|
||||
/--
|
||||
Joins a list of paths into a suitable value for the current platform's `$PATH` (or `%PATH%`)
|
||||
|
||||
@@ -10,7 +10,6 @@ public import Init.System.IOError
|
||||
public import Init.System.FilePath
|
||||
public import Init.Data.Ord.UInt
|
||||
import Init.Data.String.TakeDrop
|
||||
import Init.Data.String.Search
|
||||
|
||||
public section
|
||||
|
||||
@@ -565,20 +564,9 @@ Waits until any of the tasks in the list has finished, then return its result.
|
||||
(h : tasks.length > 0 := by exact Nat.zero_lt_succ _) : BaseIO α :=
|
||||
return tasks[0].get
|
||||
|
||||
/--
|
||||
Given a non-empty list of tasks, wait for the first to complete.
|
||||
Return the value and the list of remaining tasks.
|
||||
-/
|
||||
def waitAny' (tasks : List (Task α)) (h : 0 < tasks.length := by exact Nat.zero_lt_succ _) :
|
||||
BaseIO (α × List (Task α)) := do
|
||||
let (i, a) ← IO.waitAny
|
||||
(tasks.mapIdx fun i t => t.map (sync := true) fun a => (i, a))
|
||||
(by simp_all)
|
||||
return (a, tasks.eraseIdx i)
|
||||
|
||||
/--
|
||||
Returns the number of _heartbeats_ that have occurred during the current thread's execution. The
|
||||
heartbeat count is the number of "small" memory allocations performed in a thread.
|
||||
heartbeat count is the number of “small” memory allocations performed in a thread.
|
||||
|
||||
Heartbeats used to implement timeouts that are more deterministic across different hardware.
|
||||
-/
|
||||
|
||||
@@ -9,7 +9,6 @@ prelude
|
||||
public import Init.System.FilePath
|
||||
import Init.Data.String.TakeDrop
|
||||
import Init.Data.String.Modify
|
||||
import Init.Data.String.Search
|
||||
|
||||
public section
|
||||
|
||||
|
||||
@@ -55,9 +55,6 @@ syntax (name := tryTrace) "try?" optConfig : tactic
|
||||
/-- Helper internal tactic for implementing the tactic `try?`. -/
|
||||
syntax (name := attemptAll) "attempt_all " withPosition((ppDedent(ppLine) colGe "| " tacticSeq)+) : tactic
|
||||
|
||||
/-- Helper internal tactic for implementing the tactic `try?` with parallel execution. -/
|
||||
syntax (name := attemptAllPar) "attempt_all_par " withPosition((ppDedent(ppLine) colGe "| " tacticSeq)+) : tactic
|
||||
|
||||
/-- Helper internal tactic used to implement `evalSuggest` in `try?` -/
|
||||
syntax (name := tryResult) "try_suggestions " tactic* : tactic
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ partial def Loop.forIn {β : Type u} {m : Type u → Type v} [Monad m] (_ : Loop
|
||||
| ForInStep.yield b => loop b
|
||||
loop init
|
||||
|
||||
instance [Monad m] : ForIn m Loop Unit where
|
||||
instance : ForIn m Loop Unit where
|
||||
forIn := Loop.forIn
|
||||
|
||||
syntax "repeat " doSeq : doElem
|
||||
|
||||
@@ -76,7 +76,7 @@ builtin_initialize externAttr : ParametricAttribute ExternAttrData ←
|
||||
def getExternAttrData? (env : Environment) (n : Name) : Option ExternAttrData :=
|
||||
externAttr.getParam? env n
|
||||
|
||||
private def parseOptNum : Nat → (pattern : String) → (it : pattern.Pos) → Nat → pattern.Pos × Nat
|
||||
private def parseOptNum : Nat → (pattern : String) → (it : pattern.ValidPos) → Nat → pattern.ValidPos × Nat
|
||||
| 0, _ , it, r => (it, r)
|
||||
| n+1, pattern, it, r =>
|
||||
if h : it.IsAtEnd then (it, r)
|
||||
@@ -86,7 +86,7 @@ private def parseOptNum : Nat → (pattern : String) → (it : pattern.Pos) →
|
||||
then parseOptNum n pattern (it.next h) (r*10 + (c.toNat - '0'.toNat))
|
||||
else (it, r)
|
||||
|
||||
def expandExternPatternAux (args : List String) : Nat → (pattern : String) → (it : pattern.Pos) → String → String
|
||||
def expandExternPatternAux (args : List String) : Nat → (pattern : String) → (it : pattern.ValidPos) → String → String
|
||||
| 0, _, _, r => r
|
||||
| i+1, pattern, it, r =>
|
||||
if h : it.IsAtEnd then r
|
||||
@@ -99,7 +99,7 @@ def expandExternPatternAux (args : List String) : Nat → (pattern : String) →
|
||||
expandExternPatternAux args i pattern it (r ++ args.getD j "")
|
||||
|
||||
def expandExternPattern (pattern : String) (args : List String) : String :=
|
||||
expandExternPatternAux args pattern.length pattern pattern.startPos ""
|
||||
expandExternPatternAux args pattern.length pattern pattern.startValidPos ""
|
||||
|
||||
def mkSimpleFnCall (fn : String) (args : List String) : String :=
|
||||
fn ++ "(" ++ ((args.intersperse ", ").foldl (·++·) "") ++ ")"
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user