mirror of
https://github.com/leanprover/lean4.git
synced 2026-03-21 04:14:07 +00:00
Compare commits
62 Commits
grind_para
...
grind_map_
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e9efd52f22 | ||
|
|
1981c62604 | ||
|
|
bb3dd13f72 | ||
|
|
808d123e6f | ||
|
|
14d76cc062 | ||
|
|
d2f76ade61 | ||
|
|
12750d25b5 | ||
|
|
334fa475b4 | ||
|
|
8fe260de55 | ||
|
|
7e1be20317 | ||
|
|
3a42ee0c30 | ||
|
|
30ecacd625 | ||
|
|
a0e742be5e | ||
|
|
50e2fdaa74 | ||
|
|
77ddfd49e6 | ||
|
|
4887eeb77c | ||
|
|
9cf2877945 | ||
|
|
97d63db52c | ||
|
|
f8b0beeba9 | ||
|
|
93c5bd0fdd | ||
|
|
feb864712f | ||
|
|
2f3211028b | ||
|
|
cdaa827b2a | ||
|
|
a9d6bc60d0 | ||
|
|
9166c71e08 | ||
|
|
43b2d41e81 | ||
|
|
e8620255a0 | ||
|
|
48f0eb206c | ||
|
|
962e7d5a30 | ||
|
|
aa59c01742 | ||
|
|
cd60d9c14a | ||
|
|
b3ef7c9f25 | ||
|
|
be2c2bcf9b | ||
|
|
d5ca0c7032 | ||
|
|
3c2ab0fefa | ||
|
|
1643fd7532 | ||
|
|
53442d48f5 | ||
|
|
96bace56fa | ||
|
|
b0127e01e3 | ||
|
|
e71d0abc7d | ||
|
|
a6d50a61b3 | ||
|
|
dec007693a | ||
|
|
1145498521 | ||
|
|
2f07b70870 | ||
|
|
09b36c332a | ||
|
|
955fff52c5 | ||
|
|
6d665f3e91 | ||
|
|
74fd46894f | ||
|
|
ffaadcc990 | ||
|
|
54175f3b99 | ||
|
|
59573646c2 | ||
|
|
ba7798b389 | ||
|
|
f1203f3d0d | ||
|
|
881a131ad3 | ||
|
|
fb3e2c15fd | ||
|
|
fad0e69cc7 | ||
|
|
cf22c367a1 | ||
|
|
291d238ec4 | ||
|
|
69e1eae480 | ||
|
|
b1d4c9b9d5 | ||
|
|
d748b0c8c9 | ||
|
|
90af66d64b |
4
.github/workflows/ci.yml
vendored
4
.github/workflows/ci.yml
vendored
@@ -200,8 +200,8 @@ jobs:
|
||||
"test": true,
|
||||
// NOTE: `test-speedcenter` currently seems to be broken on `ubuntu-latest`
|
||||
"test-speedcenter": large && level >= 2,
|
||||
// made explicit until it can be assumed to have propagated to PRs
|
||||
"CMAKE_OPTIONS": "-DUSE_LAKE=ON",
|
||||
// We are not warning-free yet on all platforms, start here
|
||||
"CMAKE_OPTIONS": "-DLEAN_EXTRA_CXX_FLAGS=-Werror",
|
||||
},
|
||||
{
|
||||
"name": "Linux Reldebug",
|
||||
|
||||
@@ -131,10 +131,11 @@ structure State where
|
||||
`transDeps[i]` is the (non-reflexive) transitive closure of `mods[i].imports`. More specifically,
|
||||
* `j ∈ transDeps[i].pub` if `i -(public import)->+ j`
|
||||
* `j ∈ transDeps[i].priv` if `i -(import ...)-> _ -(public import)->* j`
|
||||
* `j ∈ transDeps[i].priv` if `i -(import all)->+ -(public import ...)-> _ -(public import)->* j`
|
||||
* `j ∈ transDeps[i].metaPub` if `i -(public (meta)? import)->* _ -(public meta import)-> _ -(public (meta)? import ...)->* j`
|
||||
* `j ∈ transDeps[i].metaPriv` if `i -(meta import ...)-> _ -(public (meta)? import ...)->* j`
|
||||
* `j ∈ transDeps[i].metaPriv` if `i -(import all)->+ -(public meta import ...)-> _ -(public (meta)? import ...)->* j`
|
||||
* `j ∈ transDeps[i].priv` if `i -(import all)->+ i'` and `j ∈ transDeps[i'].pub/priv`
|
||||
* `j ∈ transDeps[i].metaPub` if `i -(public (meta)? import)->* _ -(public meta import)-> _ -(public (meta)? import)->* j`
|
||||
* `j ∈ transDeps[i].metaPriv` if `i -(meta import ...)-> _ -(public (meta)? import)->* j`
|
||||
* `j ∈ transDeps[i].metaPriv` if `i -(import ...)-> i'` and `j ∈ transDeps[i'].metaPub`
|
||||
* `j ∈ transDeps[i].metaPriv` if `i -(import all)->+ i'` and `j ∈ transDeps[i'].metaPub/metaPriv`
|
||||
-/
|
||||
transDeps : Array Needs := #[]
|
||||
/--
|
||||
@@ -162,10 +163,10 @@ def addTransitiveImps (transImps : Needs) (imp : Import) (j : Nat) (impTransImps
|
||||
-- `j ∈ transDeps[i].priv` if `i -(import ...)-> _ -(public import)->* j`
|
||||
transImps := transImps.union .priv {j} |>.union .priv (impTransImps.get .pub)
|
||||
if imp.importAll then
|
||||
-- `j ∈ transDeps[i].priv` if `i -(import all)->+ -(public import ...)-> _ -(public import)->* j`
|
||||
transImps := transImps.union .priv (impTransImps.get .pub)
|
||||
-- `j ∈ transDeps[i].priv` if `i -(import all)->+ i'` and `j ∈ transDeps[i'].pub/priv`
|
||||
transImps := transImps.union .priv (impTransImps.get .pub ∪ impTransImps.get .priv)
|
||||
|
||||
-- `j ∈ transDeps[i].metaPub` if `i -(public (meta)? import)->* _ -(public meta import)-> _ -(public (meta)? import ...)->* j`
|
||||
-- `j ∈ transDeps[i].metaPub` if `i -(public (meta)? import)->* _ -(public meta import)-> _ -(public (meta)? import)->* j`
|
||||
if imp.isExported then
|
||||
transImps := transImps.union .metaPub (impTransImps.get .metaPub)
|
||||
if imp.isMeta then
|
||||
@@ -173,10 +174,13 @@ def addTransitiveImps (transImps : Needs) (imp : Import) (j : Nat) (impTransImps
|
||||
|
||||
if !imp.isExported then
|
||||
if imp.isMeta then
|
||||
-- `j ∈ transDeps[i].metaPriv` if `i -(meta import ...)-> _ -(public (meta)? import ...)->* j`
|
||||
-- `j ∈ transDeps[i].metaPriv` if `i -(meta import ...)-> _ -(public (meta)? import)->* j`
|
||||
transImps := transImps.union .metaPriv {j} |>.union .metaPriv (impTransImps.get .pub ∪ impTransImps.get .metaPub)
|
||||
if imp.importAll then
|
||||
-- `j ∈ transDeps[i].metaPriv` if `i -(import all)->+ -(public meta import ...)-> _ -(public (meta)? import ...)->* j`
|
||||
-- `j ∈ transDeps[i].metaPriv` if `i -(import all)->+ i'` and `j ∈ transDeps[i'].metaPub/metaPriv`
|
||||
transImps := transImps.union .metaPriv (impTransImps.get .metaPub ∪ impTransImps.get .metaPriv)
|
||||
else
|
||||
-- `j ∈ transDeps[i].metaPriv` if `i -(import ...)-> i'` and `j ∈ transDeps[i'].metaPub`
|
||||
transImps := transImps.union .metaPriv (impTransImps.get .metaPub)
|
||||
|
||||
transImps
|
||||
@@ -185,7 +189,8 @@ def addTransitiveImps (transImps : Needs) (imp : Import) (j : Nat) (impTransImps
|
||||
def calcNeeds (env : Environment) (i : ModuleIdx) : Needs := Id.run do
|
||||
let mut needs := default
|
||||
for ci in env.header.moduleData[i]!.constants do
|
||||
let pubCI? := env.setExporting true |>.find? ci.name
|
||||
-- Added guard for cases like `structure` that are still exported even if private
|
||||
let pubCI? := guard (!isPrivateName ci.name) *> (env.setExporting true).find? ci.name
|
||||
let k := { isExported := pubCI?.isSome, isMeta := isMeta env ci.name }
|
||||
needs := visitExpr k ci.type needs
|
||||
if let some e := ci.value? (allowOpaque := true) then
|
||||
@@ -216,7 +221,8 @@ def getExplanations (env : Environment) (i : ModuleIdx) :
|
||||
Std.HashMap (ModuleIdx × NeedsKind) (Option (Name × Name)) := Id.run do
|
||||
let mut deps := default
|
||||
for ci in env.header.moduleData[i]!.constants do
|
||||
let pubCI? := env.setExporting true |>.find? ci.name
|
||||
-- Added guard for cases like `structure` that are still exported even if private
|
||||
let pubCI? := guard (!isPrivateName ci.name) *> (env.setExporting true).find? ci.name
|
||||
let k := { isExported := pubCI?.isSome, isMeta := isMeta env ci.name }
|
||||
deps := visitExpr k ci.name ci.type deps
|
||||
if let some e := ci.value? (allowOpaque := true) then
|
||||
@@ -286,7 +292,7 @@ and `endPos` is the position of the end of the header.
|
||||
-/
|
||||
def parseHeaderFromString (text path : String) :
|
||||
IO (System.FilePath × Parser.InputContext ×
|
||||
TSyntaxArray ``Parser.Module.import × String.Pos) := do
|
||||
TSyntax ``Parser.Module.header × String.Pos.Raw) := do
|
||||
let inputCtx := Parser.mkInputContext text path
|
||||
let (header, parserState, msgs) ← Parser.parseHeader inputCtx
|
||||
if !msgs.toList.isEmpty then -- skip this file if there are parse errors
|
||||
@@ -294,8 +300,8 @@ def parseHeaderFromString (text path : String) :
|
||||
throw <| .userError "parse errors in file"
|
||||
-- the insertion point for `add` is the first newline after the imports
|
||||
let insertion := header.raw.getTailPos?.getD parserState.pos
|
||||
let insertion := text.findAux (· == '\n') text.endPos insertion + ⟨1⟩
|
||||
pure (path, inputCtx, .mk header.raw[2].getArgs, insertion)
|
||||
let insertion := text.findAux (· == '\n') text.endPos insertion + '\n'
|
||||
pure (path, inputCtx, header, insertion)
|
||||
|
||||
/-- Parse a source file to extract the location of the import lines, for edits and error messages.
|
||||
|
||||
@@ -304,13 +310,18 @@ and `endPos` is the position of the end of the header.
|
||||
-/
|
||||
def parseHeader (srcSearchPath : SearchPath) (mod : Name) :
|
||||
IO (System.FilePath × Parser.InputContext ×
|
||||
TSyntaxArray ``Parser.Module.import × String.Pos) := do
|
||||
TSyntax ``Parser.Module.header × String.Pos.Raw) := do
|
||||
-- Parse the input file
|
||||
let some path ← srcSearchPath.findModuleWithExt "lean" mod
|
||||
| throw <| .userError s!"error: failed to find source file for {mod}"
|
||||
let text ← IO.FS.readFile path
|
||||
parseHeaderFromString text path.toString
|
||||
|
||||
def decodeHeader : TSyntax ``Parser.Module.header → Option (TSyntax `module) × Option (TSyntax `prelude) × TSyntaxArray ``Parser.Module.import
|
||||
| `(Parser.Module.header| $[module%$moduleTk?]? $[prelude%$preludeTk?]? $imports*) =>
|
||||
(moduleTk?.map .mk, preludeTk?.map .mk, imports)
|
||||
| _ => unreachable!
|
||||
|
||||
def decodeImport : TSyntax ``Parser.Module.import → Import
|
||||
| `(Parser.Module.import| $[public%$pubTk?]? $[meta%$metaTk?]? import $[all%$allTk?]? $id) =>
|
||||
{ module := id.getId, isExported := pubTk?.isSome, isMeta := metaTk?.isSome, importAll := allTk?.isSome }
|
||||
@@ -326,11 +337,20 @@ def decodeImport : TSyntax ``Parser.Module.import → Import
|
||||
* `addOnly`: if true, only add missing imports, do not remove unused ones
|
||||
-/
|
||||
def visitModule (srcSearchPath : SearchPath)
|
||||
(i : Nat) (needs : Needs) (preserve : Needs) (edits : Edits)
|
||||
(i : Nat) (needs : Needs) (preserve : Needs) (edits : Edits) (headerStx : TSyntax ``Parser.Module.header)
|
||||
(addOnly := false) (githubStyle := false) (explain := false) : StateT State IO Edits := do
|
||||
let s ← get
|
||||
-- Do transitive reduction of `needs` in `deps`.
|
||||
let mut deps := needs
|
||||
let (_, prelude?, imports) := decodeHeader headerStx
|
||||
if prelude?.isNone then
|
||||
deps := deps.union .pub {s.env.getModuleIdx? `Init |>.get!}
|
||||
for imp in imports do
|
||||
if addOnly || imp.raw.getTrailing?.any (·.toString.toSlice.contains "shake: keep") then
|
||||
let imp := decodeImport imp
|
||||
let j := s.env.getModuleIdx? imp.module |>.get!
|
||||
let k := NeedsKind.ofImport imp
|
||||
deps := deps.union k {j}
|
||||
for j in [0:s.mods.size] do
|
||||
let transDeps := s.transDeps[j]!
|
||||
for k in NeedsKind.all do
|
||||
@@ -354,7 +374,8 @@ def visitModule (srcSearchPath : SearchPath)
|
||||
newDeps := addTransitiveImps newDeps imp j s.transDeps[j]!
|
||||
else
|
||||
let k := NeedsKind.ofImport imp
|
||||
if !addOnly && !deps.has k j && !deps.has { k with isExported := false } j then
|
||||
-- A private import should also be removed if the public version is needed
|
||||
if !deps.has k j || !k.isExported && deps.has { k with isExported := true } j then
|
||||
toRemove := toRemove.push imp
|
||||
else
|
||||
newDeps := addTransitiveImps newDeps imp j s.transDeps[j]!
|
||||
@@ -385,7 +406,8 @@ def visitModule (srcSearchPath : SearchPath)
|
||||
|
||||
if githubStyle then
|
||||
try
|
||||
let (path, inputCtx, imports, endHeader) ← parseHeader srcSearchPath s.modNames[i]!
|
||||
let (path, inputCtx, stx, endHeader) ← parseHeader srcSearchPath s.modNames[i]!
|
||||
let (_, _, imports) := decodeHeader stx
|
||||
for stx in imports do
|
||||
if toRemove.any fun imp => imp == decodeImport stx then
|
||||
let pos := inputCtx.fileMap.toPosition stx.raw.getPos?.get!
|
||||
@@ -529,33 +551,43 @@ def main (args : List String) : IO UInt32 := do
|
||||
let needs := s.mods.mapIdx fun i _ =>
|
||||
Task.spawn fun _ => calcNeeds s.env i
|
||||
|
||||
-- Parse headers in parallel
|
||||
let headers ← s.mods.mapIdxM fun i _ =>
|
||||
BaseIO.asTask (parseHeader srcSearchPath s.modNames[i]! |>.toBaseIO)
|
||||
|
||||
if args.fix then
|
||||
println! "The following changes will be made automatically:"
|
||||
|
||||
-- Check all selected modules
|
||||
let mut edits : Edits := ∅
|
||||
let mut revNeeds : Needs := default
|
||||
for i in [0:s.mods.size], t in needs do
|
||||
edits ← visitModule (addOnly := !pkg.isPrefixOf s.modNames[i]!) srcSearchPath i t.get revNeeds edits args.githubStyle args.explain
|
||||
if isExtraRevModUse s.env i then
|
||||
revNeeds := revNeeds.union .priv {i}
|
||||
for i in [0:s.mods.size], t in needs, header in headers do
|
||||
match header.get with
|
||||
| .ok (_, _, stx, _) =>
|
||||
edits ← visitModule (addOnly := !pkg.isPrefixOf s.modNames[i]!)
|
||||
srcSearchPath i t.get revNeeds edits stx args.githubStyle args.explain
|
||||
if isExtraRevModUse s.env i then
|
||||
revNeeds := revNeeds.union .priv {i}
|
||||
| .error e =>
|
||||
println! e.toString
|
||||
|
||||
if !args.fix then
|
||||
-- return error if any issues were found
|
||||
return if edits.isEmpty then 0 else 1
|
||||
|
||||
-- Apply the edits to existing files
|
||||
let count ← edits.foldM (init := 0) fun count mod (remove, add) => do
|
||||
let mut count := 0
|
||||
for mod in s.modNames, header? in headers do
|
||||
let some (remove, add) := edits[mod]? | continue
|
||||
let add : Array Import := add.qsortOrd
|
||||
|
||||
-- Parse the input file
|
||||
let (path, inputCtx, imports, insertion) ←
|
||||
try parseHeader srcSearchPath mod
|
||||
catch e => println! e.toString; return count
|
||||
let .ok (path, inputCtx, stx, insertion) := header?.get | continue
|
||||
let (_, _, imports) := decodeHeader stx
|
||||
let text := inputCtx.fileMap.source
|
||||
|
||||
-- Calculate the edit result
|
||||
let mut pos : String.Pos := 0
|
||||
let mut pos : String.Pos.Raw := 0
|
||||
let mut out : String := ""
|
||||
let mut seen : Std.HashSet Import := {}
|
||||
for stx in imports do
|
||||
@@ -563,7 +595,7 @@ def main (args : List String) : IO UInt32 := do
|
||||
if remove.contains mod || seen.contains mod then
|
||||
out := out ++ text.extract pos stx.raw.getPos?.get!
|
||||
-- We use the end position of the syntax, but include whitespace up to the first newline
|
||||
pos := text.findAux (· == '\n') text.rawEndPos stx.raw.getTailPos?.get! + ⟨1⟩
|
||||
pos := text.findAux (· == '\n') text.rawEndPos stx.raw.getTailPos?.get! + '\n'
|
||||
seen := seen.insert mod
|
||||
out := out ++ text.extract pos insertion
|
||||
for mod in add do
|
||||
@@ -573,7 +605,7 @@ def main (args : List String) : IO UInt32 := do
|
||||
out := out ++ text.extract insertion text.rawEndPos
|
||||
|
||||
IO.FS.writeFile path out
|
||||
return count + 1
|
||||
count := count + 1
|
||||
|
||||
-- Since we throw an error upon encountering issues, we can be sure that everything worked
|
||||
-- if we reach this point of the script.
|
||||
|
||||
@@ -14,7 +14,6 @@ public import Init.ByCases
|
||||
public import Init.RCases
|
||||
public import Init.Core
|
||||
public import Init.Control
|
||||
public import Init.Data.Basic
|
||||
public import Init.WF
|
||||
public import Init.WFTactics
|
||||
public import Init.Data
|
||||
|
||||
@@ -181,9 +181,6 @@ theorem not_imp_iff_and_not : ¬(a → b) ↔ a ∧ ¬b := Decidable.not_imp_iff
|
||||
|
||||
theorem not_and_iff_not_or_not : ¬(a ∧ b) ↔ ¬a ∨ ¬b := Decidable.not_and_iff_not_or_not
|
||||
|
||||
@[deprecated not_and_iff_not_or_not (since := "2025-03-18")]
|
||||
abbrev not_and_iff_or_not_not := @not_and_iff_not_or_not
|
||||
|
||||
theorem not_iff : ¬(a ↔ b) ↔ (¬a ↔ b) := Decidable.not_iff
|
||||
|
||||
@[simp] theorem imp_iff_left_iff : (b ↔ a → b) ↔ a ∨ b := Decidable.imp_iff_left_iff
|
||||
|
||||
@@ -45,9 +45,6 @@ instance (priority := 500) instForInOfForIn' [ForIn' m ρ α d] : ForIn m ρ α
|
||||
forIn x b f = forIn' x b (fun x h => binderNameHint x f <| binderNameHint h () <| f x) := by
|
||||
rfl
|
||||
|
||||
@[deprecated forIn_eq_forIn' (since := "2025-04-04")]
|
||||
abbrev forIn_eq_forin' := @forIn_eq_forIn'
|
||||
|
||||
/--
|
||||
Extracts the value from a `ForInStep`, ignoring whether it is `ForInStep.done` or `ForInStep.yield`.
|
||||
-/
|
||||
|
||||
@@ -255,11 +255,6 @@ instance : LawfulMonad Id := by
|
||||
@[simp] theorem run_seqLeft (x y : Id α) : (x <* y).run = x.run := rfl
|
||||
@[simp] theorem run_seq (f : Id (α → β)) (x : Id α) : (f <*> x).run = f.run x.run := rfl
|
||||
|
||||
-- These lemmas are bad as they abuse the defeq of `Id α` and `α`
|
||||
@[deprecated run_map (since := "2025-03-05")] theorem map_eq (x : Id α) (f : α → β) : f <$> x = f x := rfl
|
||||
@[deprecated run_bind (since := "2025-03-05")] theorem bind_eq (x : Id α) (f : α → id β) : x >>= f = f x := rfl
|
||||
@[deprecated run_pure (since := "2025-03-05")] theorem pure_eq (a : α) : (pure a : Id α) = a := rfl
|
||||
|
||||
end Id
|
||||
|
||||
/-! # Option -/
|
||||
|
||||
@@ -600,17 +600,6 @@ export LawfulSingleton (insert_empty_eq)
|
||||
|
||||
attribute [simp] insert_empty_eq
|
||||
|
||||
@[deprecated insert_empty_eq (since := "2025-03-12")]
|
||||
theorem insert_emptyc_eq [EmptyCollection β] [Insert α β] [Singleton α β]
|
||||
[LawfulSingleton α β] (x : α) : (insert x ∅ : β) = singleton x :=
|
||||
insert_empty_eq _
|
||||
|
||||
@[deprecated insert_empty_eq (since := "2025-03-12")]
|
||||
theorem LawfulSingleton.insert_emptyc_eq [EmptyCollection β] [Insert α β] [Singleton α β]
|
||||
[LawfulSingleton α β] (x : α) : (insert x ∅ : β) = singleton x :=
|
||||
insert_empty_eq _
|
||||
|
||||
|
||||
/-- Type class used to implement the notation `{ a ∈ c | p a }` -/
|
||||
class Sep (α : outParam <| Type u) (γ : Type v) where
|
||||
/-- Computes `{ a ∈ c | p a }`. -/
|
||||
@@ -1095,14 +1084,6 @@ theorem of_toBoolUsing_eq_true {p : Prop} {d : Decidable p} (h : toBoolUsing d =
|
||||
theorem of_toBoolUsing_eq_false {p : Prop} {d : Decidable p} (h : toBoolUsing d = false) : ¬p :=
|
||||
of_decide_eq_false h
|
||||
|
||||
set_option linter.missingDocs false in
|
||||
@[deprecated of_toBoolUsing_eq_true (since := "2025-04-04")]
|
||||
abbrev ofBoolUsing_eq_true := @of_toBoolUsing_eq_true
|
||||
|
||||
set_option linter.missingDocs false in
|
||||
@[deprecated of_toBoolUsing_eq_false (since := "2025-04-04")]
|
||||
abbrev ofBoolUsing_eq_false := @of_toBoolUsing_eq_false
|
||||
|
||||
instance : Decidable True :=
|
||||
isTrue trivial
|
||||
|
||||
@@ -1159,12 +1140,21 @@ variable {p q : Prop}
|
||||
decidable_of_decidable_of_iff (p := p) (h ▸ Iff.rfl)
|
||||
end
|
||||
|
||||
@[macro_inline] instance {p q} [Decidable p] [Decidable q] : Decidable (p → q) :=
|
||||
if hp : p then
|
||||
if hq : q then isTrue (fun _ => hq)
|
||||
else isFalse (fun h => absurd (h hp) hq)
|
||||
else isTrue (fun h => absurd h hp)
|
||||
@[inline]
|
||||
instance exists_prop_decidable {p} (P : p → Prop)
|
||||
[Decidable p] [∀ h, Decidable (P h)] : Decidable (Exists P) :=
|
||||
if h : p then
|
||||
decidable_of_decidable_of_iff ⟨fun h2 => ⟨h, h2⟩, fun ⟨_, h2⟩ => h2⟩
|
||||
else isFalse fun ⟨h', _⟩ => h h'
|
||||
|
||||
@[inline]
|
||||
instance forall_prop_decidable {p} (P : p → Prop)
|
||||
[Decidable p] [∀ h, Decidable (P h)] : Decidable (∀ h, P h) :=
|
||||
if h : p then
|
||||
decidable_of_decidable_of_iff ⟨fun h2 _ => h2, fun al => al h⟩
|
||||
else isTrue fun h2 => absurd h2 h
|
||||
|
||||
@[inline]
|
||||
instance {p q} [Decidable p] [Decidable q] : Decidable (p ↔ q) :=
|
||||
if hp : p then
|
||||
if hq : q then
|
||||
@@ -1212,11 +1202,13 @@ theorem dif_eq_if (c : Prop) {h : Decidable c} {α : Sort u} (t : α) (e : α) :
|
||||
| isTrue _ => rfl
|
||||
| isFalse _ => rfl
|
||||
|
||||
@[macro_inline]
|
||||
instance {c t e : Prop} [dC : Decidable c] [dT : Decidable t] [dE : Decidable e] : Decidable (if c then t else e) :=
|
||||
match dC with
|
||||
| isTrue _ => dT
|
||||
| isFalse _ => dE
|
||||
|
||||
@[inline]
|
||||
instance {c : Prop} {t : c → Prop} {e : ¬c → Prop} [dC : Decidable c] [dT : ∀ h, Decidable (t h)] [dE : ∀ h, Decidable (e h)] : Decidable (if h : c then t h else e h) :=
|
||||
match dC with
|
||||
| isTrue hc => dT hc
|
||||
@@ -1367,10 +1359,6 @@ namespace Subtype
|
||||
theorem exists_of_subtype {α : Type u} {p : α → Prop} : { x // p x } → Exists (fun x => p x)
|
||||
| ⟨a, h⟩ => ⟨a, h⟩
|
||||
|
||||
set_option linter.missingDocs false in
|
||||
@[deprecated exists_of_subtype (since := "2025-04-04")]
|
||||
abbrev existsOfSubtype := @exists_of_subtype
|
||||
|
||||
variable {α : Type u} {p : α → Prop}
|
||||
|
||||
protected theorem eq : ∀ {a1 a2 : {x // p x}}, val a1 = val a2 → a1 = a2
|
||||
|
||||
@@ -6,7 +6,6 @@ Authors: Leonardo de Moura
|
||||
module
|
||||
|
||||
prelude
|
||||
public import Init.Data.Basic
|
||||
public import Init.Data.Nat
|
||||
public import Init.Data.Bool
|
||||
public import Init.Data.BitVec
|
||||
|
||||
@@ -749,9 +749,6 @@ and simplifies these to the function directly taking the value.
|
||||
(Array.replicate n x).unattach = Array.replicate n x.1 := by
|
||||
simp [unattach]
|
||||
|
||||
@[deprecated unattach_replicate (since := "2025-03-18")]
|
||||
abbrev unattach_mkArray := @unattach_replicate
|
||||
|
||||
/-! ### Well-founded recursion preprocessing setup -/
|
||||
|
||||
@[wf_preprocess] theorem map_wfParam {xs : Array α} {f : α → β} :
|
||||
|
||||
@@ -209,20 +209,6 @@ Examples:
|
||||
def replicate {α : Type u} (n : Nat) (v : α) : Array α where
|
||||
toList := List.replicate n v
|
||||
|
||||
/--
|
||||
Creates an array that contains `n` repetitions of `v`.
|
||||
|
||||
The corresponding `List` function is `List.replicate`.
|
||||
|
||||
Examples:
|
||||
* `Array.mkArray 2 true = #[true, true]`
|
||||
* `Array.mkArray 3 () = #[(), (), ()]`
|
||||
* `Array.mkArray 0 "anything" = #[]`
|
||||
-/
|
||||
@[extern "lean_mk_array", deprecated replicate (since := "2025-03-18")]
|
||||
def mkArray {α : Type u} (n : Nat) (v : α) : Array α where
|
||||
toList := List.replicate n v
|
||||
|
||||
/--
|
||||
Swaps two elements of an array. The modification is performed in-place when the reference to the
|
||||
array is unique.
|
||||
@@ -2147,5 +2133,3 @@ instance [ToString α] : ToString (Array α) where
|
||||
toString xs := String.Internal.append "#" (toString xs.toList)
|
||||
|
||||
end Array
|
||||
|
||||
export Array (mkArray)
|
||||
|
||||
@@ -99,9 +99,6 @@ theorem countP_le_size : countP p xs ≤ xs.size := by
|
||||
theorem countP_replicate {a : α} {n : Nat} : countP p (replicate n a) = if p a then n else 0 := by
|
||||
simp [← List.toArray_replicate, List.countP_replicate]
|
||||
|
||||
@[deprecated countP_replicate (since := "2025-03-18")]
|
||||
abbrev countP_mkArray := @countP_replicate
|
||||
|
||||
theorem boole_getElem_le_countP {xs : Array α} {i : Nat} (h : i < xs.size) :
|
||||
(if p xs[i] then 1 else 0) ≤ xs.countP p := by
|
||||
rcases xs with ⟨xs⟩
|
||||
@@ -262,15 +259,9 @@ theorem count_eq_size {xs : Array α} : count a xs = xs.size ↔ ∀ b ∈ xs, a
|
||||
@[simp] theorem count_replicate_self {a : α} {n : Nat} : count a (replicate n a) = n := by
|
||||
simp [← List.toArray_replicate]
|
||||
|
||||
@[deprecated count_replicate_self (since := "2025-03-18")]
|
||||
abbrev count_mkArray_self := @count_replicate_self
|
||||
|
||||
theorem count_replicate {a b : α} {n : Nat} : count a (replicate n b) = if b == a then n else 0 := by
|
||||
simp [← List.toArray_replicate, List.count_replicate]
|
||||
|
||||
@[deprecated count_replicate (since := "2025-03-18")]
|
||||
abbrev count_mkArray := @count_replicate
|
||||
|
||||
theorem filter_beq {xs : Array α} (a : α) : xs.filter (· == a) = replicate (count a xs) a := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simp [List.filter_beq]
|
||||
@@ -284,9 +275,6 @@ theorem replicate_count_eq_of_count_eq_size {xs : Array α} (h : count a xs = xs
|
||||
rw [← toList_inj]
|
||||
simp [List.replicate_count_eq_of_count_eq_length (by simpa using h)]
|
||||
|
||||
@[deprecated replicate_count_eq_of_count_eq_size (since := "2025-03-18")]
|
||||
abbrev mkArray_count_eq_of_count_eq_size := @replicate_count_eq_of_count_eq_size
|
||||
|
||||
@[simp] theorem count_filter {xs : Array α} (h : p a) : count a (filter p xs) = count a xs := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simp [List.count_filter, h]
|
||||
|
||||
@@ -139,25 +139,16 @@ theorem eraseP_replicate {n : Nat} {a : α} {p : α → Bool} :
|
||||
simp only [← List.toArray_replicate, List.eraseP_toArray, List.eraseP_replicate]
|
||||
split <;> simp
|
||||
|
||||
@[deprecated eraseP_replicate (since := "2025-03-18")]
|
||||
abbrev eraseP_mkArray := @eraseP_replicate
|
||||
|
||||
@[simp] theorem eraseP_replicate_of_pos {n : Nat} {a : α} (h : p a) :
|
||||
(replicate n a).eraseP p = replicate (n - 1) a := by
|
||||
simp only [← List.toArray_replicate, List.eraseP_toArray]
|
||||
simp [h]
|
||||
|
||||
@[deprecated eraseP_replicate_of_pos (since := "2025-03-18")]
|
||||
abbrev eraseP_mkArray_of_pos := @eraseP_replicate_of_pos
|
||||
|
||||
@[simp] theorem eraseP_replicate_of_neg {n : Nat} {a : α} (h : ¬p a) :
|
||||
(replicate n a).eraseP p = replicate n a := by
|
||||
simp only [← List.toArray_replicate, List.eraseP_toArray]
|
||||
simp [h]
|
||||
|
||||
@[deprecated eraseP_replicate_of_neg (since := "2025-03-18")]
|
||||
abbrev eraseP_mkArray_of_neg := @eraseP_replicate_of_neg
|
||||
|
||||
theorem eraseP_eq_iff {p} {xs : Array α} :
|
||||
xs.eraseP p = ys ↔
|
||||
((∀ a ∈ xs, ¬ p a) ∧ xs = ys) ∨
|
||||
@@ -278,9 +269,6 @@ theorem erase_replicate [LawfulBEq α] {n : Nat} {a b : α} :
|
||||
simp only [List.erase_replicate, beq_iff_eq, List.toArray_replicate]
|
||||
split <;> simp
|
||||
|
||||
@[deprecated erase_replicate (since := "2025-03-18")]
|
||||
abbrev erase_mkArray := @erase_replicate
|
||||
|
||||
-- The arguments `a b` are explicit,
|
||||
-- so they can be specified to prevent `simp` repeatedly applying the lemma.
|
||||
@[grind =]
|
||||
@@ -308,17 +296,11 @@ theorem erase_eq_iff [LawfulBEq α] {a : α} {xs : Array α} :
|
||||
simp only [← List.toArray_replicate, List.erase_toArray]
|
||||
simp
|
||||
|
||||
@[deprecated erase_replicate_self (since := "2025-03-18")]
|
||||
abbrev erase_mkArray_self := @erase_replicate_self
|
||||
|
||||
@[simp] theorem erase_replicate_ne [LawfulBEq α] {a b : α} (h : !b == a) :
|
||||
(replicate n a).erase b = replicate n a := by
|
||||
rw [erase_of_not_mem]
|
||||
simp_all
|
||||
|
||||
@[deprecated erase_replicate_ne (since := "2025-03-18")]
|
||||
abbrev erase_mkArray_ne := @erase_replicate_ne
|
||||
|
||||
end erase
|
||||
|
||||
/-! ### eraseIdxIfInBounds -/
|
||||
@@ -429,9 +411,6 @@ theorem eraseIdx_replicate {n : Nat} {a : α} {k : Nat} {h} :
|
||||
simp only [← List.toArray_replicate, List.eraseIdx_toArray]
|
||||
simp [List.eraseIdx_replicate, h]
|
||||
|
||||
@[deprecated eraseIdx_replicate (since := "2025-03-18")]
|
||||
abbrev eraseIdx_mkArray := @eraseIdx_replicate
|
||||
|
||||
theorem mem_eraseIdx_iff_getElem {x : α} {xs : Array α} {k} {h} : x ∈ xs.eraseIdx k h ↔ ∃ i w, i ≠ k ∧ xs[i]'w = x := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simp [List.mem_eraseIdx_iff_getElem, *]
|
||||
|
||||
@@ -289,9 +289,6 @@ theorem extract_append_right {as bs : Array α} :
|
||||
· simp only [size_extract, size_replicate] at h₁ h₂
|
||||
simp only [getElem_extract, getElem_replicate]
|
||||
|
||||
@[deprecated extract_replicate (since := "2025-03-18")]
|
||||
abbrev extract_mkArray := @extract_replicate
|
||||
|
||||
theorem extract_eq_extract_right {as : Array α} {i j j' : Nat} :
|
||||
as.extract i j = as.extract i j' ↔ min (j - i) (as.size - i) = min (j' - i) (as.size - i) := by
|
||||
rcases as with ⟨as⟩
|
||||
@@ -429,32 +426,20 @@ theorem popWhile_append {xs ys : Array α} :
|
||||
(replicate n a).takeWhile p = (replicate n a).filter p := by
|
||||
simp [← List.toArray_replicate]
|
||||
|
||||
@[deprecated takeWhile_replicate_eq_filter (since := "2025-03-18")]
|
||||
abbrev takeWhile_mkArray_eq_filter := @takeWhile_replicate_eq_filter
|
||||
|
||||
theorem takeWhile_replicate {p : α → Bool} :
|
||||
(replicate n a).takeWhile p = if p a then replicate n a else #[] := by
|
||||
simp [takeWhile_replicate_eq_filter, filter_replicate]
|
||||
|
||||
@[deprecated takeWhile_replicate (since := "2025-03-18")]
|
||||
abbrev takeWhile_mkArray := @takeWhile_replicate
|
||||
|
||||
@[simp] theorem popWhile_replicate_eq_filter_not {p : α → Bool} :
|
||||
(replicate n a).popWhile p = (replicate n a).filter (fun a => !p a) := by
|
||||
simp [← List.toArray_replicate, ← List.filter_reverse]
|
||||
|
||||
@[deprecated popWhile_replicate_eq_filter_not (since := "2025-03-18")]
|
||||
abbrev popWhile_mkArray_eq_filter_not := @popWhile_replicate_eq_filter_not
|
||||
|
||||
theorem popWhile_replicate {p : α → Bool} :
|
||||
(replicate n a).popWhile p = if p a then #[] else replicate n a := by
|
||||
simp only [popWhile_replicate_eq_filter_not, size_replicate, filter_replicate, Bool.not_eq_eq_eq_not,
|
||||
Bool.not_true]
|
||||
split <;> simp_all
|
||||
|
||||
@[deprecated popWhile_replicate (since := "2025-03-18")]
|
||||
abbrev popWhile_mkArray := @popWhile_replicate
|
||||
|
||||
theorem extract_takeWhile {as : Array α} {i : Nat} :
|
||||
(as.takeWhile p).extract 0 i = (as.extract 0 i).takeWhile p := by
|
||||
rcases as with ⟨as⟩
|
||||
|
||||
@@ -129,31 +129,19 @@ theorem getElem_zero_flatten {xss : Array (Array α)} (h) :
|
||||
theorem findSome?_replicate : findSome? f (replicate n a) = if n = 0 then none else f a := by
|
||||
simp [← List.toArray_replicate, List.findSome?_replicate]
|
||||
|
||||
@[deprecated findSome?_replicate (since := "2025-03-18")]
|
||||
abbrev findSome?_mkArray := @findSome?_replicate
|
||||
|
||||
@[simp] theorem findSome?_replicate_of_pos (h : 0 < n) : findSome? f (replicate n a) = f a := by
|
||||
simp [findSome?_replicate, Nat.ne_of_gt h]
|
||||
|
||||
@[deprecated findSome?_replicate_of_pos (since := "2025-03-18")]
|
||||
abbrev findSome?_mkArray_of_pos := @findSome?_replicate_of_pos
|
||||
|
||||
-- Argument is unused, but used to decide whether `simp` should unfold.
|
||||
@[simp] theorem findSome?_replicate_of_isSome (_ : (f a).isSome) :
|
||||
findSome? f (replicate n a) = if n = 0 then none else f a := by
|
||||
simp [findSome?_replicate]
|
||||
|
||||
@[deprecated findSome?_replicate_of_isSome (since := "2025-03-18")]
|
||||
abbrev findSome?_mkArray_of_isSome := @findSome?_replicate_of_isSome
|
||||
|
||||
@[simp] theorem findSome?_replicate_of_isNone (h : (f a).isNone) :
|
||||
findSome? f (replicate n a) = none := by
|
||||
rw [Option.isNone_iff_eq_none] at h
|
||||
simp [findSome?_replicate, h]
|
||||
|
||||
@[deprecated findSome?_replicate_of_isNone (since := "2025-03-18")]
|
||||
abbrev findSome?_mkArray_of_isNone := @findSome?_replicate_of_isNone
|
||||
|
||||
/-! ### find? -/
|
||||
|
||||
@[simp, grind =] theorem find?_empty : find? p #[] = none := rfl
|
||||
@@ -318,16 +306,10 @@ theorem find?_replicate :
|
||||
find? p (replicate n a) = if p a then some a else none := by
|
||||
simp [find?_replicate, Nat.ne_of_gt h]
|
||||
|
||||
@[deprecated find?_replicate_of_size_pos (since := "2025-03-18")]
|
||||
abbrev find?_mkArray_of_length_pos := @find?_replicate_of_size_pos
|
||||
|
||||
@[simp] theorem find?_replicate_of_pos (h : p a) :
|
||||
find? p (replicate n a) = if n = 0 then none else some a := by
|
||||
simp [find?_replicate, h]
|
||||
|
||||
@[deprecated find?_replicate_of_pos (since := "2025-03-18")]
|
||||
abbrev find?_mkArray_of_pos := @find?_replicate_of_pos
|
||||
|
||||
@[simp] theorem find?_replicate_of_neg (h : ¬ p a) : find? p (replicate n a) = none := by
|
||||
simp [find?_replicate, h]
|
||||
|
||||
@@ -583,9 +565,6 @@ theorem findIdx?_flatten {xss : Array (Array α)} {p : α → Bool} :
|
||||
simp only [List.findIdx?_toArray]
|
||||
simp
|
||||
|
||||
@[deprecated findIdx?_replicate (since := "2025-03-18")]
|
||||
abbrev findIdx?_mkArray := @findIdx?_replicate
|
||||
|
||||
theorem findIdx?_eq_findSome?_zipIdx {xs : Array α} {p : α → Bool} :
|
||||
xs.findIdx? p = xs.zipIdx.findSome? fun ⟨a, i⟩ => if p a then some i else none := by
|
||||
rcases xs with ⟨xs⟩
|
||||
|
||||
@@ -317,41 +317,23 @@ theorem singleton_inj : #[a] = #[b] ↔ a = b := by
|
||||
@[simp, grind =] theorem size_replicate {n : Nat} {v : α} : (replicate n v).size = n :=
|
||||
List.length_replicate ..
|
||||
|
||||
@[deprecated size_replicate (since := "2025-03-18")]
|
||||
abbrev size_mkArray := @size_replicate
|
||||
|
||||
@[simp] theorem toList_replicate : (replicate n a).toList = List.replicate n a := by
|
||||
simp only [replicate]
|
||||
|
||||
@[deprecated toList_replicate (since := "2025-03-18")]
|
||||
abbrev toList_mkArray := @toList_replicate
|
||||
|
||||
@[simp, grind =] theorem replicate_zero : replicate 0 a = #[] := rfl
|
||||
|
||||
@[deprecated replicate_zero (since := "2025-03-18")]
|
||||
abbrev mkArray_zero := @replicate_zero
|
||||
|
||||
@[grind =]
|
||||
theorem replicate_succ : replicate (n + 1) a = (replicate n a).push a := by
|
||||
apply toList_inj.1
|
||||
simp [List.replicate_succ']
|
||||
|
||||
@[deprecated replicate_succ (since := "2025-03-18")]
|
||||
abbrev mkArray_succ := @replicate_succ
|
||||
|
||||
@[simp, grind =] theorem getElem_replicate {n : Nat} {v : α} {i : Nat} (h : i < (replicate n v).size) :
|
||||
(replicate n v)[i] = v := by simp [← getElem_toList]
|
||||
|
||||
@[deprecated getElem_replicate (since := "2025-03-18")]
|
||||
abbrev getElem_mkArray := @getElem_replicate
|
||||
|
||||
@[grind =] theorem getElem?_replicate {n : Nat} {v : α} {i : Nat} :
|
||||
(replicate n v)[i]? = if i < n then some v else none := by
|
||||
simp [getElem?_def]
|
||||
|
||||
@[deprecated getElem?_replicate (since := "2025-03-18")]
|
||||
abbrev getElem?_mkArray := @getElem?_replicate
|
||||
|
||||
/-! ### mem -/
|
||||
|
||||
@[grind ←]
|
||||
@@ -1074,12 +1056,6 @@ theorem mem_or_eq_of_mem_setIfInBounds
|
||||
cases xs
|
||||
simp
|
||||
|
||||
@[deprecated beq_empty_eq (since := "2025-04-04")]
|
||||
abbrev beq_empty_iff := @beq_empty_eq
|
||||
|
||||
@[deprecated empty_beq_eq (since := "2025-04-04")]
|
||||
abbrev empty_beq_iff := @empty_beq_eq
|
||||
|
||||
@[simp, grind =] theorem push_beq_push [BEq α] {a b : α} {xs ys : Array α} :
|
||||
(xs.push a == ys.push b) = (xs == ys && a == b) := by
|
||||
cases xs
|
||||
@@ -1100,9 +1076,6 @@ theorem size_eq_of_beq [BEq α] {xs ys : Array α} (h : xs == ys) : xs.size = ys
|
||||
rw [Bool.eq_iff_iff]
|
||||
simp +contextual
|
||||
|
||||
@[deprecated replicate_beq_replicate (since := "2025-03-18")]
|
||||
abbrev mkArray_beq_mkArray := @replicate_beq_replicate
|
||||
|
||||
private theorem beq_of_beq_singleton [BEq α] {a b : α} : #[a] == #[b] → a == b := by
|
||||
intro h
|
||||
have : isEqv #[a] #[b] BEq.beq = true := h
|
||||
@@ -1718,9 +1691,6 @@ theorem forall_none_of_filterMap_eq_empty (h : filterMap f xs = #[]) : ∀ x ∈
|
||||
cases xs
|
||||
simp
|
||||
|
||||
@[deprecated filterMap_eq_empty_iff (since := "2025-04-04")]
|
||||
abbrev filterMap_eq_nil_iff := @filterMap_eq_empty_iff
|
||||
|
||||
theorem filterMap_eq_push_iff {f : α → Option β} {xs : Array α} {ys : Array β} {b : β} :
|
||||
filterMap f xs = ys.push b ↔ ∃ as a bs,
|
||||
xs = as.push a ++ bs ∧ filterMap f as = ys ∧ f a = some b ∧ (∀ x, x ∈ bs → f x = none) := by
|
||||
@@ -2390,77 +2360,44 @@ theorem flatMap_eq_foldl {f : α → Array β} {xs : Array α} :
|
||||
|
||||
@[simp] theorem replicate_one : replicate 1 a = #[a] := rfl
|
||||
|
||||
@[deprecated replicate_one (since := "2025-03-18")]
|
||||
abbrev mkArray_one := @replicate_one
|
||||
|
||||
/-- Variant of `replicate_succ` that prepends `a` at the beginning of the array. -/
|
||||
theorem replicate_succ' : replicate (n + 1) a = #[a] ++ replicate n a := by
|
||||
apply Array.ext'
|
||||
simp [List.replicate_succ]
|
||||
|
||||
@[deprecated replicate_succ' (since := "2025-03-18")]
|
||||
abbrev mkArray_succ' := @replicate_succ'
|
||||
|
||||
@[simp, grind =] theorem mem_replicate {a b : α} {n} : b ∈ replicate n a ↔ n ≠ 0 ∧ b = a := by
|
||||
unfold replicate
|
||||
simp only [List.mem_toArray, List.mem_replicate]
|
||||
|
||||
@[deprecated mem_replicate (since := "2025-03-18")]
|
||||
abbrev mem_mkArray := @mem_replicate
|
||||
|
||||
@[grind →] theorem eq_of_mem_replicate {a b : α} {n} (h : b ∈ replicate n a) : b = a := (mem_replicate.1 h).2
|
||||
|
||||
@[deprecated eq_of_mem_mkArray (since := "2025-03-18")]
|
||||
abbrev eq_of_mem_mkArray := @eq_of_mem_replicate
|
||||
|
||||
theorem forall_mem_replicate {p : α → Prop} {a : α} {n} :
|
||||
(∀ b, b ∈ replicate n a → p b) ↔ n = 0 ∨ p a := by
|
||||
cases n <;> simp [mem_replicate]
|
||||
|
||||
@[deprecated forall_mem_replicate (since := "2025-03-18")]
|
||||
abbrev forall_mem_mkArray := @forall_mem_replicate
|
||||
|
||||
@[simp] theorem replicate_succ_ne_empty {n : Nat} {a : α} : replicate (n+1) a ≠ #[] := by
|
||||
simp [replicate_succ]
|
||||
|
||||
@[deprecated replicate_succ_ne_empty (since := "2025-03-18")]
|
||||
abbrev mkArray_succ_ne_empty := @replicate_succ_ne_empty
|
||||
|
||||
@[simp] theorem replicate_eq_empty_iff {n : Nat} {a : α} : replicate n a = #[] ↔ n = 0 := by
|
||||
cases n <;> simp
|
||||
|
||||
@[deprecated replicate_eq_empty_iff (since := "2025-03-18")]
|
||||
abbrev mkArray_eq_empty_iff := @replicate_eq_empty_iff
|
||||
|
||||
@[simp] theorem replicate_inj : replicate n a = replicate m b ↔ n = m ∧ (n = 0 ∨ a = b) := by
|
||||
rw [← toList_inj]
|
||||
simp
|
||||
|
||||
@[deprecated replicate_inj (since := "2025-03-18")]
|
||||
abbrev mkArray_inj := @replicate_inj
|
||||
|
||||
theorem eq_replicate_of_mem {a : α} {xs : Array α} (h : ∀ (b) (_ : b ∈ xs), b = a) : xs = replicate xs.size a := by
|
||||
rw [← toList_inj]
|
||||
simpa using List.eq_replicate_of_mem (by simpa using h)
|
||||
|
||||
@[deprecated eq_replicate_of_mem (since := "2025-03-18")]
|
||||
abbrev eq_mkArray_of_mem := @eq_replicate_of_mem
|
||||
|
||||
theorem eq_replicate_iff {a : α} {n} {xs : Array α} :
|
||||
xs = replicate n a ↔ xs.size = n ∧ ∀ (b) (_ : b ∈ xs), b = a := by
|
||||
rw [← toList_inj]
|
||||
simpa using List.eq_replicate_iff (l := xs.toList)
|
||||
|
||||
@[deprecated eq_replicate_iff (since := "2025-03-18")]
|
||||
abbrev eq_mkArray_iff := @eq_replicate_iff
|
||||
|
||||
theorem map_eq_replicate_iff {xs : Array α} {f : α → β} {b : β} :
|
||||
xs.map f = replicate xs.size b ↔ ∀ x ∈ xs, f x = b := by
|
||||
simp [eq_replicate_iff]
|
||||
|
||||
@[deprecated map_eq_replicate_iff (since := "2025-03-18")]
|
||||
abbrev map_eq_mkArray_iff := @map_eq_replicate_iff
|
||||
|
||||
@[simp] theorem map_const {xs : Array α} {b : β} : map (Function.const α b) xs = replicate xs.size b :=
|
||||
map_eq_replicate_iff.mpr fun _ _ => rfl
|
||||
|
||||
@@ -2477,143 +2414,86 @@ theorem map_const' {xs : Array α} {b : β} : map (fun _ => b) xs = replicate xs
|
||||
apply Array.ext'
|
||||
simp
|
||||
|
||||
@[deprecated set_replicate_self (since := "2025-03-18")]
|
||||
abbrev set_mkArray_self := @set_replicate_self
|
||||
|
||||
@[simp] theorem setIfInBounds_replicate_self : (replicate n a).setIfInBounds i a = replicate n a := by
|
||||
apply Array.ext'
|
||||
simp
|
||||
|
||||
@[deprecated setIfInBounds_replicate_self (since := "2025-03-18")]
|
||||
abbrev setIfInBounds_mkArray_self := @setIfInBounds_replicate_self
|
||||
|
||||
@[simp] theorem replicate_append_replicate : replicate n a ++ replicate m a = replicate (n + m) a := by
|
||||
apply Array.ext'
|
||||
simp
|
||||
|
||||
@[deprecated replicate_append_replicate (since := "2025-03-18")]
|
||||
abbrev mkArray_append_mkArray := @replicate_append_replicate
|
||||
|
||||
theorem append_eq_replicate_iff {xs ys : Array α} {a : α} :
|
||||
xs ++ ys = replicate n a ↔
|
||||
xs.size + ys.size = n ∧ xs = replicate xs.size a ∧ ys = replicate ys.size a := by
|
||||
simp [← toList_inj, List.append_eq_replicate_iff]
|
||||
|
||||
@[deprecated append_eq_replicate_iff (since := "2025-03-18")]
|
||||
abbrev append_eq_mkArray_iff := @append_eq_replicate_iff
|
||||
|
||||
theorem replicate_eq_append_iff {xs ys : Array α} {a : α} :
|
||||
replicate n a = xs ++ ys ↔
|
||||
xs.size + ys.size = n ∧ xs = replicate xs.size a ∧ ys = replicate ys.size a := by
|
||||
rw [eq_comm, append_eq_replicate_iff]
|
||||
|
||||
@[deprecated replicate_eq_append_iff (since := "2025-03-18")]
|
||||
abbrev replicate_eq_mkArray_iff := @replicate_eq_append_iff
|
||||
|
||||
@[simp] theorem map_replicate : (replicate n a).map f = replicate n (f a) := by
|
||||
apply Array.ext'
|
||||
simp
|
||||
|
||||
@[deprecated map_replicate (since := "2025-03-18")]
|
||||
abbrev map_mkArray := @map_replicate
|
||||
|
||||
@[grind =] theorem filter_replicate (w : stop = n) :
|
||||
(replicate n a).filter p 0 stop = if p a then replicate n a else #[] := by
|
||||
apply Array.ext'
|
||||
simp only [w]
|
||||
split <;> simp_all
|
||||
|
||||
@[deprecated filter_replicate (since := "2025-03-18")]
|
||||
abbrev filter_mkArray := @filter_replicate
|
||||
|
||||
@[simp] theorem filter_replicate_of_pos (w : stop = n) (h : p a) :
|
||||
(replicate n a).filter p 0 stop = replicate n a := by
|
||||
simp [filter_replicate, h, w]
|
||||
|
||||
@[deprecated filter_replicate_of_pos (since := "2025-03-18")]
|
||||
abbrev filter_mkArray_of_pos := @filter_replicate_of_pos
|
||||
|
||||
@[simp] theorem filter_replicate_of_neg (w : stop = n) (h : ¬ p a) :
|
||||
(replicate n a).filter p 0 stop = #[] := by
|
||||
simp [filter_replicate, h, w]
|
||||
|
||||
@[deprecated filter_replicate_of_neg (since := "2025-03-18")]
|
||||
abbrev filter_mkArray_of_neg := @filter_replicate_of_neg
|
||||
|
||||
theorem filterMap_replicate {f : α → Option β} (w : stop = n := by simp) :
|
||||
(replicate n a).filterMap f 0 stop = match f a with | none => #[] | .some b => replicate n b := by
|
||||
apply Array.ext'
|
||||
simp only [w, size_replicate, toList_filterMap', toList_replicate, List.filterMap_replicate]
|
||||
split <;> simp_all
|
||||
|
||||
@[deprecated filterMap_replicate (since := "2025-03-18")]
|
||||
abbrev filterMap_mkArray := @filterMap_replicate
|
||||
|
||||
-- This is not a useful `simp` lemma because `b` is unknown.
|
||||
theorem filterMap_replicate_of_some {f : α → Option β} (h : f a = some b) :
|
||||
(replicate n a).filterMap f = replicate n b := by
|
||||
simp [filterMap_replicate, h]
|
||||
|
||||
@[deprecated filterMap_replicate_of_some (since := "2025-03-18")]
|
||||
abbrev filterMap_mkArray_of_some := @filterMap_replicate_of_some
|
||||
|
||||
@[simp] theorem filterMap_replicate_of_isSome {f : α → Option β} (h : (f a).isSome) :
|
||||
(replicate n a).filterMap f = replicate n (Option.get _ h) := by
|
||||
match w : f a, h with
|
||||
| some b, _ => simp [filterMap_replicate, w]
|
||||
|
||||
@[deprecated filterMap_replicate_of_isSome (since := "2025-03-18")]
|
||||
abbrev filterMap_mkArray_of_isSome := @filterMap_replicate_of_isSome
|
||||
|
||||
@[simp] theorem filterMap_replicate_of_none {f : α → Option β} (h : f a = none) :
|
||||
(replicate n a).filterMap f = #[] := by
|
||||
simp [filterMap_replicate, h]
|
||||
|
||||
@[deprecated filterMap_replicate_of_none (since := "2025-03-18")]
|
||||
abbrev filterMap_mkArray_of_none := @filterMap_replicate_of_none
|
||||
|
||||
@[simp] theorem flatten_replicate_empty : (replicate n (#[] : Array α)).flatten = #[] := by
|
||||
rw [← toList_inj]
|
||||
simp
|
||||
|
||||
@[deprecated flatten_replicate_empty (since := "2025-03-18")]
|
||||
abbrev flatten_mkArray_empty := @flatten_replicate_empty
|
||||
|
||||
@[simp] theorem flatten_replicate_singleton : (replicate n #[a]).flatten = replicate n a := by
|
||||
rw [← toList_inj]
|
||||
simp
|
||||
|
||||
@[deprecated flatten_replicate_singleton (since := "2025-03-18")]
|
||||
abbrev flatten_mkArray_singleton := @flatten_replicate_singleton
|
||||
|
||||
@[simp] theorem flatten_replicate_replicate : (replicate n (replicate m a)).flatten = replicate (n * m) a := by
|
||||
rw [← toList_inj]
|
||||
simp
|
||||
|
||||
@[deprecated flatten_replicate_replicate (since := "2025-03-18")]
|
||||
abbrev flatten_mkArray_replicate := @flatten_replicate_replicate
|
||||
|
||||
theorem flatMap_replicate {f : α → Array β} : (replicate n a).flatMap f = (replicate n (f a)).flatten := by
|
||||
rw [← toList_inj]
|
||||
simp [List.flatMap_replicate]
|
||||
|
||||
@[deprecated flatMap_replicate (since := "2025-03-18")]
|
||||
abbrev flatMap_mkArray := @flatMap_replicate
|
||||
|
||||
@[simp] theorem isEmpty_replicate : (replicate n a).isEmpty = decide (n = 0) := by
|
||||
rw [← List.toArray_replicate, List.isEmpty_toArray]
|
||||
simp
|
||||
|
||||
@[deprecated isEmpty_replicate (since := "2025-03-18")]
|
||||
abbrev isEmpty_mkArray := @isEmpty_replicate
|
||||
|
||||
@[simp] theorem sum_replicate_nat {n : Nat} {a : Nat} : (replicate n a).sum = n * a := by
|
||||
rw [← List.toArray_replicate, List.sum_toArray]
|
||||
simp
|
||||
|
||||
@[deprecated sum_replicate_nat (since := "2025-03-18")]
|
||||
abbrev sum_mkArray_nat := @sum_replicate_nat
|
||||
|
||||
/-! ### Preliminaries about `swap` needed for `reverse`. -/
|
||||
|
||||
@[grind =]
|
||||
@@ -2800,9 +2680,6 @@ theorem flatten_reverse {xss : Array (Array α)} :
|
||||
rw [← toList_inj]
|
||||
simp
|
||||
|
||||
@[deprecated reverse_replicate (since := "2025-03-18")]
|
||||
abbrev reverse_mkArray := @reverse_replicate
|
||||
|
||||
/-! ### extract -/
|
||||
|
||||
theorem extract_loop_zero {xs ys : Array α} {start : Nat} : extract.loop xs 0 start ys = ys := by
|
||||
@@ -3712,15 +3589,9 @@ theorem back?_replicate {a : α} {n : Nat} :
|
||||
rw [replicate_eq_toArray_replicate]
|
||||
simp only [List.back?_toArray, List.getLast?_replicate]
|
||||
|
||||
@[deprecated back?_replicate (since := "2025-03-18")]
|
||||
abbrev back?_mkArray := @back?_replicate
|
||||
|
||||
@[simp] theorem back_replicate {xs : Array α} (w : 0 < n) : (replicate n xs).back (by simpa using w) = xs := by
|
||||
simp [back_eq_getElem]
|
||||
|
||||
@[deprecated back_replicate (since := "2025-03-18")]
|
||||
abbrev back_mkArray := @back_replicate
|
||||
|
||||
/-! ## Additional operations -/
|
||||
|
||||
/-! ### leftpad -/
|
||||
@@ -3738,9 +3609,6 @@ theorem size_rightpad {n : Nat} {a : α} {xs : Array α} :
|
||||
|
||||
theorem elem_push_self [BEq α] [LawfulBEq α] {xs : Array α} {a : α} : (xs.push a).elem a = true := by simp
|
||||
|
||||
@[deprecated elem_push_self (since := "2025-04-04")]
|
||||
abbrev elem_cons_self := @elem_push_self
|
||||
|
||||
theorem contains_eq_any_beq [BEq α] {xs : Array α} {a : α} : xs.contains a = xs.any (a == ·) := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simp [List.contains_eq_any_beq]
|
||||
@@ -3818,9 +3686,6 @@ theorem pop_append {xs ys : Array α} :
|
||||
@[simp, grind =] theorem pop_replicate {n : Nat} {a : α} : (replicate n a).pop = replicate (n - 1) a := by
|
||||
ext <;> simp
|
||||
|
||||
@[deprecated pop_replicate (since := "2025-03-18")]
|
||||
abbrev pop_mkArray := @pop_replicate
|
||||
|
||||
/-! ## Logic -/
|
||||
|
||||
/-! ### any / all -/
|
||||
@@ -4050,16 +3915,10 @@ theorem all_filterMap {xs : Array α} {f : α → Option β} {p : β → Bool} :
|
||||
(replicate n a).any f = if n = 0 then false else f a := by
|
||||
induction n <;> simp_all [replicate_succ']
|
||||
|
||||
@[deprecated any_replicate (since := "2025-03-18")]
|
||||
abbrev any_mkArray := @any_replicate
|
||||
|
||||
@[simp] theorem all_replicate {n : Nat} {a : α} :
|
||||
(replicate n a).all f = if n = 0 then true else f a := by
|
||||
induction n <;> simp_all +contextual [replicate_succ']
|
||||
|
||||
@[deprecated all_replicate (since := "2025-03-18")]
|
||||
abbrev all_mkArray := @all_replicate
|
||||
|
||||
/-! ### modify -/
|
||||
|
||||
@[simp, grind =] theorem size_modify {xs : Array α} {i : Nat} {f : α → α} : (xs.modify i f).size = xs.size := by
|
||||
@@ -4234,17 +4093,11 @@ theorem replace_extract {xs : Array α} {i : Nat} :
|
||||
(replicate n a).replace a b = #[b] ++ replicate (n - 1) a := by
|
||||
cases n <;> simp_all [replicate_succ', replace_append]
|
||||
|
||||
@[deprecated replace_replicate_self (since := "2025-03-18")]
|
||||
abbrev replace_mkArray_self := @replace_replicate_self
|
||||
|
||||
@[simp] theorem replace_replicate_ne {a b c : α} (h : !b == a) :
|
||||
(replicate n a).replace b c = replicate n a := by
|
||||
rw [replace_of_not_mem]
|
||||
simp_all
|
||||
|
||||
@[deprecated replace_replicate_ne (since := "2025-03-18")]
|
||||
abbrev replace_mkArray_ne := @replace_replicate_ne
|
||||
|
||||
end replace
|
||||
|
||||
/-! ### toListRev -/
|
||||
@@ -4412,9 +4265,6 @@ theorem getElem!_eq_getD [Inhabited α] {xs : Array α} {i} : xs[i]! = xs.getD i
|
||||
@[deprecated mem_toList_iff (since := "2025-05-26")]
|
||||
theorem mem_toList {a : α} {xs : Array α} : a ∈ xs.toList ↔ a ∈ xs := mem_def.symm
|
||||
|
||||
@[deprecated not_mem_empty (since := "2025-03-25")]
|
||||
theorem not_mem_nil (a : α) : ¬ a ∈ #[] := nofun
|
||||
|
||||
/-! # get lemmas -/
|
||||
|
||||
theorem lt_of_getElem {x : α} {xs : Array α} {i : Nat} {hidx : i < xs.size} (_ : xs[i] = x) :
|
||||
@@ -4463,12 +4313,6 @@ theorem getElem?_push_eq {xs : Array α} {x : α} : (xs.push x)[xs.size]? = some
|
||||
cases xs
|
||||
simp
|
||||
|
||||
/-! ### contains -/
|
||||
|
||||
@[deprecated contains_iff (since := "2025-04-07")]
|
||||
abbrev contains_def [DecidableEq α] {a : α} {xs : Array α} : xs.contains a ↔ a ∈ xs :=
|
||||
contains_iff
|
||||
|
||||
/-! ### isPrefixOf -/
|
||||
|
||||
@[simp, grind =] theorem isPrefixOf_toList [BEq α] {xs ys : Array α} :
|
||||
|
||||
@@ -296,9 +296,6 @@ theorem mapFinIdx_eq_replicate_iff {xs : Array α} {f : (i : Nat) → α → (h
|
||||
rw [← toList_inj]
|
||||
simp [List.mapFinIdx_eq_replicate_iff]
|
||||
|
||||
@[deprecated mapFinIdx_eq_replicate_iff (since := "2025-03-18")]
|
||||
abbrev mapFinIdx_eq_mkArray_iff := @mapFinIdx_eq_replicate_iff
|
||||
|
||||
@[simp, grind =] theorem mapFinIdx_reverse {xs : Array α} {f : (i : Nat) → α → (h : i < xs.reverse.size) → β} :
|
||||
xs.reverse.mapFinIdx f = (xs.mapFinIdx (fun i a h => f (xs.size - 1 - i) a (by simp; omega))).reverse := by
|
||||
rcases xs with ⟨l⟩
|
||||
@@ -438,9 +435,6 @@ theorem mapIdx_eq_replicate_iff {xs : Array α} {f : Nat → α → β} {b : β}
|
||||
rw [← toList_inj]
|
||||
simp [List.mapIdx_eq_replicate_iff]
|
||||
|
||||
@[deprecated mapIdx_eq_replicate_iff (since := "2025-03-18")]
|
||||
abbrev mapIdx_eq_mkArray_iff := @mapIdx_eq_replicate_iff
|
||||
|
||||
@[simp, grind =] theorem mapIdx_reverse {xs : Array α} {f : Nat → α → β} :
|
||||
xs.reverse.mapIdx f = (mapIdx (fun i => f (xs.size - 1 - i)) xs).reverse := by
|
||||
rcases xs with ⟨xs⟩
|
||||
|
||||
@@ -84,9 +84,6 @@ theorem Perm.size_eq {xs ys : Array α} (p : xs ~ ys) : xs.size = ys.size := by
|
||||
simp only [perm_iff_toList_perm] at p
|
||||
simpa using p.length_eq
|
||||
|
||||
@[deprecated Perm.size_eq (since := "2025-04-17")]
|
||||
abbrev Perm.length_eq := @Perm.size_eq
|
||||
|
||||
theorem Perm.mem_iff {a : α} {xs ys : Array α} (p : xs ~ ys) : a ∈ xs ↔ a ∈ ys := by
|
||||
rcases xs with ⟨xs⟩
|
||||
rcases ys with ⟨ys⟩
|
||||
|
||||
@@ -166,9 +166,6 @@ theorem zipWith_eq_append_iff {f : α → β → γ} {as : Array α} {bs : Array
|
||||
zipWith f (replicate m a) (replicate n b) = replicate (min m n) (f a b) := by
|
||||
simp [← List.toArray_replicate]
|
||||
|
||||
@[deprecated zipWith_replicate (since := "2025-03-18")]
|
||||
abbrev zipWith_mkArray := @zipWith_replicate
|
||||
|
||||
theorem map_uncurry_zip_eq_zipWith {f : α → β → γ} {as : Array α} {bs : Array β} :
|
||||
map (Function.uncurry f) (as.zip bs) = zipWith f as bs := by
|
||||
cases as
|
||||
@@ -294,9 +291,6 @@ theorem zip_eq_append_iff {as : Array α} {bs : Array β} :
|
||||
zip (replicate m a) (replicate n b) = replicate (min m n) (a, b) := by
|
||||
simp [← List.toArray_replicate]
|
||||
|
||||
@[deprecated zip_replicate (since := "2025-03-18")]
|
||||
abbrev zip_mkArray := @zip_replicate
|
||||
|
||||
theorem zip_eq_zip_take_min {as : Array α} {bs : Array β} :
|
||||
zip as bs = zip (as.take (min as.size bs.size)) (bs.take (min as.size bs.size)) := by
|
||||
cases as
|
||||
@@ -348,9 +342,6 @@ theorem map_zipWithAll {δ : Type _} {f : α → β} {g : Option γ → Option
|
||||
zipWithAll f (replicate n a) (replicate n b) = replicate n (f (some a) (some b)) := by
|
||||
simp [← List.toArray_replicate]
|
||||
|
||||
@[deprecated zipWithAll_replicate (since := "2025-03-18")]
|
||||
abbrev zipWithAll_mkArray := @zipWithAll_replicate
|
||||
|
||||
/-! ### zipWithM -/
|
||||
|
||||
@[simp, grind =]
|
||||
@@ -408,7 +399,4 @@ theorem zip_of_prod {as : Array α} {bs : Array β} {xs : Array (α × β)} (hl
|
||||
unzip (replicate n (a, b)) = (replicate n a, replicate n b) := by
|
||||
ext1 <;> simp
|
||||
|
||||
@[deprecated unzip_replicate (since := "2025-03-18")]
|
||||
abbrev unzip_mkArray := @unzip_replicate
|
||||
|
||||
end Array
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
/-
|
||||
Copyright (c) 2016 Microsoft Corporation. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Leonardo de Moura
|
||||
-/
|
||||
module
|
||||
|
||||
prelude
|
||||
public import Init.Data.UInt
|
||||
public import Init.Data.String.Extra
|
||||
@@ -34,14 +34,6 @@ namespace BitVec
|
||||
simp only [Bool.and_eq_false_imp, decide_eq_true_eq]
|
||||
omega
|
||||
|
||||
set_option linter.missingDocs false in
|
||||
@[deprecated getLsbD_of_ge (since := "2025-04-04")]
|
||||
abbrev getLsbD_ge := @getLsbD_of_ge
|
||||
|
||||
set_option linter.missingDocs false in
|
||||
@[deprecated getMsbD_of_ge (since := "2025-04-04")]
|
||||
abbrev getMsbD_ge := @getMsbD_of_ge
|
||||
|
||||
theorem lt_of_getLsbD {x : BitVec w} {i : Nat} : getLsbD x i = true → i < w := by
|
||||
if h : i < w then
|
||||
simp [h]
|
||||
@@ -175,12 +167,6 @@ theorem getLsbD_eq_getMsbD (x : BitVec w) (i : Nat) : x.getLsbD i = (decide (i <
|
||||
@[simp] theorem getMsb?_of_ge (x : BitVec w) (i : Nat) (ge : w ≤ i) : getMsb? x i = none := by
|
||||
simp [getMsb?_eq_getLsb?]; omega
|
||||
|
||||
set_option linter.missingDocs false in
|
||||
@[deprecated getElem?_of_ge (since := "2025-04-04")] abbrev getLsb?_ge := @getElem?_of_ge
|
||||
|
||||
set_option linter.missingDocs false in
|
||||
@[deprecated getMsb?_of_ge (since := "2025-04-04")] abbrev getMsb?_ge := @getMsb?_of_ge
|
||||
|
||||
theorem lt_of_getElem?_eq_some (x : BitVec w) (i : Nat) : x[i]? = some b → i < w := by
|
||||
cases h : x[i]? with
|
||||
| none => simp
|
||||
@@ -203,18 +189,6 @@ theorem lt_of_isSome_getMsb? (x : BitVec w) (i : Nat) : (getMsb? x i).isSome →
|
||||
else
|
||||
simp [Nat.ge_of_not_lt h]
|
||||
|
||||
set_option linter.missingDocs false in
|
||||
@[deprecated lt_of_getElem?_eq_some (since := "2025-04-04")]
|
||||
abbrev lt_of_getLsb?_eq_some := @lt_of_getElem?_eq_some
|
||||
|
||||
set_option linter.missingDocs false in
|
||||
@[deprecated lt_of_isSome_getElem? (since := "2025-04-04")]
|
||||
abbrev lt_of_getLsb?_isSome := @lt_of_isSome_getElem?
|
||||
|
||||
set_option linter.missingDocs false in
|
||||
@[deprecated lt_of_isSome_getMsb? (since := "2025-04-04")]
|
||||
abbrev lt_of_getMsb?_isSome := @lt_of_isSome_getMsb?
|
||||
|
||||
theorem getMsbD_eq_getMsb?_getD (x : BitVec w) (i : Nat) :
|
||||
x.getMsbD i = (x.getMsb? i).getD false := by
|
||||
rw [getMsbD_eq_getLsbD]
|
||||
@@ -1750,9 +1724,6 @@ theorem not_eq_comm {x y : BitVec w} : ~~~ x = y ↔ x = ~~~ y := by
|
||||
rw [h]
|
||||
simp
|
||||
|
||||
set_option linter.missingDocs false in
|
||||
@[deprecated getMsbD_not (since := "2025-04-04")] abbrev getMsb_not := @getMsbD_not
|
||||
|
||||
@[simp] theorem msb_not {x : BitVec w} : (~~~x).msb = (decide (0 < w) && !x.msb) := by
|
||||
simp [BitVec.msb]
|
||||
|
||||
@@ -2572,10 +2543,6 @@ theorem signExtend_eq_setWidth_of_le (x : BitVec w) {v : Nat} (hv : v ≤ w) :
|
||||
ext i h
|
||||
simp [getElem_signExtend, show i < w by omega]
|
||||
|
||||
@[deprecated signExtend_eq_setWidth_of_le (since := "2025-03-07")]
|
||||
theorem signExtend_eq_setWidth_of_lt (x : BitVec w) {v : Nat} (hv : v ≤ w) :
|
||||
x.signExtend v = x.setWidth v := signExtend_eq_setWidth_of_le x hv
|
||||
|
||||
/-- Sign extending to the same bitwidth is a no op. -/
|
||||
@[simp] theorem signExtend_eq (x : BitVec w) : x.signExtend w = x := by
|
||||
rw [signExtend_eq_setWidth_of_le _ (Nat.le_refl _), setWidth_eq]
|
||||
@@ -3635,9 +3602,6 @@ theorem sub_eq_add_neg {n} (x y : BitVec n) : x - y = x + - y := by
|
||||
simp only [toNat_sub, toNat_add, toNat_neg, Nat.add_mod_mod]
|
||||
rw [Nat.add_comm]
|
||||
|
||||
set_option linter.missingDocs false in
|
||||
@[deprecated sub_eq_add_neg (since := "2025-04-04")] abbrev sub_toAdd := @sub_eq_add_neg
|
||||
|
||||
theorem add_left_neg (x : BitVec w) : -x + x = 0#w := by
|
||||
apply toInt_inj.mp
|
||||
simp [toInt_neg, Int.add_left_neg]
|
||||
@@ -3677,10 +3641,6 @@ theorem neg_one_eq_allOnes : -1#w = allOnes w := by
|
||||
have r : (2^w - 1) < 2^w := by omega
|
||||
simp [Nat.mod_eq_of_lt q, Nat.mod_eq_of_lt r]
|
||||
|
||||
set_option linter.missingDocs false in
|
||||
@[deprecated neg_one_eq_allOnes (since := "2025-04-04")]
|
||||
abbrev negOne_eq_allOnes := @neg_one_eq_allOnes
|
||||
|
||||
theorem neg_eq_not_add (x : BitVec w) : -x = ~~~x + 1#w := by
|
||||
apply eq_of_toNat_eq
|
||||
simp only [toNat_neg, toNat_add, toNat_not, toNat_ofNat, Nat.add_mod_mod]
|
||||
@@ -4682,9 +4642,6 @@ theorem zero_smod {x : BitVec w} : (0#w).smod x = 0#w := by
|
||||
@[simp, grind =] theorem getLsbD_ofBoolListLE : (ofBoolListLE bs).getLsbD i = bs.getD i false := by
|
||||
induction bs generalizing i <;> cases i <;> simp_all [ofBoolListLE]
|
||||
|
||||
set_option linter.missingDocs false in
|
||||
@[deprecated getLsbD_ofBoolListLE (since := "2025-04-04")] abbrev getLsb_ofBoolListLE := @getLsbD_ofBoolListLE
|
||||
|
||||
@[simp, grind =] theorem getMsbD_ofBoolListLE :
|
||||
(ofBoolListLE bs).getMsbD i = (decide (i < bs.length) && bs.getD (bs.length - 1 - i) false) := by
|
||||
simp [getMsbD_eq_getLsbD]
|
||||
@@ -4755,14 +4712,6 @@ theorem getLsbD_rotateLeftAux_of_ge {x : BitVec w} {r : Nat} {i : Nat} (hi : i
|
||||
apply getLsbD_of_ge
|
||||
omega
|
||||
|
||||
set_option linter.missingDocs false in
|
||||
@[deprecated getLsbD_rotateLeftAux_of_lt (since := "2025-04-04")]
|
||||
abbrev getLsbD_rotateLeftAux_of_le := @getLsbD_rotateLeftAux_of_lt
|
||||
|
||||
set_option linter.missingDocs false in
|
||||
@[deprecated getLsbD_rotateLeftAux_of_ge (since := "2025-04-04")]
|
||||
abbrev getLsbD_rotateLeftAux_of_geq := @getLsbD_rotateLeftAux_of_ge
|
||||
|
||||
/-- When `r < w`, we give a formula for `(x.rotateLeft r).getLsbD i`. -/
|
||||
theorem getLsbD_rotateLeft_of_le {x : BitVec w} {r i : Nat} (hr: r < w) :
|
||||
(x.rotateLeft r).getLsbD i =
|
||||
@@ -4919,14 +4868,6 @@ theorem getLsbD_rotateRightAux_of_ge {x : BitVec w} {r : Nat} {i : Nat} (hi : i
|
||||
apply getLsbD_of_ge
|
||||
omega
|
||||
|
||||
set_option linter.missingDocs false in
|
||||
@[deprecated getLsbD_rotateRightAux_of_lt (since := "2025-04-04")]
|
||||
abbrev getLsbD_rotateRightAux_of_le := @getLsbD_rotateRightAux_of_lt
|
||||
|
||||
set_option linter.missingDocs false in
|
||||
@[deprecated getLsbD_rotateRightAux_of_ge (since := "2025-04-04")]
|
||||
abbrev getLsbD_rotateRightAux_of_geq := @getLsbD_rotateRightAux_of_ge
|
||||
|
||||
/-- `rotateRight` equals the bit fiddling definition of `rotateRightAux` when the rotation amount is
|
||||
smaller than the bitwidth. -/
|
||||
theorem rotateRight_eq_rotateRightAux_of_lt {x : BitVec w} {r : Nat} (hr : r < w) :
|
||||
|
||||
@@ -111,35 +111,11 @@ Needed for confluence of term `(a && b) ↔ a` which reduces to `(a && b) = a` v
|
||||
@[simp] theorem eq_self_and : ∀ {a b : Bool}, (a = (a && b)) ↔ (a → b) := by decide
|
||||
@[simp] theorem eq_and_self : ∀ {a b : Bool}, (b = (a && b)) ↔ (b → a) := by decide
|
||||
|
||||
@[deprecated and_eq_left_iff_imp (since := "2025-04-04")]
|
||||
abbrev and_iff_left_iff_imp := @and_eq_left_iff_imp
|
||||
|
||||
@[deprecated and_eq_right_iff_imp (since := "2025-04-04")]
|
||||
abbrev and_iff_right_iff_imp := @and_eq_right_iff_imp
|
||||
|
||||
@[deprecated eq_self_and (since := "2025-04-04")]
|
||||
abbrev iff_self_and := @eq_self_and
|
||||
|
||||
@[deprecated eq_and_self (since := "2025-04-04")]
|
||||
abbrev iff_and_self := @eq_and_self
|
||||
|
||||
@[simp] theorem not_and_eq_left_iff_and : ∀ {a b : Bool}, ((!a && b) = a) ↔ !a ∧ !b := by decide
|
||||
@[simp] theorem and_not_eq_right_iff_and : ∀ {a b : Bool}, ((a && !b) = b) ↔ !a ∧ !b := by decide
|
||||
@[simp] theorem eq_not_self_and : ∀ {a b : Bool}, (a = (!a && b)) ↔ !a ∧ !b := by decide
|
||||
@[simp] theorem eq_and_not_self : ∀ {a b : Bool}, (b = (a && !b)) ↔ !a ∧ !b := by decide
|
||||
|
||||
@[deprecated not_and_eq_left_iff_and (since := "2025-04-04")]
|
||||
abbrev not_and_iff_left_iff_imp := @not_and_eq_left_iff_and
|
||||
|
||||
@[deprecated and_not_eq_right_iff_and (since := "2025-04-04")]
|
||||
abbrev and_not_iff_right_iff_imp := @and_not_eq_right_iff_and
|
||||
|
||||
@[deprecated eq_not_self_and (since := "2025-04-04")]
|
||||
abbrev iff_not_self_and := @eq_not_self_and
|
||||
|
||||
@[deprecated eq_and_not_self (since := "2025-04-04")]
|
||||
abbrev iff_and_not_self := @eq_and_not_self
|
||||
|
||||
/-! ### or -/
|
||||
|
||||
@[simp] theorem or_self_left : ∀ (a b : Bool), (a || (a || b)) = (a || b) := by decide
|
||||
@@ -169,35 +145,11 @@ Needed for confluence of term `(a || b) ↔ a` which reduces to `(a || b) = a` v
|
||||
@[simp] theorem eq_self_or : ∀ {a b : Bool}, (a = (a || b)) ↔ (b → a) := by decide
|
||||
@[simp] theorem eq_or_self : ∀ {a b : Bool}, (b = (a || b)) ↔ (a → b) := by decide
|
||||
|
||||
@[deprecated or_eq_left_iff_imp (since := "2025-04-04")]
|
||||
abbrev or_iff_left_iff_imp := @or_eq_left_iff_imp
|
||||
|
||||
@[deprecated or_eq_right_iff_imp (since := "2025-04-04")]
|
||||
abbrev or_iff_right_iff_imp := @or_eq_right_iff_imp
|
||||
|
||||
@[deprecated eq_self_or (since := "2025-04-04")]
|
||||
abbrev iff_self_or := @eq_self_or
|
||||
|
||||
@[deprecated eq_or_self (since := "2025-04-04")]
|
||||
abbrev iff_or_self := @eq_or_self
|
||||
|
||||
@[simp] theorem not_or_eq_left_iff_and : ∀ {a b : Bool}, ((!a || b) = a) ↔ a ∧ b := by decide
|
||||
@[simp] theorem or_not_eq_right_iff_and : ∀ {a b : Bool}, ((a || !b) = b) ↔ a ∧ b := by decide
|
||||
@[simp] theorem eq_not_self_or : ∀ {a b : Bool}, (a = (!a || b)) ↔ a ∧ b := by decide
|
||||
@[simp] theorem eq_or_not_self : ∀ {a b : Bool}, (b = (a || !b)) ↔ a ∧ b := by decide
|
||||
|
||||
@[deprecated not_or_eq_left_iff_and (since := "2025-04-04")]
|
||||
abbrev not_or_iff_left_iff_imp := @not_or_eq_left_iff_and
|
||||
|
||||
@[deprecated or_not_eq_right_iff_and (since := "2025-04-04")]
|
||||
abbrev or_not_iff_right_iff_imp := @or_not_eq_right_iff_and
|
||||
|
||||
@[deprecated eq_not_self_or (since := "2025-04-04")]
|
||||
abbrev iff_not_self_or := @eq_not_self_or
|
||||
|
||||
@[deprecated eq_or_not_self (since := "2025-04-04")]
|
||||
abbrev iff_or_not_self := @eq_or_not_self
|
||||
|
||||
theorem or_comm : ∀ (x y : Bool), (x || y) = (y || x) := by decide
|
||||
instance : Std.Commutative (· || ·) := ⟨or_comm⟩
|
||||
|
||||
@@ -621,11 +573,6 @@ protected theorem cond_false {α : Sort u} {a b : α} : cond false a b = b := co
|
||||
@[simp] theorem cond_then_self : ∀ (c b : Bool), cond c c b = (c || b) := by decide
|
||||
@[simp] theorem cond_else_self : ∀ (c b : Bool), cond c b c = (c && b) := by decide
|
||||
|
||||
@[deprecated cond_then_not_self (since := "2025-04-04")] abbrev cond_true_not_same := @cond_then_not_self
|
||||
@[deprecated cond_else_not_self (since := "2025-04-04")] abbrev cond_false_not_same := @cond_else_not_self
|
||||
@[deprecated cond_then_self (since := "2025-04-04")] abbrev cond_true_same := @cond_then_self
|
||||
@[deprecated cond_else_self (since := "2025-04-04")] abbrev cond_false_same := @cond_else_self
|
||||
|
||||
theorem cond_pos {b : Bool} {a a' : α} (h : b = true) : (bif b then a else a') = a := by
|
||||
rw [h, cond_true]
|
||||
|
||||
|
||||
@@ -24,9 +24,6 @@ attribute [ext] ByteArray
|
||||
instance : DecidableEq ByteArray :=
|
||||
fun _ _ => decidable_of_decidable_of_iff ByteArray.ext_iff.symm
|
||||
|
||||
@[deprecated emptyWithCapacity (since := "2025-03-12")]
|
||||
abbrev mkEmpty := emptyWithCapacity
|
||||
|
||||
instance : Inhabited ByteArray where
|
||||
default := empty
|
||||
|
||||
|
||||
@@ -10,6 +10,8 @@ public import Init.Data.ByteArray.Basic
|
||||
|
||||
public section
|
||||
|
||||
namespace ByteArray
|
||||
|
||||
-- At present the preferred normal form for empty byte arrays is `ByteArray.empty`
|
||||
@[simp]
|
||||
theorem emptyc_eq_empty : (∅ : ByteArray) = ByteArray.empty := rfl
|
||||
@@ -18,10 +20,10 @@ theorem emptyc_eq_empty : (∅ : ByteArray) = ByteArray.empty := rfl
|
||||
theorem emptyWithCapacity_eq_empty : ByteArray.emptyWithCapacity 0 = ByteArray.empty := rfl
|
||||
|
||||
@[simp]
|
||||
theorem ByteArray.data_empty : ByteArray.empty.data = #[] := rfl
|
||||
theorem data_empty : ByteArray.empty.data = #[] := rfl
|
||||
|
||||
@[simp]
|
||||
theorem ByteArray.data_extract {a : ByteArray} {b e : Nat} :
|
||||
theorem data_extract {a : ByteArray} {b e : Nat} :
|
||||
(a.extract b e).data = a.data.extract b e := by
|
||||
simp [extract, copySlice]
|
||||
by_cases b ≤ e
|
||||
@@ -29,39 +31,39 @@ theorem ByteArray.data_extract {a : ByteArray} {b e : Nat} :
|
||||
· rw [Array.extract_eq_empty_of_le (by omega), Array.extract_eq_empty_of_le (by omega)]
|
||||
|
||||
@[simp]
|
||||
theorem ByteArray.extract_zero_size {b : ByteArray} : b.extract 0 b.size = b := by
|
||||
theorem extract_zero_size {b : ByteArray} : b.extract 0 b.size = b := by
|
||||
ext1
|
||||
simp
|
||||
|
||||
@[simp]
|
||||
theorem ByteArray.extract_same {b : ByteArray} {i : Nat} : b.extract i i = ByteArray.empty := by
|
||||
theorem extract_same {b : ByteArray} {i : Nat} : b.extract i i = ByteArray.empty := by
|
||||
ext1
|
||||
simp [Nat.min_le_left]
|
||||
|
||||
theorem ByteArray.fastAppend_eq_copySlice {a b : ByteArray} :
|
||||
theorem fastAppend_eq_copySlice {a b : ByteArray} :
|
||||
a.fastAppend b = b.copySlice 0 a a.size b.size false := rfl
|
||||
|
||||
@[simp]
|
||||
theorem List.toByteArray_append {l l' : List UInt8} :
|
||||
theorem _root_.List.toByteArray_append {l l' : List UInt8} :
|
||||
(l ++ l').toByteArray = l.toByteArray ++ l'.toByteArray := by
|
||||
simp [List.toByteArray_append']
|
||||
|
||||
@[simp]
|
||||
theorem ByteArray.toList_data_append {l l' : ByteArray} :
|
||||
theorem toList_data_append {l l' : ByteArray} :
|
||||
(l ++ l').data.toList = l.data.toList ++ l'.data.toList := by
|
||||
simp [← append_eq]
|
||||
|
||||
@[simp]
|
||||
theorem ByteArray.data_append {l l' : ByteArray} :
|
||||
theorem data_append {l l' : ByteArray} :
|
||||
(l ++ l').data = l.data ++ l'.data := by
|
||||
simp [← Array.toList_inj]
|
||||
|
||||
@[simp]
|
||||
theorem ByteArray.size_empty : ByteArray.empty.size = 0 := by
|
||||
theorem size_empty : ByteArray.empty.size = 0 := by
|
||||
simp [← ByteArray.size_data]
|
||||
|
||||
@[simp]
|
||||
theorem List.data_toByteArray {l : List UInt8} :
|
||||
theorem _root_.List.data_toByteArray {l : List UInt8} :
|
||||
l.toByteArray.data = l.toArray := by
|
||||
rw [List.toByteArray]
|
||||
suffices ∀ a b, (List.toByteArray.loop a b).data = b.data ++ a.toArray by
|
||||
@@ -70,153 +72,159 @@ theorem List.data_toByteArray {l : List UInt8} :
|
||||
fun_induction List.toByteArray.loop a b with simp_all
|
||||
|
||||
@[simp]
|
||||
theorem List.size_toByteArray {l : List UInt8} :
|
||||
theorem _root_.List.size_toByteArray {l : List UInt8} :
|
||||
l.toByteArray.size = l.length := by
|
||||
simp [← ByteArray.size_data]
|
||||
|
||||
@[simp]
|
||||
theorem List.toByteArray_nil : List.toByteArray [] = ByteArray.empty := rfl
|
||||
theorem _root_.List.toByteArray_nil : List.toByteArray [] = ByteArray.empty := rfl
|
||||
|
||||
@[simp]
|
||||
theorem ByteArray.empty_append {b : ByteArray} : ByteArray.empty ++ b = b := by
|
||||
theorem empty_append {b : ByteArray} : ByteArray.empty ++ b = b := by
|
||||
ext1
|
||||
simp
|
||||
|
||||
@[simp]
|
||||
theorem ByteArray.append_empty {b : ByteArray} : b ++ ByteArray.empty = b := by
|
||||
theorem append_empty {b : ByteArray} : b ++ ByteArray.empty = b := by
|
||||
ext1
|
||||
simp
|
||||
|
||||
@[simp, grind =]
|
||||
theorem ByteArray.size_append {a b : ByteArray} : (a ++ b).size = a.size + b.size := by
|
||||
theorem size_append {a b : ByteArray} : (a ++ b).size = a.size + b.size := by
|
||||
simp [← size_data]
|
||||
|
||||
@[simp]
|
||||
theorem ByteArray.size_eq_zero_iff {a : ByteArray} : a.size = 0 ↔ a = ByteArray.empty := by
|
||||
theorem size_eq_zero_iff {a : ByteArray} : a.size = 0 ↔ a = ByteArray.empty := by
|
||||
refine ⟨fun h => ?_, fun h => h ▸ ByteArray.size_empty⟩
|
||||
ext1
|
||||
simp [← Array.size_eq_zero_iff, h]
|
||||
|
||||
theorem ByteArray.getElem_eq_getElem_data {a : ByteArray} {i : Nat} {h : i < a.size} :
|
||||
theorem getElem_eq_getElem_data {a : ByteArray} {i : Nat} {h : i < a.size} :
|
||||
a[i] = a.data[i]'(by simpa [← size_data]) := rfl
|
||||
|
||||
@[simp]
|
||||
theorem ByteArray.getElem_append_left {i : Nat} {a b : ByteArray} {h : i < (a ++ b).size}
|
||||
theorem getElem_append_left {i : Nat} {a b : ByteArray} {h : i < (a ++ b).size}
|
||||
(hlt : i < a.size) : (a ++ b)[i] = a[i] := by
|
||||
simp only [getElem_eq_getElem_data, data_append]
|
||||
rw [Array.getElem_append_left (by simpa)]
|
||||
|
||||
theorem ByteArray.getElem_append_right {i : Nat} {a b : ByteArray} {h : i < (a ++ b).size}
|
||||
theorem getElem_append_right {i : Nat} {a b : ByteArray} {h : i < (a ++ b).size}
|
||||
(hle : a.size ≤ i) : (a ++ b)[i] = b[i - a.size]'(by simp_all; omega) := by
|
||||
simp only [getElem_eq_getElem_data, data_append]
|
||||
rw [Array.getElem_append_right (by simpa)]
|
||||
simp
|
||||
|
||||
@[simp]
|
||||
theorem List.getElem_toByteArray {l : List UInt8} {i : Nat} {h : i < l.toByteArray.size} :
|
||||
theorem _root_.List.getElem_toByteArray {l : List UInt8} {i : Nat} {h : i < l.toByteArray.size} :
|
||||
l.toByteArray[i]'h = l[i]'(by simp_all) := by
|
||||
simp [ByteArray.getElem_eq_getElem_data]
|
||||
|
||||
theorem List.getElem_eq_getElem_toByteArray {l : List UInt8} {i : Nat} {h : i < l.length} :
|
||||
theorem _root_.List.getElem_eq_getElem_toByteArray {l : List UInt8} {i : Nat} {h : i < l.length} :
|
||||
l[i]'h = l.toByteArray[i]'(by simp_all) := by
|
||||
simp
|
||||
|
||||
@[simp]
|
||||
theorem ByteArray.size_extract {a : ByteArray} {b e : Nat} :
|
||||
theorem size_extract {a : ByteArray} {b e : Nat} :
|
||||
(a.extract b e).size = min e a.size - b := by
|
||||
simp [← size_data]
|
||||
|
||||
@[simp]
|
||||
theorem ByteArray.extract_eq_empty_iff {b : ByteArray} {i j : Nat} : b.extract i j = ByteArray.empty ↔ min j b.size ≤ i := by
|
||||
theorem extract_eq_empty_iff {b : ByteArray} {i j : Nat} : b.extract i j = ByteArray.empty ↔ min j b.size ≤ i := by
|
||||
rw [← size_eq_zero_iff, size_extract]
|
||||
omega
|
||||
|
||||
@[simp]
|
||||
theorem ByteArray.extract_add_left {b : ByteArray} {i j : Nat} : b.extract (i + j) i = ByteArray.empty := by
|
||||
theorem extract_add_left {b : ByteArray} {i j : Nat} : b.extract (i + j) i = ByteArray.empty := by
|
||||
simp only [extract_eq_empty_iff]
|
||||
exact Nat.le_trans (Nat.min_le_left _ _) (by simp)
|
||||
|
||||
@[simp]
|
||||
theorem ByteArray.append_eq_empty_iff {a b : ByteArray} :
|
||||
theorem append_eq_empty_iff {a b : ByteArray} :
|
||||
a ++ b = ByteArray.empty ↔ a = ByteArray.empty ∧ b = ByteArray.empty := by
|
||||
simp [← size_eq_zero_iff, size_append]
|
||||
|
||||
@[simp]
|
||||
theorem List.toByteArray_eq_empty {l : List UInt8} :
|
||||
theorem toByteArray_eq_empty {l : List UInt8} :
|
||||
l.toByteArray = ByteArray.empty ↔ l = [] := by
|
||||
simp [← ByteArray.size_eq_zero_iff]
|
||||
|
||||
theorem ByteArray.append_right_inj {ys₁ ys₂ : ByteArray} (xs : ByteArray) :
|
||||
@[simp]
|
||||
theorem append_right_inj {ys₁ ys₂ : ByteArray} (xs : ByteArray) :
|
||||
xs ++ ys₁ = xs ++ ys₂ ↔ ys₁ = ys₂ := by
|
||||
simp [ByteArray.ext_iff, Array.append_right_inj]
|
||||
|
||||
@[simp]
|
||||
theorem ByteArray.extract_append_extract {a : ByteArray} {i j k : Nat} :
|
||||
theorem append_left_inj {xs₁ xs₂ : ByteArray} (ys : ByteArray) :
|
||||
xs₁ ++ ys = xs₂ ++ ys ↔ xs₁ = xs₂ := by
|
||||
simp [ByteArray.ext_iff, Array.append_left_inj]
|
||||
|
||||
@[simp]
|
||||
theorem extract_append_extract {a : ByteArray} {i j k : Nat} :
|
||||
a.extract i j ++ a.extract j k = a.extract (min i j) (max j k) := by
|
||||
ext1
|
||||
simp
|
||||
|
||||
theorem ByteArray.extract_eq_extract_append_extract {a : ByteArray} {i k : Nat} (j : Nat)
|
||||
theorem extract_eq_extract_append_extract {a : ByteArray} {i k : Nat} (j : Nat)
|
||||
(hi : i ≤ j) (hk : j ≤ k) :
|
||||
a.extract i k = a.extract i j ++ a.extract j k := by
|
||||
simp
|
||||
rw [Nat.min_eq_left hi, Nat.max_eq_right hk]
|
||||
|
||||
theorem ByteArray.append_inj_left {xs₁ xs₂ ys₁ ys₂ : ByteArray} (h : xs₁ ++ ys₁ = xs₂ ++ ys₂) (hl : xs₁.size = xs₂.size) : xs₁ = xs₂ := by
|
||||
theorem append_inj_left {xs₁ xs₂ ys₁ ys₂ : ByteArray} (h : xs₁ ++ ys₁ = xs₂ ++ ys₂) (hl : xs₁.size = xs₂.size) : xs₁ = xs₂ := by
|
||||
simp only [ByteArray.ext_iff, ← ByteArray.size_data, ByteArray.data_append] at *
|
||||
exact Array.append_inj_left h hl
|
||||
|
||||
theorem ByteArray.extract_append_eq_right {a b : ByteArray} {i j : Nat} (hi : i = a.size) (hj : j = a.size + b.size) :
|
||||
theorem extract_append_eq_right {a b : ByteArray} {i j : Nat} (hi : i = a.size) (hj : j = a.size + b.size) :
|
||||
(a ++ b).extract i j = b := by
|
||||
subst hi hj
|
||||
ext1
|
||||
simp [← size_data]
|
||||
|
||||
theorem ByteArray.extract_append_eq_left {a b : ByteArray} {i : Nat} (hi : i = a.size) :
|
||||
theorem extract_append_eq_left {a b : ByteArray} {i : Nat} (hi : i = a.size) :
|
||||
(a ++ b).extract 0 i = a := by
|
||||
subst hi
|
||||
ext1
|
||||
simp
|
||||
|
||||
theorem ByteArray.extract_append_size_left {a b : ByteArray} {i : Nat} :
|
||||
theorem extract_append_size_left {a b : ByteArray} {i : Nat} :
|
||||
(a ++ b).extract i a.size = a.extract i a.size := by
|
||||
ext1
|
||||
simp
|
||||
|
||||
theorem ByteArray.extract_append_size_add {a b : ByteArray} {i j : Nat} :
|
||||
theorem extract_append_size_add {a b : ByteArray} {i j : Nat} :
|
||||
(a ++ b).extract (a.size + i) (a.size + j) = b.extract i j := by
|
||||
ext1
|
||||
simp
|
||||
|
||||
theorem ByteArray.extract_append {as bs : ByteArray} {i j : Nat} :
|
||||
theorem extract_append {as bs : ByteArray} {i j : Nat} :
|
||||
(as ++ bs).extract i j = as.extract i j ++ bs.extract (i - as.size) (j - as.size) := by
|
||||
ext1
|
||||
simp
|
||||
|
||||
theorem ByteArray.extract_append_size_add' {a b : ByteArray} {i j k : Nat} (h : k = a.size) :
|
||||
theorem extract_append_size_add' {a b : ByteArray} {i j k : Nat} (h : k = a.size) :
|
||||
(a ++ b).extract (k + i) (k + j) = b.extract i j := by
|
||||
cases h
|
||||
rw [extract_append_size_add]
|
||||
|
||||
theorem ByteArray.extract_extract {a : ByteArray} {i j k l : Nat} :
|
||||
theorem extract_extract {a : ByteArray} {i j k l : Nat} :
|
||||
(a.extract i j).extract k l = a.extract (i + k) (min (i + l) j) := by
|
||||
ext1
|
||||
simp
|
||||
|
||||
theorem ByteArray.getElem_extract_aux {xs : ByteArray} {start stop : Nat} (h : i < (xs.extract start stop).size) :
|
||||
theorem getElem_extract_aux {xs : ByteArray} {start stop : Nat} (h : i < (xs.extract start stop).size) :
|
||||
start + i < xs.size := by
|
||||
rw [size_extract] at h; apply Nat.add_lt_of_lt_sub'; apply Nat.lt_of_lt_of_le h
|
||||
apply Nat.sub_le_sub_right; apply Nat.min_le_right
|
||||
|
||||
theorem ByteArray.getElem_extract {i : Nat} {b : ByteArray} {start stop : Nat}
|
||||
theorem getElem_extract {i : Nat} {b : ByteArray} {start stop : Nat}
|
||||
(h) : (b.extract start stop)[i]'h = b[start + i]'(getElem_extract_aux h) := by
|
||||
simp [getElem_eq_getElem_data]
|
||||
|
||||
theorem ByteArray.extract_eq_extract_left {a : ByteArray} {i i' j : Nat} :
|
||||
theorem extract_eq_extract_left {a : ByteArray} {i i' j : Nat} :
|
||||
a.extract i j = a.extract i' j ↔ min j a.size - i = min j a.size - i' := by
|
||||
simp [ByteArray.ext_iff, Array.extract_eq_extract_left]
|
||||
|
||||
theorem ByteArray.extract_add_one {a : ByteArray} {i : Nat} (ha : i + 1 ≤ a.size) :
|
||||
theorem extract_add_one {a : ByteArray} {i : Nat} (ha : i + 1 ≤ a.size) :
|
||||
a.extract i (i + 1) = [a[i]].toByteArray := by
|
||||
ext
|
||||
· simp
|
||||
@@ -225,50 +233,57 @@ theorem ByteArray.extract_add_one {a : ByteArray} {i : Nat} (ha : i + 1 ≤ a.si
|
||||
obtain rfl : j = 0 := by simpa using hj'
|
||||
simp [ByteArray.getElem_eq_getElem_data]
|
||||
|
||||
theorem ByteArray.extract_add_two {a : ByteArray} {i : Nat} (ha : i + 2 ≤ a.size) :
|
||||
theorem extract_add_two {a : ByteArray} {i : Nat} (ha : i + 2 ≤ a.size) :
|
||||
a.extract i (i + 2) = [a[i], a[i + 1]].toByteArray := by
|
||||
rw [extract_eq_extract_append_extract (i + 1) (by simp) (by omega),
|
||||
extract_add_one (by omega), extract_add_one (by omega)]
|
||||
simp [← List.toByteArray_append]
|
||||
|
||||
theorem ByteArray.extract_add_three {a : ByteArray} {i : Nat} (ha : i + 3 ≤ a.size) :
|
||||
theorem extract_add_three {a : ByteArray} {i : Nat} (ha : i + 3 ≤ a.size) :
|
||||
a.extract i (i + 3) = [a[i], a[i + 1], a[i + 2]].toByteArray := by
|
||||
rw [extract_eq_extract_append_extract (i + 1) (by simp) (by omega),
|
||||
extract_add_one (by omega), extract_add_two (by omega)]
|
||||
simp [← List.toByteArray_append]
|
||||
|
||||
theorem ByteArray.extract_add_four {a : ByteArray} {i : Nat} (ha : i + 4 ≤ a.size) :
|
||||
theorem extract_add_four {a : ByteArray} {i : Nat} (ha : i + 4 ≤ a.size) :
|
||||
a.extract i (i + 4) = [a[i], a[i + 1], a[i + 2], a[i + 3]].toByteArray := by
|
||||
rw [extract_eq_extract_append_extract (i + 1) (by simp) (by omega),
|
||||
extract_add_one (by omega), extract_add_three (by omega)]
|
||||
simp [← List.toByteArray_append]
|
||||
|
||||
theorem ByteArray.append_assoc {a b c : ByteArray} : a ++ b ++ c = a ++ (b ++ c) := by
|
||||
theorem append_assoc {a b c : ByteArray} : a ++ b ++ c = a ++ (b ++ c) := by
|
||||
ext1
|
||||
simp
|
||||
|
||||
@[simp]
|
||||
theorem ByteArray.toList_empty : ByteArray.empty.toList = [] := by
|
||||
theorem toList_empty : ByteArray.empty.toList = [] := by
|
||||
simp [ByteArray.toList, ByteArray.toList.loop]
|
||||
|
||||
theorem ByteArray.copySlice_eq_append {src : ByteArray} {srcOff : Nat} {dest : ByteArray} {destOff len : Nat} {exact : Bool} :
|
||||
theorem copySlice_eq_append {src : ByteArray} {srcOff : Nat} {dest : ByteArray} {destOff len : Nat} {exact : Bool} :
|
||||
ByteArray.copySlice src srcOff dest destOff len exact =
|
||||
dest.extract 0 destOff ++ src.extract srcOff (srcOff +len) ++ dest.extract (destOff + min len (src.data.size - srcOff)) dest.data.size := by
|
||||
ext1
|
||||
simp [copySlice]
|
||||
|
||||
@[simp]
|
||||
theorem ByteArray.data_set {as : ByteArray} {i : Nat} {h : i < as.size} {a : UInt8} :
|
||||
theorem data_set {as : ByteArray} {i : Nat} {h : i < as.size} {a : UInt8} :
|
||||
(as.set i a h).data = as.data.set i a (by simpa) := by
|
||||
simp [set]
|
||||
|
||||
theorem ByteArray.set_eq_push_extract_append_extract {as : ByteArray} {i : Nat} (h : i < as.size) {a : UInt8} :
|
||||
theorem set_eq_push_extract_append_extract {as : ByteArray} {i : Nat} (h : i < as.size) {a : UInt8} :
|
||||
as.set i a h = (as.extract 0 i).push a ++ as.extract (i + 1) as.size := by
|
||||
ext1
|
||||
simpa using Array.set_eq_push_extract_append_extract _
|
||||
|
||||
@[simp]
|
||||
theorem ByteArray.append_toByteArray_singleton {as : ByteArray} {a : UInt8} :
|
||||
theorem append_toByteArray_singleton {as : ByteArray} {a : UInt8} :
|
||||
as ++ [a].toByteArray = as.push a := by
|
||||
ext1
|
||||
simp
|
||||
|
||||
@[simp]
|
||||
theorem extract_zero_max_size {a : ByteArray} {i : Nat} : a.extract 0 (max i a.size) = a := by
|
||||
ext1
|
||||
simp [Nat.le_max_right]
|
||||
|
||||
end ByteArray
|
||||
|
||||
@@ -69,4 +69,9 @@ def notLTTotal : Std.Total (¬ · < · : Char → Char → Prop) where
|
||||
rw [Char.ofNat, dif_pos]
|
||||
rfl
|
||||
|
||||
@[simp]
|
||||
theorem toUInt8_val {c : Char} : c.val.toUInt8 = c.toUInt8 := rfl
|
||||
|
||||
theorem toString_eq_singleton {c : Char} : c.toString = String.singleton c := rfl
|
||||
|
||||
end Char
|
||||
|
||||
@@ -29,9 +29,6 @@ attribute [ext] FloatArray
|
||||
def emptyWithCapacity (c : @& Nat) : FloatArray :=
|
||||
{ data := #[] }
|
||||
|
||||
@[deprecated emptyWithCapacity (since := "2025-03-12")]
|
||||
abbrev mkEmpty := emptyWithCapacity
|
||||
|
||||
def empty : FloatArray :=
|
||||
emptyWithCapacity 0
|
||||
|
||||
|
||||
@@ -369,9 +369,6 @@ def toNat? : Int → Option Nat
|
||||
| (n : Nat) => some n
|
||||
| -[_+1] => none
|
||||
|
||||
@[deprecated toNat? (since := "2025-03-11"), inherit_doc toNat?]
|
||||
abbrev toNat' := toNat?
|
||||
|
||||
/-! ## divisibility -/
|
||||
|
||||
/--
|
||||
|
||||
@@ -118,9 +118,6 @@ instance : Mod Int where
|
||||
|
||||
@[simp, norm_cast] theorem natCast_ediv (m n : Nat) : (↑(m / n) : Int) = ↑m / ↑n := rfl
|
||||
|
||||
@[deprecated natCast_ediv (since := "2025-04-17")]
|
||||
theorem ofNat_ediv (m n : Nat) : (↑(m / n) : Int) = ↑m / ↑n := natCast_ediv m n
|
||||
|
||||
theorem ofNat_ediv_ofNat {a b : Nat} : (↑a / ↑b : Int) = (a / b : Nat) := rfl
|
||||
@[norm_cast]
|
||||
theorem negSucc_ediv_ofNat_succ {a b : Nat} : ((-[a+1]) / ↑(b+1) : Int) = -[a / succ b +1] := rfl
|
||||
|
||||
@@ -92,9 +92,6 @@ theorem ofNat_dvd_left {n : Nat} {z : Int} : (↑n : Int) ∣ z ↔ n ∣ z.natA
|
||||
|
||||
@[simp, norm_cast] theorem natCast_emod (m n : Nat) : (↑(m % n) : Int) = m % n := rfl
|
||||
|
||||
@[deprecated natCast_emod (since := "2025-04-17")]
|
||||
theorem ofNat_emod (m n : Nat) : (↑(m % n) : Int) = m % n := natCast_emod m n
|
||||
|
||||
/-! ### mod definitions -/
|
||||
|
||||
theorem emod_add_mul_ediv : ∀ a b : Int, a % b + b * (a / b) = a
|
||||
@@ -233,10 +230,6 @@ theorem emod_lt_of_pos (a : Int) {b : Int} (H : 0 < b) : a % b < b :=
|
||||
@[simp] theorem mul_add_emod_self_left (a b c : Int) : (a * b + c) % a = c % a := by
|
||||
rw [Int.add_comm, add_mul_emod_self_left]
|
||||
|
||||
@[deprecated add_mul_emod_self_right (since := "2025-04-11")]
|
||||
theorem add_mul_emod_self {a b c : Int} : (a + b * c) % c = a % c :=
|
||||
add_mul_emod_self_right ..
|
||||
|
||||
@[simp] theorem emod_add_emod (m n k : Int) : (m % n + k) % n = (m + k) % n := by
|
||||
have := (add_mul_emod_self_left (m % n + k) n (m / n)).symm
|
||||
rwa [Int.add_right_comm, emod_add_mul_ediv] at this
|
||||
|
||||
@@ -510,9 +510,6 @@ theorem ediv_neg_of_neg_of_pos {a b : Int} (Ha : a < 0) (Hb : 0 < b) : a / b < 0
|
||||
match a, b, eq_negSucc_of_lt_zero Ha, eq_succ_of_zero_lt Hb with
|
||||
| _, _, ⟨_, rfl⟩, ⟨_, rfl⟩ => negSucc_lt_zero _
|
||||
|
||||
@[deprecated ediv_neg_of_neg_of_pos (since := "2025-03-04")]
|
||||
abbrev ediv_neg' := @ediv_neg_of_neg_of_pos
|
||||
|
||||
theorem negSucc_ediv (m : Nat) {b : Int} (H : 0 < b) : -[m+1] / b = -(ediv m b + 1) :=
|
||||
match b, eq_succ_of_zero_lt H with
|
||||
| _, ⟨_, rfl⟩ => rfl
|
||||
@@ -545,9 +542,6 @@ theorem ediv_pos_of_neg_of_neg {a b : Int} (ha : a < 0) (hb : b < 0) : 0 < a / b
|
||||
theorem ediv_nonpos_of_nonneg_of_nonpos {a b : Int} (Ha : 0 ≤ a) (Hb : b ≤ 0) : a / b ≤ 0 :=
|
||||
Int.nonpos_of_neg_nonneg <| Int.ediv_neg .. ▸ Int.ediv_nonneg Ha (Int.neg_nonneg_of_nonpos Hb)
|
||||
|
||||
@[deprecated ediv_nonpos_of_nonneg_of_nonpos (since := "2025-03-04")]
|
||||
abbrev ediv_nonpos := @ediv_nonpos_of_nonneg_of_nonpos
|
||||
|
||||
theorem ediv_eq_zero_of_lt {a b : Int} (H1 : 0 ≤ a) (H2 : a < b) : a / b = 0 :=
|
||||
match a, b, eq_ofNat_of_zero_le H1, eq_succ_of_zero_lt (Int.lt_of_le_of_lt H1 H2) with
|
||||
| _, _, ⟨_, rfl⟩, ⟨_, rfl⟩ => congrArg Nat.cast <| Nat.div_eq_of_lt <| ofNat_lt.1 H2
|
||||
@@ -678,25 +672,15 @@ theorem ofNat_mod_ofNat (m n : Nat) : (m % n : Int) = ↑(m % n) := rfl
|
||||
@[simp] theorem add_neg_mul_emod_self_right (a b c : Int) : (a + -(b * c)) % c = a % c := by
|
||||
rw [Int.neg_mul_eq_neg_mul, add_mul_emod_self_right]
|
||||
|
||||
@[deprecated add_neg_mul_emod_self_right (since := "2025-04-11")]
|
||||
theorem add_neg_mul_emod_self {a b c : Int} : (a + -(b * c)) % c = a % c :=
|
||||
add_neg_mul_emod_self_right ..
|
||||
|
||||
@[simp] theorem add_neg_mul_emod_self_left (a b c : Int) : (a + -(b * c)) % b = a % b := by
|
||||
rw [Int.neg_mul_eq_mul_neg, add_mul_emod_self_left]
|
||||
|
||||
@[simp] theorem add_emod_right (a b : Int) : (a + b) % b = a % b := by
|
||||
have := add_mul_emod_self_left a b 1; rwa [Int.mul_one] at this
|
||||
|
||||
@[deprecated add_emod_right (since := "2025-04-11")]
|
||||
theorem add_emod_self {a b : Int} : (a + b) % b = a % b := add_emod_right ..
|
||||
|
||||
@[simp] theorem add_emod_left (a b : Int) : (a + b) % a = b % a := by
|
||||
rw [Int.add_comm, add_emod_right]
|
||||
|
||||
@[deprecated add_emod_left (since := "2025-04-11")]
|
||||
theorem add_emod_self_left {a b : Int} : (a + b) % a = b % a := add_emod_left ..
|
||||
|
||||
@[simp] theorem sub_mul_emod_self_right (a b c : Int) : (a - b * c) % c = a % c := by
|
||||
simp [Int.sub_eq_add_neg]
|
||||
|
||||
@@ -937,9 +921,6 @@ where
|
||||
| -[_+1], 0 => Nat.zero_le _
|
||||
| -[_+1], succ _ => Nat.succ_le_succ (Nat.div_le_self _ _)
|
||||
|
||||
@[deprecated natAbs_ediv_le_natAbs (since := "2025-03-05")]
|
||||
abbrev natAbs_div_le_natAbs := natAbs_ediv_le_natAbs
|
||||
|
||||
theorem ediv_le_self {a : Int} (b : Int) (Ha : 0 ≤ a) : a / b ≤ a := by
|
||||
have := Int.le_trans le_natAbs (ofNat_le.2 <| natAbs_ediv_le_natAbs a b)
|
||||
rwa [natAbs_of_nonneg Ha] at this
|
||||
@@ -972,14 +953,6 @@ theorem emod_eq_iff {a b c : Int} (hb : b ≠ 0) : a % b = c ↔ 0 ≤ c ∧ c <
|
||||
rw [← dvd_iff_emod_eq_zero, Int.dvd_neg]
|
||||
exact Int.dvd_mul_right a b
|
||||
|
||||
@[deprecated mul_ediv_cancel (since := "2025-03-05")]
|
||||
theorem neg_mul_ediv_cancel (a b : Int) (h : b ≠ 0) : -(a * b) / b = -a := by
|
||||
rw [neg_ediv_of_dvd (Int.dvd_mul_left a b), mul_ediv_cancel _ h]
|
||||
|
||||
@[deprecated mul_ediv_cancel (since := "2025-03-05")]
|
||||
theorem neg_mul_ediv_cancel_left (a b : Int) (h : a ≠ 0) : -(a * b) / a = -b := by
|
||||
rw [neg_ediv_of_dvd (Int.dvd_mul_right a b), mul_ediv_cancel_left _ h]
|
||||
|
||||
@[simp] theorem ediv_one : ∀ a : Int, a / 1 = a
|
||||
| (_:Nat) => congrArg Nat.cast (Nat.div_one _)
|
||||
| -[_+1] => congrArg negSucc (Nat.div_one _)
|
||||
@@ -993,10 +966,6 @@ theorem ediv_minus_one (a : Int) : a / (-1) = -a := by
|
||||
theorem emod_minus_one (a : Int) : a % (-1) = 0 := by
|
||||
simp
|
||||
|
||||
@[deprecated sub_emod_right (since := "2025-04-11")]
|
||||
theorem emod_sub_cancel (x y : Int) : (x - y) % y = x % y :=
|
||||
sub_emod_right ..
|
||||
|
||||
@[simp] theorem add_neg_emod_self (a b : Int) : (a + -b) % b = a % b := by
|
||||
rw [Int.add_neg_eq_sub, sub_emod_right]
|
||||
|
||||
@@ -1007,10 +976,6 @@ theorem emod_sub_cancel (x y : Int) : (x - y) % y = x % y :=
|
||||
theorem dvd_self_sub_of_emod_eq {a b : Int} : {c : Int} → a % b = c → b ∣ a - c
|
||||
| _, rfl => dvd_self_sub_emod
|
||||
|
||||
@[deprecated dvd_self_sub_of_emod_eq (since := "2025-04-12")]
|
||||
theorem dvd_sub_of_emod_eq {a b : Int} : {c : Int} → a % b = c → b ∣ a - c :=
|
||||
dvd_self_sub_of_emod_eq
|
||||
|
||||
theorem dvd_sub_self_of_emod_eq {a b : Int} : {c : Int} → a % b = c → b ∣ c - a
|
||||
| _, rfl => dvd_emod_sub_self
|
||||
|
||||
@@ -1329,9 +1294,6 @@ theorem tdiv_nonneg_of_nonpos_of_nonpos {a b : Int} (Ha : a ≤ 0) (Hb : b ≤ 0
|
||||
protected theorem tdiv_nonpos_of_nonneg_of_nonpos {a b : Int} (Ha : 0 ≤ a) (Hb : b ≤ 0) : a.tdiv b ≤ 0 :=
|
||||
Int.nonpos_of_neg_nonneg <| Int.tdiv_neg .. ▸ Int.tdiv_nonneg Ha (Int.neg_nonneg_of_nonpos Hb)
|
||||
|
||||
@[deprecated Int.tdiv_nonpos_of_nonneg_of_nonpos (since := "2025-03-04")]
|
||||
abbrev tdiv_nonpos := @Int.tdiv_nonpos_of_nonneg_of_nonpos
|
||||
|
||||
theorem tdiv_eq_zero_of_lt {a b : Int} (H1 : 0 ≤ a) (H2 : a < b) : a.tdiv b = 0 :=
|
||||
match a, b, eq_ofNat_of_zero_le H1, eq_succ_of_zero_lt (Int.lt_of_le_of_lt H1 H2) with
|
||||
| _, _, ⟨_, rfl⟩, ⟨_, rfl⟩ => congrArg Nat.cast <| Nat.div_eq_of_lt <| ofNat_lt.1 H2
|
||||
@@ -1890,10 +1852,6 @@ theorem le_emod_self_add_one_iff {a b : Int} (h : 0 < b) : b ≤ a % b + 1 ↔ b
|
||||
sign_eq_one_of_pos (by omega), Int.mul_add]
|
||||
omega
|
||||
|
||||
@[deprecated le_emod_self_add_one_iff (since := "2025-04-12")]
|
||||
theorem le_mod_self_add_one_iff {a b : Int} (h : 0 < b) : b ≤ a % b + 1 ↔ b ∣ a + 1 :=
|
||||
le_emod_self_add_one_iff h
|
||||
|
||||
theorem add_one_tdiv_of_pos {a b : Int} (h : 0 < b) :
|
||||
(a + 1).tdiv b = a.tdiv b + if (0 < a + 1 ∧ b ∣ a + 1) ∨ (a < 0 ∧ b ∣ a) then 1 else 0 := by
|
||||
match b, h with
|
||||
@@ -2029,9 +1987,6 @@ theorem fdiv_nonpos_of_nonneg_of_nonpos : ∀ {a b : Int}, 0 ≤ a → b ≤ 0
|
||||
| 0, 0, _, _ | 0, -[_+1], _, _ | succ _, 0, _, _ | succ _, -[_+1], _, _ => by
|
||||
simp [fdiv, negSucc_le_zero]
|
||||
|
||||
@[deprecated fdiv_nonpos_of_nonneg_of_nonpos (since := "2025-03-04")]
|
||||
abbrev fdiv_nonpos := @fdiv_nonpos_of_nonneg_of_nonpos
|
||||
|
||||
theorem fdiv_neg_of_neg_of_pos : ∀ {a b : Int}, a < 0 → 0 < b → a.fdiv b < 0
|
||||
| -[_+1], succ _, _, _ => negSucc_lt_zero _
|
||||
|
||||
@@ -2150,9 +2105,6 @@ theorem fmod_nonneg {a b : Int} (ha : 0 ≤ a) (hb : 0 ≤ b) : 0 ≤ a.fmod b :
|
||||
theorem fmod_nonneg_of_pos (a : Int) {b : Int} (hb : 0 < b) : 0 ≤ a.fmod b :=
|
||||
fmod_eq_emod_of_nonneg _ (Int.le_of_lt hb) ▸ emod_nonneg _ (Int.ne_of_lt hb).symm
|
||||
|
||||
@[deprecated fmod_nonneg_of_pos (since := "2025-03-04")]
|
||||
abbrev fmod_nonneg' := @fmod_nonneg_of_pos
|
||||
|
||||
theorem fmod_lt_of_pos (a : Int) {b : Int} (H : 0 < b) : a.fmod b < b :=
|
||||
fmod_eq_emod_of_nonneg _ (Int.le_of_lt H) ▸ emod_lt_of_pos a H
|
||||
|
||||
@@ -2162,10 +2114,6 @@ theorem fmod_lt_of_pos (a : Int) {b : Int} (H : 0 < b) : a.fmod b < b :=
|
||||
rw [fmod_eq_emod, add_mul_emod_self_right, fmod_eq_emod]
|
||||
simp
|
||||
|
||||
@[deprecated add_mul_fmod_self_right (since := "2025-04-11")]
|
||||
theorem add_mul_fmod_self {a b c : Int} : (a + b * c).fmod c = a.fmod c :=
|
||||
add_mul_fmod_self_right ..
|
||||
|
||||
@[simp] theorem add_mul_fmod_self_left (a b c : Int) : (a + b * c).fmod b = a.fmod b := by
|
||||
rw [Int.mul_comm, Int.add_mul_fmod_self_right]
|
||||
|
||||
@@ -2464,20 +2412,12 @@ theorem dvd_sub_self_of_fmod_eq {a b c : Int} (h : a.fmod b = c) :
|
||||
@[simp] theorem fmod_one (a : Int) : a.fmod 1 = 0 := by
|
||||
simp [fmod_def, Int.one_mul, Int.sub_self]
|
||||
|
||||
@[deprecated sub_fmod_right (since := "2025-04-12")]
|
||||
theorem fmod_sub_cancel (x y : Int) : (x - y).fmod y = x.fmod y :=
|
||||
sub_fmod_right _ _
|
||||
|
||||
@[simp] theorem add_neg_fmod_self (a b : Int) : (a + -b).fmod b = a.fmod b := by
|
||||
rw [Int.add_neg_eq_sub, sub_fmod_right]
|
||||
|
||||
@[simp] theorem neg_add_fmod_self (a b : Int) : (-a + b).fmod a = b.fmod a := by
|
||||
rw [Int.add_comm, add_neg_fmod_self]
|
||||
|
||||
@[deprecated dvd_self_sub_of_fmod_eq (since := "2025-04-12")]
|
||||
theorem dvd_sub_of_fmod_eq {a b c : Int} (h : a.fmod b = c) : b ∣ a - c :=
|
||||
dvd_self_sub_of_fmod_eq h
|
||||
|
||||
theorem fdiv_sign {a b : Int} : a.fdiv (sign b) = a * sign b := by
|
||||
rw [fdiv_eq_ediv]
|
||||
rcases sign_trichotomy b with h | h | h <;> simp [h]
|
||||
@@ -2511,10 +2451,6 @@ theorem lt_mul_fdiv_self_add {x k : Int} (h : 0 < k) : x < k * (x.fdiv k) + k :=
|
||||
theorem emod_bmod (x : Int) (n : Nat) : Int.bmod (x%n) n = Int.bmod x n := by
|
||||
simp [bmod]
|
||||
|
||||
@[deprecated emod_bmod (since := "2025-04-11")]
|
||||
theorem emod_bmod_congr (x : Int) (n : Nat) : Int.bmod (x%n) n = Int.bmod x n :=
|
||||
emod_bmod ..
|
||||
|
||||
theorem bdiv_add_bmod (x : Int) (m : Nat) : m * bdiv x m + bmod x m = x := by
|
||||
unfold bdiv bmod
|
||||
split
|
||||
@@ -2556,9 +2492,6 @@ theorem bmod_eq_emod (x : Int) (m : Nat) : bmod x m = x % m - if x % m ≥ (m +
|
||||
theorem bmod_one (x : Int) : Int.bmod x 1 = 0 := by
|
||||
simp [Int.bmod]
|
||||
|
||||
@[deprecated bmod_one (since := "2025-04-10")]
|
||||
abbrev bmod_one_is_zero := @bmod_one
|
||||
|
||||
@[simp] theorem add_bmod_right (a : Int) (b : Nat) : (a + b).bmod b = a.bmod b := by
|
||||
simp [bmod_def]
|
||||
|
||||
@@ -2601,76 +2534,36 @@ abbrev bmod_one_is_zero := @bmod_one
|
||||
@[simp] theorem add_neg_mul_bmod_self_left (a : Int) (b : Nat) (c : Int) : (a + -(b * c)).bmod b = a.bmod b := by
|
||||
simp [bmod_def]
|
||||
|
||||
@[deprecated add_bmod_right (since := "2025-04-10")]
|
||||
theorem bmod_add_cancel {x : Int} {n : Nat} : Int.bmod (x + n) n = Int.bmod x n :=
|
||||
add_bmod_right ..
|
||||
|
||||
@[deprecated add_mul_bmod_self_left (since := "2025-04-10")]
|
||||
theorem bmod_add_mul_cancel (x : Int) (n : Nat) (k : Int) : Int.bmod (x + n * k) n = Int.bmod x n :=
|
||||
add_mul_bmod_self_left ..
|
||||
|
||||
@[deprecated sub_bmod_right (since := "2025-04-10")]
|
||||
theorem bmod_sub_cancel (x : Int) (n : Nat) : Int.bmod (x - n) n = Int.bmod x n :=
|
||||
sub_bmod_right ..
|
||||
|
||||
@[deprecated sub_mul_bmod_self_left (since := "2025-04-10")]
|
||||
theorem Int.bmod_sub_mul_cancel (x : Int) (n : Nat) (k : Int) : (x - n * k).bmod n = x.bmod n :=
|
||||
sub_mul_bmod_self_left ..
|
||||
|
||||
@[simp]
|
||||
theorem emod_add_bmod (x : Int) (n : Nat) : Int.bmod (x % n + y) n = Int.bmod (x + y) n := by
|
||||
simp [Int.emod_def, Int.sub_eq_add_neg]
|
||||
rw [←Int.mul_neg, Int.add_right_comm, Int.add_mul_bmod_self_left]
|
||||
|
||||
@[deprecated emod_add_bmod (since := "2025-04-11")]
|
||||
theorem emod_add_bmod_congr (x : Int) (n : Nat) : Int.bmod (x % n + y) n = Int.bmod (x + y) n :=
|
||||
emod_add_bmod ..
|
||||
|
||||
@[simp]
|
||||
theorem emod_sub_bmod (x : Int) (n : Nat) : Int.bmod (x % n - y) n = Int.bmod (x - y) n := by
|
||||
simp only [emod_def, Int.sub_eq_add_neg]
|
||||
rw [←Int.mul_neg, Int.add_right_comm, Int.add_mul_bmod_self_left]
|
||||
|
||||
@[deprecated emod_sub_bmod (since := "2025-04-11")]
|
||||
theorem emod_sub_bmod_congr (x : Int) (n : Nat) : Int.bmod (x % n - y) n = Int.bmod (x - y) n :=
|
||||
emod_sub_bmod ..
|
||||
|
||||
@[simp]
|
||||
theorem sub_emod_bmod (x : Int) (n : Nat) : Int.bmod (x - y % n) n = Int.bmod (x - y) n := by
|
||||
simp only [emod_def]
|
||||
rw [Int.sub_eq_add_neg, Int.neg_sub, Int.sub_eq_add_neg, ← Int.add_assoc, Int.add_right_comm,
|
||||
Int.add_mul_bmod_self_left, Int.sub_eq_add_neg]
|
||||
|
||||
@[deprecated sub_emod_bmod (since := "2025-04-11")]
|
||||
theorem sub_emod_bmod_congr (x : Int) (n : Nat) : Int.bmod (x - y % n) n = Int.bmod (x - y) n :=
|
||||
sub_emod_bmod ..
|
||||
|
||||
@[simp]
|
||||
theorem emod_mul_bmod (x : Int) (n : Nat) : Int.bmod (x % n * y) n = Int.bmod (x * y) n := by
|
||||
simp [Int.emod_def, Int.sub_eq_add_neg]
|
||||
rw [←Int.mul_neg, Int.add_mul, Int.mul_assoc, Int.add_mul_bmod_self_left]
|
||||
|
||||
@[deprecated emod_mul_bmod (since := "2025-04-11")]
|
||||
theorem emod_mul_bmod_congr (x : Int) (n : Nat) : Int.bmod (x % n * y) n = Int.bmod (x * y) n :=
|
||||
emod_mul_bmod ..
|
||||
|
||||
@[simp]
|
||||
theorem bmod_add_bmod : Int.bmod (Int.bmod x n + y) n = Int.bmod (x + y) n := by
|
||||
have := (@add_mul_bmod_self_left (Int.bmod x n + y) n (bdiv x n)).symm
|
||||
rwa [Int.add_right_comm, bmod_add_bdiv] at this
|
||||
|
||||
@[deprecated bmod_add_bmod (since := "2025-04-11")]
|
||||
theorem bmod_add_bmod_congr : Int.bmod (Int.bmod x n + y) n = Int.bmod (x + y) n :=
|
||||
bmod_add_bmod ..
|
||||
|
||||
@[simp]
|
||||
theorem bmod_sub_bmod : Int.bmod (Int.bmod x n - y) n = Int.bmod (x - y) n :=
|
||||
@bmod_add_bmod x n (-y)
|
||||
|
||||
@[deprecated bmod_sub_bmod (since := "2025-04-11")]
|
||||
theorem bmod_sub_bmod_congr : Int.bmod (Int.bmod x n - y) n = Int.bmod (x - y) n :=
|
||||
bmod_sub_bmod ..
|
||||
|
||||
theorem add_bmod_eq_add_bmod_right (i : Int)
|
||||
(H : bmod x n = bmod y n) : bmod (x + i) n = bmod (y + i) n := by
|
||||
rw [← bmod_add_bmod, ← @bmod_add_bmod y, H]
|
||||
@@ -2863,9 +2756,6 @@ theorem bmod_natAbs_add_one (x : Int) (w : x ≠ -1) : x.bmod (x.natAbs + 1) = -
|
||||
· rw [sign_eq_one_iff_pos.2 hx]
|
||||
exact ⟨by omega, by omega, ⟨-1, by omega⟩⟩
|
||||
|
||||
@[deprecated bmod_natAbs_add_one (since := "2025-04-04")]
|
||||
abbrev bmod_natAbs_plus_one := @bmod_natAbs_add_one
|
||||
|
||||
theorem bmod_self_add_one {x : Nat} : (x : Int).bmod (x + 1) = if x = 0 then 0 else -1 := by
|
||||
have := bmod_natAbs_add_one x (by omega)
|
||||
simp only [natAbs_natCast] at this
|
||||
@@ -2986,11 +2876,6 @@ theorem bmod_eq_of_le {n : Int} {m : Nat} (hn' : -(m / 2) ≤ n) (hn : n < (m +
|
||||
n.bmod m = n :=
|
||||
(Nat.eq_zero_or_pos m).elim (by rintro rfl; simp) (fun hm => by simp_all [bmod_eq_iff])
|
||||
|
||||
@[deprecated bmod_eq_of_le (since := "2025-04-11")]
|
||||
theorem bmod_eq_self_of_le {n : Int} {m : Nat} (hn' : -(m / 2) ≤ n) (hn : n < (m + 1) / 2) :
|
||||
n.bmod m = n :=
|
||||
bmod_eq_of_le hn' hn
|
||||
|
||||
theorem bmod_bmod_of_dvd {a : Int} {n m : Nat} (hnm : n ∣ m) :
|
||||
(a.bmod m).bmod n = a.bmod n := by
|
||||
rw [← Int.sub_eq_iff_eq_add.2 (bmod_add_bdiv a m).symm]
|
||||
@@ -3001,11 +2886,6 @@ theorem bmod_eq_of_le_mul_two {x : Int} {y : Nat} (hle : -y ≤ x * 2) (hlt : x
|
||||
x.bmod y = x := by
|
||||
apply bmod_eq_of_le (by omega) (by omega)
|
||||
|
||||
@[deprecated bmod_eq_of_le_mul_two (since := "2025-04-11")]
|
||||
theorem bmod_eq_self_of_le_mul_two {x : Int} {y : Nat} (hle : -y ≤ x * 2) (hlt : x * 2 < y) :
|
||||
x.bmod y = x :=
|
||||
bmod_eq_of_le_mul_two hle hlt
|
||||
|
||||
/- ### ediv -/
|
||||
|
||||
theorem ediv_lt_self_of_pos_of_ne_one {x y : Int} (hx : 0 < x) (hy : y ≠ 1) :
|
||||
|
||||
@@ -74,9 +74,6 @@ theorem negSucc_inj : negSucc m = negSucc n ↔ m = n := ⟨negSucc.inj, fun H =
|
||||
|
||||
theorem negSucc_eq (n : Nat) : -[n+1] = -((n : Int) + 1) := rfl
|
||||
|
||||
@[deprecated negSucc_eq (since := "2025-03-11")]
|
||||
theorem negSucc_coe (n : Nat) : -[n+1] = -↑(n + 1) := rfl
|
||||
|
||||
@[simp] theorem negSucc_ne_zero (n : Nat) : -[n+1] ≠ 0 := nofun
|
||||
|
||||
@[simp] theorem zero_ne_negSucc (n : Nat) : 0 ≠ -[n+1] := nofun
|
||||
@@ -353,10 +350,6 @@ protected theorem add_sub_assoc (a b c : Int) : a + b - c = a + (b - c) := by
|
||||
change ofNat (n - succ m) = subNatNat n (succ m)
|
||||
rw [subNatNat, Nat.sub_eq_zero_of_le h]
|
||||
|
||||
@[deprecated negSucc_eq (since := "2025-03-11")]
|
||||
theorem negSucc_coe' (n : Nat) : -[n+1] = -↑n - 1 := by
|
||||
rw [Int.sub_eq_add_neg, ← Int.neg_add]; rfl
|
||||
|
||||
protected theorem subNatNat_eq_coe {m n : Nat} : subNatNat m n = ↑m - ↑n := by
|
||||
apply subNatNat_elim m n fun m n i => i = m - n
|
||||
· intro i n
|
||||
|
||||
@@ -118,14 +118,8 @@ theorem pos_iff_toNat_pos {n : Int} : 0 < n ↔ 0 < n.toNat := by
|
||||
|
||||
theorem natCast_toNat_eq_self {a : Int} : a.toNat = a ↔ 0 ≤ a := by omega
|
||||
|
||||
@[deprecated natCast_toNat_eq_self (since := "2025-04-16")]
|
||||
theorem ofNat_toNat_eq_self {a : Int} : a.toNat = a ↔ 0 ≤ a := natCast_toNat_eq_self
|
||||
|
||||
theorem eq_natCast_toNat {a : Int} : a = a.toNat ↔ 0 ≤ a := by omega
|
||||
|
||||
@[deprecated eq_natCast_toNat (since := "2025-04-16")]
|
||||
theorem eq_ofNat_toNat {a : Int} : a = a.toNat ↔ 0 ≤ a := eq_natCast_toNat
|
||||
|
||||
theorem toNat_le_toNat {n m : Int} (h : n ≤ m) : n.toNat ≤ m.toNat := by omega
|
||||
theorem toNat_lt_toNat {n m : Int} (hn : 0 < m) : n.toNat < m.toNat ↔ n < m := by omega
|
||||
|
||||
|
||||
@@ -234,9 +234,6 @@ theorem eq_natAbs_of_nonneg {a : Int} (h : 0 ≤ a) : a = natAbs a := by
|
||||
let ⟨n, e⟩ := eq_ofNat_of_zero_le h
|
||||
rw [e]; rfl
|
||||
|
||||
@[deprecated eq_natAbs_of_nonneg (since := "2025-03-11")]
|
||||
abbrev eq_natAbs_of_zero_le := @eq_natAbs_of_nonneg
|
||||
|
||||
theorem le_natAbs {a : Int} : a ≤ natAbs a :=
|
||||
match Int.le_total 0 a with
|
||||
| .inl h => by rw [eq_natAbs_of_nonneg h]; apply Int.le_refl
|
||||
@@ -554,9 +551,6 @@ protected theorem mul_le_mul_of_nonpos_left {a b c : Int}
|
||||
|
||||
@[simp, norm_cast] theorem natAbs_natCast (n : Nat) : natAbs ↑n = n := rfl
|
||||
|
||||
@[deprecated natAbs_natCast (since := "2025-04-16")]
|
||||
theorem natAbs_ofNat (n : Nat) : natAbs ↑n = n := natAbs_natCast n
|
||||
|
||||
/-
|
||||
TODO: rename `natAbs_ofNat'` to `natAbs_ofNat` once the current deprecated alias
|
||||
`natAbs_ofNat := natAbs_natCast` is removed
|
||||
@@ -646,17 +640,11 @@ theorem toNat_of_nonneg {a : Int} (h : 0 ≤ a) : (toNat a : Int) = a := by
|
||||
|
||||
@[simp] theorem toNat_natCast (n : Nat) : toNat ↑n = n := rfl
|
||||
|
||||
@[deprecated toNat_natCast (since := "2025-04-16")]
|
||||
theorem toNat_ofNat (n : Nat) : toNat ↑n = n := rfl
|
||||
|
||||
@[simp] theorem toNat_negSucc (n : Nat) : (Int.negSucc n).toNat = 0 := by
|
||||
simp [toNat]
|
||||
|
||||
@[simp] theorem toNat_natCast_add_one {n : Nat} : ((n : Int) + 1).toNat = n + 1 := rfl
|
||||
|
||||
@[deprecated toNat_natCast_add_one (since := "2025-04-16")]
|
||||
theorem toNat_ofNat_add_one {n : Nat} : ((n : Int) + 1).toNat = n + 1 := toNat_natCast_add_one
|
||||
|
||||
@[simp] theorem ofNat_toNat (a : Int) : (a.toNat : Int) = max a 0 := by
|
||||
match a with
|
||||
| (n : Nat) => simp
|
||||
@@ -717,9 +705,6 @@ theorem mem_toNat? : ∀ {a : Int} {n : Nat}, toNat? a = some n ↔ a = n
|
||||
| (m : Nat), n => by simp [toNat?, Int.ofNat_inj]
|
||||
| -[m+1], n => by constructor <;> nofun
|
||||
|
||||
@[deprecated mem_toNat? (since := "2025-03-11")]
|
||||
abbrev mem_toNat' := @mem_toNat?
|
||||
|
||||
/-! ## Order properties of the integers -/
|
||||
|
||||
protected theorem le_of_not_le {a b : Int} : ¬ a ≤ b → b ≤ a := (Int.le_total a b).resolve_left
|
||||
@@ -1259,18 +1244,10 @@ theorem natAbs_sign (z : Int) : z.sign.natAbs = if z = 0 then 0 else 1 :=
|
||||
theorem natAbs_sign_of_ne_zero {z : Int} (hz : z ≠ 0) : z.sign.natAbs = 1 := by
|
||||
rw [Int.natAbs_sign, if_neg hz]
|
||||
|
||||
@[deprecated natAbs_sign_of_ne_zero (since := "2025-04-16")]
|
||||
theorem natAbs_sign_of_nonzero {z : Int} (hz : z ≠ 0) : z.sign.natAbs = 1 :=
|
||||
natAbs_sign_of_ne_zero hz
|
||||
|
||||
theorem sign_natCast_of_ne_zero {n : Nat} (hn : n ≠ 0) : Int.sign n = 1 :=
|
||||
match n, Nat.exists_eq_succ_of_ne_zero hn with
|
||||
| _, ⟨n, rfl⟩ => Int.sign_of_add_one n
|
||||
|
||||
@[deprecated sign_natCast_of_ne_zero (since := "2025-04-16")]
|
||||
theorem sign_ofNat_of_nonzero {n : Nat} (hn : n ≠ 0) : Int.sign n = 1 :=
|
||||
sign_natCast_of_ne_zero hn
|
||||
|
||||
@[simp] theorem sign_neg (z : Int) : Int.sign (-z) = -Int.sign z := by
|
||||
match z with | 0 | succ _ | -[_+1] => rfl
|
||||
|
||||
@@ -1325,8 +1302,6 @@ theorem neg_of_sign_eq_neg_one : ∀ {a : Int}, sign a = -1 → a < 0
|
||||
exact Int.le_add_one (natCast_nonneg _)
|
||||
| .negSucc _ => simp +decide [sign]
|
||||
|
||||
@[deprecated sign_nonneg_iff (since := "2025-03-11")] abbrev sign_nonneg := @sign_nonneg_iff
|
||||
|
||||
@[simp] theorem sign_pos_iff : 0 < sign x ↔ 0 < x := by
|
||||
match x with
|
||||
| 0
|
||||
@@ -1409,9 +1384,6 @@ theorem natAbs_add_of_nonpos {a b : Int} (ha : a ≤ 0) (hb : b ≤ 0) :
|
||||
natAbs_add_of_nonneg (Int.neg_nonneg_of_nonpos ha) (Int.neg_nonneg_of_nonpos hb),
|
||||
natAbs_neg (-a), natAbs_neg (-b)]
|
||||
|
||||
@[deprecated negSucc_eq (since := "2025-03-11")]
|
||||
theorem negSucc_eq' (m : Nat) : -[m+1] = -m - 1 := by simp only [negSucc_eq, Int.neg_add]; rfl
|
||||
|
||||
theorem natAbs_lt_natAbs_of_nonneg_of_lt {a b : Int}
|
||||
(w₁ : 0 ≤ a) (w₂ : a < b) : a.natAbs < b.natAbs :=
|
||||
match a, b, eq_ofNat_of_zero_le w₁, eq_ofNat_of_zero_le (Int.le_trans w₁ (Int.le_of_lt w₂)) with
|
||||
@@ -1420,9 +1392,6 @@ theorem natAbs_lt_natAbs_of_nonneg_of_lt {a b : Int}
|
||||
theorem natAbs_eq_iff_mul_eq_zero : natAbs a = n ↔ (a - n) * (a + n) = 0 := by
|
||||
rw [natAbs_eq_iff, Int.mul_eq_zero, ← Int.sub_neg, Int.sub_eq_zero, Int.sub_eq_zero]
|
||||
|
||||
@[deprecated natAbs_eq_iff_mul_eq_zero (since := "2025-03-11")]
|
||||
abbrev eq_natAbs_iff_mul_eq_zero := @natAbs_eq_iff_mul_eq_zero
|
||||
|
||||
instance instIsLinearOrder : IsLinearOrder Int := by
|
||||
apply IsLinearOrder.of_le
|
||||
case le_antisymm => constructor; apply Int.le_antisymm
|
||||
|
||||
@@ -49,10 +49,6 @@ protected theorem pow_ne_zero {n : Int} {m : Nat} : n ≠ 0 → n ^ m ≠ 0 := b
|
||||
|
||||
instance {n : Int} {m : Nat} [NeZero n] : NeZero (n ^ m) := ⟨Int.pow_ne_zero (NeZero.ne _)⟩
|
||||
|
||||
-- This can't be removed until the next update-stage0
|
||||
@[deprecated Nat.pow_pos (since := "2025-02-17")]
|
||||
abbrev _root_.Nat.pos_pow_of_pos := @Nat.pow_pos
|
||||
|
||||
@[simp, norm_cast]
|
||||
protected theorem natCast_pow (b n : Nat) : ((b^n : Nat) : Int) = (b : Int) ^ n := by
|
||||
match n with
|
||||
|
||||
@@ -1038,9 +1038,6 @@ def dropLast {α} : List α → List α
|
||||
@[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₂ :
|
||||
(x::y::zs).dropLast = x :: (y::zs).dropLast := rfl
|
||||
|
||||
|
||||
@@ -705,12 +705,6 @@ theorem mem_or_eq_of_mem_set : ∀ {l : List α} {i : Nat} {a b : α}, a ∈ l.s
|
||||
@[simp, grind =] theorem nil_beq_eq [BEq α] {l : List α} : ([] == l) = l.isEmpty := by
|
||||
cases l <;> rfl
|
||||
|
||||
@[deprecated beq_nil_eq (since := "2025-04-04")]
|
||||
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 α} :
|
||||
(a :: l₁ == b :: l₂) = (a == b && l₁ == l₂) := rfl
|
||||
|
||||
@@ -933,9 +927,6 @@ theorem head?_eq_some_iff {xs : List α} {a : α} : xs.head? = some a ↔ ∃ ys
|
||||
@[simp] theorem isSome_head? : l.head?.isSome ↔ l ≠ [] := by
|
||||
cases l <;> simp
|
||||
|
||||
@[deprecated isSome_head? (since := "2025-03-18")]
|
||||
abbrev head?_isSome := @isSome_head?
|
||||
|
||||
@[simp] theorem head_mem : ∀ {l : List α} (h : l ≠ []), head l h ∈ l
|
||||
| [], h => absurd rfl h
|
||||
| _::_, _ => .head ..
|
||||
@@ -1266,9 +1257,6 @@ theorem length_filter_eq_length_iff {l} : (filter p l).length = l.length ↔ ∀
|
||||
· have := Nat.ne_of_lt (Nat.lt_succ.mpr (length_filter_le p l))
|
||||
simp_all
|
||||
|
||||
@[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
|
||||
induction as with
|
||||
| nil => simp
|
||||
|
||||
@@ -548,9 +548,6 @@ theorem _root_.Array.replicate_eq_toArray_replicate :
|
||||
Array.replicate n v = (List.replicate n v).toArray := by
|
||||
simp
|
||||
|
||||
@[deprecated _root_.Array.replicate_eq_toArray_replicate (since := "2025-03-18")]
|
||||
abbrev _root_.Array.mkArray_eq_toArray_replicate := @_root_.Array.replicate_eq_toArray_replicate
|
||||
|
||||
@[simp, grind =] theorem flatMap_empty {β} (f : α → Array β) : (#[] : Array α).flatMap f = #[] := rfl
|
||||
|
||||
theorem flatMap_toArray_cons {β} (f : α → Array β) (a : α) (as : List α) :
|
||||
|
||||
@@ -627,9 +627,6 @@ theorem eq_zero_or_eq_succ_pred : ∀ n, n = 0 ∨ n = succ (pred n)
|
||||
|
||||
theorem succ_inj : succ a = succ b ↔ a = b := (Nat.succ.injEq a b).to_iff
|
||||
|
||||
@[deprecated succ_inj (since := "2025-04-14")]
|
||||
theorem succ_inj' : succ a = succ b ↔ a = b := succ_inj
|
||||
|
||||
theorem succ_le_succ_iff : succ a ≤ succ b ↔ a ≤ b := ⟨le_of_succ_le_succ, succ_le_succ⟩
|
||||
|
||||
theorem succ_lt_succ_iff : succ a < succ b ↔ a < b := ⟨lt_of_succ_lt_succ, succ_lt_succ⟩
|
||||
|
||||
@@ -132,9 +132,6 @@ theorem testBit_eq_decide_div_mod_eq {x : Nat} : testBit x i = decide (x / 2^i %
|
||||
| succ i hyp =>
|
||||
simp [hyp, Nat.div_div_eq_div_mul, Nat.pow_succ']
|
||||
|
||||
@[deprecated testBit_eq_decide_div_mod_eq (since := "2025-04-04")]
|
||||
abbrev testBit_to_div_mod := @testBit_eq_decide_div_mod_eq
|
||||
|
||||
theorem toNat_testBit (x i : Nat) :
|
||||
(x.testBit i).toNat = x / 2 ^ i % 2 := by
|
||||
rw [testBit_eq_decide_div_mod_eq]
|
||||
@@ -155,9 +152,6 @@ theorem exists_testBit_of_ne_zero {x : Nat} (xnz : x ≠ 0) : ∃ i, testBit x i
|
||||
apply Exists.intro 0
|
||||
simp_all
|
||||
|
||||
@[deprecated exists_testBit_of_ne_zero (since := "2025-04-04")]
|
||||
abbrev ne_zero_implies_bit_true := @exists_testBit_of_ne_zero
|
||||
|
||||
theorem exists_testBit_ne_of_ne {x y : Nat} (p : x ≠ y) : ∃ i, testBit x i ≠ testBit y i := by
|
||||
induction y using Nat.div2Induction generalizing x with
|
||||
| ind y hyp =>
|
||||
@@ -183,9 +177,6 @@ theorem exists_testBit_ne_of_ne {x y : Nat} (p : x ≠ y) : ∃ i, testBit x i
|
||||
cases mod_two_eq_zero_or_one x with
|
||||
| _ p => cases mod_two_eq_zero_or_one y with | _ q => simp [p,q]
|
||||
|
||||
@[deprecated exists_testBit_ne_of_ne (since := "2025-04-04")]
|
||||
abbrev ne_implies_bit_diff := @exists_testBit_ne_of_ne
|
||||
|
||||
/--
|
||||
`eq_of_testBit_eq` allows proving two natural numbers are equal
|
||||
if their bits are all equal.
|
||||
@@ -218,9 +209,6 @@ theorem exists_ge_and_testBit_of_ge_two_pow {x : Nat} (p : x ≥ 2^n) : ∃ i
|
||||
case right =>
|
||||
simpa using jp.right
|
||||
|
||||
@[deprecated exists_ge_and_testBit_of_ge_two_pow (since := "2025-04-04")]
|
||||
abbrev ge_two_pow_implies_high_bit_true := @exists_ge_and_testBit_of_ge_two_pow
|
||||
|
||||
theorem ge_two_pow_of_testBit {x : Nat} (p : testBit x i = true) : x ≥ 2^i := by
|
||||
simp only [Nat.testBit_eq_decide_div_mod_eq] at p
|
||||
apply Decidable.by_contra
|
||||
@@ -228,9 +216,6 @@ theorem ge_two_pow_of_testBit {x : Nat} (p : testBit x i = true) : x ≥ 2^i :=
|
||||
have x_lt : x < 2^i := Nat.lt_of_not_le not_ge
|
||||
simp [div_eq_of_lt x_lt] at p
|
||||
|
||||
@[deprecated ge_two_pow_of_testBit (since := "2025-04-04")]
|
||||
abbrev testBit_implies_ge := @ge_two_pow_of_testBit
|
||||
|
||||
theorem testBit_lt_two_pow {x i : Nat} (lt : x < 2^i) : x.testBit i = false := by
|
||||
match p : x.testBit i with
|
||||
| false => trivial
|
||||
@@ -529,16 +514,10 @@ theorem and_lt_two_pow (x : Nat) {y n : Nat} (right : y < 2^n) : (x &&& y) < 2^n
|
||||
simp only [testBit_and, testBit_mod_two_pow]
|
||||
cases testBit x i <;> simp
|
||||
|
||||
@[deprecated and_two_pow_sub_one_eq_mod (since := "2025-03-18")]
|
||||
abbrev and_pow_two_sub_one_eq_mod := @and_two_pow_sub_one_eq_mod
|
||||
|
||||
theorem and_two_pow_sub_one_of_lt_two_pow {x : Nat} (lt : x < 2^n) : x &&& 2^n - 1 = x := by
|
||||
rw [and_two_pow_sub_one_eq_mod]
|
||||
apply Nat.mod_eq_of_lt lt
|
||||
|
||||
@[deprecated and_two_pow_sub_one_of_lt_two_pow (since := "2025-03-18")]
|
||||
abbrev and_pow_two_sub_one_of_lt_two_pow := @and_two_pow_sub_one_of_lt_two_pow
|
||||
|
||||
@[simp] theorem and_mod_two_eq_one : (a &&& b) % 2 = 1 ↔ a % 2 = 1 ∧ b % 2 = 1 := by
|
||||
simp only [mod_two_eq_one_iff_testBit_zero]
|
||||
rw [testBit_and]
|
||||
@@ -728,9 +707,6 @@ theorem testBit_two_pow_mul_add (a : Nat) {b i : Nat} (b_lt : b < 2^i) (j : Nat)
|
||||
Nat.div_eq_of_lt b_lt,
|
||||
Nat.two_pow_pos i]
|
||||
|
||||
@[deprecated testBit_two_pow_mul_add (since := "2025-03-18")]
|
||||
abbrev testBit_mul_pow_two_add := @testBit_two_pow_mul_add
|
||||
|
||||
@[grind =]
|
||||
theorem testBit_two_pow_mul :
|
||||
testBit (2 ^ i * a) j = (decide (j ≥ i) && testBit a (j-i)) := by
|
||||
@@ -745,9 +721,6 @@ theorem testBit_mul_two_pow (x j i : Nat) :
|
||||
(x * 2 ^ i).testBit j = (decide (i ≤ j) && x.testBit (j - i)) := by
|
||||
rw [Nat.mul_comm, testBit_two_pow_mul]
|
||||
|
||||
@[deprecated testBit_two_pow_mul (since := "2025-03-18")]
|
||||
abbrev testBit_mul_pow_two := @testBit_two_pow_mul
|
||||
|
||||
theorem two_pow_add_eq_or_of_lt {b : Nat} (b_lt : b < 2^i) (a : Nat) :
|
||||
2^i * a + b = 2^i * a ||| b := by
|
||||
apply eq_of_testBit_eq
|
||||
@@ -763,9 +736,6 @@ theorem two_pow_add_eq_or_of_lt {b : Nat} (b_lt : b < 2^i) (a : Nat) :
|
||||
_ ≤ 2 ^ j := Nat.pow_le_pow_right Nat.zero_lt_two i_le
|
||||
simp [i_le, j_lt, testBit_lt_two_pow, b_lt_j]
|
||||
|
||||
@[deprecated two_pow_add_eq_or_of_lt (since := "2025-03-18")]
|
||||
abbrev mul_add_lt_is_or := @two_pow_add_eq_or_of_lt
|
||||
|
||||
/-! ### shiftLeft and shiftRight -/
|
||||
|
||||
@[simp, grind =] theorem testBit_shiftLeft (x : Nat) : testBit (x <<< i) j =
|
||||
|
||||
@@ -30,9 +30,6 @@ theorem compare_eq_ite_lt (a b : Nat) :
|
||||
| .inl h => simp [h, Nat.ne_of_gt h]
|
||||
| .inr rfl => simp
|
||||
|
||||
@[deprecated compare_eq_ite_lt (since := "2025-03_28")]
|
||||
def compare_def_lt := compare_eq_ite_lt
|
||||
|
||||
theorem compare_eq_ite_le (a b : Nat) :
|
||||
compare a b = if a ≤ b then if b ≤ a then .eq else .lt else .gt := by
|
||||
rw [compare_eq_ite_lt]
|
||||
@@ -43,9 +40,6 @@ theorem compare_eq_ite_le (a b : Nat) :
|
||||
next hgt => simp [Nat.not_le.2 hgt]
|
||||
next hle => simp [Nat.not_lt.1 hge, Nat.not_lt.1 hle]
|
||||
|
||||
@[deprecated compare_eq_ite_le (since := "2025-03_28")]
|
||||
def compare_def_le := compare_eq_ite_le
|
||||
|
||||
protected theorem compare_swap (a b : Nat) : (compare a b).swap = compare b a := by
|
||||
simp only [compare_eq_ite_le]; (repeat' split) <;> try rfl
|
||||
next h1 h2 => cases h1 (Nat.le_of_not_le h2)
|
||||
|
||||
@@ -182,17 +182,9 @@ theorem gcd_dvd_gcd_of_dvd_right {m k : Nat} (n : Nat) (H : m ∣ k) : gcd n m
|
||||
theorem gcd_dvd_gcd_mul_left_left (m n k : Nat) : gcd m n ∣ gcd (k * m) n :=
|
||||
gcd_dvd_gcd_of_dvd_left _ (Nat.dvd_mul_left _ _)
|
||||
|
||||
@[deprecated gcd_dvd_gcd_mul_left_left (since := "2025-04-01")]
|
||||
theorem gcd_dvd_gcd_mul_left (m n k : Nat) : gcd m n ∣ gcd (k * m) n :=
|
||||
gcd_dvd_gcd_mul_left_left m n k
|
||||
|
||||
theorem gcd_dvd_gcd_mul_right_left (m n k : Nat) : gcd m n ∣ gcd (m * k) n :=
|
||||
gcd_dvd_gcd_of_dvd_left _ (Nat.dvd_mul_right _ _)
|
||||
|
||||
@[deprecated gcd_dvd_gcd_mul_right_left (since := "2025-04-01")]
|
||||
theorem gcd_dvd_gcd_mul_right (m n k : Nat) : gcd m n ∣ gcd (m * k) n :=
|
||||
gcd_dvd_gcd_mul_right_left m n k
|
||||
|
||||
theorem gcd_dvd_gcd_mul_left_right (m n k : Nat) : gcd m n ∣ gcd m (k * n) :=
|
||||
gcd_dvd_gcd_of_dvd_right _ (Nat.dvd_mul_left _ _)
|
||||
|
||||
@@ -242,10 +234,6 @@ theorem gcd_left_eq_iff {m m' n : Nat} : gcd m n = gcd m' n ↔ ∀ k, k ∣ n
|
||||
@[simp] theorem gcd_add_mul_right_right (m n k : Nat) : gcd m (n + k * m) = gcd m n := by
|
||||
simp [gcd_rec m (n + k * m), gcd_rec m n]
|
||||
|
||||
@[deprecated gcd_add_mul_right_right (since := "2025-03-31")]
|
||||
theorem gcd_add_mul_self (m n k : Nat) : gcd m (n + k * m) = gcd m n :=
|
||||
gcd_add_mul_right_right _ _ _
|
||||
|
||||
@[simp] theorem gcd_add_mul_left_right (m n k : Nat) : gcd m (n + m * k) = gcd m n := by
|
||||
rw [Nat.mul_comm, gcd_add_mul_right_right]
|
||||
|
||||
@@ -389,11 +377,6 @@ def dvdProdDvdOfDvdProd {k m n : Nat} (h : k ∣ m * n) :
|
||||
rw [hd, ← gcd_mul_right]
|
||||
exact Nat.dvd_gcd (Nat.dvd_mul_right _ _) h
|
||||
|
||||
@[inherit_doc dvdProdDvdOfDvdProd, deprecated dvdProdDvdOfDvdProd (since := "2025-04-01")]
|
||||
def prod_dvd_and_dvd_of_dvd_prod {k m n : Nat} (H : k ∣ m * n) :
|
||||
{d : {m' // m' ∣ m} × {n' // n' ∣ n} // k = d.1.val * d.2.val} :=
|
||||
dvdProdDvdOfDvdProd H
|
||||
|
||||
protected theorem dvd_mul {k m n : Nat} : k ∣ m * n ↔ ∃ k₁ k₂, k₁ ∣ m ∧ k₂ ∣ n ∧ k₁ * k₂ = k := by
|
||||
refine ⟨fun h => ?_, ?_⟩
|
||||
· obtain ⟨⟨⟨k₁, hk₁⟩, ⟨k₂, hk₂⟩⟩, rfl⟩ := dvdProdDvdOfDvdProd h
|
||||
@@ -410,10 +393,6 @@ theorem gcd_mul_right_dvd_mul_gcd (k m n : Nat) : gcd k (m * n) ∣ gcd k m * gc
|
||||
(dvd_gcd (Nat.dvd_trans (Nat.dvd_mul_right m' n') h') hm')
|
||||
(dvd_gcd (Nat.dvd_trans (Nat.dvd_mul_left n' m') h') hn')
|
||||
|
||||
@[deprecated gcd_mul_right_dvd_mul_gcd (since := "2025-04-02")]
|
||||
theorem gcd_mul_dvd_mul_gcd (k m n : Nat) : gcd k (m * n) ∣ gcd k m * gcd k n :=
|
||||
gcd_mul_right_dvd_mul_gcd k m n
|
||||
|
||||
theorem gcd_mul_left_dvd_mul_gcd (k m n : Nat) : gcd (m * n) k ∣ gcd m k * gcd n k := by
|
||||
simpa [gcd_comm, Nat.mul_comm] using gcd_mul_right_dvd_mul_gcd _ _ _
|
||||
|
||||
|
||||
@@ -220,15 +220,6 @@ protected theorem add_right_inj {n : Nat} : n + m = n + k ↔ m = k := Nat.add_l
|
||||
@[simp high] protected theorem left_eq_add {a b : Nat} : a = a + b ↔ b = 0 := by omega
|
||||
@[simp high] protected theorem right_eq_add {a b : Nat} : b = a + b ↔ a = 0 := by omega
|
||||
|
||||
@[deprecated Nat.add_eq_right (since := "2025-04-15")]
|
||||
protected theorem add_left_eq_self {a b : Nat} : a + b = b ↔ a = 0 := Nat.add_eq_right
|
||||
@[deprecated Nat.add_eq_left (since := "2025-04-15")]
|
||||
protected theorem add_right_eq_self {a b : Nat} : a + b = a ↔ b = 0 := Nat.add_eq_left
|
||||
@[deprecated Nat.left_eq_add (since := "2025-04-15")]
|
||||
protected theorem self_eq_add_right {a b : Nat} : a = a + b ↔ b = 0 := Nat.left_eq_add
|
||||
@[deprecated Nat.right_eq_add (since := "2025-04-15")]
|
||||
protected theorem self_eq_add_left {a b : Nat} : a = b + a ↔ b = 0 := Nat.right_eq_add
|
||||
|
||||
protected theorem lt_of_add_lt_add_right : ∀ {n : Nat}, k + n < m + n → k < m
|
||||
| 0, h => h
|
||||
| _+1, h => Nat.lt_of_add_lt_add_right (Nat.lt_of_succ_lt_succ h)
|
||||
|
||||
@@ -46,16 +46,10 @@ def isPowerOfTwo (n : Nat) := ∃ k, n = 2 ^ k
|
||||
theorem isPowerOfTwo_one : isPowerOfTwo 1 :=
|
||||
⟨0, by decide⟩
|
||||
|
||||
@[deprecated isPowerOfTwo_one (since := "2025-03-18")]
|
||||
abbrev one_isPowerOfTwo := isPowerOfTwo_one
|
||||
|
||||
theorem isPowerOfTwo_mul_two_of_isPowerOfTwo (h : isPowerOfTwo n) : isPowerOfTwo (n * 2) :=
|
||||
have ⟨k, h⟩ := h
|
||||
⟨k+1, by simp [h, Nat.pow_succ]⟩
|
||||
|
||||
@[deprecated isPowerOfTwo_mul_two_of_isPowerOfTwo (since := "2025-04-04")]
|
||||
abbrev mul2_isPowerOfTwo_of_isPowerOfTwo := @isPowerOfTwo_mul_two_of_isPowerOfTwo
|
||||
|
||||
theorem pos_of_isPowerOfTwo (h : isPowerOfTwo n) : n > 0 := by
|
||||
have ⟨k, h⟩ := h
|
||||
rw [h]
|
||||
|
||||
@@ -390,27 +390,6 @@ Examples:
|
||||
| none => List.toArray .nil
|
||||
| some a => List.toArray (.cons a .nil)
|
||||
|
||||
/--
|
||||
Applies a function to a two optional values if both are present. Otherwise, if one value is present,
|
||||
it is returned and the function is not used.
|
||||
|
||||
The value is `some (f a b)` if the inputs are `some a` and `some b`. Otherwise, the behavior is
|
||||
equivalent to `Option.orElse`. If only one input is `some x`, then the value is `some x`. If both
|
||||
are `none`, then the value is `none`.
|
||||
|
||||
Examples:
|
||||
* `Option.liftOrGet (· + ·) none (some 3) = some 3`
|
||||
* `Option.liftOrGet (· + ·) (some 2) (some 3) = some 5`
|
||||
* `Option.liftOrGet (· + ·) (some 2) none = some 2`
|
||||
* `Option.liftOrGet (· + ·) none none = none`
|
||||
-/
|
||||
@[deprecated merge (since := "2025-04-04")]
|
||||
def liftOrGet (f : α → α → α) : Option α → Option α → Option α
|
||||
| none, none => none
|
||||
| some a, none => some a
|
||||
| none, some b => some b
|
||||
| some a, some b => some (f a b)
|
||||
|
||||
/-- Lifts a relation `α → β → Prop` to a relation `Option α → Option β → Prop` by just adding
|
||||
`none ~ none`. -/
|
||||
inductive Rel (r : α → β → Prop) : Option α → Option β → Prop
|
||||
|
||||
@@ -46,10 +46,6 @@ Try to use the Boolean comparisons `Option.isNone` or `Option.isSome` instead.
|
||||
@[inline] def decidableEqNone {o : Option α} : Decidable (o = none) :=
|
||||
decidable_of_decidable_of_iff isNone_iff_eq_none
|
||||
|
||||
@[deprecated decidableEqNone (since := "2025-04-10"), inline]
|
||||
def decidable_eq_none {o : Option α} : Decidable (o = none) :=
|
||||
decidableEqNone
|
||||
|
||||
instance decidableForallMem {p : α → Prop} [DecidablePred p] :
|
||||
∀ o : Option α, Decidable (∀ a, a ∈ o → p a)
|
||||
| none => isTrue nofun
|
||||
|
||||
@@ -19,9 +19,6 @@ namespace Option
|
||||
|
||||
@[grind =] theorem default_eq_none : (default : Option α) = none := rfl
|
||||
|
||||
@[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
|
||||
|
||||
theorem mem_some_iff {a b : α} : a ∈ some b ↔ b = a := mem_some
|
||||
@@ -177,10 +174,6 @@ theorem exists_ne_none {p : Option α → Prop} : (∃ x, x ≠ none ∧ p x)
|
||||
⟨fun ⟨x, hx, hp⟩ => ⟨x.get <| ne_none_iff_isSome.1 hx, by rwa [some_get]⟩,
|
||||
fun ⟨x, hx⟩ => ⟨some x, some_ne_none x, hx⟩⟩
|
||||
|
||||
@[deprecated exists_ne_none (since := "2025-04-04")]
|
||||
theorem bex_ne_none {p : Option α → Prop} : (∃ x, ∃ (_ : x ≠ none), p x) ↔ ∃ x, p (some x) := by
|
||||
simp only [exists_prop, exists_ne_none]
|
||||
|
||||
theorem forall_ne_none {p : Option α → Prop} : (∀ x (_ : x ≠ none), p x) ↔ ∀ x, p (some x) :=
|
||||
⟨fun h x => h (some x) (some_ne_none x),
|
||||
fun h x hx => by
|
||||
@@ -188,9 +181,6 @@ theorem forall_ne_none {p : Option α → Prop} : (∀ x (_ : x ≠ none), p x)
|
||||
simp [some_get] at this ⊢
|
||||
exact this⟩
|
||||
|
||||
@[deprecated forall_ne_none (since := "2025-04-04")]
|
||||
abbrev ball_ne_none := @forall_ne_none
|
||||
|
||||
@[simp] theorem pure_def : pure = @some α := rfl
|
||||
|
||||
@[grind =] theorem pure_apply : pure x = some x := rfl
|
||||
@@ -207,15 +197,9 @@ abbrev ball_ne_none := @forall_ne_none
|
||||
theorem bind_eq_some_iff : x.bind f = some b ↔ ∃ a, x = some a ∧ f a = some b := by
|
||||
cases x <;> simp
|
||||
|
||||
@[deprecated bind_eq_some_iff (since := "2025-04-10")]
|
||||
abbrev bind_eq_some := @bind_eq_some_iff
|
||||
|
||||
@[simp] theorem bind_eq_none_iff {o : Option α} {f : α → Option β} :
|
||||
o.bind f = none ↔ ∀ a, o = some a → f a = none := by cases o <;> simp
|
||||
|
||||
@[deprecated bind_eq_none_iff (since := "2025-04-10")]
|
||||
abbrev bind_eq_none := @bind_eq_none_iff
|
||||
|
||||
theorem bind_eq_none' {o : Option α} {f : α → Option β} :
|
||||
o.bind f = none ↔ ∀ b a, o = some a → f a ≠ some b := by
|
||||
cases o <;> simp [eq_none_iff_forall_ne_some]
|
||||
@@ -272,9 +256,6 @@ theorem isSome_apply_of_isSome_bind {α β : Type _} {x : Option α} {f : α →
|
||||
theorem join_eq_some_iff : x.join = some a ↔ x = some (some a) := by
|
||||
simp [← bind_id_eq_join, bind_eq_some_iff]
|
||||
|
||||
@[deprecated join_eq_some_iff (since := "2025-04-10")]
|
||||
abbrev join_eq_some := @join_eq_some_iff
|
||||
|
||||
theorem join_ne_none : x.join ≠ none ↔ ∃ z, x = some (some z) := by
|
||||
simp only [ne_none_iff_exists', join_eq_some_iff, iff_self]
|
||||
|
||||
@@ -284,9 +265,6 @@ theorem join_ne_none' : ¬x.join = none ↔ ∃ z, x = some (some z) :=
|
||||
theorem join_eq_none_iff : o.join = none ↔ o = none ∨ o = some none :=
|
||||
match o with | none | some none | some (some _) => by simp
|
||||
|
||||
@[deprecated join_eq_none_iff (since := "2025-04-10")]
|
||||
abbrev join_eq_none := @join_eq_none_iff
|
||||
|
||||
theorem bind_join {f : α → Option β} {o : Option (Option α)} :
|
||||
o.join.bind f = o.bind (·.bind f) := by
|
||||
cases o <;> simp
|
||||
@@ -295,36 +273,15 @@ theorem bind_join {f : α → Option β} {o : Option (Option α)} :
|
||||
|
||||
@[grind =] theorem map_apply : Functor.map f x = Option.map f x := rfl
|
||||
|
||||
@[deprecated map_none (since := "2025-04-10")]
|
||||
abbrev map_none' := @map_none
|
||||
|
||||
@[deprecated map_some (since := "2025-04-10")]
|
||||
abbrev map_some' := @map_some
|
||||
|
||||
@[simp] theorem map_eq_some_iff : x.map f = some b ↔ ∃ a, x = some a ∧ f a = b := by
|
||||
cases x <;> simp
|
||||
|
||||
@[deprecated map_eq_some_iff (since := "2025-04-10")]
|
||||
abbrev map_eq_some := @map_eq_some_iff
|
||||
|
||||
@[deprecated map_eq_some_iff (since := "2025-04-10")]
|
||||
abbrev map_eq_some' := @map_eq_some_iff
|
||||
|
||||
@[simp] theorem map_eq_none_iff : x.map f = none ↔ x = none := by
|
||||
cases x <;> simp [map_none, map_some]
|
||||
|
||||
@[deprecated map_eq_none_iff (since := "2025-04-10")]
|
||||
abbrev map_eq_none := @map_eq_none_iff
|
||||
|
||||
@[deprecated map_eq_none_iff (since := "2025-04-10")]
|
||||
abbrev map_eq_none' := @map_eq_none_iff
|
||||
|
||||
@[simp, grind =] theorem isSome_map {x : Option α} : (x.map f).isSome = x.isSome := by
|
||||
cases x <;> simp
|
||||
|
||||
@[deprecated isSome_map (since := "2025-04-10")]
|
||||
abbrev isSome_map' := @isSome_map
|
||||
|
||||
@[simp, grind =] theorem isNone_map {x : Option α} : (x.map f).isNone = x.isNone := by
|
||||
cases x <;> simp
|
||||
|
||||
@@ -396,16 +353,10 @@ theorem isSome_of_isSome_filter (p : α → Bool) (o : Option α) (h : (o.filter
|
||||
o.isSome := by
|
||||
cases o <;> simp at h ⊢
|
||||
|
||||
@[deprecated isSome_of_isSome_filter (since := "2025-03-18")]
|
||||
abbrev isSome_filter_of_isSome := @isSome_of_isSome_filter
|
||||
|
||||
@[simp] theorem filter_eq_none_iff {o : Option α} {p : α → Bool} :
|
||||
o.filter p = none ↔ ∀ a, o = some a → ¬ p a := by
|
||||
cases o <;> simp [filter_some]
|
||||
|
||||
@[deprecated filter_eq_none_iff (since := "2025-04-10")]
|
||||
abbrev filter_eq_none := @filter_eq_none_iff
|
||||
|
||||
@[simp] theorem filter_eq_some_iff {o : Option α} {p : α → Bool} :
|
||||
o.filter p = some a ↔ o = some a ∧ p a := by
|
||||
cases o with
|
||||
@@ -420,9 +371,6 @@ abbrev filter_eq_none := @filter_eq_none_iff
|
||||
rintro rfl
|
||||
simpa using h
|
||||
|
||||
@[deprecated filter_eq_some_iff (since := "2025-04-10")]
|
||||
abbrev filter_eq_some := @filter_eq_some_iff
|
||||
|
||||
theorem filter_some_eq_some : Option.filter p (some a) = some a ↔ p a := by simp
|
||||
|
||||
theorem filter_some_eq_none : Option.filter p (some a) = none ↔ ¬p a := by simp
|
||||
@@ -610,15 +558,9 @@ theorem join_eq_get {x : Option (Option α)} {h} : x.join = x.get h := by
|
||||
@[simp] theorem guard_eq_some_iff : guard p a = some b ↔ a = b ∧ p a :=
|
||||
if h : p a then by simp [Option.guard, h] else by simp [Option.guard, h]
|
||||
|
||||
@[deprecated guard_eq_some_iff (since := "2025-04-10")]
|
||||
abbrev guard_eq_some := @guard_eq_some_iff
|
||||
|
||||
@[simp, grind =] theorem isSome_guard : (Option.guard p a).isSome = p a :=
|
||||
if h : p a then by simp [Option.guard, h] else by simp [Option.guard, h]
|
||||
|
||||
@[deprecated isSome_guard (since := "2025-03-18")]
|
||||
abbrev guard_isSome := @isSome_guard
|
||||
|
||||
@[simp, grind =] theorem isNone_guard : (Option.guard p a).isNone = !p a := by
|
||||
rw [← not_isSome, isSome_guard]
|
||||
|
||||
@@ -724,23 +666,6 @@ theorem merge_eq_or_eq {f : α → α → α} (h : ∀ a b, f a b = a ∨ f a b
|
||||
@[simp, grind =] theorem merge_some_some {f} {a b : α} :
|
||||
merge f (some a) (some b) = some (f a b) := rfl
|
||||
|
||||
@[deprecated merge_eq_or_eq (since := "2025-04-04")]
|
||||
theorem liftOrGet_eq_or_eq {f : α → α → α} (h : ∀ a b, f a b = a ∨ f a b = b) :
|
||||
∀ o₁ o₂, merge f o₁ o₂ = o₁ ∨ merge f o₁ o₂ = o₂ :=
|
||||
merge_eq_or_eq h
|
||||
|
||||
@[deprecated merge_none_left (since := "2025-04-04")]
|
||||
theorem liftOrGet_none_left {f} {b : Option α} : merge f none b = b :=
|
||||
merge_none_left
|
||||
|
||||
@[deprecated merge_none_right (since := "2025-04-04")]
|
||||
theorem liftOrGet_none_right {f} {a : Option α} : merge f a none = a :=
|
||||
merge_none_right
|
||||
|
||||
@[deprecated merge_some_some (since := "2025-04-04")]
|
||||
theorem liftOrGet_some_some {f} {a b : α} : merge f (some a) (some b) = some (f a b) :=
|
||||
merge_some_some
|
||||
|
||||
instance commutative_merge (f : α → α → α) [Std.Commutative f] :
|
||||
Std.Commutative (merge f) :=
|
||||
⟨fun a b ↦ by cases a <;> cases b <;> simp [merge, Std.Commutative.comm]⟩
|
||||
@@ -861,9 +786,6 @@ grind_pattern isSome_choice_iff_nonempty => (choice α).isSome
|
||||
theorem isSome_choice [Nonempty α] : (choice α).isSome :=
|
||||
isSome_choice_iff_nonempty.2 inferInstance
|
||||
|
||||
@[deprecated isSome_choice_iff_nonempty (since := "2025-03-18")]
|
||||
abbrev choice_isSome_iff_nonempty := @isSome_choice_iff_nonempty
|
||||
|
||||
@[simp]
|
||||
theorem isNone_choice_eq_false [Nonempty α] : (choice α).isNone = false := by
|
||||
simp [← not_isSome]
|
||||
@@ -915,15 +837,9 @@ theorem or_eq_bif : or o o' = bif o.isSome then o else o' := by
|
||||
@[simp] theorem or_eq_none_iff : or o o' = none ↔ o = none ∧ o' = none := by
|
||||
cases o <;> simp
|
||||
|
||||
@[deprecated or_eq_none_iff (since := "2025-04-10")]
|
||||
abbrev or_eq_none := @or_eq_none_iff
|
||||
|
||||
@[simp] theorem or_eq_some_iff : or o o' = some a ↔ o = some a ∨ (o = none ∧ o' = some a) := by
|
||||
cases o <;> simp
|
||||
|
||||
@[deprecated or_eq_some_iff (since := "2025-04-10")]
|
||||
abbrev or_eq_some := @or_eq_some_iff
|
||||
|
||||
@[grind _=_] theorem or_assoc : or (or o₁ o₂) o₃ = or o₁ (or o₂ o₃) := by
|
||||
cases o₁ <;> cases o₂ <;> rfl
|
||||
instance : Std.Associative (or (α := α)) := ⟨@or_assoc _⟩
|
||||
@@ -943,9 +859,6 @@ instance : Std.IdempotentOp (or (α := α)) := ⟨@or_self _⟩
|
||||
@[grind _=_] theorem map_or : (or o o').map f = (o.map f).or (o'.map f) := by
|
||||
cases o <;> rfl
|
||||
|
||||
@[deprecated map_or (since := "2025-04-10")]
|
||||
abbrev map_or' := @map_or
|
||||
|
||||
theorem or_of_isSome {o o' : Option α} (h : o.isSome) : o.or o' = o := by
|
||||
match o, h with
|
||||
| some _, _ => simp
|
||||
@@ -1227,11 +1140,6 @@ theorem isNone_pbind_iff {o : Option α} {f : (a : α) → o = some a → Option
|
||||
(o.pbind f).isNone ↔ o = none ∨ ∃ a h, f a h = none := by
|
||||
cases o <;> simp
|
||||
|
||||
@[deprecated "isSome_pbind_iff" (since := "2025-04-01")]
|
||||
theorem pbind_isSome {o : Option α} {f : (a : α) → o = some a → Option β} :
|
||||
(o.pbind f).isSome = ∃ a h, (f a h).isSome := by
|
||||
exact propext isSome_pbind_iff
|
||||
|
||||
theorem pbind_eq_some_iff {o : Option α} {f : (a : α) → o = some a → Option β} {b : β} :
|
||||
o.pbind f = some b ↔ ∃ a h, f a h = some b := by
|
||||
cases o <;> simp
|
||||
@@ -1281,8 +1189,6 @@ theorem get_pbind {o : Option α} {f : (a : α) → o = some a → Option β} {h
|
||||
(pmap f o h).isNone = o.isNone := by
|
||||
cases o <;> simp
|
||||
|
||||
@[deprecated isSome_pmap (since := "2025-04-01")] abbrev pmap_isSome := @isSome_pmap
|
||||
|
||||
@[simp] theorem pmap_eq_some_iff {p : α → Prop} {f : ∀ (a : α), p a → β} {o : Option α} {h} :
|
||||
pmap f o h = some b ↔ ∃ (a : α) (h : p a), o = some a ∧ b = f a h := by
|
||||
cases o with
|
||||
|
||||
@@ -1011,7 +1011,6 @@ theorem intCast_neg_iff {a : Int} :
|
||||
/--
|
||||
Alternative statement of `ofScientific_def`.
|
||||
-/
|
||||
@[grind =]
|
||||
theorem ofScientific_def' :
|
||||
(OfScientific.ofScientific m s e : Rat) = m * (10 ^ (if s then -e else e : Int)) := by
|
||||
change Rat.ofScientific _ _ _ = _
|
||||
@@ -1023,6 +1022,13 @@ theorem ofScientific_def' :
|
||||
· push_cast
|
||||
rfl
|
||||
|
||||
theorem ofScientific_def_eq_if :
|
||||
(OfScientific.ofScientific m s e : Rat) = if s then (m : Rat) / (10 : Rat) ^ e else (m : Rat) * (10 : Rat) ^ e := by
|
||||
simp [ofScientific_def']
|
||||
split
|
||||
next => rw [Rat.zpow_neg, ← Rat.div_def, Rat.zpow_natCast]
|
||||
next => rw [Rat.zpow_natCast]
|
||||
|
||||
/-!
|
||||
# min and max
|
||||
-/
|
||||
|
||||
@@ -59,28 +59,6 @@ declare_int_theorems Int32 32
|
||||
declare_int_theorems Int64 64
|
||||
declare_int_theorems ISize System.Platform.numBits
|
||||
|
||||
@[deprecated Int8.le_iff_toBitVec_sle (since := "2025-03-20")]
|
||||
theorem Int8.le_def {a b : Int8} : a ≤ b ↔ a.toBitVec.sle b.toBitVec := Iff.rfl
|
||||
@[deprecated Int16.le_iff_toBitVec_sle (since := "2025-03-20")]
|
||||
theorem Int16.le_def {a b : Int16} : a ≤ b ↔ a.toBitVec.sle b.toBitVec := Iff.rfl
|
||||
@[deprecated Int32.le_iff_toBitVec_sle (since := "2025-03-20")]
|
||||
theorem Int32.le_def {a b : Int32} : a ≤ b ↔ a.toBitVec.sle b.toBitVec := Iff.rfl
|
||||
@[deprecated Int64.le_iff_toBitVec_sle (since := "2025-03-20")]
|
||||
theorem Int64.le_def {a b : Int64} : a ≤ b ↔ a.toBitVec.sle b.toBitVec := Iff.rfl
|
||||
@[deprecated ISize.le_iff_toBitVec_sle (since := "2025-03-20")]
|
||||
theorem ISize.le_def {a b : ISize} : a ≤ b ↔ a.toBitVec.sle b.toBitVec := Iff.rfl
|
||||
|
||||
@[deprecated Int8.lt_iff_toBitVec_slt (since := "2025-03-20")]
|
||||
theorem Int8.lt_def {a b : Int8} : a < b ↔ a.toBitVec.slt b.toBitVec := Iff.rfl
|
||||
@[deprecated Int16.lt_iff_toBitVec_slt (since := "2025-03-20")]
|
||||
theorem Int16.lt_def {a b : Int16} : a < b ↔ a.toBitVec.slt b.toBitVec := Iff.rfl
|
||||
@[deprecated Int32.lt_iff_toBitVec_slt (since := "2025-03-20")]
|
||||
theorem Int32.lt_def {a b : Int32} : a < b ↔ a.toBitVec.slt b.toBitVec := Iff.rfl
|
||||
@[deprecated Int64.lt_iff_toBitVec_slt (since := "2025-03-20")]
|
||||
theorem Int64.lt_def {a b : Int64} : a < b ↔ a.toBitVec.slt b.toBitVec := Iff.rfl
|
||||
@[deprecated ISize.lt_iff_toBitVec_slt (since := "2025-03-20")]
|
||||
theorem ISize.lt_def {a b : ISize} : a < b ↔ a.toBitVec.slt b.toBitVec := Iff.rfl
|
||||
|
||||
theorem Int8.toInt.inj {x y : Int8} (h : x.toInt = y.toInt) : x = y := Int8.toBitVec.inj (BitVec.eq_of_toInt_eq h)
|
||||
theorem Int8.toInt_inj {x y : Int8} : x.toInt = y.toInt ↔ x = y := ⟨Int8.toInt.inj, fun h => h ▸ rfl⟩
|
||||
theorem Int16.toInt.inj {x y : Int16} (h : x.toInt = y.toInt) : x = y := Int16.toBitVec.inj (BitVec.eq_of_toInt_eq h)
|
||||
|
||||
@@ -9,6 +9,7 @@ prelude
|
||||
public import Init.Data.String.Basic
|
||||
public import Init.Data.String.Bootstrap
|
||||
public import Init.Data.String.Decode
|
||||
public import Init.Data.String.Defs
|
||||
public import Init.Data.String.Extra
|
||||
public import Init.Data.String.Lemmas
|
||||
public import Init.Data.String.Repr
|
||||
@@ -19,3 +20,5 @@ public import Init.Data.String.Stream
|
||||
public import Init.Data.String.PosRaw
|
||||
public import Init.Data.String.Substring
|
||||
public import Init.Data.String.TakeDrop
|
||||
public import Init.Data.String.Modify
|
||||
public import Init.Data.String.Termination
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -11,6 +11,14 @@ import Init.Data.Char.Lemmas
|
||||
public import Init.Data.ByteArray.Basic
|
||||
import Init.Data.ByteArray.Lemmas
|
||||
|
||||
/-!
|
||||
# UTF-8 decoding
|
||||
|
||||
This file contains the low-level proof that UTF-8 decoding and encoding are inverses.
|
||||
An important corollary is that attempting to decode a byte array that is valid UTF-8 will
|
||||
succeed, which is required for the definition of `String.toList`.
|
||||
-/
|
||||
|
||||
/-! # `Char.utf8Size` -/
|
||||
|
||||
public theorem Char.utf8Size_eq_one_iff {c : Char} : c.utf8Size = 1 ↔ c.val ≤ 127 := by
|
||||
@@ -182,7 +190,7 @@ theorem String.toBitVec_getElem_utf8EncodeChar_zero_of_utf8Size_eq_one {c : Char
|
||||
simpa [Char.utf8Size_eq_one_iff, UInt32.le_iff_toNat_le] using h
|
||||
have h₁ : c.val.toNat < 256 := by omega
|
||||
rw [← BitVec.toNat_inj, BitVec.toNat_append]
|
||||
simp [utf8EncodeChar_eq_singleton h, Nat.mod_eq_of_lt h₀, Nat.mod_eq_of_lt h₁]
|
||||
simp [-Char.toUInt8_val, utf8EncodeChar_eq_singleton h, Nat.mod_eq_of_lt h₀, Nat.mod_eq_of_lt h₁]
|
||||
|
||||
/-! ### Size two -/
|
||||
|
||||
@@ -495,7 +503,8 @@ theorem assemble₁_eq_some_iff_utf8EncodeChar_eq {w : UInt8} {c : Char} :
|
||||
have : c.val.toNat < 256 := by
|
||||
simp only [Char.utf8Size_eq_one_iff, UInt32.le_iff_toNat_le, UInt32.reduceToNat] at hc
|
||||
omega
|
||||
simpa [String.utf8EncodeChar_eq_singleton hc, assemble₁, Char.ext_iff, ← UInt32.toNat_inj]
|
||||
simpa [String.utf8EncodeChar_eq_singleton hc, assemble₁, Char.ext_iff, ← UInt32.toNat_inj,
|
||||
-Char.toUInt8_val]
|
||||
|
||||
@[inline, expose]
|
||||
public def verify₁ (_w : UInt8) (_h : parseFirstByte w = .done) : Bool :=
|
||||
|
||||
595
src/Init/Data/String/Defs.lean
Normal file
595
src/Init/Data/String/Defs.lean
Normal file
@@ -0,0 +1,595 @@
|
||||
/-
|
||||
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.ByteArray.Basic
|
||||
public import Init.Data.String.PosRaw
|
||||
import Init.Data.ByteArray.Lemmas
|
||||
|
||||
/-!
|
||||
# Preliminary developments for strings
|
||||
|
||||
This file contains the material about strings which we can write down without the results in
|
||||
`Init.Data.String.Decode`, i.e., without knowing about the bijection between `String` and
|
||||
`List Char` given by UTF-8 decoding and encoding.
|
||||
|
||||
Note that this file, despite being called `Defs`, contains quite a few lemmas.
|
||||
-/
|
||||
|
||||
public section
|
||||
|
||||
@[simp]
|
||||
theorem List.utf8Encode_nil : List.utf8Encode [] = ByteArray.empty := by simp [utf8Encode]
|
||||
|
||||
theorem List.utf8Encode_singleton {c : Char} : [c].utf8Encode = (String.utf8EncodeChar c).toByteArray := by
|
||||
simp [utf8Encode]
|
||||
|
||||
@[simp]
|
||||
theorem List.utf8Encode_append {l l' : List Char} :
|
||||
(l ++ l').utf8Encode = l.utf8Encode ++ l'.utf8Encode := by
|
||||
simp [utf8Encode]
|
||||
|
||||
theorem List.utf8Encode_cons {c : Char} {l : List Char} : (c :: l).utf8Encode = [c].utf8Encode ++ l.utf8Encode := by
|
||||
rw [← singleton_append, List.utf8Encode_append]
|
||||
|
||||
@[simp]
|
||||
theorem String.utf8EncodeChar_ne_nil {c : Char} : String.utf8EncodeChar c ≠ [] := by
|
||||
fun_cases String.utf8EncodeChar with simp
|
||||
|
||||
@[simp]
|
||||
theorem List.utf8Encode_eq_empty {l : List Char} : l.utf8Encode = ByteArray.empty ↔ l = [] := by
|
||||
simp [utf8Encode, ← List.eq_nil_iff_forall_not_mem]
|
||||
|
||||
theorem ByteArray.isValidUTF8_utf8Encode {l : List Char} : IsValidUTF8 l.utf8Encode :=
|
||||
.intro l rfl
|
||||
|
||||
@[simp]
|
||||
theorem ByteArray.isValidUTF8_empty : IsValidUTF8 ByteArray.empty :=
|
||||
.intro [] (by simp)
|
||||
|
||||
theorem Char.isValidUTF8_toByteArray_utf8EncodeChar {c : Char} :
|
||||
ByteArray.IsValidUTF8 (String.utf8EncodeChar c).toByteArray :=
|
||||
.intro [c] (by simp [List.utf8Encode_singleton])
|
||||
|
||||
theorem ByteArray.IsValidUTF8.append {b b' : ByteArray} (h : IsValidUTF8 b) (h' : IsValidUTF8 b') :
|
||||
IsValidUTF8 (b ++ b') := by
|
||||
rcases h with ⟨m, rfl⟩
|
||||
rcases h' with ⟨m', rfl⟩
|
||||
exact .intro (m ++ m') (by simp)
|
||||
|
||||
/--
|
||||
Decodes an array of bytes that encode a string as [UTF-8](https://en.wikipedia.org/wiki/UTF-8) into
|
||||
the corresponding string.
|
||||
-/
|
||||
@[inline, expose]
|
||||
def String.fromUTF8 (a : @& ByteArray) (h : a.IsValidUTF8) : String :=
|
||||
.ofByteArray a h
|
||||
|
||||
/--
|
||||
Encodes a string in UTF-8 as an array of bytes.
|
||||
-/
|
||||
@[extern "lean_string_to_utf8"]
|
||||
def String.toUTF8 (a : @& String) : ByteArray :=
|
||||
a.bytes
|
||||
|
||||
@[simp] theorem String.toUTF8_eq_bytes {s : String} : s.toUTF8 = s.bytes := (rfl)
|
||||
|
||||
@[simp] theorem String.bytes_empty : "".bytes = ByteArray.empty := (rfl)
|
||||
|
||||
/--
|
||||
Appends two strings. Usually accessed via the `++` operator.
|
||||
|
||||
The internal implementation will perform destructive updates if the string is not shared.
|
||||
|
||||
Examples:
|
||||
* `"abc".append "def" = "abcdef"`
|
||||
* `"abc" ++ "def" = "abcdef"`
|
||||
* `"" ++ "" = ""`
|
||||
-/
|
||||
@[extern "lean_string_append", expose]
|
||||
def String.append (s : String) (t : @& String) : String where
|
||||
bytes := s.bytes ++ t.bytes
|
||||
isValidUTF8 := s.isValidUTF8.append t.isValidUTF8
|
||||
|
||||
instance : Append String where
|
||||
append s t := s.append t
|
||||
|
||||
@[simp]
|
||||
theorem String.bytes_append {s t : String} : (s ++ t).bytes = s.bytes ++ t.bytes := (rfl)
|
||||
|
||||
theorem String.bytes_inj {s t : String} : s.bytes = t.bytes ↔ s = t := by
|
||||
refine ⟨fun h => ?_, (· ▸ rfl)⟩
|
||||
rcases s with ⟨s⟩
|
||||
rcases t with ⟨t⟩
|
||||
subst h
|
||||
rfl
|
||||
|
||||
@[simp] theorem List.bytes_asString {l : List Char} : l.asString.bytes = l.utf8Encode := by
|
||||
simp [List.asString, String.mk]
|
||||
|
||||
theorem String.exists_eq_asString (s : String) :
|
||||
∃ l : List Char, s = l.asString := by
|
||||
rcases s with ⟨_, ⟨l, rfl⟩⟩
|
||||
refine ⟨l, by simp [← String.bytes_inj]⟩
|
||||
|
||||
@[simp]
|
||||
theorem String.utf8ByteSize_empty : "".utf8ByteSize = 0 := (rfl)
|
||||
|
||||
@[simp]
|
||||
theorem String.utf8ByteSize_append {s t : String} :
|
||||
(s ++ t).utf8ByteSize = s.utf8ByteSize + t.utf8ByteSize := by
|
||||
simp [utf8ByteSize]
|
||||
|
||||
@[simp]
|
||||
theorem String.size_bytes {s : String} : s.bytes.size = s.utf8ByteSize := rfl
|
||||
|
||||
@[simp]
|
||||
theorem String.bytes_push {s : String} {c : Char} : (s.push c).bytes = s.bytes ++ [c].utf8Encode := by
|
||||
simp [push]
|
||||
|
||||
namespace String
|
||||
|
||||
@[deprecated rawEndPos (since := "2025-10-20")]
|
||||
def endPos (s : String) : String.Pos.Raw :=
|
||||
s.rawEndPos
|
||||
|
||||
/-- The start position of the string, as a `String.Pos.Raw.` -/
|
||||
def rawStartPos (_s : String) : String.Pos.Raw :=
|
||||
0
|
||||
|
||||
@[simp]
|
||||
theorem rawStartPos_eq {s : String} : s.rawStartPos = 0 := (rfl)
|
||||
|
||||
@[simp]
|
||||
theorem byteIdx_rawEndPos {s : String} : s.rawEndPos.byteIdx = s.utf8ByteSize := rfl
|
||||
|
||||
@[deprecated byteIdx_rawEndPos (since := "2025-10-20")]
|
||||
theorem byteIdx_endPos {s : String} : s.rawEndPos.byteIdx = s.utf8ByteSize := rfl
|
||||
|
||||
@[simp]
|
||||
theorem utf8ByteSize_ofByteArray {b : ByteArray} {h} :
|
||||
(String.ofByteArray b h).utf8ByteSize = b.size := rfl
|
||||
|
||||
@[simp]
|
||||
theorem bytes_singleton {c : Char} : (String.singleton c).bytes = [c].utf8Encode := by
|
||||
simp [singleton]
|
||||
|
||||
theorem singleton_eq_asString {c : Char} : String.singleton c = [c].asString := by
|
||||
simp [← String.bytes_inj]
|
||||
|
||||
@[simp]
|
||||
theorem append_singleton {s : String} {c : Char} : s ++ singleton c = s.push c := by
|
||||
simp [← bytes_inj]
|
||||
|
||||
@[simp]
|
||||
theorem append_left_inj {s₁ s₂ : String} (t : String) :
|
||||
s₁ ++ t = s₂ ++ t ↔ s₁ = s₂ := by
|
||||
simp [← bytes_inj]
|
||||
|
||||
theorem append_assoc {s₁ s₂ s₃ : String} : s₁ ++ s₂ ++ s₃ = s₁ ++ (s₂ ++ s₃) := by
|
||||
simp [← bytes_inj, ByteArray.append_assoc]
|
||||
|
||||
@[simp]
|
||||
theorem utf8ByteSize_eq_zero_iff {s : String} : s.utf8ByteSize = 0 ↔ s = "" := by
|
||||
refine ⟨fun h => ?_, fun h => h ▸ utf8ByteSize_empty⟩
|
||||
simpa [← bytes_inj, ← ByteArray.size_eq_zero_iff] using h
|
||||
|
||||
theorem rawEndPos_eq_zero_iff {b : String} : b.rawEndPos = 0 ↔ b = "" := by
|
||||
simp
|
||||
|
||||
@[deprecated rawEndPos_eq_zero_iff (since := "2025-10-20")]
|
||||
theorem endPos_eq_zero_iff {b : String} : b.rawEndPos = 0 ↔ b = "" :=
|
||||
rawEndPos_eq_zero_iff
|
||||
|
||||
/--
|
||||
Adds multiple repetitions of a character to the end of a string.
|
||||
|
||||
Returns `s`, with `n` repetitions of `c` at the end. Internally, the implementation repeatedly calls
|
||||
`String.push`, so the string is modified in-place if there is a unique reference to it.
|
||||
|
||||
Examples:
|
||||
* `"indeed".pushn '!' 2 = "indeed!!"`
|
||||
* `"indeed".pushn '!' 0 = "indeed"`
|
||||
* `"".pushn ' ' 4 = " "`
|
||||
-/
|
||||
@[inline] def pushn (s : String) (c : Char) (n : Nat) : String :=
|
||||
n.repeat (fun s => s.push c) s
|
||||
|
||||
theorem pushn_eq_repeat_push {s : String} {c : Char} {n : Nat} :
|
||||
s.pushn c n = n.repeat (fun s => s.push c) s := (rfl)
|
||||
|
||||
@[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.
|
||||
|
||||
Empty strings are equal to `""` and have length and end position `0`.
|
||||
|
||||
Examples:
|
||||
* `"".isEmpty = true`
|
||||
* `"empty".isEmpty = false`
|
||||
* `" ".isEmpty = false`
|
||||
-/
|
||||
@[inline] def isEmpty (s : String) : Bool :=
|
||||
s.utf8ByteSize == 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.
|
||||
|
||||
Use `String.intercalate` to place a separator string between the strings in a list.
|
||||
|
||||
Examples:
|
||||
* `String.join ["gr", "ee", "n"] = "green"`
|
||||
* `String.join ["b", "", "l", "", "ue"] = "blue"`
|
||||
* `String.join [] = ""`
|
||||
-/
|
||||
@[inline] def join (l : List String) : String :=
|
||||
l.foldl (fun r s => r ++ s) ""
|
||||
|
||||
/--
|
||||
Appends the strings in a list of strings, placing the separator `s` between each pair.
|
||||
|
||||
Examples:
|
||||
* `", ".intercalate ["red", "green", "blue"] = "red, green, blue"`
|
||||
* `" and ".intercalate ["tea", "coffee"] = "tea and coffee"`
|
||||
* `" | ".intercalate ["M", "", "N"] = "M | | N"`
|
||||
-/
|
||||
def intercalate (s : String) : List String → String
|
||||
| [] => ""
|
||||
| a :: as => go a s as
|
||||
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
|
||||
|
||||
/--
|
||||
Predicate for validity of positions inside a `String`.
|
||||
|
||||
There are multiple equivalent definitions for validity.
|
||||
|
||||
We say that a position is valid if the string obtained by taking all of the bytes up to, but
|
||||
excluding, the given position, is valid UTF-8; see `Pos.isValid_iff_isValidUTF8_extract_zero`.
|
||||
|
||||
Similarly, a position is valid if the string obtained by taking all of the bytes starting at the
|
||||
given position is valid UTF-8; see `Pos.isValid_iff_isValidUTF8_extract_utf8ByteSize`.
|
||||
|
||||
An equivalent condition is that the position is the length of the UTF-8 encoding of
|
||||
some prefix of the characters of the string; see `Pos.isValid_iff_exists_append` and
|
||||
`Pos.isValid_iff_exists_take_data`.
|
||||
|
||||
Another equivalent condition that can be checked efficiently is that the position is either the
|
||||
end position or strictly smaller than the end position and the byte at the position satisfies
|
||||
`UInt8.IsUTF8FirstByte`; see `Pos.isValid_iff_isUTF8FirstByte`.
|
||||
|
||||
Examples:
|
||||
* `String.Pos.IsValid "abc" ⟨0⟩`
|
||||
* `String.Pos.IsValid "abc" ⟨1⟩`
|
||||
* `String.Pos.IsValid "abc" ⟨3⟩`
|
||||
* `¬ String.Pos.IsValid "abc" ⟨4⟩`
|
||||
* `String.Pos.IsValid "𝒫(A)" ⟨0⟩`
|
||||
* `¬ String.Pos.IsValid "𝒫(A)" ⟨1⟩`
|
||||
* `¬ String.Pos.IsValid "𝒫(A)" ⟨2⟩`
|
||||
* `¬ String.Pos.IsValid "𝒫(A)" ⟨3⟩`
|
||||
* `String.Pos.IsValid "𝒫(A)" ⟨4⟩`
|
||||
-/
|
||||
structure Pos.Raw.IsValid (s : String) (off : String.Pos.Raw) : Prop where private mk ::
|
||||
le_rawEndPos : off ≤ s.rawEndPos
|
||||
isValidUTF8_extract_zero : (s.bytes.extract 0 off.byteIdx).IsValidUTF8
|
||||
|
||||
theorem Pos.Raw.IsValid.le_utf8ByteSize {s : String} {off : String.Pos.Raw} (h : off.IsValid s) :
|
||||
off.byteIdx ≤ s.utf8ByteSize := by
|
||||
simpa [Pos.Raw.le_iff] using h.le_rawEndPos
|
||||
|
||||
theorem Pos.Raw.isValid_iff_isValidUTF8_extract_zero {s : String} {p : Pos.Raw} :
|
||||
p.IsValid s ↔ p ≤ s.rawEndPos ∧ (s.bytes.extract 0 p.byteIdx).IsValidUTF8 :=
|
||||
⟨fun ⟨h₁, h₂⟩ => ⟨h₁, h₂⟩, fun ⟨h₁, h₂⟩ => ⟨h₁, h₂⟩⟩
|
||||
|
||||
@[deprecated le_rawEndPos (since := "2025-10-20")]
|
||||
theorem Pos.Raw.IsValid.le_endPos {s : String} {off : String.Pos.Raw} (h : off.IsValid s) :
|
||||
off ≤ s.rawEndPos :=
|
||||
h.le_rawEndPos
|
||||
|
||||
@[simp]
|
||||
theorem Pos.Raw.isValid_zero {s : String} : (0 : Pos.Raw).IsValid s where
|
||||
le_rawEndPos := by simp [Pos.Raw.le_iff]
|
||||
isValidUTF8_extract_zero := by simp
|
||||
|
||||
@[simp]
|
||||
theorem Pos.Raw.isValid_rawEndPos {s : String} : s.rawEndPos.IsValid s where
|
||||
le_rawEndPos := by simp
|
||||
isValidUTF8_extract_zero := by simp [← size_bytes, s.isValidUTF8]
|
||||
|
||||
theorem Pos.Raw.isValid_of_eq_rawEndPos {s : String} {p : Pos.Raw} (h : p = s.rawEndPos) :
|
||||
p.IsValid s := by
|
||||
subst h
|
||||
exact isValid_rawEndPos
|
||||
|
||||
@[simp]
|
||||
theorem Pos.Raw.isValid_empty_iff {p : Pos.Raw} : p.IsValid "" ↔ p = 0 := by
|
||||
refine ⟨?_, ?_⟩
|
||||
· rintro ⟨h₁, h₂⟩
|
||||
simp only [le_iff, byteIdx_rawEndPos, utf8ByteSize_empty, Nat.le_zero_eq] at h₁
|
||||
ext
|
||||
omega
|
||||
· rintro rfl
|
||||
simp
|
||||
|
||||
/--
|
||||
A `ValidPos s` is a byte offset in `s` together with a proof that this position is at a UTF-8
|
||||
character boundary.
|
||||
-/
|
||||
@[ext]
|
||||
structure ValidPos (s : String) where
|
||||
/-- The underlying byte offset of the `ValidPos`. -/
|
||||
offset : Pos.Raw
|
||||
/-- The proof that `offset` is valid for the string `s`. -/
|
||||
isValid : offset.IsValid s
|
||||
deriving @[expose] DecidableEq
|
||||
|
||||
/-- The start position of `s`, as an `s.ValidPos`. -/
|
||||
@[inline, expose]
|
||||
def startValidPos (s : String) : s.ValidPos where
|
||||
offset := 0
|
||||
isValid := by simp
|
||||
|
||||
@[simp]
|
||||
theorem offset_startValidPos {s : String} : s.startValidPos.offset = 0 := (rfl)
|
||||
|
||||
instance {s : String} : Inhabited s.ValidPos where
|
||||
default := s.startValidPos
|
||||
|
||||
/-- The past-the-end position of `s`, as an `s.ValidPos`. -/
|
||||
@[inline, expose]
|
||||
def endValidPos (s : String) : s.ValidPos where
|
||||
offset := s.rawEndPos
|
||||
isValid := by simp
|
||||
|
||||
@[simp]
|
||||
theorem offset_endValidPos {s : String} : s.endValidPos.offset = s.rawEndPos := (rfl)
|
||||
|
||||
instance {s : String} : LE s.ValidPos where
|
||||
le l r := l.offset ≤ r.offset
|
||||
|
||||
instance {s : String} : LT s.ValidPos where
|
||||
lt l r := l.offset < r.offset
|
||||
|
||||
theorem ValidPos.le_iff {s : String} {l r : s.ValidPos} : l ≤ r ↔ l.offset ≤ r.offset :=
|
||||
Iff.rfl
|
||||
|
||||
theorem ValidPos.lt_iff {s : String} {l r : s.ValidPos} : l < r ↔ l.offset < r.offset :=
|
||||
Iff.rfl
|
||||
|
||||
instance {s : String} (l r : s.ValidPos) : Decidable (l ≤ r) :=
|
||||
decidable_of_iff' _ ValidPos.le_iff
|
||||
|
||||
instance {s : String} (l r : s.ValidPos) : Decidable (l < r) :=
|
||||
decidable_of_iff' _ ValidPos.lt_iff
|
||||
|
||||
/--
|
||||
A region or slice of some underlying string.
|
||||
|
||||
A slice consists of a string together with the start and end byte positions of a region of
|
||||
interest. Actually extracting a substring requires copying and memory allocation, while many
|
||||
slices of the same underlying string may exist with very little overhead. While this could be achieved by tracking the bounds by hand, the slice API is much more convenient.
|
||||
|
||||
`String.Slice` bundles proofs to ensure that the start and end positions always delineate a valid
|
||||
string. For this reason, it should be preferred over `Substring`.
|
||||
-/
|
||||
structure Slice where
|
||||
/-- The underlying strings. -/
|
||||
str : String
|
||||
/-- The byte position of the start of the string slice. -/
|
||||
startInclusive : str.ValidPos
|
||||
/-- The byte position of the end of the string slice. -/
|
||||
endExclusive : str.ValidPos
|
||||
/-- The slice is not degenerate (but it may be empty). -/
|
||||
startInclusive_le_endExclusive : startInclusive ≤ endExclusive
|
||||
|
||||
instance : Inhabited Slice where
|
||||
default := ⟨"", "".startValidPos, "".startValidPos, by simp [ValidPos.le_iff]⟩
|
||||
|
||||
/--
|
||||
Returns a slice that contains the entire string.
|
||||
-/
|
||||
@[inline, expose] -- expose for the defeq `s.toSlice.str = s`.
|
||||
def toSlice (s : String) : Slice where
|
||||
str := s
|
||||
startInclusive := s.startValidPos
|
||||
endExclusive := s.endValidPos
|
||||
startInclusive_le_endExclusive := by simp [ValidPos.le_iff, Pos.Raw.le_iff]
|
||||
|
||||
@[simp]
|
||||
theorem startInclusive_toSlice {s : String} : s.toSlice.startInclusive = s.startValidPos := rfl
|
||||
|
||||
@[simp]
|
||||
theorem endExclusive_toSlice {s : String} : s.toSlice.endExclusive = s.endValidPos := rfl
|
||||
|
||||
@[simp]
|
||||
theorem str_toSlice {s : String} : s.toSlice.str = s := rfl
|
||||
|
||||
/-- The number of bytes of the UTF-8 encoding of the string slice. -/
|
||||
@[expose]
|
||||
def Slice.utf8ByteSize (s : Slice) : Nat :=
|
||||
s.startInclusive.offset.byteDistance s.endExclusive.offset
|
||||
|
||||
theorem Slice.utf8ByteSize_eq {s : Slice} :
|
||||
s.utf8ByteSize = s.endExclusive.offset.byteIdx - s.startInclusive.offset.byteIdx := (rfl)
|
||||
|
||||
instance : HAdd Pos.Raw Slice Pos.Raw where
|
||||
hAdd p s := { byteIdx := p.byteIdx + s.utf8ByteSize }
|
||||
|
||||
instance : HAdd Slice Pos.Raw Pos.Raw where
|
||||
hAdd s p := { byteIdx := s.utf8ByteSize + p.byteIdx }
|
||||
|
||||
instance : HSub Pos.Raw Slice Pos.Raw where
|
||||
hSub p s := { byteIdx := p.byteIdx - s.utf8ByteSize }
|
||||
|
||||
@[simp]
|
||||
theorem Pos.Raw.byteIdx_add_slide {p : Pos.Raw} {s : Slice} :
|
||||
(p + s).byteIdx = p.byteIdx + s.utf8ByteSize := rfl
|
||||
|
||||
@[simp]
|
||||
theorem Pos.Raw.byteIdx_slice_add {s : Slice} {p : Pos.Raw} :
|
||||
(s + p).byteIdx = s.utf8ByteSize + p.byteIdx := rfl
|
||||
|
||||
@[simp]
|
||||
theorem Pos.Raw.byteIdx_sub_slice {p : Pos.Raw} {s : Slice} :
|
||||
(p - s).byteIdx = p.byteIdx - s.utf8ByteSize := rfl
|
||||
|
||||
/-- The end position of a slice, as a `Pos.Raw`. -/
|
||||
@[expose]
|
||||
def Slice.rawEndPos (s : Slice) : Pos.Raw where
|
||||
byteIdx := s.utf8ByteSize
|
||||
|
||||
@[simp]
|
||||
theorem Slice.byteIdx_rawEndPos {s : Slice} : s.rawEndPos.byteIdx = s.utf8ByteSize := (rfl)
|
||||
|
||||
/-- Criterion for validity of positions in string slices. -/
|
||||
structure Pos.Raw.IsValidForSlice (s : Slice) (p : Pos.Raw) : Prop where
|
||||
le_rawEndPos : p ≤ s.rawEndPos
|
||||
isValid_offsetBy : (p.offsetBy s.startInclusive.offset).IsValid s.str
|
||||
|
||||
theorem Pos.Raw.IsValidForSlice.le_utf8ByteSize {s : Slice} {p : Pos.Raw}
|
||||
(h : p.IsValidForSlice s) : p.byteIdx ≤ s.utf8ByteSize := by
|
||||
simpa [Pos.Raw.le_iff] using h.le_rawEndPos
|
||||
|
||||
/--
|
||||
Accesses the indicated byte in the UTF-8 encoding of a string slice.
|
||||
|
||||
At runtime, this function is implemented by efficient, constant-time code.
|
||||
-/
|
||||
@[inline, expose]
|
||||
def Slice.getUTF8Byte (s : Slice) (p : Pos.Raw) (h : p < s.rawEndPos) : UInt8 :=
|
||||
s.str.getUTF8Byte (p.offsetBy s.startInclusive.offset) (by
|
||||
have := s.endExclusive.isValid.le_rawEndPos
|
||||
simp only [Pos.Raw.lt_iff, byteIdx_rawEndPos, utf8ByteSize_eq, Pos.Raw.le_iff, byteIdx_rawEndPos,
|
||||
Pos.Raw.byteIdx_offsetBy] at *
|
||||
omega)
|
||||
|
||||
/--
|
||||
Accesses the indicated byte in the UTF-8 encoding of the string slice, or panics if the position
|
||||
is out-of-bounds.
|
||||
-/
|
||||
@[expose]
|
||||
def Slice.getUTF8Byte! (s : Slice) (p : String.Pos.Raw) : UInt8 :=
|
||||
if h : p < s.rawEndPos then
|
||||
s.getUTF8Byte p h
|
||||
else
|
||||
panic! "String slice access is out of bounds."
|
||||
|
||||
/--
|
||||
A `Slice.Pos s` is a byte offset in `s` together with a proof that this position is at a UTF-8
|
||||
character boundary.
|
||||
-/
|
||||
@[ext]
|
||||
structure Slice.Pos (s : Slice) where
|
||||
/-- The underlying byte offset of the `Slice.Pos`. -/
|
||||
offset : String.Pos.Raw
|
||||
/-- The proof that `offset` is valid for the string slice `s`. -/
|
||||
isValidForSlice : offset.IsValidForSlice s
|
||||
deriving @[expose] DecidableEq
|
||||
|
||||
/-- The start position of `s`, as an `s.Pos`. -/
|
||||
@[inline, expose]
|
||||
def Slice.startPos (s : Slice) : s.Pos where
|
||||
offset := 0
|
||||
isValidForSlice := ⟨by simp [Pos.Raw.le_iff], by simpa using s.startInclusive.isValid⟩
|
||||
|
||||
@[simp]
|
||||
theorem Slice.offset_startPos {s : Slice} : s.startPos.offset = 0 := (rfl)
|
||||
|
||||
instance {s : Slice} : Inhabited s.Pos where
|
||||
default := s.startPos
|
||||
|
||||
@[simp]
|
||||
theorem Slice.offset_startInclusive_add_self {s : Slice} :
|
||||
s.startInclusive.offset + s = s.endExclusive.offset := by
|
||||
have := s.startInclusive_le_endExclusive
|
||||
simp_all [String.Pos.Raw.ext_iff, ValidPos.le_iff, Pos.Raw.le_iff, utf8ByteSize_eq]
|
||||
|
||||
@[simp]
|
||||
theorem Pos.Raw.offsetBy_rawEndPos_left {p : Pos.Raw} {s : String} :
|
||||
s.rawEndPos.offsetBy p = p + s := by
|
||||
simp [Pos.Raw.ext_iff]
|
||||
|
||||
@[simp]
|
||||
theorem Pos.Raw.offsetBy_rawEndPos_right {p : Pos.Raw} {s : String} :
|
||||
p.offsetBy s.rawEndPos = s + p := by
|
||||
simp [Pos.Raw.ext_iff]
|
||||
|
||||
@[simp]
|
||||
theorem Pos.Raw.offsetBy_sliceRawEndPos_left {p : Pos.Raw} {s : Slice} :
|
||||
s.rawEndPos.offsetBy p = p + s := by
|
||||
simp [Pos.Raw.ext_iff]
|
||||
|
||||
@[simp]
|
||||
theorem Pos.Raw.offsetBy_sliceRawEndPos_right {p : Pos.Raw} {s : Slice} :
|
||||
p.offsetBy s.rawEndPos = s + p := by
|
||||
simp [Pos.Raw.ext_iff]
|
||||
|
||||
@[simp]
|
||||
theorem Pos.Raw.isValidForSlice_rawEndPos {s : Slice} : (s.rawEndPos).IsValidForSlice s where
|
||||
le_rawEndPos := by simp
|
||||
isValid_offsetBy := by simpa using s.endExclusive.isValid
|
||||
|
||||
theorem Pos.Raw.isValidForSlice_of_eq_rawEndPos {p : Pos.Raw} {s : Slice} (h : p = s.rawEndPos) :
|
||||
p.IsValidForSlice s := by
|
||||
subst h; simp
|
||||
|
||||
/-- The past-the-end position of `s`, as an `s.Pos`. -/
|
||||
@[inline, expose]
|
||||
def Slice.endPos (s : Slice) : s.Pos where
|
||||
offset := s.rawEndPos
|
||||
isValidForSlice := Pos.Raw.isValidForSlice_rawEndPos
|
||||
|
||||
@[simp]
|
||||
theorem Slice.offset_endPos {s : Slice} : s.endPos.offset = s.rawEndPos := (rfl)
|
||||
|
||||
instance {s : Slice} : LE s.Pos where
|
||||
le l r := l.offset ≤ r.offset
|
||||
|
||||
instance {s : Slice} : LT s.Pos where
|
||||
lt l r := l.offset < r.offset
|
||||
|
||||
theorem Slice.Pos.le_iff {s : Slice} {l r : s.Pos} : l ≤ r ↔ l.offset ≤ r.offset :=
|
||||
Iff.rfl
|
||||
|
||||
theorem Slice.Pos.lt_iff {s : Slice} {l r : s.Pos} : l < r ↔ l.offset < r.offset :=
|
||||
Iff.rfl
|
||||
|
||||
instance {s : Slice} (l r : s.Pos) : Decidable (l ≤ r) :=
|
||||
decidable_of_iff' _ Slice.Pos.le_iff
|
||||
|
||||
instance {s : Slice} (l r : s.Pos) : Decidable (l < r) :=
|
||||
decidable_of_iff' _ Slice.Pos.lt_iff
|
||||
|
||||
/-- Returns the byte at a position in a slice that is not the end position. -/
|
||||
@[inline, expose]
|
||||
def Slice.Pos.byte {s : Slice} (pos : s.Pos) (h : pos ≠ s.endPos) : UInt8 :=
|
||||
s.getUTF8Byte pos.offset (by
|
||||
have := pos.isValidForSlice.le_rawEndPos
|
||||
simp_all [Pos.ext_iff, String.Pos.Raw.ext_iff, Pos.Raw.le_iff, Pos.Raw.lt_iff]
|
||||
omega)
|
||||
|
||||
@[simp] theorem default_eq : default = "" := rfl
|
||||
|
||||
@[simp]
|
||||
theorem mk_eq_asString (s : List Char) : String.mk s = List.asString s := rfl
|
||||
|
||||
theorem push_eq_append (c : Char) : String.push s c = s ++ singleton c := by
|
||||
simp
|
||||
|
||||
end String
|
||||
@@ -12,6 +12,7 @@ import all Init.Data.String.Basic
|
||||
public import Init.Data.String.Iterator
|
||||
import all Init.Data.String.Iterator
|
||||
public import Init.Data.String.Substring
|
||||
public import Init.Data.String.Modify
|
||||
|
||||
public section
|
||||
|
||||
@@ -79,6 +80,16 @@ macro_rules
|
||||
|
||||
namespace Iterator
|
||||
|
||||
/--
|
||||
Replaces the current character in the string.
|
||||
|
||||
Does nothing if the iterator is at the end of the string. If both the replacement character and the
|
||||
replaced character are 7-bit ASCII characters and the string is not shared, then it is updated
|
||||
in-place and not copied.
|
||||
-/
|
||||
@[inline] def setCurr : Iterator → Char → Iterator
|
||||
| ⟨s, i⟩, c => ⟨i.set s c, i⟩
|
||||
|
||||
/--
|
||||
Moves the iterator forward until the Boolean predicate `p` returns `true` for the iterator's current
|
||||
character or until the end of the string is reached. Does nothing if the current character already
|
||||
|
||||
@@ -144,16 +144,6 @@ This function is faster that `String.Iterator.next` due to avoiding a run-time b
|
||||
match it with
|
||||
| ⟨s, i⟩ => ⟨s, i.next' s (by simpa only [hasNext, rawEndPos, decide_eq_true_eq, Pos.Raw.atEnd, ge_iff_le, Nat.not_le] using h)⟩
|
||||
|
||||
/--
|
||||
Replaces the current character in the string.
|
||||
|
||||
Does nothing if the iterator is at the end of the string. If both the replacement character and the
|
||||
replaced character are 7-bit ASCII characters and the string is not shared, then it is updated
|
||||
in-place and not copied.
|
||||
-/
|
||||
@[inline] def setCurr : Iterator → Char → Iterator
|
||||
| ⟨s, i⟩, c => ⟨i.set s c, i⟩
|
||||
|
||||
/--
|
||||
Moves the iterator's position to the end of the string, just past the last character.
|
||||
-/
|
||||
|
||||
@@ -6,6 +6,7 @@ Authors: Leonardo de Moura
|
||||
module
|
||||
|
||||
prelude
|
||||
public import Init.Data.String.Lemmas.Splits
|
||||
public import Init.Data.Char.Order
|
||||
public import Init.Data.Char.Lemmas
|
||||
public import Init.Data.List.Lex
|
||||
|
||||
92
src/Init/Data/String/Lemmas/Splits.lean
Normal file
92
src/Init/Data/String/Lemmas/Splits.lean
Normal file
@@ -0,0 +1,92 @@
|
||||
/-
|
||||
Copyright (c) 2025 Lean FRO, LLC. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Author: Markus Himmel
|
||||
-/
|
||||
module
|
||||
|
||||
prelude
|
||||
public import Init.Data.String.Basic
|
||||
import Init.Data.ByteArray.Lemmas
|
||||
|
||||
/-!
|
||||
# `Splits` predicates on `String.ValidPos` and `String.Slice.Pos`.
|
||||
|
||||
We introduce the predicate `p.Splits t₁ t₂` for a position `p` on a string or slice `s`, which means
|
||||
that `s = t₁ ++ t₂` with `p` lying between the two parts. This is a useful primitive when verifying
|
||||
string operations.
|
||||
-/
|
||||
|
||||
public section
|
||||
|
||||
namespace String
|
||||
|
||||
/--
|
||||
We say that `p` splits `s` into `t₁` and `t₂` if `s = t₁ ++ t₂` and `p` is the position between `t₁`
|
||||
and `t₂`.
|
||||
-/
|
||||
structure ValidPos.Splits {s : String} (p : s.ValidPos) (t₁ t₂ : String) : Prop where
|
||||
eq_append : s = t₁ ++ t₂
|
||||
offset_eq_rawEndPos : p.offset = t₁.rawEndPos
|
||||
|
||||
/--
|
||||
We say that `p` splits `s` into `t₁` and `t₂` if `s = t₁ ++ t₂` and `p` is the position between `t₁`
|
||||
and `t₂`.
|
||||
-/
|
||||
structure Slice.Pos.Splits {s : Slice} (p : s.Pos) (t₁ t₂ : String) : Prop where
|
||||
eq_append : s.copy = t₁ ++ t₂
|
||||
offset_eq_rawEndPos : p.offset = t₁.rawEndPos
|
||||
|
||||
@[simp]
|
||||
theorem ValidPos.splits_cast_iff {s₁ s₂ : String} {h : s₁ = s₂} {p : s₁.ValidPos} {t₁ t₂ : String} :
|
||||
(p.cast h).Splits t₁ t₂ ↔ p.Splits t₁ t₂ := by
|
||||
subst h; simp
|
||||
|
||||
theorem ValidPos.Splits.cast {s₁ s₂ : String} {p : s₁.ValidPos} {t₁ t₂ : String} (h : s₁ = s₂) :
|
||||
p.Splits t₁ t₂ → (p.cast h).Splits t₁ t₂ :=
|
||||
splits_cast_iff.mpr
|
||||
|
||||
@[simp]
|
||||
theorem Slice.Pos.splits_cast_iff {s₁ s₂ : Slice} {h : s₁ = s₂} {p : s₁.Pos} {t₁ t₂ : String} :
|
||||
(p.cast h).Splits t₁ t₂ ↔ p.Splits t₁ t₂ := by
|
||||
subst h; simp
|
||||
|
||||
theorem Slice.Pos.Splits.cast {s₁ s₂ : Slice} {p : s₁.Pos} {t₁ t₂ : String} (h : s₁ = s₂) :
|
||||
p.Splits t₁ t₂ → (p.cast h).Splits t₁ t₂ :=
|
||||
splits_cast_iff.mpr
|
||||
|
||||
theorem Slice.Pos.Splits.toCopy {s : Slice} {p : s.Pos} {t₁ t₂ : String}
|
||||
(h : p.Splits t₁ t₂) : p.toCopy.Splits t₁ t₂ where
|
||||
eq_append := h.eq_append
|
||||
offset_eq_rawEndPos := by simpa using h.offset_eq_rawEndPos
|
||||
|
||||
theorem Slice.Pos.splits_of_splits_toCopy {s : Slice} {p : s.Pos} {t₁ t₂ : String}
|
||||
(h : p.toCopy.Splits t₁ t₂) : p.Splits t₁ t₂ where
|
||||
eq_append := h.eq_append
|
||||
offset_eq_rawEndPos := by simpa using h.offset_eq_rawEndPos
|
||||
|
||||
@[simp]
|
||||
theorem Slice.Pos.splits_toCopy_iff {s : Slice} {p : s.Pos} {t₁ t₂ : String} :
|
||||
p.toCopy.Splits t₁ t₂ ↔ p.Splits t₁ t₂ :=
|
||||
⟨splits_of_splits_toCopy, (·.toCopy)⟩
|
||||
|
||||
@[simp]
|
||||
theorem ValidPos.splits_toSlice_iff {s : String} {p : s.ValidPos} {t₁ t₂ : String} :
|
||||
p.toSlice.Splits t₁ t₂ ↔ p.Splits t₁ t₂ := by
|
||||
rw [← Slice.Pos.splits_toCopy_iff, p.toCopy_toSlice_eq_cast, splits_cast_iff]
|
||||
|
||||
theorem ValidPos.Splits.toSlice {s : String} {p : s.ValidPos} {t₁ t₂ : String}
|
||||
(h : p.Splits t₁ t₂) : p.toSlice.Splits t₁ t₂ :=
|
||||
splits_toSlice_iff.mpr h
|
||||
|
||||
theorem ValidPos.splits {s : String} (p : s.ValidPos) :
|
||||
p.Splits (s.replaceEnd p).copy (s.replaceStart p).copy where
|
||||
eq_append := by simp [← bytes_inj, Slice.bytes_copy, ← size_bytes]
|
||||
offset_eq_rawEndPos := by simp
|
||||
|
||||
theorem Slice.Pos.splits {s : Slice} (p : s.Pos) :
|
||||
p.Splits (s.replaceEnd p).copy (s.replaceStart p).copy where
|
||||
eq_append := copy_eq_copy_replaceEnd
|
||||
offset_eq_rawEndPos := by simp
|
||||
|
||||
end String
|
||||
294
src/Init/Data/String/Modify.lean
Normal file
294
src/Init/Data/String/Modify.lean
Normal file
@@ -0,0 +1,294 @@
|
||||
/-
|
||||
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.String.Termination
|
||||
import Init.Data.ByteArray.Lemmas
|
||||
import Init.Data.Char.Lemmas
|
||||
|
||||
/-!
|
||||
# Modification operations on strings
|
||||
|
||||
This file contains operations on strings which modify the string, like `set` or `map`.
|
||||
There will usually not be a `String.Slice` version of these operations.
|
||||
-/
|
||||
|
||||
public section
|
||||
|
||||
namespace String
|
||||
|
||||
/--
|
||||
Replaces the character at a specified position in a string with a new character.
|
||||
|
||||
If both the replacement character and the replaced character are 7-bit ASCII characters and the
|
||||
string is not shared, then it is updated in-place and not copied.
|
||||
|
||||
Examples:
|
||||
* `("abc".pos ⟨1⟩ (by decide)).set 'B' (by decide) = "aBc"`
|
||||
* `("L∃∀N".pos ⟨4⟩ (by decide)).set 'X' (by decide) = "L∃XN"`
|
||||
-/
|
||||
@[extern "lean_string_utf8_set", expose]
|
||||
def ValidPos.set {s : String} (p : s.ValidPos) (c : Char) (hp : p ≠ s.endValidPos) : String :=
|
||||
if hc : c.utf8Size = 1 ∧ (p.byte hp).utf8ByteSize isUTF8FirstByte_byte = 1 then
|
||||
.ofByteArray (s.bytes.set p.offset.byteIdx c.toUInt8 (p.byteIdx_lt_utf8ByteSize hp)) (by
|
||||
rw [ByteArray.set_eq_push_extract_append_extract, ← hc.2, utf8ByteSize_byte,
|
||||
← ValidPos.byteIdx_offset_next]
|
||||
refine ByteArray.IsValidUTF8.append ?_ (p.next hp).isValid.isValidUTF8_extract_utf8ByteSize
|
||||
exact p.isValid.isValidUTF8_extract_zero.push hc.1)
|
||||
else
|
||||
(s.replaceEnd p).copy ++ singleton c ++ (s.replaceStart (p.next hp)).copy
|
||||
|
||||
theorem ValidPos.set_eq_append {s : String} {p : s.ValidPos} {c : Char} {hp} :
|
||||
p.set c hp = (s.replaceEnd p).copy ++ singleton c ++ (s.replaceStart (p.next hp)).copy := by
|
||||
rw [set]
|
||||
split
|
||||
· rename_i h
|
||||
simp [← bytes_inj, ByteArray.set_eq_push_extract_append_extract, Slice.bytes_copy,
|
||||
List.utf8Encode_singleton, String.utf8EncodeChar_eq_singleton h.1, utf8ByteSize_byte ▸ h.2]
|
||||
· rfl
|
||||
|
||||
theorem Pos.Raw.IsValid.set_of_le {s : String} {p : s.ValidPos} {c : Char} {hp : p ≠ s.endValidPos}
|
||||
{q : Pos.Raw} (hq : q.IsValid s) (hpq : q ≤ p.offset) : q.IsValid (p.set c hp) := by
|
||||
rw [ValidPos.set_eq_append, String.append_assoc]
|
||||
apply append_right
|
||||
rw [isValid_copy_iff, isValidForSlice_stringReplaceEnd]
|
||||
exact ⟨hpq, hq⟩
|
||||
|
||||
/-- Given a valid position in a string, obtain the corresponding position after setting a character on
|
||||
that string, provided that the position was before the changed position. -/
|
||||
@[inline]
|
||||
def ValidPos.toSetOfLE {s : String} (q p : s.ValidPos) (c : Char) (hp : p ≠ s.endValidPos)
|
||||
(hpq : q ≤ p) : (p.set c hp).ValidPos where
|
||||
offset := q.offset
|
||||
isValid := q.isValid.set_of_le hpq
|
||||
|
||||
@[simp]
|
||||
theorem ValidPos.offset_toSetOfLE {s : String} {q p : s.ValidPos} {c : Char} {hp : p ≠ s.endValidPos}
|
||||
{hpq : q ≤ p} : (q.toSetOfLE p c hp hpq).offset = q.offset := (rfl)
|
||||
|
||||
theorem Pos.Raw.isValid_add_char_set {s : String} {p : s.ValidPos} {c : Char} {hp} :
|
||||
(p.offset + c).IsValid (p.set c hp) :=
|
||||
ValidPos.set_eq_append ▸ IsValid.append_right (isValid_of_eq_rawEndPos (by simp [Pos.Raw.ext_iff])) _
|
||||
|
||||
/-- The position just after the position that changed in a `ValidPos.set` call. -/
|
||||
@[inline]
|
||||
def ValidPos.pastSet {s : String} (p : s.ValidPos) (c : Char) (hp) : (p.set c hp).ValidPos where
|
||||
offset := p.offset + c
|
||||
isValid := Pos.Raw.isValid_add_char_set
|
||||
|
||||
@[simp]
|
||||
theorem ValidPos.offset_pastSet {s : String} {p : s.ValidPos} {c : Char} {hp} :
|
||||
(p.pastSet c hp).offset = p.offset + c := (rfl)
|
||||
|
||||
@[inline]
|
||||
def ValidPos.appendRight {s : String} (p : s.ValidPos) (t : String) : (s ++ t).ValidPos where
|
||||
offset := p.offset
|
||||
isValid := p.isValid.append_right t
|
||||
|
||||
theorem ValidPos.splits_pastSet {s : String} {p : s.ValidPos} {c : Char} {hp} :
|
||||
(p.pastSet c hp).Splits ((s.replaceEnd p).copy ++ singleton c) (s.replaceStart (p.next hp)).copy where
|
||||
eq_append := set_eq_append
|
||||
offset_eq_rawEndPos := by simp [Pos.Raw.ext_iff]
|
||||
|
||||
theorem remainingBytes_pastSet {s : String} {p : s.ValidPos} {c : Char} {hp} :
|
||||
(p.pastSet c hp).remainingBytes = (p.next hp).remainingBytes := by
|
||||
rw [(p.next hp).splits.remainingBytes_eq, p.splits_pastSet.remainingBytes_eq]
|
||||
|
||||
/--
|
||||
Replaces the character at position `p` in the string `s` with the result of applying `f` to that
|
||||
character.
|
||||
|
||||
If both the replacement character and the replaced character are 7-bit ASCII characters and the
|
||||
string is not shared, then it is updated in-place and not copied.
|
||||
|
||||
Examples:
|
||||
* `("abc".pos ⟨1⟩ (by decide)).modify Char.toUpper (by decide) = "aBc"`
|
||||
-/
|
||||
@[inline]
|
||||
def ValidPos.modify {s : String} (p : s.ValidPos) (f : Char → Char) (hp : p ≠ s.endValidPos) :
|
||||
String :=
|
||||
p.set (f <| p.get hp) hp
|
||||
|
||||
theorem Pos.Raw.IsValid.modify_of_le {s : String} {p : s.ValidPos} {f : Char → Char}
|
||||
{hp : p ≠ s.endValidPos} {q : Pos.Raw} (hq : q.IsValid s) (hpq : q ≤ p.offset) :
|
||||
q.IsValid (p.modify f hp) :=
|
||||
set_of_le hq hpq
|
||||
|
||||
/-- Given a valid position in a string, obtain the corresponding position after modifying a character
|
||||
in that string, provided that the position was before the changed position. -/
|
||||
@[inline]
|
||||
def ValidPos.toModifyOfLE {s : String} (q p : s.ValidPos) (f : Char → Char)
|
||||
(hp : p ≠ s.endValidPos) (hpq : q ≤ p) : (p.modify f hp).ValidPos where
|
||||
offset := q.offset
|
||||
isValid := q.isValid.modify_of_le hpq
|
||||
|
||||
@[simp]
|
||||
theorem ValidPos.offset_toModifyOfLE {s : String} {q p : s.ValidPos} {f : Char → Char}
|
||||
{hp : p ≠ s.endValidPos} {hpq : q ≤ p} : (q.toModifyOfLE p f hp hpq).offset = q.offset := (rfl)
|
||||
|
||||
/-- The position just after the position that was modified in a `ValidPos.modify` call. -/
|
||||
@[inline]
|
||||
def ValidPos.pastModify {s : String} (p : s.ValidPos) (f : Char → Char)
|
||||
(hp : p ≠ s.endValidPos) : (p.modify f hp).ValidPos :=
|
||||
p.pastSet _ _
|
||||
|
||||
theorem remainingBytes_pastModify {s : String} {p : s.ValidPos} {f : Char → Char} {hp} :
|
||||
(p.pastModify f hp).remainingBytes = (p.next hp).remainingBytes :=
|
||||
remainingBytes_pastSet
|
||||
|
||||
/--
|
||||
Replaces the character at a specified position in a string with a new character. If the position is
|
||||
invalid, the string is returned unchanged.
|
||||
|
||||
If both the replacement character and the replaced character are 7-bit ASCII characters and the
|
||||
string is not shared, then it is updated in-place and not copied.
|
||||
|
||||
This is a legacy function. The recommended alternative is `String.ValidPos.set`, combined with
|
||||
`String.pos` or another means of obtaining a `String.ValidPos`.
|
||||
|
||||
Examples:
|
||||
* `"abc".set ⟨1⟩ 'B' = "aBc"`
|
||||
* `"abc".set ⟨3⟩ 'D' = "abc"`
|
||||
* `"L∃∀N".set ⟨4⟩ 'X' = "L∃XN"`
|
||||
* `"L∃∀N".set ⟨2⟩ 'X' = "L∃∀N"` because `'∃'` is a multi-byte character, so the byte index `2` is an
|
||||
invalid position.
|
||||
-/
|
||||
@[extern "lean_string_utf8_set", expose]
|
||||
def Pos.Raw.set : String → (@& Pos.Raw) → Char → String
|
||||
| s, i, c => (Pos.Raw.utf8SetAux c s.data 0 i).asString
|
||||
|
||||
@[extern "lean_string_utf8_set", expose, deprecated Pos.Raw.set (since := "2025-10-14")]
|
||||
def set : String → (@& Pos.Raw) → Char → String
|
||||
| s, i, c => (Pos.Raw.utf8SetAux c s.data 0 i).asString
|
||||
|
||||
/--
|
||||
Replaces the character at position `p` in the string `s` with the result of applying `f` to that
|
||||
character. If `p` is an invalid position, the string is returned unchanged.
|
||||
|
||||
If both the replacement character and the replaced character are 7-bit ASCII characters and the
|
||||
string is not shared, then it is updated in-place and not copied.
|
||||
|
||||
This is a legacy function. The recommended alternative is `String.ValidPos.set`, combined with
|
||||
`String.pos` or another means of obtaining a `String.ValidPos`.
|
||||
|
||||
Examples:
|
||||
* `"abc".modify ⟨1⟩ Char.toUpper = "aBc"`
|
||||
* `"abc".modify ⟨3⟩ Char.toUpper = "abc"`
|
||||
-/
|
||||
@[expose]
|
||||
def Pos.Raw.modify (s : String) (i : Pos.Raw) (f : Char → Char) : String :=
|
||||
i.set s (f (i.get s))
|
||||
|
||||
@[expose, inherit_doc Pos.Raw.modify, deprecated Pos.Raw.modify (since := "2025-10-10")]
|
||||
def modify (s : String) (i : Pos.Raw) (f : Char → Char) : String :=
|
||||
i.set s (f (i.get s))
|
||||
|
||||
@[specialize] def mapAux (f : Char → Char) (s : String) (p : s.ValidPos) : String :=
|
||||
if h : p = s.endValidPos then
|
||||
s
|
||||
else
|
||||
mapAux f (p.modify f h) (p.pastModify f h)
|
||||
termination_by p.remainingBytes
|
||||
decreasing_by
|
||||
simp [remainingBytes_pastModify, ← ValidPos.lt_iff_remainingBytes_lt]
|
||||
|
||||
/--
|
||||
Applies the function `f` to every character in a string, returning a string that contains the
|
||||
resulting characters.
|
||||
|
||||
Examples:
|
||||
* `"abc123".map Char.toUpper = "ABC123"`
|
||||
* `"".map Char.toUpper = ""`
|
||||
-/
|
||||
@[inline] def map (f : Char → Char) (s : String) : String :=
|
||||
mapAux f s s.startValidPos
|
||||
|
||||
/--
|
||||
In the string `s`, replaces all occurrences of `pattern` with `replacement`.
|
||||
|
||||
Examples:
|
||||
* `"red green blue".replace "e" "" = "rd grn blu"`
|
||||
* `"red green blue".replace "ee" "E" = "red grEn blue"`
|
||||
* `"red green blue".replace "e" "E" = "rEd grEEn bluE"`
|
||||
-/
|
||||
def replace (s pattern replacement : String) : String :=
|
||||
if h : pattern.rawEndPos.1 = 0 then s
|
||||
else
|
||||
have hPatt := Nat.zero_lt_of_ne_zero h
|
||||
let rec loop (acc : String) (accStop pos : String.Pos.Raw) :=
|
||||
if h : pos.byteIdx + pattern.rawEndPos.byteIdx > s.rawEndPos.byteIdx then
|
||||
acc ++ accStop.extract s s.rawEndPos
|
||||
else
|
||||
have := Nat.lt_of_lt_of_le (Nat.add_lt_add_left hPatt _) (Nat.ge_of_not_lt h)
|
||||
if Pos.Raw.substrEq s pos pattern 0 pattern.rawEndPos.byteIdx then
|
||||
have := Nat.sub_lt_sub_left this (Nat.add_lt_add_left hPatt _)
|
||||
loop (acc ++ accStop.extract s pos ++ replacement) (pos + pattern) (pos + pattern)
|
||||
else
|
||||
have := Nat.sub_lt_sub_left this (Pos.Raw.lt_next s pos)
|
||||
loop acc accStop (pos.next s)
|
||||
termination_by s.rawEndPos.1 - pos.1
|
||||
loop "" 0 0
|
||||
|
||||
/--
|
||||
Replaces each character in `s` with the result of applying `Char.toUpper` to it.
|
||||
|
||||
`Char.toUpper` has no effect on characters outside of the range `'a'`–`'z'`.
|
||||
|
||||
Examples:
|
||||
* `"orange".toUpper = "ORANGE"`
|
||||
* `"abc123".toUpper = "ABC123"`
|
||||
-/
|
||||
@[inline] def toUpper (s : String) : String :=
|
||||
s.map Char.toUpper
|
||||
|
||||
/--
|
||||
Replaces each character in `s` with the result of applying `Char.toLower` to it.
|
||||
|
||||
`Char.toLower` has no effect on characters outside of the range `'A'`–`'Z'`.
|
||||
|
||||
Examples:
|
||||
* `"ORANGE".toLower = "orange"`
|
||||
* `"Orange".toLower = "orange"`
|
||||
* `"ABc123".toLower = "abc123"`
|
||||
-/
|
||||
@[inline] def toLower (s : String) : String :=
|
||||
s.map Char.toLower
|
||||
|
||||
/--
|
||||
Replaces the first character in `s` with the result of applying `Char.toUpper` to it. Returns the
|
||||
empty string if the string is empty.
|
||||
|
||||
`Char.toUpper` has no effect on characters outside of the range `'a'`–`'z'`.
|
||||
|
||||
Examples:
|
||||
* `"orange".capitalize = "Orange"`
|
||||
* `"ORANGE".capitalize = "ORANGE"`
|
||||
* `"".capitalize = ""`
|
||||
-/
|
||||
@[inline] def capitalize (s : String) : String :=
|
||||
(0 : Pos.Raw).set s <| (0 : Pos.Raw).get s |>.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.
|
||||
|
||||
`Char.toLower` has no effect on characters outside of the range `'A'`–`'Z'`.
|
||||
|
||||
Examples:
|
||||
* `"Orange".decapitalize = "orange"`
|
||||
* `"ORANGE".decapitalize = "oRANGE"`
|
||||
* `"".decapitalize = ""`
|
||||
-/
|
||||
@[inline] def decapitalize (s : String) :=
|
||||
(0 : Pos.Raw).set s <| (0 : Pos.Raw).get s |>.toLower
|
||||
|
||||
end String
|
||||
@@ -38,7 +38,7 @@ inductive SearchStep (s : Slice) where
|
||||
The subslice starting at {name}`startPos` and ending at {name}`endPos` matches the pattern.
|
||||
-/
|
||||
| matched (startPos endPos : s.Pos)
|
||||
deriving Inhabited
|
||||
deriving Inhabited, BEq
|
||||
|
||||
/--
|
||||
Provides a conversion from a pattern to an iterator of {name}`SearchStep` that searches for matches
|
||||
|
||||
@@ -9,6 +9,7 @@ prelude
|
||||
public import Init.Data.String.Pattern.Basic
|
||||
public import Init.Data.Iterators.Internal.Termination
|
||||
public import Init.Data.Iterators.Consumers.Monadic.Loop
|
||||
import Init.Data.String.Termination
|
||||
|
||||
set_option doc.verso true
|
||||
|
||||
@@ -60,8 +61,7 @@ instance (s : Slice) : Std.Iterators.Iterator (ForwardCharSearcher s) Id (Search
|
||||
pure (.deflate ⟨.yield nextIt (.rejected currPos nextPos), by simp [h1, h2, nextIt, nextPos]⟩)
|
||||
|
||||
def finitenessRelation : Std.Iterators.FinitenessRelation (ForwardCharSearcher s) Id where
|
||||
rel := InvImage WellFoundedRelation.rel
|
||||
(fun it => s.utf8ByteSize - it.internalState.currPos.offset.byteIdx)
|
||||
rel := InvImage WellFoundedRelation.rel (fun it => it.internalState.currPos)
|
||||
wf := InvImage.wf _ WellFoundedRelation.wf
|
||||
subrelation {it it'} h := by
|
||||
simp_wf
|
||||
@@ -69,10 +69,7 @@ def finitenessRelation : Std.Iterators.FinitenessRelation (ForwardCharSearcher s
|
||||
cases step
|
||||
· cases h
|
||||
obtain ⟨_, h1, h2, _⟩ := h'
|
||||
have h3 := Char.utf8Size_pos (it.internalState.currPos.get h1)
|
||||
have h4 := it.internalState.currPos.isValidForSlice.le_utf8ByteSize
|
||||
simp [Pos.ext_iff, String.Pos.Raw.ext_iff, Pos.Raw.le_iff] at h1 h2 h4
|
||||
omega
|
||||
simp [h2]
|
||||
· cases h'
|
||||
· cases h
|
||||
|
||||
@@ -129,8 +126,7 @@ instance (s : Slice) : Std.Iterators.Iterator (BackwardCharSearcher s) Id (Searc
|
||||
pure (.deflate ⟨.yield nextIt (.rejected nextPos currPos), by simp [h1, h2, nextIt, nextPos]⟩)
|
||||
|
||||
def finitenessRelation : Std.Iterators.FinitenessRelation (BackwardCharSearcher s) Id where
|
||||
rel := InvImage WellFoundedRelation.rel
|
||||
(fun it => it.internalState.currPos.offset.byteIdx)
|
||||
rel := InvImage WellFoundedRelation.rel (fun it => it.internalState.currPos.down)
|
||||
wf := InvImage.wf _ WellFoundedRelation.wf
|
||||
subrelation {it it'} h := by
|
||||
simp_wf
|
||||
@@ -138,9 +134,7 @@ def finitenessRelation : Std.Iterators.FinitenessRelation (BackwardCharSearcher
|
||||
cases step
|
||||
· cases h
|
||||
obtain ⟨_, h1, h2, _⟩ := h'
|
||||
have h3 := Pos.offset_prev_lt_offset (h := h1)
|
||||
simp [Pos.ext_iff, String.Pos.Raw.ext_iff, String.Pos.Raw.lt_iff] at h2 h3
|
||||
omega
|
||||
simp [h2]
|
||||
· cases h'
|
||||
· cases h
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ prelude
|
||||
public import Init.Data.String.Pattern.Basic
|
||||
public import Init.Data.Iterators.Internal.Termination
|
||||
public import Init.Data.Iterators.Consumers.Monadic.Loop
|
||||
import Init.Data.String.Termination
|
||||
|
||||
set_option doc.verso true
|
||||
|
||||
@@ -62,8 +63,7 @@ instance (s : Slice) : Std.Iterators.Iterator (ForwardCharPredSearcher s) Id (Se
|
||||
|
||||
|
||||
def finitenessRelation : Std.Iterators.FinitenessRelation (ForwardCharPredSearcher s) Id where
|
||||
rel := InvImage WellFoundedRelation.rel
|
||||
(fun it => s.utf8ByteSize - it.internalState.currPos.offset.byteIdx)
|
||||
rel := InvImage WellFoundedRelation.rel (fun it => it.internalState.currPos)
|
||||
wf := InvImage.wf _ WellFoundedRelation.wf
|
||||
subrelation {it it'} h := by
|
||||
simp_wf
|
||||
@@ -71,10 +71,7 @@ def finitenessRelation : Std.Iterators.FinitenessRelation (ForwardCharPredSearch
|
||||
cases step
|
||||
· cases h
|
||||
obtain ⟨_, h1, h2, _⟩ := h'
|
||||
have h3 := Char.utf8Size_pos (it.internalState.currPos.get h1)
|
||||
have h4 := it.internalState.currPos.isValidForSlice.le_utf8ByteSize
|
||||
simp [Pos.ext_iff, String.Pos.Raw.ext_iff, Pos.Raw.le_iff] at h1 h2 h4
|
||||
omega
|
||||
simp [h2]
|
||||
· cases h'
|
||||
· cases h
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ prelude
|
||||
public import Init.Data.String.Pattern.Basic
|
||||
public import Init.Data.Iterators.Internal.Termination
|
||||
public import Init.Data.Iterators.Consumers.Monadic.Loop
|
||||
import Init.Data.String.Termination
|
||||
|
||||
set_option doc.verso true
|
||||
|
||||
@@ -22,7 +23,8 @@ public section
|
||||
namespace String.Slice.Pattern
|
||||
|
||||
inductive ForwardSliceSearcher (s : Slice) where
|
||||
| empty (pos : s.Pos)
|
||||
| emptyBefore (pos : s.Pos)
|
||||
| emptyAt (pos : s.Pos) (h : pos ≠ s.endPos)
|
||||
| proper (needle : Slice) (table : Array String.Pos.Raw) (stackPos : String.Pos.Raw) (needlePos : String.Pos.Raw)
|
||||
| atEnd
|
||||
deriving Inhabited
|
||||
@@ -56,7 +58,7 @@ where
|
||||
@[inline]
|
||||
def iter (s : Slice) (pat : Slice) : Std.Iter (α := ForwardSliceSearcher s) (SearchStep s) :=
|
||||
if pat.utf8ByteSize == 0 then
|
||||
{ internalState := .empty s.startPos }
|
||||
{ internalState := .emptyBefore s.startPos }
|
||||
else
|
||||
{ internalState := .proper pat (buildTable pat) s.startPos.offset pat.startPos.offset }
|
||||
|
||||
@@ -71,9 +73,8 @@ instance (s : Slice) : Std.Iterators.Iterator (ForwardSliceSearcher s) Id (Searc
|
||||
IsPlausibleStep it
|
||||
| .yield it' out =>
|
||||
match it.internalState with
|
||||
| .empty pos =>
|
||||
(∃ newPos, pos < newPos ∧ it'.internalState = .empty newPos) ∨
|
||||
it'.internalState = .atEnd
|
||||
| .emptyBefore pos => (∃ h, it'.internalState = .emptyAt pos h) ∨ it'.internalState = .atEnd
|
||||
| .emptyAt pos h => ∃ newPos, pos < newPos ∧ it'.internalState = .emptyBefore newPos
|
||||
| .proper needle table stackPos needlePos =>
|
||||
(∃ newStackPos newNeedlePos,
|
||||
stackPos < newStackPos ∧
|
||||
@@ -85,12 +86,15 @@ instance (s : Slice) : Std.Iterators.Iterator (ForwardSliceSearcher s) Id (Searc
|
||||
| .done => True
|
||||
step := fun ⟨iter⟩ =>
|
||||
match iter with
|
||||
| .empty pos =>
|
||||
| .emptyBefore pos =>
|
||||
let res := .matched pos pos
|
||||
if h : pos ≠ s.endPos then
|
||||
pure (.deflate ⟨.yield ⟨.empty (pos.next h)⟩ res, by simp⟩)
|
||||
pure (.deflate ⟨.yield ⟨.emptyAt pos h⟩ res, by simp [h]⟩)
|
||||
else
|
||||
pure (.deflate ⟨.yield ⟨.atEnd⟩ res, by simp⟩)
|
||||
| .emptyAt pos h =>
|
||||
let res := .rejected pos (pos.next h)
|
||||
pure (.deflate ⟨.yield ⟨.emptyBefore (pos.next h)⟩ res, by simp⟩)
|
||||
| .proper needle table stackPos needlePos =>
|
||||
let rec findNext (startPos : String.Pos.Raw)
|
||||
(currStackPos : String.Pos.Raw) (needlePos : String.Pos.Raw) (h : stackPos ≤ currStackPos) :=
|
||||
@@ -148,15 +152,17 @@ instance (s : Slice) : Std.Iterators.Iterator (ForwardSliceSearcher s) Id (Searc
|
||||
findNext stackPos stackPos needlePos (by simp)
|
||||
| .atEnd => pure (.deflate ⟨.done, by simp⟩)
|
||||
|
||||
private def toPair : ForwardSliceSearcher s → (Nat × Nat)
|
||||
| .empty pos => (1, s.utf8ByteSize - pos.offset.byteIdx)
|
||||
| .proper _ _ sp _ => (1, s.utf8ByteSize - sp.byteIdx)
|
||||
| .atEnd => (0, 0)
|
||||
private def toOption : ForwardSliceSearcher s → Option (Nat × Nat)
|
||||
| .emptyBefore pos => some (pos.remainingBytes, 1)
|
||||
| .emptyAt pos _ => some (pos.remainingBytes, 0)
|
||||
| .proper _ _ sp _ => some (s.utf8ByteSize - sp.byteIdx, 0)
|
||||
| .atEnd => none
|
||||
|
||||
private instance : WellFoundedRelation (ForwardSliceSearcher s) where
|
||||
rel s1 s2 := Prod.Lex (· < ·) (· < ·) s1.toPair s2.toPair
|
||||
rel := InvImage (Option.lt (Prod.Lex (· < ·) (· < ·))) ForwardSliceSearcher.toOption
|
||||
wf := by
|
||||
apply InvImage.wf
|
||||
apply Option.wellFounded_lt
|
||||
apply (Prod.lex _ _).wf
|
||||
|
||||
private def finitenessRelation :
|
||||
@@ -168,30 +174,24 @@ private def finitenessRelation :
|
||||
obtain ⟨step, h, h'⟩ := h
|
||||
cases step
|
||||
· cases h
|
||||
simp only [Std.Iterators.IterM.IsPlausibleStep, Std.Iterators.Iterator.IsPlausibleStep] at h'
|
||||
split at h'
|
||||
· next heq =>
|
||||
rw [heq]
|
||||
rcases h' with ⟨np, h1', h2'⟩ | h'
|
||||
· rw [h2']
|
||||
apply Prod.Lex.right'
|
||||
· simp
|
||||
· have haux := np.isValidForSlice.le_utf8ByteSize
|
||||
simp [Slice.Pos.lt_iff, String.Pos.Raw.le_iff, String.Pos.Raw.lt_iff] at h1' haux ⊢
|
||||
omega
|
||||
· apply Prod.Lex.left
|
||||
simp [h']
|
||||
· next heq =>
|
||||
rw [heq]
|
||||
rcases h' with ⟨np, sp, h1', h2', h3'⟩ | h'
|
||||
· rw [h3']
|
||||
apply Prod.Lex.right'
|
||||
· simp
|
||||
· simp [String.Pos.Raw.le_iff, String.Pos.Raw.lt_iff] at h1' h2' ⊢
|
||||
omega
|
||||
· apply Prod.Lex.left
|
||||
simp [h']
|
||||
· contradiction
|
||||
revert h'
|
||||
simp only [Std.Iterators.IterM.IsPlausibleStep, Std.Iterators.Iterator.IsPlausibleStep]
|
||||
match it.internalState with
|
||||
| .emptyBefore pos =>
|
||||
rintro (⟨h, h'⟩|h') <;> simp [h', ForwardSliceSearcher.toOption, Option.lt, Prod.lex_def]
|
||||
| .emptyAt pos h =>
|
||||
simp only [forall_exists_index, and_imp]
|
||||
intro x hx h
|
||||
simpa [h, ForwardSliceSearcher.toOption, Option.lt, Prod.lex_def,
|
||||
← Pos.lt_iff_remainingBytes_lt]
|
||||
| .proper needle table stackPos needlePos =>
|
||||
simp only [exists_and_left]
|
||||
rintro (⟨newStackPos, h₁, h₂, ⟨x, hx⟩⟩|h)
|
||||
· simp [hx, ForwardSliceSearcher.toOption, Option.lt, Prod.lex_def, Pos.Raw.lt_iff,
|
||||
Pos.Raw.le_iff] at ⊢ h₁ h₂
|
||||
omega
|
||||
· simp [h, ForwardSliceSearcher.toOption, Option.lt]
|
||||
| .atEnd .. => simp
|
||||
· cases h'
|
||||
· cases h
|
||||
|
||||
|
||||
@@ -322,9 +322,6 @@ theorem ne_of_gt {i₁ i₂ : Pos.Raw} (h : i₁ < i₂) : i₂ ≠ i₁ := (ne_
|
||||
theorem byteIdx_addString (p : Pos.Raw) (s : String) :
|
||||
(p + s).byteIdx = p.byteIdx + s.utf8ByteSize := byteIdx_add_string
|
||||
|
||||
@[deprecated byteIdx_addString (since := "2025-03-18")]
|
||||
abbrev addString_byteIdx := @byteIdx_add_string
|
||||
|
||||
theorem addString_eq (p : Pos.Raw) (s : String) : p + s = ⟨p.byteIdx + s.utf8ByteSize⟩ := rfl
|
||||
|
||||
theorem byteIdx_zero_add_string (s : String) : ((0 : Pos.Raw) + s).byteIdx = s.utf8ByteSize := by
|
||||
@@ -334,9 +331,6 @@ theorem byteIdx_zero_add_string (s : String) : ((0 : Pos.Raw) + s).byteIdx = s.u
|
||||
theorem byteIdx_zero_addString (s : String) : ((0 : Pos.Raw) + s).byteIdx = s.utf8ByteSize :=
|
||||
byteIdx_zero_add_string s
|
||||
|
||||
@[deprecated byteIdx_zero_addString (since := "2025-03-18")]
|
||||
abbrev zero_addString_byteIdx := @byteIdx_zero_add_string
|
||||
|
||||
theorem zero_add_string_eq (s : String) : (0 : Pos.Raw) + s = ⟨s.utf8ByteSize⟩ := by
|
||||
rw [← byteIdx_zero_add_string]
|
||||
|
||||
|
||||
@@ -861,7 +861,7 @@ private def finitenessRelation [Pure m] :
|
||||
obtain ⟨h1, h2, _⟩ := h'
|
||||
have h3 := Char.utf8Size_pos (it.internalState.currPos.get h1)
|
||||
have h4 := it.internalState.currPos.isValidForSlice.le_utf8ByteSize
|
||||
simp [Pos.ext_iff, String.Pos.Raw.ext_iff, Pos.Raw.le_iff] at h1 h2 h4
|
||||
simp [Pos.ext_iff, String.Pos.Raw.ext_iff] at h1 h2 h4
|
||||
omega
|
||||
· cases h'
|
||||
· cases h
|
||||
|
||||
257
src/Init/Data/String/Termination.lean
Normal file
257
src/Init/Data/String/Termination.lean
Normal file
@@ -0,0 +1,257 @@
|
||||
/-
|
||||
Copyright (c) 2025 Lean FRO, LLC. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Author: Markus Himmel
|
||||
-/
|
||||
module
|
||||
|
||||
prelude
|
||||
public import Init.Data.String.Basic
|
||||
public import Init.Data.String.Lemmas.Splits
|
||||
|
||||
/-!
|
||||
# Helpers for termination arguments about functions operating on strings
|
||||
-/
|
||||
|
||||
public section
|
||||
|
||||
namespace String
|
||||
|
||||
namespace Slice.Pos
|
||||
|
||||
/-- The number of bytes between `p` and the end position. This number decreases as `p` advances. -/
|
||||
def remainingBytes {s : Slice} (p : s.Pos) : Nat :=
|
||||
p.offset.byteDistance s.endPos.offset
|
||||
|
||||
theorem remainingBytes_eq_byteDistance {s : Slice} {p : s.Pos} :
|
||||
p.remainingBytes = p.offset.byteDistance s.endPos.offset := (rfl)
|
||||
|
||||
theorem remainingBytes_eq {s : Slice} {p : s.Pos} :
|
||||
p.remainingBytes = s.utf8ByteSize - p.offset.byteIdx := by
|
||||
simp [remainingBytes_eq_byteDistance, Pos.Raw.byteDistance_eq]
|
||||
|
||||
theorem remainingBytes_inj {s : Slice} {p q : s.Pos} :
|
||||
p.remainingBytes = q.remainingBytes ↔ p = q := by
|
||||
have := p.isValidForSlice.le_utf8ByteSize
|
||||
have := q.isValidForSlice.le_utf8ByteSize
|
||||
simp only [remainingBytes_eq, Pos.ext_iff, Pos.Raw.ext_iff]
|
||||
omega
|
||||
|
||||
theorem le_iff_remainingBytes_le {s : Slice} (p q : s.Pos) :
|
||||
p ≤ q ↔ q.remainingBytes ≤ p.remainingBytes := by
|
||||
have := p.isValidForSlice.le_utf8ByteSize
|
||||
have := q.isValidForSlice.le_utf8ByteSize
|
||||
simp only [remainingBytes_eq, Slice.Pos.le_iff, Pos.Raw.le_iff]
|
||||
omega
|
||||
|
||||
theorem lt_iff_remainingBytes_lt {s : Slice} (p q : s.Pos) :
|
||||
p < q ↔ q.remainingBytes < p.remainingBytes := by
|
||||
have := p.isValidForSlice.le_utf8ByteSize
|
||||
have := q.isValidForSlice.le_utf8ByteSize
|
||||
simp only [remainingBytes_eq, Slice.Pos.lt_iff, Pos.Raw.lt_iff]
|
||||
omega
|
||||
|
||||
theorem wellFounded_lt {s : Slice} : WellFounded (fun (p : s.Pos) q => p < q) := by
|
||||
simpa [lt_iff, Pos.Raw.lt_iff] using
|
||||
InvImage.wf (Pos.Raw.byteIdx ∘ Slice.Pos.offset) Nat.lt_wfRel.wf
|
||||
|
||||
theorem wellFounded_gt {s : Slice} : WellFounded (fun (p : s.Pos) q => q < p) := by
|
||||
simpa [lt_iff_remainingBytes_lt] using
|
||||
InvImage.wf Slice.Pos.remainingBytes Nat.lt_wfRel.wf
|
||||
|
||||
instance {s : Slice} : WellFoundedRelation s.Pos where
|
||||
rel p q := q < p
|
||||
wf := Slice.Pos.wellFounded_gt
|
||||
|
||||
/-- Type alias for `String.Slice.Pos` representing that the given position is expected to decrease
|
||||
in recursive calls. -/
|
||||
structure Down (s : Slice) : Type where
|
||||
inner : s.Pos
|
||||
|
||||
/-- Use `termination_by pos.down` to signify that in a recursive call, the parameter `pos` is
|
||||
expected to decrease. -/
|
||||
def down {s : Slice} (p : s.Pos) : Pos.Down s where
|
||||
inner := p
|
||||
|
||||
@[simp]
|
||||
theorem inner_down {s : Slice} {p : s.Pos} : p.down.inner = p := (rfl)
|
||||
|
||||
instance {s : Slice} : WellFoundedRelation (Pos.Down s) where
|
||||
rel p q := p.inner < q.inner
|
||||
wf := InvImage.wf Down.inner wellFounded_lt
|
||||
|
||||
theorem ne_endPos_of_next?_eq_some {s : Slice} {p q : s.Pos} :
|
||||
p.next? = some q → p ≠ s.endPos := by
|
||||
simpa [next?] using fun h _ => h
|
||||
|
||||
theorem eq_next_of_next?_eq_some {s : Slice} {p q : s.Pos} :
|
||||
(h : p.next? = some q) → q = p.next (ne_endPos_of_next?_eq_some h) := by
|
||||
simpa [next?] using fun _ h => h.symm
|
||||
|
||||
theorem ne_startPos_of_prev?_eq_some {s : Slice} {p q : s.Pos} :
|
||||
p.prev? = some q → p ≠ s.startPos := by
|
||||
simpa [prev?] using fun h _ => h
|
||||
|
||||
theorem eq_prev_of_prev?_eq_some {s : Slice} {p q : s.Pos} :
|
||||
(h : p.prev? = some q) → q = p.prev (ne_startPos_of_prev?_eq_some h) := by
|
||||
simpa [prev?] using fun _ h => h.symm
|
||||
|
||||
@[simp]
|
||||
theorem le_refl {s : Slice} (p : s.Pos) : p ≤ p := by
|
||||
simp [le_iff]
|
||||
|
||||
theorem lt_trans {s : Slice} {p q r : s.Pos} : p < q → q < r → p < r := by
|
||||
simpa [Pos.lt_iff, Pos.Raw.lt_iff] using Nat.lt_trans
|
||||
|
||||
@[simp]
|
||||
theorem lt_next_next {s : Slice} {p : s.Pos} {h h'} : p < (p.next h).next h' :=
|
||||
lt_trans p.lt_next (p.next h).lt_next
|
||||
|
||||
@[simp]
|
||||
theorem prev_prev_lt {s : Slice} {p : s.Pos} {h h'} : (p.prev h).prev h' < p :=
|
||||
lt_trans (p.prev h).prev_lt p.prev_lt
|
||||
|
||||
end Slice.Pos
|
||||
|
||||
namespace ValidPos
|
||||
|
||||
/-- The number of bytes between `p` and the end position. This number decreases as `p` advances. -/
|
||||
def remainingBytes {s : String} (p : s.ValidPos) : Nat :=
|
||||
p.toSlice.remainingBytes
|
||||
|
||||
@[simp]
|
||||
theorem remainingBytes_toSlice {s : String} {p : s.ValidPos} :
|
||||
p.toSlice.remainingBytes = p.remainingBytes := (rfl)
|
||||
|
||||
theorem remainingBytes_eq_byteDistance {s : String} {p : s.ValidPos} :
|
||||
p.remainingBytes = p.offset.byteDistance s.endValidPos.offset := (rfl)
|
||||
|
||||
theorem remainingBytes_eq {s : String} {p : s.ValidPos} :
|
||||
p.remainingBytes = s.utf8ByteSize - p.offset.byteIdx := by
|
||||
simp [remainingBytes_eq_byteDistance, Pos.Raw.byteDistance_eq]
|
||||
|
||||
theorem remainingBytes_inj {s : String} {p q : s.ValidPos} :
|
||||
p.remainingBytes = q.remainingBytes ↔ p = q := by
|
||||
simp [← remainingBytes_toSlice, ValidPos.toSlice_inj, Slice.Pos.remainingBytes_inj]
|
||||
|
||||
theorem le_iff_remainingBytes_le {s : String} (p q : s.ValidPos) :
|
||||
p ≤ q ↔ q.remainingBytes ≤ p.remainingBytes := by
|
||||
simp [← remainingBytes_toSlice, ← Slice.Pos.le_iff_remainingBytes_le]
|
||||
|
||||
theorem lt_iff_remainingBytes_lt {s : String} (p q : s.ValidPos) :
|
||||
p < q ↔ q.remainingBytes < p.remainingBytes := by
|
||||
simp [← remainingBytes_toSlice, ← Slice.Pos.lt_iff_remainingBytes_lt]
|
||||
|
||||
theorem wellFounded_lt {s : String} : WellFounded (fun (p : s.ValidPos) q => p < q) := by
|
||||
simpa [lt_iff, Pos.Raw.lt_iff] using
|
||||
InvImage.wf (Pos.Raw.byteIdx ∘ ValidPos.offset) Nat.lt_wfRel.wf
|
||||
|
||||
theorem wellFounded_gt {s : String} : WellFounded (fun (p : s.ValidPos) q => q < p) := by
|
||||
simpa [lt_iff_remainingBytes_lt] using
|
||||
InvImage.wf ValidPos.remainingBytes Nat.lt_wfRel.wf
|
||||
|
||||
instance {s : String} : WellFoundedRelation s.ValidPos where
|
||||
rel p q := q < p
|
||||
wf := ValidPos.wellFounded_gt
|
||||
|
||||
/-- Type alias for `String.ValidPos` representing that the given position is expected to decrease
|
||||
in recursive calls. -/
|
||||
structure Down (s : String) : Type where
|
||||
inner : s.ValidPos
|
||||
|
||||
/-- Use `termination_by pos.down` to signify that in a recursive call, the parameter `pos` is
|
||||
expected to decrease. -/
|
||||
def down {s : String} (p : s.ValidPos) : ValidPos.Down s where
|
||||
inner := p
|
||||
|
||||
@[simp]
|
||||
theorem inner_down {s : String} {p : s.ValidPos} : p.down.inner = p := (rfl)
|
||||
|
||||
instance {s : String} : WellFoundedRelation (ValidPos.Down s) where
|
||||
rel p q := p.inner < q.inner
|
||||
wf := InvImage.wf ValidPos.Down.inner ValidPos.wellFounded_lt
|
||||
|
||||
theorem map_toSlice_next? {s : String} {p : s.ValidPos} :
|
||||
p.next?.map ValidPos.toSlice = p.toSlice.next? := by
|
||||
simp [next?]
|
||||
|
||||
theorem map_toSlice_prev? {s : String} {p : s.ValidPos} :
|
||||
p.prev?.map ValidPos.toSlice = p.toSlice.prev? := by
|
||||
simp [prev?]
|
||||
|
||||
theorem ne_endValidPos_of_next?_eq_some {s : String} {p q : s.ValidPos}
|
||||
(h : p.next? = some q) : p ≠ s.endValidPos :=
|
||||
ne_of_apply_ne ValidPos.toSlice (Slice.Pos.ne_endPos_of_next?_eq_some
|
||||
(by simpa only [ValidPos.map_toSlice_next?, Option.map_some] using congrArg (·.map toSlice) h))
|
||||
|
||||
theorem eq_next_of_next?_eq_some {s : String} {p q : s.ValidPos} (h : p.next? = some q) :
|
||||
q = p.next (ne_endValidPos_of_next?_eq_some h) := by
|
||||
simpa only [← toSlice_inj, toSlice_next] using Slice.Pos.eq_next_of_next?_eq_some
|
||||
(by simpa [ValidPos.map_toSlice_next?] using congrArg (·.map toSlice) h)
|
||||
|
||||
theorem ne_startValidPos_of_prev?_eq_some {s : String} {p q : s.ValidPos}
|
||||
(h : p.prev? = some q) : p ≠ s.startValidPos :=
|
||||
ne_of_apply_ne ValidPos.toSlice (Slice.Pos.ne_startPos_of_prev?_eq_some
|
||||
(by simpa only [ValidPos.map_toSlice_prev?, Option.map_some] using congrArg (·.map toSlice) h))
|
||||
|
||||
theorem eq_prev_of_prev?_eq_some {s : String} {p q : s.ValidPos} (h : p.prev? = some q) :
|
||||
q = p.prev (ne_startValidPos_of_prev?_eq_some h) := by
|
||||
simpa only [← toSlice_inj, toSlice_prev] using Slice.Pos.eq_prev_of_prev?_eq_some
|
||||
(by simpa [ValidPos.map_toSlice_prev?] using congrArg (·.map toSlice) h)
|
||||
|
||||
@[simp]
|
||||
theorem le_refl {s : String} (p : s.ValidPos) : p ≤ p := by
|
||||
simp [ValidPos.le_iff]
|
||||
|
||||
theorem lt_trans {s : String} {p q r : s.ValidPos} : p < q → q < r → p < r := by
|
||||
simpa [ValidPos.lt_iff, Pos.Raw.lt_iff] using Nat.lt_trans
|
||||
|
||||
@[simp]
|
||||
theorem lt_next_next {s : String} {p : s.ValidPos} {h h'} : p < (p.next h).next h' :=
|
||||
lt_trans p.lt_next (p.next h).lt_next
|
||||
|
||||
@[simp]
|
||||
theorem prev_prev_lt {s : String} {p : s.ValidPos} {h h'} : (p.prev h).prev h' < p :=
|
||||
lt_trans (p.prev h).prev_lt p.prev_lt
|
||||
|
||||
theorem Splits.remainingBytes_eq {s : String} {p : s.ValidPos} {t₁ t₂}
|
||||
(h : p.Splits t₁ t₂) : p.remainingBytes = t₂.utf8ByteSize := by
|
||||
simp [ValidPos.remainingBytes_eq, h.eq_append, h.offset_eq_rawEndPos]
|
||||
|
||||
end ValidPos
|
||||
|
||||
namespace Slice.Pos
|
||||
|
||||
@[simp]
|
||||
theorem remainingBytes_toCopy {s : Slice} {p : s.Pos} :
|
||||
p.toCopy.remainingBytes = p.remainingBytes := by
|
||||
simp [remainingBytes_eq, ValidPos.remainingBytes_eq, Slice.utf8ByteSize_eq]
|
||||
|
||||
theorem Splits.remainingBytes_eq {s : Slice} {p : s.Pos} {t₁ t₂} (h : p.Splits t₁ t₂) :
|
||||
p.remainingBytes = t₂.utf8ByteSize := by
|
||||
simpa using h.toCopy.remainingBytes_eq
|
||||
|
||||
end Slice.Pos
|
||||
|
||||
macro_rules | `(tactic| decreasing_trivial) => `(tactic|
|
||||
(with_reducible change (_ : Slice.Pos _) < _
|
||||
simp [
|
||||
Slice.Pos.eq_next_of_next?_eq_some (by assumption),
|
||||
]) <;> done)
|
||||
macro_rules | `(tactic| decreasing_trivial) => `(tactic|
|
||||
(with_reducible change (_ : Slice.Pos _) < _
|
||||
simp [
|
||||
Slice.Pos.eq_prev_of_prev?_eq_some (by assumption),
|
||||
]) <;> done)
|
||||
macro_rules | `(tactic| decreasing_trivial) => `(tactic|
|
||||
(with_reducible change (_ : String.ValidPos _) < _
|
||||
simp [
|
||||
ValidPos.eq_next_of_next?_eq_some (by assumption),
|
||||
]) <;> done)
|
||||
macro_rules | `(tactic| decreasing_trivial) => `(tactic|
|
||||
(with_reducible change (_ : String.ValidPos _) < _
|
||||
simp [
|
||||
ValidPos.eq_prev_of_prev?_eq_some (by assumption),
|
||||
]) <;> done)
|
||||
|
||||
end String
|
||||
@@ -60,14 +60,8 @@ macro "declare_uint_theorems" typeName:ident bits:term:arg : command => do
|
||||
|
||||
@[int_toBitVec] theorem le_iff_toBitVec_le {a b : $typeName} : a ≤ b ↔ a.toBitVec ≤ b.toBitVec := .rfl
|
||||
|
||||
@[deprecated le_iff_toBitVec_le (since := "2025-03-20")]
|
||||
protected theorem le_def {a b : $typeName} : a ≤ b ↔ a.toBitVec ≤ b.toBitVec := .rfl
|
||||
|
||||
@[int_toBitVec] theorem lt_iff_toBitVec_lt {a b : $typeName} : a < b ↔ a.toBitVec < b.toBitVec := .rfl
|
||||
|
||||
@[deprecated lt_iff_toBitVec_lt (since := "2025-03-20")]
|
||||
protected theorem lt_def {a b : $typeName} : a < b ↔ a.toBitVec < b.toBitVec := .rfl
|
||||
|
||||
theorem le_iff_toNat_le {a b : $typeName} : a ≤ b ↔ a.toNat ≤ b.toNat := .rfl
|
||||
|
||||
theorem lt_iff_toNat_lt {a b : $typeName} : a < b ↔ a.toNat < b.toNat := .rfl
|
||||
@@ -304,22 +298,6 @@ theorem UInt32.le_ofNat_iff {n : UInt32} {m : Nat} (h : m < size) : n ≤ ofNat
|
||||
theorem UInt32.ofNat_le_iff {n : UInt32} {m : Nat} (h : m < size) : ofNat m ≤ n ↔ m ≤ n.toNat := by
|
||||
rw [le_iff_toNat_le, toNat_ofNat_of_lt' h]
|
||||
|
||||
@[deprecated UInt32.lt_ofNat_iff (since := "2025-03-18")]
|
||||
theorem UInt32.toNat_lt_of_lt {n : UInt32} {m : Nat} (h : m < size) : n < ofNat m → n.toNat < m :=
|
||||
(UInt32.lt_ofNat_iff h).1
|
||||
|
||||
@[deprecated UInt32.ofNat_lt_iff (since := "2025-03-18")]
|
||||
theorem UInt32.lt_toNat_of_lt {n : UInt32} {m : Nat} (h : m < size) : ofNat m < n → m < n.toNat :=
|
||||
(UInt32.ofNat_lt_iff h).1
|
||||
|
||||
@[deprecated UInt32.le_ofNat_iff (since := "2025-03-18")]
|
||||
theorem UInt32.toNat_le_of_le {n : UInt32} {m : Nat} (h : m < size) : n ≤ ofNat m → n.toNat ≤ m :=
|
||||
(UInt32.le_ofNat_iff h).1
|
||||
|
||||
@[deprecated UInt32.ofNat_le_iff (since := "2025-03-18")]
|
||||
theorem UInt32.le_toNat_of_le {n : UInt32} {m : Nat} (h : m < size) : ofNat m ≤ n → m ≤ n.toNat :=
|
||||
(UInt32.ofNat_le_iff h).1
|
||||
|
||||
theorem UInt64.lt_ofNat_iff {n : UInt64} {m : Nat} (h : m < size) : n < ofNat m ↔ n.toNat < m := by
|
||||
rw [lt_iff_toNat_lt, toNat_ofNat_of_lt' h]
|
||||
theorem UInt64.ofNat_lt_iff {n : UInt64} {m : Nat} (h : m < size) : ofNat m < n ↔ m < n.toNat := by
|
||||
|
||||
@@ -603,7 +603,4 @@ and simplifies these to the function directly taking the value.
|
||||
(replicate n x).unattach = replicate n x.1 := by
|
||||
simp [unattach]
|
||||
|
||||
@[deprecated unattach_replicate (since := "2025-03-18")]
|
||||
abbrev unattach_mkVector := @unattach_replicate
|
||||
|
||||
end Vector
|
||||
|
||||
@@ -80,15 +80,9 @@ def elimAsList {motive : Vector α n → Sort u}
|
||||
/-- Make an empty vector with pre-allocated capacity. -/
|
||||
@[inline, expose] def emptyWithCapacity (capacity : Nat) : Vector α 0 := ⟨.emptyWithCapacity capacity, by simp⟩
|
||||
|
||||
@[deprecated emptyWithCapacity (since := "2025-03-12"), inherit_doc emptyWithCapacity]
|
||||
abbrev mkEmpty := @emptyWithCapacity
|
||||
|
||||
/-- Makes a vector of size `n` with all cells containing `v`. -/
|
||||
@[inline, expose] def replicate (n) (v : α) : Vector α n := ⟨Array.replicate n v, by simp⟩
|
||||
|
||||
@[deprecated replicate (since := "2025-03-18")]
|
||||
abbrev mkVector := @replicate
|
||||
|
||||
instance : Nonempty (Vector α 0) := ⟨#v[]⟩
|
||||
instance [Nonempty α] : Nonempty (Vector α n) := ⟨replicate _ Classical.ofNonempty⟩
|
||||
|
||||
|
||||
@@ -82,9 +82,6 @@ theorem countP_replicate {a : α} {n : Nat} : countP p (replicate n a) = if p a
|
||||
simp only [replicate_eq_mk_replicate, countP_mk]
|
||||
simp [Array.countP_replicate]
|
||||
|
||||
@[deprecated countP_replicate (since := "2025-03-18")]
|
||||
abbrev countP_mkVector := @countP_replicate
|
||||
|
||||
theorem boole_getElem_le_countP {p : α → Bool} {xs : Vector α n} (h : i < n) :
|
||||
(if p xs[i] then 1 else 0) ≤ xs.countP p := by
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
@@ -227,16 +224,10 @@ theorem count_eq_size {xs : Vector α n} : count a xs = n ↔ ∀ b ∈ xs, a =
|
||||
simp only [replicate_eq_mk_replicate, count_mk]
|
||||
simp
|
||||
|
||||
@[deprecated count_replicate_self (since := "2025-03-18")]
|
||||
abbrev count_mkVector_self := @count_replicate_self
|
||||
|
||||
theorem count_replicate {a b : α} {n : Nat} : count a (replicate n b) = if b == a then n else 0 := by
|
||||
simp only [replicate_eq_mk_replicate, count_mk]
|
||||
simp [Array.count_replicate]
|
||||
|
||||
@[deprecated count_replicate (since := "2025-03-18")]
|
||||
abbrev count_mkVector := @count_replicate
|
||||
|
||||
theorem count_le_count_map [BEq β] [LawfulBEq β] {xs : Vector α n} {f : α → β} {x : α} :
|
||||
count x xs ≤ count (f x) (map f xs) := by
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
|
||||
@@ -93,9 +93,6 @@ theorem eraseIdx_replicate {n : Nat} {a : α} {k : Nat} {h} :
|
||||
rw [replicate_eq_mk_replicate, eraseIdx_mk]
|
||||
simp [Array.eraseIdx_replicate, *]
|
||||
|
||||
@[deprecated eraseIdx_replicate (since := "2025-03-18")]
|
||||
abbrev eraseIdx_mkVector := @eraseIdx_replicate
|
||||
|
||||
theorem mem_eraseIdx_iff_getElem {x : α} {xs : Vector α n} {k} {h} : x ∈ xs.eraseIdx k h ↔ ∃ i w, i ≠ k ∧ xs[i]'w = x := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simp [Array.mem_eraseIdx_iff_getElem, *]
|
||||
|
||||
@@ -156,9 +156,6 @@ theorem extract_append_left {xs : Vector α n} {ys : Vector α m} :
|
||||
ext i h
|
||||
simp
|
||||
|
||||
@[deprecated extract_mkVector (since := "2025-03-18")]
|
||||
abbrev extract_mkVector := @extract_replicate
|
||||
|
||||
theorem extract_add_left {xs : Vector α n} {i j k : Nat} :
|
||||
xs.extract (i + j) k = ((xs.extract i k).extract j (k - i)).cast (by omega) := by
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
|
||||
@@ -130,31 +130,19 @@ theorem getElem_zero_flatten {xss : Vector (Vector α m) n} (h : 0 < n * m) :
|
||||
theorem findSome?_replicate : findSome? f (replicate n a) = if n = 0 then none else f a := by
|
||||
rw [replicate_eq_mk_replicate, findSome?_mk, Array.findSome?_replicate]
|
||||
|
||||
@[deprecated findSome?_replicate (since := "2025-03-18")]
|
||||
abbrev findSome?_mkVector := @findSome?_replicate
|
||||
|
||||
@[simp] theorem findSome?_replicate_of_pos (h : 0 < n) : findSome? f (replicate n a) = f a := by
|
||||
simp [findSome?_replicate, Nat.ne_of_gt h]
|
||||
|
||||
@[deprecated findSome?_replicate_of_pos (since := "2025-03-18")]
|
||||
abbrev findSome?_mkVector_of_pos := @findSome?_replicate_of_pos
|
||||
|
||||
-- Argument is unused, but used to decide whether `simp` should unfold.
|
||||
@[simp] theorem findSome?_replicate_of_isSome (_ : (f a).isSome) :
|
||||
findSome? f (replicate n a) = if n = 0 then none else f a := by
|
||||
simp [findSome?_replicate]
|
||||
|
||||
@[deprecated findSome?_replicate_of_isSome (since := "2025-03-18")]
|
||||
abbrev findSome?_mkVector_of_isSome := @findSome?_replicate_of_isSome
|
||||
|
||||
@[simp] theorem findSome?_replicate_of_isNone (h : (f a).isNone) :
|
||||
findSome? f (replicate n a) = none := by
|
||||
rw [Option.isNone_iff_eq_none] at h
|
||||
simp [findSome?_replicate, h]
|
||||
|
||||
@[deprecated findSome?_replicate_of_isNone (since := "2025-03-18")]
|
||||
abbrev findSome?_mkVector_of_isNone := @findSome?_replicate_of_isNone
|
||||
|
||||
/-! ### find? -/
|
||||
|
||||
@[simp, grind =] theorem find?_empty : find? p #v[] = none := rfl
|
||||
@@ -263,53 +251,32 @@ theorem find?_replicate :
|
||||
find? p (replicate n a) = if n = 0 then none else if p a then some a else none := by
|
||||
rw [replicate_eq_mk_replicate, find?_mk, Array.find?_replicate]
|
||||
|
||||
@[deprecated find?_replicate (since := "2025-03-18")]
|
||||
abbrev find?_mkVector := @find?_replicate
|
||||
|
||||
@[simp] theorem find?_replicate_of_size_pos (h : 0 < n) :
|
||||
find? p (replicate n a) = if p a then some a else none := by
|
||||
simp [find?_replicate, Nat.ne_of_gt h]
|
||||
|
||||
@[deprecated find?_replicate_of_size_pos (since := "2025-03-18")]
|
||||
abbrev find?_mkVector_of_length_pos := @find?_replicate_of_size_pos
|
||||
|
||||
@[simp] theorem find?_replicate_of_pos (h : p a) :
|
||||
find? p (replicate n a) = if n = 0 then none else some a := by
|
||||
simp [find?_replicate, h]
|
||||
|
||||
@[deprecated find?_replicate_of_pos (since := "2025-03-18")]
|
||||
abbrev find?_mkVector_of_pos := @find?_replicate_of_pos
|
||||
|
||||
@[simp] theorem find?_replicate_of_neg (h : ¬ p a) : find? p (replicate n a) = none := by
|
||||
simp [find?_replicate, h]
|
||||
|
||||
@[deprecated find?_replicate_of_neg (since := "2025-03-18")]
|
||||
abbrev find?_mkVector_of_neg := @find?_replicate_of_neg
|
||||
|
||||
-- This isn't a `@[simp]` lemma since there is already a lemma for `l.find? p = none` for any `l`.
|
||||
theorem find?_replicate_eq_none_iff {n : Nat} {a : α} {p : α → Bool} :
|
||||
(replicate n a).find? p = none ↔ n = 0 ∨ !p a := by
|
||||
simp [Classical.or_iff_not_imp_left]
|
||||
|
||||
@[deprecated find?_replicate_eq_none_iff (since := "2025-03-18")]
|
||||
abbrev find?_mkVector_eq_none_iff := @find?_replicate_eq_none_iff
|
||||
|
||||
@[simp] theorem find?_replicate_eq_some_iff {n : Nat} {a b : α} {p : α → Bool} :
|
||||
(replicate n a).find? p = some b ↔ n ≠ 0 ∧ p a ∧ a = b := by
|
||||
rw [replicate_eq_mk_replicate, find?_mk]
|
||||
simp
|
||||
|
||||
@[deprecated find?_replicate_eq_some_iff (since := "2025-03-18")]
|
||||
abbrev find?_mkVector_eq_some_iff := @find?_replicate_eq_some_iff
|
||||
|
||||
@[simp] theorem get_find?_replicate {n : Nat} {a : α} {p : α → Bool} (h) :
|
||||
((replicate n a).find? p).get h = a := by
|
||||
simp only [replicate_eq_mk_replicate, find?_mk]
|
||||
simp
|
||||
|
||||
@[deprecated get_find?_replicate (since := "2025-03-18")]
|
||||
abbrev get_find?_mkVector := @get_find?_replicate
|
||||
|
||||
@[grind =]
|
||||
theorem find?_pmap {P : α → Prop} {f : (a : α) → P a → β} {xs : Vector α n}
|
||||
(H : ∀ (a : α), a ∈ xs → P a) {p : β → Bool} :
|
||||
|
||||
@@ -287,9 +287,6 @@ set_option linter.indexVariables false in
|
||||
@[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) :
|
||||
(xs.eraseIdx i h).toArray = xs.toArray.eraseIdx i (by simp [h]) := rfl
|
||||
|
||||
@@ -474,9 +471,6 @@ theorem toArray_swapAt! {xs : Vector α n} {i x} :
|
||||
|
||||
@[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
|
||||
|
||||
@[simp] theorem toArray_inj {xs ys : Vector α n} : xs.toArray = ys.toArray ↔ xs = ys := by
|
||||
cases xs
|
||||
cases ys
|
||||
@@ -531,9 +525,6 @@ theorem toList_empty : (#v[] : Vector α 0).toList = [] := rfl
|
||||
theorem toList_emptyWithCapacity {cap} :
|
||||
(Vector.emptyWithCapacity (α := α) cap).toList = [] := rfl
|
||||
|
||||
@[deprecated toList_emptyWithCapacity (since := "2025-03-12")]
|
||||
abbrev toList_mkEmpty := @toList_emptyWithCapacity
|
||||
|
||||
theorem toList_eraseIdx {xs : Vector α n} {i} (h) :
|
||||
(xs.eraseIdx i h).toList = xs.toList.eraseIdx i := by simp [toList]
|
||||
|
||||
@@ -663,9 +654,6 @@ theorem toList_swap {xs : Vector α n} {i j} (hi hj) :
|
||||
|
||||
@[simp] theorem toList_replicate : (replicate n a).toList = List.replicate n a := rfl
|
||||
|
||||
@[deprecated toList_replicate (since := "2025-03-18")]
|
||||
abbrev toList_mkVector := @toList_replicate
|
||||
|
||||
theorem toList_inj {xs ys : Vector α n} : xs.toList = ys.toList ↔ xs = ys := by
|
||||
cases xs
|
||||
cases ys
|
||||
@@ -676,9 +664,6 @@ theorem toList_inj {xs ys : Vector α n} : xs.toList = ys.toList ↔ xs = ys :=
|
||||
simp only [toList, Array.toList_eq_nil_iff]
|
||||
exact ⟨by rintro rfl; simp_all, by rintro rfl; simpa using h⟩
|
||||
|
||||
@[deprecated toList_eq_nil_iff (since := "2025-04-04")]
|
||||
abbrev toList_eq_empty_iff {α n} (xs) := @toList_eq_nil_iff α n xs
|
||||
|
||||
@[simp] theorem mem_toList_iff {a : α} {xs : Vector α n} : a ∈ xs.toList ↔ a ∈ xs := by
|
||||
simp [toList]
|
||||
|
||||
@@ -784,35 +769,20 @@ theorem singleton_inj : #v[a] = #v[b] ↔ a = b := by
|
||||
|
||||
@[simp, grind =] theorem replicate_zero : replicate 0 a = #v[] := rfl
|
||||
|
||||
@[deprecated replicate_zero (since := "2025-03-18")]
|
||||
abbrev replicate_mkVector := @replicate_zero
|
||||
|
||||
@[grind =]
|
||||
theorem replicate_succ : replicate (n + 1) a = (replicate n a).push a := by
|
||||
simp [replicate, Array.replicate_succ]
|
||||
|
||||
@[deprecated replicate_succ (since := "2025-03-18")]
|
||||
abbrev replicate_mkVector_succ := @replicate_succ
|
||||
|
||||
@[simp] theorem replicate_inj : replicate n a = replicate n b ↔ n = 0 ∨ a = b := by
|
||||
simp [← toArray_inj, toArray_replicate, Array.replicate_inj]
|
||||
|
||||
@[deprecated replicate_inj (since := "2025-03-18")]
|
||||
abbrev mkVector_inj := @replicate_inj
|
||||
|
||||
@[simp] theorem _root_.Array.vector_mk_replicate {a : α} {n : Nat} :
|
||||
mk (n := n) (Array.replicate n a) (by simp) = replicate n a := rfl
|
||||
|
||||
@[deprecated _root_.Array.vector_mk_replicate (since := "2025-03-18")]
|
||||
abbrev _root_.Array.mk_mkArray := @_root_.Array.vector_mk_replicate
|
||||
|
||||
theorem replicate_eq_mk_replicate {a : α} {n : Nat} :
|
||||
replicate n a = mk (n := n) (Array.replicate n a) (by simp) := by
|
||||
simp
|
||||
|
||||
@[deprecated replicate_eq_mk_replicate (since := "2025-03-18")]
|
||||
abbrev mkVector_eq_mk_mkArray := @replicate_eq_mk_replicate
|
||||
|
||||
/-! ## L[i] and L[i]? -/
|
||||
|
||||
theorem getElem?_eq_none_iff {xs : Vector α n} : xs[i]? = none ↔ n ≤ i := by
|
||||
@@ -1373,9 +1343,6 @@ theorem mem_setIfInBounds {xs : Vector α n} {a : α} (hi : i < n) :
|
||||
rw [Bool.eq_iff_iff]
|
||||
simp +contextual
|
||||
|
||||
@[deprecated replicate_beq_replicate (since := "2025-03-18")]
|
||||
abbrev mkVector_beq_mkVector := @replicate_beq_replicate
|
||||
|
||||
@[simp] theorem reflBEq_iff [BEq α] [NeZero n] : ReflBEq (Vector α n) ↔ ReflBEq α := by
|
||||
match n, NeZero.ne n with
|
||||
| n + 1, _ =>
|
||||
@@ -2074,78 +2041,45 @@ theorem map_eq_flatMap {f : α → β} {xs : Vector α n} :
|
||||
|
||||
@[simp] theorem replicate_one : replicate 1 a = #v[a] := rfl
|
||||
|
||||
@[deprecated replicate_one (since := "2025-03-18")]
|
||||
abbrev replicate_mkVector_one := @replicate_one
|
||||
|
||||
/-- Variant of `replicate_succ` that prepends `a` at the beginning of the vector. -/
|
||||
theorem replicate_succ' : replicate (n + 1) a = (#v[a] ++ replicate n a).cast (by omega) := by
|
||||
rw [← toArray_inj]
|
||||
simp [Array.replicate_succ']
|
||||
|
||||
@[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
|
||||
unfold replicate
|
||||
simp only [mem_mk]
|
||||
simp
|
||||
|
||||
@[deprecated mem_replicate (since := "2025-03-18")]
|
||||
abbrev mem_mkVector := @mem_replicate
|
||||
|
||||
@[grind →] theorem eq_of_mem_replicate {a b : α} {n} (h : b ∈ replicate n a) : b = a := (mem_replicate.1 h).2
|
||||
|
||||
@[deprecated eq_of_mem_replicate (since := "2025-03-18")]
|
||||
abbrev eq_of_mem_mkVector := @eq_of_mem_replicate
|
||||
|
||||
theorem forall_mem_replicate {p : α → Prop} {a : α} {n} :
|
||||
(∀ b, b ∈ replicate n a → p b) ↔ n = 0 ∨ p a := by
|
||||
cases n <;> simp [mem_replicate]
|
||||
|
||||
@[deprecated forall_mem_replicate (since := "2025-03-18")]
|
||||
abbrev forall_mem_mkVector := @forall_mem_replicate
|
||||
|
||||
@[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
|
||||
simp [getElem?_def]
|
||||
|
||||
@[deprecated getElem?_replicate (since := "2025-03-18")]
|
||||
abbrev getElem?_mkVector := @getElem?_replicate
|
||||
|
||||
@[simp] theorem getElem?_replicate_of_lt {n : Nat} {i : Nat} (h : i < n) : (replicate n a)[i]? = some a := by
|
||||
simp [h]
|
||||
|
||||
@[deprecated getElem?_replicate_of_lt (since := "2025-03-18")]
|
||||
abbrev getElem?_mkVector_of_lt := @getElem?_replicate_of_lt
|
||||
|
||||
theorem eq_replicate_of_mem {a : α} {xs : Vector α n} (h : ∀ (b) (_ : b ∈ xs), b = a) : xs = replicate n a := by
|
||||
rw [← toArray_inj]
|
||||
simpa using Array.eq_replicate_of_mem (xs := xs.toArray) (by simpa using h)
|
||||
|
||||
@[deprecated eq_replicate_of_mem (since := "2025-03-18")]
|
||||
abbrev eq_mkVector_of_mem := @eq_replicate_of_mem
|
||||
|
||||
theorem eq_replicate_iff {a : α} {n} {xs : Vector α n} :
|
||||
xs = replicate n a ↔ ∀ (b) (_ : b ∈ xs), b = a := by
|
||||
rw [← toArray_inj]
|
||||
simpa using Array.eq_replicate_iff (xs := xs.toArray) (n := n)
|
||||
|
||||
@[deprecated eq_replicate_iff (since := "2025-03-18")]
|
||||
abbrev eq_mkVector_iff := @eq_replicate_iff
|
||||
|
||||
theorem map_eq_replicate_iff {xs : Vector α n} {f : α → β} {b : β} :
|
||||
xs.map f = replicate n b ↔ ∀ x ∈ xs, f x = b := by
|
||||
simp [eq_replicate_iff]
|
||||
|
||||
@[deprecated map_eq_replicate_iff (since := "2025-03-18")]
|
||||
abbrev map_eq_mkVector_iff := @map_eq_replicate_iff
|
||||
|
||||
@[simp] theorem map_const {xs : Vector α n} {b : β} : map (Function.const α b) xs = replicate n b :=
|
||||
map_eq_replicate_iff.mpr fun _ _ => rfl
|
||||
|
||||
@@ -2162,78 +2096,45 @@ theorem map_const' {xs : Vector α n} {b : β} : map (fun _ => b) xs = replicate
|
||||
rw [← toArray_inj]
|
||||
simp
|
||||
|
||||
@[deprecated set_replicate_self (since := "2025-03-18")]
|
||||
abbrev set_mkVector_self := @set_replicate_self
|
||||
|
||||
@[simp] theorem setIfInBounds_replicate_self : (replicate n a).setIfInBounds i a = replicate n a := by
|
||||
rw [← toArray_inj]
|
||||
simp
|
||||
|
||||
@[deprecated setIfInBounds_replicate_self (since := "2025-03-18")]
|
||||
abbrev setIfInBounds_mkVector_self := @setIfInBounds_replicate_self
|
||||
|
||||
@[simp] theorem replicate_append_replicate : replicate n a ++ replicate m a = replicate (n + m) a := by
|
||||
rw [← toArray_inj]
|
||||
simp
|
||||
|
||||
@[deprecated replicate_append_replicate (since := "2025-03-18")]
|
||||
abbrev mkVector_append_mkVector := @replicate_append_replicate
|
||||
|
||||
theorem append_eq_replicate_iff {xs : Vector α n} {ys : Vector α m} {a : α} :
|
||||
xs ++ ys = replicate (n + m) a ↔ xs = replicate n a ∧ ys = replicate m a := by
|
||||
simp [← toArray_inj, Array.append_eq_replicate_iff]
|
||||
|
||||
@[deprecated append_eq_replicate_iff (since := "2025-03-18")]
|
||||
abbrev append_eq_mkVector_iff := @append_eq_replicate_iff
|
||||
|
||||
theorem replicate_eq_append_iff {xs : Vector α n} {ys : Vector α m} {a : α} :
|
||||
replicate (n + m) a = xs ++ ys ↔ xs = replicate n a ∧ ys = replicate m a := by
|
||||
rw [eq_comm, append_eq_replicate_iff]
|
||||
|
||||
@[deprecated replicate_eq_append_iff (since := "2025-03-18")]
|
||||
abbrev mkVector_eq_append_iff := @replicate_eq_append_iff
|
||||
|
||||
@[simp] theorem map_replicate : (replicate n a).map f = replicate n (f a) := by
|
||||
rw [← toArray_inj]
|
||||
simp
|
||||
|
||||
@[deprecated map_replicate (since := "2025-03-18")]
|
||||
abbrev map_mkVector := @map_replicate
|
||||
|
||||
@[simp] theorem flatten_replicate_empty : (replicate n (#v[] : Vector α 0)).flatten = #v[] := by
|
||||
rw [← toArray_inj]
|
||||
simp
|
||||
|
||||
@[deprecated flatten_replicate_empty (since := "2025-03-18")]
|
||||
abbrev flatten_mkVector_empty := @flatten_replicate_empty
|
||||
|
||||
@[simp] theorem flatten_replicate_singleton : (replicate n #v[a]).flatten = (replicate n a).cast (by simp) := by
|
||||
ext i h
|
||||
simp
|
||||
|
||||
@[deprecated flatten_replicate_singleton (since := "2025-03-18")]
|
||||
abbrev flatten_mkVector_singleton := @flatten_replicate_singleton
|
||||
|
||||
@[simp] theorem flatten_replicate_replicate : (replicate n (replicate m a)).flatten = replicate (n * m) a := by
|
||||
ext i h
|
||||
simp
|
||||
|
||||
@[deprecated flatten_replicate_replicate (since := "2025-03-18")]
|
||||
abbrev flatten_mkVector_mkVector := @flatten_replicate_replicate
|
||||
|
||||
theorem flatMap_replicate {f : α → Vector β m} : (replicate n a).flatMap f = (replicate n (f a)).flatten := by
|
||||
ext i h
|
||||
simp
|
||||
|
||||
@[deprecated flatMap_replicate (since := "2025-03-18")]
|
||||
abbrev flatMap_mkVector := @flatMap_replicate
|
||||
|
||||
@[simp] theorem sum_replicate_nat {n : Nat} {a : Nat} : (replicate n a).sum = n * a := by
|
||||
simp [sum, toArray_replicate]
|
||||
|
||||
@[deprecated sum_replicate_nat (since := "2025-03-18")]
|
||||
abbrev sum_mkVector := @sum_replicate_nat
|
||||
|
||||
/-! ### reverse -/
|
||||
|
||||
theorem reverse_empty : reverse (#v[] : Vector α 0) = #v[] := rfl
|
||||
@@ -2335,9 +2236,6 @@ theorem flatMap_reverse {xs : Vector α n} {f : α → Vector β m} :
|
||||
rw [← toArray_inj]
|
||||
simp
|
||||
|
||||
@[deprecated reverse_replicate (since := "2025-03-18")]
|
||||
abbrev reverse_mkVector := @reverse_replicate
|
||||
|
||||
/-! ### extract -/
|
||||
|
||||
@[simp] theorem getElem_extract {as : Vector α n} {start stop : Nat}
|
||||
@@ -2662,15 +2560,9 @@ theorem back?_replicate {a : α} {n : Nat} :
|
||||
rw [replicate_eq_mk_replicate]
|
||||
simp only [back?_mk, Array.back?_replicate]
|
||||
|
||||
@[deprecated back?_replicate (since := "2025-03-18")]
|
||||
abbrev back?_mkVector := @back?_replicate
|
||||
|
||||
@[simp] theorem back_replicate [NeZero n] : (replicate n a).back = a := by
|
||||
simp [back_eq_getElem]
|
||||
|
||||
@[deprecated back_replicate (since := "2025-03-18")]
|
||||
abbrev back_mkVector := @back_replicate
|
||||
|
||||
/-! ### leftpad and rightpad -/
|
||||
|
||||
@[simp] theorem leftpad_mk {n : Nat} {a : α} {xs : Array α} (h : xs.size = m) :
|
||||
@@ -2811,9 +2703,6 @@ theorem pop_append {xs : Vector α n} {ys : Vector α m} :
|
||||
@[simp] theorem pop_replicate {n : Nat} {a : α} : (replicate n a).pop = replicate (n - 1) a := by
|
||||
ext <;> simp
|
||||
|
||||
@[deprecated pop_replicate (since := "2025-03-18")]
|
||||
abbrev pop_mkVector := @pop_replicate
|
||||
|
||||
/-! ## Logic -/
|
||||
|
||||
/-! ### any / all -/
|
||||
@@ -2969,16 +2858,10 @@ theorem all_filterMap {xs : Vector α n} {f : α → Option β} {p : β → Bool
|
||||
(replicate n a).any f = if n = 0 then false else f a := by
|
||||
induction n <;> simp_all [replicate_succ']
|
||||
|
||||
@[deprecated any_replicate (since := "2025-03-18")]
|
||||
abbrev any_mkVector := @any_replicate
|
||||
|
||||
@[simp] theorem all_replicate {n : Nat} {a : α} :
|
||||
(replicate n a).all f = if n = 0 then true else f a := by
|
||||
induction n <;> simp_all +contextual [replicate_succ']
|
||||
|
||||
@[deprecated all_replicate (since := "2025-03-18")]
|
||||
abbrev all_mkVector := @all_replicate
|
||||
|
||||
/-! ### replace -/
|
||||
|
||||
section replace
|
||||
@@ -3053,17 +2936,11 @@ theorem replace_extract {xs : Vector α n} {i : Nat} :
|
||||
match n, h with
|
||||
| n + 1, _ => simp_all [replicate_succ', replace_append]
|
||||
|
||||
@[deprecated replace_replicate_self (since := "2025-03-18")]
|
||||
abbrev replace_mkArray_self := @replace_replicate_self
|
||||
|
||||
@[simp] theorem replace_replicate_ne {a b c : α} (h : !b == a) :
|
||||
(replicate n a).replace b c = replicate n a := by
|
||||
rw [replace_of_not_mem]
|
||||
simp_all
|
||||
|
||||
@[deprecated replace_replicate_ne (since := "2025-03-18")]
|
||||
abbrev replace_mkArray_ne := @replace_replicate_ne
|
||||
|
||||
end replace
|
||||
|
||||
/-! Content below this point has not yet been aligned with `List` and `Array`. -/
|
||||
|
||||
@@ -216,9 +216,6 @@ theorem mapFinIdx_eq_replicate_iff {xs : Vector α n} {f : (i : Nat) → α →
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
simp [Array.mapFinIdx_eq_replicate_iff]
|
||||
|
||||
@[deprecated mapFinIdx_eq_replicate_iff (since := "2025-03-18")]
|
||||
abbrev mapFinIdx_eq_mkVector_iff := @mapFinIdx_eq_replicate_iff
|
||||
|
||||
@[simp, grind =] theorem mapFinIdx_reverse {xs : Vector α n} {f : (i : Nat) → α → (h : i < n) → β} :
|
||||
xs.reverse.mapFinIdx f = (xs.mapFinIdx (fun i a h => f (n - 1 - i) a (by omega))).reverse := by
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
@@ -351,9 +348,6 @@ theorem mapIdx_eq_replicate_iff {xs : Vector α n} {f : Nat → α → β} {b :
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
simp [Array.mapIdx_eq_replicate_iff]
|
||||
|
||||
@[deprecated mapIdx_eq_replicate_iff (since := "2025-03-18")]
|
||||
abbrev mapIdx_eq_mkVector_iff := @mapIdx_eq_replicate_iff
|
||||
|
||||
@[simp, grind =] theorem mapIdx_reverse {xs : Vector α n} {f : Nat → α → β} :
|
||||
xs.reverse.mapIdx f = (mapIdx (fun i => f (n - 1 - i)) xs).reverse := by
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
|
||||
@@ -163,9 +163,6 @@ theorem zipWith_replicate {a : α} {b : β} {n : Nat} :
|
||||
ext
|
||||
simp
|
||||
|
||||
@[deprecated zipWith_replicate (since := "2025-03-18")]
|
||||
abbrev zipWith_mkVector := @zipWith_replicate
|
||||
|
||||
theorem map_uncurry_zip_eq_zipWith {f : α → β → γ} {as : Vector α n} {bs : Vector β n} :
|
||||
map (Function.uncurry f) (as.zip bs) = zipWith f as bs := by
|
||||
rcases as with ⟨as, rfl⟩
|
||||
@@ -268,9 +265,6 @@ theorem zip_replicate {a : α} {b : β} {n : Nat} :
|
||||
zip (replicate n a) (replicate n b) = replicate n (a, b) := by
|
||||
ext <;> simp
|
||||
|
||||
@[deprecated zip_replicate (since := "2025-03-18")]
|
||||
abbrev zip_mkVector := @zip_replicate
|
||||
|
||||
/-! ### unzip -/
|
||||
|
||||
@[simp, grind =]
|
||||
@@ -320,7 +314,4 @@ theorem unzip_replicate {a : α} {b : β} {n : Nat} :
|
||||
unzip (replicate n (a, b)) = (replicate n a, replicate n b) := by
|
||||
ext1 <;> simp
|
||||
|
||||
@[deprecated unzip_replicate (since := "2025-03-18")]
|
||||
abbrev unzip_mkVector := @unzip_replicate
|
||||
|
||||
end Vector
|
||||
|
||||
@@ -130,7 +130,7 @@ If `grind!` is used, then only minimal indexable subexpressions are considered.
|
||||
syntax grindLR := patternIgnore("⇒" <|> "=>")
|
||||
/--
|
||||
The `.` modifier instructs `grind` to select a multi-pattern by traversing the conclusion of the
|
||||
theorem, and then the hypotheses from eft to right. We say this is the default modifier.
|
||||
theorem, and then the hypotheses from left to right. We say this is the default modifier.
|
||||
Each time it encounters a subexpression which covers an argument which was not
|
||||
previously covered, it adds that subexpression as a pattern, until all arguments have been covered.
|
||||
If `grind!` is used, then only minimal indexable subexpressions are considered.
|
||||
|
||||
216
src/Init/Grind/Config.lean
Normal file
216
src/Init/Grind/Config.lean
Normal file
@@ -0,0 +1,216 @@
|
||||
/-
|
||||
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.Core
|
||||
public section
|
||||
namespace Lean.Grind
|
||||
/--
|
||||
The configuration for `grind`.
|
||||
Passed to `grind` using, for example, the `grind (config := { matchEqs := true })` syntax.
|
||||
-/
|
||||
structure Config where
|
||||
/-- If `trace` is `true`, `grind` records used E-matching theorems and case-splits. -/
|
||||
trace : Bool := false
|
||||
/-- If `lax` is `true`, `grind` will silently ignore any parameters referring to non-existent theorems
|
||||
or for which no patterns can be generated. -/
|
||||
lax : Bool := false
|
||||
/-- If `premises` is `true`, `grind` will invoke the currently configured premise selecor on the current goal,
|
||||
and add attempt to use the resulting suggestions as premises to the `grind` tactic. -/
|
||||
premises : Bool := false
|
||||
/-- Maximum number of case-splits in a proof search branch. It does not include splits performed during normalization. -/
|
||||
splits : Nat := 9
|
||||
/-- Maximum number of E-matching (aka heuristic theorem instantiation) rounds before each case split. -/
|
||||
ematch : Nat := 5
|
||||
/--
|
||||
Maximum term generation.
|
||||
The input goal terms have generation 0. When we instantiate a theorem using a term from generation `n`,
|
||||
the new terms have generation `n+1`. Thus, this parameter limits the length of an instantiation chain. -/
|
||||
gen : Nat := 8
|
||||
/-- Maximum number of theorem instances generated using E-matching in a proof search tree branch. -/
|
||||
instances : Nat := 1000
|
||||
/-- If `matchEqs` is `true`, `grind` uses `match`-equations as E-matching theorems. -/
|
||||
matchEqs : Bool := true
|
||||
/-- If `splitMatch` is `true`, `grind` performs case-splitting on `match`-expressions during the search. -/
|
||||
splitMatch : Bool := true
|
||||
/-- If `splitIte` is `true`, `grind` performs case-splitting on `if-then-else` expressions during the search. -/
|
||||
splitIte : Bool := true
|
||||
/--
|
||||
If `splitIndPred` is `true`, `grind` performs case-splitting on inductive predicates.
|
||||
Otherwise, it performs case-splitting only on types marked with `[grind cases]` attribute. -/
|
||||
splitIndPred : Bool := false
|
||||
/--
|
||||
If `splitImp` is `true`, then given an implication `p → q` or `(h : p) → q h`, `grind` splits on `p`
|
||||
if the implication is true. Otherwise, it will split only if `p` is an arithmetic predicate.
|
||||
-/
|
||||
splitImp : Bool := false
|
||||
/-- Maximum number of heartbeats (in thousands) the canonicalizer can spend per definitional equality test. -/
|
||||
canonHeartbeats : Nat := 1000
|
||||
/-- If `ext` is `true`, `grind` uses extensionality theorems that have been marked with `[grind ext]`. -/
|
||||
ext : Bool := true
|
||||
/-- If `extAll` is `true`, `grind` uses any extensionality theorems available in the environment. -/
|
||||
extAll : Bool := false
|
||||
/--
|
||||
If `etaStruct` is `true`, then for each term `t : S` such that `S` is a structure,
|
||||
and is tagged with `[grind ext]`, `grind` adds the equation `t = ⟨t.1, ..., t.n⟩`
|
||||
which holds by reflexivity. Moreover, the extensionality theorem for `S` is not used.
|
||||
-/
|
||||
etaStruct : Bool := true
|
||||
/--
|
||||
If `funext` is `true`, `grind` creates new opportunities for applying function extensionality by case-splitting
|
||||
on equalities between lambda expressions.
|
||||
-/
|
||||
funext : Bool := true
|
||||
/-- TODO -/
|
||||
lookahead : Bool := true
|
||||
/-- If `verbose` is `false`, additional diagnostics information is not collected. -/
|
||||
verbose : Bool := true
|
||||
/-- If `clean` is `true`, `grind` uses `expose_names` and only generates accessible names. -/
|
||||
clean : Bool := true
|
||||
/--
|
||||
If `qlia` is `true`, `grind` may generate counterexamples for integer constraints
|
||||
using rational numbers, and ignoring divisibility constraints.
|
||||
This approach is cheaper but incomplete. -/
|
||||
qlia : Bool := false
|
||||
/--
|
||||
If `mbtc` is `true`, `grind` will use model-based theory combination for creating new case splits.
|
||||
See paper "Model-based Theory Combination" for details.
|
||||
-/
|
||||
mbtc : Bool := true
|
||||
/--
|
||||
When set to `true` (default: `true`), local definitions are unfolded during normalization and internalization.
|
||||
In other words, given a local context with an entry `x : t := e`, the free variable `x` is reduced to `e`.
|
||||
Note that this behavior is also available in `simp`, but there its default is `false` because `simp` is not
|
||||
always used as a terminal tactic, and it important to preserve the abstractions introduced by users.
|
||||
Additionally, in `grind` we observed that `zetaDelta` is particularly important when combined with function induction.
|
||||
In such scenarios, the same let-expressions can be introduced by function induction and also by unfolding the
|
||||
corresponding definition. We want to avoid a situation in which `zetaDelta` is not applied to let-declarations
|
||||
introduced by function induction while `zeta` unfolds the definition, causing a mismatch.
|
||||
Finally, note that congruence closure is less effective on terms containing many binders such as
|
||||
`lambda` and `let` expressions.
|
||||
-/
|
||||
zetaDelta := true
|
||||
/--
|
||||
When `true` (default: `true`), performs zeta reduction of let expressions during normalization.
|
||||
That is, `let x := v; e[x]` reduces to `e[v]`. See also `zetaDelta`.
|
||||
-/
|
||||
zeta := true
|
||||
/--
|
||||
When `true` (default: `true`), uses procedure for handling equalities over commutative rings.
|
||||
This solver also support commutative semirings, fields, and normalizer non-commutative rings and
|
||||
semirings.
|
||||
-/
|
||||
ring := true
|
||||
/--
|
||||
Maximum number of steps performed by the `ring` solver.
|
||||
A step is counted whenever one polynomial is used to simplify another.
|
||||
For example, given `x^2 + 1` and `x^2 * y^3 + x * y`, the first can be
|
||||
used to simplify the second to `-1 * y^3 + x * y`.
|
||||
-/
|
||||
ringSteps := 10000
|
||||
/--
|
||||
When `true` (default: `true`), uses procedure for handling linear arithmetic for `IntModule`, and
|
||||
`CommRing`.
|
||||
-/
|
||||
linarith := true
|
||||
/--
|
||||
When `true` (default: `true`), uses procedure for handling linear integer arithmetic for `Int` and `Nat`.
|
||||
-/
|
||||
cutsat := true
|
||||
/--
|
||||
When `true` (default: `true`), uses procedure for handling associative (and commutative) operators.
|
||||
-/
|
||||
ac := true
|
||||
/--
|
||||
Maximum number of steps performed by the `ac` solver.
|
||||
A step is counted whenever one AC equation is used to simplify another.
|
||||
For example, given `ma x z = w` and `max x (max y z) = x`, the first can be
|
||||
used to simplify the second to `max w y = x`.
|
||||
-/
|
||||
acSteps := 1000
|
||||
/--
|
||||
Maximum exponent eagerly evaluated while computing bounds for `ToInt` and
|
||||
the characteristic of a ring.
|
||||
-/
|
||||
exp : Nat := 2^20
|
||||
/--
|
||||
When `true` (default: `true`), automatically creates an auxiliary theorem to store the proof.
|
||||
-/
|
||||
abstractProof := true
|
||||
/--
|
||||
When `true` (default: `true`), enables the procedure for handling injective functions.
|
||||
In this mode, `grind` takes into account theorems such as:
|
||||
```
|
||||
@[grind inj] theorem double_inj : Function.Injective double
|
||||
```
|
||||
-/
|
||||
inj := true
|
||||
/--
|
||||
When `true` (default: `true`), enables the procedure for handling orders that implement
|
||||
at least `Std.IsPreorder`
|
||||
-/
|
||||
order := true
|
||||
/--
|
||||
When `true` (default: `true`), enables the legacy module `offset`. This module will be deleted in
|
||||
the future.
|
||||
-/
|
||||
offset := true
|
||||
deriving Inhabited, BEq
|
||||
|
||||
/--
|
||||
Configuration for interactive mode.
|
||||
We disable `clean := false`.
|
||||
-/
|
||||
structure ConfigInteractive extends Config where
|
||||
clean := false
|
||||
|
||||
/--
|
||||
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
|
||||
@@ -16,6 +16,16 @@ when selecting patterns.
|
||||
-/
|
||||
syntax grindLemmaMin := ppGroup("!" (Attr.grindMod ppSpace)? ident)
|
||||
|
||||
/-!
|
||||
`grind` tactic and related tactics.
|
||||
-/
|
||||
syntax grindErase := "-" ident
|
||||
/--
|
||||
The `!` modifier instructs `grind` to consider only minimal indexable subexpressions
|
||||
when selecting patterns.
|
||||
-/
|
||||
syntax grindParam := grindErase <|> grindLemma <|> grindLemmaMin
|
||||
|
||||
namespace Grind
|
||||
declare_syntax_cat grind_filter (behavior := both)
|
||||
|
||||
@@ -73,6 +83,10 @@ that may have redundant arguments.
|
||||
-/
|
||||
syntax (name := instantiate) "instantiate" (&" only")? (&" approx")? (" [" withoutPosition(thm,*,?) "]")? : grind
|
||||
|
||||
/-- Shorthand for `instantiate only` -/
|
||||
syntax (name := use) "use" " [" withoutPosition(thm,*,?) "]" : grind
|
||||
macro_rules | `(grind| use%$u [$ts:thm,*]) => `(grind| instantiate%$u only [$ts,*])
|
||||
|
||||
-- **Note**: Should we rename the following tactics to `trace_`?
|
||||
/-- Shows asserted facts. -/
|
||||
syntax (name := showAsserted) "show_asserted" ppSpace grindFilter : grind
|
||||
@@ -98,8 +112,17 @@ declare_syntax_cat grind_ref (behavior := both)
|
||||
syntax:max anchor : grind_ref
|
||||
syntax term : grind_ref
|
||||
|
||||
/--
|
||||
Performs a case-split on a logical connective, `match`-expression, `if-then-else`-expression,
|
||||
or inductive predicate. The argument is an anchor referencing one of the case-split candidates
|
||||
in the `grind` state. You can use `cases?` to select a specific candidate using a code action.
|
||||
-/
|
||||
syntax (name := cases) "cases " grind_ref : grind
|
||||
|
||||
/--
|
||||
A variant of `cases` that provides a code-action for selecting one of the candidate case-splits
|
||||
available in the `grind` state.
|
||||
-/
|
||||
syntax (name := casesTrace) "cases?" grindFilter : grind
|
||||
|
||||
/-- `done` succeeds iff there are no remaining goals. -/
|
||||
@@ -111,6 +134,14 @@ syntax (name := finish) "finish" : grind
|
||||
/-- `finish?` tries to close the current goal using `grind`'s default strategy and suggests a tactic script. -/
|
||||
syntax (name := finishTrace) "finish?" : grind
|
||||
|
||||
/--
|
||||
The `have` tactic is for adding opaque definitions and hypotheses to the local context of the main goal.
|
||||
The definitions forget their associated value and cannot be unfolded.
|
||||
|
||||
* `have h : t := e` adds the hypothesis `h : t` if `e` is a term of type `t`.
|
||||
* `have h := e` uses the type of `e` for `t`.
|
||||
* `have : t := e` and `have := e` use `this` for the name of the hypothesis.
|
||||
-/
|
||||
syntax (name := «have») "have" letDecl : grind
|
||||
|
||||
/-- Executes the given tactic block to close the current goal. -/
|
||||
@@ -128,8 +159,19 @@ Usually `· tac`, which enforces that the goal is closed by `tac`, should be pre
|
||||
-/
|
||||
syntax (name := focus) "focus " grindSeq : grind
|
||||
|
||||
/--
|
||||
`next => tac` focuses on the next goal and solves it using `tac`, or else fails.
|
||||
`next x₁ ... xₙ => tac` additionally renames the `n` most recent hypotheses with
|
||||
inaccessible names to the given names.
|
||||
-/
|
||||
syntax (name := next) "next " binderIdent* " => " grindSeq : grind
|
||||
|
||||
/--
|
||||
`· grindSeq` focuses on the main `grind` goal and tries to solve it using the given
|
||||
sequence of `grind` tactics.
|
||||
-/
|
||||
macro dot:patternIgnore("· " <|> ". ") s:grindSeq : grind => `(grind| next%$dot =>%$dot $s:grindSeq )
|
||||
|
||||
/--
|
||||
`any_goals tac` applies the tactic `tac` to every goal,
|
||||
concatenating the resulting goals for successful tactic applications.
|
||||
@@ -198,5 +240,20 @@ syntax (name := exposeNames) "expose_names" : grind
|
||||
but it sets the option only within the tactics `tacs`. -/
|
||||
syntax (name := setOption) "set_option " (ident (noWs "." noWs ident)?) ppSpace optionValue " in " grindSeq : grind
|
||||
|
||||
/--
|
||||
`set_config configItem+ in tacs` executes `tacs` with the updated configuration options `configItem+`
|
||||
-/
|
||||
syntax (name := setConfig) "set_config " configItem+ " in " grindSeq : grind
|
||||
|
||||
/--
|
||||
Proves `<term>` using the current `grind` state and default search strategy.
|
||||
-/
|
||||
syntax (name := haveSilent) "have" (ppSpace ident)? ppSpace ": " term : grind
|
||||
|
||||
/--
|
||||
Adds new case-splits using model-based theory combination.
|
||||
-/
|
||||
syntax (name := mbtc) "mbtc" : grind
|
||||
|
||||
end Grind
|
||||
end Lean.Parser.Tactic
|
||||
|
||||
@@ -4,11 +4,10 @@ Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Leonardo de Moura
|
||||
-/
|
||||
module
|
||||
|
||||
prelude
|
||||
public import Init.Data.Int.Linear
|
||||
public import Init.Grind.Ring.Field
|
||||
|
||||
public import Init.Data.Rat.Lemmas
|
||||
public section
|
||||
|
||||
namespace Lean.Grind
|
||||
@@ -153,7 +152,7 @@ init_grind_norm
|
||||
/- Pre theorems -/
|
||||
|
|
||||
/- Post theorems -/
|
||||
iff_eq heq_eq_eq
|
||||
iff_eq heq_eq_eq eq_self
|
||||
-- And
|
||||
and_true true_and and_false false_and and_assoc
|
||||
-- ite
|
||||
@@ -208,5 +207,7 @@ init_grind_norm
|
||||
Ring.intCast_mul
|
||||
Ring.intCast_pow
|
||||
Ring.intCast_sub
|
||||
-- Rationals
|
||||
Rat.ofScientific_def_eq_if Rat.zpow_neg
|
||||
|
||||
end Lean.Grind
|
||||
|
||||
@@ -107,6 +107,11 @@ Helper theorem for equality propagation
|
||||
theorem eq_of_le_of_le {α} [LE α] [Std.IsPartialOrder α] {a b : α} : a ≤ b → b ≤ a → a = b :=
|
||||
Std.IsPartialOrder.le_antisymm _ _
|
||||
|
||||
theorem eq_of_le_of_le_0 {α} [LE α] [Std.IsPartialOrder α] [Ring α]
|
||||
{a b : α} : a ≤ b + Int.cast (R := α) 0 → b ≤ a + Int.cast (R := α) 0 → a = b := by
|
||||
simp [Ring.intCast_zero, Semiring.add_zero]
|
||||
apply Std.IsPartialOrder.le_antisymm
|
||||
|
||||
/-!
|
||||
Transitivity
|
||||
-/
|
||||
|
||||
@@ -7,6 +7,7 @@ module
|
||||
prelude
|
||||
public import Init.Grind.Ring.Basic
|
||||
public import Init.Grind.Ring.Field
|
||||
public import Init.Grind.Ring.OfScientific
|
||||
public import Init.Grind.Ring.Envelope
|
||||
public import Init.Grind.Ring.CommSolver
|
||||
public import Init.Grind.Ring.CommSemiringAdapter
|
||||
|
||||
@@ -201,6 +201,9 @@ theorem pow_add (a : α) (k₁ k₂ : Nat) : a ^ (k₁ + k₂) = a^k₁ * a^k₂
|
||||
next => simp [pow_zero, mul_one]
|
||||
next k₂ ih => rw [Nat.add_succ, pow_succ, pow_succ, ih, mul_assoc]
|
||||
|
||||
theorem pow_add_congr (a r : α) (k k₁ k₂ : Nat) : k = k₁ + k₂ → a^k₁ * a^k₂ = r → a ^ k = r := by
|
||||
intros; subst k r; rw [pow_add]
|
||||
|
||||
theorem natCast_pow (x : Nat) (k : Nat) : ((x ^ k : Nat) : α) = (x : α) ^ k := by
|
||||
induction k
|
||||
next => simp [pow_zero, Nat.pow_zero, natCast_one]
|
||||
|
||||
29
src/Init/Grind/Ring/OfScientific.lean
Normal file
29
src/Init/Grind/Ring/OfScientific.lean
Normal file
@@ -0,0 +1,29 @@
|
||||
/-
|
||||
Copyright (c) 2025 Lean FRO, LLC. or its affiliates. All Rights Reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Kim Morrison
|
||||
-/
|
||||
module
|
||||
|
||||
prelude
|
||||
public import Init.Grind.Ring.Field
|
||||
public import Init.Data.OfScientific
|
||||
|
||||
public section
|
||||
|
||||
namespace Lean.Grind
|
||||
|
||||
attribute [local instance] Semiring.natCast
|
||||
|
||||
/--
|
||||
A type class that ensures that `OfScientific.ofScientific` is properly defined with respect to
|
||||
the field structure.
|
||||
-/
|
||||
class LawfulOfScientific (α : Type u) [Field α] [OfScientific α] : Prop where
|
||||
/--
|
||||
`OfScientific.ofScientific` is properly defined with respect to the field structure.
|
||||
-/
|
||||
ofScientific_def :
|
||||
OfScientific.ofScientific m s e = if s then (Nat.cast m : α) / 10^e else (Nat.cast m : α) * 10^e
|
||||
|
||||
end Lean.Grind
|
||||
@@ -7,221 +7,9 @@ module
|
||||
prelude
|
||||
public import Init.Core
|
||||
public import Init.Grind.Interactive
|
||||
public import Init.Grind.Config
|
||||
public section
|
||||
namespace Lean.Grind
|
||||
/--
|
||||
The configuration for `grind`.
|
||||
Passed to `grind` using, for example, the `grind (config := { matchEqs := true })` syntax.
|
||||
-/
|
||||
structure Config where
|
||||
/-- If `trace` is `true`, `grind` records used E-matching theorems and case-splits. -/
|
||||
trace : Bool := false
|
||||
/-- Maximum number of case-splits in a proof search branch. It does not include splits performed during normalization. -/
|
||||
splits : Nat := 9
|
||||
/-- Maximum number of E-matching (aka heuristic theorem instantiation) rounds before each case split. -/
|
||||
ematch : Nat := 5
|
||||
/--
|
||||
Maximum term generation.
|
||||
The input goal terms have generation 0. When we instantiate a theorem using a term from generation `n`,
|
||||
the new terms have generation `n+1`. Thus, this parameter limits the length of an instantiation chain. -/
|
||||
gen : Nat := 8
|
||||
/-- Maximum number of theorem instances generated using E-matching in a proof search tree branch. -/
|
||||
instances : Nat := 1000
|
||||
/-- If `matchEqs` is `true`, `grind` uses `match`-equations as E-matching theorems. -/
|
||||
matchEqs : Bool := true
|
||||
/-- If `splitMatch` is `true`, `grind` performs case-splitting on `match`-expressions during the search. -/
|
||||
splitMatch : Bool := true
|
||||
/-- If `splitIte` is `true`, `grind` performs case-splitting on `if-then-else` expressions during the search. -/
|
||||
splitIte : Bool := true
|
||||
/--
|
||||
If `splitIndPred` is `true`, `grind` performs case-splitting on inductive predicates.
|
||||
Otherwise, it performs case-splitting only on types marked with `[grind cases]` attribute. -/
|
||||
splitIndPred : Bool := false
|
||||
/--
|
||||
If `splitImp` is `true`, then given an implication `p → q` or `(h : p) → q h`, `grind` splits on `p`
|
||||
if the implication is true. Otherwise, it will split only if `p` is an arithmetic predicate.
|
||||
-/
|
||||
splitImp : Bool := false
|
||||
/-- Maximum number of heartbeats (in thousands) the canonicalizer can spend per definitional equality test. -/
|
||||
canonHeartbeats : Nat := 1000
|
||||
/-- If `ext` is `true`, `grind` uses extensionality theorems that have been marked with `[grind ext]`. -/
|
||||
ext : Bool := true
|
||||
/-- If `extAll` is `true`, `grind` uses any extensionality theorems available in the environment. -/
|
||||
extAll : Bool := false
|
||||
/--
|
||||
If `etaStruct` is `true`, then for each term `t : S` such that `S` is a structure,
|
||||
and is tagged with `[grind ext]`, `grind` adds the equation `t = ⟨t.1, ..., t.n⟩`
|
||||
which holds by reflexivity. Moreover, the extensionality theorem for `S` is not used.
|
||||
-/
|
||||
etaStruct : Bool := true
|
||||
/--
|
||||
If `funext` is `true`, `grind` creates new opportunities for applying function extensionality by case-splitting
|
||||
on equalities between lambda expressions.
|
||||
-/
|
||||
funext : Bool := true
|
||||
/-- TODO -/
|
||||
lookahead : Bool := true
|
||||
/-- If `verbose` is `false`, additional diagnostics information is not collected. -/
|
||||
verbose : Bool := true
|
||||
/-- If `clean` is `true`, `grind` uses `expose_names` and only generates accessible names. -/
|
||||
clean : Bool := true
|
||||
/--
|
||||
If `qlia` is `true`, `grind` may generate counterexamples for integer constraints
|
||||
using rational numbers, and ignoring divisibility constraints.
|
||||
This approach is cheaper but incomplete. -/
|
||||
qlia : Bool := false
|
||||
/--
|
||||
If `mbtc` is `true`, `grind` will use model-based theory combination for creating new case splits.
|
||||
See paper "Model-based Theory Combination" for details.
|
||||
-/
|
||||
mbtc : Bool := true
|
||||
/--
|
||||
When set to `true` (default: `true`), local definitions are unfolded during normalization and internalization.
|
||||
In other words, given a local context with an entry `x : t := e`, the free variable `x` is reduced to `e`.
|
||||
Note that this behavior is also available in `simp`, but there its default is `false` because `simp` is not
|
||||
always used as a terminal tactic, and it important to preserve the abstractions introduced by users.
|
||||
Additionally, in `grind` we observed that `zetaDelta` is particularly important when combined with function induction.
|
||||
In such scenarios, the same let-expressions can be introduced by function induction and also by unfolding the
|
||||
corresponding definition. We want to avoid a situation in which `zetaDelta` is not applied to let-declarations
|
||||
introduced by function induction while `zeta` unfolds the definition, causing a mismatch.
|
||||
Finally, note that congruence closure is less effective on terms containing many binders such as
|
||||
`lambda` and `let` expressions.
|
||||
-/
|
||||
zetaDelta := true
|
||||
/--
|
||||
When `true` (default: `true`), performs zeta reduction of let expressions during normalization.
|
||||
That is, `let x := v; e[x]` reduces to `e[v]`. See also `zetaDelta`.
|
||||
-/
|
||||
zeta := true
|
||||
/--
|
||||
When `true` (default: `true`), uses procedure for handling equalities over commutative rings.
|
||||
This solver also support commutative semirings, fields, and normalizer non-commutative rings and
|
||||
semirings.
|
||||
-/
|
||||
ring := true
|
||||
/--
|
||||
Maximum number of steps performed by the `ring` solver.
|
||||
A step is counted whenever one polynomial is used to simplify another.
|
||||
For example, given `x^2 + 1` and `x^2 * y^3 + x * y`, the first can be
|
||||
used to simplify the second to `-1 * y^3 + x * y`.
|
||||
-/
|
||||
ringSteps := 10000
|
||||
/--
|
||||
When `true` (default: `true`), uses procedure for handling linear arithmetic for `IntModule`, and
|
||||
`CommRing`.
|
||||
-/
|
||||
linarith := true
|
||||
/--
|
||||
When `true` (default: `true`), uses procedure for handling linear integer arithmetic for `Int` and `Nat`.
|
||||
-/
|
||||
cutsat := true
|
||||
/--
|
||||
When `true` (default: `true`), uses procedure for handling associative (and commutative) operators.
|
||||
-/
|
||||
ac := true
|
||||
/--
|
||||
Maximum number of steps performed by the `ac` solver.
|
||||
A step is counted whenever one AC equation is used to simplify another.
|
||||
For example, given `ma x z = w` and `max x (max y z) = x`, the first can be
|
||||
used to simplify the second to `max w y = x`.
|
||||
-/
|
||||
acSteps := 1000
|
||||
/--
|
||||
Maximum exponent eagerly evaluated while computing bounds for `ToInt` and
|
||||
the characteristic of a ring.
|
||||
-/
|
||||
exp : Nat := 2^20
|
||||
/--
|
||||
When `true` (default: `true`), automatically creates an auxiliary theorem to store the proof.
|
||||
-/
|
||||
abstractProof := true
|
||||
/--
|
||||
When `true` (default: `true`), enables the procedure for handling injective functions.
|
||||
In this mode, `grind` takes into account theorems such as:
|
||||
```
|
||||
@[grind inj] theorem double_inj : Function.Injective double
|
||||
```
|
||||
-/
|
||||
inj := true
|
||||
/--
|
||||
When `true` (default: `true`), enables the procedure for handling orders that implement
|
||||
at least `Std.IsPreorder`
|
||||
-/
|
||||
order := true
|
||||
/--
|
||||
When `true` (default: `true`), enables the legacy module `offset`. This module will be deleted in
|
||||
the future.
|
||||
-/
|
||||
offset := true
|
||||
deriving Inhabited, BEq
|
||||
|
||||
/--
|
||||
Configuration for interactive mode.
|
||||
We disable `clean := false`.
|
||||
-/
|
||||
structure ConfigInteractive extends Config where
|
||||
clean := false
|
||||
|
||||
/--
|
||||
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
|
||||
|
||||
/-!
|
||||
`grind` tactic and related tactics.
|
||||
-/
|
||||
syntax grindErase := "-" ident
|
||||
/--
|
||||
The `!` modifier instructs `grind` to consider only minimal indexable subexpressions
|
||||
when selecting patterns.
|
||||
-/
|
||||
syntax grindParam := grindErase <|> grindLemma <|> grindLemmaMin
|
||||
|
||||
open Parser.Tactic.Grind
|
||||
|
||||
/--
|
||||
|
||||
@@ -6,7 +6,7 @@ Authors: Robin Arnez
|
||||
module
|
||||
|
||||
prelude
|
||||
public import Init.Grind.Ring.Field
|
||||
public import Init.Grind.Ring.OfScientific
|
||||
public import Init.Data.Rat.Lemmas
|
||||
|
||||
public section
|
||||
@@ -56,4 +56,7 @@ instance : NoNatZeroDivisors Rat where
|
||||
change k * a = k * b at h₂
|
||||
simpa [← Rat.mul_assoc, Rat.inv_mul_cancel, h₁] using congrArg ((k : Rat)⁻¹ * ·) h₂
|
||||
|
||||
instance : LawfulOfScientific Rat where
|
||||
ofScientific_def {m s e} := by rw [Rat.ofScientific_def_eq_if]
|
||||
|
||||
end Lean.Grind
|
||||
|
||||
@@ -1099,6 +1099,7 @@ until `c` is known.
|
||||
| Or.inl h => hp h
|
||||
| Or.inr h => hq h
|
||||
|
||||
@[inline]
|
||||
instance [dp : Decidable p] : Decidable (Not p) :=
|
||||
match dp with
|
||||
| isTrue hp => isFalse (absurd hp)
|
||||
|
||||
@@ -447,18 +447,6 @@ theorem Decidable.by_contra [Decidable p] : (¬p → False) → p := of_not_not
|
||||
@[expose] protected def Or.by_cases' [Decidable q] {α : Sort u} (h : p ∨ q) (h₁ : p → α) (h₂ : q → α) : α :=
|
||||
if hq : q then h₂ hq else h₁ (h.resolve_right hq)
|
||||
|
||||
instance exists_prop_decidable {p} (P : p → Prop)
|
||||
[Decidable p] [∀ h, Decidable (P h)] : Decidable (∃ h, P h) :=
|
||||
if h : p then
|
||||
decidable_of_decidable_of_iff ⟨fun h2 => ⟨h, h2⟩, fun ⟨_, h2⟩ => h2⟩
|
||||
else isFalse fun ⟨h', _⟩ => h h'
|
||||
|
||||
instance forall_prop_decidable {p} (P : p → Prop)
|
||||
[Decidable p] [∀ h, Decidable (P h)] : Decidable (∀ h, P h) :=
|
||||
if h : p then
|
||||
decidable_of_decidable_of_iff ⟨fun h2 _ => h2, fun al => al h⟩
|
||||
else isTrue fun h2 => absurd h2 h
|
||||
|
||||
@[bool_to_prop] theorem decide_eq_true_iff {p : Prop} [Decidable p] : (decide p = true) ↔ p := by simp
|
||||
|
||||
@[simp, bool_to_prop] theorem decide_eq_decide {p q : Prop} {_ : Decidable p} {_ : Decidable q} :
|
||||
@@ -543,31 +531,15 @@ theorem Decidable.not_and_not_right [Decidable b] : ¬(a ∧ ¬b) ↔ (a → b)
|
||||
theorem Decidable.not_and_iff_not_or_not [Decidable a] : ¬(a ∧ b) ↔ ¬a ∨ ¬b :=
|
||||
⟨fun h => if ha : a then .inr (h ⟨ha, ·⟩) else .inl ha, not_and_of_not_or_not⟩
|
||||
|
||||
set_option linter.missingDocs false in
|
||||
@[deprecated Decidable.not_and_iff_not_or_not (since := "2025-03-18")]
|
||||
abbrev Decidable.not_and_iff_or_not_not := @Decidable.not_and_iff_not_or_not
|
||||
|
||||
theorem Decidable.not_and_iff_not_or_not' [Decidable b] : ¬(a ∧ b) ↔ ¬a ∨ ¬b :=
|
||||
⟨fun h => if hb : b then .inl (h ⟨·, hb⟩) else .inr hb, not_and_of_not_or_not⟩
|
||||
|
||||
set_option linter.missingDocs false in
|
||||
@[deprecated Decidable.not_and_iff_not_or_not' (since := "2025-03-18")]
|
||||
abbrev Decidable.not_and_iff_or_not_not' := @Decidable.not_and_iff_not_or_not'
|
||||
|
||||
theorem Decidable.or_iff_not_not_and_not [Decidable a] [Decidable b] : a ∨ b ↔ ¬(¬a ∧ ¬b) := by
|
||||
rw [← not_or, not_not]
|
||||
|
||||
set_option linter.missingDocs false in
|
||||
@[deprecated Decidable.or_iff_not_not_and_not (since := "2025-03-18")]
|
||||
abbrev Decidable.or_iff_not_and_not := @Decidable.or_iff_not_not_and_not
|
||||
|
||||
theorem Decidable.and_iff_not_not_or_not [Decidable a] [Decidable b] : a ∧ b ↔ ¬(¬a ∨ ¬b) := by
|
||||
rw [← not_and_iff_not_or_not, not_not]
|
||||
|
||||
set_option linter.missingDocs false in
|
||||
@[deprecated Decidable.and_iff_not_not_or_not (since := "2025-03-18")]
|
||||
abbrev Decidable.and_iff_not_or_not := @Decidable.and_iff_not_not_or_not
|
||||
|
||||
theorem Decidable.imp_iff_right_iff [Decidable a] : (a → b ↔ b) ↔ a ∨ b :=
|
||||
Iff.intro
|
||||
(fun h => (Decidable.em a).imp_right fun ha' => h.mp fun ha => (ha' ha).elim)
|
||||
|
||||
@@ -8,6 +8,7 @@ module
|
||||
prelude
|
||||
public import Init.Data.String.Basic
|
||||
import Init.Data.String.Iterator
|
||||
import Init.Data.String.Modify
|
||||
|
||||
public section
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ module
|
||||
|
||||
prelude
|
||||
public import Init.Data.ToString.Basic
|
||||
import Init.Data.String.Basic
|
||||
import Init.Data.String.Modify
|
||||
|
||||
public section
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ A restricted version of `IO` in which mutable state is the only side effect.
|
||||
|
||||
It is possible to run `ST` computations in a non-monadic context using `runST`.
|
||||
-/
|
||||
abbrev ST (σ : Type) (α : Type) := Void σ → ST.Out σ α
|
||||
@[expose] def ST (σ : Type) (α : Type) := Void σ → ST.Out σ α
|
||||
|
||||
namespace ST
|
||||
|
||||
|
||||
@@ -6,9 +6,9 @@ Authors: Chris Lovett
|
||||
module
|
||||
|
||||
prelude
|
||||
public import Init.Data.String.Extra
|
||||
public import Init.System.FilePath
|
||||
import Init.Data.String.TakeDrop
|
||||
import Init.Data.String.Modify
|
||||
|
||||
public section
|
||||
|
||||
|
||||
@@ -2317,6 +2317,12 @@ Theorems tagged with the `wf_preprocess` attribute are used during the processin
|
||||
by well-founded recursion. They are applied to the function's body to add additional hypotheses,
|
||||
such as replacing `if c then _ else _` with `if h : c then _ else _` or `xs.map` with
|
||||
`xs.attach.map`. Also see `wfParam`.
|
||||
|
||||
Warning: These rewrites are only applied to the declaration for the purpose of the logical
|
||||
definition, but do not affect the compiled code. In particular they can cause a function definition
|
||||
that diverges as compiled to be accepted without an explicit `partial` keyword, for example if they
|
||||
remove irrelevant subterms or change the evaluation order by hiding terms under binders. Therefore
|
||||
avoid tagging theorems with `[wf_preprocess]` unless they preserve also operational behavior.
|
||||
-/
|
||||
syntax (name := wf_preprocess) "wf_preprocess" (Tactic.simpPre <|> Tactic.simpPost)? patternIgnore("← " <|> "<- ")? (ppSpace prio)? : attr
|
||||
|
||||
|
||||
@@ -102,9 +102,6 @@ theorem fixF_eq (x : α) (acx : Acc r x) : fixF F x acx = F x (fun (y : α) (p :
|
||||
induction acx with
|
||||
| intro x r _ => exact rfl
|
||||
|
||||
@[deprecated fixF_eq (since := "2025-04-04")]
|
||||
abbrev fixFEq := @fixF_eq
|
||||
|
||||
end
|
||||
|
||||
variable {α : Sort u} {C : α → Sort v} {r : α → α → Prop}
|
||||
|
||||
@@ -7,7 +7,7 @@ module
|
||||
|
||||
prelude
|
||||
public import Init.System.FilePath
|
||||
import Init.Data.String.Basic
|
||||
import Init.Data.String.Modify
|
||||
|
||||
public section
|
||||
|
||||
|
||||
@@ -48,5 +48,26 @@ partial def inferMeta (decls : Array Decl) : CompilerM Unit := do
|
||||
modifyEnv (setDeclMeta · decl.name)
|
||||
setClosureMeta decl
|
||||
|
||||
/--
|
||||
Checks meta availability just before `evalConst`. This is a "last line of defense" as accesses
|
||||
should have been checked at declaration time in case of attributes. We do not solely want to rely on
|
||||
errors from the interpreter itself as those depend on whether we are running in the server.
|
||||
-/
|
||||
@[export lean_eval_check_meta]
|
||||
private partial def evalCheckMeta (env : Environment) (declName : Name) : Except String Unit := do
|
||||
if !env.header.isModule then
|
||||
return
|
||||
go declName |>.run' {}
|
||||
where go (ref : Name) : StateT NameSet (Except String) Unit := do
|
||||
if (← get).contains ref then
|
||||
return
|
||||
modify (·.insert ref)
|
||||
if let some localDecl := declMapExt.getState env |>.find? ref then
|
||||
for ref in collectUsedFDecls localDecl do
|
||||
go ref
|
||||
else
|
||||
if getIRPhases env ref == .runtime then
|
||||
throw s!"Cannot evaluate constant `{declName}` as it uses `{ref}` which is neither marked nor imported as `meta`"
|
||||
|
||||
builtin_initialize
|
||||
registerTraceClass `compiler.ir.inferMeta
|
||||
|
||||
@@ -173,9 +173,9 @@ def ofLCNFLit : LCNF.LitValue → Value
|
||||
-- TODO: We could make this much more precise but the payoff is questionable
|
||||
| .str .. => .top
|
||||
|
||||
partial def proj : Value → Nat → Value
|
||||
partial def proj (env : Environment) : Value → Nat → Value
|
||||
| .ctor _ vs , i => vs.getD i bot
|
||||
| .choice vs, i => vs.foldl (fun r v => merge r (proj v i)) bot
|
||||
| .choice vs, i => vs.foldl (fun r v => widening env r (proj env v i)) bot
|
||||
| v, _ => v
|
||||
|
||||
/--
|
||||
@@ -351,8 +351,9 @@ def findArgValue (arg : Arg) : InterpM Value := do
|
||||
Update the assignment of `var` by merging the current value with `newVal`.
|
||||
-/
|
||||
def updateVarAssignment (var : FVarId) (newVal : Value) : InterpM Unit := do
|
||||
let env ← getEnv
|
||||
let val ← findVarValue var
|
||||
let updatedVal := .merge val newVal
|
||||
let updatedVal := .widening env val newVal
|
||||
modifyAssignment (·.insert var updatedVal)
|
||||
|
||||
/--
|
||||
@@ -378,10 +379,11 @@ a partial application and set the values of the remaining parameters to
|
||||
-/
|
||||
def updateFunDeclParamsAssignment (params : Array Param) (args : Array Arg) : InterpM Bool := do
|
||||
let mut ret := false
|
||||
let env ← getEnv
|
||||
for param in params, arg in args do
|
||||
let paramVal ← findVarValue param.fvarId
|
||||
let argVal ← findArgValue arg
|
||||
let newVal := .merge paramVal argVal
|
||||
let newVal := .widening env paramVal argVal
|
||||
if newVal != paramVal then
|
||||
modifyAssignment (·.insert param.fvarId newVal)
|
||||
ret := true
|
||||
@@ -460,7 +462,9 @@ where
|
||||
interpLetValue (letVal : LetValue) : InterpM Value := do
|
||||
match letVal with
|
||||
| .lit val => return .ofLCNFLit val
|
||||
| .proj _ idx struct => return (← findVarValue struct).proj idx
|
||||
| .proj _ idx struct =>
|
||||
let env ← getEnv
|
||||
return (← findVarValue struct).proj env idx
|
||||
| .const declName _ args =>
|
||||
let env ← getEnv
|
||||
args.forM handleFunArg
|
||||
|
||||
@@ -113,30 +113,6 @@ where go (isMeta isPublic : Bool) (decl : Decl) : StateT NameSet CompilerM Unit
|
||||
if let some refDecl ← getLocalDecl? ref then
|
||||
go isMeta isPublic refDecl
|
||||
|
||||
/--
|
||||
Checks meta availability just before `evalConst`. This is a "last line of defense" as accesses
|
||||
should have been checked at declaration time in case of attributes. We do not solely want to rely on
|
||||
errors from the interpreter itself as those depend on whether we are running in the server.
|
||||
-/
|
||||
@[export lean_eval_check_meta]
|
||||
private partial def evalCheckMeta (env : Environment) (declName : Name) : Except String Unit := do
|
||||
if !env.header.isModule then
|
||||
return
|
||||
let some decl := getDeclCore? env baseExt declName
|
||||
| return -- We might not have the LCNF available, in which case there's nothing we can do
|
||||
go decl |>.run' {}
|
||||
where go (decl : Decl) : StateT NameSet (Except String) Unit :=
|
||||
decl.value.forCodeM fun code =>
|
||||
for ref in collectUsedDecls code do
|
||||
if (← get).contains ref then
|
||||
continue
|
||||
modify (·.insert ref)
|
||||
if let some localDecl := baseExt.getState env |>.find? ref then
|
||||
go localDecl
|
||||
else
|
||||
if getIRPhases env ref == .runtime then
|
||||
throw s!"Cannot evaluate constant `{declName}` as it uses `{ref}` which is neither marked nor imported as `meta`"
|
||||
|
||||
/--
|
||||
Checks that imports necessary for inlining/specialization are public as otherwise we may run into
|
||||
unknown declarations at the point of inlining/specializing. This is a limitation that we want to
|
||||
|
||||
@@ -1,72 +1,217 @@
|
||||
/-
|
||||
Copyright (c) 2018 Microsoft Corporation. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Author: Leonardo de Moura
|
||||
Author: Leonardo de Moura, Robin Arnez
|
||||
-/
|
||||
module
|
||||
|
||||
prelude
|
||||
public import Lean.Data.Name
|
||||
import Init.Data.String.Iterator
|
||||
|
||||
public section
|
||||
public import Init.Prelude
|
||||
import Init.Data.String.Termination
|
||||
|
||||
namespace String
|
||||
|
||||
private def mangleAux : Nat → String.Iterator → String → String
|
||||
| 0, _, r => r
|
||||
| i+1, it, r =>
|
||||
let c := it.curr
|
||||
if c.isAlpha || c.isDigit then
|
||||
mangleAux i it.next (r.push c)
|
||||
else if c = '_' then
|
||||
mangleAux i it.next (r ++ "__")
|
||||
else if c.toNat < 0x100 then
|
||||
let n := c.toNat
|
||||
let r := r ++ "_x"
|
||||
let r := r.push <| Nat.digitChar (n / 0x10)
|
||||
let r := r.push <| Nat.digitChar (n % 0x10)
|
||||
mangleAux i it.next r
|
||||
else if c.toNat < 0x10000 then
|
||||
let n := c.toNat
|
||||
let r := r ++ "_u"
|
||||
let r := r.push <| Nat.digitChar (n / 0x1000)
|
||||
let n := n % 0x1000
|
||||
let r := r.push <| Nat.digitChar (n / 0x100)
|
||||
let n := n % 0x100
|
||||
let r := r.push <| Nat.digitChar (n / 0x10)
|
||||
let r := r.push <| Nat.digitChar (n % 0x10)
|
||||
mangleAux i it.next r
|
||||
else
|
||||
let n := c.toNat
|
||||
let r := r ++ "_U"
|
||||
let ds := Nat.toDigits 16 n
|
||||
let r := Nat.repeat (·.push '0') (8 - ds.length) r
|
||||
let r := ds.foldl (fun r c => r.push c) r
|
||||
mangleAux i it.next r
|
||||
def digitChar (n : UInt32) (h : n < 16) : Char :=
|
||||
if h' : n < 10 then ⟨n + 48, ?_⟩
|
||||
else ⟨n + 87, ?_⟩
|
||||
where finally all_goals
|
||||
simp_all [UInt32.lt_iff_toNat_lt, UInt32.isValidChar, Nat.isValidChar]; omega
|
||||
|
||||
def mangle (s : String) : String :=
|
||||
mangleAux s.length s.mkIterator ""
|
||||
def pushHex (n : Nat) (val : UInt32) (s : String) : String :=
|
||||
match n with
|
||||
| 0 => s
|
||||
| k + 1 =>
|
||||
let i := (val >>> (4 * k.toUInt32)) &&& 15
|
||||
pushHex k val (s.push (digitChar i ?_))
|
||||
where finally
|
||||
have := Nat.and_two_pow_sub_one_eq_mod (n := 4)
|
||||
simp only [Nat.reducePow, Nat.add_one_sub_one] at this
|
||||
simp [i, UInt32.lt_iff_toNat_lt, this]; omega
|
||||
|
||||
|
||||
def mangleAux (s : String) (pos : s.ValidPos) (r : String) : String :=
|
||||
if h : pos = s.endValidPos then r else
|
||||
let c := pos.get h
|
||||
let pos := pos.next h
|
||||
if c.isAlpha || c.isDigit then
|
||||
mangleAux s pos (r.push c)
|
||||
else if c = '_' then
|
||||
mangleAux s pos (r ++ "__")
|
||||
else if c.toNat < 0x100 then
|
||||
mangleAux s pos (pushHex 2 c.val (r ++ "_x"))
|
||||
else if c.toNat < 0x10000 then
|
||||
mangleAux s pos (pushHex 4 c.val (r ++ "_u"))
|
||||
else
|
||||
mangleAux s pos (pushHex 8 c.val (r ++ "_U"))
|
||||
termination_by pos
|
||||
|
||||
public def mangle (s : String) : String :=
|
||||
mangleAux s s.startValidPos ""
|
||||
|
||||
end String
|
||||
|
||||
namespace Lean
|
||||
|
||||
private def Name.mangleAux : Name → String
|
||||
def checkLowerHex : Nat → (s : String) → s.ValidPos → Bool
|
||||
| 0, _, _ => true
|
||||
| k + 1, s, pos =>
|
||||
if h : pos = s.endValidPos then
|
||||
false
|
||||
else
|
||||
let ch := pos.get h
|
||||
(ch.isDigit || (ch.val >= 97 && ch.val <= 102)) && -- 0-9a-f
|
||||
checkLowerHex k s (pos.next h)
|
||||
|
||||
def fromHex? (c : Char) : Option Nat :=
|
||||
if c.isDigit then
|
||||
some (c.val - 48).toNat
|
||||
else if c.val >= 97 && c.val <= 102 then
|
||||
some (c.val - 87).toNat
|
||||
else none
|
||||
|
||||
def parseLowerHex? (k : Nat) (s : String) (p : s.ValidPos) (acc : Nat) :
|
||||
Option (s.ValidPos × Nat) :=
|
||||
match k with
|
||||
| 0 => some (p, acc)
|
||||
| k + 1 =>
|
||||
if h : p = s.endValidPos then
|
||||
none
|
||||
else
|
||||
match fromHex? (p.get h) with
|
||||
| some d => parseLowerHex? k s (p.next h) (acc <<< 4 ||| d)
|
||||
| none => none
|
||||
|
||||
theorem lt_of_parseLowerHex?_eq_some {k : Nat} {s : String} {p q : s.ValidPos} {acc : Nat}
|
||||
{r : Nat} (hk : 0 < k) : parseLowerHex? k s p acc = some (q, r) → p < q := by
|
||||
fun_induction parseLowerHex? with
|
||||
| case1 => simp at hk
|
||||
| case2 => simp
|
||||
| case3 p acc k h d x ih =>
|
||||
match k with
|
||||
| 0 => simpa [parseLowerHex?] using fun h _ => h ▸ p.lt_next
|
||||
| k + 1 => exact fun h => String.ValidPos.lt_trans p.lt_next (ih (by simp) h)
|
||||
| case4 => simp
|
||||
|
||||
def checkDisambiguation (s : String) (p : s.ValidPos) : Bool :=
|
||||
if h : _ then
|
||||
let b := p.get h
|
||||
if b = '_' then
|
||||
checkDisambiguation s (p.next h)
|
||||
else if b = 'x' then
|
||||
checkLowerHex 2 s (p.next h)
|
||||
else if b = 'u' then
|
||||
checkLowerHex 4 s (p.next h)
|
||||
else if b = 'U' then
|
||||
checkLowerHex 8 s (p.next h)
|
||||
else if b.val >= 48 && b.val <= 57 then
|
||||
true
|
||||
else false
|
||||
else true
|
||||
termination_by p
|
||||
|
||||
def needDisambiguation (prev : Name) (next : String) : Bool :=
|
||||
(match prev with
|
||||
| .str _ s => ∃ h, (s.endValidPos.prev h).get (by simp) = '_'
|
||||
| _ => false) || checkDisambiguation next next.startValidPos
|
||||
|
||||
def Name.mangleAux : Name → String
|
||||
| Name.anonymous => ""
|
||||
| Name.str p s =>
|
||||
let m := String.mangle s
|
||||
match p with
|
||||
| Name.anonymous => m
|
||||
| p => mangleAux p ++ "_" ++ m
|
||||
| Name.num p n => mangleAux p ++ "_" ++ toString n ++ "_"
|
||||
| Name.anonymous =>
|
||||
if checkDisambiguation m m.startValidPos then "00" ++ m else m
|
||||
| p =>
|
||||
let m1 := mangleAux p
|
||||
m1 ++ (if needDisambiguation p m then "_00" else "_") ++ m
|
||||
| Name.num p n =>
|
||||
match p with
|
||||
| Name.anonymous => n.repr ++ "_"
|
||||
| p =>
|
||||
mangleAux p ++ "_" ++ n.repr ++ "_"
|
||||
|
||||
@[export lean_name_mangle]
|
||||
def Name.mangle (n : Name) (pre : String := "l_") : String :=
|
||||
public def Name.mangle (n : Name) (pre : String := "l_") : String :=
|
||||
pre ++ Name.mangleAux n
|
||||
|
||||
@[export lean_mk_module_initialization_function_name]
|
||||
def mkModuleInitializationFunctionName (moduleName : Name) : String :=
|
||||
public def mkModuleInitializationFunctionName (moduleName : Name) : String :=
|
||||
"initialize_" ++ moduleName.mangle ""
|
||||
|
||||
-- assumes `s` has been generated `Name.mangle n ""`
|
||||
def Name.demangleAux (s : String) (p₀ : s.ValidPos) (res : Name)
|
||||
(acc : String) (ucount : Nat) : Name :=
|
||||
if hp₀ : p₀ = s.endValidPos then res.str (acc.pushn '_' (ucount / 2)) else
|
||||
let ch := p₀.get hp₀
|
||||
let p := p₀.next hp₀
|
||||
if ch = '_' then demangleAux s p res acc (ucount + 1) else
|
||||
if ucount % 2 = 0 then
|
||||
demangleAux s p res (acc.pushn '_' (ucount / 2) |>.push ch) 0
|
||||
else if ch.isDigit then
|
||||
let res := res.str (acc.pushn '_' (ucount / 2))
|
||||
if h : ch = '0' ∧ ∃ h : p ≠ s.endValidPos, p.get h = '0' then
|
||||
demangleAux s (p.next h.2.1) res "" 0
|
||||
else
|
||||
decodeNum s p res (ch.val - 48).toNat
|
||||
else
|
||||
match ch, h₁ : parseLowerHex? 2 s p 0 with
|
||||
| 'x', some (q, v) =>
|
||||
let acc := acc.pushn '_' (ucount / 2)
|
||||
have : p₀ < q := String.ValidPos.lt_trans p₀.lt_next (lt_of_parseLowerHex?_eq_some (by decide) h₁)
|
||||
demangleAux s q res (acc.push (Char.ofNat v)) 0
|
||||
| _, _ =>
|
||||
match ch, h₂ : parseLowerHex? 4 s p 0 with
|
||||
| 'u', some (q, v) =>
|
||||
let acc := acc.pushn '_' (ucount / 2)
|
||||
have : p₀ < q := String.ValidPos.lt_trans p₀.lt_next (lt_of_parseLowerHex?_eq_some (by decide) h₂)
|
||||
demangleAux s q res (acc.push (Char.ofNat v)) 0
|
||||
| _, _ =>
|
||||
match ch, h₃ : parseLowerHex? 8 s p 0 with
|
||||
| 'U', some (q, v) =>
|
||||
let acc := acc.pushn '_' (ucount / 2)
|
||||
have : p₀ < q := String.ValidPos.lt_trans p₀.lt_next (lt_of_parseLowerHex?_eq_some (by decide) h₃)
|
||||
demangleAux s q res (acc.push (Char.ofNat v)) 0
|
||||
| _, _ => demangleAux s p (res.str acc) ("".pushn '_' (ucount / 2) |>.push ch) 0
|
||||
termination_by p₀
|
||||
where
|
||||
decodeNum (s : String) (p : s.ValidPos) (res : Name) (n : Nat) : Name :=
|
||||
if h : p = s.endValidPos then res.num n else
|
||||
let ch := p.get h
|
||||
let p := p.next h
|
||||
if ch.isDigit then
|
||||
decodeNum s p res (n * 10 + (ch.val - 48).toNat)
|
||||
else -- assume ch = '_'
|
||||
let res := res.num n
|
||||
if h : p = s.endValidPos then res else
|
||||
nameStart s (p.next h) res -- assume s.get' p h = '_'
|
||||
termination_by p
|
||||
nameStart (s : String) (p : s.ValidPos) (res : Name) : Name :=
|
||||
if h : p = s.endValidPos then res else
|
||||
let ch := p.get h
|
||||
let p := p.next h
|
||||
if ch.isDigit then
|
||||
if h : ch = '0' ∧ ∃ h : p ≠ s.endValidPos, p.get h = '0' then
|
||||
demangleAux s (p.next h.2.1) res "" 0
|
||||
else
|
||||
decodeNum s p res (ch.val - 48).toNat
|
||||
else if ch = '_' then
|
||||
demangleAux s p res "" 1
|
||||
else
|
||||
demangleAux s p res (String.singleton ch) 0
|
||||
termination_by p
|
||||
|
||||
/-- Assuming `s` has been produced by `Name.mangle _ ""`, return the original name. -/
|
||||
public def Name.demangle (s : String) : Name :=
|
||||
demangleAux.nameStart s s.startValidPos .anonymous
|
||||
|
||||
/--
|
||||
Returns the demangled version of `s`, if it's the result of `Name.mangle _ ""`. Otherwise returns
|
||||
`none`.
|
||||
-/
|
||||
public def Name.demangle? (s : String) : Option Name :=
|
||||
let n := demangle s
|
||||
if mangleAux n = s then some n else none
|
||||
|
||||
-- For correctness of mangle/demangle, see https://gist.github.com/Rob23oba/5ddef42a1743858e9334461ca57c4be8
|
||||
|
||||
end Lean
|
||||
|
||||
@@ -508,11 +508,6 @@ def isDefinition : ConstantInfo → Bool
|
||||
| .defnInfo _ => true
|
||||
| _ => false
|
||||
|
||||
@[deprecated "May be inaccurate for theorems imported under the module system, use `Lean.getOriginalConstKind?` instead" (since := "2025-04-24")]
|
||||
def isTheorem : ConstantInfo → Bool
|
||||
| .thmInfo _ => true
|
||||
| _ => false
|
||||
|
||||
def inductiveVal! : ConstantInfo → InductiveVal
|
||||
| .inductInfo val => val
|
||||
| _ => panic! "Expected a `ConstantInfo.inductInfo`."
|
||||
|
||||
@@ -8,6 +8,7 @@ module
|
||||
prelude
|
||||
public import Lean.DeclarationRange
|
||||
public import Lean.DocString.Markdown
|
||||
public import Init.Data.String.Extra
|
||||
|
||||
public section
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@ import Init.Data.Ord
|
||||
public import Lean.DocString.Types
|
||||
public import Init.Data.String.TakeDrop
|
||||
import Init.Data.String.Iterator
|
||||
public import Init.Data.String.Modify
|
||||
|
||||
set_option linter.missingDocs true
|
||||
|
||||
|
||||
@@ -1340,7 +1340,7 @@ private def resolveLValAux (e : Expr) (eType : Expr) (lval : LVal) : TermElabM L
|
||||
throwErrorAt ref m!"{msg}{.nil}"
|
||||
if eType.isForall then
|
||||
match lval with
|
||||
| LVal.fieldName _ fieldName suffix? fullRef =>
|
||||
| LVal.fieldName ref fieldName suffix? _fullRef =>
|
||||
let fullName := Name.str `Function fieldName
|
||||
if (← getEnv).contains fullName then
|
||||
return LValResolution.const `Function `Function fullName
|
||||
@@ -1349,7 +1349,7 @@ private def resolveLValAux (e : Expr) (eType : Expr) (lval : LVal) : TermElabM L
|
||||
been a field in the `Function` namespace, so we needn't wait to check if this is actually
|
||||
a constant. If `suffix?` is non-`none`, we prefer to throw the "unknown constant" error
|
||||
(because of monad namespaces like `IO` and auxiliary declarations like `mutual_induct`) -/
|
||||
throwInvalidFieldAt fullRef fieldName fullName
|
||||
throwInvalidFieldAt ref fieldName fullName
|
||||
| .fieldIdx .. =>
|
||||
throwLValError e eType "Invalid projection: Projections cannot be used on functions"
|
||||
else if eType.getAppFn.isMVar then
|
||||
@@ -1386,7 +1386,7 @@ private def resolveLValAux (e : Expr) (eType : Expr) (lval : LVal) : TermElabM L
|
||||
throwError m!"Invalid projection: Index `{idx}` is invalid for this structure; {bounds}"
|
||||
++ .note m!"The expression{inlineExpr e}has type{inlineExpr eType}which has only {numFields} {fields}"
|
||||
++ tupleHint
|
||||
| some structName, LVal.fieldName _ fieldName _ fullRef =>
|
||||
| some structName, LVal.fieldName ref fieldName _ _ => withRef ref do
|
||||
let env ← getEnv
|
||||
if isStructure env structName then
|
||||
if let some baseStructName := findField? env structName (Name.mkSimple fieldName) then
|
||||
@@ -1402,15 +1402,15 @@ private def resolveLValAux (e : Expr) (eType : Expr) (lval : LVal) : TermElabM L
|
||||
-- Then search the environment
|
||||
if let some (baseStructName, fullName) ← findMethod? structName (.mkSimple fieldName) then
|
||||
return LValResolution.const baseStructName structName fullName
|
||||
throwInvalidFieldAt fullRef fieldName fullName
|
||||
throwInvalidFieldAt ref fieldName fullName
|
||||
-- Suggest a potential unreachable private name as hint. This does not cover structure
|
||||
-- inheritance, nor `import all`.
|
||||
(declHint := (mkPrivateName env structName).mkStr fieldName)
|
||||
| none, LVal.fieldName _ _ (some suffix) fullRef =>
|
||||
| none, LVal.fieldName ref _ (some suffix) _fullRef =>
|
||||
-- This may be a function constant whose implicit arguments have already been filled in:
|
||||
let c := e.getAppFn
|
||||
if c.isConst then
|
||||
throwUnknownConstantAt fullRef (c.constName! ++ suffix)
|
||||
throwUnknownConstantAt ref (c.constName! ++ suffix)
|
||||
else
|
||||
throwInvalidFieldNotation e eType
|
||||
| _, _ => throwInvalidFieldNotation e eType
|
||||
@@ -1619,7 +1619,7 @@ private def elabAppLValsAux (namedArgs : Array NamedArg) (args : Array Arg) (exp
|
||||
let some info := getFieldInfo? (← getEnv) baseStructName fieldName | unreachable!
|
||||
if (← isInaccessiblePrivateName info.projFn) then
|
||||
throwError "Field `{fieldName}` from structure `{structName}` is private"
|
||||
let projFn ← mkConst info.projFn
|
||||
let projFn ← withRef lval.getRef <| mkConst info.projFn
|
||||
let projFn ← addProjTermInfo lval.getRef projFn
|
||||
if lvals.isEmpty then
|
||||
let namedArgs ← addNamedArg namedArgs { name := `self, val := Arg.expr f, suppressDeps := true }
|
||||
@@ -1629,7 +1629,7 @@ private def elabAppLValsAux (namedArgs : Array NamedArg) (args : Array Arg) (exp
|
||||
loop f lvals
|
||||
| LValResolution.const baseStructName structName constName =>
|
||||
let f ← if baseStructName != structName then mkBaseProjections baseStructName structName f else pure f
|
||||
let projFn ← mkConst constName
|
||||
let projFn ← withRef lval.getRef <| mkConst constName
|
||||
let projFn ← addProjTermInfo lval.getRef projFn
|
||||
if lvals.isEmpty then
|
||||
let (args, namedArgs) ← addLValArg baseStructName f args namedArgs projFn explicit
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user