mirror of
https://github.com/leanprover/lean4.git
synced 2026-03-31 09:14:11 +00:00
Compare commits
117 Commits
hbv/select
...
grind_patt
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6b9e5e111b | ||
|
|
244d1080af | ||
|
|
e7bc38a6c1 | ||
|
|
28e6556682 | ||
|
|
e7d1cdd36a | ||
|
|
dfcb5bb3a8 | ||
|
|
01ed345643 | ||
|
|
176fb1cf0e | ||
|
|
6b387da032 | ||
|
|
c3667e2861 | ||
|
|
33266b23cd | ||
|
|
a4a2bfa426 | ||
|
|
b7520e7232 | ||
|
|
0b84c3912e | ||
|
|
e96467f500 | ||
|
|
bdab63048a | ||
|
|
30a041902b | ||
|
|
fbcad8f593 | ||
|
|
0a6bd5c0c6 | ||
|
|
de2e935f30 | ||
|
|
57bce526f9 | ||
|
|
b136906939 | ||
|
|
f4c7a0d25c | ||
|
|
3e2124bb48 | ||
|
|
fc6a6cc4e2 | ||
|
|
bb61a2d481 | ||
|
|
2d8de4235d | ||
|
|
a0ecff4610 | ||
|
|
923c3d10a2 | ||
|
|
ac4c752608 | ||
|
|
4d2576362b | ||
|
|
f6a2c6d07c | ||
|
|
1a203c7fe5 | ||
|
|
e75e6fbe9e | ||
|
|
d98b626633 | ||
|
|
fd0177afe3 | ||
|
|
757426b099 | ||
|
|
b81ea5ee9c | ||
|
|
c75d37f76b | ||
|
|
dd87739fc2 | ||
|
|
01e6928da0 | ||
|
|
e36d1925f1 | ||
|
|
f9b2e550bb | ||
|
|
ed99ad63f3 | ||
|
|
eb337b820f | ||
|
|
1dc72b1880 | ||
|
|
e86ab1b1db | ||
|
|
c34ea82bc2 | ||
|
|
79051fb5c0 | ||
|
|
81fe3b6d05 | ||
|
|
05d6b8648c | ||
|
|
5c03ab9630 | ||
|
|
3e24d5dee8 | ||
|
|
4a73532fbe | ||
|
|
f6cf54fb2f | ||
|
|
058f6008c0 | ||
|
|
ab30577acb | ||
|
|
be1e090833 | ||
|
|
6a8d7cc17c | ||
|
|
13795fb3ad | ||
|
|
612c7588d0 | ||
|
|
d70b619500 | ||
|
|
9402c307fe | ||
|
|
1ab115648d | ||
|
|
aa0a31ae7d | ||
|
|
19bd0254c3 | ||
|
|
0b3550f284 | ||
|
|
5463e10ce4 | ||
|
|
8fd8821b61 | ||
|
|
975b6e758f | ||
|
|
a31eb94e5a | ||
|
|
652868c308 | ||
|
|
0d28e450c2 | ||
|
|
a872cec0a7 | ||
|
|
2ff41f43be | ||
|
|
52a9fe3b67 | ||
|
|
316ff35afd | ||
|
|
aaa0cf3cf6 | ||
|
|
8b09366c78 | ||
|
|
5f75c55191 | ||
|
|
752b53e936 | ||
|
|
3f671cca92 | ||
|
|
8735447d44 | ||
|
|
1861cc6bbc | ||
|
|
974c649e2e | ||
|
|
184f716da1 | ||
|
|
3f7f1c87f6 | ||
|
|
7ba0ae1f72 | ||
|
|
9923a8d9f8 | ||
|
|
de38a16fa9 | ||
|
|
c0238e396c | ||
|
|
c7cc398935 | ||
|
|
849bb770fd | ||
|
|
6cefbc4bb0 | ||
|
|
9b6a4a7588 | ||
|
|
47787dc1cb | ||
|
|
25ab3dd93d | ||
|
|
bbd45b13f4 | ||
|
|
85f168bbd0 | ||
|
|
89aed0931e | ||
|
|
92d24e1c40 | ||
|
|
c15ee8a9f0 | ||
|
|
320b02108b | ||
|
|
80df86dfdd | ||
|
|
fef390df08 | ||
|
|
37be918c50 | ||
|
|
2efbe4ac36 | ||
|
|
6d68aab56a | ||
|
|
ccb8568756 | ||
|
|
a4f6f391fe | ||
|
|
dac61c406f | ||
|
|
db35f98b26 | ||
|
|
e6f50b0181 | ||
|
|
2877196656 | ||
|
|
f748d1c4ef | ||
|
|
848832dd61 | ||
|
|
c5f2c192d6 |
2
.github/workflows/actionlint.yml
vendored
2
.github/workflows/actionlint.yml
vendored
@@ -15,7 +15,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
- name: actionlint
|
||||
uses: raven-actions/actionlint@v2
|
||||
with:
|
||||
|
||||
2
.github/workflows/build-template.yml
vendored
2
.github/workflows/build-template.yml
vendored
@@ -70,7 +70,7 @@ jobs:
|
||||
if: runner.os == 'macOS'
|
||||
- name: Checkout
|
||||
if: (!endsWith(matrix.os, '-with-cache'))
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
# the default is to use a virtual merge commit between the PR and master: just use the PR
|
||||
ref: ${{ github.event.pull_request.head.sha }}
|
||||
|
||||
2
.github/workflows/check-prelude.yml
vendored
2
.github/workflows/check-prelude.yml
vendored
@@ -7,7 +7,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
# the default is to use a virtual merge commit between the PR and master: just use the PR
|
||||
ref: ${{ github.event.pull_request.head.sha }}
|
||||
|
||||
2
.github/workflows/check-stage0.yml
vendored
2
.github/workflows/check-stage0.yml
vendored
@@ -8,7 +8,7 @@ jobs:
|
||||
check-stage0-on-queue:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
with:
|
||||
ref: ${{ github.event.pull_request.head.sha }}
|
||||
filter: blob:none
|
||||
|
||||
8
.github/workflows/ci.yml
vendored
8
.github/workflows/ci.yml
vendored
@@ -54,7 +54,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
# don't schedule nightlies on forks
|
||||
if: github.event_name == 'schedule' && github.repository == 'leanprover/lean4' || inputs.action == 'release nightly'
|
||||
- name: Set Nightly
|
||||
@@ -363,7 +363,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
needs: build
|
||||
steps:
|
||||
- uses: actions/download-artifact@v4
|
||||
- uses: actions/download-artifact@v5
|
||||
with:
|
||||
path: artifacts
|
||||
- name: Release
|
||||
@@ -388,12 +388,12 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
# needed for tagging
|
||||
fetch-depth: 0
|
||||
token: ${{ secrets.PUSH_NIGHTLY_TOKEN }}
|
||||
- uses: actions/download-artifact@v4
|
||||
- uses: actions/download-artifact@v5
|
||||
with:
|
||||
path: artifacts
|
||||
- name: Prepare Nightly Release
|
||||
|
||||
2
.github/workflows/copyright-header.yml
vendored
2
.github/workflows/copyright-header.yml
vendored
@@ -6,7 +6,7 @@ jobs:
|
||||
check-lean-files:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
|
||||
- name: Verify .lean files start with a copyright header.
|
||||
run: |
|
||||
|
||||
6
.github/workflows/pr-release.yml
vendored
6
.github/workflows/pr-release.yml
vendored
@@ -395,7 +395,7 @@ jobs:
|
||||
# Checkout the Batteries repository with all branches
|
||||
- name: Checkout Batteries repository
|
||||
if: steps.workflow-info.outputs.pullRequestNumber != '' && steps.ready.outputs.mathlib_ready == 'true'
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
repository: leanprover-community/batteries
|
||||
token: ${{ secrets.MATHLIB4_BOT }}
|
||||
@@ -454,7 +454,7 @@ jobs:
|
||||
# Checkout the mathlib4 repository with all branches
|
||||
- name: Checkout mathlib4 repository
|
||||
if: steps.workflow-info.outputs.pullRequestNumber != '' && steps.ready.outputs.mathlib_ready == 'true'
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
repository: leanprover-community/mathlib4-nightly-testing
|
||||
token: ${{ secrets.MATHLIB4_BOT }}
|
||||
@@ -524,7 +524,7 @@ jobs:
|
||||
# Checkout the reference manual repository with all branches
|
||||
- name: Checkout mathlib4 repository
|
||||
if: steps.workflow-info.outputs.pullRequestNumber != '' && steps.reference-manual-ready.outputs.manual_ready == 'true'
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
repository: leanprover/reference-manual
|
||||
token: ${{ secrets.MANUAL_PR_BOT }}
|
||||
|
||||
2
.github/workflows/update-stage0.yml
vendored
2
.github/workflows/update-stage0.yml
vendored
@@ -25,7 +25,7 @@ jobs:
|
||||
# This action should push to an otherwise protected branch, so it
|
||||
# uses a deploy key with write permissions, as suggested at
|
||||
# https://stackoverflow.com/a/76135647/946226
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
with:
|
||||
ssh-key: ${{secrets.STAGE0_SSH_KEY}}
|
||||
- run: echo "should_update_stage0=yes" >> "$GITHUB_ENV"
|
||||
|
||||
@@ -8,7 +8,7 @@ You should not edit the `stage0` directory except using the commands described i
|
||||
|
||||
## Development Setup
|
||||
|
||||
You can use any of the [supported editors](../setup.md) for editing the Lean source code.
|
||||
You can use any of the [supported editors](https://lean-lang.org/install/manual/) for editing the Lean source code.
|
||||
Please see below for specific instructions for VS Code.
|
||||
|
||||
### Dev setup using elan
|
||||
@@ -99,3 +99,19 @@ on to `nightly-with-manual` branch. (It is fine to force push after rebasing.)
|
||||
CI will generate a branch of the reference manual called `lean-pr-testing-NNNN`
|
||||
in `leanprover/reference-manual`. This branch uses the toolchain for your PR,
|
||||
and will report back to the Lean PR with results from Mathlib CI.
|
||||
|
||||
### Avoiding rebuilds for downstream projects
|
||||
|
||||
If you want to test changes to Lean on downstream projects and would like to avoid rebuilding modules you have already built/fetched using the project's configured Lean toolchain, you can often do so as long as your build of Lean is close enough to that Lean toolchain (compatible .olean format including structure of all relevant environment extensions).
|
||||
|
||||
To override the toolchain without rebuilding for a single command, for example `lake build` or `lake lean`, you can use the prefix
|
||||
```
|
||||
LEAN_GITHASH=$(lean --githash) lake +lean4 ...
|
||||
```
|
||||
Alternatively, use
|
||||
```
|
||||
export LEAN_GITHASH=$(lean --githash)
|
||||
export ELAN_TOOLCHAIN=lean4
|
||||
```
|
||||
to persist these changes for the lifetime of the current shell, which will affect any processes spawned from it such as VS Code started via `code .`.
|
||||
If you use a setup where you cannot directly start your editor from the command line, such as VS Code Remote, you might want to consider using [direnv](https://direnv.net/) together with an editor extension for it instead so that you can put the lines above into `.envrc`.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
These are instructions to set up a working development environment for those who wish to make changes to Lean itself. It is part of the [Development Guide](../dev/index.md).
|
||||
|
||||
We strongly suggest that new users instead follow the [Quickstart](../quickstart.md) to get started using Lean, since this sets up an environment that can automatically manage multiple Lean toolchain versions, which is necessary when working within the Lean ecosystem.
|
||||
We strongly suggest that new users instead follow the [Installation Instructions](https://lean-lang.org/install/) to get started using Lean, since this sets up an environment that can automatically manage multiple Lean toolchain versions, which is necessary when working within the Lean ecosystem.
|
||||
|
||||
Requirements
|
||||
------------
|
||||
|
||||
@@ -19,8 +19,8 @@ variable {ε σ α : Type u}
|
||||
|
||||
instance [ToString ε] [ToString α] : ToString (Result ε σ α) where
|
||||
toString
|
||||
| Result.ok a _ => "ok: " ++ toString a
|
||||
| Result.error e _ => "error: " ++ toString e
|
||||
| Result.ok a _ => String.Internal.append "ok: " (toString a)
|
||||
| Result.error e _ => String.Internal.append "error: " (toString e)
|
||||
|
||||
instance [Repr ε] [Repr α] : Repr (Result ε σ α) where
|
||||
reprPrec
|
||||
|
||||
@@ -22,23 +22,24 @@ open Function
|
||||
|
||||
namespace ExceptT
|
||||
|
||||
@[ext] theorem ext {x y : ExceptT ε m α} (h : x.run = y.run) : x = y := by
|
||||
@[ext, grind ext] theorem ext {x y : ExceptT ε m α} (h : x.run = y.run) : x = y := by
|
||||
simp [run] at h
|
||||
assumption
|
||||
|
||||
@[simp] theorem run_pure [Monad m] (x : α) : run (pure x : ExceptT ε m α) = pure (Except.ok x) := rfl
|
||||
@[simp, grind =] theorem run_pure [Monad m] (x : α) : run (pure x : ExceptT ε m α) = pure (Except.ok x) := rfl
|
||||
|
||||
@[simp] theorem run_lift [Monad.{u, v} m] (x : m α) : run (ExceptT.lift x : ExceptT ε m α) = (Except.ok <$> x : m (Except ε α)) := rfl
|
||||
@[simp, grind =] theorem run_lift [Monad.{u, v} m] (x : m α) : run (ExceptT.lift x : ExceptT ε m α) = (Except.ok <$> x : m (Except ε α)) := rfl
|
||||
|
||||
@[simp] theorem run_throw [Monad m] : run (throw e : ExceptT ε m β) = pure (Except.error e) := rfl
|
||||
@[simp, grind =] theorem run_throw [Monad m] : run (throw e : ExceptT ε m β) = pure (Except.error e) := rfl
|
||||
|
||||
@[simp] theorem run_bind_lift [Monad m] [LawfulMonad m] (x : m α) (f : α → ExceptT ε m β) : run (ExceptT.lift x >>= f : ExceptT ε m β) = x >>= fun a => run (f a) := by
|
||||
@[simp, grind =] theorem run_bind_lift [Monad m] [LawfulMonad m] (x : m α) (f : α → ExceptT ε m β) : run (ExceptT.lift x >>= f : ExceptT ε m β) = x >>= fun a => run (f a) := by
|
||||
simp [ExceptT.run, ExceptT.lift, bind, ExceptT.bind, ExceptT.mk, ExceptT.bindCont]
|
||||
|
||||
@[simp] theorem bind_throw [Monad m] [LawfulMonad m] (f : α → ExceptT ε m β) : (throw e >>= f) = throw e := by
|
||||
@[simp, grind =] theorem bind_throw [Monad m] [LawfulMonad m] (f : α → ExceptT ε m β) : (throw e >>= f) = throw e := by
|
||||
simp [throw, throwThe, MonadExceptOf.throw, bind, ExceptT.bind, ExceptT.bindCont, ExceptT.mk]
|
||||
|
||||
theorem run_bind [Monad m] (x : ExceptT ε m α)
|
||||
@[grind =]
|
||||
theorem run_bind [Monad m] (x : ExceptT ε m α) (f : α → ExceptT ε m β)
|
||||
: run (x >>= f : ExceptT ε m β)
|
||||
=
|
||||
run x >>= fun
|
||||
@@ -46,10 +47,10 @@ theorem run_bind [Monad m] (x : ExceptT ε m α)
|
||||
| Except.error e => pure (Except.error e) :=
|
||||
rfl
|
||||
|
||||
@[simp] theorem lift_pure [Monad m] [LawfulMonad m] (a : α) : ExceptT.lift (pure a) = (pure a : ExceptT ε m α) := by
|
||||
@[simp, grind =] theorem lift_pure [Monad m] [LawfulMonad m] (a : α) : ExceptT.lift (pure a) = (pure a : ExceptT ε m α) := by
|
||||
simp [ExceptT.lift, pure, ExceptT.pure]
|
||||
|
||||
@[simp] theorem run_map [Monad m] [LawfulMonad m] (f : α → β) (x : ExceptT ε m α)
|
||||
@[simp, grind =] theorem run_map [Monad m] [LawfulMonad m] (f : α → β) (x : ExceptT ε m α)
|
||||
: (f <$> x).run = Except.map f <$> x.run := by
|
||||
simp [Functor.map, ExceptT.map, ←bind_pure_comp]
|
||||
apply bind_congr
|
||||
@@ -113,28 +114,28 @@ instance : LawfulFunctor (Except ε) := inferInstance
|
||||
|
||||
namespace ReaderT
|
||||
|
||||
@[ext] theorem ext {x y : ReaderT ρ m α} (h : ∀ ctx, x.run ctx = y.run ctx) : x = y := by
|
||||
@[ext, grind ext] theorem ext {x y : ReaderT ρ m α} (h : ∀ ctx, x.run ctx = y.run ctx) : x = y := by
|
||||
simp [run] at h
|
||||
exact funext h
|
||||
|
||||
@[simp] theorem run_pure [Monad m] (a : α) (ctx : ρ) : (pure a : ReaderT ρ m α).run ctx = pure a := rfl
|
||||
@[simp, grind =] theorem run_pure [Monad m] (a : α) (ctx : ρ) : (pure a : ReaderT ρ m α).run ctx = pure a := rfl
|
||||
|
||||
@[simp] theorem run_bind [Monad m] (x : ReaderT ρ m α) (f : α → ReaderT ρ m β) (ctx : ρ)
|
||||
@[simp, grind =] theorem run_bind [Monad m] (x : ReaderT ρ m α) (f : α → ReaderT ρ m β) (ctx : ρ)
|
||||
: (x >>= f).run ctx = x.run ctx >>= λ a => (f a).run ctx := rfl
|
||||
|
||||
@[simp] theorem run_mapConst [Monad m] (a : α) (x : ReaderT ρ m β) (ctx : ρ)
|
||||
@[simp, grind =] theorem run_mapConst [Monad m] (a : α) (x : ReaderT ρ m β) (ctx : ρ)
|
||||
: (Functor.mapConst a x).run ctx = Functor.mapConst a (x.run ctx) := rfl
|
||||
|
||||
@[simp] theorem run_map [Monad m] (f : α → β) (x : ReaderT ρ m α) (ctx : ρ)
|
||||
@[simp, grind =] theorem run_map [Monad m] (f : α → β) (x : ReaderT ρ m α) (ctx : ρ)
|
||||
: (f <$> x).run ctx = f <$> x.run ctx := rfl
|
||||
|
||||
@[simp] theorem run_monadLift [MonadLiftT n m] (x : n α) (ctx : ρ)
|
||||
@[simp, grind =] theorem run_monadLift [MonadLiftT n m] (x : n α) (ctx : ρ)
|
||||
: (monadLift x : ReaderT ρ m α).run ctx = (monadLift x : m α) := rfl
|
||||
|
||||
@[simp] theorem run_monadMap [MonadFunctorT n m] (f : {β : Type u} → n β → n β) (x : ReaderT ρ m α) (ctx : ρ)
|
||||
@[simp, grind =] theorem run_monadMap [MonadFunctorT n m] (f : {β : Type u} → n β → n β) (x : ReaderT ρ m α) (ctx : ρ)
|
||||
: (monadMap @f x : ReaderT ρ m α).run ctx = monadMap @f (x.run ctx) := rfl
|
||||
|
||||
@[simp] theorem run_read [Monad m] (ctx : ρ) : (ReaderT.read : ReaderT ρ m ρ).run ctx = pure ctx := rfl
|
||||
@[simp, grind =] theorem run_read [Monad m] (ctx : ρ) : (ReaderT.read : ReaderT ρ m ρ).run ctx = pure ctx := rfl
|
||||
|
||||
@[simp] theorem run_seq {α β : Type u} [Monad m] (f : ReaderT ρ m (α → β)) (x : ReaderT ρ m α) (ctx : ρ)
|
||||
: (f <*> x).run ctx = (f.run ctx <*> x.run ctx) := rfl
|
||||
@@ -175,38 +176,39 @@ instance [Monad m] [LawfulMonad m] : LawfulMonad (StateRefT' ω σ m) :=
|
||||
|
||||
namespace StateT
|
||||
|
||||
@[ext] theorem ext {x y : StateT σ m α} (h : ∀ s, x.run s = y.run s) : x = y :=
|
||||
@[ext, grind ext] theorem ext {x y : StateT σ m α} (h : ∀ s, x.run s = y.run s) : x = y :=
|
||||
funext h
|
||||
|
||||
@[simp] theorem run'_eq [Monad m] (x : StateT σ m α) (s : σ) : run' x s = (·.1) <$> run x s :=
|
||||
@[simp, grind =] theorem run'_eq [Monad m] (x : StateT σ m α) (s : σ) : run' x s = (·.1) <$> run x s :=
|
||||
rfl
|
||||
|
||||
@[simp] theorem run_pure [Monad m] (a : α) (s : σ) : (pure a : StateT σ m α).run s = pure (a, s) := rfl
|
||||
@[simp, grind =] theorem run_pure [Monad m] (a : α) (s : σ) : (pure a : StateT σ m α).run s = pure (a, s) := rfl
|
||||
|
||||
@[simp] theorem run_bind [Monad m] (x : StateT σ m α) (f : α → StateT σ m β) (s : σ)
|
||||
@[simp, grind =] theorem run_bind [Monad m] (x : StateT σ m α) (f : α → StateT σ m β) (s : σ)
|
||||
: (x >>= f).run s = x.run s >>= λ p => (f p.1).run p.2 := by
|
||||
simp [bind, StateT.bind, run]
|
||||
|
||||
@[simp] theorem run_map {α β σ : Type u} [Monad m] [LawfulMonad m] (f : α → β) (x : StateT σ m α) (s : σ) : (f <$> x).run s = (fun (p : α × σ) => (f p.1, p.2)) <$> x.run s := by
|
||||
@[simp, grind =] theorem run_map {α β σ : Type u} [Monad m] [LawfulMonad m] (f : α → β) (x : StateT σ m α) (s : σ) : (f <$> x).run s = (fun (p : α × σ) => (f p.1, p.2)) <$> x.run s := by
|
||||
simp [Functor.map, StateT.map, run, ←bind_pure_comp]
|
||||
|
||||
@[simp] theorem run_get [Monad m] (s : σ) : (get : StateT σ m σ).run s = pure (s, s) := rfl
|
||||
@[simp, grind =] theorem run_get [Monad m] (s : σ) : (get : StateT σ m σ).run s = pure (s, s) := rfl
|
||||
|
||||
@[simp] theorem run_set [Monad m] (s s' : σ) : (set s' : StateT σ m PUnit).run s = pure (⟨⟩, s') := rfl
|
||||
@[simp, grind =] theorem run_set [Monad m] (s s' : σ) : (set s' : StateT σ m PUnit).run s = pure (⟨⟩, s') := rfl
|
||||
|
||||
@[simp] theorem run_modify [Monad m] (f : σ → σ) (s : σ) : (modify f : StateT σ m PUnit).run s = pure (⟨⟩, f s) := rfl
|
||||
@[simp, grind =] theorem run_modify [Monad m] (f : σ → σ) (s : σ) : (modify f : StateT σ m PUnit).run s = pure (⟨⟩, f s) := rfl
|
||||
|
||||
@[simp] theorem run_modifyGet [Monad m] (f : σ → α × σ) (s : σ) : (modifyGet f : StateT σ m α).run s = pure ((f s).1, (f s).2) := by
|
||||
@[simp, grind =] theorem run_modifyGet [Monad m] (f : σ → α × σ) (s : σ) : (modifyGet f : StateT σ m α).run s = pure ((f s).1, (f s).2) := by
|
||||
simp [modifyGet, MonadStateOf.modifyGet, StateT.modifyGet, run]
|
||||
|
||||
@[simp] theorem run_lift {α σ : Type u} [Monad m] (x : m α) (s : σ) : (StateT.lift x : StateT σ m α).run s = x >>= fun a => pure (a, s) := rfl
|
||||
@[simp, grind =] theorem run_lift {α σ : Type u} [Monad m] (x : m α) (s : σ) : (StateT.lift x : StateT σ m α).run s = x >>= fun a => pure (a, s) := rfl
|
||||
|
||||
@[grind =]
|
||||
theorem run_bind_lift {α σ : Type u} [Monad m] [LawfulMonad m] (x : m α) (f : α → StateT σ m β) (s : σ) : (StateT.lift x >>= f).run s = x >>= fun a => (f a).run s := by
|
||||
simp [StateT.lift, StateT.run, bind, StateT.bind]
|
||||
|
||||
@[simp] theorem run_monadLift {α σ : Type u} [Monad m] [MonadLiftT n m] (x : n α) (s : σ) : (monadLift x : StateT σ m α).run s = (monadLift x : m α) >>= fun a => pure (a, s) := rfl
|
||||
@[simp, grind =] theorem run_monadLift {α σ : Type u} [Monad m] [MonadLiftT n m] (x : n α) (s : σ) : (monadLift x : StateT σ m α).run s = (monadLift x : m α) >>= fun a => pure (a, s) := rfl
|
||||
|
||||
@[simp] theorem run_monadMap [MonadFunctorT n m] (f : {β : Type u} → n β → n β) (x : StateT σ m α) (s : σ) :
|
||||
@[simp, grind =] theorem run_monadMap [MonadFunctorT n m] (f : {β : Type u} → n β → n β) (x : StateT σ m α) (s : σ) :
|
||||
(monadMap @f x : StateT σ m α).run s = monadMap @f (x.run s) := rfl
|
||||
|
||||
@[simp] theorem run_seq {α β σ : Type u} [Monad m] [LawfulMonad m] (f : StateT σ m (α → β)) (x : StateT σ m α) (s : σ) : (f <*> x).run s = (f.run s >>= fun fs => (fun (p : α × σ) => (fs.1 p.1, p.2)) <$> x.run fs.2) := by
|
||||
|
||||
@@ -201,7 +201,7 @@ theorem mem_attach (xs : Array α) : ∀ x, x ∈ xs.attach
|
||||
rcases this with ⟨⟨_, _⟩, m, rfl⟩
|
||||
exact m
|
||||
|
||||
@[simp, grind]
|
||||
@[simp, grind =]
|
||||
theorem mem_attachWith {xs : Array α} {q : α → Prop} (H) (x : {x // q x}) :
|
||||
x ∈ xs.attachWith q H ↔ x.1 ∈ xs := by
|
||||
cases xs
|
||||
@@ -212,12 +212,13 @@ theorem mem_pmap {p : α → Prop} {f : ∀ a, p a → β} {xs H b} :
|
||||
b ∈ pmap f xs H ↔ ∃ (a : _) (h : a ∈ xs), f a (H a h) = b := by
|
||||
simp only [pmap_eq_map_attach, mem_map, mem_attach, true_and, Subtype.exists, eq_comm]
|
||||
|
||||
@[grind]
|
||||
theorem mem_pmap_of_mem {p : α → Prop} {f : ∀ a, p a → β} {xs H} {a} (h : a ∈ xs) :
|
||||
f a (H a h) ∈ pmap f xs H := by
|
||||
rw [mem_pmap]
|
||||
exact ⟨a, h, rfl⟩
|
||||
|
||||
grind_pattern mem_pmap_of_mem => _ ∈ pmap f xs H, a ∈ xs
|
||||
|
||||
@[simp, grind =]
|
||||
theorem size_pmap {p : α → Prop} {f : ∀ a, p a → β} {xs H} : (pmap f xs H).size = xs.size := by
|
||||
cases xs; simp
|
||||
@@ -706,7 +707,7 @@ and simplifies these to the function directly taking the value.
|
||||
{f : { x // p x } → Array β} {g : α → Array β} (hf : ∀ x h, f ⟨x, h⟩ = g x) :
|
||||
(xs.flatMap f) = xs.unattach.flatMap g := by
|
||||
cases xs
|
||||
simp only [List.flatMap_toArray, List.unattach_toArray,
|
||||
simp only [List.flatMap_toArray, List.unattach_toArray,
|
||||
mk.injEq]
|
||||
rw [List.flatMap_subtype]
|
||||
simp [hf]
|
||||
|
||||
@@ -10,8 +10,6 @@ public import Init.WFTactics
|
||||
public import Init.Data.Nat.Basic
|
||||
public import Init.Data.Fin.Basic
|
||||
public import Init.Data.UInt.BasicAux
|
||||
public import Init.Data.Repr
|
||||
public import Init.Data.ToString.Basic
|
||||
public import Init.GetElem
|
||||
public import Init.Data.List.ToArrayImpl
|
||||
import all Init.Data.List.ToArrayImpl
|
||||
@@ -42,11 +40,11 @@ namespace Array
|
||||
|
||||
/-! ### Preliminary theorems -/
|
||||
|
||||
@[simp, grind] theorem size_set {xs : Array α} {i : Nat} {v : α} (h : i < xs.size) :
|
||||
@[simp, grind =] theorem size_set {xs : Array α} {i : Nat} {v : α} (h : i < xs.size) :
|
||||
(set xs i v h).size = xs.size :=
|
||||
List.length_set ..
|
||||
|
||||
@[simp, grind] theorem size_push {xs : Array α} (v : α) : (push xs v).size = xs.size + 1 :=
|
||||
@[simp, grind =] theorem size_push {xs : Array α} (v : α) : (push xs v).size = xs.size + 1 :=
|
||||
List.length_concat ..
|
||||
|
||||
theorem ext {xs ys : Array α}
|
||||
@@ -113,10 +111,12 @@ theorem mem_def {a : α} {as : Array α} : a ∈ as ↔ a ∈ as.toList :=
|
||||
@[simp, grind =] theorem mem_toArray {a : α} {l : List α} : a ∈ l.toArray ↔ a ∈ l := by
|
||||
simp [mem_def]
|
||||
|
||||
@[simp, grind] theorem getElem_mem {xs : Array α} {i : Nat} (h : i < xs.size) : xs[i] ∈ xs := by
|
||||
@[simp] theorem getElem_mem {xs : Array α} {i : Nat} (h : i < xs.size) : xs[i] ∈ xs := by
|
||||
rw [Array.mem_def, ← getElem_toList]
|
||||
apply List.getElem_mem
|
||||
|
||||
grind_pattern getElem_mem => xs[i] ∈ xs
|
||||
|
||||
@[simp, grind =] theorem emptyWithCapacity_eq {α n} : @emptyWithCapacity α n = #[] := rfl
|
||||
|
||||
@[simp] theorem mkEmpty_eq {α n} : @mkEmpty α n = #[] := rfl
|
||||
@@ -134,7 +134,7 @@ theorem toList_toArray {as : List α} : as.toArray.toList = as := rfl
|
||||
@[deprecated toList_toArray (since := "2025-02-17")]
|
||||
abbrev _root_.Array.toList_toArray := @List.toList_toArray
|
||||
|
||||
@[simp, grind] theorem size_toArray {as : List α} : as.toArray.size = as.length := by simp [Array.size]
|
||||
@[simp, grind =] theorem size_toArray {as : List α} : as.toArray.size = as.length := by simp [Array.size]
|
||||
|
||||
@[deprecated size_toArray (since := "2025-02-17")]
|
||||
abbrev _root_.Array.size_toArray := @List.size_toArray
|
||||
@@ -164,7 +164,7 @@ This is a low-level version of `Array.size` that directly queries the runtime sy
|
||||
representation of arrays. While this is not provable, `Array.usize` always returns the exact size of
|
||||
the array since the implementation only supports arrays of size less than `USize.size`.
|
||||
-/
|
||||
@[extern "lean_array_size", simp]
|
||||
@[extern "lean_array_size", simp, expose]
|
||||
def usize (xs : @& Array α) : USize := xs.size.toUSize
|
||||
|
||||
/--
|
||||
@@ -199,7 +199,7 @@ Examples:
|
||||
def pop (xs : Array α) : Array α where
|
||||
toList := xs.toList.dropLast
|
||||
|
||||
@[simp, grind] theorem size_pop {xs : Array α} : xs.pop.size = xs.size - 1 := by
|
||||
@[simp, grind =] theorem size_pop {xs : Array α} : xs.pop.size = xs.size - 1 := by
|
||||
match xs with
|
||||
| ⟨[]⟩ => rfl
|
||||
| ⟨a::as⟩ => simp [pop, Nat.succ_sub_succ_eq_sub, size]
|
||||
@@ -443,7 +443,7 @@ def swapAt! (xs : Array α) (i : Nat) (v : α) : α × Array α :=
|
||||
swapAt xs i v
|
||||
else
|
||||
have : Inhabited (α × Array α) := ⟨(v, xs)⟩
|
||||
panic! ("index " ++ toString i ++ " out of bounds")
|
||||
panic! String.Internal.append (String.Internal.append "index " (toString i)) " out of bounds"
|
||||
|
||||
/--
|
||||
Returns the first `n` elements of an array. The resulting array is produced by repeatedly calling
|
||||
@@ -2169,7 +2169,7 @@ instance {α : Type u} [Repr α] : Repr (Array α) where
|
||||
reprPrec xs _ := Array.repr xs
|
||||
|
||||
instance [ToString α] : ToString (Array α) where
|
||||
toString xs := "#" ++ toString xs.toList
|
||||
toString xs := String.Internal.append "#" (toString xs.toList)
|
||||
|
||||
end Array
|
||||
|
||||
|
||||
@@ -91,7 +91,7 @@ theorem mem_of_mem_eraseP {xs : Array α} : a ∈ xs.eraseP p → a ∈ xs := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simpa using List.mem_of_mem_eraseP
|
||||
|
||||
@[simp, grind] theorem mem_eraseP_of_neg {xs : Array α} (pa : ¬p a) : a ∈ xs.eraseP p ↔ a ∈ xs := by
|
||||
@[simp, grind =] theorem mem_eraseP_of_neg {xs : Array α} (pa : ¬p a) : a ∈ xs.eraseP p ↔ a ∈ xs := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simpa using List.mem_eraseP_of_neg pa
|
||||
|
||||
@@ -240,7 +240,7 @@ theorem mem_of_mem_erase {a b : α} {xs : Array α} (h : a ∈ xs.erase b) : a
|
||||
rcases xs with ⟨xs⟩
|
||||
simpa using List.mem_of_mem_erase (by simpa using h)
|
||||
|
||||
@[simp, grind] theorem mem_erase_of_ne [LawfulBEq α] {a b : α} {xs : Array α} (ab : a ≠ b) :
|
||||
@[simp, grind =] theorem mem_erase_of_ne [LawfulBEq α] {a b : α} {xs : Array α} (ab : a ≠ b) :
|
||||
a ∈ xs.erase b ↔ a ∈ xs :=
|
||||
erase_eq_eraseP b xs ▸ mem_eraseP_of_neg (mt eq_of_beq ab.symm)
|
||||
|
||||
|
||||
@@ -27,11 +27,11 @@ open Nat
|
||||
|
||||
/-! ### findSome? -/
|
||||
|
||||
@[simp, grind] theorem findSome?_empty : (#[] : Array α).findSome? f = none := rfl
|
||||
@[simp, grind] theorem findSome?_push {xs : Array α} : (xs.push a).findSome? f = (xs.findSome? f).or (f a) := by
|
||||
@[simp, grind =] theorem findSome?_empty : (#[] : Array α).findSome? f = none := rfl
|
||||
@[simp, grind =] theorem findSome?_push {xs : Array α} : (xs.push a).findSome? f = (xs.findSome? f).or (f a) := by
|
||||
cases xs; simp [List.findSome?_append]
|
||||
|
||||
@[grind]
|
||||
@[grind =]
|
||||
theorem findSome?_singleton {a : α} {f : α → Option β} : #[a].findSome? f = f a := by
|
||||
simp
|
||||
|
||||
@@ -228,11 +228,12 @@ theorem mem_of_find?_eq_some {xs : Array α} (h : find? p xs = some a) : a ∈ x
|
||||
simp at h
|
||||
simpa using List.mem_of_find?_eq_some h
|
||||
|
||||
@[grind]
|
||||
theorem get_find?_mem {xs : Array α} (h) : (xs.find? p).get h ∈ xs := by
|
||||
cases xs
|
||||
simp [List.get_find?_mem]
|
||||
|
||||
grind_pattern get_find?_mem => (xs.find? p).get h
|
||||
|
||||
@[simp, grind =] theorem find?_filter {xs : Array α} (p q : α → Bool) :
|
||||
(xs.filter p).find? q = xs.find? (fun a => p a ∧ q a) := by
|
||||
cases xs; simp
|
||||
@@ -395,7 +396,6 @@ theorem findIdx_singleton {a : α} {p : α → Bool} :
|
||||
#[a].findIdx p = if p a then 0 else 1 := by
|
||||
simp
|
||||
|
||||
@[grind →]
|
||||
theorem findIdx_of_getElem?_eq_some {xs : Array α} (w : xs[xs.findIdx p]? = some y) : p y := by
|
||||
rcases xs with ⟨xs⟩
|
||||
exact List.findIdx_of_getElem?_eq_some (by simpa using w)
|
||||
@@ -728,7 +728,7 @@ theorem isNone_findFinIdx? {xs : Array α} {p : α → Bool} :
|
||||
cases xs
|
||||
simp only [List.findFinIdx?_toArray, hf, List.findFinIdx?_subtype]
|
||||
rw [findFinIdx?_congr List.unattach_toArray]
|
||||
simp only [Option.map_map, Function.comp_def, Fin.cast_trans]
|
||||
simp only [Option.map_map, Function.comp_def, Fin.cast_cast]
|
||||
simp [Array.size]
|
||||
|
||||
/-! ### idxOf
|
||||
|
||||
@@ -15,7 +15,6 @@ public import Init.Data.List.Monadic
|
||||
public import Init.Data.List.OfFn
|
||||
public import Init.Data.Array.Mem
|
||||
public import Init.Data.Array.DecidableEq
|
||||
public import Init.Data.Array.Lex.Basic
|
||||
public import Init.Data.Range.Lemmas
|
||||
public import Init.TacticsExtra
|
||||
public import Init.Data.List.ToArray
|
||||
@@ -62,7 +61,7 @@ theorem toArray_eq : List.toArray as = xs ↔ as = xs.toList := by
|
||||
@[simp] theorem empty_eq {xs : Array α} : #[] = xs ↔ xs = #[] := by
|
||||
cases xs <;> simp
|
||||
|
||||
@[grind] theorem size_empty : (#[] : Array α).size = 0 := rfl
|
||||
@[grind =] theorem size_empty : (#[] : Array α).size = 0 := rfl
|
||||
|
||||
/-! ### size -/
|
||||
|
||||
@@ -197,7 +196,7 @@ theorem getElem?_push_size {xs : Array α} {x} : (xs.push x)[xs.size]? = some x
|
||||
theorem getElem_singleton {a : α} {i : Nat} (h : i < 1) : #[a][i] = a := by
|
||||
simp
|
||||
|
||||
@[grind]
|
||||
@[grind =]
|
||||
theorem getElem?_singleton {a : α} {i : Nat} : #[a][i]? = if i = 0 then some a else none := by
|
||||
simp [List.getElem?_singleton]
|
||||
|
||||
@@ -212,12 +211,12 @@ theorem ext_getElem? {xs ys : Array α} (h : ∀ i : Nat, xs[i]? = ys[i]?) : xs
|
||||
|
||||
@[simp] theorem pop_push {xs : Array α} {x : α} : (xs.push x).pop = xs := by simp [pop]
|
||||
|
||||
@[simp, grind] theorem getElem_pop {xs : Array α} {i : Nat} (h : i < xs.pop.size) :
|
||||
@[simp, grind =] theorem getElem_pop {xs : Array α} {i : Nat} (h : i < xs.pop.size) :
|
||||
xs.pop[i] = xs[i]'(by simp at h; omega) := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simp [List.getElem_dropLast]
|
||||
|
||||
@[grind] theorem getElem?_pop {xs : Array α} {i : Nat} :
|
||||
@[grind =] theorem getElem?_pop {xs : Array α} {i : Nat} :
|
||||
xs.pop[i]? = if i < xs.size - 1 then xs[i]? else none := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simp [List.getElem?_dropLast]
|
||||
@@ -332,7 +331,7 @@ theorem singleton_inj : #[a] = #[b] ↔ a = b := by
|
||||
|
||||
/-! ### replicate -/
|
||||
|
||||
@[simp, grind] theorem size_replicate {n : Nat} {v : α} : (replicate n v).size = n :=
|
||||
@[simp, grind =] theorem size_replicate {n : Nat} {v : α} : (replicate n v).size = n :=
|
||||
List.length_replicate ..
|
||||
|
||||
@[deprecated size_replicate (since := "2025-03-18")]
|
||||
@@ -344,12 +343,12 @@ abbrev size_mkArray := @size_replicate
|
||||
@[deprecated toList_replicate (since := "2025-03-18")]
|
||||
abbrev toList_mkArray := @toList_replicate
|
||||
|
||||
@[simp, grind] theorem replicate_zero : replicate 0 a = #[] := rfl
|
||||
@[simp, grind =] theorem replicate_zero : replicate 0 a = #[] := rfl
|
||||
|
||||
@[deprecated replicate_zero (since := "2025-03-18")]
|
||||
abbrev mkArray_zero := @replicate_zero
|
||||
|
||||
@[grind]
|
||||
@[grind =]
|
||||
theorem replicate_succ : replicate (n + 1) a = (replicate n a).push a := by
|
||||
apply toList_inj.1
|
||||
simp [List.replicate_succ']
|
||||
@@ -357,13 +356,13 @@ theorem replicate_succ : replicate (n + 1) a = (replicate n a).push a := by
|
||||
@[deprecated replicate_succ (since := "2025-03-18")]
|
||||
abbrev mkArray_succ := @replicate_succ
|
||||
|
||||
@[simp, grind] theorem getElem_replicate {n : Nat} {v : α} {i : Nat} (h : i < (replicate n v).size) :
|
||||
@[simp, grind =] theorem getElem_replicate {n : Nat} {v : α} {i : Nat} (h : i < (replicate n v).size) :
|
||||
(replicate n v)[i] = v := by simp [← getElem_toList]
|
||||
|
||||
@[deprecated getElem_replicate (since := "2025-03-18")]
|
||||
abbrev getElem_mkArray := @getElem_replicate
|
||||
|
||||
@[grind] theorem getElem?_replicate {n : Nat} {v : α} {i : Nat} :
|
||||
@[grind =] theorem getElem?_replicate {n : Nat} {v : α} {i : Nat} :
|
||||
(replicate n v)[i]? = if i < n then some v else none := by
|
||||
simp [getElem?_def]
|
||||
|
||||
@@ -374,14 +373,20 @@ abbrev getElem?_mkArray := @getElem?_replicate
|
||||
|
||||
theorem not_mem_empty (a : α) : ¬ a ∈ #[] := by simp
|
||||
|
||||
@[simp] theorem mem_push {xs : Array α} {x y : α} : x ∈ xs.push y ↔ x ∈ xs ∨ x = y := by
|
||||
@[simp, grind =] theorem mem_push {xs : Array α} {x y : α} : x ∈ xs.push y ↔ x ∈ xs ∨ x = y := by
|
||||
simp only [mem_def]
|
||||
simp
|
||||
|
||||
@[grind] theorem mem_or_eq_of_mem_push {a b : α} {xs : Array α} :
|
||||
theorem mem_or_eq_of_mem_push {a b : α} {xs : Array α} :
|
||||
a ∈ xs.push b → a ∈ xs ∨ a = b := Array.mem_push.mp
|
||||
|
||||
@[grind] theorem mem_push_self {xs : Array α} {x : α} : x ∈ xs.push x :=
|
||||
-- This pattern may be excessively general:
|
||||
-- it fires anytime we ae thinking about membership of arrays,
|
||||
-- and constructing a list via `push`, even if the elements are unrelated.
|
||||
-- Nevertheless in practice it is quite helpful!
|
||||
grind_pattern mem_or_eq_of_mem_push => xs.push b, a ∈ xs
|
||||
|
||||
theorem mem_push_self {xs : Array α} {x : α} : x ∈ xs.push x :=
|
||||
mem_push.2 (Or.inr rfl)
|
||||
|
||||
theorem eq_push_append_of_mem {xs : Array α} {x : α} (h : x ∈ xs) :
|
||||
@@ -392,7 +397,7 @@ theorem eq_push_append_of_mem {xs : Array α} {x : α} (h : x ∈ xs) :
|
||||
obtain rfl := h
|
||||
exact ⟨as.toArray, bs.toArray, by simp, by simpa using w⟩
|
||||
|
||||
@[grind] theorem mem_push_of_mem {xs : Array α} {x : α} (y : α) (h : x ∈ xs) : x ∈ xs.push y :=
|
||||
theorem mem_push_of_mem {xs : Array α} {x : α} (y : α) (h : x ∈ xs) : x ∈ xs.push y :=
|
||||
mem_push.2 (Or.inl h)
|
||||
|
||||
-- The argument `xs : Array α` is intentionally explicit,
|
||||
@@ -521,8 +526,8 @@ theorem forall_getElem {xs : Array α} {p : α → Prop} :
|
||||
|
||||
/-! ### isEmpty -/
|
||||
|
||||
@[grind] theorem isEmpty_empty : (#[] : Array α).isEmpty = true := rfl
|
||||
@[simp, grind] theorem isEmpty_push {xs : Array α} : (xs.push x).isEmpty = false := by
|
||||
@[grind =] theorem isEmpty_empty : (#[] : Array α).isEmpty = true := rfl
|
||||
@[simp, grind =] theorem isEmpty_push {xs : Array α} : (xs.push x).isEmpty = false := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simp
|
||||
|
||||
@@ -729,18 +734,18 @@ theorem all_eq_true_iff_forall_mem {xs : Array α} : xs.all p ↔ ∀ x, x ∈ x
|
||||
subst h
|
||||
rw [all_toList]
|
||||
|
||||
@[grind] theorem _root_.List.anyM_toArray [Monad m] [LawfulMonad m] {p : α → m Bool} {l : List α} :
|
||||
@[grind =] theorem _root_.List.anyM_toArray [Monad m] [LawfulMonad m] {p : α → m Bool} {l : List α} :
|
||||
l.toArray.anyM p = l.anyM p := by
|
||||
rw [← anyM_toList]
|
||||
|
||||
@[grind] theorem _root_.List.any_toArray {p : α → Bool} {l : List α} : l.toArray.any p = l.any p := by
|
||||
@[grind =] theorem _root_.List.any_toArray {p : α → Bool} {l : List α} : l.toArray.any p = l.any p := by
|
||||
rw [any_toList]
|
||||
|
||||
@[grind] theorem _root_.List.allM_toArray [Monad m] [LawfulMonad m] {p : α → m Bool} {l : List α} :
|
||||
@[grind =] theorem _root_.List.allM_toArray [Monad m] [LawfulMonad m] {p : α → m Bool} {l : List α} :
|
||||
l.toArray.allM p = l.allM p := by
|
||||
rw [← allM_toList]
|
||||
|
||||
@[grind] theorem _root_.List.all_toArray {p : α → Bool} {l : List α} : l.toArray.all p = l.all p := by
|
||||
@[grind =] theorem _root_.List.all_toArray {p : α → Bool} {l : List α} : l.toArray.all p = l.all p := by
|
||||
rw [all_toList]
|
||||
|
||||
/-- Variant of `any_eq_true` in terms of membership rather than an array index. -/
|
||||
@@ -847,7 +852,7 @@ theorem contains_eq_true_of_mem [BEq α] [ReflBEq α] {a : α} {as : Array α} (
|
||||
elem a xs = xs.contains a := by
|
||||
simp [elem]
|
||||
|
||||
@[grind] theorem contains_empty [BEq α] : (#[] : Array α).contains a = false := by simp
|
||||
@[grind =] theorem contains_empty [BEq α] : (#[] : Array α).contains a = false := by simp
|
||||
|
||||
theorem elem_iff [BEq α] [LawfulBEq α] {a : α} {xs : Array α} :
|
||||
elem a xs = true ↔ a ∈ xs := ⟨mem_of_contains_eq_true, contains_eq_true_of_mem⟩
|
||||
@@ -861,14 +866,14 @@ instance [BEq α] [LawfulBEq α] (a : α) (as : Array α) : Decidable (a ∈ as)
|
||||
theorem elem_eq_mem [BEq α] [LawfulBEq α] {a : α} {xs : Array α} :
|
||||
elem a xs = decide (a ∈ xs) := by rw [Bool.eq_iff_iff, elem_iff, decide_eq_true_iff]
|
||||
|
||||
@[simp, grind] theorem contains_eq_mem [BEq α] [LawfulBEq α] {a : α} {xs : Array α} :
|
||||
@[simp, grind =] theorem contains_eq_mem [BEq α] [LawfulBEq α] {a : α} {xs : Array α} :
|
||||
xs.contains a = decide (a ∈ xs) := by rw [← elem_eq_contains, elem_eq_mem]
|
||||
|
||||
@[grind] theorem any_empty [BEq α] {p : α → Bool} : (#[] : Array α).any p = false := by simp
|
||||
@[grind] theorem all_empty [BEq α] {p : α → Bool} : (#[] : Array α).all p = true := by simp
|
||||
@[grind =] theorem any_empty [BEq α] {p : α → Bool} : (#[] : Array α).any p = false := by simp
|
||||
@[grind =] theorem all_empty [BEq α] {p : α → Bool} : (#[] : Array α).all p = true := by simp
|
||||
|
||||
/-- Variant of `any_push` with a side condition on `stop`. -/
|
||||
@[simp, grind] theorem any_push' {xs : Array α} {a : α} {p : α → Bool} (h : stop = xs.size + 1) :
|
||||
@[simp, grind =] theorem any_push' {xs : Array α} {a : α} {p : α → Bool} (h : stop = xs.size + 1) :
|
||||
(xs.push a).any p 0 stop = (xs.any p || p a) := by
|
||||
cases xs
|
||||
rw [List.push_toArray]
|
||||
@@ -879,7 +884,7 @@ theorem any_push {xs : Array α} {a : α} {p : α → Bool} :
|
||||
any_push' (by simp)
|
||||
|
||||
/-- Variant of `all_push` with a side condition on `stop`. -/
|
||||
@[simp, grind] theorem all_push' {xs : Array α} {a : α} {p : α → Bool} (h : stop = xs.size + 1) :
|
||||
@[simp, grind =] theorem all_push' {xs : Array α} {a : α} {p : α → Bool} (h : stop = xs.size + 1) :
|
||||
(xs.push a).all p 0 stop = (xs.all p && p a) := by
|
||||
cases xs
|
||||
rw [List.push_toArray]
|
||||
@@ -912,13 +917,13 @@ theorem all_push {xs : Array α} {a : α} {p : α → Bool} :
|
||||
(ne : i ≠ j) : (xs.set i v)[j]? = xs[j]? := by
|
||||
by_cases h : j < xs.size <;> simp [ne, h]
|
||||
|
||||
@[grind] theorem getElem_set {xs : Array α} {i : Nat} (h' : i < xs.size) {v : α} {j : Nat}
|
||||
@[grind =] theorem getElem_set {xs : Array α} {i : Nat} (h' : i < xs.size) {v : α} {j : Nat}
|
||||
(h : j < (xs.set i v).size) :
|
||||
(xs.set i v)[j] = if i = j then v else xs[j]'(by simpa using h) := by
|
||||
simp at h
|
||||
by_cases p : i = j <;> simp [p, h]
|
||||
|
||||
@[grind] theorem getElem?_set {xs : Array α} {i : Nat} (h : i < xs.size) {v : α} {j : Nat} :
|
||||
@[grind =] theorem getElem?_set {xs : Array α} {i : Nat} (h : i < xs.size) {v : α} {j : Nat} :
|
||||
(xs.set i v)[j]? = if i = j then some v else xs[j]? := by
|
||||
split <;> simp_all
|
||||
|
||||
@@ -984,23 +989,23 @@ grind_pattern mem_or_eq_of_mem_set => a ∈ xs.set i b
|
||||
|
||||
/-! ### setIfInBounds -/
|
||||
|
||||
@[simp, grind] theorem setIfInBounds_empty {i : Nat} {a : α} :
|
||||
@[simp, grind =] theorem setIfInBounds_empty {i : Nat} {a : α} :
|
||||
#[].setIfInBounds i a = #[] := rfl
|
||||
|
||||
@[simp, grind =] theorem set!_eq_setIfInBounds : set! xs i v = setIfInBounds xs i v := rfl
|
||||
|
||||
@[grind]
|
||||
@[grind =]
|
||||
theorem setIfInBounds_def (xs : Array α) (i : Nat) (a : α) :
|
||||
xs.setIfInBounds i a = if h : i < xs.size then xs.set i a else xs := rfl
|
||||
|
||||
@[simp, grind] theorem size_setIfInBounds {xs : Array α} {i : Nat} {a : α} :
|
||||
@[simp, grind =] theorem size_setIfInBounds {xs : Array α} {i : Nat} {a : α} :
|
||||
(xs.setIfInBounds i a).size = xs.size := by
|
||||
if h : i < xs.size then
|
||||
simp [setIfInBounds, h]
|
||||
else
|
||||
simp [setIfInBounds, h]
|
||||
|
||||
@[grind] theorem getElem_setIfInBounds {xs : Array α} {i : Nat} {a : α} {j : Nat}
|
||||
@[grind =] theorem getElem_setIfInBounds {xs : Array α} {i : Nat} {a : α} {j : Nat}
|
||||
(hj : j < xs.size) :
|
||||
(xs.setIfInBounds i a)[j]'(by simp [hj]) = if i = j then a else xs[j] := by
|
||||
simp only [setIfInBounds]
|
||||
@@ -1019,7 +1024,7 @@ theorem setIfInBounds_def (xs : Array α) (i : Nat) (a : α) :
|
||||
(xs.setIfInBounds i a)[j]'(by simpa using hj) = xs[j] := by
|
||||
simp [getElem_setIfInBounds, hj, h]
|
||||
|
||||
@[grind] theorem getElem?_setIfInBounds {xs : Array α} {i j : Nat} {a : α} :
|
||||
@[grind =] theorem getElem?_setIfInBounds {xs : Array α} {i j : Nat} {a : α} :
|
||||
(xs.setIfInBounds i a)[j]? = if i = j then if i < xs.size then some a else none else xs[j]? := by
|
||||
cases xs
|
||||
simp [List.getElem?_set]
|
||||
@@ -1083,11 +1088,11 @@ theorem mem_or_eq_of_mem_setIfInBounds
|
||||
|
||||
/-! ### BEq -/
|
||||
|
||||
@[simp, grind] theorem beq_empty_eq [BEq α] {xs : Array α} : (xs == #[]) = xs.isEmpty := by
|
||||
@[simp, grind =] theorem beq_empty_eq [BEq α] {xs : Array α} : (xs == #[]) = xs.isEmpty := by
|
||||
cases xs
|
||||
simp
|
||||
|
||||
@[simp, grind] theorem empty_beq_eq [BEq α] {xs : Array α} : (#[] == xs) = xs.isEmpty := by
|
||||
@[simp, grind =] theorem empty_beq_eq [BEq α] {xs : Array α} : (#[] == xs) = xs.isEmpty := by
|
||||
cases xs
|
||||
simp
|
||||
|
||||
@@ -1097,7 +1102,7 @@ abbrev beq_empty_iff := @beq_empty_eq
|
||||
@[deprecated empty_beq_eq (since := "2025-04-04")]
|
||||
abbrev empty_beq_iff := @empty_beq_eq
|
||||
|
||||
@[simp, grind] theorem push_beq_push [BEq α] {a b : α} {xs ys : Array α} :
|
||||
@[simp, grind =] theorem push_beq_push [BEq α] {a b : α} {xs ys : Array α} :
|
||||
(xs.push a == ys.push b) = (xs == ys && a == b) := by
|
||||
cases xs
|
||||
cases ys
|
||||
@@ -1157,16 +1162,16 @@ private theorem beq_of_beq_singleton [BEq α] {a b : α} : #[a] == #[b] → a ==
|
||||
|
||||
/-! ### back -/
|
||||
|
||||
@[grind] theorem back_singleton {a : α} : #[a].back = a := by simp
|
||||
@[grind =] theorem back_singleton {a : α} : #[a].back = a := by simp
|
||||
|
||||
@[grind]
|
||||
@[grind =]
|
||||
theorem back_eq_getElem {xs : Array α} (h : 0 < xs.size) : xs.back = xs[xs.size - 1] := by
|
||||
cases xs
|
||||
simp [List.getLast_eq_getElem]
|
||||
|
||||
@[grind] theorem back?_empty : (#[] : Array α).back? = none := by simp
|
||||
@[grind =] theorem back?_empty : (#[] : Array α).back? = none := by simp
|
||||
|
||||
@[grind] theorem back?_eq_getElem? {xs : Array α} : xs.back? = xs[xs.size - 1]? := by
|
||||
@[grind =] theorem back?_eq_getElem? {xs : Array α} : xs.back? = xs[xs.size - 1]? := by
|
||||
cases xs
|
||||
simp [List.getLast?_eq_getElem?]
|
||||
|
||||
@@ -1203,17 +1208,17 @@ where
|
||||
apply ext'
|
||||
simp
|
||||
|
||||
@[simp, grind] theorem size_map {f : α → β} {xs : Array α} : (xs.map f).size = xs.size := by
|
||||
@[simp, grind =] theorem size_map {f : α → β} {xs : Array α} : (xs.map f).size = xs.size := by
|
||||
simp only [← length_toList]
|
||||
simp
|
||||
|
||||
-- The argument `f : α → β` is explicit, to facilitate rewriting from right to left.
|
||||
@[simp, grind] theorem getElem_map (f : α → β) {xs : Array α} {i : Nat} (hi : i < (xs.map f).size) :
|
||||
@[simp, grind =] theorem getElem_map (f : α → β) {xs : Array α} {i : Nat} (hi : i < (xs.map f).size) :
|
||||
(xs.map f)[i] = f (xs[i]'(by simpa using hi)) := by
|
||||
cases xs
|
||||
simp
|
||||
|
||||
@[simp, grind] theorem getElem?_map {f : α → β} {xs : Array α} {i : Nat} :
|
||||
@[simp, grind =] theorem getElem?_map {f : α → β} {xs : Array α} {i : Nat} :
|
||||
(xs.map f)[i]? = xs[i]?.map f := by
|
||||
simp [getElem?_def]
|
||||
|
||||
@@ -1221,9 +1226,9 @@ where
|
||||
@[simp] theorem mapM_empty [Monad m] (f : α → m β) : mapM f #[] = pure #[] := by
|
||||
rw [mapM, mapM.map]; rfl
|
||||
|
||||
@[grind] theorem map_empty {f : α → β} : map f #[] = #[] := by simp
|
||||
@[grind =] theorem map_empty {f : α → β} : map f #[] = #[] := by simp
|
||||
|
||||
@[simp, grind] theorem map_push {f : α → β} {as : Array α} {x : α} :
|
||||
@[simp, grind =] theorem map_push {f : α → β} {as : Array α} {x : α} :
|
||||
(as.push x).map f = (as.map f).push (f x) := by
|
||||
ext
|
||||
· simp
|
||||
@@ -1384,7 +1389,7 @@ theorem array₃_induction (P : Array (Array (Array α)) → Prop)
|
||||
|
||||
/-! ### filter -/
|
||||
|
||||
@[grind] theorem filter_empty {p : α → Bool} : #[].filter p = #[] := rfl
|
||||
@[grind =] theorem filter_empty {p : α → Bool} : #[].filter p = #[] := rfl
|
||||
|
||||
@[congr]
|
||||
theorem filter_congr {xs ys : Array α} (h : xs = ys)
|
||||
@@ -1405,7 +1410,7 @@ theorem filter_congr {xs ys : Array α} (h : xs = ys)
|
||||
induction xs with simp
|
||||
| cons => split <;> simp [*]
|
||||
|
||||
@[grind] theorem toList_filter {p : α → Bool} {xs : Array α} :
|
||||
@[grind =] theorem toList_filter {p : α → Bool} {xs : Array α} :
|
||||
(xs.filter p).toList = xs.toList.filter p := by
|
||||
simp
|
||||
|
||||
@@ -1414,7 +1419,7 @@ theorem filter_congr {xs ys : Array α} (h : xs = ys)
|
||||
apply ext'
|
||||
simp [h]
|
||||
|
||||
@[grind] theorem _root_.List.filter_toArray {p : α → Bool} {l : List α} :
|
||||
@[grind =] theorem _root_.List.filter_toArray {p : α → Bool} {l : List α} :
|
||||
l.toArray.filter p = (l.filter p).toArray := by
|
||||
simp
|
||||
|
||||
@@ -1432,7 +1437,7 @@ theorem filter_congr {xs ys : Array α} (h : xs = ys)
|
||||
rcases xs with ⟨xs⟩
|
||||
simp [h]
|
||||
|
||||
@[grind] theorem filter_push {p : α → Bool} {a : α} {xs : Array α} :
|
||||
@[grind =] theorem filter_push {p : α → Bool} {a : α} {xs : Array α} :
|
||||
(xs.push a).filter p = if p a then (xs.filter p).push a else xs.filter p := by
|
||||
split <;> simp [*]
|
||||
|
||||
@@ -1453,7 +1458,7 @@ grind_pattern Array.size_filter_le => (xs.filter p).size
|
||||
rcases xs with ⟨xs⟩
|
||||
simp
|
||||
|
||||
@[simp, grind] theorem mem_filter {p : α → Bool} {xs : Array α} {a : α} :
|
||||
@[simp, grind =] theorem mem_filter {p : α → Bool} {xs : Array α} {a : α} :
|
||||
a ∈ xs.filter p ↔ a ∈ xs ∧ p a := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simp
|
||||
@@ -1515,7 +1520,7 @@ theorem map_filter_eq_foldl {f : α → β} {p : α → Bool} {xs : Array α} :
|
||||
simp only [List.filter_cons, List.foldr_cons]
|
||||
split <;> simp_all
|
||||
|
||||
@[simp, grind] theorem filter_append {p : α → Bool} {xs ys : Array α} {stop : Nat} (w : stop = xs.size + ys.size) :
|
||||
@[simp, grind =] theorem filter_append {p : α → Bool} {xs ys : Array α} {stop : Nat} (w : stop = xs.size + ys.size) :
|
||||
filter p (xs ++ ys) 0 stop = filter p xs ++ filter p ys := by
|
||||
subst w
|
||||
rcases xs with ⟨xs⟩
|
||||
@@ -1569,7 +1574,7 @@ theorem size_filter_lt_size_iff_exists {xs : Array α} {p : α → Bool} :
|
||||
|
||||
/-! ### filterMap -/
|
||||
|
||||
@[simp, grind] theorem filterMap_empty {f : α → Option β} : filterMap f #[] = #[] := rfl
|
||||
@[simp, grind =] theorem filterMap_empty {f : α → Option β} : filterMap f #[] = #[] := rfl
|
||||
|
||||
@[congr]
|
||||
theorem filterMap_congr {as bs : Array α} (h : as = bs)
|
||||
@@ -1592,7 +1597,7 @@ theorem filterMap_congr {as bs : Array α} (h : as = bs)
|
||||
· simp_all [List.filterMap_cons]
|
||||
split <;> simp_all
|
||||
|
||||
@[grind] theorem toList_filterMap {f : α → Option β} {xs : Array α} :
|
||||
@[grind =] theorem toList_filterMap {f : α → Option β} {xs : Array α} :
|
||||
(xs.filterMap f).toList = xs.toList.filterMap f := by
|
||||
simp [toList_filterMap']
|
||||
|
||||
@@ -1602,7 +1607,7 @@ theorem filterMap_congr {as bs : Array α} (h : as = bs)
|
||||
apply ext'
|
||||
simp [h]
|
||||
|
||||
@[grind] theorem _root_.List.filterMap_toArray {f : α → Option β} {l : List α} :
|
||||
@[grind =] theorem _root_.List.filterMap_toArray {f : α → Option β} {l : List α} :
|
||||
l.toArray.filterMap f = (l.filterMap f).toArray := by
|
||||
simp
|
||||
|
||||
@@ -1620,7 +1625,7 @@ theorem filterMap_congr {as bs : Array α} (h : as = bs)
|
||||
rcases xs with ⟨xs⟩
|
||||
simp [h]
|
||||
|
||||
@[grind] theorem filterMap_push {f : α → Option β} {a : α} {xs : Array α}
|
||||
@[grind =] theorem filterMap_push {f : α → Option β} {a : α} {xs : Array α}
|
||||
(w : stop = xs.size + 1) :
|
||||
filterMap f (xs.push a) 0 stop =
|
||||
match f a with
|
||||
@@ -1645,7 +1650,7 @@ theorem filterMap_some_fun : filterMap (some : α → Option α) = id := by
|
||||
cases xs
|
||||
simp
|
||||
|
||||
@[simp, grind] theorem filterMap_some {xs : Array α} : filterMap some xs = xs := by
|
||||
@[simp, grind =] theorem filterMap_some {xs : Array α} : filterMap some xs = xs := by
|
||||
cases xs
|
||||
simp
|
||||
|
||||
@@ -1673,19 +1678,19 @@ theorem filterMap_eq_filter {p : α → Bool} (w : stop = as.size) :
|
||||
cases as
|
||||
simp
|
||||
|
||||
@[grind]
|
||||
@[grind =]
|
||||
theorem filterMap_filterMap {f : α → Option β} {g : β → Option γ} {xs : Array α} :
|
||||
filterMap g (filterMap f xs) = filterMap (fun x => (f x).bind g) xs := by
|
||||
cases xs
|
||||
simp [List.filterMap_filterMap]
|
||||
|
||||
@[grind]
|
||||
@[grind =]
|
||||
theorem map_filterMap {f : α → Option β} {g : β → γ} {xs : Array α} :
|
||||
map g (filterMap f xs) = filterMap (fun x => (f x).map g) xs := by
|
||||
cases xs
|
||||
simp [List.map_filterMap]
|
||||
|
||||
@[simp, grind] theorem filterMap_map {f : α → β} {g : β → Option γ} {xs : Array α} :
|
||||
@[simp, grind =] theorem filterMap_map {f : α → β} {g : β → Option γ} {xs : Array α} :
|
||||
filterMap g (map f xs) = filterMap (g ∘ f) xs := by
|
||||
cases xs
|
||||
simp [List.filterMap_map]
|
||||
@@ -1700,7 +1705,7 @@ theorem filterMap_filter {p : α → Bool} {f : α → Option β} {xs : Array α
|
||||
cases xs
|
||||
simp [List.filterMap_filter]
|
||||
|
||||
@[simp, grind] theorem mem_filterMap {f : α → Option β} {xs : Array α} {b : β} :
|
||||
@[simp, grind =] theorem mem_filterMap {f : α → Option β} {xs : Array α} {b : β} :
|
||||
b ∈ filterMap f xs ↔ ∃ a, a ∈ xs ∧ f a = some b := by
|
||||
simp only [mem_def, toList_filterMap, List.mem_filterMap]
|
||||
|
||||
@@ -1712,7 +1717,7 @@ theorem forall_mem_filterMap {f : α → Option β} {xs : Array α} {P : β →
|
||||
intro a
|
||||
rw [forall_comm]
|
||||
|
||||
@[simp, grind] theorem filterMap_append {α β : Type _} {xs ys : Array α} {f : α → Option β}
|
||||
@[simp, grind =] theorem filterMap_append {α β : Type _} {xs ys : Array α} {f : α → Option β}
|
||||
{stop : Nat} (w : stop = xs.size + ys.size) :
|
||||
filterMap f (xs ++ ys) 0 stop = filterMap f xs ++ filterMap f ys := by
|
||||
subst w
|
||||
@@ -1771,7 +1776,7 @@ theorem size_filterMap_lt_size_iff_exists {xs : Array α} {f : α → Option β}
|
||||
|
||||
/-! ### append -/
|
||||
|
||||
@[simp, grind] theorem size_append {xs ys : Array α} : (xs ++ ys).size = xs.size + ys.size := by
|
||||
@[simp, grind =] theorem size_append {xs ys : Array α} : (xs ++ ys).size = xs.size + ys.size := by
|
||||
simp only [size, toList_append, List.length_append]
|
||||
|
||||
@[simp, grind _=_] theorem push_append {a : α} {xs ys : Array α} : (xs ++ ys).push a = xs ++ ys.push a := by
|
||||
@@ -1808,7 +1813,7 @@ theorem empty_append_fun : ((#[] : Array α) ++ ·) = id := by
|
||||
funext ⟨l⟩
|
||||
simp
|
||||
|
||||
@[simp, grind] theorem mem_append {a : α} {xs ys : Array α} : a ∈ xs ++ ys ↔ a ∈ xs ∨ a ∈ ys := by
|
||||
@[simp, grind =] theorem mem_append {a : α} {xs ys : Array α} : a ∈ xs ++ ys ↔ a ∈ xs ∨ a ∈ ys := by
|
||||
simp only [mem_def, toList_append, List.mem_append]
|
||||
|
||||
theorem mem_append_left {a : α} {xs : Array α} (ys : Array α) (h : a ∈ xs) : a ∈ xs ++ ys :=
|
||||
@@ -1836,7 +1841,7 @@ theorem forall_mem_append {p : α → Prop} {xs ys : Array α} :
|
||||
(∀ (x) (_ : x ∈ xs ++ ys), p x) ↔ (∀ (x) (_ : x ∈ xs), p x) ∧ (∀ (x) (_ : x ∈ ys), p x) := by
|
||||
simp only [mem_append, or_imp, forall_and]
|
||||
|
||||
@[grind] theorem getElem_append {xs ys : Array α} (h : i < (xs ++ ys).size) :
|
||||
@[grind =] theorem getElem_append {xs ys : Array α} (h : i < (xs ++ ys).size) :
|
||||
(xs ++ ys)[i] = if h' : i < xs.size then xs[i] else ys[i - xs.size]'(by simp at h; omega) := by
|
||||
cases xs; cases ys
|
||||
simp [List.getElem_append]
|
||||
@@ -1870,7 +1875,7 @@ theorem getElem?_append_right {xs ys : Array α} {i : Nat} (h : xs.size ≤ i) :
|
||||
simp at h
|
||||
simp [List.getElem?_append_right, h]
|
||||
|
||||
@[grind] theorem getElem?_append {xs ys : Array α} {i : Nat} :
|
||||
@[grind =] theorem getElem?_append {xs ys : Array α} {i : Nat} :
|
||||
(xs ++ ys)[i]? = if i < xs.size then xs[i]? else ys[i - xs.size]? := by
|
||||
split <;> rename_i h
|
||||
· exact getElem?_append_left h
|
||||
@@ -1951,7 +1956,6 @@ theorem append_left_inj {xs₁ xs₂ : Array α} (ys) : xs₁ ++ ys = xs₂ ++ y
|
||||
@[simp] theorem append_eq_empty_iff {xs ys : Array α} : xs ++ ys = #[] ↔ xs = #[] ∧ ys = #[] := by
|
||||
cases xs <;> simp
|
||||
|
||||
@[grind →]
|
||||
theorem eq_empty_of_append_eq_empty {xs ys : Array α} (h : xs ++ ys = #[]) : xs = #[] ∧ ys = #[] :=
|
||||
append_eq_empty_iff.mp h
|
||||
|
||||
@@ -2013,7 +2017,7 @@ theorem append_eq_append_iff {ws xs ys zs : Array α} :
|
||||
· left; exact ⟨as.toList, by simp⟩
|
||||
· right; exact ⟨cs.toList, by simp⟩
|
||||
|
||||
@[grind] theorem set_append {xs ys : Array α} {i : Nat} {x : α} (h : i < (xs ++ ys).size) :
|
||||
@[grind =] theorem set_append {xs ys : Array α} {i : Nat} {x : α} (h : i < (xs ++ ys).size) :
|
||||
(xs ++ ys).set i x =
|
||||
if h' : i < xs.size then
|
||||
xs.set i x ++ ys
|
||||
@@ -2033,7 +2037,7 @@ theorem append_eq_append_iff {ws xs ys zs : Array α} :
|
||||
(xs ++ ys).set i x = xs ++ ys.set (i - xs.size) x (by simp at h'; omega) := by
|
||||
rw [set_append, dif_neg (by omega)]
|
||||
|
||||
@[grind] theorem setIfInBounds_append {xs ys : Array α} {i : Nat} {x : α} :
|
||||
@[grind =] theorem setIfInBounds_append {xs ys : Array α} {i : Nat} {x : α} :
|
||||
(xs ++ ys).setIfInBounds i x =
|
||||
if i < xs.size then
|
||||
xs.setIfInBounds i x ++ ys
|
||||
@@ -2070,7 +2074,7 @@ theorem append_eq_filterMap_iff {f : α → Option β} :
|
||||
∃ as bs, zs = as ++ bs ∧ filterMap f as = xs ∧ filterMap f bs = ys := by
|
||||
rw [eq_comm, filterMap_eq_append_iff]
|
||||
|
||||
@[simp, grind] theorem map_append {f : α → β} {xs ys : Array α} :
|
||||
@[simp, grind =] theorem map_append {f : α → β} {xs ys : Array α} :
|
||||
map f (xs ++ ys) = map f xs ++ map f ys := by
|
||||
rcases xs with ⟨xs⟩
|
||||
rcases ys with ⟨ys⟩
|
||||
@@ -2086,9 +2090,9 @@ theorem append_eq_map_iff {f : α → β} :
|
||||
|
||||
/-! ### flatten -/
|
||||
|
||||
@[simp, grind] theorem flatten_empty : (#[] : Array (Array α)).flatten = #[] := by simp [flatten]; rfl
|
||||
@[simp, grind =] theorem flatten_empty : (#[] : Array (Array α)).flatten = #[] := by simp [flatten]; rfl
|
||||
|
||||
@[simp, grind] theorem toList_flatten {xss : Array (Array α)} :
|
||||
@[simp, grind =] theorem toList_flatten {xss : Array (Array α)} :
|
||||
xss.flatten.toList = (xss.toList.map toList).flatten := by
|
||||
dsimp [flatten]
|
||||
simp only [← foldl_toList]
|
||||
@@ -2114,11 +2118,11 @@ theorem flatten_map_toArray {L : List (List α)} :
|
||||
apply ext'
|
||||
simp
|
||||
|
||||
@[simp, grind] theorem size_flatten {xss : Array (Array α)} : xss.flatten.size = (xss.map size).sum := by
|
||||
@[simp, grind =] theorem size_flatten {xss : Array (Array α)} : xss.flatten.size = (xss.map size).sum := by
|
||||
cases xss using array₂_induction
|
||||
simp [Function.comp_def]
|
||||
|
||||
@[simp, grind] theorem flatten_singleton {xs : Array α} : #[xs].flatten = xs := by simp [flatten]; rfl
|
||||
@[simp, grind =] theorem flatten_singleton {xs : Array α} : #[xs].flatten = xs := by simp [flatten]; rfl
|
||||
|
||||
theorem mem_flatten : ∀ {xss : Array (Array α)}, a ∈ xss.flatten ↔ ∃ xs, xs ∈ xss ∧ a ∈ xs := by
|
||||
simp only [mem_def, toList_flatten, List.mem_flatten, List.mem_map]
|
||||
@@ -2161,7 +2165,7 @@ theorem flatten_eq_flatMap {xss : Array (Array α)} : flatten xss = xss.flatMap
|
||||
Function.comp_def]
|
||||
rw [← Function.comp_def, ← List.map_map, flatten_toArray_map]
|
||||
|
||||
@[simp, grind] theorem filterMap_flatten {f : α → Option β} {xss : Array (Array α)} {stop : Nat} (w : stop = xss.flatten.size) :
|
||||
@[simp, grind =] theorem filterMap_flatten {f : α → Option β} {xss : Array (Array α)} {stop : Nat} (w : stop = xss.flatten.size) :
|
||||
filterMap f (flatten xss) 0 stop = flatten (map (filterMap f) xss) := by
|
||||
subst w
|
||||
induction xss using array₂_induction
|
||||
@@ -2169,7 +2173,7 @@ theorem flatten_eq_flatMap {xss : Array (Array α)} : flatten xss = xss.flatMap
|
||||
List.filterMap_flatten, List.map_toArray, List.map_map, Function.comp_def]
|
||||
rw [← Function.comp_def, ← List.map_map, flatten_toArray_map]
|
||||
|
||||
@[simp, grind] theorem filter_flatten {p : α → Bool} {xss : Array (Array α)} {stop : Nat} (w : stop = xss.flatten.size) :
|
||||
@[simp, grind =] theorem filter_flatten {p : α → Bool} {xss : Array (Array α)} {stop : Nat} (w : stop = xss.flatten.size) :
|
||||
filter p (flatten xss) 0 stop = flatten (map (filter p) xss) := by
|
||||
subst w
|
||||
induction xss using array₂_induction
|
||||
@@ -2193,7 +2197,7 @@ theorem flatten_filter_ne_empty [DecidablePred fun xs : Array α => xs ≠ #[]]
|
||||
induction xss₂ using array₂_induction
|
||||
simp [← List.map_append]
|
||||
|
||||
@[grind] theorem flatten_push {xss : Array (Array α)} {xs : Array α} :
|
||||
@[grind =] theorem flatten_push {xss : Array (Array α)} {xs : Array α} :
|
||||
flatten (xss.push xs) = flatten xss ++ xs := by
|
||||
induction xss using array₂_induction
|
||||
rcases xs with ⟨l⟩
|
||||
@@ -2284,7 +2288,7 @@ theorem flatMap_def {xs : Array α} {f : α → Array β} : xs.flatMap f = flatt
|
||||
rcases xs with ⟨l⟩
|
||||
simp [flatten_toArray, Function.comp_def, List.flatMap_def]
|
||||
|
||||
@[simp, grind] theorem flatMap_empty {β} {f : α → Array β} : (#[] : Array α).flatMap f = #[] := rfl
|
||||
@[simp, grind =] theorem flatMap_empty {β} {f : α → Array β} : (#[] : Array α).flatMap f = #[] := rfl
|
||||
|
||||
theorem flatMap_toList {xs : Array α} {f : α → List β} :
|
||||
xs.toList.flatMap f = (xs.flatMap (fun a => (f a).toArray)).toList := by
|
||||
@@ -2320,7 +2324,7 @@ theorem size_flatMap {xs : Array α} {f : α → Array β} :
|
||||
rcases xs with ⟨l⟩
|
||||
simp
|
||||
|
||||
@[simp, grind] theorem mem_flatMap {f : α → Array β} {b} {xs : Array α} : b ∈ xs.flatMap f ↔ ∃ a, a ∈ xs ∧ b ∈ f a := by
|
||||
@[simp, grind =] theorem mem_flatMap {f : α → Array β} {b} {xs : Array α} : b ∈ xs.flatMap f ↔ ∃ a, a ∈ xs ∧ b ∈ f a := by
|
||||
simp [flatMap_def, mem_flatten]
|
||||
exact ⟨fun ⟨_, ⟨a, h₁, rfl⟩, h₂⟩ => ⟨a, h₁, h₂⟩, fun ⟨a, h₁, h₂⟩ => ⟨_, ⟨a, h₁, rfl⟩, h₂⟩⟩
|
||||
|
||||
@@ -2348,7 +2352,7 @@ theorem flatMap_singleton {f : α → Array β} {x : α} : #[x].flatMap f = f x
|
||||
rcases xs with ⟨xs⟩
|
||||
simp
|
||||
|
||||
@[simp, grind] theorem flatMap_push {xs : Array α} {x : α} {f : α → Array β} :
|
||||
@[simp, grind =] theorem flatMap_push {xs : Array α} {x : α} {f : α → Array β} :
|
||||
(xs.push x).flatMap f = xs.flatMap f ++ f x := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simp
|
||||
@@ -2417,7 +2421,7 @@ theorem replicate_succ' : replicate (n + 1) a = #[a] ++ replicate n a := by
|
||||
@[deprecated replicate_succ' (since := "2025-03-18")]
|
||||
abbrev mkArray_succ' := @replicate_succ'
|
||||
|
||||
@[simp, grind] theorem mem_replicate {a b : α} {n} : b ∈ replicate n a ↔ n ≠ 0 ∧ b = a := by
|
||||
@[simp, grind =] theorem mem_replicate {a b : α} {n} : b ∈ replicate n a ↔ n ≠ 0 ∧ b = a := by
|
||||
unfold replicate
|
||||
simp only [mem_toArray, List.mem_replicate]
|
||||
|
||||
@@ -2533,7 +2537,7 @@ abbrev replicate_eq_mkArray_iff := @replicate_eq_append_iff
|
||||
@[deprecated map_replicate (since := "2025-03-18")]
|
||||
abbrev map_mkArray := @map_replicate
|
||||
|
||||
@[grind] theorem filter_replicate (w : stop = n) :
|
||||
@[grind =] theorem filter_replicate (w : stop = n) :
|
||||
(replicate n a).filter p 0 stop = if p a then replicate n a else #[] := by
|
||||
apply Array.ext'
|
||||
simp only [w]
|
||||
@@ -2632,14 +2636,14 @@ abbrev sum_mkArray_nat := @sum_replicate_nat
|
||||
|
||||
/-! ### Preliminaries about `swap` needed for `reverse`. -/
|
||||
|
||||
@[grind]
|
||||
@[grind =]
|
||||
theorem getElem?_swap {xs : Array α} {i j : Nat} (hi hj) {k : Nat} : (xs.swap i j hi hj)[k]? =
|
||||
if j = k then some xs[i] else if i = k then some xs[j] else xs[k]? := by
|
||||
simp [swap_def, getElem?_set]
|
||||
|
||||
/-! ### reverse -/
|
||||
|
||||
@[simp, grind] theorem size_reverse {xs : Array α} : xs.reverse.size = xs.size := by
|
||||
@[simp, grind =] theorem size_reverse {xs : Array α} : xs.reverse.size = xs.size := by
|
||||
let rec go (as : Array α) (i j) : (reverse.loop as i j).size = as.size := by
|
||||
rw [reverse.loop]
|
||||
if h : i < j then
|
||||
@@ -2648,7 +2652,7 @@ theorem getElem?_swap {xs : Array α} {i j : Nat} (hi hj) {k : Nat} : (xs.swap i
|
||||
termination_by j - i
|
||||
simp only [reverse]; split <;> simp [go]
|
||||
|
||||
@[simp, grind] theorem reverse_empty : reverse (#[] : Array α) = #[] := rfl
|
||||
@[simp, grind =] theorem reverse_empty : reverse (#[] : Array α) = #[] := rfl
|
||||
|
||||
@[simp] theorem toList_reverse {xs : Array α} : xs.reverse.toList = xs.toList.reverse := by
|
||||
let rec go (as : Array α) (i j hj)
|
||||
@@ -2703,7 +2707,7 @@ theorem getElem?_swap {xs : Array α} {i j : Nat} (hi hj) {k : Nat} : (xs.swap i
|
||||
cases xs
|
||||
simp
|
||||
|
||||
@[simp, grind] theorem getElem_reverse {xs : Array α} {i : Nat} (hi : i < xs.reverse.size) :
|
||||
@[simp, grind =] theorem getElem_reverse {xs : Array α} {i : Nat} (hi : i < xs.reverse.size) :
|
||||
(xs.reverse)[i] = xs[xs.size - 1 - i]'(by simp at hi; omega) := by
|
||||
cases xs
|
||||
simp
|
||||
@@ -2732,14 +2736,14 @@ theorem getElem?_reverse' {xs : Array α} {i j} (h : i + j + 1 = xs.size) : xs.r
|
||||
simp only [List.reverse_toArray, List.getElem?_toArray]
|
||||
rw [List.getElem?_reverse' h]
|
||||
|
||||
@[simp, grind]
|
||||
@[simp, grind =]
|
||||
theorem getElem?_reverse {xs : Array α} {i} (h : i < xs.size) :
|
||||
xs.reverse[i]? = xs[xs.size - 1 - i]? := by
|
||||
cases xs
|
||||
simp_all
|
||||
|
||||
-- The argument `xs : Array α` is explicit to allow rewriting from right to left.
|
||||
@[simp, grind] theorem reverse_reverse (xs : Array α) : xs.reverse.reverse = xs := by
|
||||
@[simp, grind =] theorem reverse_reverse (xs : Array α) : xs.reverse.reverse = xs := by
|
||||
cases xs
|
||||
simp
|
||||
|
||||
@@ -2778,7 +2782,7 @@ theorem reverse_eq_iff {xs ys : Array α} : xs.reverse = ys ↔ xs = ys.reverse
|
||||
cases xs
|
||||
simp
|
||||
|
||||
@[simp, grind] theorem reverse_append {xs ys : Array α} : (xs ++ ys).reverse = ys.reverse ++ xs.reverse := by
|
||||
@[simp, grind =] theorem reverse_append {xs ys : Array α} : (xs ++ ys).reverse = ys.reverse ++ xs.reverse := by
|
||||
cases xs
|
||||
cases ys
|
||||
simp
|
||||
@@ -2802,17 +2806,17 @@ theorem flatten_reverse {xss : Array (Array α)} :
|
||||
cases xss using array₂_induction
|
||||
simp [flatten_toArray, List.flatten_reverse, Function.comp_def]
|
||||
|
||||
@[grind] theorem reverse_flatMap {β} {xs : Array α} {f : α → Array β} :
|
||||
@[grind =] theorem reverse_flatMap {β} {xs : Array α} {f : α → Array β} :
|
||||
(xs.flatMap f).reverse = xs.reverse.flatMap (reverse ∘ f) := by
|
||||
cases xs
|
||||
simp [List.reverse_flatMap, Function.comp_def]
|
||||
|
||||
@[grind] theorem flatMap_reverse {β} {xs : Array α} {f : α → Array β} :
|
||||
@[grind =] theorem flatMap_reverse {β} {xs : Array α} {f : α → Array β} :
|
||||
(xs.reverse.flatMap f) = (xs.flatMap (reverse ∘ f)).reverse := by
|
||||
cases xs
|
||||
simp [List.flatMap_reverse, Function.comp_def]
|
||||
|
||||
@[simp, grind] theorem reverse_replicate {n : Nat} {a : α} : reverse (replicate n a) = replicate n a := by
|
||||
@[simp, grind =] theorem reverse_replicate {n : Nat} {a : α} : reverse (replicate n a) = replicate n a := by
|
||||
rw [← toList_inj]
|
||||
simp
|
||||
|
||||
@@ -2973,10 +2977,10 @@ theorem extract_empty_of_size_le_start {xs : Array α} {start stop : Nat} (h : x
|
||||
simp only [extract, Nat.sub_eq, emptyWithCapacity_eq]
|
||||
rw [←Nat.sub_min_sub_right, Nat.sub_eq_zero_of_le h, Nat.min_zero, extract_loop_zero]
|
||||
|
||||
@[simp, grind] theorem extract_empty {start stop : Nat} : (#[] : Array α).extract start stop = #[] :=
|
||||
@[simp, grind =] theorem extract_empty {start stop : Nat} : (#[] : Array α).extract start stop = #[] :=
|
||||
extract_empty_of_size_le_start (Nat.zero_le _)
|
||||
|
||||
@[simp, grind] theorem extract_zero {xs : Array α} : xs.extract start 0 = #[] := by
|
||||
@[simp, grind =] theorem extract_zero {xs : Array α} : xs.extract start 0 = #[] := by
|
||||
ext i h₁ h₂
|
||||
· simp
|
||||
· simp at h₁
|
||||
@@ -3170,7 +3174,7 @@ theorem foldlM_append [Monad m] [LawfulMonad m] {f : β → α → m β} {b} {xs
|
||||
· rfl
|
||||
· simp at h₂
|
||||
|
||||
@[simp, grind] theorem foldrM_empty [Monad m] {f : α → β → m β} {init : β} {start stop : Nat} :
|
||||
@[simp, grind =] theorem foldrM_empty [Monad m] {f : α → β → m β} {init : β} {start stop : Nat} :
|
||||
foldrM f init #[] start stop = return init := by
|
||||
simp [foldrM]
|
||||
|
||||
@@ -3244,6 +3248,7 @@ rather than `(arr.push a).size` as the argument.
|
||||
(xs.push a).foldrM f init start = f a init >>= xs.foldrM f := by
|
||||
simp [← foldrM_push, h]
|
||||
|
||||
-- TODO: a multi-pattern is being selected there because E-matching does not go inside lambdas.
|
||||
@[simp, grind] theorem _root_.List.foldrM_push_eq_append [Monad m] [LawfulMonad m] {l : List α} {f : α → m β} {xs : Array β} :
|
||||
l.foldrM (fun x xs => xs.push <$> f x) xs = do return xs ++ (← l.reverse.mapM f).toArray := by
|
||||
induction l with
|
||||
@@ -3256,15 +3261,16 @@ rather than `(arr.push a).size` as the argument.
|
||||
funext x
|
||||
simp
|
||||
|
||||
-- TODO: a multi-pattern is being selected there because E-matching does not go inside lambdas.
|
||||
@[simp, grind] theorem _root_.List.foldlM_push_eq_append [Monad m] [LawfulMonad m] {l : List α} {f : α → m β} {xs : Array β} :
|
||||
l.foldlM (fun xs x => xs.push <$> f x) xs = do return xs ++ (← l.mapM f).toArray := by
|
||||
induction l generalizing xs <;> simp [*]
|
||||
|
||||
/-! ### foldl / foldr -/
|
||||
|
||||
@[grind] theorem foldl_empty {f : β → α → β} {init : β} : (#[].foldl f init) = init := rfl
|
||||
@[grind =] theorem foldl_empty {f : β → α → β} {init : β} : (#[].foldl f init) = init := rfl
|
||||
|
||||
@[grind] theorem foldr_empty {f : α → β → β} {init : β} : (#[].foldr f init) = init := rfl
|
||||
@[grind =] theorem foldr_empty {f : α → β → β} {init : β} : (#[].foldr f init) = init := rfl
|
||||
|
||||
theorem foldl_induction
|
||||
{as : Array α} (motive : Nat → β → Prop) {init : β} (h0 : motive 0 init) {f : β → α → β}
|
||||
@@ -3312,7 +3318,7 @@ theorem foldl_push {f : β → α → β} {init : β} {xs : Array α} {a : α} :
|
||||
foldlM_push ..
|
||||
|
||||
/-- Variant of `foldl_push` with a side condition for the `stop` argument. -/
|
||||
@[simp, grind] theorem foldl_push' {f : β → α → β} {init : β} {xs : Array α} {a : α} {stop : Nat}
|
||||
@[simp, grind =] theorem foldl_push' {f : β → α → β} {init : β} {xs : Array α} {a : α} {stop : Nat}
|
||||
(h : stop = xs.size + 1) :
|
||||
(xs.push a).foldl f init 0 stop = f (xs.foldl f init) a := by
|
||||
subst h
|
||||
@@ -3325,10 +3331,11 @@ theorem foldr_push {f : α → β → β} {init : β} {xs : Array α} {a : α} :
|
||||
Variant of `foldr_push` with the `h : start = arr.size + 1`
|
||||
rather than `(arr.push a).size` as the argument.
|
||||
-/
|
||||
@[simp, grind] theorem foldr_push' {f : α → β → β} {init : β} {xs : Array α} {a : α} {start : Nat}
|
||||
@[simp, grind =] theorem foldr_push' {f : α → β → β} {init : β} {xs : Array α} {a : α} {start : Nat}
|
||||
(h : start = xs.size + 1) : (xs.push a).foldr f init start = xs.foldr f (f a init) :=
|
||||
foldrM_push' h
|
||||
|
||||
-- TODO: a multi-pattern is being selected there because E-matching does not go inside lambdas.
|
||||
@[simp, grind] theorem foldl_push_eq_append {as : Array α} {bs : Array β} {f : α → β} (w : stop = as.size) :
|
||||
as.foldl (fun acc a => acc.push (f a)) bs 0 stop = bs ++ as.map f := by
|
||||
subst w
|
||||
@@ -3337,12 +3344,14 @@ rather than `(arr.push a).size` as the argument.
|
||||
simp only [List.foldl_toArray']
|
||||
induction as generalizing bs <;> simp [*]
|
||||
|
||||
-- TODO: a multi-pattern is being selected there because E-matching does not go inside lambdas.
|
||||
@[simp, grind] theorem foldl_cons_eq_append {as : Array α} {bs : List β} {f : α → β} (w : stop = as.size) :
|
||||
as.foldl (fun acc a => (f a) :: acc) bs 0 stop = (as.map f).reverse.toList ++ bs := by
|
||||
subst w
|
||||
rcases as with ⟨as⟩
|
||||
simp
|
||||
|
||||
-- TODO: a multi-pattern is being selected there because E-matching does not go inside lambdas.
|
||||
@[simp, grind] theorem foldr_cons_eq_append {as : Array α} {bs : List β} {f : α → β} (w : start = as.size) :
|
||||
as.foldr (fun a acc => (f a) :: acc) bs start 0 = (as.map f).toList ++ bs := by
|
||||
subst w
|
||||
@@ -3350,27 +3359,29 @@ rather than `(arr.push a).size` as the argument.
|
||||
simp
|
||||
|
||||
/-- Variant of `foldr_cons_eq_append` specialized to `f = id`. -/
|
||||
@[simp, grind] theorem foldr_cons_eq_append' {as : Array α} {bs : List α} (w : start = as.size) :
|
||||
@[simp, grind =] theorem foldr_cons_eq_append' {as : Array α} {bs : List α} (w : start = as.size) :
|
||||
as.foldr List.cons bs start 0 = as.toList ++ bs := by
|
||||
subst w
|
||||
rcases as with ⟨as⟩
|
||||
simp
|
||||
|
||||
-- TODO: a multi-pattern is being selected there because E-matching does not go inside lambdas.
|
||||
@[simp, grind] theorem _root_.List.foldr_push_eq_append {l : List α} {f : α → β} {xs : Array β} :
|
||||
l.foldr (fun x xs => xs.push (f x)) xs = xs ++ (l.reverse.map f).toArray := by
|
||||
induction l <;> simp [*]
|
||||
|
||||
/-- Variant of `List.foldr_push_eq_append` specialized to `f = id`. -/
|
||||
@[simp, grind] theorem _root_.List.foldr_push_eq_append' {l : List α} {xs : Array α} :
|
||||
@[simp, grind =] theorem _root_.List.foldr_push_eq_append' {l : List α} {xs : Array α} :
|
||||
l.foldr (fun x xs => xs.push x) xs = xs ++ l.reverse.toArray := by
|
||||
induction l <;> simp [*]
|
||||
|
||||
-- TODO: a multi-pattern is being selected there because E-matching does not go inside lambdas.
|
||||
@[simp, grind] theorem _root_.List.foldl_push_eq_append {l : List α} {f : α → β} {xs : Array β} :
|
||||
l.foldl (fun xs x => xs.push (f x)) xs = xs ++ (l.map f).toArray := by
|
||||
induction l generalizing xs <;> simp [*]
|
||||
|
||||
/-- Variant of `List.foldl_push_eq_append` specialized to `f = id`. -/
|
||||
@[simp, grind] theorem _root_.List.foldl_push_eq_append' {l : List α} {xs : Array α} :
|
||||
@[simp, grind =] theorem _root_.List.foldl_push_eq_append' {l : List α} {xs : Array α} :
|
||||
l.foldl (fun xs x => xs.push x) xs = xs ++ l.toArray := by
|
||||
simpa using List.foldl_push_eq_append (f := id)
|
||||
|
||||
@@ -3382,24 +3393,28 @@ theorem _root_.List.foldl_push {l : List α} {as : Array α} : l.foldl Array.pus
|
||||
theorem _root_.List.foldr_push {l : List α} {as : Array α} : l.foldr (fun a bs => push bs a) as = as ++ l.reverse.toArray := by
|
||||
rw [List.foldr_eq_foldl_reverse, List.foldl_push_eq_append']
|
||||
|
||||
-- TODO: a multi-pattern is being selected there because E-matching does not go inside lambdas.
|
||||
@[simp, grind] theorem foldr_append_eq_append {xs : Array α} {f : α → Array β} {ys : Array β} :
|
||||
xs.foldr (f · ++ ·) ys = (xs.map f).flatten ++ ys := by
|
||||
rcases xs with ⟨xs⟩
|
||||
rcases ys with ⟨ys⟩
|
||||
induction xs <;> simp_all [Function.comp_def, flatten_toArray]
|
||||
|
||||
-- TODO: a multi-pattern is being selected there because E-matching does not go inside lambdas.
|
||||
@[simp, grind] theorem foldl_append_eq_append {xs : Array α} {f : α → Array β} {ys : Array β} :
|
||||
xs.foldl (· ++ f ·) ys = ys ++ (xs.map f).flatten := by
|
||||
rcases xs with ⟨xs⟩
|
||||
rcases ys with ⟨ys⟩
|
||||
induction xs generalizing ys <;> simp_all [Function.comp_def, flatten_toArray]
|
||||
|
||||
-- TODO: a multi-pattern is being selected there because E-matching does not go inside lambdas.
|
||||
@[simp, grind] theorem foldr_flip_append_eq_append {xs : Array α} {f : α → Array β} {ys : Array β} :
|
||||
xs.foldr (fun x acc => acc ++ f x) ys = ys ++ (xs.map f).reverse.flatten := by
|
||||
rcases xs with ⟨xs⟩
|
||||
rcases ys with ⟨ys⟩
|
||||
induction xs generalizing ys <;> simp_all [Function.comp_def, flatten_toArray]
|
||||
|
||||
-- TODO: a multi-pattern is being selected there because E-matching does not go inside lambdas.
|
||||
@[simp, grind] theorem foldl_flip_append_eq_append {xs : Array α} {f : α → Array β} {ys : Array β} :
|
||||
xs.foldl (fun acc y => f y ++ acc) ys = (xs.map f).reverse.flatten ++ ys:= by
|
||||
rcases xs with ⟨l⟩
|
||||
@@ -3528,12 +3543,12 @@ theorem foldrM_append [Monad m] [LawfulMonad m] {f : α → β → m β} {b} {xs
|
||||
cases xss using array₂_induction
|
||||
simp [List.foldr_flatten, List.foldr_map]
|
||||
|
||||
@[grind] theorem foldl_flatten {f : β → α → β} {b} {xss : Array (Array α)} :
|
||||
@[grind =] theorem foldl_flatten {f : β → α → β} {b} {xss : Array (Array α)} :
|
||||
(flatten xss).foldl f b = xss.foldl (fun b xs => xs.foldl f b) b := by
|
||||
cases xss using array₂_induction
|
||||
simp [List.foldl_flatten, List.foldl_map]
|
||||
|
||||
@[grind] theorem foldr_flatten {f : α → β → β} {b} {xss : Array (Array α)} :
|
||||
@[grind =] theorem foldr_flatten {f : α → β → β} {b} {xss : Array (Array α)} :
|
||||
(flatten xss).foldr f b = xss.foldr (fun xs b => xs.foldr f b) b := by
|
||||
cases xss using array₂_induction
|
||||
simp [List.foldr_flatten, List.foldr_map]
|
||||
@@ -3550,11 +3565,11 @@ theorem foldrM_append [Monad m] [LawfulMonad m] {f : α → β → m β} {b} {xs
|
||||
xs.reverse.foldr f b start 0 = xs.foldl (fun x y => f y x) b :=
|
||||
foldrM_reverse' w
|
||||
|
||||
@[grind] theorem foldl_reverse {xs : Array α} {f : β → α → β} {b} :
|
||||
@[grind =] theorem foldl_reverse {xs : Array α} {f : β → α → β} {b} :
|
||||
xs.reverse.foldl f b = xs.foldr (fun x y => f y x) b :=
|
||||
foldlM_reverse
|
||||
|
||||
@[grind] theorem foldr_reverse {xs : Array α} {f : α → β → β} {b} :
|
||||
@[grind =] theorem foldr_reverse {xs : Array α} {f : α → β → β} {b} :
|
||||
xs.reverse.foldr f b = xs.foldl (fun x y => f y x) b :=
|
||||
foldrM_reverse
|
||||
|
||||
@@ -3659,7 +3674,7 @@ theorem mem_of_back? {xs : Array α} {a : α} (h : xs.back? = some a) : a ∈ xs
|
||||
simp only [List.append_toArray, List.back_toArray]
|
||||
rw [List.getLast_append_of_ne_nil]
|
||||
|
||||
@[grind] theorem back_append {xs : Array α} (h : 0 < (xs ++ ys).size) :
|
||||
@[grind =] theorem back_append {xs : Array α} (h : 0 < (xs ++ ys).size) :
|
||||
(xs ++ ys).back h =
|
||||
if h' : ys.isEmpty then
|
||||
xs.back (by simp_all)
|
||||
@@ -3690,7 +3705,7 @@ theorem back_append_left {xs ys : Array α} (w : 0 < (xs ++ ys).size) (h : ys.si
|
||||
rw [List.getLast_append_left]
|
||||
simpa using h
|
||||
|
||||
@[simp, grind] theorem back?_append {xs ys : Array α} : (xs ++ ys).back? = ys.back?.or xs.back? := by
|
||||
@[simp, grind =] theorem back?_append {xs ys : Array α} : (xs ++ ys).back? = ys.back?.or xs.back? := by
|
||||
rcases xs with ⟨xs⟩
|
||||
rcases ys with ⟨ys⟩
|
||||
simp only [List.append_toArray, List.back?_toArray]
|
||||
@@ -3762,6 +3777,10 @@ theorem contains_iff_exists_mem_beq [BEq α] {xs : Array α} {a : α} :
|
||||
rcases xs with ⟨xs⟩
|
||||
simp [List.contains_iff_exists_mem_beq]
|
||||
|
||||
-- We add this as a `grind` lemma because it is useful without `LawfulBEq α`.
|
||||
-- With `LawfulBEq α`, it would be better to use `contains_iff_mem` directly.
|
||||
grind_pattern contains_iff_exists_mem_beq => xs.contains a
|
||||
|
||||
@[grind _=_]
|
||||
theorem contains_iff_mem [BEq α] [LawfulBEq α] {xs : Array α} {a : α} :
|
||||
xs.contains a ↔ a ∈ xs := by
|
||||
@@ -4004,10 +4023,10 @@ theorem all_filterMap {xs : Array α} {f : α → Option β} {p : β → Bool} :
|
||||
cases xss using array₂_induction
|
||||
simp [Function.comp_def]
|
||||
|
||||
@[grind] theorem any_flatten {xss : Array (Array α)} : xss.flatten.any f = xss.any (any · f) := by
|
||||
@[grind =] theorem any_flatten {xss : Array (Array α)} : xss.flatten.any f = xss.any (any · f) := by
|
||||
simp
|
||||
|
||||
@[grind] theorem all_flatten {xss : Array (Array α)} : xss.flatten.all f = xss.all (all · f) := by
|
||||
@[grind =] theorem all_flatten {xss : Array (Array α)} : xss.flatten.all f = xss.all (all · f) := by
|
||||
simp
|
||||
|
||||
/-- Variant of `any_flatMap` with a side condition for the `stop` argument. -/
|
||||
@@ -4026,11 +4045,11 @@ theorem all_filterMap {xs : Array α} {f : α → Option β} {p : β → Bool} :
|
||||
rw [List.flatMap_toArray]
|
||||
simp [List.all_flatMap]
|
||||
|
||||
@[grind] theorem any_flatMap {xs : Array α} {f : α → Array β} {p : β → Bool} :
|
||||
@[grind =] theorem any_flatMap {xs : Array α} {f : α → Array β} {p : β → Bool} :
|
||||
(xs.flatMap f).any p 0 = xs.any fun a => (f a).any p := by
|
||||
simp
|
||||
|
||||
@[grind] theorem all_flatMap {xs : Array α} {f : α → Array β} {p : β → Bool} :
|
||||
@[grind =] theorem all_flatMap {xs : Array α} {f : α → Array β} {p : β → Bool} :
|
||||
(xs.flatMap f).all p 0 = xs.all fun a => (f a).all p := by
|
||||
simp
|
||||
|
||||
@@ -4048,10 +4067,10 @@ theorem all_filterMap {xs : Array α} {f : α → Option β} {p : β → Bool} :
|
||||
rw [List.reverse_toArray]
|
||||
simp [List.all_reverse]
|
||||
|
||||
@[grind] theorem any_reverse {xs : Array α} : xs.reverse.any f 0 = xs.any f := by
|
||||
@[grind =] theorem any_reverse {xs : Array α} : xs.reverse.any f 0 = xs.any f := by
|
||||
simp
|
||||
|
||||
@[grind] theorem all_reverse {xs : Array α} : xs.reverse.all f 0 = xs.all f := by
|
||||
@[grind =] theorem all_reverse {xs : Array α} : xs.reverse.all f 0 = xs.all f := by
|
||||
simp
|
||||
|
||||
@[simp] theorem any_replicate {n : Nat} {a : α} :
|
||||
@@ -4122,7 +4141,7 @@ theorem getElem_swap' {xs : Array α} {i j : Nat} {hi hj} {k : Nat} (hk : k < xs
|
||||
· simp_all only [getElem_swap_left]
|
||||
· split <;> simp_all
|
||||
|
||||
@[grind]
|
||||
@[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'
|
||||
@@ -4173,13 +4192,13 @@ theorem swapAt!_def {xs : Array α} {i : Nat} {v : α} (h : i < xs.size) :
|
||||
section replace
|
||||
variable [BEq α]
|
||||
|
||||
@[simp, grind] theorem replace_empty : (#[] : Array α).replace a b = #[] := by simp [replace]
|
||||
@[simp, grind =] theorem replace_empty : (#[] : Array α).replace a b = #[] := by simp [replace]
|
||||
|
||||
@[simp, grind] theorem replace_singleton {a b c : α} : #[a].replace b c = #[if a == b then c else a] := by
|
||||
@[simp, grind =] theorem replace_singleton {a b c : α} : #[a].replace b c = #[if a == b then c else a] := by
|
||||
simp only [replace, List.finIdxOf?_toArray, List.finIdxOf?]
|
||||
by_cases h : a == b <;> simp [h]
|
||||
|
||||
@[simp, grind] theorem size_replace {xs : Array α} : (xs.replace a b).size = xs.size := by
|
||||
@[simp, grind =] theorem size_replace {xs : Array α} : (xs.replace a b).size = xs.size := by
|
||||
simp only [replace]
|
||||
split <;> simp
|
||||
|
||||
@@ -4191,7 +4210,7 @@ variable [LawfulBEq α]
|
||||
cases xs
|
||||
simp_all
|
||||
|
||||
@[grind] theorem getElem?_replace {xs : Array α} {i : Nat} :
|
||||
@[grind =] theorem getElem?_replace {xs : Array α} {i : Nat} :
|
||||
(xs.replace a b)[i]? = if xs[i]? == some a then if a ∈ xs.take i then some a else some b else xs[i]? := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simp only [List.replace_toArray, List.getElem?_toArray, List.getElem?_replace, take_eq_extract,
|
||||
@@ -4201,7 +4220,7 @@ theorem getElem?_replace_of_ne {xs : Array α} {i : Nat} (h : xs[i]? ≠ some a)
|
||||
(xs.replace a b)[i]? = xs[i]? := by
|
||||
simp_all [getElem?_replace]
|
||||
|
||||
@[grind] theorem getElem_replace {xs : Array α} {i : Nat} (h : i < xs.size) :
|
||||
@[grind =] theorem getElem_replace {xs : Array α} {i : Nat} (h : i < xs.size) :
|
||||
(xs.replace a b)[i]'(by simpa) = if xs[i] == a then if a ∈ xs.take i then a else b else xs[i] := by
|
||||
apply Option.some.inj
|
||||
rw [← getElem?_eq_getElem, getElem?_replace]
|
||||
@@ -4212,14 +4231,14 @@ theorem getElem_replace_of_ne {xs : Array α} {i : Nat} {h : i < xs.size} (h' :
|
||||
rw [getElem_replace h]
|
||||
simp [h']
|
||||
|
||||
@[grind] theorem replace_append {xs ys : Array α} :
|
||||
@[grind =] theorem replace_append {xs ys : Array α} :
|
||||
(xs ++ ys).replace a b = if a ∈ xs then xs.replace a b ++ ys else xs ++ ys.replace a b := by
|
||||
rcases xs with ⟨xs⟩
|
||||
rcases ys with ⟨ys⟩
|
||||
simp only [List.append_toArray, List.replace_toArray, List.replace_append, mem_toArray]
|
||||
split <;> simp
|
||||
|
||||
@[grind] theorem replace_push {xs : Array α} {a b c : α} :
|
||||
@[grind =] theorem replace_push {xs : Array α} {a b c : α} :
|
||||
(xs.push a).replace b c = if b ∈ xs then (xs.replace b c).push a else xs.push (if b == a then c else a) := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simp [List.replace_append]
|
||||
@@ -4370,7 +4389,7 @@ theorem getElem?_range {n : Nat} {i : Nat} : (Array.range n)[i]? = if i < n then
|
||||
|
||||
/-! ### sum -/
|
||||
|
||||
@[simp, grind] theorem sum_empty [Add α] [Zero α] : (#[] : Array α).sum = 0 := rfl
|
||||
@[simp, grind =] theorem sum_empty [Add α] [Zero α] : (#[] : Array α).sum = 0 := rfl
|
||||
|
||||
-- Without further algebraic hypotheses, there's no useful `sum_push` lemma.
|
||||
|
||||
@@ -4443,7 +4462,7 @@ theorem getElem_mem_toList {xs : Array α} {i : Nat} (h : i < xs.size) : xs[i]
|
||||
theorem back!_eq_back? [Inhabited α] {xs : Array α} : xs.back! = xs.back?.getD default := by
|
||||
simp [back!, back?, getElem!_def, Option.getD]; rfl
|
||||
|
||||
@[simp, grind] theorem back?_push {xs : Array α} {x : α} : (xs.push x).back? = some x := by
|
||||
@[simp, grind =] theorem back?_push {xs : Array α} {x : α} : (xs.push x).back? = some x := by
|
||||
simp [back?]
|
||||
|
||||
@[simp] theorem back!_push [Inhabited α] {xs : Array α} {x : α} : (xs.push x).back! = x := by
|
||||
|
||||
@@ -70,8 +70,8 @@ private theorem cons_lex_cons [BEq α] {lt : α → α → Bool} {a b : α} {xs
|
||||
rw [cons_lex_cons.forIn'_congr_aux Std.PRange.toList_eq_match rfl (fun _ _ _ => rfl)]
|
||||
simp only [Std.PRange.SupportsUpperBound.IsSatisfied, bind_pure_comp, map_pure]
|
||||
rw [cons_lex_cons.forIn'_congr_aux (if_pos (by omega)) rfl (fun _ _ _ => rfl)]
|
||||
simp only [Std.PRange.toList_open_eq_toList_closed_of_isSome_succ? (lo := 0) (h := rfl),
|
||||
Std.PRange.UpwardEnumerable.succ?, Nat.add_comm 1, Std.PRange.Nat.ClosedOpen.toList_succ_succ,
|
||||
simp only [Std.PRange.toList_Rox_eq_toList_Rcx_of_isSome_succ? (lo := 0) (h := rfl),
|
||||
Std.PRange.UpwardEnumerable.succ?, Nat.add_comm 1, Std.PRange.Nat.toList_Rco_succ_succ,
|
||||
Option.get_some, List.forIn'_cons, List.size_toArray, List.length_cons, List.length_nil,
|
||||
Nat.lt_add_one, getElem_append_left, List.getElem_toArray, List.getElem_cons_zero]
|
||||
cases lt a b
|
||||
|
||||
@@ -206,10 +206,13 @@ Converts a bitvector into a fixed-width hexadecimal number with enough digits to
|
||||
|
||||
If `n` is `0`, then one digit is returned. Otherwise, `⌊(n + 3) / 4⌋` digits are returned.
|
||||
-/
|
||||
-- If we ever want to prove something about this, we can avoid having to use the opaque
|
||||
-- `Internal` string functions by moving this definition out to a separate file that can live
|
||||
-- downstream of `Init.Data.String.Basic`.
|
||||
protected def toHex {n : Nat} (x : BitVec n) : String :=
|
||||
let s := (Nat.toDigits 16 x.toNat).asString
|
||||
let t := (List.replicate ((n+3) / 4 - s.length) '0').asString
|
||||
t ++ s
|
||||
let t := (List.replicate ((n+3) / 4 - String.Internal.length s) '0').asString
|
||||
String.Internal.append t s
|
||||
|
||||
/-- `BitVec` representation. -/
|
||||
protected def BitVec.repr (a : BitVec n) : Std.Format :=
|
||||
|
||||
@@ -21,13 +21,6 @@ namespace BitVec
|
||||
|
||||
section Nat
|
||||
|
||||
/--
|
||||
The bitvector with value `i mod 2^n`.
|
||||
-/
|
||||
@[expose, match_pattern]
|
||||
protected def ofNat (n : Nat) (i : Nat) : BitVec n where
|
||||
toFin := Fin.ofNat (2^n) i
|
||||
|
||||
instance instOfNat : OfNat (BitVec n) i where ofNat := .ofNat n i
|
||||
|
||||
/-- Return the bound in terms of toNat. -/
|
||||
|
||||
@@ -19,7 +19,7 @@ theorem testBit_toNat (x : BitVec w) : x.toNat.testBit i = x.getLsbD i := rfl
|
||||
@[simp, grind =] theorem getLsbD_ofFin (x : Fin (2^n)) (i : Nat) :
|
||||
getLsbD (BitVec.ofFin x) i = x.val.testBit i := rfl
|
||||
|
||||
@[simp, grind] theorem getLsbD_of_ge (x : BitVec w) (i : Nat) (ge : w ≤ i) : getLsbD x i = false := by
|
||||
@[simp, grind =] theorem getLsbD_of_ge (x : BitVec w) (i : Nat) (ge : w ≤ i) : getLsbD x i = false := by
|
||||
let ⟨x, x_lt⟩ := x
|
||||
simp only [getLsbD_ofFin]
|
||||
apply Nat.testBit_lt_two_pow
|
||||
|
||||
@@ -37,7 +37,7 @@ namespace BitVec
|
||||
@[simp] theorem getElem_ofFin (x : Fin (2^n)) (i : Nat) (h : i < n) :
|
||||
(BitVec.ofFin x)[i] = x.val.testBit i := rfl
|
||||
|
||||
@[simp, grind] theorem getMsbD_of_ge (x : BitVec w) (i : Nat) (ge : w ≤ i) : getMsbD x i = false := by
|
||||
@[simp, grind =] theorem getMsbD_of_ge (x : BitVec w) (i : Nat) (ge : w ≤ i) : getMsbD x i = false := by
|
||||
rw [getMsbD]
|
||||
simp only [Bool.and_eq_false_imp, decide_eq_true_eq]
|
||||
omega
|
||||
@@ -122,7 +122,7 @@ theorem getElem_of_getLsbD_eq_true {x : BitVec w} {i : Nat} (h : x.getLsbD i = t
|
||||
This normalized a bitvec using `ofFin` to `ofNat`.
|
||||
-/
|
||||
theorem ofFin_eq_ofNat : @BitVec.ofFin w (Fin.mk x lt) = BitVec.ofNat w x := by
|
||||
simp only [BitVec.ofNat, Fin.ofNat, lt, Nat.mod_eq_of_lt]
|
||||
simp only [BitVec.ofNat, Fin.Internal.ofNat_eq_ofNat, Fin.ofNat, lt, Nat.mod_eq_of_lt]
|
||||
|
||||
/-- Prove nonequality of bitvectors in terms of nat operations. -/
|
||||
theorem toNat_ne_iff_ne {n} {x y : BitVec n} : x.toNat ≠ y.toNat ↔ x ≠ y := by
|
||||
@@ -299,7 +299,7 @@ theorem length_pos_of_ne {x y : BitVec w} (h : x ≠ y) : 0 < w :=
|
||||
|
||||
theorem ofFin_ofNat (n : Nat) :
|
||||
ofFin (no_index (OfNat.ofNat n : Fin (2^w))) = OfNat.ofNat n := by
|
||||
simp only [OfNat.ofNat, Fin.ofNat, BitVec.ofNat]
|
||||
simp only [OfNat.ofNat, Fin.Internal.ofNat_eq_ofNat, Fin.ofNat, BitVec.ofNat]
|
||||
|
||||
-- We use a `grind_pattern` as `@[grind]` will not use the `no_index` term.
|
||||
grind_pattern ofFin_ofNat => ofFin (OfNat.ofNat n : Fin (2^w))
|
||||
|
||||
@@ -10,7 +10,6 @@ public import Init.NotationExtra
|
||||
|
||||
public section
|
||||
|
||||
|
||||
namespace Bool
|
||||
|
||||
/--
|
||||
|
||||
@@ -7,5 +7,6 @@ module
|
||||
|
||||
prelude
|
||||
public import Init.Data.ByteArray.Basic
|
||||
public import Init.Data.ByteArray.Extra
|
||||
|
||||
public section
|
||||
|
||||
@@ -6,7 +6,6 @@ Author: Leonardo de Moura
|
||||
module
|
||||
|
||||
prelude
|
||||
public import Init.Data.Array.Basic
|
||||
public import Init.Data.Array.DecidableEq
|
||||
public import Init.Data.UInt.Basic
|
||||
public import Init.Data.UInt.BasicAux
|
||||
@@ -361,27 +360,3 @@ def List.toByteArray (bs : List UInt8) : ByteArray :=
|
||||
loop bs ByteArray.empty
|
||||
|
||||
instance : ToString ByteArray := ⟨fun bs => bs.toList.toString⟩
|
||||
|
||||
/-- Interpret a `ByteArray` of size 8 as a little-endian `UInt64`. -/
|
||||
def ByteArray.toUInt64LE! (bs : ByteArray) : UInt64 :=
|
||||
assert! bs.size == 8
|
||||
(bs.get! 7).toUInt64 <<< 0x38 |||
|
||||
(bs.get! 6).toUInt64 <<< 0x30 |||
|
||||
(bs.get! 5).toUInt64 <<< 0x28 |||
|
||||
(bs.get! 4).toUInt64 <<< 0x20 |||
|
||||
(bs.get! 3).toUInt64 <<< 0x18 |||
|
||||
(bs.get! 2).toUInt64 <<< 0x10 |||
|
||||
(bs.get! 1).toUInt64 <<< 0x8 |||
|
||||
(bs.get! 0).toUInt64
|
||||
|
||||
/-- Interpret a `ByteArray` of size 8 as a big-endian `UInt64`. -/
|
||||
def ByteArray.toUInt64BE! (bs : ByteArray) : UInt64 :=
|
||||
assert! bs.size == 8
|
||||
(bs.get! 0).toUInt64 <<< 0x38 |||
|
||||
(bs.get! 1).toUInt64 <<< 0x30 |||
|
||||
(bs.get! 2).toUInt64 <<< 0x28 |||
|
||||
(bs.get! 3).toUInt64 <<< 0x20 |||
|
||||
(bs.get! 4).toUInt64 <<< 0x18 |||
|
||||
(bs.get! 5).toUInt64 <<< 0x10 |||
|
||||
(bs.get! 6).toUInt64 <<< 0x8 |||
|
||||
(bs.get! 7).toUInt64
|
||||
|
||||
34
src/Init/Data/ByteArray/Extra.lean
Normal file
34
src/Init/Data/ByteArray/Extra.lean
Normal file
@@ -0,0 +1,34 @@
|
||||
/-
|
||||
Copyright (c) 2019 Microsoft Corporation. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Author: Leonardo de Moura
|
||||
-/
|
||||
module
|
||||
|
||||
prelude
|
||||
public import Init.Data.ByteArray.Basic
|
||||
import Init.Data.String.Basic
|
||||
|
||||
/-- Interpret a `ByteArray` of size 8 as a little-endian `UInt64`. -/
|
||||
public def ByteArray.toUInt64LE! (bs : ByteArray) : UInt64 :=
|
||||
assert! bs.size == 8
|
||||
(bs.get! 7).toUInt64 <<< 0x38 |||
|
||||
(bs.get! 6).toUInt64 <<< 0x30 |||
|
||||
(bs.get! 5).toUInt64 <<< 0x28 |||
|
||||
(bs.get! 4).toUInt64 <<< 0x20 |||
|
||||
(bs.get! 3).toUInt64 <<< 0x18 |||
|
||||
(bs.get! 2).toUInt64 <<< 0x10 |||
|
||||
(bs.get! 1).toUInt64 <<< 0x8 |||
|
||||
(bs.get! 0).toUInt64
|
||||
|
||||
/-- Interpret a `ByteArray` of size 8 as a big-endian `UInt64`. -/
|
||||
public def ByteArray.toUInt64BE! (bs : ByteArray) : UInt64 :=
|
||||
assert! bs.size == 8
|
||||
(bs.get! 0).toUInt64 <<< 0x38 |||
|
||||
(bs.get! 1).toUInt64 <<< 0x30 |||
|
||||
(bs.get! 2).toUInt64 <<< 0x28 |||
|
||||
(bs.get! 3).toUInt64 <<< 0x20 |||
|
||||
(bs.get! 4).toUInt64 <<< 0x18 |||
|
||||
(bs.get! 5).toUInt64 <<< 0x10 |||
|
||||
(bs.get! 6).toUInt64 <<< 0x8 |||
|
||||
(bs.get! 7).toUInt64
|
||||
@@ -66,11 +66,6 @@ instance leTotal : Std.Total (· ≤ · : Char → Char → Prop) where
|
||||
def notLTTotal : Std.Total (¬ · < · : Char → Char → Prop) where
|
||||
total := fun x y => by simpa using Char.le_total y x
|
||||
|
||||
theorem utf8Size_eq (c : Char) : c.utf8Size = 1 ∨ c.utf8Size = 2 ∨ c.utf8Size = 3 ∨ c.utf8Size = 4 := by
|
||||
have := c.utf8Size_pos
|
||||
have := c.utf8Size_le_four
|
||||
omega
|
||||
|
||||
@[simp] theorem ofNat_toNat (c : Char) : Char.ofNat c.toNat = c := by
|
||||
rw [Char.ofNat, dif_pos]
|
||||
rfl
|
||||
|
||||
@@ -51,6 +51,11 @@ The assumption `NeZero n` ensures that `Fin n` is nonempty.
|
||||
@[expose] protected def ofNat (n : Nat) [NeZero n] (a : Nat) : Fin n :=
|
||||
⟨a % n, Nat.mod_lt _ (pos_of_neZero n)⟩
|
||||
|
||||
@[simp]
|
||||
theorem Internal.ofNat_eq_ofNat {n : Nat} {hn} {a : Nat} :
|
||||
letI : NeZero n := ⟨Nat.pos_iff_ne_zero.1 hn⟩
|
||||
Fin.Internal.ofNat n hn a = Fin.ofNat n a := rfl
|
||||
|
||||
@[deprecated Fin.ofNat (since := "2025-05-28")]
|
||||
protected def ofNat' (n : Nat) [NeZero n] (a : Nat) : Fin n :=
|
||||
Fin.ofNat n a
|
||||
|
||||
@@ -25,12 +25,12 @@ namespace Fin
|
||||
|
||||
@[deprecated ofNat_zero (since := "2025-05-28")] abbrev ofNat'_zero := @ofNat_zero
|
||||
|
||||
theorem mod_def (a m : Fin n) : a % m = Fin.mk (a % m) (Nat.lt_of_le_of_lt (Nat.mod_le _ _) a.2) :=
|
||||
theorem mod_def (a m : Fin n) : a % m = Fin.mk (a.val % m.val) (Nat.lt_of_le_of_lt (Nat.mod_le _ _) a.2) :=
|
||||
rfl
|
||||
|
||||
theorem mul_def (a b : Fin n) : a * b = Fin.mk ((a * b) % n) (Nat.mod_lt _ a.pos) := rfl
|
||||
theorem mul_def (a b : Fin n) : a * b = Fin.mk ((a.val * b.val) % n) (Nat.mod_lt _ a.pos) := rfl
|
||||
|
||||
theorem sub_def (a b : Fin n) : a - b = Fin.mk (((n - b) + a) % n) (Nat.mod_lt _ a.pos) := rfl
|
||||
theorem sub_def (a b : Fin n) : a - b = Fin.mk (((n - b.val) + a.val) % n) (Nat.mod_lt _ a.pos) := rfl
|
||||
|
||||
theorem pos' : ∀ [Nonempty (Fin n)], 0 < n | ⟨i⟩ => i.pos
|
||||
|
||||
@@ -81,7 +81,7 @@ theorem mk_val (i : Fin n) : (⟨i, i.isLt⟩ : Fin n) = i := Fin.eta ..
|
||||
|
||||
@[deprecated ofNat_self (since := "2025-05-28")] abbrev ofNat'_self := @ofNat_self
|
||||
|
||||
@[simp] theorem ofNat_val_eq_self [NeZero n] (x : Fin n) : (Fin.ofNat n x) = x := by
|
||||
@[simp] theorem ofNat_val_eq_self [NeZero n] (x : Fin n) : (Fin.ofNat n x.val) = x := by
|
||||
ext
|
||||
rw [val_ofNat, Nat.mod_eq_of_lt]
|
||||
exact x.2
|
||||
@@ -121,8 +121,6 @@ Non-trivial loops lead to undesirable and counterintuitive elaboration behavior.
|
||||
For example, for `x : Fin k` and `n : Nat`,
|
||||
it causes `x < n` to be elaborated as `x < ↑n` rather than `↑x < n`,
|
||||
silently introducing wraparound arithmetic.
|
||||
|
||||
Note: as of 2025-06-03, Mathlib has such a coercion for `Fin n` anyway!
|
||||
-/
|
||||
@[expose]
|
||||
def instNatCast (n : Nat) [NeZero n] : NatCast (Fin n) where
|
||||
@@ -265,7 +263,7 @@ instance : LawfulOrderLT (Fin n) where
|
||||
lt_iff := by
|
||||
simp [← Fin.not_le, Decidable.imp_iff_not_or, Std.Total.total]
|
||||
|
||||
@[simp, grind =] theorem val_rev (i : Fin n) : rev i = n - (i + 1) := rfl
|
||||
@[simp, grind =] theorem val_rev (i : Fin n) : (rev i).val = n - (i + 1) := rfl
|
||||
|
||||
@[simp] theorem rev_rev (i : Fin n) : rev (rev i) = i := Fin.ext <| by
|
||||
rw [val_rev, val_rev, ← Nat.sub_sub, Nat.sub_sub_self (by exact i.2), Nat.add_sub_cancel]
|
||||
@@ -500,9 +498,11 @@ theorem succ_succ_ne_one (a : Fin n) : Fin.succ (Fin.succ a) ≠ 1 :=
|
||||
ext
|
||||
simp
|
||||
|
||||
@[simp] theorem cast_trans {k : Nat} (h : n = m) (h' : m = k) {i : Fin n} :
|
||||
@[simp, grind =] theorem cast_cast {k : Nat} (h : n = m) (h' : m = k) {i : Fin n} :
|
||||
(i.cast h).cast h' = i.cast (Eq.trans h h') := rfl
|
||||
|
||||
@[deprecated cast_cast (since := "2025-09-03")] abbrev cast_trans := @cast_cast
|
||||
|
||||
theorem castLE_of_eq {m n : Nat} (h : m = n) {h' : m ≤ n} : castLE h' = Fin.cast h := rfl
|
||||
|
||||
@[simp] theorem coe_castAdd (m : Nat) (i : Fin n) : (castAdd m i : Nat) = i := rfl
|
||||
@@ -531,7 +531,7 @@ theorem cast_castAdd_left {n n' m : Nat} (i : Fin n') (h : n' + m = n + m) :
|
||||
(i.castAdd m').cast h = i.castAdd m := rfl
|
||||
|
||||
theorem castAdd_castAdd {m n p : Nat} (i : Fin m) :
|
||||
(i.castAdd n).castAdd p = (i.castAdd (n + p)).cast (Nat.add_assoc ..).symm := rfl
|
||||
(i.castAdd n).castAdd p = (i.castAdd (n + p)).cast (Nat.add_assoc ..).symm := rfl
|
||||
|
||||
/-- The cast of the successor is the successor of the cast. See `Fin.succ_cast_eq` for rewriting in
|
||||
the reverse direction. -/
|
||||
|
||||
@@ -8,7 +8,7 @@ module
|
||||
prelude
|
||||
public import Init.Control.State
|
||||
public import Init.Data.Int.Basic
|
||||
public import Init.Data.String.Basic
|
||||
public import Init.Data.String.Bootstrap
|
||||
|
||||
public section
|
||||
|
||||
@@ -168,8 +168,8 @@ private def spaceUptoLine : Format → Bool → Int → Nat → SpaceResult
|
||||
else
|
||||
{ foundLine := true }
|
||||
| text s, flatten, _, _ =>
|
||||
let p := s.posOf '\n'
|
||||
let off := s.offsetOfPos p
|
||||
let p := String.Internal.posOf s '\n'
|
||||
let off := String.Internal.offsetOfPos s p
|
||||
{ foundLine := p != s.endPos, foundFlattenedHardLine := flatten && p != s.endPos, space := off }
|
||||
| append f₁ f₂, flatten, m, w => merge w (spaceUptoLine f₁ flatten m w) (spaceUptoLine f₂ flatten m)
|
||||
| nest n f, flatten, m, w => spaceUptoLine f flatten (m - n) w
|
||||
@@ -263,15 +263,15 @@ private partial def be (w : Nat) [Monad m] [MonadPrettyFormat m] : List WorkGrou
|
||||
| append f₁ f₂ => be w (gs' ({ i with f := f₁, activeTags := 0 }::{ i with f := f₂ }::is))
|
||||
| nest n f => be w (gs' ({ i with f, indent := i.indent + n }::is))
|
||||
| text s =>
|
||||
let p := s.posOf '\n'
|
||||
let p := String.Internal.posOf s '\n'
|
||||
if p == s.endPos then
|
||||
pushOutput s
|
||||
endTags i.activeTags
|
||||
be w (gs' is)
|
||||
else
|
||||
pushOutput (s.extract {} p)
|
||||
pushOutput (String.Internal.extract s {} p)
|
||||
pushNewline i.indent.toNat
|
||||
let is := { i with f := text (s.extract (s.next p) s.endPos) }::is
|
||||
let is := { i with f := text (String.Internal.extract s (String.Internal.next s p) s.endPos) }::is
|
||||
-- after a hard line break, re-evaluate whether to flatten the remaining group
|
||||
-- note that we shouldn't start flattening after a hard break outside a group
|
||||
if g.fla == .disallow then
|
||||
@@ -298,7 +298,7 @@ private partial def be (w : Nat) [Monad m] [MonadPrettyFormat m] : List WorkGrou
|
||||
pushGroup FlattenBehavior.fill is gs w >>= be w
|
||||
-- if preceding fill item fit in a single line, try to fit next one too
|
||||
if g.fla.shouldFlatten then
|
||||
let gs'@(g'::_) ← pushGroup FlattenBehavior.fill is gs (w - " ".length)
|
||||
let gs'@(g'::_) ← pushGroup FlattenBehavior.fill is gs (w - String.Internal.length " ")
|
||||
| panic "unreachable"
|
||||
if g'.fla.shouldFlatten then
|
||||
pushOutput " "
|
||||
@@ -316,7 +316,7 @@ private partial def be (w : Nat) [Monad m] [MonadPrettyFormat m] : List WorkGrou
|
||||
else
|
||||
let k ← currColumn
|
||||
if k < i.indent then
|
||||
pushOutput ("".pushn ' ' (i.indent - k).toNat)
|
||||
pushOutput (String.Internal.pushn "" ' ' (i.indent - k).toNat)
|
||||
endTags i.activeTags
|
||||
be w (gs' is)
|
||||
else
|
||||
@@ -350,7 +350,7 @@ Creates a format `l ++ f ++ r` with a flattening group, nesting the contents by
|
||||
The group's `FlattenBehavior` is `allOrNone`; for `fill` use `Std.Format.bracketFill`.
|
||||
-/
|
||||
@[inline] def bracket (l : String) (f : Format) (r : String) : Format :=
|
||||
group (nest l.length $ l ++ f ++ r)
|
||||
group (nest (String.Internal.length l) $ l ++ f ++ r)
|
||||
|
||||
/--
|
||||
Creates the format `"(" ++ f ++ ")"` with a flattening group, nesting by one space.
|
||||
@@ -372,7 +372,7 @@ Creates a format `l ++ f ++ r` with a flattening group, nesting the contents by
|
||||
The group's `FlattenBehavior` is `fill`; for `allOrNone` use `Std.Format.bracketFill`.
|
||||
-/
|
||||
@[inline] def bracketFill (l : String) (f : Format) (r : String) : Format :=
|
||||
fill (nest l.length $ l ++ f ++ r)
|
||||
fill (nest (String.Internal.length l) $ l ++ f ++ r)
|
||||
|
||||
/-- The default indentation level, which is two spaces. -/
|
||||
def defIndent := 2
|
||||
@@ -397,8 +397,8 @@ private structure State where
|
||||
|
||||
private instance : MonadPrettyFormat (StateM State) where
|
||||
-- We avoid a structure instance update, and write these functions using pattern matching because of issue #316
|
||||
pushOutput s := modify fun ⟨out, col⟩ => ⟨out ++ s, col + s.length⟩
|
||||
pushNewline indent := modify fun ⟨out, _⟩ => ⟨out ++ "\n".pushn ' ' indent, indent⟩
|
||||
pushOutput s := modify fun ⟨out, col⟩ => ⟨String.Internal.append out s, col + (String.Internal.length s)⟩
|
||||
pushNewline indent := modify fun ⟨out, _⟩ => ⟨String.Internal.append out (String.Internal.pushn "\n" ' ' indent), indent⟩
|
||||
currColumn := return (← get).column
|
||||
startTag _ := return ()
|
||||
endTags _ := return ()
|
||||
|
||||
@@ -9,6 +9,7 @@ prelude
|
||||
public import Init.Data.Format.Basic
|
||||
public import Init.Data.Array.Basic
|
||||
public import Init.Data.ToString.Basic
|
||||
import Init.Data.String.Basic
|
||||
|
||||
public section
|
||||
|
||||
|
||||
@@ -9,6 +9,8 @@ prelude
|
||||
public import Init.Data.Format.Macro
|
||||
public import Init.Data.Format.Instances
|
||||
public import Init.Meta
|
||||
import Init.Data.String.Basic
|
||||
import Init.Data.ToString.Name
|
||||
|
||||
public section
|
||||
|
||||
|
||||
@@ -34,20 +34,104 @@ Examples:
|
||||
@[inline, expose]
|
||||
def uncurry : (α → β → φ) → α × β → φ := fun f a => f a.1 a.2
|
||||
|
||||
@[simp, grind]
|
||||
@[simp, grind =]
|
||||
theorem curry_uncurry (f : α → β → φ) : curry (uncurry f) = f :=
|
||||
rfl
|
||||
|
||||
@[simp, grind]
|
||||
@[simp, grind =]
|
||||
theorem uncurry_curry (f : α × β → φ) : uncurry (curry f) = f :=
|
||||
funext fun ⟨_a, _b⟩ => rfl
|
||||
|
||||
@[simp, grind]
|
||||
@[simp, grind =]
|
||||
theorem uncurry_apply_pair {α β γ} (f : α → β → γ) (x : α) (y : β) : uncurry f (x, y) = f x y :=
|
||||
rfl
|
||||
|
||||
@[simp, grind]
|
||||
@[simp, grind =]
|
||||
theorem curry_apply {α β γ} (f : α × β → γ) (x : α) (y : β) : curry f x y = f (x, y) :=
|
||||
rfl
|
||||
|
||||
/-- A function `f : α → β` is called injective if `f x = f y` implies `x = y`. -/
|
||||
def Injective (f : α → β) : Prop :=
|
||||
∀ ⦃a₁ a₂⦄, f a₁ = f a₂ → a₁ = a₂
|
||||
|
||||
theorem Injective.comp {g : β → φ} {f : α → β} (hg : Injective g) (hf : Injective f) :
|
||||
Injective (g ∘ f) := fun _a₁ _a₂ => fun h => hf (hg h)
|
||||
|
||||
/-- A function `f : α → β` is called surjective if every `b : β` is equal to `f a`
|
||||
for some `a : α`. -/
|
||||
def Surjective (f : α → β) : Prop :=
|
||||
∀ b, Exists fun a => f a = b
|
||||
|
||||
theorem Surjective.comp {g : β → φ} {f : α → β} (hg : Surjective g) (hf : Surjective f) :
|
||||
Surjective (g ∘ f) := fun c : φ =>
|
||||
Exists.elim (hg c) fun b hb =>
|
||||
Exists.elim (hf b) fun a ha =>
|
||||
Exists.intro a (show g (f a) = c from Eq.trans (congrArg g ha) hb)
|
||||
|
||||
/-- `LeftInverse g f` means that `g` is a left inverse to `f`. That is, `g ∘ f = id`. -/
|
||||
@[grind]
|
||||
def LeftInverse (g : β → α) (f : α → β) : Prop :=
|
||||
∀ x, g (f x) = x
|
||||
|
||||
/-- `HasLeftInverse f` means that `f` has an unspecified left inverse. -/
|
||||
def HasLeftInverse (f : α → β) : Prop :=
|
||||
Exists fun finv : β → α => LeftInverse finv f
|
||||
|
||||
/-- `RightInverse g f` means that `g` is a right inverse to `f`. That is, `f ∘ g = id`. -/
|
||||
@[grind]
|
||||
def RightInverse (g : β → α) (f : α → β) : Prop :=
|
||||
LeftInverse f g
|
||||
|
||||
/-- `HasRightInverse f` means that `f` has an unspecified right inverse. -/
|
||||
def HasRightInverse (f : α → β) : Prop :=
|
||||
Exists fun finv : β → α => RightInverse finv f
|
||||
|
||||
theorem LeftInverse.injective {g : β → α} {f : α → β} : LeftInverse g f → Injective f :=
|
||||
fun h a b faeqfb => ((h a).symm.trans (congrArg g faeqfb)).trans (h b)
|
||||
|
||||
theorem HasLeftInverse.injective {f : α → β} : HasLeftInverse f → Injective f := fun h =>
|
||||
Exists.elim h fun _finv inv => inv.injective
|
||||
|
||||
theorem rightInverse_of_injective_of_leftInverse {f : α → β} {g : β → α} (injf : Injective f)
|
||||
(lfg : LeftInverse f g) : RightInverse f g := fun x =>
|
||||
have h : f (g (f x)) = f x := lfg (f x)
|
||||
injf h
|
||||
|
||||
theorem RightInverse.surjective {f : α → β} {g : β → α} (h : RightInverse g f) : Surjective f :=
|
||||
fun y => ⟨g y, h y⟩
|
||||
|
||||
theorem HasRightInverse.surjective {f : α → β} : HasRightInverse f → Surjective f
|
||||
| ⟨_finv, inv⟩ => inv.surjective
|
||||
|
||||
theorem leftInverse_of_surjective_of_rightInverse {f : α → β} {g : β → α} (surjf : Surjective f)
|
||||
(rfg : RightInverse f g) : LeftInverse f g := fun y =>
|
||||
Exists.elim (surjf y) fun x hx => ((hx ▸ rfl : f (g y) = f (g (f x))).trans (Eq.symm (rfg x) ▸ rfl)).trans hx
|
||||
|
||||
theorem injective_id : Injective (@id α) := fun _a₁ _a₂ h => h
|
||||
|
||||
theorem surjective_id : Surjective (@id α) := fun a => ⟨a, rfl⟩
|
||||
|
||||
variable {f : α → β}
|
||||
|
||||
theorem Injective.eq_iff (I : Injective f) {a b : α} : f a = f b ↔ a = b :=
|
||||
⟨@I _ _, congrArg f⟩
|
||||
|
||||
theorem Injective.eq_iff' (I : Injective f) {a b : α} {c : β} (h : f b = c) : f a = c ↔ a = b :=
|
||||
h ▸ I.eq_iff
|
||||
|
||||
theorem Injective.ne (hf : Injective f) {a₁ a₂ : α} : a₁ ≠ a₂ → f a₁ ≠ f a₂ :=
|
||||
mt fun h ↦ hf h
|
||||
|
||||
theorem Injective.ne_iff (hf : Injective f) {x y : α} : f x ≠ f y ↔ x ≠ y :=
|
||||
⟨mt <| congrArg f, hf.ne⟩
|
||||
|
||||
theorem Injective.ne_iff' (hf : Injective f) {x y : α} {z : β} (h : f y = z) : f x ≠ z ↔ x ≠ y :=
|
||||
h ▸ hf.ne_iff
|
||||
|
||||
protected theorem LeftInverse.id {g : β → α} {f : α → β} (h : LeftInverse g f) : g ∘ f = id :=
|
||||
funext h
|
||||
|
||||
protected theorem RightInverse.id {g : β → α} {f : α → β} (h : RightInverse g f) : f ∘ g = id :=
|
||||
funext h
|
||||
|
||||
end Function
|
||||
|
||||
@@ -379,8 +379,11 @@ def Poly.mul (p : Poly) (k : Int) : Poly :=
|
||||
p₁)
|
||||
fuel
|
||||
|
||||
@[expose] noncomputable def Poly.combine_mul_k (a b : Int) : Poly → Poly → Poly :=
|
||||
combine_mul_k' hugeFuel a b
|
||||
@[expose] noncomputable def Poly.combine_mul_k (a b : Int) (p₁ p₂ : Poly) : Poly :=
|
||||
Bool.rec
|
||||
(Bool.rec (combine_mul_k' hugeFuel a b p₁ p₂) (p₁.mul_k a) (Int.beq' b 0))
|
||||
(p₂.mul_k b)
|
||||
(Int.beq' a 0)
|
||||
|
||||
@[simp] theorem Poly.denote_mul (ctx : Context) (p : Poly) (k : Int) : (p.mul k).denote ctx = k * p.denote ctx := by
|
||||
simp [mul]
|
||||
@@ -424,34 +427,36 @@ theorem Poly.denote_combine (ctx : Context) (p₁ p₂ : Poly) : (p₁.combine p
|
||||
|
||||
theorem Poly.denote_combine_mul_k (ctx : Context) (a b : Int) (p₁ p₂ : Poly) : (p₁.combine_mul_k a b p₂).denote ctx = a * p₁.denote ctx + b * p₂.denote ctx := by
|
||||
unfold combine_mul_k
|
||||
cases h₁ : Int.beq' a 0 <;> simp at h₁ <;> simp [*]
|
||||
cases h₂ : Int.beq' b 0 <;> simp at h₂ <;> simp [*]
|
||||
generalize hugeFuel = fuel
|
||||
induction fuel generalizing p₁ p₂
|
||||
next => show ((p₁.mul a).append (p₂.mul b)).denote ctx = _; simp
|
||||
next fuel ih =>
|
||||
cases p₁ <;> cases p₂ <;> simp [combine_mul_k']
|
||||
next k₁ k₂ v₂ p₂ =>
|
||||
show _ + (combine_mul_k' fuel a b (.num k₁) p₂).denote ctx = _
|
||||
simp [ih, Int.mul_assoc]
|
||||
next k₁ v₁ p₁ k₂ =>
|
||||
show _ + (combine_mul_k' fuel a b p₁ (.num k₂)).denote ctx = _
|
||||
simp [ih, Int.mul_assoc]
|
||||
next k₁ v₁ p₁ k₂ v₂ p₂ =>
|
||||
cases h₁ : Nat.beq v₁ v₂ <;> simp
|
||||
next =>
|
||||
cases h₂ : Nat.blt v₂ v₁ <;> simp
|
||||
next =>
|
||||
show _ + (combine_mul_k' fuel a b (add k₁ v₁ p₁) p₂).denote ctx = _
|
||||
simp [ih, Int.mul_assoc]
|
||||
next =>
|
||||
show _ + (combine_mul_k' fuel a b p₁ (add k₂ v₂ p₂)).denote ctx = _
|
||||
simp [ih, Int.mul_assoc]
|
||||
next =>
|
||||
simp at h₁; subst v₂
|
||||
cases h₂ : (a * k₁ + b * k₂).beq' 0 <;> simp
|
||||
next =>
|
||||
cases p₁ <;> cases p₂ <;> simp [combine_mul_k']
|
||||
next k₁ k₂ v₂ p₂ =>
|
||||
show _ + (combine_mul_k' fuel a b (.num k₁) p₂).denote ctx = _
|
||||
simp [ih, Int.mul_assoc]
|
||||
next k₁ v₁ p₁ k₂ =>
|
||||
show _ + (combine_mul_k' fuel a b p₁ (.num k₂)).denote ctx = _
|
||||
simp [ih, Int.mul_assoc]
|
||||
next k₁ v₁ p₁ k₂ v₂ p₂ =>
|
||||
cases h₁ : Nat.beq v₁ v₂ <;> simp
|
||||
next =>
|
||||
cases h₂ : Nat.blt v₂ v₁ <;> simp
|
||||
next =>
|
||||
show _ + (combine_mul_k' fuel a b (add k₁ v₁ p₁) p₂).denote ctx = _
|
||||
simp [ih, Int.mul_assoc]
|
||||
next =>
|
||||
show _ + (combine_mul_k' fuel a b p₁ (add k₂ v₂ p₂)).denote ctx = _
|
||||
simp [ih, Int.mul_assoc]
|
||||
next =>
|
||||
simp at h₁; subst v₂
|
||||
cases h₂ : (a * k₁ + b * k₂).beq' 0 <;> simp
|
||||
next =>
|
||||
show a * k₁ * v₁.denote ctx + (b * k₂ * v₁.denote ctx + (combine_mul_k' fuel a b p₁ p₂).denote ctx) = _
|
||||
simp [ih, Int.mul_assoc]
|
||||
next =>
|
||||
next =>
|
||||
simp at h₂
|
||||
show (combine_mul_k' fuel a b p₁ p₂).denote ctx = _
|
||||
simp [ih, ← Int.mul_assoc, ← Int.add_mul, h₂]
|
||||
|
||||
@@ -174,7 +174,7 @@ theorem mem_attach (l : List α) : ∀ x, x ∈ l.attach
|
||||
rcases this with ⟨⟨_, _⟩, m, rfl⟩
|
||||
exact m
|
||||
|
||||
@[simp, grind]
|
||||
@[simp, grind =]
|
||||
theorem mem_attachWith {l : List α} {q : α → Prop} (H) (x : {x // q x}) :
|
||||
x ∈ l.attachWith q H ↔ x.1 ∈ l := by
|
||||
induction l with
|
||||
@@ -192,12 +192,13 @@ theorem mem_pmap {p : α → Prop} {f : ∀ a, p a → β} {l H b} :
|
||||
b ∈ pmap f l H ↔ ∃ (a : _) (h : a ∈ l), f a (H a h) = b := by
|
||||
simp only [pmap_eq_map_attach, mem_map, mem_attach, true_and, Subtype.exists, eq_comm]
|
||||
|
||||
@[grind]
|
||||
theorem mem_pmap_of_mem {p : α → Prop} {f : ∀ a, p a → β} {l H} {a} (h : a ∈ l) :
|
||||
f a (H a h) ∈ pmap f l H := by
|
||||
rw [mem_pmap]
|
||||
exact ⟨a, h, rfl⟩
|
||||
|
||||
grind_pattern mem_pmap_of_mem => _ ∈ pmap f l H, a ∈ l
|
||||
|
||||
@[simp, grind =]
|
||||
theorem length_pmap {p : α → Prop} {f : ∀ a, p a → β} {l H} : (pmap f l H).length = l.length := by
|
||||
induction l
|
||||
@@ -370,13 +371,13 @@ theorem getElem_attach {xs : List α} {i : Nat} (h : i < xs.attach.length) :
|
||||
xs.attach.tail = xs.tail.attach.map (fun ⟨x, h⟩ => ⟨x, mem_of_mem_tail h⟩) := by
|
||||
cases xs <;> simp
|
||||
|
||||
@[grind]
|
||||
@[grind =]
|
||||
theorem foldl_pmap {l : List α} {P : α → Prop} {f : (a : α) → P a → β}
|
||||
(H : ∀ (a : α), a ∈ l → P a) (g : γ → β → γ) (x : γ) :
|
||||
(l.pmap f H).foldl g x = l.attach.foldl (fun acc a => g acc (f a.1 (H _ a.2))) x := by
|
||||
rw [pmap_eq_map_attach, foldl_map]
|
||||
|
||||
@[grind]
|
||||
@[grind =]
|
||||
theorem foldr_pmap {l : List α} {P : α → Prop} {f : (a : α) → P a → β}
|
||||
(H : ∀ (a : α), a ∈ l → P a) (g : β → γ → γ) (x : γ) :
|
||||
(l.pmap f H).foldr g x = l.attach.foldr (fun a acc => g (f a.1 (H _ a.2)) acc) x := by
|
||||
|
||||
@@ -80,17 +80,17 @@ namespace List
|
||||
|
||||
/-! ### length -/
|
||||
|
||||
@[simp, grind] theorem length_nil : length ([] : List α) = 0 :=
|
||||
@[simp, grind =] theorem length_nil : length ([] : List α) = 0 :=
|
||||
rfl
|
||||
|
||||
@[simp] theorem length_singleton {a : α} : length [a] = 1 := rfl
|
||||
|
||||
@[simp, grind] theorem length_cons {a : α} {as : List α} : (cons a as).length = as.length + 1 :=
|
||||
@[simp, grind =] theorem length_cons {a : α} {as : List α} : (cons a as).length = as.length + 1 :=
|
||||
rfl
|
||||
|
||||
/-! ### set -/
|
||||
|
||||
@[simp, grind] theorem length_set {as : List α} {i : Nat} {a : α} : (as.set i a).length = as.length := by
|
||||
@[simp, grind =] theorem length_set {as : List α} {i : Nat} {a : α} : (as.set i a).length = as.length := by
|
||||
induction as generalizing i with
|
||||
| nil => rfl
|
||||
| cons x xs ih =>
|
||||
@@ -101,8 +101,8 @@ namespace List
|
||||
/-! ### foldl -/
|
||||
|
||||
-- As `List.foldl` is defined in `Init.Prelude`, we write the basic simplification lemmas here.
|
||||
@[simp, grind] theorem foldl_nil : [].foldl f b = b := rfl
|
||||
@[simp, grind] theorem foldl_cons {l : List α} {f : β → α → β} {b : β} : (a :: l).foldl f b = l.foldl f (f b a) := rfl
|
||||
@[simp, grind =] theorem foldl_nil : [].foldl f b = b := rfl
|
||||
@[simp, grind =] theorem foldl_cons {l : List α} {f : β → α → β} {b : β} : (a :: l).foldl f b = l.foldl f (f b a) := rfl
|
||||
|
||||
/-! ### concat -/
|
||||
|
||||
@@ -332,7 +332,7 @@ def getLast? : List α → Option α
|
||||
| [] => none
|
||||
| a::as => some (getLast (a::as) (fun h => List.noConfusion h))
|
||||
|
||||
@[simp, grind] theorem getLast?_nil : @getLast? α [] = none := rfl
|
||||
@[simp, grind =] theorem getLast?_nil : @getLast? α [] = none := rfl
|
||||
|
||||
/-! ### getLastD -/
|
||||
|
||||
@@ -365,7 +365,7 @@ Returns the first element of a non-empty list.
|
||||
def head : (as : List α) → as ≠ [] → α
|
||||
| a::_, _ => a
|
||||
|
||||
@[simp, grind] theorem head_cons {a : α} {l : List α} {h} : head (a::l) h = a := rfl
|
||||
@[simp, grind =] theorem head_cons {a : α} {l : List α} {h} : head (a::l) h = a := rfl
|
||||
|
||||
/-! ### head? -/
|
||||
|
||||
@@ -383,8 +383,8 @@ def head? : List α → Option α
|
||||
| [] => none
|
||||
| a::_ => some a
|
||||
|
||||
@[simp, grind] theorem head?_nil : head? ([] : List α) = none := rfl
|
||||
@[simp, grind] theorem head?_cons {a : α} {l : List α} : head? (a::l) = some a := rfl
|
||||
@[simp, grind =] theorem head?_nil : head? ([] : List α) = none := rfl
|
||||
@[simp, grind =] theorem head?_cons {a : α} {l : List α} : head? (a::l) = some a := rfl
|
||||
|
||||
/-! ### headD -/
|
||||
|
||||
@@ -420,8 +420,8 @@ def tail : List α → List α
|
||||
| [] => []
|
||||
| _::as => as
|
||||
|
||||
@[simp, grind] theorem tail_nil : tail ([] : List α) = [] := rfl
|
||||
@[simp, grind] theorem tail_cons {a : α} {as : List α} : tail (a::as) = as := rfl
|
||||
@[simp, grind =] theorem tail_nil : tail ([] : List α) = [] := rfl
|
||||
@[simp, grind =] theorem tail_cons {a : α} {as : List α} : tail (a::as) = as := rfl
|
||||
|
||||
/-! ### tail? -/
|
||||
|
||||
@@ -441,8 +441,8 @@ def tail? : List α → Option (List α)
|
||||
| [] => none
|
||||
| _::as => some as
|
||||
|
||||
@[simp, grind] theorem tail?_nil : tail? ([] : List α) = none := rfl
|
||||
@[simp, grind] theorem tail?_cons {a : α} {l : List α} : tail? (a::l) = some l := rfl
|
||||
@[simp, grind =] theorem tail?_nil : tail? ([] : List α) = none := rfl
|
||||
@[simp, grind =] theorem tail?_cons {a : α} {l : List α} : tail? (a::l) = some l := rfl
|
||||
|
||||
/-! ### tailD -/
|
||||
|
||||
@@ -490,8 +490,8 @@ Examples:
|
||||
| [] => []
|
||||
| a::as => f a :: map f as
|
||||
|
||||
@[simp, grind] theorem map_nil {f : α → β} : map f [] = [] := rfl
|
||||
@[simp, grind] theorem map_cons {f : α → β} {a : α} {l : List α} : map f (a :: l) = f a :: map f l := rfl
|
||||
@[simp, grind =] theorem map_nil {f : α → β} : map f [] = [] := rfl
|
||||
@[simp, grind =] theorem map_cons {f : α → β} {a : α} {l : List α} : map f (a :: l) = f a :: map f l := rfl
|
||||
|
||||
/-! ### filter -/
|
||||
|
||||
@@ -511,7 +511,7 @@ def filter (p : α → Bool) : (l : List α) → List α
|
||||
| true => a :: filter p as
|
||||
| false => filter p as
|
||||
|
||||
@[simp, grind] theorem filter_nil {p : α → Bool} : filter p [] = [] := rfl
|
||||
@[simp, grind =] theorem filter_nil {p : α → Bool} : filter p [] = [] := rfl
|
||||
|
||||
/-! ### filterMap -/
|
||||
|
||||
@@ -537,8 +537,8 @@ Example:
|
||||
| none => filterMap f as
|
||||
| some b => b :: filterMap f as
|
||||
|
||||
@[simp, grind] theorem filterMap_nil {f : α → Option β} : filterMap f [] = [] := rfl
|
||||
@[grind] theorem filterMap_cons {f : α → Option β} {a : α} {l : List α} :
|
||||
@[simp, grind =] theorem filterMap_nil {f : α → Option β} : filterMap f [] = [] := rfl
|
||||
@[grind =] theorem filterMap_cons {f : α → Option β} {a : α} {l : List α} :
|
||||
filterMap f (a :: l) =
|
||||
match f a with
|
||||
| none => filterMap f l
|
||||
@@ -561,8 +561,8 @@ Examples:
|
||||
| [] => init
|
||||
| a :: l => f a (foldr f init l)
|
||||
|
||||
@[simp, grind] theorem foldr_nil : [].foldr f b = b := rfl
|
||||
@[simp, grind] theorem foldr_cons {a} {l : List α} {f : α → β → β} {b} :
|
||||
@[simp, grind =] theorem foldr_nil : [].foldr f b = b := rfl
|
||||
@[simp, grind =] theorem foldr_cons {a} {l : List α} {f : α → β → β} {b} :
|
||||
(a :: l).foldr f b = f a (l.foldr f b) := rfl
|
||||
|
||||
/-! ### reverse -/
|
||||
@@ -591,7 +591,7 @@ Examples:
|
||||
@[expose] def reverse (as : List α) : List α :=
|
||||
reverseAux as []
|
||||
|
||||
@[simp, grind] theorem reverse_nil : reverse ([] : List α) = [] := rfl
|
||||
@[simp, grind =] theorem reverse_nil : reverse ([] : List α) = [] := rfl
|
||||
|
||||
theorem reverseAux_reverseAux {as bs cs : List α} :
|
||||
reverseAux (reverseAux as bs) cs = reverseAux bs (reverseAux (reverseAux as []) cs) := by
|
||||
@@ -645,10 +645,10 @@ instance : Append (List α) := ⟨List.append⟩
|
||||
|
||||
@[simp] theorem append_eq {as bs : List α} : List.append as bs = as ++ bs := rfl
|
||||
|
||||
@[simp, grind] theorem nil_append (as : List α) : [] ++ as = as := rfl
|
||||
@[simp, grind =] theorem nil_append (as : List α) : [] ++ as = as := rfl
|
||||
@[simp, grind _=_] theorem cons_append {a : α} {as bs : List α} : (a::as) ++ bs = a::(as ++ bs) := rfl
|
||||
|
||||
@[simp, grind] theorem append_nil (as : List α) : as ++ [] = as := by
|
||||
@[simp, grind =] theorem append_nil (as : List α) : as ++ [] = as := by
|
||||
induction as with
|
||||
| nil => rfl
|
||||
| cons a as ih =>
|
||||
@@ -658,7 +658,7 @@ instance : Std.LawfulIdentity (α := List α) (· ++ ·) [] where
|
||||
left_id := nil_append
|
||||
right_id := append_nil
|
||||
|
||||
@[simp, grind] theorem length_append {as bs : List α} : (as ++ bs).length = as.length + bs.length := by
|
||||
@[simp, grind =] theorem length_append {as bs : List α} : (as ++ bs).length = as.length + bs.length := by
|
||||
induction as with
|
||||
| nil => simp
|
||||
| cons _ as ih => simp [ih, Nat.succ_add]
|
||||
@@ -685,7 +685,7 @@ theorem reverseAux_eq_append {as bs : List α} : reverseAux as bs = reverseAux a
|
||||
rw [ih (bs := a :: bs), ih (bs := [a]), append_assoc]
|
||||
rfl
|
||||
|
||||
@[simp, grind] theorem reverse_cons {a : α} {as : List α} : reverse (a :: as) = reverse as ++ [a] := by
|
||||
@[simp, grind =] theorem reverse_cons {a : α} {as : List α} : reverse (a :: as) = reverse as ++ [a] := by
|
||||
simp [reverse, reverseAux]
|
||||
rw [← reverseAux_eq_append]
|
||||
|
||||
@@ -704,8 +704,8 @@ def flatten : List (List α) → List α
|
||||
| [] => []
|
||||
| l :: L => l ++ flatten L
|
||||
|
||||
@[simp, grind] theorem flatten_nil : List.flatten ([] : List (List α)) = [] := rfl
|
||||
@[simp, grind] theorem flatten_cons : (l :: L).flatten = l ++ L.flatten := rfl
|
||||
@[simp, grind =] theorem flatten_nil : List.flatten ([] : List (List α)) = [] := rfl
|
||||
@[simp, grind =] theorem flatten_cons : (l :: L).flatten = l ++ L.flatten := rfl
|
||||
|
||||
/-! ### singleton -/
|
||||
|
||||
@@ -731,8 +731,8 @@ Examples:
|
||||
-/
|
||||
@[inline] def flatMap {α : Type u} {β : Type v} (b : α → List β) (as : List α) : List β := flatten (map b as)
|
||||
|
||||
@[simp, grind] theorem flatMap_nil {f : α → List β} : List.flatMap f [] = [] := by simp [List.flatMap]
|
||||
@[simp, grind] theorem flatMap_cons {x : α} {xs : List α} {f : α → List β} :
|
||||
@[simp, grind =] theorem flatMap_nil {f : α → List β} : List.flatMap f [] = [] := by simp [List.flatMap]
|
||||
@[simp, grind =] theorem flatMap_cons {x : α} {xs : List α} {f : α → List β} :
|
||||
List.flatMap f (x :: xs) = f x ++ List.flatMap f xs := by simp [List.flatMap]
|
||||
|
||||
/-! ### replicate -/
|
||||
@@ -748,10 +748,10 @@ def replicate : (n : Nat) → (a : α) → List α
|
||||
| 0, _ => []
|
||||
| n+1, a => a :: replicate n a
|
||||
|
||||
@[simp, grind] theorem replicate_zero {a : α} : replicate 0 a = [] := rfl
|
||||
@[grind] theorem replicate_succ {a : α} {n : Nat} : replicate (n+1) a = a :: replicate n a := rfl
|
||||
@[simp, grind =] theorem replicate_zero {a : α} : replicate 0 a = [] := rfl
|
||||
@[grind =] theorem replicate_succ {a : α} {n : Nat} : replicate (n+1) a = a :: replicate n a := rfl
|
||||
|
||||
@[simp, grind] theorem length_replicate {n : Nat} {a : α} : (replicate n a).length = n := by
|
||||
@[simp, grind =] theorem length_replicate {n : Nat} {a : α} : (replicate n a).length = n := by
|
||||
induction n with
|
||||
| zero => simp
|
||||
| succ n ih => simp only [ih, replicate_succ, length_cons]
|
||||
@@ -819,8 +819,8 @@ def isEmpty : List α → Bool
|
||||
| [] => true
|
||||
| _ :: _ => false
|
||||
|
||||
@[simp, grind] theorem isEmpty_nil : ([] : List α).isEmpty = true := rfl
|
||||
@[simp, grind] theorem isEmpty_cons : (x :: xs : List α).isEmpty = false := rfl
|
||||
@[simp, grind =] theorem isEmpty_nil : ([] : List α).isEmpty = true := rfl
|
||||
@[simp, grind =] theorem isEmpty_cons : (x :: xs : List α).isEmpty = false := rfl
|
||||
|
||||
/-! ### elem -/
|
||||
|
||||
@@ -842,7 +842,7 @@ def elem [BEq α] (a : α) : (l : List α) → Bool
|
||||
| true => true
|
||||
| false => elem a bs
|
||||
|
||||
@[simp, grind] theorem elem_nil [BEq α] : ([] : List α).elem a = false := rfl
|
||||
@[simp, grind =] theorem elem_nil [BEq α] : ([] : List α).elem a = false := rfl
|
||||
theorem elem_cons [BEq α] {a : α} :
|
||||
(b::bs).elem a = match a == b with | true => true | false => bs.elem a := rfl
|
||||
|
||||
@@ -958,9 +958,9 @@ def take : (n : Nat) → (xs : List α) → List α
|
||||
| _+1, [] => []
|
||||
| n+1, a::as => a :: take n as
|
||||
|
||||
@[simp, grind] theorem take_nil {i : Nat} : ([] : List α).take i = [] := by cases i <;> rfl
|
||||
@[simp, grind] theorem take_zero {l : List α} : l.take 0 = [] := rfl
|
||||
@[simp, grind] theorem take_succ_cons {a : α} {as : List α} {i : Nat} : (a::as).take (i+1) = a :: as.take i := rfl
|
||||
@[simp, grind =] theorem take_nil {i : Nat} : ([] : List α).take i = [] := by cases i <;> rfl
|
||||
@[simp, grind =] theorem take_zero {l : List α} : l.take 0 = [] := rfl
|
||||
@[simp, grind =] theorem take_succ_cons {a : α} {as : List α} {i : Nat} : (a::as).take (i+1) = a :: as.take i := rfl
|
||||
|
||||
/-! ### drop -/
|
||||
|
||||
@@ -980,10 +980,10 @@ def drop : (n : Nat) → (xs : List α) → List α
|
||||
| _+1, [] => []
|
||||
| n+1, _::as => drop n as
|
||||
|
||||
@[simp, grind] theorem drop_nil : ([] : List α).drop i = [] := by
|
||||
@[simp, grind =] theorem drop_nil : ([] : List α).drop i = [] := by
|
||||
cases i <;> rfl
|
||||
@[simp, grind] theorem drop_zero {l : List α} : l.drop 0 = l := rfl
|
||||
@[simp, grind] theorem drop_succ_cons {a : α} {l : List α} {i : Nat} : (a :: l).drop (i + 1) = l.drop i := rfl
|
||||
@[simp, grind =] theorem drop_zero {l : List α} : l.drop 0 = l := rfl
|
||||
@[simp, grind =] theorem drop_succ_cons {a : α} {l : List α} {i : Nat} : (a :: l).drop (i + 1) = l.drop i := rfl
|
||||
|
||||
theorem drop_eq_nil_of_le {as : List α} {i : Nat} (h : as.length ≤ i) : as.drop i = [] := by
|
||||
match as, i with
|
||||
@@ -1094,13 +1094,13 @@ def dropLast {α} : List α → List α
|
||||
| [_] => []
|
||||
| a::as => a :: dropLast as
|
||||
|
||||
@[simp, grind] theorem dropLast_nil : ([] : List α).dropLast = [] := rfl
|
||||
@[simp, grind] theorem dropLast_singleton : [x].dropLast = [] := rfl
|
||||
@[simp, grind =] theorem dropLast_nil : ([] : List α).dropLast = [] := rfl
|
||||
@[simp, grind =] theorem dropLast_singleton : [x].dropLast = [] := rfl
|
||||
|
||||
@[deprecated dropLast_singleton (since := "2025-04-16")]
|
||||
theorem dropLast_single : [x].dropLast = [] := dropLast_singleton
|
||||
|
||||
@[simp, grind] theorem dropLast_cons₂ :
|
||||
@[simp, grind =] theorem dropLast_cons₂ :
|
||||
(x::y::zs).dropLast = x :: (y::zs).dropLast := rfl
|
||||
|
||||
-- Later this can be proved by `simp` via `[List.length_dropLast, List.length_cons, Nat.add_sub_cancel]`,
|
||||
@@ -1439,8 +1439,8 @@ def replace [BEq α] : (l : List α) → (a : α) → (b : α) → List α
|
||||
| true => c::as
|
||||
| false => a :: replace as b c
|
||||
|
||||
@[simp, grind] theorem replace_nil [BEq α] : ([] : List α).replace a b = [] := rfl
|
||||
@[grind] theorem replace_cons [BEq α] {a : α} :
|
||||
@[simp, grind =] theorem replace_nil [BEq α] : ([] : List α).replace a b = [] := rfl
|
||||
@[grind =] theorem replace_cons [BEq α] {a : α} :
|
||||
(a::as).replace b c = match b == a with | true => c::as | false => a :: replace as b c :=
|
||||
rfl
|
||||
|
||||
@@ -1648,8 +1648,8 @@ def findSome? (f : α → Option β) : List α → Option β
|
||||
| some b => some b
|
||||
| none => findSome? f as
|
||||
|
||||
@[simp, grind] theorem findSome?_nil : ([] : List α).findSome? f = none := rfl
|
||||
@[grind] theorem findSome?_cons {f : α → Option β} :
|
||||
@[simp, grind =] theorem findSome?_nil : ([] : List α).findSome? f = none := rfl
|
||||
@[grind =] theorem findSome?_cons {f : α → Option β} :
|
||||
(a::as).findSome? f = match f a with | some b => some b | none => as.findSome? f :=
|
||||
rfl
|
||||
|
||||
@@ -1906,8 +1906,8 @@ def any : (l : List α) → (p : α → Bool) → Bool
|
||||
| [], _ => false
|
||||
| h :: t, p => p h || any t p
|
||||
|
||||
@[simp, grind] theorem any_nil : [].any f = false := rfl
|
||||
@[simp, grind] theorem any_cons : (a::l).any f = (f a || l.any f) := rfl
|
||||
@[simp, grind =] theorem any_nil : [].any f = false := rfl
|
||||
@[simp, grind =] theorem any_cons : (a::l).any f = (f a || l.any f) := rfl
|
||||
|
||||
/-! ### all -/
|
||||
|
||||
@@ -1925,8 +1925,8 @@ def all : List α → (α → Bool) → Bool
|
||||
| [], _ => true
|
||||
| h :: t, p => p h && all t p
|
||||
|
||||
@[simp, grind] theorem all_nil : [].all f = true := rfl
|
||||
@[simp, grind] theorem all_cons : (a::l).all f = (f a && l.all f) := rfl
|
||||
@[simp, grind =] theorem all_nil : [].all f = true := rfl
|
||||
@[simp, grind =] theorem all_cons : (a::l).all f = (f a && l.all f) := rfl
|
||||
|
||||
/-! ### or -/
|
||||
|
||||
@@ -2066,8 +2066,8 @@ Examples:
|
||||
def sum {α} [Add α] [Zero α] : List α → α :=
|
||||
foldr (· + ·) 0
|
||||
|
||||
@[simp, grind] theorem sum_nil [Add α] [Zero α] : ([] : List α).sum = 0 := rfl
|
||||
@[simp, grind] theorem sum_cons [Add α] [Zero α] {a : α} {l : List α} : (a::l).sum = a + l.sum := rfl
|
||||
@[simp, grind =] theorem sum_nil [Add α] [Zero α] : ([] : List α).sum = 0 := rfl
|
||||
@[simp, grind =] theorem sum_cons [Add α] [Zero α] {a : α} {l : List α} : (a::l).sum = a + l.sum := rfl
|
||||
|
||||
/-! ### range -/
|
||||
|
||||
|
||||
@@ -223,7 +223,7 @@ variable [BEq α]
|
||||
|
||||
@[simp, grind =] theorem count_nil {a : α} : count a [] = 0 := rfl
|
||||
|
||||
@[grind]
|
||||
@[grind =]
|
||||
theorem count_cons {a b : α} {l : List α} :
|
||||
count a (b :: l) = count a l + if b == a then 1 else 0 := by
|
||||
simp [count, countP_cons]
|
||||
@@ -237,7 +237,7 @@ theorem count_eq_countP' {a : α} : count a = countP (· == a) := by
|
||||
theorem count_eq_length_filter {a : α} {l : List α} : count a l = (filter (· == a) l).length := by
|
||||
simp [count, countP_eq_length_filter]
|
||||
|
||||
@[grind]
|
||||
@[grind =]
|
||||
theorem count_tail : ∀ {l : List α} {a : α},
|
||||
l.tail.count a = l.count a - if l.head? == some a then 1 else 0
|
||||
| [], a => by simp
|
||||
@@ -380,7 +380,7 @@ theorem count_filterMap {α} [BEq β] {b : β} {f : α → Option β} {l : List
|
||||
theorem count_flatMap {α} [BEq β] {l : List α} {f : α → List β} {x : β} :
|
||||
count x (l.flatMap f) = sum (map (count x ∘ f) l) := countP_flatMap
|
||||
|
||||
@[grind]
|
||||
@[grind =]
|
||||
theorem count_erase {a b : α} :
|
||||
∀ {l : List α}, count a (l.erase b) = count a l - if b == a then 1 else 0
|
||||
| [] => by simp
|
||||
|
||||
@@ -130,7 +130,7 @@ theorem le_length_eraseP {l : List α} : l.length - 1 ≤ (l.eraseP p).length :=
|
||||
@[grind →]
|
||||
theorem mem_of_mem_eraseP {l : List α} : a ∈ l.eraseP p → a ∈ l := (eraseP_subset ·)
|
||||
|
||||
@[simp, grind] theorem mem_eraseP_of_neg {l : List α} (pa : ¬p a) : a ∈ l.eraseP p ↔ a ∈ l := by
|
||||
@[simp, grind =] theorem mem_eraseP_of_neg {l : List α} (pa : ¬p a) : a ∈ l.eraseP p ↔ a ∈ l := by
|
||||
refine ⟨mem_of_mem_eraseP, fun al => ?_⟩
|
||||
match exists_or_eq_self_of_eraseP p l with
|
||||
| .inl h => rw [h]; assumption
|
||||
@@ -265,14 +265,18 @@ theorem eraseP_eq_iff {p} {l : List α} :
|
||||
subst p
|
||||
simp_all
|
||||
|
||||
@[grind ←]
|
||||
theorem Pairwise.eraseP (q) : Pairwise p l → Pairwise p (l.eraseP q) :=
|
||||
Pairwise.sublist <| eraseP_sublist
|
||||
|
||||
@[grind ←]
|
||||
grind_pattern Pairwise.eraseP => Pairwise p (l.eraseP q)
|
||||
grind_pattern Pairwise.eraseP => Pairwise p l, l.eraseP q
|
||||
|
||||
theorem Nodup.eraseP (p) : Nodup l → Nodup (l.eraseP p) :=
|
||||
Pairwise.eraseP p
|
||||
|
||||
grind_pattern Nodup.eraseP => Nodup (l.eraseP p)
|
||||
grind_pattern Nodup.eraseP => Nodup l, l.eraseP p
|
||||
|
||||
@[grind =]
|
||||
theorem eraseP_comm {l : List α} (h : ∀ a ∈ l, ¬ p a ∨ ¬ q a) :
|
||||
(l.eraseP p).eraseP q = (l.eraseP q).eraseP p := by
|
||||
@@ -393,7 +397,7 @@ theorem le_length_erase [LawfulBEq α] {a : α} {l : List α} : l.length - 1 ≤
|
||||
@[grind →]
|
||||
theorem mem_of_mem_erase {a b : α} {l : List α} (h : a ∈ l.erase b) : a ∈ l := erase_subset h
|
||||
|
||||
@[simp, grind] theorem mem_erase_of_ne [LawfulBEq α] {a b : α} {l : List α} (ab : a ≠ b) :
|
||||
@[simp, grind =] theorem mem_erase_of_ne [LawfulBEq α] {a b : α} {l : List α} (ab : a ≠ b) :
|
||||
a ∈ l.erase b ↔ a ∈ l :=
|
||||
erase_eq_eraseP b l ▸ mem_eraseP_of_neg (mt eq_of_beq ab.symm)
|
||||
|
||||
@@ -508,10 +512,12 @@ theorem Nodup.not_mem_erase [LawfulBEq α] {a : α} (h : Nodup l) : a ∉ l.eras
|
||||
-- Only activate `not_mem_erase` when `l.Nodup` is already available.
|
||||
grind_pattern List.Nodup.not_mem_erase => a ∈ l.erase a, l.Nodup
|
||||
|
||||
@[grind]
|
||||
theorem Nodup.erase [LawfulBEq α] (a : α) : Nodup l → Nodup (l.erase a) :=
|
||||
Pairwise.erase a
|
||||
|
||||
grind_pattern Nodup.erase => Nodup (l.erase a)
|
||||
grind_pattern Nodup.erase => Nodup l, l.erase a
|
||||
|
||||
theorem head_erase_mem (xs : List α) (a : α) (h) : (xs.erase a).head h ∈ xs :=
|
||||
erase_sublist.head_mem h
|
||||
|
||||
@@ -578,21 +584,21 @@ theorem eraseIdx_ne_nil_iff {l : List α} {i : Nat} : eraseIdx l i ≠ [] ↔ 2
|
||||
| [a]
|
||||
| a::b::l => simp
|
||||
|
||||
|
||||
|
||||
@[grind]
|
||||
theorem eraseIdx_sublist : ∀ (l : List α) (k : Nat), eraseIdx l k <+ l
|
||||
| [], _ => by simp
|
||||
| a::l, 0 => by simp
|
||||
| a::l, k + 1 => by simp [eraseIdx_sublist]
|
||||
|
||||
grind_pattern eraseIdx_sublist => l.eraseIdx k, _ <+ l
|
||||
|
||||
theorem mem_of_mem_eraseIdx {l : List α} {i : Nat} {a : α} (h : a ∈ l.eraseIdx i) : a ∈ l :=
|
||||
(eraseIdx_sublist _ _).mem h
|
||||
|
||||
@[grind]
|
||||
theorem eraseIdx_subset {l : List α} {k : Nat} : eraseIdx l k ⊆ l :=
|
||||
(eraseIdx_sublist _ _).subset
|
||||
|
||||
grind_pattern eraseIdx_sublist => l.eraseIdx k, _ ⊆ l
|
||||
|
||||
@[simp]
|
||||
theorem eraseIdx_eq_self : ∀ {l : List α} {k : Nat}, eraseIdx l k = l ↔ length l ≤ k
|
||||
| [], _ => by simp
|
||||
@@ -649,15 +655,18 @@ theorem eraseIdx_replicate {n : Nat} {a : α} {k : Nat} :
|
||||
exact m.2
|
||||
· rw [eraseIdx_of_length_le (by simpa using h)]
|
||||
|
||||
@[grind ←]
|
||||
theorem Pairwise.eraseIdx {l : List α} (k) : Pairwise p l → Pairwise p (l.eraseIdx k) :=
|
||||
Pairwise.sublist <| eraseIdx_sublist _ _
|
||||
|
||||
@[grind ←]
|
||||
grind_pattern Pairwise.eraseIdx => Pairwise p (l.eraseIdx k)
|
||||
grind_pattern Pairwise.eraseIdx => Pairwise p l, l.eraseIdx k
|
||||
|
||||
theorem Nodup.eraseIdx {l : List α} (k) : Nodup l → Nodup (l.eraseIdx k) :=
|
||||
Pairwise.eraseIdx k
|
||||
|
||||
@[grind ←]
|
||||
grind_pattern Nodup.eraseIdx => Nodup (l.eraseIdx k)
|
||||
grind_pattern Nodup.eraseIdx => Nodup l, l.eraseIdx k
|
||||
|
||||
protected theorem IsPrefix.eraseIdx {l l' : List α} (h : l <+: l') (k : Nat) :
|
||||
eraseIdx l k <+: eraseIdx l' k := by
|
||||
rcases h with ⟨t, rfl⟩
|
||||
@@ -667,6 +676,10 @@ protected theorem IsPrefix.eraseIdx {l l' : List α} (h : l <+: l') (k : Nat) :
|
||||
rw [Nat.not_lt] at hkl
|
||||
simp [eraseIdx_append_of_length_le hkl, eraseIdx_of_length_le hkl]
|
||||
|
||||
grind_pattern IsPrefix.eraseIdx => eraseIdx l k <+: eraseIdx l' k
|
||||
grind_pattern IsPrefix.eraseIdx => eraseIdx l k, l <+: l'
|
||||
grind_pattern IsPrefix.eraseIdx => eraseIdx l' k, l <+: l'
|
||||
|
||||
-- See also `mem_eraseIdx_iff_getElem` and `mem_eraseIdx_iff_getElem?` in
|
||||
-- `Init/Data/List/Nat/Basic.lean`.
|
||||
|
||||
@@ -686,6 +699,4 @@ theorem erase_eq_eraseIdx_of_idxOf [BEq α] [LawfulBEq α]
|
||||
rw [eq_comm, eraseIdx_eq_self]
|
||||
exact Nat.le_of_eq (idxOf_eq_length h).symm
|
||||
|
||||
|
||||
|
||||
end List
|
||||
|
||||
@@ -293,7 +293,6 @@ theorem mem_of_find?_eq_some : ∀ {l}, find? p l = some a → a ∈ l
|
||||
· exact H ▸ .head _
|
||||
· exact .tail _ (mem_of_find?_eq_some H)
|
||||
|
||||
@[grind]
|
||||
theorem get_find?_mem {xs : List α} {p : α → Bool} (h) : (xs.find? p).get h ∈ xs := by
|
||||
induction xs with
|
||||
| nil => simp at h
|
||||
@@ -305,6 +304,8 @@ theorem get_find?_mem {xs : List α} {p : α → Bool} (h) : (xs.find? p).get h
|
||||
right
|
||||
apply ih
|
||||
|
||||
grind_pattern get_find?_mem => (xs.find? p).get h
|
||||
|
||||
@[simp, grind =] theorem find?_filter {xs : List α} {p : α → Bool} {q : α → Bool} :
|
||||
(xs.filter p).find? q = xs.find? (fun a => p a ∧ q a) := by
|
||||
induction xs with
|
||||
@@ -558,7 +559,6 @@ where
|
||||
@[simp] theorem findIdx_singleton {a : α} {p : α → Bool} : [a].findIdx p = if p a then 0 else 1 := by
|
||||
simp [findIdx_cons, findIdx_nil]
|
||||
|
||||
@[grind →]
|
||||
theorem findIdx_of_getElem?_eq_some {xs : List α} (w : xs[xs.findIdx p]? = some y) : p y := by
|
||||
induction xs with
|
||||
| nil => simp_all
|
||||
|
||||
@@ -306,7 +306,7 @@ theorem getD_getElem? {l : List α} {i : Nat} {d : α} :
|
||||
match i, h with
|
||||
| 0, _ => rfl
|
||||
|
||||
@[grind]
|
||||
@[grind =]
|
||||
theorem getElem?_singleton {a : α} {i : Nat} : [a][i]? = if i = 0 then some a else none := by
|
||||
simp [getElem?_cons]
|
||||
|
||||
@@ -382,14 +382,20 @@ theorem get!_eq_getElem! [Inhabited α] (l : List α) (i) : l.get! i = l[i]! :=
|
||||
|
||||
@[simp] theorem not_mem_nil {a : α} : ¬ a ∈ [] := nofun
|
||||
|
||||
@[simp] theorem mem_cons : a ∈ b :: l ↔ a = b ∨ a ∈ l :=
|
||||
@[simp, grind =] theorem mem_cons : a ∈ b :: l ↔ a = b ∨ a ∈ l :=
|
||||
⟨fun h => by cases h <;> simp [Membership.mem, *],
|
||||
fun | Or.inl rfl => by constructor | Or.inr h => by constructor; assumption⟩
|
||||
|
||||
@[grind] theorem eq_or_mem_of_mem_cons {a b : α} {l : List α} :
|
||||
theorem eq_or_mem_of_mem_cons {a b : α} {l : List α} :
|
||||
a ∈ b :: l → a = b ∨ a ∈ l := List.mem_cons.mp
|
||||
|
||||
@[grind] theorem mem_cons_self {a : α} {l : List α} : a ∈ a :: l := .head ..
|
||||
-- This pattern may be excessively general:
|
||||
-- it fires anytime we ae thinking about membership of lists,
|
||||
-- and constructing a list via `cons`, even if the elements are unrelated.
|
||||
-- Nevertheless in practice it is quite helpful!
|
||||
grind_pattern eq_or_mem_of_mem_cons => b :: l, a ∈ l
|
||||
|
||||
theorem mem_cons_self {a : α} {l : List α} : a ∈ a :: l := .head ..
|
||||
|
||||
theorem mem_concat_self {xs : List α} {a : α} : a ∈ xs ++ [a] :=
|
||||
mem_append_right xs mem_cons_self
|
||||
@@ -411,7 +417,7 @@ theorem eq_append_cons_of_mem {a : α} {xs : List α} (h : a ∈ xs) :
|
||||
· obtain ⟨as, bs, rfl, h⟩ := ih h
|
||||
exact ⟨x :: as, bs, rfl, by simp_all⟩
|
||||
|
||||
@[grind] theorem mem_cons_of_mem (y : α) {a : α} {l : List α} : a ∈ l → a ∈ y :: l := .tail _
|
||||
theorem mem_cons_of_mem (y : α) {a : α} {l : List α} : a ∈ l → a ∈ y :: l := .tail _
|
||||
|
||||
-- The argument `l : List α` is intentionally explicit,
|
||||
-- as a tactic may generate `h` without determining `l`.
|
||||
@@ -547,10 +553,10 @@ theorem contains_iff [BEq α] [LawfulBEq α] {a : α} {as : List α} :
|
||||
theorem elem_eq_mem [BEq α] [LawfulBEq α] (a : α) (as : List α) :
|
||||
elem a as = decide (a ∈ as) := by rw [Bool.eq_iff_iff, elem_iff, decide_eq_true_iff]
|
||||
|
||||
@[simp, grind] theorem contains_eq_mem [BEq α] [LawfulBEq α] (a : α) (as : List α) :
|
||||
@[simp, grind =] theorem contains_eq_mem [BEq α] [LawfulBEq α] (a : α) (as : List α) :
|
||||
as.contains a = decide (a ∈ as) := by rw [Bool.eq_iff_iff, elem_iff, decide_eq_true_iff]
|
||||
|
||||
@[simp, grind] theorem contains_cons [BEq α] {a : α} {b : α} {l : List α} :
|
||||
@[simp, grind =] theorem contains_cons [BEq α] {a : α} {b : α} {l : List α} :
|
||||
(a :: l).contains b = (b == a || l.contains b) := by
|
||||
simp only [contains, elem_cons]
|
||||
split <;> simp_all
|
||||
@@ -605,7 +611,7 @@ theorem decide_forall_mem {l : List α} {p : α → Prop} [DecidablePred p] :
|
||||
@[simp] theorem all_eq_false {l : List α} : l.all p = false ↔ ∃ x, x ∈ l ∧ ¬p x := by
|
||||
simp [all_eq]
|
||||
|
||||
@[grind] theorem any_beq [BEq α] {l : List α} {a : α} : (l.any fun x => a == x) = l.contains a := by
|
||||
theorem any_beq [BEq α] {l : List α} {a : α} : (l.any fun x => a == x) = l.contains a := by
|
||||
induction l <;> simp_all [contains_cons]
|
||||
|
||||
/-- Variant of `any_beq` with `==` reversed. -/
|
||||
@@ -613,7 +619,7 @@ theorem any_beq' [BEq α] [PartialEquivBEq α] {l : List α} :
|
||||
(l.any fun x => x == a) = l.contains a := by
|
||||
simp only [BEq.comm, any_beq]
|
||||
|
||||
@[grind] theorem all_bne [BEq α] {l : List α} : (l.all fun x => a != x) = !l.contains a := by
|
||||
theorem all_bne [BEq α] {l : List α} : (l.all fun x => a != x) = !l.contains a := by
|
||||
induction l <;> simp_all [bne]
|
||||
|
||||
/-- Variant of `all_bne` with `!=` reversed. -/
|
||||
@@ -624,10 +630,10 @@ theorem all_bne' [BEq α] [PartialEquivBEq α] {l : List α} :
|
||||
/-! ### set -/
|
||||
|
||||
-- As `List.set` is defined in `Init.Prelude`, we write the basic simplification lemmas here.
|
||||
@[simp, grind] theorem set_nil {i : Nat} {a : α} : [].set i a = [] := rfl
|
||||
@[simp, grind] theorem set_cons_zero {x : α} {xs : List α} {a : α} :
|
||||
@[simp, grind =] theorem set_nil {i : Nat} {a : α} : [].set i a = [] := rfl
|
||||
@[simp, grind =] theorem set_cons_zero {x : α} {xs : List α} {a : α} :
|
||||
(x :: xs).set 0 a = a :: xs := rfl
|
||||
@[simp, grind] theorem set_cons_succ {x : α} {xs : List α} {i : Nat} {a : α} :
|
||||
@[simp, grind =] theorem set_cons_succ {x : α} {xs : List α} {i : Nat} {a : α} :
|
||||
(x :: xs).set (i + 1) a = x :: xs.set i a := rfl
|
||||
|
||||
@[simp] theorem getElem_set_self {l : List α} {i : Nat} {a : α} (h : i < (l.set i a).length) :
|
||||
@@ -670,14 +676,14 @@ theorem getElem?_set_self' {l : List α} {i : Nat} {a : α} :
|
||||
simp_all
|
||||
· rw [getElem?_eq_none (by simp_all), getElem?_eq_none (by simp_all)]
|
||||
|
||||
@[grind] theorem getElem_set {l : List α} {i j} {a} (h) :
|
||||
@[grind =] theorem getElem_set {l : List α} {i j} {a} (h) :
|
||||
(set l i a)[j]'h = if i = j then a else l[j]'(length_set .. ▸ h) := by
|
||||
if h : i = j then
|
||||
subst h; simp only [getElem_set_self, ↓reduceIte]
|
||||
else
|
||||
simp [h]
|
||||
|
||||
@[grind] theorem getElem?_set {l : List α} {i j : Nat} {a : α} :
|
||||
@[grind =] theorem getElem?_set {l : List α} {i j : Nat} {a : α} :
|
||||
(l.set i a)[j]? = if i = j then if i < l.length then some a else none else l[j]? := by
|
||||
if h : i = j then
|
||||
subst h
|
||||
@@ -747,10 +753,10 @@ theorem mem_or_eq_of_mem_set : ∀ {l : List α} {i : Nat} {a b : α}, a ∈ l.s
|
||||
|
||||
/-! ### BEq -/
|
||||
|
||||
@[simp, grind] theorem beq_nil_eq [BEq α] {l : List α} : (l == []) = l.isEmpty := by
|
||||
@[simp, grind =] theorem beq_nil_eq [BEq α] {l : List α} : (l == []) = l.isEmpty := by
|
||||
cases l <;> rfl
|
||||
|
||||
@[simp, grind] theorem nil_beq_eq [BEq α] {l : List α} : ([] == l) = l.isEmpty := by
|
||||
@[simp, grind =] theorem nil_beq_eq [BEq α] {l : List α} : ([] == l) = l.isEmpty := by
|
||||
cases l <;> rfl
|
||||
|
||||
@[deprecated beq_nil_eq (since := "2025-04-04")]
|
||||
@@ -759,7 +765,7 @@ abbrev beq_nil_iff := @beq_nil_eq
|
||||
@[deprecated nil_beq_eq (since := "2025-04-04")]
|
||||
abbrev nil_beq_iff := @nil_beq_eq
|
||||
|
||||
@[simp, grind] theorem cons_beq_cons [BEq α] {a b : α} {l₁ l₂ : List α} :
|
||||
@[simp, grind =] theorem cons_beq_cons [BEq α] {a b : α} {l₁ l₂ : List α} :
|
||||
(a :: l₁ == b :: l₂) = (a == b && l₁ == l₂) := rfl
|
||||
|
||||
@[simp] theorem concat_beq_concat [BEq α] {a b : α} {l₁ l₂ : List α} :
|
||||
@@ -825,7 +831,7 @@ theorem length_eq_of_beq [BEq α] {l₁ l₂ : List α} (h : l₁ == l₂) : l
|
||||
|
||||
/-! ### getLast -/
|
||||
|
||||
@[grind]
|
||||
@[grind =]
|
||||
theorem getLast_eq_getElem : ∀ {l : List α} (h : l ≠ []),
|
||||
getLast l h = l[l.length - 1]'(by
|
||||
match l with
|
||||
@@ -839,7 +845,7 @@ theorem getElem_length_sub_one_eq_getLast {l : List α} (h : l.length - 1 < l.le
|
||||
l[l.length - 1] = getLast l (by cases l; simp at h; simp) := by
|
||||
rw [← getLast_eq_getElem]
|
||||
|
||||
@[simp, grind] theorem getLast_cons_cons {a : α} {l : List α} :
|
||||
@[simp, grind =] theorem getLast_cons_cons {a : α} {l : List α} :
|
||||
getLast (a :: b :: l) (by simp) = getLast (b :: l) (by simp) :=
|
||||
rfl
|
||||
|
||||
@@ -852,10 +858,10 @@ theorem getLast_cons {a : α} {l : List α} : ∀ (h : l ≠ nil),
|
||||
theorem getLast_eq_getLastD {a l} (h) : @getLast α (a::l) h = getLastD l a := by
|
||||
cases l <;> rfl
|
||||
|
||||
@[simp, grind] theorem getLastD_eq_getLast? {a l} : @getLastD α l a = (getLast? l).getD a := by
|
||||
@[simp, grind =] theorem getLastD_eq_getLast? {a l} : @getLastD α l a = (getLast? l).getD a := by
|
||||
cases l <;> rfl
|
||||
|
||||
@[simp, grind] theorem getLast_singleton {a} (h) : @getLast α [a] h = a := rfl
|
||||
@[simp, grind =] theorem getLast_singleton {a} (h) : @getLast α [a] h = a := rfl
|
||||
|
||||
theorem getLast!_cons_eq_getLastD [Inhabited α] : @getLast! α _ (a::l) = getLastD l a := by
|
||||
simp [getLast!, getLast_eq_getLastD]
|
||||
@@ -888,7 +894,7 @@ theorem getLast?_eq_getLast : ∀ {l : List α} h, l.getLast? = some (l.getLast
|
||||
| [], h => nomatch h rfl
|
||||
| _ :: _, _ => rfl
|
||||
|
||||
@[grind] theorem getLast?_eq_getElem? : ∀ {l : List α}, l.getLast? = l[l.length - 1]?
|
||||
@[grind =] theorem getLast?_eq_getElem? : ∀ {l : List α}, l.getLast? = l[l.length - 1]?
|
||||
| [] => rfl
|
||||
| a::l => by
|
||||
rw [getLast?_eq_getLast (l := a :: l) nofun, getLast_eq_getElem, getElem?_eq_getElem]
|
||||
@@ -901,14 +907,14 @@ theorem getLast_eq_iff_getLast?_eq_some {xs : List α} (h) :
|
||||
-- `getLast?_eq_none_iff`, `getLast?_eq_some_iff`, `getLast?_isSome`, and `getLast_mem`
|
||||
-- are proved later once more `reverse` theorems are available.
|
||||
|
||||
@[grind]
|
||||
@[grind =]
|
||||
theorem getLast?_cons {a : α} : (a::l).getLast? = some (l.getLast?.getD a) := by
|
||||
cases l <;> simp [getLast?, getLast]
|
||||
|
||||
@[simp] theorem getLast?_cons_cons : (a :: b :: l).getLast? = (b :: l).getLast? := by
|
||||
simp [getLast?_cons]
|
||||
|
||||
@[grind]
|
||||
@[grind =]
|
||||
theorem getLast?_concat {l : List α} {a : α} : (l ++ [a]).getLast? = some a := by
|
||||
simp [getLast?_eq_getElem?, Nat.succ_sub_succ]
|
||||
|
||||
@@ -927,7 +933,7 @@ theorem getLast!_nil [Inhabited α] : ([] : List α).getLast! = default := rfl
|
||||
theorem getLast!_of_getLast? [Inhabited α] : ∀ {l : List α}, getLast? l = some a → getLast! l = a
|
||||
| _ :: _, rfl => rfl
|
||||
|
||||
@[grind]
|
||||
@[grind =]
|
||||
theorem getLast!_eq_getElem! [Inhabited α] {l : List α} : l.getLast! = l[l.length - 1]! := by
|
||||
cases l with
|
||||
| nil => simp
|
||||
@@ -955,7 +961,7 @@ theorem head?_eq_getElem? : ∀ {l : List α}, l.head? = l[0]?
|
||||
|
||||
theorem head_singleton {a : α} : head [a] (by simp) = a := by simp
|
||||
|
||||
@[grind]
|
||||
@[grind =]
|
||||
theorem head_eq_getElem {l : List α} (h : l ≠ []) : head l h = l[0]'(length_pos_iff.mpr h) := by
|
||||
cases l with
|
||||
| nil => simp at h
|
||||
@@ -1017,18 +1023,18 @@ theorem head_of_mem_head? {l : List α} {x} (hx : x ∈ l.head?) :
|
||||
/-! ### headD -/
|
||||
|
||||
/-- `simp` unfolds `headD` in terms of `head?` and `Option.getD`. -/
|
||||
@[simp, grind] theorem headD_eq_head?_getD {l : List α} : headD l a = (head? l).getD a := by
|
||||
@[simp, grind =] theorem headD_eq_head?_getD {l : List α} : headD l a = (head? l).getD a := by
|
||||
cases l <;> simp [headD]
|
||||
|
||||
/-! ### tailD -/
|
||||
|
||||
/-- `simp` unfolds `tailD` in terms of `tail?` and `Option.getD`. -/
|
||||
@[simp, grind] theorem tailD_eq_tail? {l l' : List α} : tailD l l' = (tail? l).getD l' := by
|
||||
@[simp, grind =] theorem tailD_eq_tail? {l l' : List α} : tailD l l' = (tail? l).getD l' := by
|
||||
cases l <;> rfl
|
||||
|
||||
/-! ### tail -/
|
||||
|
||||
@[simp, grind] theorem length_tail {l : List α} : l.tail.length = l.length - 1 := by cases l <;> rfl
|
||||
@[simp, grind =] theorem length_tail {l : List α} : l.tail.length = l.length - 1 := by cases l <;> rfl
|
||||
|
||||
theorem tail_eq_tailD {l : List α} : l.tail = tailD l [] := by cases l <;> rfl
|
||||
|
||||
@@ -1040,13 +1046,13 @@ theorem mem_of_mem_tail {a : α} {l : List α} (h : a ∈ tail l) : a ∈ l := b
|
||||
theorem ne_nil_of_tail_ne_nil {l : List α} : l.tail ≠ [] → l ≠ [] := by
|
||||
cases l <;> simp
|
||||
|
||||
@[simp, grind] theorem getElem_tail {l : List α} {i : Nat} (h : i < l.tail.length) :
|
||||
@[simp, grind =] theorem getElem_tail {l : List α} {i : Nat} (h : i < l.tail.length) :
|
||||
(tail l)[i] = l[i + 1]'(add_lt_of_lt_sub (by simpa using h)) := by
|
||||
cases l with
|
||||
| nil => simp at h
|
||||
| cons _ l => simp
|
||||
|
||||
@[simp, grind] theorem getElem?_tail {l : List α} {i : Nat} :
|
||||
@[simp, grind =] theorem getElem?_tail {l : List α} {i : Nat} :
|
||||
(tail l)[i]? = l[i + 1]? := by
|
||||
cases l <;> simp
|
||||
|
||||
@@ -1070,7 +1076,7 @@ theorem one_lt_length_of_tail_ne_nil {l : List α} (h : l.tail ≠ []) : 1 < l.l
|
||||
@[simp] theorem head?_tail {l : List α} : (tail l).head? = l[1]? := by
|
||||
simp [head?_eq_getElem?]
|
||||
|
||||
@[simp, grind] theorem getLast_tail {l : List α} (h : l.tail ≠ []) :
|
||||
@[simp, grind =] theorem getLast_tail {l : List α} (h : l.tail ≠ []) :
|
||||
(tail l).getLast h = l.getLast (ne_nil_of_tail_ne_nil h) := by
|
||||
simp only [getLast_eq_getElem, length_tail, getElem_tail]
|
||||
congr
|
||||
@@ -1096,7 +1102,7 @@ theorem cons_head_tail (h : l ≠ []) : l.head h :: l.tail = l := by
|
||||
|
||||
/-! ### map -/
|
||||
|
||||
@[simp, grind] theorem length_map {as : List α} (f : α → β) : (as.map f).length = as.length := by
|
||||
@[simp, grind =] theorem length_map {as : List α} (f : α → β) : (as.map f).length = as.length := by
|
||||
induction as with
|
||||
| nil => simp [List.map]
|
||||
| cons _ as ih => simp [List.map, ih]
|
||||
@@ -1104,13 +1110,13 @@ theorem cons_head_tail (h : l ≠ []) : l.head h :: l.tail = l := by
|
||||
@[simp] theorem isEmpty_map {l : List α} {f : α → β} : (l.map f).isEmpty = l.isEmpty := by
|
||||
cases l <;> simp
|
||||
|
||||
@[simp, grind] theorem getElem?_map {f : α → β} : ∀ {l : List α} {i : Nat}, (map f l)[i]? = Option.map f l[i]?
|
||||
@[simp, grind =] theorem getElem?_map {f : α → β} : ∀ {l : List α} {i : Nat}, (map f l)[i]? = Option.map f l[i]?
|
||||
| [], _ => rfl
|
||||
| _ :: _, 0 => by simp
|
||||
| _ :: l, i+1 => by simp [getElem?_map]
|
||||
|
||||
-- The argument `f : α → β` is explicit, to facilitate rewriting from right to left.
|
||||
@[simp, grind] theorem getElem_map (f : α → β) {l} {i : Nat} {h : i < (map f l).length} :
|
||||
@[simp, grind =] theorem getElem_map (f : α → β) {l} {i : Nat} {h : i < (map f l).length} :
|
||||
(map f l)[i] = f (l[i]'(length_map f ▸ h)) :=
|
||||
Option.some.inj <| by rw [← getElem?_eq_getElem, getElem?_map, getElem?_eq_getElem]; rfl
|
||||
|
||||
@@ -1276,7 +1282,7 @@ theorem getLastD_map {f : α → β} {l : List α} {a : α} : (map f l).getLastD
|
||||
@[simp] theorem filter_cons_of_neg {p : α → Bool} {a : α} {l} (pa : ¬ p a) :
|
||||
filter p (a :: l) = filter p l := by rw [filter, eq_false_of_ne_true pa]
|
||||
|
||||
@[grind] theorem filter_cons :
|
||||
@[grind =] theorem filter_cons :
|
||||
(x :: xs : List α).filter p = if p x then x :: (xs.filter p) else xs.filter p := by
|
||||
split <;> simp [*]
|
||||
|
||||
@@ -1315,7 +1321,7 @@ theorem length_filter_eq_length_iff {l} : (filter p l).length = l.length ↔ ∀
|
||||
@[deprecated length_filter_eq_length_iff (since := "2025-04-04")]
|
||||
abbrev filter_length_eq_length := @length_filter_eq_length_iff
|
||||
|
||||
@[simp, grind] theorem mem_filter : x ∈ filter p as ↔ x ∈ as ∧ p x := by
|
||||
@[simp, grind =] theorem mem_filter : x ∈ filter p as ↔ x ∈ as ∧ p x := by
|
||||
induction as with
|
||||
| nil => simp
|
||||
| cons a as ih =>
|
||||
@@ -1330,10 +1336,12 @@ theorem forall_mem_filter {l : List α} {p : α → Bool} {P : α → Prop} :
|
||||
(∀ (i) (_ : i ∈ l.filter p), P i) ↔ ∀ (j) (_ : j ∈ l), p j → P j := by
|
||||
simp
|
||||
|
||||
@[grind] theorem getElem_filter {xs : List α} {p : α → Bool} {i : Nat} (h : i < (xs.filter p).length) :
|
||||
theorem getElem_filter {xs : List α} {p : α → Bool} {i : Nat} (h : i < (xs.filter p).length) :
|
||||
p (xs.filter p)[i] :=
|
||||
(mem_filter.mp (getElem_mem h)).2
|
||||
|
||||
grind_pattern getElem_filter => (xs.filter p)[i]
|
||||
|
||||
theorem getElem?_filter {xs : List α} {p : α → Bool} {i : Nat} (h : i < (xs.filter p).length)
|
||||
(w : (xs.filter p)[i]? = some a) : p a := by
|
||||
rw [getElem?_eq_getElem] at w
|
||||
@@ -1377,7 +1385,7 @@ theorem map_filter_eq_foldr {f : α → β} {p : α → Bool} {as : List α} :
|
||||
simp only [foldr]
|
||||
cases hp : p head <;> simp [filter, *]
|
||||
|
||||
@[simp, grind] theorem filter_append {p : α → Bool} :
|
||||
@[simp, grind =] theorem filter_append {p : α → Bool} :
|
||||
∀ (l₁ l₂ : List α), filter p (l₁ ++ l₂) = filter p l₁ ++ filter p l₂
|
||||
| [], _ => rfl
|
||||
| a :: l₁, l₂ => by simp only [cons_append, filter]; split <;> simp [filter_append l₁]
|
||||
@@ -1442,7 +1450,7 @@ theorem filterMap_some_fun : filterMap (some : α → Option α) = id := by
|
||||
erw [filterMap_eq_map]
|
||||
simp
|
||||
|
||||
@[simp, grind] theorem filterMap_some {l : List α} : filterMap some l = l := by
|
||||
@[simp, grind =] theorem filterMap_some {l : List α} : filterMap some l = l := by
|
||||
rw [filterMap_some_fun, id]
|
||||
|
||||
theorem map_filterMap_some_eq_filter_map_isSome {f : α → Option β} {l : List α} :
|
||||
@@ -1477,19 +1485,19 @@ theorem filterMap_eq_filter {p : α → Bool} :
|
||||
| nil => rfl
|
||||
| cons a l IH => by_cases pa : p a <;> simp [Option.guard, pa, ← IH]
|
||||
|
||||
@[grind]
|
||||
@[grind =]
|
||||
theorem filterMap_filterMap {f : α → Option β} {g : β → Option γ} {l : List α} :
|
||||
filterMap g (filterMap f l) = filterMap (fun x => (f x).bind g) l := by
|
||||
induction l with
|
||||
| nil => rfl
|
||||
| cons a l IH => cases h : f a <;> simp [filterMap_cons, *]
|
||||
|
||||
@[grind]
|
||||
@[grind =]
|
||||
theorem map_filterMap {f : α → Option β} {g : β → γ} {l : List α} :
|
||||
map g (filterMap f l) = filterMap (fun x => (f x).map g) l := by
|
||||
simp only [← filterMap_eq_map, filterMap_filterMap, Option.map_eq_bind]
|
||||
|
||||
@[simp, grind]
|
||||
@[simp, grind =]
|
||||
theorem filterMap_map {f : α → β} {g : β → Option γ} {l : List α} :
|
||||
filterMap g (map f l) = filterMap (g ∘ f) l := by
|
||||
rw [← filterMap_eq_map, filterMap_filterMap]; rfl
|
||||
@@ -1504,7 +1512,7 @@ theorem filterMap_filter {p : α → Bool} {f : α → Option β} {l : List α}
|
||||
rw [← filterMap_eq_filter, filterMap_filterMap]
|
||||
congr; funext x; by_cases h : p x <;> simp [Option.guard, h]
|
||||
|
||||
@[simp, grind] theorem mem_filterMap {f : α → Option β} {l : List α} {b : β} :
|
||||
@[simp, grind =] theorem mem_filterMap {f : α → Option β} {l : List α} {b : β} :
|
||||
b ∈ filterMap f l ↔ ∃ a, a ∈ l ∧ f a = some b := by
|
||||
induction l <;> simp [filterMap_cons]; split <;> simp [*, eq_comm]
|
||||
|
||||
@@ -1516,7 +1524,7 @@ theorem forall_mem_filterMap {f : α → Option β} {l : List α} {P : β → Pr
|
||||
intro a
|
||||
rw [forall_comm]
|
||||
|
||||
@[simp, grind] theorem filterMap_append {l l' : List α} {f : α → Option β} :
|
||||
@[simp, grind =] theorem filterMap_append {l l' : List α} {f : α → Option β} :
|
||||
filterMap f (l ++ l') = filterMap f l ++ filterMap f l' := by
|
||||
induction l <;> simp [filterMap_cons]; split <;> simp [*]
|
||||
|
||||
@@ -1588,7 +1596,7 @@ theorem filterMap_eq_cons_iff {l} {b} {bs} :
|
||||
@[simp] theorem cons_append_fun {a : α} {as : List α} :
|
||||
(fun bs => ((a :: as) ++ bs)) = fun bs => a :: (as ++ bs) := rfl
|
||||
|
||||
@[simp, grind] theorem mem_append {a : α} {s t : List α} : a ∈ s ++ t ↔ a ∈ s ∨ a ∈ t := by
|
||||
@[simp, grind =] theorem mem_append {a : α} {s t : List α} : a ∈ s ++ t ↔ a ∈ s ∨ a ∈ t := by
|
||||
induction s <;> simp_all [or_assoc]
|
||||
|
||||
theorem not_mem_append {a : α} {s t : List α} (h₁ : a ∉ s) (h₂ : a ∉ t) : a ∉ s ++ t :=
|
||||
@@ -1611,7 +1619,7 @@ theorem forall_mem_append {p : α → Prop} {l₁ l₂ : List α} :
|
||||
(∀ (x) (_ : x ∈ l₁ ++ l₂), p x) ↔ (∀ (x) (_ : x ∈ l₁), p x) ∧ (∀ (x) (_ : x ∈ l₂), p x) := by
|
||||
simp only [mem_append, or_imp, forall_and]
|
||||
|
||||
@[grind] theorem getElem_append {l₁ l₂ : List α} {i : Nat} (h : i < (l₁ ++ l₂).length) :
|
||||
@[grind =] theorem getElem_append {l₁ l₂ : List α} {i : Nat} (h : i < (l₁ ++ l₂).length) :
|
||||
(l₁ ++ l₂)[i] = if h' : i < l₁.length then l₁[i] else l₂[i - l₁.length]'(by simp at h h'; exact Nat.sub_lt_left_of_lt_add h' h) := by
|
||||
split <;> rename_i h'
|
||||
· rw [getElem_append_left h']
|
||||
@@ -1630,7 +1638,7 @@ theorem getElem?_append_right : ∀ {l₁ l₂ : List α} {i : Nat}, l₁.length
|
||||
rw [cons_append]
|
||||
simp [Nat.succ_sub_succ_eq_sub, getElem?_append_right (Nat.lt_succ.1 h₁)]
|
||||
|
||||
@[grind] theorem getElem?_append {l₁ l₂ : List α} {i : Nat} :
|
||||
@[grind =] theorem getElem?_append {l₁ l₂ : List α} {i : Nat} :
|
||||
(l₁ ++ l₂)[i]? = if i < l₁.length then l₁[i]? else l₂[i - l₁.length]? := by
|
||||
split <;> rename_i h
|
||||
· exact getElem?_append_left h
|
||||
@@ -1709,7 +1717,6 @@ theorem getLast_concat {a : α} : ∀ {l : List α}, getLast (l ++ [a]) (by simp
|
||||
theorem nil_eq_append_iff : [] = a ++ b ↔ a = [] ∧ b = [] := by
|
||||
simp
|
||||
|
||||
@[grind →]
|
||||
theorem eq_nil_of_append_eq_nil {l₁ l₂ : List α} (h : l₁ ++ l₂ = []) : l₁ = [] ∧ l₂ = [] :=
|
||||
append_eq_nil_iff.mp h
|
||||
|
||||
@@ -1739,12 +1746,12 @@ theorem append_eq_append_iff {ws xs ys zs : List α} :
|
||||
| nil => simp_all
|
||||
| cons a as ih => cases ys <;> simp [eq_comm, and_assoc, ih, and_or_left]
|
||||
|
||||
@[simp, grind] theorem head_append_of_ne_nil {l : List α} {w₁} (w₂) :
|
||||
@[simp, grind =] theorem head_append_of_ne_nil {l : List α} {w₁} (w₂) :
|
||||
head (l ++ l') w₁ = head l w₂ := by
|
||||
match l, w₂ with
|
||||
| a :: l, _ => rfl
|
||||
|
||||
@[grind] theorem head_append {l₁ l₂ : List α} (w : l₁ ++ l₂ ≠ []) :
|
||||
@[grind =] theorem head_append {l₁ l₂ : List α} (w : l₁ ++ l₂ ≠ []) :
|
||||
head (l₁ ++ l₂) w =
|
||||
if h : l₁.isEmpty then
|
||||
head l₂ (by simp_all [isEmpty_iff])
|
||||
@@ -1765,28 +1772,28 @@ theorem head_append_right {l₁ l₂ : List α} (w : l₁ ++ l₂ ≠ []) (h : l
|
||||
head (l₁ ++ l₂) w = head l₂ (by simp_all) := by
|
||||
rw [head_append, dif_pos (by simp_all)]
|
||||
|
||||
@[simp, grind] theorem head?_append {l : List α} : (l ++ l').head? = l.head?.or l'.head? := by
|
||||
@[simp, grind =] theorem head?_append {l : List α} : (l ++ l').head? = l.head?.or l'.head? := by
|
||||
cases l <;> simp
|
||||
|
||||
-- Note:
|
||||
-- `getLast_append_of_ne_nil`, `getLast_append` and `getLast?_append`
|
||||
-- are stated and proved later in the `reverse` section.
|
||||
|
||||
@[grind] theorem tail?_append {l l' : List α} : (l ++ l').tail? = (l.tail?.map (· ++ l')).or l'.tail? := by
|
||||
@[grind =] theorem tail?_append {l l' : List α} : (l ++ l').tail? = (l.tail?.map (· ++ l')).or l'.tail? := by
|
||||
cases l <;> simp
|
||||
|
||||
theorem tail?_append_of_ne_nil {l l' : List α} (_ : l ≠ []) : (l ++ l').tail? = some (l.tail ++ l') :=
|
||||
match l with
|
||||
| _ :: _ => by simp
|
||||
|
||||
@[grind] theorem tail_append {l l' : List α} : (l ++ l').tail = if l.isEmpty then l'.tail else l.tail ++ l' := by
|
||||
@[grind =] theorem tail_append {l l' : List α} : (l ++ l').tail = if l.isEmpty then l'.tail else l.tail ++ l' := by
|
||||
cases l <;> simp
|
||||
|
||||
@[simp] theorem tail_append_of_ne_nil {xs ys : List α} (h : xs ≠ []) :
|
||||
(xs ++ ys).tail = xs.tail ++ ys := by
|
||||
simp_all [tail_append]
|
||||
|
||||
@[grind] theorem set_append {s t : List α} :
|
||||
@[grind =] theorem set_append {s t : List α} :
|
||||
(s ++ t).set i x = if i < s.length then s.set i x ++ t else s ++ t.set (i - s.length) x := by
|
||||
induction s generalizing i with
|
||||
| nil => simp
|
||||
@@ -1844,7 +1851,7 @@ theorem append_eq_filter_iff {p : α → Bool} :
|
||||
L₁ ++ L₂ = filter p l ↔ ∃ l₁ l₂, l = l₁ ++ l₂ ∧ filter p l₁ = L₁ ∧ filter p l₂ = L₂ := by
|
||||
rw [eq_comm, filter_eq_append_iff]
|
||||
|
||||
@[simp, grind] theorem map_append {f : α → β} : ∀ {l₁ l₂}, map f (l₁ ++ l₂) = map f l₁ ++ map f l₂ := by
|
||||
@[simp, grind =] theorem map_append {f : α → β} : ∀ {l₁ l₂}, map f (l₁ ++ l₂) = map f l₁ ++ map f l₂ := by
|
||||
intro l₁; induction l₁ <;> intros <;> simp_all
|
||||
|
||||
theorem map_eq_append_iff {f : α → β} :
|
||||
@@ -1917,7 +1924,7 @@ theorem eq_nil_or_concat : ∀ l : List α, l = [] ∨ ∃ l' b, l = concat l' b
|
||||
| cons =>
|
||||
simp [flatten, length_append, *]
|
||||
|
||||
@[grind] theorem flatten_singleton {l : List α} : [l].flatten = l := by simp
|
||||
@[grind =] theorem flatten_singleton {l : List α} : [l].flatten = l := by simp
|
||||
|
||||
@[simp] theorem mem_flatten : ∀ {L : List (List α)}, a ∈ L.flatten ↔ ∃ l, l ∈ L ∧ a ∈ l
|
||||
| [] => by simp
|
||||
@@ -2092,7 +2099,7 @@ theorem length_flatMap {l : List α} {f : α → List β} :
|
||||
length (l.flatMap f) = sum (map (fun a => (f a).length) l) := by
|
||||
rw [List.flatMap, length_flatten, map_map, Function.comp_def]
|
||||
|
||||
@[simp, grind] theorem mem_flatMap {f : α → List β} {b} {l : List α} : b ∈ l.flatMap f ↔ ∃ a, a ∈ l ∧ b ∈ f a := by
|
||||
@[simp, grind =] theorem mem_flatMap {f : α → List β} {b} {l : List α} : b ∈ l.flatMap f ↔ ∃ a, a ∈ l ∧ b ∈ f a := by
|
||||
simp [flatMap_def, mem_flatten]
|
||||
exact ⟨fun ⟨_, ⟨a, h₁, rfl⟩, h₂⟩ => ⟨a, h₁, h₂⟩, fun ⟨a, h₁, h₂⟩ => ⟨_, ⟨a, h₁, rfl⟩, h₂⟩⟩
|
||||
|
||||
@@ -2119,7 +2126,7 @@ theorem flatMap_singleton (f : α → List β) (x : α) : [x].flatMap f = f x :=
|
||||
@[simp] theorem flatMap_singleton' (l : List α) : (l.flatMap fun x => [x]) = l := by
|
||||
induction l <;> simp [*]
|
||||
|
||||
@[grind] theorem head?_flatMap {l : List α} {f : α → List β} :
|
||||
@[grind =] theorem head?_flatMap {l : List α} {f : α → List β} :
|
||||
(l.flatMap f).head? = l.findSome? fun a => (f a).head? := by
|
||||
induction l with
|
||||
| nil => rfl
|
||||
@@ -2172,7 +2179,7 @@ theorem flatMap_eq_foldl {f : α → List β} {l : List α} :
|
||||
theorem replicate_succ' : replicate (n + 1) a = replicate n a ++ [a] := by
|
||||
induction n <;> simp_all [replicate_succ, ← cons_append]
|
||||
|
||||
@[simp, grind] theorem mem_replicate {a b : α} : ∀ {n}, b ∈ replicate n a ↔ n ≠ 0 ∧ b = a
|
||||
@[simp, grind =] theorem mem_replicate {a b : α} : ∀ {n}, b ∈ replicate n a ↔ n ≠ 0 ∧ b = a
|
||||
| 0 => by simp
|
||||
| n+1 => by simp [replicate_succ, mem_replicate, Nat.succ_ne_zero]
|
||||
|
||||
@@ -2197,11 +2204,11 @@ theorem forall_mem_replicate {p : α → Prop} {a : α} {n} :
|
||||
@[simp] theorem replicate_eq_nil_iff {n : Nat} (a : α) : replicate n a = [] ↔ n = 0 := by
|
||||
cases n <;> simp
|
||||
|
||||
@[simp, grind] theorem getElem_replicate {a : α} {n : Nat} {i : Nat} (h : i < (replicate n a).length) :
|
||||
@[simp, grind =] theorem getElem_replicate {a : α} {n : Nat} {i : Nat} (h : i < (replicate n a).length) :
|
||||
(replicate n a)[i] = a :=
|
||||
eq_of_mem_replicate (getElem_mem _)
|
||||
|
||||
@[grind] theorem getElem?_replicate : (replicate n a)[i]? = if i < n then some a else none := by
|
||||
@[grind =] theorem getElem?_replicate : (replicate n a)[i]? = if i < n then some a else none := by
|
||||
by_cases h : i < n
|
||||
· rw [getElem?_eq_getElem (by simpa), getElem_replicate, if_pos h]
|
||||
· rw [getElem?_eq_none (by simpa using h), if_neg h]
|
||||
@@ -2209,7 +2216,7 @@ theorem forall_mem_replicate {p : α → Prop} {a : α} {n} :
|
||||
@[simp] theorem getElem?_replicate_of_lt {n : Nat} {i : Nat} (h : i < n) : (replicate n a)[i]? = some a := by
|
||||
simp [h]
|
||||
|
||||
@[grind] theorem head?_replicate {a : α} {n : Nat} : (replicate n a).head? = if n = 0 then none else some a := by
|
||||
@[grind =] theorem head?_replicate {a : α} {n : Nat} : (replicate n a).head? = if n = 0 then none else some a := by
|
||||
cases n <;> simp [replicate_succ]
|
||||
|
||||
@[simp] theorem head_replicate (w : replicate n a ≠ []) : (replicate n a).head w = a := by
|
||||
@@ -2298,7 +2305,7 @@ theorem replicate_eq_append_iff {l₁ l₂ : List α} {a : α} :
|
||||
simp only [getElem?_map, getElem?_replicate]
|
||||
split <;> simp
|
||||
|
||||
@[grind] theorem filter_replicate : (replicate n a).filter p = if p a then replicate n a else [] := by
|
||||
@[grind =] theorem filter_replicate : (replicate n a).filter p = if p a then replicate n a else [] := by
|
||||
cases n with
|
||||
| zero => simp
|
||||
| succ n =>
|
||||
@@ -2401,7 +2408,7 @@ termination_by l.length
|
||||
|
||||
/-! ### reverse -/
|
||||
|
||||
@[simp, grind] theorem length_reverse {as : List α} : (as.reverse).length = as.length := by
|
||||
@[simp, grind =] theorem length_reverse {as : List α} : (as.reverse).length = as.length := by
|
||||
induction as with
|
||||
| nil => rfl
|
||||
| cons a as ih => simp [ih]
|
||||
@@ -2410,7 +2417,7 @@ theorem mem_reverseAux {x : α} : ∀ {as bs}, x ∈ reverseAux as bs ↔ x ∈
|
||||
| [], _ => ⟨.inr, fun | .inr h => h⟩
|
||||
| a :: _, _ => by rw [reverseAux, mem_cons, or_assoc, or_left_comm, mem_reverseAux, mem_cons]
|
||||
|
||||
@[simp, grind] theorem mem_reverse {x : α} {as : List α} : x ∈ reverse as ↔ x ∈ as := by
|
||||
@[simp, grind =] theorem mem_reverse {x : α} {as : List α} : x ∈ reverse as ↔ x ∈ as := by
|
||||
simp [reverse, mem_reverseAux]
|
||||
|
||||
@[simp] theorem reverse_eq_nil_iff {xs : List α} : xs.reverse = [] ↔ xs = [] := by
|
||||
@@ -2434,14 +2441,14 @@ theorem getElem?_reverse' : ∀ {l : List α} {i j}, i + j + 1 = length l →
|
||||
rw [getElem?_append_left, getElem?_reverse' this]
|
||||
rw [length_reverse, ← this]; apply Nat.lt_add_of_pos_right (Nat.succ_pos _)
|
||||
|
||||
@[simp, grind]
|
||||
@[simp, grind =]
|
||||
theorem getElem?_reverse {l : List α} {i} (h : i < length l) :
|
||||
l.reverse[i]? = l[l.length - 1 - i]? :=
|
||||
getElem?_reverse' <| by
|
||||
rw [Nat.add_sub_of_le (Nat.le_sub_one_of_lt h),
|
||||
Nat.sub_add_cancel (Nat.lt_of_le_of_lt (Nat.zero_le _) h)]
|
||||
|
||||
@[simp, grind]
|
||||
@[simp, grind =]
|
||||
theorem getElem_reverse {l : List α} {i} (h : i < l.reverse.length) :
|
||||
l.reverse[i] = l[l.length - 1 - i]'(Nat.sub_one_sub_lt_of_lt (by simpa using h)) := by
|
||||
apply Option.some.inj
|
||||
@@ -2454,7 +2461,7 @@ theorem reverseAux_reverseAux_nil {as bs : List α} : reverseAux (reverseAux as
|
||||
| cons a as ih => simp [reverseAux, ih]
|
||||
|
||||
-- The argument `as : List α` is explicit to allow rewriting from right to left.
|
||||
@[simp, grind] theorem reverse_reverse (as : List α) : as.reverse.reverse = as := by
|
||||
@[simp, grind =] theorem reverse_reverse (as : List α) : as.reverse.reverse = as := by
|
||||
simp only [reverse]; rw [reverseAux_reverseAux_nil]; rfl
|
||||
|
||||
theorem reverse_eq_iff {as bs : List α} : as.reverse = bs ↔ as = bs.reverse := by
|
||||
@@ -2467,10 +2474,10 @@ theorem reverse_eq_iff {as bs : List α} : as.reverse = bs ↔ as = bs.reverse :
|
||||
xs.reverse = a :: ys ↔ xs = ys.reverse ++ [a] := by
|
||||
rw [reverse_eq_iff, reverse_cons]
|
||||
|
||||
@[simp, grind] theorem getLast?_reverse {l : List α} : l.reverse.getLast? = l.head? := by
|
||||
@[simp, grind =] theorem getLast?_reverse {l : List α} : l.reverse.getLast? = l.head? := by
|
||||
cases l <;> simp [getLast?_concat]
|
||||
|
||||
@[simp, grind] theorem head?_reverse {l : List α} : l.reverse.head? = l.getLast? := by
|
||||
@[simp, grind =] theorem head?_reverse {l : List α} : l.reverse.head? = l.getLast? := by
|
||||
rw [← getLast?_reverse, reverse_reverse]
|
||||
|
||||
theorem getLast?_eq_head?_reverse {xs : List α} : xs.getLast? = xs.reverse.head? := by
|
||||
@@ -2534,16 +2541,16 @@ theorem flatten_reverse {L : List (List α)} :
|
||||
L.reverse.flatten = (L.map reverse).flatten.reverse := by
|
||||
induction L <;> simp_all
|
||||
|
||||
@[grind] theorem reverse_flatMap {β} {l : List α} {f : α → List β} : (l.flatMap f).reverse = l.reverse.flatMap (reverse ∘ f) := by
|
||||
@[grind =] theorem reverse_flatMap {β} {l : List α} {f : α → List β} : (l.flatMap f).reverse = l.reverse.flatMap (reverse ∘ f) := by
|
||||
induction l <;> simp_all
|
||||
|
||||
@[grind] theorem flatMap_reverse {β} {l : List α} {f : α → List β} : (l.reverse.flatMap f) = (l.flatMap (reverse ∘ f)).reverse := by
|
||||
@[grind =] theorem flatMap_reverse {β} {l : List α} {f : α → List β} : (l.reverse.flatMap f) = (l.flatMap (reverse ∘ f)).reverse := by
|
||||
induction l <;> simp_all
|
||||
|
||||
@[simp] theorem reverseAux_eq {as bs : List α} : reverseAux as bs = reverse as ++ bs :=
|
||||
reverseAux_eq_append ..
|
||||
|
||||
@[simp, grind] theorem reverse_replicate {n : Nat} {a : α} : (replicate n a).reverse = replicate n a :=
|
||||
@[simp, grind =] theorem reverse_replicate {n : Nat} {a : α} : (replicate n a).reverse = replicate n a :=
|
||||
eq_replicate_iff.2
|
||||
⟨by rw [length_reverse, length_replicate],
|
||||
fun _ h => eq_of_mem_replicate (mem_reverse.1 h)⟩
|
||||
@@ -2555,7 +2562,7 @@ theorem flatten_reverse {L : List (List α)} :
|
||||
(l ++ l').foldlM f b = l.foldlM f b >>= l'.foldlM f := by
|
||||
induction l generalizing b <;> simp [*]
|
||||
|
||||
@[simp, grind] theorem foldrM_cons [Monad m] [LawfulMonad m] {a : α} {l : List α} {f : α → β → m β} {b : β} :
|
||||
@[simp, grind =] theorem foldrM_cons [Monad m] [LawfulMonad m] {a : α} {l : List α} {f : α → β → m β} {b : β} :
|
||||
(a :: l).foldrM f b = l.foldrM f b >>= f a := by
|
||||
simp only [foldrM]
|
||||
induction l <;> simp_all
|
||||
@@ -2599,37 +2606,37 @@ theorem id_run_foldrM {f : α → β → Id β} {b : β} {l : List α} :
|
||||
|
||||
/-! ### foldl and foldr -/
|
||||
|
||||
@[simp, grind] theorem foldr_cons_eq_append {l : List α} {f : α → β} {l' : List β} :
|
||||
@[simp] theorem foldr_cons_eq_append {l : List α} {f : α → β} {l' : List β} :
|
||||
l.foldr (fun x ys => f x :: ys) l' = l.map f ++ l' := by
|
||||
induction l <;> simp [*]
|
||||
|
||||
/-- Variant of `foldr_cons_eq_append` specalized to `f = id`. -/
|
||||
@[simp, grind] theorem foldr_cons_eq_append' {l l' : List β} :
|
||||
@[simp, grind =] theorem foldr_cons_eq_append' {l l' : List β} :
|
||||
l.foldr cons l' = l ++ l' := by
|
||||
induction l <;> simp [*]
|
||||
|
||||
@[simp, grind] theorem foldl_flip_cons_eq_append {l : List α} {f : α → β} {l' : List β} :
|
||||
@[simp] theorem foldl_flip_cons_eq_append {l : List α} {f : α → β} {l' : List β} :
|
||||
l.foldl (fun xs y => f y :: xs) l' = (l.map f).reverse ++ l' := by
|
||||
induction l generalizing l' <;> simp [*]
|
||||
|
||||
/-- Variant of `foldl_flip_cons_eq_append` specalized to `f = id`. -/
|
||||
@[grind] theorem foldl_flip_cons_eq_append' {l l' : List α} :
|
||||
theorem foldl_flip_cons_eq_append' {l l' : List α} :
|
||||
l.foldl (fun xs y => y :: xs) l' = l.reverse ++ l' := by
|
||||
simp
|
||||
|
||||
@[simp, grind] theorem foldr_append_eq_append {l : List α} {f : α → List β} {l' : List β} :
|
||||
@[simp] theorem foldr_append_eq_append {l : List α} {f : α → List β} {l' : List β} :
|
||||
l.foldr (f · ++ ·) l' = (l.map f).flatten ++ l' := by
|
||||
induction l <;> simp [*]
|
||||
|
||||
@[simp, grind] theorem foldl_append_eq_append {l : List α} {f : α → List β} {l' : List β} :
|
||||
@[simp] theorem foldl_append_eq_append {l : List α} {f : α → List β} {l' : List β} :
|
||||
l.foldl (· ++ f ·) l' = l' ++ (l.map f).flatten := by
|
||||
induction l generalizing l'<;> simp [*]
|
||||
|
||||
@[simp, grind] theorem foldr_flip_append_eq_append {l : List α} {f : α → List β} {l' : List β} :
|
||||
@[simp] theorem foldr_flip_append_eq_append {l : List α} {f : α → List β} {l' : List β} :
|
||||
l.foldr (fun x ys => ys ++ f x) l' = l' ++ (l.map f).reverse.flatten := by
|
||||
induction l generalizing l' <;> simp [*]
|
||||
|
||||
@[simp, grind] theorem foldl_flip_append_eq_append {l : List α} {f : α → List β} {l' : List β} :
|
||||
@[simp] theorem foldl_flip_append_eq_append {l : List α} {f : α → List β} {l' : List β} :
|
||||
l.foldl (fun xs y => f y ++ xs) l' = (l.map f).reverse.flatten ++ l' := by
|
||||
induction l generalizing l' <;> simp [*]
|
||||
|
||||
@@ -2683,19 +2690,19 @@ theorem foldr_map_hom {g : α → β} {f : α → α → α} {f' : β → β →
|
||||
@[simp, grind _=_] theorem foldr_append {f : α → β → β} {b : β} {l l' : List α} :
|
||||
(l ++ l').foldr f b = l.foldr f (l'.foldr f b) := by simp [foldr_eq_foldrM, -foldrM_pure]
|
||||
|
||||
@[grind] theorem foldl_flatten {f : β → α → β} {b : β} {L : List (List α)} :
|
||||
@[grind =] theorem foldl_flatten {f : β → α → β} {b : β} {L : List (List α)} :
|
||||
(flatten L).foldl f b = L.foldl (fun b l => l.foldl f b) b := by
|
||||
induction L generalizing b <;> simp_all
|
||||
|
||||
@[grind] theorem foldr_flatten {f : α → β → β} {b : β} {L : List (List α)} :
|
||||
@[grind =] theorem foldr_flatten {f : α → β → β} {b : β} {L : List (List α)} :
|
||||
(flatten L).foldr f b = L.foldr (fun l b => l.foldr f b) b := by
|
||||
induction L <;> simp_all
|
||||
|
||||
@[simp, grind] theorem foldl_reverse {l : List α} {f : β → α → β} {b : β} :
|
||||
@[simp, grind =] theorem foldl_reverse {l : List α} {f : β → α → β} {b : β} :
|
||||
l.reverse.foldl f b = l.foldr (fun x y => f y x) b := by
|
||||
simp [foldl_eq_foldlM, foldr_eq_foldrM, -foldrM_pure]
|
||||
|
||||
@[simp, grind] theorem foldr_reverse {l : List α} {f : α → β → β} {b : β} :
|
||||
@[simp, grind =] theorem foldr_reverse {l : List α} {f : α → β → β} {b : β} :
|
||||
l.reverse.foldr f b = l.foldl (fun x y => f y x) b :=
|
||||
(foldl_reverse ..).symm.trans <| by simp
|
||||
|
||||
@@ -2849,7 +2856,7 @@ theorem foldr_rel {l : List α} {f : α → β → β} {g : α → γ → γ} {a
|
||||
|
||||
/-! #### Further results about `getLast` and `getLast?` -/
|
||||
|
||||
@[simp, grind] theorem head_reverse {l : List α} (h : l.reverse ≠ []) :
|
||||
@[simp, grind =] theorem head_reverse {l : List α} (h : l.reverse ≠ []) :
|
||||
l.reverse.head h = getLast l (by simp_all) := by
|
||||
induction l with
|
||||
| nil => contradiction
|
||||
@@ -2879,7 +2886,7 @@ theorem getLast?_eq_some_iff {xs : List α} {a : α} : xs.getLast? = some a ↔
|
||||
rw [getLast?_eq_head?_reverse, isSome_head?]
|
||||
simp
|
||||
|
||||
@[simp, grind] theorem getLast_reverse {l : List α} (h : l.reverse ≠ []) :
|
||||
@[simp, grind =] theorem getLast_reverse {l : List α} (h : l.reverse ≠ []) :
|
||||
l.reverse.getLast h = l.head (by simp_all) := by
|
||||
simp [getLast_eq_head_reverse]
|
||||
|
||||
@@ -2892,7 +2899,7 @@ theorem head_eq_getLast_reverse {l : List α} (h : l ≠ []) :
|
||||
simp only [getLast_eq_head_reverse, reverse_append]
|
||||
rw [head_append_of_ne_nil]
|
||||
|
||||
@[grind] theorem getLast_append {l : List α} (h : l ++ l' ≠ []) :
|
||||
@[grind =] theorem getLast_append {l : List α} (h : l ++ l' ≠ []) :
|
||||
(l ++ l').getLast h =
|
||||
if h' : l'.isEmpty then
|
||||
l.getLast (by simp_all [isEmpty_iff])
|
||||
@@ -2913,7 +2920,7 @@ theorem getLast_append_left {l : List α} (w : l ++ l' ≠ []) (h : l' = []) :
|
||||
(l ++ l').getLast w = l.getLast (by simp_all) := by
|
||||
rw [getLast_append, dif_pos (by simp_all)]
|
||||
|
||||
@[simp, grind] theorem getLast?_append {l l' : List α} : (l ++ l').getLast? = l'.getLast?.or l.getLast? := by
|
||||
@[simp, grind =] theorem getLast?_append {l l' : List α} : (l ++ l').getLast? = l'.getLast?.or l.getLast? := by
|
||||
simp [← head?_reverse]
|
||||
|
||||
theorem getLast_filter_of_pos {p : α → Bool} {l : List α} (w : l ≠ []) (h : p (getLast l w) = true) :
|
||||
@@ -2949,7 +2956,7 @@ theorem getLast?_replicate {a : α} {n : Nat} : (replicate n a).getLast? = if n
|
||||
/-! ### leftpad -/
|
||||
|
||||
-- We unfold `leftpad` and `rightpad` for verification purposes.
|
||||
attribute [simp, grind] leftpad rightpad
|
||||
attribute [simp, grind =] leftpad rightpad
|
||||
|
||||
-- `length_leftpad` and `length_rightpad` are in `Init.Data.List.Nat.Basic`.
|
||||
|
||||
@@ -2978,17 +2985,21 @@ theorem contains_iff_exists_mem_beq [BEq α] {l : List α} {a : α} :
|
||||
l.contains a ↔ ∃ a' ∈ l, a == a' := by
|
||||
induction l <;> simp_all
|
||||
|
||||
-- We add this as a `grind` lemma because it is useful without `LawfulBEq α`.
|
||||
-- With `LawfulBEq α`, it would be better to use `contains_iff_mem` directly.
|
||||
grind_pattern contains_iff_exists_mem_beq => l.contains a
|
||||
|
||||
@[grind _=_]
|
||||
theorem contains_iff_mem [BEq α] [LawfulBEq α] {l : List α} {a : α} :
|
||||
l.contains a ↔ a ∈ l := by
|
||||
simp
|
||||
|
||||
@[simp, grind]
|
||||
@[simp, grind =]
|
||||
theorem contains_map [BEq β] {l : List α} {x : β} {f : α → β} :
|
||||
(l.map f).contains x = l.any (fun a => x == f a) := by
|
||||
induction l with simp_all
|
||||
|
||||
@[simp, grind]
|
||||
@[simp, grind =]
|
||||
theorem contains_filter [BEq α] {l : List α} {x : α} {p : α → Bool} :
|
||||
(l.filter p).contains x = l.any (fun a => x == a && p a) := by
|
||||
induction l with
|
||||
@@ -2997,7 +3008,7 @@ theorem contains_filter [BEq α] {l : List α} {x : α} {p : α → Bool} :
|
||||
simp only [filter_cons, any_cons]
|
||||
split <;> simp_all
|
||||
|
||||
@[simp, grind]
|
||||
@[simp, grind =]
|
||||
theorem contains_filterMap [BEq β] {l : List α} {x : β} {f : α → Option β} :
|
||||
(l.filterMap f).contains x = l.any (fun a => (f a).any fun b => x == b) := by
|
||||
induction l with
|
||||
@@ -3013,21 +3024,21 @@ theorem contains_append [BEq α] {l₁ l₂ : List α} {x : α} :
|
||||
| nil => simp
|
||||
| cons a l ih => simp [ih, Bool.or_assoc]
|
||||
|
||||
@[simp, grind]
|
||||
@[simp, grind =]
|
||||
theorem contains_flatten [BEq α] {l : List (List α)} {x : α} :
|
||||
l.flatten.contains x = l.any fun l => l.contains x := by
|
||||
induction l with
|
||||
| nil => simp
|
||||
| cons _ l ih => simp [ih]
|
||||
|
||||
@[simp, grind]
|
||||
@[simp, grind =]
|
||||
theorem contains_reverse [BEq α] {l : List α} {x : α} :
|
||||
(l.reverse).contains x = l.contains x := by
|
||||
induction l with
|
||||
| nil => simp
|
||||
| cons a l ih => simp [ih, Bool.or_comm]
|
||||
|
||||
@[simp, grind]
|
||||
@[simp, grind =]
|
||||
theorem contains_flatMap [BEq β] {l : List α} {f : α → List β} {x : β} :
|
||||
(l.flatMap f).contains x = l.any fun a => (f a).contains x := by
|
||||
induction l with
|
||||
@@ -3042,7 +3053,7 @@ Because we immediately simplify `partition` into two `filter`s for verification
|
||||
we do not separately develop much theory about it.
|
||||
-/
|
||||
|
||||
@[simp, grind] theorem partition_eq_filter_filter {p : α → Bool} {l : List α} :
|
||||
@[simp, grind =] theorem partition_eq_filter_filter {p : α → Bool} {l : List α} :
|
||||
partition p l = (filter p l, filter (not ∘ p) l) := by simp [partition, aux]
|
||||
where
|
||||
aux : ∀ l {as bs}, partition.loop p l (as, bs) =
|
||||
@@ -3062,16 +3073,16 @@ grind_pattern mem_partition => a ∈ (partition p l).2
|
||||
are often used for theorems about `Array.pop`.
|
||||
-/
|
||||
|
||||
@[simp, grind] theorem length_dropLast : ∀ {xs : List α}, xs.dropLast.length = xs.length - 1
|
||||
@[simp, grind =] theorem length_dropLast : ∀ {xs : List α}, xs.dropLast.length = xs.length - 1
|
||||
| [] => rfl
|
||||
| x::xs => by simp
|
||||
|
||||
@[simp, grind] theorem getElem_dropLast : ∀ {xs : List α} {i : Nat} (h : i < xs.dropLast.length),
|
||||
@[simp, grind =] theorem getElem_dropLast : ∀ {xs : List α} {i : Nat} (h : i < xs.dropLast.length),
|
||||
xs.dropLast[i] = xs[i]'(Nat.lt_of_lt_of_le h (length_dropLast .. ▸ Nat.pred_le _))
|
||||
| _ :: _ :: _, 0, _ => rfl
|
||||
| _ :: _ :: _, _ + 1, h => getElem_dropLast (Nat.add_one_lt_add_one_iff.mp h)
|
||||
|
||||
@[grind] theorem getElem?_dropLast {xs : List α} {i : Nat} :
|
||||
@[grind =] theorem getElem?_dropLast {xs : List α} {i : Nat} :
|
||||
xs.dropLast[i]? = if i < xs.length - 1 then xs[i]? else none := by
|
||||
split
|
||||
· rw [getElem?_eq_getElem, getElem?_eq_getElem, getElem_dropLast]
|
||||
@@ -3269,24 +3280,24 @@ theorem all_eq_not_any_not {l : List α} {p : α → Bool} : l.all p = !l.any (!
|
||||
| nil => rfl
|
||||
| cons h t ih => simp_all [Bool.and_assoc]
|
||||
|
||||
@[simp, grind] theorem any_flatten {l : List (List α)} : l.flatten.any f = l.any (any · f) := by
|
||||
@[simp, grind =] theorem any_flatten {l : List (List α)} : l.flatten.any f = l.any (any · f) := by
|
||||
induction l <;> simp_all
|
||||
|
||||
@[simp, grind] theorem all_flatten {l : List (List α)} : l.flatten.all f = l.all (all · f) := by
|
||||
@[simp, grind =] theorem all_flatten {l : List (List α)} : l.flatten.all f = l.all (all · f) := by
|
||||
induction l <;> simp_all
|
||||
|
||||
@[simp, grind] theorem any_flatMap {l : List α} {f : α → List β} :
|
||||
@[simp, grind =] theorem any_flatMap {l : List α} {f : α → List β} :
|
||||
(l.flatMap f).any p = l.any fun a => (f a).any p := by
|
||||
induction l <;> simp_all
|
||||
|
||||
@[simp, grind] theorem all_flatMap {l : List α} {f : α → List β} :
|
||||
@[simp, grind =] theorem all_flatMap {l : List α} {f : α → List β} :
|
||||
(l.flatMap f).all p = l.all fun a => (f a).all p := by
|
||||
induction l <;> simp_all
|
||||
|
||||
@[simp, grind] theorem any_reverse {l : List α} : l.reverse.any f = l.any f := by
|
||||
@[simp, grind =] theorem any_reverse {l : List α} : l.reverse.any f = l.any f := by
|
||||
induction l <;> simp_all [Bool.or_comm]
|
||||
|
||||
@[simp, grind] theorem all_reverse {l : List α} : l.reverse.all f = l.all f := by
|
||||
@[simp, grind =] theorem all_reverse {l : List α} : l.reverse.all f = l.all f := by
|
||||
induction l <;> simp_all [Bool.and_comm]
|
||||
|
||||
@[simp] theorem any_replicate {n : Nat} {a : α} :
|
||||
@@ -3336,14 +3347,14 @@ variable [BEq α]
|
||||
simp only [replace_cons]
|
||||
split <;> simp_all
|
||||
|
||||
@[simp, grind] theorem length_replace {l : List α} : (l.replace a b).length = l.length := by
|
||||
@[simp, grind =] theorem length_replace {l : List α} : (l.replace a b).length = l.length := by
|
||||
induction l with
|
||||
| nil => simp
|
||||
| cons x l ih =>
|
||||
simp only [replace_cons]
|
||||
split <;> simp_all
|
||||
|
||||
@[grind] theorem getElem?_replace [LawfulBEq α] {l : List α} {i : Nat} :
|
||||
@[grind =] theorem getElem?_replace [LawfulBEq α] {l : List α} {i : Nat} :
|
||||
(l.replace a b)[i]? = if l[i]? == some a then if a ∈ l.take i then some a else some b else l[i]? := by
|
||||
induction l generalizing i with
|
||||
| nil => cases i <;> simp
|
||||
@@ -3356,7 +3367,7 @@ theorem getElem?_replace_of_ne [LawfulBEq α] {l : List α} {i : Nat} (h : l[i]?
|
||||
(l.replace a b)[i]? = l[i]? := by
|
||||
simp_all [getElem?_replace]
|
||||
|
||||
@[grind] theorem getElem_replace [LawfulBEq α] {l : List α} {i : Nat} (h : i < l.length) :
|
||||
@[grind =] theorem getElem_replace [LawfulBEq α] {l : List α} {i : Nat} (h : i < l.length) :
|
||||
(l.replace a b)[i]'(by simpa) = if l[i] == a then if a ∈ l.take i then a else b else l[i] := by
|
||||
apply Option.some.inj
|
||||
rw [← getElem?_eq_getElem, getElem?_replace]
|
||||
@@ -3386,7 +3397,7 @@ theorem head_replace {l : List α} {a b : α} (w) :
|
||||
apply Option.some.inj
|
||||
rw [← head?_eq_head, head?_replace, head?_eq_head]
|
||||
|
||||
@[grind] theorem replace_append [LawfulBEq α] {l₁ l₂ : List α} :
|
||||
@[grind =] theorem replace_append [LawfulBEq α] {l₁ l₂ : List α} :
|
||||
(l₁ ++ l₂).replace a b = if a ∈ l₁ then l₁.replace a b ++ l₂ else l₁ ++ l₂.replace a b := by
|
||||
induction l₁ with
|
||||
| nil => simp
|
||||
@@ -3430,9 +3441,9 @@ end replace
|
||||
section insert
|
||||
variable [BEq α]
|
||||
|
||||
@[simp, grind] theorem insert_nil (a : α) : [].insert a = [a] := rfl
|
||||
@[simp, grind =] theorem insert_nil (a : α) : [].insert a = [a] := rfl
|
||||
|
||||
@[simp, grind] theorem contains_insert [PartialEquivBEq α] {l : List α} {a : α} {x : α} :
|
||||
@[simp, grind =] theorem contains_insert [PartialEquivBEq α] {l : List α} {a : α} {x : α} :
|
||||
(l.insert a).contains x = (x == a || l.contains x) := by
|
||||
simp only [List.insert]
|
||||
split <;> rename_i h
|
||||
@@ -3449,7 +3460,7 @@ variable [LawfulBEq α]
|
||||
@[simp] theorem insert_of_not_mem {l : List α} (h : a ∉ l) : l.insert a = a :: l := by
|
||||
simp [List.insert, h]
|
||||
|
||||
@[simp, grind] theorem mem_insert_iff {l : List α} : a ∈ l.insert b ↔ a = b ∨ a ∈ l := by
|
||||
@[simp, grind =] theorem mem_insert_iff {l : List α} : a ∈ l.insert b ↔ a = b ∨ a ∈ l := by
|
||||
if h : b ∈ l then
|
||||
rw [insert_of_mem h]
|
||||
constructor; {apply Or.inr}
|
||||
@@ -3473,7 +3484,7 @@ theorem eq_or_mem_of_mem_insert {l : List α} (h : a ∈ l.insert b) : a = b ∨
|
||||
@[simp] theorem length_insert_of_not_mem {l : List α} (h : a ∉ l) :
|
||||
length (l.insert a) = length l + 1 := by rw [insert_of_not_mem h]; rfl
|
||||
|
||||
@[grind] theorem length_insert {l : List α} :
|
||||
@[grind =] theorem length_insert {l : List α} :
|
||||
(l.insert a).length = l.length + if a ∈ l then 0 else 1 := by
|
||||
split <;> simp_all
|
||||
|
||||
@@ -3508,13 +3519,13 @@ theorem getElem?_insert_succ {l : List α} {a : α} {i : Nat} :
|
||||
simp only [insert_eq]
|
||||
split <;> simp
|
||||
|
||||
@[grind] theorem getElem?_insert {l : List α} {a : α} {i : Nat} :
|
||||
@[grind =] theorem getElem?_insert {l : List α} {a : α} {i : Nat} :
|
||||
(l.insert a)[i]? = if a ∈ l then l[i]? else if i = 0 then some a else l[i-1]? := by
|
||||
cases i
|
||||
· simp [getElem?_insert_zero]
|
||||
· simp [getElem?_insert_succ]
|
||||
|
||||
@[grind] theorem getElem_insert {l : List α} {a : α} {i : Nat} (h : i < l.length) :
|
||||
@[grind =] theorem getElem_insert {l : List α} {a : α} {i : Nat} (h : i < l.length) :
|
||||
(l.insert a)[i]'(Nat.lt_of_lt_of_le h length_le_length_insert) =
|
||||
if a ∈ l then l[i] else if i = 0 then a else l[i-1]'(Nat.lt_of_le_of_lt (Nat.pred_le _) h) := by
|
||||
apply Option.some.inj
|
||||
@@ -3538,7 +3549,7 @@ theorem head_insert {l : List α} {a : α} (w) :
|
||||
apply Option.some.inj
|
||||
rw [← head?_eq_head, head?_insert]
|
||||
|
||||
@[grind] theorem insert_append {l₁ l₂ : List α} {a : α} :
|
||||
@[grind =] theorem insert_append {l₁ l₂ : List α} {a : α} :
|
||||
(l₁ ++ l₂).insert a = if a ∈ l₂ then l₁ ++ l₂ else l₁.insert a ++ l₂ := by
|
||||
simp only [insert_eq, mem_append]
|
||||
(repeat split) <;> simp_all
|
||||
@@ -3551,7 +3562,7 @@ theorem insert_append_of_not_mem_left {l₁ l₂ : List α} (h : ¬ a ∈ l₂)
|
||||
(l₁ ++ l₂).insert a = l₁.insert a ++ l₂ := by
|
||||
simp [insert_append, h]
|
||||
|
||||
@[simp, grind] theorem insert_replicate_self {a : α} (h : 0 < n) : (replicate n a).insert a = replicate n a := by
|
||||
@[simp, grind =] theorem insert_replicate_self {a : α} (h : 0 < n) : (replicate n a).insert a = replicate n a := by
|
||||
cases n <;> simp_all
|
||||
|
||||
@[simp] theorem insert_replicate_ne {a b : α} (h : !b == a) :
|
||||
|
||||
@@ -248,11 +248,10 @@ theorem pairwise_le_range {n : Nat} : Pairwise (· ≤ ·) (range n) :=
|
||||
theorem nodup_range {n : Nat} : Nodup (range n) := by
|
||||
simp +decide only [range_eq_range', nodup_range']
|
||||
|
||||
@[simp, grind] theorem find?_range_eq_some {n : Nat} {i : Nat} {p : Nat → Bool} :
|
||||
@[simp] theorem find?_range_eq_some {n : Nat} {i : Nat} {p : Nat → Bool} :
|
||||
(range n).find? p = some i ↔ p i ∧ i ∈ range n ∧ ∀ j, j < i → !p j := by
|
||||
simp [range_eq_range']
|
||||
|
||||
@[grind]
|
||||
theorem find?_range_eq_none {n : Nat} {p : Nat → Bool} :
|
||||
(range n).find? p = none ↔ ∀ i, i < n → !p i := by
|
||||
simp
|
||||
|
||||
@@ -43,7 +43,7 @@ theorem rel_of_pairwise_cons (p : (a :: l).Pairwise R) : ∀ {a'}, a' ∈ l →
|
||||
(pairwise_cons.1 p).2
|
||||
|
||||
set_option linter.unusedVariables false in
|
||||
@[grind] theorem Pairwise.tail : ∀ {l : List α} (h : Pairwise R l), Pairwise R l.tail
|
||||
@[grind ←] theorem Pairwise.tail : ∀ {l : List α} (h : Pairwise R l), Pairwise R l.tail
|
||||
| [], h => h
|
||||
| _ :: _, h => h.of_cons
|
||||
|
||||
@@ -103,7 +103,7 @@ theorem Pairwise.forall_of_forall_of_flip (h₁ : ∀ x ∈ l, R x x) (h₂ : Pa
|
||||
· exact h₃.1 _ hx
|
||||
· exact ih (fun x hx => h₁ _ <| mem_cons_of_mem _ hx) h₂.2 h₃.2 hx hy
|
||||
|
||||
@[grind] theorem pairwise_singleton (R) (a : α) : Pairwise R [a] := by simp
|
||||
@[grind ←] theorem pairwise_singleton (R) (a : α) : Pairwise R [a] := by simp
|
||||
|
||||
@[grind =] theorem pairwise_pair {a b : α} : Pairwise R [a, b] ↔ R a b := by simp
|
||||
|
||||
@@ -117,7 +117,7 @@ theorem Pairwise.of_map {S : β → β → Prop} (f : α → β) (H : ∀ a b :
|
||||
(p : Pairwise S (map f l)) : Pairwise R l :=
|
||||
(pairwise_map.1 p).imp (H _ _)
|
||||
|
||||
@[grind] theorem Pairwise.map {S : β → β → Prop} (f : α → β) (H : ∀ a b : α, R a b → S (f a) (f b))
|
||||
@[grind <=] theorem Pairwise.map {S : β → β → Prop} (f : α → β) (H : ∀ a b : α, R a b → S (f a) (f b))
|
||||
(p : Pairwise R l) : Pairwise S (map f l) :=
|
||||
pairwise_map.2 <| p.imp (H _ _)
|
||||
|
||||
@@ -136,7 +136,7 @@ theorem Pairwise.of_map {S : β → β → Prop} (f : α → β) (H : ∀ a b :
|
||||
simpa [IH, e] using fun _ =>
|
||||
⟨fun h a ha b hab => h _ _ ha hab, fun h a b ha hab => h _ ha _ hab⟩
|
||||
|
||||
@[grind] theorem Pairwise.filterMap {S : β → β → Prop} (f : α → Option β)
|
||||
@[grind <=] theorem Pairwise.filterMap {S : β → β → Prop} (f : α → Option β)
|
||||
(H : ∀ a a' : α, R a a' → ∀ b, f a = some b → ∀ b', f a' = some b' → S b b') {l : List α} (p : Pairwise R l) :
|
||||
Pairwise S (filterMap f l) :=
|
||||
pairwise_filterMap.2 <| p.imp (H _ _)
|
||||
@@ -146,7 +146,7 @@ theorem Pairwise.of_map {S : β → β → Prop} (f : α → β) (H : ∀ a b :
|
||||
rw [← filterMap_eq_filter, pairwise_filterMap]
|
||||
simp
|
||||
|
||||
@[grind] theorem Pairwise.filter (p : α → Bool) : Pairwise R l → Pairwise R (filter p l) :=
|
||||
@[grind ←] theorem Pairwise.filter (p : α → Bool) : Pairwise R l → Pairwise R (filter p l) :=
|
||||
Pairwise.sublist filter_sublist
|
||||
|
||||
@[grind =] theorem pairwise_append {l₁ l₂ : List α} :
|
||||
@@ -207,10 +207,10 @@ theorem pairwise_append_comm {R : α → α → Prop} (s : ∀ {x y}, R x y →
|
||||
simp
|
||||
· exact ⟨fun _ => h, Or.inr h⟩
|
||||
|
||||
@[grind] theorem Pairwise.drop {l : List α} {i : Nat} (h : List.Pairwise R l) : List.Pairwise R (l.drop i) :=
|
||||
@[grind ←] theorem Pairwise.drop {l : List α} {i : Nat} (h : List.Pairwise R l) : List.Pairwise R (l.drop i) :=
|
||||
h.sublist (drop_sublist _ _)
|
||||
|
||||
@[grind] theorem Pairwise.take {l : List α} {i : Nat} (h : List.Pairwise R l) : List.Pairwise R (l.take i) :=
|
||||
@[grind ←] theorem Pairwise.take {l : List α} {i : Nat} (h : List.Pairwise R l) : List.Pairwise R (l.take i) :=
|
||||
h.sublist (take_sublist _ _)
|
||||
|
||||
-- This theorem is not annotated with `grind` because it leads to a loop of instantiations with `Pairwise.sublist`.
|
||||
@@ -266,7 +266,7 @@ theorem pairwise_of_forall_mem_list {l : List α} {r : α → α → Prop} (h :
|
||||
rintro H _ b hb rfl
|
||||
exact H b hb _ _
|
||||
|
||||
@[grind] theorem Pairwise.pmap {l : List α} (hl : Pairwise R l) {p : α → Prop} {f : ∀ a, p a → β}
|
||||
@[grind <=] theorem Pairwise.pmap {l : List α} (hl : Pairwise R l) {p : α → Prop} {f : ∀ a, p a → β}
|
||||
(h : ∀ x ∈ l, p x) {S : β → β → Prop}
|
||||
(hS : ∀ ⦃x⦄ (hx : p x) ⦃y⦄ (hy : p y), R x y → S (f x hx) (f y hy)) :
|
||||
Pairwise S (l.pmap f h) := by
|
||||
@@ -277,10 +277,12 @@ theorem pairwise_of_forall_mem_list {l : List α} {r : α → α → Prop} (h :
|
||||
|
||||
@[grind =] theorem nodup_iff_pairwise_ne : List.Nodup l ↔ List.Pairwise (· ≠ ·) l := Iff.rfl
|
||||
|
||||
@[simp, grind]
|
||||
@[simp]
|
||||
theorem nodup_nil : @Nodup α [] :=
|
||||
Pairwise.nil
|
||||
|
||||
grind_pattern nodup_nil => @Nodup α []
|
||||
|
||||
@[simp, grind =]
|
||||
theorem nodup_cons {a : α} {l : List α} : Nodup (a :: l) ↔ a ∉ l ∧ Nodup l := by
|
||||
simp only [Nodup, pairwise_cons, forall_mem_ne]
|
||||
|
||||
@@ -202,12 +202,18 @@ theorem sublist_or_mem_of_sublist (h : l <+ l₁ ++ a :: l₂) : l <+ l₁ ++ l
|
||||
protected theorem Sublist.mem (hx : a ∈ l₁) (hl : l₁ <+ l₂) : a ∈ l₂ :=
|
||||
hl.subset hx
|
||||
|
||||
@[grind] theorem Sublist.head_mem (s : ys <+ xs) (h) : ys.head h ∈ xs :=
|
||||
theorem Sublist.head_mem (s : ys <+ xs) (h) : ys.head h ∈ xs :=
|
||||
s.mem (List.head_mem h)
|
||||
|
||||
@[grind] theorem Sublist.getLast_mem (s : ys <+ xs) (h) : ys.getLast h ∈ xs :=
|
||||
grind_pattern Sublist.head_mem => ys <+ xs, ys.head h
|
||||
grind_pattern Sublist.head_mem => ys.head h ∈ xs -- This is somewhat aggressive, as it initiates sublist based reasoning.
|
||||
|
||||
theorem Sublist.getLast_mem (s : ys <+ xs) (h) : ys.getLast h ∈ xs :=
|
||||
s.mem (List.getLast_mem h)
|
||||
|
||||
grind_pattern Sublist.getLast_mem => ys <+ xs, ys.getLast h
|
||||
grind_pattern Sublist.getLast_mem => ys.getLast h ∈ xs -- This is somewhat aggressive, as it initiates sublist based reasoning.
|
||||
|
||||
instance : Trans (@Sublist α) Subset Subset :=
|
||||
⟨fun h₁ h₂ => trans h₁.subset h₂⟩
|
||||
|
||||
@@ -248,12 +254,13 @@ theorem Sublist.eq_of_length_le (s : l₁ <+ l₂) (h : length l₂ ≤ length l
|
||||
theorem Sublist.length_eq (s : l₁ <+ l₂) : length l₁ = length l₂ ↔ l₁ = l₂ :=
|
||||
⟨s.eq_of_length, congrArg _⟩
|
||||
|
||||
@[grind]
|
||||
theorem tail_sublist : ∀ l : List α, tail l <+ l
|
||||
| [] => .slnil
|
||||
| a::l => sublist_cons_self a l
|
||||
|
||||
@[grind]
|
||||
grind_pattern tail_sublist => tail l <+ _
|
||||
|
||||
@[grind ←]
|
||||
protected theorem Sublist.tail : ∀ {l₁ l₂ : List α}, l₁ <+ l₂ → tail l₁ <+ tail l₂
|
||||
| _, _, slnil => .slnil
|
||||
| _, _, Sublist.cons _ h => (tail_sublist _).trans h
|
||||
@@ -263,7 +270,7 @@ protected theorem Sublist.tail : ∀ {l₁ l₂ : List α}, l₁ <+ l₂ → tai
|
||||
theorem Sublist.of_cons_cons {l₁ l₂ : List α} {a b : α} (h : a :: l₁ <+ b :: l₂) : l₁ <+ l₂ :=
|
||||
h.tail
|
||||
|
||||
@[grind]
|
||||
@[grind ←]
|
||||
protected theorem Sublist.map (f : α → β) {l₁ l₂} (s : l₁ <+ l₂) : map f l₁ <+ map f l₂ := by
|
||||
induction s with
|
||||
| slnil => simp
|
||||
@@ -275,7 +282,7 @@ protected theorem Sublist.map (f : α → β) {l₁ l₂} (s : l₁ <+ l₂) : m
|
||||
grind_pattern Sublist.map => l₁ <+ l₂, map f l₁
|
||||
grind_pattern Sublist.map => l₁ <+ l₂, map f l₂
|
||||
|
||||
@[grind]
|
||||
@[grind ←]
|
||||
protected theorem Sublist.filterMap (f : α → Option β) (s : l₁ <+ l₂) :
|
||||
filterMap f l₁ <+ filterMap f l₂ := by
|
||||
induction s <;> simp [filterMap_cons] <;> split <;> simp [*, cons]
|
||||
@@ -283,7 +290,7 @@ protected theorem Sublist.filterMap (f : α → Option β) (s : l₁ <+ l₂) :
|
||||
grind_pattern Sublist.filterMap => l₁ <+ l₂, filterMap f l₁
|
||||
grind_pattern Sublist.filterMap => l₁ <+ l₂, filterMap f l₂
|
||||
|
||||
@[grind]
|
||||
@[grind ←]
|
||||
protected theorem Sublist.filter (p : α → Bool) {l₁ l₂} (s : l₁ <+ l₂) : filter p l₁ <+ filter p l₂ := by
|
||||
rw [← filterMap_eq_filter]; apply s.filterMap
|
||||
|
||||
@@ -481,7 +488,7 @@ theorem Sublist.of_sublist_append_right (w : ∀ a, a ∈ l → a ∉ l₁) (h :
|
||||
exact fun x m => w x (mem_append_left l₂' m) (h₁.mem m)
|
||||
simp_all
|
||||
|
||||
@[grind]
|
||||
@[grind ←]
|
||||
theorem Sublist.middle {l : List α} (h : l <+ l₁ ++ l₂) (a : α) : l <+ l₁ ++ a :: l₂ := by
|
||||
rw [sublist_append_iff] at h
|
||||
obtain ⟨l₁', l₂', rfl, h₁, h₂⟩ := h
|
||||
@@ -624,22 +631,28 @@ theorem flatten_sublist_iff {L : List (List α)} {l} :
|
||||
instance [DecidableEq α] (l₁ l₂ : List α) : Decidable (l₁ <+ l₂) :=
|
||||
decidable_of_iff (l₁.isSublist l₂) isSublist_iff_sublist
|
||||
|
||||
@[grind]
|
||||
@[grind ←]
|
||||
protected theorem Sublist.drop : ∀ {l₁ l₂ : List α}, l₁ <+ l₂ → ∀ i, l₁.drop i <+ l₂.drop i
|
||||
| _, _, h, 0 => h
|
||||
| _, _, h, i + 1 => by rw [← drop_tail, ← drop_tail]; exact h.tail.drop i
|
||||
|
||||
/-! ### IsPrefix / IsSuffix / IsInfix -/
|
||||
|
||||
@[simp, grind] theorem prefix_append (l₁ l₂ : List α) : l₁ <+: l₁ ++ l₂ := ⟨l₂, rfl⟩
|
||||
@[simp] theorem prefix_append (l₁ l₂ : List α) : l₁ <+: l₁ ++ l₂ := ⟨l₂, rfl⟩
|
||||
|
||||
@[simp, grind] theorem suffix_append (l₁ l₂ : List α) : l₂ <:+ l₁ ++ l₂ := ⟨l₁, rfl⟩
|
||||
grind_pattern prefix_append => l₁ <+: l₁ ++ l₂
|
||||
|
||||
@[simp] theorem suffix_append (l₁ l₂ : List α) : l₂ <:+ l₁ ++ l₂ := ⟨l₁, rfl⟩
|
||||
|
||||
grind_pattern suffix_append => l₂ <:+ l₁ ++ l₂
|
||||
|
||||
theorem infix_append (l₁ l₂ l₃ : List α) : l₂ <:+: l₁ ++ l₂ ++ l₃ := ⟨l₁, l₃, rfl⟩
|
||||
|
||||
@[simp, grind] theorem infix_append' (l₁ l₂ l₃ : List α) : l₂ <:+: l₁ ++ (l₂ ++ l₃) := by
|
||||
@[simp] theorem infix_append' (l₁ l₂ l₃ : List α) : l₂ <:+: l₁ ++ (l₂ ++ l₃) := by
|
||||
rw [← List.append_assoc]; apply infix_append
|
||||
|
||||
grind_pattern infix_append' => l₂ <:+: l₁ ++ (l₂ ++ l₃)
|
||||
|
||||
theorem infix_append_left : l₁ <:+: l₁ ++ l₂ := ⟨[], l₂, rfl⟩
|
||||
theorem infix_append_right : l₂ <:+: l₁ ++ l₂ := ⟨l₁, [], by simp⟩
|
||||
|
||||
@@ -666,7 +679,9 @@ theorem suffix_refl (l : List α) : l <:+ l := ⟨[], rfl⟩
|
||||
theorem infix_refl (l : List α) : l <:+: l := prefix_rfl.isInfix
|
||||
@[simp, grind] theorem infix_rfl {l : List α} : l <:+: l := infix_refl l
|
||||
|
||||
@[simp, grind] theorem suffix_cons (a : α) : ∀ l, l <:+ a :: l := suffix_append [a]
|
||||
@[simp] theorem suffix_cons (a : α) : ∀ l, l <:+ a :: l := suffix_append [a]
|
||||
|
||||
grind_pattern suffix_cons => _ <:+ a :: l
|
||||
|
||||
theorem infix_cons : l₁ <:+: l₂ → l₁ <:+: a :: l₂ := fun ⟨l₁', l₂', h⟩ => ⟨a :: l₁', l₂', h ▸ rfl⟩
|
||||
|
||||
@@ -1108,24 +1123,36 @@ theorem infix_of_mem_flatten : ∀ {L : List (List α)}, l ∈ L → l <:+: flat
|
||||
theorem prefix_cons_inj (a) : a :: l₁ <+: a :: l₂ ↔ l₁ <+: l₂ :=
|
||||
prefix_append_right_inj [a]
|
||||
|
||||
@[grind] theorem take_prefix (i) (l : List α) : take i l <+: l :=
|
||||
theorem take_prefix (i) (l : List α) : take i l <+: l :=
|
||||
⟨_, take_append_drop _ _⟩
|
||||
|
||||
@[grind] theorem drop_suffix (i) (l : List α) : drop i l <:+ l :=
|
||||
grind_pattern take_prefix => take i l <+: _
|
||||
|
||||
theorem drop_suffix (i) (l : List α) : drop i l <:+ l :=
|
||||
⟨_, take_append_drop _ _⟩
|
||||
|
||||
@[grind] theorem take_sublist (i) (l : List α) : take i l <+ l :=
|
||||
grind_pattern drop_suffix => drop i l <+: _
|
||||
|
||||
theorem take_sublist (i) (l : List α) : take i l <+ l :=
|
||||
(take_prefix i l).sublist
|
||||
|
||||
@[grind] theorem drop_sublist (i) (l : List α) : drop i l <+ l :=
|
||||
grind_pattern take_sublist => take i l <+ l
|
||||
|
||||
theorem drop_sublist (i) (l : List α) : drop i l <+ l :=
|
||||
(drop_suffix i l).sublist
|
||||
|
||||
grind_pattern drop_sublist => drop i l <+ l
|
||||
|
||||
theorem take_subset (i) (l : List α) : take i l ⊆ l :=
|
||||
(take_sublist i l).subset
|
||||
|
||||
grind_pattern take_subset => take i l ⊆ l
|
||||
|
||||
theorem drop_subset (i) (l : List α) : drop i l ⊆ l :=
|
||||
(drop_sublist i l).subset
|
||||
|
||||
grind_pattern drop_subset => drop i l ⊆ l
|
||||
|
||||
theorem mem_of_mem_take {l : List α} (h : a ∈ l.take i) : a ∈ l :=
|
||||
take_subset _ _ h
|
||||
|
||||
@@ -1138,64 +1165,84 @@ theorem drop_suffix_drop_left (l : List α) {i j : Nat} (h : i ≤ j) : drop j l
|
||||
|
||||
-- See `Init.Data.List.Nat.TakeDrop` for `take_prefix_take_left`.
|
||||
|
||||
@[grind] theorem drop_sublist_drop_left (l : List α) {i j : Nat} (h : i ≤ j) : drop j l <+ drop i l :=
|
||||
@[grind ←] theorem drop_sublist_drop_left (l : List α) {i j : Nat} (h : i ≤ j) : drop j l <+ drop i l :=
|
||||
(drop_suffix_drop_left l h).sublist
|
||||
|
||||
@[grind] theorem drop_subset_drop_left (l : List α) {i j : Nat} (h : i ≤ j) : drop j l ⊆ drop i l :=
|
||||
@[grind ←] theorem drop_subset_drop_left (l : List α) {i j : Nat} (h : i ≤ j) : drop j l ⊆ drop i l :=
|
||||
(drop_sublist_drop_left l h).subset
|
||||
|
||||
@[grind] theorem takeWhile_prefix (p : α → Bool) : l.takeWhile p <+: l :=
|
||||
theorem takeWhile_prefix (p : α → Bool) : l.takeWhile p <+: l :=
|
||||
⟨l.dropWhile p, takeWhile_append_dropWhile⟩
|
||||
|
||||
@[grind] theorem dropWhile_suffix (p : α → Bool) : l.dropWhile p <:+ l :=
|
||||
grind_pattern takeWhile_prefix => l.takeWhile p <+: _
|
||||
|
||||
theorem dropWhile_suffix (p : α → Bool) : l.dropWhile p <:+ l :=
|
||||
⟨l.takeWhile p, takeWhile_append_dropWhile⟩
|
||||
|
||||
@[grind] theorem takeWhile_sublist (p : α → Bool) : l.takeWhile p <+ l :=
|
||||
grind_pattern dropWhile_suffix => l.dropWhile p <+: _
|
||||
|
||||
theorem takeWhile_sublist (p : α → Bool) : l.takeWhile p <+ l :=
|
||||
(takeWhile_prefix p).sublist
|
||||
|
||||
@[grind] theorem dropWhile_sublist (p : α → Bool) : l.dropWhile p <+ l :=
|
||||
grind_pattern takeWhile_sublist => l.takeWhile p <+ _
|
||||
|
||||
theorem dropWhile_sublist (p : α → Bool) : l.dropWhile p <+ l :=
|
||||
(dropWhile_suffix p).sublist
|
||||
|
||||
grind_pattern dropWhile_sublist => l.dropWhile p <+ _
|
||||
|
||||
theorem takeWhile_subset {l : List α} (p : α → Bool) : l.takeWhile p ⊆ l :=
|
||||
(takeWhile_sublist p).subset
|
||||
|
||||
grind_pattern takeWhile_subset => l.takeWhile p ⊆ _
|
||||
|
||||
theorem dropWhile_subset {l : List α} (p : α → Bool) : l.dropWhile p ⊆ l :=
|
||||
(dropWhile_sublist p).subset
|
||||
|
||||
@[grind] theorem dropLast_prefix : ∀ l : List α, l.dropLast <+: l
|
||||
grind_pattern dropWhile_subset => l.dropWhile p ⊆ _
|
||||
|
||||
theorem dropLast_prefix : ∀ l : List α, l.dropLast <+: l
|
||||
| [] => ⟨nil, by rw [dropLast, List.append_nil]⟩
|
||||
| a :: l => ⟨_, dropLast_concat_getLast (cons_ne_nil a l)⟩
|
||||
|
||||
@[grind] theorem dropLast_sublist (l : List α) : l.dropLast <+ l :=
|
||||
grind_pattern dropLast_prefix => l.dropLast <+: _
|
||||
|
||||
theorem dropLast_sublist (l : List α) : l.dropLast <+ l :=
|
||||
(dropLast_prefix l).sublist
|
||||
|
||||
grind_pattern dropLast_sublist => l.dropLast <+ _
|
||||
|
||||
theorem dropLast_subset (l : List α) : l.dropLast ⊆ l :=
|
||||
(dropLast_sublist l).subset
|
||||
|
||||
@[grind] theorem tail_suffix (l : List α) : tail l <:+ l := by rw [← drop_one]; apply drop_suffix
|
||||
grind_pattern dropLast_subset => l.dropLast ⊆ _
|
||||
|
||||
@[grind] theorem IsPrefix.map {β} (f : α → β) ⦃l₁ l₂ : List α⦄ (h : l₁ <+: l₂) : l₁.map f <+: l₂.map f := by
|
||||
theorem tail_suffix (l : List α) : tail l <:+ l := by rw [← drop_one]; apply drop_suffix
|
||||
|
||||
grind_pattern tail_suffix => tail l <+: _
|
||||
|
||||
@[grind ←] theorem IsPrefix.map {β} (f : α → β) ⦃l₁ l₂ : List α⦄ (h : l₁ <+: l₂) : l₁.map f <+: l₂.map f := by
|
||||
obtain ⟨r, rfl⟩ := h
|
||||
rw [map_append]; apply prefix_append
|
||||
|
||||
grind_pattern IsPrefix.map => l₁ <+: l₂, l₁.map f
|
||||
grind_pattern IsPrefix.map => l₁ <+: l₂, l₂.map f
|
||||
|
||||
@[grind] theorem IsSuffix.map {β} (f : α → β) ⦃l₁ l₂ : List α⦄ (h : l₁ <:+ l₂) : l₁.map f <:+ l₂.map f := by
|
||||
@[grind ←] theorem IsSuffix.map {β} (f : α → β) ⦃l₁ l₂ : List α⦄ (h : l₁ <:+ l₂) : l₁.map f <:+ l₂.map f := by
|
||||
obtain ⟨r, rfl⟩ := h
|
||||
rw [map_append]; apply suffix_append
|
||||
|
||||
grind_pattern IsSuffix.map => l₁ <:+ l₂, l₁.map f
|
||||
grind_pattern IsSuffix.map => l₁ <:+ l₂, l₂.map f
|
||||
|
||||
@[grind] theorem IsInfix.map {β} (f : α → β) ⦃l₁ l₂ : List α⦄ (h : l₁ <:+: l₂) : l₁.map f <:+: l₂.map f := by
|
||||
@[grind ←] theorem IsInfix.map {β} (f : α → β) ⦃l₁ l₂ : List α⦄ (h : l₁ <:+: l₂) : l₁.map f <:+: l₂.map f := by
|
||||
obtain ⟨r₁, r₂, rfl⟩ := h
|
||||
rw [map_append, map_append]; apply infix_append
|
||||
|
||||
grind_pattern IsInfix.map => l₁ <:+: l₂, l₁.map f
|
||||
grind_pattern IsInfix.map => l₁ <:+: l₂, l₂.map f
|
||||
|
||||
@[grind] theorem IsPrefix.filter (p : α → Bool) ⦃l₁ l₂ : List α⦄ (h : l₁ <+: l₂) :
|
||||
@[grind ←] theorem IsPrefix.filter (p : α → Bool) ⦃l₁ l₂ : List α⦄ (h : l₁ <+: l₂) :
|
||||
l₁.filter p <+: l₂.filter p := by
|
||||
obtain ⟨xs, rfl⟩ := h
|
||||
rw [filter_append]; apply prefix_append
|
||||
@@ -1203,7 +1250,7 @@ grind_pattern IsInfix.map => l₁ <:+: l₂, l₂.map f
|
||||
grind_pattern IsPrefix.filter => l₁ <+: l₂, l₁.filter p
|
||||
grind_pattern IsPrefix.filter => l₁ <+: l₂, l₂.filter p
|
||||
|
||||
@[grind] theorem IsSuffix.filter (p : α → Bool) ⦃l₁ l₂ : List α⦄ (h : l₁ <:+ l₂) :
|
||||
@[grind ←] theorem IsSuffix.filter (p : α → Bool) ⦃l₁ l₂ : List α⦄ (h : l₁ <:+ l₂) :
|
||||
l₁.filter p <:+ l₂.filter p := by
|
||||
obtain ⟨xs, rfl⟩ := h
|
||||
rw [filter_append]; apply suffix_append
|
||||
@@ -1211,7 +1258,7 @@ grind_pattern IsPrefix.filter => l₁ <+: l₂, l₂.filter p
|
||||
grind_pattern IsSuffix.filter => l₁ <:+ l₂, l₁.filter p
|
||||
grind_pattern IsSuffix.filter => l₁ <:+ l₂, l₂.filter p
|
||||
|
||||
@[grind] theorem IsInfix.filter (p : α → Bool) ⦃l₁ l₂ : List α⦄ (h : l₁ <:+: l₂) :
|
||||
@[grind ←] theorem IsInfix.filter (p : α → Bool) ⦃l₁ l₂ : List α⦄ (h : l₁ <:+: l₂) :
|
||||
l₁.filter p <:+: l₂.filter p := by
|
||||
obtain ⟨xs, ys, rfl⟩ := h
|
||||
rw [filter_append, filter_append]; apply infix_append _
|
||||
@@ -1219,7 +1266,7 @@ grind_pattern IsSuffix.filter => l₁ <:+ l₂, l₂.filter p
|
||||
grind_pattern IsInfix.filter => l₁ <:+: l₂, l₁.filter p
|
||||
grind_pattern IsInfix.filter => l₁ <:+: l₂, l₂.filter p
|
||||
|
||||
@[grind] theorem IsPrefix.filterMap {β} (f : α → Option β) ⦃l₁ l₂ : List α⦄ (h : l₁ <+: l₂) :
|
||||
@[grind ←] theorem IsPrefix.filterMap {β} (f : α → Option β) ⦃l₁ l₂ : List α⦄ (h : l₁ <+: l₂) :
|
||||
filterMap f l₁ <+: filterMap f l₂ := by
|
||||
obtain ⟨xs, rfl⟩ := h
|
||||
rw [filterMap_append]; apply prefix_append
|
||||
@@ -1227,7 +1274,7 @@ grind_pattern IsInfix.filter => l₁ <:+: l₂, l₂.filter p
|
||||
grind_pattern IsPrefix.filterMap => l₁ <+: l₂, filterMap f l₁
|
||||
grind_pattern IsPrefix.filterMap => l₁ <+: l₂, filterMap f l₂
|
||||
|
||||
@[grind] theorem IsSuffix.filterMap {β} (f : α → Option β) ⦃l₁ l₂ : List α⦄ (h : l₁ <:+ l₂) :
|
||||
@[grind ←] theorem IsSuffix.filterMap {β} (f : α → Option β) ⦃l₁ l₂ : List α⦄ (h : l₁ <:+ l₂) :
|
||||
filterMap f l₁ <:+ filterMap f l₂ := by
|
||||
obtain ⟨xs, rfl⟩ := h
|
||||
rw [filterMap_append]; apply suffix_append
|
||||
@@ -1235,7 +1282,7 @@ grind_pattern IsPrefix.filterMap => l₁ <+: l₂, filterMap f l₂
|
||||
grind_pattern IsSuffix.filterMap => l₁ <:+ l₂, filterMap f l₁
|
||||
grind_pattern IsSuffix.filterMap => l₁ <:+ l₂, filterMap f l₂
|
||||
|
||||
@[grind] theorem IsInfix.filterMap {β} (f : α → Option β) ⦃l₁ l₂ : List α⦄ (h : l₁ <:+: l₂) :
|
||||
@[grind ←] theorem IsInfix.filterMap {β} (f : α → Option β) ⦃l₁ l₂ : List α⦄ (h : l₁ <:+: l₂) :
|
||||
filterMap f l₁ <:+: filterMap f l₂ := by
|
||||
obtain ⟨xs, ys, rfl⟩ := h
|
||||
rw [filterMap_append, filterMap_append]; apply infix_append
|
||||
|
||||
@@ -12,7 +12,6 @@ public import Init.Data.List.Impl
|
||||
public import Init.Data.List.Nat.Erase
|
||||
public import Init.Data.List.Monadic
|
||||
public import Init.Data.List.Nat.InsertIdx
|
||||
public import Init.Data.Array.Lex.Basic
|
||||
public import Init.Data.Array.Basic
|
||||
import all Init.Data.Array.Basic
|
||||
public import Init.Data.Array.Set
|
||||
|
||||
@@ -257,8 +257,6 @@ attribute [simp] Nat.le_refl
|
||||
|
||||
theorem succ_lt_succ {n m : Nat} : n < m → succ n < succ m := succ_le_succ
|
||||
|
||||
theorem lt_succ_of_le {n m : Nat} : n ≤ m → n < succ m := succ_le_succ
|
||||
|
||||
theorem le_of_lt_add_one {n m : Nat} : n < m + 1 → n ≤ m := le_of_succ_le_succ
|
||||
|
||||
theorem lt_add_one_of_le {n m : Nat} : n ≤ m → n < m + 1 := succ_le_succ
|
||||
@@ -271,37 +269,15 @@ theorem not_add_one_le_self : (n : Nat) → ¬ n + 1 ≤ n := Nat.not_succ_le_se
|
||||
|
||||
theorem add_one_pos (n : Nat) : 0 < n + 1 := Nat.zero_lt_succ n
|
||||
|
||||
theorem succ_sub_succ_eq_sub (n m : Nat) : succ n - succ m = n - m := by
|
||||
induction m with
|
||||
| zero => exact rfl
|
||||
| succ m ih => apply congrArg pred ih
|
||||
|
||||
theorem pred_le : ∀ (n : Nat), pred n ≤ n
|
||||
| zero => Nat.le.refl
|
||||
| succ _ => le_succ _
|
||||
|
||||
theorem pred_lt : ∀ {n : Nat}, n ≠ 0 → pred n < n
|
||||
| zero, h => absurd rfl h
|
||||
| succ _, _ => lt_succ_of_le (Nat.le_refl _)
|
||||
|
||||
theorem sub_one_lt : ∀ {n : Nat}, n ≠ 0 → n - 1 < n := pred_lt
|
||||
|
||||
@[simp] theorem sub_le (n m : Nat) : n - m ≤ n := by
|
||||
induction m with
|
||||
| zero => exact Nat.le_refl (n - 0)
|
||||
| succ m ih => apply Nat.le_trans (pred_le (n - m)) ih
|
||||
|
||||
theorem sub_lt_of_lt {a b c : Nat} (h : a < c) : a - b < c :=
|
||||
Nat.lt_of_le_of_lt (Nat.sub_le _ _) h
|
||||
|
||||
theorem sub_lt : ∀ {n m : Nat}, 0 < n → 0 < m → n - m < n
|
||||
| 0, _, h1, _ => absurd h1 (Nat.lt_irrefl 0)
|
||||
| _+1, 0, _, h2 => absurd h2 (Nat.lt_irrefl 0)
|
||||
| n+1, m+1, _, _ =>
|
||||
Eq.symm (succ_sub_succ_eq_sub n m) ▸
|
||||
show n - m < succ n from
|
||||
lt_succ_of_le (sub_le n m)
|
||||
|
||||
theorem sub_succ (n m : Nat) : n - succ m = pred (n - m) := rfl
|
||||
|
||||
theorem succ_sub_succ (n m : Nat) : succ n - succ m = n - m :=
|
||||
@@ -316,9 +292,6 @@ theorem sub_add_eq (a b c : Nat) : a - (b + c) = a - b - c := by
|
||||
| zero => simp
|
||||
| succ c ih => simp only [Nat.add_succ, Nat.sub_succ, ih]
|
||||
|
||||
protected theorem lt_of_lt_of_le {n m k : Nat} : n < m → m ≤ k → n < k :=
|
||||
Nat.le_trans
|
||||
|
||||
protected theorem lt_of_lt_of_eq {n m k : Nat} : n < m → m = k → n < k :=
|
||||
fun h₁ h₂ => h₂ ▸ h₁
|
||||
|
||||
@@ -356,12 +329,10 @@ protected theorem pos_of_ne_zero {n : Nat} : n ≠ 0 → 0 < n := (eq_zero_or_po
|
||||
|
||||
theorem pos_of_neZero (n : Nat) [NeZero n] : 0 < n := Nat.pos_of_ne_zero (NeZero.ne _)
|
||||
|
||||
attribute [simp] Nat.lt_add_one
|
||||
|
||||
theorem lt.base (n : Nat) : n < succ n := Nat.le_refl (succ n)
|
||||
|
||||
theorem lt_succ_self (n : Nat) : n < succ n := lt.base n
|
||||
|
||||
@[simp] protected theorem lt_add_one (n : Nat) : n < n + 1 := lt.base n
|
||||
|
||||
protected theorem le_total (m n : Nat) : m ≤ n ∨ n ≤ m :=
|
||||
match Nat.lt_or_ge m n with
|
||||
| Or.inl h => Or.inl (Nat.le_of_lt h)
|
||||
@@ -457,7 +428,6 @@ protected theorem le_lt_asymm : ∀{a b : Nat}, a ≤ b → ¬(b < a) := flip Na
|
||||
|
||||
theorem gt_of_not_le {n m : Nat} (h : ¬ n ≤ m) : n > m := (Nat.lt_or_ge m n).resolve_right h
|
||||
protected theorem lt_of_not_ge : ∀{a b : Nat}, ¬(b ≥ a) → b < a := Nat.gt_of_not_le
|
||||
protected theorem lt_of_not_le : ∀{a b : Nat}, ¬(a ≤ b) → b < a := Nat.gt_of_not_le
|
||||
|
||||
theorem ge_of_not_lt {n m : Nat} (h : ¬ n < m) : n ≥ m := (Nat.lt_or_ge n m).resolve_left h
|
||||
protected theorem le_of_not_gt : ∀{a b : Nat}, ¬(b > a) → b ≤ a := Nat.ge_of_not_lt
|
||||
@@ -770,10 +740,6 @@ protected theorem mul_lt_mul_of_pos_left {n m k : Nat} (h : n < m) (hk : k > 0)
|
||||
protected theorem mul_lt_mul_of_pos_right {n m k : Nat} (h : n < m) (hk : k > 0) : n * k < m * k :=
|
||||
Nat.mul_comm k m ▸ Nat.mul_comm k n ▸ Nat.mul_lt_mul_of_pos_left h hk
|
||||
|
||||
protected theorem mul_pos {n m : Nat} (ha : n > 0) (hb : m > 0) : n * m > 0 :=
|
||||
have h : 0 * m < n * m := Nat.mul_lt_mul_of_pos_right ha hb
|
||||
Nat.zero_mul m ▸ h
|
||||
|
||||
protected theorem le_of_mul_le_mul_left {a b c : Nat} (h : c * a ≤ c * b) (hc : 0 < c) : a ≤ b :=
|
||||
Nat.ge_of_not_lt fun hlt : b < a =>
|
||||
have h' : c * b < c * a := Nat.mul_lt_mul_of_pos_left hlt hc
|
||||
@@ -833,11 +799,6 @@ set_option linter.missingDocs false in
|
||||
@[deprecated Nat.pow_le_pow_right (since := "2025-02-17")]
|
||||
abbrev pow_le_pow_of_le_right := @Nat.pow_le_pow_right
|
||||
|
||||
protected theorem pow_pos (h : 0 < a) : 0 < a^n :=
|
||||
match n with
|
||||
| 0 => Nat.zero_lt_one
|
||||
| _ + 1 => Nat.mul_pos (Nat.pow_pos h) h
|
||||
|
||||
set_option linter.missingDocs false in
|
||||
@[deprecated Nat.pow_pos (since := "2025-02-17")]
|
||||
abbrev pos_pow_of_pos := @Nat.pow_pos
|
||||
@@ -1199,6 +1160,8 @@ protected theorem sub_eq_iff_eq_add {c : Nat} (h : b ≤ a) : a - b = c ↔ a =
|
||||
protected theorem sub_eq_iff_eq_add' {c : Nat} (h : b ≤ a) : a - b = c ↔ a = b + c := by
|
||||
rw [Nat.add_comm, Nat.sub_eq_iff_eq_add h]
|
||||
|
||||
attribute [simp] sub_le
|
||||
|
||||
protected theorem sub_one_sub_lt_of_lt (h : a < b) : b - 1 - a < b := by
|
||||
rw [← Nat.sub_add_eq]
|
||||
exact sub_lt (zero_lt_of_lt h) (Nat.lt_add_right a Nat.one_pos)
|
||||
|
||||
@@ -24,47 +24,6 @@ there is some `c` such that `b = a * c`.
|
||||
instance : Dvd Nat where
|
||||
dvd a b := Exists (fun c => b = a * c)
|
||||
|
||||
theorem div_rec_lemma {x y : Nat} : 0 < y ∧ y ≤ x → x - y < x :=
|
||||
fun ⟨ypos, ylex⟩ => sub_lt (Nat.lt_of_lt_of_le ypos ylex) ypos
|
||||
|
||||
theorem div_rec_fuel_lemma {x y fuel : Nat} (hy : 0 < y) (hle : y ≤ x) (hfuel : x < fuel + 1) :
|
||||
x - y < fuel :=
|
||||
Nat.lt_of_lt_of_le (div_rec_lemma ⟨hy, hle⟩) (Nat.le_of_lt_succ hfuel)
|
||||
|
||||
/--
|
||||
Division of natural numbers, discarding the remainder. Division by `0` returns `0`. Usually accessed
|
||||
via the `/` operator.
|
||||
|
||||
This operation is sometimes called “floor division.”
|
||||
|
||||
This function is overridden at runtime with an efficient implementation. This definition is
|
||||
the logical model.
|
||||
|
||||
Examples:
|
||||
* `21 / 3 = 7`
|
||||
* `21 / 5 = 4`
|
||||
* `0 / 22 = 0`
|
||||
* `5 / 0 = 0`
|
||||
-/
|
||||
@[extern "lean_nat_div", irreducible]
|
||||
protected def div (x y : @& Nat) : Nat :=
|
||||
if hy : 0 < y then
|
||||
let rec
|
||||
go (fuel : Nat) (x : Nat) (hfuel : x < fuel) : Nat :=
|
||||
match fuel with
|
||||
| 0 => by contradiction
|
||||
| succ fuel =>
|
||||
if h : y ≤ x then
|
||||
go fuel (x - y) (div_rec_fuel_lemma hy h hfuel) + 1
|
||||
else
|
||||
0
|
||||
termination_by structural fuel
|
||||
go (x + 1) x (Nat.lt_succ_self _)
|
||||
else
|
||||
0
|
||||
|
||||
instance instDiv : Div Nat := ⟨Nat.div⟩
|
||||
|
||||
private theorem div.go.fuel_congr (x y fuel1 fuel2 : Nat) (hy : 0 < y) (h1 : x < fuel1) (h2 : x < fuel2) :
|
||||
Nat.div.go y hy fuel1 x h1 = Nat.div.go y hy fuel2 x h2 := by
|
||||
match fuel1, fuel2 with
|
||||
@@ -154,36 +113,6 @@ protected def divExact (x y : @& Nat) (h : y ∣ x) : Nat :=
|
||||
@[simp]
|
||||
theorem divExact_eq_div {x y : Nat} (h : y ∣ x) : x.divExact y h = x / y := rfl
|
||||
|
||||
/--
|
||||
The modulo operator, which computes the remainder when dividing one natural number by another.
|
||||
Usually accessed via the `%` operator. When the divisor is `0`, the result is the dividend rather
|
||||
than an error.
|
||||
|
||||
This is the core implementation of `Nat.mod`. It computes the correct result for any two closed
|
||||
natural numbers, but it does not have some convenient [definitional
|
||||
reductions](lean-manual://section/type-system) when the `Nat`s contain free variables. The wrapper
|
||||
`Nat.mod` handles those cases specially and then calls `Nat.modCore`.
|
||||
|
||||
This function is overridden at runtime with an efficient implementation. This definition is the
|
||||
logical model.
|
||||
-/
|
||||
@[extern "lean_nat_mod", irreducible]
|
||||
protected noncomputable def modCore (x y : Nat) : Nat :=
|
||||
if hy : 0 < y then
|
||||
let rec
|
||||
go (fuel : Nat) (x : Nat) (hfuel : x < fuel) : Nat :=
|
||||
match fuel with
|
||||
| 0 => by contradiction
|
||||
| succ fuel =>
|
||||
if h : y ≤ x then
|
||||
go fuel (x - y) (div_rec_fuel_lemma hy h hfuel)
|
||||
else
|
||||
x
|
||||
termination_by structural fuel
|
||||
go (x + 1) x (Nat.lt_succ_self _)
|
||||
else
|
||||
x
|
||||
|
||||
private theorem modCore.go.fuel_congr (x y fuel1 fuel2 : Nat) (hy : 0 < y) (h1 : x < fuel1) (h2 : x < fuel2) :
|
||||
Nat.modCore.go y hy fuel1 x h1 = Nat.modCore.go y hy fuel2 x h2 := by
|
||||
match fuel1, fuel2 with
|
||||
@@ -214,51 +143,6 @@ protected theorem modCore_eq (x y : Nat) : Nat.modCore x y =
|
||||
next =>
|
||||
simp only [false_and, ↓reduceIte, *]
|
||||
|
||||
|
||||
/--
|
||||
The modulo operator, which computes the remainder when dividing one natural number by another.
|
||||
Usually accessed via the `%` operator. When the divisor is `0`, the result is the dividend rather
|
||||
than an error.
|
||||
|
||||
`Nat.mod` is a wrapper around `Nat.modCore` that special-cases two situations, giving better
|
||||
definitional reductions:
|
||||
* `Nat.mod 0 m` should reduce to `m`, for all terms `m : Nat`.
|
||||
* `Nat.mod n (m + n + 1)` should reduce to `n` for concrete `Nat` literals `n`.
|
||||
|
||||
These reductions help `Fin n` literals work well, because the `OfNat` instance for `Fin` uses
|
||||
`Nat.mod`. In particular, `(0 : Fin (n + 1)).val` should reduce definitionally to `0`. `Nat.modCore`
|
||||
can handle all numbers, but its definitional reductions are not as convenient.
|
||||
|
||||
This function is overridden at runtime with an efficient implementation. This definition is the
|
||||
logical model.
|
||||
|
||||
Examples:
|
||||
* `7 % 2 = 1`
|
||||
* `9 % 3 = 0`
|
||||
* `5 % 7 = 5`
|
||||
* `5 % 0 = 5`
|
||||
* `show ∀ (n : Nat), 0 % n = 0 from fun _ => rfl`
|
||||
* `show ∀ (m : Nat), 5 % (m + 6) = 5 from fun _ => rfl`
|
||||
-/
|
||||
@[extern "lean_nat_mod"]
|
||||
protected def mod : @& Nat → @& Nat → Nat
|
||||
/-
|
||||
Nat.modCore is defined with fuel and thus does not reduce with open terms very well.
|
||||
Nevertheless it is desirable for trivial `Nat.mod` calculations, namely
|
||||
* `Nat.mod 0 m` for all `m`
|
||||
* `Nat.mod n (m + n + 1)` for concrete literals `n`,
|
||||
to reduce definitionally.
|
||||
This property is desirable for `Fin n` literals, as it means `(ofNat 0 : Fin n).val = 0` by
|
||||
definition.
|
||||
-/
|
||||
| 0, _ => 0
|
||||
| n@(_ + 1), m =>
|
||||
if m ≤ n -- NB: if n < m does not reduce as well as `m ≤ n`!
|
||||
then Nat.modCore n m
|
||||
else n
|
||||
|
||||
instance instMod : Mod Nat := ⟨Nat.mod⟩
|
||||
|
||||
protected theorem modCore_eq_mod (n m : Nat) : Nat.modCore n m = n % m := by
|
||||
change Nat.modCore n m = Nat.mod n m
|
||||
match n, m with
|
||||
@@ -315,24 +199,6 @@ theorem mod_eq_sub_mod {a b : Nat} (h : a ≥ b) : a % b = (a - b) % b :=
|
||||
| Or.inl h₁ => h₁.symm ▸ (Nat.sub_zero a).symm ▸ rfl
|
||||
| Or.inr h₁ => (mod_eq a b).symm ▸ if_pos ⟨h₁, h⟩
|
||||
|
||||
theorem mod_lt (x : Nat) {y : Nat} : y > 0 → x % y < y := by
|
||||
induction x, y using mod.inductionOn with
|
||||
| base x y h₁ =>
|
||||
intro h₂
|
||||
have h₁ : ¬ 0 < y ∨ ¬ y ≤ x := Decidable.not_and_iff_or_not.mp h₁
|
||||
match h₁ with
|
||||
| Or.inl h₁ => exact absurd h₂ h₁
|
||||
| Or.inr h₁ =>
|
||||
have hgt : y > x := gt_of_not_le h₁
|
||||
have heq : x % y = x := mod_eq_of_lt hgt
|
||||
rw [← heq] at hgt
|
||||
exact hgt
|
||||
| ind x y h h₂ =>
|
||||
intro h₃
|
||||
have ⟨_, h₁⟩ := h
|
||||
rw [mod_eq_sub_mod h₁]
|
||||
exact h₂ h₃
|
||||
|
||||
@[simp] protected theorem sub_mod_add_mod_cancel (a b : Nat) [NeZero a] : a - b % a + b % a = a := by
|
||||
rw [Nat.sub_add_cancel]
|
||||
cases a with
|
||||
|
||||
@@ -264,9 +264,6 @@ protected theorem pos_of_lt_add_left : n < k + n → 0 < k := by
|
||||
protected theorem add_pos_left (h : 0 < m) (n) : 0 < m + n :=
|
||||
Nat.lt_of_lt_of_le h (Nat.le_add_right ..)
|
||||
|
||||
protected theorem add_pos_right (m) (h : 0 < n) : 0 < m + n :=
|
||||
Nat.lt_of_lt_of_le h (Nat.le_add_left ..)
|
||||
|
||||
protected theorem add_self_ne_one : ∀ n, n + n ≠ 1
|
||||
| n+1, h => by rw [Nat.succ_add, Nat.succ.injEq] at h; contradiction
|
||||
|
||||
|
||||
@@ -15,30 +15,30 @@ public section
|
||||
|
||||
namespace Option
|
||||
|
||||
@[simp, grind] theorem mem_toArray {a : α} {o : Option α} : a ∈ o.toArray ↔ o = some a := by
|
||||
@[simp, grind =] theorem mem_toArray {a : α} {o : Option α} : a ∈ o.toArray ↔ o = some a := by
|
||||
cases o <;> simp [eq_comm]
|
||||
|
||||
@[simp, grind] theorem forIn'_toArray [Monad m] (o : Option α) (b : β) (f : (a : α) → a ∈ o.toArray → β → m (ForInStep β)) :
|
||||
@[simp, grind =] theorem forIn'_toArray [Monad m] (o : Option α) (b : β) (f : (a : α) → a ∈ o.toArray → β → m (ForInStep β)) :
|
||||
forIn' o.toArray b f = forIn' o b fun a m b => f a (by simpa using m) b := by
|
||||
cases o <;> simp <;> rfl
|
||||
|
||||
@[simp, grind] theorem forIn_toArray [Monad m] (o : Option α) (b : β) (f : α → β → m (ForInStep β)) :
|
||||
@[simp, grind =] theorem forIn_toArray [Monad m] (o : Option α) (b : β) (f : α → β → m (ForInStep β)) :
|
||||
forIn o.toArray b f = forIn o b f := by
|
||||
cases o <;> simp <;> rfl
|
||||
|
||||
@[simp, grind] theorem foldlM_toArray [Monad m] [LawfulMonad m] (o : Option β) (a : α) (f : α → β → m α) :
|
||||
@[simp, grind =] theorem foldlM_toArray [Monad m] [LawfulMonad m] (o : Option β) (a : α) (f : α → β → m α) :
|
||||
o.toArray.foldlM f a = o.elim (pure a) (fun b => f a b) := by
|
||||
cases o <;> simp
|
||||
|
||||
@[simp, grind] theorem foldrM_toArray [Monad m] [LawfulMonad m] (o : Option β) (a : α) (f : β → α → m α) :
|
||||
@[simp, grind =] theorem foldrM_toArray [Monad m] [LawfulMonad m] (o : Option β) (a : α) (f : β → α → m α) :
|
||||
o.toArray.foldrM f a = o.elim (pure a) (fun b => f b a) := by
|
||||
cases o <;> simp
|
||||
|
||||
@[simp, grind] theorem foldl_toArray (o : Option β) (a : α) (f : α → β → α) :
|
||||
@[simp, grind =] theorem foldl_toArray (o : Option β) (a : α) (f : α → β → α) :
|
||||
o.toArray.foldl f a = o.elim a (fun b => f a b) := by
|
||||
cases o <;> simp
|
||||
|
||||
@[simp, grind] theorem foldr_toArray (o : Option β) (a : α) (f : β → α → α) :
|
||||
@[simp, grind =] theorem foldr_toArray (o : Option β) (a : α) (f : β → α → α) :
|
||||
o.toArray.foldr f a = o.elim a (fun b => f b a) := by
|
||||
cases o <;> simp
|
||||
|
||||
|
||||
@@ -97,7 +97,7 @@ theorem attach_eq_some : ∀ (o : Option α) (x : {x // o = some x}), o.attach =
|
||||
| none, ⟨x, h⟩ => by simp at h
|
||||
| some a, ⟨x, h⟩ => by simpa using h
|
||||
|
||||
@[grind]
|
||||
@[grind ←]
|
||||
theorem mem_attach : ∀ (o : Option α) (x : {x // o = some x}), x ∈ o.attach :=
|
||||
attach_eq_some
|
||||
|
||||
|
||||
@@ -18,27 +18,27 @@ namespace Option
|
||||
deriving instance DecidableEq for Option
|
||||
deriving instance BEq for Option
|
||||
|
||||
@[simp, grind] theorem getD_none : getD none a = a := rfl
|
||||
@[simp, grind] theorem getD_some : getD (some a) b = a := rfl
|
||||
@[simp, grind =] theorem getD_none : getD none a = a := rfl
|
||||
@[simp, grind =] theorem getD_some : getD (some a) b = a := rfl
|
||||
|
||||
@[simp, grind] theorem map_none (f : α → β) : none.map f = none := rfl
|
||||
@[simp, grind] theorem map_some (a) (f : α → β) : (some a).map f = some (f a) := rfl
|
||||
@[simp, grind =] theorem map_none (f : α → β) : none.map f = none := rfl
|
||||
@[simp, grind =] theorem map_some (a) (f : α → β) : (some a).map f = some (f a) := rfl
|
||||
|
||||
/-- Lifts an optional value to any `Alternative`, sending `none` to `failure`. -/
|
||||
def getM [Alternative m] : Option α → m α
|
||||
| none => failure
|
||||
| some a => pure a
|
||||
|
||||
@[simp, grind] theorem getM_none [Alternative m] : getM none = (failure : m α) := rfl
|
||||
@[simp, grind] theorem getM_some [Alternative m] {a : α} : getM (some a) = (pure a : m α) := rfl
|
||||
@[simp, grind =] theorem getM_none [Alternative m] : getM none = (failure : m α) := rfl
|
||||
@[simp, grind =] theorem getM_some [Alternative m] {a : α} : getM (some a) = (pure a : m α) := rfl
|
||||
|
||||
/-- Returns `true` on `some x` and `false` on `none`. -/
|
||||
@[inline] def isSome : Option α → Bool
|
||||
| some _ => true
|
||||
| none => false
|
||||
|
||||
@[simp, grind] theorem isSome_none : @isSome α none = false := rfl
|
||||
@[simp, grind] theorem isSome_some : isSome (some a) = true := rfl
|
||||
@[simp, grind =] theorem isSome_none : @isSome α none = false := rfl
|
||||
@[simp, grind =] theorem isSome_some : isSome (some a) = true := rfl
|
||||
|
||||
/--
|
||||
Returns `true` on `none` and `false` on `some x`.
|
||||
@@ -53,8 +53,8 @@ Examples:
|
||||
| some _ => false
|
||||
| none => true
|
||||
|
||||
@[simp, grind] theorem isNone_none : @isNone α none = true := rfl
|
||||
@[simp, grind] theorem isNone_some : isNone (some a) = false := rfl
|
||||
@[simp, grind =] theorem isNone_none : @isNone α none = true := rfl
|
||||
@[simp, grind =] theorem isNone_some : isNone (some a) = false := rfl
|
||||
|
||||
/--
|
||||
Checks whether an optional value is both present and equal to some other value.
|
||||
@@ -89,8 +89,8 @@ Examples:
|
||||
| none, _ => none
|
||||
| some a, f => f a
|
||||
|
||||
@[simp, grind] theorem bind_none (f : α → Option β) : none.bind f = none := rfl
|
||||
@[simp, grind] theorem bind_some (a) (f : α → Option β) : (some a).bind f = f a := rfl
|
||||
@[simp, grind =] theorem bind_none (f : α → Option β) : none.bind f = none := rfl
|
||||
@[simp, grind =] theorem bind_some (a) (f : α → Option β) : (some a).bind f = f a := rfl
|
||||
|
||||
@[deprecated bind_none (since := "2025-05-03")]
|
||||
abbrev none_bind := @bind_none
|
||||
@@ -125,8 +125,8 @@ This function only requires `m` to be an applicative functor. An alias `Option.m
|
||||
| none => pure none
|
||||
| some x => some <$> f x
|
||||
|
||||
@[simp, grind] theorem mapM_none [Applicative m] (f : α → m β) : none.mapM f = pure none := rfl
|
||||
@[simp, grind] theorem mapM_some [Applicative m] (x) (f : α → m β) : (some x).mapM f = some <$> f x := rfl
|
||||
@[simp, grind =] theorem mapM_none [Applicative m] (f : α → m β) : none.mapM f = pure none := rfl
|
||||
@[simp, grind =] theorem mapM_some [Applicative m] (x) (f : α → m β) : (some x).mapM f = some <$> f x := rfl
|
||||
|
||||
/--
|
||||
Applies a function in some applicative functor to an optional value, returning `none` with no
|
||||
@@ -138,9 +138,9 @@ This is an alias for `Option.mapM`, which already works for applicative functors
|
||||
Option.mapM f
|
||||
|
||||
/-- For verification purposes, we replace `mapA` with `mapM`. -/
|
||||
@[simp, grind] theorem mapA_eq_mapM [Applicative m] {f : α → m β} : Option.mapA f o = Option.mapM f o := rfl
|
||||
@[simp, grind =] theorem mapA_eq_mapM [Applicative m] {f : α → m β} : Option.mapA f o = Option.mapM f o := rfl
|
||||
|
||||
@[simp, grind]
|
||||
@[simp, grind =]
|
||||
theorem map_id : (Option.map id : Option α → Option α) = id :=
|
||||
funext (fun o => match o with | none => rfl | some _ => rfl)
|
||||
|
||||
@@ -182,8 +182,8 @@ Examples:
|
||||
| some a => p a
|
||||
| none => true
|
||||
|
||||
@[simp, grind] theorem all_none : Option.all p none = true := rfl
|
||||
@[simp, grind] theorem all_some : Option.all p (some x) = p x := rfl
|
||||
@[simp, grind =] theorem all_none : Option.all p none = true := rfl
|
||||
@[simp, grind =] theorem all_some : Option.all p (some x) = p x := rfl
|
||||
|
||||
/--
|
||||
Checks whether an optional value is not `none` and satisfies a Boolean predicate.
|
||||
@@ -197,8 +197,8 @@ Examples:
|
||||
| some a => p a
|
||||
| none => false
|
||||
|
||||
@[simp, grind] theorem any_none : Option.any p none = false := rfl
|
||||
@[simp, grind] theorem any_some : Option.any p (some x) = p x := rfl
|
||||
@[simp, grind =] theorem any_none : Option.any p none = false := rfl
|
||||
@[simp, grind =] theorem any_some : Option.any p (some x) = p x := rfl
|
||||
|
||||
/--
|
||||
Implementation of `OrElse`'s `<|>` syntax for `Option`. If the first argument is `some a`, returns
|
||||
@@ -210,8 +210,8 @@ See also `or` for a version that is strict in the second argument.
|
||||
| some a, _ => some a
|
||||
| none, b => b ()
|
||||
|
||||
@[simp, grind] theorem orElse_some : (some a).orElse b = some a := rfl
|
||||
@[simp, grind] theorem orElse_none : none.orElse b = b () := rfl
|
||||
@[simp, grind =] theorem orElse_some : (some a).orElse b = some a := rfl
|
||||
@[simp, grind =] theorem orElse_none : none.orElse b = b () := rfl
|
||||
|
||||
instance : OrElse (Option α) where
|
||||
orElse := Option.orElse
|
||||
@@ -351,9 +351,9 @@ Extracts the value from an option that can be proven to be `some`.
|
||||
@[inline] def get {α : Type u} : (o : Option α) → isSome o → α
|
||||
| some x, _ => x
|
||||
|
||||
@[simp, grind] theorem some_get : ∀ {x : Option α} (h : isSome x), some (x.get h) = x
|
||||
@[simp, grind =] theorem some_get : ∀ {x : Option α} (h : isSome x), some (x.get h) = x
|
||||
| some _, _ => rfl
|
||||
@[simp, grind] theorem get_some (x : α) (h : isSome (some x)) : (some x).get h = x := rfl
|
||||
@[simp, grind =] theorem get_some (x : α) (h : isSome (some x)) : (some x).get h = x := rfl
|
||||
|
||||
/--
|
||||
Returns `none` if a value doesn't satisfy a Boolean predicate, or the value itself otherwise.
|
||||
@@ -431,8 +431,8 @@ Examples:
|
||||
-/
|
||||
@[inline] def join (x : Option (Option α)) : Option α := x.bind id
|
||||
|
||||
@[simp, grind] theorem join_none : (none : Option (Option α)).join = none := rfl
|
||||
@[simp, grind] theorem join_some : (some o).join = o := rfl
|
||||
@[simp, grind =] theorem join_none : (none : Option (Option α)).join = none := rfl
|
||||
@[simp, grind =] theorem join_some : (some o).join = o := rfl
|
||||
|
||||
/--
|
||||
Converts an optional monadic computation into a monadic computation of an optional value.
|
||||
@@ -457,8 +457,8 @@ some "world"
|
||||
| none => pure none
|
||||
| some f => some <$> f
|
||||
|
||||
@[simp, grind] theorem sequence_none [Applicative m] : (none : Option (m α)).sequence = pure none := rfl
|
||||
@[simp, grind] theorem sequence_some [Applicative m] (f : m α) : (some f).sequence = some <$> f := rfl
|
||||
@[simp, grind =] theorem sequence_none [Applicative m] : (none : Option (m α)).sequence = pure none := rfl
|
||||
@[simp, grind =] theorem sequence_some [Applicative m] (f : m α) : (some f).sequence = some <$> f := rfl
|
||||
|
||||
/--
|
||||
A monadic case analysis function for `Option`.
|
||||
@@ -483,8 +483,8 @@ This is the monadic analogue of `Option.getD`.
|
||||
| some a => pure a
|
||||
| none => y
|
||||
|
||||
@[simp, grind] theorem getDM_none [Pure m] (y : m α) : (none : Option α).getDM y = y := rfl
|
||||
@[simp, grind] theorem getDM_some [Pure m] (a : α) (y : m α) : (some a).getDM y = pure a := rfl
|
||||
@[simp, grind =] theorem getDM_none [Pure m] (y : m α) : (none : Option α).getDM y = y := rfl
|
||||
@[simp, grind =] theorem getDM_some [Pure m] (a : α) (y : m α) : (some a).getDM y = pure a := rfl
|
||||
|
||||
instance (α) [BEq α] [ReflBEq α] : ReflBEq (Option α) where
|
||||
rfl {x} := private
|
||||
@@ -520,10 +520,10 @@ protected def min [Min α] : Option α → Option α → Option α
|
||||
|
||||
instance [Min α] : Min (Option α) where min := Option.min
|
||||
|
||||
@[simp, grind] theorem min_some_some [Min α] {a b : α} : min (some a) (some b) = some (min a b) := rfl
|
||||
@[simp, grind] theorem min_none_left [Min α] {o : Option α} : min none o = none := by
|
||||
@[simp, grind =] theorem min_some_some [Min α] {a b : α} : min (some a) (some b) = some (min a b) := rfl
|
||||
@[simp, grind =] theorem min_none_left [Min α] {o : Option α} : min none o = none := by
|
||||
cases o <;> rfl
|
||||
@[simp, grind] theorem min_none_right [Min α] {o : Option α} : min o none = none := by
|
||||
@[simp, grind =] theorem min_none_right [Min α] {o : Option α} : min o none = none := by
|
||||
cases o <;> rfl
|
||||
|
||||
@[deprecated min_none_right (since := "2025-05-12")]
|
||||
@@ -553,10 +553,10 @@ protected def max [Max α] : Option α → Option α → Option α
|
||||
|
||||
instance [Max α] : Max (Option α) where max := Option.max
|
||||
|
||||
@[simp, grind] theorem max_some_some [Max α] {a b : α} : max (some a) (some b) = some (max a b) := rfl
|
||||
@[simp, grind] theorem max_none_left [Max α] {o : Option α} : max none o = o := by
|
||||
@[simp, grind =] theorem max_some_some [Max α] {a b : α} : max (some a) (some b) = some (max a b) := rfl
|
||||
@[simp, grind =] theorem max_none_left [Max α] {o : Option α} : max none o = o := by
|
||||
cases o <;> rfl
|
||||
@[simp, grind] theorem max_none_right [Max α] {o : Option α} : max o none = o := by
|
||||
@[simp, grind =] theorem max_none_right [Max α] {o : Option α} : max o none = o := by
|
||||
cases o <;> rfl
|
||||
|
||||
@[deprecated max_none_right (since := "2025-05-12")]
|
||||
|
||||
@@ -24,7 +24,7 @@ namespace Option
|
||||
@[deprecated mem_def (since := "2025-04-07")]
|
||||
theorem mem_iff {a : α} {b : Option α} : a ∈ b ↔ b = some a := .rfl
|
||||
|
||||
@[grind] theorem mem_some {a b : α} : a ∈ some b ↔ b = a := by simp
|
||||
@[grind =] theorem mem_some {a b : α} : a ∈ some b ↔ b = a := by simp
|
||||
|
||||
theorem mem_some_iff {a b : α} : a ∈ some b ↔ b = a := mem_some
|
||||
|
||||
|
||||
@@ -16,30 +16,30 @@ public section
|
||||
|
||||
namespace Option
|
||||
|
||||
@[simp, grind] theorem mem_toList {a : α} {o : Option α} : a ∈ o.toList ↔ o = some a := by
|
||||
@[simp, grind =] theorem mem_toList {a : α} {o : Option α} : a ∈ o.toList ↔ o = some a := by
|
||||
cases o <;> simp [eq_comm]
|
||||
|
||||
@[simp, grind] theorem forIn'_toList [Monad m] (o : Option α) (b : β) (f : (a : α) → a ∈ o.toList → β → m (ForInStep β)) :
|
||||
@[simp, grind =] theorem forIn'_toList [Monad m] (o : Option α) (b : β) (f : (a : α) → a ∈ o.toList → β → m (ForInStep β)) :
|
||||
forIn' o.toList b f = forIn' o b fun a m b => f a (by simpa using m) b := by
|
||||
cases o <;> rfl
|
||||
|
||||
@[simp, grind] theorem forIn_toList [Monad m] (o : Option α) (b : β) (f : α → β → m (ForInStep β)) :
|
||||
@[simp, grind =] theorem forIn_toList [Monad m] (o : Option α) (b : β) (f : α → β → m (ForInStep β)) :
|
||||
forIn o.toList b f = forIn o b f := by
|
||||
cases o <;> rfl
|
||||
|
||||
@[simp, grind] theorem foldlM_toList [Monad m] [LawfulMonad m] (o : Option β) (a : α) (f : α → β → m α) :
|
||||
@[simp, grind =] theorem foldlM_toList [Monad m] [LawfulMonad m] (o : Option β) (a : α) (f : α → β → m α) :
|
||||
o.toList.foldlM f a = o.elim (pure a) (fun b => f a b) := by
|
||||
cases o <;> simp
|
||||
|
||||
@[simp, grind] theorem foldrM_toList [Monad m] [LawfulMonad m] (o : Option β) (a : α) (f : β → α → m α) :
|
||||
@[simp, grind =] theorem foldrM_toList [Monad m] [LawfulMonad m] (o : Option β) (a : α) (f : β → α → m α) :
|
||||
o.toList.foldrM f a = o.elim (pure a) (fun b => f b a) := by
|
||||
cases o <;> simp
|
||||
|
||||
@[simp, grind] theorem foldl_toList (o : Option β) (a : α) (f : α → β → α) :
|
||||
@[simp, grind =] theorem foldl_toList (o : Option β) (a : α) (f : α → β → α) :
|
||||
o.toList.foldl f a = o.elim a (fun b => f a b) := by
|
||||
cases o <;> simp
|
||||
|
||||
@[simp, grind] theorem foldr_toList (o : Option β) (a : α) (f : β → α → α) :
|
||||
@[simp, grind =] theorem foldr_toList (o : Option β) (a : α) (f : β → α → α) :
|
||||
o.toList.foldr f a = o.elim a (fun b => f b a) := by
|
||||
cases o <;> simp
|
||||
|
||||
@@ -47,7 +47,7 @@ namespace Option
|
||||
theorem pairwise_toList {P : α → α → Prop} {o : Option α} : o.toList.Pairwise P := by
|
||||
cases o <;> simp
|
||||
|
||||
@[simp, grind]
|
||||
@[simp, grind =]
|
||||
theorem head?_toList {o : Option α} : o.toList.head? = o := by
|
||||
cases o <;> simp
|
||||
|
||||
|
||||
@@ -16,20 +16,20 @@ public section
|
||||
|
||||
namespace Option
|
||||
|
||||
@[simp, grind] theorem bindM_none [Pure m] (f : α → m (Option β)) : none.bindM f = pure none := rfl
|
||||
@[simp, grind] theorem bindM_some [Pure m] (a) (f : α → m (Option β)) : (some a).bindM f = f a := by
|
||||
@[simp, grind =] theorem bindM_none [Pure m] (f : α → m (Option β)) : none.bindM f = pure none := rfl
|
||||
@[simp, grind =] theorem bindM_some [Pure m] (a) (f : α → m (Option β)) : (some a).bindM f = f a := by
|
||||
simp [Option.bindM]
|
||||
|
||||
-- We simplify `Option.forM` to `forM`.
|
||||
@[simp] theorem forM_eq_forM [Monad m] : @Option.forM m α _ = forM := rfl
|
||||
|
||||
@[simp, grind] theorem forM_none [Monad m] (f : α → m PUnit) :
|
||||
@[simp, grind =] theorem forM_none [Monad m] (f : α → m PUnit) :
|
||||
forM none f = pure .unit := rfl
|
||||
|
||||
@[simp, grind] theorem forM_some [Monad m] (f : α → m PUnit) (a : α) :
|
||||
@[simp, grind =] theorem forM_some [Monad m] (f : α → m PUnit) (a : α) :
|
||||
forM (some a) f = f a := rfl
|
||||
|
||||
@[simp, grind] theorem forM_map [Monad m] [LawfulMonad m] (o : Option α) (g : α → β) (f : β → m PUnit) :
|
||||
@[simp, grind =] theorem forM_map [Monad m] [LawfulMonad m] (o : Option α) (g : α → β) (f : β → m PUnit) :
|
||||
forM (o.map g) f = forM o (fun a => f (g a)) := by
|
||||
cases o <;> simp
|
||||
|
||||
@@ -37,11 +37,11 @@ theorem forM_join [Monad m] [LawfulMonad m] (o : Option (Option α)) (f : α →
|
||||
forM o.join f = forM o (forM · f) := by
|
||||
cases o <;> simp
|
||||
|
||||
@[simp, grind] theorem forIn'_none [Monad m] (b : β) (f : (a : α) → a ∈ none → β → m (ForInStep β)) :
|
||||
@[simp, grind =] theorem forIn'_none [Monad m] (b : β) (f : (a : α) → a ∈ none → β → m (ForInStep β)) :
|
||||
forIn' none b f = pure b := by
|
||||
rfl
|
||||
|
||||
@[simp, grind] theorem forIn'_some [Monad m] [LawfulMonad m] (a : α) (b : β) (f : (a' : α) → a' ∈ some a → β → m (ForInStep β)) :
|
||||
@[simp, grind =] theorem forIn'_some [Monad m] [LawfulMonad m] (a : α) (b : β) (f : (a' : α) → a' ∈ some a → β → m (ForInStep β)) :
|
||||
forIn' (some a) b f = bind (f a rfl b) (fun r => pure (ForInStep.value r)) := by
|
||||
simp only [forIn', bind_pure_comp]
|
||||
rw [map_eq_pure_bind]
|
||||
@@ -49,11 +49,11 @@ theorem forM_join [Monad m] [LawfulMonad m] (o : Option (Option α)) (f : α →
|
||||
funext x
|
||||
split <;> simp
|
||||
|
||||
@[simp, grind] theorem forIn_none [Monad m] (b : β) (f : α → β → m (ForInStep β)) :
|
||||
@[simp, grind =] theorem forIn_none [Monad m] (b : β) (f : α → β → m (ForInStep β)) :
|
||||
forIn none b f = pure b := by
|
||||
rfl
|
||||
|
||||
@[simp, grind] theorem forIn_some [Monad m] [LawfulMonad m] (a : α) (b : β) (f : α → β → m (ForInStep β)) :
|
||||
@[simp, grind =] theorem forIn_some [Monad m] [LawfulMonad m] (a : α) (b : β) (f : α → β → m (ForInStep β)) :
|
||||
forIn (some a) b f = bind (f a b) (fun r => pure (ForInStep.value r)) := by
|
||||
simp only [forIn, forIn', bind_pure_comp]
|
||||
rw [map_eq_pure_bind]
|
||||
@@ -106,7 +106,7 @@ theorem forIn'_id_yield_eq_pelim
|
||||
o.pelim b (fun a h => f a h b) :=
|
||||
forIn'_pure_yield_eq_pelim _ _ _
|
||||
|
||||
@[simp, grind] theorem forIn'_map [Monad m] [LawfulMonad m]
|
||||
@[simp, grind =] theorem forIn'_map [Monad m] [LawfulMonad m]
|
||||
(o : Option α) (g : α → β) (f : (b : β) → b ∈ o.map g → γ → m (ForInStep γ)) :
|
||||
forIn' (o.map g) init f = forIn' o init fun a h y => f (g a) (mem_map_of_mem g h) y := by
|
||||
cases o <;> simp
|
||||
@@ -149,7 +149,7 @@ theorem forIn_id_yield_eq_elim
|
||||
o.elim b (fun a => f a b) :=
|
||||
forIn_pure_yield_eq_elim _ _ _
|
||||
|
||||
@[simp, grind] theorem forIn_map [Monad m] [LawfulMonad m]
|
||||
@[simp, grind =] theorem forIn_map [Monad m] [LawfulMonad m]
|
||||
(o : Option α) (g : α → β) (f : β → γ → m (ForInStep γ)) :
|
||||
forIn (o.map g) init f = forIn o init fun a y => f (g a) y := by
|
||||
cases o <;> simp
|
||||
|
||||
@@ -349,13 +349,13 @@ theorem LawfulEqCmp.compare_beq_iff_eq {a b : α} : cmp a b == .eq ↔ a = b :=
|
||||
beq_iff_eq.trans compare_eq_iff_eq
|
||||
|
||||
/-- The corresponding lemma for `LawfulEqCmp` is `LawfulEqCmp.compare_eq_iff_eq` -/
|
||||
@[simp, grind]
|
||||
@[simp, grind =]
|
||||
theorem LawfulEqOrd.compare_eq_iff_eq [Ord α] [LawfulEqOrd α] {a b : α} :
|
||||
compare a b = .eq ↔ a = b :=
|
||||
LawfulEqCmp.compare_eq_iff_eq
|
||||
|
||||
/-- The corresponding lemma for `LawfulEqCmp` is `LawfulEqCmp.compare_beq_iff_eq` -/
|
||||
@[grind]
|
||||
@[grind =]
|
||||
theorem LawfulEqOrd.compare_beq_iff_eq [Ord α] [LawfulEqOrd α] {a b : α} :
|
||||
compare a b == .eq ↔ a = b :=
|
||||
LawfulEqCmp.compare_beq_iff_eq
|
||||
|
||||
@@ -67,20 +67,20 @@ public structure Packages.PreorderOfLEArgs (α : Type u) where
|
||||
extract_lets
|
||||
first
|
||||
| infer_instance
|
||||
| exact Classical.Order.instLT
|
||||
| exact _root_.Classical.Order.instLT
|
||||
beq :
|
||||
let := le; let := decidableLE
|
||||
BEq α := by
|
||||
extract_lets
|
||||
first
|
||||
| infer_instance
|
||||
| exact FactoryInstances.beqOfDecidableLE
|
||||
| exact _root_.Std.FactoryInstances.beqOfDecidableLE
|
||||
lt_iff :
|
||||
let := le; let := lt
|
||||
∀ a b : α, a < b ↔ a ≤ b ∧ ¬ b ≤ a := by
|
||||
extract_lets
|
||||
first
|
||||
| exact LawfulOrderLT.lt_iff
|
||||
| exact _root_.Std.LawfulOrderLT.lt_iff
|
||||
| fail "Failed to automatically prove that the `LE` and `LT` instances are compatible. \
|
||||
Please ensure that a `LawfulOrderLT` instance can be synthesized or \
|
||||
manually provide the field `lt_iff`."
|
||||
@@ -89,10 +89,10 @@ public structure Packages.PreorderOfLEArgs (α : Type u) where
|
||||
have := lt_iff
|
||||
DecidableLT α := by
|
||||
extract_lets
|
||||
haveI := @LawfulOrderLT.mk (lt_iff := by assumption) ..
|
||||
haveI := @_root_.Std.LawfulOrderLT.mk (lt_iff := by assumption) ..
|
||||
first
|
||||
| infer_instance
|
||||
| exact FactoryInstances.decidableLTOfLE
|
||||
| exact _root_.Std.FactoryInstances.decidableLTOfLE
|
||||
| fail "Failed to automatically derive that `LT` is decidable. \
|
||||
Please ensure that a `DecidableLT` instance can be synthesized or \
|
||||
manually provide the field `decidableLT`."
|
||||
@@ -101,7 +101,7 @@ public structure Packages.PreorderOfLEArgs (α : Type u) where
|
||||
∀ a b : α, a == b ↔ a ≤ b ∧ b ≤ a := by
|
||||
extract_lets
|
||||
first
|
||||
| exact LawfulOrderBEq.beq_iff_le_and_ge
|
||||
| exact _root_.Std.LawfulOrderBEq.beq_iff_le_and_ge
|
||||
| fail "Failed to automatically prove that the `LE` and `BEq` instances are compatible. \
|
||||
Please ensure that a `LawfulOrderBEq` instance can be synthesized or \
|
||||
manually provide the field `beq_iff_le_and_ge`."
|
||||
@@ -110,7 +110,7 @@ public structure Packages.PreorderOfLEArgs (α : Type u) where
|
||||
∀ a : α, a ≤ a := by
|
||||
extract_lets
|
||||
first
|
||||
| exact Std.Refl.refl (r := (· ≤ ·))
|
||||
| exact _root_.Std.Refl.refl (r := (· ≤ ·))
|
||||
| fail "Failed to automatically prove that the `LE` instance is reflexive. \
|
||||
Please ensure that a `Refl` instance can be synthesized or \
|
||||
manually provide the field `le_refl`."
|
||||
@@ -119,7 +119,7 @@ public structure Packages.PreorderOfLEArgs (α : Type u) where
|
||||
∀ a b c : α, a ≤ b → b ≤ c → a ≤ c := by
|
||||
extract_lets
|
||||
first
|
||||
| exact fun _ _ _ hab hbc => Trans.trans (r := (· ≤ ·)) (s := (· ≤ ·)) (t := (· ≤ ·)) hab hbc
|
||||
| exact fun _ _ _ hab hbc => _root_.Trans.trans (r := (· ≤ ·)) (s := (· ≤ ·)) (t := (· ≤ ·)) hab hbc
|
||||
| fail "Failed to automatically prove that the `LE` instance is transitive. \
|
||||
Please ensure that a `Trans` instance can be synthesized or \
|
||||
manually provide the field `le_trans`."
|
||||
@@ -202,7 +202,7 @@ public structure Packages.PartialOrderOfLEArgs (α : Type u) extends Packages.Pr
|
||||
∀ a b : α, a ≤ b → b ≤ a → a = b := by
|
||||
extract_lets
|
||||
first
|
||||
| exact Antisymm.antisymm
|
||||
| exact _root_.Std.Antisymm.antisymm
|
||||
| fail "Failed to automatically prove that the `LE` instance is antisymmetric. \
|
||||
Please ensure that a `Antisymm` instance can be synthesized or \
|
||||
manually provide the field `le_antisymm`."
|
||||
@@ -310,11 +310,11 @@ public structure Packages.LinearPreorderOfLEArgs (α : Type u) extends
|
||||
extract_lets
|
||||
first
|
||||
| infer_instance
|
||||
| exact FactoryInstances.instOrdOfDecidableLE
|
||||
| exact _root_.Std.FactoryInstances.instOrdOfDecidableLE
|
||||
le_total :
|
||||
∀ a b : α, a ≤ b ∨ b ≤ a := by
|
||||
first
|
||||
| exact Total.total
|
||||
| exact _root_.Std.Total.total
|
||||
| fail "Failed to automatically prove that the `LE` instance is total. \
|
||||
Please ensure that a `Total` instance can be synthesized or \
|
||||
manually provide the field `le_total`."
|
||||
@@ -324,7 +324,7 @@ public structure Packages.LinearPreorderOfLEArgs (α : Type u) extends
|
||||
∀ a b : α, (compare a b).isLE ↔ a ≤ b := by
|
||||
extract_lets
|
||||
first
|
||||
| exact LawfulOrderOrd.isLE_compare
|
||||
| exact _root_.Std.LawfulOrderOrd.isLE_compare
|
||||
| fail "Failed to automatically prove that `(compare a b).isLE` is equivalent to `a ≤ b`. \
|
||||
Please ensure that a `LawfulOrderOrd` instance can be synthesized or \
|
||||
manually provide the field `isLE_compare`."
|
||||
@@ -333,7 +333,7 @@ public structure Packages.LinearPreorderOfLEArgs (α : Type u) extends
|
||||
∀ a b : α, (compare a b).isGE ↔ b ≤ a := by
|
||||
extract_lets
|
||||
first
|
||||
| exact LawfulOrderOrd.isGE_compare
|
||||
| exact _root_.Std.LawfulOrderOrd.isGE_compare
|
||||
| fail "Failed to automatically prove that `(compare a b).isGE` is equivalent to `b ≤ a`. \
|
||||
Please ensure that a `LawfulOrderOrd` instance can be synthesized or \
|
||||
manually provide the field `isGE_compare`."
|
||||
@@ -411,20 +411,20 @@ public structure Packages.LinearOrderOfLEArgs (α : Type u) extends
|
||||
extract_lets
|
||||
first
|
||||
| infer_instance
|
||||
| exact Min.leftLeaningOfLE _
|
||||
| exact _root_.Min.leftLeaningOfLE _
|
||||
max :
|
||||
let := le; let := decidableLE
|
||||
Max α := by
|
||||
extract_lets
|
||||
first
|
||||
| infer_instance
|
||||
| exact Max.leftLeaningOfLE _
|
||||
| exact _root_.Max.leftLeaningOfLE _
|
||||
min_eq :
|
||||
let := le; let := decidableLE; let := min
|
||||
∀ a b : α, Min.min a b = if a ≤ b then a else b := by
|
||||
extract_lets
|
||||
first
|
||||
| exact fun a b => Std.min_eq_if (a := a) (b := b)
|
||||
| exact fun a b => _root_.Std.min_eq_if (a := a) (b := b)
|
||||
| fail "Failed to automatically prove that `min` is left-leaning. \
|
||||
Please ensure that a `LawfulOrderLeftLeaningMin` instance can be synthesized or \
|
||||
manually provide the field `min_eq`."
|
||||
@@ -433,7 +433,7 @@ public structure Packages.LinearOrderOfLEArgs (α : Type u) extends
|
||||
∀ a b : α, Max.max a b = if b ≤ a then a else b := by
|
||||
extract_lets
|
||||
first
|
||||
| exact fun a b => Std.max_eq_if (a := a) (b := b)
|
||||
| exact fun a b => _root_.Std.max_eq_if (a := a) (b := b)
|
||||
| fail "Failed to automatically prove that `max` is left-leaning. \
|
||||
Please ensure that a `LawfulOrderLeftLeaningMax` instance can be synthesized or \
|
||||
manually provide the field `max_eq`."
|
||||
@@ -538,7 +538,7 @@ public structure Packages.LinearPreorderOfOrdArgs (α : Type u) where
|
||||
extract_lets
|
||||
first
|
||||
| infer_instance
|
||||
| exact LE.ofOrd _
|
||||
| exact _root_.LE.ofOrd _
|
||||
lawfulOrderOrd :
|
||||
let := ord; let := transOrd; let := le
|
||||
LawfulOrderOrd α := by
|
||||
@@ -554,7 +554,7 @@ public structure Packages.LinearPreorderOfOrdArgs (α : Type u) where
|
||||
extract_lets
|
||||
first
|
||||
| infer_instance
|
||||
| exact DecidableLE.ofOrd _
|
||||
| exact _root_.DecidableLE.ofOrd _
|
||||
| fail "Failed to automatically derive that `LE` is decidable.\
|
||||
Please ensure that a `DecidableLE` instance can be synthesized or \
|
||||
manually provide the field `decidableLE`."
|
||||
@@ -570,7 +570,7 @@ public structure Packages.LinearPreorderOfOrdArgs (α : Type u) where
|
||||
∀ a b : α, a < b ↔ compare a b = .lt := by
|
||||
extract_lets
|
||||
first
|
||||
| exact fun _ _ => Std.compare_eq_lt.symm
|
||||
| exact fun _ _ => _root_.Std.compare_eq_lt.symm
|
||||
| fail "Failed to automatically derive that `LT` and `Ord` are compatible. \
|
||||
Please ensure that a `LawfulOrderLT` instance can be synthesized or \
|
||||
manually provide the field `lt_iff`."
|
||||
@@ -580,7 +580,7 @@ public structure Packages.LinearPreorderOfOrdArgs (α : Type u) where
|
||||
extract_lets
|
||||
first
|
||||
| infer_instance
|
||||
| exact DecidableLT.ofOrd _
|
||||
| exact _root_DecidableLT.ofOrd _
|
||||
| fail "Failed to automatically derive that `LT` is decidable. \
|
||||
Please ensure that a `DecidableLT` instance can be synthesized or \
|
||||
manually provide the field `decidableLT`."
|
||||
@@ -589,7 +589,7 @@ public structure Packages.LinearPreorderOfOrdArgs (α : Type u) where
|
||||
extract_lets
|
||||
first
|
||||
| infer_instance
|
||||
| exact BEq.ofOrd _
|
||||
| exact _root_.BEq.ofOrd _
|
||||
beq_iff :
|
||||
let := ord; let := le; have := lawfulOrderOrd; let := beq
|
||||
∀ a b : α, a == b ↔ compare a b = .eq := by
|
||||
@@ -708,7 +708,7 @@ public structure Packages.LinearOrderOfOrdArgs (α : Type u) extends
|
||||
∀ a b : α, compare a b = .eq → a = b := by
|
||||
extract_lets
|
||||
first
|
||||
| exact LawfulEqOrd.eq_of_compare
|
||||
| exact fun _ _ => _root_.Std.LawfulEqOrd.eq_of_compare
|
||||
| fail "Failed to derive a `LawfulEqOrd` instance. \
|
||||
Please make sure that it can be synthesized or \
|
||||
manually provide the field `eq_of_compare`."
|
||||
@@ -718,20 +718,20 @@ public structure Packages.LinearOrderOfOrdArgs (α : Type u) extends
|
||||
extract_lets
|
||||
first
|
||||
| infer_instance
|
||||
| exact FactoryInstances.instMinOfOrd
|
||||
| exact _root_.Std.FactoryInstances.instMinOfOrd
|
||||
max :
|
||||
let := ord
|
||||
Max α := by
|
||||
extract_lets
|
||||
first
|
||||
| infer_instance
|
||||
| exact FactoryInstances.instMaxOfOrd
|
||||
| exact _root_.Std.FactoryInstances.instMaxOfOrd
|
||||
min_eq :
|
||||
let := ord; let := le; let := min; have := lawfulOrderOrd
|
||||
∀ a b : α, Min.min a b = if (compare a b).isLE then a else b := by
|
||||
extract_lets
|
||||
first
|
||||
| exact fun a b => Std.min_eq_if_isLE_compare (a := a) (b := b)
|
||||
| exact fun a b => _root_.Std.min_eq_if_isLE_compare (a := a) (b := b)
|
||||
| fail "Failed to automatically prove that `min` is left-leaning. \
|
||||
Please ensure that a `LawfulOrderLeftLeaningMin` instance can be synthesized or \
|
||||
manually provide the field `min_eq`."
|
||||
@@ -740,7 +740,7 @@ public structure Packages.LinearOrderOfOrdArgs (α : Type u) extends
|
||||
∀ a b : α, Max.max a b = if (compare a b).isGE then a else b := by
|
||||
extract_lets
|
||||
first
|
||||
| exact fun a b => Std.max_eq_if_isGE_compare (a := a) (b := b)
|
||||
| exact fun a b => _root_.Std.max_eq_if_isGE_compare (a := a) (b := b)
|
||||
| fail "Failed to automatically prove that `max` is left-leaning. \
|
||||
Please ensure that a `LawfulOrderLeftLeaningMax` instance can be synthesized or \
|
||||
manually provide the field `max_eq`."
|
||||
|
||||
@@ -7,6 +7,7 @@ module
|
||||
|
||||
prelude
|
||||
public import Init.System.IO
|
||||
import Init.Data.ByteArray.Extra
|
||||
|
||||
public section
|
||||
universe u
|
||||
|
||||
@@ -24,14 +24,14 @@ namespace Std.PRange
|
||||
instance [LE α] [LT α] [UpwardEnumerable α] [LawfulUpwardEnumerable α]
|
||||
[LawfulUpwardEnumerableLE α] [LawfulOrderLT α] : LawfulUpwardEnumerableLT α where
|
||||
lt_iff a b := by
|
||||
simp only [LawfulOrderLT.lt_iff, LawfulUpwardEnumerableLE.le_iff]
|
||||
simp only [LawfulOrderLT.lt_iff, UpwardEnumerable.le_iff]
|
||||
constructor
|
||||
· intro h
|
||||
obtain ⟨n, hn⟩ := h.1
|
||||
cases n
|
||||
· apply h.2.elim
|
||||
refine ⟨0, ?_⟩
|
||||
simpa [UpwardEnumerable.succMany?_zero] using hn.symm
|
||||
simpa [succMany?_zero] using hn.symm
|
||||
exact ⟨_, hn⟩
|
||||
· intro h
|
||||
constructor
|
||||
@@ -41,63 +41,60 @@ instance [LE α] [LT α] [UpwardEnumerable α] [LawfulUpwardEnumerable α]
|
||||
instance [LE α] [DecidableLE α] [UpwardEnumerable α] [LawfulUpwardEnumerableLE α] :
|
||||
LawfulUpwardEnumerableLowerBound .closed α where
|
||||
isSatisfied_iff a l := by
|
||||
simp [SupportsLowerBound.IsSatisfied, BoundedUpwardEnumerable.init?,
|
||||
LawfulUpwardEnumerableLE.le_iff]
|
||||
simp [SupportsLowerBound.IsSatisfied, init?, UpwardEnumerable.le_iff]
|
||||
|
||||
instance [LE α] [DecidableLE α] [UpwardEnumerable α] [LawfulUpwardEnumerableLE α]
|
||||
[Trans (α := α) (· ≤ ·) (· ≤ ·) (· ≤ ·)]:
|
||||
LawfulUpwardEnumerableUpperBound .closed α where
|
||||
isSatisfied_of_le u a b hub hab := by
|
||||
simp only [SupportsUpperBound.IsSatisfied, ← LawfulUpwardEnumerableLE.le_iff] at hub hab ⊢
|
||||
simp only [SupportsUpperBound.IsSatisfied, ← UpwardEnumerable.le_iff] at hub hab ⊢
|
||||
exact Trans.trans hab hub
|
||||
|
||||
instance [LT α] [DecidableLT α] [UpwardEnumerable α] [LawfulUpwardEnumerable α]
|
||||
[LawfulUpwardEnumerableLT α] :
|
||||
LawfulUpwardEnumerableLowerBound .open α where
|
||||
isSatisfied_iff a l := by
|
||||
simp only [SupportsLowerBound.IsSatisfied, BoundedUpwardEnumerable.init?,
|
||||
LawfulUpwardEnumerableLT.lt_iff]
|
||||
simp only [SupportsLowerBound.IsSatisfied, init?, UpwardEnumerable.lt_iff]
|
||||
constructor
|
||||
· rintro ⟨n, hn⟩
|
||||
simp only [LawfulUpwardEnumerable.succMany?_succ_eq_succ?_bind_succMany?] at hn
|
||||
cases h : UpwardEnumerable.succ? l
|
||||
simp only [succMany?_succ?_eq_succ?_bind_succMany?] at hn
|
||||
cases h : succ? l
|
||||
· simp [h] at hn
|
||||
· exact ⟨_, rfl, n, by simpa [h] using hn⟩
|
||||
· rintro ⟨init, hi, n, hn⟩
|
||||
exact ⟨n, by simpa [LawfulUpwardEnumerable.succMany?_succ_eq_succ?_bind_succMany?, hi] using hn⟩
|
||||
exact ⟨n, by simpa [succMany?_succ?_eq_succ?_bind_succMany?, hi] using hn⟩
|
||||
|
||||
instance [LT α] [DecidableLT α] [UpwardEnumerable α] [LawfulUpwardEnumerable α]
|
||||
[LawfulUpwardEnumerableLT α] :
|
||||
LawfulUpwardEnumerableUpperBound .open α where
|
||||
isSatisfied_of_le u a b hub hab := by
|
||||
simp only [SupportsUpperBound.IsSatisfied, LawfulUpwardEnumerableLT.lt_iff] at hub ⊢
|
||||
simp only [SupportsUpperBound.IsSatisfied, UpwardEnumerable.lt_iff] at hub ⊢
|
||||
exact UpwardEnumerable.lt_of_le_of_lt hab hub
|
||||
|
||||
instance [UpwardEnumerable α] [Least? α] [LawfulUpwardEnumerableLeast? α] :
|
||||
LawfulUpwardEnumerableLowerBound .unbounded α where
|
||||
isSatisfied_iff a l := by
|
||||
simpa [SupportsLowerBound.IsSatisfied, BoundedUpwardEnumerable.init?] using
|
||||
LawfulUpwardEnumerableLeast?.eq_succMany?_least? a
|
||||
simpa [SupportsLowerBound.IsSatisfied, init?] using UpwardEnumerable.least?_le
|
||||
|
||||
instance [LE α] [Total (α := α) (· ≤ ·)] [UpwardEnumerable α] [LawfulUpwardEnumerable α]
|
||||
[LawfulUpwardEnumerableLE α] :
|
||||
LinearlyUpwardEnumerable α where
|
||||
eq_of_succ?_eq a b hab := by
|
||||
cases Total.total (α := α) (r := (· ≤ ·)) a b <;> rename_i h <;>
|
||||
simp only [LawfulUpwardEnumerableLE.le_iff] at h
|
||||
simp only [UpwardEnumerable.le_iff] at h
|
||||
· obtain ⟨n, hn⟩ := h
|
||||
cases n
|
||||
· simpa [UpwardEnumerable.succMany?_zero] using hn
|
||||
· simpa [succMany?_zero] using hn
|
||||
· exfalso
|
||||
rw [LawfulUpwardEnumerable.succMany?_succ_eq_succ?_bind_succMany?, hab,
|
||||
← LawfulUpwardEnumerable.succMany?_succ_eq_succ?_bind_succMany?] at hn
|
||||
rw [succMany?_succ?_eq_succ?_bind_succMany?, hab,
|
||||
← succMany?_succ?_eq_succ?_bind_succMany?] at hn
|
||||
exact UpwardEnumerable.lt_irrefl ⟨_, hn⟩
|
||||
· obtain ⟨n, hn⟩ := h
|
||||
cases n
|
||||
· simpa [UpwardEnumerable.succMany?_zero] using hn.symm
|
||||
· simpa [succMany?_zero] using hn.symm
|
||||
· exfalso
|
||||
rw [LawfulUpwardEnumerable.succMany?_succ_eq_succ?_bind_succMany?, hab.symm,
|
||||
← LawfulUpwardEnumerable.succMany?_succ_eq_succ?_bind_succMany?] at hn
|
||||
rw [succMany?_succ?_eq_succ?_bind_succMany?, hab.symm,
|
||||
← succMany?_succ?_eq_succ?_bind_succMany?] at hn
|
||||
exact UpwardEnumerable.lt_irrefl ⟨_, hn⟩
|
||||
|
||||
instance [UpwardEnumerable α] : LawfulUpwardEnumerableUpperBound .unbounded α where
|
||||
@@ -122,24 +119,24 @@ instance LawfulRangeSize.open_of_closed [UpwardEnumerable α] [LE α] [Decidable
|
||||
simp only [SupportsUpperBound.IsSatisfied] at h
|
||||
simp only [RangeSize.size]
|
||||
by_cases h' : a ≤ bound
|
||||
· match hs : UpwardEnumerable.succ? a with
|
||||
· match hs : succ? a with
|
||||
| none => rw [LawfulRangeSize.size_eq_one_of_succ?_eq_none (h := h') (h' := by omega)]
|
||||
| some b =>
|
||||
rw [LawfulRangeSize.size_eq_succ_of_succ?_eq_some (h := h') (h' := hs)]
|
||||
have : ¬ b ≤ bound := by
|
||||
intro hb
|
||||
have : a < b := by
|
||||
rw [LawfulUpwardEnumerableLT.lt_iff]
|
||||
exact ⟨0, by simpa [UpwardEnumerable.succMany?_one] using hs⟩
|
||||
rw [UpwardEnumerable.lt_iff]
|
||||
exact ⟨0, by simpa [succMany?_one] using hs⟩
|
||||
exact h (lt_of_lt_of_le this hb)
|
||||
rw [LawfulRangeSize.size_eq_zero_of_not_isSatisfied (h := this)]
|
||||
· suffices RangeSize.size (shape := .closed) bound a = 0 by omega
|
||||
exact LawfulRangeSize.size_eq_zero_of_not_isSatisfied _ _ h'
|
||||
size_eq_one_of_succ?_eq_none bound a h h' := by
|
||||
exfalso
|
||||
simp only [SupportsUpperBound.IsSatisfied, LawfulUpwardEnumerableLT.lt_iff] at h
|
||||
simp only [SupportsUpperBound.IsSatisfied, UpwardEnumerable.lt_iff] at h
|
||||
obtain ⟨n, hn⟩ := h
|
||||
simp [LawfulUpwardEnumerable.succMany?_succ_eq_succ?_bind_succMany?, h'] at hn
|
||||
simp [succMany?_succ?_eq_succ?_bind_succMany?, h'] at hn
|
||||
size_eq_succ_of_succ?_eq_some bound a a' h h' := by
|
||||
simp only [SupportsUpperBound.IsSatisfied] at h
|
||||
simp only [RangeSize.size, Nat.pred_eq_succ_iff]
|
||||
@@ -148,10 +145,10 @@ instance LawfulRangeSize.open_of_closed [UpwardEnumerable α] [LE α] [Decidable
|
||||
· omega
|
||||
· simp only [Nat.succ_le_iff, LawfulRangeSize.size_pos_iff_isSatisfied,
|
||||
SupportsUpperBound.IsSatisfied]
|
||||
rw [LawfulUpwardEnumerableLE.le_iff]
|
||||
rw [LawfulUpwardEnumerableLT.lt_iff] at h
|
||||
rw [UpwardEnumerable.le_iff]
|
||||
rw [UpwardEnumerable.lt_iff] at h
|
||||
refine ⟨h.choose, ?_⟩
|
||||
simpa [LawfulUpwardEnumerable.succMany?_succ_eq_succ?_bind_succMany?, h'] using h.choose_spec
|
||||
simpa [succMany?_succ?_eq_succ?_bind_succMany?, h'] using h.choose_spec
|
||||
|
||||
instance LawfulRangeSize.instHasFiniteRanges [UpwardEnumerable α] [LawfulUpwardEnumerable α]
|
||||
[RangeSize su α] [SupportsUpperBound su α] [LawfulRangeSize su α] : HasFiniteRanges su α where
|
||||
@@ -161,11 +158,11 @@ instance LawfulRangeSize.instHasFiniteRanges [UpwardEnumerable α] [LawfulUpward
|
||||
induction n generalizing init with
|
||||
| zero =>
|
||||
simp only [LawfulRangeSize.size_eq_zero_iff_not_isSatisfied] at hn
|
||||
simp [UpwardEnumerable.succMany?_zero, hn]
|
||||
simp [succMany?_zero, hn]
|
||||
| succ =>
|
||||
rename_i n ih
|
||||
rw [LawfulUpwardEnumerable.succMany?_succ_eq_succ?_bind_succMany?]
|
||||
match hs : UpwardEnumerable.succ? init with
|
||||
rw [succMany?_succ?_eq_succ?_bind_succMany?]
|
||||
match hs : succ? init with
|
||||
| none => simp
|
||||
| some a =>
|
||||
simp only [Option.bind_some]
|
||||
|
||||
@@ -7,7 +7,7 @@ module
|
||||
|
||||
prelude
|
||||
public import Init.Data.Iterators
|
||||
public import Init.Data.Iterators.Lemmas.Consumers.Collect
|
||||
import Init.Data.Iterators.Lemmas.Consumers.Collect
|
||||
public import Init.Data.Range.Polymorphic.Basic
|
||||
import all Init.Data.Range.Polymorphic.Basic
|
||||
public import Init.Data.Range.Polymorphic.RangeIterator
|
||||
@@ -30,13 +30,13 @@ open Std.Iterators
|
||||
|
||||
variable {shape : RangeShape} {α : Type u}
|
||||
|
||||
private theorem Internal.iter_open_eq_iter_closed_of_isSome_succ? {su} [UpwardEnumerable α]
|
||||
private theorem Internal.iter_Rox_eq_iter_Rcx_of_isSome_succ? {su} [UpwardEnumerable α]
|
||||
[SupportsUpperBound su α] [HasFiniteRanges su α]
|
||||
[LawfulUpwardEnumerable α]
|
||||
{lo : Bound .open α} {hi} (h : (UpwardEnumerable.succ? lo).isSome) :
|
||||
Internal.iter (PRange.mk (shape := ⟨.open, su⟩) lo hi) =
|
||||
Internal.iter (PRange.mk (shape := ⟨.closed, su⟩) (UpwardEnumerable.succ? lo |>.get h) hi) := by
|
||||
simp [Internal.iter, BoundedUpwardEnumerable.init?]
|
||||
simp [Internal.iter, init?]
|
||||
|
||||
private theorem Internal.toList_eq_toList_iter {sl su} [UpwardEnumerable α]
|
||||
[BoundedUpwardEnumerable sl α] [SupportsUpperBound su α] [HasFiniteRanges su α]
|
||||
@@ -44,7 +44,7 @@ private theorem Internal.toList_eq_toList_iter {sl su} [UpwardEnumerable α]
|
||||
r.toList = (Internal.iter r).toList := by
|
||||
rfl
|
||||
|
||||
theorem RangeIterator.toList_eq_match {su} [UpwardEnumerable α]
|
||||
public theorem RangeIterator.toList_eq_match {su} [UpwardEnumerable α]
|
||||
[SupportsUpperBound su α] [HasFiniteRanges su α]
|
||||
[LawfulUpwardEnumerable α]
|
||||
{it : Iter (α := RangeIterator su α) α} :
|
||||
@@ -61,11 +61,11 @@ theorem RangeIterator.toList_eq_match {su} [UpwardEnumerable α]
|
||||
· simp [*]
|
||||
· split <;> rename_i heq' <;> simp [*]
|
||||
|
||||
theorem toList_eq_match {sl su} [UpwardEnumerable α] [BoundedUpwardEnumerable sl α]
|
||||
public theorem toList_eq_match {sl su} [UpwardEnumerable α] [BoundedUpwardEnumerable sl α]
|
||||
[SupportsUpperBound su α] [HasFiniteRanges su α]
|
||||
[LawfulUpwardEnumerable α]
|
||||
{r : PRange ⟨sl, su⟩ α} :
|
||||
r.toList = match BoundedUpwardEnumerable.init? r.lower with
|
||||
r.toList = match init? r.lower with
|
||||
| none => []
|
||||
| some a => if SupportsUpperBound.IsSatisfied r.upper a then
|
||||
a :: (PRange.mk (shape := ⟨.open, su⟩) a r.upper).toList
|
||||
@@ -73,26 +73,35 @@ theorem toList_eq_match {sl su} [UpwardEnumerable α] [BoundedUpwardEnumerable s
|
||||
[] := by
|
||||
rw [Internal.toList_eq_toList_iter, RangeIterator.toList_eq_match]; rfl
|
||||
|
||||
theorem toList_open_eq_toList_closed_of_isSome_succ? {su} [UpwardEnumerable α]
|
||||
public theorem toList_Rox_eq_toList_Rcx_of_isSome_succ? {su} [UpwardEnumerable α]
|
||||
[SupportsUpperBound su α] [HasFiniteRanges su α]
|
||||
[LawfulUpwardEnumerable α]
|
||||
{lo : Bound .open α} {hi} (h : (UpwardEnumerable.succ? lo).isSome) :
|
||||
(PRange.mk (shape := ⟨.open, su⟩) lo hi).toList =
|
||||
(PRange.mk (shape := ⟨.closed, su⟩) (UpwardEnumerable.succ? lo |>.get h) hi).toList := by
|
||||
simp [Internal.toList_eq_toList_iter, Internal.iter_open_eq_iter_closed_of_isSome_succ?, h]
|
||||
simp [Internal.toList_eq_toList_iter, Internal.iter_Rox_eq_iter_Rcx_of_isSome_succ?, h]
|
||||
|
||||
theorem toList_eq_nil_iff {sl su} [UpwardEnumerable α]
|
||||
@[deprecated toList_Rox_eq_toList_Rcx_of_isSome_succ? (since := "2025-08-22")]
|
||||
public theorem toList_open_eq_toList_closed_of_isSome_succ? {su} [UpwardEnumerable α]
|
||||
[SupportsUpperBound su α] [HasFiniteRanges su α]
|
||||
[LawfulUpwardEnumerable α]
|
||||
{lo : Bound .open α} {hi} (h : (UpwardEnumerable.succ? lo).isSome) :
|
||||
(PRange.mk (shape := ⟨.open, su⟩) lo hi).toList =
|
||||
(PRange.mk (shape := ⟨.closed, su⟩) (UpwardEnumerable.succ? lo |>.get h) hi).toList :=
|
||||
toList_Rox_eq_toList_Rcx_of_isSome_succ? h
|
||||
|
||||
public theorem toList_eq_nil_iff {sl su} [UpwardEnumerable α]
|
||||
[SupportsUpperBound su α] [HasFiniteRanges su α] [BoundedUpwardEnumerable sl α]
|
||||
[LawfulUpwardEnumerable α]
|
||||
{r : PRange ⟨sl, su⟩ α} :
|
||||
r.toList = [] ↔
|
||||
¬ (∃ a, BoundedUpwardEnumerable.init? r.lower = some a ∧ SupportsUpperBound.IsSatisfied r.upper a) := by
|
||||
¬ (∃ a, init? r.lower = some a ∧ SupportsUpperBound.IsSatisfied r.upper a) := by
|
||||
rw [Internal.toList_eq_toList_iter]
|
||||
rw [RangeIterator.toList_eq_match, Internal.iter]
|
||||
simp only
|
||||
split <;> rename_i heq <;> simp [heq]
|
||||
|
||||
theorem mem_toList_iff_mem {sl su} [UpwardEnumerable α]
|
||||
public theorem mem_toList_iff_mem {sl su} [UpwardEnumerable α]
|
||||
[SupportsUpperBound su α] [SupportsLowerBound sl α] [HasFiniteRanges su α]
|
||||
[BoundedUpwardEnumerable sl α] [LawfulUpwardEnumerable α]
|
||||
[LawfulUpwardEnumerableLowerBound sl α] [LawfulUpwardEnumerableUpperBound su α]
|
||||
@@ -101,17 +110,24 @@ theorem mem_toList_iff_mem {sl su} [UpwardEnumerable α]
|
||||
rw [Internal.toList_eq_toList_iter, Iter.mem_toList_iff_isPlausibleIndirectOutput,
|
||||
Internal.isPlausibleIndirectOutput_iter_iff]
|
||||
|
||||
theorem BoundedUpwardEnumerable.Closed.init?_succ [UpwardEnumerable α]
|
||||
public theorem BoundedUpwardEnumerable.init?_succ?_closed [UpwardEnumerable α]
|
||||
[LawfulUpwardEnumerable α] {lower lower' : Bound .closed α}
|
||||
(h : UpwardEnumerable.succ? lower = some lower') :
|
||||
BoundedUpwardEnumerable.init? lower' = (BoundedUpwardEnumerable.init? lower).bind UpwardEnumerable.succ? := by
|
||||
init? lower' = (init? lower).bind UpwardEnumerable.succ? := by
|
||||
cases h : init? lower <;> rename_i ilower <;> cases h' : init? lower' <;> rename_i ilower'
|
||||
· simp
|
||||
· simp [init?] at h
|
||||
· simp [init?] at h'
|
||||
· simp_all [init?]
|
||||
|
||||
theorem pairwise_toList_upwardEnumerableLt {sl su} [UpwardEnumerable α]
|
||||
@[deprecated BoundedUpwardEnumerable.init?_succ?_closed (since := "2025-08-22")]
|
||||
public theorem BoundedUpwardEnumerable.Closed.init?_succ [UpwardEnumerable α]
|
||||
[LawfulUpwardEnumerable α] {lower lower' : Bound .closed α}
|
||||
(h : UpwardEnumerable.succ? lower = some lower') :
|
||||
init? lower' = (init? lower).bind UpwardEnumerable.succ? :=
|
||||
init?_succ?_closed h
|
||||
|
||||
public theorem pairwise_toList_upwardEnumerableLt {sl su} [UpwardEnumerable α]
|
||||
[SupportsUpperBound su α] [SupportsLowerBound sl α] [HasFiniteRanges su α]
|
||||
[BoundedUpwardEnumerable sl α] [LawfulUpwardEnumerable α]
|
||||
[LawfulUpwardEnumerableLowerBound sl α] [LawfulUpwardEnumerableUpperBound su α]
|
||||
@@ -130,14 +146,14 @@ theorem pairwise_toList_upwardEnumerableLt {sl su} [UpwardEnumerable α]
|
||||
simp only at ha
|
||||
have : UpwardEnumerable.LT a ha.choose := by
|
||||
refine ⟨0, ?_⟩
|
||||
simp only [UpwardEnumerable.succMany?_succ, UpwardEnumerable.succMany?_zero,
|
||||
simp only [succMany?_succ?, succMany?_zero,
|
||||
Option.bind_some]
|
||||
exact ha.choose_spec.1
|
||||
exact UpwardEnumerable.lt_of_lt_of_le this ha.choose_spec.2
|
||||
· apply ihy (out := a)
|
||||
simp_all [RangeIterator.isPlausibleStep_iff, RangeIterator.step]
|
||||
|
||||
theorem pairwise_toList_ne {sl su} [UpwardEnumerable α]
|
||||
public theorem pairwise_toList_ne {sl su} [UpwardEnumerable α]
|
||||
[SupportsUpperBound su α] [SupportsLowerBound sl α] [HasFiniteRanges su α]
|
||||
[BoundedUpwardEnumerable sl α] [LawfulUpwardEnumerable α]
|
||||
[LawfulUpwardEnumerableLowerBound sl α] [LawfulUpwardEnumerableUpperBound su α]
|
||||
@@ -145,7 +161,7 @@ theorem pairwise_toList_ne {sl su} [UpwardEnumerable α]
|
||||
r.toList.Pairwise (fun a b => a ≠ b) :=
|
||||
List.Pairwise.imp (fun hlt => UpwardEnumerable.ne_of_lt hlt) pairwise_toList_upwardEnumerableLt
|
||||
|
||||
theorem pairwise_toList_lt {sl su} [LT α] [UpwardEnumerable α]
|
||||
public theorem pairwise_toList_lt {sl su} [LT α] [UpwardEnumerable α]
|
||||
[SupportsUpperBound su α] [SupportsLowerBound sl α] [HasFiniteRanges su α]
|
||||
[BoundedUpwardEnumerable sl α] [LawfulUpwardEnumerable α] [LawfulUpwardEnumerableLT α]
|
||||
[LawfulUpwardEnumerableLowerBound sl α] [LawfulUpwardEnumerableUpperBound su α]
|
||||
@@ -154,7 +170,7 @@ theorem pairwise_toList_lt {sl su} [LT α] [UpwardEnumerable α]
|
||||
List.Pairwise.imp
|
||||
(fun hlt => (LawfulUpwardEnumerableLT.lt_iff ..).mpr hlt) pairwise_toList_upwardEnumerableLt
|
||||
|
||||
theorem pairwise_toList_le {sl su} [LE α] [UpwardEnumerable α]
|
||||
public theorem pairwise_toList_le {sl su} [LE α] [UpwardEnumerable α]
|
||||
[SupportsUpperBound su α] [SupportsLowerBound sl α] [HasFiniteRanges su α]
|
||||
[BoundedUpwardEnumerable sl α] [LawfulUpwardEnumerable α] [LawfulUpwardEnumerableLE α]
|
||||
[LawfulUpwardEnumerableLowerBound sl α] [LawfulUpwardEnumerableUpperBound su α]
|
||||
@@ -162,38 +178,44 @@ theorem pairwise_toList_le {sl su} [LE α] [UpwardEnumerable α]
|
||||
r.toList.Pairwise (fun a b => a ≤ b) :=
|
||||
pairwise_toList_upwardEnumerableLt
|
||||
|> List.Pairwise.imp UpwardEnumerable.le_of_lt
|
||||
|> List.Pairwise.imp (fun hle => (LawfulUpwardEnumerableLE.le_iff ..).mpr hle)
|
||||
|> List.Pairwise.imp (fun hle => (UpwardEnumerable.le_iff ..).mpr hle)
|
||||
|
||||
theorem ClosedOpen.mem_succ_iff [UpwardEnumerable α]
|
||||
public theorem mem_Rco_succ_succ_iff [UpwardEnumerable α]
|
||||
[LinearlyUpwardEnumerable α] [InfinitelyUpwardEnumerable α] [SupportsUpperBound .open α]
|
||||
[SupportsLowerBound .closed α] [LawfulUpwardEnumerableLowerBound .closed α]
|
||||
[HasFiniteRanges .open α] [LawfulUpwardEnumerable α] [LawfulOpenUpperBound α]
|
||||
{lower : Bound .closed α} {upper : Bound .open α} {a : α} :
|
||||
a ∈ PRange.mk (shape := ⟨.closed, .open⟩) (UpwardEnumerable.succ lower) (UpwardEnumerable.succ upper) ↔
|
||||
∃ a', a = UpwardEnumerable.succ a' ∧ a' ∈ PRange.mk (shape := ⟨.closed, .open⟩) lower upper := by
|
||||
(a ∈ (succ lower)...(succ upper)) ↔ ∃ a', a = succ a' ∧ a' ∈ lower...upper := by
|
||||
simp [Membership.mem, LawfulUpwardEnumerableLowerBound.isSatisfied_iff,
|
||||
BoundedUpwardEnumerable.init?, LawfulOpenUpperBound.isSatisfied_iff_le]
|
||||
init?, LawfulOpenUpperBound.isSatisfied_iff_le]
|
||||
rw [← Option.some_get (InfinitelyUpwardEnumerable.isSome_succ? _)]
|
||||
simp only [Option.some.injEq, ← UpwardEnumerable.succ.eq_def]
|
||||
simp
|
||||
constructor
|
||||
· rintro ⟨⟨n, hn⟩, h⟩
|
||||
rw [UpwardEnumerable.succMany?_eq_some_iff_succMany, ← UpwardEnumerable.succMany_one,
|
||||
← UpwardEnumerable.succMany_add, Nat.add_comm, UpwardEnumerable.succMany_add,
|
||||
UpwardEnumerable.succMany_one] at hn
|
||||
rw [succMany?_eq_some_iff_succMany, ← succMany_one, ← succMany_add, Nat.add_comm, succMany_add,
|
||||
succMany_one] at hn
|
||||
rw [← hn]
|
||||
refine ⟨UpwardEnumerable.succMany n lower, rfl, ?_, ?_⟩
|
||||
· exact ⟨n, by simp [UpwardEnumerable.succMany_eq_get]⟩
|
||||
refine ⟨succMany n lower, rfl, ?_, ?_⟩
|
||||
· exact ⟨n, by simp [succMany_eq_get]⟩
|
||||
· obtain ⟨m, hm⟩ := h
|
||||
refine ⟨m, ?_⟩
|
||||
rw [UpwardEnumerable.succMany?_eq_some_iff_succMany] at hm ⊢
|
||||
rwa [← hn, ← UpwardEnumerable.succMany_one, ← UpwardEnumerable.succMany_add, Nat.add_comm,
|
||||
UpwardEnumerable.succMany_add, UpwardEnumerable.succMany_one,
|
||||
UpwardEnumerable.succ_eq_succ_iff] at hm
|
||||
rw [succMany?_eq_some_iff_succMany] at hm ⊢
|
||||
rwa [← hn, ← succMany_one, ← succMany_add, Nat.add_comm, succMany_add, succMany_one,
|
||||
succ_eq_succ_iff] at hm
|
||||
· rintro ⟨a', rfl, hl, hu⟩
|
||||
simp [UpwardEnumerable.succ_le_succ_iff, UpwardEnumerable.succ_lt_succ_iff]
|
||||
exact ⟨hl, hu⟩
|
||||
|
||||
@[deprecated mem_Rco_succ_succ_iff (since := "2025-08-22")]
|
||||
public theorem ClosedOpen.mem_succ_iff [UpwardEnumerable α]
|
||||
[LinearlyUpwardEnumerable α] [InfinitelyUpwardEnumerable α] [SupportsUpperBound .open α]
|
||||
[SupportsLowerBound .closed α] [LawfulUpwardEnumerableLowerBound .closed α]
|
||||
[HasFiniteRanges .open α] [LawfulUpwardEnumerable α] [LawfulOpenUpperBound α]
|
||||
{lower : Bound .closed α} {upper : Bound .open α} {a : α} :
|
||||
(a ∈ (succ lower)...(succ upper)) ↔ ∃ a', a = succ a' ∧ a' ∈ lower...upper :=
|
||||
mem_Rco_succ_succ_iff
|
||||
|
||||
private theorem eq_of_pairwise_lt_of_mem_iff_mem {lt : α → α → Prop} [asymm : Asymm lt]
|
||||
{l l' : List α} (hl : l.Pairwise lt) (hl' : l'.Pairwise lt)
|
||||
(h : ∀ a, a ∈ l ↔ a ∈ l') : l = l' := by
|
||||
@@ -246,13 +268,13 @@ private theorem eq_of_pairwise_lt_of_mem_iff_mem {lt : α → α → Prop} [asym
|
||||
have hgt := hl.1 y ‹_›
|
||||
cases Asymm.asymm _ _ hlt hgt
|
||||
|
||||
theorem ClosedOpen.toList_succ_succ_eq_map [UpwardEnumerable α] [SupportsLowerBound .closed α]
|
||||
public theorem toList_Rco_succ_succ_eq_map [UpwardEnumerable α] [SupportsLowerBound .closed α]
|
||||
[LinearlyUpwardEnumerable α] [InfinitelyUpwardEnumerable α] [SupportsUpperBound .open α]
|
||||
[HasFiniteRanges .open α] [LawfulUpwardEnumerable α] [LawfulOpenUpperBound α]
|
||||
[LawfulUpwardEnumerableLowerBound .closed α] [LawfulUpwardEnumerableUpperBound .open α]
|
||||
{lower : Bound .closed α} {upper : Bound .open α} :
|
||||
(PRange.mk (shape := ⟨.closed, .open⟩) (UpwardEnumerable.succ lower) (UpwardEnumerable.succ upper)).toList =
|
||||
(PRange.mk (shape := ⟨.closed, .open⟩) lower upper).toList.map UpwardEnumerable.succ := by
|
||||
((succ lower)...(succ upper)).toList =
|
||||
(lower...upper).toList.map succ := by
|
||||
apply eq_of_pairwise_lt_of_mem_iff_mem (lt := UpwardEnumerable.LT) (asymm := ?_)
|
||||
· apply pairwise_toList_upwardEnumerableLt
|
||||
· apply List.Pairwise.map (R := UpwardEnumerable.LT) (S := UpwardEnumerable.LT)
|
||||
@@ -261,7 +283,7 @@ theorem ClosedOpen.toList_succ_succ_eq_map [UpwardEnumerable α] [SupportsLowerB
|
||||
· apply pairwise_toList_upwardEnumerableLt
|
||||
· simp only [List.mem_map, mem_toList_iff_mem]
|
||||
intro a
|
||||
rw [mem_succ_iff]
|
||||
rw [mem_Rco_succ_succ_iff]
|
||||
constructor
|
||||
· rintro ⟨a, rfl, h⟩
|
||||
exact ⟨a, h, rfl⟩
|
||||
@@ -269,6 +291,16 @@ theorem ClosedOpen.toList_succ_succ_eq_map [UpwardEnumerable α] [SupportsLowerB
|
||||
exact ⟨_, h'.symm, h⟩
|
||||
· exact ⟨fun _ _ => UpwardEnumerable.not_gt_of_lt⟩
|
||||
|
||||
@[deprecated toList_Rco_succ_succ_eq_map (since := "2025-08-22")]
|
||||
public theorem ClosedOpen.toList_succ_succ_eq_map [UpwardEnumerable α] [SupportsLowerBound .closed α]
|
||||
[LinearlyUpwardEnumerable α] [InfinitelyUpwardEnumerable α] [SupportsUpperBound .open α]
|
||||
[HasFiniteRanges .open α] [LawfulUpwardEnumerable α] [LawfulOpenUpperBound α]
|
||||
[LawfulUpwardEnumerableLowerBound .closed α] [LawfulUpwardEnumerableUpperBound .open α]
|
||||
{lower : Bound .closed α} {upper : Bound .open α} :
|
||||
((succ lower)...(succ upper)).toList =
|
||||
(lower...upper).toList.map succ :=
|
||||
toList_Rco_succ_succ_eq_map
|
||||
|
||||
private theorem Internal.forIn'_eq_forIn'_iter [UpwardEnumerable α]
|
||||
[SupportsUpperBound su α] [SupportsLowerBound sl α] [HasFiniteRanges su α]
|
||||
[BoundedUpwardEnumerable sl α] [LawfulUpwardEnumerable α]
|
||||
@@ -280,7 +312,7 @@ private theorem Internal.forIn'_eq_forIn'_iter [UpwardEnumerable α]
|
||||
ForIn'.forIn' (Internal.iter r) init (fun a ha acc => f a (Internal.isPlausibleIndirectOutput_iter_iff.mp ha) acc) := by
|
||||
rfl
|
||||
|
||||
theorem forIn'_eq_forIn'_toList [UpwardEnumerable α]
|
||||
public theorem forIn'_eq_forIn'_toList [UpwardEnumerable α]
|
||||
[SupportsUpperBound su α] [SupportsLowerBound sl α] [HasFiniteRanges su α]
|
||||
[BoundedUpwardEnumerable sl α] [LawfulUpwardEnumerable α]
|
||||
[LawfulUpwardEnumerableLowerBound sl α] [LawfulUpwardEnumerableUpperBound su α]
|
||||
@@ -292,7 +324,7 @@ theorem forIn'_eq_forIn'_toList [UpwardEnumerable α]
|
||||
simp [Internal.forIn'_eq_forIn'_iter, Internal.toList_eq_toList_iter,
|
||||
Iter.forIn'_eq_forIn'_toList]
|
||||
|
||||
theorem forIn'_toList_eq_forIn' [UpwardEnumerable α]
|
||||
public theorem forIn'_toList_eq_forIn' [UpwardEnumerable α]
|
||||
[SupportsUpperBound su α] [SupportsLowerBound sl α] [HasFiniteRanges su α]
|
||||
[BoundedUpwardEnumerable sl α] [LawfulUpwardEnumerable α]
|
||||
[LawfulUpwardEnumerableLowerBound sl α] [LawfulUpwardEnumerableUpperBound su α]
|
||||
@@ -303,7 +335,7 @@ theorem forIn'_toList_eq_forIn' [UpwardEnumerable α]
|
||||
ForIn'.forIn' r init (fun a ha acc => f a (mem_toList_iff_mem.mpr ha) acc) := by
|
||||
simp [forIn'_eq_forIn'_toList]
|
||||
|
||||
theorem mem_of_mem_open [UpwardEnumerable α]
|
||||
public theorem mem_of_mem_open [UpwardEnumerable α]
|
||||
[SupportsUpperBound su α] [SupportsLowerBound sl α] [HasFiniteRanges su α]
|
||||
[BoundedUpwardEnumerable sl α] [LawfulUpwardEnumerable α]
|
||||
[LawfulUpwardEnumerableLowerBound sl α] [LawfulUpwardEnumerableUpperBound su α]
|
||||
@@ -314,22 +346,21 @@ theorem mem_of_mem_open [UpwardEnumerable α]
|
||||
a ∈ r := by
|
||||
refine ⟨?_, hmem.2⟩
|
||||
have := hmem.1
|
||||
simp only [LawfulUpwardEnumerableLowerBound.isSatisfied_iff,
|
||||
BoundedUpwardEnumerable.init?] at this hrb ⊢
|
||||
simp only [LawfulUpwardEnumerableLowerBound.isSatisfied_iff, init?] at this hrb ⊢
|
||||
obtain ⟨init, hi⟩ := hrb
|
||||
obtain ⟨b', hb'⟩ := this
|
||||
refine ⟨init, hi.1, UpwardEnumerable.le_trans hi.2 (UpwardEnumerable.le_trans ?_ hb'.2)⟩
|
||||
exact UpwardEnumerable.le_of_succ?_eq hb'.1
|
||||
|
||||
theorem SupportsLowerBound.isSatisfied_init? {sl} [UpwardEnumerable α]
|
||||
public theorem SupportsLowerBound.isSatisfied_init? {sl} [UpwardEnumerable α]
|
||||
[SupportsLowerBound sl α] [BoundedUpwardEnumerable sl α] [LawfulUpwardEnumerable α]
|
||||
[LawfulUpwardEnumerableLowerBound sl α]
|
||||
{bound : Bound sl α} {a : α} (h : BoundedUpwardEnumerable.init? bound = some a) :
|
||||
{bound : Bound sl α} {a : α} (h : init? bound = some a) :
|
||||
SupportsLowerBound.IsSatisfied bound a := by
|
||||
simp only [LawfulUpwardEnumerableLowerBound.isSatisfied_iff]
|
||||
exact ⟨a, h, UpwardEnumerable.le_refl _⟩
|
||||
|
||||
theorem forIn'_eq_match {sl su} [UpwardEnumerable α]
|
||||
public theorem forIn'_eq_match {sl su} [UpwardEnumerable α]
|
||||
[SupportsUpperBound su α] [SupportsLowerBound sl α] [HasFiniteRanges su α]
|
||||
[BoundedUpwardEnumerable sl α] [LawfulUpwardEnumerable α]
|
||||
[LawfulUpwardEnumerableLowerBound sl α] [LawfulUpwardEnumerableUpperBound su α]
|
||||
@@ -337,7 +368,7 @@ theorem forIn'_eq_match {sl su} [UpwardEnumerable α]
|
||||
{r : PRange ⟨sl, su⟩ α}
|
||||
{γ : Type u} {init : γ} {m : Type u → Type w} [Monad m] [LawfulMonad m]
|
||||
{f : (a : α) → _ → γ → m (ForInStep γ)} :
|
||||
ForIn'.forIn' r init f = match hi : BoundedUpwardEnumerable.init? r.lower with
|
||||
ForIn'.forIn' r init f = match hi : init? r.lower with
|
||||
| none => pure init
|
||||
| some a => if hu : SupportsUpperBound.IsSatisfied r.upper a then do
|
||||
match ← f a ⟨SupportsLowerBound.isSatisfied_init? hi, hu⟩ init with
|
||||
@@ -362,7 +393,7 @@ theorem forIn'_eq_match {sl su} [UpwardEnumerable α]
|
||||
· simp
|
||||
· simp
|
||||
|
||||
instance {su} [UpwardEnumerable α] [SupportsUpperBound su α] [RangeSize su α]
|
||||
public instance {su} [UpwardEnumerable α] [SupportsUpperBound su α] [RangeSize su α]
|
||||
[LawfulUpwardEnumerable α] [HasFiniteRanges su α] [LawfulRangeSize su α] :
|
||||
LawfulIteratorSize (RangeIterator su α) where
|
||||
size_eq_size_toArray {it} := by
|
||||
@@ -400,7 +431,7 @@ instance {su} [UpwardEnumerable α] [SupportsUpperBound su α] [RangeSize su α]
|
||||
· have := LawfulRangeSize.size_eq_zero_of_not_isSatisfied _ _ h'
|
||||
simp [*] at this
|
||||
|
||||
theorem isEmpty_iff_forall_not_mem {sl su} [UpwardEnumerable α] [LawfulUpwardEnumerable α]
|
||||
public theorem isEmpty_iff_forall_not_mem {sl su} [UpwardEnumerable α] [LawfulUpwardEnumerable α]
|
||||
[BoundedUpwardEnumerable sl α] [SupportsLowerBound sl α] [SupportsUpperBound su α]
|
||||
[LawfulUpwardEnumerableLowerBound sl α] [LawfulUpwardEnumerableUpperBound su α]
|
||||
{r : PRange ⟨sl, su⟩ α} :
|
||||
@@ -422,6 +453,6 @@ theorem isEmpty_iff_forall_not_mem {sl su} [UpwardEnumerable α] [LawfulUpwardEn
|
||||
intro hu
|
||||
have hl := SupportsLowerBound.isSatisfied_init? (bound := r.lower)
|
||||
(Option.some_get hi).symm
|
||||
exact h ((BoundedUpwardEnumerable.init? r.lower).get hi) ⟨hl, hu⟩
|
||||
exact h ((init? r.lower).get hi) ⟨hl, hu⟩
|
||||
|
||||
end Std.PRange
|
||||
|
||||
@@ -6,8 +6,11 @@ Authors: Paul Reichert
|
||||
module
|
||||
|
||||
prelude
|
||||
public import Init.Data.Nat.Lemmas
|
||||
public import Init.Data.Range.Polymorphic.Basic
|
||||
import Init.Data.Nat.Lemmas
|
||||
public import Init.Data.Nat.Order
|
||||
public import Init.Data.Range.Polymorphic.Instances
|
||||
public import Init.Data.Order.Classes
|
||||
import Init.Data.Order.Lemmas
|
||||
|
||||
public section
|
||||
|
||||
@@ -20,6 +23,10 @@ instance : UpwardEnumerable Nat where
|
||||
instance : Least? Nat where
|
||||
least? := some 0
|
||||
|
||||
instance : LawfulUpwardEnumerableLeast? Nat where
|
||||
least?_le a := by
|
||||
simpa [Least?.least?] using ⟨a, by simp [UpwardEnumerable.succMany?]⟩
|
||||
|
||||
instance : LawfulUpwardEnumerableLE Nat where
|
||||
le_iff a b := by
|
||||
constructor
|
||||
@@ -30,98 +37,29 @@ instance : LawfulUpwardEnumerableLE Nat where
|
||||
rw [← hn]
|
||||
exact Nat.le_add_right _ _
|
||||
|
||||
instance : LawfulUpwardEnumerableLT Nat where
|
||||
lt_iff a b := by
|
||||
constructor
|
||||
· intro h
|
||||
refine ⟨b - a - 1, ?_⟩
|
||||
simp [UpwardEnumerable.succMany?]
|
||||
rw [Nat.sub_add_cancel, Nat.add_sub_cancel']
|
||||
· exact Nat.le_of_lt h
|
||||
· rwa [Nat.lt_iff_add_one_le, ← Nat.le_sub_iff_add_le'] at h
|
||||
exact Nat.le_trans (Nat.le_succ _) h
|
||||
· rintro ⟨n, hn⟩
|
||||
simp only [UpwardEnumerable.succMany?, Option.some.injEq] at hn
|
||||
rw [← hn]
|
||||
apply Nat.lt_add_of_pos_right
|
||||
apply Nat.zero_lt_succ
|
||||
|
||||
instance : LawfulUpwardEnumerable Nat where
|
||||
succMany?_zero := by simp [UpwardEnumerable.succMany?]
|
||||
succMany?_succ := by simp [UpwardEnumerable.succMany?, UpwardEnumerable.succ?, Nat.add_assoc]
|
||||
ne_of_lt a b hlt := by
|
||||
rw [← LawfulUpwardEnumerableLT.lt_iff] at hlt
|
||||
exact Nat.ne_of_lt hlt
|
||||
have hn := hlt.choose_spec
|
||||
simp only [UpwardEnumerable.succMany?, Option.some.injEq] at hn
|
||||
omega
|
||||
|
||||
instance : LawfulUpwardEnumerableLowerBound .closed Nat where
|
||||
isSatisfied_iff a l := by
|
||||
simp [← LawfulUpwardEnumerableLE.le_iff, BoundedUpwardEnumerable.init?,
|
||||
SupportsLowerBound.IsSatisfied]
|
||||
|
||||
instance : LawfulUpwardEnumerableUpperBound .closed Nat where
|
||||
isSatisfied_of_le u a b hub hab := by
|
||||
rw [← LawfulUpwardEnumerableLE.le_iff] at hab
|
||||
exact Nat.le_trans hab hub
|
||||
|
||||
instance : LawfulUpwardEnumerableLowerBound .open Nat where
|
||||
isSatisfied_iff a l := by
|
||||
simp [← LawfulUpwardEnumerableLE.le_iff, BoundedUpwardEnumerable.init?,
|
||||
SupportsLowerBound.IsSatisfied, UpwardEnumerable.succ?, Nat.lt_iff_add_one_le]
|
||||
|
||||
instance : LawfulUpwardEnumerableUpperBound .open Nat where
|
||||
isSatisfied_of_le u a b hub hab := by
|
||||
rw [← LawfulUpwardEnumerableLE.le_iff] at hab
|
||||
exact Nat.lt_of_le_of_lt hab hub
|
||||
|
||||
instance : LawfulUpwardEnumerableLowerBound .unbounded Nat where
|
||||
isSatisfied_iff a l := by
|
||||
simp [← LawfulUpwardEnumerableLE.le_iff, BoundedUpwardEnumerable.init?,
|
||||
SupportsLowerBound.IsSatisfied, Least?.least?]
|
||||
|
||||
instance : LawfulUpwardEnumerableUpperBound .unbounded Nat where
|
||||
isSatisfied_of_le _ _ _ _ _ := .intro
|
||||
|
||||
instance : LinearlyUpwardEnumerable Nat where
|
||||
eq_of_succ?_eq a b := by simp [UpwardEnumerable.succ?]
|
||||
instance : LawfulUpwardEnumerableLT Nat := inferInstance
|
||||
instance : LawfulUpwardEnumerableLowerBound .closed Nat := inferInstance
|
||||
instance : LawfulUpwardEnumerableUpperBound .closed Nat := inferInstance
|
||||
instance : LawfulUpwardEnumerableLowerBound .open Nat := inferInstance
|
||||
instance : LawfulUpwardEnumerableUpperBound .open Nat := inferInstance
|
||||
instance : LawfulUpwardEnumerableLowerBound .unbounded Nat := inferInstance
|
||||
instance : LawfulUpwardEnumerableUpperBound .unbounded Nat := inferInstance
|
||||
|
||||
instance : InfinitelyUpwardEnumerable Nat where
|
||||
isSome_succ? a := by simp [UpwardEnumerable.succ?]
|
||||
|
||||
private def rangeRev (k : Nat) :=
|
||||
match k with
|
||||
| 0 => []
|
||||
| k + 1 => k :: rangeRev k
|
||||
|
||||
private theorem mem_rangeRev {k l : Nat} (h : l < k) : l ∈ rangeRev k := by
|
||||
induction k
|
||||
case zero => cases h
|
||||
case succ k ih =>
|
||||
rw [rangeRev]
|
||||
by_cases hl : l = k
|
||||
· simp [hl]
|
||||
· apply List.mem_cons_of_mem
|
||||
exact ih (Nat.lt_of_le_of_ne (Nat.le_of_lt_succ h) hl)
|
||||
|
||||
@[no_expose]
|
||||
instance : HasFiniteRanges .closed Nat where
|
||||
finite init u := by
|
||||
refine ⟨u - init + 1, ?_⟩
|
||||
simp only [UpwardEnumerable.succMany?, SupportsUpperBound.IsSatisfied, Nat.not_le,
|
||||
Option.elim_some]
|
||||
omega
|
||||
|
||||
@[no_expose]
|
||||
instance : HasFiniteRanges .open Nat where
|
||||
finite init u := by
|
||||
refine ⟨u - init, ?_⟩
|
||||
simp only [UpwardEnumerable.succMany?, SupportsUpperBound.IsSatisfied, Option.elim_some]
|
||||
omega
|
||||
|
||||
instance : RangeSize .closed Nat where
|
||||
size bound a := bound + 1 - a
|
||||
|
||||
instance : RangeSize .open Nat where
|
||||
size bound a := bound - a
|
||||
instance : RangeSize .open Nat := .openOfClosed
|
||||
|
||||
instance : LawfulRangeSize .closed Nat where
|
||||
size_eq_zero_of_not_isSatisfied upperBound init hu := by
|
||||
@@ -135,17 +73,16 @@ instance : LawfulRangeSize .closed Nat where
|
||||
Option.some.injEq] at hu h ⊢
|
||||
omega
|
||||
|
||||
instance : LawfulRangeSize .open Nat where
|
||||
size_eq_zero_of_not_isSatisfied upperBound init hu := by
|
||||
simp only [SupportsUpperBound.IsSatisfied, RangeSize.size] at hu ⊢
|
||||
omega
|
||||
size_eq_one_of_succ?_eq_none upperBound init hu h := by
|
||||
simp only [UpwardEnumerable.succ?] at h
|
||||
cases h
|
||||
size_eq_succ_of_succ?_eq_some upperBound init hu h := by
|
||||
simp only [SupportsUpperBound.IsSatisfied, RangeSize.size, UpwardEnumerable.succ?,
|
||||
Option.some.injEq] at hu h ⊢
|
||||
omega
|
||||
instance : LawfulRangeSize .open Nat := inferInstance
|
||||
instance : HasFiniteRanges .closed Nat := inferInstance
|
||||
instance : HasFiniteRanges .open Nat := inferInstance
|
||||
instance : LinearlyUpwardEnumerable Nat := by
|
||||
exact instLinearlyUpwardEnumerableOfTotalLeOfLawfulUpwardEnumerableOfLawfulUpwardEnumerableLE
|
||||
|
||||
/-!
|
||||
The following instances are used for the implementation of array slices a.k.a. `Subarray`.
|
||||
See also `Init.Data.Slice.Array`.
|
||||
-/
|
||||
|
||||
instance : ClosedOpenIntersection ⟨.open, .open⟩ Nat where
|
||||
intersection r s := PRange.mk (max (r.lower + 1) s.lower) (min r.upper s.upper)
|
||||
|
||||
@@ -13,13 +13,16 @@ public section
|
||||
|
||||
namespace Std.PRange.Nat
|
||||
|
||||
theorem succ_eq {n : Nat} : UpwardEnumerable.succ n = n + 1 :=
|
||||
theorem succ_eq {n : Nat} : succ n = n + 1 :=
|
||||
rfl
|
||||
|
||||
theorem ClosedOpen.toList_succ_succ {m n : Nat} :
|
||||
((m+1)...(n+1)).toList =
|
||||
(m...n).toList.map (· + 1) := by
|
||||
theorem toList_Rco_succ_succ {m n : Nat} :
|
||||
((m+1)...(n+1)).toList = (m...n).toList.map (· + 1) := by
|
||||
simp only [← succ_eq]
|
||||
rw [Std.PRange.ClosedOpen.toList_succ_succ_eq_map]
|
||||
rw [Std.PRange.toList_Rco_succ_succ_eq_map]
|
||||
|
||||
@[deprecated toList_Rco_succ_succ (since := "2025-08-22")]
|
||||
theorem ClosedOpen.toList_succ_succ {m n : Nat} :
|
||||
((m+1)...(n+1)).toList = (m...n).toList.map (· + 1) := toList_Rco_succ_succ
|
||||
|
||||
end Std.PRange.Nat
|
||||
|
||||
@@ -53,14 +53,16 @@ A range of elements of some type `α`. It is characterized by its upper and lowe
|
||||
may be inclusive, exclusive or absent.
|
||||
|
||||
* `a...=b` is the range of elements greater than or equal to `a` and less than or equal to `b`.
|
||||
* `a<...=b` is the range of elements greater than `a` and less than or equal to `b`.
|
||||
* `a...b` or `a...<b` is the range of elements greater than or equal to `a` and less than `b`.
|
||||
* `a...*` is the range of elements greater than or equal to `a`.
|
||||
* `a<...=b` is the range of elements greater than `a` and less than or equal to `b`.
|
||||
* `a<...b` or `a<...<b` is the range of elements greater than `a` and less than `b`.
|
||||
* `a<...*` is the range of elements greater than `a`.
|
||||
* `*...=b` is the range of elements less than or equal to `b`.
|
||||
* `*...b` or `*...<b` is the range of elements less than `b`.
|
||||
* `a...*` is the range of elements greater than or equal to `a`.
|
||||
* `a<...*` is the range of elements greater than `a`.
|
||||
* `*...*` contains all elements of `α`.
|
||||
|
||||
The recommended spelling for these ranges can be found in the `PRange.mk` constructor's docstring.
|
||||
-/
|
||||
structure _root_.Std.PRange (shape : RangeShape) (α : Type u) where
|
||||
/-- The lower bound of the range. -/
|
||||
@@ -68,6 +70,14 @@ structure _root_.Std.PRange (shape : RangeShape) (α : Type u) where
|
||||
/-- The upper bound of the range. -/
|
||||
upper : Bound shape.upper α
|
||||
|
||||
/--
|
||||
Creates a new range. For more information about ranges, see `Std.PRange`.
|
||||
|
||||
The implicit `shape` parameter specifies the shape of the explicitly given
|
||||
lower and upper bounds.
|
||||
-/
|
||||
add_decl_doc _root_.Std.PRange.mk
|
||||
|
||||
/-- `a...*` is the range of elements greater than or equal to `a`. See also `Std.PRange`. -/
|
||||
syntax:max (term "...*") : term
|
||||
/-- `*...*` is the range that is unbounded in both directions. See also `Std.PRange`. -/
|
||||
@@ -125,6 +135,27 @@ macro_rules
|
||||
| `($a<...<$b) => ``(PRange.mk (shape := RangeShape.mk BoundShape.open BoundShape.open) $a $b)
|
||||
| `($a<...$b) => ``(PRange.mk (shape := RangeShape.mk BoundShape.open BoundShape.open) $a $b)
|
||||
|
||||
recommended_spelling "Rcc" for "a...=b" in [PRange.mk, «term_...=_»]
|
||||
recommended_spelling "Rco" for "a...b" in [PRange.mk, «term_..._», «term_...<_»]
|
||||
recommended_spelling "Rco" for "a...<b" in [«term_...<_»]
|
||||
recommended_spelling "Rci" for "a...*" in [PRange.mk, «term_...*»]
|
||||
recommended_spelling "Roc" for "a<...=b" in [PRange.mk, «term_<...=_»]
|
||||
recommended_spelling "Roo" for "a<...b" in [PRange.mk, «term_<..._», «term_<...<_»]
|
||||
recommended_spelling "Roo" for "a<...<b" in [«term_<...<_»]
|
||||
recommended_spelling "Roi" for "a<...*" in [PRange.mk, «term_<...*»]
|
||||
recommended_spelling "Ric" for "*...=b" in [PRange.mk, «term*...=_»]
|
||||
recommended_spelling "Rio" for "*...b" in [PRange.mk, «term*..._», «term*...<_»]
|
||||
recommended_spelling "Rio" for "*...<b" in [«term*...<_»]
|
||||
recommended_spelling "Rii" for "*...*" in [PRange.mk, «term*...*»]
|
||||
|
||||
recommended_spelling "Rcx" for "PRange.mk .closed ub" in [PRange.mk]
|
||||
recommended_spelling "Rox" for "PRange.mk .open ub" in [PRange.mk]
|
||||
recommended_spelling "Rix" for "PRange.mk .unbounded ub" in [PRange.mk]
|
||||
recommended_spelling "Rxc" for "PRange.mk lb .closed" in [PRange.mk]
|
||||
recommended_spelling "Rxo" for "PRange.mk lb .open" in [PRange.mk]
|
||||
recommended_spelling "Rxi" for "PRange.mk lb .unbounded" in [PRange.mk]
|
||||
recommended_spelling "Rxx" for "PRange.mk lb ub" in [PRange.mk]
|
||||
|
||||
/--
|
||||
This typeclass provides decidable lower bound checks of the given shape.
|
||||
|
||||
@@ -138,6 +169,8 @@ class SupportsLowerBound (shape : BoundShape) (α : Type u) where
|
||||
IsSatisfied : Bound shape α → α → Prop
|
||||
decidableSatisfiesLowerBound : DecidableRel IsSatisfied := by infer_instance
|
||||
|
||||
attribute [simp] SupportsLowerBound.IsSatisfied
|
||||
|
||||
instance : SupportsLowerBound .unbounded α where
|
||||
IsSatisfied _ _ := True
|
||||
|
||||
@@ -154,6 +187,8 @@ class SupportsUpperBound (shape : BoundShape) (α : Type u) where
|
||||
IsSatisfied : Bound shape α → α → Prop
|
||||
decidableSatisfiesUpperBound : DecidableRel IsSatisfied := by infer_instance
|
||||
|
||||
attribute [simp] SupportsUpperBound.IsSatisfied
|
||||
|
||||
instance {α} : SupportsUpperBound .unbounded α where
|
||||
IsSatisfied _ _ := True
|
||||
|
||||
@@ -192,6 +227,9 @@ Instances are automatically generated in the following cases:
|
||||
class BoundedUpwardEnumerable (lowerBoundShape : BoundShape) (α : Type u) where
|
||||
init? : Bound lowerBoundShape α → Option α
|
||||
|
||||
attribute [simp] BoundedUpwardEnumerable.init?
|
||||
export BoundedUpwardEnumerable (init?)
|
||||
|
||||
/--
|
||||
This typeclass ensures that the lower bound predicate from `SupportsLowerBound sl α`
|
||||
can be characterized in terms of `UpwardEnumerable α` and `BoundedUpwardEnumerable sl α`.
|
||||
@@ -200,11 +238,10 @@ class LawfulUpwardEnumerableLowerBound (sl α) [UpwardEnumerable α]
|
||||
[SupportsLowerBound sl α] [BoundedUpwardEnumerable sl α] where
|
||||
/--
|
||||
An element `a` satisfies the lower bound `l` if and only if it is
|
||||
`BoundedUpwardEnumerable.init? l` or one of its transitive successors.
|
||||
`init? l` or one of its transitive successors.
|
||||
-/
|
||||
isSatisfied_iff (a : α) (l : Bound sl α) :
|
||||
SupportsLowerBound.IsSatisfied l a ↔
|
||||
∃ init, BoundedUpwardEnumerable.init? l = some init ∧ UpwardEnumerable.LE init a
|
||||
SupportsLowerBound.IsSatisfied l a ↔ ∃ init, init? l = some init ∧ UpwardEnumerable.LE init a
|
||||
|
||||
/--
|
||||
This typeclass ensures that if `b` is a transitive successor of `a` and `b` satisfies an upper bound
|
||||
|
||||
@@ -251,14 +251,14 @@ private def RangeIterator.instFinitenessRelation [UpwardEnumerable α] [Supports
|
||||
obtain ⟨n, hn⟩ := HasFiniteRanges.finite init bound
|
||||
induction n generalizing init with
|
||||
| zero =>
|
||||
simp only [UpwardEnumerable.succMany?_zero, Option.elim_some] at hn
|
||||
simp only [succMany?_zero, Option.elim_some] at hn
|
||||
constructor
|
||||
simp [hn, IterStep.successor]
|
||||
| succ n ih =>
|
||||
constructor
|
||||
rintro it'
|
||||
simp only [LawfulUpwardEnumerable.succMany?_succ_eq_succ?_bind_succMany?] at hn
|
||||
match hs : UpwardEnumerable.succ? init with
|
||||
simp only [succMany?_succ?_eq_succ?_bind_succMany?] at hn
|
||||
match hs : succ? init with
|
||||
| none =>
|
||||
simp only [hs]
|
||||
intro h
|
||||
@@ -316,7 +316,7 @@ instance RangeIterator.instIteratorAccess {su} [UpwardEnumerable α] [SupportsUp
|
||||
· split <;> rename_i heq
|
||||
· apply IterM.IsPlausibleNthOutputStep.done
|
||||
simp only [Monadic.isPlausibleStep_iff, Monadic.step]
|
||||
simp only [Option.bind_eq_none_iff, UpwardEnumerable.succMany?_zero, reduceCtorEq,
|
||||
simp only [Option.bind_eq_none_iff, succMany?_zero, reduceCtorEq,
|
||||
imp_false] at heq
|
||||
cases heq' : it.internalState.next
|
||||
· simp
|
||||
@@ -325,7 +325,7 @@ instance RangeIterator.instIteratorAccess {su} [UpwardEnumerable α] [SupportsUp
|
||||
exact heq _ rfl
|
||||
· cases heq' : it.internalState.next
|
||||
· simp [heq'] at heq
|
||||
simp only [heq', Option.bind_some, UpwardEnumerable.succMany?_zero, Option.some.injEq] at heq
|
||||
simp only [heq', Option.bind_some, succMany?_zero, Option.some.injEq] at heq
|
||||
cases heq
|
||||
split <;> rename_i heq''
|
||||
· apply IterM.IsPlausibleNthOutputStep.zero_yield
|
||||
@@ -338,7 +338,7 @@ instance RangeIterator.instIteratorAccess {su} [UpwardEnumerable α] [SupportsUp
|
||||
· apply IterM.IsPlausibleNthOutputStep.done
|
||||
simp only [Monadic.isPlausibleStep_iff, Monadic.step, heq']
|
||||
· rename_i out
|
||||
simp only [heq', Option.bind_some, LawfulUpwardEnumerable.succMany?_succ_eq_succ?_bind_succMany?] at heq
|
||||
simp only [heq', Option.bind_some, succMany?_succ?_eq_succ?_bind_succMany?] at heq
|
||||
specialize ih ⟨⟨UpwardEnumerable.succ? out, it.internalState.upperBound⟩⟩
|
||||
simp only [heq] at ih
|
||||
by_cases heq'' : SupportsUpperBound.IsSatisfied it.internalState.upperBound out
|
||||
@@ -354,7 +354,7 @@ instance RangeIterator.instIteratorAccess {su} [UpwardEnumerable α] [SupportsUp
|
||||
rename_i out
|
||||
simp only [heq', Option.bind_some] at heq
|
||||
have hle : UpwardEnumerable.LE out _ := ⟨n + 1, heq⟩
|
||||
simp only [LawfulUpwardEnumerable.succMany?_succ_eq_succ?_bind_succMany?] at heq
|
||||
simp only [succMany?_succ?_eq_succ?_bind_succMany?] at heq
|
||||
specialize ih ⟨⟨UpwardEnumerable.succ? out, it.internalState.upperBound⟩⟩
|
||||
simp only [heq] at ih
|
||||
by_cases hout : SupportsUpperBound.IsSatisfied it.internalState.upperBound out
|
||||
@@ -378,7 +378,7 @@ theorem RangeIterator.Monadic.isPlausibleIndirectOutput_iff {su α}
|
||||
[LawfulUpwardEnumerable α] [LawfulUpwardEnumerableUpperBound su α]
|
||||
{it : IterM (α := RangeIterator su α) Id α} {out : α} :
|
||||
it.IsPlausibleIndirectOutput out ↔
|
||||
∃ n, it.internalState.next.bind (UpwardEnumerable.succMany? n ·) = some out ∧
|
||||
∃ n, it.internalState.next.bind (succMany? n ·) = some out ∧
|
||||
SupportsUpperBound.IsSatisfied it.internalState.upperBound out := by
|
||||
constructor
|
||||
· intro h
|
||||
@@ -391,7 +391,7 @@ theorem RangeIterator.Monadic.isPlausibleIndirectOutput_iff {su α}
|
||||
obtain ⟨n, hn⟩ := ih
|
||||
obtain ⟨a, ha, h₁, h₂, h₃⟩ := h
|
||||
refine ⟨n + 1, ?_⟩
|
||||
simp [ha, ← h₃, hn.2, LawfulUpwardEnumerable.succMany?_succ_eq_succ?_bind_succMany?, h₂, hn]
|
||||
simp [ha, ← h₃, hn.2, succMany?_succ?_eq_succ?_bind_succMany?, h₂, hn]
|
||||
· rintro ⟨n, hn, hu⟩
|
||||
induction n generalizing it
|
||||
case zero =>
|
||||
@@ -404,8 +404,8 @@ theorem RangeIterator.Monadic.isPlausibleIndirectOutput_iff {su α}
|
||||
rename_i a
|
||||
simp only [hn', Option.bind_some] at hn
|
||||
have hle : UpwardEnumerable.LE a out := ⟨_, hn⟩
|
||||
rw [LawfulUpwardEnumerable.succMany?_succ_eq_succ?_bind_succMany?] at hn
|
||||
cases hn' : UpwardEnumerable.succ? a
|
||||
rw [succMany?_succ?_eq_succ?_bind_succMany?] at hn
|
||||
cases hn' : succ? a
|
||||
· simp only [hn', Option.bind_none, reduceCtorEq] at hn
|
||||
rename_i a'
|
||||
simp only [hn', Option.bind_some] at hn
|
||||
@@ -422,7 +422,7 @@ theorem RangeIterator.isPlausibleIndirectOutput_iff {su α}
|
||||
[LawfulUpwardEnumerable α] [LawfulUpwardEnumerableUpperBound su α]
|
||||
{it : Iter (α := RangeIterator su α) α} {out : α} :
|
||||
it.IsPlausibleIndirectOutput out ↔
|
||||
∃ n, it.internalState.next.bind (UpwardEnumerable.succMany? n ·) = some out ∧
|
||||
∃ n, it.internalState.next.bind (succMany? n ·) = some out ∧
|
||||
SupportsUpperBound.IsSatisfied it.internalState.upperBound out := by
|
||||
simp only [Iter.isPlausibleIndirectOutput_iff_isPlausibleIndirectOutput_toIterM,
|
||||
Monadic.isPlausibleIndirectOutput_iff, Iter.toIterM]
|
||||
@@ -476,7 +476,7 @@ instance RangeIterator.instIteratorLoop {su} [UpwardEnumerable α] [SupportsUppe
|
||||
exact UpwardEnumerable.le_refl _
|
||||
case hle' =>
|
||||
refine UpwardEnumerable.le_trans hl ⟨1, ?_⟩
|
||||
simp [UpwardEnumerable.succMany?_one, hs]
|
||||
simp [succMany?_one, hs]
|
||||
|
||||
partial instance RepeatIterator.instIteratorLoopPartial {su} [UpwardEnumerable α]
|
||||
[SupportsUpperBound su α] [LawfulUpwardEnumerable α] [LawfulUpwardEnumerableUpperBound su α]
|
||||
@@ -496,7 +496,7 @@ partial instance RepeatIterator.instIteratorLoopPartial {su} [UpwardEnumerable
|
||||
(next : α) (hl : UpwardEnumerable.LE least next) (hu : SupportsUpperBound.IsSatisfied upperBound next) : n γ := do
|
||||
match ← f next hl hu acc with
|
||||
| .yield acc' =>
|
||||
match hs : UpwardEnumerable.succ? next with
|
||||
match hs : succ? next with
|
||||
| some next' =>
|
||||
if hu : SupportsUpperBound.IsSatisfied upperBound next' then
|
||||
loop γ upperBound least acc' f next' ?hle' hu
|
||||
@@ -513,10 +513,10 @@ partial instance RepeatIterator.instIteratorLoopPartial {su} [UpwardEnumerable
|
||||
exact UpwardEnumerable.le_refl _
|
||||
case hle' =>
|
||||
refine UpwardEnumerable.le_trans hl ⟨1, ?_⟩
|
||||
simp [UpwardEnumerable.succMany?_one, hs]
|
||||
simp [succMany?_one, hs]
|
||||
|
||||
theorem RangeIterator.instIteratorLoop.loop_eq {su} [UpwardEnumerable α] [SupportsUpperBound su α]
|
||||
[LawfulUpwardEnumerable α] [LawfulUpwardEnumerableUpperBound su α]
|
||||
theorem RangeIterator.instIteratorLoop.loop_eq {su} [UpwardEnumerable α]
|
||||
[SupportsUpperBound su α] [LawfulUpwardEnumerable α] [LawfulUpwardEnumerableUpperBound su α]
|
||||
{n : Type u → Type w} [Monad n] [LawfulMonad n] {γ : Type u}
|
||||
{lift} [Internal.LawfulMonadLiftBindFunction lift]
|
||||
{PlausibleForInStep} {upperBound} {next} {hl} {hu} {f} {acc} {wf} :
|
||||
@@ -524,16 +524,18 @@ theorem RangeIterator.instIteratorLoop.loop_eq {su} [UpwardEnumerable α] [Suppo
|
||||
(do
|
||||
match ← f next hl hu acc with
|
||||
| ⟨.yield c, _⟩ =>
|
||||
letI it' : IterM (α := RangeIterator su α) Id α := ⟨⟨UpwardEnumerable.succ? next, upperBound⟩⟩
|
||||
letI it' : IterM (α := RangeIterator su α) Id α := ⟨⟨succ? next, upperBound⟩⟩
|
||||
IterM.DefaultConsumers.forIn' (m := Id) lift γ
|
||||
PlausibleForInStep wf it' c it'.IsPlausibleIndirectOutput (fun _ => id)
|
||||
(fun b h c => f b
|
||||
(by
|
||||
refine UpwardEnumerable.le_trans hl ?_
|
||||
simp only [RangeIterator.Monadic.isPlausibleIndirectOutput_iff, it',
|
||||
← LawfulUpwardEnumerable.succMany?_succ_eq_succ?_bind_succMany?] at h
|
||||
← succMany?_succ?_eq_succ?_bind_succMany?] at h
|
||||
exact ⟨h.choose + 1, h.choose_spec.1⟩)
|
||||
(by simp only [RangeIterator.Monadic.isPlausibleIndirectOutput_iff, it'] at h; exact h.choose_spec.2) c)
|
||||
(by
|
||||
simp only [RangeIterator.Monadic.isPlausibleIndirectOutput_iff, it'] at h
|
||||
exact h.choose_spec.2) c)
|
||||
| ⟨.done c, _⟩ => return c) := by
|
||||
rw [loop]
|
||||
apply bind_congr
|
||||
|
||||
@@ -40,13 +40,16 @@ class UpwardEnumerable (α : Type u) where
|
||||
-/
|
||||
succMany? (n : Nat) (a : α) : Option α := Nat.repeat (· >>= succ?) n (some a)
|
||||
|
||||
attribute [simp] UpwardEnumerable.succ? UpwardEnumerable.succMany?
|
||||
export UpwardEnumerable (succ? succMany?)
|
||||
|
||||
/--
|
||||
According to `UpwardEnumerable.LE`, `a` is less than or equal to `b` if `b` is `a` or a transitive
|
||||
successor of `a`.
|
||||
-/
|
||||
@[expose]
|
||||
def UpwardEnumerable.LE {α : Type u} [UpwardEnumerable α] (a b : α) : Prop :=
|
||||
∃ n, UpwardEnumerable.succMany? n a = some b
|
||||
protected def UpwardEnumerable.LE {α : Type u} [UpwardEnumerable α] (a b : α) : Prop :=
|
||||
∃ n, succMany? n a = some b
|
||||
|
||||
/--
|
||||
According to `UpwardEnumerable.LT`, `a` is less than `b` if `b` is a proper transitive successor of
|
||||
@@ -55,10 +58,10 @@ According to `UpwardEnumerable.LT`, `a` is less than `b` if `b` is a proper tran
|
||||
Given `LawfulUpwardEnumerable α`, no element of `α` is less than itself.
|
||||
-/
|
||||
@[expose]
|
||||
def UpwardEnumerable.LT {α : Type u} [UpwardEnumerable α] (a b : α) : Prop :=
|
||||
∃ n, UpwardEnumerable.succMany? (n + 1) a = some b
|
||||
protected def UpwardEnumerable.LT {α : Type u} [UpwardEnumerable α] (a b : α) : Prop :=
|
||||
∃ n, succMany? (n + 1) a = some b
|
||||
|
||||
theorem UpwardEnumerable.le_of_lt {α : Type u} [UpwardEnumerable α] {a b : α}
|
||||
protected theorem UpwardEnumerable.le_of_lt {α : Type u} [UpwardEnumerable α] {a b : α}
|
||||
(h : UpwardEnumerable.LT a b) : UpwardEnumerable.LE a b :=
|
||||
⟨h.choose + 1, h.choose_spec⟩
|
||||
|
||||
@@ -77,6 +80,9 @@ class Least? (α : Type u) where
|
||||
-/
|
||||
least? : Option α
|
||||
|
||||
attribute [simp] Least?.least?
|
||||
export Least? (least?)
|
||||
|
||||
/--
|
||||
This typeclass ensures that an `UpwardEnumerable α` instance is well-behaved.
|
||||
-/
|
||||
@@ -84,99 +90,110 @@ class LawfulUpwardEnumerable (α : Type u) [UpwardEnumerable α] where
|
||||
/-- There is no cyclic chain of successors. -/
|
||||
ne_of_lt (a b : α) : UpwardEnumerable.LT a b → a ≠ b
|
||||
/-- The `0`-th successor of `a` is `a` itself. -/
|
||||
succMany?_zero (a : α) : UpwardEnumerable.succMany? 0 a = some a
|
||||
succMany?_zero (a : α) : succMany? 0 a = some a
|
||||
/--
|
||||
The `n + 1`-th successor of `a` is the successor of the `n`-th successor, given that said
|
||||
successors actually exist.
|
||||
-/
|
||||
succMany?_succ (n : Nat) (a : α) :
|
||||
UpwardEnumerable.succMany? (n + 1) a = (UpwardEnumerable.succMany? n a).bind UpwardEnumerable.succ?
|
||||
succMany? (n + 1) a = (succMany? n a).bind succ?
|
||||
|
||||
theorem UpwardEnumerable.succMany?_zero [UpwardEnumerable α] [LawfulUpwardEnumerable α] {a : α} :
|
||||
UpwardEnumerable.succMany? 0 a = some a :=
|
||||
succMany? 0 a = some a :=
|
||||
LawfulUpwardEnumerable.succMany?_zero a
|
||||
|
||||
theorem UpwardEnumerable.succMany?_succ [UpwardEnumerable α] [LawfulUpwardEnumerable α]
|
||||
theorem UpwardEnumerable.succMany?_succ? [UpwardEnumerable α] [LawfulUpwardEnumerable α]
|
||||
{n : Nat} {a : α} :
|
||||
UpwardEnumerable.succMany? (n + 1) a =
|
||||
(UpwardEnumerable.succMany? n a).bind UpwardEnumerable.succ? :=
|
||||
succMany? (n + 1) a = (succMany? n a).bind succ? :=
|
||||
LawfulUpwardEnumerable.succMany?_succ n a
|
||||
|
||||
@[deprecated succMany?_succ? (since := "2025-09-03")]
|
||||
theorem UpwardEnumerable.succMany?_succ [UpwardEnumerable α] [LawfulUpwardEnumerable α]
|
||||
{n : Nat} {a : α} :
|
||||
succMany? (n + 1) a = (succMany? n a).bind succ? :=
|
||||
succMany?_succ?
|
||||
|
||||
theorem UpwardEnumerable.succMany?_one [UpwardEnumerable α] [LawfulUpwardEnumerable α] {a : α} :
|
||||
UpwardEnumerable.succMany? 1 a = UpwardEnumerable.succ? a := by
|
||||
simp [UpwardEnumerable.succMany?_succ, UpwardEnumerable.succMany?_zero]
|
||||
succMany? 1 a = succ? a := by
|
||||
simp [succMany?_succ?, succMany?_zero]
|
||||
|
||||
theorem UpwardEnumerable.succMany?_add [UpwardEnumerable α] [LawfulUpwardEnumerable α]
|
||||
(m n : Nat) (a : α) :
|
||||
UpwardEnumerable.succMany? (m + n) a =
|
||||
(UpwardEnumerable.succMany? m a).bind (UpwardEnumerable.succMany? n ·) := by
|
||||
{m n : Nat} {a : α} :
|
||||
succMany? (m + n) a = (succMany? m a).bind (succMany? n ·) := by
|
||||
induction n
|
||||
case zero => simp [LawfulUpwardEnumerable.succMany?_zero]
|
||||
case zero => simp [succMany?_zero]
|
||||
case succ n ih =>
|
||||
rw [← Nat.add_assoc, LawfulUpwardEnumerable.succMany?_succ, ih, Option.bind_assoc]
|
||||
simp only [LawfulUpwardEnumerable.succMany?_succ]
|
||||
rw [← Nat.add_assoc, succMany?_succ?, ih, Option.bind_assoc]
|
||||
simp [succMany?_succ?]
|
||||
|
||||
theorem UpwardEnumerable.succMany?_succ?_eq_succ?_bind_succMany?
|
||||
[UpwardEnumerable α] [LawfulUpwardEnumerable α]
|
||||
{n : Nat} {a : α} :
|
||||
succMany? (n + 1) a = (succ? a).bind (succMany? n ·) := by
|
||||
rw [Nat.add_comm]
|
||||
simp [succMany?_add, succMany?_succ?, succMany?_zero]
|
||||
|
||||
@[deprecated UpwardEnumerable.succMany?_succ?_eq_succ?_bind_succMany? (since := "2025-09-03")]
|
||||
theorem LawfulUpwardEnumerable.succMany?_succ_eq_succ?_bind_succMany?
|
||||
[UpwardEnumerable α] [LawfulUpwardEnumerable α]
|
||||
(n : Nat) (a : α) :
|
||||
UpwardEnumerable.succMany? (n + 1) a =
|
||||
(UpwardEnumerable.succ? a).bind (UpwardEnumerable.succMany? n ·) := by
|
||||
rw [Nat.add_comm]
|
||||
simp [UpwardEnumerable.succMany?_add, LawfulUpwardEnumerable.succMany?_succ,
|
||||
LawfulUpwardEnumerable.succMany?_zero]
|
||||
succMany? (n + 1) a = (succ? a).bind (succMany? n ·) :=
|
||||
UpwardEnumerable.succMany?_succ?_eq_succ?_bind_succMany?
|
||||
|
||||
theorem UpwardEnumerable.le_refl {α : Type u} [UpwardEnumerable α] [LawfulUpwardEnumerable α]
|
||||
(a : α) : UpwardEnumerable.LE a a :=
|
||||
⟨0, LawfulUpwardEnumerable.succMany?_zero a⟩
|
||||
export UpwardEnumerable (succMany?_zero succMany?_succ? succMany?_one succMany?_add
|
||||
succMany?_succ?_eq_succ?_bind_succMany?)
|
||||
|
||||
theorem UpwardEnumerable.lt_irrefl {α : Type u} [UpwardEnumerable α] [LawfulUpwardEnumerable α]
|
||||
{a : α} : ¬ UpwardEnumerable.LT a a :=
|
||||
protected theorem UpwardEnumerable.le_refl {α : Type u} [UpwardEnumerable α]
|
||||
[LawfulUpwardEnumerable α] (a : α) : UpwardEnumerable.LE a a :=
|
||||
⟨0, succMany?_zero⟩
|
||||
|
||||
protected theorem UpwardEnumerable.lt_irrefl {α : Type u} [UpwardEnumerable α]
|
||||
[LawfulUpwardEnumerable α] {a : α} : ¬ UpwardEnumerable.LT a a :=
|
||||
fun h => LawfulUpwardEnumerable.ne_of_lt a a h rfl
|
||||
|
||||
theorem UpwardEnumerable.le_trans {α : Type u} [UpwardEnumerable α] [LawfulUpwardEnumerable α]
|
||||
{a b c : α} (hab : UpwardEnumerable.LE a b) (hbc : UpwardEnumerable.LE b c) :
|
||||
UpwardEnumerable.LE a c := by
|
||||
protected theorem UpwardEnumerable.ne_of_lt {α : Type u} [UpwardEnumerable α]
|
||||
[LawfulUpwardEnumerable α] {a b : α} (h : UpwardEnumerable.LT a b) : a ≠ b :=
|
||||
LawfulUpwardEnumerable.ne_of_lt a b h
|
||||
|
||||
protected theorem UpwardEnumerable.le_trans {α : Type u} [UpwardEnumerable α]
|
||||
[LawfulUpwardEnumerable α] {a b c : α} (hab : UpwardEnumerable.LE a b)
|
||||
(hbc : UpwardEnumerable.LE b c) : UpwardEnumerable.LE a c := by
|
||||
refine ⟨hab.choose + hbc.choose, ?_⟩
|
||||
simp [succMany?_add, hab.choose_spec, hbc.choose_spec]
|
||||
|
||||
theorem UpwardEnumerable.le_of_succ?_eq {α : Type u} [UpwardEnumerable α] [LawfulUpwardEnumerable α]
|
||||
{a b : α} (hab : UpwardEnumerable.succ? a = some b) : UpwardEnumerable.LE a b :=
|
||||
⟨1, by simp [UpwardEnumerable.succMany?_one, hab]⟩
|
||||
⟨1, by simp [succMany?_one, hab]⟩
|
||||
|
||||
theorem UpwardEnumerable.lt_of_lt_of_le {α : Type u} [UpwardEnumerable α] [LawfulUpwardEnumerable α]
|
||||
{a b c : α} (hab : UpwardEnumerable.LT a b) (hbc : UpwardEnumerable.LE b c) :
|
||||
UpwardEnumerable.LT a c := by
|
||||
protected theorem UpwardEnumerable.lt_of_lt_of_le {α : Type u} [UpwardEnumerable α]
|
||||
[LawfulUpwardEnumerable α] {a b c : α} (hab : UpwardEnumerable.LT a b)
|
||||
(hbc : UpwardEnumerable.LE b c) : UpwardEnumerable.LT a c := by
|
||||
refine ⟨hab.choose + hbc.choose, ?_⟩
|
||||
rw [Nat.add_right_comm, succMany?_add, hab.choose_spec, Option.bind_some, hbc.choose_spec]
|
||||
|
||||
theorem UpwardEnumerable.lt_of_le_of_lt {α : Type u} [UpwardEnumerable α] [LawfulUpwardEnumerable α]
|
||||
{a b c : α} (hab : UpwardEnumerable.LE a b) (hbc : UpwardEnumerable.LT b c) :
|
||||
UpwardEnumerable.LT a c := by
|
||||
protected theorem UpwardEnumerable.lt_of_le_of_lt {α : Type u} [UpwardEnumerable α]
|
||||
[LawfulUpwardEnumerable α] {a b c : α} (hab : UpwardEnumerable.LE a b)
|
||||
(hbc : UpwardEnumerable.LT b c) : UpwardEnumerable.LT a c := by
|
||||
refine ⟨hab.choose + hbc.choose, ?_⟩
|
||||
rw [Nat.add_assoc, succMany?_add, hab.choose_spec, Option.bind_some, hbc.choose_spec]
|
||||
|
||||
theorem UpwardEnumerable.not_gt_of_le {α : Type u} [UpwardEnumerable α] [LawfulUpwardEnumerable α]
|
||||
{a b : α} :
|
||||
protected theorem UpwardEnumerable.not_gt_of_le {α : Type u} [UpwardEnumerable α]
|
||||
[LawfulUpwardEnumerable α] {a b : α} :
|
||||
UpwardEnumerable.LE a b → ¬ UpwardEnumerable.LT b a := by
|
||||
rintro ⟨n, hle⟩ ⟨m, hgt⟩
|
||||
have : UpwardEnumerable.LT a a := by
|
||||
refine ⟨n + m, ?_⟩
|
||||
rw [Nat.add_assoc, UpwardEnumerable.succMany?_add, hle, Option.bind_some, hgt]
|
||||
exact LawfulUpwardEnumerable.ne_of_lt _ _ this rfl
|
||||
rw [Nat.add_assoc, succMany?_add, hle, Option.bind_some, hgt]
|
||||
exact UpwardEnumerable.ne_of_lt this rfl
|
||||
|
||||
theorem UpwardEnumerable.not_ge_of_lt {α : Type u} [UpwardEnumerable α] [LawfulUpwardEnumerable α]
|
||||
{a b : α} :
|
||||
protected theorem UpwardEnumerable.not_ge_of_lt {α : Type u} [UpwardEnumerable α]
|
||||
[LawfulUpwardEnumerable α] {a b : α} :
|
||||
UpwardEnumerable.LT a b → ¬ UpwardEnumerable.LE b a :=
|
||||
flip not_gt_of_le
|
||||
flip UpwardEnumerable.not_gt_of_le
|
||||
|
||||
theorem UpwardEnumerable.not_gt_of_lt {α : Type u} [UpwardEnumerable α] [LawfulUpwardEnumerable α]
|
||||
{a b : α} (h : UpwardEnumerable.LT a b) : ¬ UpwardEnumerable.LT b a :=
|
||||
not_gt_of_le (le_of_lt h)
|
||||
|
||||
theorem UpwardEnumerable.ne_of_lt {α : Type w} [UpwardEnumerable α] [LawfulUpwardEnumerable α]
|
||||
{a b : α} :
|
||||
UpwardEnumerable.LT a b → a ≠ b :=
|
||||
LawfulUpwardEnumerable.ne_of_lt a b
|
||||
protected theorem UpwardEnumerable.not_gt_of_lt {α : Type u} [UpwardEnumerable α]
|
||||
[LawfulUpwardEnumerable α] {a b : α} (h : UpwardEnumerable.LT a b) : ¬ UpwardEnumerable.LT b a :=
|
||||
UpwardEnumerable.not_gt_of_le (UpwardEnumerable.le_of_lt h)
|
||||
|
||||
/--
|
||||
This propositional typeclass ensures that `UpwardEnumerable.succ?` will never return `none`.
|
||||
@@ -192,15 +209,23 @@ class LinearlyUpwardEnumerable (α : Type u) [UpwardEnumerable α] where
|
||||
eq_of_succ?_eq : ∀ a b : α, UpwardEnumerable.succ? a = UpwardEnumerable.succ? b → a = b
|
||||
|
||||
theorem UpwardEnumerable.isSome_succ? {α : Type u} [UpwardEnumerable α]
|
||||
[InfinitelyUpwardEnumerable α] {a : α} :
|
||||
(succ? a).isSome :=
|
||||
[InfinitelyUpwardEnumerable α] {a : α} : (succ? a).isSome :=
|
||||
InfinitelyUpwardEnumerable.isSome_succ? a
|
||||
|
||||
theorem UpwardEnumerable.eq_of_succ?_eq {α : Type u} [UpwardEnumerable α]
|
||||
[LinearlyUpwardEnumerable α] {a b : α} (h : succ? a = succ? b) :
|
||||
theorem UpwardEnumerable.succ?_inj {α : Type u} [UpwardEnumerable α] [LinearlyUpwardEnumerable α]
|
||||
{a b : α} (h : succ? a = succ? b) :
|
||||
a = b :=
|
||||
LinearlyUpwardEnumerable.eq_of_succ?_eq a b h
|
||||
|
||||
@[deprecated succ?_inj (since := "2025-09-03")]
|
||||
theorem UpwardEnumerable.eq_of_succ?_eq {α : Type u} [UpwardEnumerable α] [LinearlyUpwardEnumerable α]
|
||||
{a b : α} (h : succ? a = succ? b) :
|
||||
a = b :=
|
||||
succ?_inj h
|
||||
|
||||
/--
|
||||
Maps elements of `α` to their immediate successor.
|
||||
-/
|
||||
@[always_inline, inline]
|
||||
abbrev UpwardEnumerable.succ {α : Type u} [UpwardEnumerable α] [InfinitelyUpwardEnumerable α]
|
||||
(a : α) : α :=
|
||||
@@ -216,17 +241,23 @@ theorem UpwardEnumerable.succ?_eq_some {α : Type u} [UpwardEnumerable α]
|
||||
succ? a = some (succ a) := by
|
||||
simp
|
||||
|
||||
theorem UpwardEnumerable.eq_of_succ_eq {α : Type u} [UpwardEnumerable α]
|
||||
theorem UpwardEnumerable.succ_inj {α : Type u} [UpwardEnumerable α]
|
||||
[InfinitelyUpwardEnumerable α] [LinearlyUpwardEnumerable α] {a b : α}
|
||||
(h : succ a = succ b) : a = b := by
|
||||
rw [succ, succ, ← Option.some.injEq, Option.some_get, Option.some_get] at h
|
||||
exact eq_of_succ?_eq h
|
||||
exact succ?_inj h
|
||||
|
||||
@[deprecated succ_inj (since := "2025-09-03")]
|
||||
theorem UpwardEnumerable.eq_of_succ_eq {α : Type u} [UpwardEnumerable α]
|
||||
[InfinitelyUpwardEnumerable α] [LinearlyUpwardEnumerable α] {a b : α}
|
||||
(h : succ a = succ b) : a = b :=
|
||||
succ_inj h
|
||||
|
||||
theorem UpwardEnumerable.succ_eq_succ_iff {α : Type u} [UpwardEnumerable α]
|
||||
[InfinitelyUpwardEnumerable α] [LinearlyUpwardEnumerable α] {a b : α} :
|
||||
succ a = succ b ↔ a = b := by
|
||||
constructor
|
||||
· apply eq_of_succ_eq
|
||||
· apply succ_inj
|
||||
· exact congrArg succ
|
||||
|
||||
theorem UpwardEnumerable.isSome_succMany? {α : Type u} [UpwardEnumerable α]
|
||||
@@ -235,10 +266,19 @@ theorem UpwardEnumerable.isSome_succMany? {α : Type u} [UpwardEnumerable α]
|
||||
induction n
|
||||
· simp [succMany?_zero]
|
||||
· rename_i ih
|
||||
simp only [succMany?_succ]
|
||||
simp only [succMany?_succ?]
|
||||
rw [← Option.some_get ih, Option.bind_some]
|
||||
apply InfinitelyUpwardEnumerable.isSome_succ?
|
||||
|
||||
/--
|
||||
Maps elements of `α` to their `n`-th successor. This should semantically behave like repeatedly
|
||||
applying `succ`, but it might be more efficient.
|
||||
|
||||
This function uses an `UpwardEnumerable α` instance.
|
||||
`LawfulUpwardEnumerable α` ensures the compatibility with `succ` and `succ?`.
|
||||
|
||||
If no other implementation is provided in UpwardEnumerable instance, succMany? repeatedly applies succ?.
|
||||
-/
|
||||
@[always_inline, inline]
|
||||
def UpwardEnumerable.succMany {α : Type u} [UpwardEnumerable α]
|
||||
[LawfulUpwardEnumerable α] [InfinitelyUpwardEnumerable α]
|
||||
@@ -260,6 +300,11 @@ theorem UpwardEnumerable.succMany?_eq_some_iff_succMany {α : Type u} [UpwardEnu
|
||||
succMany? n a = some b ↔ succMany n a = b := by
|
||||
simp [succMany?_eq_some]
|
||||
|
||||
theorem UpwardEnumerable.succMany_zero {α : Type u} [UpwardEnumerable α]
|
||||
[LawfulUpwardEnumerable α] [InfinitelyUpwardEnumerable α] {a : α} :
|
||||
succMany 0 a = a := by
|
||||
simp [succMany, succMany?_zero]
|
||||
|
||||
theorem UpwardEnumerable.succMany_one {α : Type u} [UpwardEnumerable α]
|
||||
[LawfulUpwardEnumerable α] [InfinitelyUpwardEnumerable α] {a : α} :
|
||||
succMany 1 a = succ a := by
|
||||
@@ -270,43 +315,49 @@ theorem UpwardEnumerable.succMany_add {α : Type u} [UpwardEnumerable α]
|
||||
{m n : Nat} {a : α} : succMany (m + n) a = succMany n (succMany m a) := by
|
||||
simp [succMany, succMany?_add]
|
||||
|
||||
theorem UpwardEnumerable.succ_le_succ_iff {α : Type w} [UpwardEnumerable α] [LawfulUpwardEnumerable α]
|
||||
[LinearlyUpwardEnumerable α] [InfinitelyUpwardEnumerable α] {a b : α} :
|
||||
UpwardEnumerable.LE (UpwardEnumerable.succ a) (UpwardEnumerable.succ b) ↔
|
||||
export UpwardEnumerable (isSome_succ? succ?_inj succ succ_eq_get succ?_eq_some succ_inj
|
||||
succ_eq_succ_iff isSome_succMany? succMany succMany_eq_get
|
||||
succMany?_eq_some succMany?_eq_some_iff_succMany succMany_one succMany_zero
|
||||
succMany_add)
|
||||
|
||||
theorem UpwardEnumerable.succ_le_succ_iff {α : Type w} [UpwardEnumerable α]
|
||||
[LawfulUpwardEnumerable α] [LinearlyUpwardEnumerable α] [InfinitelyUpwardEnumerable α]
|
||||
{a b : α} : UpwardEnumerable.LE (succ a) (succ b) ↔
|
||||
UpwardEnumerable.LE a b := by
|
||||
constructor
|
||||
· rintro ⟨n, hn⟩
|
||||
simp only [succ] at hn
|
||||
refine ⟨n, ?_⟩
|
||||
simp [succMany?_eq_some]
|
||||
apply eq_of_succ?_eq
|
||||
apply succ?_inj
|
||||
rw [← Option.bind_some (f := succMany? n), Option.some_get,
|
||||
← LawfulUpwardEnumerable.succMany?_succ_eq_succ?_bind_succMany?, Option.some_get] at hn
|
||||
rw [← Option.bind_some (f := succ?), ← succMany?_eq_some, ← succMany?_succ, hn]
|
||||
← succMany?_succ?_eq_succ?_bind_succMany?, Option.some_get] at hn
|
||||
rw [← Option.bind_some (f := succ?), ← succMany?_eq_some, ← succMany?_succ?, hn]
|
||||
· rintro ⟨n, hn⟩
|
||||
refine ⟨n, ?_⟩
|
||||
rw [succ_eq_get, succ_eq_get, ← Option.bind_some (f := succMany? n), Option.some_get,
|
||||
Option.some_get, ← LawfulUpwardEnumerable.succMany?_succ_eq_succ?_bind_succMany?,
|
||||
succMany?_succ, hn, Option.bind_some]
|
||||
Option.some_get, ← succMany?_succ?_eq_succ?_bind_succMany?,
|
||||
succMany?_succ?, hn, Option.bind_some]
|
||||
|
||||
theorem UpwardEnumerable.succ_lt_succ_iff {α : Type w} [UpwardEnumerable α] [LawfulUpwardEnumerable α]
|
||||
[LinearlyUpwardEnumerable α] [InfinitelyUpwardEnumerable α] {a b : α} :
|
||||
UpwardEnumerable.LT (UpwardEnumerable.succ a) (UpwardEnumerable.succ b) ↔
|
||||
theorem UpwardEnumerable.succ_lt_succ_iff {α : Type w} [UpwardEnumerable α]
|
||||
[LawfulUpwardEnumerable α] [LinearlyUpwardEnumerable α] [InfinitelyUpwardEnumerable α]
|
||||
{a b : α} :
|
||||
UpwardEnumerable.LT (succ a) (succ b) ↔
|
||||
UpwardEnumerable.LT a b := by
|
||||
constructor
|
||||
· rintro ⟨n, hn⟩
|
||||
simp only [succ] at hn
|
||||
refine ⟨n, ?_⟩
|
||||
rw [succMany?_eq_some_iff_succMany]
|
||||
apply eq_of_succ?_eq
|
||||
apply succ?_inj
|
||||
rw [← Option.bind_some (f := succMany? _), Option.some_get,
|
||||
← LawfulUpwardEnumerable.succMany?_succ_eq_succ?_bind_succMany?, Option.some_get] at hn
|
||||
rw [← Option.bind_some (f := succ?), ← succMany?_eq_some, ← succMany?_succ, hn]
|
||||
← succMany?_succ?_eq_succ?_bind_succMany?, Option.some_get] at hn
|
||||
rw [← Option.bind_some (f := succ?), ← succMany?_eq_some, ← succMany?_succ?, hn]
|
||||
· rintro ⟨n, hn⟩
|
||||
refine ⟨n, ?_⟩
|
||||
rw [succ_eq_get, succ_eq_get, ← Option.bind_some (f := succMany? _), Option.some_get,
|
||||
Option.some_get, ← LawfulUpwardEnumerable.succMany?_succ_eq_succ?_bind_succMany?,
|
||||
succMany?_succ, hn, Option.bind_some]
|
||||
Option.some_get, ← succMany?_succ?_eq_succ?_bind_succMany?, succMany?_succ?, hn,
|
||||
Option.bind_some]
|
||||
|
||||
/--
|
||||
This typeclass ensures that an `UpwardEnumerable α` instance is compatible with `≤`.
|
||||
@@ -317,7 +368,11 @@ class LawfulUpwardEnumerableLE (α : Type u) [UpwardEnumerable α] [LE α] where
|
||||
`a` is less than or equal to `b` if and only if `b` is either `a` or a transitive successor
|
||||
of `a`.
|
||||
-/
|
||||
le_iff (a b : α) : a ≤ b ↔ UpwardEnumerable.LE a b
|
||||
protected le_iff (a b : α) : a ≤ b ↔ UpwardEnumerable.LE a b
|
||||
|
||||
protected theorem UpwardEnumerable.le_iff {α : Type u} [LE α] [UpwardEnumerable α]
|
||||
[LawfulUpwardEnumerableLE α] {a b : α} : a ≤ b ↔ UpwardEnumerable.LE a b :=
|
||||
LawfulUpwardEnumerableLE.le_iff a b
|
||||
|
||||
/--
|
||||
This typeclass ensures that an `UpwardEnumerable α` instance is compatible with `<`.
|
||||
@@ -329,6 +384,10 @@ class LawfulUpwardEnumerableLT (α : Type u) [UpwardEnumerable α] [LT α] where
|
||||
-/
|
||||
lt_iff (a b : α) : a < b ↔ UpwardEnumerable.LT a b
|
||||
|
||||
protected theorem UpwardEnumerable.lt_iff {α : Type u} [LT α] [UpwardEnumerable α]
|
||||
[LawfulUpwardEnumerableLT α] {a b : α} : a < b ↔ UpwardEnumerable.LT a b :=
|
||||
LawfulUpwardEnumerableLT.lt_iff a b
|
||||
|
||||
/--
|
||||
This typeclass ensures that an `UpwardEnumerable α` instance is compatible with a `Least? α`
|
||||
instance. For nonempty `α`, it ensures that `least?` has a value and that every other value is
|
||||
@@ -336,6 +395,11 @@ a transitive successor of it.
|
||||
-/
|
||||
class LawfulUpwardEnumerableLeast? (α : Type u) [UpwardEnumerable α] [Least? α] where
|
||||
/-- For nonempty `α`, `least?` has a value and every other value is a transitive successor of it. -/
|
||||
eq_succMany?_least? (a : α) : ∃ init, Least?.least? = some init ∧ UpwardEnumerable.LE init a
|
||||
least?_le (a : α) : ∃ init, Least?.least? = some init ∧ UpwardEnumerable.LE init a
|
||||
|
||||
theorem UpwardEnumerable.least?_le {α : Type u} [UpwardEnumerable α] [Least? α]
|
||||
[LawfulUpwardEnumerableLeast? α] {a : α} :
|
||||
∃ init, least? = some init ∧ UpwardEnumerable.LE init a :=
|
||||
LawfulUpwardEnumerableLeast?.least?_le a
|
||||
|
||||
end Std.PRange
|
||||
|
||||
@@ -356,7 +356,7 @@ Returns the decimal string representation of an integer.
|
||||
-/
|
||||
protected def Int.repr : Int → String
|
||||
| ofNat m => Nat.repr m
|
||||
| negSucc m => "-" ++ Nat.repr (succ m)
|
||||
| negSucc m => String.Internal.append "-" (Nat.repr (succ m))
|
||||
|
||||
instance : Repr Int where
|
||||
reprPrec i prec := if i < 0 then Repr.addAppParen i.repr prec else i.repr
|
||||
@@ -370,14 +370,14 @@ def Char.quoteCore (c : Char) (inString : Bool := false) : String :=
|
||||
else if c = '\\' then "\\\\"
|
||||
else if c = '\"' then "\\\""
|
||||
else if !inString && c = '\'' then "\\\'"
|
||||
else if c.toNat <= 31 ∨ c = '\x7f' then "\\x" ++ smallCharToHex c
|
||||
else if c.toNat <= 31 ∨ c = '\x7f' then String.Internal.append "\\x" (smallCharToHex c)
|
||||
else String.singleton c
|
||||
where
|
||||
smallCharToHex (c : Char) : String :=
|
||||
let n := Char.toNat c;
|
||||
let d2 := n / 16;
|
||||
let d1 := n % 16;
|
||||
hexDigitRepr d2 ++ hexDigitRepr d1
|
||||
String.Internal.append (hexDigitRepr d2) (hexDigitRepr d1)
|
||||
|
||||
/--
|
||||
Quotes the character to its representation as a character literal, surrounded by single quotes and
|
||||
@@ -388,7 +388,7 @@ Examples:
|
||||
* `'"'.quote = "'\\\"'"`
|
||||
-/
|
||||
def Char.quote (c : Char) : String :=
|
||||
"'" ++ Char.quoteCore c ++ "'"
|
||||
String.Internal.append (String.Internal.append "'" (Char.quoteCore c)) "'"
|
||||
|
||||
instance : Repr Char where
|
||||
reprPrec c _ := c.quote
|
||||
@@ -405,8 +405,8 @@ Examples:
|
||||
* `"\"".quote = "\"\\\"\""`
|
||||
-/
|
||||
def String.quote (s : String) : String :=
|
||||
if s.isEmpty then "\"\""
|
||||
else s.foldl (fun s c => s ++ c.quoteCore (inString := true)) "\"" ++ "\""
|
||||
if String.Internal.isEmpty s then "\"\""
|
||||
else String.Internal.append (String.Internal.foldl (fun s c => String.Internal.append s (c.quoteCore (inString := true))) "\"" s) "\""
|
||||
|
||||
instance : Repr String where
|
||||
reprPrec s _ := s.quote
|
||||
@@ -415,10 +415,7 @@ instance : Repr String.Pos where
|
||||
reprPrec p _ := "{ byteIdx := " ++ repr p.byteIdx ++ " }"
|
||||
|
||||
instance : Repr Substring where
|
||||
reprPrec s _ := Format.text <| String.quote s.toString ++ ".toSubstring"
|
||||
|
||||
instance : Repr String.Iterator where
|
||||
reprPrec | ⟨s, pos⟩, prec => Repr.addAppParen ("String.Iterator.mk " ++ reprArg s ++ " " ++ reprArg pos) prec
|
||||
reprPrec s _ := Format.text <| String.Internal.append (String.quote (Substring.Internal.toString s)) ".toSubstring"
|
||||
|
||||
instance (n : Nat) : Repr (Fin n) where
|
||||
reprPrec f _ := repr f.val
|
||||
|
||||
@@ -8,6 +8,7 @@ module
|
||||
prelude
|
||||
public import Init.Data.Range
|
||||
public import Init.Data.Array.Subarray
|
||||
public import Init.Data.String.Basic
|
||||
|
||||
import Init.Data.Slice.Array.Basic
|
||||
|
||||
|
||||
@@ -7,7 +7,10 @@ module
|
||||
|
||||
prelude
|
||||
public import Init.Data.String.Basic
|
||||
public import Init.Data.String.Bootstrap
|
||||
public import Init.Data.String.Extra
|
||||
public import Init.Data.String.Lemmas
|
||||
public import Init.Data.String.Repr
|
||||
public import Init.Data.String.Bootstrap
|
||||
|
||||
public section
|
||||
|
||||
@@ -8,22 +8,12 @@ module
|
||||
prelude
|
||||
public import Init.Data.List.Basic
|
||||
public import Init.Data.Char.Basic
|
||||
public import Init.Data.String.Bootstrap
|
||||
|
||||
public section
|
||||
|
||||
universe u
|
||||
|
||||
/--
|
||||
Creates a string that contains the characters in a list, in order.
|
||||
|
||||
Examples:
|
||||
* `['L', '∃', '∀', 'N'].asString = "L∃∀N"`
|
||||
* `[].asString = ""`
|
||||
* `['a', 'a', 'a'].asString = "aaa"`
|
||||
-/
|
||||
def List.asString (s : List Char) : String :=
|
||||
⟨s⟩
|
||||
|
||||
namespace String
|
||||
|
||||
instance : HAdd String.Pos String.Pos String.Pos where
|
||||
@@ -32,6 +22,10 @@ instance : HAdd String.Pos String.Pos String.Pos where
|
||||
instance : HSub String.Pos String.Pos String.Pos where
|
||||
hSub p₁ p₂ := { byteIdx := p₁.byteIdx - p₂.byteIdx }
|
||||
|
||||
@[export lean_string_pos_sub]
|
||||
def Pos.Internal.subImpl : String.Pos → String.Pos → String.Pos :=
|
||||
(· - ·)
|
||||
|
||||
instance : HAdd String.Pos Char String.Pos where
|
||||
hAdd p c := { byteIdx := p.byteIdx + c.utf8Size }
|
||||
|
||||
@@ -53,9 +47,6 @@ instance (p₁ p₂ : String.Pos) : Decidable (LT.lt p₁ p₂) :=
|
||||
instance : Min String.Pos := minOfLe
|
||||
instance : Max String.Pos := maxOfLe
|
||||
|
||||
instance : OfNat String.Pos (nat_lit 0) where
|
||||
ofNat := {}
|
||||
|
||||
instance : LT String :=
|
||||
⟨fun s₁ s₂ => s₁.data < s₂.data⟩
|
||||
|
||||
@@ -90,20 +81,6 @@ Examples:
|
||||
def length : (@& String) → Nat
|
||||
| ⟨s⟩ => s.length
|
||||
|
||||
/--
|
||||
Adds a character to the end of a string.
|
||||
|
||||
The internal implementation uses dynamic arrays and will perform destructive updates
|
||||
if the string is not shared.
|
||||
|
||||
Examples:
|
||||
* `"abc".push 'd' = "abcd"`
|
||||
* `"".push 'a' = "a"`
|
||||
-/
|
||||
@[extern "lean_string_push", expose]
|
||||
def push : String → Char → String
|
||||
| ⟨s⟩, c => ⟨s ++ [c]⟩
|
||||
|
||||
/--
|
||||
Appends two strings. Usually accessed via the `++` operator.
|
||||
|
||||
@@ -305,6 +282,10 @@ Examples:
|
||||
@[inline] def front (s : String) : Char :=
|
||||
get s 0
|
||||
|
||||
@[export lean_string_front]
|
||||
def Internal.frontImpl (s : String) : Char :=
|
||||
String.front s
|
||||
|
||||
/--
|
||||
Returns the last character in `s`. If `s = ""`, returns `(default : Char)`.
|
||||
|
||||
@@ -385,6 +366,10 @@ theorem _root_.Char.utf8Size_pos (c : Char) : 0 < c.utf8Size := by
|
||||
theorem _root_.Char.utf8Size_le_four (c : Char) : c.utf8Size ≤ 4 := by
|
||||
repeat first | apply iteInduction (motive := (· ≤ 4)) <;> intros | decide
|
||||
|
||||
theorem _root_.Char.utf8Size_eq (c : Char) : c.utf8Size = 1 ∨ c.utf8Size = 2 ∨ c.utf8Size = 3 ∨ c.utf8Size = 4 := by
|
||||
match c.utf8Size, c.utf8Size_pos, c.utf8Size_le_four with
|
||||
| 1, _, _ | 2, _, _ | 3, _, _ | 4, _, _ => simp
|
||||
|
||||
@[deprecated Char.utf8Size_pos (since := "2026-06-04")] abbrev one_le_csize := Char.utf8Size_pos
|
||||
|
||||
@[simp] theorem pos_lt_eq (p₁ p₂ : Pos) : (p₁ < p₂) = (p₁.1 < p₂.1) := rfl
|
||||
@@ -430,6 +415,10 @@ Examples:
|
||||
@[inline] def posOf (s : String) (c : Char) : Pos :=
|
||||
posOfAux s c s.endPos 0
|
||||
|
||||
@[export lean_string_posof]
|
||||
def Internal.posOfImpl (s : String) (c : Char) : Pos :=
|
||||
String.posOf s c
|
||||
|
||||
def revPosOfAux (s : String) (c : Char) (pos : Pos) : Option Pos :=
|
||||
if h : pos = 0 then none
|
||||
else
|
||||
@@ -500,6 +489,10 @@ Returns either `p₁` or `p₂`, whichever has the least byte index.
|
||||
abbrev Pos.min (p₁ p₂ : Pos) : Pos :=
|
||||
{ byteIdx := p₁.byteIdx.min p₂.byteIdx }
|
||||
|
||||
@[export lean_string_pos_min]
|
||||
def Pos.Internal.minImpl (p₁ p₂ : Pos) : Pos :=
|
||||
Pos.min p₁ p₂
|
||||
|
||||
/--
|
||||
Returns the first position where the two strings differ.
|
||||
|
||||
@@ -660,6 +653,10 @@ Examples:
|
||||
@[inline] def pushn (s : String) (c : Char) (n : Nat) : String :=
|
||||
n.repeat (fun s => s.push c) s
|
||||
|
||||
@[export lean_string_pushn]
|
||||
def Internal.pushnImpl (s : String) (c : Char) (n : Nat) : String :=
|
||||
String.pushn s c n
|
||||
|
||||
/--
|
||||
Checks whether a string is empty.
|
||||
|
||||
@@ -673,6 +670,10 @@ Examples:
|
||||
@[inline] def isEmpty (s : String) : Bool :=
|
||||
s.endPos == 0
|
||||
|
||||
@[export lean_string_isempty]
|
||||
def Internal.isEmptyImpl (s : String) : Bool :=
|
||||
String.isEmpty s
|
||||
|
||||
/--
|
||||
Appends all the strings in a list of strings, in order.
|
||||
|
||||
@@ -686,20 +687,6 @@ Examples:
|
||||
@[inline] def join (l : List String) : String :=
|
||||
l.foldl (fun r s => r ++ s) ""
|
||||
|
||||
/--
|
||||
Returns a new string that contains only the character `c`.
|
||||
|
||||
Because strings are encoded in UTF-8, the resulting string may take multiple bytes.
|
||||
|
||||
Examples:
|
||||
* `String.singleton 'L' = "L"`
|
||||
* `String.singleton ' ' = " "`
|
||||
* `String.singleton '"' = "\""`
|
||||
* `String.singleton '𝒫' = "𝒫"`
|
||||
-/
|
||||
@[inline,expose] def singleton (c : Char) : String :=
|
||||
"".push c
|
||||
|
||||
/--
|
||||
Appends the strings in a list of strings, placing the separator `s` between each pair.
|
||||
|
||||
@@ -715,6 +702,10 @@ where go (acc : String) (s : String) : List String → String
|
||||
| a :: as => go (acc ++ s ++ a) s as
|
||||
| [] => acc
|
||||
|
||||
@[export lean_string_intercalate]
|
||||
def Internal.intercalateImpl (s : String) : List String → String :=
|
||||
String.intercalate s
|
||||
|
||||
/--
|
||||
An iterator over the characters (Unicode code points) in a `String`. Typically created by
|
||||
`String.iter`.
|
||||
@@ -926,6 +917,10 @@ Examples:
|
||||
@[inline] def offsetOfPos (s : String) (pos : Pos) : Nat :=
|
||||
offsetOfPosAux s pos 0 0
|
||||
|
||||
@[export lean_string_offsetofpos]
|
||||
def Internal.offsetOfPosImpl (s : String) (pos : Pos) : Nat :=
|
||||
String.offsetOfPos s pos
|
||||
|
||||
@[specialize] def foldlAux {α : Type u} (f : α → Char → α) (s : String) (stopPos : Pos) (i : Pos) (a : α) : α :=
|
||||
if h : i < stopPos then
|
||||
have := Nat.sub_lt_sub_left h (lt_next s i)
|
||||
@@ -945,6 +940,10 @@ Examples:
|
||||
@[inline] def foldl {α : Type u} (f : α → Char → α) (init : α) (s : String) : α :=
|
||||
foldlAux f s s.endPos 0 init
|
||||
|
||||
@[export lean_string_foldl]
|
||||
def Internal.foldlImpl (f : String → Char → String) (init : String) (s : String) : String :=
|
||||
String.foldl f init s
|
||||
|
||||
@[specialize] def foldrAux {α : Type u} (f : Char → α → α) (a : α) (s : String) (i begPos : Pos) : α :=
|
||||
if h : begPos < i then
|
||||
have := String.prev_lt_of_pos s i <| mt (congrArg String.Pos.byteIdx) <|
|
||||
@@ -990,6 +989,10 @@ Examples:
|
||||
@[inline] def any (s : String) (p : Char → Bool) : Bool :=
|
||||
anyAux s s.endPos p 0
|
||||
|
||||
@[export lean_string_any]
|
||||
def Internal.anyImpl (s : String) (p : Char → Bool) :=
|
||||
String.any s p
|
||||
|
||||
/--
|
||||
Checks whether the Boolean predicate `p` returns `true` for every character in a string.
|
||||
|
||||
@@ -1012,7 +1015,11 @@ Examples:
|
||||
* `"".contains 'x' = false`
|
||||
-/
|
||||
@[inline] def contains (s : String) (c : Char) : Bool :=
|
||||
s.any (fun a => a == c)
|
||||
s.any (fun a => a == c)
|
||||
|
||||
@[export lean_string_contains]
|
||||
def Internal.containsImpl (s : String) (c : Char) : Bool :=
|
||||
String.contains s c
|
||||
|
||||
theorem utf8SetAux_of_gt (c' : Char) : ∀ (cs : List Char) {i p : Pos}, i > p → utf8SetAux c' cs i p = cs
|
||||
| [], _, _, _ => rfl
|
||||
@@ -1155,6 +1162,10 @@ Examples:
|
||||
def isPrefixOf (p : String) (s : String) : Bool :=
|
||||
substrEq p 0 s 0 p.endPos.byteIdx
|
||||
|
||||
@[export lean_string_isprefixof]
|
||||
def Internal.isPrefixOfImpl (p : String) (s : String) : Bool :=
|
||||
String.isPrefixOf p s
|
||||
|
||||
/--
|
||||
In the string `s`, replaces all occurrences of `pattern` with `replacement`.
|
||||
|
||||
@@ -1204,12 +1215,20 @@ A substring is empty if its start and end positions are the same.
|
||||
@[inline] def isEmpty (ss : Substring) : Bool :=
|
||||
ss.bsize == 0
|
||||
|
||||
@[export lean_substring_isempty]
|
||||
def Internal.isEmptyImpl (ss : Substring) : Bool :=
|
||||
Substring.isEmpty ss
|
||||
|
||||
/--
|
||||
Copies the region of the underlying string pointed to by a substring into a fresh string.
|
||||
-/
|
||||
@[inline] def toString : Substring → String
|
||||
| ⟨s, b, e⟩ => s.extract b e
|
||||
|
||||
@[export lean_substring_tostring]
|
||||
def Internal.toStringImpl : Substring → String :=
|
||||
Substring.toString
|
||||
|
||||
/--
|
||||
Returns an iterator into the underlying string, at the substring's starting position. The ending
|
||||
position is discarded, so the iterator alone cannot be used to determine whether its current
|
||||
@@ -1229,6 +1248,10 @@ returned. Does not panic.
|
||||
@[inline] def get : Substring → String.Pos → Char
|
||||
| ⟨s, b, _⟩, p => s.get (b+p)
|
||||
|
||||
@[export lean_substring_get]
|
||||
def Internal.getImpl : Substring → String.Pos → Char :=
|
||||
Substring.get
|
||||
|
||||
/--
|
||||
Returns the next position in a substring after the given position. If the position is at the end of
|
||||
the substring, it is returned unmodified.
|
||||
@@ -1262,6 +1285,10 @@ position, not the underlying string.
|
||||
let absP := b+p
|
||||
if absP = b then p else { byteIdx := (s.prev absP).byteIdx - b.byteIdx }
|
||||
|
||||
@[export lean_substring_prev]
|
||||
def Internal.prevImpl : Substring → String.Pos → String.Pos :=
|
||||
Substring.prev
|
||||
|
||||
/--
|
||||
Returns the position that's the specified number of characters forward from the given position in a
|
||||
substring. If the end position of the substring is reached, it is returned.
|
||||
@@ -1295,6 +1322,10 @@ returned. Does not panic.
|
||||
@[inline] def front (s : Substring) : Char :=
|
||||
s.get 0
|
||||
|
||||
@[export lean_substring_front]
|
||||
def Internal.frontImpl : Substring → Char :=
|
||||
Substring.front
|
||||
|
||||
/--
|
||||
Returns the substring-relative position of the first occurrence of `c` in `s`, or `s.bsize` if `c`
|
||||
doesn't occur.
|
||||
@@ -1312,6 +1343,10 @@ If the substring's end position is reached, the start position is not advanced p
|
||||
@[inline] def drop : Substring → Nat → Substring
|
||||
| ss@⟨s, b, e⟩, n => ⟨s, b + ss.nextn n 0, e⟩
|
||||
|
||||
@[export lean_substring_drop]
|
||||
def Internal.dropImpl : Substring → Nat → Substring :=
|
||||
Substring.drop
|
||||
|
||||
/--
|
||||
Removes the specified number of characters (Unicode code points) from the end of a substring
|
||||
by moving its end position towards its start position.
|
||||
@@ -1360,6 +1395,10 @@ positions adjusted.
|
||||
@[inline] def extract : Substring → String.Pos → String.Pos → Substring
|
||||
| ⟨s, b, e⟩, b', e' => if b' ≥ e' then ⟨"", 0, 0⟩ else ⟨s, e.min (b+b'), e.min (b+e')⟩
|
||||
|
||||
@[export lean_substring_extract]
|
||||
def Internal.extractImpl : Substring → String.Pos → String.Pos → Substring :=
|
||||
Substring.extract
|
||||
|
||||
/--
|
||||
Splits a substring `s` on occurrences of the separator string `sep`. The default separator is `" "`.
|
||||
|
||||
@@ -1426,6 +1465,10 @@ Short-circuits at the first character for which `p` returns `false`.
|
||||
@[inline] def all (s : Substring) (p : Char → Bool) : Bool :=
|
||||
!s.any (fun c => !p c)
|
||||
|
||||
@[export lean_substring_all]
|
||||
def Internal.allImpl (s : Substring) (p : Char → Bool) : Bool :=
|
||||
Substring.all s p
|
||||
|
||||
/--
|
||||
Checks whether a substring contains the specified character.
|
||||
-/
|
||||
@@ -1450,6 +1493,10 @@ characters by moving the substring's end position towards its start position.
|
||||
let e := takeWhileAux s e p b;
|
||||
⟨s, b, e⟩
|
||||
|
||||
@[export lean_substring_takewhile]
|
||||
def Internal.takeWhileImpl : Substring → (Char → Bool) → Substring :=
|
||||
Substring.takeWhile
|
||||
|
||||
/--
|
||||
Removes the longest prefix of a substring in which a Boolean predicate returns `true` for all
|
||||
characters by moving the substring's start position. The start position is moved to the position of
|
||||
@@ -1567,6 +1614,10 @@ instead, they are equal if they contain the same sequence of characters.
|
||||
def beq (ss1 ss2 : Substring) : Bool :=
|
||||
ss1.bsize == ss2.bsize && ss1.str.substrEq ss1.startPos ss2.str ss2.startPos ss1.bsize
|
||||
|
||||
@[export lean_substring_beq]
|
||||
def Internal.beqImpl (ss1 ss2 : Substring) : Bool :=
|
||||
Substring.beq ss1 ss2
|
||||
|
||||
instance hasBeq : BEq Substring := ⟨beq⟩
|
||||
|
||||
/--
|
||||
@@ -1664,6 +1715,10 @@ Examples:
|
||||
@[inline] def drop (s : String) (n : Nat) : String :=
|
||||
(s.toSubstring.drop n).toString
|
||||
|
||||
@[export lean_string_drop]
|
||||
def Internal.dropImpl (s : String) (n : Nat) : String :=
|
||||
String.drop s n
|
||||
|
||||
/--
|
||||
Removes the specified number of characters (Unicode code points) from the end of the string.
|
||||
|
||||
@@ -1677,6 +1732,10 @@ Examples:
|
||||
@[inline] def dropRight (s : String) (n : Nat) : String :=
|
||||
(s.toSubstring.dropRight n).toString
|
||||
|
||||
@[export lean_string_dropright]
|
||||
def Internal.dropRightImpl (s : String) (n : Nat) : String :=
|
||||
String.dropRight s n
|
||||
|
||||
/--
|
||||
Creates a new string that contains the first `n` characters (Unicode code points) of `s`.
|
||||
|
||||
@@ -1828,6 +1887,10 @@ Examples:
|
||||
@[inline] def trim (s : String) : String :=
|
||||
s.toSubstring.trim.toString
|
||||
|
||||
@[export lean_string_trim]
|
||||
def Internal.trimImpl (s : String) : String :=
|
||||
String.trim s
|
||||
|
||||
/--
|
||||
Repeatedly increments a position in a string, as if by `String.next`, while the predicate `p`
|
||||
returns `true` for the character at the position. Stops incrementing at the end of the string or
|
||||
@@ -1841,6 +1904,10 @@ Examples:
|
||||
@[inline] def nextWhile (s : String) (p : Char → Bool) (i : String.Pos) : String.Pos :=
|
||||
Substring.takeWhileAux s s.endPos p i
|
||||
|
||||
@[export lean_string_nextwhile]
|
||||
def Internal.nextWhileImpl (s : String) (p : Char → Bool) (i : String.Pos) : String.Pos :=
|
||||
String.nextWhile s p i
|
||||
|
||||
/--
|
||||
Repeatedly increments a position in a string, as if by `String.next`, while the predicate `p`
|
||||
returns `false` for the character at the position. Stops incrementing at the end of the string or
|
||||
@@ -1890,9 +1957,13 @@ Examples:
|
||||
* `"ORANGE".capitalize = "ORANGE"`
|
||||
* `"".capitalize = ""`
|
||||
-/
|
||||
@[inline] def capitalize (s : String) :=
|
||||
@[inline] def capitalize (s : String) : String :=
|
||||
s.set 0 <| s.get 0 |>.toUpper
|
||||
|
||||
@[export lean_string_capitalize]
|
||||
def Internal.capitalizeImpl (s : String) : String :=
|
||||
String.capitalize s
|
||||
|
||||
/--
|
||||
Replaces the first character in `s` with the result of applying `Char.toLower` to it. Returns the
|
||||
empty string if the string is empty.
|
||||
@@ -1975,16 +2046,6 @@ end String
|
||||
|
||||
namespace Char
|
||||
|
||||
/--
|
||||
Constructs a singleton string that contains only the provided character.
|
||||
|
||||
Examples:
|
||||
* `'L'.toString = "L"`
|
||||
* `'"'.toString = "\""`
|
||||
-/
|
||||
@[inline, expose] protected def toString (c : Char) : String :=
|
||||
String.singleton c
|
||||
|
||||
@[simp] theorem length_toString (c : Char) : c.toString.length = 1 := rfl
|
||||
|
||||
end Char
|
||||
|
||||
186
src/Init/Data/String/Bootstrap.lean
Normal file
186
src/Init/Data/String/Bootstrap.lean
Normal file
@@ -0,0 +1,186 @@
|
||||
/-
|
||||
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.List.Basic
|
||||
public import Init.Data.Char.Basic
|
||||
|
||||
public section
|
||||
|
||||
namespace String
|
||||
|
||||
instance : OfNat String.Pos (nat_lit 0) where
|
||||
ofNat := {}
|
||||
|
||||
instance : Inhabited String where
|
||||
default := ""
|
||||
|
||||
/--
|
||||
Adds a character to the end of a string.
|
||||
|
||||
The internal implementation uses dynamic arrays and will perform destructive updates
|
||||
if the string is not shared.
|
||||
|
||||
Examples:
|
||||
* `"abc".push 'd' = "abcd"`
|
||||
* `"".push 'a' = "a"`
|
||||
-/
|
||||
@[extern "lean_string_push", expose]
|
||||
def push : String → Char → String
|
||||
| ⟨s⟩, c => ⟨s ++ [c]⟩
|
||||
|
||||
/--
|
||||
Returns a new string that contains only the character `c`.
|
||||
|
||||
Because strings are encoded in UTF-8, the resulting string may take multiple bytes.
|
||||
|
||||
Examples:
|
||||
* `String.singleton 'L' = "L"`
|
||||
* `String.singleton ' ' = " "`
|
||||
* `String.singleton '"' = "\""`
|
||||
* `String.singleton '𝒫' = "𝒫"`
|
||||
-/
|
||||
@[inline, expose] def singleton (c : Char) : String :=
|
||||
"".push c
|
||||
|
||||
end String
|
||||
|
||||
namespace String.Internal
|
||||
|
||||
@[extern "lean_string_posof"]
|
||||
opaque posOf (s : String) (c : Char) : Pos
|
||||
|
||||
@[extern "lean_string_offsetofpos"]
|
||||
opaque offsetOfPos (s : String) (pos : Pos) : Nat
|
||||
|
||||
@[extern "lean_string_utf8_extract"]
|
||||
opaque extract : (@& String) → (@& Pos) → (@& Pos) → String
|
||||
|
||||
@[extern "lean_string_length"]
|
||||
opaque length : (@& String) → Nat
|
||||
|
||||
@[extern "lean_string_pushn"]
|
||||
opaque pushn (s : String) (c : Char) (n : Nat) : String
|
||||
|
||||
@[extern "lean_string_append"]
|
||||
opaque append : String → (@& String) → String
|
||||
|
||||
@[extern "lean_string_utf8_next"]
|
||||
opaque next (s : @& String) (p : @& Pos) : Pos
|
||||
|
||||
@[extern "lean_string_isempty"]
|
||||
opaque isEmpty (s : String) : Bool
|
||||
|
||||
@[extern "lean_string_foldl"]
|
||||
opaque foldl (f : String → Char → String) (init : String) (s : String) : String
|
||||
|
||||
@[extern "lean_string_isprefixof"]
|
||||
opaque isPrefixOf (p : String) (s : String) : Bool
|
||||
|
||||
@[extern "lean_string_any"]
|
||||
opaque any (s : String) (p : Char → Bool) : Bool
|
||||
|
||||
@[extern "lean_string_contains"]
|
||||
opaque contains (s : String) (c : Char) : Bool
|
||||
|
||||
@[extern "lean_string_utf8_get"]
|
||||
opaque get (s : @& String) (p : @& Pos) : Char
|
||||
|
||||
@[extern "lean_string_capitalize"]
|
||||
opaque capitalize (s : String) : String
|
||||
|
||||
@[extern "lean_string_utf8_at_end"]
|
||||
opaque atEnd : (@& String) → (@& Pos) → Bool
|
||||
|
||||
@[extern "lean_string_nextwhile"]
|
||||
opaque nextWhile (s : String) (p : Char → Bool) (i : String.Pos) : String.Pos
|
||||
|
||||
@[extern "lean_string_trim"]
|
||||
opaque trim (s : String) : String
|
||||
|
||||
@[extern "lean_string_intercalate"]
|
||||
opaque intercalate (s : String) : List String → String
|
||||
|
||||
@[extern "lean_string_front"]
|
||||
opaque front (s : String) : Char
|
||||
|
||||
@[extern "lean_string_drop"]
|
||||
opaque drop (s : String) (n : Nat) : String
|
||||
|
||||
@[extern "lean_string_dropright"]
|
||||
opaque dropRight (s : String) (n : Nat) : String
|
||||
|
||||
end String.Internal
|
||||
|
||||
/--
|
||||
Creates a string that contains the characters in a list, in order.
|
||||
|
||||
Examples:
|
||||
* `['L', '∃', '∀', 'N'].asString = "L∃∀N"`
|
||||
* `[].asString = ""`
|
||||
* `['a', 'a', 'a'].asString = "aaa"`
|
||||
-/
|
||||
def List.asString (s : List Char) : String :=
|
||||
⟨s⟩
|
||||
|
||||
namespace Substring.Internal
|
||||
|
||||
@[extern "lean_substring_tostring"]
|
||||
opaque toString : Substring → String
|
||||
|
||||
@[extern "lean_substring_drop"]
|
||||
opaque drop : Substring → Nat → Substring
|
||||
|
||||
@[extern "lean_substring_front"]
|
||||
opaque front (s : Substring) : Char
|
||||
|
||||
@[extern "lean_substring_takewhile"]
|
||||
opaque takeWhile : Substring → (Char → Bool) → Substring
|
||||
|
||||
@[extern "lean_substring_extract"]
|
||||
opaque extract : Substring → String.Pos → String.Pos → Substring
|
||||
|
||||
@[extern "lean_substring_all"]
|
||||
opaque all (s : Substring) (p : Char → Bool) : Bool
|
||||
|
||||
@[extern "lean_substring_beq"]
|
||||
opaque beq (ss1 ss2 : Substring) : Bool
|
||||
|
||||
@[extern "lean_substring_isempty"]
|
||||
opaque isEmpty (ss : Substring) : Bool
|
||||
|
||||
@[extern "lean_substring_get"]
|
||||
opaque get : Substring → String.Pos → Char
|
||||
|
||||
@[extern "lean_substring_prev"]
|
||||
opaque prev : Substring → String.Pos → String.Pos
|
||||
|
||||
end Substring.Internal
|
||||
|
||||
namespace String.Pos.Internal
|
||||
|
||||
@[extern "lean_string_pos_sub"]
|
||||
opaque sub : String.Pos → String.Pos → String.Pos
|
||||
|
||||
@[extern "lean_string_pos_min"]
|
||||
opaque min (p₁ p₂ : Pos) : Pos
|
||||
|
||||
end String.Pos.Internal
|
||||
|
||||
namespace Char
|
||||
|
||||
/--
|
||||
Constructs a singleton string that contains only the provided character.
|
||||
|
||||
Examples:
|
||||
* `'L'.toString = "L"`
|
||||
* `'"'.toString = "\""`
|
||||
-/
|
||||
@[inline, expose] protected def toString (c : Char) : String :=
|
||||
String.singleton c
|
||||
|
||||
end Char
|
||||
@@ -11,6 +11,7 @@ import all Init.Data.ByteArray.Basic
|
||||
public import Init.Data.String.Basic
|
||||
import all Init.Data.String.Basic
|
||||
import Init.Data.UInt.Lemmas
|
||||
import Init.Data.UInt.Bitwise
|
||||
|
||||
public section
|
||||
|
||||
@@ -135,7 +136,7 @@ the corresponding string, or panics if the array is not a valid UTF-8 encoding o
|
||||
/--
|
||||
Returns the sequence of bytes in a character's UTF-8 encoding.
|
||||
-/
|
||||
def utf8EncodeChar (c : Char) : List UInt8 :=
|
||||
def utf8EncodeCharFast (c : Char) : List UInt8 :=
|
||||
let v := c.val
|
||||
if v ≤ 0x7f then
|
||||
[v.toUInt8]
|
||||
@@ -152,8 +153,58 @@ def utf8EncodeChar (c : Char) : List UInt8 :=
|
||||
(v >>> 6).toUInt8 &&& 0x3f ||| 0x80,
|
||||
v.toUInt8 &&& 0x3f ||| 0x80]
|
||||
|
||||
private theorem Nat.add_two_pow_eq_or_of_lt {b : Nat} (i : Nat) (b_lt : b < 2 ^ i) (a : Nat) :
|
||||
b + 2 ^ i * a = b ||| 2 ^ i * a := by
|
||||
rw [Nat.add_comm, Nat.or_comm, Nat.two_pow_add_eq_or_of_lt b_lt]
|
||||
|
||||
@[csimp]
|
||||
theorem utf8EncodeChar_eq_utf8EncodeCharFast : @utf8EncodeChar = @utf8EncodeCharFast := by
|
||||
funext c
|
||||
simp only [utf8EncodeChar, utf8EncodeCharFast, UInt8.ofNat_uInt32ToNat, UInt8.ofNat_add,
|
||||
UInt8.reduceOfNat, UInt32.le_iff_toNat_le, UInt32.reduceToNat]
|
||||
split
|
||||
· rfl
|
||||
· split
|
||||
· simp only [List.cons.injEq, ← UInt8.toNat_inj, UInt8.toNat_add, UInt8.toNat_ofNat',
|
||||
Nat.reducePow, UInt8.reduceToNat, Nat.mod_add_mod, UInt8.toNat_or, UInt8.toNat_and,
|
||||
UInt32.toNat_toUInt8, UInt32.toNat_shiftRight, UInt32.reduceToNat, Nat.reduceMod, and_true]
|
||||
refine ⟨?_, ?_⟩
|
||||
· rw [Nat.mod_eq_of_lt (by omega), Nat.add_two_pow_eq_or_of_lt 5 (by omega) 6,
|
||||
Nat.and_two_pow_sub_one_eq_mod _ 5, Nat.shiftRight_eq_div_pow,
|
||||
Nat.mod_eq_of_lt (b := 256) (by omega)]
|
||||
· rw [Nat.mod_eq_of_lt (by omega), Nat.add_two_pow_eq_or_of_lt 6 (by omega) 2,
|
||||
Nat.and_two_pow_sub_one_eq_mod _ 6, Nat.mod_mod_of_dvd _ (by decide)]
|
||||
· split
|
||||
· simp only [List.cons.injEq, ← UInt8.toNat_inj, UInt8.toNat_add, UInt8.toNat_ofNat',
|
||||
Nat.reducePow, UInt8.reduceToNat, Nat.mod_add_mod, UInt8.toNat_or, UInt8.toNat_and,
|
||||
UInt32.toNat_toUInt8, UInt32.toNat_shiftRight, UInt32.reduceToNat, Nat.reduceMod, and_true]
|
||||
refine ⟨?_, ?_, ?_⟩
|
||||
· rw [Nat.mod_eq_of_lt (by omega), Nat.add_two_pow_eq_or_of_lt 4 (by omega) 14,
|
||||
Nat.and_two_pow_sub_one_eq_mod _ 4, Nat.shiftRight_eq_div_pow,
|
||||
Nat.mod_eq_of_lt (b := 256) (by omega)]
|
||||
· rw [Nat.mod_eq_of_lt (by omega), Nat.add_two_pow_eq_or_of_lt 6 (by omega) 2,
|
||||
Nat.and_two_pow_sub_one_eq_mod _ 6, Nat.shiftRight_eq_div_pow,
|
||||
Nat.mod_mod_of_dvd (c.val.toNat / 2 ^ 6) (by decide)]
|
||||
· rw [Nat.mod_eq_of_lt (by omega), Nat.add_two_pow_eq_or_of_lt 6 (by omega) 2,
|
||||
Nat.and_two_pow_sub_one_eq_mod _ 6, Nat.mod_mod_of_dvd c.val.toNat (by decide)]
|
||||
· simp only [List.cons.injEq, ← UInt8.toNat_inj, UInt8.toNat_add, UInt8.toNat_ofNat',
|
||||
Nat.reducePow, UInt8.reduceToNat, Nat.mod_add_mod, UInt8.toNat_or, UInt8.toNat_and,
|
||||
UInt32.toNat_toUInt8, UInt32.toNat_shiftRight, UInt32.reduceToNat, Nat.reduceMod, and_true]
|
||||
refine ⟨?_, ?_, ?_, ?_⟩
|
||||
· rw [Nat.mod_eq_of_lt (by omega), Nat.add_two_pow_eq_or_of_lt 3 (by omega) 30,
|
||||
Nat.and_two_pow_sub_one_eq_mod _ 3, Nat.shiftRight_eq_div_pow,
|
||||
Nat.mod_mod_of_dvd _ (by decide)]
|
||||
· rw [Nat.mod_eq_of_lt (by omega), Nat.add_two_pow_eq_or_of_lt 6 (by omega) 2,
|
||||
Nat.and_two_pow_sub_one_eq_mod _ 6, Nat.shiftRight_eq_div_pow,
|
||||
Nat.mod_mod_of_dvd (c.val.toNat / 2 ^ 12) (by decide)]
|
||||
· rw [Nat.mod_eq_of_lt (by omega), Nat.add_two_pow_eq_or_of_lt 6 (by omega) 2,
|
||||
Nat.and_two_pow_sub_one_eq_mod _ 6, Nat.shiftRight_eq_div_pow,
|
||||
Nat.mod_mod_of_dvd (c.val.toNat / 2 ^ 6) (by decide)]
|
||||
· rw [Nat.mod_eq_of_lt (by omega), Nat.add_two_pow_eq_or_of_lt 6 (by omega) 2,
|
||||
Nat.and_two_pow_sub_one_eq_mod _ 6, Nat.mod_mod_of_dvd c.val.toNat (by decide)]
|
||||
|
||||
@[simp] theorem length_utf8EncodeChar (c : Char) : (utf8EncodeChar c).length = c.utf8Size := by
|
||||
simp [Char.utf8Size, utf8EncodeChar]
|
||||
simp [Char.utf8Size, utf8EncodeChar_eq_utf8EncodeCharFast, utf8EncodeCharFast]
|
||||
cases Decidable.em (c.val ≤ 0x7f) <;> simp [*]
|
||||
cases Decidable.em (c.val ≤ 0x7ff) <;> simp [*]
|
||||
cases Decidable.em (c.val ≤ 0xffff) <;> simp [*]
|
||||
|
||||
@@ -10,6 +10,7 @@ public import Init.Data.Char.Order
|
||||
public import Init.Data.Char.Lemmas
|
||||
public import Init.Data.List.Lex
|
||||
import Init.Data.Order.Lemmas
|
||||
public import Init.Data.String.Basic
|
||||
|
||||
public section
|
||||
|
||||
|
||||
95
src/Init/Data/String/Repr.lean
Normal file
95
src/Init/Data/String/Repr.lean
Normal file
@@ -0,0 +1,95 @@
|
||||
/-
|
||||
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
|
||||
public import Init.Data.ToString.Basic
|
||||
|
||||
public section
|
||||
|
||||
instance : Repr String.Iterator where
|
||||
reprPrec | ⟨s, pos⟩, prec => Repr.addAppParen ("String.Iterator.mk " ++ reprArg s ++ " " ++ reprArg pos) prec
|
||||
|
||||
instance : ToString String.Iterator :=
|
||||
⟨fun it => it.remainingToString⟩
|
||||
|
||||
/--
|
||||
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.get 0 = '-' then do
|
||||
let v ← (s.toSubstring.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.get 0 = '-' then
|
||||
(s.toSubstring.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"
|
||||
@@ -8,5 +8,6 @@ module
|
||||
prelude
|
||||
public import Init.Data.ToString.Basic
|
||||
public import Init.Data.ToString.Macro
|
||||
public meta import Init.Data.ToString.Name
|
||||
|
||||
public section
|
||||
|
||||
@@ -38,10 +38,10 @@ instance : ToString String :=
|
||||
⟨fun s => s⟩
|
||||
|
||||
instance : ToString Substring :=
|
||||
⟨fun s => s.toString⟩
|
||||
⟨fun s => Substring.Internal.toString s⟩
|
||||
|
||||
instance : ToString String.Iterator :=
|
||||
⟨fun it => it.remainingToString⟩
|
||||
instance : ToString Char :=
|
||||
⟨fun c => Char.toString c⟩
|
||||
|
||||
instance : ToString Bool :=
|
||||
⟨fun b => cond b "true" "false"⟩
|
||||
@@ -67,8 +67,9 @@ Examples:
|
||||
-/
|
||||
protected def List.toString [ToString α] : List α → String
|
||||
| [] => "[]"
|
||||
| [x] => "[" ++ toString x ++ "]"
|
||||
| x::xs => xs.foldl (· ++ ", " ++ toString ·) ("[" ++ toString x) |>.push ']'
|
||||
| [x] => String.Internal.append (String.Internal.append "[" (toString x)) "]"
|
||||
| x::xs => String.push (xs.foldl (fun l r => String.Internal.append (String.Internal.append l ", ") (toString r))
|
||||
(String.Internal.append "[" (toString x))) ']'
|
||||
|
||||
instance {α : Type u} [ToString α] : ToString (List α) :=
|
||||
⟨List.toString⟩
|
||||
@@ -91,10 +92,7 @@ instance : ToString String.Pos :=
|
||||
instance : ToString Int where
|
||||
toString
|
||||
| Int.ofNat m => toString m
|
||||
| Int.negSucc m => "-" ++ toString (succ m)
|
||||
|
||||
instance : ToString Char :=
|
||||
⟨fun c => c.toString⟩
|
||||
| Int.negSucc m => String.Internal.append "-" (toString (succ m))
|
||||
|
||||
instance (n : Nat) : ToString (Fin n) :=
|
||||
⟨fun f => toString (Fin.val f)⟩
|
||||
@@ -118,108 +116,43 @@ instance : ToString Format where
|
||||
toString f := f.pretty
|
||||
|
||||
def addParenHeuristic (s : String) : String :=
|
||||
if "(".isPrefixOf s || "[".isPrefixOf s || "{".isPrefixOf s || "#[".isPrefixOf s then s
|
||||
else if !s.any Char.isWhitespace then s
|
||||
else "(" ++ s ++ ")"
|
||||
if String.Internal.isPrefixOf "(" s || String.Internal.isPrefixOf "[" s || String.Internal.isPrefixOf "{" s || String.Internal.isPrefixOf "#[" s then s
|
||||
else if !(String.Internal.any s Char.isWhitespace) then s
|
||||
else String.Internal.append (String.Internal.append "(" s) ")"
|
||||
|
||||
instance {α : Type u} [ToString α] : ToString (Option α) := ⟨fun
|
||||
| none => "none"
|
||||
| (some a) => "(some " ++ addParenHeuristic (toString a) ++ ")"⟩
|
||||
| (some a) => String.Internal.append (String.Internal.append "(some " (addParenHeuristic (toString a))) ")"⟩
|
||||
|
||||
instance {α : Type u} {β : Type v} [ToString α] [ToString β] : ToString (Sum α β) := ⟨fun
|
||||
| (inl a) => "(inl " ++ addParenHeuristic (toString a) ++ ")"
|
||||
| (inr b) => "(inr " ++ addParenHeuristic (toString b) ++ ")"⟩
|
||||
| (inl a) => String.Internal.append (String.Internal.append "(inl " (addParenHeuristic (toString a))) ")"
|
||||
| (inr b) => String.Internal.append (String.Internal.append "(inr " (addParenHeuristic (toString b))) ")"⟩
|
||||
|
||||
instance {α : Type u} {β : Type v} [ToString α] [ToString β] : ToString (α × β) := ⟨fun (a, b) =>
|
||||
"(" ++ toString a ++ ", " ++ toString b ++ ")"⟩
|
||||
String.Internal.append
|
||||
(String.Internal.append
|
||||
(String.Internal.append
|
||||
(String.Internal.append "(" (toString a))
|
||||
", ")
|
||||
(toString b))
|
||||
")"⟩
|
||||
|
||||
instance {α : Type u} {β : α → Type v} [ToString α] [∀ x, ToString (β x)] : ToString (Sigma β) := ⟨fun ⟨a, b⟩ =>
|
||||
"⟨" ++ toString a ++ ", " ++ toString b ++ "⟩"⟩
|
||||
String.Internal.append
|
||||
(String.Internal.append
|
||||
(String.Internal.append
|
||||
(String.Internal.append "⟨" (toString a))
|
||||
", ")
|
||||
(toString b))
|
||||
"⟩"⟩
|
||||
|
||||
instance {α : Type u} {p : α → Prop} [ToString α] : ToString (Subtype p) := ⟨fun s =>
|
||||
toString (val s)⟩
|
||||
|
||||
/--
|
||||
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.get 0 = '-' then do
|
||||
let v ← (s.toSubstring.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.get 0 = '-' then
|
||||
(s.toSubstring.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"
|
||||
|
||||
instance [ToString ε] [ToString α] : ToString (Except ε α) where
|
||||
toString
|
||||
| Except.error e => "error: " ++ toString e
|
||||
| Except.ok a => "ok: " ++ toString a
|
||||
| Except.error e => String.Internal.append "error: " (toString e)
|
||||
| Except.ok a => String.Internal.append "ok: " (toString a)
|
||||
|
||||
instance [Repr ε] [Repr α] : Repr (Except ε α) where
|
||||
reprPrec
|
||||
|
||||
128
src/Init/Data/ToString/Name.lean
Normal file
128
src/Init/Data/ToString/Name.lean
Normal file
@@ -0,0 +1,128 @@
|
||||
/-
|
||||
Copyright (c) 2019 Microsoft Corporation. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Leonardo de Moura and Sebastian Ullrich
|
||||
-/
|
||||
module
|
||||
|
||||
prelude
|
||||
public import Init.Meta
|
||||
import Init.Data.String.Extra
|
||||
|
||||
/-!
|
||||
Here we give the. implementation of `Name.toString`. There is also a private implementation in
|
||||
`Init.Meta`, which we cannot import this implementation due to import hierarchy limitations.
|
||||
|
||||
The difference between the two versions is that the one in `Init.Meta` uses the `String.Internal.*`
|
||||
functions, while the one here uses the public String functions. These differ in
|
||||
that the latter versions have better inferred borrowing annotations, which is significant for an
|
||||
inner-loop function like `Name.toString`.
|
||||
-/
|
||||
|
||||
public section
|
||||
|
||||
namespace Lean.Name
|
||||
|
||||
-- If you change this, also change the corresponding function in `Init.Meta`.
|
||||
private partial def needsNoEscapeAsciiRest (s : String) (i : Nat) : Bool :=
|
||||
if h : i < s.utf8ByteSize then
|
||||
let c := s.getUtf8Byte i h
|
||||
isIdRestAscii c && needsNoEscapeAsciiRest s (i + 1)
|
||||
else
|
||||
true
|
||||
|
||||
-- If you change this, also change the corresponding function in `Init.Meta`.
|
||||
@[inline] private def needsNoEscapeAscii (s : String) (h : s.utf8ByteSize > 0) : Bool :=
|
||||
let c := s.getUtf8Byte 0 h
|
||||
isIdFirstAscii c && needsNoEscapeAsciiRest s 1
|
||||
|
||||
-- If you change this, also change the corresponding function in `Init.Meta`.
|
||||
@[inline] private def needsNoEscape (s : String) (h : s.utf8ByteSize > 0) : Bool :=
|
||||
needsNoEscapeAscii s h || isIdFirst (s.get 0) && (s.toSubstring.drop 1).all isIdRest
|
||||
|
||||
-- If you change this, also change the corresponding function in `Init.Meta`.
|
||||
@[inline] private def escape (s : String) : String :=
|
||||
idBeginEscape.toString ++ s ++ idEndEscape.toString
|
||||
|
||||
/--
|
||||
Creates a round-trippable string name component if possible, otherwise returns `none`.
|
||||
Names that are valid identifiers are not escaped, and otherwise, if they do not contain `»`, they are escaped.
|
||||
- If `force` is `true`, then even valid identifiers are escaped.
|
||||
-/
|
||||
-- If you change this, also change the corresponding function in `Init.Meta`.
|
||||
@[inline]
|
||||
def escapePart (s : String) (force : Bool := false) : Option String :=
|
||||
if h : s.utf8ByteSize > 0 then
|
||||
if !force && needsNoEscape s h then
|
||||
some s
|
||||
else if s.any isIdEndEscape then
|
||||
none
|
||||
else
|
||||
some <| escape s
|
||||
else
|
||||
some <| escape s
|
||||
|
||||
variable (sep : String) (escape : Bool) in
|
||||
/--
|
||||
Uses the separator `sep` (usually `"."`) to combine the components of the `Name` into a string.
|
||||
See the documentation for `Name.toStringWithToken` for an explanation of `escape` and `isToken`.
|
||||
-/
|
||||
-- If you change this, also change the corresponding function in `Init.Meta`.
|
||||
@[specialize isToken] -- explicit annotation because isToken is overridden in recursive call
|
||||
def toStringWithSep (n : Name) (isToken : String → Bool := fun _ => false) : String :=
|
||||
match n with
|
||||
| anonymous => "[anonymous]"
|
||||
| str anonymous s => maybeEscape s (isToken s)
|
||||
| num anonymous v => toString v
|
||||
| str n s =>
|
||||
-- Escape the last component if the identifier would otherwise be a token
|
||||
let r := toStringWithSep n isToken
|
||||
let r' := r ++ sep ++ (maybeEscape s false)
|
||||
if escape && isToken r' then r ++ sep ++ (maybeEscape s true) else r'
|
||||
| num n v => toStringWithSep n (isToken := fun _ => false) ++ sep ++ Nat.repr v
|
||||
where
|
||||
maybeEscape s force := if escape then escapePart s force |>.getD s else s
|
||||
|
||||
/--
|
||||
Converts a name to a string.
|
||||
|
||||
- If `escape` is `true`, then escapes name components using `«` and `»` to ensure that
|
||||
those names that can appear in source files round trip.
|
||||
Names with number components, anonymous names, and names containing `»` might not round trip.
|
||||
Furthermore, "pseudo-syntax" produced by the delaborator, such as `_`, `#0` or `?u`, is not escaped.
|
||||
- The optional `isToken` function is used when `escape` is `true` to determine whether more
|
||||
escaping is necessary to avoid parser tokens.
|
||||
The insertion algorithm works so long as parser tokens do not themselves contain `«` or `»`.
|
||||
-/
|
||||
-- If you change this, also change the corresponding function in `Init.Meta`.
|
||||
@[specialize]
|
||||
def toStringWithToken (n : Name) (escape := true) (isToken : String → Bool) : String :=
|
||||
-- never escape "prettified" inaccessible names or macro scopes or pseudo-syntax introduced by the delaborator
|
||||
toStringWithSep "." (escape && !n.isInaccessibleUserName && !n.hasMacroScopes && !maybePseudoSyntax) n isToken
|
||||
where
|
||||
maybePseudoSyntax :=
|
||||
if n == `_ then
|
||||
-- output hole as is
|
||||
true
|
||||
else if let .str _ s := n.getRoot then
|
||||
-- could be pseudo-syntax for loose bvar or universe mvar, output as is
|
||||
"#".isPrefixOf s || "?".isPrefixOf s
|
||||
else
|
||||
false
|
||||
|
||||
/--
|
||||
Converts a name to a string.
|
||||
|
||||
- If `escape` is `true`, then escapes name components using `«` and `»` to ensure that
|
||||
those names that can appear in source files round trip.
|
||||
Names with number components, anonymous names, and names containing `»` might not round trip.
|
||||
Furthermore, "pseudo-syntax" produced by the delaborator, such as `_`, `#0` or `?u`, is not escaped.
|
||||
-/
|
||||
-- If you change this, also change the corresponding function in `Init.Meta`.
|
||||
protected def toString (n : Name) (escape := true) : String :=
|
||||
Name.toStringWithToken n escape (fun _ => false)
|
||||
|
||||
instance : ToString Name where
|
||||
toString n := n.toString
|
||||
|
||||
end Lean.Name
|
||||
@@ -139,16 +139,6 @@ This function is overridden at runtime with an efficient implementation.
|
||||
-/
|
||||
@[extern "lean_uint8_shift_right"]
|
||||
protected def UInt8.shiftRight (a b : UInt8) : UInt8 := ⟨a.toBitVec >>> (UInt8.mod b 8).toBitVec⟩
|
||||
/--
|
||||
Strict inequality of 8-bit unsigned integers, defined as inequality of the corresponding
|
||||
natural numbers. Usually accessed via the `<` operator.
|
||||
-/
|
||||
protected def UInt8.lt (a b : UInt8) : Prop := a.toBitVec < b.toBitVec
|
||||
/--
|
||||
Non-strict inequality of 8-bit unsigned integers, defined as inequality of the corresponding
|
||||
natural numbers. Usually accessed via the `≤` operator.
|
||||
-/
|
||||
protected def UInt8.le (a b : UInt8) : Prop := a.toBitVec ≤ b.toBitVec
|
||||
|
||||
instance : Add UInt8 := ⟨UInt8.add⟩
|
||||
instance : Sub UInt8 := ⟨UInt8.sub⟩
|
||||
@@ -160,8 +150,6 @@ set_option linter.deprecated false in
|
||||
instance : HMod UInt8 Nat UInt8 := ⟨UInt8.modn⟩
|
||||
|
||||
instance : Div UInt8 := ⟨UInt8.div⟩
|
||||
instance : LT UInt8 := ⟨UInt8.lt⟩
|
||||
instance : LE UInt8 := ⟨UInt8.le⟩
|
||||
|
||||
/--
|
||||
Bitwise complement, also known as bitwise negation, for 8-bit unsigned integers. Usually accessed
|
||||
@@ -197,39 +185,6 @@ Converts `true` to `1` and `false` to `0`.
|
||||
@[extern "lean_bool_to_uint8"]
|
||||
def Bool.toUInt8 (b : Bool) : UInt8 := if b then 1 else 0
|
||||
|
||||
/--
|
||||
Decides whether one 8-bit unsigned integer is strictly less than another. Usually accessed via the
|
||||
`DecidableLT UInt8` instance.
|
||||
|
||||
This function is overridden at runtime with an efficient implementation.
|
||||
|
||||
Examples:
|
||||
* `(if (6 : UInt8) < 7 then "yes" else "no") = "yes"`
|
||||
* `(if (5 : UInt8) < 5 then "yes" else "no") = "no"`
|
||||
* `show ¬((7 : UInt8) < 7) by decide`
|
||||
-/
|
||||
@[extern "lean_uint8_dec_lt"]
|
||||
def UInt8.decLt (a b : UInt8) : Decidable (a < b) :=
|
||||
inferInstanceAs (Decidable (a.toBitVec < b.toBitVec))
|
||||
|
||||
/--
|
||||
Decides whether one 8-bit unsigned integer is less than or equal to another. Usually accessed via the
|
||||
`DecidableLE UInt8` instance.
|
||||
|
||||
This function is overridden at runtime with an efficient implementation.
|
||||
|
||||
Examples:
|
||||
* `(if (15 : UInt8) ≤ 15 then "yes" else "no") = "yes"`
|
||||
* `(if (15 : UInt8) ≤ 5 then "yes" else "no") = "no"`
|
||||
* `(if (5 : UInt8) ≤ 15 then "yes" else "no") = "yes"`
|
||||
* `show (7 : UInt8) ≤ 7 by decide`
|
||||
-/
|
||||
@[extern "lean_uint8_dec_le"]
|
||||
def UInt8.decLe (a b : UInt8) : Decidable (a ≤ b) :=
|
||||
inferInstanceAs (Decidable (a.toBitVec ≤ b.toBitVec))
|
||||
|
||||
attribute [instance] UInt8.decLt UInt8.decLe
|
||||
|
||||
instance : Max UInt8 := maxOfLe
|
||||
instance : Min UInt8 := minOfLe
|
||||
|
||||
|
||||
@@ -29,21 +29,6 @@ def UInt8.toFin (x : UInt8) : Fin UInt8.size := x.toBitVec.toFin
|
||||
@[deprecated UInt8.toFin (since := "2025-02-12"), inherit_doc UInt8.toFin]
|
||||
def UInt8.val (x : UInt8) : Fin UInt8.size := x.toFin
|
||||
|
||||
/--
|
||||
Converts a natural number to an 8-bit unsigned integer, wrapping on overflow.
|
||||
|
||||
This function is overridden at runtime with an efficient implementation.
|
||||
|
||||
Examples:
|
||||
* `UInt8.ofNat 5 = 5`
|
||||
* `UInt8.ofNat 255 = 255`
|
||||
* `UInt8.ofNat 256 = 0`
|
||||
* `UInt8.ofNat 259 = 3`
|
||||
* `UInt8.ofNat 32770 = 2`
|
||||
-/
|
||||
@[extern "lean_uint8_of_nat"]
|
||||
def UInt8.ofNat (n : @& Nat) : UInt8 := ⟨BitVec.ofNat 8 n⟩
|
||||
|
||||
/--
|
||||
Converts a natural number to an 8-bit unsigned integer, returning the largest representable value if
|
||||
the number is too large.
|
||||
@@ -222,8 +207,8 @@ instance UInt32.instOfNat : OfNat UInt32 n := ⟨UInt32.ofNat n⟩
|
||||
|
||||
theorem UInt32.ofNatLT_lt_of_lt {n m : Nat} (h1 : n < UInt32.size) (h2 : m < UInt32.size) :
|
||||
n < m → UInt32.ofNatLT n h1 < UInt32.ofNat m := by
|
||||
simp only [(· < ·), BitVec.toNat, ofNatLT, BitVec.ofNatLT, ofNat, BitVec.ofNat, Fin.ofNat,
|
||||
Nat.mod_eq_of_lt h2, imp_self]
|
||||
simp only [(· < ·), BitVec.toNat, ofNatLT, BitVec.ofNatLT, ofNat, BitVec.ofNat,
|
||||
Fin.Internal.ofNat_eq_ofNat, Fin.ofNat, Nat.mod_eq_of_lt h2, imp_self]
|
||||
|
||||
@[deprecated UInt32.ofNatLT_lt_of_lt (since := "2025-02-13")]
|
||||
theorem UInt32.ofNat'_lt_of_lt {n m : Nat} (h1 : n < UInt32.size) (h2 : m < UInt32.size) :
|
||||
@@ -231,8 +216,8 @@ theorem UInt32.ofNat'_lt_of_lt {n m : Nat} (h1 : n < UInt32.size) (h2 : m < UInt
|
||||
|
||||
theorem UInt32.lt_ofNatLT_of_lt {n m : Nat} (h1 : n < UInt32.size) (h2 : m < UInt32.size) :
|
||||
m < n → UInt32.ofNat m < UInt32.ofNatLT n h1 := by
|
||||
simp only [(· < ·), BitVec.toNat, ofNatLT, BitVec.ofNatLT, ofNat, BitVec.ofNat, Fin.ofNat,
|
||||
Nat.mod_eq_of_lt h2, imp_self]
|
||||
simp only [(· < ·), BitVec.toNat, ofNatLT, BitVec.ofNatLT, ofNat, BitVec.ofNat, Fin.Internal.ofNat_eq_ofNat,
|
||||
Fin.ofNat, Nat.mod_eq_of_lt h2, imp_self]
|
||||
|
||||
@[deprecated UInt32.lt_ofNatLT_of_lt (since := "2025-02-13")]
|
||||
theorem UInt32.lt_ofNat'_of_lt {n m : Nat} (h1 : n < UInt32.size) (h2 : m < UInt32.size) :
|
||||
|
||||
@@ -200,7 +200,7 @@ theorem mem_attach (xs : Vector α n) : ∀ x, x ∈ xs.attach
|
||||
rcases this with ⟨⟨_, _⟩, m, rfl⟩
|
||||
exact m
|
||||
|
||||
@[simp, grind]
|
||||
@[simp, grind =]
|
||||
theorem mem_attachWith {xs : Vector α n} {q : α → Prop} (H) (x : {x // q x}) :
|
||||
x ∈ xs.attachWith q H ↔ x.1 ∈ xs := by
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
@@ -211,12 +211,13 @@ theorem mem_pmap {p : α → Prop} {f : ∀ a, p a → β} {xs : Vector α n} {H
|
||||
b ∈ pmap f xs H ↔ ∃ (a : _) (h : a ∈ xs), f a (H a h) = b := by
|
||||
simp only [pmap_eq_map_attach, mem_map, mem_attach, true_and, Subtype.exists, eq_comm]
|
||||
|
||||
@[grind]
|
||||
theorem mem_pmap_of_mem {p : α → Prop} {f : ∀ a, p a → β} {xs : Vector α n} {H} {a} (h : a ∈ xs) :
|
||||
f a (H a h) ∈ pmap f xs H := by
|
||||
rw [mem_pmap]
|
||||
exact ⟨a, h, rfl⟩
|
||||
|
||||
grind_pattern mem_pmap_of_mem => _ ∈ pmap f xs H, a ∈ xs
|
||||
|
||||
theorem pmap_eq_self {xs : Vector α n} {p : α → Prop} {hp : ∀ (a : α), a ∈ xs → p a}
|
||||
{f : (a : α) → p a → α} : xs.pmap f hp = xs ↔ ∀ a (h : a ∈ xs), f a (hp a h) = a := by
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
|
||||
@@ -36,7 +36,7 @@ structure Vector (α : Type u) (n : Nat) where
|
||||
size_toArray : toArray.size = n
|
||||
deriving Repr, DecidableEq
|
||||
|
||||
attribute [simp, grind] Vector.size_toArray
|
||||
attribute [simp, grind =] Vector.size_toArray
|
||||
|
||||
/--
|
||||
Converts an array to a vector. The resulting vector's size is the array's size.
|
||||
|
||||
@@ -32,11 +32,11 @@ open Nat
|
||||
|
||||
/-! ### findSome? -/
|
||||
|
||||
@[simp, grind] theorem findSome?_empty : (#v[] : Vector α 0).findSome? f = none := rfl
|
||||
@[simp, grind] theorem findSome?_push {xs : Vector α n} : (xs.push a).findSome? f = (xs.findSome? f).or (f a) := by
|
||||
@[simp, grind =] theorem findSome?_empty : (#v[] : Vector α 0).findSome? f = none := rfl
|
||||
@[simp, grind =] theorem findSome?_push {xs : Vector α n} : (xs.push a).findSome? f = (xs.findSome? f).or (f a) := by
|
||||
cases xs; simp
|
||||
|
||||
@[grind]
|
||||
@[grind =]
|
||||
theorem findSome?_singleton {a : α} {f : α → Option β} : #v[a].findSome? f = f a := by
|
||||
simp
|
||||
|
||||
@@ -228,11 +228,12 @@ theorem mem_of_find?_eq_some {xs : Vector α n} (h : find? p xs = some a) : a
|
||||
simp at h
|
||||
simpa using Array.mem_of_find?_eq_some h
|
||||
|
||||
@[grind]
|
||||
theorem get_find?_mem {xs : Vector α n} (h) : (xs.find? p).get h ∈ xs := by
|
||||
cases xs
|
||||
simp [Array.get_find?_mem]
|
||||
|
||||
grind_pattern get_find?_mem => (xs.find? p).get h
|
||||
|
||||
@[simp, grind =] theorem find?_map {f : β → α} {xs : Vector β n} :
|
||||
find? p (xs.map f) = (xs.find? (p ∘ f)).map f := by
|
||||
cases xs; simp
|
||||
|
||||
@@ -266,12 +266,12 @@ theorem toArray_mk {xs : Array α} (h : xs.size = n) : (Vector.mk xs h).toArray
|
||||
|
||||
/-! ### toArray lemmas -/
|
||||
|
||||
@[simp, grind] theorem getElem_toArray {α n} {xs : Vector α n} {i : Nat} (h : i < xs.toArray.size) :
|
||||
@[simp, grind =] theorem getElem_toArray {α n} {xs : Vector α n} {i : Nat} (h : i < xs.toArray.size) :
|
||||
xs.toArray[i] = xs[i]'(by simpa using h) := by
|
||||
cases xs
|
||||
simp
|
||||
|
||||
@[simp, grind] theorem getElem?_toArray {α n} {xs : Vector α n} {i : Nat} :
|
||||
@[simp, grind =] theorem getElem?_toArray {α n} {xs : Vector α n} {i : Nat} :
|
||||
xs.toArray[i]? = xs[i]? := by
|
||||
cases xs
|
||||
simp
|
||||
@@ -280,45 +280,45 @@ theorem toArray_mk {xs : Array α} (h : xs.size = n) : (Vector.mk xs h).toArray
|
||||
(xs ++ ys).toArray = xs.toArray ++ ys.toArray := rfl
|
||||
|
||||
set_option linter.indexVariables false in
|
||||
@[simp, grind] theorem toArray_drop {xs : Vector α n} {i} :
|
||||
@[simp, grind =] theorem toArray_drop {xs : Vector α n} {i} :
|
||||
(xs.drop i).toArray = xs.toArray.extract i n := by
|
||||
simp [drop]
|
||||
|
||||
@[simp, grind =] theorem toArray_empty : (#v[] : Vector α 0).toArray = #[] := rfl
|
||||
|
||||
@[simp, grind] theorem toArray_emptyWithCapacity {cap} :
|
||||
@[simp, grind =] theorem toArray_emptyWithCapacity {cap} :
|
||||
(Vector.emptyWithCapacity (α := α) cap).toArray = Array.emptyWithCapacity cap := rfl
|
||||
|
||||
@[deprecated toArray_emptyWithCapacity (since := "2025-03-12")]
|
||||
abbrev toArray_mkEmpty := @toArray_emptyWithCapacity
|
||||
|
||||
@[simp, grind] theorem toArray_eraseIdx {xs : Vector α n} {i} (h) :
|
||||
@[simp, grind =] theorem toArray_eraseIdx {xs : Vector α n} {i} (h) :
|
||||
(xs.eraseIdx i h).toArray = xs.toArray.eraseIdx i (by simp [h]) := rfl
|
||||
|
||||
@[simp, grind] theorem toArray_eraseIdx! {xs : Vector α n} {i} (hi : i < n) :
|
||||
@[simp, grind =] theorem toArray_eraseIdx! {xs : Vector α n} {i} (hi : i < n) :
|
||||
(xs.eraseIdx! i).toArray = xs.toArray.eraseIdx! i := by
|
||||
cases xs; simp_all [Array.eraseIdx!]
|
||||
|
||||
@[simp, grind] theorem toArray_insertIdx {xs : Vector α n} {i x} (h) :
|
||||
@[simp, grind =] theorem toArray_insertIdx {xs : Vector α n} {i x} (h) :
|
||||
(xs.insertIdx i x h).toArray = xs.toArray.insertIdx i x (by simp [h]) := rfl
|
||||
|
||||
@[simp, grind] theorem toArray_insertIdx! {xs : Vector α n} {i x} (hi : i ≤ n) :
|
||||
@[simp, grind =] theorem toArray_insertIdx! {xs : Vector α n} {i x} (hi : i ≤ n) :
|
||||
(xs.insertIdx! i x).toArray = xs.toArray.insertIdx! i x := by
|
||||
cases xs; simp_all [Array.insertIdx!]
|
||||
|
||||
@[simp, grind] theorem toArray_cast {xs : Vector α n} (h : n = m) :
|
||||
@[simp, grind =] theorem toArray_cast {xs : Vector α n} (h : n = m) :
|
||||
(xs.cast h).toArray = xs.toArray := rfl
|
||||
|
||||
@[simp, grind] theorem toArray_extract {xs : Vector α n} {start stop} :
|
||||
@[simp, grind =] theorem toArray_extract {xs : Vector α n} {start stop} :
|
||||
(xs.extract start stop).toArray = xs.toArray.extract start stop := rfl
|
||||
|
||||
@[simp, grind] theorem toArray_map {f : α → β} {xs : Vector α n} :
|
||||
@[simp, grind =] theorem toArray_map {f : α → β} {xs : Vector α n} :
|
||||
(xs.map f).toArray = xs.toArray.map f := rfl
|
||||
|
||||
@[simp, grind] theorem toArray_mapIdx {f : Nat → α → β} {xs : Vector α n} :
|
||||
@[simp, grind =] theorem toArray_mapIdx {f : Nat → α → β} {xs : Vector α n} :
|
||||
(xs.mapIdx f).toArray = xs.toArray.mapIdx f := rfl
|
||||
|
||||
@[simp, grind] theorem toArray_mapFinIdx {f : (i : Nat) → α → (h : i < n) → β} {xs : Vector α n} :
|
||||
@[simp, grind =] theorem toArray_mapFinIdx {f : (i : Nat) → α → (h : i < n) → β} {xs : Vector α n} :
|
||||
(xs.mapFinIdx f).toArray =
|
||||
xs.toArray.mapFinIdx (fun i a h => f i a (by simpa [xs.size_toArray] using h)) :=
|
||||
rfl
|
||||
@@ -336,42 +336,42 @@ private theorem toArray_mapM_go [Monad m] [LawfulMonad m] {f : α → m β} {xs
|
||||
rfl
|
||||
· simp
|
||||
|
||||
@[simp, grind] theorem toArray_mapM [Monad m] [LawfulMonad m] {f : α → m β} {xs : Vector α n} :
|
||||
@[simp, grind =] theorem toArray_mapM [Monad m] [LawfulMonad m] {f : α → m β} {xs : Vector α n} :
|
||||
toArray <$> xs.mapM f = xs.toArray.mapM f := by
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
unfold mapM
|
||||
rw [toArray_mapM_go]
|
||||
rfl
|
||||
|
||||
@[simp, grind] theorem toArray_ofFn {f : Fin n → α} : (Vector.ofFn f).toArray = Array.ofFn f := rfl
|
||||
@[simp, grind =] theorem toArray_ofFn {f : Fin n → α} : (Vector.ofFn f).toArray = Array.ofFn f := rfl
|
||||
|
||||
@[simp, grind] theorem toArray_pop {xs : Vector α n} : xs.pop.toArray = xs.toArray.pop := rfl
|
||||
@[simp, grind =] theorem toArray_pop {xs : Vector α n} : xs.pop.toArray = xs.toArray.pop := rfl
|
||||
|
||||
@[simp, grind] theorem toArray_push {xs : Vector α n} {x} : (xs.push x).toArray = xs.toArray.push x := rfl
|
||||
@[simp, grind =] theorem toArray_push {xs : Vector α n} {x} : (xs.push x).toArray = xs.toArray.push x := rfl
|
||||
|
||||
@[simp, grind] theorem toArray_beq_toArray [BEq α] {xs : Vector α n} {ys : Vector α n} :
|
||||
@[simp, grind =] theorem toArray_beq_toArray [BEq α] {xs : Vector α n} {ys : Vector α n} :
|
||||
(xs.toArray == ys.toArray) = (xs == ys) := by
|
||||
simp [instBEq, isEqv, Array.instBEq, Array.isEqv, xs.2, ys.2]
|
||||
|
||||
@[simp, grind] theorem toArray_range : (Vector.range n).toArray = Array.range n := rfl
|
||||
@[simp, grind =] theorem toArray_range : (Vector.range n).toArray = Array.range n := rfl
|
||||
|
||||
@[simp, grind] theorem toArray_reverse (xs : Vector α n) : xs.reverse.toArray = xs.toArray.reverse := rfl
|
||||
@[simp, grind =] theorem toArray_reverse (xs : Vector α n) : xs.reverse.toArray = xs.toArray.reverse := rfl
|
||||
|
||||
@[simp, grind] theorem toArray_set {xs : Vector α n} {i x} (h) :
|
||||
@[simp, grind =] theorem toArray_set {xs : Vector α n} {i x} (h) :
|
||||
(xs.set i x).toArray = xs.toArray.set i x (by simpa using h):= rfl
|
||||
|
||||
@[simp, grind] theorem toArray_set! {xs : Vector α n} {i x} :
|
||||
@[simp, grind =] theorem toArray_set! {xs : Vector α n} {i x} :
|
||||
(xs.set! i x).toArray = xs.toArray.set! i x := rfl
|
||||
|
||||
@[simp, grind] theorem toArray_setIfInBounds {xs : Vector α n} {i x} :
|
||||
@[simp, grind =] theorem toArray_setIfInBounds {xs : Vector α n} {i x} :
|
||||
(xs.setIfInBounds i x).toArray = xs.toArray.setIfInBounds i x := rfl
|
||||
|
||||
@[simp, grind] theorem toArray_singleton {x : α} : (Vector.singleton x).toArray = #[x] := rfl
|
||||
@[simp, grind =] theorem toArray_singleton {x : α} : (Vector.singleton x).toArray = #[x] := rfl
|
||||
|
||||
@[simp, grind] theorem toArray_swap {xs : Vector α n} {i j} (hi hj) : (xs.swap i j).toArray =
|
||||
@[simp, grind =] theorem toArray_swap {xs : Vector α n} {i j} (hi hj) : (xs.swap i j).toArray =
|
||||
xs.toArray.swap i j (by simp [hj]) (by simp [hi]) := rfl
|
||||
|
||||
@[simp, grind] theorem toArray_swapIfInBounds {xs : Vector α n} {i j} :
|
||||
@[simp, grind =] theorem toArray_swapIfInBounds {xs : Vector α n} {i j} :
|
||||
(xs.swapIfInBounds i j).toArray = xs.toArray.swapIfInBounds i j := rfl
|
||||
|
||||
theorem toArray_swapAt {xs : Vector α n} {i x} (h) :
|
||||
@@ -383,98 +383,98 @@ theorem toArray_swapAt! {xs : Vector α n} {i x} :
|
||||
((xs.swapAt! i x).fst, (xs.swapAt! i x).snd.toArray) =
|
||||
((xs.toArray.swapAt! i x).fst, (xs.toArray.swapAt! i x).snd) := rfl
|
||||
|
||||
@[simp, grind] theorem toArray_take {xs : Vector α n} {i} : (xs.take i).toArray = xs.toArray.take i := rfl
|
||||
@[simp, grind =] theorem toArray_take {xs : Vector α n} {i} : (xs.take i).toArray = xs.toArray.take i := rfl
|
||||
|
||||
@[simp, grind] theorem toArray_zipIdx {xs : Vector α n} (k : Nat := 0) :
|
||||
@[simp, grind =] theorem toArray_zipIdx {xs : Vector α n} (k : Nat := 0) :
|
||||
(xs.zipIdx k).toArray = xs.toArray.zipIdx k := rfl
|
||||
|
||||
@[simp, grind] theorem toArray_zipWith {f : α → β → γ} {as : Vector α n} {bs : Vector β n} :
|
||||
@[simp, grind =] theorem toArray_zipWith {f : α → β → γ} {as : Vector α n} {bs : Vector β n} :
|
||||
(Vector.zipWith f as bs).toArray = Array.zipWith f as.toArray bs.toArray := rfl
|
||||
|
||||
@[simp, grind] theorem anyM_toArray [Monad m] {p : α → m Bool} {xs : Vector α n} :
|
||||
@[simp, grind =] theorem anyM_toArray [Monad m] {p : α → m Bool} {xs : Vector α n} :
|
||||
xs.toArray.anyM p = xs.anyM p := by
|
||||
cases xs
|
||||
simp
|
||||
|
||||
@[simp, grind] theorem allM_toArray [Monad m] {p : α → m Bool} {xs : Vector α n} :
|
||||
@[simp, grind =] theorem allM_toArray [Monad m] {p : α → m Bool} {xs : Vector α n} :
|
||||
xs.toArray.allM p = xs.allM p := by
|
||||
cases xs
|
||||
simp
|
||||
|
||||
@[simp, grind] theorem any_toArray {p : α → Bool} {xs : Vector α n} :
|
||||
@[simp, grind =] theorem any_toArray {p : α → Bool} {xs : Vector α n} :
|
||||
xs.toArray.any p = xs.any p := by
|
||||
cases xs
|
||||
simp
|
||||
|
||||
@[simp, grind] theorem all_toArray {p : α → Bool} {xs : Vector α n} :
|
||||
@[simp, grind =] theorem all_toArray {p : α → Bool} {xs : Vector α n} :
|
||||
xs.toArray.all p = xs.all p := by
|
||||
cases xs
|
||||
simp
|
||||
|
||||
@[simp, grind] theorem countP_toArray {p : α → Bool} {xs : Vector α n} :
|
||||
@[simp, grind =] theorem countP_toArray {p : α → Bool} {xs : Vector α n} :
|
||||
xs.toArray.countP p = xs.countP p := by
|
||||
cases xs
|
||||
simp
|
||||
|
||||
@[simp, grind] theorem count_toArray [BEq α] {a : α} {xs : Vector α n} :
|
||||
@[simp, grind =] theorem count_toArray [BEq α] {a : α} {xs : Vector α n} :
|
||||
xs.toArray.count a = xs.count a := by
|
||||
cases xs
|
||||
simp
|
||||
|
||||
@[simp, grind] theorem replace_toArray [BEq α] {xs : Vector α n} {a b} :
|
||||
@[simp, grind =] theorem replace_toArray [BEq α] {xs : Vector α n} {a b} :
|
||||
xs.toArray.replace a b = (xs.replace a b).toArray := rfl
|
||||
|
||||
@[simp, grind] theorem find?_toArray {p : α → Bool} {xs : Vector α n} :
|
||||
@[simp, grind =] theorem find?_toArray {p : α → Bool} {xs : Vector α n} :
|
||||
xs.toArray.find? p = xs.find? p := by
|
||||
cases xs
|
||||
simp
|
||||
|
||||
@[simp, grind] theorem findSome?_toArray {f : α → Option β} {xs : Vector α n} :
|
||||
@[simp, grind =] theorem findSome?_toArray {f : α → Option β} {xs : Vector α n} :
|
||||
xs.toArray.findSome? f = xs.findSome? f := by
|
||||
cases xs
|
||||
simp
|
||||
|
||||
@[simp, grind] theorem findRev?_toArray {p : α → Bool} {xs : Vector α n} :
|
||||
@[simp, grind =] theorem findRev?_toArray {p : α → Bool} {xs : Vector α n} :
|
||||
xs.toArray.findRev? p = xs.findRev? p := by
|
||||
cases xs
|
||||
simp
|
||||
|
||||
@[simp, grind] theorem findSomeRev?_toArray {f : α → Option β} {xs : Vector α n} :
|
||||
@[simp, grind =] theorem findSomeRev?_toArray {f : α → Option β} {xs : Vector α n} :
|
||||
xs.toArray.findSomeRev? f = xs.findSomeRev? f := by
|
||||
cases xs
|
||||
simp
|
||||
|
||||
@[simp, grind] theorem findM?_toArray [Monad m] {p : α → m Bool} {xs : Vector α n} :
|
||||
@[simp, grind =] theorem findM?_toArray [Monad m] {p : α → m Bool} {xs : Vector α n} :
|
||||
xs.toArray.findM? p = xs.findM? p := by
|
||||
cases xs
|
||||
simp
|
||||
|
||||
@[simp, grind] theorem findSomeM?_toArray [Monad m] {f : α → m (Option β)} {xs : Vector α n} :
|
||||
@[simp, grind =] theorem findSomeM?_toArray [Monad m] {f : α → m (Option β)} {xs : Vector α n} :
|
||||
xs.toArray.findSomeM? f = xs.findSomeM? f := by
|
||||
cases xs
|
||||
simp
|
||||
|
||||
@[simp, grind] theorem findRevM?_toArray [Monad m] {p : α → m Bool} {xs : Vector α n} :
|
||||
@[simp, grind =] theorem findRevM?_toArray [Monad m] {p : α → m Bool} {xs : Vector α n} :
|
||||
xs.toArray.findRevM? p = xs.findRevM? p := by
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
simp
|
||||
|
||||
@[simp, grind] theorem findSomeRevM?_toArray [Monad m] {f : α → m (Option β)} {xs : Vector α n} :
|
||||
@[simp, grind =] theorem findSomeRevM?_toArray [Monad m] {f : α → m (Option β)} {xs : Vector α n} :
|
||||
xs.toArray.findSomeRevM? f = xs.findSomeRevM? f := by
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
simp
|
||||
|
||||
@[simp, grind] theorem finIdxOf?_toArray [BEq α] {a : α} {xs : Vector α n} :
|
||||
@[simp, grind =] theorem finIdxOf?_toArray [BEq α] {a : α} {xs : Vector α n} :
|
||||
xs.toArray.finIdxOf? a = (xs.finIdxOf? a).map (Fin.cast xs.size_toArray.symm) := by
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
simp
|
||||
|
||||
@[simp, grind] theorem findFinIdx?_toArray {p : α → Bool} {xs : Vector α n} :
|
||||
@[simp, grind =] theorem findFinIdx?_toArray {p : α → Bool} {xs : Vector α n} :
|
||||
xs.toArray.findFinIdx? p = (xs.findFinIdx? p).map (Fin.cast xs.size_toArray.symm) := by
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
simp
|
||||
|
||||
@[simp, grind] theorem toArray_replicate : (replicate n a).toArray = Array.replicate n a := rfl
|
||||
@[simp, grind =] theorem toArray_replicate : (replicate n a).toArray = Array.replicate n a := rfl
|
||||
|
||||
@[deprecated toArray_replicate (since := "2025-03-18")]
|
||||
abbrev toArray_mkVector := @toArray_replicate
|
||||
@@ -503,13 +503,13 @@ protected theorem ext {xs ys : Vector α n} (h : (i : Nat) → (_ : i < n) → x
|
||||
|
||||
/-! ### toList -/
|
||||
|
||||
@[simp, grind] theorem length_toList {xs : Vector α n} : xs.toList.length = n := by
|
||||
@[simp, grind =] theorem length_toList {xs : Vector α n} : xs.toList.length = n := by
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
simp [toList]
|
||||
|
||||
@[grind =_] theorem toList_toArray {xs : Vector α n} : xs.toArray.toList = xs.toList := rfl
|
||||
|
||||
@[simp, grind] theorem toList_mk : (Vector.mk xs h).toList = xs.toList := rfl
|
||||
@[simp, grind =] theorem toList_mk : (Vector.mk xs h).toList = xs.toList := rfl
|
||||
|
||||
@[simp] theorem getElem_toList {xs : Vector α n} {i : Nat} (h : i < xs.toList.length) :
|
||||
xs.toList[i] = xs[i]'(by simpa using h) := by
|
||||
@@ -784,12 +784,12 @@ theorem singleton_inj : #v[a] = #v[b] ↔ a = b := by
|
||||
|
||||
/-! ### replicate -/
|
||||
|
||||
@[simp, grind] theorem replicate_zero : replicate 0 a = #v[] := rfl
|
||||
@[simp, grind =] theorem replicate_zero : replicate 0 a = #v[] := rfl
|
||||
|
||||
@[deprecated replicate_zero (since := "2025-03-18")]
|
||||
abbrev replicate_mkVector := @replicate_zero
|
||||
|
||||
@[grind]
|
||||
@[grind =]
|
||||
theorem replicate_succ : replicate (n + 1) a = (replicate n a).push a := by
|
||||
simp [replicate, Array.replicate_succ]
|
||||
|
||||
@@ -895,26 +895,35 @@ theorem getElem?_push_size {xs : Vector α n} {x : α} : (xs.push x)[n]? = some
|
||||
theorem getElem_singleton {a : α} (h : i < 1) : #v[a][i] = a := by
|
||||
simp
|
||||
|
||||
@[grind]
|
||||
@[grind =]
|
||||
theorem getElem?_singleton {a : α} {i : Nat} : #v[a][i]? = if i = 0 then some a else none := by
|
||||
simp [List.getElem?_singleton]
|
||||
|
||||
/-! ### mem -/
|
||||
|
||||
@[simp, grind] theorem getElem_mem {xs : Vector α n} {i : Nat} (h : i < n) : xs[i] ∈ xs := by
|
||||
@[simp] theorem getElem_mem {xs : Vector α n} {i : Nat} (h : i < n) : xs[i] ∈ xs := by
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
simp
|
||||
|
||||
grind_pattern getElem_mem => xs[i] ∈ xs
|
||||
|
||||
theorem not_mem_empty (a : α) : ¬ a ∈ #v[] := nofun
|
||||
|
||||
@[simp] theorem mem_push {xs : Vector α n} {x y : α} : x ∈ xs.push y ↔ x ∈ xs ∨ x = y := by
|
||||
@[simp, grind =] theorem mem_push {xs : Vector α n} {x y : α} : x ∈ xs.push y ↔ x ∈ xs ∨ x = y := by
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
simp
|
||||
|
||||
@[grind] theorem mem_or_eq_of_mem_push {a b : α} {xs : Vector α n} :
|
||||
theorem mem_or_eq_of_mem_push {a b : α} {xs : Vector α n} :
|
||||
a ∈ xs.push b → a ∈ xs ∨ a = b := Vector.mem_push.mp
|
||||
|
||||
@[grind] theorem mem_push_self {xs : Vector α n} {x : α} : x ∈ xs.push x :=
|
||||
-- This pattern may be excessively general:
|
||||
-- it fires anytime we ae thinking about membership of vectors,
|
||||
-- and constructing a list via `push`, even if the elements are unrelated.
|
||||
-- Nevertheless in practice it is quite helpful!
|
||||
grind_pattern mem_or_eq_of_mem_push => xs.push b, a ∈ xs
|
||||
|
||||
|
||||
theorem mem_push_self {xs : Vector α n} {x : α} : x ∈ xs.push x :=
|
||||
mem_push.2 (Or.inr rfl)
|
||||
|
||||
theorem eq_push_append_of_mem {xs : Vector α n} {x : α} (h : x ∈ xs) :
|
||||
@@ -926,7 +935,7 @@ theorem eq_push_append_of_mem {xs : Vector α n} {x : α} (h : x ∈ xs) :
|
||||
obtain rfl := h
|
||||
exact ⟨_, _, as.toVector, bs.toVector, by simp, by simp, by simpa using w⟩
|
||||
|
||||
@[grind] theorem mem_push_of_mem {xs : Vector α n} {x : α} (y : α) (h : x ∈ xs) : x ∈ xs.push y :=
|
||||
theorem mem_push_of_mem {xs : Vector α n} {x : α} (y : α) (h : x ∈ xs) : x ∈ xs.push y :=
|
||||
mem_push.2 (Or.inl h)
|
||||
|
||||
theorem exists_mem_of_size_pos {xs : Vector α n} (h : 0 < n) : ∃ x, x ∈ xs := by
|
||||
@@ -1213,9 +1222,9 @@ theorem contains_iff [BEq α] [LawfulBEq α] {a : α} {as : Vector α n} :
|
||||
instance [BEq α] [LawfulBEq α] (a : α) (as : Vector α n) : Decidable (a ∈ as) :=
|
||||
decidable_of_decidable_of_iff contains_iff
|
||||
|
||||
@[grind] theorem contains_empty [BEq α] : (#v[] : Vector α 0).contains a = false := by simp
|
||||
@[grind =] theorem contains_empty [BEq α] : (#v[] : Vector α 0).contains a = false := by simp
|
||||
|
||||
@[simp, grind] theorem contains_eq_mem [BEq α] [LawfulBEq α] {a : α} {as : Vector α n} :
|
||||
@[simp, grind =] theorem contains_eq_mem [BEq α] [LawfulBEq α] {a : α} {as : Vector α n} :
|
||||
as.contains a = decide (a ∈ as) := by
|
||||
rw [Bool.eq_iff_iff, contains_iff, decide_eq_true_iff]
|
||||
|
||||
@@ -1236,7 +1245,7 @@ instance [BEq α] [LawfulBEq α] (a : α) (as : Vector α n) : Decidable (a ∈
|
||||
|
||||
/-! ### set -/
|
||||
|
||||
@[grind] theorem getElem_set {xs : Vector α n} {i : Nat} {x : α} (hi : i < n) {j : Nat} (hj : j < n) :
|
||||
@[grind =] theorem getElem_set {xs : Vector α n} {i : Nat} {x : α} (hi : i < n) {j : Nat} (hj : j < n) :
|
||||
(xs.set i x hi)[j] = if i = j then x else xs[j] := by
|
||||
cases xs
|
||||
split <;> simp_all
|
||||
@@ -1249,7 +1258,7 @@ instance [BEq α] [LawfulBEq α] (a : α) (as : Vector α n) : Decidable (a ∈
|
||||
@[simp] theorem getElem_set_ne {xs : Vector α n} {x : α} (hi : i < n) (hj : j < n) (h : i ≠ j) :
|
||||
(xs.set i x hi)[j] = xs[j] := by simp [getElem_set, h]
|
||||
|
||||
@[grind] theorem getElem?_set {xs : Vector α n} {x : α} (hi : i < n) :
|
||||
@[grind =] theorem getElem?_set {xs : Vector α n} {x : α} (hi : i < n) :
|
||||
(xs.set i x hi)[j]? = if i = j then some x else xs[j]? := by
|
||||
cases xs
|
||||
split <;> simp_all
|
||||
@@ -1294,10 +1303,10 @@ grind_pattern mem_or_eq_of_mem_set => a ∈ xs.set i b
|
||||
|
||||
/-! ### setIfInBounds -/
|
||||
|
||||
@[simp, grind] theorem setIfInBounds_empty {i : Nat} {a : α} :
|
||||
@[simp, grind =] theorem setIfInBounds_empty {i : Nat} {a : α} :
|
||||
#v[].setIfInBounds i a = #v[] := rfl
|
||||
|
||||
@[grind] theorem getElem_setIfInBounds {xs : Vector α n} {x : α} (hj : j < n) :
|
||||
@[grind =] theorem getElem_setIfInBounds {xs : Vector α n} {x : α} (hj : j < n) :
|
||||
(xs.setIfInBounds i x)[j] = if i = j then x else xs[j] := by
|
||||
cases xs
|
||||
split <;> simp_all
|
||||
@@ -1310,7 +1319,7 @@ grind_pattern mem_or_eq_of_mem_set => a ∈ xs.set i b
|
||||
@[simp] theorem getElem_setIfInBounds_ne {xs : Vector α n} {x : α} (hj : j < n) (h : i ≠ j) :
|
||||
(xs.setIfInBounds i x)[j] = xs[j] := by simp [getElem_setIfInBounds, h]
|
||||
|
||||
@[grind] theorem getElem?_setIfInBounds {xs : Vector α n} {x : α} :
|
||||
@[grind =] theorem getElem?_setIfInBounds {xs : Vector α n} {x : α} :
|
||||
(xs.setIfInBounds i x)[j]? = if i = j then if i < n then some x else none else xs[j]? := by
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
simp [Array.getElem?_setIfInBounds]
|
||||
@@ -1347,7 +1356,7 @@ theorem mem_setIfInBounds {xs : Vector α n} {a : α} (hi : i < n) :
|
||||
|
||||
/-! ### BEq -/
|
||||
|
||||
@[simp, grind] theorem push_beq_push [BEq α] {a b : α} {n : Nat} {xs : Vector α n} {ys : Vector α n} :
|
||||
@[simp, grind =] theorem push_beq_push [BEq α] {a b : α} {n : Nat} {xs : Vector α n} {ys : Vector α n} :
|
||||
(xs.push a == ys.push b) = (xs == ys && a == b) := by
|
||||
cases xs
|
||||
cases ys
|
||||
@@ -1410,16 +1419,16 @@ abbrev mkVector_beq_mkVector := @replicate_beq_replicate
|
||||
|
||||
/-! ### back -/
|
||||
|
||||
@[grind] theorem back_singleton {a : α} : #v[a].back = a := by simp
|
||||
@[grind =] theorem back_singleton {a : α} : #v[a].back = a := by simp
|
||||
|
||||
@[grind]
|
||||
@[grind =]
|
||||
theorem back_eq_getElem [NeZero n] {xs : Vector α n} : xs.back = xs[n - 1]'(by have := NeZero.ne n; omega) := by
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
simp [Array.back_eq_getElem]
|
||||
|
||||
@[grind] theorem back?_empty : (#v[] : Vector α 0).back? = none := by simp
|
||||
@[grind =] theorem back?_empty : (#v[] : Vector α 0).back? = none := by simp
|
||||
|
||||
@[grind] theorem back?_eq_getElem? {xs : Vector α n} : xs.back? = xs[n - 1]? := by
|
||||
@[grind =] theorem back?_eq_getElem? {xs : Vector α n} : xs.back? = xs[n - 1]? := by
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
simp [Array.back?_eq_getElem?]
|
||||
|
||||
@@ -1430,22 +1439,22 @@ theorem back_eq_getElem [NeZero n] {xs : Vector α n} : xs.back = xs[n - 1]'(by
|
||||
/-! ### map -/
|
||||
|
||||
-- The argument `f : α → β` is explicit, to facilitate rewriting from right to left.
|
||||
@[simp, grind] theorem getElem_map (f : α → β) {xs : Vector α n} (hi : i < n) :
|
||||
@[simp, grind =] theorem getElem_map (f : α → β) {xs : Vector α n} (hi : i < n) :
|
||||
(xs.map f)[i] = f xs[i] := by
|
||||
cases xs
|
||||
simp
|
||||
|
||||
@[simp, grind] theorem getElem?_map {f : α → β} {xs : Vector α n} {i : Nat}:
|
||||
@[simp, grind =] theorem getElem?_map {f : α → β} {xs : Vector α n} {i : Nat}:
|
||||
(xs.map f)[i]? = xs[i]?.map f := by
|
||||
cases xs
|
||||
simp
|
||||
|
||||
/-- The empty vector maps to the empty vector. -/
|
||||
@[grind]
|
||||
@[grind =]
|
||||
theorem map_empty {f : α → β} : map f #v[] = #v[] := by
|
||||
simp
|
||||
|
||||
@[simp, grind] theorem map_push {f : α → β} {as : Vector α n} {x : α} :
|
||||
@[simp, grind =] theorem map_push {f : α → β} {as : Vector α n} {x : α} :
|
||||
(as.push x).map f = (as.map f).push (f x) := by
|
||||
cases as
|
||||
simp
|
||||
@@ -1620,7 +1629,7 @@ theorem append_push {as : Vector α n} {bs : Vector α m} {a : α} :
|
||||
|
||||
theorem singleton_eq_toVector_singleton {a : α} : #v[a] = #[a].toVector := rfl
|
||||
|
||||
@[simp, grind] theorem mem_append {a : α} {xs : Vector α n} {ys : Vector α m} :
|
||||
@[simp, grind =] theorem mem_append {a : α} {xs : Vector α n} {ys : Vector α m} :
|
||||
a ∈ xs ++ ys ↔ a ∈ xs ∨ a ∈ ys := by
|
||||
cases xs
|
||||
cases ys
|
||||
@@ -1656,16 +1665,16 @@ theorem forall_mem_append {p : α → Prop} {xs : Vector α n} {ys : Vector α m
|
||||
(∀ (x) (_ : x ∈ xs ++ ys), p x) ↔ (∀ (x) (_ : x ∈ xs), p x) ∧ (∀ (x) (_ : x ∈ ys), p x) := by
|
||||
simp only [mem_append, or_imp, forall_and]
|
||||
|
||||
@[simp, grind]
|
||||
@[simp, grind =]
|
||||
theorem empty_append {xs : Vector α n} : (#v[] : Vector α 0) ++ xs = xs.cast (by omega) := by
|
||||
rcases xs with ⟨as, rfl⟩
|
||||
simp
|
||||
|
||||
@[simp, grind]
|
||||
@[simp, grind =]
|
||||
theorem append_empty {xs : Vector α n} : xs ++ (#v[] : Vector α 0) = xs := by
|
||||
rw [← toArray_inj, toArray_append, Array.append_empty]
|
||||
|
||||
@[grind]
|
||||
@[grind =]
|
||||
theorem getElem_append {xs : Vector α n} {ys : Vector α m} (hi : i < n + m) :
|
||||
(xs ++ ys)[i] = if h : i < n then xs[i] else ys[i - n] := by
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
@@ -1692,7 +1701,7 @@ theorem getElem?_append_right {xs : Vector α n} {ys : Vector α m} (h : n ≤ i
|
||||
rcases ys with ⟨ys, rfl⟩
|
||||
simp [Array.getElem?_append_right, h]
|
||||
|
||||
@[grind]
|
||||
@[grind =]
|
||||
theorem getElem?_append {xs : Vector α n} {ys : Vector α m} {i : Nat} :
|
||||
(xs ++ ys)[i]? = if i < n then xs[i]? else ys[i - n]? := by
|
||||
split <;> rename_i h
|
||||
@@ -1771,7 +1780,7 @@ theorem append_eq_append_iff {ws : Vector α n} {xs : Vector α m} {ys : Vector
|
||||
right
|
||||
refine ⟨cs.toArray, ha, rfl⟩
|
||||
|
||||
@[simp, grind] theorem append_assoc {xs : Vector α n} {ys : Vector α m} {zs : Vector α k} :
|
||||
@[simp, grind =] theorem append_assoc {xs : Vector α n} {ys : Vector α m} {zs : Vector α k} :
|
||||
(xs ++ ys) ++ zs = (xs ++ (ys ++ zs)).cast (by omega) := by
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
rcases ys with ⟨ys, rfl⟩
|
||||
@@ -1779,14 +1788,14 @@ theorem append_eq_append_iff {ws : Vector α n} {xs : Vector α m} {ys : Vector
|
||||
simp [Array.append_assoc]
|
||||
|
||||
-- Variant for rewriting the other direction: we can't use `append_assoc` as it has a `cast` on the right-hand side.
|
||||
@[grind] theorem append_assoc_symm {xs : Vector α n} {ys : Vector α m} {zs : Vector α k} :
|
||||
@[grind =] theorem append_assoc_symm {xs : Vector α n} {ys : Vector α m} {zs : Vector α k} :
|
||||
xs ++ (ys ++ zs) = ((xs ++ ys) ++ zs).cast (by omega) := by
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
rcases ys with ⟨ys, rfl⟩
|
||||
rcases zs with ⟨zs, rfl⟩
|
||||
simp [Array.append_assoc]
|
||||
|
||||
@[grind] theorem set_append {xs : Vector α n} {ys : Vector α m} {i : Nat} {x : α} (h : i < n + m) :
|
||||
@[grind =] theorem set_append {xs : Vector α n} {ys : Vector α m} {i : Nat} {x : α} (h : i < n + m) :
|
||||
(xs ++ ys).set i x =
|
||||
if h' : i < n then
|
||||
xs.set i x ++ ys
|
||||
@@ -1806,7 +1815,7 @@ theorem append_eq_append_iff {ws : Vector α n} {xs : Vector α m} {ys : Vector
|
||||
(xs ++ ys).set i x = xs ++ ys.set (i - n) x := by
|
||||
rw [set_append, dif_neg (by omega)]
|
||||
|
||||
@[grind] theorem setIfInBounds_append {xs : Vector α n} {ys : Vector α m} {i : Nat} {x : α} :
|
||||
@[grind =] theorem setIfInBounds_append {xs : Vector α n} {ys : Vector α m} {i : Nat} {x : α} :
|
||||
(xs ++ ys).setIfInBounds i x =
|
||||
if i < n then
|
||||
xs.setIfInBounds i x ++ ys
|
||||
@@ -1826,7 +1835,7 @@ theorem append_eq_append_iff {ws : Vector α n} {xs : Vector α m} {ys : Vector
|
||||
(xs ++ ys).setIfInBounds i x = xs ++ ys.setIfInBounds (i - n) x := by
|
||||
rw [setIfInBounds_append, if_neg (by omega)]
|
||||
|
||||
@[simp, grind] theorem map_append {f : α → β} {xs : Vector α n} {ys : Vector α m} :
|
||||
@[simp, grind =] theorem map_append {f : α → β} {xs : Vector α n} {ys : Vector α m} :
|
||||
map f (xs ++ ys) = map f xs ++ map f ys := by
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
rcases ys with ⟨ys, rfl⟩
|
||||
@@ -1895,7 +1904,7 @@ theorem getElem?_flatten {xss : Vector (Vector β m) n} {i : Nat} :
|
||||
none := by
|
||||
simp [getElem?_def]
|
||||
|
||||
@[simp, grind] theorem flatten_singleton {xs : Vector α n} : #v[xs].flatten = xs.cast (by simp) := by
|
||||
@[simp, grind =] theorem flatten_singleton {xs : Vector α n} : #v[xs].flatten = xs.cast (by simp) := by
|
||||
simp [flatten]
|
||||
|
||||
set_option linter.listVariables false in
|
||||
@@ -1922,17 +1931,17 @@ theorem forall_mem_flatten {p : α → Prop} {xss : Vector (Vector α n) m} :
|
||||
induction xss using vector₂_induction with
|
||||
| of xss h₁ h₂ => simp
|
||||
|
||||
@[simp, grind] theorem flatten_append {xss₁ : Vector (Vector α n) m₁} {xss₂ : Vector (Vector α n) m₂} :
|
||||
@[simp, grind =] theorem flatten_append {xss₁ : Vector (Vector α n) m₁} {xss₂ : Vector (Vector α n) m₂} :
|
||||
flatten (xss₁ ++ xss₂) = (flatten xss₁ ++ flatten xss₂).cast (by simp [Nat.add_mul]) := by
|
||||
induction xss₁ using vector₂_induction
|
||||
induction xss₂ using vector₂_induction
|
||||
simp
|
||||
|
||||
@[grind] theorem append_flatten {xss₁ : Vector (Vector α n) m₁} {xss₂ : Vector (Vector α n) m₂} :
|
||||
@[grind =] theorem append_flatten {xss₁ : Vector (Vector α n) m₁} {xss₂ : Vector (Vector α n) m₂} :
|
||||
flatten xss₁ ++ flatten xss₂ = (flatten (xss₁ ++ xss₂)).cast (by simp [Nat.add_mul]) := by
|
||||
simp
|
||||
|
||||
@[grind] theorem flatten_push {xss : Vector (Vector α n) m} {xs : Vector α n} :
|
||||
@[grind =] theorem flatten_push {xss : Vector (Vector α n) m} {xs : Vector α n} :
|
||||
flatten (xss.push xs) = (flatten xss ++ xs).cast (by simp [Nat.add_mul]) := by
|
||||
induction xss using vector₂_induction
|
||||
rcases xs with ⟨xs⟩
|
||||
@@ -1982,10 +1991,10 @@ theorem flatMap_def {xs : Vector α n} {f : α → Vector β m} : xs.flatMap f =
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
simp [Array.flatMap_def, Function.comp_def]
|
||||
|
||||
@[simp, grind] theorem flatMap_empty {f : α → Vector β m} :
|
||||
@[simp, grind =] theorem flatMap_empty {f : α → Vector β m} :
|
||||
(#v[] : Vector α 0).flatMap f = #v[].cast (by simp) := rfl
|
||||
|
||||
@[simp, grind] theorem flatMap_push {xs : Vector α n} {x : α} {f : α → Vector β m} :
|
||||
@[simp, grind =] theorem flatMap_push {xs : Vector α n} {x : α} {f : α → Vector β m} :
|
||||
(xs.push x).flatMap f = (xs.flatMap f ++ f x).cast (by simp [Nat.add_mul]) := by
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
simp
|
||||
@@ -2011,7 +2020,7 @@ theorem getElem?_flatMap {xs : Vector α n} {f : α → Vector β m} {i : Nat} :
|
||||
|
||||
@[simp] theorem flatMap_id' {xss : Vector (Vector α m) n} : xss.flatMap (fun xs => xs) = xss.flatten := by simp [flatMap_def]
|
||||
|
||||
@[simp, grind] theorem mem_flatMap {f : α → Vector β m} {b} {xs : Vector α n} : b ∈ xs.flatMap f ↔ ∃ a, a ∈ xs ∧ b ∈ f a := by
|
||||
@[simp, grind =] theorem mem_flatMap {f : α → Vector β m} {b} {xs : Vector α n} : b ∈ xs.flatMap f ↔ ∃ a, a ∈ xs ∧ b ∈ f a := by
|
||||
simp [flatMap_def, mem_flatten]
|
||||
exact ⟨fun ⟨_, ⟨a, h₁, rfl⟩, h₂⟩ => ⟨a, h₁, h₂⟩, fun ⟨a, h₁, h₂⟩ => ⟨_, ⟨a, h₁, rfl⟩, h₂⟩⟩
|
||||
|
||||
@@ -2074,7 +2083,7 @@ theorem replicate_succ' : replicate (n + 1) a = (#v[a] ++ replicate n a).cast (b
|
||||
@[deprecated replicate_succ' (since := "2025-03-18")]
|
||||
abbrev mkVector_succ' := @replicate_succ'
|
||||
|
||||
@[simp, grind] theorem mem_replicate {a b : α} {n} : b ∈ replicate n a ↔ n ≠ 0 ∧ b = a := by
|
||||
@[simp, grind =] theorem mem_replicate {a b : α} {n} : b ∈ replicate n a ↔ n ≠ 0 ∧ b = a := by
|
||||
unfold replicate
|
||||
simp only [mem_mk]
|
||||
simp
|
||||
@@ -2094,14 +2103,14 @@ theorem forall_mem_replicate {p : α → Prop} {a : α} {n} :
|
||||
@[deprecated forall_mem_replicate (since := "2025-03-18")]
|
||||
abbrev forall_mem_mkVector := @forall_mem_replicate
|
||||
|
||||
@[simp, grind] theorem getElem_replicate {a : α} (h : i < n) : (replicate n a)[i] = a := by
|
||||
@[simp, grind =] theorem getElem_replicate {a : α} (h : i < n) : (replicate n a)[i] = a := by
|
||||
rw [replicate_eq_mk_replicate, getElem_mk]
|
||||
simp
|
||||
|
||||
@[deprecated getElem_replicate (since := "2025-03-18")]
|
||||
abbrev getElem_mkVector := @getElem_replicate
|
||||
|
||||
@[grind] theorem getElem?_replicate {a : α} {n i : Nat} : (replicate n a)[i]? = if i < n then some a else none := by
|
||||
@[grind =] theorem getElem?_replicate {a : α} {n i : Nat} : (replicate n a)[i]? = if i < n then some a else none := by
|
||||
simp [getElem?_def]
|
||||
|
||||
@[deprecated getElem?_replicate (since := "2025-03-18")]
|
||||
@@ -2227,16 +2236,16 @@ abbrev sum_mkVector := @sum_replicate_nat
|
||||
|
||||
theorem reverse_empty : reverse (#v[] : Vector α 0) = #v[] := rfl
|
||||
|
||||
@[simp, grind] theorem reverse_push {as : Vector α n} {a : α} :
|
||||
@[simp, grind =] theorem reverse_push {as : Vector α n} {a : α} :
|
||||
(as.push a).reverse = (#v[a] ++ as.reverse).cast (by omega) := by
|
||||
rcases as with ⟨as, rfl⟩
|
||||
simp [Array.reverse_push]
|
||||
|
||||
@[simp, grind] theorem mem_reverse {x : α} {as : Vector α n} : x ∈ as.reverse ↔ x ∈ as := by
|
||||
@[simp, grind =] theorem mem_reverse {x : α} {as : Vector α n} : x ∈ as.reverse ↔ x ∈ as := by
|
||||
cases as
|
||||
simp
|
||||
|
||||
@[simp, grind] theorem getElem_reverse {xs : Vector α n} {i : Nat} (hi : i < n) :
|
||||
@[simp, grind =] theorem getElem_reverse {xs : Vector α n} {i : Nat} (hi : i < n) :
|
||||
(xs.reverse)[i] = xs[n - 1 - i] := by
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
simp
|
||||
@@ -2252,14 +2261,14 @@ theorem getElem?_reverse' {xs : Vector α n} {i j : Nat} (h : i + j + 1 = n) : x
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
simpa using Array.getElem?_reverse' h
|
||||
|
||||
@[simp, grind]
|
||||
@[simp, grind =]
|
||||
theorem getElem?_reverse {xs : Vector α n} {i} (h : i < n) :
|
||||
xs.reverse[i]? = xs[n - 1 - i]? := by
|
||||
cases xs
|
||||
simp_all
|
||||
|
||||
-- The argument `xs : Vector α n` is explicit so we can rewrite from right to left.
|
||||
@[simp, grind] theorem reverse_reverse (xs : Vector α n) : xs.reverse.reverse = xs := by
|
||||
@[simp, grind =] theorem reverse_reverse (xs : Vector α n) : xs.reverse.reverse = xs := by
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
simp [Array.reverse_reverse]
|
||||
|
||||
@@ -2279,13 +2288,13 @@ theorem reverse_eq_iff {xs ys : Vector α n} : xs.reverse = ys ↔ xs = ys.rever
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
simp [Array.map_reverse]
|
||||
|
||||
@[simp, grind] theorem reverse_append {xs : Vector α n} {ys : Vector α m} :
|
||||
@[simp, grind =] theorem reverse_append {xs : Vector α n} {ys : Vector α m} :
|
||||
(xs ++ ys).reverse = (ys.reverse ++ xs.reverse).cast (by omega) := by
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
rcases ys with ⟨ys, rfl⟩
|
||||
simp [Array.reverse_append]
|
||||
|
||||
@[grind] theorem append_reverse {xs : Vector α n} {ys : Vector α m} :
|
||||
@[grind =] theorem append_reverse {xs : Vector α n} {ys : Vector α m} :
|
||||
ys.reverse ++ xs.reverse = (xs ++ ys).reverse.cast (by omega) := by
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
rcases ys with ⟨ys, rfl⟩
|
||||
@@ -2320,7 +2329,7 @@ theorem flatMap_reverse {xs : Vector α n} {f : α → Vector β m} :
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
simp [Array.flatMap_reverse, Function.comp_def]
|
||||
|
||||
@[simp, grind] theorem reverse_replicate {n : Nat} {a : α} : reverse (replicate n a) = replicate n a := by
|
||||
@[simp, grind =] theorem reverse_replicate {n : Nat} {a : α} : reverse (replicate n a) = replicate n a := by
|
||||
rw [← toArray_inj]
|
||||
simp
|
||||
|
||||
@@ -2345,7 +2354,7 @@ set_option linter.indexVariables false in
|
||||
rcases as with ⟨as, rfl⟩
|
||||
simp
|
||||
|
||||
@[grind] theorem extract_empty {start stop : Nat} :
|
||||
@[grind =] theorem extract_empty {start stop : Nat} :
|
||||
(#v[] : Vector α 0).extract start stop = #v[].cast (by simp) := by
|
||||
simp
|
||||
|
||||
@@ -2361,11 +2370,11 @@ theorem foldlM_empty [Monad m] {f : β → α → m β} {init : β} :
|
||||
foldlM f init #v[] = return init := by
|
||||
simp
|
||||
|
||||
@[grind] theorem foldrM_empty [Monad m] {f : α → β → m β} {init : β} :
|
||||
@[grind =] theorem foldrM_empty [Monad m] {f : α → β → m β} {init : β} :
|
||||
foldrM f init #v[] = return init := by
|
||||
simp
|
||||
|
||||
@[simp, grind] theorem foldlM_push [Monad m] [LawfulMonad m] {xs : Vector α n} {a : α} {f : β → α → m β} {b} :
|
||||
@[simp, grind =] theorem foldlM_push [Monad m] [LawfulMonad m] {xs : Vector α n} {a : α} {f : β → α → m β} {b} :
|
||||
(xs.push a).foldlM f b = xs.foldlM f b >>= fun b => f b a := by
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
simp
|
||||
@@ -2410,16 +2419,16 @@ theorem id_run_foldrM {f : α → β → Id β} {b} {xs : Vector α n} :
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
simp
|
||||
|
||||
@[simp, grind] theorem foldrM_push [Monad m] {f : α → β → m β} {init : β} {xs : Vector α n} {a : α} :
|
||||
@[simp, grind =] theorem foldrM_push [Monad m] {f : α → β → m β} {init : β} {xs : Vector α n} {a : α} :
|
||||
(xs.push a).foldrM f init = f a init >>= xs.foldrM f := by
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
simp
|
||||
|
||||
/-! ### foldl / foldr -/
|
||||
|
||||
@[grind] theorem foldl_empty {f : β → α → β} {init : β} : (#v[].foldl f init) = init := rfl
|
||||
@[grind =] theorem foldl_empty {f : β → α → β} {init : β} : (#v[].foldl f init) = init := rfl
|
||||
|
||||
@[grind] theorem foldr_empty {f : α → β → β} {init : β} : (#v[].foldr f init) = init := rfl
|
||||
@[grind =] theorem foldr_empty {f : α → β → β} {init : β} : (#v[].foldr f init) = init := rfl
|
||||
|
||||
@[congr]
|
||||
theorem foldl_congr {xs ys : Vector α n} (h₀ : xs = ys) {f g : β → α → β} (h₁ : f = g)
|
||||
@@ -2433,12 +2442,12 @@ theorem foldr_congr {xs ys : Vector α n} (h₀ : xs = ys) {f g : α → β →
|
||||
xs.foldr f a = ys.foldr g b := by
|
||||
congr
|
||||
|
||||
@[simp, grind] theorem foldl_push {f : β → α → β} {init : β} {xs : Vector α n} {a : α} :
|
||||
@[simp, grind =] theorem foldl_push {f : β → α → β} {init : β} {xs : Vector α n} {a : α} :
|
||||
(xs.push a).foldl f init = f (xs.foldl f init) a := by
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
simp
|
||||
|
||||
@[simp, grind] theorem foldr_push {f : α → β → β} {init : β} {xs : Vector α n} {a : α} :
|
||||
@[simp, grind =] theorem foldr_push {f : α → β → β} {init : β} {xs : Vector α n} {a : α} :
|
||||
(xs.push a).foldr f init = xs.foldr f (f a init) := by
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
simp
|
||||
@@ -2490,21 +2499,21 @@ theorem foldr_map_hom {g : α → β} {f : α → α → α} {f' : β → β →
|
||||
@[simp, grind _=_] theorem foldr_append {f : α → β → β} {b} {xs : Vector α n} {ys : Vector α k} :
|
||||
(xs ++ ys).foldr f b = xs.foldr f (ys.foldr f b) := foldrM_append
|
||||
|
||||
@[simp, grind] theorem foldl_flatten {f : β → α → β} {b} {xss : Vector (Vector α m) n} :
|
||||
@[simp, grind =] theorem foldl_flatten {f : β → α → β} {b} {xss : Vector (Vector α m) n} :
|
||||
(flatten xss).foldl f b = xss.foldl (fun b xs => xs.foldl f b) b := by
|
||||
cases xss using vector₂_induction
|
||||
simp [Array.foldl_flatten', Array.foldl_map']
|
||||
|
||||
@[simp, grind] theorem foldr_flatten {f : α → β → β} {b} {xss : Vector (Vector α m) n} :
|
||||
@[simp, grind =] theorem foldr_flatten {f : α → β → β} {b} {xss : Vector (Vector α m) n} :
|
||||
(flatten xss).foldr f b = xss.foldr (fun xs b => xs.foldr f b) b := by
|
||||
cases xss using vector₂_induction
|
||||
simp [Array.foldr_flatten', Array.foldr_map']
|
||||
|
||||
@[simp, grind] theorem foldl_reverse {xs : Vector α n} {f : β → α → β} {b} :
|
||||
@[simp, grind =] theorem foldl_reverse {xs : Vector α n} {f : β → α → β} {b} :
|
||||
xs.reverse.foldl f b = xs.foldr (fun x y => f y x) b :=
|
||||
foldlM_reverse
|
||||
|
||||
@[simp, grind] theorem foldr_reverse {xs : Vector α n} {f : α → β → β} {b} :
|
||||
@[simp, grind =] theorem foldr_reverse {xs : Vector α n} {f : α → β → β} {b} :
|
||||
xs.reverse.foldr f b = xs.foldl (fun x y => f y x) b :=
|
||||
(foldl_reverse ..).symm.trans <| by simp
|
||||
|
||||
@@ -2598,7 +2607,7 @@ theorem back?_eq_some_iff {xs : Vector α n} {a : α} :
|
||||
simp only [mk_append_mk, back_mk]
|
||||
rw [Array.back_append_of_size_pos]
|
||||
|
||||
@[grind] theorem back_append {xs : Vector α n} {ys : Vector α m} [NeZero (n + m)] :
|
||||
@[grind =] theorem back_append {xs : Vector α n} {ys : Vector α m} [NeZero (n + m)] :
|
||||
(xs ++ ys).back =
|
||||
if h' : m = 0 then
|
||||
have : NeZero n := by subst h'; simp_all
|
||||
@@ -2629,7 +2638,7 @@ theorem back_append_left {xs : Vector α n} {ys : Vector α 0} [NeZero n] :
|
||||
simp only [mk_append_mk, back_mk]
|
||||
rw [Array.back_append_left _ h]
|
||||
|
||||
@[simp, grind] theorem back?_append {xs : Vector α n} {ys : Vector α m} : (xs ++ ys).back? = ys.back?.or xs.back? := by
|
||||
@[simp, grind =] theorem back?_append {xs : Vector α n} {ys : Vector α m} : (xs ++ ys).back? = ys.back?.or xs.back? := by
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
rcases ys with ⟨ys, rfl⟩
|
||||
simp
|
||||
@@ -2681,24 +2690,28 @@ theorem contains_iff_exists_mem_beq [BEq α] {xs : Vector α n} {a : α} :
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
simp [Array.contains_iff_exists_mem_beq]
|
||||
|
||||
-- We add this as a `grind` lemma because it is useful without `LawfulBEq α`.
|
||||
-- With `LawfulBEq α`, it would be better to use `contains_iff_mem` directly.
|
||||
grind_pattern contains_iff_exists_mem_beq => xs.contains a
|
||||
|
||||
@[grind _=_]
|
||||
theorem contains_iff_mem [BEq α] [LawfulBEq α] {xs : Vector α n} {a : α} :
|
||||
xs.contains a ↔ a ∈ xs := by
|
||||
simp
|
||||
|
||||
@[simp, grind]
|
||||
@[simp, grind =]
|
||||
theorem contains_toList [BEq α] {xs : Vector α n} {x : α} :
|
||||
xs.toList.contains x = xs.contains x := by
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
simp
|
||||
|
||||
@[simp, grind]
|
||||
@[simp, grind =]
|
||||
theorem contains_toArray [BEq α] {xs : Vector α n} {x : α} :
|
||||
xs.toArray.contains x = xs.contains x := by
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
simp
|
||||
|
||||
@[simp, grind]
|
||||
@[simp, grind =]
|
||||
theorem contains_map [BEq β] {xs : Vector α n} {x : β} {f : α → β} :
|
||||
(xs.map f).contains x = xs.any (fun a => x == f a) := by
|
||||
rcases xs with ⟨xs⟩
|
||||
@@ -2723,19 +2736,19 @@ theorem contains_append [BEq α] {xs : Vector α n} {ys : Vector α m} {x : α}
|
||||
rcases ys with ⟨ys, rfl⟩
|
||||
simp
|
||||
|
||||
@[simp, grind]
|
||||
@[simp, grind =]
|
||||
theorem contains_flatten [BEq α] {xs : Vector (Vector α n) m} {x : α} :
|
||||
(xs.flatten).contains x = xs.any fun xs => xs.contains x := by
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
simp
|
||||
|
||||
@[simp, grind]
|
||||
@[simp, grind =]
|
||||
theorem contains_reverse [BEq α] {xs : Vector α n} {x : α} :
|
||||
(xs.reverse).contains x = xs.contains x := by
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
simp
|
||||
|
||||
@[simp, grind]
|
||||
@[simp, grind =]
|
||||
theorem contains_flatMap [BEq β] {xs : Vector α n} {f : α → Vector β m} {x : β} :
|
||||
(xs.flatMap f).contains x = xs.any fun a => (f a).contains x := by
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
@@ -2747,7 +2760,7 @@ theorem contains_flatMap [BEq β] {xs : Vector α n} {f : α → Vector β m} {x
|
||||
|
||||
@[simp] theorem pop_push {xs : Vector α n} {x : α} : (xs.push x).pop = xs := by simp [pop]
|
||||
|
||||
@[simp, grind] theorem getElem_pop {xs : Vector α n} {i : Nat} (h : i < n - 1) :
|
||||
@[simp, grind =] theorem getElem_pop {xs : Vector α n} {i : Nat} (h : i < n - 1) :
|
||||
xs.pop[i] = xs[i] := by
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
simp
|
||||
@@ -2760,7 +2773,7 @@ defeq issues in the implicit size argument.
|
||||
@getElem (Vector α n) Nat α (fun _ i => i < n) instGetElemNatLt xs.pop i h = xs[i] :=
|
||||
getElem_pop h
|
||||
|
||||
@[grind] theorem getElem?_pop {xs : Vector α n} {i : Nat} :
|
||||
@[grind =] theorem getElem?_pop {xs : Vector α n} {i : Nat} :
|
||||
xs.pop[i]? = if i < n - 1 then xs[i]? else none := by
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
simp [Array.getElem?_pop]
|
||||
@@ -2908,15 +2921,15 @@ theorem all_filterMap {xs : Vector α n} {f : α → Option β} {p : β → Bool
|
||||
unfold all
|
||||
apply allM_congr w h
|
||||
|
||||
@[simp, grind] theorem any_flatten {xss : Vector (Vector α n) m} : xss.flatten.any f = xss.any (any · f) := by
|
||||
@[simp, grind =] theorem any_flatten {xss : Vector (Vector α n) m} : xss.flatten.any f = xss.any (any · f) := by
|
||||
cases xss using vector₂_induction
|
||||
simp
|
||||
|
||||
@[simp, grind] theorem all_flatten {xss : Vector (Vector α n) m} : xss.flatten.all f = xss.all (all · f) := by
|
||||
@[simp, grind =] theorem all_flatten {xss : Vector (Vector α n) m} : xss.flatten.all f = xss.all (all · f) := by
|
||||
cases xss using vector₂_induction
|
||||
simp
|
||||
|
||||
@[simp, grind] theorem any_flatMap {xs : Vector α n} {f : α → Vector β m} {p : β → Bool} :
|
||||
@[simp, grind =] theorem any_flatMap {xs : Vector α n} {f : α → Vector β m} {p : β → Bool} :
|
||||
(xs.flatMap f).any p = xs.any fun a => (f a).any p := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simp only [flatMap_mk, any_mk, Array.size_flatMap, size_toArray, Array.any_flatMap']
|
||||
@@ -2925,7 +2938,7 @@ theorem all_filterMap {xs : Vector α n} {f : α → Option β} {p : β → Bool
|
||||
congr
|
||||
simp [Vector.size_toArray]
|
||||
|
||||
@[simp, grind] theorem all_flatMap {xs : Vector α n} {f : α → Vector β m} {p : β → Bool} :
|
||||
@[simp, grind =] theorem all_flatMap {xs : Vector α n} {f : α → Vector β m} {p : β → Bool} :
|
||||
(xs.flatMap f).all p = xs.all fun a => (f a).all p := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simp only [flatMap_mk, all_mk, Array.size_flatMap, size_toArray, Array.all_flatMap']
|
||||
@@ -2934,11 +2947,11 @@ theorem all_filterMap {xs : Vector α n} {f : α → Option β} {p : β → Bool
|
||||
congr
|
||||
simp [Vector.size_toArray]
|
||||
|
||||
@[simp, grind] theorem any_reverse {xs : Vector α n} : xs.reverse.any f = xs.any f := by
|
||||
@[simp, grind =] theorem any_reverse {xs : Vector α n} : xs.reverse.any f = xs.any f := by
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
simp
|
||||
|
||||
@[simp, grind] theorem all_reverse {xs : Vector α n} : xs.reverse.all f = xs.all f := by
|
||||
@[simp, grind =] theorem all_reverse {xs : Vector α n} : xs.reverse.all f = xs.all f := by
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
simp
|
||||
|
||||
@@ -2974,9 +2987,9 @@ variable [BEq α]
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
simp
|
||||
|
||||
@[simp, grind] theorem replace_empty : (#v[] : Vector α 0).replace a b = #v[] := by simp
|
||||
@[simp, grind =] theorem replace_empty : (#v[] : Vector α 0).replace a b = #v[] := by simp
|
||||
|
||||
@[grind] theorem replace_singleton {a b c : α} : #v[a].replace b c = #v[if a == b then c else a] := by
|
||||
@[grind =] theorem replace_singleton {a b c : α} : #v[a].replace b c = #v[if a == b then c else a] := by
|
||||
simp
|
||||
|
||||
-- This hypothesis could probably be dropped from some of the lemmas below,
|
||||
@@ -2987,7 +3000,7 @@ variable [LawfulBEq α]
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
simp_all
|
||||
|
||||
@[grind] theorem getElem?_replace {xs : Vector α n} {i : Nat} :
|
||||
@[grind =] theorem getElem?_replace {xs : Vector α n} {i : Nat} :
|
||||
(xs.replace a b)[i]? = if xs[i]? == some a then if a ∈ xs.take i then some a else some b else xs[i]? := by
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
simp [Array.getElem?_replace, -beq_iff_eq]
|
||||
@@ -2996,7 +3009,7 @@ theorem getElem?_replace_of_ne {xs : Vector α n} {i : Nat} (h : xs[i]? ≠ some
|
||||
(xs.replace a b)[i]? = xs[i]? := by
|
||||
simp_all [getElem?_replace]
|
||||
|
||||
@[grind] theorem getElem_replace {xs : Vector α n} {i : Nat} (h : i < n) :
|
||||
@[grind =] theorem getElem_replace {xs : Vector α n} {i : Nat} (h : i < n) :
|
||||
(xs.replace a b)[i] = if xs[i] == a then if a ∈ xs.take i then a else b else xs[i] := by
|
||||
apply Option.some.inj
|
||||
rw [← getElem?_eq_getElem, getElem?_replace]
|
||||
@@ -3007,7 +3020,7 @@ theorem getElem_replace_of_ne {xs : Vector α n} {i : Nat} {h : i < n} (h' : xs[
|
||||
rw [getElem_replace h]
|
||||
simp [h']
|
||||
|
||||
@[grind] theorem replace_append {xs : Vector α n} {ys : Vector α m} :
|
||||
@[grind =] theorem replace_append {xs : Vector α n} {ys : Vector α m} :
|
||||
(xs ++ ys).replace a b = if a ∈ xs then xs.replace a b ++ ys else xs ++ ys.replace a b := by
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
rcases ys with ⟨ys, rfl⟩
|
||||
@@ -3022,7 +3035,7 @@ theorem replace_append_right {xs : Vector α n} {ys : Vector α m} (h : ¬ a ∈
|
||||
(xs ++ ys).replace a b = xs ++ ys.replace a b := by
|
||||
simp [replace_append, h]
|
||||
|
||||
@[grind] theorem replace_push {xs : Vector α n} {a b c : α} :
|
||||
@[grind =] theorem replace_push {xs : Vector α n} {a b c : α} :
|
||||
(xs.push a).replace b c = if b ∈ xs then (xs.replace b c).push a else xs.push (if b == a then c else a) := by
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
simp only [push_mk, replace_mk, Array.replace_push, mem_mk]
|
||||
@@ -3091,7 +3104,7 @@ theorem take_size {as : Vector α n} : as.take n = as.cast (by simp) := by
|
||||
|
||||
/-! ### swap -/
|
||||
|
||||
@[grind] theorem getElem_swap {xs : Vector α n} {i j : Nat} (hi hj) {k : Nat} (hk : k < n) :
|
||||
@[grind =] theorem getElem_swap {xs : Vector α n} {i j : Nat} (hi hj) {k : Nat} (hk : k < n) :
|
||||
(xs.swap i j hi hj)[k] = if k = i then xs[j] else if k = j then xs[i] else xs[k] := by
|
||||
cases xs
|
||||
simp_all [Array.getElem_swap]
|
||||
@@ -3108,7 +3121,7 @@ theorem take_size {as : Vector α n} : as.take n = as.cast (by simp) := by
|
||||
(hi' : k ≠ i) (hj' : k ≠ j) : (xs.swap i j hi hj)[k] = xs[k] := by
|
||||
simp_all [getElem_swap]
|
||||
|
||||
@[grind]
|
||||
@[grind =]
|
||||
theorem getElem?_swap {xs : Vector α n} {i j : Nat} (hi hj) {k : Nat} : (xs.swap i j hi hj)[k]? =
|
||||
if j = k then some xs[i] else if i = k then some xs[j] else xs[k]? := by
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
|
||||
@@ -166,25 +166,25 @@ export LawfulGetElem (getElem?_def getElem!_def)
|
||||
instance (priority := low) [GetElem coll idx elem valid] [∀ xs i, Decidable (valid xs i)] :
|
||||
LawfulGetElem coll idx elem valid where
|
||||
|
||||
@[simp, grind] theorem getElem?_pos [GetElem? cont idx elem dom] [LawfulGetElem cont idx elem dom]
|
||||
@[simp, grind =] theorem getElem?_pos [GetElem? cont idx elem dom] [LawfulGetElem cont idx elem dom]
|
||||
(c : cont) (i : idx) (h : dom c i) : c[i]? = some (c[i]'h) := by
|
||||
have : Decidable (dom c i) := .isTrue h
|
||||
rw [getElem?_def]
|
||||
exact dif_pos h
|
||||
|
||||
@[simp, grind] theorem getElem?_neg [GetElem? cont idx elem dom] [LawfulGetElem cont idx elem dom]
|
||||
@[simp, grind =] theorem getElem?_neg [GetElem? cont idx elem dom] [LawfulGetElem cont idx elem dom]
|
||||
(c : cont) (i : idx) (h : ¬dom c i) : c[i]? = none := by
|
||||
have : Decidable (dom c i) := .isFalse h
|
||||
rw [getElem?_def]
|
||||
exact dif_neg h
|
||||
|
||||
@[simp, grind] theorem getElem!_pos [GetElem? cont idx elem dom] [LawfulGetElem cont idx elem dom]
|
||||
@[simp, grind =] theorem getElem!_pos [GetElem? cont idx elem dom] [LawfulGetElem cont idx elem dom]
|
||||
[Inhabited elem] (c : cont) (i : idx) (h : dom c i) :
|
||||
c[i]! = c[i]'h := by
|
||||
have : Decidable (dom c i) := .isTrue h
|
||||
simp [getElem!_def, h]
|
||||
|
||||
@[simp, grind] theorem getElem!_neg [GetElem? cont idx elem dom] [LawfulGetElem cont idx elem dom]
|
||||
@[simp, grind =] theorem getElem!_neg [GetElem? cont idx elem dom] [LawfulGetElem cont idx elem dom]
|
||||
[Inhabited elem] (c : cont) (i : idx) (h : ¬dom c i) : c[i]! = default := by
|
||||
have : Decidable (dom c i) := .isFalse h
|
||||
simp [getElem!_def, h]
|
||||
@@ -291,18 +291,20 @@ namespace List
|
||||
instance : GetElem (List α) Nat α fun as i => i < as.length where
|
||||
getElem as i h := as.get ⟨i, h⟩
|
||||
|
||||
@[simp, grind]
|
||||
@[simp, grind =]
|
||||
theorem getElem_cons_zero (a : α) (as : List α) (h : 0 < (a :: as).length) :
|
||||
getElem (a :: as) 0 h = a := rfl
|
||||
|
||||
@[simp, grind]
|
||||
@[simp, grind =]
|
||||
theorem getElem_cons_succ (a : α) (as : List α) (i : Nat) (h : i + 1 < (a :: as).length) : getElem (a :: as) (i+1) h = getElem as i (Nat.lt_of_succ_lt_succ h) :=
|
||||
rfl
|
||||
|
||||
@[simp, grind] theorem getElem_mem : ∀ {l : List α} {n} (h : n < l.length), l[n]'h ∈ l
|
||||
@[simp] theorem getElem_mem : ∀ {l : List α} {n} (h : n < l.length), l[n]'h ∈ l
|
||||
| _ :: _, 0, _ => .head ..
|
||||
| _ :: l, _+1, _ => .tail _ (getElem_mem (l := l) ..)
|
||||
|
||||
grind_pattern getElem_mem => l[n]'h ∈ l
|
||||
|
||||
theorem getElem_cons_drop_succ_eq_drop {as : List α} {i : Nat} (h : i < as.length) :
|
||||
as[i] :: as.drop (i+1) = as.drop i :=
|
||||
match as, i with
|
||||
|
||||
@@ -518,7 +518,7 @@ theorem Seq.contains_k_cons (y x : Var) (s : Seq) : Seq.contains_k (.cons y s) x
|
||||
|
||||
attribute [local simp] Seq.contains_k_var Seq.contains_k_cons
|
||||
|
||||
theorem Seq.denote_insert_of_contains {α} (ctx : Context α) {inst₁ : Std.Associative ctx.op} {inst₂ : Std.Commutative ctx.op} {inst₃ : Std.IdempotentOp ctx.op}
|
||||
theorem Seq.denote_insert_of_contains {α} (ctx : Context α) [inst₁ : Std.Associative ctx.op] [inst₂ : Std.Commutative ctx.op] [inst₃ : Std.IdempotentOp ctx.op]
|
||||
(s : Seq) (x : Var) : s.contains_k x → (s.insert x).denote ctx = s.denote ctx := by
|
||||
induction s
|
||||
next => simp; intro; subst x; rw [Std.IdempotentOp.idempotent (self := inst₃)]
|
||||
@@ -544,7 +544,68 @@ theorem superpose_ac_idempotent {α} (ctx : Context α) {inst₁ : Std.Associati
|
||||
simp [superpose_ac_idempotent_cert]; intro h₁ _ h₂; subst rhs
|
||||
replace h₂ : Seq.denote ctx (lhs₁.insert x) = Seq.denote ctx (rhs₁.insert x) := by
|
||||
simp [h₂]
|
||||
rw [← h₂, Seq.denote_insert_of_contains ctx lhs₁ x h₁] <;> assumption
|
||||
rw [← h₂, Seq.denote_insert_of_contains ctx lhs₁ x h₁]
|
||||
|
||||
noncomputable def Seq.startsWithVar_k (s : Seq) (x : Var) : Bool :=
|
||||
Seq.rec (fun y => Nat.beq x y) (fun y _ _ => Nat.beq x y) s
|
||||
|
||||
theorem Seq.startsWithVar_k_var (y x : Var) : Seq.startsWithVar_k (.var y) x = (x == y) := by
|
||||
simp [startsWithVar_k]; rw [Bool.eq_iff_iff]; simp
|
||||
|
||||
theorem Seq.startsWithVar_k_cons (y x : Var) (s : Seq) : Seq.startsWithVar_k (.cons y s) x = (x == y) := by
|
||||
simp [startsWithVar_k]; rw [Bool.eq_iff_iff]; simp
|
||||
|
||||
attribute [local simp] Seq.startsWithVar_k_var Seq.startsWithVar_k_cons
|
||||
|
||||
theorem Seq.denote_concat_of_startsWithVar {α} (ctx : Context α) [inst₁ : Std.Associative ctx.op] [inst₂ : Std.IdempotentOp ctx.op]
|
||||
(s : Seq) (x : Var) : s.startsWithVar_k x → (concat_k (.var x) s).denote ctx = s.denote ctx := by
|
||||
cases s <;> simp <;> intro <;> subst x
|
||||
next => rw [Std.IdempotentOp.idempotent (self := inst₂)]
|
||||
next => rw [← Std.Associative.assoc (self := inst₁), Std.IdempotentOp.idempotent (self := inst₂)]
|
||||
|
||||
noncomputable def superpose_head_idempotent_cert (x : Var) (lhs₁ rhs₁ rhs : Seq) : Bool :=
|
||||
lhs₁.startsWithVar_k x |>.and' (rhs.beq' (Seq.concat (.var x) rhs₁))
|
||||
|
||||
/--
|
||||
`superpose_ac_idempotent` for the non-commutative case. This is the "head"-case
|
||||
-/
|
||||
theorem superpose_head_idempotent {α} (ctx : Context α) {inst₁ : Std.Associative ctx.op} {inst₂ : Std.IdempotentOp ctx.op}
|
||||
(x : Var) (lhs₁ rhs₁ rhs : Seq) : superpose_head_idempotent_cert x lhs₁ rhs₁ rhs → lhs₁.denote ctx = rhs₁.denote ctx → lhs₁.denote ctx = rhs.denote ctx := by
|
||||
simp [superpose_head_idempotent_cert]; intro h₁ _ h₂; subst rhs
|
||||
replace h₂ : Seq.denote ctx (Seq.concat (.var x) lhs₁) = Seq.denote ctx (Seq.concat (.var x) rhs₁) := by
|
||||
simp [h₂]
|
||||
rw [← h₂, ← Seq.concat_k_eq_concat, Seq.denote_concat_of_startsWithVar ctx lhs₁ x h₁]
|
||||
|
||||
noncomputable def Seq.endsWithVar_k (s : Seq) (x : Var) : Bool :=
|
||||
Seq.rec (fun y => Nat.beq x y) (fun _ _ ih => ih) s
|
||||
|
||||
theorem Seq.endsWithVar_k_var (y x : Var) : Seq.endsWithVar_k (.var y) x = (x == y) := by
|
||||
simp [Seq.endsWithVar_k]; rw [Bool.eq_iff_iff]; simp
|
||||
|
||||
theorem Seq.endsWithVar_k_cons (y x : Var) (s : Seq) : Seq.endsWithVar_k (.cons y s) x = s.endsWithVar_k x := rfl
|
||||
|
||||
attribute [local simp] Seq.endsWithVar_k_var Seq.endsWithVar_k_cons
|
||||
|
||||
theorem Seq.denote_concat_of_endsWithVar {α} (ctx : Context α) [inst₁ : Std.Associative ctx.op] [inst₂ : Std.IdempotentOp ctx.op]
|
||||
(s : Seq) (x : Var) : s.endsWithVar_k x → (s.concat_k (.var x)).denote ctx = s.denote ctx := by
|
||||
induction s
|
||||
next => simp; intro; subst x; rw [Std.IdempotentOp.idempotent (self := inst₂)]
|
||||
next ih =>
|
||||
simp; intro h; replace ih := ih h
|
||||
simp at ih; rw [Std.Associative.assoc (self := inst₁), ih]
|
||||
|
||||
noncomputable def superpose_tail_idempotent_cert (x : Var) (lhs₁ rhs₁ rhs : Seq) : Bool :=
|
||||
lhs₁.endsWithVar_k x |>.and' (rhs.beq' (Seq.concat rhs₁ (.var x)))
|
||||
|
||||
/--
|
||||
`superpose_ac_idempotent` for the non-commutative case. It is similar to `superpose_head_idempotent` but for the "tail"-case
|
||||
-/
|
||||
theorem superpose_tail_idempotent {α} (ctx : Context α) {inst₁ : Std.Associative ctx.op} {inst₂ : Std.IdempotentOp ctx.op}
|
||||
(x : Var) (lhs₁ rhs₁ rhs : Seq) : superpose_tail_idempotent_cert x lhs₁ rhs₁ rhs → lhs₁.denote ctx = rhs₁.denote ctx → lhs₁.denote ctx = rhs.denote ctx := by
|
||||
simp [superpose_tail_idempotent_cert]; intro h₁ _ h₂; subst rhs
|
||||
replace h₂ : Seq.denote ctx (Seq.concat lhs₁ (.var x) ) = Seq.denote ctx (Seq.concat rhs₁ (.var x) ) := by
|
||||
simp [h₂]
|
||||
rw [← h₂, ← Seq.concat_k_eq_concat, Seq.denote_concat_of_endsWithVar ctx lhs₁ x h₁]
|
||||
|
||||
noncomputable def eq_norm_a_cert (lhs rhs : Expr) (lhs' rhs' : Seq) : Bool :=
|
||||
lhs.toSeq.beq' lhs' |>.and' (rhs.toSeq.beq' rhs')
|
||||
@@ -618,4 +679,37 @@ noncomputable def diseq_unsat_cert (lhs rhs : Seq) : Bool :=
|
||||
theorem diseq_unsat {α} (ctx : Context α) (lhs rhs : Seq) : diseq_unsat_cert lhs rhs → lhs.denote ctx ≠ rhs.denote ctx → False := by
|
||||
simp [diseq_unsat_cert]; intro; subst lhs; simp
|
||||
|
||||
theorem norm_a {α} (ctx : Context α) {_ : Std.Associative ctx.op} (e : Expr) (s : Seq)
|
||||
: e.toSeq.beq' s → e.denote ctx = s.denote ctx := by
|
||||
simp; intro _; subst s; simp
|
||||
|
||||
theorem norm_ac {α} (ctx : Context α) {_ : Std.Associative ctx.op} {_ : Std.Commutative ctx.op} (e : Expr) (s : Seq)
|
||||
: e.toSeq.sort.beq' s → e.denote ctx = s.denote ctx := by
|
||||
simp; intro _; subst s; simp
|
||||
|
||||
theorem norm_ai {α} (ctx : Context α) {_ : Std.Associative ctx.op} {_ : Std.LawfulIdentity ctx.op (Var.denote ctx 0)}
|
||||
(e : Expr) (s : Seq) : e.toSeq.erase0.beq' s → e.denote ctx = s.denote ctx := by
|
||||
simp; intro _; subst s; simp
|
||||
|
||||
theorem norm_aci {α} (ctx : Context α) {_ : Std.Associative ctx.op} {_ : Std.Commutative ctx.op} {_ : Std.LawfulIdentity ctx.op (Var.denote ctx 0)}
|
||||
(e : Expr) (s : Seq) : e.toSeq.erase0.sort.beq' s → e.denote ctx = s.denote ctx := by
|
||||
simp; intro _ ; subst s; simp
|
||||
|
||||
theorem eq_erase0_rhs {α} (ctx : Context α) {_ : Std.Associative ctx.op} {_ : Std.LawfulIdentity ctx.op (Var.denote ctx 0)}
|
||||
(lhs rhs rhs' : Seq) : rhs.erase0.beq' rhs' → lhs.denote ctx = rhs.denote ctx → lhs.denote ctx = rhs'.denote ctx := by
|
||||
simp; intro _ _; subst rhs'; simp [*]
|
||||
|
||||
theorem eq_erase_dup_rhs {α} (ctx : Context α) {_ : Std.Associative ctx.op} {_ : Std.IdempotentOp ctx.op}
|
||||
(lhs rhs rhs' : Seq) : rhs.eraseDup.beq' rhs' → lhs.denote ctx = rhs.denote ctx → lhs.denote ctx = rhs'.denote ctx := by
|
||||
simp; intro _ _; subst rhs'; simp [*]
|
||||
|
||||
theorem eq_expr_seq_seq {α} (ctx : Context α) (e : Expr) (s₁ s₂ : Seq) : e.denote ctx = s₁.denote ctx → s₁.denote ctx = s₂.denote ctx → e.denote ctx = s₂.denote ctx := by
|
||||
apply Eq.trans
|
||||
|
||||
theorem imp_eq {α} (ctx : Context α) (lhs rhs : Expr) (s : Seq)
|
||||
: lhs.denote ctx = s.denote ctx → rhs.denote ctx = s.denote ctx → lhs.denote ctx = rhs.denote ctx := by
|
||||
simp_all
|
||||
|
||||
theorem refl {α} (ctx : Context α) (s : Seq) : s.denote ctx = s.denote ctx := (rfl)
|
||||
|
||||
end Lean.Grind.AC
|
||||
|
||||
@@ -95,7 +95,7 @@ Ordinarily, the grind attribute does not consider the `=` symbol when generating
|
||||
-/
|
||||
syntax grindEqBwd := patternIgnore(atomic("←" "=") <|> atomic("<-" "="))
|
||||
/--
|
||||
The `→` modifier instructs `grind` to select a multi-pattern from the conclusion of theorem.
|
||||
The `←` modifier instructs `grind` to select a multi-pattern from the conclusion of theorem.
|
||||
In other words, `grind` will use the theorem for backwards reasoning.
|
||||
This may fail if not all of the arguments to the theorem appear in the conclusion.
|
||||
-/
|
||||
|
||||
@@ -4,10 +4,9 @@ Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Kim Morrison
|
||||
-/
|
||||
module
|
||||
|
||||
prelude
|
||||
public import Init.Grind.Module.Basic
|
||||
public import Init.Grind.Module.Envelope
|
||||
public import Init.Grind.Module.OfNatModule
|
||||
|
||||
public import Init.Grind.Module.NatModuleNorm
|
||||
public section
|
||||
|
||||
@@ -227,7 +227,7 @@ theorem toQ_add (a b : α) : toQ (a + b) = toQ a + toQ b := by
|
||||
theorem toQ_zero : toQ (0 : α) = 0 := by
|
||||
simp; apply Quot.sound; simp
|
||||
|
||||
theorem toQ_smul (n : Nat) (a : α) : toQ (n • a) = (↑n : Int) • toQ a := by
|
||||
theorem toQ_smul (n : Nat) (a : α) : toQ (n • a) = n • toQ a := by
|
||||
simp; apply Quot.sound; simp
|
||||
|
||||
/-!
|
||||
@@ -318,6 +318,29 @@ instance [LE α] [IsPreorder α] [OrderedAdd α] : IsPreorder (OfNatModule.Q α)
|
||||
rw [this]; clear this
|
||||
exact OrderedAdd.add_le_add h₁ h₂
|
||||
|
||||
instance [LE α] [IsPartialOrder α] [OrderedAdd α] : IsPartialOrder (OfNatModule.Q α) where
|
||||
le_antisymm a b h₁ h₂ := by
|
||||
induction a using Q.ind with | _ a
|
||||
induction b using Q.ind with | _ b
|
||||
rcases a with ⟨a₁, a₂⟩; rcases b with ⟨b₁, b₂⟩
|
||||
simp only [mk_le_mk] at h₁ h₂
|
||||
rw [AddCommMonoid.add_comm b₁ a₂, AddCommMonoid.add_comm b₂ a₁] at h₂
|
||||
have := IsPartialOrder.le_antisymm _ _ h₁ h₂
|
||||
apply Quot.sound
|
||||
simp; exists 0
|
||||
rw [this]
|
||||
|
||||
instance [LE α] [IsLinearPreorder α] [OrderedAdd α] : IsLinearPreorder (OfNatModule.Q α) where
|
||||
le_total a b := by
|
||||
induction a using Q.ind with | _ a
|
||||
induction b using Q.ind with | _ b
|
||||
rcases a with ⟨a₁, a₂⟩; rcases b with ⟨b₁, b₂⟩
|
||||
simp only [mk_le_mk]
|
||||
rw [AddCommMonoid.add_comm b₁ a₂, AddCommMonoid.add_comm b₂ a₁]
|
||||
apply le_total
|
||||
|
||||
instance [LE α] [IsLinearOrder α] [OrderedAdd α] : IsLinearOrder (OfNatModule.Q α) where
|
||||
|
||||
attribute [-simp] Q.mk
|
||||
|
||||
@[local simp] private theorem mk_lt_mk
|
||||
|
||||
199
src/Init/Grind/Module/NatModuleNorm.lean
Normal file
199
src/Init/Grind/Module/NatModuleNorm.lean
Normal file
@@ -0,0 +1,199 @@
|
||||
/-
|
||||
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.Module.Envelope
|
||||
public import Init.Grind.Ordered.Linarith
|
||||
@[expose] public section
|
||||
namespace Lean.Grind.Linarith
|
||||
open Std
|
||||
|
||||
def Expr.denoteN {α} [NatModule α] (ctx : Context α) : Expr → α
|
||||
| .sub .. | .neg .. | .intMul ..
|
||||
| zero => 0
|
||||
| .var v => v.denote ctx
|
||||
| .add a b => denoteN ctx a + denoteN ctx b
|
||||
| .natMul k a => k • denoteN ctx a
|
||||
|
||||
inductive Poly.NonnegCoeffs : Poly → Prop
|
||||
| nil : NonnegCoeffs .nil
|
||||
| add (a : Int) (x : Var) (p : Poly) : a ≥ 0 → NonnegCoeffs p → NonnegCoeffs (.add a x p)
|
||||
|
||||
def Poly.denoteN {α} [NatModule α] (ctx : Context α) (p : Poly) : α :=
|
||||
match p with
|
||||
| .nil => 0
|
||||
| .add k v p =>
|
||||
bif k < 0 then
|
||||
0
|
||||
else
|
||||
k.natAbs • v.denote ctx + denoteN ctx p
|
||||
|
||||
def Poly.denoteN_nil {α} [NatModule α] (ctx : Context α) : Poly.denoteN ctx .nil = 0 := rfl
|
||||
|
||||
def Poly.denoteN_add {α} [NatModule α] (ctx : Context α) (k : Int) (x : Var) (p : Poly)
|
||||
: k ≥ 0 → Poly.denoteN ctx (.add k x p) = k.toNat • x.denote ctx + p.denoteN ctx := by
|
||||
intro h; simp [denoteN, cond_eq_if]; split
|
||||
next => omega
|
||||
next =>
|
||||
have : (k.natAbs : Int) = k.toNat := by
|
||||
rw [Int.toNat_of_nonneg h, Int.natAbs_of_nonneg h]
|
||||
rw [Int.ofNat_inj.mp this]
|
||||
|
||||
attribute [local simp] Poly.denoteN_nil Poly.denoteN_add
|
||||
open AddCommMonoid AddCommGroup NatModule IntModule
|
||||
|
||||
-- Helper instance for `ac_rfl`
|
||||
local instance {α} [NatModule α] : Std.Associative (· + · : α → α → α) where
|
||||
assoc := AddCommMonoid.add_assoc
|
||||
-- Helper instance for `ac_rfl`
|
||||
local instance {α} [NatModule α] : Std.Commutative (· + · : α → α → α) where
|
||||
comm := AddCommMonoid.add_comm
|
||||
|
||||
theorem Poly.denoteN_insert {α} [NatModule α] (ctx : Context α) (k : Int) (x : Var) (p : Poly)
|
||||
: k ≥ 0 → p.NonnegCoeffs → (insert k x p).denoteN ctx = k.toNat • x.denote ctx + p.denoteN ctx := by
|
||||
fun_induction insert
|
||||
next => intros; simp [*]
|
||||
next => intro h₁ h₂; cases h₂; simp [*]
|
||||
next h₁ h₂ h₃ =>
|
||||
intro h₄ h₅; cases h₅; simp [*]
|
||||
simp at h₃; simp at h₂; subst h₂
|
||||
rw [← add_assoc, ← add_nsmul, ← Int.toNat_add, h₃, Int.toNat_zero, zero_nsmul, zero_add] <;> assumption
|
||||
next h _ =>
|
||||
intro h₁ h₂; cases h₂; rw [denoteN_add] <;> simp <;> try omega
|
||||
next h₂ _ =>
|
||||
simp at h; subst h;
|
||||
rw [Int.toNat_add h₁ h₂, add_nsmul]; simp [*]; ac_rfl
|
||||
next ih =>
|
||||
intro h₁ h₂; cases h₂; simp [*]; ac_rfl
|
||||
|
||||
attribute [local simp] Poly.denoteN_insert
|
||||
|
||||
theorem Poly.denoteN_append {α} [NatModule α] (ctx : Context α) (p₁ p₂ : Poly)
|
||||
: p₁.NonnegCoeffs → p₂.NonnegCoeffs → (append p₁ p₂).denoteN ctx = p₁.denoteN ctx + p₂.denoteN ctx := by
|
||||
fun_induction append <;> intro h₁ h₂; simp [*]
|
||||
next => rw [zero_add]
|
||||
next ih => cases h₁; next hn₁ hn₂ => simp [ih hn₂ h₂, *]; ac_rfl
|
||||
|
||||
attribute [local simp] Poly.denoteN_append
|
||||
|
||||
theorem Poly.denoteN_combine' {α} [NatModule α] (ctx : Context α) (fuel : Nat) (p₁ p₂ : Poly)
|
||||
: p₁.NonnegCoeffs → p₂.NonnegCoeffs → (p₁.combine' fuel p₂).denoteN ctx = p₁.denoteN ctx + p₂.denoteN ctx := by
|
||||
fun_induction p₁.combine' fuel p₂ <;> intro h₁ h₂ <;> try simp [*, zero_add, add_zero]
|
||||
next hx _ h ih =>
|
||||
simp at hx
|
||||
simp +zetaDelta at h
|
||||
cases h₁; cases h₂
|
||||
next h₁ _ h₂ =>
|
||||
simp [ih h₁ h₂, *]
|
||||
rw [add_left_comm, add_assoc, ← add_assoc, ← add_nsmul, ← Int.toNat_add, Int.add_comm, h,
|
||||
Int.toNat_zero, zero_nsmul, zero_add] <;> assumption
|
||||
next hx _ h ih =>
|
||||
simp at hx
|
||||
cases h₁; cases h₂
|
||||
next hp₁ h₁ hp₂ h₂ =>
|
||||
simp +zetaDelta [*]
|
||||
rw [denoteN_add, ih h₁ h₂, Int.toNat_add hp₁ hp₂, add_nsmul]; ac_rfl; omega
|
||||
next ih =>
|
||||
cases h₁; next h₁ =>
|
||||
simp [ih h₁ h₂, *]; ac_rfl
|
||||
next ih =>
|
||||
cases h₂; next h₂ =>
|
||||
simp [ih h₁ h₂, *]; ac_rfl
|
||||
|
||||
theorem Poly.denoteN_combine {α} [NatModule α] (ctx : Context α) (p₁ p₂ : Poly)
|
||||
: p₁.NonnegCoeffs → p₂.NonnegCoeffs → (p₁.combine p₂).denoteN ctx = p₁.denoteN ctx + p₂.denoteN ctx := by
|
||||
intros; simp [combine, denoteN_combine', *]
|
||||
|
||||
theorem Poly.denoteN_mul' {α} [NatModule α] (ctx : Context α) (p : Poly) (k : Nat) : p.NonnegCoeffs → (p.mul' k).denoteN ctx = k • p.denoteN ctx := by
|
||||
induction p <;> simp [mul', *, nsmul_zero]
|
||||
next ih =>
|
||||
intro h; cases h; next hp h =>
|
||||
have hk : (k : Int) ≥ 0 := by simp
|
||||
simp [*]
|
||||
rw [denoteN_add, Int.toNat_mul, mul_nsmul, Int.toNat_natCast, nsmul_add, ih h]
|
||||
assumption; assumption;
|
||||
exact Int.mul_nonneg hk hp
|
||||
|
||||
theorem Poly.denoteN_mul {α} [NatModule α] (ctx : Context α) (p : Poly) (k : Nat) : p.NonnegCoeffs → (p.mul k).denoteN ctx = k • p.denoteN ctx := by
|
||||
simp [mul]; intro h
|
||||
split
|
||||
next => simp [*, zero_nsmul]
|
||||
next => simp [denoteN_mul', *]
|
||||
|
||||
def Expr.toPolyN : Expr → Poly
|
||||
| .sub .. | .neg .. | .intMul ..
|
||||
| zero => .nil
|
||||
| .var v => .add 1 v .nil
|
||||
| .add a b => a.toPolyN.combine b.toPolyN
|
||||
| .natMul k a => a.toPolyN.mul k
|
||||
|
||||
theorem Poly.mul'_Nonneg (p : Poly) (k : Nat) : p.NonnegCoeffs → (p.mul' k).NonnegCoeffs := by
|
||||
induction p
|
||||
next => intro; simp [mul']; assumption
|
||||
next ih =>
|
||||
have hk : (k : Int) ≥ 0 := by simp
|
||||
intro h; cases h; next hp h =>
|
||||
simp [mul']
|
||||
constructor
|
||||
next => exact Int.mul_nonneg hk hp
|
||||
next => exact ih h
|
||||
|
||||
theorem Poly.mul_Nonneg (p : Poly) (k : Nat) : p.NonnegCoeffs → (p.mul k).NonnegCoeffs := by
|
||||
simp [mul]; intro h
|
||||
split
|
||||
next => constructor
|
||||
next => simp [Poly.mul'_Nonneg, *]
|
||||
|
||||
theorem Poly.append_Nonneg (p₁ p₂ : Poly) : p₁.NonnegCoeffs → p₂.NonnegCoeffs → (p₁.append p₂).NonnegCoeffs := by
|
||||
fun_induction append <;> intro h₁ h₂; simp [*]
|
||||
next ih => cases h₁; constructor; assumption; apply ih <;> assumption
|
||||
|
||||
theorem Poly.combine'_Nonneg (fuel : Nat) (p₁ p₂ : Poly) : p₁.NonnegCoeffs → p₂.NonnegCoeffs → (p₁.combine' fuel p₂).NonnegCoeffs := by
|
||||
fun_induction Poly.combine'
|
||||
next => apply Poly.append_Nonneg
|
||||
next => intros; assumption
|
||||
next => intros; assumption
|
||||
next ih =>
|
||||
intro h₁ h₂; cases h₁; cases h₂
|
||||
apply ih <;> assumption
|
||||
next h ih =>
|
||||
intro h₁ h₂; cases h₁; cases h₂
|
||||
constructor; simp +zetaDelta; omega
|
||||
apply ih <;> assumption
|
||||
next ih =>
|
||||
intro h₁ h₂; cases h₁; cases h₂
|
||||
constructor; simp +zetaDelta; omega
|
||||
apply ih; assumption; constructor; assumption; assumption
|
||||
next ih =>
|
||||
intro h₁ h₂; cases h₁; cases h₂
|
||||
constructor; assumption
|
||||
apply ih; constructor; assumption; assumption; assumption
|
||||
|
||||
theorem Poly.combine_Nonneg (p₁ p₂ : Poly) : p₁.NonnegCoeffs → p₂.NonnegCoeffs → (p₁.combine p₂).NonnegCoeffs := by
|
||||
simp [combine]; apply Poly.combine'_Nonneg
|
||||
|
||||
theorem Expr.toPolyN_Nonneg (e : Expr) : e.toPolyN.NonnegCoeffs := by
|
||||
fun_induction toPolyN <;> try constructor <;> simp
|
||||
next => constructor; simp; constructor
|
||||
next => apply Poly.combine_Nonneg <;> assumption
|
||||
next => apply Poly.mul_Nonneg; assumption
|
||||
|
||||
theorem Expr.denoteN_toPolyN {α} [NatModule α] (ctx : Context α) (e : Expr) : e.toPolyN.denoteN ctx = e.denoteN ctx := by
|
||||
fun_induction toPolyN <;> simp [denoteN, add_zero, one_nsmul]
|
||||
next => rw [Poly.denoteN_combine]; simp [*]; apply toPolyN_Nonneg; apply toPolyN_Nonneg
|
||||
next => rw [Poly.denoteN_mul]; simp [*]; apply toPolyN_Nonneg
|
||||
|
||||
def eq_normN_cert (lhs rhs : Expr) : Bool :=
|
||||
lhs.toPolyN == rhs.toPolyN
|
||||
|
||||
theorem eq_normN {α} [NatModule α] (ctx : Context α) (lhs rhs : Expr)
|
||||
: eq_normN_cert lhs rhs → lhs.denoteN ctx = rhs.denoteN ctx := by
|
||||
simp [eq_normN_cert]; intro h
|
||||
replace h := congrArg (Poly.denoteN ctx) h
|
||||
simp [Expr.denoteN_toPolyN, *] at h
|
||||
assumption
|
||||
|
||||
end Lean.Grind.Linarith
|
||||
@@ -4,13 +4,11 @@ Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Leonardo de Moura
|
||||
-/
|
||||
module
|
||||
|
||||
prelude
|
||||
import Init.Grind.Module.Envelope
|
||||
|
||||
open Std
|
||||
|
||||
public import Init.Grind.Module.Envelope
|
||||
public section
|
||||
namespace Lean.Grind.IntModule.OfNatModule
|
||||
open Std
|
||||
|
||||
/-!
|
||||
Support for `NatModule` in the `grind` linear arithmetic module.
|
||||
@@ -44,8 +42,7 @@ theorem add_congr {α} [NatModule α] {a b : α} {a' b' : Q α}
|
||||
(h₁ : toQ a = a') (h₂ : toQ b = b') : toQ (a + b) = a' + b' := by
|
||||
rw [toQ_add, h₁, h₂]
|
||||
|
||||
theorem smul_congr {α} [NatModule α] (n : Nat) (a : α) (i : Int) (a' : Q α)
|
||||
(h₁ : ↑n == i) (h₂ : toQ a = a') : toQ (n • a) = i • a' := by
|
||||
simp at h₁; rw [← h₁, ← h₂, toQ_smul]
|
||||
theorem smul_congr {α} [NatModule α] (n : Nat) (a : α) (a' : Q α) (h : toQ a = a') : toQ (n • a) = n • a' := by
|
||||
rw [← h, toQ_smul]
|
||||
|
||||
end Lean.Grind.IntModule.OfNatModule
|
||||
|
||||
@@ -205,5 +205,13 @@ init_grind_norm
|
||||
Field.inv_zero Field.inv_inv Field.inv_one Field.inv_neg
|
||||
-- SMul normalizer
|
||||
smul_int_eq_mul smul_nat_eq_mul
|
||||
-- NatCast & IntCast for algebraic structures
|
||||
Semiring.natCast_add
|
||||
Semiring.natCast_pow
|
||||
Semiring.natCast_mul
|
||||
Ring.intCast_add
|
||||
Ring.intCast_mul
|
||||
Ring.intCast_pow
|
||||
Ring.intCast_sub
|
||||
|
||||
end Lean.Grind
|
||||
|
||||
@@ -7,6 +7,7 @@ module
|
||||
|
||||
prelude
|
||||
public import Init.NotationExtra
|
||||
meta import Init.Data.String.Basic
|
||||
|
||||
public section
|
||||
|
||||
|
||||
@@ -169,7 +169,8 @@ 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]
|
||||
|
||||
instance [IsCharP α 0] : NoNatZeroDivisors α := NoNatZeroDivisors.mk' <| by
|
||||
-- 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
|
||||
have := IsCharP.natCast_eq_zero_iff (α := α) 0 a
|
||||
simp only [Nat.mod_zero, h, iff_false] at this
|
||||
|
||||
@@ -126,6 +126,52 @@ structure Config where
|
||||
abstractProof := true
|
||||
deriving Inhabited, BEq
|
||||
|
||||
/--
|
||||
A minimal configuration, with ematching and splitting disabled, and all solver modules turned off.
|
||||
`grind` will not do anything in this configuration,
|
||||
which can be used a starting point for minimal configurations.
|
||||
-/
|
||||
-- This is a `structure` rather than `def` so we can use `declare_config_elab`.
|
||||
structure NoopConfig extends Config where
|
||||
-- Disable splitting
|
||||
splits := 0
|
||||
-- We don't override the various `splitMatch` / `splitIte` settings separately.
|
||||
|
||||
-- Disable e-matching
|
||||
ematch := 0
|
||||
-- We don't override `matchEqs` separately.
|
||||
|
||||
-- Disable extensionality
|
||||
ext := false
|
||||
extAll := false
|
||||
etaStruct := false
|
||||
funext := false
|
||||
|
||||
-- Disable all solver modules
|
||||
ring := false
|
||||
linarith := false
|
||||
cutsat := false
|
||||
ac := false
|
||||
|
||||
/--
|
||||
A `grind` configuration that only uses `cutsat` and splitting.
|
||||
|
||||
Note: `cutsat` benefits from some amount of instantiation, e.g. `Nat.max_def`.
|
||||
We don't currently have a mechanism to enable only a small set of lemmas.
|
||||
-/
|
||||
-- This is a `structure` rather than `def` so we can use `declare_config_elab`.
|
||||
structure CutsatConfig extends NoopConfig where
|
||||
cutsat := true
|
||||
-- Allow the default number of splits.
|
||||
splits := ({} : Config).splits
|
||||
|
||||
/--
|
||||
A `grind` configuration that only uses `ring`.
|
||||
-/
|
||||
-- This is a `structure` rather than `def` so we can use `declare_config_elab`.
|
||||
structure GrobnerConfig extends NoopConfig where
|
||||
ring := true
|
||||
|
||||
end Lean.Grind
|
||||
|
||||
namespace Lean.Parser.Tactic
|
||||
@@ -420,6 +466,23 @@ syntax (name := grindTrace)
|
||||
(" [" withoutPosition(grindParam,*) "]")?
|
||||
(&" on_failure " term)? : tactic
|
||||
|
||||
/--
|
||||
`cutsat` 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 := cutsat) "cutsat" 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.
|
||||
|
||||
It is a implemented as a thin wrapper around the `grind` tactic, enabling only the `grobner` solver.
|
||||
Please use `grind` instead if you need additional capabilities.
|
||||
-/
|
||||
syntax (name := grobner) "grobner" optConfig : tactic
|
||||
|
||||
/-!
|
||||
Sets symbol priorities for the E-matching pattern inference procedure used in `grind`
|
||||
-/
|
||||
|
||||
@@ -40,7 +40,7 @@ theorem intCast_ofNat (x : Nat) : (OfNat.ofNat (α := Int) x : UInt8) = OfNat.of
|
||||
rw [Int.toNat_emod (Int.zero_le_ofNat x) (by decide)]
|
||||
erw [Int.toNat_natCast]
|
||||
rw [Int.toNat_pow_of_nonneg (by decide)]
|
||||
simp only [ofNat, BitVec.ofNat, Fin.ofNat, Int.reduceToNat, Nat.dvd_refl,
|
||||
simp only [ofNat, BitVec.ofNat, Fin.Internal.ofNat_eq_ofNat, Fin.ofNat, Int.reduceToNat, Nat.dvd_refl,
|
||||
Nat.mod_mod_of_dvd, instOfNat]
|
||||
|
||||
end UInt8
|
||||
@@ -70,7 +70,7 @@ theorem intCast_ofNat (x : Nat) : (OfNat.ofNat (α := Int) x : UInt16) = OfNat.o
|
||||
rw [Int.toNat_emod (Int.zero_le_ofNat x) (by decide)]
|
||||
erw [Int.toNat_natCast]
|
||||
rw [Int.toNat_pow_of_nonneg (by decide)]
|
||||
simp only [ofNat, BitVec.ofNat, Fin.ofNat, Int.reduceToNat, Nat.dvd_refl,
|
||||
simp only [ofNat, BitVec.ofNat, Fin.Internal.ofNat_eq_ofNat, Fin.ofNat, Int.reduceToNat, Nat.dvd_refl,
|
||||
Nat.mod_mod_of_dvd, instOfNat]
|
||||
|
||||
end UInt16
|
||||
@@ -100,7 +100,7 @@ theorem intCast_ofNat (x : Nat) : (OfNat.ofNat (α := Int) x : UInt32) = OfNat.o
|
||||
rw [Int.toNat_emod (Int.zero_le_ofNat x) (by decide)]
|
||||
erw [Int.toNat_natCast]
|
||||
rw [Int.toNat_pow_of_nonneg (by decide)]
|
||||
simp only [ofNat, BitVec.ofNat, Fin.ofNat, Int.reduceToNat, Nat.dvd_refl,
|
||||
simp only [ofNat, BitVec.ofNat, Fin.Internal.ofNat_eq_ofNat, Fin.ofNat, Int.reduceToNat, Nat.dvd_refl,
|
||||
Nat.mod_mod_of_dvd, instOfNat]
|
||||
|
||||
end UInt32
|
||||
@@ -130,7 +130,7 @@ theorem intCast_ofNat (x : Nat) : (OfNat.ofNat (α := Int) x : UInt64) = OfNat.o
|
||||
rw [Int.toNat_emod (Int.zero_le_ofNat x) (by decide)]
|
||||
erw [Int.toNat_natCast]
|
||||
rw [Int.toNat_pow_of_nonneg (by decide)]
|
||||
simp only [ofNat, BitVec.ofNat, Fin.ofNat, Int.reduceToNat, Nat.dvd_refl,
|
||||
simp only [ofNat, BitVec.ofNat, Fin.Internal.ofNat_eq_ofNat, Fin.ofNat, Int.reduceToNat, Nat.dvd_refl,
|
||||
Nat.mod_mod_of_dvd, instOfNat]
|
||||
|
||||
end UInt64
|
||||
@@ -157,7 +157,7 @@ theorem intCast_ofNat (x : Nat) : (OfNat.ofNat (α := Int) x : USize) = OfNat.of
|
||||
rw [Int.toNat_emod (Int.zero_le_ofNat x)]
|
||||
· erw [Int.toNat_natCast]
|
||||
rw [Int.toNat_pow_of_nonneg (by decide)]
|
||||
simp only [ofNat, BitVec.ofNat, Fin.ofNat, Int.reduceToNat, Nat.dvd_refl,
|
||||
simp only [ofNat, BitVec.ofNat, Fin.Internal.ofNat_eq_ofNat, Fin.ofNat, Int.reduceToNat, Nat.dvd_refl,
|
||||
Nat.mod_mod_of_dvd, instOfNat]
|
||||
· obtain _ | _ := System.Platform.numBits_eq <;> simp_all
|
||||
|
||||
|
||||
@@ -10,7 +10,13 @@ prelude
|
||||
public import Init.ByCases
|
||||
public import Init.RCases
|
||||
public import Init.Control.Except -- for `MonoBind` instance
|
||||
public import Init.Control.StateRef -- for `MonoBind` instance
|
||||
public import Init.Control.Option -- for `MonoBind` instance
|
||||
public import Init.System.IO -- for `MonoBind` instance
|
||||
import all Init.Control.Except -- for `MonoBind` instance
|
||||
import all Init.Control.StateRef -- for `MonoBind` instance
|
||||
import all Init.Control.Option -- for `MonoBind` instance
|
||||
import all Init.System.IO -- for `MonoBind` instance
|
||||
|
||||
public section
|
||||
|
||||
@@ -790,14 +796,14 @@ on `m` is monotone in both arguments with regard to that order.
|
||||
This is intended to be used in the construction of `partial_fixpoint`, and not meant to be used otherwise.
|
||||
-/
|
||||
class MonoBind (m : Type u → Type v) [Bind m] [∀ α, PartialOrder (m α)] where
|
||||
bind_mono_left {a₁ a₂ : m α} {f : α → m b} (h : a₁ ⊑ a₂) : a₁ >>= f ⊑ a₂ >>= f
|
||||
bind_mono_right {a : m α} {f₁ f₂ : α → m b} (h : ∀ x, f₁ x ⊑ f₂ x) : a >>= f₁ ⊑ a >>= f₂
|
||||
bind_mono_left {a₁ a₂ : m α} {f : α → m β} (h : a₁ ⊑ a₂) : a₁ >>= f ⊑ a₂ >>= f
|
||||
bind_mono_right {a : m α} {f₁ f₂ : α → m β} (h : ∀ x, f₁ x ⊑ f₂ x) : a >>= f₁ ⊑ a >>= f₂
|
||||
|
||||
@[partial_fixpoint_monotone]
|
||||
theorem monotone_bind
|
||||
(m : Type u → Type v) [Bind m] [∀ α, PartialOrder (m α)] [MonoBind m]
|
||||
{α β : Type u}
|
||||
{γ : Type w} [PartialOrder γ]
|
||||
{γ : Sort w} [PartialOrder γ]
|
||||
(f : γ → m α) (g : γ → α → m β)
|
||||
(hmono₁ : monotone f)
|
||||
(hmono₂ : monotone g) :
|
||||
@@ -823,9 +829,9 @@ theorem Option.admissible_eq_some (P : Prop) (y : α) :
|
||||
admissible (fun (x : Option α) => x = some y → P) := by
|
||||
apply admissible_flatOrder; simp
|
||||
|
||||
instance [Monad m] [inst : ∀ α, PartialOrder (m α)] : PartialOrder (ExceptT ε m α) := inst _
|
||||
instance [Monad m] [∀ α, PartialOrder (m α)] [inst : ∀ α, CCPO (m α)] : CCPO (ExceptT ε m α) := inst _
|
||||
instance [Monad m] [∀ α, PartialOrder (m α)] [∀ α, CCPO (m α)] [MonoBind m] : MonoBind (ExceptT ε m) where
|
||||
instance [inst : ∀ α, PartialOrder (m α)] : PartialOrder (ExceptT ε m α) := inst _
|
||||
instance [inst : ∀ α, CCPO (m α)] : CCPO (ExceptT ε m α) := inst _
|
||||
instance [Monad m] [∀ α, PartialOrder (m α)] [MonoBind m] : MonoBind (ExceptT ε m) where
|
||||
bind_mono_left h₁₂ := by
|
||||
apply MonoBind.bind_mono_left (m := m)
|
||||
exact h₁₂
|
||||
@@ -836,6 +842,112 @@ instance [Monad m] [∀ α, PartialOrder (m α)] [∀ α, CCPO (m α)] [MonoBind
|
||||
· apply PartialOrder.rel_refl
|
||||
· apply h₁₂
|
||||
|
||||
@[partial_fixpoint_monotone]
|
||||
theorem monotone_exceptTRun [PartialOrder γ]
|
||||
[Monad m] [∀ α, PartialOrder (m α)]
|
||||
(f : γ → ExceptT ε m α) (hmono : monotone f) :
|
||||
monotone (fun (x : γ) => ExceptT.run (f x)) :=
|
||||
hmono
|
||||
|
||||
instance [inst : ∀ α, PartialOrder (m α)] : PartialOrder (OptionT m α) := inst _
|
||||
instance [inst : ∀ α, CCPO (m α)] : CCPO (OptionT m α) := inst _
|
||||
instance [Monad m] [∀ α, PartialOrder (m α)] [MonoBind m] : MonoBind (OptionT m) where
|
||||
bind_mono_left h₁₂ := by
|
||||
apply MonoBind.bind_mono_left (m := m)
|
||||
exact h₁₂
|
||||
bind_mono_right h₁₂ := by
|
||||
apply MonoBind.bind_mono_right (m := m)
|
||||
intro x
|
||||
cases x
|
||||
· apply PartialOrder.rel_refl
|
||||
· apply h₁₂
|
||||
|
||||
@[partial_fixpoint_monotone]
|
||||
theorem monotone_optionTRun [PartialOrder γ]
|
||||
[Monad m] [∀ α, PartialOrder (m α)]
|
||||
(f : γ → OptionT m α) (hmono : monotone f) :
|
||||
monotone (fun (x : γ) => OptionT.run (f x)) :=
|
||||
hmono
|
||||
|
||||
instance [inst : PartialOrder (m α)] : PartialOrder (ReaderT ρ m α) := instOrderPi
|
||||
instance [inst : CCPO (m α)] : CCPO (ReaderT ρ m α) := instCCPOPi
|
||||
instance [Monad m] [∀ α, PartialOrder (m α)] [MonoBind m] : MonoBind (ReaderT ρ m) where
|
||||
bind_mono_left h₁₂ := by
|
||||
intro x
|
||||
apply MonoBind.bind_mono_left (m := m)
|
||||
exact h₁₂ x
|
||||
bind_mono_right h₁₂ := by
|
||||
intro x
|
||||
apply MonoBind.bind_mono_right (m := m)
|
||||
intro y
|
||||
apply h₁₂
|
||||
|
||||
@[partial_fixpoint_monotone]
|
||||
theorem monotone_readerTRun [PartialOrder γ]
|
||||
[Monad m] [PartialOrder (m α)]
|
||||
(f : γ → ReaderT σ m α) (hmono : monotone f) (s : σ) :
|
||||
monotone (fun (x : γ) => ReaderT.run (f x) s) :=
|
||||
monotone_apply s _ hmono
|
||||
|
||||
instance [inst : PartialOrder (m α)] : PartialOrder (StateRefT' ω σ m α) := instOrderPi
|
||||
instance [inst : CCPO (m α)] : CCPO (StateRefT' ω σ m α) := instCCPOPi
|
||||
instance [Monad m] [∀ α, PartialOrder (m α)] [MonoBind m] : MonoBind (StateRefT' ω σ m) :=
|
||||
inferInstanceAs (MonoBind (ReaderT _ _))
|
||||
|
||||
@[partial_fixpoint_monotone]
|
||||
theorem monotone_stateRefT'Run [PartialOrder γ]
|
||||
[Monad m] [MonadLiftT (ST ω) m] [∀ α, PartialOrder (m α)] [MonoBind m]
|
||||
(f : γ → StateRefT' ω σ m α) (hmono : monotone f) (s : σ) :
|
||||
monotone (fun (x : γ) => StateRefT'.run (f x) s) := by
|
||||
apply monotone_bind
|
||||
· apply monotone_const
|
||||
· refine monotone_of_monotone_apply _ fun ref => ?_
|
||||
apply monotone_bind
|
||||
· exact monotone_apply _ _ hmono
|
||||
· apply monotone_const
|
||||
|
||||
instance [inst : ∀ α, PartialOrder (m α)] : PartialOrder (StateT σ m α) := instOrderPi
|
||||
instance [inst : ∀ α, CCPO (m α)] : CCPO (StateT σ m α) := instCCPOPi
|
||||
instance [Monad m] [∀ α, PartialOrder (m α)] [MonoBind m] : MonoBind (StateT ρ m) where
|
||||
bind_mono_left h₁₂ := by
|
||||
intro x
|
||||
apply MonoBind.bind_mono_left (m := m)
|
||||
exact h₁₂ x
|
||||
bind_mono_right h₁₂ := by
|
||||
intro x
|
||||
apply MonoBind.bind_mono_right (m := m)
|
||||
intro y
|
||||
apply h₁₂
|
||||
|
||||
@[partial_fixpoint_monotone]
|
||||
theorem monotone_stateTRun [PartialOrder γ]
|
||||
[Monad m] [∀ α, PartialOrder (m α)]
|
||||
(f : γ → StateT σ m α) (hmono : monotone f) (s : σ) :
|
||||
monotone (fun (x : γ) => StateT.run (f x) s) :=
|
||||
monotone_apply s _ hmono
|
||||
|
||||
-- TODO: axiomatize these instances (ideally without `Nonempty ε`) when EIO is opaque
|
||||
noncomputable instance [Nonempty ε] : CCPO (EIO ε α) :=
|
||||
inferInstanceAs (CCPO ((s : _) → FlatOrder (.error Classical.ofNonempty (Classical.choice ⟨s⟩))))
|
||||
|
||||
noncomputable instance [Nonempty ε] : MonoBind (EIO ε) where
|
||||
bind_mono_left {_ _ a₁ a₂ f} h₁₂ := by
|
||||
intro s
|
||||
specialize h₁₂ s
|
||||
change FlatOrder.rel (a₁.bind f s) (a₂.bind f s)
|
||||
simp only [EStateM.bind]
|
||||
generalize a₁ s = a₁ at h₁₂; generalize a₂ s = a₂ at h₁₂
|
||||
cases h₁₂
|
||||
· exact .bot
|
||||
· exact .refl
|
||||
bind_mono_right {_ _ a f₁ f₂} h₁₂ := by
|
||||
intro w
|
||||
change FlatOrder.rel (a.bind f₁ w) (a.bind f₂ w)
|
||||
simp only [EStateM.bind]
|
||||
split
|
||||
· apply h₁₂
|
||||
· exact .refl
|
||||
|
||||
end mono_bind
|
||||
|
||||
section implication_order
|
||||
|
||||
@@ -8,8 +8,8 @@ Additional goodies for writing macros
|
||||
module
|
||||
|
||||
prelude
|
||||
public import Init.Prelude -- for unfolding `Name.beq`
|
||||
import all Init.Prelude -- for unfolding `Name.beq`
|
||||
public import Init.Prelude
|
||||
import all Init.Prelude -- for unfolding `Name.beq`
|
||||
public import Init.MetaTypes
|
||||
public import Init.Syntax
|
||||
public import Init.Data.Array.GetLit
|
||||
@@ -47,15 +47,21 @@ opaque version.getSpecialDesc (u : Unit) : String
|
||||
def version.specialDesc : String := version.getSpecialDesc ()
|
||||
|
||||
def versionStringCore :=
|
||||
toString version.major ++ "." ++ toString version.minor ++ "." ++ toString version.patch
|
||||
String.Internal.append
|
||||
(String.Internal.append
|
||||
(String.Internal.append
|
||||
(String.Internal.append (toString version.major) ".")
|
||||
(toString version.minor))
|
||||
".")
|
||||
(toString version.patch)
|
||||
|
||||
def versionString :=
|
||||
if version.specialDesc ≠ "" then
|
||||
versionStringCore ++ "-" ++ version.specialDesc
|
||||
String.Internal.append (String.Internal.append versionStringCore "-") version.specialDesc
|
||||
else if version.isRelease then
|
||||
versionStringCore
|
||||
else
|
||||
versionStringCore ++ ", commit " ++ githash
|
||||
(String.Internal.append (String.Internal.append versionStringCore ", commit ") githash)
|
||||
|
||||
def origin :=
|
||||
"leanprover/lean4"
|
||||
@@ -63,11 +69,17 @@ def origin :=
|
||||
def toolchain :=
|
||||
if version.specialDesc ≠ "" then
|
||||
if version.isRelease then
|
||||
origin ++ ":" ++ versionStringCore ++ "-" ++ version.specialDesc
|
||||
String.Internal.append
|
||||
(String.Internal.append
|
||||
(String.Internal.append
|
||||
(String.Internal.append origin ":")
|
||||
versionStringCore)
|
||||
"-")
|
||||
version.specialDesc
|
||||
else
|
||||
origin ++ ":" ++ version.specialDesc
|
||||
String.Internal.append (String.Internal.append origin ":") version.specialDesc
|
||||
else if version.isRelease then
|
||||
origin ++ ":" ++ versionStringCore
|
||||
String.Internal.append (String.Internal.append origin ":") versionStringCore
|
||||
else
|
||||
""
|
||||
|
||||
@@ -109,9 +121,22 @@ def isSubScriptAlnum (c : Char) : Bool :=
|
||||
@[inline] def isIdFirst (c : Char) : Bool :=
|
||||
c.isAlpha || c = '_' || isLetterLike c
|
||||
|
||||
@[inline] private def isAlphaAscii (c : UInt8) : Bool :=
|
||||
'a'.toUInt8 ≤ c && c ≤ 'z'.toUInt8
|
||||
|| 'A'.toUInt8 ≤ c && c ≤ 'Z'.toUInt8
|
||||
|
||||
@[inline] def isIdFirstAscii (c : UInt8) : Bool :=
|
||||
isAlphaAscii c || c = '_'.toUInt8
|
||||
|
||||
@[inline] private def isAlphanumAscii (c : UInt8) : Bool :=
|
||||
isAlphaAscii c || '0'.toUInt8 ≤ c && c ≤ '9'.toUInt8
|
||||
|
||||
@[inline] def isIdRest (c : Char) : Bool :=
|
||||
c.isAlphanum || c = '_' || c = '\'' || c == '!' || c == '?' || isLetterLike c || isSubScriptAlnum c
|
||||
|
||||
@[inline] def isIdRestAscii (c : UInt8) : Bool :=
|
||||
isAlphanumAscii c || c = '_'.toUInt8 || c = '\''.toUInt8 || c == '!'.toUInt8 || c == '?'.toUInt8
|
||||
|
||||
def idBeginEscape := '«'
|
||||
def idEndEscape := '»'
|
||||
@[inline] def isIdBeginEscape (c : Char) : Bool := c = idBeginEscape
|
||||
@@ -127,7 +152,7 @@ def getRoot : Name → Name
|
||||
|
||||
@[export lean_is_inaccessible_user_name]
|
||||
def isInaccessibleUserName : Name → Bool
|
||||
| Name.str _ s => s.contains '✝' || s == "_inaccessible"
|
||||
| Name.str _ s => (String.Internal.contains s '✝') || s == "_inaccessible"
|
||||
| Name.num p _ => isInaccessibleUserName p
|
||||
| _ => false
|
||||
|
||||
@@ -137,24 +162,65 @@ def isInaccessibleUserName : Name → Bool
|
||||
@[extern "lean_string_get_byte_fast"]
|
||||
private opaque getUtf8Byte' (s : @& String) (n : Nat) (h : n < s.utf8ByteSize) : UInt8
|
||||
|
||||
section ToString
|
||||
|
||||
/-!
|
||||
Here we give a private implementation of `Name.toString`. The real implementation is in
|
||||
`Init.Data.ToString.Name`, which we cannot import here due to import hierarchy limitations.
|
||||
|
||||
The difference between the two versions is that this one uses the `String.Internal.*` functions,
|
||||
while the one in `Init.Data.ToString.Name` uses the public String functions. These differ in
|
||||
that the latter versions have better inferred borrowing annotations, which is significant for an
|
||||
inner-loop function like `Name.toString`.
|
||||
-/
|
||||
|
||||
-- If you change this, also change the corresponding function in `Init.Data.ToString.Name`.
|
||||
private partial def needsNoEscapeAsciiRest (s : String) (i : Nat) : Bool :=
|
||||
if h : i < s.utf8ByteSize then
|
||||
let c := getUtf8Byte' s i h
|
||||
isIdRestAscii c && needsNoEscapeAsciiRest s (i + 1)
|
||||
else
|
||||
true
|
||||
|
||||
-- If you change this, also change the corresponding function in `Init.Data.ToString.Name`.
|
||||
@[inline] private def needsNoEscapeAscii (s : String) (h : s.utf8ByteSize > 0) : Bool :=
|
||||
let c := getUtf8Byte' s 0 h
|
||||
isIdFirstAscii c && needsNoEscapeAsciiRest s 1
|
||||
|
||||
-- If you change this, also change the corresponding function in `Init.Data.ToString.Name`.
|
||||
@[inline] private def needsNoEscape (s : String) (h : s.utf8ByteSize > 0) : Bool :=
|
||||
needsNoEscapeAscii s h || isIdFirst (String.Internal.get s 0) && Substring.Internal.all (Substring.Internal.drop s.toSubstring 1) isIdRest
|
||||
|
||||
-- If you change this, also change the corresponding function in `Init.Data.ToString.Name`.
|
||||
@[inline] private def escape (s : String) : String :=
|
||||
String.Internal.append (String.Internal.append idBeginEscape.toString s) idEndEscape.toString
|
||||
|
||||
/--
|
||||
Creates a round-trippable string name component if possible, otherwise returns `none`.
|
||||
Names that are valid identifiers are not escaped, and otherwise, if they do not contain `»`, they are escaped.
|
||||
- If `force` is `true`, then even valid identifiers are escaped.
|
||||
-/
|
||||
-- If you change this, also change the corresponding function in `Init.Data.ToString.Name`.
|
||||
@[inline]
|
||||
def escapePart (s : String) (force : Bool := false) : Option String :=
|
||||
if s.length > 0 && !force && isIdFirst (s.get 0) && (s.toSubstring.drop 1).all isIdRest then some s
|
||||
else if s.any isIdEndEscape then none
|
||||
else some <| idBeginEscape.toString ++ s ++ idEndEscape.toString
|
||||
private def Internal.Meta.escapePart (s : String) (force : Bool := false) : Option String :=
|
||||
if h : s.utf8ByteSize > 0 then
|
||||
if !force && needsNoEscape s h then
|
||||
some s
|
||||
else if String.Internal.any s isIdEndEscape then
|
||||
none
|
||||
else
|
||||
some <| escape s
|
||||
else
|
||||
some <| escape s
|
||||
|
||||
variable (sep : String) (escape : Bool) in
|
||||
/--
|
||||
Uses the separator `sep` (usually `"."`) to combine the components of the `Name` into a string.
|
||||
See the documentation for `Name.toStringWithToken` for an explanation of `escape` and `isToken`.
|
||||
-/
|
||||
-- If you change this, also change the corresponding function in `Init.Data.ToString.Name`.
|
||||
@[specialize isToken] -- explicit annotation because isToken is overridden in recursive call
|
||||
def toStringWithSep (n : Name) (isToken : String → Bool := fun _ => false) : String :=
|
||||
private def Internal.Meta.toStringWithSep (n : Name) (isToken : String → Bool := fun _ => false) : String :=
|
||||
match n with
|
||||
| anonymous => "[anonymous]"
|
||||
| str anonymous s => maybeEscape s (isToken s)
|
||||
@@ -162,9 +228,9 @@ def toStringWithSep (n : Name) (isToken : String → Bool := fun _ => false) : S
|
||||
| str n s =>
|
||||
-- Escape the last component if the identifier would otherwise be a token
|
||||
let r := toStringWithSep n isToken
|
||||
let r' := r ++ sep ++ maybeEscape s false
|
||||
if escape && isToken r' then r ++ sep ++ maybeEscape s true else r'
|
||||
| num n v => toStringWithSep n (isToken := fun _ => false) ++ sep ++ Nat.repr v
|
||||
let r' := String.Internal.append (String.Internal.append r sep) (maybeEscape s false)
|
||||
if escape && isToken r' then String.Internal.append (String.Internal.append r sep) (maybeEscape s true) else r'
|
||||
| num n v => String.Internal.append (String.Internal.append (toStringWithSep n (isToken := fun _ => false)) sep) (Nat.repr v)
|
||||
where
|
||||
maybeEscape s force := if escape then escapePart s force |>.getD s else s
|
||||
|
||||
@@ -180,7 +246,8 @@ Converts a name to a string.
|
||||
The insertion algorithm works so long as parser tokens do not themselves contain `«` or `»`.
|
||||
-/
|
||||
@[specialize]
|
||||
def toStringWithToken (n : Name) (escape := true) (isToken : String → Bool) : String :=
|
||||
-- If you change this, also change the corresponding function in `Init.Data.ToString.Name`.
|
||||
private def Internal.Meta.toStringWithToken (n : Name) (escape := true) (isToken : String → Bool) : String :=
|
||||
-- never escape "prettified" inaccessible names or macro scopes or pseudo-syntax introduced by the delaborator
|
||||
toStringWithSep "." (escape && !n.isInaccessibleUserName && !n.hasMacroScopes && !maybePseudoSyntax) n isToken
|
||||
where
|
||||
@@ -190,7 +257,7 @@ where
|
||||
true
|
||||
else if let .str _ s := n.getRoot then
|
||||
-- could be pseudo-syntax for loose bvar or universe mvar, output as is
|
||||
"#".isPrefixOf s || "?".isPrefixOf s
|
||||
String.Internal.isPrefixOf "#" s || String.Internal.isPrefixOf "?" s
|
||||
else
|
||||
false
|
||||
|
||||
@@ -202,11 +269,11 @@ Converts a name to a string.
|
||||
Names with number components, anonymous names, and names containing `»` might not round trip.
|
||||
Furthermore, "pseudo-syntax" produced by the delaborator, such as `_`, `#0` or `?u`, is not escaped.
|
||||
-/
|
||||
protected def toString (n : Name) (escape := true) : String :=
|
||||
Name.toStringWithToken n escape (fun _ => false)
|
||||
-- If you change this, also change the corresponding function in `Init.Data.ToString.Name`.
|
||||
private def Internal.Meta.toString (n : Name) (escape := true) : String :=
|
||||
toStringWithToken n escape (fun _ => false)
|
||||
|
||||
instance : ToString Name where
|
||||
toString n := n.toString
|
||||
end ToString
|
||||
|
||||
private def hasNum : Name → Bool
|
||||
| anonymous => false
|
||||
@@ -221,13 +288,13 @@ protected def reprPrec (n : Name) (prec : Nat) : Std.Format :=
|
||||
if p.hasNum then
|
||||
Repr.addAppParen ("Lean.Name.mkStr " ++ Name.reprPrec p max_prec ++ " " ++ repr s) prec
|
||||
else
|
||||
Std.Format.text "`" ++ n.toString
|
||||
Std.Format.text "`" ++ Internal.Meta.toString n
|
||||
|
||||
instance : Repr Name where
|
||||
reprPrec := Name.reprPrec
|
||||
|
||||
def capitalize : Name → Name
|
||||
| .str p s => .str p s.capitalize
|
||||
| .str p s => .str p (String.Internal.capitalize s)
|
||||
| n => n
|
||||
|
||||
def replacePrefix : Name → Name → Name → Name
|
||||
@@ -256,20 +323,20 @@ def eraseSuffix? : Name → Name → Option Name
|
||||
@[export lean_name_append_after]
|
||||
def appendAfter (n : Name) (suffix : String) : Name :=
|
||||
n.modifyBase fun
|
||||
| str p s => Name.mkStr p (s ++ suffix)
|
||||
| str p s => Name.mkStr p (String.Internal.append s suffix)
|
||||
| n => Name.mkStr n suffix
|
||||
|
||||
@[export lean_name_append_index_after]
|
||||
def appendIndexAfter (n : Name) (idx : Nat) : Name :=
|
||||
n.modifyBase fun
|
||||
| str p s => Name.mkStr p (s ++ "_" ++ toString idx)
|
||||
| n => Name.mkStr n ("_" ++ toString idx)
|
||||
| str p s => Name.mkStr p (String.Internal.append (String.Internal.append s "_") (toString idx))
|
||||
| n => Name.mkStr n (String.Internal.append "_" (toString idx))
|
||||
|
||||
@[export lean_name_append_before]
|
||||
def appendBefore (n : Name) (pre : String) : Name :=
|
||||
n.modifyBase fun
|
||||
| anonymous => Name.mkStr anonymous pre
|
||||
| str p s => Name.mkStr p (pre ++ s)
|
||||
| str p s => Name.mkStr p (String.Internal.append pre s)
|
||||
| num p n => Name.mkNum (Name.mkStr p pre) n
|
||||
|
||||
protected theorem beq_iff_eq {m n : Name} : m == n ↔ m = n := by
|
||||
@@ -446,7 +513,7 @@ partial def structEq : Syntax → Syntax → Bool
|
||||
| Syntax.missing, Syntax.missing => true
|
||||
| Syntax.node _ k args, Syntax.node _ k' args' => k == k' && args.isEqv args' structEq
|
||||
| Syntax.atom _ val, Syntax.atom _ val' => val == val'
|
||||
| Syntax.ident _ rawVal val preresolved, Syntax.ident _ rawVal' val' preresolved' => rawVal == rawVal' && val == val' && preresolved == preresolved'
|
||||
| Syntax.ident _ rawVal val preresolved, Syntax.ident _ rawVal' val' preresolved' => Substring.Internal.beq rawVal rawVal' && val == val' && preresolved == preresolved'
|
||||
| _, _ => false
|
||||
|
||||
instance : BEq Lean.Syntax := ⟨structEq⟩
|
||||
@@ -641,7 +708,7 @@ partial def expandMacros (stx : Syntax) (p : SyntaxNodeKind → Bool := fun k =>
|
||||
Create an identifier copying the position from `src`.
|
||||
To refer to a specific constant, use `mkCIdentFrom` instead. -/
|
||||
def mkIdentFrom (src : Syntax) (val : Name) (canonical := false) : Ident :=
|
||||
⟨Syntax.ident (SourceInfo.fromRef src canonical) (toString val).toSubstring val []⟩
|
||||
⟨Syntax.ident (SourceInfo.fromRef src canonical) (Name.Internal.Meta.toString val).toSubstring val []⟩
|
||||
|
||||
def mkIdentFromRef [Monad m] [MonadRef m] (val : Name) (canonical := false) : m Ident := do
|
||||
return mkIdentFrom (← getRef) val canonical
|
||||
@@ -653,7 +720,7 @@ def mkIdentFromRef [Monad m] [MonadRef m] (val : Name) (canonical := false) : m
|
||||
def mkCIdentFrom (src : Syntax) (c : Name) (canonical := false) : Ident :=
|
||||
-- Remark: We use the reserved macro scope to make sure there are no accidental collision with our frontend
|
||||
let id := addMacroScope `_internal c reservedMacroScope
|
||||
⟨Syntax.ident (SourceInfo.fromRef src canonical) (toString id).toSubstring id [.decl c []]⟩
|
||||
⟨Syntax.ident (SourceInfo.fromRef src canonical) (Name.Internal.Meta.toString id).toSubstring id [.decl c []]⟩
|
||||
|
||||
def mkCIdentFromRef [Monad m] [MonadRef m] (c : Name) (canonical := false) : m Syntax := do
|
||||
return mkCIdentFrom (← getRef) c canonical
|
||||
@@ -663,7 +730,7 @@ def mkCIdent (c : Name) : Ident :=
|
||||
|
||||
@[export lean_mk_syntax_ident]
|
||||
def mkIdent (val : Name) : Ident :=
|
||||
⟨Syntax.ident SourceInfo.none (toString val).toSubstring val []⟩
|
||||
⟨Syntax.ident SourceInfo.none (Name.Internal.Meta.toString val).toSubstring val []⟩
|
||||
|
||||
@[inline] def mkGroupNode (args : Array Syntax := #[]) : Syntax :=
|
||||
mkNode groupKind args
|
||||
@@ -693,11 +760,11 @@ def mkSep (a : Array Syntax) (sep : Syntax) : Syntax :=
|
||||
mkNullNode <| mkSepArray a sep
|
||||
|
||||
def SepArray.ofElems {sep} (elems : Array Syntax) : SepArray sep :=
|
||||
⟨mkSepArray elems (if sep.isEmpty then mkNullNode else mkAtom sep)⟩
|
||||
⟨mkSepArray elems (if String.Internal.isEmpty sep then mkNullNode else mkAtom sep)⟩
|
||||
|
||||
def SepArray.ofElemsUsingRef [Monad m] [MonadRef m] {sep} (elems : Array Syntax) : m (SepArray sep) := do
|
||||
let ref ← getRef;
|
||||
return ⟨mkSepArray elems (if sep.isEmpty then mkNullNode else mkAtomFrom ref sep)⟩
|
||||
return ⟨mkSepArray elems (if String.Internal.isEmpty sep then mkNullNode else mkAtomFrom ref sep)⟩
|
||||
|
||||
instance : Coe (Array Syntax) (SepArray sep) where
|
||||
coe := SepArray.ofElems
|
||||
@@ -752,55 +819,55 @@ def mkNameLit (val : String) (info := SourceInfo.none) : NameLit :=
|
||||
for Syntax objects representing these numerals. -/
|
||||
|
||||
private partial def decodeBinLitAux (s : String) (i : String.Pos) (val : Nat) : Option Nat :=
|
||||
if s.atEnd i then some val
|
||||
if String.Internal.atEnd s i then some val
|
||||
else
|
||||
let c := s.get i
|
||||
if c == '0' then decodeBinLitAux s (s.next i) (2*val)
|
||||
else if c == '1' then decodeBinLitAux s (s.next i) (2*val + 1)
|
||||
else if c == '_' then decodeBinLitAux s (s.next i) val
|
||||
let c := String.Internal.get s i
|
||||
if c == '0' then decodeBinLitAux s (String.Internal.next s i) (2*val)
|
||||
else if c == '1' then decodeBinLitAux s (String.Internal.next s i) (2*val + 1)
|
||||
else if c == '_' then decodeBinLitAux s (String.Internal.next s i) val
|
||||
else none
|
||||
|
||||
private partial def decodeOctalLitAux (s : String) (i : String.Pos) (val : Nat) : Option Nat :=
|
||||
if s.atEnd i then some val
|
||||
if String.Internal.atEnd s i then some val
|
||||
else
|
||||
let c := s.get i
|
||||
if '0' ≤ c && c ≤ '7' then decodeOctalLitAux s (s.next i) (8*val + c.toNat - '0'.toNat)
|
||||
else if c == '_' then decodeOctalLitAux s (s.next i) val
|
||||
let c := String.Internal.get s i
|
||||
if '0' ≤ c && c ≤ '7' then decodeOctalLitAux s (String.Internal.next s i) (8*val + c.toNat - '0'.toNat)
|
||||
else if c == '_' then decodeOctalLitAux s (String.Internal.next s i) val
|
||||
else none
|
||||
|
||||
private def decodeHexDigit (s : String) (i : String.Pos) : Option (Nat × String.Pos) :=
|
||||
let c := s.get i
|
||||
let i := s.next i
|
||||
let c := String.Internal.get s i
|
||||
let i := String.Internal.next s i
|
||||
if '0' ≤ c && c ≤ '9' then some (c.toNat - '0'.toNat, i)
|
||||
else if 'a' ≤ c && c ≤ 'f' then some (10 + c.toNat - 'a'.toNat, i)
|
||||
else if 'A' ≤ c && c ≤ 'F' then some (10 + c.toNat - 'A'.toNat, i)
|
||||
else none
|
||||
|
||||
private partial def decodeHexLitAux (s : String) (i : String.Pos) (val : Nat) : Option Nat :=
|
||||
if s.atEnd i then some val
|
||||
if String.Internal.atEnd s i then some val
|
||||
else match decodeHexDigit s i with
|
||||
| some (d, i) => decodeHexLitAux s i (16*val + d)
|
||||
| none =>
|
||||
if s.get i == '_' then decodeHexLitAux s (s.next i) val
|
||||
if String.Internal.get s i == '_' then decodeHexLitAux s (String.Internal.next s i) val
|
||||
else none
|
||||
|
||||
private partial def decodeDecimalLitAux (s : String) (i : String.Pos) (val : Nat) : Option Nat :=
|
||||
if s.atEnd i then some val
|
||||
if String.Internal.atEnd s i then some val
|
||||
else
|
||||
let c := s.get i
|
||||
if '0' ≤ c && c ≤ '9' then decodeDecimalLitAux s (s.next i) (10*val + c.toNat - '0'.toNat)
|
||||
else if c == '_' then decodeDecimalLitAux s (s.next i) val
|
||||
let c := String.Internal.get s i
|
||||
if '0' ≤ c && c ≤ '9' then decodeDecimalLitAux s (String.Internal.next s i) (10*val + c.toNat - '0'.toNat)
|
||||
else if c == '_' then decodeDecimalLitAux s (String.Internal.next s i) val
|
||||
else none
|
||||
|
||||
def decodeNatLitVal? (s : String) : Option Nat :=
|
||||
let len := s.length
|
||||
let len := String.Internal.length s
|
||||
if len == 0 then none
|
||||
else
|
||||
let c := s.get 0
|
||||
let c := String.Internal.get s 0
|
||||
if c == '0' then
|
||||
if len == 1 then some 0
|
||||
else
|
||||
let c := s.get ⟨1⟩
|
||||
let c := String.Internal.get s ⟨1⟩
|
||||
if c == 'x' || c == 'X' then decodeHexLitAux s ⟨2⟩ 0
|
||||
else if c == 'b' || c == 'B' then decodeBinLitAux s ⟨2⟩ 0
|
||||
else if c == 'o' || c == 'O' then decodeOctalLitAux s ⟨2⟩ 0
|
||||
@@ -836,16 +903,16 @@ def isFieldIdx? (s : Syntax) : Option Nat :=
|
||||
`n * 10^-e` if `sign` else `n * 10^e`.
|
||||
-/
|
||||
partial def decodeScientificLitVal? (s : String) : Option (Nat × Bool × Nat) :=
|
||||
let len := s.length
|
||||
let len := String.Internal.length s
|
||||
if len == 0 then none
|
||||
else
|
||||
let c := s.get 0
|
||||
let c := String.Internal.get s 0
|
||||
if c.isDigit then
|
||||
decode 0 0
|
||||
else none
|
||||
where
|
||||
decodeAfterExp (i : String.Pos) (val : Nat) (e : Nat) (sign : Bool) (exp : Nat) : Option (Nat × Bool × Nat) :=
|
||||
if s.atEnd i then
|
||||
if String.Internal.atEnd s i then
|
||||
if sign then
|
||||
some (val, sign, exp + e)
|
||||
else if exp >= e then
|
||||
@@ -853,51 +920,51 @@ where
|
||||
else
|
||||
some (val, true, e - exp)
|
||||
else
|
||||
let c := s.get i
|
||||
let c := String.Internal.get s i
|
||||
if '0' ≤ c && c ≤ '9' then
|
||||
decodeAfterExp (s.next i) val e sign (10*exp + c.toNat - '0'.toNat)
|
||||
decodeAfterExp (String.Internal.next s i) val e sign (10*exp + c.toNat - '0'.toNat)
|
||||
else if c == '_' then
|
||||
decodeAfterExp (s.next i) val e sign exp
|
||||
decodeAfterExp (String.Internal.next s i) val e sign exp
|
||||
else
|
||||
none
|
||||
|
||||
decodeExp (i : String.Pos) (val : Nat) (e : Nat) : Option (Nat × Bool × Nat) :=
|
||||
if s.atEnd i then none else
|
||||
let c := s.get i
|
||||
if String.Internal.atEnd s i then none else
|
||||
let c := String.Internal.get s i
|
||||
if c == '-' then
|
||||
decodeAfterExp (s.next i) val e true 0
|
||||
decodeAfterExp (String.Internal.next s i) val e true 0
|
||||
else if c == '+' then
|
||||
decodeAfterExp (s.next i) val e false 0
|
||||
decodeAfterExp (String.Internal.next s i) val e false 0
|
||||
else
|
||||
decodeAfterExp i val e false 0
|
||||
|
||||
decodeAfterDot (i : String.Pos) (val : Nat) (e : Nat) : Option (Nat × Bool × Nat) :=
|
||||
if s.atEnd i then
|
||||
if String.Internal.atEnd s i then
|
||||
some (val, true, e)
|
||||
else
|
||||
let c := s.get i
|
||||
let c := String.Internal.get s i
|
||||
if '0' ≤ c && c ≤ '9' then
|
||||
decodeAfterDot (s.next i) (10*val + c.toNat - '0'.toNat) (e+1)
|
||||
decodeAfterDot (String.Internal.next s i) (10*val + c.toNat - '0'.toNat) (e+1)
|
||||
else if c == '_' then
|
||||
decodeAfterDot (s.next i) val e
|
||||
decodeAfterDot (String.Internal.next s i) val e
|
||||
else if c == 'e' || c == 'E' then
|
||||
decodeExp (s.next i) val e
|
||||
decodeExp (String.Internal.next s i) val e
|
||||
else
|
||||
none
|
||||
|
||||
decode (i : String.Pos) (val : Nat) : Option (Nat × Bool × Nat) :=
|
||||
if s.atEnd i then
|
||||
if String.Internal.atEnd s i then
|
||||
none
|
||||
else
|
||||
let c := s.get i
|
||||
let c := String.Internal.get s i
|
||||
if '0' ≤ c && c ≤ '9' then
|
||||
decode (s.next i) (10*val + c.toNat - '0'.toNat)
|
||||
decode (String.Internal.next s i) (10*val + c.toNat - '0'.toNat)
|
||||
else if c == '_' then
|
||||
decode (s.next i) val
|
||||
decode (String.Internal.next s i) val
|
||||
else if c == '.' then
|
||||
decodeAfterDot (s.next i) val 0
|
||||
decodeAfterDot (String.Internal.next s i) val 0
|
||||
else if c == 'e' || c == 'E' then
|
||||
decodeExp (s.next i) val 0
|
||||
decodeExp (String.Internal.next s i) val 0
|
||||
else
|
||||
none
|
||||
|
||||
@@ -908,7 +975,7 @@ def isScientificLit? (stx : Syntax) : Option (Nat × Bool × Nat) :=
|
||||
|
||||
def isIdOrAtom? : Syntax → Option String
|
||||
| Syntax.atom _ val => some val
|
||||
| Syntax.ident _ rawVal _ _ => some rawVal.toString
|
||||
| Syntax.ident _ rawVal _ _ => some (Substring.Internal.toString rawVal)
|
||||
| _ => none
|
||||
|
||||
def toNat (stx : Syntax) : Nat :=
|
||||
@@ -917,8 +984,8 @@ def toNat (stx : Syntax) : Nat :=
|
||||
| none => 0
|
||||
|
||||
def decodeQuotedChar (s : String) (i : String.Pos) : Option (Char × String.Pos) := do
|
||||
let c := s.get i
|
||||
let i := s.next i
|
||||
let c := String.Internal.get s i
|
||||
let i := String.Internal.next s i
|
||||
if c == '\\' then pure ('\\', i)
|
||||
else if c = '\"' then pure ('\"', i)
|
||||
else if c = '\'' then pure ('\'', i)
|
||||
@@ -945,25 +1012,25 @@ the more restrictive `"\" newline whitespace*` since this simplifies the impleme
|
||||
Justification: this does not overlap with any other sequences beginning with `\`.
|
||||
-/
|
||||
def decodeStringGap (s : String) (i : String.Pos) : Option String.Pos := do
|
||||
guard <| (s.get i).isWhitespace
|
||||
some <| s.nextWhile Char.isWhitespace (s.next i)
|
||||
guard <| (String.Internal.get s i).isWhitespace
|
||||
some <| String.Internal.nextWhile s Char.isWhitespace (String.Internal.next s i)
|
||||
|
||||
partial def decodeStrLitAux (s : String) (i : String.Pos) (acc : String) : Option String := do
|
||||
let c := s.get i
|
||||
let i := s.next i
|
||||
let c := String.Internal.get s i
|
||||
let i := String.Internal.next s i
|
||||
if c == '\"' then
|
||||
pure acc
|
||||
else if s.atEnd i then
|
||||
else if String.Internal.atEnd s i then
|
||||
none
|
||||
else if c == '\\' then do
|
||||
if let some (c, i) := decodeQuotedChar s i then
|
||||
decodeStrLitAux s i (acc.push c)
|
||||
decodeStrLitAux s i (String.push acc c)
|
||||
else if let some i := decodeStringGap s i then
|
||||
decodeStrLitAux s i acc
|
||||
else
|
||||
none
|
||||
else
|
||||
decodeStrLitAux s i (acc.push c)
|
||||
decodeStrLitAux s i (String.push acc c)
|
||||
|
||||
/--
|
||||
Takes a raw string literal, counts the number of `#`'s after the `r`, and interprets it as a string.
|
||||
@@ -972,12 +1039,12 @@ The algorithm is simple: we are given `r##...#"...string..."##...#` with zero or
|
||||
By counting the number of leading `#`'s, we can extract the `...string...`.
|
||||
-/
|
||||
partial def decodeRawStrLitAux (s : String) (i : String.Pos) (num : Nat) : String :=
|
||||
let c := s.get i
|
||||
let i := s.next i
|
||||
let c := String.Internal.get s i
|
||||
let i := String.Internal.next s i
|
||||
if c == '#' then
|
||||
decodeRawStrLitAux s i (num + 1)
|
||||
else
|
||||
s.extract i ⟨s.utf8ByteSize - (num + 1)⟩
|
||||
String.Internal.extract s i ⟨s.utf8ByteSize - (num + 1)⟩
|
||||
|
||||
/--
|
||||
Takes the string literal lexical syntax parsed by the parser and interprets it as a string.
|
||||
@@ -988,7 +1055,7 @@ If it returns `none` then the string literal is ill-formed, which indicates a bu
|
||||
The function is not required to return `none` if the string literal is ill-formed.
|
||||
-/
|
||||
def decodeStrLit (s : String) : Option String :=
|
||||
if s.get 0 == 'r' then
|
||||
if String.Internal.get s 0 == 'r' then
|
||||
some <| decodeRawStrLitAux s ⟨1⟩ 0
|
||||
else
|
||||
decodeStrLitAux s ⟨1⟩ ""
|
||||
@@ -1005,7 +1072,7 @@ def isStrLit? (stx : Syntax) : Option String :=
|
||||
| _ => none
|
||||
|
||||
def decodeCharLit (s : String) : Option Char := do
|
||||
let c := s.get ⟨1⟩
|
||||
let c := String.Internal.get s ⟨1⟩
|
||||
if c == '\\' then do
|
||||
let (c, _) ← decodeQuotedChar s ⟨2⟩
|
||||
pure c
|
||||
@@ -1019,26 +1086,26 @@ def isCharLit? (stx : Syntax) : Option Char :=
|
||||
|
||||
private partial def splitNameLitAux (ss : Substring) (acc : List Substring) : List Substring :=
|
||||
let splitRest (ss : Substring) (acc : List Substring) : List Substring :=
|
||||
if ss.front == '.' then
|
||||
splitNameLitAux (ss.drop 1) acc
|
||||
else if ss.isEmpty then
|
||||
if Substring.Internal.front ss == '.' then
|
||||
splitNameLitAux (Substring.Internal.drop ss 1) acc
|
||||
else if Substring.Internal.isEmpty ss then
|
||||
acc
|
||||
else
|
||||
[]
|
||||
if ss.isEmpty then []
|
||||
if Substring.Internal.isEmpty ss then []
|
||||
else
|
||||
let curr := ss.front
|
||||
let curr := Substring.Internal.front ss
|
||||
if isIdBeginEscape curr then
|
||||
let escapedPart := ss.takeWhile (!isIdEndEscape ·)
|
||||
let escapedPart := { escapedPart with stopPos := ss.stopPos.min (escapedPart.str.next escapedPart.stopPos) }
|
||||
if !isIdEndEscape (escapedPart.get <| escapedPart.prev ⟨escapedPart.bsize⟩) then []
|
||||
else splitRest (ss.extract ⟨escapedPart.bsize⟩ ⟨ss.bsize⟩) (escapedPart :: acc)
|
||||
let escapedPart := Substring.Internal.takeWhile ss (!isIdEndEscape ·)
|
||||
let escapedPart := { escapedPart with stopPos := String.Pos.Internal.min ss.stopPos (String.Internal.next escapedPart.str escapedPart.stopPos) }
|
||||
if !isIdEndEscape (Substring.Internal.get escapedPart <| Substring.Internal.prev escapedPart ⟨escapedPart.bsize⟩) then []
|
||||
else splitRest (Substring.Internal.extract ss ⟨escapedPart.bsize⟩ ⟨ss.bsize⟩) (escapedPart :: acc)
|
||||
else if isIdFirst curr then
|
||||
let idPart := ss.takeWhile isIdRest
|
||||
splitRest (ss.extract ⟨idPart.bsize⟩ ⟨ss.bsize⟩) (idPart :: acc)
|
||||
let idPart := Substring.Internal.takeWhile ss isIdRest
|
||||
splitRest (Substring.Internal.extract ss ⟨idPart.bsize⟩ ⟨ss.bsize⟩) (idPart :: acc)
|
||||
else if curr.isDigit then
|
||||
let idPart := ss.takeWhile Char.isDigit
|
||||
splitRest (ss.extract ⟨idPart.bsize⟩ ⟨ss.bsize⟩) (idPart :: acc)
|
||||
let idPart := Substring.Internal.takeWhile ss Char.isDigit
|
||||
splitRest (Substring.Internal.extract ss ⟨idPart.bsize⟩ ⟨ss.bsize⟩) (idPart :: acc)
|
||||
else
|
||||
[]
|
||||
|
||||
@@ -1059,10 +1126,10 @@ def _root_.Substring.toName (s : Substring) : Name :=
|
||||
| [] => .anonymous
|
||||
| comps => comps.foldr (init := Name.anonymous)
|
||||
fun comp n =>
|
||||
let comp := comp.toString
|
||||
if isIdBeginEscape comp.front then
|
||||
Name.mkStr n (comp.drop 1 |>.dropRight 1)
|
||||
else if comp.front.isDigit then
|
||||
let comp := Substring.Internal.toString comp
|
||||
if isIdBeginEscape (String.Internal.front comp) then
|
||||
Name.mkStr n (String.Internal.dropRight (String.Internal.drop comp 1) 1)
|
||||
else if (String.Internal.front comp).isDigit then
|
||||
if let some k := decodeNatLitVal? comp then
|
||||
Name.mkNum n k
|
||||
else
|
||||
@@ -1080,8 +1147,8 @@ def _root_.String.toName (s : String) : Name :=
|
||||
s.toSubstring.toName
|
||||
|
||||
def decodeNameLit (s : String) : Option Name :=
|
||||
if s.get 0 == '`' then
|
||||
match (s.toSubstring.drop 1).toName with
|
||||
if String.Internal.get s 0 == '`' then
|
||||
match (Substring.Internal.drop s.toSubstring 1).toName with
|
||||
| .anonymous => none
|
||||
| name => some name
|
||||
else
|
||||
@@ -1101,7 +1168,7 @@ def isAtom : Syntax → Bool
|
||||
| _ => false
|
||||
|
||||
def isToken (token : String) : Syntax → Bool
|
||||
| atom _ val => val.trim == token.trim
|
||||
| atom _ val => String.Internal.trim val == String.Internal.trim token
|
||||
| _ => false
|
||||
|
||||
def isNone (stx : Syntax) : Bool :=
|
||||
@@ -1199,7 +1266,7 @@ end TSyntax
|
||||
def HygieneInfo.mkIdent (s : HygieneInfo) (val : Name) (canonical := false) : Ident :=
|
||||
let src := s.raw[0]
|
||||
let id := { extractMacroScopes src.getId with name := val.eraseMacroScopes }.review
|
||||
⟨Syntax.ident (SourceInfo.fromRef src canonical) (toString val).toSubstring id []⟩
|
||||
⟨Syntax.ident (SourceInfo.fromRef src canonical) (Name.Internal.Meta.toString val).toSubstring id []⟩
|
||||
|
||||
/-- Reflect a runtime datum back to surface syntax (best-effort). -/
|
||||
class Quote (α : Type) (k : SyntaxNodeKind := `term) where
|
||||
@@ -1215,13 +1282,13 @@ instance : Quote Bool := ⟨fun | true => mkCIdent ``Bool.true | false => mkCIde
|
||||
instance : Quote Char charLitKind := ⟨Syntax.mkCharLit⟩
|
||||
instance : Quote String strLitKind := ⟨Syntax.mkStrLit⟩
|
||||
instance : Quote Nat numLitKind := ⟨fun n => Syntax.mkNumLit <| toString n⟩
|
||||
instance : Quote Substring := ⟨fun s => Syntax.mkCApp ``String.toSubstring' #[quote s.toString]⟩
|
||||
instance : Quote Substring := ⟨fun s => Syntax.mkCApp ``String.toSubstring' #[quote (Substring.Internal.toString s)]⟩
|
||||
|
||||
-- in contrast to `Name.toString`, we can, and want to be, precise here
|
||||
private def getEscapedNameParts? (acc : List String) : Name → Option (List String)
|
||||
| Name.anonymous => if acc.isEmpty then none else some acc
|
||||
| Name.str n s => do
|
||||
let s ← Name.escapePart s
|
||||
let s ← Name.Internal.Meta.escapePart s false
|
||||
getEscapedNameParts? (s::acc) n
|
||||
| Name.num _ _ => none
|
||||
|
||||
@@ -1233,7 +1300,7 @@ def quoteNameMk : Name → Term
|
||||
instance : Quote Name `term where
|
||||
quote n := private
|
||||
match getEscapedNameParts? [] n with
|
||||
| some ss => ⟨mkNode `Lean.Parser.Term.quotedName #[Syntax.mkNameLit ("`" ++ ".".intercalate ss)]⟩
|
||||
| some ss => ⟨mkNode `Lean.Parser.Term.quotedName #[Syntax.mkNameLit (String.Internal.append "`" (String.Internal.intercalate "." ss))]⟩
|
||||
| none => ⟨quoteNameMk n⟩
|
||||
|
||||
instance [Quote α `term] [Quote β `term] : Quote (α × β) `term where
|
||||
@@ -1257,7 +1324,7 @@ where
|
||||
if h : i < xs.size then
|
||||
go (i+1) (args.push (quote xs[i]))
|
||||
else
|
||||
Syntax.mkCApp (Name.mkStr2 "Array" ("mkArray" ++ toString xs.size)) args
|
||||
Syntax.mkCApp (Name.mkStr2 "Array" (String.Internal.append "mkArray" (toString xs.size))) args
|
||||
termination_by xs.size - i
|
||||
decreasing_by decreasing_trivial_pre_omega
|
||||
|
||||
@@ -1415,28 +1482,28 @@ private def decodeInterpStrQuotedChar (s : String) (i : String.Pos) : Option (Ch
|
||||
match decodeQuotedChar s i with
|
||||
| some r => some r
|
||||
| none =>
|
||||
let c := s.get i
|
||||
let i := s.next i
|
||||
let c := String.Internal.get s i
|
||||
let i := String.Internal.next s i
|
||||
if c == '{' then pure ('{', i)
|
||||
else none
|
||||
|
||||
private partial def decodeInterpStrLit (s : String) : Option String :=
|
||||
let rec loop (i : String.Pos) (acc : String) : Option String :=
|
||||
let c := s.get i
|
||||
let i := s.next i
|
||||
let c := String.Internal.get s i
|
||||
let i := String.Internal.next s i
|
||||
if c == '\"' || c == '{' then
|
||||
pure acc
|
||||
else if s.atEnd i then
|
||||
else if String.Internal.atEnd s i then
|
||||
none
|
||||
else if c == '\\' then do
|
||||
if let some (c, i) := decodeInterpStrQuotedChar s i then
|
||||
loop i (acc.push c)
|
||||
loop i (String.push acc c)
|
||||
else if let some i := decodeStringGap s i then
|
||||
loop i acc
|
||||
else
|
||||
none
|
||||
else
|
||||
loop i (acc.push c)
|
||||
loop i (String.push acc c)
|
||||
loop ⟨1⟩ ""
|
||||
|
||||
partial def isInterpolatedStrLit? (stx : Syntax) : Option String :=
|
||||
@@ -1451,28 +1518,38 @@ end Syntax
|
||||
|
||||
namespace TSyntax
|
||||
|
||||
def expandInterpolatedStrChunks (chunks : Array Syntax) (mkAppend : Syntax → Syntax → MacroM Syntax) (mkElem : Syntax → MacroM Syntax) : MacroM Syntax := do
|
||||
let mut i := 0
|
||||
def expandInterpolatedStrChunks (chunks : Array Syntax) (mkAppend : Syntax → Syntax → MacroM Syntax)
|
||||
(mkElem : Syntax → MacroM Syntax) (mkLit : String → MacroM Syntax) : MacroM Syntax := do
|
||||
let mut result := Syntax.missing
|
||||
for elem in chunks do
|
||||
let elem ← withRef elem <| match elem.isInterpolatedStrLit? with
|
||||
| none => mkElem elem
|
||||
| some str => mkElem (Syntax.mkStrLit str)
|
||||
if i == 0 then
|
||||
let elem ← match elem.isInterpolatedStrLit? with
|
||||
| none => withRef elem <| mkElem elem
|
||||
| some str =>
|
||||
if String.Internal.isEmpty str then continue
|
||||
else withRef elem <| mkLit str
|
||||
if result.isMissing then
|
||||
result := elem
|
||||
else
|
||||
result ← mkAppend result elem
|
||||
i := i+1
|
||||
return result
|
||||
if result.isMissing then
|
||||
mkLit ""
|
||||
else
|
||||
return result
|
||||
|
||||
open TSyntax.Compat in
|
||||
def expandInterpolatedStr (interpStr : TSyntax interpolatedStrKind) (type : Term) (toTypeFn : Term) : MacroM Term := do
|
||||
let r ← expandInterpolatedStrChunks interpStr.raw.getArgs (fun a b => `($a ++ $b)) (fun a => `($toTypeFn $a))
|
||||
/-- Expand `interpStr` into a term of type `type` (which supports ` ++ `),
|
||||
calling `ofInterpFn` on terms within `{}`,
|
||||
and `ofLitFn` on the literals between the interpolations. -/
|
||||
def expandInterpolatedStr (interpStr : TSyntax interpolatedStrKind) (type : Term) (ofInterpFn : Term) (ofLitFn : Term := ofInterpFn) : MacroM Term := do
|
||||
let r ← expandInterpolatedStrChunks interpStr.raw.getArgs
|
||||
(fun a b => `($a ++ $b))
|
||||
(fun a => `($ofInterpFn $a))
|
||||
(fun s => `($ofLitFn $(Syntax.mkStrLit s)))
|
||||
`(($r : $type))
|
||||
|
||||
def getDocString (stx : TSyntax `Lean.Parser.Command.docComment) : String :=
|
||||
match stx.raw[1] with
|
||||
| Syntax.atom _ val => val.extract 0 (val.endPos - ⟨2⟩)
|
||||
| Syntax.atom _ val => String.Internal.extract val 0 (String.Pos.Internal.sub val.endPos ⟨2⟩)
|
||||
| _ => ""
|
||||
|
||||
end TSyntax
|
||||
@@ -1646,8 +1723,8 @@ macro (name := declareSimpLikeTactic) doc?:(docComment)?
|
||||
return s)
|
||||
|
||||
/-- `simp!` is shorthand for `simp` with `autoUnfold := true`.
|
||||
This will rewrite with all equation lemmas, which can be used to
|
||||
partially evaluate many definitions. -/
|
||||
This will unfold applications of functions defined by pattern matching, when one of the patterns applies.
|
||||
This can be used to partially evaluate many definitions. -/
|
||||
declare_simp_like_tactic simpAutoUnfold "simp! " (autoUnfold := true)
|
||||
|
||||
/--
|
||||
@@ -1663,8 +1740,8 @@ Note that `+decide` is not needed for reducing arithmetic terms since simprocs h
|
||||
syntax (name := simpArithBang) "simp_arith! " optConfig (discharger)? (&" only")? (" [" (simpStar <|> simpErase <|> simpLemma),* "]")? (location)? : tactic
|
||||
|
||||
/-- `simp_all!` is shorthand for `simp_all` with `autoUnfold := true`.
|
||||
This will rewrite with all equation lemmas, which can be used to
|
||||
partially evaluate many definitions. -/
|
||||
This will unfold applications of functions defined by pattern matching, when one of the patterns applies.
|
||||
This can be used to partially evaluate many definitions. -/
|
||||
declare_simp_like_tactic (all := true) simpAllAutoUnfold "simp_all! " (autoUnfold := true)
|
||||
|
||||
/--
|
||||
@@ -1681,8 +1758,8 @@ syntax (name := simpAllArithBang) "simp_all_arith!" optConfig (discharger)? (&"
|
||||
|
||||
|
||||
/-- `dsimp!` is shorthand for `dsimp` with `autoUnfold := true`.
|
||||
This will rewrite with all equation lemmas, which can be used to
|
||||
partially evaluate many definitions. -/
|
||||
This will unfold applications of functions defined by pattern matching, when one of the patterns applies.
|
||||
This can be used to partially evaluate many definitions. -/
|
||||
declare_simp_like_tactic (dsimp := true) dsimpAutoUnfold "dsimp! " (autoUnfold := true)
|
||||
|
||||
end Tactic
|
||||
|
||||
@@ -94,7 +94,7 @@ structure Config where
|
||||
-/
|
||||
decide : Bool := false
|
||||
/--
|
||||
When `true` (default: `false`), unfolds definitions.
|
||||
When `true` (default: `false`), unfolds applications of functions defined by pattern matching, when one of the patterns applies.
|
||||
This can be enabled using the `simp!` syntax.
|
||||
-/
|
||||
autoUnfold : Bool := false
|
||||
@@ -208,7 +208,7 @@ structure Config where
|
||||
/-- When `true` (default: `false`), simplifies simple arithmetic expressions. -/
|
||||
arith : Bool := false
|
||||
/--
|
||||
When `true` (default: `false`), unfolds definitions.
|
||||
When `true` (default: `false`), unfolds applications of functions defined by pattern matching, when one of the patterns applies.
|
||||
This can be enabled using the `simp!` syntax.
|
||||
-/
|
||||
autoUnfold : Bool := false
|
||||
|
||||
@@ -44,8 +44,11 @@ deriving BEq, DecidableEq, Repr
|
||||
|
||||
namespace Constraint
|
||||
|
||||
private local instance : Append String where
|
||||
append := String.Internal.append
|
||||
|
||||
instance : ToString Constraint where
|
||||
toString := fun
|
||||
toString := private fun
|
||||
| ⟨none, none⟩ => "(-∞, ∞)"
|
||||
| ⟨none, some y⟩ => s!"(-∞, {y}]"
|
||||
| ⟨some x, none⟩ => s!"[{x}, ∞)"
|
||||
|
||||
@@ -33,9 +33,15 @@ deriving DecidableEq, Repr
|
||||
|
||||
namespace LinearCombo
|
||||
|
||||
private def join (l : List String) : String :=
|
||||
l.foldl (init := "") (fun sofar next => String.Internal.append sofar next)
|
||||
|
||||
private local instance : Append String where
|
||||
append := String.Internal.append
|
||||
|
||||
instance : ToString LinearCombo where
|
||||
toString lc :=
|
||||
s!"{lc.const}{String.join <| lc.coeffs.toList.zipIdx.map fun ⟨c, i⟩ => s!" + {c} * x{i+1}"}"
|
||||
toString lc := private
|
||||
s!"{lc.const}{join <| lc.coeffs.toList.zipIdx.map fun ⟨c, i⟩ => s!" + {c} * x{i+1}"}"
|
||||
|
||||
instance : Inhabited LinearCombo := ⟨{const := 1}⟩
|
||||
|
||||
|
||||
@@ -141,6 +141,9 @@ unsafe axiom lcErased : Type
|
||||
/-- Marker for type dependency that has been erased by the code generator. -/
|
||||
unsafe axiom lcAny : Type
|
||||
|
||||
/-- Internal representation of `IO.RealWorld` in the compiler. -/
|
||||
unsafe axiom lcRealWorld : Type
|
||||
|
||||
/--
|
||||
Auxiliary unsafe constant used by the Compiler when erasing proofs from code.
|
||||
|
||||
@@ -1778,6 +1781,20 @@ theorem Nat.ne_of_beq_eq_false : {n m : Nat} → Eq (beq n m) false → Not (Eq
|
||||
have : Eq (beq n m) false := h₁
|
||||
Nat.noConfusion h₂ (fun h₂ => absurd h₂ (ne_of_beq_eq_false this))
|
||||
|
||||
|
||||
private theorem noConfusion_of_Nat.aux : (a : Nat) → (Nat.beq a a).rec False True
|
||||
| Nat.zero => True.intro
|
||||
| Nat.succ n => noConfusion_of_Nat.aux n
|
||||
|
||||
/--
|
||||
A helper theorem to deduce `False` from `a = b` when `f a ≠ f b` for some function `f : α → Nat`
|
||||
(typically `.ctorIdx`). Used as a simpler alternative to the no-confusion theorems.
|
||||
-/
|
||||
theorem noConfusion_of_Nat {α : Sort u} (f : α → Nat) {a b : α} (h : Eq a b) :
|
||||
(Nat.beq (f a) (f b)).rec False True :=
|
||||
congrArg f h ▸ noConfusion_of_Nat.aux (f a)
|
||||
|
||||
|
||||
/--
|
||||
A decision procedure for equality of natural numbers, usually accessed via the `DecidableEq Nat`
|
||||
instance.
|
||||
@@ -1865,6 +1882,9 @@ protected theorem Nat.le_trans {n m k : Nat} : LE.le n m → LE.le m k → LE.le
|
||||
| h, Nat.le.refl => h
|
||||
| h₁, Nat.le.step h₂ => Nat.le.step (Nat.le_trans h₁ h₂)
|
||||
|
||||
protected theorem Nat.lt_of_lt_of_le {n m k : Nat} : LT.lt n m → LE.le m k → LT.lt n k :=
|
||||
Nat.le_trans
|
||||
|
||||
protected theorem Nat.lt_trans {n m k : Nat} (h₁ : LT.lt n m) : LT.lt m k → LT.lt n k :=
|
||||
Nat.le_trans (le_step h₁)
|
||||
|
||||
@@ -1968,6 +1988,27 @@ theorem Nat.ble_eq_true_of_le (h : LE.le n m) : Eq (Nat.ble n m) true :=
|
||||
theorem Nat.not_le_of_not_ble_eq_true (h : Not (Eq (Nat.ble n m) true)) : Not (LE.le n m) :=
|
||||
fun h' => absurd (Nat.ble_eq_true_of_le h') h
|
||||
|
||||
theorem Nat.lt_succ_of_le {n m : Nat} : LE.le n m → LT.lt n (succ m) := succ_le_succ
|
||||
|
||||
protected theorem Nat.lt_add_one (n : Nat) : LT.lt n (HAdd.hAdd n 1) := Nat.le_refl (succ n)
|
||||
|
||||
theorem Nat.lt_succ_self (n : Nat) : LT.lt n (succ n) := Nat.lt_add_one _
|
||||
|
||||
protected theorem Nat.lt_of_not_le {a b : Nat} (h : Not (LE.le a b)) : LT.lt b a :=
|
||||
(Nat.lt_or_ge b a).resolve_right h
|
||||
|
||||
protected theorem Nat.add_pos_right :
|
||||
{b : Nat} → (a : Nat) → (hb : LT.lt 0 b) → LT.lt 0 (HAdd.hAdd a b)
|
||||
| succ _, _, _ => Nat.zero_lt_succ _
|
||||
|
||||
protected theorem Nat.mul_pos :
|
||||
{n m : Nat} → (hn : LT.lt 0 n) → (hm : LT.lt 0 m) → LT.lt 0 (HMul.hMul n m)
|
||||
| _, succ _, ha, _ => Nat.add_pos_right _ ha
|
||||
|
||||
protected theorem Nat.pow_pos {a : Nat} : {n : Nat} → (h : LT.lt 0 a) → LT.lt 0 (HPow.hPow a n)
|
||||
| zero, _ => Nat.zero_lt_succ _
|
||||
| succ _, h => Nat.mul_pos (Nat.pow_pos h) h
|
||||
|
||||
/--
|
||||
A decision procedure for non-strict inequality of natural numbers, usually accessed via the
|
||||
`DecidableLE Nat` instance.
|
||||
@@ -2021,6 +2062,160 @@ protected def Nat.sub : (@& Nat) → (@& Nat) → Nat
|
||||
instance instSubNat : Sub Nat where
|
||||
sub := Nat.sub
|
||||
|
||||
theorem Nat.succ_sub_succ_eq_sub (n m : Nat) : Eq (HSub.hSub (succ n) (succ m)) (HSub.hSub n m) :=
|
||||
m.rec rfl (fun _ ih => congrArg pred ih)
|
||||
|
||||
theorem Nat.pred_le : ∀ (n : Nat), LE.le (Nat.pred n) n
|
||||
| zero => Nat.le.refl
|
||||
| succ _ => le_succ _
|
||||
|
||||
theorem Nat.sub_le (n m : Nat) : LE.le (HSub.hSub n m) n :=
|
||||
m.rec (Nat.le_refl _) (fun _ ih => Nat.le_trans (pred_le _) ih)
|
||||
|
||||
theorem Nat.sub_lt : ∀ {n m : Nat}, LT.lt 0 n → LT.lt 0 m → LT.lt (HSub.hSub n m) n
|
||||
| 0, _, h1, _ => absurd h1 (Nat.lt_irrefl 0)
|
||||
| Nat.succ _, 0, _, h2 => absurd h2 (Nat.lt_irrefl 0)
|
||||
| Nat.succ n, Nat.succ m, _, _ =>
|
||||
Eq.symm (succ_sub_succ_eq_sub n m) ▸
|
||||
show LT.lt (HSub.hSub n m) (succ n) from
|
||||
lt_succ_of_le (sub_le n m)
|
||||
|
||||
theorem Nat.div_rec_lemma {x y : Nat} :
|
||||
(And (LT.lt 0 y) (LE.le y x)) → LT.lt (HSub.hSub x y) x :=
|
||||
fun ⟨ypos, ylex⟩ => sub_lt (Nat.lt_of_lt_of_le ypos ylex) ypos
|
||||
|
||||
theorem Nat.div_rec_fuel_lemma {x y fuel : Nat} (hy : LT.lt 0 y) (hle : LE.le y x)
|
||||
(hfuel : LT.lt x (HAdd.hAdd fuel 1)) : LT.lt (HSub.hSub x y) fuel :=
|
||||
Nat.lt_of_lt_of_le (div_rec_lemma ⟨hy, hle⟩) (Nat.le_of_lt_succ hfuel)
|
||||
|
||||
set_option bootstrap.genMatcherCode false in
|
||||
/--
|
||||
Division of natural numbers, discarding the remainder. Division by `0` returns `0`. Usually accessed
|
||||
via the `/` operator.
|
||||
|
||||
This operation is sometimes called “floor division.”
|
||||
|
||||
This function is overridden at runtime with an efficient implementation. This definition is
|
||||
the logical model.
|
||||
|
||||
Examples:
|
||||
* `21 / 3 = 7`
|
||||
* `21 / 5 = 4`
|
||||
* `0 / 22 = 0`
|
||||
* `5 / 0 = 0`
|
||||
-/
|
||||
@[extern "lean_nat_div", irreducible]
|
||||
protected def Nat.div (x y : @& Nat) : Nat :=
|
||||
dite (LT.lt 0 y) (fun hy =>
|
||||
let rec
|
||||
go (fuel : Nat) (x : Nat) (hfuel : LT.lt x fuel) : Nat :=
|
||||
match fuel with
|
||||
| succ fuel =>
|
||||
dite (LE.le y x)
|
||||
(fun h => HAdd.hAdd (go fuel (HSub.hSub x y) (div_rec_fuel_lemma hy h hfuel)) 1)
|
||||
(fun _ => 0)
|
||||
termination_by structural fuel
|
||||
go (succ x) x (Nat.lt_succ_self _))
|
||||
(fun _ => 0)
|
||||
|
||||
instance Nat.instDiv : Div Nat := ⟨Nat.div⟩
|
||||
|
||||
set_option bootstrap.genMatcherCode false in
|
||||
/--
|
||||
The modulo operator, which computes the remainder when dividing one natural number by another.
|
||||
Usually accessed via the `%` operator. When the divisor is `0`, the result is the dividend rather
|
||||
than an error.
|
||||
|
||||
This is the core implementation of `Nat.mod`. It computes the correct result for any two closed
|
||||
natural numbers, but it does not have some convenient [definitional
|
||||
reductions](lean-manual://section/type-system) when the `Nat`s contain free variables. The wrapper
|
||||
`Nat.mod` handles those cases specially and then calls `Nat.modCore`.
|
||||
|
||||
This function is overridden at runtime with an efficient implementation. This definition is the
|
||||
logical model.
|
||||
-/
|
||||
@[extern "lean_nat_mod"]
|
||||
protected noncomputable def Nat.modCore (x y : Nat) : Nat :=
|
||||
dite (LT.lt 0 y)
|
||||
(fun hy =>
|
||||
let rec
|
||||
go (fuel : Nat) (x : Nat) (hfuel : LT.lt x fuel) : Nat :=
|
||||
match fuel with
|
||||
| succ fuel =>
|
||||
dite (LE.le y x)
|
||||
(fun h => go fuel (HSub.hSub x y) (div_rec_fuel_lemma hy h hfuel))
|
||||
(fun _ => x)
|
||||
termination_by structural fuel
|
||||
go (succ x) x (Nat.lt_succ_self _))
|
||||
(fun _ => x)
|
||||
|
||||
theorem Nat.modCoreGo_lt {fuel y : Nat} (hy : LT.lt 0 y) : (x : Nat) → (hfuel : LT.lt x fuel) →
|
||||
LT.lt (Nat.modCore.go y hy fuel x hfuel) y :=
|
||||
fuel.rec (fun _ h => absurd h (Nat.not_lt_zero _))
|
||||
(fun _ ih x _ =>
|
||||
show LT.lt (dite _ _ _) _ from
|
||||
match Nat.decLe y x with
|
||||
| .isTrue _ => ih _ _
|
||||
| .isFalse h => Nat.lt_of_not_le h)
|
||||
|
||||
theorem Nat.modCore_lt {x y : Nat} (hy : LT.lt 0 y) : LT.lt (Nat.modCore x y) y :=
|
||||
show LT.lt (dite _ _ _) y from
|
||||
match Nat.decLt 0 y with
|
||||
| .isTrue _ => Nat.modCoreGo_lt hy x (Nat.lt_succ_self _)
|
||||
| .isFalse h => absurd hy h
|
||||
|
||||
attribute [irreducible] Nat.modCore
|
||||
|
||||
set_option bootstrap.genMatcherCode false in
|
||||
/--
|
||||
The modulo operator, which computes the remainder when dividing one natural number by another.
|
||||
Usually accessed via the `%` operator. When the divisor is `0`, the result is the dividend rather
|
||||
than an error.
|
||||
|
||||
`Nat.mod` is a wrapper around `Nat.modCore` that special-cases two situations, giving better
|
||||
definitional reductions:
|
||||
* `Nat.mod 0 m` should reduce to `m`, for all terms `m : Nat`.
|
||||
* `Nat.mod n (m + n + 1)` should reduce to `n` for concrete `Nat` literals `n`.
|
||||
|
||||
These reductions help `Fin n` literals work well, because the `OfNat` instance for `Fin` uses
|
||||
`Nat.mod`. In particular, `(0 : Fin (n + 1)).val` should reduce definitionally to `0`. `Nat.modCore`
|
||||
can handle all numbers, but its definitional reductions are not as convenient.
|
||||
|
||||
This function is overridden at runtime with an efficient implementation. This definition is the
|
||||
logical model.
|
||||
|
||||
Examples:
|
||||
* `7 % 2 = 1`
|
||||
* `9 % 3 = 0`
|
||||
* `5 % 7 = 5`
|
||||
* `5 % 0 = 5`
|
||||
* `show ∀ (n : Nat), 0 % n = 0 from fun _ => rfl`
|
||||
* `show ∀ (m : Nat), 5 % (m + 6) = 5 from fun _ => rfl`
|
||||
-/
|
||||
@[extern "lean_nat_mod"]
|
||||
protected def Nat.mod : @& Nat → @& Nat → Nat
|
||||
/-
|
||||
Nat.modCore is defined with fuel and thus does not reduce with open terms very well.
|
||||
Nevertheless it is desirable for trivial `Nat.mod` calculations, namely
|
||||
* `Nat.mod 0 m` for all `m`
|
||||
* `Nat.mod n (m + n + 1)` for concrete literals `n`,
|
||||
to reduce definitionally.
|
||||
This property is desirable for `Fin n` literals, as it means `(ofNat 0 : Fin n).val = 0` by
|
||||
definition.
|
||||
-/
|
||||
| 0, _ => 0
|
||||
| n@(succ _), m => ite (LE.le m n) (Nat.modCore n m) n
|
||||
|
||||
instance Nat.instMod : Mod Nat := ⟨Nat.mod⟩
|
||||
|
||||
theorem Nat.mod_lt : (x : Nat) → {y : Nat} → (hy : LT.lt 0 y) → LT.lt (HMod.hMod x y) y
|
||||
| 0, succ _, _ => Nat.zero_lt_succ _
|
||||
| succ n, m, hm =>
|
||||
show LT.lt (ite (LE.le m (succ n)) (Nat.modCore (succ n) m) (succ n)) _ from
|
||||
match Nat.decLe m (succ n) with
|
||||
| .isTrue _ => Nat.modCore_lt hm
|
||||
| .isFalse h => Nat.lt_of_not_le h
|
||||
|
||||
attribute [gen_constructor_elims] Nat
|
||||
|
||||
/--
|
||||
@@ -2090,6 +2285,14 @@ instance {n} : LE (Fin n) where
|
||||
instance Fin.decLt {n} (a b : Fin n) : Decidable (LT.lt a b) := Nat.decLt ..
|
||||
instance Fin.decLe {n} (a b : Fin n) : Decidable (LE.le a b) := Nat.decLe ..
|
||||
|
||||
/--
|
||||
Returns `a` modulo `n` as a `Fin n`.
|
||||
|
||||
This function exists for bootstrapping purposes. Use `Fin.ofNat` instead.
|
||||
-/
|
||||
@[expose] protected def Fin.Internal.ofNat (n : Nat) (hn : LT.lt 0 n) (a : Nat) : Fin n :=
|
||||
⟨HMod.hMod a n, Nat.mod_lt _ hn⟩
|
||||
|
||||
/--
|
||||
A bitvector of the specified width.
|
||||
|
||||
@@ -2126,6 +2329,13 @@ instance : DecidableEq (BitVec w) := BitVec.decEq
|
||||
protected def BitVec.ofNatLT {w : Nat} (i : Nat) (p : LT.lt i (hPow 2 w)) : BitVec w where
|
||||
toFin := ⟨i, p⟩
|
||||
|
||||
/--
|
||||
The bitvector with value `i mod 2^n`.
|
||||
-/
|
||||
@[expose, match_pattern]
|
||||
protected def BitVec.ofNat (n : Nat) (i : Nat) : BitVec n where
|
||||
toFin := Fin.Internal.ofNat (HPow.hPow 2 n) (Nat.pow_pos (Nat.zero_lt_succ _)) i
|
||||
|
||||
/--
|
||||
Return the underlying `Nat` that represents a bitvector.
|
||||
|
||||
@@ -2174,6 +2384,21 @@ This function is overridden at runtime with an efficient implementation.
|
||||
def UInt8.ofNatLT (n : @& Nat) (h : LT.lt n UInt8.size) : UInt8 where
|
||||
toBitVec := BitVec.ofNatLT n h
|
||||
|
||||
/--
|
||||
Converts a natural number to an 8-bit unsigned integer, wrapping on overflow.
|
||||
|
||||
This function is overridden at runtime with an efficient implementation.
|
||||
|
||||
Examples:
|
||||
* `UInt8.ofNat 5 = 5`
|
||||
* `UInt8.ofNat 255 = 255`
|
||||
* `UInt8.ofNat 256 = 0`
|
||||
* `UInt8.ofNat 259 = 3`
|
||||
* `UInt8.ofNat 32770 = 2`
|
||||
-/
|
||||
@[extern "lean_uint8_of_nat"]
|
||||
def UInt8.ofNat (n : @& Nat) : UInt8 := ⟨BitVec.ofNat 8 n⟩
|
||||
|
||||
set_option bootstrap.genMatcherCode false in
|
||||
/--
|
||||
Decides whether two 8-bit unsigned integers are equal. Usually accessed via the `DecidableEq UInt8`
|
||||
@@ -2199,6 +2424,52 @@ instance : DecidableEq UInt8 := UInt8.decEq
|
||||
instance : Inhabited UInt8 where
|
||||
default := UInt8.ofNatLT 0 (of_decide_eq_true rfl)
|
||||
|
||||
/--
|
||||
Strict inequality of 8-bit unsigned integers, defined as inequality of the corresponding
|
||||
natural numbers. Usually accessed via the `<` operator.
|
||||
-/
|
||||
protected def UInt8.lt (a b : UInt8) : Prop := LT.lt a.toBitVec b.toBitVec
|
||||
/--
|
||||
Non-strict inequality of 8-bit unsigned integers, defined as inequality of the corresponding
|
||||
natural numbers. Usually accessed via the `≤` operator.
|
||||
-/
|
||||
protected def UInt8.le (a b : UInt8) : Prop := LE.le a.toBitVec b.toBitVec
|
||||
instance : LT UInt8 := ⟨UInt8.lt⟩
|
||||
instance : LE UInt8 := ⟨UInt8.le⟩
|
||||
|
||||
/--
|
||||
Decides whether one 8-bit unsigned integer is strictly less than another. Usually accessed via the
|
||||
`DecidableLT UInt8` instance.
|
||||
|
||||
This function is overridden at runtime with an efficient implementation.
|
||||
|
||||
Examples:
|
||||
* `(if (6 : UInt8) < 7 then "yes" else "no") = "yes"`
|
||||
* `(if (5 : UInt8) < 5 then "yes" else "no") = "no"`
|
||||
* `show ¬((7 : UInt8) < 7) by decide`
|
||||
-/
|
||||
@[extern "lean_uint8_dec_lt"]
|
||||
def UInt8.decLt (a b : UInt8) : Decidable (LT.lt a b) :=
|
||||
inferInstanceAs (Decidable (LT.lt a.toBitVec b.toBitVec))
|
||||
|
||||
/--
|
||||
Decides whether one 8-bit unsigned integer is less than or equal to another. Usually accessed via the
|
||||
`DecidableLE UInt8` instance.
|
||||
|
||||
This function is overridden at runtime with an efficient implementation.
|
||||
|
||||
Examples:
|
||||
* `(if (15 : UInt8) ≤ 15 then "yes" else "no") = "yes"`
|
||||
* `(if (15 : UInt8) ≤ 5 then "yes" else "no") = "no"`
|
||||
* `(if (5 : UInt8) ≤ 15 then "yes" else "no") = "yes"`
|
||||
* `show (7 : UInt8) ≤ 7 by decide`
|
||||
-/
|
||||
@[extern "lean_uint8_dec_le"]
|
||||
def UInt8.decLe (a b : UInt8) : Decidable (LE.le a b) :=
|
||||
inferInstanceAs (Decidable (LE.le a.toBitVec b.toBitVec))
|
||||
|
||||
attribute [instance] UInt8.decLt UInt8.decLe
|
||||
|
||||
/-- The number of distinct values representable by `UInt16`, that is, `2^16 = 65536`. -/
|
||||
abbrev UInt16.size : Nat := 65536
|
||||
|
||||
@@ -2738,6 +3009,37 @@ def List.concat {α : Type u} : List α → α → List α
|
||||
| nil, b => cons b nil
|
||||
| cons a as, b => cons a (concat as b)
|
||||
|
||||
/--
|
||||
Returns the sequence of bytes in a character's UTF-8 encoding.
|
||||
-/
|
||||
def String.utf8EncodeChar (c : Char) : List UInt8 :=
|
||||
let v := c.val.toNat
|
||||
ite (LE.le v 0x7f)
|
||||
(List.cons (UInt8.ofNat v) List.nil)
|
||||
(ite (LE.le v 0x7ff)
|
||||
(List.cons
|
||||
(UInt8.ofNat (HAdd.hAdd (HMod.hMod (HDiv.hDiv v 64) 0x20) 0xc0))
|
||||
(List.cons
|
||||
(UInt8.ofNat (HAdd.hAdd (HMod.hMod v 0x40) 0x80))
|
||||
List.nil))
|
||||
(ite (LE.le v 0xffff)
|
||||
(List.cons
|
||||
(UInt8.ofNat (HAdd.hAdd (HMod.hMod (HDiv.hDiv v 4096) 0x10) 0xe0))
|
||||
(List.cons
|
||||
(UInt8.ofNat (HAdd.hAdd (HMod.hMod (HDiv.hDiv v 64) 0x40) 0x80))
|
||||
(List.cons
|
||||
(UInt8.ofNat (HAdd.hAdd (HMod.hMod v 0x40) 0x80))
|
||||
List.nil)))
|
||||
(List.cons
|
||||
(UInt8.ofNat (HAdd.hAdd (HMod.hMod (HDiv.hDiv v 262144) 0x08) 0xf0))
|
||||
(List.cons
|
||||
(UInt8.ofNat (HAdd.hAdd (HMod.hMod (HDiv.hDiv v 4096) 0x40) 0x80))
|
||||
(List.cons
|
||||
(UInt8.ofNat (HAdd.hAdd (HMod.hMod (HDiv.hDiv v 64) 0x40) 0x80))
|
||||
(List.cons
|
||||
(UInt8.ofNat (HAdd.hAdd (HMod.hMod v 0x40) 0x80))
|
||||
List.nil))))))
|
||||
|
||||
/--
|
||||
A string is a sequence of Unicode code points.
|
||||
|
||||
@@ -4545,7 +4847,7 @@ abbrev scientificLitKind : SyntaxNodeKind := `scientific
|
||||
/-- `` `name `` is the node kind of name literals like `` `foo ``. -/
|
||||
abbrev nameLitKind : SyntaxNodeKind := `name
|
||||
|
||||
/-- `` `fieldIdx ` is the node kind of projection indices like the `2` in `x.2`. -/
|
||||
/-- `` `fieldIdx `` is the node kind of projection indices like the `2` in `x.2`. -/
|
||||
abbrev fieldIdxKind : SyntaxNodeKind := `fieldIdx
|
||||
|
||||
/--
|
||||
|
||||
@@ -7,6 +7,7 @@ module
|
||||
|
||||
prelude
|
||||
public import Init.NotationExtra
|
||||
import Init.Data.ToString.Name
|
||||
|
||||
public section
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ module
|
||||
prelude
|
||||
public import Init.System.Platform
|
||||
public import Init.Data.ToString.Basic
|
||||
public import Init.Data.String.Basic
|
||||
|
||||
public section
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user