mirror of
https://github.com/leanprover/lean4.git
synced 2026-03-22 12:54:06 +00:00
Compare commits
1 Commits
context-no
...
grind_modi
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
dc58ef43ae |
2
.github/workflows/build-template.yml
vendored
2
.github/workflows/build-template.yml
vendored
@@ -229,7 +229,7 @@ jobs:
|
||||
id: test
|
||||
run: |
|
||||
ulimit -c unlimited # coredumps
|
||||
time ctest --preset ${{ matrix.CMAKE_PRESET || 'release' }} --test-dir build/$TARGET_STAGE -j$NPROC --output-junit test-results.xml ${{ matrix.CTEST_OPTIONS }}
|
||||
time ctest --preset ${{ matrix.CMAKE_PRESET || 'release' }} --test-dir build/$TARGET_STAGE -j$NPROC --output-junit test-results.xml
|
||||
if: (matrix.wasm || !matrix.cross) && (inputs.check-level >= 1 || matrix.test)
|
||||
- name: Test Summary
|
||||
uses: test-summary/action@v2
|
||||
|
||||
4
.github/workflows/ci.yml
vendored
4
.github/workflows/ci.yml
vendored
@@ -200,6 +200,8 @@ jobs:
|
||||
"os": "ubuntu-latest",
|
||||
"check-level": 2,
|
||||
"CMAKE_PRESET": "reldebug",
|
||||
// exclude seriously slow/stackoverflowing tests
|
||||
"CTEST_OPTIONS": "-E 'interactivetest|leanpkgtest|laketest|benchtest|bv_bitblast_stress|3807'"
|
||||
},
|
||||
// TODO: suddenly started failing in CI
|
||||
/*{
|
||||
@@ -245,6 +247,8 @@ jobs:
|
||||
"check-level": 2,
|
||||
"shell": "msys2 {0}",
|
||||
"CMAKE_OPTIONS": "-G \"Unix Makefiles\"",
|
||||
// for reasons unknown, interactivetests are flaky on Windows
|
||||
"CTEST_OPTIONS": "--repeat until-pass:2",
|
||||
"llvm-url": "https://github.com/leanprover/lean-llvm/releases/download/19.1.2/lean-llvm-x86_64-w64-windows-gnu.tar.zst",
|
||||
"prepare-llvm": "../script/prepare-llvm-mingw.sh lean-llvm*",
|
||||
"binary-check": "ldd",
|
||||
|
||||
@@ -8,7 +8,7 @@ You should not edit the `stage0` directory except using the commands described i
|
||||
|
||||
## Development Setup
|
||||
|
||||
You can use any of the [supported editors](https://lean-lang.org/install/manual/) for editing the Lean source code.
|
||||
You can use any of the [supported editors](../setup.md) for editing the Lean source code.
|
||||
Please see below for specific instructions for VS Code.
|
||||
|
||||
### Dev setup using elan
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
These are instructions to set up a working development environment for those who wish to make changes to Lean itself. It is part of the [Development Guide](../dev/index.md).
|
||||
|
||||
We strongly suggest that new users instead follow the [Installation Instructions](https://lean-lang.org/install/) to get started using Lean, since this sets up an environment that can automatically manage multiple Lean toolchain versions, which is necessary when working within the Lean ecosystem.
|
||||
We strongly suggest that new users instead follow the [Quickstart](../quickstart.md) to get started using Lean, since this sets up an environment that can automatically manage multiple Lean toolchain versions, which is necessary when working within the Lean ecosystem.
|
||||
|
||||
Requirements
|
||||
------------
|
||||
|
||||
@@ -19,8 +19,8 @@ variable {ε σ α : Type u}
|
||||
|
||||
instance [ToString ε] [ToString α] : ToString (Result ε σ α) where
|
||||
toString
|
||||
| Result.ok a _ => String.Internal.append "ok: " (toString a)
|
||||
| Result.error e _ => String.Internal.append "error: " (toString e)
|
||||
| Result.ok a _ => "ok: " ++ toString a
|
||||
| Result.error e _ => "error: " ++ toString e
|
||||
|
||||
instance [Repr ε] [Repr α] : Repr (Result ε σ α) where
|
||||
reprPrec
|
||||
|
||||
@@ -22,24 +22,23 @@ open Function
|
||||
|
||||
namespace ExceptT
|
||||
|
||||
@[ext, grind ext] theorem ext {x y : ExceptT ε m α} (h : x.run = y.run) : x = y := by
|
||||
@[ext] theorem ext {x y : ExceptT ε m α} (h : x.run = y.run) : x = y := by
|
||||
simp [run] at h
|
||||
assumption
|
||||
|
||||
@[simp, grind =] theorem run_pure [Monad m] (x : α) : run (pure x : ExceptT ε m α) = pure (Except.ok x) := rfl
|
||||
@[simp] theorem run_pure [Monad m] (x : α) : run (pure x : ExceptT ε m α) = pure (Except.ok x) := rfl
|
||||
|
||||
@[simp, grind =] theorem run_lift [Monad.{u, v} m] (x : m α) : run (ExceptT.lift x : ExceptT ε m α) = (Except.ok <$> x : m (Except ε α)) := rfl
|
||||
@[simp] theorem run_lift [Monad.{u, v} m] (x : m α) : run (ExceptT.lift x : ExceptT ε m α) = (Except.ok <$> x : m (Except ε α)) := rfl
|
||||
|
||||
@[simp, grind =] theorem run_throw [Monad m] : run (throw e : ExceptT ε m β) = pure (Except.error e) := rfl
|
||||
@[simp] theorem run_throw [Monad m] : run (throw e : ExceptT ε m β) = pure (Except.error e) := rfl
|
||||
|
||||
@[simp, grind =] theorem run_bind_lift [Monad m] [LawfulMonad m] (x : m α) (f : α → ExceptT ε m β) : run (ExceptT.lift x >>= f : ExceptT ε m β) = x >>= fun a => run (f a) := by
|
||||
@[simp] theorem run_bind_lift [Monad m] [LawfulMonad m] (x : m α) (f : α → ExceptT ε m β) : run (ExceptT.lift x >>= f : ExceptT ε m β) = x >>= fun a => run (f a) := by
|
||||
simp [ExceptT.run, ExceptT.lift, bind, ExceptT.bind, ExceptT.mk, ExceptT.bindCont]
|
||||
|
||||
@[simp, grind =] theorem bind_throw [Monad m] [LawfulMonad m] (f : α → ExceptT ε m β) : (throw e >>= f) = throw e := by
|
||||
@[simp] theorem bind_throw [Monad m] [LawfulMonad m] (f : α → ExceptT ε m β) : (throw e >>= f) = throw e := by
|
||||
simp [throw, throwThe, MonadExceptOf.throw, bind, ExceptT.bind, ExceptT.bindCont, ExceptT.mk]
|
||||
|
||||
@[grind =]
|
||||
theorem run_bind [Monad m] (x : ExceptT ε m α) (f : α → ExceptT ε m β)
|
||||
theorem run_bind [Monad m] (x : ExceptT ε m α)
|
||||
: run (x >>= f : ExceptT ε m β)
|
||||
=
|
||||
run x >>= fun
|
||||
@@ -47,10 +46,10 @@ theorem run_bind [Monad m] (x : ExceptT ε m α) (f : α → ExceptT ε m β)
|
||||
| Except.error e => pure (Except.error e) :=
|
||||
rfl
|
||||
|
||||
@[simp, grind =] theorem lift_pure [Monad m] [LawfulMonad m] (a : α) : ExceptT.lift (pure a) = (pure a : ExceptT ε m α) := by
|
||||
@[simp] theorem lift_pure [Monad m] [LawfulMonad m] (a : α) : ExceptT.lift (pure a) = (pure a : ExceptT ε m α) := by
|
||||
simp [ExceptT.lift, pure, ExceptT.pure]
|
||||
|
||||
@[simp, grind =] theorem run_map [Monad m] [LawfulMonad m] (f : α → β) (x : ExceptT ε m α)
|
||||
@[simp] theorem run_map [Monad m] [LawfulMonad m] (f : α → β) (x : ExceptT ε m α)
|
||||
: (f <$> x).run = Except.map f <$> x.run := by
|
||||
simp [Functor.map, ExceptT.map, ←bind_pure_comp]
|
||||
apply bind_congr
|
||||
@@ -114,28 +113,28 @@ instance : LawfulFunctor (Except ε) := inferInstance
|
||||
|
||||
namespace ReaderT
|
||||
|
||||
@[ext, grind ext] theorem ext {x y : ReaderT ρ m α} (h : ∀ ctx, x.run ctx = y.run ctx) : x = y := by
|
||||
@[ext] theorem ext {x y : ReaderT ρ m α} (h : ∀ ctx, x.run ctx = y.run ctx) : x = y := by
|
||||
simp [run] at h
|
||||
exact funext h
|
||||
|
||||
@[simp, grind =] theorem run_pure [Monad m] (a : α) (ctx : ρ) : (pure a : ReaderT ρ m α).run ctx = pure a := rfl
|
||||
@[simp] theorem run_pure [Monad m] (a : α) (ctx : ρ) : (pure a : ReaderT ρ m α).run ctx = pure a := rfl
|
||||
|
||||
@[simp, grind =] theorem run_bind [Monad m] (x : ReaderT ρ m α) (f : α → ReaderT ρ m β) (ctx : ρ)
|
||||
@[simp] theorem run_bind [Monad m] (x : ReaderT ρ m α) (f : α → ReaderT ρ m β) (ctx : ρ)
|
||||
: (x >>= f).run ctx = x.run ctx >>= λ a => (f a).run ctx := rfl
|
||||
|
||||
@[simp, grind =] theorem run_mapConst [Monad m] (a : α) (x : ReaderT ρ m β) (ctx : ρ)
|
||||
@[simp] theorem run_mapConst [Monad m] (a : α) (x : ReaderT ρ m β) (ctx : ρ)
|
||||
: (Functor.mapConst a x).run ctx = Functor.mapConst a (x.run ctx) := rfl
|
||||
|
||||
@[simp, grind =] theorem run_map [Monad m] (f : α → β) (x : ReaderT ρ m α) (ctx : ρ)
|
||||
@[simp] theorem run_map [Monad m] (f : α → β) (x : ReaderT ρ m α) (ctx : ρ)
|
||||
: (f <$> x).run ctx = f <$> x.run ctx := rfl
|
||||
|
||||
@[simp, grind =] theorem run_monadLift [MonadLiftT n m] (x : n α) (ctx : ρ)
|
||||
@[simp] theorem run_monadLift [MonadLiftT n m] (x : n α) (ctx : ρ)
|
||||
: (monadLift x : ReaderT ρ m α).run ctx = (monadLift x : m α) := rfl
|
||||
|
||||
@[simp, grind =] theorem run_monadMap [MonadFunctorT n m] (f : {β : Type u} → n β → n β) (x : ReaderT ρ m α) (ctx : ρ)
|
||||
@[simp] theorem run_monadMap [MonadFunctorT n m] (f : {β : Type u} → n β → n β) (x : ReaderT ρ m α) (ctx : ρ)
|
||||
: (monadMap @f x : ReaderT ρ m α).run ctx = monadMap @f (x.run ctx) := rfl
|
||||
|
||||
@[simp, grind =] theorem run_read [Monad m] (ctx : ρ) : (ReaderT.read : ReaderT ρ m ρ).run ctx = pure ctx := rfl
|
||||
@[simp] theorem run_read [Monad m] (ctx : ρ) : (ReaderT.read : ReaderT ρ m ρ).run ctx = pure ctx := rfl
|
||||
|
||||
@[simp] theorem run_seq {α β : Type u} [Monad m] (f : ReaderT ρ m (α → β)) (x : ReaderT ρ m α) (ctx : ρ)
|
||||
: (f <*> x).run ctx = (f.run ctx <*> x.run ctx) := rfl
|
||||
@@ -176,39 +175,38 @@ instance [Monad m] [LawfulMonad m] : LawfulMonad (StateRefT' ω σ m) :=
|
||||
|
||||
namespace StateT
|
||||
|
||||
@[ext, grind ext] theorem ext {x y : StateT σ m α} (h : ∀ s, x.run s = y.run s) : x = y :=
|
||||
@[ext] theorem ext {x y : StateT σ m α} (h : ∀ s, x.run s = y.run s) : x = y :=
|
||||
funext h
|
||||
|
||||
@[simp, grind =] theorem run'_eq [Monad m] (x : StateT σ m α) (s : σ) : run' x s = (·.1) <$> run x s :=
|
||||
@[simp] theorem run'_eq [Monad m] (x : StateT σ m α) (s : σ) : run' x s = (·.1) <$> run x s :=
|
||||
rfl
|
||||
|
||||
@[simp, grind =] theorem run_pure [Monad m] (a : α) (s : σ) : (pure a : StateT σ m α).run s = pure (a, s) := rfl
|
||||
@[simp] theorem run_pure [Monad m] (a : α) (s : σ) : (pure a : StateT σ m α).run s = pure (a, s) := rfl
|
||||
|
||||
@[simp, grind =] theorem run_bind [Monad m] (x : StateT σ m α) (f : α → StateT σ m β) (s : σ)
|
||||
@[simp] theorem run_bind [Monad m] (x : StateT σ m α) (f : α → StateT σ m β) (s : σ)
|
||||
: (x >>= f).run s = x.run s >>= λ p => (f p.1).run p.2 := by
|
||||
simp [bind, StateT.bind, run]
|
||||
|
||||
@[simp, grind =] theorem run_map {α β σ : Type u} [Monad m] [LawfulMonad m] (f : α → β) (x : StateT σ m α) (s : σ) : (f <$> x).run s = (fun (p : α × σ) => (f p.1, p.2)) <$> x.run s := by
|
||||
@[simp] theorem run_map {α β σ : Type u} [Monad m] [LawfulMonad m] (f : α → β) (x : StateT σ m α) (s : σ) : (f <$> x).run s = (fun (p : α × σ) => (f p.1, p.2)) <$> x.run s := by
|
||||
simp [Functor.map, StateT.map, run, ←bind_pure_comp]
|
||||
|
||||
@[simp, grind =] theorem run_get [Monad m] (s : σ) : (get : StateT σ m σ).run s = pure (s, s) := rfl
|
||||
@[simp] theorem run_get [Monad m] (s : σ) : (get : StateT σ m σ).run s = pure (s, s) := rfl
|
||||
|
||||
@[simp, grind =] theorem run_set [Monad m] (s s' : σ) : (set s' : StateT σ m PUnit).run s = pure (⟨⟩, s') := rfl
|
||||
@[simp] theorem run_set [Monad m] (s s' : σ) : (set s' : StateT σ m PUnit).run s = pure (⟨⟩, s') := rfl
|
||||
|
||||
@[simp, grind =] theorem run_modify [Monad m] (f : σ → σ) (s : σ) : (modify f : StateT σ m PUnit).run s = pure (⟨⟩, f s) := rfl
|
||||
@[simp] theorem run_modify [Monad m] (f : σ → σ) (s : σ) : (modify f : StateT σ m PUnit).run s = pure (⟨⟩, f s) := rfl
|
||||
|
||||
@[simp, grind =] theorem run_modifyGet [Monad m] (f : σ → α × σ) (s : σ) : (modifyGet f : StateT σ m α).run s = pure ((f s).1, (f s).2) := by
|
||||
@[simp] theorem run_modifyGet [Monad m] (f : σ → α × σ) (s : σ) : (modifyGet f : StateT σ m α).run s = pure ((f s).1, (f s).2) := by
|
||||
simp [modifyGet, MonadStateOf.modifyGet, StateT.modifyGet, run]
|
||||
|
||||
@[simp, grind =] theorem run_lift {α σ : Type u} [Monad m] (x : m α) (s : σ) : (StateT.lift x : StateT σ m α).run s = x >>= fun a => pure (a, s) := rfl
|
||||
@[simp] theorem run_lift {α σ : Type u} [Monad m] (x : m α) (s : σ) : (StateT.lift x : StateT σ m α).run s = x >>= fun a => pure (a, s) := rfl
|
||||
|
||||
@[grind =]
|
||||
theorem run_bind_lift {α σ : Type u} [Monad m] [LawfulMonad m] (x : m α) (f : α → StateT σ m β) (s : σ) : (StateT.lift x >>= f).run s = x >>= fun a => (f a).run s := by
|
||||
simp [StateT.lift, StateT.run, bind, StateT.bind]
|
||||
|
||||
@[simp, grind =] theorem run_monadLift {α σ : Type u} [Monad m] [MonadLiftT n m] (x : n α) (s : σ) : (monadLift x : StateT σ m α).run s = (monadLift x : m α) >>= fun a => pure (a, s) := rfl
|
||||
@[simp] theorem run_monadLift {α σ : Type u} [Monad m] [MonadLiftT n m] (x : n α) (s : σ) : (monadLift x : StateT σ m α).run s = (monadLift x : m α) >>= fun a => pure (a, s) := rfl
|
||||
|
||||
@[simp, grind =] theorem run_monadMap [MonadFunctorT n m] (f : {β : Type u} → n β → n β) (x : StateT σ m α) (s : σ) :
|
||||
@[simp] theorem run_monadMap [MonadFunctorT n m] (f : {β : Type u} → n β → n β) (x : StateT σ m α) (s : σ) :
|
||||
(monadMap @f x : StateT σ m α).run s = monadMap @f (x.run s) := rfl
|
||||
|
||||
@[simp] theorem run_seq {α β σ : Type u} [Monad m] [LawfulMonad m] (f : StateT σ m (α → β)) (x : StateT σ m α) (s : σ) : (f <*> x).run s = (f.run s >>= fun fs => (fun (p : α × σ) => (fs.1 p.1, p.2)) <$> x.run fs.2) := by
|
||||
|
||||
@@ -101,6 +101,7 @@ instance : DecidableEq Empty := fun a => a.elim
|
||||
/-- Decidable equality for PEmpty -/
|
||||
instance : DecidableEq PEmpty := fun a => a.elim
|
||||
|
||||
set_option genInjectivity false in
|
||||
/--
|
||||
Delays evaluation. The delayed code is evaluated at most once.
|
||||
|
||||
@@ -616,6 +617,7 @@ class Sep (α : outParam <| Type u) (γ : Type v) where
|
||||
/-- Computes `{ a ∈ c | p a }`. -/
|
||||
sep : (α → Prop) → γ → γ
|
||||
|
||||
set_option genInjectivity false in
|
||||
/--
|
||||
`Task α` is a primitive for asynchronous computation.
|
||||
It represents a computation that will resolve to a value of type `α`,
|
||||
|
||||
@@ -10,6 +10,8 @@ public import Init.WFTactics
|
||||
public import Init.Data.Nat.Basic
|
||||
public import Init.Data.Fin.Basic
|
||||
public import Init.Data.UInt.BasicAux
|
||||
public import Init.Data.Repr
|
||||
public import Init.Data.ToString.Basic
|
||||
public import Init.GetElem
|
||||
public import Init.Data.List.ToArrayImpl
|
||||
import all Init.Data.List.ToArrayImpl
|
||||
@@ -162,7 +164,7 @@ This is a low-level version of `Array.size` that directly queries the runtime sy
|
||||
representation of arrays. While this is not provable, `Array.usize` always returns the exact size of
|
||||
the array since the implementation only supports arrays of size less than `USize.size`.
|
||||
-/
|
||||
@[extern "lean_array_size", simp, expose]
|
||||
@[extern "lean_array_size", simp]
|
||||
def usize (xs : @& Array α) : USize := xs.size.toUSize
|
||||
|
||||
/--
|
||||
@@ -441,7 +443,7 @@ def swapAt! (xs : Array α) (i : Nat) (v : α) : α × Array α :=
|
||||
swapAt xs i v
|
||||
else
|
||||
have : Inhabited (α × Array α) := ⟨(v, xs)⟩
|
||||
panic! String.Internal.append (String.Internal.append "index " (toString i)) " out of bounds"
|
||||
panic! ("index " ++ toString i ++ " out of bounds")
|
||||
|
||||
/--
|
||||
Returns the first `n` elements of an array. The resulting array is produced by repeatedly calling
|
||||
@@ -2167,7 +2169,7 @@ instance {α : Type u} [Repr α] : Repr (Array α) where
|
||||
reprPrec xs _ := Array.repr xs
|
||||
|
||||
instance [ToString α] : ToString (Array α) where
|
||||
toString xs := String.Internal.append "#" (toString xs.toList)
|
||||
toString xs := "#" ++ toString xs.toList
|
||||
|
||||
end Array
|
||||
|
||||
|
||||
@@ -728,7 +728,7 @@ theorem isNone_findFinIdx? {xs : Array α} {p : α → Bool} :
|
||||
cases xs
|
||||
simp only [List.findFinIdx?_toArray, hf, List.findFinIdx?_subtype]
|
||||
rw [findFinIdx?_congr List.unattach_toArray]
|
||||
simp only [Option.map_map, Function.comp_def, Fin.cast_cast]
|
||||
simp only [Option.map_map, Function.comp_def, Fin.cast_trans]
|
||||
simp [Array.size]
|
||||
|
||||
/-! ### idxOf
|
||||
|
||||
@@ -15,6 +15,7 @@ public import Init.Data.List.Monadic
|
||||
public import Init.Data.List.OfFn
|
||||
public import Init.Data.Array.Mem
|
||||
public import Init.Data.Array.DecidableEq
|
||||
public import Init.Data.Array.Lex.Basic
|
||||
public import Init.Data.Range.Lemmas
|
||||
public import Init.TacticsExtra
|
||||
public import Init.Data.List.ToArray
|
||||
|
||||
@@ -70,8 +70,8 @@ private theorem cons_lex_cons [BEq α] {lt : α → α → Bool} {a b : α} {xs
|
||||
rw [cons_lex_cons.forIn'_congr_aux Std.PRange.toList_eq_match rfl (fun _ _ _ => rfl)]
|
||||
simp only [Std.PRange.SupportsUpperBound.IsSatisfied, bind_pure_comp, map_pure]
|
||||
rw [cons_lex_cons.forIn'_congr_aux (if_pos (by omega)) rfl (fun _ _ _ => rfl)]
|
||||
simp only [Std.PRange.toList_Rox_eq_toList_Rcx_of_isSome_succ? (lo := 0) (h := rfl),
|
||||
Std.PRange.UpwardEnumerable.succ?, Nat.add_comm 1, Std.PRange.Nat.toList_Rco_succ_succ,
|
||||
simp only [Std.PRange.toList_open_eq_toList_closed_of_isSome_succ? (lo := 0) (h := rfl),
|
||||
Std.PRange.UpwardEnumerable.succ?, Nat.add_comm 1, Std.PRange.Nat.ClosedOpen.toList_succ_succ,
|
||||
Option.get_some, List.forIn'_cons, List.size_toArray, List.length_cons, List.length_nil,
|
||||
Nat.lt_add_one, getElem_append_left, List.getElem_toArray, List.getElem_cons_zero]
|
||||
cases lt a b
|
||||
|
||||
@@ -206,13 +206,10 @@ Converts a bitvector into a fixed-width hexadecimal number with enough digits to
|
||||
|
||||
If `n` is `0`, then one digit is returned. Otherwise, `⌊(n + 3) / 4⌋` digits are returned.
|
||||
-/
|
||||
-- If we ever want to prove something about this, we can avoid having to use the opaque
|
||||
-- `Internal` string functions by moving this definition out to a separate file that can live
|
||||
-- downstream of `Init.Data.String.Basic`.
|
||||
protected def toHex {n : Nat} (x : BitVec n) : String :=
|
||||
let s := (Nat.toDigits 16 x.toNat).asString
|
||||
let t := (List.replicate ((n+3) / 4 - String.Internal.length s) '0').asString
|
||||
String.Internal.append t s
|
||||
let t := (List.replicate ((n+3) / 4 - s.length) '0').asString
|
||||
t ++ s
|
||||
|
||||
/-- `BitVec` representation. -/
|
||||
protected def BitVec.repr (a : BitVec n) : Std.Format :=
|
||||
|
||||
@@ -21,6 +21,13 @@ namespace BitVec
|
||||
|
||||
section Nat
|
||||
|
||||
/--
|
||||
The bitvector with value `i mod 2^n`.
|
||||
-/
|
||||
@[expose, match_pattern]
|
||||
protected def ofNat (n : Nat) (i : Nat) : BitVec n where
|
||||
toFin := Fin.ofNat (2^n) i
|
||||
|
||||
instance instOfNat : OfNat (BitVec n) i where ofNat := .ofNat n i
|
||||
|
||||
/-- Return the bound in terms of toNat. -/
|
||||
|
||||
@@ -122,7 +122,7 @@ theorem getElem_of_getLsbD_eq_true {x : BitVec w} {i : Nat} (h : x.getLsbD i = t
|
||||
This normalized a bitvec using `ofFin` to `ofNat`.
|
||||
-/
|
||||
theorem ofFin_eq_ofNat : @BitVec.ofFin w (Fin.mk x lt) = BitVec.ofNat w x := by
|
||||
simp only [BitVec.ofNat, Fin.Internal.ofNat_eq_ofNat, Fin.ofNat, lt, Nat.mod_eq_of_lt]
|
||||
simp only [BitVec.ofNat, Fin.ofNat, lt, Nat.mod_eq_of_lt]
|
||||
|
||||
/-- Prove nonequality of bitvectors in terms of nat operations. -/
|
||||
theorem toNat_ne_iff_ne {n} {x y : BitVec n} : x.toNat ≠ y.toNat ↔ x ≠ y := by
|
||||
@@ -299,7 +299,7 @@ theorem length_pos_of_ne {x y : BitVec w} (h : x ≠ y) : 0 < w :=
|
||||
|
||||
theorem ofFin_ofNat (n : Nat) :
|
||||
ofFin (no_index (OfNat.ofNat n : Fin (2^w))) = OfNat.ofNat n := by
|
||||
simp only [OfNat.ofNat, Fin.Internal.ofNat_eq_ofNat, Fin.ofNat, BitVec.ofNat]
|
||||
simp only [OfNat.ofNat, Fin.ofNat, BitVec.ofNat]
|
||||
|
||||
-- We use a `grind_pattern` as `@[grind]` will not use the `no_index` term.
|
||||
grind_pattern ofFin_ofNat => ofFin (OfNat.ofNat n : Fin (2^w))
|
||||
|
||||
@@ -10,6 +10,7 @@ public import Init.NotationExtra
|
||||
|
||||
public section
|
||||
|
||||
|
||||
namespace Bool
|
||||
|
||||
/--
|
||||
|
||||
@@ -7,6 +7,5 @@ module
|
||||
|
||||
prelude
|
||||
public import Init.Data.ByteArray.Basic
|
||||
public import Init.Data.ByteArray.Extra
|
||||
|
||||
public section
|
||||
|
||||
@@ -6,6 +6,7 @@ Author: Leonardo de Moura
|
||||
module
|
||||
|
||||
prelude
|
||||
public import Init.Data.Array.Basic
|
||||
public import Init.Data.Array.DecidableEq
|
||||
public import Init.Data.UInt.Basic
|
||||
public import Init.Data.UInt.BasicAux
|
||||
@@ -15,12 +16,15 @@ public import Init.Data.Option.Basic
|
||||
@[expose] public section
|
||||
universe u
|
||||
|
||||
set_option genInjectivity false in
|
||||
structure ByteArray where
|
||||
data : Array UInt8
|
||||
|
||||
attribute [extern "lean_byte_array_mk"] ByteArray.mk
|
||||
attribute [extern "lean_byte_array_data"] ByteArray.data
|
||||
|
||||
gen_injective_theorems% ByteArray
|
||||
|
||||
namespace ByteArray
|
||||
|
||||
deriving instance BEq for ByteArray
|
||||
@@ -360,3 +364,27 @@ def List.toByteArray (bs : List UInt8) : ByteArray :=
|
||||
loop bs ByteArray.empty
|
||||
|
||||
instance : ToString ByteArray := ⟨fun bs => bs.toList.toString⟩
|
||||
|
||||
/-- Interpret a `ByteArray` of size 8 as a little-endian `UInt64`. -/
|
||||
def ByteArray.toUInt64LE! (bs : ByteArray) : UInt64 :=
|
||||
assert! bs.size == 8
|
||||
(bs.get! 7).toUInt64 <<< 0x38 |||
|
||||
(bs.get! 6).toUInt64 <<< 0x30 |||
|
||||
(bs.get! 5).toUInt64 <<< 0x28 |||
|
||||
(bs.get! 4).toUInt64 <<< 0x20 |||
|
||||
(bs.get! 3).toUInt64 <<< 0x18 |||
|
||||
(bs.get! 2).toUInt64 <<< 0x10 |||
|
||||
(bs.get! 1).toUInt64 <<< 0x8 |||
|
||||
(bs.get! 0).toUInt64
|
||||
|
||||
/-- Interpret a `ByteArray` of size 8 as a big-endian `UInt64`. -/
|
||||
def ByteArray.toUInt64BE! (bs : ByteArray) : UInt64 :=
|
||||
assert! bs.size == 8
|
||||
(bs.get! 0).toUInt64 <<< 0x38 |||
|
||||
(bs.get! 1).toUInt64 <<< 0x30 |||
|
||||
(bs.get! 2).toUInt64 <<< 0x28 |||
|
||||
(bs.get! 3).toUInt64 <<< 0x20 |||
|
||||
(bs.get! 4).toUInt64 <<< 0x18 |||
|
||||
(bs.get! 5).toUInt64 <<< 0x10 |||
|
||||
(bs.get! 6).toUInt64 <<< 0x8 |||
|
||||
(bs.get! 7).toUInt64
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
/-
|
||||
Copyright (c) 2019 Microsoft Corporation. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Author: Leonardo de Moura
|
||||
-/
|
||||
module
|
||||
|
||||
prelude
|
||||
public import Init.Data.ByteArray.Basic
|
||||
import Init.Data.String.Basic
|
||||
|
||||
/-- Interpret a `ByteArray` of size 8 as a little-endian `UInt64`. -/
|
||||
public def ByteArray.toUInt64LE! (bs : ByteArray) : UInt64 :=
|
||||
assert! bs.size == 8
|
||||
(bs.get! 7).toUInt64 <<< 0x38 |||
|
||||
(bs.get! 6).toUInt64 <<< 0x30 |||
|
||||
(bs.get! 5).toUInt64 <<< 0x28 |||
|
||||
(bs.get! 4).toUInt64 <<< 0x20 |||
|
||||
(bs.get! 3).toUInt64 <<< 0x18 |||
|
||||
(bs.get! 2).toUInt64 <<< 0x10 |||
|
||||
(bs.get! 1).toUInt64 <<< 0x8 |||
|
||||
(bs.get! 0).toUInt64
|
||||
|
||||
/-- Interpret a `ByteArray` of size 8 as a big-endian `UInt64`. -/
|
||||
public def ByteArray.toUInt64BE! (bs : ByteArray) : UInt64 :=
|
||||
assert! bs.size == 8
|
||||
(bs.get! 0).toUInt64 <<< 0x38 |||
|
||||
(bs.get! 1).toUInt64 <<< 0x30 |||
|
||||
(bs.get! 2).toUInt64 <<< 0x28 |||
|
||||
(bs.get! 3).toUInt64 <<< 0x20 |||
|
||||
(bs.get! 4).toUInt64 <<< 0x18 |||
|
||||
(bs.get! 5).toUInt64 <<< 0x10 |||
|
||||
(bs.get! 6).toUInt64 <<< 0x8 |||
|
||||
(bs.get! 7).toUInt64
|
||||
@@ -66,6 +66,11 @@ instance leTotal : Std.Total (· ≤ · : Char → Char → Prop) where
|
||||
def notLTTotal : Std.Total (¬ · < · : Char → Char → Prop) where
|
||||
total := fun x y => by simpa using Char.le_total y x
|
||||
|
||||
theorem utf8Size_eq (c : Char) : c.utf8Size = 1 ∨ c.utf8Size = 2 ∨ c.utf8Size = 3 ∨ c.utf8Size = 4 := by
|
||||
have := c.utf8Size_pos
|
||||
have := c.utf8Size_le_four
|
||||
omega
|
||||
|
||||
@[simp] theorem ofNat_toNat (c : Char) : Char.ofNat c.toNat = c := by
|
||||
rw [Char.ofNat, dif_pos]
|
||||
rfl
|
||||
|
||||
@@ -9,4 +9,3 @@ prelude
|
||||
public import Init.Data.Dyadic.Basic
|
||||
public import Init.Data.Dyadic.Instances
|
||||
public import Init.Data.Dyadic.Round
|
||||
public import Init.Data.Dyadic.Inv
|
||||
|
||||
@@ -75,7 +75,7 @@ theorem trailingZeros_two_mul {i : Int} (h : i ≠ 0) :
|
||||
|
||||
theorem shiftRight_trailingZeros_mod_two {i : Int} (h : i ≠ 0) :
|
||||
(i >>> i.trailingZeros) % 2 = 1 := by
|
||||
rw (occs := .pos [2]) [← Int.emod_add_mul_ediv i 2]
|
||||
rw (occs := .pos [2]) [← Int.emod_add_ediv i 2]
|
||||
rcases i.emod_two_eq with h' | h' <;> rw [h']
|
||||
· rcases Int.dvd_of_emod_eq_zero h' with ⟨a, rfl⟩
|
||||
simp only [ne_eq, Int.mul_eq_zero, Int.reduceEq, false_or] at h
|
||||
@@ -92,7 +92,7 @@ theorem two_pow_trailingZeros_dvd {i : Int} (h : i ≠ 0) :
|
||||
simp only [ne_eq, Int.mul_eq_zero, Int.reduceEq, false_or] at h
|
||||
rw [trailingZeros_two_mul h, Int.pow_succ']
|
||||
exact Int.mul_dvd_mul_left _ (two_pow_trailingZeros_dvd h)
|
||||
· rw (occs := .pos [1]) [← Int.emod_add_mul_ediv i 2, h', Int.add_comm, trailingZeros_two_mul_add_one]
|
||||
· rw (occs := .pos [1]) [← Int.emod_add_ediv i 2, h', Int.add_comm, trailingZeros_two_mul_add_one]
|
||||
exact Int.one_dvd _
|
||||
termination_by i.natAbs
|
||||
|
||||
@@ -415,22 +415,16 @@ theorem precision_ofIntWithPrec_le {i : Int} (h : i ≠ 0) (prec : Int) :
|
||||
| .zero => rfl
|
||||
| .ofOdd _ _ _ => rfl
|
||||
|
||||
end Dyadic
|
||||
|
||||
namespace Rat
|
||||
|
||||
open Dyadic
|
||||
|
||||
/--
|
||||
Convert a rational number `x` to the greatest dyadic number with precision at most `prec`
|
||||
which is less than or equal to `x`.
|
||||
-/
|
||||
def toDyadic (x : Rat) (prec : Int) : Dyadic :=
|
||||
def _root_.Rat.toDyadic (x : Rat) (prec : Int) : Dyadic :=
|
||||
match prec with
|
||||
| (n : Nat) => .ofIntWithPrec ((x.num <<< n) / x.den) prec
|
||||
| -(n + 1 : Nat) => .ofIntWithPrec (x.num / (x.den <<< (n + 1))) prec
|
||||
|
||||
theorem toDyadic_mkRat (a : Int) (b : Nat) (prec : Int) :
|
||||
theorem _root_.Rat.toDyadic_mkRat (a : Int) (b : Nat) (prec : Int) :
|
||||
Rat.toDyadic (mkRat a b) prec =
|
||||
.ofIntWithPrec ((a <<< prec.toNat) / (b <<< (-prec).toNat)) prec := by
|
||||
by_cases hb : b = 0
|
||||
@@ -438,96 +432,15 @@ theorem toDyadic_mkRat (a : Int) (b : Nat) (prec : Int) :
|
||||
rcases h : mkRat a b with ⟨n, d, hnz, hr⟩
|
||||
obtain ⟨m, hm, rfl, rfl⟩ := Rat.mkRat_num_den hb h
|
||||
cases prec
|
||||
· simp only [Rat.toDyadic, Int.ofNat_eq_coe, Int.toNat_natCast, Int.toNat_neg_natCast,
|
||||
· simp only [Rat.toDyadic, Int.ofNat_eq_coe, Int.toNat_natCast, Int.toNat_neg_nat,
|
||||
shiftLeft_zero, Int.natCast_mul]
|
||||
rw [Int.mul_comm d, ← Int.ediv_ediv (by simp), ← Int.shiftLeft_mul,
|
||||
Int.mul_ediv_cancel _ (by simpa using hm)]
|
||||
· simp only [Rat.toDyadic, Int.natCast_shiftLeft, Int.negSucc_eq, ← Int.natCast_add_one,
|
||||
Int.toNat_neg_natCast, Int.shiftLeft_zero, Int.neg_neg, Int.toNat_natCast, Int.natCast_mul]
|
||||
Int.toNat_neg_nat, Int.shiftLeft_zero, Int.neg_neg, Int.toNat_natCast, Int.natCast_mul]
|
||||
rw [Int.mul_comm d, ← Int.mul_shiftLeft, ← Int.ediv_ediv (by simp),
|
||||
Int.mul_ediv_cancel _ (by simpa using hm)]
|
||||
|
||||
theorem toDyadic_eq_ofIntWithPrec (x : Rat) (prec : Int) :
|
||||
x.toDyadic prec = .ofIntWithPrec ((x.num <<< prec.toNat) / (x.den <<< (-prec).toNat)) prec := by
|
||||
conv => lhs; rw [← Rat.mkRat_self x]
|
||||
rw [Rat.toDyadic_mkRat]
|
||||
|
||||
/--
|
||||
Converting a rational to a dyadic at a given precision and then back to a rational
|
||||
gives the same result as taking the floor of the rational at precision `2 ^ prec`.
|
||||
-/
|
||||
theorem toRat_toDyadic (x : Rat) (prec : Int) :
|
||||
(x.toDyadic prec).toRat = (x * 2 ^ prec).floor / 2 ^ prec := by
|
||||
rw [Rat.toDyadic_eq_ofIntWithPrec, toRat_ofIntWithPrec_eq_mul_two_pow, Rat.zpow_neg, Rat.div_def]
|
||||
congr 2
|
||||
rw [Rat.floor_def, Int.shiftLeft_eq, Nat.shiftLeft_eq]
|
||||
match prec with
|
||||
| .ofNat prec =>
|
||||
simp only [Int.ofNat_eq_coe, Int.toNat_natCast, Int.toNat_neg_natCast, Nat.pow_zero,
|
||||
Nat.mul_one]
|
||||
have : (2 ^ prec : Rat) = ((2 ^ prec : Nat) : Rat) := by simp
|
||||
rw [Rat.zpow_natCast, this, Rat.mul_def']
|
||||
simp only [Rat.num_mkRat, Rat.den_mkRat]
|
||||
simp only [Rat.natCast_pow, Rat.natCast_ofNat, Rat.num_pow, Rat.num_ofNat, Rat.den_pow,
|
||||
Rat.den_ofNat, Nat.one_pow, Nat.mul_one]
|
||||
split
|
||||
· simp_all
|
||||
· rw [Int.ediv_ediv (Int.ofNat_zero_le _)]
|
||||
congr 1
|
||||
rw [Int.natCast_ediv, Int.mul_ediv_cancel']
|
||||
rw [Int.natCast_dvd_natCast]
|
||||
apply gcd_dvd_left
|
||||
| .negSucc prec =>
|
||||
simp only [Int.toNat_negSucc, Int.pow_zero, Int.mul_one, Int.neg_negSucc, Int.natCast_mul,
|
||||
Int.natCast_pow, Int.cast_ofNat_Int]
|
||||
have : (2 ^ ((prec : Int) + 1)) = ((2 ^ (prec + 1) : Nat) : Rat) := by simp; rfl
|
||||
rw [Int.negSucc_eq, Rat.zpow_neg, this, Rat.mul_def']
|
||||
simp only [Rat.num_mkRat, Rat.den_mkRat]
|
||||
simp only [natCast_pow, natCast_ofNat, den_inv, num_pow, num_ofNat, Int.natAbs_pow,
|
||||
Int.reduceAbs, num_inv, den_pow, den_ofNat, Nat.one_pow, Int.cast_ofNat_Int, Int.mul_one]
|
||||
have : ¬ (2 ^ (prec + 1) : Int) = 0 := NeZero.out
|
||||
simp only [if_neg this]
|
||||
have : (2 ^ (prec + 1) : Int).sign = 1 := by simpa using Int.pow_pos (by decide)
|
||||
simp only [this]
|
||||
have : x.den * 2 ^ (prec + 1) = 0 ↔ x.den = 0 := by
|
||||
rw [Nat.mul_eq_zero]
|
||||
simp_all
|
||||
simp only [this, Int.mul_one]
|
||||
split
|
||||
· simp_all
|
||||
· rw [Int.ediv_ediv (Int.ofNat_zero_le _)]
|
||||
congr 1
|
||||
rw [Int.natCast_ediv, Int.mul_ediv_cancel']
|
||||
· simp
|
||||
· rw [Int.natCast_dvd_natCast]
|
||||
apply gcd_dvd_left
|
||||
|
||||
theorem toRat_toDyadic_le {x : Rat} {prec : Int} : (x.toDyadic prec).toRat ≤ x := by
|
||||
rw [toRat_toDyadic]
|
||||
have : (x * 2 ^ prec).floor ≤ x * 2 ^ prec := Rat.floor_le _
|
||||
apply Rat.le_of_mul_le_mul_right (c := 2 ^ prec)
|
||||
rw [Rat.div_mul_cancel]
|
||||
exact this
|
||||
· apply Rat.ne_of_gt (Rat.zpow_pos (by decide))
|
||||
· exact Rat.zpow_pos (by decide)
|
||||
|
||||
theorem lt_toRat_toDyadic_add {x : Rat} {prec : Int} :
|
||||
x < (x.toDyadic prec + ofIntWithPrec 1 prec).toRat := by
|
||||
rw [toRat_add, toRat_toDyadic, toRat_ofIntWithPrec_eq_mul_two_pow]
|
||||
have := Rat.lt_floor_add_one (x * 2 ^ prec)
|
||||
rw [Rat.zpow_neg, Rat.div_def, ← Rat.add_mul]
|
||||
apply Rat.lt_of_mul_lt_mul_right (c := 2 ^ prec)
|
||||
rw [Rat.mul_assoc, Rat.inv_mul_cancel, Rat.mul_one]
|
||||
exact mod_cast this
|
||||
· apply Rat.ne_of_gt (Rat.zpow_pos (by decide))
|
||||
· exact Rat.zpow_nonneg (by decide)
|
||||
|
||||
-- TODO: `x.toDyadic prec` is the unique dyadic with the given precision satisfying the two inequalities above.
|
||||
|
||||
end Rat
|
||||
|
||||
namespace Dyadic
|
||||
|
||||
/--
|
||||
Rounds a dyadic rational `x` down to the greatest dyadic number with precision at most `prec`
|
||||
which is less than or equal to `x`.
|
||||
@@ -566,11 +479,10 @@ theorem toDyadic_toRat (x : Dyadic) (prec : Int) :
|
||||
rw [this]
|
||||
cases h : k - prec
|
||||
· simp
|
||||
· simp only [Int.neg_negSucc, Int.natCast_add, Int.cast_ofNat_Int, Int.toNat_natCast_add_one,
|
||||
Int.toNat_negSucc, Int.shiftRight_zero]
|
||||
· simp
|
||||
rw [Int.negSucc_eq, Int.eq_neg_comm, Int.neg_sub, eq_comm, Int.sub_eq_iff_eq_add] at h
|
||||
simp only [h, ← Int.natCast_add_one, Int.add_comm _ k, ofIntWithPrec_shiftLeft_add,
|
||||
ofOdd_eq_ofIntWithPrec]
|
||||
simp only [Int.neg_negSucc, h, ← Int.natCast_add_one, Int.add_comm _ k,
|
||||
Nat.succ_eq_add_one, Int.toNat_natCast, ofIntWithPrec_shiftLeft_add, ofOdd_eq_ofIntWithPrec]
|
||||
|
||||
theorem toRat_inj {x y : Dyadic} : x.toRat = y.toRat ↔ x = y := by
|
||||
refine ⟨fun h => ?_, fun h => h ▸ rfl⟩
|
||||
@@ -666,7 +578,7 @@ theorem blt_eq_false_iff : blt x y = false ↔ ble y x = true := by
|
||||
rcases k₁ - k₂ with (_ | _) | _
|
||||
· simp
|
||||
· simp [← Int.negSucc_eq]
|
||||
· simp only [Int.neg_negSucc, decide_eq_false_iff_not, Int.not_lt,
|
||||
· simp only [Int.neg_negSucc, succ_eq_add_one, decide_eq_false_iff_not, Int.not_lt,
|
||||
decide_eq_true_eq]
|
||||
|
||||
theorem ble_iff_toRat : ble x y ↔ x.toRat ≤ y.toRat := by
|
||||
|
||||
@@ -1,80 +0,0 @@
|
||||
/-
|
||||
Copyright (c) 2025 Lean FRO, LLC. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Kim Morrison
|
||||
-/
|
||||
module
|
||||
prelude
|
||||
import Init.Data.Dyadic.Basic
|
||||
import Init.Data.Dyadic.Round
|
||||
import Init.Grind.Ordered.Ring
|
||||
|
||||
/-!
|
||||
# Inversion for dyadic numbers
|
||||
-/
|
||||
|
||||
namespace Dyadic
|
||||
|
||||
/--
|
||||
Inverts a dyadic number at a given (maximum) precision.
|
||||
Returns the greatest dyadic number with precision at most `prec` which is less than or equal to `1/x`.
|
||||
For `x = 0`, returns `0`.
|
||||
-/
|
||||
def invAtPrec (x : Dyadic) (prec : Int) : Dyadic :=
|
||||
match x with
|
||||
| .zero => .zero
|
||||
| _ => x.toRat.inv.toDyadic prec
|
||||
|
||||
/-- For a positive dyadic `x`, `invAtPrec x prec * x ≤ 1`. -/
|
||||
theorem invAtPrec_mul_le_one {x : Dyadic} (hx : 0 < x) (prec : Int) :
|
||||
invAtPrec x prec * x ≤ 1 := by
|
||||
rw [le_iff_toRat]
|
||||
rw [toRat_mul]
|
||||
rw [show (1 : Dyadic).toRat = (1 : Rat) from rfl]
|
||||
unfold invAtPrec
|
||||
cases x with
|
||||
| zero =>
|
||||
exfalso
|
||||
contradiction
|
||||
| ofOdd n k hn =>
|
||||
simp only
|
||||
have h_le : ((ofOdd n k hn).toRat.inv.toDyadic prec).toRat ≤ (ofOdd n k hn).toRat.inv := Rat.toRat_toDyadic_le
|
||||
have h_pos : 0 ≤ (ofOdd n k hn).toRat := by
|
||||
rw [lt_iff_toRat, toRat_zero] at hx
|
||||
exact Rat.le_of_lt hx
|
||||
calc ((ofOdd n k hn).toRat.inv.toDyadic prec).toRat * (ofOdd n k hn).toRat
|
||||
≤ (ofOdd n k hn).toRat.inv * (ofOdd n k hn).toRat := Rat.mul_le_mul_of_nonneg_right h_le h_pos
|
||||
_ = 1 := by
|
||||
apply Rat.inv_mul_cancel
|
||||
rw [lt_iff_toRat, toRat_zero] at hx
|
||||
exact Rat.ne_of_gt hx
|
||||
|
||||
/-- For a positive dyadic `x`, `1 < (invAtPrec x prec + 2^(-prec)) * x`. -/
|
||||
theorem one_lt_invAtPrec_add_inc_mul {x : Dyadic} (hx : 0 < x) (prec : Int) :
|
||||
1 < (invAtPrec x prec + ofIntWithPrec 1 prec) * x := by
|
||||
rw [lt_iff_toRat]
|
||||
rw [toRat_mul]
|
||||
rw [show (1 : Dyadic).toRat = (1 : Rat) from rfl]
|
||||
unfold invAtPrec
|
||||
cases x with
|
||||
| zero =>
|
||||
exfalso
|
||||
contradiction
|
||||
| ofOdd n k hn =>
|
||||
simp only
|
||||
have h_le : (ofOdd n k hn).toRat.inv < ((ofOdd n k hn).toRat.inv.toDyadic prec + ofIntWithPrec 1 prec).toRat :=
|
||||
Rat.lt_toRat_toDyadic_add
|
||||
have h_pos : 0 < (ofOdd n k hn).toRat := by
|
||||
rwa [lt_iff_toRat, toRat_zero] at hx
|
||||
calc
|
||||
1 = (ofOdd n k hn).toRat.inv * (ofOdd n k hn).toRat := by
|
||||
symm
|
||||
apply Rat.inv_mul_cancel
|
||||
rw [lt_iff_toRat, toRat_zero] at hx
|
||||
exact Rat.ne_of_gt hx
|
||||
_ < ((ofOdd n k hn).toRat.inv.toDyadic prec + ofIntWithPrec 1 prec).toRat * (ofOdd n k hn).toRat :=
|
||||
Rat.mul_lt_mul_of_pos_right h_le h_pos
|
||||
|
||||
-- TODO: `invAtPrec` is the unique dyadic with the given precision satisfying the two inequalities above.
|
||||
|
||||
end Dyadic
|
||||
@@ -51,11 +51,6 @@ The assumption `NeZero n` ensures that `Fin n` is nonempty.
|
||||
@[expose] protected def ofNat (n : Nat) [NeZero n] (a : Nat) : Fin n :=
|
||||
⟨a % n, Nat.mod_lt _ (pos_of_neZero n)⟩
|
||||
|
||||
@[simp]
|
||||
theorem Internal.ofNat_eq_ofNat {n : Nat} {hn} {a : Nat} :
|
||||
letI : NeZero n := ⟨Nat.pos_iff_ne_zero.1 hn⟩
|
||||
Fin.Internal.ofNat n hn a = Fin.ofNat n a := rfl
|
||||
|
||||
@[deprecated Fin.ofNat (since := "2025-05-28")]
|
||||
protected def ofNat' (n : Nat) [NeZero n] (a : Nat) : Fin n :=
|
||||
Fin.ofNat n a
|
||||
|
||||
@@ -25,12 +25,12 @@ namespace Fin
|
||||
|
||||
@[deprecated ofNat_zero (since := "2025-05-28")] abbrev ofNat'_zero := @ofNat_zero
|
||||
|
||||
theorem mod_def (a m : Fin n) : a % m = Fin.mk (a.val % m.val) (Nat.lt_of_le_of_lt (Nat.mod_le _ _) a.2) :=
|
||||
theorem mod_def (a m : Fin n) : a % m = Fin.mk (a % m) (Nat.lt_of_le_of_lt (Nat.mod_le _ _) a.2) :=
|
||||
rfl
|
||||
|
||||
theorem mul_def (a b : Fin n) : a * b = Fin.mk ((a.val * b.val) % n) (Nat.mod_lt _ a.pos) := rfl
|
||||
theorem mul_def (a b : Fin n) : a * b = Fin.mk ((a * b) % n) (Nat.mod_lt _ a.pos) := rfl
|
||||
|
||||
theorem sub_def (a b : Fin n) : a - b = Fin.mk (((n - b.val) + a.val) % n) (Nat.mod_lt _ a.pos) := rfl
|
||||
theorem sub_def (a b : Fin n) : a - b = Fin.mk (((n - b) + a) % n) (Nat.mod_lt _ a.pos) := rfl
|
||||
|
||||
theorem pos' : ∀ [Nonempty (Fin n)], 0 < n | ⟨i⟩ => i.pos
|
||||
|
||||
@@ -81,7 +81,7 @@ theorem mk_val (i : Fin n) : (⟨i, i.isLt⟩ : Fin n) = i := Fin.eta ..
|
||||
|
||||
@[deprecated ofNat_self (since := "2025-05-28")] abbrev ofNat'_self := @ofNat_self
|
||||
|
||||
@[simp] theorem ofNat_val_eq_self [NeZero n] (x : Fin n) : (Fin.ofNat n x.val) = x := by
|
||||
@[simp] theorem ofNat_val_eq_self [NeZero n] (x : Fin n) : (Fin.ofNat n x) = x := by
|
||||
ext
|
||||
rw [val_ofNat, Nat.mod_eq_of_lt]
|
||||
exact x.2
|
||||
@@ -121,6 +121,8 @@ Non-trivial loops lead to undesirable and counterintuitive elaboration behavior.
|
||||
For example, for `x : Fin k` and `n : Nat`,
|
||||
it causes `x < n` to be elaborated as `x < ↑n` rather than `↑x < n`,
|
||||
silently introducing wraparound arithmetic.
|
||||
|
||||
Note: as of 2025-06-03, Mathlib has such a coercion for `Fin n` anyway!
|
||||
-/
|
||||
@[expose]
|
||||
def instNatCast (n : Nat) [NeZero n] : NatCast (Fin n) where
|
||||
@@ -263,7 +265,7 @@ instance : LawfulOrderLT (Fin n) where
|
||||
lt_iff := by
|
||||
simp [← Fin.not_le, Decidable.imp_iff_not_or, Std.Total.total]
|
||||
|
||||
@[simp, grind =] theorem val_rev (i : Fin n) : (rev i).val = n - (i + 1) := rfl
|
||||
@[simp, grind =] theorem val_rev (i : Fin n) : rev i = n - (i + 1) := rfl
|
||||
|
||||
@[simp] theorem rev_rev (i : Fin n) : rev (rev i) = i := Fin.ext <| by
|
||||
rw [val_rev, val_rev, ← Nat.sub_sub, Nat.sub_sub_self (by exact i.2), Nat.add_sub_cancel]
|
||||
@@ -498,11 +500,9 @@ theorem succ_succ_ne_one (a : Fin n) : Fin.succ (Fin.succ a) ≠ 1 :=
|
||||
ext
|
||||
simp
|
||||
|
||||
@[simp, grind =] theorem cast_cast {k : Nat} (h : n = m) (h' : m = k) {i : Fin n} :
|
||||
@[simp] theorem cast_trans {k : Nat} (h : n = m) (h' : m = k) {i : Fin n} :
|
||||
(i.cast h).cast h' = i.cast (Eq.trans h h') := rfl
|
||||
|
||||
@[deprecated cast_cast (since := "2025-09-03")] abbrev cast_trans := @cast_cast
|
||||
|
||||
theorem castLE_of_eq {m n : Nat} (h : m = n) {h' : m ≤ n} : castLE h' = Fin.cast h := rfl
|
||||
|
||||
@[simp] theorem coe_castAdd (m : Nat) (i : Fin n) : (castAdd m i : Nat) = i := rfl
|
||||
@@ -531,7 +531,7 @@ theorem cast_castAdd_left {n n' m : Nat} (i : Fin n') (h : n' + m = n + m) :
|
||||
(i.castAdd m').cast h = i.castAdd m := rfl
|
||||
|
||||
theorem castAdd_castAdd {m n p : Nat} (i : Fin m) :
|
||||
(i.castAdd n).castAdd p = (i.castAdd (n + p)).cast (Nat.add_assoc ..).symm := rfl
|
||||
(i.castAdd n).castAdd p = (i.castAdd (n + p)).cast (Nat.add_assoc ..).symm := rfl
|
||||
|
||||
/-- The cast of the successor is the successor of the cast. See `Fin.succ_cast_eq` for rewriting in
|
||||
the reverse direction. -/
|
||||
|
||||
@@ -30,6 +30,7 @@ opaque floatSpec : FloatSpec := {
|
||||
decLe := fun _ _ => inferInstanceAs (Decidable True)
|
||||
}
|
||||
|
||||
set_option genInjectivity false in
|
||||
/--
|
||||
64-bit floating-point numbers.
|
||||
|
||||
@@ -500,3 +501,5 @@ This function does not reduce in the kernel.
|
||||
-/
|
||||
@[extern "lean_float_scaleb"]
|
||||
opaque Float.scaleB (x : Float) (i : @& Int) : Float
|
||||
|
||||
gen_injective_theorems% Float
|
||||
|
||||
@@ -23,6 +23,7 @@ opaque float32Spec : FloatSpec := {
|
||||
decLe := fun _ _ => inferInstanceAs (Decidable True)
|
||||
}
|
||||
|
||||
set_option genInjectivity false in
|
||||
/--
|
||||
32-bit floating-point numbers.
|
||||
|
||||
@@ -513,3 +514,5 @@ This may lose precision.
|
||||
This function does not reduce in the kernel.
|
||||
-/
|
||||
@[extern "lean_float_to_float32"] opaque Float.toFloat32 : Float → Float32
|
||||
|
||||
gen_injective_theorems% Float32
|
||||
|
||||
@@ -15,12 +15,15 @@ public import Init.Data.Array.DecidableEq
|
||||
public section
|
||||
universe u
|
||||
|
||||
set_option genInjectivity false in
|
||||
structure FloatArray where
|
||||
data : Array Float
|
||||
|
||||
attribute [extern "lean_float_array_mk"] FloatArray.mk
|
||||
attribute [extern "lean_float_array_data"] FloatArray.data
|
||||
|
||||
gen_injective_theorems% FloatArray
|
||||
|
||||
namespace FloatArray
|
||||
|
||||
deriving instance BEq for FloatArray
|
||||
|
||||
@@ -8,7 +8,7 @@ module
|
||||
prelude
|
||||
public import Init.Control.State
|
||||
public import Init.Data.Int.Basic
|
||||
public import Init.Data.String.Bootstrap
|
||||
public import Init.Data.String.Basic
|
||||
|
||||
public section
|
||||
|
||||
@@ -168,8 +168,8 @@ private def spaceUptoLine : Format → Bool → Int → Nat → SpaceResult
|
||||
else
|
||||
{ foundLine := true }
|
||||
| text s, flatten, _, _ =>
|
||||
let p := String.Internal.posOf s '\n'
|
||||
let off := String.Internal.offsetOfPos s p
|
||||
let p := s.posOf '\n'
|
||||
let off := s.offsetOfPos p
|
||||
{ foundLine := p != s.endPos, foundFlattenedHardLine := flatten && p != s.endPos, space := off }
|
||||
| append f₁ f₂, flatten, m, w => merge w (spaceUptoLine f₁ flatten m w) (spaceUptoLine f₂ flatten m)
|
||||
| nest n f, flatten, m, w => spaceUptoLine f flatten (m - n) w
|
||||
@@ -263,15 +263,15 @@ private partial def be (w : Nat) [Monad m] [MonadPrettyFormat m] : List WorkGrou
|
||||
| append f₁ f₂ => be w (gs' ({ i with f := f₁, activeTags := 0 }::{ i with f := f₂ }::is))
|
||||
| nest n f => be w (gs' ({ i with f, indent := i.indent + n }::is))
|
||||
| text s =>
|
||||
let p := String.Internal.posOf s '\n'
|
||||
let p := s.posOf '\n'
|
||||
if p == s.endPos then
|
||||
pushOutput s
|
||||
endTags i.activeTags
|
||||
be w (gs' is)
|
||||
else
|
||||
pushOutput (String.Internal.extract s {} p)
|
||||
pushOutput (s.extract {} p)
|
||||
pushNewline i.indent.toNat
|
||||
let is := { i with f := text (String.Internal.extract s (String.Internal.next s p) s.endPos) }::is
|
||||
let is := { i with f := text (s.extract (s.next p) s.endPos) }::is
|
||||
-- after a hard line break, re-evaluate whether to flatten the remaining group
|
||||
-- note that we shouldn't start flattening after a hard break outside a group
|
||||
if g.fla == .disallow then
|
||||
@@ -298,7 +298,7 @@ private partial def be (w : Nat) [Monad m] [MonadPrettyFormat m] : List WorkGrou
|
||||
pushGroup FlattenBehavior.fill is gs w >>= be w
|
||||
-- if preceding fill item fit in a single line, try to fit next one too
|
||||
if g.fla.shouldFlatten then
|
||||
let gs'@(g'::_) ← pushGroup FlattenBehavior.fill is gs (w - String.Internal.length " ")
|
||||
let gs'@(g'::_) ← pushGroup FlattenBehavior.fill is gs (w - " ".length)
|
||||
| panic "unreachable"
|
||||
if g'.fla.shouldFlatten then
|
||||
pushOutput " "
|
||||
@@ -316,7 +316,7 @@ private partial def be (w : Nat) [Monad m] [MonadPrettyFormat m] : List WorkGrou
|
||||
else
|
||||
let k ← currColumn
|
||||
if k < i.indent then
|
||||
pushOutput (String.Internal.pushn "" ' ' (i.indent - k).toNat)
|
||||
pushOutput ("".pushn ' ' (i.indent - k).toNat)
|
||||
endTags i.activeTags
|
||||
be w (gs' is)
|
||||
else
|
||||
@@ -350,7 +350,7 @@ Creates a format `l ++ f ++ r` with a flattening group, nesting the contents by
|
||||
The group's `FlattenBehavior` is `allOrNone`; for `fill` use `Std.Format.bracketFill`.
|
||||
-/
|
||||
@[inline] def bracket (l : String) (f : Format) (r : String) : Format :=
|
||||
group (nest (String.Internal.length l) $ l ++ f ++ r)
|
||||
group (nest l.length $ l ++ f ++ r)
|
||||
|
||||
/--
|
||||
Creates the format `"(" ++ f ++ ")"` with a flattening group, nesting by one space.
|
||||
@@ -372,7 +372,7 @@ Creates a format `l ++ f ++ r` with a flattening group, nesting the contents by
|
||||
The group's `FlattenBehavior` is `fill`; for `allOrNone` use `Std.Format.bracketFill`.
|
||||
-/
|
||||
@[inline] def bracketFill (l : String) (f : Format) (r : String) : Format :=
|
||||
fill (nest (String.Internal.length l) $ l ++ f ++ r)
|
||||
fill (nest l.length $ l ++ f ++ r)
|
||||
|
||||
/-- The default indentation level, which is two spaces. -/
|
||||
def defIndent := 2
|
||||
@@ -397,8 +397,8 @@ private structure State where
|
||||
|
||||
private instance : MonadPrettyFormat (StateM State) where
|
||||
-- We avoid a structure instance update, and write these functions using pattern matching because of issue #316
|
||||
pushOutput s := modify fun ⟨out, col⟩ => ⟨String.Internal.append out s, col + (String.Internal.length s)⟩
|
||||
pushNewline indent := modify fun ⟨out, _⟩ => ⟨String.Internal.append out (String.Internal.pushn "\n" ' ' indent), indent⟩
|
||||
pushOutput s := modify fun ⟨out, col⟩ => ⟨out ++ s, col + s.length⟩
|
||||
pushNewline indent := modify fun ⟨out, _⟩ => ⟨out ++ "\n".pushn ' ' indent, indent⟩
|
||||
currColumn := return (← get).column
|
||||
startTag _ := return ()
|
||||
endTags _ := return ()
|
||||
|
||||
@@ -9,7 +9,6 @@ prelude
|
||||
public import Init.Data.Format.Basic
|
||||
public import Init.Data.Array.Basic
|
||||
public import Init.Data.ToString.Basic
|
||||
import Init.Data.String.Basic
|
||||
|
||||
public section
|
||||
|
||||
|
||||
@@ -9,8 +9,6 @@ prelude
|
||||
public import Init.Data.Format.Macro
|
||||
public import Init.Data.Format.Instances
|
||||
public import Init.Meta
|
||||
import Init.Data.String.Basic
|
||||
import Init.Data.ToString.Name
|
||||
|
||||
public section
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ This file defines the `Int` type as well as
|
||||
Division and modulus operations are defined in `Init.Data.Int.DivMod.Basic`.
|
||||
-/
|
||||
|
||||
set_option genCtorIdx false in
|
||||
set_option genInjectivity false in
|
||||
/--
|
||||
The integers.
|
||||
|
||||
@@ -321,7 +321,7 @@ def natAbs (m : @& Int) : Nat :=
|
||||
| ofNat m => m
|
||||
| -[m +1] => m.succ
|
||||
|
||||
attribute [gen_constructor_elims] Int
|
||||
gen_injective_theorems% Int
|
||||
|
||||
/-! ## sign -/
|
||||
|
||||
|
||||
@@ -97,7 +97,7 @@ 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
|
||||
theorem emod_add_ediv : ∀ a b : Int, a % b + b * (a / b) = a
|
||||
| ofNat _, ofNat _ => congrArg ofNat <| Nat.mod_add_div ..
|
||||
| ofNat m, -[n+1] => by
|
||||
change (m % succ n + -↑(succ n) * -↑(m / succ n) : Int) = m
|
||||
@@ -111,35 +111,19 @@ where
|
||||
← Int.neg_neg (_-_), Int.neg_sub, Int.sub_sub_self, Int.add_right_comm]
|
||||
exact congrArg (fun x => -(ofNat x + 1)) (Nat.mod_add_div ..)
|
||||
|
||||
@[deprecated emod_add_mul_ediv (since := "2025-09-01")]
|
||||
def emod_add_ediv := @emod_add_mul_ediv
|
||||
/-- Variant of `emod_add_ediv` with the multiplication written the other way around. -/
|
||||
theorem emod_add_ediv' (a b : Int) : a % b + a / b * b = a := by
|
||||
rw [Int.mul_comm]; exact emod_add_ediv ..
|
||||
|
||||
theorem emod_add_ediv_mul (a b : Int) : a % b + a / b * b = a := by
|
||||
rw [Int.mul_comm]; exact emod_add_mul_ediv ..
|
||||
theorem ediv_add_emod (a b : Int) : b * (a / b) + a % b = a := by
|
||||
rw [Int.add_comm]; exact emod_add_ediv ..
|
||||
|
||||
@[deprecated emod_add_ediv_mul (since := "2025-09-01")]
|
||||
def emod_add_ediv' := @emod_add_ediv_mul
|
||||
|
||||
theorem mul_ediv_add_emod (a b : Int) : b * (a / b) + a % b = a := by
|
||||
rw [Int.add_comm]; exact emod_add_mul_ediv ..
|
||||
|
||||
@[deprecated mul_ediv_add_emod (since := "2025-09-01")]
|
||||
def ediv_add_emod := @mul_ediv_add_emod
|
||||
|
||||
theorem ediv_mul_add_emod (a b : Int) : a / b * b + a % b = a := by
|
||||
rw [Int.mul_comm]; exact mul_ediv_add_emod ..
|
||||
|
||||
@[deprecated ediv_mul_add_emod (since := "2025-09-01")]
|
||||
def ediv_add_emod' := @ediv_mul_add_emod
|
||||
/-- Variant of `ediv_add_emod` with the multiplication written the other way around. -/
|
||||
theorem ediv_add_emod' (a b : Int) : a / b * b + a % b = a := by
|
||||
rw [Int.mul_comm]; exact ediv_add_emod ..
|
||||
|
||||
theorem emod_def (a b : Int) : a % b = a - b * (a / b) := by
|
||||
rw [← Int.add_sub_cancel (a % b), emod_add_mul_ediv]
|
||||
|
||||
theorem mul_ediv_self (a b : Int) : b * (a / b) = a - a % b := by
|
||||
rw [emod_def, Int.sub_sub_self]
|
||||
|
||||
theorem ediv_mul_self (a b : Int) : a / b * b = a - a % b := by
|
||||
rw [Int.mul_comm, emod_def, Int.sub_sub_self]
|
||||
rw [← Int.add_sub_cancel (a % b), emod_add_ediv]
|
||||
|
||||
/-! ### `/` ediv -/
|
||||
|
||||
@@ -242,7 +226,7 @@ theorem add_mul_emod_self {a b c : Int} : (a + b * c) % c = a % c :=
|
||||
|
||||
@[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
|
||||
rwa [Int.add_right_comm, emod_add_ediv] at this
|
||||
|
||||
@[simp] theorem add_emod_emod (m n k : Int) : (m + n % k) % k = (m + n) % k := by
|
||||
rw [Int.add_comm, emod_add_emod, Int.add_comm]
|
||||
@@ -268,7 +252,7 @@ theorem emod_add_cancel_right {m n k : Int} (i) : (m + i) % n = (k + i) % n ↔
|
||||
|
||||
theorem mul_emod (a b n : Int) : (a * b) % n = (a % n) * (b % n) % n := by
|
||||
conv => lhs; rw [
|
||||
← emod_add_mul_ediv a n, ← emod_add_ediv_mul b n, Int.add_mul, Int.mul_add, Int.mul_add,
|
||||
← emod_add_ediv a n, ← emod_add_ediv' b n, Int.add_mul, Int.mul_add, Int.mul_add,
|
||||
Int.mul_assoc, Int.mul_assoc, ← Int.mul_add n _ _, add_mul_emod_self_left,
|
||||
← Int.mul_assoc, add_mul_emod_self_right]
|
||||
|
||||
@@ -277,7 +261,7 @@ theorem mul_emod (a b n : Int) : (a * b) % n = (a % n) * (b % n) % n := by
|
||||
|
||||
@[simp] theorem emod_emod_of_dvd (n : Int) {m k : Int}
|
||||
(h : m ∣ k) : (n % k) % m = n % m := by
|
||||
conv => rhs; rw [← emod_add_mul_ediv n k]
|
||||
conv => rhs; rw [← emod_add_ediv n k]
|
||||
match k, h with
|
||||
| _, ⟨t, rfl⟩ => rw [Int.mul_assoc, add_mul_emod_self_left]
|
||||
|
||||
@@ -291,7 +275,7 @@ theorem sub_emod (a b n : Int) : (a - b) % n = (a % n - b % n) % n := by
|
||||
/-! ### properties of `/` and `%` -/
|
||||
|
||||
theorem mul_ediv_cancel_of_emod_eq_zero {a b : Int} (H : a % b = 0) : b * (a / b) = a := by
|
||||
have := emod_add_mul_ediv a b; rwa [H, Int.zero_add] at this
|
||||
have := emod_add_ediv a b; rwa [H, Int.zero_add] at this
|
||||
|
||||
theorem ediv_mul_cancel_of_emod_eq_zero {a b : Int} (H : a % b = 0) : a / b * b = a := by
|
||||
rw [Int.mul_comm, mul_ediv_cancel_of_emod_eq_zero H]
|
||||
@@ -342,11 +326,11 @@ theorem emod_pos_of_not_dvd {a b : Int} (h : ¬ a ∣ b) : a = 0 ∨ 0 < b % a :
|
||||
theorem mul_ediv_self_le {x k : Int} (h : k ≠ 0) : k * (x / k) ≤ x :=
|
||||
calc k * (x / k)
|
||||
_ ≤ k * (x / k) + x % k := Int.le_add_of_nonneg_right (emod_nonneg x h)
|
||||
_ = x := mul_ediv_add_emod _ _
|
||||
_ = x := ediv_add_emod _ _
|
||||
|
||||
theorem lt_mul_ediv_self_add {x k : Int} (h : 0 < k) : x < k * (x / k) + k :=
|
||||
calc x
|
||||
_ = k * (x / k) + x % k := (mul_ediv_add_emod _ _).symm
|
||||
_ = k * (x / k) + x % k := (ediv_add_emod _ _).symm
|
||||
_ < k * (x / k) + k := Int.add_lt_add_left (emod_lt_of_pos x h) _
|
||||
|
||||
/-! ### bmod -/
|
||||
|
||||
@@ -334,7 +334,7 @@ theorem fdiv_eq_ediv_of_dvd {a b : Int} (h : b ∣ a) : a.fdiv b = a / b := by
|
||||
|
||||
/-! ### mod definitions -/
|
||||
|
||||
theorem tmod_add_mul_tdiv : ∀ a b : Int, tmod a b + b * (a.tdiv b) = a
|
||||
theorem tmod_add_tdiv : ∀ a b : Int, tmod a b + b * (a.tdiv b) = a
|
||||
| ofNat _, ofNat _ => congrArg ofNat (Nat.mod_add_div ..)
|
||||
| ofNat m, -[n+1] => by
|
||||
change (m % succ n + -↑(succ n) * -↑(m / succ n) : Int) = m
|
||||
@@ -351,37 +351,21 @@ theorem tmod_add_mul_tdiv : ∀ a b : Int, tmod a b + b * (a.tdiv b) = a
|
||||
rw [Int.neg_mul, ← Int.neg_add]
|
||||
exact congrArg (-ofNat ·) (Nat.mod_add_div ..)
|
||||
|
||||
@[deprecated tmod_add_mul_tdiv (since := "2025-09-01")]
|
||||
def tmod_add_tdiv := @tmod_add_mul_tdiv
|
||||
theorem tdiv_add_tmod (a b : Int) : b * a.tdiv b + tmod a b = a := by
|
||||
rw [Int.add_comm]; apply tmod_add_tdiv ..
|
||||
|
||||
theorem mul_tdiv_add_tmod (a b : Int) : b * a.tdiv b + tmod a b = a := by
|
||||
rw [Int.add_comm]; apply tmod_add_mul_tdiv ..
|
||||
/-- Variant of `tmod_add_tdiv` with the multiplication written the other way around. -/
|
||||
theorem tmod_add_tdiv' (m k : Int) : tmod m k + m.tdiv k * k = m := by
|
||||
rw [Int.mul_comm]; apply tmod_add_tdiv
|
||||
|
||||
@[deprecated mul_tdiv_add_tmod (since := "2025-09-01")]
|
||||
def tdiv_add_tmod := @mul_tdiv_add_tmod
|
||||
|
||||
theorem tmod_add_tdiv_mul (m k : Int) : tmod m k + m.tdiv k * k = m := by
|
||||
rw [Int.mul_comm]; apply tmod_add_mul_tdiv
|
||||
|
||||
@[deprecated tmod_add_tdiv_mul (since := "2025-09-01")]
|
||||
def tmod_add_tdiv' := @tmod_add_mul_tdiv
|
||||
|
||||
theorem tdiv_mul_add_tmod (m k : Int) : m.tdiv k * k + tmod m k = m := by
|
||||
rw [Int.mul_comm]; apply mul_tdiv_add_tmod
|
||||
|
||||
@[deprecated tdiv_mul_add_tmod (since := "2025-09-01")]
|
||||
def tdiv_add_tmod' := @tdiv_mul_add_tmod
|
||||
/-- Variant of `tdiv_add_tmod` with the multiplication written the other way around. -/
|
||||
theorem tdiv_add_tmod' (m k : Int) : m.tdiv k * k + tmod m k = m := by
|
||||
rw [Int.mul_comm]; apply tdiv_add_tmod
|
||||
|
||||
theorem tmod_def (a b : Int) : tmod a b = a - b * a.tdiv b := by
|
||||
rw [← Int.add_sub_cancel (tmod a b), tmod_add_mul_tdiv]
|
||||
rw [← Int.add_sub_cancel (tmod a b), tmod_add_tdiv]
|
||||
|
||||
theorem mul_tdiv_self (a b : Int) : b * (a.tdiv b) = a - a.tmod b := by
|
||||
rw [tmod_def, Int.sub_sub_self]
|
||||
|
||||
theorem tdiv_mul_self (a b : Int) : a.tdiv b * b = a - a.tmod b := by
|
||||
rw [Int.mul_comm, tmod_def, Int.sub_sub_self]
|
||||
|
||||
theorem fmod_add_mul_fdiv : ∀ a b : Int, a.fmod b + b * a.fdiv b = a
|
||||
theorem fmod_add_fdiv : ∀ a b : Int, a.fmod b + b * a.fdiv b = a
|
||||
| 0, ofNat _ | 0, -[_+1] => congrArg ofNat <| by simp
|
||||
| succ _, ofNat _ => congrArg ofNat <| Nat.mod_add_div ..
|
||||
| succ m, -[n+1] => by
|
||||
@@ -398,35 +382,19 @@ theorem fmod_add_mul_fdiv : ∀ a b : Int, a.fmod b + b * a.fdiv b = a
|
||||
change -(↑(succ m % succ n) : Int) + -↑(succ n * (succ m / succ n)) = -↑(succ m)
|
||||
rw [← Int.neg_add]; exact congrArg (-ofNat ·) <| Nat.mod_add_div ..
|
||||
|
||||
@[deprecated fmod_add_mul_fdiv (since := "2025-09-01")]
|
||||
def fmod_add_fdiv := @fmod_add_mul_fdiv
|
||||
/-- Variant of `fmod_add_fdiv` with the multiplication written the other way around. -/
|
||||
theorem fmod_add_fdiv' (a b : Int) : a.fmod b + (a.fdiv b) * b = a := by
|
||||
rw [Int.mul_comm]; exact fmod_add_fdiv ..
|
||||
|
||||
theorem fmod_add_fdiv_mul (a b : Int) : a.fmod b + (a.fdiv b) * b = a := by
|
||||
rw [Int.mul_comm]; exact fmod_add_mul_fdiv ..
|
||||
theorem fdiv_add_fmod (a b : Int) : b * a.fdiv b + a.fmod b = a := by
|
||||
rw [Int.add_comm]; exact fmod_add_fdiv ..
|
||||
|
||||
@[deprecated fmod_add_fdiv_mul (since := "2025-09-01")]
|
||||
def fmod_add_fdiv' := @fmod_add_fdiv_mul
|
||||
|
||||
theorem mul_fdiv_add_fmod (a b : Int) : b * a.fdiv b + a.fmod b = a := by
|
||||
rw [Int.add_comm]; exact fmod_add_mul_fdiv ..
|
||||
|
||||
@[deprecated mul_fdiv_add_fmod (since := "2025-09-01")]
|
||||
def fdiv_add_fmod := @mul_fdiv_add_fmod
|
||||
|
||||
theorem fdiv_mul_add_fmod (a b : Int) : (a.fdiv b) * b + a.fmod b = a := by
|
||||
rw [Int.mul_comm]; exact mul_fdiv_add_fmod ..
|
||||
|
||||
@[deprecated mul_fdiv_add_fmod (since := "2025-09-01")]
|
||||
def fdiv_add_fmod' := @mul_fdiv_add_fmod
|
||||
/-- Variant of `fdiv_add_fmod` with the multiplication written the other way around. -/
|
||||
theorem fdiv_add_fmod' (a b : Int) : (a.fdiv b) * b + a.fmod b = a := by
|
||||
rw [Int.mul_comm]; exact fdiv_add_fmod ..
|
||||
|
||||
theorem fmod_def (a b : Int) : a.fmod b = a - b * a.fdiv b := by
|
||||
rw [← Int.add_sub_cancel (a.fmod b), fmod_add_mul_fdiv]
|
||||
|
||||
theorem mul_fdiv_self (a b : Int) : b * (a.fdiv b) = a - a.fmod b := by
|
||||
rw [fmod_def, Int.sub_sub_self]
|
||||
|
||||
theorem fdiv_mul_self (a b : Int) : a.fdiv b * b = a - a.fmod b := by
|
||||
rw [Int.mul_comm, fmod_def, Int.sub_sub_self]
|
||||
rw [← Int.add_sub_cancel (a.fmod b), fmod_add_fdiv]
|
||||
|
||||
/-! ### mod equivalences -/
|
||||
|
||||
@@ -805,7 +773,7 @@ protected theorem ediv_emod_unique {a b r q : Int} (h : 0 < b) :
|
||||
a / b = q ∧ a % b = r ↔ r + b * q = a ∧ 0 ≤ r ∧ r < b := by
|
||||
constructor
|
||||
· intro ⟨rfl, rfl⟩
|
||||
exact ⟨emod_add_mul_ediv a b, emod_nonneg _ (Int.ne_of_gt h), emod_lt_of_pos _ h⟩
|
||||
exact ⟨emod_add_ediv a b, emod_nonneg _ (Int.ne_of_gt h), emod_lt_of_pos _ h⟩
|
||||
· intro ⟨rfl, hz, hb⟩
|
||||
constructor
|
||||
· rw [Int.add_mul_ediv_left r q (Int.ne_of_gt h), ediv_eq_zero_of_lt hz hb]
|
||||
@@ -829,7 +797,7 @@ theorem neg_ediv {a b : Int} : (-a) / b = -(a / b) - if b ∣ a then 0 else b.si
|
||||
if hb : b = 0 then
|
||||
simp [hb]
|
||||
else
|
||||
conv => lhs; rw [← mul_ediv_add_emod a b]
|
||||
conv => lhs; rw [← ediv_add_emod a b]
|
||||
rw [Int.neg_add, ← Int.mul_neg, mul_add_ediv_left _ _ hb, Int.add_comm]
|
||||
split <;> rename_i h
|
||||
· rw [emod_eq_zero_of_dvd h]
|
||||
@@ -1119,10 +1087,6 @@ theorem emod_natAbs_of_neg {x : Int} (h : x < 0) {n : Nat} (w : n ≠ 0) :
|
||||
protected theorem ediv_mul_le (a : Int) {b : Int} (H : b ≠ 0) : a / b * b ≤ a :=
|
||||
Int.le_of_sub_nonneg <| by rw [Int.mul_comm, ← emod_def]; apply emod_nonneg _ H
|
||||
|
||||
protected theorem lt_ediv_mul (a : Int) {b : Int} (H : 0 < b) : a - b < a / b * b := by
|
||||
rw [ediv_mul_self, Int.sub_lt_sub_left_iff]
|
||||
exact emod_lt_of_pos a H
|
||||
|
||||
theorem le_of_mul_le_mul_left {a b c : Int} (w : a * b ≤ a * c) (h : 0 < a) : b ≤ c := by
|
||||
have w := Int.sub_nonneg_of_le w
|
||||
rw [← Int.mul_sub] at w
|
||||
@@ -1213,9 +1177,9 @@ theorem ediv_eq_iff_of_pos {k x y : Int} (h : 0 < k) : x / k = y ↔ y * k ≤ x
|
||||
theorem add_ediv_of_pos {a b c : Int} (h : 0 < c) :
|
||||
(a + b) / c = a / c + b / c + if c ≤ a % c + b % c then 1 else 0 := by
|
||||
have h' : c ≠ 0 := by omega
|
||||
conv => lhs; rw [← Int.mul_ediv_add_emod a c]
|
||||
conv => lhs; rw [← Int.ediv_add_emod a c]
|
||||
rw [Int.add_assoc, Int.mul_add_ediv_left _ _ h']
|
||||
conv => lhs; rw [← Int.mul_ediv_add_emod b c]
|
||||
conv => lhs; rw [← Int.ediv_add_emod b c]
|
||||
rw [Int.add_comm (a % c), Int.add_assoc, Int.mul_add_ediv_left _ _ h',
|
||||
← Int.add_assoc, Int.add_comm (b % c)]
|
||||
congr
|
||||
@@ -1246,7 +1210,7 @@ theorem not_dvd_iff_lt_mul_succ (m : Int) (hn : 0 < n) :
|
||||
¬n ∣ m ↔ (∃ k, n * k < m ∧ m < n * (k + 1)) := by
|
||||
refine ⟨fun h ↦ ?_, ?_⟩
|
||||
· rw [dvd_iff_emod_eq_zero, ← Ne] at h
|
||||
rw [← emod_add_mul_ediv m n]
|
||||
rw [← emod_add_ediv m n]
|
||||
refine ⟨m / n, Int.lt_add_of_pos_left _ ?_, ?_⟩
|
||||
· have := emod_nonneg m (Int.ne_of_gt hn)
|
||||
omega
|
||||
@@ -1521,7 +1485,7 @@ theorem sign_tmod (a b : Int) : sign (tmod a b) = if b ∣ a then 0 else sign a
|
||||
-- Analogues of statements about `ediv` and `emod` from `Bootstrap.lean`
|
||||
|
||||
theorem mul_tdiv_cancel_of_tmod_eq_zero {a b : Int} (H : a.tmod b = 0) : b * (a.tdiv b) = a := by
|
||||
have := tmod_add_mul_tdiv a b; rwa [H, Int.zero_add] at this
|
||||
have := tmod_add_tdiv a b; rwa [H, Int.zero_add] at this
|
||||
|
||||
theorem tdiv_mul_cancel_of_tmod_eq_zero {a b : Int} (H : a.tmod b = 0) : a.tdiv b * b = a := by
|
||||
rw [Int.mul_comm, mul_tdiv_cancel_of_tmod_eq_zero H]
|
||||
@@ -2246,7 +2210,7 @@ theorem fmod_add_cancel_right {m n k : Int} (i) : (m + i).fmod n = (k + i).fmod
|
||||
|
||||
theorem mul_fmod (a b n : Int) : (a * b).fmod n = (a.fmod n * b.fmod n).fmod n := by
|
||||
conv => lhs; rw [
|
||||
← fmod_add_mul_fdiv a n, ← fmod_add_fdiv_mul b n, Int.add_mul, Int.mul_add, Int.mul_add,
|
||||
← fmod_add_fdiv a n, ← fmod_add_fdiv' b n, Int.add_mul, Int.mul_add, Int.mul_add,
|
||||
Int.mul_assoc, Int.mul_assoc, ← Int.mul_add n _ _, add_mul_fmod_self_left,
|
||||
← Int.mul_assoc, add_mul_fmod_self_right]
|
||||
|
||||
@@ -2255,7 +2219,7 @@ theorem mul_fmod (a b n : Int) : (a * b).fmod n = (a.fmod n * b.fmod n).fmod n :
|
||||
|
||||
@[simp] theorem fmod_fmod_of_dvd (n : Int) {m k : Int}
|
||||
(h : m ∣ k) : (n.fmod k).fmod m = n.fmod m := by
|
||||
conv => rhs; rw [← fmod_add_mul_fdiv n k]
|
||||
conv => rhs; rw [← fmod_add_fdiv n k]
|
||||
match k, h with
|
||||
| _, ⟨t, rfl⟩ => rw [Int.mul_assoc, add_mul_fmod_self_left]
|
||||
|
||||
@@ -2285,7 +2249,7 @@ theorem fmod_eq_of_lt {a b : Int} (H1 : 0 ≤ a) (H2 : a < b) : a.fmod b = a :=
|
||||
-- Analogues of properties of `ediv` and `emod` from `Bootstrap.lean`
|
||||
|
||||
theorem mul_fdiv_cancel_of_fmod_eq_zero {a b : Int} (H : a.fmod b = 0) : b * (a.fdiv b) = a := by
|
||||
have := fmod_add_mul_fdiv a b; rwa [H, Int.zero_add] at this
|
||||
have := fmod_add_fdiv a b; rwa [H, Int.zero_add] at this
|
||||
|
||||
theorem fdiv_mul_cancel_of_fmod_eq_zero {a b : Int} (H : a.fmod b = 0) : (a.fdiv b) * b= a := by
|
||||
rw [Int.mul_comm, mul_fdiv_cancel_of_fmod_eq_zero H]
|
||||
@@ -2527,9 +2491,9 @@ theorem bdiv_add_bmod (x : Int) (m : Nat) : m * bdiv x m + bmod x m = x := by
|
||||
ite_self]
|
||||
· dsimp only
|
||||
split
|
||||
· exact mul_ediv_add_emod x m
|
||||
· exact ediv_add_emod x m
|
||||
· rw [Int.mul_add, Int.mul_one, Int.add_assoc, Int.add_comm m, Int.sub_add_cancel]
|
||||
exact mul_ediv_add_emod x m
|
||||
exact ediv_add_emod x m
|
||||
|
||||
theorem bmod_add_bdiv (x : Int) (m : Nat) : bmod x m + m * bdiv x m = x := by
|
||||
rw [Int.add_comm]; exact bdiv_add_bmod x m
|
||||
@@ -2786,7 +2750,7 @@ theorem le_bmod {x : Int} {m : Nat} (h : 0 < m) : - (m/2) ≤ Int.bmod x m := by
|
||||
· exact Int.ne_of_gt (natCast_pos.mpr h)
|
||||
· simp [Int.not_lt] at w
|
||||
refine Int.le_trans ?_ (Int.sub_le_sub_right w _)
|
||||
rw [← mul_ediv_add_emod m 2]
|
||||
rw [← ediv_add_emod m 2]
|
||||
generalize (m : Int) / 2 = q
|
||||
generalize h : (m : Int) % 2 = r at *
|
||||
rcases v with rfl | rfl
|
||||
@@ -2947,7 +2911,7 @@ theorem neg_bmod {a : Int} {b : Nat} :
|
||||
simp only [gt_iff_lt, Nat.zero_lt_succ, Nat.mul_pos_iff_of_pos_left, Int.natCast_mul,
|
||||
cast_ofNat_Int, Int.not_lt] at *
|
||||
rw [Int.mul_dvd_mul_iff_left (by omega)]
|
||||
have := mul_ediv_add_emod a (2 * c)
|
||||
have := ediv_add_emod a (2 * c)
|
||||
rw [(by omega : a % (2 * c) = c)] at this
|
||||
rw [← this]
|
||||
apply Int.dvd_add _ (by simp)
|
||||
|
||||
@@ -40,7 +40,7 @@ theorem ofNat_succ (n : Nat) : (succ n : Int) = n + 1 := rfl
|
||||
|
||||
theorem neg_ofNat_zero : -((0 : Nat) : Int) = 0 := rfl
|
||||
theorem neg_ofNat_succ (n : Nat) : -(succ n : Int) = -[n+1] := rfl
|
||||
@[simp] theorem neg_negSucc (n : Nat) : -(-[n+1]) = ((n + 1 : Nat) : Int) := rfl
|
||||
theorem neg_negSucc (n : Nat) : -(-[n+1]) = succ n := rfl
|
||||
|
||||
theorem negOfNat_eq : negOfNat n = -ofNat n := rfl
|
||||
|
||||
|
||||
@@ -247,7 +247,7 @@ def cmod (a b : Int) : Int :=
|
||||
|
||||
theorem cdiv_add_cmod (a b : Int) : b*(cdiv a b) + cmod a b = a := by
|
||||
unfold cdiv cmod
|
||||
have := Int.mul_ediv_add_emod (-a) b
|
||||
have := Int.ediv_add_emod (-a) b
|
||||
have := congrArg (Neg.neg) this
|
||||
simp at this
|
||||
conv => rhs; rw[← this]
|
||||
@@ -272,7 +272,7 @@ private abbrev div_mul_cancel_of_mod_zero :=
|
||||
theorem cdiv_eq_div_of_divides {a b : Int} (h : a % b = 0) : a/b = cdiv a b := by
|
||||
replace h := div_mul_cancel_of_mod_zero h
|
||||
have hz : a % b = 0 := by
|
||||
have := Int.mul_ediv_add_emod a b
|
||||
have := Int.ediv_add_emod a b
|
||||
conv at this => rhs; rw [← Int.add_zero a]
|
||||
rw [Int.mul_comm, h] at this
|
||||
exact Int.add_left_cancel this
|
||||
@@ -379,11 +379,8 @@ def Poly.mul (p : Poly) (k : Int) : Poly :=
|
||||
p₁)
|
||||
fuel
|
||||
|
||||
@[expose] noncomputable def Poly.combine_mul_k (a b : Int) (p₁ p₂ : Poly) : Poly :=
|
||||
Bool.rec
|
||||
(Bool.rec (combine_mul_k' hugeFuel a b p₁ p₂) (p₁.mul_k a) (Int.beq' b 0))
|
||||
(p₂.mul_k b)
|
||||
(Int.beq' a 0)
|
||||
@[expose] noncomputable def Poly.combine_mul_k (a b : Int) : Poly → Poly → Poly :=
|
||||
combine_mul_k' hugeFuel a b
|
||||
|
||||
@[simp] theorem Poly.denote_mul (ctx : Context) (p : Poly) (k : Int) : (p.mul k).denote ctx = k * p.denote ctx := by
|
||||
simp [mul]
|
||||
@@ -427,36 +424,34 @@ theorem Poly.denote_combine (ctx : Context) (p₁ p₂ : Poly) : (p₁.combine p
|
||||
|
||||
theorem Poly.denote_combine_mul_k (ctx : Context) (a b : Int) (p₁ p₂ : Poly) : (p₁.combine_mul_k a b p₂).denote ctx = a * p₁.denote ctx + b * p₂.denote ctx := by
|
||||
unfold combine_mul_k
|
||||
cases h₁ : Int.beq' a 0 <;> simp at h₁ <;> simp [*]
|
||||
cases h₂ : Int.beq' b 0 <;> simp at h₂ <;> simp [*]
|
||||
generalize hugeFuel = fuel
|
||||
induction fuel generalizing p₁ p₂
|
||||
next => show ((p₁.mul a).append (p₂.mul b)).denote ctx = _; simp
|
||||
next fuel ih =>
|
||||
cases p₁ <;> cases p₂ <;> simp [combine_mul_k']
|
||||
next k₁ k₂ v₂ p₂ =>
|
||||
show _ + (combine_mul_k' fuel a b (.num k₁) p₂).denote ctx = _
|
||||
simp [ih, Int.mul_assoc]
|
||||
next k₁ v₁ p₁ k₂ =>
|
||||
show _ + (combine_mul_k' fuel a b p₁ (.num k₂)).denote ctx = _
|
||||
simp [ih, Int.mul_assoc]
|
||||
next k₁ v₁ p₁ k₂ v₂ p₂ =>
|
||||
cases h₁ : Nat.beq v₁ v₂ <;> simp
|
||||
next =>
|
||||
cases h₂ : Nat.blt v₂ v₁ <;> simp
|
||||
next =>
|
||||
show _ + (combine_mul_k' fuel a b (add k₁ v₁ p₁) p₂).denote ctx = _
|
||||
simp [ih, Int.mul_assoc]
|
||||
next =>
|
||||
show _ + (combine_mul_k' fuel a b p₁ (add k₂ v₂ p₂)).denote ctx = _
|
||||
simp [ih, Int.mul_assoc]
|
||||
next =>
|
||||
simp at h₁; subst v₂
|
||||
cases h₂ : (a * k₁ + b * k₂).beq' 0 <;> simp
|
||||
next =>
|
||||
cases p₁ <;> cases p₂ <;> simp [combine_mul_k']
|
||||
next k₁ k₂ v₂ p₂ =>
|
||||
show _ + (combine_mul_k' fuel a b (.num k₁) p₂).denote ctx = _
|
||||
simp [ih, Int.mul_assoc]
|
||||
next k₁ v₁ p₁ k₂ =>
|
||||
show _ + (combine_mul_k' fuel a b p₁ (.num k₂)).denote ctx = _
|
||||
simp [ih, Int.mul_assoc]
|
||||
next k₁ v₁ p₁ k₂ v₂ p₂ =>
|
||||
cases h₁ : Nat.beq v₁ v₂ <;> simp
|
||||
next =>
|
||||
cases h₂ : Nat.blt v₂ v₁ <;> simp
|
||||
next =>
|
||||
show _ + (combine_mul_k' fuel a b (add k₁ v₁ p₁) p₂).denote ctx = _
|
||||
simp [ih, Int.mul_assoc]
|
||||
next =>
|
||||
show _ + (combine_mul_k' fuel a b p₁ (add k₂ v₂ p₂)).denote ctx = _
|
||||
simp [ih, Int.mul_assoc]
|
||||
next =>
|
||||
simp at h₁; subst v₂
|
||||
cases h₂ : (a * k₁ + b * k₂).beq' 0 <;> simp
|
||||
next =>
|
||||
show a * k₁ * v₁.denote ctx + (b * k₂ * v₁.denote ctx + (combine_mul_k' fuel a b p₁ p₂).denote ctx) = _
|
||||
simp [ih, Int.mul_assoc]
|
||||
next =>
|
||||
next =>
|
||||
simp at h₂
|
||||
show (combine_mul_k' fuel a b p₁ p₂).denote ctx = _
|
||||
simp [ih, ← Int.mul_assoc, ← Int.add_mul, h₂]
|
||||
@@ -1758,7 +1753,7 @@ theorem cooper_right_split_dvd (ctx : Context) (p₁ p₂ : Poly) (k : Nat) (b :
|
||||
intros; subst b p'; simp; assumption
|
||||
|
||||
private theorem one_emod_eq_one {a : Int} (h : a > 1) : 1 % a = 1 := by
|
||||
have aux₁ := Int.mul_ediv_add_emod 1 a
|
||||
have aux₁ := Int.ediv_add_emod 1 a
|
||||
have : 1 / a = 0 := Int.ediv_eq_zero_of_lt (by decide) h
|
||||
simp [this] at aux₁
|
||||
assumption
|
||||
@@ -1785,7 +1780,7 @@ private theorem ex_of_dvd {α β a b d x : Int}
|
||||
rw [Int.mul_emod, aux₁, Int.one_mul, Int.emod_emod] at this
|
||||
assumption
|
||||
have : x = (x / d)*d + (- α * b) % d := by
|
||||
conv => lhs; rw [← Int.mul_ediv_add_emod x d]
|
||||
conv => lhs; rw [← Int.ediv_add_emod x d]
|
||||
rw [Int.mul_comm, this]
|
||||
exists x / d
|
||||
|
||||
@@ -1868,7 +1863,7 @@ theorem cooper_unsat (ctx : Context) (p₁ p₂ p₃ : Poly) (d : Int) (α β :
|
||||
exact cooper_unsat' h₁ h₂ h₃ h₄ h₅ h₆
|
||||
|
||||
theorem ediv_emod (x y : Int) : -1 * x + y * (x / y) + x % y = 0 := by
|
||||
rw [Int.add_assoc, Int.mul_ediv_add_emod x y, Int.add_comm]
|
||||
rw [Int.add_assoc, Int.ediv_add_emod x y, Int.add_comm]
|
||||
simp
|
||||
rw [Int.add_neg_eq_sub, Int.sub_self]
|
||||
|
||||
|
||||
@@ -701,13 +701,10 @@ theorem toNat_sub_toNat_neg : ∀ n : Int, ↑n.toNat - ↑(-n).toNat = n
|
||||
| (_+1:Nat) => Nat.add_zero _
|
||||
| -[_+1] => Nat.zero_add _
|
||||
|
||||
@[simp] theorem toNat_neg_natCast : ∀ n : Nat, (-(n : Int)).toNat = 0
|
||||
@[simp] theorem toNat_neg_nat : ∀ n : Nat, (-(n : Int)).toNat = 0
|
||||
| 0 => rfl
|
||||
| _+1 => rfl
|
||||
|
||||
@[deprecated toNat_neg_natCast (since := "2025-08-29")]
|
||||
theorem toNat_neg_nat : ∀ n : Nat, (-(n : Int)).toNat = 0 := toNat_neg_natCast
|
||||
|
||||
/-! ### toNat? -/
|
||||
|
||||
theorem mem_toNat? : ∀ {a : Int} {n : Nat}, toNat? a = some n ↔ a = n
|
||||
|
||||
@@ -12,6 +12,7 @@ public import Init.Data.List.Impl
|
||||
public import Init.Data.List.Nat.Erase
|
||||
public import Init.Data.List.Monadic
|
||||
public import Init.Data.List.Nat.InsertIdx
|
||||
public import Init.Data.Array.Lex.Basic
|
||||
public import Init.Data.Array.Basic
|
||||
import all Init.Data.Array.Basic
|
||||
public import Init.Data.Array.Set
|
||||
|
||||
@@ -257,6 +257,8 @@ attribute [simp] Nat.le_refl
|
||||
|
||||
theorem succ_lt_succ {n m : Nat} : n < m → succ n < succ m := succ_le_succ
|
||||
|
||||
theorem lt_succ_of_le {n m : Nat} : n ≤ m → n < succ m := succ_le_succ
|
||||
|
||||
theorem le_of_lt_add_one {n m : Nat} : n < m + 1 → n ≤ m := le_of_succ_le_succ
|
||||
|
||||
theorem lt_add_one_of_le {n m : Nat} : n ≤ m → n < m + 1 := succ_le_succ
|
||||
@@ -269,15 +271,37 @@ theorem not_add_one_le_self : (n : Nat) → ¬ n + 1 ≤ n := Nat.not_succ_le_se
|
||||
|
||||
theorem add_one_pos (n : Nat) : 0 < n + 1 := Nat.zero_lt_succ n
|
||||
|
||||
theorem succ_sub_succ_eq_sub (n m : Nat) : succ n - succ m = n - m := by
|
||||
induction m with
|
||||
| zero => exact rfl
|
||||
| succ m ih => apply congrArg pred ih
|
||||
|
||||
theorem pred_le : ∀ (n : Nat), pred n ≤ n
|
||||
| zero => Nat.le.refl
|
||||
| succ _ => le_succ _
|
||||
|
||||
theorem pred_lt : ∀ {n : Nat}, n ≠ 0 → pred n < n
|
||||
| zero, h => absurd rfl h
|
||||
| succ _, _ => lt_succ_of_le (Nat.le_refl _)
|
||||
|
||||
theorem sub_one_lt : ∀ {n : Nat}, n ≠ 0 → n - 1 < n := pred_lt
|
||||
|
||||
@[simp] theorem sub_le (n m : Nat) : n - m ≤ n := by
|
||||
induction m with
|
||||
| zero => exact Nat.le_refl (n - 0)
|
||||
| succ m ih => apply Nat.le_trans (pred_le (n - m)) ih
|
||||
|
||||
theorem sub_lt_of_lt {a b c : Nat} (h : a < c) : a - b < c :=
|
||||
Nat.lt_of_le_of_lt (Nat.sub_le _ _) h
|
||||
|
||||
theorem sub_lt : ∀ {n m : Nat}, 0 < n → 0 < m → n - m < n
|
||||
| 0, _, h1, _ => absurd h1 (Nat.lt_irrefl 0)
|
||||
| _+1, 0, _, h2 => absurd h2 (Nat.lt_irrefl 0)
|
||||
| n+1, m+1, _, _ =>
|
||||
Eq.symm (succ_sub_succ_eq_sub n m) ▸
|
||||
show n - m < succ n from
|
||||
lt_succ_of_le (sub_le n m)
|
||||
|
||||
theorem sub_succ (n m : Nat) : n - succ m = pred (n - m) := rfl
|
||||
|
||||
theorem succ_sub_succ (n m : Nat) : succ n - succ m = n - m :=
|
||||
@@ -292,6 +316,9 @@ theorem sub_add_eq (a b c : Nat) : a - (b + c) = a - b - c := by
|
||||
| zero => simp
|
||||
| succ c ih => simp only [Nat.add_succ, Nat.sub_succ, ih]
|
||||
|
||||
protected theorem lt_of_lt_of_le {n m k : Nat} : n < m → m ≤ k → n < k :=
|
||||
Nat.le_trans
|
||||
|
||||
protected theorem lt_of_lt_of_eq {n m k : Nat} : n < m → m = k → n < k :=
|
||||
fun h₁ h₂ => h₂ ▸ h₁
|
||||
|
||||
@@ -329,10 +356,12 @@ protected theorem pos_of_ne_zero {n : Nat} : n ≠ 0 → 0 < n := (eq_zero_or_po
|
||||
|
||||
theorem pos_of_neZero (n : Nat) [NeZero n] : 0 < n := Nat.pos_of_ne_zero (NeZero.ne _)
|
||||
|
||||
attribute [simp] Nat.lt_add_one
|
||||
|
||||
theorem lt.base (n : Nat) : n < succ n := Nat.le_refl (succ n)
|
||||
|
||||
theorem lt_succ_self (n : Nat) : n < succ n := lt.base n
|
||||
|
||||
@[simp] protected theorem lt_add_one (n : Nat) : n < n + 1 := lt.base n
|
||||
|
||||
protected theorem le_total (m n : Nat) : m ≤ n ∨ n ≤ m :=
|
||||
match Nat.lt_or_ge m n with
|
||||
| Or.inl h => Or.inl (Nat.le_of_lt h)
|
||||
@@ -428,6 +457,7 @@ protected theorem le_lt_asymm : ∀{a b : Nat}, a ≤ b → ¬(b < a) := flip Na
|
||||
|
||||
theorem gt_of_not_le {n m : Nat} (h : ¬ n ≤ m) : n > m := (Nat.lt_or_ge m n).resolve_right h
|
||||
protected theorem lt_of_not_ge : ∀{a b : Nat}, ¬(b ≥ a) → b < a := Nat.gt_of_not_le
|
||||
protected theorem lt_of_not_le : ∀{a b : Nat}, ¬(a ≤ b) → b < a := Nat.gt_of_not_le
|
||||
|
||||
theorem ge_of_not_lt {n m : Nat} (h : ¬ n < m) : n ≥ m := (Nat.lt_or_ge n m).resolve_left h
|
||||
protected theorem le_of_not_gt : ∀{a b : Nat}, ¬(b > a) → b ≤ a := Nat.ge_of_not_lt
|
||||
@@ -740,6 +770,10 @@ protected theorem mul_lt_mul_of_pos_left {n m k : Nat} (h : n < m) (hk : k > 0)
|
||||
protected theorem mul_lt_mul_of_pos_right {n m k : Nat} (h : n < m) (hk : k > 0) : n * k < m * k :=
|
||||
Nat.mul_comm k m ▸ Nat.mul_comm k n ▸ Nat.mul_lt_mul_of_pos_left h hk
|
||||
|
||||
protected theorem mul_pos {n m : Nat} (ha : n > 0) (hb : m > 0) : n * m > 0 :=
|
||||
have h : 0 * m < n * m := Nat.mul_lt_mul_of_pos_right ha hb
|
||||
Nat.zero_mul m ▸ h
|
||||
|
||||
protected theorem le_of_mul_le_mul_left {a b c : Nat} (h : c * a ≤ c * b) (hc : 0 < c) : a ≤ b :=
|
||||
Nat.ge_of_not_lt fun hlt : b < a =>
|
||||
have h' : c * b < c * a := Nat.mul_lt_mul_of_pos_left hlt hc
|
||||
@@ -799,6 +833,11 @@ set_option linter.missingDocs false in
|
||||
@[deprecated Nat.pow_le_pow_right (since := "2025-02-17")]
|
||||
abbrev pow_le_pow_of_le_right := @Nat.pow_le_pow_right
|
||||
|
||||
protected theorem pow_pos (h : 0 < a) : 0 < a^n :=
|
||||
match n with
|
||||
| 0 => Nat.zero_lt_one
|
||||
| _ + 1 => Nat.mul_pos (Nat.pow_pos h) h
|
||||
|
||||
set_option linter.missingDocs false in
|
||||
@[deprecated Nat.pow_pos (since := "2025-02-17")]
|
||||
abbrev pos_pow_of_pos := @Nat.pow_pos
|
||||
@@ -1160,8 +1199,6 @@ protected theorem sub_eq_iff_eq_add {c : Nat} (h : b ≤ a) : a - b = c ↔ a =
|
||||
protected theorem sub_eq_iff_eq_add' {c : Nat} (h : b ≤ a) : a - b = c ↔ a = b + c := by
|
||||
rw [Nat.add_comm, Nat.sub_eq_iff_eq_add h]
|
||||
|
||||
attribute [simp] sub_le
|
||||
|
||||
protected theorem sub_one_sub_lt_of_lt (h : a < b) : b - 1 - a < b := by
|
||||
rw [← Nat.sub_add_eq]
|
||||
exact sub_lt (zero_lt_of_lt h) (Nat.lt_add_right a Nat.one_pos)
|
||||
|
||||
@@ -24,6 +24,47 @@ there is some `c` such that `b = a * c`.
|
||||
instance : Dvd Nat where
|
||||
dvd a b := Exists (fun c => b = a * c)
|
||||
|
||||
theorem div_rec_lemma {x y : Nat} : 0 < y ∧ y ≤ x → x - y < x :=
|
||||
fun ⟨ypos, ylex⟩ => sub_lt (Nat.lt_of_lt_of_le ypos ylex) ypos
|
||||
|
||||
theorem div_rec_fuel_lemma {x y fuel : Nat} (hy : 0 < y) (hle : y ≤ x) (hfuel : x < fuel + 1) :
|
||||
x - y < fuel :=
|
||||
Nat.lt_of_lt_of_le (div_rec_lemma ⟨hy, hle⟩) (Nat.le_of_lt_succ hfuel)
|
||||
|
||||
/--
|
||||
Division of natural numbers, discarding the remainder. Division by `0` returns `0`. Usually accessed
|
||||
via the `/` operator.
|
||||
|
||||
This operation is sometimes called “floor division.”
|
||||
|
||||
This function is overridden at runtime with an efficient implementation. This definition is
|
||||
the logical model.
|
||||
|
||||
Examples:
|
||||
* `21 / 3 = 7`
|
||||
* `21 / 5 = 4`
|
||||
* `0 / 22 = 0`
|
||||
* `5 / 0 = 0`
|
||||
-/
|
||||
@[extern "lean_nat_div", irreducible]
|
||||
protected def div (x y : @& Nat) : Nat :=
|
||||
if hy : 0 < y then
|
||||
let rec
|
||||
go (fuel : Nat) (x : Nat) (hfuel : x < fuel) : Nat :=
|
||||
match fuel with
|
||||
| 0 => by contradiction
|
||||
| succ fuel =>
|
||||
if h : y ≤ x then
|
||||
go fuel (x - y) (div_rec_fuel_lemma hy h hfuel) + 1
|
||||
else
|
||||
0
|
||||
termination_by structural fuel
|
||||
go (x + 1) x (Nat.lt_succ_self _)
|
||||
else
|
||||
0
|
||||
|
||||
instance instDiv : Div Nat := ⟨Nat.div⟩
|
||||
|
||||
private theorem div.go.fuel_congr (x y fuel1 fuel2 : Nat) (hy : 0 < y) (h1 : x < fuel1) (h2 : x < fuel2) :
|
||||
Nat.div.go y hy fuel1 x h1 = Nat.div.go y hy fuel2 x h2 := by
|
||||
match fuel1, fuel2 with
|
||||
@@ -113,6 +154,36 @@ protected def divExact (x y : @& Nat) (h : y ∣ x) : Nat :=
|
||||
@[simp]
|
||||
theorem divExact_eq_div {x y : Nat} (h : y ∣ x) : x.divExact y h = x / y := rfl
|
||||
|
||||
/--
|
||||
The modulo operator, which computes the remainder when dividing one natural number by another.
|
||||
Usually accessed via the `%` operator. When the divisor is `0`, the result is the dividend rather
|
||||
than an error.
|
||||
|
||||
This is the core implementation of `Nat.mod`. It computes the correct result for any two closed
|
||||
natural numbers, but it does not have some convenient [definitional
|
||||
reductions](lean-manual://section/type-system) when the `Nat`s contain free variables. The wrapper
|
||||
`Nat.mod` handles those cases specially and then calls `Nat.modCore`.
|
||||
|
||||
This function is overridden at runtime with an efficient implementation. This definition is the
|
||||
logical model.
|
||||
-/
|
||||
@[extern "lean_nat_mod", irreducible]
|
||||
protected noncomputable def modCore (x y : Nat) : Nat :=
|
||||
if hy : 0 < y then
|
||||
let rec
|
||||
go (fuel : Nat) (x : Nat) (hfuel : x < fuel) : Nat :=
|
||||
match fuel with
|
||||
| 0 => by contradiction
|
||||
| succ fuel =>
|
||||
if h : y ≤ x then
|
||||
go fuel (x - y) (div_rec_fuel_lemma hy h hfuel)
|
||||
else
|
||||
x
|
||||
termination_by structural fuel
|
||||
go (x + 1) x (Nat.lt_succ_self _)
|
||||
else
|
||||
x
|
||||
|
||||
private theorem modCore.go.fuel_congr (x y fuel1 fuel2 : Nat) (hy : 0 < y) (h1 : x < fuel1) (h2 : x < fuel2) :
|
||||
Nat.modCore.go y hy fuel1 x h1 = Nat.modCore.go y hy fuel2 x h2 := by
|
||||
match fuel1, fuel2 with
|
||||
@@ -143,6 +214,51 @@ protected theorem modCore_eq (x y : Nat) : Nat.modCore x y =
|
||||
next =>
|
||||
simp only [false_and, ↓reduceIte, *]
|
||||
|
||||
|
||||
/--
|
||||
The modulo operator, which computes the remainder when dividing one natural number by another.
|
||||
Usually accessed via the `%` operator. When the divisor is `0`, the result is the dividend rather
|
||||
than an error.
|
||||
|
||||
`Nat.mod` is a wrapper around `Nat.modCore` that special-cases two situations, giving better
|
||||
definitional reductions:
|
||||
* `Nat.mod 0 m` should reduce to `m`, for all terms `m : Nat`.
|
||||
* `Nat.mod n (m + n + 1)` should reduce to `n` for concrete `Nat` literals `n`.
|
||||
|
||||
These reductions help `Fin n` literals work well, because the `OfNat` instance for `Fin` uses
|
||||
`Nat.mod`. In particular, `(0 : Fin (n + 1)).val` should reduce definitionally to `0`. `Nat.modCore`
|
||||
can handle all numbers, but its definitional reductions are not as convenient.
|
||||
|
||||
This function is overridden at runtime with an efficient implementation. This definition is the
|
||||
logical model.
|
||||
|
||||
Examples:
|
||||
* `7 % 2 = 1`
|
||||
* `9 % 3 = 0`
|
||||
* `5 % 7 = 5`
|
||||
* `5 % 0 = 5`
|
||||
* `show ∀ (n : Nat), 0 % n = 0 from fun _ => rfl`
|
||||
* `show ∀ (m : Nat), 5 % (m + 6) = 5 from fun _ => rfl`
|
||||
-/
|
||||
@[extern "lean_nat_mod"]
|
||||
protected def mod : @& Nat → @& Nat → Nat
|
||||
/-
|
||||
Nat.modCore is defined with fuel and thus does not reduce with open terms very well.
|
||||
Nevertheless it is desirable for trivial `Nat.mod` calculations, namely
|
||||
* `Nat.mod 0 m` for all `m`
|
||||
* `Nat.mod n (m + n + 1)` for concrete literals `n`,
|
||||
to reduce definitionally.
|
||||
This property is desirable for `Fin n` literals, as it means `(ofNat 0 : Fin n).val = 0` by
|
||||
definition.
|
||||
-/
|
||||
| 0, _ => 0
|
||||
| n@(_ + 1), m =>
|
||||
if m ≤ n -- NB: if n < m does not reduce as well as `m ≤ n`!
|
||||
then Nat.modCore n m
|
||||
else n
|
||||
|
||||
instance instMod : Mod Nat := ⟨Nat.mod⟩
|
||||
|
||||
protected theorem modCore_eq_mod (n m : Nat) : Nat.modCore n m = n % m := by
|
||||
change Nat.modCore n m = Nat.mod n m
|
||||
match n, m with
|
||||
@@ -199,6 +315,24 @@ theorem mod_eq_sub_mod {a b : Nat} (h : a ≥ b) : a % b = (a - b) % b :=
|
||||
| Or.inl h₁ => h₁.symm ▸ (Nat.sub_zero a).symm ▸ rfl
|
||||
| Or.inr h₁ => (mod_eq a b).symm ▸ if_pos ⟨h₁, h⟩
|
||||
|
||||
theorem mod_lt (x : Nat) {y : Nat} : y > 0 → x % y < y := by
|
||||
induction x, y using mod.inductionOn with
|
||||
| base x y h₁ =>
|
||||
intro h₂
|
||||
have h₁ : ¬ 0 < y ∨ ¬ y ≤ x := Decidable.not_and_iff_or_not.mp h₁
|
||||
match h₁ with
|
||||
| Or.inl h₁ => exact absurd h₂ h₁
|
||||
| Or.inr h₁ =>
|
||||
have hgt : y > x := gt_of_not_le h₁
|
||||
have heq : x % y = x := mod_eq_of_lt hgt
|
||||
rw [← heq] at hgt
|
||||
exact hgt
|
||||
| ind x y h h₂ =>
|
||||
intro h₃
|
||||
have ⟨_, h₁⟩ := h
|
||||
rw [mod_eq_sub_mod h₁]
|
||||
exact h₂ h₃
|
||||
|
||||
@[simp] protected theorem sub_mod_add_mod_cancel (a b : Nat) [NeZero a] : a - b % a + b % a = a := by
|
||||
rw [Nat.sub_add_cancel]
|
||||
cases a with
|
||||
|
||||
@@ -264,6 +264,9 @@ protected theorem pos_of_lt_add_left : n < k + n → 0 < k := by
|
||||
protected theorem add_pos_left (h : 0 < m) (n) : 0 < m + n :=
|
||||
Nat.lt_of_lt_of_le h (Nat.le_add_right ..)
|
||||
|
||||
protected theorem add_pos_right (m) (h : 0 < n) : 0 < m + n :=
|
||||
Nat.lt_of_lt_of_le h (Nat.le_add_left ..)
|
||||
|
||||
protected theorem add_self_ne_one : ∀ n, n + n ≠ 1
|
||||
| n+1, h => by rw [Nat.succ_add, Nat.succ.injEq] at h; contradiction
|
||||
|
||||
|
||||
@@ -67,20 +67,20 @@ public structure Packages.PreorderOfLEArgs (α : Type u) where
|
||||
extract_lets
|
||||
first
|
||||
| infer_instance
|
||||
| exact _root_.Classical.Order.instLT
|
||||
| exact Classical.Order.instLT
|
||||
beq :
|
||||
let := le; let := decidableLE
|
||||
BEq α := by
|
||||
extract_lets
|
||||
first
|
||||
| infer_instance
|
||||
| exact _root_.Std.FactoryInstances.beqOfDecidableLE
|
||||
| exact FactoryInstances.beqOfDecidableLE
|
||||
lt_iff :
|
||||
let := le; let := lt
|
||||
∀ a b : α, a < b ↔ a ≤ b ∧ ¬ b ≤ a := by
|
||||
extract_lets
|
||||
first
|
||||
| exact _root_.Std.LawfulOrderLT.lt_iff
|
||||
| exact LawfulOrderLT.lt_iff
|
||||
| fail "Failed to automatically prove that the `LE` and `LT` instances are compatible. \
|
||||
Please ensure that a `LawfulOrderLT` instance can be synthesized or \
|
||||
manually provide the field `lt_iff`."
|
||||
@@ -89,10 +89,10 @@ public structure Packages.PreorderOfLEArgs (α : Type u) where
|
||||
have := lt_iff
|
||||
DecidableLT α := by
|
||||
extract_lets
|
||||
haveI := @_root_.Std.LawfulOrderLT.mk (lt_iff := by assumption) ..
|
||||
haveI := @LawfulOrderLT.mk (lt_iff := by assumption) ..
|
||||
first
|
||||
| infer_instance
|
||||
| exact _root_.Std.FactoryInstances.decidableLTOfLE
|
||||
| exact FactoryInstances.decidableLTOfLE
|
||||
| fail "Failed to automatically derive that `LT` is decidable. \
|
||||
Please ensure that a `DecidableLT` instance can be synthesized or \
|
||||
manually provide the field `decidableLT`."
|
||||
@@ -101,7 +101,7 @@ public structure Packages.PreorderOfLEArgs (α : Type u) where
|
||||
∀ a b : α, a == b ↔ a ≤ b ∧ b ≤ a := by
|
||||
extract_lets
|
||||
first
|
||||
| exact _root_.Std.LawfulOrderBEq.beq_iff_le_and_ge
|
||||
| exact LawfulOrderBEq.beq_iff_le_and_ge
|
||||
| fail "Failed to automatically prove that the `LE` and `BEq` instances are compatible. \
|
||||
Please ensure that a `LawfulOrderBEq` instance can be synthesized or \
|
||||
manually provide the field `beq_iff_le_and_ge`."
|
||||
@@ -110,7 +110,7 @@ public structure Packages.PreorderOfLEArgs (α : Type u) where
|
||||
∀ a : α, a ≤ a := by
|
||||
extract_lets
|
||||
first
|
||||
| exact _root_.Std.Refl.refl (r := (· ≤ ·))
|
||||
| exact Std.Refl.refl (r := (· ≤ ·))
|
||||
| fail "Failed to automatically prove that the `LE` instance is reflexive. \
|
||||
Please ensure that a `Refl` instance can be synthesized or \
|
||||
manually provide the field `le_refl`."
|
||||
@@ -119,7 +119,7 @@ public structure Packages.PreorderOfLEArgs (α : Type u) where
|
||||
∀ a b c : α, a ≤ b → b ≤ c → a ≤ c := by
|
||||
extract_lets
|
||||
first
|
||||
| exact fun _ _ _ hab hbc => _root_.Trans.trans (r := (· ≤ ·)) (s := (· ≤ ·)) (t := (· ≤ ·)) hab hbc
|
||||
| exact fun _ _ _ hab hbc => Trans.trans (r := (· ≤ ·)) (s := (· ≤ ·)) (t := (· ≤ ·)) hab hbc
|
||||
| fail "Failed to automatically prove that the `LE` instance is transitive. \
|
||||
Please ensure that a `Trans` instance can be synthesized or \
|
||||
manually provide the field `le_trans`."
|
||||
@@ -202,7 +202,7 @@ public structure Packages.PartialOrderOfLEArgs (α : Type u) extends Packages.Pr
|
||||
∀ a b : α, a ≤ b → b ≤ a → a = b := by
|
||||
extract_lets
|
||||
first
|
||||
| exact _root_.Std.Antisymm.antisymm
|
||||
| exact Antisymm.antisymm
|
||||
| fail "Failed to automatically prove that the `LE` instance is antisymmetric. \
|
||||
Please ensure that a `Antisymm` instance can be synthesized or \
|
||||
manually provide the field `le_antisymm`."
|
||||
@@ -310,11 +310,11 @@ public structure Packages.LinearPreorderOfLEArgs (α : Type u) extends
|
||||
extract_lets
|
||||
first
|
||||
| infer_instance
|
||||
| exact _root_.Std.FactoryInstances.instOrdOfDecidableLE
|
||||
| exact FactoryInstances.instOrdOfDecidableLE
|
||||
le_total :
|
||||
∀ a b : α, a ≤ b ∨ b ≤ a := by
|
||||
first
|
||||
| exact _root_.Std.Total.total
|
||||
| exact Total.total
|
||||
| fail "Failed to automatically prove that the `LE` instance is total. \
|
||||
Please ensure that a `Total` instance can be synthesized or \
|
||||
manually provide the field `le_total`."
|
||||
@@ -324,7 +324,7 @@ public structure Packages.LinearPreorderOfLEArgs (α : Type u) extends
|
||||
∀ a b : α, (compare a b).isLE ↔ a ≤ b := by
|
||||
extract_lets
|
||||
first
|
||||
| exact _root_.Std.LawfulOrderOrd.isLE_compare
|
||||
| exact LawfulOrderOrd.isLE_compare
|
||||
| fail "Failed to automatically prove that `(compare a b).isLE` is equivalent to `a ≤ b`. \
|
||||
Please ensure that a `LawfulOrderOrd` instance can be synthesized or \
|
||||
manually provide the field `isLE_compare`."
|
||||
@@ -333,7 +333,7 @@ public structure Packages.LinearPreorderOfLEArgs (α : Type u) extends
|
||||
∀ a b : α, (compare a b).isGE ↔ b ≤ a := by
|
||||
extract_lets
|
||||
first
|
||||
| exact _root_.Std.LawfulOrderOrd.isGE_compare
|
||||
| exact LawfulOrderOrd.isGE_compare
|
||||
| fail "Failed to automatically prove that `(compare a b).isGE` is equivalent to `b ≤ a`. \
|
||||
Please ensure that a `LawfulOrderOrd` instance can be synthesized or \
|
||||
manually provide the field `isGE_compare`."
|
||||
@@ -411,20 +411,20 @@ public structure Packages.LinearOrderOfLEArgs (α : Type u) extends
|
||||
extract_lets
|
||||
first
|
||||
| infer_instance
|
||||
| exact _root_.Min.leftLeaningOfLE _
|
||||
| exact Min.leftLeaningOfLE _
|
||||
max :
|
||||
let := le; let := decidableLE
|
||||
Max α := by
|
||||
extract_lets
|
||||
first
|
||||
| infer_instance
|
||||
| exact _root_.Max.leftLeaningOfLE _
|
||||
| exact Max.leftLeaningOfLE _
|
||||
min_eq :
|
||||
let := le; let := decidableLE; let := min
|
||||
∀ a b : α, Min.min a b = if a ≤ b then a else b := by
|
||||
extract_lets
|
||||
first
|
||||
| exact fun a b => _root_.Std.min_eq_if (a := a) (b := b)
|
||||
| exact fun a b => Std.min_eq_if (a := a) (b := b)
|
||||
| fail "Failed to automatically prove that `min` is left-leaning. \
|
||||
Please ensure that a `LawfulOrderLeftLeaningMin` instance can be synthesized or \
|
||||
manually provide the field `min_eq`."
|
||||
@@ -433,7 +433,7 @@ public structure Packages.LinearOrderOfLEArgs (α : Type u) extends
|
||||
∀ a b : α, Max.max a b = if b ≤ a then a else b := by
|
||||
extract_lets
|
||||
first
|
||||
| exact fun a b => _root_.Std.max_eq_if (a := a) (b := b)
|
||||
| exact fun a b => Std.max_eq_if (a := a) (b := b)
|
||||
| fail "Failed to automatically prove that `max` is left-leaning. \
|
||||
Please ensure that a `LawfulOrderLeftLeaningMax` instance can be synthesized or \
|
||||
manually provide the field `max_eq`."
|
||||
@@ -538,7 +538,7 @@ public structure Packages.LinearPreorderOfOrdArgs (α : Type u) where
|
||||
extract_lets
|
||||
first
|
||||
| infer_instance
|
||||
| exact _root_.LE.ofOrd _
|
||||
| exact LE.ofOrd _
|
||||
lawfulOrderOrd :
|
||||
let := ord; let := transOrd; let := le
|
||||
LawfulOrderOrd α := by
|
||||
@@ -554,7 +554,7 @@ public structure Packages.LinearPreorderOfOrdArgs (α : Type u) where
|
||||
extract_lets
|
||||
first
|
||||
| infer_instance
|
||||
| exact _root_.DecidableLE.ofOrd _
|
||||
| exact DecidableLE.ofOrd _
|
||||
| fail "Failed to automatically derive that `LE` is decidable.\
|
||||
Please ensure that a `DecidableLE` instance can be synthesized or \
|
||||
manually provide the field `decidableLE`."
|
||||
@@ -570,7 +570,7 @@ public structure Packages.LinearPreorderOfOrdArgs (α : Type u) where
|
||||
∀ a b : α, a < b ↔ compare a b = .lt := by
|
||||
extract_lets
|
||||
first
|
||||
| exact fun _ _ => _root_.Std.compare_eq_lt.symm
|
||||
| exact fun _ _ => Std.compare_eq_lt.symm
|
||||
| fail "Failed to automatically derive that `LT` and `Ord` are compatible. \
|
||||
Please ensure that a `LawfulOrderLT` instance can be synthesized or \
|
||||
manually provide the field `lt_iff`."
|
||||
@@ -580,7 +580,7 @@ public structure Packages.LinearPreorderOfOrdArgs (α : Type u) where
|
||||
extract_lets
|
||||
first
|
||||
| infer_instance
|
||||
| exact _root_DecidableLT.ofOrd _
|
||||
| exact DecidableLT.ofOrd _
|
||||
| fail "Failed to automatically derive that `LT` is decidable. \
|
||||
Please ensure that a `DecidableLT` instance can be synthesized or \
|
||||
manually provide the field `decidableLT`."
|
||||
@@ -589,7 +589,7 @@ public structure Packages.LinearPreorderOfOrdArgs (α : Type u) where
|
||||
extract_lets
|
||||
first
|
||||
| infer_instance
|
||||
| exact _root_.BEq.ofOrd _
|
||||
| exact BEq.ofOrd _
|
||||
beq_iff :
|
||||
let := ord; let := le; have := lawfulOrderOrd; let := beq
|
||||
∀ a b : α, a == b ↔ compare a b = .eq := by
|
||||
@@ -708,7 +708,7 @@ public structure Packages.LinearOrderOfOrdArgs (α : Type u) extends
|
||||
∀ a b : α, compare a b = .eq → a = b := by
|
||||
extract_lets
|
||||
first
|
||||
| exact fun _ _ => _root_.Std.LawfulEqOrd.eq_of_compare
|
||||
| exact LawfulEqOrd.eq_of_compare
|
||||
| fail "Failed to derive a `LawfulEqOrd` instance. \
|
||||
Please make sure that it can be synthesized or \
|
||||
manually provide the field `eq_of_compare`."
|
||||
@@ -718,20 +718,20 @@ public structure Packages.LinearOrderOfOrdArgs (α : Type u) extends
|
||||
extract_lets
|
||||
first
|
||||
| infer_instance
|
||||
| exact _root_.Std.FactoryInstances.instMinOfOrd
|
||||
| exact FactoryInstances.instMinOfOrd
|
||||
max :
|
||||
let := ord
|
||||
Max α := by
|
||||
extract_lets
|
||||
first
|
||||
| infer_instance
|
||||
| exact _root_.Std.FactoryInstances.instMaxOfOrd
|
||||
| exact FactoryInstances.instMaxOfOrd
|
||||
min_eq :
|
||||
let := ord; let := le; let := min; have := lawfulOrderOrd
|
||||
∀ a b : α, Min.min a b = if (compare a b).isLE then a else b := by
|
||||
extract_lets
|
||||
first
|
||||
| exact fun a b => _root_.Std.min_eq_if_isLE_compare (a := a) (b := b)
|
||||
| exact fun a b => Std.min_eq_if_isLE_compare (a := a) (b := b)
|
||||
| fail "Failed to automatically prove that `min` is left-leaning. \
|
||||
Please ensure that a `LawfulOrderLeftLeaningMin` instance can be synthesized or \
|
||||
manually provide the field `min_eq`."
|
||||
@@ -740,7 +740,7 @@ public structure Packages.LinearOrderOfOrdArgs (α : Type u) extends
|
||||
∀ a b : α, Max.max a b = if (compare a b).isGE then a else b := by
|
||||
extract_lets
|
||||
first
|
||||
| exact fun a b => _root_.Std.max_eq_if_isGE_compare (a := a) (b := b)
|
||||
| exact fun a b => Std.max_eq_if_isGE_compare (a := a) (b := b)
|
||||
| fail "Failed to automatically prove that `max` is left-leaning. \
|
||||
Please ensure that a `LawfulOrderLeftLeaningMax` instance can be synthesized or \
|
||||
manually provide the field `max_eq`."
|
||||
|
||||
@@ -7,7 +7,6 @@ module
|
||||
|
||||
prelude
|
||||
public import Init.System.IO
|
||||
import Init.Data.ByteArray.Extra
|
||||
|
||||
public section
|
||||
universe u
|
||||
|
||||
@@ -24,14 +24,14 @@ namespace Std.PRange
|
||||
instance [LE α] [LT α] [UpwardEnumerable α] [LawfulUpwardEnumerable α]
|
||||
[LawfulUpwardEnumerableLE α] [LawfulOrderLT α] : LawfulUpwardEnumerableLT α where
|
||||
lt_iff a b := by
|
||||
simp only [LawfulOrderLT.lt_iff, UpwardEnumerable.le_iff]
|
||||
simp only [LawfulOrderLT.lt_iff, LawfulUpwardEnumerableLE.le_iff]
|
||||
constructor
|
||||
· intro h
|
||||
obtain ⟨n, hn⟩ := h.1
|
||||
cases n
|
||||
· apply h.2.elim
|
||||
refine ⟨0, ?_⟩
|
||||
simpa [succMany?_zero] using hn.symm
|
||||
simpa [UpwardEnumerable.succMany?_zero] using hn.symm
|
||||
exact ⟨_, hn⟩
|
||||
· intro h
|
||||
constructor
|
||||
@@ -41,60 +41,63 @@ instance [LE α] [LT α] [UpwardEnumerable α] [LawfulUpwardEnumerable α]
|
||||
instance [LE α] [DecidableLE α] [UpwardEnumerable α] [LawfulUpwardEnumerableLE α] :
|
||||
LawfulUpwardEnumerableLowerBound .closed α where
|
||||
isSatisfied_iff a l := by
|
||||
simp [SupportsLowerBound.IsSatisfied, init?, UpwardEnumerable.le_iff]
|
||||
simp [SupportsLowerBound.IsSatisfied, BoundedUpwardEnumerable.init?,
|
||||
LawfulUpwardEnumerableLE.le_iff]
|
||||
|
||||
instance [LE α] [DecidableLE α] [UpwardEnumerable α] [LawfulUpwardEnumerableLE α]
|
||||
[Trans (α := α) (· ≤ ·) (· ≤ ·) (· ≤ ·)]:
|
||||
LawfulUpwardEnumerableUpperBound .closed α where
|
||||
isSatisfied_of_le u a b hub hab := by
|
||||
simp only [SupportsUpperBound.IsSatisfied, ← UpwardEnumerable.le_iff] at hub hab ⊢
|
||||
simp only [SupportsUpperBound.IsSatisfied, ← LawfulUpwardEnumerableLE.le_iff] at hub hab ⊢
|
||||
exact Trans.trans hab hub
|
||||
|
||||
instance [LT α] [DecidableLT α] [UpwardEnumerable α] [LawfulUpwardEnumerable α]
|
||||
[LawfulUpwardEnumerableLT α] :
|
||||
LawfulUpwardEnumerableLowerBound .open α where
|
||||
isSatisfied_iff a l := by
|
||||
simp only [SupportsLowerBound.IsSatisfied, init?, UpwardEnumerable.lt_iff]
|
||||
simp only [SupportsLowerBound.IsSatisfied, BoundedUpwardEnumerable.init?,
|
||||
LawfulUpwardEnumerableLT.lt_iff]
|
||||
constructor
|
||||
· rintro ⟨n, hn⟩
|
||||
simp only [succMany?_succ?_eq_succ?_bind_succMany?] at hn
|
||||
cases h : succ? l
|
||||
simp only [LawfulUpwardEnumerable.succMany?_succ_eq_succ?_bind_succMany?] at hn
|
||||
cases h : UpwardEnumerable.succ? l
|
||||
· simp [h] at hn
|
||||
· exact ⟨_, rfl, n, by simpa [h] using hn⟩
|
||||
· rintro ⟨init, hi, n, hn⟩
|
||||
exact ⟨n, by simpa [succMany?_succ?_eq_succ?_bind_succMany?, hi] using hn⟩
|
||||
exact ⟨n, by simpa [LawfulUpwardEnumerable.succMany?_succ_eq_succ?_bind_succMany?, hi] using hn⟩
|
||||
|
||||
instance [LT α] [DecidableLT α] [UpwardEnumerable α] [LawfulUpwardEnumerable α]
|
||||
[LawfulUpwardEnumerableLT α] :
|
||||
LawfulUpwardEnumerableUpperBound .open α where
|
||||
isSatisfied_of_le u a b hub hab := by
|
||||
simp only [SupportsUpperBound.IsSatisfied, UpwardEnumerable.lt_iff] at hub ⊢
|
||||
simp only [SupportsUpperBound.IsSatisfied, LawfulUpwardEnumerableLT.lt_iff] at hub ⊢
|
||||
exact UpwardEnumerable.lt_of_le_of_lt hab hub
|
||||
|
||||
instance [UpwardEnumerable α] [Least? α] [LawfulUpwardEnumerableLeast? α] :
|
||||
LawfulUpwardEnumerableLowerBound .unbounded α where
|
||||
isSatisfied_iff a l := by
|
||||
simpa [SupportsLowerBound.IsSatisfied, init?] using UpwardEnumerable.least?_le
|
||||
simpa [SupportsLowerBound.IsSatisfied, BoundedUpwardEnumerable.init?] using
|
||||
LawfulUpwardEnumerableLeast?.eq_succMany?_least? a
|
||||
|
||||
instance [LE α] [Total (α := α) (· ≤ ·)] [UpwardEnumerable α] [LawfulUpwardEnumerable α]
|
||||
[LawfulUpwardEnumerableLE α] :
|
||||
LinearlyUpwardEnumerable α where
|
||||
eq_of_succ?_eq a b hab := by
|
||||
cases Total.total (α := α) (r := (· ≤ ·)) a b <;> rename_i h <;>
|
||||
simp only [UpwardEnumerable.le_iff] at h
|
||||
simp only [LawfulUpwardEnumerableLE.le_iff] at h
|
||||
· obtain ⟨n, hn⟩ := h
|
||||
cases n
|
||||
· simpa [succMany?_zero] using hn
|
||||
· simpa [UpwardEnumerable.succMany?_zero] using hn
|
||||
· exfalso
|
||||
rw [succMany?_succ?_eq_succ?_bind_succMany?, hab,
|
||||
← succMany?_succ?_eq_succ?_bind_succMany?] at hn
|
||||
rw [LawfulUpwardEnumerable.succMany?_succ_eq_succ?_bind_succMany?, hab,
|
||||
← LawfulUpwardEnumerable.succMany?_succ_eq_succ?_bind_succMany?] at hn
|
||||
exact UpwardEnumerable.lt_irrefl ⟨_, hn⟩
|
||||
· obtain ⟨n, hn⟩ := h
|
||||
cases n
|
||||
· simpa [succMany?_zero] using hn.symm
|
||||
· simpa [UpwardEnumerable.succMany?_zero] using hn.symm
|
||||
· exfalso
|
||||
rw [succMany?_succ?_eq_succ?_bind_succMany?, hab.symm,
|
||||
← succMany?_succ?_eq_succ?_bind_succMany?] at hn
|
||||
rw [LawfulUpwardEnumerable.succMany?_succ_eq_succ?_bind_succMany?, hab.symm,
|
||||
← LawfulUpwardEnumerable.succMany?_succ_eq_succ?_bind_succMany?] at hn
|
||||
exact UpwardEnumerable.lt_irrefl ⟨_, hn⟩
|
||||
|
||||
instance [UpwardEnumerable α] : LawfulUpwardEnumerableUpperBound .unbounded α where
|
||||
@@ -119,24 +122,24 @@ instance LawfulRangeSize.open_of_closed [UpwardEnumerable α] [LE α] [Decidable
|
||||
simp only [SupportsUpperBound.IsSatisfied] at h
|
||||
simp only [RangeSize.size]
|
||||
by_cases h' : a ≤ bound
|
||||
· match hs : succ? a with
|
||||
· match hs : UpwardEnumerable.succ? a with
|
||||
| none => rw [LawfulRangeSize.size_eq_one_of_succ?_eq_none (h := h') (h' := by omega)]
|
||||
| some b =>
|
||||
rw [LawfulRangeSize.size_eq_succ_of_succ?_eq_some (h := h') (h' := hs)]
|
||||
have : ¬ b ≤ bound := by
|
||||
intro hb
|
||||
have : a < b := by
|
||||
rw [UpwardEnumerable.lt_iff]
|
||||
exact ⟨0, by simpa [succMany?_one] using hs⟩
|
||||
rw [LawfulUpwardEnumerableLT.lt_iff]
|
||||
exact ⟨0, by simpa [UpwardEnumerable.succMany?_one] using hs⟩
|
||||
exact h (lt_of_lt_of_le this hb)
|
||||
rw [LawfulRangeSize.size_eq_zero_of_not_isSatisfied (h := this)]
|
||||
· suffices RangeSize.size (shape := .closed) bound a = 0 by omega
|
||||
exact LawfulRangeSize.size_eq_zero_of_not_isSatisfied _ _ h'
|
||||
size_eq_one_of_succ?_eq_none bound a h h' := by
|
||||
exfalso
|
||||
simp only [SupportsUpperBound.IsSatisfied, UpwardEnumerable.lt_iff] at h
|
||||
simp only [SupportsUpperBound.IsSatisfied, LawfulUpwardEnumerableLT.lt_iff] at h
|
||||
obtain ⟨n, hn⟩ := h
|
||||
simp [succMany?_succ?_eq_succ?_bind_succMany?, h'] at hn
|
||||
simp [LawfulUpwardEnumerable.succMany?_succ_eq_succ?_bind_succMany?, h'] at hn
|
||||
size_eq_succ_of_succ?_eq_some bound a a' h h' := by
|
||||
simp only [SupportsUpperBound.IsSatisfied] at h
|
||||
simp only [RangeSize.size, Nat.pred_eq_succ_iff]
|
||||
@@ -145,10 +148,10 @@ instance LawfulRangeSize.open_of_closed [UpwardEnumerable α] [LE α] [Decidable
|
||||
· omega
|
||||
· simp only [Nat.succ_le_iff, LawfulRangeSize.size_pos_iff_isSatisfied,
|
||||
SupportsUpperBound.IsSatisfied]
|
||||
rw [UpwardEnumerable.le_iff]
|
||||
rw [UpwardEnumerable.lt_iff] at h
|
||||
rw [LawfulUpwardEnumerableLE.le_iff]
|
||||
rw [LawfulUpwardEnumerableLT.lt_iff] at h
|
||||
refine ⟨h.choose, ?_⟩
|
||||
simpa [succMany?_succ?_eq_succ?_bind_succMany?, h'] using h.choose_spec
|
||||
simpa [LawfulUpwardEnumerable.succMany?_succ_eq_succ?_bind_succMany?, h'] using h.choose_spec
|
||||
|
||||
instance LawfulRangeSize.instHasFiniteRanges [UpwardEnumerable α] [LawfulUpwardEnumerable α]
|
||||
[RangeSize su α] [SupportsUpperBound su α] [LawfulRangeSize su α] : HasFiniteRanges su α where
|
||||
@@ -158,11 +161,11 @@ instance LawfulRangeSize.instHasFiniteRanges [UpwardEnumerable α] [LawfulUpward
|
||||
induction n generalizing init with
|
||||
| zero =>
|
||||
simp only [LawfulRangeSize.size_eq_zero_iff_not_isSatisfied] at hn
|
||||
simp [succMany?_zero, hn]
|
||||
simp [UpwardEnumerable.succMany?_zero, hn]
|
||||
| succ =>
|
||||
rename_i n ih
|
||||
rw [succMany?_succ?_eq_succ?_bind_succMany?]
|
||||
match hs : succ? init with
|
||||
rw [LawfulUpwardEnumerable.succMany?_succ_eq_succ?_bind_succMany?]
|
||||
match hs : UpwardEnumerable.succ? init with
|
||||
| none => simp
|
||||
| some a =>
|
||||
simp only [Option.bind_some]
|
||||
|
||||
@@ -7,7 +7,7 @@ module
|
||||
|
||||
prelude
|
||||
public import Init.Data.Iterators
|
||||
import Init.Data.Iterators.Lemmas.Consumers.Collect
|
||||
public import Init.Data.Iterators.Lemmas.Consumers.Collect
|
||||
public import Init.Data.Range.Polymorphic.Basic
|
||||
import all Init.Data.Range.Polymorphic.Basic
|
||||
public import Init.Data.Range.Polymorphic.RangeIterator
|
||||
@@ -30,13 +30,13 @@ open Std.Iterators
|
||||
|
||||
variable {shape : RangeShape} {α : Type u}
|
||||
|
||||
private theorem Internal.iter_Rox_eq_iter_Rcx_of_isSome_succ? {su} [UpwardEnumerable α]
|
||||
private theorem Internal.iter_open_eq_iter_closed_of_isSome_succ? {su} [UpwardEnumerable α]
|
||||
[SupportsUpperBound su α] [HasFiniteRanges su α]
|
||||
[LawfulUpwardEnumerable α]
|
||||
{lo : Bound .open α} {hi} (h : (UpwardEnumerable.succ? lo).isSome) :
|
||||
Internal.iter (PRange.mk (shape := ⟨.open, su⟩) lo hi) =
|
||||
Internal.iter (PRange.mk (shape := ⟨.closed, su⟩) (UpwardEnumerable.succ? lo |>.get h) hi) := by
|
||||
simp [Internal.iter, init?]
|
||||
simp [Internal.iter, BoundedUpwardEnumerable.init?]
|
||||
|
||||
private theorem Internal.toList_eq_toList_iter {sl su} [UpwardEnumerable α]
|
||||
[BoundedUpwardEnumerable sl α] [SupportsUpperBound su α] [HasFiniteRanges su α]
|
||||
@@ -44,7 +44,7 @@ private theorem Internal.toList_eq_toList_iter {sl su} [UpwardEnumerable α]
|
||||
r.toList = (Internal.iter r).toList := by
|
||||
rfl
|
||||
|
||||
public theorem RangeIterator.toList_eq_match {su} [UpwardEnumerable α]
|
||||
theorem RangeIterator.toList_eq_match {su} [UpwardEnumerable α]
|
||||
[SupportsUpperBound su α] [HasFiniteRanges su α]
|
||||
[LawfulUpwardEnumerable α]
|
||||
{it : Iter (α := RangeIterator su α) α} :
|
||||
@@ -61,11 +61,11 @@ public theorem RangeIterator.toList_eq_match {su} [UpwardEnumerable α]
|
||||
· simp [*]
|
||||
· split <;> rename_i heq' <;> simp [*]
|
||||
|
||||
public theorem toList_eq_match {sl su} [UpwardEnumerable α] [BoundedUpwardEnumerable sl α]
|
||||
theorem toList_eq_match {sl su} [UpwardEnumerable α] [BoundedUpwardEnumerable sl α]
|
||||
[SupportsUpperBound su α] [HasFiniteRanges su α]
|
||||
[LawfulUpwardEnumerable α]
|
||||
{r : PRange ⟨sl, su⟩ α} :
|
||||
r.toList = match init? r.lower with
|
||||
r.toList = match BoundedUpwardEnumerable.init? r.lower with
|
||||
| none => []
|
||||
| some a => if SupportsUpperBound.IsSatisfied r.upper a then
|
||||
a :: (PRange.mk (shape := ⟨.open, su⟩) a r.upper).toList
|
||||
@@ -73,35 +73,26 @@ public theorem toList_eq_match {sl su} [UpwardEnumerable α] [BoundedUpwardEnume
|
||||
[] := by
|
||||
rw [Internal.toList_eq_toList_iter, RangeIterator.toList_eq_match]; rfl
|
||||
|
||||
public theorem toList_Rox_eq_toList_Rcx_of_isSome_succ? {su} [UpwardEnumerable α]
|
||||
theorem toList_open_eq_toList_closed_of_isSome_succ? {su} [UpwardEnumerable α]
|
||||
[SupportsUpperBound su α] [HasFiniteRanges su α]
|
||||
[LawfulUpwardEnumerable α]
|
||||
{lo : Bound .open α} {hi} (h : (UpwardEnumerable.succ? lo).isSome) :
|
||||
(PRange.mk (shape := ⟨.open, su⟩) lo hi).toList =
|
||||
(PRange.mk (shape := ⟨.closed, su⟩) (UpwardEnumerable.succ? lo |>.get h) hi).toList := by
|
||||
simp [Internal.toList_eq_toList_iter, Internal.iter_Rox_eq_iter_Rcx_of_isSome_succ?, h]
|
||||
simp [Internal.toList_eq_toList_iter, Internal.iter_open_eq_iter_closed_of_isSome_succ?, h]
|
||||
|
||||
@[deprecated toList_Rox_eq_toList_Rcx_of_isSome_succ? (since := "2025-08-22")]
|
||||
public theorem toList_open_eq_toList_closed_of_isSome_succ? {su} [UpwardEnumerable α]
|
||||
[SupportsUpperBound su α] [HasFiniteRanges su α]
|
||||
[LawfulUpwardEnumerable α]
|
||||
{lo : Bound .open α} {hi} (h : (UpwardEnumerable.succ? lo).isSome) :
|
||||
(PRange.mk (shape := ⟨.open, su⟩) lo hi).toList =
|
||||
(PRange.mk (shape := ⟨.closed, su⟩) (UpwardEnumerable.succ? lo |>.get h) hi).toList :=
|
||||
toList_Rox_eq_toList_Rcx_of_isSome_succ? h
|
||||
|
||||
public theorem toList_eq_nil_iff {sl su} [UpwardEnumerable α]
|
||||
theorem toList_eq_nil_iff {sl su} [UpwardEnumerable α]
|
||||
[SupportsUpperBound su α] [HasFiniteRanges su α] [BoundedUpwardEnumerable sl α]
|
||||
[LawfulUpwardEnumerable α]
|
||||
{r : PRange ⟨sl, su⟩ α} :
|
||||
r.toList = [] ↔
|
||||
¬ (∃ a, init? r.lower = some a ∧ SupportsUpperBound.IsSatisfied r.upper a) := by
|
||||
¬ (∃ a, BoundedUpwardEnumerable.init? r.lower = some a ∧ SupportsUpperBound.IsSatisfied r.upper a) := by
|
||||
rw [Internal.toList_eq_toList_iter]
|
||||
rw [RangeIterator.toList_eq_match, Internal.iter]
|
||||
simp only
|
||||
split <;> rename_i heq <;> simp [heq]
|
||||
|
||||
public theorem mem_toList_iff_mem {sl su} [UpwardEnumerable α]
|
||||
theorem mem_toList_iff_mem {sl su} [UpwardEnumerable α]
|
||||
[SupportsUpperBound su α] [SupportsLowerBound sl α] [HasFiniteRanges su α]
|
||||
[BoundedUpwardEnumerable sl α] [LawfulUpwardEnumerable α]
|
||||
[LawfulUpwardEnumerableLowerBound sl α] [LawfulUpwardEnumerableUpperBound su α]
|
||||
@@ -110,24 +101,17 @@ public theorem mem_toList_iff_mem {sl su} [UpwardEnumerable α]
|
||||
rw [Internal.toList_eq_toList_iter, Iter.mem_toList_iff_isPlausibleIndirectOutput,
|
||||
Internal.isPlausibleIndirectOutput_iter_iff]
|
||||
|
||||
public theorem BoundedUpwardEnumerable.init?_succ?_closed [UpwardEnumerable α]
|
||||
theorem BoundedUpwardEnumerable.Closed.init?_succ [UpwardEnumerable α]
|
||||
[LawfulUpwardEnumerable α] {lower lower' : Bound .closed α}
|
||||
(h : UpwardEnumerable.succ? lower = some lower') :
|
||||
init? lower' = (init? lower).bind UpwardEnumerable.succ? := by
|
||||
BoundedUpwardEnumerable.init? lower' = (BoundedUpwardEnumerable.init? lower).bind UpwardEnumerable.succ? := by
|
||||
cases h : init? lower <;> rename_i ilower <;> cases h' : init? lower' <;> rename_i ilower'
|
||||
· simp
|
||||
· simp [init?] at h
|
||||
· simp [init?] at h'
|
||||
· simp_all [init?]
|
||||
|
||||
@[deprecated BoundedUpwardEnumerable.init?_succ?_closed (since := "2025-08-22")]
|
||||
public theorem BoundedUpwardEnumerable.Closed.init?_succ [UpwardEnumerable α]
|
||||
[LawfulUpwardEnumerable α] {lower lower' : Bound .closed α}
|
||||
(h : UpwardEnumerable.succ? lower = some lower') :
|
||||
init? lower' = (init? lower).bind UpwardEnumerable.succ? :=
|
||||
init?_succ?_closed h
|
||||
|
||||
public theorem pairwise_toList_upwardEnumerableLt {sl su} [UpwardEnumerable α]
|
||||
theorem pairwise_toList_upwardEnumerableLt {sl su} [UpwardEnumerable α]
|
||||
[SupportsUpperBound su α] [SupportsLowerBound sl α] [HasFiniteRanges su α]
|
||||
[BoundedUpwardEnumerable sl α] [LawfulUpwardEnumerable α]
|
||||
[LawfulUpwardEnumerableLowerBound sl α] [LawfulUpwardEnumerableUpperBound su α]
|
||||
@@ -146,14 +130,14 @@ public theorem pairwise_toList_upwardEnumerableLt {sl su} [UpwardEnumerable α]
|
||||
simp only at ha
|
||||
have : UpwardEnumerable.LT a ha.choose := by
|
||||
refine ⟨0, ?_⟩
|
||||
simp only [succMany?_succ?, succMany?_zero,
|
||||
simp only [UpwardEnumerable.succMany?_succ, UpwardEnumerable.succMany?_zero,
|
||||
Option.bind_some]
|
||||
exact ha.choose_spec.1
|
||||
exact UpwardEnumerable.lt_of_lt_of_le this ha.choose_spec.2
|
||||
· apply ihy (out := a)
|
||||
simp_all [RangeIterator.isPlausibleStep_iff, RangeIterator.step]
|
||||
|
||||
public theorem pairwise_toList_ne {sl su} [UpwardEnumerable α]
|
||||
theorem pairwise_toList_ne {sl su} [UpwardEnumerable α]
|
||||
[SupportsUpperBound su α] [SupportsLowerBound sl α] [HasFiniteRanges su α]
|
||||
[BoundedUpwardEnumerable sl α] [LawfulUpwardEnumerable α]
|
||||
[LawfulUpwardEnumerableLowerBound sl α] [LawfulUpwardEnumerableUpperBound su α]
|
||||
@@ -161,7 +145,7 @@ public theorem pairwise_toList_ne {sl su} [UpwardEnumerable α]
|
||||
r.toList.Pairwise (fun a b => a ≠ b) :=
|
||||
List.Pairwise.imp (fun hlt => UpwardEnumerable.ne_of_lt hlt) pairwise_toList_upwardEnumerableLt
|
||||
|
||||
public theorem pairwise_toList_lt {sl su} [LT α] [UpwardEnumerable α]
|
||||
theorem pairwise_toList_lt {sl su} [LT α] [UpwardEnumerable α]
|
||||
[SupportsUpperBound su α] [SupportsLowerBound sl α] [HasFiniteRanges su α]
|
||||
[BoundedUpwardEnumerable sl α] [LawfulUpwardEnumerable α] [LawfulUpwardEnumerableLT α]
|
||||
[LawfulUpwardEnumerableLowerBound sl α] [LawfulUpwardEnumerableUpperBound su α]
|
||||
@@ -170,7 +154,7 @@ public theorem pairwise_toList_lt {sl su} [LT α] [UpwardEnumerable α]
|
||||
List.Pairwise.imp
|
||||
(fun hlt => (LawfulUpwardEnumerableLT.lt_iff ..).mpr hlt) pairwise_toList_upwardEnumerableLt
|
||||
|
||||
public theorem pairwise_toList_le {sl su} [LE α] [UpwardEnumerable α]
|
||||
theorem pairwise_toList_le {sl su} [LE α] [UpwardEnumerable α]
|
||||
[SupportsUpperBound su α] [SupportsLowerBound sl α] [HasFiniteRanges su α]
|
||||
[BoundedUpwardEnumerable sl α] [LawfulUpwardEnumerable α] [LawfulUpwardEnumerableLE α]
|
||||
[LawfulUpwardEnumerableLowerBound sl α] [LawfulUpwardEnumerableUpperBound su α]
|
||||
@@ -178,44 +162,38 @@ public theorem pairwise_toList_le {sl su} [LE α] [UpwardEnumerable α]
|
||||
r.toList.Pairwise (fun a b => a ≤ b) :=
|
||||
pairwise_toList_upwardEnumerableLt
|
||||
|> List.Pairwise.imp UpwardEnumerable.le_of_lt
|
||||
|> List.Pairwise.imp (fun hle => (UpwardEnumerable.le_iff ..).mpr hle)
|
||||
|> List.Pairwise.imp (fun hle => (LawfulUpwardEnumerableLE.le_iff ..).mpr hle)
|
||||
|
||||
public theorem mem_Rco_succ_succ_iff [UpwardEnumerable α]
|
||||
theorem ClosedOpen.mem_succ_iff [UpwardEnumerable α]
|
||||
[LinearlyUpwardEnumerable α] [InfinitelyUpwardEnumerable α] [SupportsUpperBound .open α]
|
||||
[SupportsLowerBound .closed α] [LawfulUpwardEnumerableLowerBound .closed α]
|
||||
[HasFiniteRanges .open α] [LawfulUpwardEnumerable α] [LawfulOpenUpperBound α]
|
||||
{lower : Bound .closed α} {upper : Bound .open α} {a : α} :
|
||||
(a ∈ (succ lower)...(succ upper)) ↔ ∃ a', a = succ a' ∧ a' ∈ lower...upper := by
|
||||
a ∈ PRange.mk (shape := ⟨.closed, .open⟩) (UpwardEnumerable.succ lower) (UpwardEnumerable.succ upper) ↔
|
||||
∃ a', a = UpwardEnumerable.succ a' ∧ a' ∈ PRange.mk (shape := ⟨.closed, .open⟩) lower upper := by
|
||||
simp [Membership.mem, LawfulUpwardEnumerableLowerBound.isSatisfied_iff,
|
||||
init?, LawfulOpenUpperBound.isSatisfied_iff_le]
|
||||
BoundedUpwardEnumerable.init?, LawfulOpenUpperBound.isSatisfied_iff_le]
|
||||
rw [← Option.some_get (InfinitelyUpwardEnumerable.isSome_succ? _)]
|
||||
simp only [Option.some.injEq, ← UpwardEnumerable.succ.eq_def]
|
||||
simp
|
||||
constructor
|
||||
· rintro ⟨⟨n, hn⟩, h⟩
|
||||
rw [succMany?_eq_some_iff_succMany, ← succMany_one, ← succMany_add, Nat.add_comm, succMany_add,
|
||||
succMany_one] at hn
|
||||
rw [UpwardEnumerable.succMany?_eq_some_iff_succMany, ← UpwardEnumerable.succMany_one,
|
||||
← UpwardEnumerable.succMany_add, Nat.add_comm, UpwardEnumerable.succMany_add,
|
||||
UpwardEnumerable.succMany_one] at hn
|
||||
rw [← hn]
|
||||
refine ⟨succMany n lower, rfl, ?_, ?_⟩
|
||||
· exact ⟨n, by simp [succMany_eq_get]⟩
|
||||
refine ⟨UpwardEnumerable.succMany n lower, rfl, ?_, ?_⟩
|
||||
· exact ⟨n, by simp [UpwardEnumerable.succMany_eq_get]⟩
|
||||
· obtain ⟨m, hm⟩ := h
|
||||
refine ⟨m, ?_⟩
|
||||
rw [succMany?_eq_some_iff_succMany] at hm ⊢
|
||||
rwa [← hn, ← succMany_one, ← succMany_add, Nat.add_comm, succMany_add, succMany_one,
|
||||
succ_eq_succ_iff] at hm
|
||||
rw [UpwardEnumerable.succMany?_eq_some_iff_succMany] at hm ⊢
|
||||
rwa [← hn, ← UpwardEnumerable.succMany_one, ← UpwardEnumerable.succMany_add, Nat.add_comm,
|
||||
UpwardEnumerable.succMany_add, UpwardEnumerable.succMany_one,
|
||||
UpwardEnumerable.succ_eq_succ_iff] at hm
|
||||
· rintro ⟨a', rfl, hl, hu⟩
|
||||
simp [UpwardEnumerable.succ_le_succ_iff, UpwardEnumerable.succ_lt_succ_iff]
|
||||
exact ⟨hl, hu⟩
|
||||
|
||||
@[deprecated mem_Rco_succ_succ_iff (since := "2025-08-22")]
|
||||
public theorem ClosedOpen.mem_succ_iff [UpwardEnumerable α]
|
||||
[LinearlyUpwardEnumerable α] [InfinitelyUpwardEnumerable α] [SupportsUpperBound .open α]
|
||||
[SupportsLowerBound .closed α] [LawfulUpwardEnumerableLowerBound .closed α]
|
||||
[HasFiniteRanges .open α] [LawfulUpwardEnumerable α] [LawfulOpenUpperBound α]
|
||||
{lower : Bound .closed α} {upper : Bound .open α} {a : α} :
|
||||
(a ∈ (succ lower)...(succ upper)) ↔ ∃ a', a = succ a' ∧ a' ∈ lower...upper :=
|
||||
mem_Rco_succ_succ_iff
|
||||
|
||||
private theorem eq_of_pairwise_lt_of_mem_iff_mem {lt : α → α → Prop} [asymm : Asymm lt]
|
||||
{l l' : List α} (hl : l.Pairwise lt) (hl' : l'.Pairwise lt)
|
||||
(h : ∀ a, a ∈ l ↔ a ∈ l') : l = l' := by
|
||||
@@ -268,13 +246,13 @@ private theorem eq_of_pairwise_lt_of_mem_iff_mem {lt : α → α → Prop} [asym
|
||||
have hgt := hl.1 y ‹_›
|
||||
cases Asymm.asymm _ _ hlt hgt
|
||||
|
||||
public theorem toList_Rco_succ_succ_eq_map [UpwardEnumerable α] [SupportsLowerBound .closed α]
|
||||
theorem ClosedOpen.toList_succ_succ_eq_map [UpwardEnumerable α] [SupportsLowerBound .closed α]
|
||||
[LinearlyUpwardEnumerable α] [InfinitelyUpwardEnumerable α] [SupportsUpperBound .open α]
|
||||
[HasFiniteRanges .open α] [LawfulUpwardEnumerable α] [LawfulOpenUpperBound α]
|
||||
[LawfulUpwardEnumerableLowerBound .closed α] [LawfulUpwardEnumerableUpperBound .open α]
|
||||
{lower : Bound .closed α} {upper : Bound .open α} :
|
||||
((succ lower)...(succ upper)).toList =
|
||||
(lower...upper).toList.map succ := by
|
||||
(PRange.mk (shape := ⟨.closed, .open⟩) (UpwardEnumerable.succ lower) (UpwardEnumerable.succ upper)).toList =
|
||||
(PRange.mk (shape := ⟨.closed, .open⟩) lower upper).toList.map UpwardEnumerable.succ := by
|
||||
apply eq_of_pairwise_lt_of_mem_iff_mem (lt := UpwardEnumerable.LT) (asymm := ?_)
|
||||
· apply pairwise_toList_upwardEnumerableLt
|
||||
· apply List.Pairwise.map (R := UpwardEnumerable.LT) (S := UpwardEnumerable.LT)
|
||||
@@ -283,7 +261,7 @@ public theorem toList_Rco_succ_succ_eq_map [UpwardEnumerable α] [SupportsLowerB
|
||||
· apply pairwise_toList_upwardEnumerableLt
|
||||
· simp only [List.mem_map, mem_toList_iff_mem]
|
||||
intro a
|
||||
rw [mem_Rco_succ_succ_iff]
|
||||
rw [mem_succ_iff]
|
||||
constructor
|
||||
· rintro ⟨a, rfl, h⟩
|
||||
exact ⟨a, h, rfl⟩
|
||||
@@ -291,16 +269,6 @@ public theorem toList_Rco_succ_succ_eq_map [UpwardEnumerable α] [SupportsLowerB
|
||||
exact ⟨_, h'.symm, h⟩
|
||||
· exact ⟨fun _ _ => UpwardEnumerable.not_gt_of_lt⟩
|
||||
|
||||
@[deprecated toList_Rco_succ_succ_eq_map (since := "2025-08-22")]
|
||||
public theorem ClosedOpen.toList_succ_succ_eq_map [UpwardEnumerable α] [SupportsLowerBound .closed α]
|
||||
[LinearlyUpwardEnumerable α] [InfinitelyUpwardEnumerable α] [SupportsUpperBound .open α]
|
||||
[HasFiniteRanges .open α] [LawfulUpwardEnumerable α] [LawfulOpenUpperBound α]
|
||||
[LawfulUpwardEnumerableLowerBound .closed α] [LawfulUpwardEnumerableUpperBound .open α]
|
||||
{lower : Bound .closed α} {upper : Bound .open α} :
|
||||
((succ lower)...(succ upper)).toList =
|
||||
(lower...upper).toList.map succ :=
|
||||
toList_Rco_succ_succ_eq_map
|
||||
|
||||
private theorem Internal.forIn'_eq_forIn'_iter [UpwardEnumerable α]
|
||||
[SupportsUpperBound su α] [SupportsLowerBound sl α] [HasFiniteRanges su α]
|
||||
[BoundedUpwardEnumerable sl α] [LawfulUpwardEnumerable α]
|
||||
@@ -312,7 +280,7 @@ private theorem Internal.forIn'_eq_forIn'_iter [UpwardEnumerable α]
|
||||
ForIn'.forIn' (Internal.iter r) init (fun a ha acc => f a (Internal.isPlausibleIndirectOutput_iter_iff.mp ha) acc) := by
|
||||
rfl
|
||||
|
||||
public theorem forIn'_eq_forIn'_toList [UpwardEnumerable α]
|
||||
theorem forIn'_eq_forIn'_toList [UpwardEnumerable α]
|
||||
[SupportsUpperBound su α] [SupportsLowerBound sl α] [HasFiniteRanges su α]
|
||||
[BoundedUpwardEnumerable sl α] [LawfulUpwardEnumerable α]
|
||||
[LawfulUpwardEnumerableLowerBound sl α] [LawfulUpwardEnumerableUpperBound su α]
|
||||
@@ -324,7 +292,7 @@ public theorem forIn'_eq_forIn'_toList [UpwardEnumerable α]
|
||||
simp [Internal.forIn'_eq_forIn'_iter, Internal.toList_eq_toList_iter,
|
||||
Iter.forIn'_eq_forIn'_toList]
|
||||
|
||||
public theorem forIn'_toList_eq_forIn' [UpwardEnumerable α]
|
||||
theorem forIn'_toList_eq_forIn' [UpwardEnumerable α]
|
||||
[SupportsUpperBound su α] [SupportsLowerBound sl α] [HasFiniteRanges su α]
|
||||
[BoundedUpwardEnumerable sl α] [LawfulUpwardEnumerable α]
|
||||
[LawfulUpwardEnumerableLowerBound sl α] [LawfulUpwardEnumerableUpperBound su α]
|
||||
@@ -335,7 +303,7 @@ public theorem forIn'_toList_eq_forIn' [UpwardEnumerable α]
|
||||
ForIn'.forIn' r init (fun a ha acc => f a (mem_toList_iff_mem.mpr ha) acc) := by
|
||||
simp [forIn'_eq_forIn'_toList]
|
||||
|
||||
public theorem mem_of_mem_open [UpwardEnumerable α]
|
||||
theorem mem_of_mem_open [UpwardEnumerable α]
|
||||
[SupportsUpperBound su α] [SupportsLowerBound sl α] [HasFiniteRanges su α]
|
||||
[BoundedUpwardEnumerable sl α] [LawfulUpwardEnumerable α]
|
||||
[LawfulUpwardEnumerableLowerBound sl α] [LawfulUpwardEnumerableUpperBound su α]
|
||||
@@ -346,21 +314,22 @@ public theorem mem_of_mem_open [UpwardEnumerable α]
|
||||
a ∈ r := by
|
||||
refine ⟨?_, hmem.2⟩
|
||||
have := hmem.1
|
||||
simp only [LawfulUpwardEnumerableLowerBound.isSatisfied_iff, init?] at this hrb ⊢
|
||||
simp only [LawfulUpwardEnumerableLowerBound.isSatisfied_iff,
|
||||
BoundedUpwardEnumerable.init?] at this hrb ⊢
|
||||
obtain ⟨init, hi⟩ := hrb
|
||||
obtain ⟨b', hb'⟩ := this
|
||||
refine ⟨init, hi.1, UpwardEnumerable.le_trans hi.2 (UpwardEnumerable.le_trans ?_ hb'.2)⟩
|
||||
exact UpwardEnumerable.le_of_succ?_eq hb'.1
|
||||
|
||||
public theorem SupportsLowerBound.isSatisfied_init? {sl} [UpwardEnumerable α]
|
||||
theorem SupportsLowerBound.isSatisfied_init? {sl} [UpwardEnumerable α]
|
||||
[SupportsLowerBound sl α] [BoundedUpwardEnumerable sl α] [LawfulUpwardEnumerable α]
|
||||
[LawfulUpwardEnumerableLowerBound sl α]
|
||||
{bound : Bound sl α} {a : α} (h : init? bound = some a) :
|
||||
{bound : Bound sl α} {a : α} (h : BoundedUpwardEnumerable.init? bound = some a) :
|
||||
SupportsLowerBound.IsSatisfied bound a := by
|
||||
simp only [LawfulUpwardEnumerableLowerBound.isSatisfied_iff]
|
||||
exact ⟨a, h, UpwardEnumerable.le_refl _⟩
|
||||
|
||||
public theorem forIn'_eq_match {sl su} [UpwardEnumerable α]
|
||||
theorem forIn'_eq_match {sl su} [UpwardEnumerable α]
|
||||
[SupportsUpperBound su α] [SupportsLowerBound sl α] [HasFiniteRanges su α]
|
||||
[BoundedUpwardEnumerable sl α] [LawfulUpwardEnumerable α]
|
||||
[LawfulUpwardEnumerableLowerBound sl α] [LawfulUpwardEnumerableUpperBound su α]
|
||||
@@ -368,7 +337,7 @@ public theorem forIn'_eq_match {sl su} [UpwardEnumerable α]
|
||||
{r : PRange ⟨sl, su⟩ α}
|
||||
{γ : Type u} {init : γ} {m : Type u → Type w} [Monad m] [LawfulMonad m]
|
||||
{f : (a : α) → _ → γ → m (ForInStep γ)} :
|
||||
ForIn'.forIn' r init f = match hi : init? r.lower with
|
||||
ForIn'.forIn' r init f = match hi : BoundedUpwardEnumerable.init? r.lower with
|
||||
| none => pure init
|
||||
| some a => if hu : SupportsUpperBound.IsSatisfied r.upper a then do
|
||||
match ← f a ⟨SupportsLowerBound.isSatisfied_init? hi, hu⟩ init with
|
||||
@@ -393,7 +362,7 @@ public theorem forIn'_eq_match {sl su} [UpwardEnumerable α]
|
||||
· simp
|
||||
· simp
|
||||
|
||||
public instance {su} [UpwardEnumerable α] [SupportsUpperBound su α] [RangeSize su α]
|
||||
instance {su} [UpwardEnumerable α] [SupportsUpperBound su α] [RangeSize su α]
|
||||
[LawfulUpwardEnumerable α] [HasFiniteRanges su α] [LawfulRangeSize su α] :
|
||||
LawfulIteratorSize (RangeIterator su α) where
|
||||
size_eq_size_toArray {it} := by
|
||||
@@ -431,7 +400,7 @@ public instance {su} [UpwardEnumerable α] [SupportsUpperBound su α] [RangeSize
|
||||
· have := LawfulRangeSize.size_eq_zero_of_not_isSatisfied _ _ h'
|
||||
simp [*] at this
|
||||
|
||||
public theorem isEmpty_iff_forall_not_mem {sl su} [UpwardEnumerable α] [LawfulUpwardEnumerable α]
|
||||
theorem isEmpty_iff_forall_not_mem {sl su} [UpwardEnumerable α] [LawfulUpwardEnumerable α]
|
||||
[BoundedUpwardEnumerable sl α] [SupportsLowerBound sl α] [SupportsUpperBound su α]
|
||||
[LawfulUpwardEnumerableLowerBound sl α] [LawfulUpwardEnumerableUpperBound su α]
|
||||
{r : PRange ⟨sl, su⟩ α} :
|
||||
@@ -453,6 +422,6 @@ public theorem isEmpty_iff_forall_not_mem {sl su} [UpwardEnumerable α] [LawfulU
|
||||
intro hu
|
||||
have hl := SupportsLowerBound.isSatisfied_init? (bound := r.lower)
|
||||
(Option.some_get hi).symm
|
||||
exact h ((init? r.lower).get hi) ⟨hl, hu⟩
|
||||
exact h ((BoundedUpwardEnumerable.init? r.lower).get hi) ⟨hl, hu⟩
|
||||
|
||||
end Std.PRange
|
||||
|
||||
@@ -6,11 +6,8 @@ Authors: Paul Reichert
|
||||
module
|
||||
|
||||
prelude
|
||||
import Init.Data.Nat.Lemmas
|
||||
public import Init.Data.Nat.Order
|
||||
public import Init.Data.Range.Polymorphic.Instances
|
||||
public import Init.Data.Order.Classes
|
||||
import Init.Data.Order.Lemmas
|
||||
public import Init.Data.Nat.Lemmas
|
||||
public import Init.Data.Range.Polymorphic.Basic
|
||||
|
||||
public section
|
||||
|
||||
@@ -23,10 +20,6 @@ instance : UpwardEnumerable Nat where
|
||||
instance : Least? Nat where
|
||||
least? := some 0
|
||||
|
||||
instance : LawfulUpwardEnumerableLeast? Nat where
|
||||
least?_le a := by
|
||||
simpa [Least?.least?] using ⟨a, by simp [UpwardEnumerable.succMany?]⟩
|
||||
|
||||
instance : LawfulUpwardEnumerableLE Nat where
|
||||
le_iff a b := by
|
||||
constructor
|
||||
@@ -37,29 +30,98 @@ instance : LawfulUpwardEnumerableLE Nat where
|
||||
rw [← hn]
|
||||
exact Nat.le_add_right _ _
|
||||
|
||||
instance : LawfulUpwardEnumerableLT Nat where
|
||||
lt_iff a b := by
|
||||
constructor
|
||||
· intro h
|
||||
refine ⟨b - a - 1, ?_⟩
|
||||
simp [UpwardEnumerable.succMany?]
|
||||
rw [Nat.sub_add_cancel, Nat.add_sub_cancel']
|
||||
· exact Nat.le_of_lt h
|
||||
· rwa [Nat.lt_iff_add_one_le, ← Nat.le_sub_iff_add_le'] at h
|
||||
exact Nat.le_trans (Nat.le_succ _) h
|
||||
· rintro ⟨n, hn⟩
|
||||
simp only [UpwardEnumerable.succMany?, Option.some.injEq] at hn
|
||||
rw [← hn]
|
||||
apply Nat.lt_add_of_pos_right
|
||||
apply Nat.zero_lt_succ
|
||||
|
||||
instance : LawfulUpwardEnumerable Nat where
|
||||
succMany?_zero := by simp [UpwardEnumerable.succMany?]
|
||||
succMany?_succ := by simp [UpwardEnumerable.succMany?, UpwardEnumerable.succ?, Nat.add_assoc]
|
||||
ne_of_lt a b hlt := by
|
||||
have hn := hlt.choose_spec
|
||||
simp only [UpwardEnumerable.succMany?, Option.some.injEq] at hn
|
||||
omega
|
||||
rw [← LawfulUpwardEnumerableLT.lt_iff] at hlt
|
||||
exact Nat.ne_of_lt hlt
|
||||
|
||||
instance : LawfulUpwardEnumerableLT Nat := inferInstance
|
||||
instance : LawfulUpwardEnumerableLowerBound .closed Nat := inferInstance
|
||||
instance : LawfulUpwardEnumerableUpperBound .closed Nat := inferInstance
|
||||
instance : LawfulUpwardEnumerableLowerBound .open Nat := inferInstance
|
||||
instance : LawfulUpwardEnumerableUpperBound .open Nat := inferInstance
|
||||
instance : LawfulUpwardEnumerableLowerBound .unbounded Nat := inferInstance
|
||||
instance : LawfulUpwardEnumerableUpperBound .unbounded Nat := inferInstance
|
||||
instance : LawfulUpwardEnumerableLowerBound .closed Nat where
|
||||
isSatisfied_iff a l := by
|
||||
simp [← LawfulUpwardEnumerableLE.le_iff, BoundedUpwardEnumerable.init?,
|
||||
SupportsLowerBound.IsSatisfied]
|
||||
|
||||
instance : LawfulUpwardEnumerableUpperBound .closed Nat where
|
||||
isSatisfied_of_le u a b hub hab := by
|
||||
rw [← LawfulUpwardEnumerableLE.le_iff] at hab
|
||||
exact Nat.le_trans hab hub
|
||||
|
||||
instance : LawfulUpwardEnumerableLowerBound .open Nat where
|
||||
isSatisfied_iff a l := by
|
||||
simp [← LawfulUpwardEnumerableLE.le_iff, BoundedUpwardEnumerable.init?,
|
||||
SupportsLowerBound.IsSatisfied, UpwardEnumerable.succ?, Nat.lt_iff_add_one_le]
|
||||
|
||||
instance : LawfulUpwardEnumerableUpperBound .open Nat where
|
||||
isSatisfied_of_le u a b hub hab := by
|
||||
rw [← LawfulUpwardEnumerableLE.le_iff] at hab
|
||||
exact Nat.lt_of_le_of_lt hab hub
|
||||
|
||||
instance : LawfulUpwardEnumerableLowerBound .unbounded Nat where
|
||||
isSatisfied_iff a l := by
|
||||
simp [← LawfulUpwardEnumerableLE.le_iff, BoundedUpwardEnumerable.init?,
|
||||
SupportsLowerBound.IsSatisfied, Least?.least?]
|
||||
|
||||
instance : LawfulUpwardEnumerableUpperBound .unbounded Nat where
|
||||
isSatisfied_of_le _ _ _ _ _ := .intro
|
||||
|
||||
instance : LinearlyUpwardEnumerable Nat where
|
||||
eq_of_succ?_eq a b := by simp [UpwardEnumerable.succ?]
|
||||
|
||||
instance : InfinitelyUpwardEnumerable Nat where
|
||||
isSome_succ? a := by simp [UpwardEnumerable.succ?]
|
||||
|
||||
private def rangeRev (k : Nat) :=
|
||||
match k with
|
||||
| 0 => []
|
||||
| k + 1 => k :: rangeRev k
|
||||
|
||||
private theorem mem_rangeRev {k l : Nat} (h : l < k) : l ∈ rangeRev k := by
|
||||
induction k
|
||||
case zero => cases h
|
||||
case succ k ih =>
|
||||
rw [rangeRev]
|
||||
by_cases hl : l = k
|
||||
· simp [hl]
|
||||
· apply List.mem_cons_of_mem
|
||||
exact ih (Nat.lt_of_le_of_ne (Nat.le_of_lt_succ h) hl)
|
||||
|
||||
@[no_expose]
|
||||
instance : HasFiniteRanges .closed Nat where
|
||||
finite init u := by
|
||||
refine ⟨u - init + 1, ?_⟩
|
||||
simp only [UpwardEnumerable.succMany?, SupportsUpperBound.IsSatisfied, Nat.not_le,
|
||||
Option.elim_some]
|
||||
omega
|
||||
|
||||
@[no_expose]
|
||||
instance : HasFiniteRanges .open Nat where
|
||||
finite init u := by
|
||||
refine ⟨u - init, ?_⟩
|
||||
simp only [UpwardEnumerable.succMany?, SupportsUpperBound.IsSatisfied, Option.elim_some]
|
||||
omega
|
||||
|
||||
instance : RangeSize .closed Nat where
|
||||
size bound a := bound + 1 - a
|
||||
|
||||
instance : RangeSize .open Nat := .openOfClosed
|
||||
instance : RangeSize .open Nat where
|
||||
size bound a := bound - a
|
||||
|
||||
instance : LawfulRangeSize .closed Nat where
|
||||
size_eq_zero_of_not_isSatisfied upperBound init hu := by
|
||||
@@ -73,16 +135,17 @@ instance : LawfulRangeSize .closed Nat where
|
||||
Option.some.injEq] at hu h ⊢
|
||||
omega
|
||||
|
||||
instance : LawfulRangeSize .open Nat := inferInstance
|
||||
instance : HasFiniteRanges .closed Nat := inferInstance
|
||||
instance : HasFiniteRanges .open Nat := inferInstance
|
||||
instance : LinearlyUpwardEnumerable Nat := by
|
||||
exact instLinearlyUpwardEnumerableOfTotalLeOfLawfulUpwardEnumerableOfLawfulUpwardEnumerableLE
|
||||
|
||||
/-!
|
||||
The following instances are used for the implementation of array slices a.k.a. `Subarray`.
|
||||
See also `Init.Data.Slice.Array`.
|
||||
-/
|
||||
instance : LawfulRangeSize .open Nat where
|
||||
size_eq_zero_of_not_isSatisfied upperBound init hu := by
|
||||
simp only [SupportsUpperBound.IsSatisfied, RangeSize.size] at hu ⊢
|
||||
omega
|
||||
size_eq_one_of_succ?_eq_none upperBound init hu h := by
|
||||
simp only [UpwardEnumerable.succ?] at h
|
||||
cases h
|
||||
size_eq_succ_of_succ?_eq_some upperBound init hu h := by
|
||||
simp only [SupportsUpperBound.IsSatisfied, RangeSize.size, UpwardEnumerable.succ?,
|
||||
Option.some.injEq] at hu h ⊢
|
||||
omega
|
||||
|
||||
instance : ClosedOpenIntersection ⟨.open, .open⟩ Nat where
|
||||
intersection r s := PRange.mk (max (r.lower + 1) s.lower) (min r.upper s.upper)
|
||||
|
||||
@@ -13,16 +13,13 @@ public section
|
||||
|
||||
namespace Std.PRange.Nat
|
||||
|
||||
theorem succ_eq {n : Nat} : succ n = n + 1 :=
|
||||
theorem succ_eq {n : Nat} : UpwardEnumerable.succ n = n + 1 :=
|
||||
rfl
|
||||
|
||||
theorem toList_Rco_succ_succ {m n : Nat} :
|
||||
((m+1)...(n+1)).toList = (m...n).toList.map (· + 1) := by
|
||||
theorem ClosedOpen.toList_succ_succ {m n : Nat} :
|
||||
((m+1)...(n+1)).toList =
|
||||
(m...n).toList.map (· + 1) := by
|
||||
simp only [← succ_eq]
|
||||
rw [Std.PRange.toList_Rco_succ_succ_eq_map]
|
||||
|
||||
@[deprecated toList_Rco_succ_succ (since := "2025-08-22")]
|
||||
theorem ClosedOpen.toList_succ_succ {m n : Nat} :
|
||||
((m+1)...(n+1)).toList = (m...n).toList.map (· + 1) := toList_Rco_succ_succ
|
||||
rw [Std.PRange.ClosedOpen.toList_succ_succ_eq_map]
|
||||
|
||||
end Std.PRange.Nat
|
||||
|
||||
@@ -53,16 +53,14 @@ A range of elements of some type `α`. It is characterized by its upper and lowe
|
||||
may be inclusive, exclusive or absent.
|
||||
|
||||
* `a...=b` is the range of elements greater than or equal to `a` and less than or equal to `b`.
|
||||
* `a...b` or `a...<b` is the range of elements greater than or equal to `a` and less than `b`.
|
||||
* `a...*` is the range of elements greater than or equal to `a`.
|
||||
* `a<...=b` is the range of elements greater than `a` and less than or equal to `b`.
|
||||
* `a...b` or `a...<b` is the range of elements greater than or equal to `a` and less than `b`.
|
||||
* `a<...b` or `a<...<b` is the range of elements greater than `a` and less than `b`.
|
||||
* `a<...*` is the range of elements greater than `a`.
|
||||
* `*...=b` is the range of elements less than or equal to `b`.
|
||||
* `*...b` or `*...<b` is the range of elements less than `b`.
|
||||
* `a...*` is the range of elements greater than or equal to `a`.
|
||||
* `a<...*` is the range of elements greater than `a`.
|
||||
* `*...*` contains all elements of `α`.
|
||||
|
||||
The recommended spelling for these ranges can be found in the `PRange.mk` constructor's docstring.
|
||||
-/
|
||||
structure _root_.Std.PRange (shape : RangeShape) (α : Type u) where
|
||||
/-- The lower bound of the range. -/
|
||||
@@ -70,14 +68,6 @@ structure _root_.Std.PRange (shape : RangeShape) (α : Type u) where
|
||||
/-- The upper bound of the range. -/
|
||||
upper : Bound shape.upper α
|
||||
|
||||
/--
|
||||
Creates a new range. For more information about ranges, see `Std.PRange`.
|
||||
|
||||
The implicit `shape` parameter specifies the shape of the explicitly given
|
||||
lower and upper bounds.
|
||||
-/
|
||||
add_decl_doc _root_.Std.PRange.mk
|
||||
|
||||
/-- `a...*` is the range of elements greater than or equal to `a`. See also `Std.PRange`. -/
|
||||
syntax:max (term "...*") : term
|
||||
/-- `*...*` is the range that is unbounded in both directions. See also `Std.PRange`. -/
|
||||
@@ -135,27 +125,6 @@ macro_rules
|
||||
| `($a<...<$b) => ``(PRange.mk (shape := RangeShape.mk BoundShape.open BoundShape.open) $a $b)
|
||||
| `($a<...$b) => ``(PRange.mk (shape := RangeShape.mk BoundShape.open BoundShape.open) $a $b)
|
||||
|
||||
recommended_spelling "Rcc" for "a...=b" in [PRange.mk, «term_...=_»]
|
||||
recommended_spelling "Rco" for "a...b" in [PRange.mk, «term_..._», «term_...<_»]
|
||||
recommended_spelling "Rco" for "a...<b" in [«term_...<_»]
|
||||
recommended_spelling "Rci" for "a...*" in [PRange.mk, «term_...*»]
|
||||
recommended_spelling "Roc" for "a<...=b" in [PRange.mk, «term_<...=_»]
|
||||
recommended_spelling "Roo" for "a<...b" in [PRange.mk, «term_<..._», «term_<...<_»]
|
||||
recommended_spelling "Roo" for "a<...<b" in [«term_<...<_»]
|
||||
recommended_spelling "Roi" for "a<...*" in [PRange.mk, «term_<...*»]
|
||||
recommended_spelling "Ric" for "*...=b" in [PRange.mk, «term*...=_»]
|
||||
recommended_spelling "Rio" for "*...b" in [PRange.mk, «term*..._», «term*...<_»]
|
||||
recommended_spelling "Rio" for "*...<b" in [«term*...<_»]
|
||||
recommended_spelling "Rii" for "*...*" in [PRange.mk, «term*...*»]
|
||||
|
||||
recommended_spelling "Rcx" for "PRange.mk .closed ub" in [PRange.mk]
|
||||
recommended_spelling "Rox" for "PRange.mk .open ub" in [PRange.mk]
|
||||
recommended_spelling "Rix" for "PRange.mk .unbounded ub" in [PRange.mk]
|
||||
recommended_spelling "Rxc" for "PRange.mk lb .closed" in [PRange.mk]
|
||||
recommended_spelling "Rxo" for "PRange.mk lb .open" in [PRange.mk]
|
||||
recommended_spelling "Rxi" for "PRange.mk lb .unbounded" in [PRange.mk]
|
||||
recommended_spelling "Rxx" for "PRange.mk lb ub" in [PRange.mk]
|
||||
|
||||
/--
|
||||
This typeclass provides decidable lower bound checks of the given shape.
|
||||
|
||||
@@ -169,8 +138,6 @@ class SupportsLowerBound (shape : BoundShape) (α : Type u) where
|
||||
IsSatisfied : Bound shape α → α → Prop
|
||||
decidableSatisfiesLowerBound : DecidableRel IsSatisfied := by infer_instance
|
||||
|
||||
attribute [simp] SupportsLowerBound.IsSatisfied
|
||||
|
||||
instance : SupportsLowerBound .unbounded α where
|
||||
IsSatisfied _ _ := True
|
||||
|
||||
@@ -187,8 +154,6 @@ class SupportsUpperBound (shape : BoundShape) (α : Type u) where
|
||||
IsSatisfied : Bound shape α → α → Prop
|
||||
decidableSatisfiesUpperBound : DecidableRel IsSatisfied := by infer_instance
|
||||
|
||||
attribute [simp] SupportsUpperBound.IsSatisfied
|
||||
|
||||
instance {α} : SupportsUpperBound .unbounded α where
|
||||
IsSatisfied _ _ := True
|
||||
|
||||
@@ -227,9 +192,6 @@ Instances are automatically generated in the following cases:
|
||||
class BoundedUpwardEnumerable (lowerBoundShape : BoundShape) (α : Type u) where
|
||||
init? : Bound lowerBoundShape α → Option α
|
||||
|
||||
attribute [simp] BoundedUpwardEnumerable.init?
|
||||
export BoundedUpwardEnumerable (init?)
|
||||
|
||||
/--
|
||||
This typeclass ensures that the lower bound predicate from `SupportsLowerBound sl α`
|
||||
can be characterized in terms of `UpwardEnumerable α` and `BoundedUpwardEnumerable sl α`.
|
||||
@@ -238,10 +200,11 @@ class LawfulUpwardEnumerableLowerBound (sl α) [UpwardEnumerable α]
|
||||
[SupportsLowerBound sl α] [BoundedUpwardEnumerable sl α] where
|
||||
/--
|
||||
An element `a` satisfies the lower bound `l` if and only if it is
|
||||
`init? l` or one of its transitive successors.
|
||||
`BoundedUpwardEnumerable.init? l` or one of its transitive successors.
|
||||
-/
|
||||
isSatisfied_iff (a : α) (l : Bound sl α) :
|
||||
SupportsLowerBound.IsSatisfied l a ↔ ∃ init, init? l = some init ∧ UpwardEnumerable.LE init a
|
||||
SupportsLowerBound.IsSatisfied l a ↔
|
||||
∃ init, BoundedUpwardEnumerable.init? l = some init ∧ UpwardEnumerable.LE init a
|
||||
|
||||
/--
|
||||
This typeclass ensures that if `b` is a transitive successor of `a` and `b` satisfies an upper bound
|
||||
|
||||
@@ -251,14 +251,14 @@ private def RangeIterator.instFinitenessRelation [UpwardEnumerable α] [Supports
|
||||
obtain ⟨n, hn⟩ := HasFiniteRanges.finite init bound
|
||||
induction n generalizing init with
|
||||
| zero =>
|
||||
simp only [succMany?_zero, Option.elim_some] at hn
|
||||
simp only [UpwardEnumerable.succMany?_zero, Option.elim_some] at hn
|
||||
constructor
|
||||
simp [hn, IterStep.successor]
|
||||
| succ n ih =>
|
||||
constructor
|
||||
rintro it'
|
||||
simp only [succMany?_succ?_eq_succ?_bind_succMany?] at hn
|
||||
match hs : succ? init with
|
||||
simp only [LawfulUpwardEnumerable.succMany?_succ_eq_succ?_bind_succMany?] at hn
|
||||
match hs : UpwardEnumerable.succ? init with
|
||||
| none =>
|
||||
simp only [hs]
|
||||
intro h
|
||||
@@ -316,7 +316,7 @@ instance RangeIterator.instIteratorAccess {su} [UpwardEnumerable α] [SupportsUp
|
||||
· split <;> rename_i heq
|
||||
· apply IterM.IsPlausibleNthOutputStep.done
|
||||
simp only [Monadic.isPlausibleStep_iff, Monadic.step]
|
||||
simp only [Option.bind_eq_none_iff, succMany?_zero, reduceCtorEq,
|
||||
simp only [Option.bind_eq_none_iff, UpwardEnumerable.succMany?_zero, reduceCtorEq,
|
||||
imp_false] at heq
|
||||
cases heq' : it.internalState.next
|
||||
· simp
|
||||
@@ -325,7 +325,7 @@ instance RangeIterator.instIteratorAccess {su} [UpwardEnumerable α] [SupportsUp
|
||||
exact heq _ rfl
|
||||
· cases heq' : it.internalState.next
|
||||
· simp [heq'] at heq
|
||||
simp only [heq', Option.bind_some, succMany?_zero, Option.some.injEq] at heq
|
||||
simp only [heq', Option.bind_some, UpwardEnumerable.succMany?_zero, Option.some.injEq] at heq
|
||||
cases heq
|
||||
split <;> rename_i heq''
|
||||
· apply IterM.IsPlausibleNthOutputStep.zero_yield
|
||||
@@ -338,7 +338,7 @@ instance RangeIterator.instIteratorAccess {su} [UpwardEnumerable α] [SupportsUp
|
||||
· apply IterM.IsPlausibleNthOutputStep.done
|
||||
simp only [Monadic.isPlausibleStep_iff, Monadic.step, heq']
|
||||
· rename_i out
|
||||
simp only [heq', Option.bind_some, succMany?_succ?_eq_succ?_bind_succMany?] at heq
|
||||
simp only [heq', Option.bind_some, LawfulUpwardEnumerable.succMany?_succ_eq_succ?_bind_succMany?] at heq
|
||||
specialize ih ⟨⟨UpwardEnumerable.succ? out, it.internalState.upperBound⟩⟩
|
||||
simp only [heq] at ih
|
||||
by_cases heq'' : SupportsUpperBound.IsSatisfied it.internalState.upperBound out
|
||||
@@ -354,7 +354,7 @@ instance RangeIterator.instIteratorAccess {su} [UpwardEnumerable α] [SupportsUp
|
||||
rename_i out
|
||||
simp only [heq', Option.bind_some] at heq
|
||||
have hle : UpwardEnumerable.LE out _ := ⟨n + 1, heq⟩
|
||||
simp only [succMany?_succ?_eq_succ?_bind_succMany?] at heq
|
||||
simp only [LawfulUpwardEnumerable.succMany?_succ_eq_succ?_bind_succMany?] at heq
|
||||
specialize ih ⟨⟨UpwardEnumerable.succ? out, it.internalState.upperBound⟩⟩
|
||||
simp only [heq] at ih
|
||||
by_cases hout : SupportsUpperBound.IsSatisfied it.internalState.upperBound out
|
||||
@@ -378,7 +378,7 @@ theorem RangeIterator.Monadic.isPlausibleIndirectOutput_iff {su α}
|
||||
[LawfulUpwardEnumerable α] [LawfulUpwardEnumerableUpperBound su α]
|
||||
{it : IterM (α := RangeIterator su α) Id α} {out : α} :
|
||||
it.IsPlausibleIndirectOutput out ↔
|
||||
∃ n, it.internalState.next.bind (succMany? n ·) = some out ∧
|
||||
∃ n, it.internalState.next.bind (UpwardEnumerable.succMany? n ·) = some out ∧
|
||||
SupportsUpperBound.IsSatisfied it.internalState.upperBound out := by
|
||||
constructor
|
||||
· intro h
|
||||
@@ -391,7 +391,7 @@ theorem RangeIterator.Monadic.isPlausibleIndirectOutput_iff {su α}
|
||||
obtain ⟨n, hn⟩ := ih
|
||||
obtain ⟨a, ha, h₁, h₂, h₃⟩ := h
|
||||
refine ⟨n + 1, ?_⟩
|
||||
simp [ha, ← h₃, hn.2, succMany?_succ?_eq_succ?_bind_succMany?, h₂, hn]
|
||||
simp [ha, ← h₃, hn.2, LawfulUpwardEnumerable.succMany?_succ_eq_succ?_bind_succMany?, h₂, hn]
|
||||
· rintro ⟨n, hn, hu⟩
|
||||
induction n generalizing it
|
||||
case zero =>
|
||||
@@ -404,8 +404,8 @@ theorem RangeIterator.Monadic.isPlausibleIndirectOutput_iff {su α}
|
||||
rename_i a
|
||||
simp only [hn', Option.bind_some] at hn
|
||||
have hle : UpwardEnumerable.LE a out := ⟨_, hn⟩
|
||||
rw [succMany?_succ?_eq_succ?_bind_succMany?] at hn
|
||||
cases hn' : succ? a
|
||||
rw [LawfulUpwardEnumerable.succMany?_succ_eq_succ?_bind_succMany?] at hn
|
||||
cases hn' : UpwardEnumerable.succ? a
|
||||
· simp only [hn', Option.bind_none, reduceCtorEq] at hn
|
||||
rename_i a'
|
||||
simp only [hn', Option.bind_some] at hn
|
||||
@@ -422,7 +422,7 @@ theorem RangeIterator.isPlausibleIndirectOutput_iff {su α}
|
||||
[LawfulUpwardEnumerable α] [LawfulUpwardEnumerableUpperBound su α]
|
||||
{it : Iter (α := RangeIterator su α) α} {out : α} :
|
||||
it.IsPlausibleIndirectOutput out ↔
|
||||
∃ n, it.internalState.next.bind (succMany? n ·) = some out ∧
|
||||
∃ n, it.internalState.next.bind (UpwardEnumerable.succMany? n ·) = some out ∧
|
||||
SupportsUpperBound.IsSatisfied it.internalState.upperBound out := by
|
||||
simp only [Iter.isPlausibleIndirectOutput_iff_isPlausibleIndirectOutput_toIterM,
|
||||
Monadic.isPlausibleIndirectOutput_iff, Iter.toIterM]
|
||||
@@ -476,7 +476,7 @@ instance RangeIterator.instIteratorLoop {su} [UpwardEnumerable α] [SupportsUppe
|
||||
exact UpwardEnumerable.le_refl _
|
||||
case hle' =>
|
||||
refine UpwardEnumerable.le_trans hl ⟨1, ?_⟩
|
||||
simp [succMany?_one, hs]
|
||||
simp [UpwardEnumerable.succMany?_one, hs]
|
||||
|
||||
partial instance RepeatIterator.instIteratorLoopPartial {su} [UpwardEnumerable α]
|
||||
[SupportsUpperBound su α] [LawfulUpwardEnumerable α] [LawfulUpwardEnumerableUpperBound su α]
|
||||
@@ -496,7 +496,7 @@ partial instance RepeatIterator.instIteratorLoopPartial {su} [UpwardEnumerable
|
||||
(next : α) (hl : UpwardEnumerable.LE least next) (hu : SupportsUpperBound.IsSatisfied upperBound next) : n γ := do
|
||||
match ← f next hl hu acc with
|
||||
| .yield acc' =>
|
||||
match hs : succ? next with
|
||||
match hs : UpwardEnumerable.succ? next with
|
||||
| some next' =>
|
||||
if hu : SupportsUpperBound.IsSatisfied upperBound next' then
|
||||
loop γ upperBound least acc' f next' ?hle' hu
|
||||
@@ -513,10 +513,10 @@ partial instance RepeatIterator.instIteratorLoopPartial {su} [UpwardEnumerable
|
||||
exact UpwardEnumerable.le_refl _
|
||||
case hle' =>
|
||||
refine UpwardEnumerable.le_trans hl ⟨1, ?_⟩
|
||||
simp [succMany?_one, hs]
|
||||
simp [UpwardEnumerable.succMany?_one, hs]
|
||||
|
||||
theorem RangeIterator.instIteratorLoop.loop_eq {su} [UpwardEnumerable α]
|
||||
[SupportsUpperBound su α] [LawfulUpwardEnumerable α] [LawfulUpwardEnumerableUpperBound su α]
|
||||
theorem RangeIterator.instIteratorLoop.loop_eq {su} [UpwardEnumerable α] [SupportsUpperBound su α]
|
||||
[LawfulUpwardEnumerable α] [LawfulUpwardEnumerableUpperBound su α]
|
||||
{n : Type u → Type w} [Monad n] [LawfulMonad n] {γ : Type u}
|
||||
{lift} [Internal.LawfulMonadLiftBindFunction lift]
|
||||
{PlausibleForInStep} {upperBound} {next} {hl} {hu} {f} {acc} {wf} :
|
||||
@@ -524,18 +524,16 @@ theorem RangeIterator.instIteratorLoop.loop_eq {su} [UpwardEnumerable α]
|
||||
(do
|
||||
match ← f next hl hu acc with
|
||||
| ⟨.yield c, _⟩ =>
|
||||
letI it' : IterM (α := RangeIterator su α) Id α := ⟨⟨succ? next, upperBound⟩⟩
|
||||
letI it' : IterM (α := RangeIterator su α) Id α := ⟨⟨UpwardEnumerable.succ? next, upperBound⟩⟩
|
||||
IterM.DefaultConsumers.forIn' (m := Id) lift γ
|
||||
PlausibleForInStep wf it' c it'.IsPlausibleIndirectOutput (fun _ => id)
|
||||
(fun b h c => f b
|
||||
(by
|
||||
refine UpwardEnumerable.le_trans hl ?_
|
||||
simp only [RangeIterator.Monadic.isPlausibleIndirectOutput_iff, it',
|
||||
← succMany?_succ?_eq_succ?_bind_succMany?] at h
|
||||
← LawfulUpwardEnumerable.succMany?_succ_eq_succ?_bind_succMany?] at h
|
||||
exact ⟨h.choose + 1, h.choose_spec.1⟩)
|
||||
(by
|
||||
simp only [RangeIterator.Monadic.isPlausibleIndirectOutput_iff, it'] at h
|
||||
exact h.choose_spec.2) c)
|
||||
(by simp only [RangeIterator.Monadic.isPlausibleIndirectOutput_iff, it'] at h; exact h.choose_spec.2) c)
|
||||
| ⟨.done c, _⟩ => return c) := by
|
||||
rw [loop]
|
||||
apply bind_congr
|
||||
|
||||
@@ -40,16 +40,13 @@ class UpwardEnumerable (α : Type u) where
|
||||
-/
|
||||
succMany? (n : Nat) (a : α) : Option α := Nat.repeat (· >>= succ?) n (some a)
|
||||
|
||||
attribute [simp] UpwardEnumerable.succ? UpwardEnumerable.succMany?
|
||||
export UpwardEnumerable (succ? succMany?)
|
||||
|
||||
/--
|
||||
According to `UpwardEnumerable.LE`, `a` is less than or equal to `b` if `b` is `a` or a transitive
|
||||
successor of `a`.
|
||||
-/
|
||||
@[expose]
|
||||
protected def UpwardEnumerable.LE {α : Type u} [UpwardEnumerable α] (a b : α) : Prop :=
|
||||
∃ n, succMany? n a = some b
|
||||
def UpwardEnumerable.LE {α : Type u} [UpwardEnumerable α] (a b : α) : Prop :=
|
||||
∃ n, UpwardEnumerable.succMany? n a = some b
|
||||
|
||||
/--
|
||||
According to `UpwardEnumerable.LT`, `a` is less than `b` if `b` is a proper transitive successor of
|
||||
@@ -58,10 +55,10 @@ According to `UpwardEnumerable.LT`, `a` is less than `b` if `b` is a proper tran
|
||||
Given `LawfulUpwardEnumerable α`, no element of `α` is less than itself.
|
||||
-/
|
||||
@[expose]
|
||||
protected def UpwardEnumerable.LT {α : Type u} [UpwardEnumerable α] (a b : α) : Prop :=
|
||||
∃ n, succMany? (n + 1) a = some b
|
||||
def UpwardEnumerable.LT {α : Type u} [UpwardEnumerable α] (a b : α) : Prop :=
|
||||
∃ n, UpwardEnumerable.succMany? (n + 1) a = some b
|
||||
|
||||
protected theorem UpwardEnumerable.le_of_lt {α : Type u} [UpwardEnumerable α] {a b : α}
|
||||
theorem UpwardEnumerable.le_of_lt {α : Type u} [UpwardEnumerable α] {a b : α}
|
||||
(h : UpwardEnumerable.LT a b) : UpwardEnumerable.LE a b :=
|
||||
⟨h.choose + 1, h.choose_spec⟩
|
||||
|
||||
@@ -80,9 +77,6 @@ class Least? (α : Type u) where
|
||||
-/
|
||||
least? : Option α
|
||||
|
||||
attribute [simp] Least?.least?
|
||||
export Least? (least?)
|
||||
|
||||
/--
|
||||
This typeclass ensures that an `UpwardEnumerable α` instance is well-behaved.
|
||||
-/
|
||||
@@ -90,110 +84,99 @@ class LawfulUpwardEnumerable (α : Type u) [UpwardEnumerable α] where
|
||||
/-- There is no cyclic chain of successors. -/
|
||||
ne_of_lt (a b : α) : UpwardEnumerable.LT a b → a ≠ b
|
||||
/-- The `0`-th successor of `a` is `a` itself. -/
|
||||
succMany?_zero (a : α) : succMany? 0 a = some a
|
||||
succMany?_zero (a : α) : UpwardEnumerable.succMany? 0 a = some a
|
||||
/--
|
||||
The `n + 1`-th successor of `a` is the successor of the `n`-th successor, given that said
|
||||
successors actually exist.
|
||||
-/
|
||||
succMany?_succ (n : Nat) (a : α) :
|
||||
succMany? (n + 1) a = (succMany? n a).bind succ?
|
||||
UpwardEnumerable.succMany? (n + 1) a = (UpwardEnumerable.succMany? n a).bind UpwardEnumerable.succ?
|
||||
|
||||
theorem UpwardEnumerable.succMany?_zero [UpwardEnumerable α] [LawfulUpwardEnumerable α] {a : α} :
|
||||
succMany? 0 a = some a :=
|
||||
UpwardEnumerable.succMany? 0 a = some a :=
|
||||
LawfulUpwardEnumerable.succMany?_zero a
|
||||
|
||||
theorem UpwardEnumerable.succMany?_succ? [UpwardEnumerable α] [LawfulUpwardEnumerable α]
|
||||
{n : Nat} {a : α} :
|
||||
succMany? (n + 1) a = (succMany? n a).bind succ? :=
|
||||
LawfulUpwardEnumerable.succMany?_succ n a
|
||||
|
||||
@[deprecated succMany?_succ? (since := "2025-09-03")]
|
||||
theorem UpwardEnumerable.succMany?_succ [UpwardEnumerable α] [LawfulUpwardEnumerable α]
|
||||
{n : Nat} {a : α} :
|
||||
succMany? (n + 1) a = (succMany? n a).bind succ? :=
|
||||
succMany?_succ?
|
||||
UpwardEnumerable.succMany? (n + 1) a =
|
||||
(UpwardEnumerable.succMany? n a).bind UpwardEnumerable.succ? :=
|
||||
LawfulUpwardEnumerable.succMany?_succ n a
|
||||
|
||||
theorem UpwardEnumerable.succMany?_one [UpwardEnumerable α] [LawfulUpwardEnumerable α] {a : α} :
|
||||
succMany? 1 a = succ? a := by
|
||||
simp [succMany?_succ?, succMany?_zero]
|
||||
UpwardEnumerable.succMany? 1 a = UpwardEnumerable.succ? a := by
|
||||
simp [UpwardEnumerable.succMany?_succ, UpwardEnumerable.succMany?_zero]
|
||||
|
||||
theorem UpwardEnumerable.succMany?_add [UpwardEnumerable α] [LawfulUpwardEnumerable α]
|
||||
{m n : Nat} {a : α} :
|
||||
succMany? (m + n) a = (succMany? m a).bind (succMany? n ·) := by
|
||||
(m n : Nat) (a : α) :
|
||||
UpwardEnumerable.succMany? (m + n) a =
|
||||
(UpwardEnumerable.succMany? m a).bind (UpwardEnumerable.succMany? n ·) := by
|
||||
induction n
|
||||
case zero => simp [succMany?_zero]
|
||||
case zero => simp [LawfulUpwardEnumerable.succMany?_zero]
|
||||
case succ n ih =>
|
||||
rw [← Nat.add_assoc, succMany?_succ?, ih, Option.bind_assoc]
|
||||
simp [succMany?_succ?]
|
||||
rw [← Nat.add_assoc, LawfulUpwardEnumerable.succMany?_succ, ih, Option.bind_assoc]
|
||||
simp only [LawfulUpwardEnumerable.succMany?_succ]
|
||||
|
||||
theorem UpwardEnumerable.succMany?_succ?_eq_succ?_bind_succMany?
|
||||
[UpwardEnumerable α] [LawfulUpwardEnumerable α]
|
||||
{n : Nat} {a : α} :
|
||||
succMany? (n + 1) a = (succ? a).bind (succMany? n ·) := by
|
||||
rw [Nat.add_comm]
|
||||
simp [succMany?_add, succMany?_succ?, succMany?_zero]
|
||||
|
||||
@[deprecated UpwardEnumerable.succMany?_succ?_eq_succ?_bind_succMany? (since := "2025-09-03")]
|
||||
theorem LawfulUpwardEnumerable.succMany?_succ_eq_succ?_bind_succMany?
|
||||
[UpwardEnumerable α] [LawfulUpwardEnumerable α]
|
||||
(n : Nat) (a : α) :
|
||||
succMany? (n + 1) a = (succ? a).bind (succMany? n ·) :=
|
||||
UpwardEnumerable.succMany?_succ?_eq_succ?_bind_succMany?
|
||||
UpwardEnumerable.succMany? (n + 1) a =
|
||||
(UpwardEnumerable.succ? a).bind (UpwardEnumerable.succMany? n ·) := by
|
||||
rw [Nat.add_comm]
|
||||
simp [UpwardEnumerable.succMany?_add, LawfulUpwardEnumerable.succMany?_succ,
|
||||
LawfulUpwardEnumerable.succMany?_zero]
|
||||
|
||||
export UpwardEnumerable (succMany?_zero succMany?_succ? succMany?_one succMany?_add
|
||||
succMany?_succ?_eq_succ?_bind_succMany?)
|
||||
theorem UpwardEnumerable.le_refl {α : Type u} [UpwardEnumerable α] [LawfulUpwardEnumerable α]
|
||||
(a : α) : UpwardEnumerable.LE a a :=
|
||||
⟨0, LawfulUpwardEnumerable.succMany?_zero a⟩
|
||||
|
||||
protected theorem UpwardEnumerable.le_refl {α : Type u} [UpwardEnumerable α]
|
||||
[LawfulUpwardEnumerable α] (a : α) : UpwardEnumerable.LE a a :=
|
||||
⟨0, succMany?_zero⟩
|
||||
|
||||
protected theorem UpwardEnumerable.lt_irrefl {α : Type u} [UpwardEnumerable α]
|
||||
[LawfulUpwardEnumerable α] {a : α} : ¬ UpwardEnumerable.LT a a :=
|
||||
theorem UpwardEnumerable.lt_irrefl {α : Type u} [UpwardEnumerable α] [LawfulUpwardEnumerable α]
|
||||
{a : α} : ¬ UpwardEnumerable.LT a a :=
|
||||
fun h => LawfulUpwardEnumerable.ne_of_lt a a h rfl
|
||||
|
||||
protected theorem UpwardEnumerable.ne_of_lt {α : Type u} [UpwardEnumerable α]
|
||||
[LawfulUpwardEnumerable α] {a b : α} (h : UpwardEnumerable.LT a b) : a ≠ b :=
|
||||
LawfulUpwardEnumerable.ne_of_lt a b h
|
||||
|
||||
protected theorem UpwardEnumerable.le_trans {α : Type u} [UpwardEnumerable α]
|
||||
[LawfulUpwardEnumerable α] {a b c : α} (hab : UpwardEnumerable.LE a b)
|
||||
(hbc : UpwardEnumerable.LE b c) : UpwardEnumerable.LE a c := by
|
||||
theorem UpwardEnumerable.le_trans {α : Type u} [UpwardEnumerable α] [LawfulUpwardEnumerable α]
|
||||
{a b c : α} (hab : UpwardEnumerable.LE a b) (hbc : UpwardEnumerable.LE b c) :
|
||||
UpwardEnumerable.LE a c := by
|
||||
refine ⟨hab.choose + hbc.choose, ?_⟩
|
||||
simp [succMany?_add, hab.choose_spec, hbc.choose_spec]
|
||||
|
||||
theorem UpwardEnumerable.le_of_succ?_eq {α : Type u} [UpwardEnumerable α] [LawfulUpwardEnumerable α]
|
||||
{a b : α} (hab : UpwardEnumerable.succ? a = some b) : UpwardEnumerable.LE a b :=
|
||||
⟨1, by simp [succMany?_one, hab]⟩
|
||||
⟨1, by simp [UpwardEnumerable.succMany?_one, hab]⟩
|
||||
|
||||
protected theorem UpwardEnumerable.lt_of_lt_of_le {α : Type u} [UpwardEnumerable α]
|
||||
[LawfulUpwardEnumerable α] {a b c : α} (hab : UpwardEnumerable.LT a b)
|
||||
(hbc : UpwardEnumerable.LE b c) : UpwardEnumerable.LT a c := by
|
||||
theorem UpwardEnumerable.lt_of_lt_of_le {α : Type u} [UpwardEnumerable α] [LawfulUpwardEnumerable α]
|
||||
{a b c : α} (hab : UpwardEnumerable.LT a b) (hbc : UpwardEnumerable.LE b c) :
|
||||
UpwardEnumerable.LT a c := by
|
||||
refine ⟨hab.choose + hbc.choose, ?_⟩
|
||||
rw [Nat.add_right_comm, succMany?_add, hab.choose_spec, Option.bind_some, hbc.choose_spec]
|
||||
|
||||
protected theorem UpwardEnumerable.lt_of_le_of_lt {α : Type u} [UpwardEnumerable α]
|
||||
[LawfulUpwardEnumerable α] {a b c : α} (hab : UpwardEnumerable.LE a b)
|
||||
(hbc : UpwardEnumerable.LT b c) : UpwardEnumerable.LT a c := by
|
||||
theorem UpwardEnumerable.lt_of_le_of_lt {α : Type u} [UpwardEnumerable α] [LawfulUpwardEnumerable α]
|
||||
{a b c : α} (hab : UpwardEnumerable.LE a b) (hbc : UpwardEnumerable.LT b c) :
|
||||
UpwardEnumerable.LT a c := by
|
||||
refine ⟨hab.choose + hbc.choose, ?_⟩
|
||||
rw [Nat.add_assoc, succMany?_add, hab.choose_spec, Option.bind_some, hbc.choose_spec]
|
||||
|
||||
protected theorem UpwardEnumerable.not_gt_of_le {α : Type u} [UpwardEnumerable α]
|
||||
[LawfulUpwardEnumerable α] {a b : α} :
|
||||
theorem UpwardEnumerable.not_gt_of_le {α : Type u} [UpwardEnumerable α] [LawfulUpwardEnumerable α]
|
||||
{a b : α} :
|
||||
UpwardEnumerable.LE a b → ¬ UpwardEnumerable.LT b a := by
|
||||
rintro ⟨n, hle⟩ ⟨m, hgt⟩
|
||||
have : UpwardEnumerable.LT a a := by
|
||||
refine ⟨n + m, ?_⟩
|
||||
rw [Nat.add_assoc, succMany?_add, hle, Option.bind_some, hgt]
|
||||
exact UpwardEnumerable.ne_of_lt this rfl
|
||||
rw [Nat.add_assoc, UpwardEnumerable.succMany?_add, hle, Option.bind_some, hgt]
|
||||
exact LawfulUpwardEnumerable.ne_of_lt _ _ this rfl
|
||||
|
||||
protected theorem UpwardEnumerable.not_ge_of_lt {α : Type u} [UpwardEnumerable α]
|
||||
[LawfulUpwardEnumerable α] {a b : α} :
|
||||
theorem UpwardEnumerable.not_ge_of_lt {α : Type u} [UpwardEnumerable α] [LawfulUpwardEnumerable α]
|
||||
{a b : α} :
|
||||
UpwardEnumerable.LT a b → ¬ UpwardEnumerable.LE b a :=
|
||||
flip UpwardEnumerable.not_gt_of_le
|
||||
flip not_gt_of_le
|
||||
|
||||
protected theorem UpwardEnumerable.not_gt_of_lt {α : Type u} [UpwardEnumerable α]
|
||||
[LawfulUpwardEnumerable α] {a b : α} (h : UpwardEnumerable.LT a b) : ¬ UpwardEnumerable.LT b a :=
|
||||
UpwardEnumerable.not_gt_of_le (UpwardEnumerable.le_of_lt h)
|
||||
theorem UpwardEnumerable.not_gt_of_lt {α : Type u} [UpwardEnumerable α] [LawfulUpwardEnumerable α]
|
||||
{a b : α} (h : UpwardEnumerable.LT a b) : ¬ UpwardEnumerable.LT b a :=
|
||||
not_gt_of_le (le_of_lt h)
|
||||
|
||||
theorem UpwardEnumerable.ne_of_lt {α : Type w} [UpwardEnumerable α] [LawfulUpwardEnumerable α]
|
||||
{a b : α} :
|
||||
UpwardEnumerable.LT a b → a ≠ b :=
|
||||
LawfulUpwardEnumerable.ne_of_lt a b
|
||||
|
||||
/--
|
||||
This propositional typeclass ensures that `UpwardEnumerable.succ?` will never return `none`.
|
||||
@@ -209,23 +192,15 @@ class LinearlyUpwardEnumerable (α : Type u) [UpwardEnumerable α] where
|
||||
eq_of_succ?_eq : ∀ a b : α, UpwardEnumerable.succ? a = UpwardEnumerable.succ? b → a = b
|
||||
|
||||
theorem UpwardEnumerable.isSome_succ? {α : Type u} [UpwardEnumerable α]
|
||||
[InfinitelyUpwardEnumerable α] {a : α} : (succ? a).isSome :=
|
||||
[InfinitelyUpwardEnumerable α] {a : α} :
|
||||
(succ? a).isSome :=
|
||||
InfinitelyUpwardEnumerable.isSome_succ? a
|
||||
|
||||
theorem UpwardEnumerable.succ?_inj {α : Type u} [UpwardEnumerable α] [LinearlyUpwardEnumerable α]
|
||||
{a b : α} (h : succ? a = succ? b) :
|
||||
theorem UpwardEnumerable.eq_of_succ?_eq {α : Type u} [UpwardEnumerable α]
|
||||
[LinearlyUpwardEnumerable α] {a b : α} (h : succ? a = succ? b) :
|
||||
a = b :=
|
||||
LinearlyUpwardEnumerable.eq_of_succ?_eq a b h
|
||||
|
||||
@[deprecated succ?_inj (since := "2025-09-03")]
|
||||
theorem UpwardEnumerable.eq_of_succ?_eq {α : Type u} [UpwardEnumerable α] [LinearlyUpwardEnumerable α]
|
||||
{a b : α} (h : succ? a = succ? b) :
|
||||
a = b :=
|
||||
succ?_inj h
|
||||
|
||||
/--
|
||||
Maps elements of `α` to their immediate successor.
|
||||
-/
|
||||
@[always_inline, inline]
|
||||
abbrev UpwardEnumerable.succ {α : Type u} [UpwardEnumerable α] [InfinitelyUpwardEnumerable α]
|
||||
(a : α) : α :=
|
||||
@@ -241,23 +216,17 @@ theorem UpwardEnumerable.succ?_eq_some {α : Type u} [UpwardEnumerable α]
|
||||
succ? a = some (succ a) := by
|
||||
simp
|
||||
|
||||
theorem UpwardEnumerable.succ_inj {α : Type u} [UpwardEnumerable α]
|
||||
theorem UpwardEnumerable.eq_of_succ_eq {α : Type u} [UpwardEnumerable α]
|
||||
[InfinitelyUpwardEnumerable α] [LinearlyUpwardEnumerable α] {a b : α}
|
||||
(h : succ a = succ b) : a = b := by
|
||||
rw [succ, succ, ← Option.some.injEq, Option.some_get, Option.some_get] at h
|
||||
exact succ?_inj h
|
||||
|
||||
@[deprecated succ_inj (since := "2025-09-03")]
|
||||
theorem UpwardEnumerable.eq_of_succ_eq {α : Type u} [UpwardEnumerable α]
|
||||
[InfinitelyUpwardEnumerable α] [LinearlyUpwardEnumerable α] {a b : α}
|
||||
(h : succ a = succ b) : a = b :=
|
||||
succ_inj h
|
||||
exact eq_of_succ?_eq h
|
||||
|
||||
theorem UpwardEnumerable.succ_eq_succ_iff {α : Type u} [UpwardEnumerable α]
|
||||
[InfinitelyUpwardEnumerable α] [LinearlyUpwardEnumerable α] {a b : α} :
|
||||
succ a = succ b ↔ a = b := by
|
||||
constructor
|
||||
· apply succ_inj
|
||||
· apply eq_of_succ_eq
|
||||
· exact congrArg succ
|
||||
|
||||
theorem UpwardEnumerable.isSome_succMany? {α : Type u} [UpwardEnumerable α]
|
||||
@@ -266,19 +235,10 @@ theorem UpwardEnumerable.isSome_succMany? {α : Type u} [UpwardEnumerable α]
|
||||
induction n
|
||||
· simp [succMany?_zero]
|
||||
· rename_i ih
|
||||
simp only [succMany?_succ?]
|
||||
simp only [succMany?_succ]
|
||||
rw [← Option.some_get ih, Option.bind_some]
|
||||
apply InfinitelyUpwardEnumerable.isSome_succ?
|
||||
|
||||
/--
|
||||
Maps elements of `α` to their `n`-th successor. This should semantically behave like repeatedly
|
||||
applying `succ`, but it might be more efficient.
|
||||
|
||||
This function uses an `UpwardEnumerable α` instance.
|
||||
`LawfulUpwardEnumerable α` ensures the compatibility with `succ` and `succ?`.
|
||||
|
||||
If no other implementation is provided in UpwardEnumerable instance, succMany? repeatedly applies succ?.
|
||||
-/
|
||||
@[always_inline, inline]
|
||||
def UpwardEnumerable.succMany {α : Type u} [UpwardEnumerable α]
|
||||
[LawfulUpwardEnumerable α] [InfinitelyUpwardEnumerable α]
|
||||
@@ -300,11 +260,6 @@ theorem UpwardEnumerable.succMany?_eq_some_iff_succMany {α : Type u} [UpwardEnu
|
||||
succMany? n a = some b ↔ succMany n a = b := by
|
||||
simp [succMany?_eq_some]
|
||||
|
||||
theorem UpwardEnumerable.succMany_zero {α : Type u} [UpwardEnumerable α]
|
||||
[LawfulUpwardEnumerable α] [InfinitelyUpwardEnumerable α] {a : α} :
|
||||
succMany 0 a = a := by
|
||||
simp [succMany, succMany?_zero]
|
||||
|
||||
theorem UpwardEnumerable.succMany_one {α : Type u} [UpwardEnumerable α]
|
||||
[LawfulUpwardEnumerable α] [InfinitelyUpwardEnumerable α] {a : α} :
|
||||
succMany 1 a = succ a := by
|
||||
@@ -315,49 +270,43 @@ theorem UpwardEnumerable.succMany_add {α : Type u} [UpwardEnumerable α]
|
||||
{m n : Nat} {a : α} : succMany (m + n) a = succMany n (succMany m a) := by
|
||||
simp [succMany, succMany?_add]
|
||||
|
||||
export UpwardEnumerable (isSome_succ? succ?_inj succ succ_eq_get succ?_eq_some succ_inj
|
||||
succ_eq_succ_iff isSome_succMany? succMany succMany_eq_get
|
||||
succMany?_eq_some succMany?_eq_some_iff_succMany succMany_one succMany_zero
|
||||
succMany_add)
|
||||
|
||||
theorem UpwardEnumerable.succ_le_succ_iff {α : Type w} [UpwardEnumerable α]
|
||||
[LawfulUpwardEnumerable α] [LinearlyUpwardEnumerable α] [InfinitelyUpwardEnumerable α]
|
||||
{a b : α} : UpwardEnumerable.LE (succ a) (succ b) ↔
|
||||
theorem UpwardEnumerable.succ_le_succ_iff {α : Type w} [UpwardEnumerable α] [LawfulUpwardEnumerable α]
|
||||
[LinearlyUpwardEnumerable α] [InfinitelyUpwardEnumerable α] {a b : α} :
|
||||
UpwardEnumerable.LE (UpwardEnumerable.succ a) (UpwardEnumerable.succ b) ↔
|
||||
UpwardEnumerable.LE a b := by
|
||||
constructor
|
||||
· rintro ⟨n, hn⟩
|
||||
simp only [succ] at hn
|
||||
refine ⟨n, ?_⟩
|
||||
simp [succMany?_eq_some]
|
||||
apply succ?_inj
|
||||
apply eq_of_succ?_eq
|
||||
rw [← Option.bind_some (f := succMany? n), Option.some_get,
|
||||
← succMany?_succ?_eq_succ?_bind_succMany?, Option.some_get] at hn
|
||||
rw [← Option.bind_some (f := succ?), ← succMany?_eq_some, ← succMany?_succ?, hn]
|
||||
← LawfulUpwardEnumerable.succMany?_succ_eq_succ?_bind_succMany?, Option.some_get] at hn
|
||||
rw [← Option.bind_some (f := succ?), ← succMany?_eq_some, ← succMany?_succ, hn]
|
||||
· rintro ⟨n, hn⟩
|
||||
refine ⟨n, ?_⟩
|
||||
rw [succ_eq_get, succ_eq_get, ← Option.bind_some (f := succMany? n), Option.some_get,
|
||||
Option.some_get, ← succMany?_succ?_eq_succ?_bind_succMany?,
|
||||
succMany?_succ?, hn, Option.bind_some]
|
||||
Option.some_get, ← LawfulUpwardEnumerable.succMany?_succ_eq_succ?_bind_succMany?,
|
||||
succMany?_succ, hn, Option.bind_some]
|
||||
|
||||
theorem UpwardEnumerable.succ_lt_succ_iff {α : Type w} [UpwardEnumerable α]
|
||||
[LawfulUpwardEnumerable α] [LinearlyUpwardEnumerable α] [InfinitelyUpwardEnumerable α]
|
||||
{a b : α} :
|
||||
UpwardEnumerable.LT (succ a) (succ b) ↔
|
||||
theorem UpwardEnumerable.succ_lt_succ_iff {α : Type w} [UpwardEnumerable α] [LawfulUpwardEnumerable α]
|
||||
[LinearlyUpwardEnumerable α] [InfinitelyUpwardEnumerable α] {a b : α} :
|
||||
UpwardEnumerable.LT (UpwardEnumerable.succ a) (UpwardEnumerable.succ b) ↔
|
||||
UpwardEnumerable.LT a b := by
|
||||
constructor
|
||||
· rintro ⟨n, hn⟩
|
||||
simp only [succ] at hn
|
||||
refine ⟨n, ?_⟩
|
||||
rw [succMany?_eq_some_iff_succMany]
|
||||
apply succ?_inj
|
||||
apply eq_of_succ?_eq
|
||||
rw [← Option.bind_some (f := succMany? _), Option.some_get,
|
||||
← succMany?_succ?_eq_succ?_bind_succMany?, Option.some_get] at hn
|
||||
rw [← Option.bind_some (f := succ?), ← succMany?_eq_some, ← succMany?_succ?, hn]
|
||||
← LawfulUpwardEnumerable.succMany?_succ_eq_succ?_bind_succMany?, Option.some_get] at hn
|
||||
rw [← Option.bind_some (f := succ?), ← succMany?_eq_some, ← succMany?_succ, hn]
|
||||
· rintro ⟨n, hn⟩
|
||||
refine ⟨n, ?_⟩
|
||||
rw [succ_eq_get, succ_eq_get, ← Option.bind_some (f := succMany? _), Option.some_get,
|
||||
Option.some_get, ← succMany?_succ?_eq_succ?_bind_succMany?, succMany?_succ?, hn,
|
||||
Option.bind_some]
|
||||
Option.some_get, ← LawfulUpwardEnumerable.succMany?_succ_eq_succ?_bind_succMany?,
|
||||
succMany?_succ, hn, Option.bind_some]
|
||||
|
||||
/--
|
||||
This typeclass ensures that an `UpwardEnumerable α` instance is compatible with `≤`.
|
||||
@@ -368,11 +317,7 @@ class LawfulUpwardEnumerableLE (α : Type u) [UpwardEnumerable α] [LE α] where
|
||||
`a` is less than or equal to `b` if and only if `b` is either `a` or a transitive successor
|
||||
of `a`.
|
||||
-/
|
||||
protected le_iff (a b : α) : a ≤ b ↔ UpwardEnumerable.LE a b
|
||||
|
||||
protected theorem UpwardEnumerable.le_iff {α : Type u} [LE α] [UpwardEnumerable α]
|
||||
[LawfulUpwardEnumerableLE α] {a b : α} : a ≤ b ↔ UpwardEnumerable.LE a b :=
|
||||
LawfulUpwardEnumerableLE.le_iff a b
|
||||
le_iff (a b : α) : a ≤ b ↔ UpwardEnumerable.LE a b
|
||||
|
||||
/--
|
||||
This typeclass ensures that an `UpwardEnumerable α` instance is compatible with `<`.
|
||||
@@ -384,10 +329,6 @@ class LawfulUpwardEnumerableLT (α : Type u) [UpwardEnumerable α] [LT α] where
|
||||
-/
|
||||
lt_iff (a b : α) : a < b ↔ UpwardEnumerable.LT a b
|
||||
|
||||
protected theorem UpwardEnumerable.lt_iff {α : Type u} [LT α] [UpwardEnumerable α]
|
||||
[LawfulUpwardEnumerableLT α] {a b : α} : a < b ↔ UpwardEnumerable.LT a b :=
|
||||
LawfulUpwardEnumerableLT.lt_iff a b
|
||||
|
||||
/--
|
||||
This typeclass ensures that an `UpwardEnumerable α` instance is compatible with a `Least? α`
|
||||
instance. For nonempty `α`, it ensures that `least?` has a value and that every other value is
|
||||
@@ -395,11 +336,6 @@ a transitive successor of it.
|
||||
-/
|
||||
class LawfulUpwardEnumerableLeast? (α : Type u) [UpwardEnumerable α] [Least? α] where
|
||||
/-- For nonempty `α`, `least?` has a value and every other value is a transitive successor of it. -/
|
||||
least?_le (a : α) : ∃ init, Least?.least? = some init ∧ UpwardEnumerable.LE init a
|
||||
|
||||
theorem UpwardEnumerable.least?_le {α : Type u} [UpwardEnumerable α] [Least? α]
|
||||
[LawfulUpwardEnumerableLeast? α] {a : α} :
|
||||
∃ init, least? = some init ∧ UpwardEnumerable.LE init a :=
|
||||
LawfulUpwardEnumerableLeast?.least?_le a
|
||||
eq_succMany?_least? (a : α) : ∃ init, Least?.least? = some init ∧ UpwardEnumerable.LE init a
|
||||
|
||||
end Std.PRange
|
||||
|
||||
@@ -150,9 +150,6 @@ instance : LE Rat := ⟨fun a b => b.blt a = false⟩
|
||||
instance (a b : Rat) : Decidable (a ≤ b) :=
|
||||
inferInstanceAs (Decidable (_ = false))
|
||||
|
||||
instance : Min Rat := minOfLe
|
||||
instance : Max Rat := maxOfLe
|
||||
|
||||
/-- Multiplication of rational numbers. (This definition is `@[irreducible]` because you don't
|
||||
want to unfold it. Use `Rat.mul_def` instead.) -/
|
||||
@[irreducible] protected def mul (a b : Rat) : Rat :=
|
||||
|
||||
@@ -7,7 +7,6 @@ module
|
||||
prelude
|
||||
|
||||
public import Init.Data.Rat.Basic
|
||||
public import Init.Data.Int.Gcd
|
||||
import Init.Data.Int.Bitwise.Lemmas
|
||||
|
||||
@[expose] public section
|
||||
@@ -42,14 +41,6 @@ theorem normalize_eq {num den} (den_nz) : normalize num den den_nz =
|
||||
reduced := normalize.reduced den_nz rfl } := by
|
||||
simp only [normalize, maybeNormalize_eq, Int.divExact_eq_ediv]
|
||||
|
||||
@[simp]
|
||||
theorem num_normalize {num den} (den_nz) : (normalize num den den_nz).num = num / num.natAbs.gcd den := by
|
||||
simp [normalize_eq]
|
||||
|
||||
@[simp]
|
||||
theorem den_normalize {num den} (den_nz) : (normalize num den den_nz).den = den / num.natAbs.gcd den := by
|
||||
simp [normalize_eq]
|
||||
|
||||
@[simp] theorem normalize_zero (nz) : normalize 0 d nz = 0 := by
|
||||
simp [normalize, Int.natAbs_zero, Nat.div_self (Nat.pos_of_ne_zero nz)]; rfl
|
||||
|
||||
@@ -120,14 +111,6 @@ theorem mkRat_num_den (z : d ≠ 0) (h : mkRat n d = ⟨n', d', z', c⟩) :
|
||||
|
||||
theorem mkRat_def (n d) : mkRat n d = if d0 : d = 0 then 0 else normalize n d d0 := rfl
|
||||
|
||||
theorem num_mkRat (n d) : (mkRat n d).num = if d = 0 then 0 else n / d.gcd n.natAbs := by
|
||||
rw [mkRat_def]
|
||||
split <;> simp [Nat.gcd_comm]
|
||||
|
||||
theorem den_mkRat (n d) : (mkRat n d).den = if d = 0 then 1 else d / d.gcd n.natAbs := by
|
||||
rw [mkRat_def]
|
||||
split <;> simp [Nat.gcd_comm]
|
||||
|
||||
@[simp]
|
||||
theorem mkRat_self (a : Rat) : mkRat a.num a.den = a := by
|
||||
rw [← normalize_eq_mkRat a.den_nz, normalize_self]
|
||||
@@ -216,27 +199,6 @@ theorem divInt_num_den (z : d ≠ 0) (h : n /. d = ⟨n', d', z', c⟩) :
|
||||
rw [← Int.neg_inj, Int.neg_neg] at h₂
|
||||
simp [Int.natCast_mul, h₁, h₂, Int.mul_neg, Int.neg_eq_zero]
|
||||
|
||||
theorem num_divInt (a b : Int) : (a /. b).num = b.sign * a / b.gcd a := by
|
||||
rw [divInt.eq_def]
|
||||
simp only [inline, Nat.succ_eq_add_one]
|
||||
split <;> rename_i d
|
||||
· simp only [num_mkRat, Int.ofNat_eq_coe]
|
||||
split <;> rename_i h
|
||||
· simp_all
|
||||
· rw [Int.sign_natCast_of_ne_zero h, Int.one_mul, Int.gcd]
|
||||
simp
|
||||
· simp [Int.gcd, Nat.gcd_comm]
|
||||
|
||||
theorem den_divInt (a b : Int) : (a /. b).den = if b = 0 then 1 else b.natAbs / b.gcd a := by
|
||||
rw [divInt.eq_def]
|
||||
simp only [inline, Nat.succ_eq_add_one]
|
||||
split <;> rename_i d
|
||||
· simp only [den_mkRat, Int.ofNat_eq_coe, Int.natAbs_cast]
|
||||
split <;> rename_i h
|
||||
· simp_all
|
||||
· simp [if_neg (by omega), Int.gcd]
|
||||
· simp [Int.gcd, Nat.gcd_comm]
|
||||
|
||||
/-- Define a (dependent) function or prove `∀ r : Rat, p r` by dealing with rational
|
||||
numbers of the form `n /. d` with `0 < d` and coprime `n`, `d`. -/
|
||||
@[elab_as_elim]
|
||||
@@ -263,11 +225,8 @@ def numDenCasesOn''.{u} {C : Rat → Sort u} (a : Rat)
|
||||
@[simp] theorem ofInt_num : (ofInt n : Rat).num = n := rfl
|
||||
@[simp] theorem ofInt_den : (ofInt n : Rat).den = 1 := rfl
|
||||
|
||||
@[simp] theorem num_ofNat : (no_index (OfNat.ofNat n : Rat)).num = OfNat.ofNat n := rfl
|
||||
@[simp] theorem den_ofNat : (no_index (OfNat.ofNat n : Rat)).den = 1 := rfl
|
||||
|
||||
@[simp] theorem num_natCast (n : Nat) : (n : Rat).num = n := rfl
|
||||
@[simp] theorem den_natCast (n : Nat) : (n : Rat).den = 1 := rfl
|
||||
@[simp] theorem num_ofNat : (OfNat.ofNat n : Rat).num = OfNat.ofNat n := rfl
|
||||
@[simp] theorem den_ofNat : (OfNat.ofNat n : Rat).den = 1 := rfl
|
||||
|
||||
@[deprecated num_ofNat (since := "2025-08-22")]
|
||||
abbrev ofNat_num := @num_ofNat
|
||||
@@ -467,22 +426,6 @@ theorem inv_def (a : Rat) : a⁻¹ = (a.den : Int) /. a.num := by
|
||||
apply (num_divInt_den _).symm.trans
|
||||
simp [Int.le_antisymm (Int.not_lt.1 h₂) (Int.not_lt.1 h₁)]
|
||||
|
||||
@[simp] theorem num_inv (a : Rat) : (a⁻¹).num = a.num.sign * a.den := by
|
||||
simp only [inv_def]
|
||||
rw [num_divInt]
|
||||
have := a.reduced
|
||||
dsimp [Nat.Coprime] at this
|
||||
simp [Int.gcd, this]
|
||||
|
||||
@[simp] theorem den_inv (a : Rat) : (a⁻¹).den = if a.num = 0 then 1 else a.num.natAbs := by
|
||||
simp only [inv_def]
|
||||
rw [den_divInt]
|
||||
split
|
||||
· rfl
|
||||
· have := a.reduced
|
||||
dsimp [Nat.Coprime] at this
|
||||
simp [Int.gcd, this]
|
||||
|
||||
@[simp] protected theorem inv_zero : (0 : Rat)⁻¹ = 0 := by
|
||||
change Rat.inv 0 = 0; unfold Rat.inv; rfl
|
||||
|
||||
@@ -545,9 +488,6 @@ theorem pow_def (q : Rat) (n : Nat) :
|
||||
q ^ n = ⟨q.num ^ n, q.den ^ n, by simp [q.den_nz],
|
||||
by rw [Int.natAbs_pow]; exact q.reduced.pow _ _⟩ := rfl
|
||||
|
||||
@[simp] theorem num_pow (q : Rat) (n : Nat) : (q ^ n).num = q.num ^ n := rfl
|
||||
@[simp] theorem den_pow (q : Rat) (n : Nat) : (q ^ n).den = q.den ^ n := rfl
|
||||
|
||||
@[simp] protected theorem pow_zero (q : Rat) : q ^ 0 = 1 := rfl
|
||||
|
||||
protected theorem pow_succ (q : Rat) (n : Nat) : q ^ (n + 1) = q ^ n * q := by
|
||||
@@ -760,17 +700,6 @@ protected theorem mul_pos {a b : Rat} (ha : 0 < a) (hb : 0 < b) : 0 < a * b := b
|
||||
refine Rat.lt_of_le_of_ne (Rat.mul_nonneg (Rat.le_of_lt ha) (Rat.le_of_lt hb)) ?_
|
||||
simp [eq_comm, Rat.mul_eq_zero, Rat.ne_of_gt ha, Rat.ne_of_gt hb]
|
||||
|
||||
protected theorem mul_le_mul_of_nonneg_left {a b c : Rat} (ha : a ≤ b) (hc : 0 ≤ c) :
|
||||
c * a ≤ c * b := by
|
||||
rw [Rat.le_iff_sub_nonneg, Rat.sub_eq_add_neg] at ha ⊢
|
||||
rw [← Rat.mul_neg, ← Rat.mul_add]
|
||||
exact Rat.mul_nonneg hc ha
|
||||
|
||||
protected theorem mul_le_mul_of_nonneg_right {a b c : Rat} (ha : a ≤ b) (hc : 0 ≤ c) :
|
||||
a * c ≤ b * c := by
|
||||
rw [Rat.mul_comm _ c, Rat.mul_comm _ c]
|
||||
exact Rat.mul_le_mul_of_nonneg_left ha hc
|
||||
|
||||
protected theorem mul_lt_mul_of_pos_left {a b c : Rat} (ha : a < b) (hc : 0 < c) :
|
||||
c * a < c * b := by
|
||||
rw [Rat.lt_iff_sub_pos, Rat.sub_eq_add_neg] at ha ⊢
|
||||
@@ -1006,63 +935,3 @@ theorem intCast_nonpos {a : Int} :
|
||||
theorem intCast_neg_iff {a : Int} :
|
||||
(a : Rat) < 0 ↔ a < 0 :=
|
||||
Rat.intCast_lt_intCast
|
||||
|
||||
theorem floor_def (a : Rat) : a.floor = a.num / a.den := by
|
||||
rw [Rat.floor]
|
||||
split <;> simp_all
|
||||
|
||||
@[simp]
|
||||
theorem floor_intCast (a : Int) : (a : Rat).floor = a := by
|
||||
simp [floor_def]
|
||||
|
||||
theorem floor_monotone {a b : Rat} (h : a ≤ b) : a.floor ≤ b.floor := by
|
||||
rw [floor_def, floor_def]
|
||||
rw [Rat.le_iff] at h
|
||||
rw [Int.ediv_le_iff_le_mul (by have := a.den_nz; omega),
|
||||
← Int.mul_lt_mul_right (a := b.den) (by have := b.den_nz; omega)]
|
||||
apply Int.lt_of_le_of_lt h
|
||||
conv =>
|
||||
rhs; congr; congr; rfl
|
||||
rw [← Int.one_mul a.den]
|
||||
rw [← Int.add_mul, Int.mul_right_comm,
|
||||
Int.mul_lt_mul_right (a := a.den) (by have := a.den_nz; omega),
|
||||
Int.add_mul, Int.one_mul, ← Int.sub_lt_iff]
|
||||
exact Int.lt_ediv_mul b.num (b := b.den) (by have := b.den_nz; omega)
|
||||
|
||||
theorem floor_le (a : Rat) : (a.floor : Rat) ≤ a := by
|
||||
rw [floor_def, Rat.le_iff, num_intCast, den_intCast, Int.cast_ofNat_Int, Int.mul_one]
|
||||
apply Int.ediv_mul_le _ (by simpa using a.den_nz)
|
||||
|
||||
theorem lt_floor_add_one (a : Rat) : a < ((a.floor + 1 : Int): Rat) := by
|
||||
rw [floor_def, Rat.lt_iff]
|
||||
have : a.num / ↑a.den + 1 = (a.num + ↑a.den) / ↑a.den := by
|
||||
rw [Int.add_ediv_of_dvd_right] <;> simp [a.den_nz]
|
||||
simp [this]
|
||||
simpa using Int.lt_ediv_mul (a.num + a.den) (b := a.den) (by have := a.den_nz; omega)
|
||||
|
||||
theorem le_floor_iff {x : Int} {a : Rat} : x ≤ a.floor ↔ (x : Rat) ≤ a := by
|
||||
constructor
|
||||
· intro h
|
||||
rw [← intCast_le_intCast] at h
|
||||
exact Rat.le_trans h (floor_le a)
|
||||
· intro h
|
||||
simpa using floor_monotone h
|
||||
|
||||
theorem floor_lt_iff {a : Rat} {x : Int} : a.floor < x ↔ a < (x : Rat) := by
|
||||
rw [← Decidable.not_iff_not, Int.not_lt, le_floor_iff, Rat.not_lt]
|
||||
|
||||
theorem ceil_eq_neg_floor_neg (a : Rat) : a.ceil = -((-a).floor) := by
|
||||
rw [Rat.ceil, Rat.floor]
|
||||
simp only [neg_den, neg_num]
|
||||
split
|
||||
· simp
|
||||
· rw [Int.neg_ediv, if_neg, Int.sign_eq_one_of_pos, Int.neg_sub, Int.sub_neg, Int.add_comm]
|
||||
· have := a.den_nz; omega
|
||||
· intro h
|
||||
rw [Int.ofNat_dvd_left] at h
|
||||
exact Nat.not_coprime_of_dvd_of_dvd (by have := a.den_nz; omega) h (Nat.dvd_refl _) a.reduced
|
||||
|
||||
@[simp]
|
||||
theorem ceil_intCast (a : Int) : (a : Rat).ceil = a := rfl
|
||||
|
||||
-- TODO: reproduce the `floor` inequalities above for `ceil`
|
||||
|
||||
@@ -356,7 +356,7 @@ Returns the decimal string representation of an integer.
|
||||
-/
|
||||
protected def Int.repr : Int → String
|
||||
| ofNat m => Nat.repr m
|
||||
| negSucc m => String.Internal.append "-" (Nat.repr (succ m))
|
||||
| negSucc m => "-" ++ Nat.repr (succ m)
|
||||
|
||||
instance : Repr Int where
|
||||
reprPrec i prec := if i < 0 then Repr.addAppParen i.repr prec else i.repr
|
||||
@@ -370,14 +370,14 @@ def Char.quoteCore (c : Char) (inString : Bool := false) : String :=
|
||||
else if c = '\\' then "\\\\"
|
||||
else if c = '\"' then "\\\""
|
||||
else if !inString && c = '\'' then "\\\'"
|
||||
else if c.toNat <= 31 ∨ c = '\x7f' then String.Internal.append "\\x" (smallCharToHex c)
|
||||
else if c.toNat <= 31 ∨ c = '\x7f' then "\\x" ++ smallCharToHex c
|
||||
else String.singleton c
|
||||
where
|
||||
smallCharToHex (c : Char) : String :=
|
||||
let n := Char.toNat c;
|
||||
let d2 := n / 16;
|
||||
let d1 := n % 16;
|
||||
String.Internal.append (hexDigitRepr d2) (hexDigitRepr d1)
|
||||
hexDigitRepr d2 ++ hexDigitRepr d1
|
||||
|
||||
/--
|
||||
Quotes the character to its representation as a character literal, surrounded by single quotes and
|
||||
@@ -388,7 +388,7 @@ Examples:
|
||||
* `'"'.quote = "'\\\"'"`
|
||||
-/
|
||||
def Char.quote (c : Char) : String :=
|
||||
String.Internal.append (String.Internal.append "'" (Char.quoteCore c)) "'"
|
||||
"'" ++ Char.quoteCore c ++ "'"
|
||||
|
||||
instance : Repr Char where
|
||||
reprPrec c _ := c.quote
|
||||
@@ -405,8 +405,8 @@ Examples:
|
||||
* `"\"".quote = "\"\\\"\""`
|
||||
-/
|
||||
def String.quote (s : String) : String :=
|
||||
if String.Internal.isEmpty s then "\"\""
|
||||
else String.Internal.append (String.Internal.foldl (fun s c => String.Internal.append s (c.quoteCore (inString := true))) "\"" s) "\""
|
||||
if s.isEmpty then "\"\""
|
||||
else s.foldl (fun s c => s ++ c.quoteCore (inString := true)) "\"" ++ "\""
|
||||
|
||||
instance : Repr String where
|
||||
reprPrec s _ := s.quote
|
||||
@@ -415,7 +415,10 @@ instance : Repr String.Pos where
|
||||
reprPrec p _ := "{ byteIdx := " ++ repr p.byteIdx ++ " }"
|
||||
|
||||
instance : Repr Substring where
|
||||
reprPrec s _ := Format.text <| String.Internal.append (String.quote (Substring.Internal.toString s)) ".toSubstring"
|
||||
reprPrec s _ := Format.text <| String.quote s.toString ++ ".toSubstring"
|
||||
|
||||
instance : Repr String.Iterator where
|
||||
reprPrec | ⟨s, pos⟩, prec => Repr.addAppParen ("String.Iterator.mk " ++ reprArg s ++ " " ++ reprArg pos) prec
|
||||
|
||||
instance (n : Nat) : Repr (Fin n) where
|
||||
reprPrec f _ := repr f.val
|
||||
|
||||
@@ -8,7 +8,6 @@ module
|
||||
prelude
|
||||
public import Init.Data.Range
|
||||
public import Init.Data.Array.Subarray
|
||||
public import Init.Data.String.Basic
|
||||
|
||||
import Init.Data.Slice.Array.Basic
|
||||
|
||||
|
||||
@@ -7,10 +7,7 @@ module
|
||||
|
||||
prelude
|
||||
public import Init.Data.String.Basic
|
||||
public import Init.Data.String.Bootstrap
|
||||
public import Init.Data.String.Extra
|
||||
public import Init.Data.String.Lemmas
|
||||
public import Init.Data.String.Repr
|
||||
public import Init.Data.String.Bootstrap
|
||||
|
||||
public section
|
||||
|
||||
@@ -8,12 +8,22 @@ module
|
||||
prelude
|
||||
public import Init.Data.List.Basic
|
||||
public import Init.Data.Char.Basic
|
||||
public import Init.Data.String.Bootstrap
|
||||
|
||||
public section
|
||||
|
||||
universe u
|
||||
|
||||
/--
|
||||
Creates a string that contains the characters in a list, in order.
|
||||
|
||||
Examples:
|
||||
* `['L', '∃', '∀', 'N'].asString = "L∃∀N"`
|
||||
* `[].asString = ""`
|
||||
* `['a', 'a', 'a'].asString = "aaa"`
|
||||
-/
|
||||
def List.asString (s : List Char) : String :=
|
||||
⟨s⟩
|
||||
|
||||
namespace String
|
||||
|
||||
instance : HAdd String.Pos String.Pos String.Pos where
|
||||
@@ -22,10 +32,6 @@ instance : HAdd String.Pos String.Pos String.Pos where
|
||||
instance : HSub String.Pos String.Pos String.Pos where
|
||||
hSub p₁ p₂ := { byteIdx := p₁.byteIdx - p₂.byteIdx }
|
||||
|
||||
@[export lean_string_pos_sub]
|
||||
def Pos.Internal.subImpl : String.Pos → String.Pos → String.Pos :=
|
||||
(· - ·)
|
||||
|
||||
instance : HAdd String.Pos Char String.Pos where
|
||||
hAdd p c := { byteIdx := p.byteIdx + c.utf8Size }
|
||||
|
||||
@@ -47,6 +53,9 @@ instance (p₁ p₂ : String.Pos) : Decidable (LT.lt p₁ p₂) :=
|
||||
instance : Min String.Pos := minOfLe
|
||||
instance : Max String.Pos := maxOfLe
|
||||
|
||||
instance : OfNat String.Pos (nat_lit 0) where
|
||||
ofNat := {}
|
||||
|
||||
instance : LT String :=
|
||||
⟨fun s₁ s₂ => s₁.data < s₂.data⟩
|
||||
|
||||
@@ -81,6 +90,20 @@ Examples:
|
||||
def length : (@& String) → Nat
|
||||
| ⟨s⟩ => s.length
|
||||
|
||||
/--
|
||||
Adds a character to the end of a string.
|
||||
|
||||
The internal implementation uses dynamic arrays and will perform destructive updates
|
||||
if the string is not shared.
|
||||
|
||||
Examples:
|
||||
* `"abc".push 'd' = "abcd"`
|
||||
* `"".push 'a' = "a"`
|
||||
-/
|
||||
@[extern "lean_string_push", expose]
|
||||
def push : String → Char → String
|
||||
| ⟨s⟩, c => ⟨s ++ [c]⟩
|
||||
|
||||
/--
|
||||
Appends two strings. Usually accessed via the `++` operator.
|
||||
|
||||
@@ -282,10 +305,6 @@ Examples:
|
||||
@[inline] def front (s : String) : Char :=
|
||||
get s 0
|
||||
|
||||
@[export lean_string_front]
|
||||
def Internal.frontImpl (s : String) : Char :=
|
||||
String.front s
|
||||
|
||||
/--
|
||||
Returns the last character in `s`. If `s = ""`, returns `(default : Char)`.
|
||||
|
||||
@@ -366,10 +385,6 @@ theorem _root_.Char.utf8Size_pos (c : Char) : 0 < c.utf8Size := by
|
||||
theorem _root_.Char.utf8Size_le_four (c : Char) : c.utf8Size ≤ 4 := by
|
||||
repeat first | apply iteInduction (motive := (· ≤ 4)) <;> intros | decide
|
||||
|
||||
theorem _root_.Char.utf8Size_eq (c : Char) : c.utf8Size = 1 ∨ c.utf8Size = 2 ∨ c.utf8Size = 3 ∨ c.utf8Size = 4 := by
|
||||
match c.utf8Size, c.utf8Size_pos, c.utf8Size_le_four with
|
||||
| 1, _, _ | 2, _, _ | 3, _, _ | 4, _, _ => simp
|
||||
|
||||
@[deprecated Char.utf8Size_pos (since := "2026-06-04")] abbrev one_le_csize := Char.utf8Size_pos
|
||||
|
||||
@[simp] theorem pos_lt_eq (p₁ p₂ : Pos) : (p₁ < p₂) = (p₁.1 < p₂.1) := rfl
|
||||
@@ -415,10 +430,6 @@ Examples:
|
||||
@[inline] def posOf (s : String) (c : Char) : Pos :=
|
||||
posOfAux s c s.endPos 0
|
||||
|
||||
@[export lean_string_posof]
|
||||
def Internal.posOfImpl (s : String) (c : Char) : Pos :=
|
||||
String.posOf s c
|
||||
|
||||
def revPosOfAux (s : String) (c : Char) (pos : Pos) : Option Pos :=
|
||||
if h : pos = 0 then none
|
||||
else
|
||||
@@ -489,10 +500,6 @@ Returns either `p₁` or `p₂`, whichever has the least byte index.
|
||||
abbrev Pos.min (p₁ p₂ : Pos) : Pos :=
|
||||
{ byteIdx := p₁.byteIdx.min p₂.byteIdx }
|
||||
|
||||
@[export lean_string_pos_min]
|
||||
def Pos.Internal.minImpl (p₁ p₂ : Pos) : Pos :=
|
||||
Pos.min p₁ p₂
|
||||
|
||||
/--
|
||||
Returns the first position where the two strings differ.
|
||||
|
||||
@@ -653,10 +660,6 @@ Examples:
|
||||
@[inline] def pushn (s : String) (c : Char) (n : Nat) : String :=
|
||||
n.repeat (fun s => s.push c) s
|
||||
|
||||
@[export lean_string_pushn]
|
||||
def Internal.pushnImpl (s : String) (c : Char) (n : Nat) : String :=
|
||||
String.pushn s c n
|
||||
|
||||
/--
|
||||
Checks whether a string is empty.
|
||||
|
||||
@@ -670,10 +673,6 @@ Examples:
|
||||
@[inline] def isEmpty (s : String) : Bool :=
|
||||
s.endPos == 0
|
||||
|
||||
@[export lean_string_isempty]
|
||||
def Internal.isEmptyImpl (s : String) : Bool :=
|
||||
String.isEmpty s
|
||||
|
||||
/--
|
||||
Appends all the strings in a list of strings, in order.
|
||||
|
||||
@@ -687,6 +686,20 @@ Examples:
|
||||
@[inline] def join (l : List String) : String :=
|
||||
l.foldl (fun r s => r ++ s) ""
|
||||
|
||||
/--
|
||||
Returns a new string that contains only the character `c`.
|
||||
|
||||
Because strings are encoded in UTF-8, the resulting string may take multiple bytes.
|
||||
|
||||
Examples:
|
||||
* `String.singleton 'L' = "L"`
|
||||
* `String.singleton ' ' = " "`
|
||||
* `String.singleton '"' = "\""`
|
||||
* `String.singleton '𝒫' = "𝒫"`
|
||||
-/
|
||||
@[inline,expose] def singleton (c : Char) : String :=
|
||||
"".push c
|
||||
|
||||
/--
|
||||
Appends the strings in a list of strings, placing the separator `s` between each pair.
|
||||
|
||||
@@ -702,10 +715,6 @@ where go (acc : String) (s : String) : List String → String
|
||||
| a :: as => go (acc ++ s ++ a) s as
|
||||
| [] => acc
|
||||
|
||||
@[export lean_string_intercalate]
|
||||
def Internal.intercalateImpl (s : String) : List String → String :=
|
||||
String.intercalate s
|
||||
|
||||
/--
|
||||
An iterator over the characters (Unicode code points) in a `String`. Typically created by
|
||||
`String.iter`.
|
||||
@@ -917,10 +926,6 @@ Examples:
|
||||
@[inline] def offsetOfPos (s : String) (pos : Pos) : Nat :=
|
||||
offsetOfPosAux s pos 0 0
|
||||
|
||||
@[export lean_string_offsetofpos]
|
||||
def Internal.offsetOfPosImpl (s : String) (pos : Pos) : Nat :=
|
||||
String.offsetOfPos s pos
|
||||
|
||||
@[specialize] def foldlAux {α : Type u} (f : α → Char → α) (s : String) (stopPos : Pos) (i : Pos) (a : α) : α :=
|
||||
if h : i < stopPos then
|
||||
have := Nat.sub_lt_sub_left h (lt_next s i)
|
||||
@@ -940,10 +945,6 @@ Examples:
|
||||
@[inline] def foldl {α : Type u} (f : α → Char → α) (init : α) (s : String) : α :=
|
||||
foldlAux f s s.endPos 0 init
|
||||
|
||||
@[export lean_string_foldl]
|
||||
def Internal.foldlImpl (f : String → Char → String) (init : String) (s : String) : String :=
|
||||
String.foldl f init s
|
||||
|
||||
@[specialize] def foldrAux {α : Type u} (f : Char → α → α) (a : α) (s : String) (i begPos : Pos) : α :=
|
||||
if h : begPos < i then
|
||||
have := String.prev_lt_of_pos s i <| mt (congrArg String.Pos.byteIdx) <|
|
||||
@@ -989,10 +990,6 @@ Examples:
|
||||
@[inline] def any (s : String) (p : Char → Bool) : Bool :=
|
||||
anyAux s s.endPos p 0
|
||||
|
||||
@[export lean_string_any]
|
||||
def Internal.anyImpl (s : String) (p : Char → Bool) :=
|
||||
String.any s p
|
||||
|
||||
/--
|
||||
Checks whether the Boolean predicate `p` returns `true` for every character in a string.
|
||||
|
||||
@@ -1015,11 +1012,7 @@ Examples:
|
||||
* `"".contains 'x' = false`
|
||||
-/
|
||||
@[inline] def contains (s : String) (c : Char) : Bool :=
|
||||
s.any (fun a => a == c)
|
||||
|
||||
@[export lean_string_contains]
|
||||
def Internal.containsImpl (s : String) (c : Char) : Bool :=
|
||||
String.contains s c
|
||||
s.any (fun a => a == c)
|
||||
|
||||
theorem utf8SetAux_of_gt (c' : Char) : ∀ (cs : List Char) {i p : Pos}, i > p → utf8SetAux c' cs i p = cs
|
||||
| [], _, _, _ => rfl
|
||||
@@ -1162,10 +1155,6 @@ Examples:
|
||||
def isPrefixOf (p : String) (s : String) : Bool :=
|
||||
substrEq p 0 s 0 p.endPos.byteIdx
|
||||
|
||||
@[export lean_string_isprefixof]
|
||||
def Internal.isPrefixOfImpl (p : String) (s : String) : Bool :=
|
||||
String.isPrefixOf p s
|
||||
|
||||
/--
|
||||
In the string `s`, replaces all occurrences of `pattern` with `replacement`.
|
||||
|
||||
@@ -1215,20 +1204,12 @@ A substring is empty if its start and end positions are the same.
|
||||
@[inline] def isEmpty (ss : Substring) : Bool :=
|
||||
ss.bsize == 0
|
||||
|
||||
@[export lean_substring_isempty]
|
||||
def Internal.isEmptyImpl (ss : Substring) : Bool :=
|
||||
Substring.isEmpty ss
|
||||
|
||||
/--
|
||||
Copies the region of the underlying string pointed to by a substring into a fresh string.
|
||||
-/
|
||||
@[inline] def toString : Substring → String
|
||||
| ⟨s, b, e⟩ => s.extract b e
|
||||
|
||||
@[export lean_substring_tostring]
|
||||
def Internal.toStringImpl : Substring → String :=
|
||||
Substring.toString
|
||||
|
||||
/--
|
||||
Returns an iterator into the underlying string, at the substring's starting position. The ending
|
||||
position is discarded, so the iterator alone cannot be used to determine whether its current
|
||||
@@ -1248,10 +1229,6 @@ returned. Does not panic.
|
||||
@[inline] def get : Substring → String.Pos → Char
|
||||
| ⟨s, b, _⟩, p => s.get (b+p)
|
||||
|
||||
@[export lean_substring_get]
|
||||
def Internal.getImpl : Substring → String.Pos → Char :=
|
||||
Substring.get
|
||||
|
||||
/--
|
||||
Returns the next position in a substring after the given position. If the position is at the end of
|
||||
the substring, it is returned unmodified.
|
||||
@@ -1285,10 +1262,6 @@ position, not the underlying string.
|
||||
let absP := b+p
|
||||
if absP = b then p else { byteIdx := (s.prev absP).byteIdx - b.byteIdx }
|
||||
|
||||
@[export lean_substring_prev]
|
||||
def Internal.prevImpl : Substring → String.Pos → String.Pos :=
|
||||
Substring.prev
|
||||
|
||||
/--
|
||||
Returns the position that's the specified number of characters forward from the given position in a
|
||||
substring. If the end position of the substring is reached, it is returned.
|
||||
@@ -1322,10 +1295,6 @@ returned. Does not panic.
|
||||
@[inline] def front (s : Substring) : Char :=
|
||||
s.get 0
|
||||
|
||||
@[export lean_substring_front]
|
||||
def Internal.frontImpl : Substring → Char :=
|
||||
Substring.front
|
||||
|
||||
/--
|
||||
Returns the substring-relative position of the first occurrence of `c` in `s`, or `s.bsize` if `c`
|
||||
doesn't occur.
|
||||
@@ -1343,10 +1312,6 @@ If the substring's end position is reached, the start position is not advanced p
|
||||
@[inline] def drop : Substring → Nat → Substring
|
||||
| ss@⟨s, b, e⟩, n => ⟨s, b + ss.nextn n 0, e⟩
|
||||
|
||||
@[export lean_substring_drop]
|
||||
def Internal.dropImpl : Substring → Nat → Substring :=
|
||||
Substring.drop
|
||||
|
||||
/--
|
||||
Removes the specified number of characters (Unicode code points) from the end of a substring
|
||||
by moving its end position towards its start position.
|
||||
@@ -1395,10 +1360,6 @@ positions adjusted.
|
||||
@[inline] def extract : Substring → String.Pos → String.Pos → Substring
|
||||
| ⟨s, b, e⟩, b', e' => if b' ≥ e' then ⟨"", 0, 0⟩ else ⟨s, e.min (b+b'), e.min (b+e')⟩
|
||||
|
||||
@[export lean_substring_extract]
|
||||
def Internal.extractImpl : Substring → String.Pos → String.Pos → Substring :=
|
||||
Substring.extract
|
||||
|
||||
/--
|
||||
Splits a substring `s` on occurrences of the separator string `sep`. The default separator is `" "`.
|
||||
|
||||
@@ -1465,10 +1426,6 @@ Short-circuits at the first character for which `p` returns `false`.
|
||||
@[inline] def all (s : Substring) (p : Char → Bool) : Bool :=
|
||||
!s.any (fun c => !p c)
|
||||
|
||||
@[export lean_substring_all]
|
||||
def Internal.allImpl (s : Substring) (p : Char → Bool) : Bool :=
|
||||
Substring.all s p
|
||||
|
||||
/--
|
||||
Checks whether a substring contains the specified character.
|
||||
-/
|
||||
@@ -1493,10 +1450,6 @@ characters by moving the substring's end position towards its start position.
|
||||
let e := takeWhileAux s e p b;
|
||||
⟨s, b, e⟩
|
||||
|
||||
@[export lean_substring_takewhile]
|
||||
def Internal.takeWhileImpl : Substring → (Char → Bool) → Substring :=
|
||||
Substring.takeWhile
|
||||
|
||||
/--
|
||||
Removes the longest prefix of a substring in which a Boolean predicate returns `true` for all
|
||||
characters by moving the substring's start position. The start position is moved to the position of
|
||||
@@ -1614,10 +1567,6 @@ instead, they are equal if they contain the same sequence of characters.
|
||||
def beq (ss1 ss2 : Substring) : Bool :=
|
||||
ss1.bsize == ss2.bsize && ss1.str.substrEq ss1.startPos ss2.str ss2.startPos ss1.bsize
|
||||
|
||||
@[export lean_substring_beq]
|
||||
def Internal.beqImpl (ss1 ss2 : Substring) : Bool :=
|
||||
Substring.beq ss1 ss2
|
||||
|
||||
instance hasBeq : BEq Substring := ⟨beq⟩
|
||||
|
||||
/--
|
||||
@@ -1715,10 +1664,6 @@ Examples:
|
||||
@[inline] def drop (s : String) (n : Nat) : String :=
|
||||
(s.toSubstring.drop n).toString
|
||||
|
||||
@[export lean_string_drop]
|
||||
def Internal.dropImpl (s : String) (n : Nat) : String :=
|
||||
String.drop s n
|
||||
|
||||
/--
|
||||
Removes the specified number of characters (Unicode code points) from the end of the string.
|
||||
|
||||
@@ -1732,10 +1677,6 @@ Examples:
|
||||
@[inline] def dropRight (s : String) (n : Nat) : String :=
|
||||
(s.toSubstring.dropRight n).toString
|
||||
|
||||
@[export lean_string_dropright]
|
||||
def Internal.dropRightImpl (s : String) (n : Nat) : String :=
|
||||
String.dropRight s n
|
||||
|
||||
/--
|
||||
Creates a new string that contains the first `n` characters (Unicode code points) of `s`.
|
||||
|
||||
@@ -1887,10 +1828,6 @@ Examples:
|
||||
@[inline] def trim (s : String) : String :=
|
||||
s.toSubstring.trim.toString
|
||||
|
||||
@[export lean_string_trim]
|
||||
def Internal.trimImpl (s : String) : String :=
|
||||
String.trim s
|
||||
|
||||
/--
|
||||
Repeatedly increments a position in a string, as if by `String.next`, while the predicate `p`
|
||||
returns `true` for the character at the position. Stops incrementing at the end of the string or
|
||||
@@ -1904,10 +1841,6 @@ Examples:
|
||||
@[inline] def nextWhile (s : String) (p : Char → Bool) (i : String.Pos) : String.Pos :=
|
||||
Substring.takeWhileAux s s.endPos p i
|
||||
|
||||
@[export lean_string_nextwhile]
|
||||
def Internal.nextWhileImpl (s : String) (p : Char → Bool) (i : String.Pos) : String.Pos :=
|
||||
String.nextWhile s p i
|
||||
|
||||
/--
|
||||
Repeatedly increments a position in a string, as if by `String.next`, while the predicate `p`
|
||||
returns `false` for the character at the position. Stops incrementing at the end of the string or
|
||||
@@ -1957,13 +1890,9 @@ Examples:
|
||||
* `"ORANGE".capitalize = "ORANGE"`
|
||||
* `"".capitalize = ""`
|
||||
-/
|
||||
@[inline] def capitalize (s : String) : String :=
|
||||
@[inline] def capitalize (s : String) :=
|
||||
s.set 0 <| s.get 0 |>.toUpper
|
||||
|
||||
@[export lean_string_capitalize]
|
||||
def Internal.capitalizeImpl (s : String) : String :=
|
||||
String.capitalize s
|
||||
|
||||
/--
|
||||
Replaces the first character in `s` with the result of applying `Char.toLower` to it. Returns the
|
||||
empty string if the string is empty.
|
||||
@@ -2046,6 +1975,16 @@ end String
|
||||
|
||||
namespace Char
|
||||
|
||||
/--
|
||||
Constructs a singleton string that contains only the provided character.
|
||||
|
||||
Examples:
|
||||
* `'L'.toString = "L"`
|
||||
* `'"'.toString = "\""`
|
||||
-/
|
||||
@[inline, expose] protected def toString (c : Char) : String :=
|
||||
String.singleton c
|
||||
|
||||
@[simp] theorem length_toString (c : Char) : c.toString.length = 1 := rfl
|
||||
|
||||
end Char
|
||||
|
||||
@@ -1,186 +0,0 @@
|
||||
/-
|
||||
Copyright (c) 2016 Microsoft Corporation. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Author: Leonardo de Moura, Mario Carneiro
|
||||
-/
|
||||
module
|
||||
|
||||
prelude
|
||||
public import Init.Data.List.Basic
|
||||
public import Init.Data.Char.Basic
|
||||
|
||||
public section
|
||||
|
||||
namespace String
|
||||
|
||||
instance : OfNat String.Pos (nat_lit 0) where
|
||||
ofNat := {}
|
||||
|
||||
instance : Inhabited String where
|
||||
default := ""
|
||||
|
||||
/--
|
||||
Adds a character to the end of a string.
|
||||
|
||||
The internal implementation uses dynamic arrays and will perform destructive updates
|
||||
if the string is not shared.
|
||||
|
||||
Examples:
|
||||
* `"abc".push 'd' = "abcd"`
|
||||
* `"".push 'a' = "a"`
|
||||
-/
|
||||
@[extern "lean_string_push", expose]
|
||||
def push : String → Char → String
|
||||
| ⟨s⟩, c => ⟨s ++ [c]⟩
|
||||
|
||||
/--
|
||||
Returns a new string that contains only the character `c`.
|
||||
|
||||
Because strings are encoded in UTF-8, the resulting string may take multiple bytes.
|
||||
|
||||
Examples:
|
||||
* `String.singleton 'L' = "L"`
|
||||
* `String.singleton ' ' = " "`
|
||||
* `String.singleton '"' = "\""`
|
||||
* `String.singleton '𝒫' = "𝒫"`
|
||||
-/
|
||||
@[inline, expose] def singleton (c : Char) : String :=
|
||||
"".push c
|
||||
|
||||
end String
|
||||
|
||||
namespace String.Internal
|
||||
|
||||
@[extern "lean_string_posof"]
|
||||
opaque posOf (s : String) (c : Char) : Pos
|
||||
|
||||
@[extern "lean_string_offsetofpos"]
|
||||
opaque offsetOfPos (s : String) (pos : Pos) : Nat
|
||||
|
||||
@[extern "lean_string_utf8_extract"]
|
||||
opaque extract : (@& String) → (@& Pos) → (@& Pos) → String
|
||||
|
||||
@[extern "lean_string_length"]
|
||||
opaque length : (@& String) → Nat
|
||||
|
||||
@[extern "lean_string_pushn"]
|
||||
opaque pushn (s : String) (c : Char) (n : Nat) : String
|
||||
|
||||
@[extern "lean_string_append"]
|
||||
opaque append : String → (@& String) → String
|
||||
|
||||
@[extern "lean_string_utf8_next"]
|
||||
opaque next (s : @& String) (p : @& Pos) : Pos
|
||||
|
||||
@[extern "lean_string_isempty"]
|
||||
opaque isEmpty (s : String) : Bool
|
||||
|
||||
@[extern "lean_string_foldl"]
|
||||
opaque foldl (f : String → Char → String) (init : String) (s : String) : String
|
||||
|
||||
@[extern "lean_string_isprefixof"]
|
||||
opaque isPrefixOf (p : String) (s : String) : Bool
|
||||
|
||||
@[extern "lean_string_any"]
|
||||
opaque any (s : String) (p : Char → Bool) : Bool
|
||||
|
||||
@[extern "lean_string_contains"]
|
||||
opaque contains (s : String) (c : Char) : Bool
|
||||
|
||||
@[extern "lean_string_utf8_get"]
|
||||
opaque get (s : @& String) (p : @& Pos) : Char
|
||||
|
||||
@[extern "lean_string_capitalize"]
|
||||
opaque capitalize (s : String) : String
|
||||
|
||||
@[extern "lean_string_utf8_at_end"]
|
||||
opaque atEnd : (@& String) → (@& Pos) → Bool
|
||||
|
||||
@[extern "lean_string_nextwhile"]
|
||||
opaque nextWhile (s : String) (p : Char → Bool) (i : String.Pos) : String.Pos
|
||||
|
||||
@[extern "lean_string_trim"]
|
||||
opaque trim (s : String) : String
|
||||
|
||||
@[extern "lean_string_intercalate"]
|
||||
opaque intercalate (s : String) : List String → String
|
||||
|
||||
@[extern "lean_string_front"]
|
||||
opaque front (s : String) : Char
|
||||
|
||||
@[extern "lean_string_drop"]
|
||||
opaque drop (s : String) (n : Nat) : String
|
||||
|
||||
@[extern "lean_string_dropright"]
|
||||
opaque dropRight (s : String) (n : Nat) : String
|
||||
|
||||
end String.Internal
|
||||
|
||||
/--
|
||||
Creates a string that contains the characters in a list, in order.
|
||||
|
||||
Examples:
|
||||
* `['L', '∃', '∀', 'N'].asString = "L∃∀N"`
|
||||
* `[].asString = ""`
|
||||
* `['a', 'a', 'a'].asString = "aaa"`
|
||||
-/
|
||||
def List.asString (s : List Char) : String :=
|
||||
⟨s⟩
|
||||
|
||||
namespace Substring.Internal
|
||||
|
||||
@[extern "lean_substring_tostring"]
|
||||
opaque toString : Substring → String
|
||||
|
||||
@[extern "lean_substring_drop"]
|
||||
opaque drop : Substring → Nat → Substring
|
||||
|
||||
@[extern "lean_substring_front"]
|
||||
opaque front (s : Substring) : Char
|
||||
|
||||
@[extern "lean_substring_takewhile"]
|
||||
opaque takeWhile : Substring → (Char → Bool) → Substring
|
||||
|
||||
@[extern "lean_substring_extract"]
|
||||
opaque extract : Substring → String.Pos → String.Pos → Substring
|
||||
|
||||
@[extern "lean_substring_all"]
|
||||
opaque all (s : Substring) (p : Char → Bool) : Bool
|
||||
|
||||
@[extern "lean_substring_beq"]
|
||||
opaque beq (ss1 ss2 : Substring) : Bool
|
||||
|
||||
@[extern "lean_substring_isempty"]
|
||||
opaque isEmpty (ss : Substring) : Bool
|
||||
|
||||
@[extern "lean_substring_get"]
|
||||
opaque get : Substring → String.Pos → Char
|
||||
|
||||
@[extern "lean_substring_prev"]
|
||||
opaque prev : Substring → String.Pos → String.Pos
|
||||
|
||||
end Substring.Internal
|
||||
|
||||
namespace String.Pos.Internal
|
||||
|
||||
@[extern "lean_string_pos_sub"]
|
||||
opaque sub : String.Pos → String.Pos → String.Pos
|
||||
|
||||
@[extern "lean_string_pos_min"]
|
||||
opaque min (p₁ p₂ : Pos) : Pos
|
||||
|
||||
end String.Pos.Internal
|
||||
|
||||
namespace Char
|
||||
|
||||
/--
|
||||
Constructs a singleton string that contains only the provided character.
|
||||
|
||||
Examples:
|
||||
* `'L'.toString = "L"`
|
||||
* `'"'.toString = "\""`
|
||||
-/
|
||||
@[inline, expose] protected def toString (c : Char) : String :=
|
||||
String.singleton c
|
||||
|
||||
end Char
|
||||
@@ -11,7 +11,6 @@ import all Init.Data.ByteArray.Basic
|
||||
public import Init.Data.String.Basic
|
||||
import all Init.Data.String.Basic
|
||||
import Init.Data.UInt.Lemmas
|
||||
import Init.Data.UInt.Bitwise
|
||||
|
||||
public section
|
||||
|
||||
@@ -136,7 +135,7 @@ the corresponding string, or panics if the array is not a valid UTF-8 encoding o
|
||||
/--
|
||||
Returns the sequence of bytes in a character's UTF-8 encoding.
|
||||
-/
|
||||
def utf8EncodeCharFast (c : Char) : List UInt8 :=
|
||||
def utf8EncodeChar (c : Char) : List UInt8 :=
|
||||
let v := c.val
|
||||
if v ≤ 0x7f then
|
||||
[v.toUInt8]
|
||||
@@ -153,58 +152,8 @@ def utf8EncodeCharFast (c : Char) : List UInt8 :=
|
||||
(v >>> 6).toUInt8 &&& 0x3f ||| 0x80,
|
||||
v.toUInt8 &&& 0x3f ||| 0x80]
|
||||
|
||||
private theorem Nat.add_two_pow_eq_or_of_lt {b : Nat} (i : Nat) (b_lt : b < 2 ^ i) (a : Nat) :
|
||||
b + 2 ^ i * a = b ||| 2 ^ i * a := by
|
||||
rw [Nat.add_comm, Nat.or_comm, Nat.two_pow_add_eq_or_of_lt b_lt]
|
||||
|
||||
@[csimp]
|
||||
theorem utf8EncodeChar_eq_utf8EncodeCharFast : @utf8EncodeChar = @utf8EncodeCharFast := by
|
||||
funext c
|
||||
simp only [utf8EncodeChar, utf8EncodeCharFast, UInt8.ofNat_uInt32ToNat, UInt8.ofNat_add,
|
||||
UInt8.reduceOfNat, UInt32.le_iff_toNat_le, UInt32.reduceToNat]
|
||||
split
|
||||
· rfl
|
||||
· split
|
||||
· simp only [List.cons.injEq, ← UInt8.toNat_inj, UInt8.toNat_add, UInt8.toNat_ofNat',
|
||||
Nat.reducePow, UInt8.reduceToNat, Nat.mod_add_mod, UInt8.toNat_or, UInt8.toNat_and,
|
||||
UInt32.toNat_toUInt8, UInt32.toNat_shiftRight, UInt32.reduceToNat, Nat.reduceMod, and_true]
|
||||
refine ⟨?_, ?_⟩
|
||||
· rw [Nat.mod_eq_of_lt (by omega), Nat.add_two_pow_eq_or_of_lt 5 (by omega) 6,
|
||||
Nat.and_two_pow_sub_one_eq_mod _ 5, Nat.shiftRight_eq_div_pow,
|
||||
Nat.mod_eq_of_lt (b := 256) (by omega)]
|
||||
· rw [Nat.mod_eq_of_lt (by omega), Nat.add_two_pow_eq_or_of_lt 6 (by omega) 2,
|
||||
Nat.and_two_pow_sub_one_eq_mod _ 6, Nat.mod_mod_of_dvd _ (by decide)]
|
||||
· split
|
||||
· simp only [List.cons.injEq, ← UInt8.toNat_inj, UInt8.toNat_add, UInt8.toNat_ofNat',
|
||||
Nat.reducePow, UInt8.reduceToNat, Nat.mod_add_mod, UInt8.toNat_or, UInt8.toNat_and,
|
||||
UInt32.toNat_toUInt8, UInt32.toNat_shiftRight, UInt32.reduceToNat, Nat.reduceMod, and_true]
|
||||
refine ⟨?_, ?_, ?_⟩
|
||||
· rw [Nat.mod_eq_of_lt (by omega), Nat.add_two_pow_eq_or_of_lt 4 (by omega) 14,
|
||||
Nat.and_two_pow_sub_one_eq_mod _ 4, Nat.shiftRight_eq_div_pow,
|
||||
Nat.mod_eq_of_lt (b := 256) (by omega)]
|
||||
· rw [Nat.mod_eq_of_lt (by omega), Nat.add_two_pow_eq_or_of_lt 6 (by omega) 2,
|
||||
Nat.and_two_pow_sub_one_eq_mod _ 6, Nat.shiftRight_eq_div_pow,
|
||||
Nat.mod_mod_of_dvd (c.val.toNat / 2 ^ 6) (by decide)]
|
||||
· rw [Nat.mod_eq_of_lt (by omega), Nat.add_two_pow_eq_or_of_lt 6 (by omega) 2,
|
||||
Nat.and_two_pow_sub_one_eq_mod _ 6, Nat.mod_mod_of_dvd c.val.toNat (by decide)]
|
||||
· simp only [List.cons.injEq, ← UInt8.toNat_inj, UInt8.toNat_add, UInt8.toNat_ofNat',
|
||||
Nat.reducePow, UInt8.reduceToNat, Nat.mod_add_mod, UInt8.toNat_or, UInt8.toNat_and,
|
||||
UInt32.toNat_toUInt8, UInt32.toNat_shiftRight, UInt32.reduceToNat, Nat.reduceMod, and_true]
|
||||
refine ⟨?_, ?_, ?_, ?_⟩
|
||||
· rw [Nat.mod_eq_of_lt (by omega), Nat.add_two_pow_eq_or_of_lt 3 (by omega) 30,
|
||||
Nat.and_two_pow_sub_one_eq_mod _ 3, Nat.shiftRight_eq_div_pow,
|
||||
Nat.mod_mod_of_dvd _ (by decide)]
|
||||
· rw [Nat.mod_eq_of_lt (by omega), Nat.add_two_pow_eq_or_of_lt 6 (by omega) 2,
|
||||
Nat.and_two_pow_sub_one_eq_mod _ 6, Nat.shiftRight_eq_div_pow,
|
||||
Nat.mod_mod_of_dvd (c.val.toNat / 2 ^ 12) (by decide)]
|
||||
· rw [Nat.mod_eq_of_lt (by omega), Nat.add_two_pow_eq_or_of_lt 6 (by omega) 2,
|
||||
Nat.and_two_pow_sub_one_eq_mod _ 6, Nat.shiftRight_eq_div_pow,
|
||||
Nat.mod_mod_of_dvd (c.val.toNat / 2 ^ 6) (by decide)]
|
||||
· rw [Nat.mod_eq_of_lt (by omega), Nat.add_two_pow_eq_or_of_lt 6 (by omega) 2,
|
||||
Nat.and_two_pow_sub_one_eq_mod _ 6, Nat.mod_mod_of_dvd c.val.toNat (by decide)]
|
||||
|
||||
@[simp] theorem length_utf8EncodeChar (c : Char) : (utf8EncodeChar c).length = c.utf8Size := by
|
||||
simp [Char.utf8Size, utf8EncodeChar_eq_utf8EncodeCharFast, utf8EncodeCharFast]
|
||||
simp [Char.utf8Size, utf8EncodeChar]
|
||||
cases Decidable.em (c.val ≤ 0x7f) <;> simp [*]
|
||||
cases Decidable.em (c.val ≤ 0x7ff) <;> simp [*]
|
||||
cases Decidable.em (c.val ≤ 0xffff) <;> simp [*]
|
||||
|
||||
@@ -10,7 +10,6 @@ public import Init.Data.Char.Order
|
||||
public import Init.Data.Char.Lemmas
|
||||
public import Init.Data.List.Lex
|
||||
import Init.Data.Order.Lemmas
|
||||
public import Init.Data.String.Basic
|
||||
|
||||
public section
|
||||
|
||||
|
||||
@@ -1,95 +0,0 @@
|
||||
/-
|
||||
Copyright (c) 2016 Microsoft Corporation. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Author: Leonardo de Moura, Mario Carneiro
|
||||
-/
|
||||
module
|
||||
|
||||
prelude
|
||||
public import Init.Data.String.Basic
|
||||
public import Init.Data.ToString.Basic
|
||||
|
||||
public section
|
||||
|
||||
instance : Repr String.Iterator where
|
||||
reprPrec | ⟨s, pos⟩, prec => Repr.addAppParen ("String.Iterator.mk " ++ reprArg s ++ " " ++ reprArg pos) prec
|
||||
|
||||
instance : ToString String.Iterator :=
|
||||
⟨fun it => it.remainingToString⟩
|
||||
|
||||
/--
|
||||
Interprets a string as the decimal representation of an integer, returning it. Returns `none` if
|
||||
the string does not contain a decimal integer.
|
||||
|
||||
A string can be interpreted as a decimal integer if it only consists of at least one decimal digit
|
||||
and optionally `-` in front. Leading `+` characters are not allowed.
|
||||
|
||||
Use `String.isInt` to check whether `String.toInt?` would return `some`. `String.toInt!` is an
|
||||
alternative that panics instead of returning `none` when the string is not an integer.
|
||||
|
||||
Examples:
|
||||
* `"".toInt? = none`
|
||||
* `"-".toInt? = none`
|
||||
* `"0".toInt? = some 0`
|
||||
* `"5".toInt? = some 5`
|
||||
* `"-5".toInt? = some (-5)`
|
||||
* `"587".toInt? = some 587`
|
||||
* `"-587".toInt? = some (-587)`
|
||||
* `" 5".toInt? = none`
|
||||
* `"2-3".toInt? = none`
|
||||
* `"0xff".toInt? = none`
|
||||
-/
|
||||
def String.toInt? (s : String) : Option Int := do
|
||||
if s.get 0 = '-' then do
|
||||
let v ← (s.toSubstring.drop 1).toNat?;
|
||||
pure <| - Int.ofNat v
|
||||
else
|
||||
Int.ofNat <$> s.toNat?
|
||||
|
||||
/--
|
||||
Checks whether the string can be interpreted as the decimal representation of an integer.
|
||||
|
||||
A string can be interpreted as a decimal integer if it only consists of at least one decimal digit
|
||||
and optionally `-` in front. Leading `+` characters are not allowed.
|
||||
|
||||
Use `String.toInt?` or `String.toInt!` to convert such a string to an integer.
|
||||
|
||||
Examples:
|
||||
* `"".isInt = false`
|
||||
* `"-".isInt = false`
|
||||
* `"0".isInt = true`
|
||||
* `"-0".isInt = true`
|
||||
* `"5".isInt = true`
|
||||
* `"587".isInt = true`
|
||||
* `"-587".isInt = true`
|
||||
* `"+587".isInt = false`
|
||||
* `" 5".isInt = false`
|
||||
* `"2-3".isInt = false`
|
||||
* `"0xff".isInt = false`
|
||||
-/
|
||||
def String.isInt (s : String) : Bool :=
|
||||
if s.get 0 = '-' then
|
||||
(s.toSubstring.drop 1).isNat
|
||||
else
|
||||
s.isNat
|
||||
|
||||
/--
|
||||
Interprets a string as the decimal representation of an integer, returning it. Panics if the string
|
||||
does not contain a decimal integer.
|
||||
|
||||
A string can be interpreted as a decimal integer if it only consists of at least one decimal digit
|
||||
and optionally `-` in front. Leading `+` characters are not allowed.
|
||||
|
||||
Use `String.isInt` to check whether `String.toInt!` would return a value. `String.toInt?` is a safer
|
||||
alternative that returns `none` instead of panicking when the string is not an integer.
|
||||
|
||||
Examples:
|
||||
* `"0".toInt! = 0`
|
||||
* `"5".toInt! = 5`
|
||||
* `"587".toInt! = 587`
|
||||
* `"-587".toInt! = -587`
|
||||
-/
|
||||
def String.toInt! (s : String) : Int :=
|
||||
match s.toInt? with
|
||||
| some v => v
|
||||
| none => panic "Int expected"
|
||||
@@ -8,6 +8,5 @@ module
|
||||
prelude
|
||||
public import Init.Data.ToString.Basic
|
||||
public import Init.Data.ToString.Macro
|
||||
public meta import Init.Data.ToString.Name
|
||||
|
||||
public section
|
||||
|
||||
@@ -38,10 +38,10 @@ instance : ToString String :=
|
||||
⟨fun s => s⟩
|
||||
|
||||
instance : ToString Substring :=
|
||||
⟨fun s => Substring.Internal.toString s⟩
|
||||
⟨fun s => s.toString⟩
|
||||
|
||||
instance : ToString Char :=
|
||||
⟨fun c => Char.toString c⟩
|
||||
instance : ToString String.Iterator :=
|
||||
⟨fun it => it.remainingToString⟩
|
||||
|
||||
instance : ToString Bool :=
|
||||
⟨fun b => cond b "true" "false"⟩
|
||||
@@ -67,9 +67,8 @@ Examples:
|
||||
-/
|
||||
protected def List.toString [ToString α] : List α → String
|
||||
| [] => "[]"
|
||||
| [x] => String.Internal.append (String.Internal.append "[" (toString x)) "]"
|
||||
| x::xs => String.push (xs.foldl (fun l r => String.Internal.append (String.Internal.append l ", ") (toString r))
|
||||
(String.Internal.append "[" (toString x))) ']'
|
||||
| [x] => "[" ++ toString x ++ "]"
|
||||
| x::xs => xs.foldl (· ++ ", " ++ toString ·) ("[" ++ toString x) |>.push ']'
|
||||
|
||||
instance {α : Type u} [ToString α] : ToString (List α) :=
|
||||
⟨List.toString⟩
|
||||
@@ -92,7 +91,10 @@ instance : ToString String.Pos :=
|
||||
instance : ToString Int where
|
||||
toString
|
||||
| Int.ofNat m => toString m
|
||||
| Int.negSucc m => String.Internal.append "-" (toString (succ m))
|
||||
| Int.negSucc m => "-" ++ toString (succ m)
|
||||
|
||||
instance : ToString Char :=
|
||||
⟨fun c => c.toString⟩
|
||||
|
||||
instance (n : Nat) : ToString (Fin n) :=
|
||||
⟨fun f => toString (Fin.val f)⟩
|
||||
@@ -116,43 +118,108 @@ instance : ToString Format where
|
||||
toString f := f.pretty
|
||||
|
||||
def addParenHeuristic (s : String) : String :=
|
||||
if String.Internal.isPrefixOf "(" s || String.Internal.isPrefixOf "[" s || String.Internal.isPrefixOf "{" s || String.Internal.isPrefixOf "#[" s then s
|
||||
else if !(String.Internal.any s Char.isWhitespace) then s
|
||||
else String.Internal.append (String.Internal.append "(" s) ")"
|
||||
if "(".isPrefixOf s || "[".isPrefixOf s || "{".isPrefixOf s || "#[".isPrefixOf s then s
|
||||
else if !s.any Char.isWhitespace then s
|
||||
else "(" ++ s ++ ")"
|
||||
|
||||
instance {α : Type u} [ToString α] : ToString (Option α) := ⟨fun
|
||||
| none => "none"
|
||||
| (some a) => String.Internal.append (String.Internal.append "(some " (addParenHeuristic (toString a))) ")"⟩
|
||||
| (some a) => "(some " ++ addParenHeuristic (toString a) ++ ")"⟩
|
||||
|
||||
instance {α : Type u} {β : Type v} [ToString α] [ToString β] : ToString (Sum α β) := ⟨fun
|
||||
| (inl a) => String.Internal.append (String.Internal.append "(inl " (addParenHeuristic (toString a))) ")"
|
||||
| (inr b) => String.Internal.append (String.Internal.append "(inr " (addParenHeuristic (toString b))) ")"⟩
|
||||
| (inl a) => "(inl " ++ addParenHeuristic (toString a) ++ ")"
|
||||
| (inr b) => "(inr " ++ addParenHeuristic (toString b) ++ ")"⟩
|
||||
|
||||
instance {α : Type u} {β : Type v} [ToString α] [ToString β] : ToString (α × β) := ⟨fun (a, b) =>
|
||||
String.Internal.append
|
||||
(String.Internal.append
|
||||
(String.Internal.append
|
||||
(String.Internal.append "(" (toString a))
|
||||
", ")
|
||||
(toString b))
|
||||
")"⟩
|
||||
"(" ++ toString a ++ ", " ++ toString b ++ ")"⟩
|
||||
|
||||
instance {α : Type u} {β : α → Type v} [ToString α] [∀ x, ToString (β x)] : ToString (Sigma β) := ⟨fun ⟨a, b⟩ =>
|
||||
String.Internal.append
|
||||
(String.Internal.append
|
||||
(String.Internal.append
|
||||
(String.Internal.append "⟨" (toString a))
|
||||
", ")
|
||||
(toString b))
|
||||
"⟩"⟩
|
||||
"⟨" ++ toString a ++ ", " ++ toString b ++ "⟩"⟩
|
||||
|
||||
instance {α : Type u} {p : α → Prop} [ToString α] : ToString (Subtype p) := ⟨fun s =>
|
||||
toString (val s)⟩
|
||||
|
||||
/--
|
||||
Interprets a string as the decimal representation of an integer, returning it. Returns `none` if
|
||||
the string does not contain a decimal integer.
|
||||
|
||||
A string can be interpreted as a decimal integer if it only consists of at least one decimal digit
|
||||
and optionally `-` in front. Leading `+` characters are not allowed.
|
||||
|
||||
Use `String.isInt` to check whether `String.toInt?` would return `some`. `String.toInt!` is an
|
||||
alternative that panics instead of returning `none` when the string is not an integer.
|
||||
|
||||
Examples:
|
||||
* `"".toInt? = none`
|
||||
* `"-".toInt? = none`
|
||||
* `"0".toInt? = some 0`
|
||||
* `"5".toInt? = some 5`
|
||||
* `"-5".toInt? = some (-5)`
|
||||
* `"587".toInt? = some 587`
|
||||
* `"-587".toInt? = some (-587)`
|
||||
* `" 5".toInt? = none`
|
||||
* `"2-3".toInt? = none`
|
||||
* `"0xff".toInt? = none`
|
||||
-/
|
||||
def String.toInt? (s : String) : Option Int := do
|
||||
if s.get 0 = '-' then do
|
||||
let v ← (s.toSubstring.drop 1).toNat?;
|
||||
pure <| - Int.ofNat v
|
||||
else
|
||||
Int.ofNat <$> s.toNat?
|
||||
|
||||
/--
|
||||
Checks whether the string can be interpreted as the decimal representation of an integer.
|
||||
|
||||
A string can be interpreted as a decimal integer if it only consists of at least one decimal digit
|
||||
and optionally `-` in front. Leading `+` characters are not allowed.
|
||||
|
||||
Use `String.toInt?` or `String.toInt!` to convert such a string to an integer.
|
||||
|
||||
Examples:
|
||||
* `"".isInt = false`
|
||||
* `"-".isInt = false`
|
||||
* `"0".isInt = true`
|
||||
* `"-0".isInt = true`
|
||||
* `"5".isInt = true`
|
||||
* `"587".isInt = true`
|
||||
* `"-587".isInt = true`
|
||||
* `"+587".isInt = false`
|
||||
* `" 5".isInt = false`
|
||||
* `"2-3".isInt = false`
|
||||
* `"0xff".isInt = false`
|
||||
-/
|
||||
def String.isInt (s : String) : Bool :=
|
||||
if s.get 0 = '-' then
|
||||
(s.toSubstring.drop 1).isNat
|
||||
else
|
||||
s.isNat
|
||||
|
||||
/--
|
||||
Interprets a string as the decimal representation of an integer, returning it. Panics if the string
|
||||
does not contain a decimal integer.
|
||||
|
||||
A string can be interpreted as a decimal integer if it only consists of at least one decimal digit
|
||||
and optionally `-` in front. Leading `+` characters are not allowed.
|
||||
|
||||
Use `String.isInt` to check whether `String.toInt!` would return a value. `String.toInt?` is a safer
|
||||
alternative that returns `none` instead of panicking when the string is not an integer.
|
||||
|
||||
Examples:
|
||||
* `"0".toInt! = 0`
|
||||
* `"5".toInt! = 5`
|
||||
* `"587".toInt! = 587`
|
||||
* `"-587".toInt! = -587`
|
||||
-/
|
||||
def String.toInt! (s : String) : Int :=
|
||||
match s.toInt? with
|
||||
| some v => v
|
||||
| none => panic "Int expected"
|
||||
|
||||
instance [ToString ε] [ToString α] : ToString (Except ε α) where
|
||||
toString
|
||||
| Except.error e => String.Internal.append "error: " (toString e)
|
||||
| Except.ok a => String.Internal.append "ok: " (toString a)
|
||||
| Except.error e => "error: " ++ toString e
|
||||
| Except.ok a => "ok: " ++ toString a
|
||||
|
||||
instance [Repr ε] [Repr α] : Repr (Except ε α) where
|
||||
reprPrec
|
||||
|
||||
@@ -1,128 +0,0 @@
|
||||
/-
|
||||
Copyright (c) 2019 Microsoft Corporation. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Leonardo de Moura and Sebastian Ullrich
|
||||
-/
|
||||
module
|
||||
|
||||
prelude
|
||||
public import Init.Meta
|
||||
import Init.Data.String.Extra
|
||||
|
||||
/-!
|
||||
Here we give the. implementation of `Name.toString`. There is also a private implementation in
|
||||
`Init.Meta`, which we cannot import this implementation due to import hierarchy limitations.
|
||||
|
||||
The difference between the two versions is that the one in `Init.Meta` uses the `String.Internal.*`
|
||||
functions, while the one here uses the public String functions. These differ in
|
||||
that the latter versions have better inferred borrowing annotations, which is significant for an
|
||||
inner-loop function like `Name.toString`.
|
||||
-/
|
||||
|
||||
public section
|
||||
|
||||
namespace Lean.Name
|
||||
|
||||
-- If you change this, also change the corresponding function in `Init.Meta`.
|
||||
private partial def needsNoEscapeAsciiRest (s : String) (i : Nat) : Bool :=
|
||||
if h : i < s.utf8ByteSize then
|
||||
let c := s.getUtf8Byte i h
|
||||
isIdRestAscii c && needsNoEscapeAsciiRest s (i + 1)
|
||||
else
|
||||
true
|
||||
|
||||
-- If you change this, also change the corresponding function in `Init.Meta`.
|
||||
@[inline] private def needsNoEscapeAscii (s : String) (h : s.utf8ByteSize > 0) : Bool :=
|
||||
let c := s.getUtf8Byte 0 h
|
||||
isIdFirstAscii c && needsNoEscapeAsciiRest s 1
|
||||
|
||||
-- If you change this, also change the corresponding function in `Init.Meta`.
|
||||
@[inline] private def needsNoEscape (s : String) (h : s.utf8ByteSize > 0) : Bool :=
|
||||
needsNoEscapeAscii s h || isIdFirst (s.get 0) && (s.toSubstring.drop 1).all isIdRest
|
||||
|
||||
-- If you change this, also change the corresponding function in `Init.Meta`.
|
||||
@[inline] private def escape (s : String) : String :=
|
||||
idBeginEscape.toString ++ s ++ idEndEscape.toString
|
||||
|
||||
/--
|
||||
Creates a round-trippable string name component if possible, otherwise returns `none`.
|
||||
Names that are valid identifiers are not escaped, and otherwise, if they do not contain `»`, they are escaped.
|
||||
- If `force` is `true`, then even valid identifiers are escaped.
|
||||
-/
|
||||
-- If you change this, also change the corresponding function in `Init.Meta`.
|
||||
@[inline]
|
||||
def escapePart (s : String) (force : Bool := false) : Option String :=
|
||||
if h : s.utf8ByteSize > 0 then
|
||||
if !force && needsNoEscape s h then
|
||||
some s
|
||||
else if s.any isIdEndEscape then
|
||||
none
|
||||
else
|
||||
some <| escape s
|
||||
else
|
||||
some <| escape s
|
||||
|
||||
variable (sep : String) (escape : Bool) in
|
||||
/--
|
||||
Uses the separator `sep` (usually `"."`) to combine the components of the `Name` into a string.
|
||||
See the documentation for `Name.toStringWithToken` for an explanation of `escape` and `isToken`.
|
||||
-/
|
||||
-- If you change this, also change the corresponding function in `Init.Meta`.
|
||||
@[specialize isToken] -- explicit annotation because isToken is overridden in recursive call
|
||||
def toStringWithSep (n : Name) (isToken : String → Bool := fun _ => false) : String :=
|
||||
match n with
|
||||
| anonymous => "[anonymous]"
|
||||
| str anonymous s => maybeEscape s (isToken s)
|
||||
| num anonymous v => toString v
|
||||
| str n s =>
|
||||
-- Escape the last component if the identifier would otherwise be a token
|
||||
let r := toStringWithSep n isToken
|
||||
let r' := r ++ sep ++ (maybeEscape s false)
|
||||
if escape && isToken r' then r ++ sep ++ (maybeEscape s true) else r'
|
||||
| num n v => toStringWithSep n (isToken := fun _ => false) ++ sep ++ Nat.repr v
|
||||
where
|
||||
maybeEscape s force := if escape then escapePart s force |>.getD s else s
|
||||
|
||||
/--
|
||||
Converts a name to a string.
|
||||
|
||||
- If `escape` is `true`, then escapes name components using `«` and `»` to ensure that
|
||||
those names that can appear in source files round trip.
|
||||
Names with number components, anonymous names, and names containing `»` might not round trip.
|
||||
Furthermore, "pseudo-syntax" produced by the delaborator, such as `_`, `#0` or `?u`, is not escaped.
|
||||
- The optional `isToken` function is used when `escape` is `true` to determine whether more
|
||||
escaping is necessary to avoid parser tokens.
|
||||
The insertion algorithm works so long as parser tokens do not themselves contain `«` or `»`.
|
||||
-/
|
||||
-- If you change this, also change the corresponding function in `Init.Meta`.
|
||||
@[specialize]
|
||||
def toStringWithToken (n : Name) (escape := true) (isToken : String → Bool) : String :=
|
||||
-- never escape "prettified" inaccessible names or macro scopes or pseudo-syntax introduced by the delaborator
|
||||
toStringWithSep "." (escape && !n.isInaccessibleUserName && !n.hasMacroScopes && !maybePseudoSyntax) n isToken
|
||||
where
|
||||
maybePseudoSyntax :=
|
||||
if n == `_ then
|
||||
-- output hole as is
|
||||
true
|
||||
else if let .str _ s := n.getRoot then
|
||||
-- could be pseudo-syntax for loose bvar or universe mvar, output as is
|
||||
"#".isPrefixOf s || "?".isPrefixOf s
|
||||
else
|
||||
false
|
||||
|
||||
/--
|
||||
Converts a name to a string.
|
||||
|
||||
- If `escape` is `true`, then escapes name components using `«` and `»` to ensure that
|
||||
those names that can appear in source files round trip.
|
||||
Names with number components, anonymous names, and names containing `»` might not round trip.
|
||||
Furthermore, "pseudo-syntax" produced by the delaborator, such as `_`, `#0` or `?u`, is not escaped.
|
||||
-/
|
||||
-- If you change this, also change the corresponding function in `Init.Meta`.
|
||||
protected def toString (n : Name) (escape := true) : String :=
|
||||
Name.toStringWithToken n escape (fun _ => false)
|
||||
|
||||
instance : ToString Name where
|
||||
toString n := n.toString
|
||||
|
||||
end Lean.Name
|
||||
@@ -139,6 +139,16 @@ This function is overridden at runtime with an efficient implementation.
|
||||
-/
|
||||
@[extern "lean_uint8_shift_right"]
|
||||
protected def UInt8.shiftRight (a b : UInt8) : UInt8 := ⟨a.toBitVec >>> (UInt8.mod b 8).toBitVec⟩
|
||||
/--
|
||||
Strict inequality of 8-bit unsigned integers, defined as inequality of the corresponding
|
||||
natural numbers. Usually accessed via the `<` operator.
|
||||
-/
|
||||
protected def UInt8.lt (a b : UInt8) : Prop := a.toBitVec < b.toBitVec
|
||||
/--
|
||||
Non-strict inequality of 8-bit unsigned integers, defined as inequality of the corresponding
|
||||
natural numbers. Usually accessed via the `≤` operator.
|
||||
-/
|
||||
protected def UInt8.le (a b : UInt8) : Prop := a.toBitVec ≤ b.toBitVec
|
||||
|
||||
instance : Add UInt8 := ⟨UInt8.add⟩
|
||||
instance : Sub UInt8 := ⟨UInt8.sub⟩
|
||||
@@ -150,6 +160,8 @@ set_option linter.deprecated false in
|
||||
instance : HMod UInt8 Nat UInt8 := ⟨UInt8.modn⟩
|
||||
|
||||
instance : Div UInt8 := ⟨UInt8.div⟩
|
||||
instance : LT UInt8 := ⟨UInt8.lt⟩
|
||||
instance : LE UInt8 := ⟨UInt8.le⟩
|
||||
|
||||
/--
|
||||
Bitwise complement, also known as bitwise negation, for 8-bit unsigned integers. Usually accessed
|
||||
@@ -185,6 +197,39 @@ Converts `true` to `1` and `false` to `0`.
|
||||
@[extern "lean_bool_to_uint8"]
|
||||
def Bool.toUInt8 (b : Bool) : UInt8 := if b then 1 else 0
|
||||
|
||||
/--
|
||||
Decides whether one 8-bit unsigned integer is strictly less than another. Usually accessed via the
|
||||
`DecidableLT UInt8` instance.
|
||||
|
||||
This function is overridden at runtime with an efficient implementation.
|
||||
|
||||
Examples:
|
||||
* `(if (6 : UInt8) < 7 then "yes" else "no") = "yes"`
|
||||
* `(if (5 : UInt8) < 5 then "yes" else "no") = "no"`
|
||||
* `show ¬((7 : UInt8) < 7) by decide`
|
||||
-/
|
||||
@[extern "lean_uint8_dec_lt"]
|
||||
def UInt8.decLt (a b : UInt8) : Decidable (a < b) :=
|
||||
inferInstanceAs (Decidable (a.toBitVec < b.toBitVec))
|
||||
|
||||
/--
|
||||
Decides whether one 8-bit unsigned integer is less than or equal to another. Usually accessed via the
|
||||
`DecidableLE UInt8` instance.
|
||||
|
||||
This function is overridden at runtime with an efficient implementation.
|
||||
|
||||
Examples:
|
||||
* `(if (15 : UInt8) ≤ 15 then "yes" else "no") = "yes"`
|
||||
* `(if (15 : UInt8) ≤ 5 then "yes" else "no") = "no"`
|
||||
* `(if (5 : UInt8) ≤ 15 then "yes" else "no") = "yes"`
|
||||
* `show (7 : UInt8) ≤ 7 by decide`
|
||||
-/
|
||||
@[extern "lean_uint8_dec_le"]
|
||||
def UInt8.decLe (a b : UInt8) : Decidable (a ≤ b) :=
|
||||
inferInstanceAs (Decidable (a.toBitVec ≤ b.toBitVec))
|
||||
|
||||
attribute [instance] UInt8.decLt UInt8.decLe
|
||||
|
||||
instance : Max UInt8 := maxOfLe
|
||||
instance : Min UInt8 := minOfLe
|
||||
|
||||
|
||||
@@ -29,6 +29,21 @@ def UInt8.toFin (x : UInt8) : Fin UInt8.size := x.toBitVec.toFin
|
||||
@[deprecated UInt8.toFin (since := "2025-02-12"), inherit_doc UInt8.toFin]
|
||||
def UInt8.val (x : UInt8) : Fin UInt8.size := x.toFin
|
||||
|
||||
/--
|
||||
Converts a natural number to an 8-bit unsigned integer, wrapping on overflow.
|
||||
|
||||
This function is overridden at runtime with an efficient implementation.
|
||||
|
||||
Examples:
|
||||
* `UInt8.ofNat 5 = 5`
|
||||
* `UInt8.ofNat 255 = 255`
|
||||
* `UInt8.ofNat 256 = 0`
|
||||
* `UInt8.ofNat 259 = 3`
|
||||
* `UInt8.ofNat 32770 = 2`
|
||||
-/
|
||||
@[extern "lean_uint8_of_nat"]
|
||||
def UInt8.ofNat (n : @& Nat) : UInt8 := ⟨BitVec.ofNat 8 n⟩
|
||||
|
||||
/--
|
||||
Converts a natural number to an 8-bit unsigned integer, returning the largest representable value if
|
||||
the number is too large.
|
||||
@@ -207,8 +222,8 @@ instance UInt32.instOfNat : OfNat UInt32 n := ⟨UInt32.ofNat n⟩
|
||||
|
||||
theorem UInt32.ofNatLT_lt_of_lt {n m : Nat} (h1 : n < UInt32.size) (h2 : m < UInt32.size) :
|
||||
n < m → UInt32.ofNatLT n h1 < UInt32.ofNat m := by
|
||||
simp only [(· < ·), BitVec.toNat, ofNatLT, BitVec.ofNatLT, ofNat, BitVec.ofNat,
|
||||
Fin.Internal.ofNat_eq_ofNat, Fin.ofNat, Nat.mod_eq_of_lt h2, imp_self]
|
||||
simp only [(· < ·), BitVec.toNat, ofNatLT, BitVec.ofNatLT, ofNat, BitVec.ofNat, Fin.ofNat,
|
||||
Nat.mod_eq_of_lt h2, imp_self]
|
||||
|
||||
@[deprecated UInt32.ofNatLT_lt_of_lt (since := "2025-02-13")]
|
||||
theorem UInt32.ofNat'_lt_of_lt {n m : Nat} (h1 : n < UInt32.size) (h2 : m < UInt32.size) :
|
||||
@@ -216,8 +231,8 @@ theorem UInt32.ofNat'_lt_of_lt {n m : Nat} (h1 : n < UInt32.size) (h2 : m < UInt
|
||||
|
||||
theorem UInt32.lt_ofNatLT_of_lt {n m : Nat} (h1 : n < UInt32.size) (h2 : m < UInt32.size) :
|
||||
m < n → UInt32.ofNat m < UInt32.ofNatLT n h1 := by
|
||||
simp only [(· < ·), BitVec.toNat, ofNatLT, BitVec.ofNatLT, ofNat, BitVec.ofNat, Fin.Internal.ofNat_eq_ofNat,
|
||||
Fin.ofNat, Nat.mod_eq_of_lt h2, imp_self]
|
||||
simp only [(· < ·), BitVec.toNat, ofNatLT, BitVec.ofNatLT, ofNat, BitVec.ofNat, Fin.ofNat,
|
||||
Nat.mod_eq_of_lt h2, imp_self]
|
||||
|
||||
@[deprecated UInt32.lt_ofNatLT_of_lt (since := "2025-02-13")]
|
||||
theorem UInt32.lt_ofNat'_of_lt {n m : Nat} (h1 : n < UInt32.size) (h2 : m < UInt32.size) :
|
||||
|
||||
@@ -299,84 +299,37 @@ theorem Seq.denote_concat {α} (ctx : Context α) {inst₁ : Std.Associative ctx
|
||||
|
||||
attribute [local simp] Seq.denote_concat
|
||||
|
||||
theorem eq_orient {α} (ctx : Context α) (lhs rhs : Seq)
|
||||
: lhs.denote ctx = rhs.denote ctx → rhs.denote ctx = lhs.denote ctx := by
|
||||
simp_all
|
||||
|
||||
theorem eq_simp_lhs_exact {α} (ctx : Context α) (lhs₁ rhs₁ rhs₂ : Seq)
|
||||
: lhs₁.denote ctx = rhs₁.denote ctx → lhs₁.denote ctx = rhs₂.denote ctx → rhs₁.denote ctx = rhs₂.denote ctx := by
|
||||
simp_all
|
||||
|
||||
theorem eq_simp_rhs_exact {α} (ctx : Context α) (lhs₁ rhs₁ lhs₂ : Seq)
|
||||
: lhs₁.denote ctx = rhs₁.denote ctx → lhs₂.denote ctx = lhs₁.denote ctx → lhs₂.denote ctx = rhs₁.denote ctx := by
|
||||
simp_all
|
||||
|
||||
theorem diseq_simp_lhs_exact {α} (ctx : Context α) (lhs₁ rhs₁ rhs₂ : Seq)
|
||||
: lhs₁.denote ctx = rhs₁.denote ctx → lhs₁.denote ctx ≠ rhs₂.denote ctx → rhs₁.denote ctx ≠ rhs₂.denote ctx := by
|
||||
simp_all
|
||||
|
||||
theorem diseq_simp_rhs_exact {α} (ctx : Context α) (lhs₁ rhs₁ lhs₂ : Seq)
|
||||
: lhs₁.denote ctx = rhs₁.denote ctx → lhs₂.denote ctx ≠ lhs₁.denote ctx → lhs₂.denote ctx ≠ rhs₁.denote ctx := by
|
||||
simp_all
|
||||
|
||||
noncomputable def simp_prefix_cert (lhs rhs tail s s' : Seq) : Bool :=
|
||||
s.beq' (lhs.concat_k tail) |>.and' (s'.beq' (rhs.concat_k tail))
|
||||
|
||||
theorem eq_simp_lhs_prefix {α} (ctx : Context α) {_ : Std.Associative ctx.op} (lhs₁ rhs₁ tail lhs₂ rhs₂ lhs₂' : Seq)
|
||||
: simp_prefix_cert lhs₁ rhs₁ tail lhs₂ lhs₂' → lhs₁.denote ctx = rhs₁.denote ctx → lhs₂.denote ctx = rhs₂.denote ctx → lhs₂'.denote ctx = rhs₂.denote ctx := by
|
||||
simp [simp_prefix_cert]; intros; subst lhs₂ lhs₂'; simp_all
|
||||
|
||||
theorem eq_simp_rhs_prefix {α} (ctx : Context α) {_ : Std.Associative ctx.op} (lhs₁ rhs₁ tail lhs₂ rhs₂ rhs₂' : Seq)
|
||||
: simp_prefix_cert lhs₁ rhs₁ tail rhs₂ rhs₂' → lhs₁.denote ctx = rhs₁.denote ctx → lhs₂.denote ctx = rhs₂.denote ctx → lhs₂.denote ctx = rhs₂'.denote ctx := by
|
||||
simp [simp_prefix_cert]; intros; subst rhs₂ rhs₂'; simp_all
|
||||
|
||||
theorem diseq_simp_lhs_prefix {α} (ctx : Context α) {_ : Std.Associative ctx.op} (lhs₁ rhs₁ tail lhs₂ rhs₂ lhs₂' : Seq)
|
||||
: simp_prefix_cert lhs₁ rhs₁ tail lhs₂ lhs₂' → lhs₁.denote ctx = rhs₁.denote ctx → lhs₂.denote ctx ≠ rhs₂.denote ctx → lhs₂'.denote ctx ≠ rhs₂.denote ctx := by
|
||||
simp [simp_prefix_cert]; intros; subst lhs₂ lhs₂'; simp_all
|
||||
|
||||
theorem diseq_simp_rhs_prefix {α} (ctx : Context α) {_ : Std.Associative ctx.op} (lhs₁ rhs₁ tail lhs₂ rhs₂ rhs₂' : Seq)
|
||||
: simp_prefix_cert lhs₁ rhs₁ tail rhs₂ rhs₂' → lhs₁.denote ctx = rhs₁.denote ctx → lhs₂.denote ctx ≠ rhs₂.denote ctx → lhs₂.denote ctx ≠ rhs₂'.denote ctx := by
|
||||
simp [simp_prefix_cert]; intros; subst rhs₂ rhs₂'; simp_all
|
||||
/--
|
||||
Given `lhs = rhs`, and a term `s := lhs * tail`, rewrite it to `s' := rhs * tail`
|
||||
-/
|
||||
theorem simp_prefix {α} (ctx : Context α) {_ : Std.Associative ctx.op} (lhs rhs tail s s' : Seq)
|
||||
: simp_prefix_cert lhs rhs tail s s' → lhs.denote ctx = rhs.denote ctx → s.denote ctx = s'.denote ctx := by
|
||||
simp [simp_prefix_cert]; intro _ _ h; subst s s'; simp [h]
|
||||
|
||||
noncomputable def simp_suffix_cert (lhs rhs head s s' : Seq) : Bool :=
|
||||
s.beq' (head.concat_k lhs) |>.and' (s'.beq' (head.concat_k rhs))
|
||||
|
||||
theorem eq_simp_lhs_suffix {α} (ctx : Context α) {_ : Std.Associative ctx.op} (lhs₁ rhs₁ head lhs₂ rhs₂ lhs₂' : Seq)
|
||||
: simp_suffix_cert lhs₁ rhs₁ head lhs₂ lhs₂' → lhs₁.denote ctx = rhs₁.denote ctx → lhs₂.denote ctx = rhs₂.denote ctx → lhs₂'.denote ctx = rhs₂.denote ctx := by
|
||||
simp [simp_suffix_cert]; intros; subst lhs₂ lhs₂'; simp_all
|
||||
|
||||
theorem eq_simp_rhs_suffix {α} (ctx : Context α) {_ : Std.Associative ctx.op} (lhs₁ rhs₁ head lhs₂ rhs₂ rhs₂' : Seq)
|
||||
: simp_suffix_cert lhs₁ rhs₁ head rhs₂ rhs₂' → lhs₁.denote ctx = rhs₁.denote ctx → lhs₂.denote ctx = rhs₂.denote ctx → lhs₂.denote ctx = rhs₂'.denote ctx := by
|
||||
simp [simp_suffix_cert]; intros; subst rhs₂ rhs₂'; simp_all
|
||||
|
||||
theorem diseq_simp_lhs_suffix {α} (ctx : Context α) {_ : Std.Associative ctx.op} (lhs₁ rhs₁ head lhs₂ rhs₂ lhs₂' : Seq)
|
||||
: simp_suffix_cert lhs₁ rhs₁ head lhs₂ lhs₂' → lhs₁.denote ctx = rhs₁.denote ctx → lhs₂.denote ctx ≠ rhs₂.denote ctx → lhs₂'.denote ctx ≠ rhs₂.denote ctx := by
|
||||
simp [simp_suffix_cert]; intros; subst lhs₂ lhs₂'; simp_all
|
||||
|
||||
theorem diseq_simp_rhs_suffix {α} (ctx : Context α) {_ : Std.Associative ctx.op} (lhs₁ rhs₁ head lhs₂ rhs₂ rhs₂' : Seq)
|
||||
: simp_suffix_cert lhs₁ rhs₁ head rhs₂ rhs₂' → lhs₁.denote ctx = rhs₁.denote ctx → lhs₂.denote ctx ≠ rhs₂.denote ctx → lhs₂.denote ctx ≠ rhs₂'.denote ctx := by
|
||||
simp [simp_suffix_cert]; intros; subst rhs₂ rhs₂'; simp_all
|
||||
/--
|
||||
Given `lhs = rhs`, and a term `s := head * lhs`, rewrite it to `s' := head * rhs`
|
||||
-/
|
||||
theorem simp_suffix {α} (ctx : Context α) {_ : Std.Associative ctx.op} (lhs rhs head s s' : Seq)
|
||||
: simp_suffix_cert lhs rhs head s s' → lhs.denote ctx = rhs.denote ctx → s.denote ctx = s'.denote ctx := by
|
||||
simp [simp_suffix_cert]; intro _ _ h; subst s s'; simp [h]
|
||||
|
||||
noncomputable def simp_middle_cert (lhs rhs head tail s s' : Seq) : Bool :=
|
||||
s.beq' (head.concat_k (lhs.concat_k tail)) |>.and' (s'.beq' (head.concat_k (rhs.concat_k tail)))
|
||||
|
||||
theorem eq_simp_lhs_middle {α} (ctx : Context α) {_ : Std.Associative ctx.op} (lhs₁ rhs₁ head tail lhs₂ rhs₂ lhs₂' : Seq)
|
||||
: simp_middle_cert lhs₁ rhs₁ head tail lhs₂ lhs₂' → lhs₁.denote ctx = rhs₁.denote ctx → lhs₂.denote ctx = rhs₂.denote ctx → lhs₂'.denote ctx = rhs₂.denote ctx := by
|
||||
simp [simp_middle_cert]; intros; subst lhs₂ lhs₂'; simp_all
|
||||
/--
|
||||
Given `lhs = rhs`, and a term `s := head * lhs * tail`, rewrite it to `s' := head * rhs * tail`
|
||||
-/
|
||||
theorem simp_middle {α} (ctx : Context α) {_ : Std.Associative ctx.op} (lhs rhs head tail s s' : Seq)
|
||||
: simp_middle_cert lhs rhs head tail s s' → lhs.denote ctx = rhs.denote ctx → s.denote ctx = s'.denote ctx := by
|
||||
simp [simp_middle_cert]; intro _ _ h; subst s s'; simp [h]
|
||||
|
||||
theorem eq_simp_rhs_middle {α} (ctx : Context α) {_ : Std.Associative ctx.op} (lhs₁ rhs₁ head tail lhs₂ rhs₂ rhs₂' : Seq)
|
||||
: simp_middle_cert lhs₁ rhs₁ head tail rhs₂ rhs₂' → lhs₁.denote ctx = rhs₁.denote ctx → lhs₂.denote ctx = rhs₂.denote ctx → lhs₂.denote ctx = rhs₂'.denote ctx := by
|
||||
simp [simp_middle_cert]; intros; subst rhs₂ rhs₂'; simp_all
|
||||
|
||||
theorem diseq_simp_lhs_middle {α} (ctx : Context α) {_ : Std.Associative ctx.op} (lhs₁ rhs₁ head tail lhs₂ rhs₂ lhs₂' : Seq)
|
||||
: simp_middle_cert lhs₁ rhs₁ head tail lhs₂ lhs₂' → lhs₁.denote ctx = rhs₁.denote ctx → lhs₂.denote ctx ≠ rhs₂.denote ctx → lhs₂'.denote ctx ≠ rhs₂.denote ctx := by
|
||||
simp [simp_middle_cert]; intros; subst lhs₂ lhs₂'; simp_all
|
||||
|
||||
theorem diseq_simp_rhs_middle {α} (ctx : Context α) {_ : Std.Associative ctx.op} (lhs₁ rhs₁ head tail lhs₂ rhs₂ rhs₂' : Seq)
|
||||
: simp_middle_cert lhs₁ rhs₁ head tail rhs₂ rhs₂' → lhs₁.denote ctx = rhs₁.denote ctx → lhs₂.denote ctx ≠ rhs₂.denote ctx → lhs₂.denote ctx ≠ rhs₂'.denote ctx := by
|
||||
simp [simp_middle_cert]; intros; subst rhs₂ rhs₂'; simp_all
|
||||
|
||||
noncomputable def superpose_cert (p c s lhs₁ rhs₁ lhs₂ rhs₂ lhs rhs : Seq) : Bool :=
|
||||
noncomputable def superpose_prefix_suffix_cert (p c s lhs₁ rhs₁ lhs₂ rhs₂ lhs rhs : Seq) : Bool :=
|
||||
lhs₁.beq' (p.concat_k c) |>.and'
|
||||
(lhs₂.beq' (c.concat_k s)) |>.and'
|
||||
(lhs.beq' (rhs₁.concat_k s)) |>.and'
|
||||
@@ -386,10 +339,10 @@ noncomputable def superpose_cert (p c s lhs₁ rhs₁ lhs₂ rhs₂ lhs rhs : Se
|
||||
Given `lhs₁ = rhs₁` and `lhs₂ = rhs₂` where `lhs₁ := p * c` and `lhs₂ := c * s`,
|
||||
`lhs = rhs` where `lhs := rhs₁ * s` and `rhs := p * rhs₂`
|
||||
-/
|
||||
theorem superpose {α} (ctx : Context α) {inst₁ : Std.Associative ctx.op} (p c s lhs₁ rhs₁ lhs₂ rhs₂ lhs rhs : Seq)
|
||||
: superpose_cert p c s lhs₁ rhs₁ lhs₂ rhs₂ lhs rhs → lhs₁.denote ctx = rhs₁.denote ctx → lhs₂.denote ctx = rhs₂.denote ctx
|
||||
theorem superpose_prefix_suffix {α} (ctx : Context α) {inst₁ : Std.Associative ctx.op} (p c s lhs₁ rhs₁ lhs₂ rhs₂ lhs rhs : Seq)
|
||||
: superpose_prefix_suffix_cert p c s lhs₁ rhs₁ lhs₂ rhs₂ lhs rhs → lhs₁.denote ctx = rhs₁.denote ctx → lhs₂.denote ctx = rhs₂.denote ctx
|
||||
→ lhs.denote ctx = rhs.denote ctx := by
|
||||
simp [superpose_cert]; intro _ _ _ _; subst lhs₁ lhs₂ lhs rhs; simp
|
||||
simp [superpose_prefix_suffix_cert]; intro _ _ _ _; subst lhs₁ lhs₂ lhs rhs; simp
|
||||
intro h₁ h₂; simp [← h₁, ← h₂, Std.Associative.assoc (self := inst₁)]
|
||||
|
||||
def Seq.unionFuel (fuel : Nat) (s₁ s₂ : Seq) : Seq :=
|
||||
@@ -469,143 +422,26 @@ theorem simp_ac {α} (ctx : Context α) {inst₁ : Std.Associative ctx.op} {inst
|
||||
: simp_ac_cert c lhs rhs s s' → lhs.denote ctx = rhs.denote ctx → s.denote ctx = s'.denote ctx := by
|
||||
simp [simp_ac_cert]; intro _ _; subst s s'; simp; intro h; rw [h]
|
||||
|
||||
theorem eq_simp_lhs_ac {α} (ctx : Context α) {inst₁ : Std.Associative ctx.op} {inst₂ : Std.Commutative ctx.op} (c lhs₁ rhs₁ lhs₂ rhs₂ lhs₂' : Seq)
|
||||
: simp_ac_cert c lhs₁ rhs₁ lhs₂ lhs₂' → lhs₁.denote ctx = rhs₁.denote ctx → lhs₂.denote ctx = rhs₂.denote ctx → lhs₂'.denote ctx = rhs₂.denote ctx := by
|
||||
simp [simp_ac_cert]; intros; subst lhs₂ lhs₂'; simp_all
|
||||
|
||||
theorem eq_simp_rhs_ac {α} (ctx : Context α) {inst₁ : Std.Associative ctx.op} {inst₂ : Std.Commutative ctx.op} (c lhs₁ rhs₁ lhs₂ rhs₂ rhs₂' : Seq)
|
||||
: simp_ac_cert c lhs₁ rhs₁ rhs₂ rhs₂' → lhs₁.denote ctx = rhs₁.denote ctx → lhs₂.denote ctx = rhs₂.denote ctx → lhs₂.denote ctx = rhs₂'.denote ctx := by
|
||||
simp [simp_ac_cert]; intros; subst rhs₂ rhs₂'; simp_all
|
||||
|
||||
theorem diseq_simp_lhs_ac {α} (ctx : Context α) {inst₁ : Std.Associative ctx.op} {inst₂ : Std.Commutative ctx.op} (c lhs₁ rhs₁ lhs₂ rhs₂ lhs₂' : Seq)
|
||||
: simp_ac_cert c lhs₁ rhs₁ lhs₂ lhs₂' → lhs₁.denote ctx = rhs₁.denote ctx → lhs₂.denote ctx ≠ rhs₂.denote ctx → lhs₂'.denote ctx ≠ rhs₂.denote ctx := by
|
||||
simp [simp_ac_cert]; intros; subst lhs₂ lhs₂'; simp_all
|
||||
|
||||
theorem diseq_simp_rhs_ac {α} (ctx : Context α) {inst₁ : Std.Associative ctx.op} {inst₂ : Std.Commutative ctx.op} (c lhs₁ rhs₁ lhs₂ rhs₂ rhs₂' : Seq)
|
||||
: simp_ac_cert c lhs₁ rhs₁ rhs₂ rhs₂' → lhs₁.denote ctx = rhs₁.denote ctx → lhs₂.denote ctx ≠ rhs₂.denote ctx → lhs₂.denote ctx ≠ rhs₂'.denote ctx := by
|
||||
simp [simp_ac_cert]; intros; subst rhs₂ rhs₂'; simp_all
|
||||
|
||||
noncomputable def superpose_ac_cert (r₁ c r₂ lhs₁ rhs₁ lhs₂ rhs₂ lhs rhs : Seq) : Bool :=
|
||||
lhs₁.beq' (c.union_k r₁) |>.and'
|
||||
(lhs₂.beq' (c.union_k r₂)) |>.and'
|
||||
(lhs.beq' (r₂.union_k rhs₁)) |>.and'
|
||||
(rhs.beq' (r₁.union_k rhs₂))
|
||||
noncomputable def superpose_ac_cert (a b c lhs₁ rhs₁ lhs₂ rhs₂ lhs rhs : Seq) : Bool :=
|
||||
lhs₁.beq' (c.union_k a) |>.and'
|
||||
(lhs₂.beq' (c.union_k b)) |>.and'
|
||||
(lhs.beq' (b.union_k rhs₁)) |>.and'
|
||||
(rhs.beq' (a.union_k rhs₂))
|
||||
|
||||
/--
|
||||
Given `lhs₁ = rhs₁` and `lhs₂ = rhs₂` where `lhs₁ := union c r₁` and `lhs₂ := union c r₂`,
|
||||
`lhs = rhs` where `lhs := union r₂ rhs₁` and `rhs := union r₁ rhs₂`
|
||||
Given `lhs₁ = rhs₁` and `lhs₂ = rhs₂` where `lhs₁ := union c a` and `lhs₂ := union c b`,
|
||||
`lhs = rhs` where `lhs := union b rhs₁` and `rhs := union a rhs₂`
|
||||
-/
|
||||
theorem superpose_ac {α} (ctx : Context α) {inst₁ : Std.Associative ctx.op} {inst₂ : Std.Commutative ctx.op} (r₁ c r₂ lhs₁ rhs₁ lhs₂ rhs₂ lhs rhs : Seq)
|
||||
: superpose_ac_cert r₁ c r₂ lhs₁ rhs₁ lhs₂ rhs₂ lhs rhs → lhs₁.denote ctx = rhs₁.denote ctx → lhs₂.denote ctx = rhs₂.denote ctx
|
||||
theorem superpose_ac {α} (ctx : Context α) {inst₁ : Std.Associative ctx.op} {inst₂ : Std.Commutative ctx.op} (a b c lhs₁ rhs₁ lhs₂ rhs₂ lhs rhs : Seq)
|
||||
: superpose_ac_cert a b c lhs₁ rhs₁ lhs₂ rhs₂ lhs rhs → lhs₁.denote ctx = rhs₁.denote ctx → lhs₂.denote ctx = rhs₂.denote ctx
|
||||
→ lhs.denote ctx = rhs.denote ctx := by
|
||||
simp [superpose_ac_cert]; intro _ _ _ _; subst lhs₁ lhs₂ lhs rhs; simp
|
||||
intro h₁ h₂; simp [← h₁, ← h₂]
|
||||
rw [← Std.Associative.assoc (self := inst₁), Std.Commutative.comm (self := inst₂) (r₂.denote ctx)]
|
||||
rw [← Std.Associative.assoc (self := inst₁), Std.Commutative.comm (self := inst₂) (r₁.denote ctx)]
|
||||
rw [← Std.Associative.assoc (self := inst₁), Std.Commutative.comm (self := inst₂) (b.denote ctx)]
|
||||
rw [← Std.Associative.assoc (self := inst₁), Std.Commutative.comm (self := inst₂) (a.denote ctx)]
|
||||
simp [Std.Associative.assoc (self := inst₁)]
|
||||
apply congrArg (ctx.op (c.denote ctx))
|
||||
rw [Std.Commutative.comm (self := inst₂) (r₂.denote ctx)]
|
||||
|
||||
noncomputable def Seq.contains_k (s : Seq) (x : Var) : Bool :=
|
||||
Seq.rec (fun y => Nat.beq x y) (fun y _ ih => Bool.or' (Nat.beq x y) ih) s
|
||||
|
||||
theorem Seq.contains_k_var (y x : Var) : Seq.contains_k (.var y) x = (x == y) := by
|
||||
simp [Seq.contains_k]; rw [Bool.eq_iff_iff]; simp
|
||||
|
||||
theorem Seq.contains_k_cons (y x : Var) (s : Seq) : Seq.contains_k (.cons y s) x = (x == y || s.contains_k x) := by
|
||||
show (Nat.beq x y |>.or' (s.contains_k x)) = (x == y || s.contains_k x)
|
||||
simp; rw [Bool.eq_iff_iff]; simp
|
||||
|
||||
attribute [local simp] Seq.contains_k_var Seq.contains_k_cons
|
||||
|
||||
theorem Seq.denote_insert_of_contains {α} (ctx : Context α) [inst₁ : Std.Associative ctx.op] [inst₂ : Std.Commutative ctx.op] [inst₃ : Std.IdempotentOp ctx.op]
|
||||
(s : Seq) (x : Var) : s.contains_k x → (s.insert x).denote ctx = s.denote ctx := by
|
||||
induction s
|
||||
next => simp; intro; subst x; rw [Std.IdempotentOp.idempotent (self := inst₃)]
|
||||
next y s ih =>
|
||||
simp; intro h; cases h
|
||||
next => subst x; rw [← Std.Associative.assoc (self := inst₁), Std.IdempotentOp.idempotent (self := inst₃)]
|
||||
next h =>
|
||||
replace ih := ih h
|
||||
simp at ih
|
||||
rw [← Std.Associative.assoc (self := inst₁), Std.Commutative.comm (self := inst₂) (x.denote ctx)]
|
||||
rw [Std.Associative.assoc (self := inst₁), ih]
|
||||
|
||||
noncomputable def superpose_ac_idempotent_cert (x : Var) (lhs₁ rhs₁ rhs : Seq) : Bool :=
|
||||
lhs₁.contains_k x |>.and' (rhs.beq' (rhs₁.insert x))
|
||||
|
||||
/-!
|
||||
Remark: see Section 4.1 of the paper "MODULARITY, COMBINATION, AC CONGRUENCE CLOSURE" to understand why
|
||||
`superpose_ac_idempotent` is needed.
|
||||
-/
|
||||
|
||||
theorem superpose_ac_idempotent {α} (ctx : Context α) {inst₁ : Std.Associative ctx.op} {inst₂ : Std.Commutative ctx.op} {inst₃ : Std.IdempotentOp ctx.op}
|
||||
(x : Var) (lhs₁ rhs₁ rhs : Seq) : superpose_ac_idempotent_cert x lhs₁ rhs₁ rhs → lhs₁.denote ctx = rhs₁.denote ctx → lhs₁.denote ctx = rhs.denote ctx := by
|
||||
simp [superpose_ac_idempotent_cert]; intro h₁ _ h₂; subst rhs
|
||||
replace h₂ : Seq.denote ctx (lhs₁.insert x) = Seq.denote ctx (rhs₁.insert x) := by
|
||||
simp [h₂]
|
||||
rw [← h₂, Seq.denote_insert_of_contains ctx lhs₁ x h₁]
|
||||
|
||||
noncomputable def Seq.startsWithVar_k (s : Seq) (x : Var) : Bool :=
|
||||
Seq.rec (fun y => Nat.beq x y) (fun y _ _ => Nat.beq x y) s
|
||||
|
||||
theorem Seq.startsWithVar_k_var (y x : Var) : Seq.startsWithVar_k (.var y) x = (x == y) := by
|
||||
simp [startsWithVar_k]; rw [Bool.eq_iff_iff]; simp
|
||||
|
||||
theorem Seq.startsWithVar_k_cons (y x : Var) (s : Seq) : Seq.startsWithVar_k (.cons y s) x = (x == y) := by
|
||||
simp [startsWithVar_k]; rw [Bool.eq_iff_iff]; simp
|
||||
|
||||
attribute [local simp] Seq.startsWithVar_k_var Seq.startsWithVar_k_cons
|
||||
|
||||
theorem Seq.denote_concat_of_startsWithVar {α} (ctx : Context α) [inst₁ : Std.Associative ctx.op] [inst₂ : Std.IdempotentOp ctx.op]
|
||||
(s : Seq) (x : Var) : s.startsWithVar_k x → (concat_k (.var x) s).denote ctx = s.denote ctx := by
|
||||
cases s <;> simp <;> intro <;> subst x
|
||||
next => rw [Std.IdempotentOp.idempotent (self := inst₂)]
|
||||
next => rw [← Std.Associative.assoc (self := inst₁), Std.IdempotentOp.idempotent (self := inst₂)]
|
||||
|
||||
noncomputable def superpose_head_idempotent_cert (x : Var) (lhs₁ rhs₁ rhs : Seq) : Bool :=
|
||||
lhs₁.startsWithVar_k x |>.and' (rhs.beq' (Seq.concat (.var x) rhs₁))
|
||||
|
||||
/--
|
||||
`superpose_ac_idempotent` for the non-commutative case. This is the "head"-case
|
||||
-/
|
||||
theorem superpose_head_idempotent {α} (ctx : Context α) {inst₁ : Std.Associative ctx.op} {inst₂ : Std.IdempotentOp ctx.op}
|
||||
(x : Var) (lhs₁ rhs₁ rhs : Seq) : superpose_head_idempotent_cert x lhs₁ rhs₁ rhs → lhs₁.denote ctx = rhs₁.denote ctx → lhs₁.denote ctx = rhs.denote ctx := by
|
||||
simp [superpose_head_idempotent_cert]; intro h₁ _ h₂; subst rhs
|
||||
replace h₂ : Seq.denote ctx (Seq.concat (.var x) lhs₁) = Seq.denote ctx (Seq.concat (.var x) rhs₁) := by
|
||||
simp [h₂]
|
||||
rw [← h₂, ← Seq.concat_k_eq_concat, Seq.denote_concat_of_startsWithVar ctx lhs₁ x h₁]
|
||||
|
||||
noncomputable def Seq.endsWithVar_k (s : Seq) (x : Var) : Bool :=
|
||||
Seq.rec (fun y => Nat.beq x y) (fun _ _ ih => ih) s
|
||||
|
||||
theorem Seq.endsWithVar_k_var (y x : Var) : Seq.endsWithVar_k (.var y) x = (x == y) := by
|
||||
simp [Seq.endsWithVar_k]; rw [Bool.eq_iff_iff]; simp
|
||||
|
||||
theorem Seq.endsWithVar_k_cons (y x : Var) (s : Seq) : Seq.endsWithVar_k (.cons y s) x = s.endsWithVar_k x := rfl
|
||||
|
||||
attribute [local simp] Seq.endsWithVar_k_var Seq.endsWithVar_k_cons
|
||||
|
||||
theorem Seq.denote_concat_of_endsWithVar {α} (ctx : Context α) [inst₁ : Std.Associative ctx.op] [inst₂ : Std.IdempotentOp ctx.op]
|
||||
(s : Seq) (x : Var) : s.endsWithVar_k x → (s.concat_k (.var x)).denote ctx = s.denote ctx := by
|
||||
induction s
|
||||
next => simp; intro; subst x; rw [Std.IdempotentOp.idempotent (self := inst₂)]
|
||||
next ih =>
|
||||
simp; intro h; replace ih := ih h
|
||||
simp at ih; rw [Std.Associative.assoc (self := inst₁), ih]
|
||||
|
||||
noncomputable def superpose_tail_idempotent_cert (x : Var) (lhs₁ rhs₁ rhs : Seq) : Bool :=
|
||||
lhs₁.endsWithVar_k x |>.and' (rhs.beq' (Seq.concat rhs₁ (.var x)))
|
||||
|
||||
/--
|
||||
`superpose_ac_idempotent` for the non-commutative case. It is similar to `superpose_head_idempotent` but for the "tail"-case
|
||||
-/
|
||||
theorem superpose_tail_idempotent {α} (ctx : Context α) {inst₁ : Std.Associative ctx.op} {inst₂ : Std.IdempotentOp ctx.op}
|
||||
(x : Var) (lhs₁ rhs₁ rhs : Seq) : superpose_tail_idempotent_cert x lhs₁ rhs₁ rhs → lhs₁.denote ctx = rhs₁.denote ctx → lhs₁.denote ctx = rhs.denote ctx := by
|
||||
simp [superpose_tail_idempotent_cert]; intro h₁ _ h₂; subst rhs
|
||||
replace h₂ : Seq.denote ctx (Seq.concat lhs₁ (.var x) ) = Seq.denote ctx (Seq.concat rhs₁ (.var x) ) := by
|
||||
simp [h₂]
|
||||
rw [← h₂, ← Seq.concat_k_eq_concat, Seq.denote_concat_of_endsWithVar ctx lhs₁ x h₁]
|
||||
rw [Std.Commutative.comm (self := inst₂) (b.denote ctx)]
|
||||
|
||||
noncomputable def eq_norm_a_cert (lhs rhs : Expr) (lhs' rhs' : Seq) : Bool :=
|
||||
lhs.toSeq.beq' lhs' |>.and' (rhs.toSeq.beq' rhs')
|
||||
@@ -669,47 +505,10 @@ theorem diseq_erase_dup {α} (ctx : Context α) {_ : Std.Associative ctx.op} {_
|
||||
(lhs rhs lhs' rhs' : Seq) : eq_erase_dup_cert lhs rhs lhs' rhs' → lhs.denote ctx ≠ rhs.denote ctx → lhs'.denote ctx ≠ rhs'.denote ctx := by
|
||||
simp [eq_erase_dup_cert]; intro _ _; subst lhs' rhs'; simp
|
||||
|
||||
theorem diseq_erase0 {α} (ctx : Context α) {_ : Std.Associative ctx.op} {_ : Std.LawfulIdentity ctx.op (Var.denote ctx 0)}
|
||||
(lhs rhs lhs' rhs' : Seq) : eq_erase0_cert lhs rhs lhs' rhs' → lhs.denote ctx ≠ rhs.denote ctx → lhs'.denote ctx ≠ rhs'.denote ctx := by
|
||||
simp [eq_erase0_cert]; intro _ _; subst lhs' rhs'; simp
|
||||
|
||||
noncomputable def diseq_unsat_cert (lhs rhs : Seq) : Bool :=
|
||||
lhs.beq' rhs
|
||||
|
||||
theorem diseq_unsat {α} (ctx : Context α) (lhs rhs : Seq) : diseq_unsat_cert lhs rhs → lhs.denote ctx ≠ rhs.denote ctx → False := by
|
||||
simp [diseq_unsat_cert]; intro; subst lhs; simp
|
||||
|
||||
theorem norm_a {α} (ctx : Context α) {_ : Std.Associative ctx.op} (e : Expr) (s : Seq)
|
||||
: e.toSeq.beq' s → e.denote ctx = s.denote ctx := by
|
||||
simp; intro _; subst s; simp
|
||||
|
||||
theorem norm_ac {α} (ctx : Context α) {_ : Std.Associative ctx.op} {_ : Std.Commutative ctx.op} (e : Expr) (s : Seq)
|
||||
: e.toSeq.sort.beq' s → e.denote ctx = s.denote ctx := by
|
||||
simp; intro _; subst s; simp
|
||||
|
||||
theorem norm_ai {α} (ctx : Context α) {_ : Std.Associative ctx.op} {_ : Std.LawfulIdentity ctx.op (Var.denote ctx 0)}
|
||||
(e : Expr) (s : Seq) : e.toSeq.erase0.beq' s → e.denote ctx = s.denote ctx := by
|
||||
simp; intro _; subst s; simp
|
||||
|
||||
theorem norm_aci {α} (ctx : Context α) {_ : Std.Associative ctx.op} {_ : Std.Commutative ctx.op} {_ : Std.LawfulIdentity ctx.op (Var.denote ctx 0)}
|
||||
(e : Expr) (s : Seq) : e.toSeq.erase0.sort.beq' s → e.denote ctx = s.denote ctx := by
|
||||
simp; intro _ ; subst s; simp
|
||||
|
||||
theorem eq_erase0_rhs {α} (ctx : Context α) {_ : Std.Associative ctx.op} {_ : Std.LawfulIdentity ctx.op (Var.denote ctx 0)}
|
||||
(lhs rhs rhs' : Seq) : rhs.erase0.beq' rhs' → lhs.denote ctx = rhs.denote ctx → lhs.denote ctx = rhs'.denote ctx := by
|
||||
simp; intro _ _; subst rhs'; simp [*]
|
||||
|
||||
theorem eq_erase_dup_rhs {α} (ctx : Context α) {_ : Std.Associative ctx.op} {_ : Std.IdempotentOp ctx.op}
|
||||
(lhs rhs rhs' : Seq) : rhs.eraseDup.beq' rhs' → lhs.denote ctx = rhs.denote ctx → lhs.denote ctx = rhs'.denote ctx := by
|
||||
simp; intro _ _; subst rhs'; simp [*]
|
||||
|
||||
theorem eq_expr_seq_seq {α} (ctx : Context α) (e : Expr) (s₁ s₂ : Seq) : e.denote ctx = s₁.denote ctx → s₁.denote ctx = s₂.denote ctx → e.denote ctx = s₂.denote ctx := by
|
||||
apply Eq.trans
|
||||
|
||||
theorem imp_eq {α} (ctx : Context α) (lhs rhs : Expr) (s : Seq)
|
||||
: lhs.denote ctx = s.denote ctx → rhs.denote ctx = s.denote ctx → lhs.denote ctx = rhs.denote ctx := by
|
||||
simp_all
|
||||
|
||||
theorem refl {α} (ctx : Context α) (s : Seq) : s.denote ctx = s.denote ctx := (rfl)
|
||||
|
||||
end Lean.Grind.AC
|
||||
|
||||
@@ -95,7 +95,7 @@ Ordinarily, the grind attribute does not consider the `=` symbol when generating
|
||||
-/
|
||||
syntax grindEqBwd := patternIgnore(atomic("←" "=") <|> atomic("<-" "="))
|
||||
/--
|
||||
The `←` modifier instructs `grind` to select a multi-pattern from the conclusion of theorem.
|
||||
The `→` modifier instructs `grind` to select a multi-pattern from the conclusion of theorem.
|
||||
In other words, `grind` will use the theorem for backwards reasoning.
|
||||
This may fail if not all of the arguments to the theorem appear in the conclusion.
|
||||
-/
|
||||
|
||||
@@ -4,9 +4,10 @@ Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Kim Morrison
|
||||
-/
|
||||
module
|
||||
|
||||
prelude
|
||||
public import Init.Grind.Module.Basic
|
||||
public import Init.Grind.Module.Envelope
|
||||
public import Init.Grind.Module.OfNatModule
|
||||
public import Init.Grind.Module.NatModuleNorm
|
||||
|
||||
public section
|
||||
|
||||
@@ -227,7 +227,7 @@ theorem toQ_add (a b : α) : toQ (a + b) = toQ a + toQ b := by
|
||||
theorem toQ_zero : toQ (0 : α) = 0 := by
|
||||
simp; apply Quot.sound; simp
|
||||
|
||||
theorem toQ_smul (n : Nat) (a : α) : toQ (n • a) = n • toQ a := by
|
||||
theorem toQ_smul (n : Nat) (a : α) : toQ (n • a) = (↑n : Int) • toQ a := by
|
||||
simp; apply Quot.sound; simp
|
||||
|
||||
/-!
|
||||
@@ -318,29 +318,6 @@ instance [LE α] [IsPreorder α] [OrderedAdd α] : IsPreorder (OfNatModule.Q α)
|
||||
rw [this]; clear this
|
||||
exact OrderedAdd.add_le_add h₁ h₂
|
||||
|
||||
instance [LE α] [IsPartialOrder α] [OrderedAdd α] : IsPartialOrder (OfNatModule.Q α) where
|
||||
le_antisymm a b h₁ h₂ := by
|
||||
induction a using Q.ind with | _ a
|
||||
induction b using Q.ind with | _ b
|
||||
rcases a with ⟨a₁, a₂⟩; rcases b with ⟨b₁, b₂⟩
|
||||
simp only [mk_le_mk] at h₁ h₂
|
||||
rw [AddCommMonoid.add_comm b₁ a₂, AddCommMonoid.add_comm b₂ a₁] at h₂
|
||||
have := IsPartialOrder.le_antisymm _ _ h₁ h₂
|
||||
apply Quot.sound
|
||||
simp; exists 0
|
||||
rw [this]
|
||||
|
||||
instance [LE α] [IsLinearPreorder α] [OrderedAdd α] : IsLinearPreorder (OfNatModule.Q α) where
|
||||
le_total a b := by
|
||||
induction a using Q.ind with | _ a
|
||||
induction b using Q.ind with | _ b
|
||||
rcases a with ⟨a₁, a₂⟩; rcases b with ⟨b₁, b₂⟩
|
||||
simp only [mk_le_mk]
|
||||
rw [AddCommMonoid.add_comm b₁ a₂, AddCommMonoid.add_comm b₂ a₁]
|
||||
apply le_total
|
||||
|
||||
instance [LE α] [IsLinearOrder α] [OrderedAdd α] : IsLinearOrder (OfNatModule.Q α) where
|
||||
|
||||
attribute [-simp] Q.mk
|
||||
|
||||
@[local simp] private theorem mk_lt_mk
|
||||
|
||||
@@ -1,199 +0,0 @@
|
||||
/-
|
||||
Copyright (c) 2025 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Leonardo de Moura
|
||||
-/
|
||||
module
|
||||
prelude
|
||||
public import Init.Grind.Module.Envelope
|
||||
public import Init.Grind.Ordered.Linarith
|
||||
@[expose] public section
|
||||
namespace Lean.Grind.Linarith
|
||||
open Std
|
||||
|
||||
def Expr.denoteN {α} [NatModule α] (ctx : Context α) : Expr → α
|
||||
| .sub .. | .neg .. | .intMul ..
|
||||
| zero => 0
|
||||
| .var v => v.denote ctx
|
||||
| .add a b => denoteN ctx a + denoteN ctx b
|
||||
| .natMul k a => k • denoteN ctx a
|
||||
|
||||
inductive Poly.NonnegCoeffs : Poly → Prop
|
||||
| nil : NonnegCoeffs .nil
|
||||
| add (a : Int) (x : Var) (p : Poly) : a ≥ 0 → NonnegCoeffs p → NonnegCoeffs (.add a x p)
|
||||
|
||||
def Poly.denoteN {α} [NatModule α] (ctx : Context α) (p : Poly) : α :=
|
||||
match p with
|
||||
| .nil => 0
|
||||
| .add k v p =>
|
||||
bif k < 0 then
|
||||
0
|
||||
else
|
||||
k.natAbs • v.denote ctx + denoteN ctx p
|
||||
|
||||
def Poly.denoteN_nil {α} [NatModule α] (ctx : Context α) : Poly.denoteN ctx .nil = 0 := rfl
|
||||
|
||||
def Poly.denoteN_add {α} [NatModule α] (ctx : Context α) (k : Int) (x : Var) (p : Poly)
|
||||
: k ≥ 0 → Poly.denoteN ctx (.add k x p) = k.toNat • x.denote ctx + p.denoteN ctx := by
|
||||
intro h; simp [denoteN, cond_eq_if]; split
|
||||
next => omega
|
||||
next =>
|
||||
have : (k.natAbs : Int) = k.toNat := by
|
||||
rw [Int.toNat_of_nonneg h, Int.natAbs_of_nonneg h]
|
||||
rw [Int.ofNat_inj.mp this]
|
||||
|
||||
attribute [local simp] Poly.denoteN_nil Poly.denoteN_add
|
||||
open AddCommMonoid AddCommGroup NatModule IntModule
|
||||
|
||||
-- Helper instance for `ac_rfl`
|
||||
local instance {α} [NatModule α] : Std.Associative (· + · : α → α → α) where
|
||||
assoc := AddCommMonoid.add_assoc
|
||||
-- Helper instance for `ac_rfl`
|
||||
local instance {α} [NatModule α] : Std.Commutative (· + · : α → α → α) where
|
||||
comm := AddCommMonoid.add_comm
|
||||
|
||||
theorem Poly.denoteN_insert {α} [NatModule α] (ctx : Context α) (k : Int) (x : Var) (p : Poly)
|
||||
: k ≥ 0 → p.NonnegCoeffs → (insert k x p).denoteN ctx = k.toNat • x.denote ctx + p.denoteN ctx := by
|
||||
fun_induction insert
|
||||
next => intros; simp [*]
|
||||
next => intro h₁ h₂; cases h₂; simp [*]
|
||||
next h₁ h₂ h₃ =>
|
||||
intro h₄ h₅; cases h₅; simp [*]
|
||||
simp at h₃; simp at h₂; subst h₂
|
||||
rw [← add_assoc, ← add_nsmul, ← Int.toNat_add, h₃, Int.toNat_zero, zero_nsmul, zero_add] <;> assumption
|
||||
next h _ =>
|
||||
intro h₁ h₂; cases h₂; rw [denoteN_add] <;> simp <;> try omega
|
||||
next h₂ _ =>
|
||||
simp at h; subst h;
|
||||
rw [Int.toNat_add h₁ h₂, add_nsmul]; simp [*]; ac_rfl
|
||||
next ih =>
|
||||
intro h₁ h₂; cases h₂; simp [*]; ac_rfl
|
||||
|
||||
attribute [local simp] Poly.denoteN_insert
|
||||
|
||||
theorem Poly.denoteN_append {α} [NatModule α] (ctx : Context α) (p₁ p₂ : Poly)
|
||||
: p₁.NonnegCoeffs → p₂.NonnegCoeffs → (append p₁ p₂).denoteN ctx = p₁.denoteN ctx + p₂.denoteN ctx := by
|
||||
fun_induction append <;> intro h₁ h₂; simp [*]
|
||||
next => rw [zero_add]
|
||||
next ih => cases h₁; next hn₁ hn₂ => simp [ih hn₂ h₂, *]; ac_rfl
|
||||
|
||||
attribute [local simp] Poly.denoteN_append
|
||||
|
||||
theorem Poly.denoteN_combine' {α} [NatModule α] (ctx : Context α) (fuel : Nat) (p₁ p₂ : Poly)
|
||||
: p₁.NonnegCoeffs → p₂.NonnegCoeffs → (p₁.combine' fuel p₂).denoteN ctx = p₁.denoteN ctx + p₂.denoteN ctx := by
|
||||
fun_induction p₁.combine' fuel p₂ <;> intro h₁ h₂ <;> try simp [*, zero_add, add_zero]
|
||||
next hx _ h ih =>
|
||||
simp at hx
|
||||
simp +zetaDelta at h
|
||||
cases h₁; cases h₂
|
||||
next h₁ _ h₂ =>
|
||||
simp [ih h₁ h₂, *]
|
||||
rw [add_left_comm, add_assoc, ← add_assoc, ← add_nsmul, ← Int.toNat_add, Int.add_comm, h,
|
||||
Int.toNat_zero, zero_nsmul, zero_add] <;> assumption
|
||||
next hx _ h ih =>
|
||||
simp at hx
|
||||
cases h₁; cases h₂
|
||||
next hp₁ h₁ hp₂ h₂ =>
|
||||
simp +zetaDelta [*]
|
||||
rw [denoteN_add, ih h₁ h₂, Int.toNat_add hp₁ hp₂, add_nsmul]; ac_rfl; omega
|
||||
next ih =>
|
||||
cases h₁; next h₁ =>
|
||||
simp [ih h₁ h₂, *]; ac_rfl
|
||||
next ih =>
|
||||
cases h₂; next h₂ =>
|
||||
simp [ih h₁ h₂, *]; ac_rfl
|
||||
|
||||
theorem Poly.denoteN_combine {α} [NatModule α] (ctx : Context α) (p₁ p₂ : Poly)
|
||||
: p₁.NonnegCoeffs → p₂.NonnegCoeffs → (p₁.combine p₂).denoteN ctx = p₁.denoteN ctx + p₂.denoteN ctx := by
|
||||
intros; simp [combine, denoteN_combine', *]
|
||||
|
||||
theorem Poly.denoteN_mul' {α} [NatModule α] (ctx : Context α) (p : Poly) (k : Nat) : p.NonnegCoeffs → (p.mul' k).denoteN ctx = k • p.denoteN ctx := by
|
||||
induction p <;> simp [mul', *, nsmul_zero]
|
||||
next ih =>
|
||||
intro h; cases h; next hp h =>
|
||||
have hk : (k : Int) ≥ 0 := by simp
|
||||
simp [*]
|
||||
rw [denoteN_add, Int.toNat_mul, mul_nsmul, Int.toNat_natCast, nsmul_add, ih h]
|
||||
assumption; assumption;
|
||||
exact Int.mul_nonneg hk hp
|
||||
|
||||
theorem Poly.denoteN_mul {α} [NatModule α] (ctx : Context α) (p : Poly) (k : Nat) : p.NonnegCoeffs → (p.mul k).denoteN ctx = k • p.denoteN ctx := by
|
||||
simp [mul]; intro h
|
||||
split
|
||||
next => simp [*, zero_nsmul]
|
||||
next => simp [denoteN_mul', *]
|
||||
|
||||
def Expr.toPolyN : Expr → Poly
|
||||
| .sub .. | .neg .. | .intMul ..
|
||||
| zero => .nil
|
||||
| .var v => .add 1 v .nil
|
||||
| .add a b => a.toPolyN.combine b.toPolyN
|
||||
| .natMul k a => a.toPolyN.mul k
|
||||
|
||||
theorem Poly.mul'_Nonneg (p : Poly) (k : Nat) : p.NonnegCoeffs → (p.mul' k).NonnegCoeffs := by
|
||||
induction p
|
||||
next => intro; simp [mul']; assumption
|
||||
next ih =>
|
||||
have hk : (k : Int) ≥ 0 := by simp
|
||||
intro h; cases h; next hp h =>
|
||||
simp [mul']
|
||||
constructor
|
||||
next => exact Int.mul_nonneg hk hp
|
||||
next => exact ih h
|
||||
|
||||
theorem Poly.mul_Nonneg (p : Poly) (k : Nat) : p.NonnegCoeffs → (p.mul k).NonnegCoeffs := by
|
||||
simp [mul]; intro h
|
||||
split
|
||||
next => constructor
|
||||
next => simp [Poly.mul'_Nonneg, *]
|
||||
|
||||
theorem Poly.append_Nonneg (p₁ p₂ : Poly) : p₁.NonnegCoeffs → p₂.NonnegCoeffs → (p₁.append p₂).NonnegCoeffs := by
|
||||
fun_induction append <;> intro h₁ h₂; simp [*]
|
||||
next ih => cases h₁; constructor; assumption; apply ih <;> assumption
|
||||
|
||||
theorem Poly.combine'_Nonneg (fuel : Nat) (p₁ p₂ : Poly) : p₁.NonnegCoeffs → p₂.NonnegCoeffs → (p₁.combine' fuel p₂).NonnegCoeffs := by
|
||||
fun_induction Poly.combine'
|
||||
next => apply Poly.append_Nonneg
|
||||
next => intros; assumption
|
||||
next => intros; assumption
|
||||
next ih =>
|
||||
intro h₁ h₂; cases h₁; cases h₂
|
||||
apply ih <;> assumption
|
||||
next h ih =>
|
||||
intro h₁ h₂; cases h₁; cases h₂
|
||||
constructor; simp +zetaDelta; omega
|
||||
apply ih <;> assumption
|
||||
next ih =>
|
||||
intro h₁ h₂; cases h₁; cases h₂
|
||||
constructor; simp +zetaDelta; omega
|
||||
apply ih; assumption; constructor; assumption; assumption
|
||||
next ih =>
|
||||
intro h₁ h₂; cases h₁; cases h₂
|
||||
constructor; assumption
|
||||
apply ih; constructor; assumption; assumption; assumption
|
||||
|
||||
theorem Poly.combine_Nonneg (p₁ p₂ : Poly) : p₁.NonnegCoeffs → p₂.NonnegCoeffs → (p₁.combine p₂).NonnegCoeffs := by
|
||||
simp [combine]; apply Poly.combine'_Nonneg
|
||||
|
||||
theorem Expr.toPolyN_Nonneg (e : Expr) : e.toPolyN.NonnegCoeffs := by
|
||||
fun_induction toPolyN <;> try constructor <;> simp
|
||||
next => constructor; simp; constructor
|
||||
next => apply Poly.combine_Nonneg <;> assumption
|
||||
next => apply Poly.mul_Nonneg; assumption
|
||||
|
||||
theorem Expr.denoteN_toPolyN {α} [NatModule α] (ctx : Context α) (e : Expr) : e.toPolyN.denoteN ctx = e.denoteN ctx := by
|
||||
fun_induction toPolyN <;> simp [denoteN, add_zero, one_nsmul]
|
||||
next => rw [Poly.denoteN_combine]; simp [*]; apply toPolyN_Nonneg; apply toPolyN_Nonneg
|
||||
next => rw [Poly.denoteN_mul]; simp [*]; apply toPolyN_Nonneg
|
||||
|
||||
def eq_normN_cert (lhs rhs : Expr) : Bool :=
|
||||
lhs.toPolyN == rhs.toPolyN
|
||||
|
||||
theorem eq_normN {α} [NatModule α] (ctx : Context α) (lhs rhs : Expr)
|
||||
: eq_normN_cert lhs rhs → lhs.denoteN ctx = rhs.denoteN ctx := by
|
||||
simp [eq_normN_cert]; intro h
|
||||
replace h := congrArg (Poly.denoteN ctx) h
|
||||
simp [Expr.denoteN_toPolyN, *] at h
|
||||
assumption
|
||||
|
||||
end Lean.Grind.Linarith
|
||||
@@ -4,12 +4,14 @@ Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Leonardo de Moura
|
||||
-/
|
||||
module
|
||||
|
||||
prelude
|
||||
public import Init.Grind.Module.Envelope
|
||||
public section
|
||||
namespace Lean.Grind.IntModule.OfNatModule
|
||||
import Init.Grind.Module.Envelope
|
||||
|
||||
open Std
|
||||
|
||||
namespace Lean.Grind.IntModule.OfNatModule
|
||||
|
||||
/-!
|
||||
Support for `NatModule` in the `grind` linear arithmetic module.
|
||||
-/
|
||||
@@ -42,7 +44,8 @@ theorem add_congr {α} [NatModule α] {a b : α} {a' b' : Q α}
|
||||
(h₁ : toQ a = a') (h₂ : toQ b = b') : toQ (a + b) = a' + b' := by
|
||||
rw [toQ_add, h₁, h₂]
|
||||
|
||||
theorem smul_congr {α} [NatModule α] (n : Nat) (a : α) (a' : Q α) (h : toQ a = a') : toQ (n • a) = n • a' := by
|
||||
rw [← h, toQ_smul]
|
||||
theorem smul_congr {α} [NatModule α] (n : Nat) (a : α) (i : Int) (a' : Q α)
|
||||
(h₁ : ↑n == i) (h₂ : toQ a = a') : toQ (n • a) = i • a' := by
|
||||
simp at h₁; rw [← h₁, ← h₂, toQ_smul]
|
||||
|
||||
end Lean.Grind.IntModule.OfNatModule
|
||||
|
||||
@@ -205,13 +205,5 @@ init_grind_norm
|
||||
Field.inv_zero Field.inv_inv Field.inv_one Field.inv_neg
|
||||
-- SMul normalizer
|
||||
smul_int_eq_mul smul_nat_eq_mul
|
||||
-- NatCast & IntCast for algebraic structures
|
||||
Semiring.natCast_add
|
||||
Semiring.natCast_pow
|
||||
Semiring.natCast_mul
|
||||
Ring.intCast_add
|
||||
Ring.intCast_mul
|
||||
Ring.intCast_pow
|
||||
Ring.intCast_sub
|
||||
|
||||
end Lean.Grind
|
||||
|
||||
@@ -7,7 +7,6 @@ module
|
||||
|
||||
prelude
|
||||
public import Init.NotationExtra
|
||||
meta import Init.Data.String.Basic
|
||||
|
||||
public section
|
||||
|
||||
|
||||
@@ -1534,7 +1534,7 @@ theorem diseq0_to_eq {α} [Field α] (a : α) : a ≠ 0 → a*a⁻¹ = 1 := by
|
||||
|
||||
private theorem of_mod_eq_0 {α} [CommRing α] {a : Int} {c : Nat} : Int.cast c = (0 : α) → a % c = 0 → (a : α) = 0 := by
|
||||
intro h h'
|
||||
have := Int.mul_ediv_add_emod a ↑c
|
||||
have := Int.ediv_add_emod a ↑c
|
||||
rw [h', Int.add_zero] at this
|
||||
replace this := congrArg (Int.cast (R := α)) this
|
||||
rw [Ring.intCast_mul] at this
|
||||
|
||||
@@ -40,7 +40,7 @@ theorem intCast_ofNat (x : Nat) : (OfNat.ofNat (α := Int) x : UInt8) = OfNat.of
|
||||
rw [Int.toNat_emod (Int.zero_le_ofNat x) (by decide)]
|
||||
erw [Int.toNat_natCast]
|
||||
rw [Int.toNat_pow_of_nonneg (by decide)]
|
||||
simp only [ofNat, BitVec.ofNat, Fin.Internal.ofNat_eq_ofNat, Fin.ofNat, Int.reduceToNat, Nat.dvd_refl,
|
||||
simp only [ofNat, BitVec.ofNat, Fin.ofNat, Int.reduceToNat, Nat.dvd_refl,
|
||||
Nat.mod_mod_of_dvd, instOfNat]
|
||||
|
||||
end UInt8
|
||||
@@ -70,7 +70,7 @@ theorem intCast_ofNat (x : Nat) : (OfNat.ofNat (α := Int) x : UInt16) = OfNat.o
|
||||
rw [Int.toNat_emod (Int.zero_le_ofNat x) (by decide)]
|
||||
erw [Int.toNat_natCast]
|
||||
rw [Int.toNat_pow_of_nonneg (by decide)]
|
||||
simp only [ofNat, BitVec.ofNat, Fin.Internal.ofNat_eq_ofNat, Fin.ofNat, Int.reduceToNat, Nat.dvd_refl,
|
||||
simp only [ofNat, BitVec.ofNat, Fin.ofNat, Int.reduceToNat, Nat.dvd_refl,
|
||||
Nat.mod_mod_of_dvd, instOfNat]
|
||||
|
||||
end UInt16
|
||||
@@ -100,7 +100,7 @@ theorem intCast_ofNat (x : Nat) : (OfNat.ofNat (α := Int) x : UInt32) = OfNat.o
|
||||
rw [Int.toNat_emod (Int.zero_le_ofNat x) (by decide)]
|
||||
erw [Int.toNat_natCast]
|
||||
rw [Int.toNat_pow_of_nonneg (by decide)]
|
||||
simp only [ofNat, BitVec.ofNat, Fin.Internal.ofNat_eq_ofNat, Fin.ofNat, Int.reduceToNat, Nat.dvd_refl,
|
||||
simp only [ofNat, BitVec.ofNat, Fin.ofNat, Int.reduceToNat, Nat.dvd_refl,
|
||||
Nat.mod_mod_of_dvd, instOfNat]
|
||||
|
||||
end UInt32
|
||||
@@ -130,7 +130,7 @@ theorem intCast_ofNat (x : Nat) : (OfNat.ofNat (α := Int) x : UInt64) = OfNat.o
|
||||
rw [Int.toNat_emod (Int.zero_le_ofNat x) (by decide)]
|
||||
erw [Int.toNat_natCast]
|
||||
rw [Int.toNat_pow_of_nonneg (by decide)]
|
||||
simp only [ofNat, BitVec.ofNat, Fin.Internal.ofNat_eq_ofNat, Fin.ofNat, Int.reduceToNat, Nat.dvd_refl,
|
||||
simp only [ofNat, BitVec.ofNat, Fin.ofNat, Int.reduceToNat, Nat.dvd_refl,
|
||||
Nat.mod_mod_of_dvd, instOfNat]
|
||||
|
||||
end UInt64
|
||||
@@ -157,7 +157,7 @@ theorem intCast_ofNat (x : Nat) : (OfNat.ofNat (α := Int) x : USize) = OfNat.of
|
||||
rw [Int.toNat_emod (Int.zero_le_ofNat x)]
|
||||
· erw [Int.toNat_natCast]
|
||||
rw [Int.toNat_pow_of_nonneg (by decide)]
|
||||
simp only [ofNat, BitVec.ofNat, Fin.Internal.ofNat_eq_ofNat, Fin.ofNat, Int.reduceToNat, Nat.dvd_refl,
|
||||
simp only [ofNat, BitVec.ofNat, Fin.ofNat, Int.reduceToNat, Nat.dvd_refl,
|
||||
Nat.mod_mod_of_dvd, instOfNat]
|
||||
· obtain _ | _ := System.Platform.numBits_eq <;> simp_all
|
||||
|
||||
|
||||
@@ -10,13 +10,7 @@ prelude
|
||||
public import Init.ByCases
|
||||
public import Init.RCases
|
||||
public import Init.Control.Except -- for `MonoBind` instance
|
||||
public import Init.Control.StateRef -- for `MonoBind` instance
|
||||
public import Init.Control.Option -- for `MonoBind` instance
|
||||
public import Init.System.IO -- for `MonoBind` instance
|
||||
import all Init.Control.Except -- for `MonoBind` instance
|
||||
import all Init.Control.StateRef -- for `MonoBind` instance
|
||||
import all Init.Control.Option -- for `MonoBind` instance
|
||||
import all Init.System.IO -- for `MonoBind` instance
|
||||
|
||||
public section
|
||||
|
||||
@@ -796,14 +790,14 @@ on `m` is monotone in both arguments with regard to that order.
|
||||
This is intended to be used in the construction of `partial_fixpoint`, and not meant to be used otherwise.
|
||||
-/
|
||||
class MonoBind (m : Type u → Type v) [Bind m] [∀ α, PartialOrder (m α)] where
|
||||
bind_mono_left {a₁ a₂ : m α} {f : α → m β} (h : a₁ ⊑ a₂) : a₁ >>= f ⊑ a₂ >>= f
|
||||
bind_mono_right {a : m α} {f₁ f₂ : α → m β} (h : ∀ x, f₁ x ⊑ f₂ x) : a >>= f₁ ⊑ a >>= f₂
|
||||
bind_mono_left {a₁ a₂ : m α} {f : α → m b} (h : a₁ ⊑ a₂) : a₁ >>= f ⊑ a₂ >>= f
|
||||
bind_mono_right {a : m α} {f₁ f₂ : α → m b} (h : ∀ x, f₁ x ⊑ f₂ x) : a >>= f₁ ⊑ a >>= f₂
|
||||
|
||||
@[partial_fixpoint_monotone]
|
||||
theorem monotone_bind
|
||||
(m : Type u → Type v) [Bind m] [∀ α, PartialOrder (m α)] [MonoBind m]
|
||||
{α β : Type u}
|
||||
{γ : Sort w} [PartialOrder γ]
|
||||
{γ : Type w} [PartialOrder γ]
|
||||
(f : γ → m α) (g : γ → α → m β)
|
||||
(hmono₁ : monotone f)
|
||||
(hmono₂ : monotone g) :
|
||||
@@ -829,9 +823,9 @@ theorem Option.admissible_eq_some (P : Prop) (y : α) :
|
||||
admissible (fun (x : Option α) => x = some y → P) := by
|
||||
apply admissible_flatOrder; simp
|
||||
|
||||
instance [inst : ∀ α, PartialOrder (m α)] : PartialOrder (ExceptT ε m α) := inst _
|
||||
instance [inst : ∀ α, CCPO (m α)] : CCPO (ExceptT ε m α) := inst _
|
||||
instance [Monad m] [∀ α, PartialOrder (m α)] [MonoBind m] : MonoBind (ExceptT ε m) where
|
||||
instance [Monad m] [inst : ∀ α, PartialOrder (m α)] : PartialOrder (ExceptT ε m α) := inst _
|
||||
instance [Monad m] [∀ α, PartialOrder (m α)] [inst : ∀ α, CCPO (m α)] : CCPO (ExceptT ε m α) := inst _
|
||||
instance [Monad m] [∀ α, PartialOrder (m α)] [∀ α, CCPO (m α)] [MonoBind m] : MonoBind (ExceptT ε m) where
|
||||
bind_mono_left h₁₂ := by
|
||||
apply MonoBind.bind_mono_left (m := m)
|
||||
exact h₁₂
|
||||
@@ -842,112 +836,6 @@ instance [Monad m] [∀ α, PartialOrder (m α)] [MonoBind m] : MonoBind (Except
|
||||
· apply PartialOrder.rel_refl
|
||||
· apply h₁₂
|
||||
|
||||
@[partial_fixpoint_monotone]
|
||||
theorem monotone_exceptTRun [PartialOrder γ]
|
||||
[Monad m] [∀ α, PartialOrder (m α)]
|
||||
(f : γ → ExceptT ε m α) (hmono : monotone f) :
|
||||
monotone (fun (x : γ) => ExceptT.run (f x)) :=
|
||||
hmono
|
||||
|
||||
instance [inst : ∀ α, PartialOrder (m α)] : PartialOrder (OptionT m α) := inst _
|
||||
instance [inst : ∀ α, CCPO (m α)] : CCPO (OptionT m α) := inst _
|
||||
instance [Monad m] [∀ α, PartialOrder (m α)] [MonoBind m] : MonoBind (OptionT m) where
|
||||
bind_mono_left h₁₂ := by
|
||||
apply MonoBind.bind_mono_left (m := m)
|
||||
exact h₁₂
|
||||
bind_mono_right h₁₂ := by
|
||||
apply MonoBind.bind_mono_right (m := m)
|
||||
intro x
|
||||
cases x
|
||||
· apply PartialOrder.rel_refl
|
||||
· apply h₁₂
|
||||
|
||||
@[partial_fixpoint_monotone]
|
||||
theorem monotone_optionTRun [PartialOrder γ]
|
||||
[Monad m] [∀ α, PartialOrder (m α)]
|
||||
(f : γ → OptionT m α) (hmono : monotone f) :
|
||||
monotone (fun (x : γ) => OptionT.run (f x)) :=
|
||||
hmono
|
||||
|
||||
instance [inst : PartialOrder (m α)] : PartialOrder (ReaderT ρ m α) := instOrderPi
|
||||
instance [inst : CCPO (m α)] : CCPO (ReaderT ρ m α) := instCCPOPi
|
||||
instance [Monad m] [∀ α, PartialOrder (m α)] [MonoBind m] : MonoBind (ReaderT ρ m) where
|
||||
bind_mono_left h₁₂ := by
|
||||
intro x
|
||||
apply MonoBind.bind_mono_left (m := m)
|
||||
exact h₁₂ x
|
||||
bind_mono_right h₁₂ := by
|
||||
intro x
|
||||
apply MonoBind.bind_mono_right (m := m)
|
||||
intro y
|
||||
apply h₁₂
|
||||
|
||||
@[partial_fixpoint_monotone]
|
||||
theorem monotone_readerTRun [PartialOrder γ]
|
||||
[Monad m] [PartialOrder (m α)]
|
||||
(f : γ → ReaderT σ m α) (hmono : monotone f) (s : σ) :
|
||||
monotone (fun (x : γ) => ReaderT.run (f x) s) :=
|
||||
monotone_apply s _ hmono
|
||||
|
||||
instance [inst : PartialOrder (m α)] : PartialOrder (StateRefT' ω σ m α) := instOrderPi
|
||||
instance [inst : CCPO (m α)] : CCPO (StateRefT' ω σ m α) := instCCPOPi
|
||||
instance [Monad m] [∀ α, PartialOrder (m α)] [MonoBind m] : MonoBind (StateRefT' ω σ m) :=
|
||||
inferInstanceAs (MonoBind (ReaderT _ _))
|
||||
|
||||
@[partial_fixpoint_monotone]
|
||||
theorem monotone_stateRefT'Run [PartialOrder γ]
|
||||
[Monad m] [MonadLiftT (ST ω) m] [∀ α, PartialOrder (m α)] [MonoBind m]
|
||||
(f : γ → StateRefT' ω σ m α) (hmono : monotone f) (s : σ) :
|
||||
monotone (fun (x : γ) => StateRefT'.run (f x) s) := by
|
||||
apply monotone_bind
|
||||
· apply monotone_const
|
||||
· refine monotone_of_monotone_apply _ fun ref => ?_
|
||||
apply monotone_bind
|
||||
· exact monotone_apply _ _ hmono
|
||||
· apply monotone_const
|
||||
|
||||
instance [inst : ∀ α, PartialOrder (m α)] : PartialOrder (StateT σ m α) := instOrderPi
|
||||
instance [inst : ∀ α, CCPO (m α)] : CCPO (StateT σ m α) := instCCPOPi
|
||||
instance [Monad m] [∀ α, PartialOrder (m α)] [MonoBind m] : MonoBind (StateT ρ m) where
|
||||
bind_mono_left h₁₂ := by
|
||||
intro x
|
||||
apply MonoBind.bind_mono_left (m := m)
|
||||
exact h₁₂ x
|
||||
bind_mono_right h₁₂ := by
|
||||
intro x
|
||||
apply MonoBind.bind_mono_right (m := m)
|
||||
intro y
|
||||
apply h₁₂
|
||||
|
||||
@[partial_fixpoint_monotone]
|
||||
theorem monotone_stateTRun [PartialOrder γ]
|
||||
[Monad m] [∀ α, PartialOrder (m α)]
|
||||
(f : γ → StateT σ m α) (hmono : monotone f) (s : σ) :
|
||||
monotone (fun (x : γ) => StateT.run (f x) s) :=
|
||||
monotone_apply s _ hmono
|
||||
|
||||
-- TODO: axiomatize these instances (ideally without `Nonempty ε`) when EIO is opaque
|
||||
noncomputable instance [Nonempty ε] : CCPO (EIO ε α) :=
|
||||
inferInstanceAs (CCPO ((s : _) → FlatOrder (.error Classical.ofNonempty (Classical.choice ⟨s⟩))))
|
||||
|
||||
noncomputable instance [Nonempty ε] : MonoBind (EIO ε) where
|
||||
bind_mono_left {_ _ a₁ a₂ f} h₁₂ := by
|
||||
intro s
|
||||
specialize h₁₂ s
|
||||
change FlatOrder.rel (a₁.bind f s) (a₂.bind f s)
|
||||
simp only [EStateM.bind]
|
||||
generalize a₁ s = a₁ at h₁₂; generalize a₂ s = a₂ at h₁₂
|
||||
cases h₁₂
|
||||
· exact .bot
|
||||
· exact .refl
|
||||
bind_mono_right {_ _ a f₁ f₂} h₁₂ := by
|
||||
intro w
|
||||
change FlatOrder.rel (a.bind f₁ w) (a.bind f₂ w)
|
||||
simp only [EStateM.bind]
|
||||
split
|
||||
· apply h₁₂
|
||||
· exact .refl
|
||||
|
||||
end mono_bind
|
||||
|
||||
section implication_order
|
||||
|
||||
@@ -47,21 +47,15 @@ opaque version.getSpecialDesc (u : Unit) : String
|
||||
def version.specialDesc : String := version.getSpecialDesc ()
|
||||
|
||||
def versionStringCore :=
|
||||
String.Internal.append
|
||||
(String.Internal.append
|
||||
(String.Internal.append
|
||||
(String.Internal.append (toString version.major) ".")
|
||||
(toString version.minor))
|
||||
".")
|
||||
(toString version.patch)
|
||||
toString version.major ++ "." ++ toString version.minor ++ "." ++ toString version.patch
|
||||
|
||||
def versionString :=
|
||||
if version.specialDesc ≠ "" then
|
||||
String.Internal.append (String.Internal.append versionStringCore "-") version.specialDesc
|
||||
versionStringCore ++ "-" ++ version.specialDesc
|
||||
else if version.isRelease then
|
||||
versionStringCore
|
||||
else
|
||||
(String.Internal.append (String.Internal.append versionStringCore ", commit ") githash)
|
||||
versionStringCore ++ ", commit " ++ githash
|
||||
|
||||
def origin :=
|
||||
"leanprover/lean4"
|
||||
@@ -69,17 +63,11 @@ def origin :=
|
||||
def toolchain :=
|
||||
if version.specialDesc ≠ "" then
|
||||
if version.isRelease then
|
||||
String.Internal.append
|
||||
(String.Internal.append
|
||||
(String.Internal.append
|
||||
(String.Internal.append origin ":")
|
||||
versionStringCore)
|
||||
"-")
|
||||
version.specialDesc
|
||||
origin ++ ":" ++ versionStringCore ++ "-" ++ version.specialDesc
|
||||
else
|
||||
String.Internal.append (String.Internal.append origin ":") version.specialDesc
|
||||
origin ++ ":" ++ version.specialDesc
|
||||
else if version.isRelease then
|
||||
String.Internal.append (String.Internal.append origin ":") versionStringCore
|
||||
origin ++ ":" ++ versionStringCore
|
||||
else
|
||||
""
|
||||
|
||||
@@ -121,22 +109,9 @@ def isSubScriptAlnum (c : Char) : Bool :=
|
||||
@[inline] def isIdFirst (c : Char) : Bool :=
|
||||
c.isAlpha || c = '_' || isLetterLike c
|
||||
|
||||
@[inline] private def isAlphaAscii (c : UInt8) : Bool :=
|
||||
'a'.toUInt8 ≤ c && c ≤ 'z'.toUInt8
|
||||
|| 'A'.toUInt8 ≤ c && c ≤ 'Z'.toUInt8
|
||||
|
||||
@[inline] def isIdFirstAscii (c : UInt8) : Bool :=
|
||||
isAlphaAscii c || c = '_'.toUInt8
|
||||
|
||||
@[inline] private def isAlphanumAscii (c : UInt8) : Bool :=
|
||||
isAlphaAscii c || '0'.toUInt8 ≤ c && c ≤ '9'.toUInt8
|
||||
|
||||
@[inline] def isIdRest (c : Char) : Bool :=
|
||||
c.isAlphanum || c = '_' || c = '\'' || c == '!' || c == '?' || isLetterLike c || isSubScriptAlnum c
|
||||
|
||||
@[inline] def isIdRestAscii (c : UInt8) : Bool :=
|
||||
isAlphanumAscii c || c = '_'.toUInt8 || c = '\''.toUInt8 || c == '!'.toUInt8 || c == '?'.toUInt8
|
||||
|
||||
def idBeginEscape := '«'
|
||||
def idEndEscape := '»'
|
||||
@[inline] def isIdBeginEscape (c : Char) : Bool := c = idBeginEscape
|
||||
@@ -152,7 +127,7 @@ def getRoot : Name → Name
|
||||
|
||||
@[export lean_is_inaccessible_user_name]
|
||||
def isInaccessibleUserName : Name → Bool
|
||||
| Name.str _ s => (String.Internal.contains s '✝') || s == "_inaccessible"
|
||||
| Name.str _ s => s.contains '✝' || s == "_inaccessible"
|
||||
| Name.num p _ => isInaccessibleUserName p
|
||||
| _ => false
|
||||
|
||||
@@ -162,65 +137,24 @@ def isInaccessibleUserName : Name → Bool
|
||||
@[extern "lean_string_get_byte_fast"]
|
||||
private opaque getUtf8Byte' (s : @& String) (n : Nat) (h : n < s.utf8ByteSize) : UInt8
|
||||
|
||||
section ToString
|
||||
|
||||
/-!
|
||||
Here we give a private implementation of `Name.toString`. The real implementation is in
|
||||
`Init.Data.ToString.Name`, which we cannot import here due to import hierarchy limitations.
|
||||
|
||||
The difference between the two versions is that this one uses the `String.Internal.*` functions,
|
||||
while the one in `Init.Data.ToString.Name` uses the public String functions. These differ in
|
||||
that the latter versions have better inferred borrowing annotations, which is significant for an
|
||||
inner-loop function like `Name.toString`.
|
||||
-/
|
||||
|
||||
-- If you change this, also change the corresponding function in `Init.Data.ToString.Name`.
|
||||
private partial def needsNoEscapeAsciiRest (s : String) (i : Nat) : Bool :=
|
||||
if h : i < s.utf8ByteSize then
|
||||
let c := getUtf8Byte' s i h
|
||||
isIdRestAscii c && needsNoEscapeAsciiRest s (i + 1)
|
||||
else
|
||||
true
|
||||
|
||||
-- If you change this, also change the corresponding function in `Init.Data.ToString.Name`.
|
||||
@[inline] private def needsNoEscapeAscii (s : String) (h : s.utf8ByteSize > 0) : Bool :=
|
||||
let c := getUtf8Byte' s 0 h
|
||||
isIdFirstAscii c && needsNoEscapeAsciiRest s 1
|
||||
|
||||
-- If you change this, also change the corresponding function in `Init.Data.ToString.Name`.
|
||||
@[inline] private def needsNoEscape (s : String) (h : s.utf8ByteSize > 0) : Bool :=
|
||||
needsNoEscapeAscii s h || isIdFirst (String.Internal.get s 0) && Substring.Internal.all (Substring.Internal.drop s.toSubstring 1) isIdRest
|
||||
|
||||
-- If you change this, also change the corresponding function in `Init.Data.ToString.Name`.
|
||||
@[inline] private def escape (s : String) : String :=
|
||||
String.Internal.append (String.Internal.append idBeginEscape.toString s) idEndEscape.toString
|
||||
|
||||
/--
|
||||
Creates a round-trippable string name component if possible, otherwise returns `none`.
|
||||
Names that are valid identifiers are not escaped, and otherwise, if they do not contain `»`, they are escaped.
|
||||
- If `force` is `true`, then even valid identifiers are escaped.
|
||||
-/
|
||||
-- If you change this, also change the corresponding function in `Init.Data.ToString.Name`.
|
||||
@[inline]
|
||||
private def Internal.Meta.escapePart (s : String) (force : Bool := false) : Option String :=
|
||||
if h : s.utf8ByteSize > 0 then
|
||||
if !force && needsNoEscape s h then
|
||||
some s
|
||||
else if String.Internal.any s isIdEndEscape then
|
||||
none
|
||||
else
|
||||
some <| escape s
|
||||
else
|
||||
some <| escape s
|
||||
def escapePart (s : String) (force : Bool := false) : Option String :=
|
||||
if s.length > 0 && !force && isIdFirst (s.get 0) && (s.toSubstring.drop 1).all isIdRest then some s
|
||||
else if s.any isIdEndEscape then none
|
||||
else some <| idBeginEscape.toString ++ s ++ idEndEscape.toString
|
||||
|
||||
variable (sep : String) (escape : Bool) in
|
||||
/--
|
||||
Uses the separator `sep` (usually `"."`) to combine the components of the `Name` into a string.
|
||||
See the documentation for `Name.toStringWithToken` for an explanation of `escape` and `isToken`.
|
||||
-/
|
||||
-- If you change this, also change the corresponding function in `Init.Data.ToString.Name`.
|
||||
@[specialize isToken] -- explicit annotation because isToken is overridden in recursive call
|
||||
private def Internal.Meta.toStringWithSep (n : Name) (isToken : String → Bool := fun _ => false) : String :=
|
||||
def toStringWithSep (n : Name) (isToken : String → Bool := fun _ => false) : String :=
|
||||
match n with
|
||||
| anonymous => "[anonymous]"
|
||||
| str anonymous s => maybeEscape s (isToken s)
|
||||
@@ -228,9 +162,9 @@ private def Internal.Meta.toStringWithSep (n : Name) (isToken : String → Bool
|
||||
| str n s =>
|
||||
-- Escape the last component if the identifier would otherwise be a token
|
||||
let r := toStringWithSep n isToken
|
||||
let r' := String.Internal.append (String.Internal.append r sep) (maybeEscape s false)
|
||||
if escape && isToken r' then String.Internal.append (String.Internal.append r sep) (maybeEscape s true) else r'
|
||||
| num n v => String.Internal.append (String.Internal.append (toStringWithSep n (isToken := fun _ => false)) sep) (Nat.repr v)
|
||||
let r' := r ++ sep ++ maybeEscape s false
|
||||
if escape && isToken r' then r ++ sep ++ maybeEscape s true else r'
|
||||
| num n v => toStringWithSep n (isToken := fun _ => false) ++ sep ++ Nat.repr v
|
||||
where
|
||||
maybeEscape s force := if escape then escapePart s force |>.getD s else s
|
||||
|
||||
@@ -246,8 +180,7 @@ Converts a name to a string.
|
||||
The insertion algorithm works so long as parser tokens do not themselves contain `«` or `»`.
|
||||
-/
|
||||
@[specialize]
|
||||
-- If you change this, also change the corresponding function in `Init.Data.ToString.Name`.
|
||||
private def Internal.Meta.toStringWithToken (n : Name) (escape := true) (isToken : String → Bool) : String :=
|
||||
def toStringWithToken (n : Name) (escape := true) (isToken : String → Bool) : String :=
|
||||
-- never escape "prettified" inaccessible names or macro scopes or pseudo-syntax introduced by the delaborator
|
||||
toStringWithSep "." (escape && !n.isInaccessibleUserName && !n.hasMacroScopes && !maybePseudoSyntax) n isToken
|
||||
where
|
||||
@@ -257,7 +190,7 @@ where
|
||||
true
|
||||
else if let .str _ s := n.getRoot then
|
||||
-- could be pseudo-syntax for loose bvar or universe mvar, output as is
|
||||
String.Internal.isPrefixOf "#" s || String.Internal.isPrefixOf "?" s
|
||||
"#".isPrefixOf s || "?".isPrefixOf s
|
||||
else
|
||||
false
|
||||
|
||||
@@ -269,11 +202,11 @@ Converts a name to a string.
|
||||
Names with number components, anonymous names, and names containing `»` might not round trip.
|
||||
Furthermore, "pseudo-syntax" produced by the delaborator, such as `_`, `#0` or `?u`, is not escaped.
|
||||
-/
|
||||
-- If you change this, also change the corresponding function in `Init.Data.ToString.Name`.
|
||||
private def Internal.Meta.toString (n : Name) (escape := true) : String :=
|
||||
toStringWithToken n escape (fun _ => false)
|
||||
protected def toString (n : Name) (escape := true) : String :=
|
||||
Name.toStringWithToken n escape (fun _ => false)
|
||||
|
||||
end ToString
|
||||
instance : ToString Name where
|
||||
toString n := n.toString
|
||||
|
||||
private def hasNum : Name → Bool
|
||||
| anonymous => false
|
||||
@@ -288,13 +221,13 @@ protected def reprPrec (n : Name) (prec : Nat) : Std.Format :=
|
||||
if p.hasNum then
|
||||
Repr.addAppParen ("Lean.Name.mkStr " ++ Name.reprPrec p max_prec ++ " " ++ repr s) prec
|
||||
else
|
||||
Std.Format.text "`" ++ Internal.Meta.toString n
|
||||
Std.Format.text "`" ++ n.toString
|
||||
|
||||
instance : Repr Name where
|
||||
reprPrec := Name.reprPrec
|
||||
|
||||
def capitalize : Name → Name
|
||||
| .str p s => .str p (String.Internal.capitalize s)
|
||||
| .str p s => .str p s.capitalize
|
||||
| n => n
|
||||
|
||||
def replacePrefix : Name → Name → Name → Name
|
||||
@@ -323,20 +256,20 @@ def eraseSuffix? : Name → Name → Option Name
|
||||
@[export lean_name_append_after]
|
||||
def appendAfter (n : Name) (suffix : String) : Name :=
|
||||
n.modifyBase fun
|
||||
| str p s => Name.mkStr p (String.Internal.append s suffix)
|
||||
| str p s => Name.mkStr p (s ++ suffix)
|
||||
| n => Name.mkStr n suffix
|
||||
|
||||
@[export lean_name_append_index_after]
|
||||
def appendIndexAfter (n : Name) (idx : Nat) : Name :=
|
||||
n.modifyBase fun
|
||||
| str p s => Name.mkStr p (String.Internal.append (String.Internal.append s "_") (toString idx))
|
||||
| n => Name.mkStr n (String.Internal.append "_" (toString idx))
|
||||
| str p s => Name.mkStr p (s ++ "_" ++ toString idx)
|
||||
| n => Name.mkStr n ("_" ++ toString idx)
|
||||
|
||||
@[export lean_name_append_before]
|
||||
def appendBefore (n : Name) (pre : String) : Name :=
|
||||
n.modifyBase fun
|
||||
| anonymous => Name.mkStr anonymous pre
|
||||
| str p s => Name.mkStr p (String.Internal.append pre s)
|
||||
| str p s => Name.mkStr p (pre ++ s)
|
||||
| num p n => Name.mkNum (Name.mkStr p pre) n
|
||||
|
||||
protected theorem beq_iff_eq {m n : Name} : m == n ↔ m = n := by
|
||||
@@ -513,7 +446,7 @@ partial def structEq : Syntax → Syntax → Bool
|
||||
| Syntax.missing, Syntax.missing => true
|
||||
| Syntax.node _ k args, Syntax.node _ k' args' => k == k' && args.isEqv args' structEq
|
||||
| Syntax.atom _ val, Syntax.atom _ val' => val == val'
|
||||
| Syntax.ident _ rawVal val preresolved, Syntax.ident _ rawVal' val' preresolved' => Substring.Internal.beq rawVal rawVal' && val == val' && preresolved == preresolved'
|
||||
| Syntax.ident _ rawVal val preresolved, Syntax.ident _ rawVal' val' preresolved' => rawVal == rawVal' && val == val' && preresolved == preresolved'
|
||||
| _, _ => false
|
||||
|
||||
instance : BEq Lean.Syntax := ⟨structEq⟩
|
||||
@@ -708,7 +641,7 @@ partial def expandMacros (stx : Syntax) (p : SyntaxNodeKind → Bool := fun k =>
|
||||
Create an identifier copying the position from `src`.
|
||||
To refer to a specific constant, use `mkCIdentFrom` instead. -/
|
||||
def mkIdentFrom (src : Syntax) (val : Name) (canonical := false) : Ident :=
|
||||
⟨Syntax.ident (SourceInfo.fromRef src canonical) (Name.Internal.Meta.toString val).toSubstring val []⟩
|
||||
⟨Syntax.ident (SourceInfo.fromRef src canonical) (toString val).toSubstring val []⟩
|
||||
|
||||
def mkIdentFromRef [Monad m] [MonadRef m] (val : Name) (canonical := false) : m Ident := do
|
||||
return mkIdentFrom (← getRef) val canonical
|
||||
@@ -720,7 +653,7 @@ def mkIdentFromRef [Monad m] [MonadRef m] (val : Name) (canonical := false) : m
|
||||
def mkCIdentFrom (src : Syntax) (c : Name) (canonical := false) : Ident :=
|
||||
-- Remark: We use the reserved macro scope to make sure there are no accidental collision with our frontend
|
||||
let id := addMacroScope `_internal c reservedMacroScope
|
||||
⟨Syntax.ident (SourceInfo.fromRef src canonical) (Name.Internal.Meta.toString id).toSubstring id [.decl c []]⟩
|
||||
⟨Syntax.ident (SourceInfo.fromRef src canonical) (toString id).toSubstring id [.decl c []]⟩
|
||||
|
||||
def mkCIdentFromRef [Monad m] [MonadRef m] (c : Name) (canonical := false) : m Syntax := do
|
||||
return mkCIdentFrom (← getRef) c canonical
|
||||
@@ -730,7 +663,7 @@ def mkCIdent (c : Name) : Ident :=
|
||||
|
||||
@[export lean_mk_syntax_ident]
|
||||
def mkIdent (val : Name) : Ident :=
|
||||
⟨Syntax.ident SourceInfo.none (Name.Internal.Meta.toString val).toSubstring val []⟩
|
||||
⟨Syntax.ident SourceInfo.none (toString val).toSubstring val []⟩
|
||||
|
||||
@[inline] def mkGroupNode (args : Array Syntax := #[]) : Syntax :=
|
||||
mkNode groupKind args
|
||||
@@ -760,11 +693,11 @@ def mkSep (a : Array Syntax) (sep : Syntax) : Syntax :=
|
||||
mkNullNode <| mkSepArray a sep
|
||||
|
||||
def SepArray.ofElems {sep} (elems : Array Syntax) : SepArray sep :=
|
||||
⟨mkSepArray elems (if String.Internal.isEmpty sep then mkNullNode else mkAtom sep)⟩
|
||||
⟨mkSepArray elems (if sep.isEmpty then mkNullNode else mkAtom sep)⟩
|
||||
|
||||
def SepArray.ofElemsUsingRef [Monad m] [MonadRef m] {sep} (elems : Array Syntax) : m (SepArray sep) := do
|
||||
let ref ← getRef;
|
||||
return ⟨mkSepArray elems (if String.Internal.isEmpty sep then mkNullNode else mkAtomFrom ref sep)⟩
|
||||
return ⟨mkSepArray elems (if sep.isEmpty then mkNullNode else mkAtomFrom ref sep)⟩
|
||||
|
||||
instance : Coe (Array Syntax) (SepArray sep) where
|
||||
coe := SepArray.ofElems
|
||||
@@ -819,55 +752,55 @@ def mkNameLit (val : String) (info := SourceInfo.none) : NameLit :=
|
||||
for Syntax objects representing these numerals. -/
|
||||
|
||||
private partial def decodeBinLitAux (s : String) (i : String.Pos) (val : Nat) : Option Nat :=
|
||||
if String.Internal.atEnd s i then some val
|
||||
if s.atEnd i then some val
|
||||
else
|
||||
let c := String.Internal.get s i
|
||||
if c == '0' then decodeBinLitAux s (String.Internal.next s i) (2*val)
|
||||
else if c == '1' then decodeBinLitAux s (String.Internal.next s i) (2*val + 1)
|
||||
else if c == '_' then decodeBinLitAux s (String.Internal.next s i) val
|
||||
let c := s.get i
|
||||
if c == '0' then decodeBinLitAux s (s.next i) (2*val)
|
||||
else if c == '1' then decodeBinLitAux s (s.next i) (2*val + 1)
|
||||
else if c == '_' then decodeBinLitAux s (s.next i) val
|
||||
else none
|
||||
|
||||
private partial def decodeOctalLitAux (s : String) (i : String.Pos) (val : Nat) : Option Nat :=
|
||||
if String.Internal.atEnd s i then some val
|
||||
if s.atEnd i then some val
|
||||
else
|
||||
let c := String.Internal.get s i
|
||||
if '0' ≤ c && c ≤ '7' then decodeOctalLitAux s (String.Internal.next s i) (8*val + c.toNat - '0'.toNat)
|
||||
else if c == '_' then decodeOctalLitAux s (String.Internal.next s i) val
|
||||
let c := s.get i
|
||||
if '0' ≤ c && c ≤ '7' then decodeOctalLitAux s (s.next i) (8*val + c.toNat - '0'.toNat)
|
||||
else if c == '_' then decodeOctalLitAux s (s.next i) val
|
||||
else none
|
||||
|
||||
private def decodeHexDigit (s : String) (i : String.Pos) : Option (Nat × String.Pos) :=
|
||||
let c := String.Internal.get s i
|
||||
let i := String.Internal.next s i
|
||||
let c := s.get i
|
||||
let i := s.next i
|
||||
if '0' ≤ c && c ≤ '9' then some (c.toNat - '0'.toNat, i)
|
||||
else if 'a' ≤ c && c ≤ 'f' then some (10 + c.toNat - 'a'.toNat, i)
|
||||
else if 'A' ≤ c && c ≤ 'F' then some (10 + c.toNat - 'A'.toNat, i)
|
||||
else none
|
||||
|
||||
private partial def decodeHexLitAux (s : String) (i : String.Pos) (val : Nat) : Option Nat :=
|
||||
if String.Internal.atEnd s i then some val
|
||||
if s.atEnd i then some val
|
||||
else match decodeHexDigit s i with
|
||||
| some (d, i) => decodeHexLitAux s i (16*val + d)
|
||||
| none =>
|
||||
if String.Internal.get s i == '_' then decodeHexLitAux s (String.Internal.next s i) val
|
||||
if s.get i == '_' then decodeHexLitAux s (s.next i) val
|
||||
else none
|
||||
|
||||
private partial def decodeDecimalLitAux (s : String) (i : String.Pos) (val : Nat) : Option Nat :=
|
||||
if String.Internal.atEnd s i then some val
|
||||
if s.atEnd i then some val
|
||||
else
|
||||
let c := String.Internal.get s i
|
||||
if '0' ≤ c && c ≤ '9' then decodeDecimalLitAux s (String.Internal.next s i) (10*val + c.toNat - '0'.toNat)
|
||||
else if c == '_' then decodeDecimalLitAux s (String.Internal.next s i) val
|
||||
let c := s.get i
|
||||
if '0' ≤ c && c ≤ '9' then decodeDecimalLitAux s (s.next i) (10*val + c.toNat - '0'.toNat)
|
||||
else if c == '_' then decodeDecimalLitAux s (s.next i) val
|
||||
else none
|
||||
|
||||
def decodeNatLitVal? (s : String) : Option Nat :=
|
||||
let len := String.Internal.length s
|
||||
let len := s.length
|
||||
if len == 0 then none
|
||||
else
|
||||
let c := String.Internal.get s 0
|
||||
let c := s.get 0
|
||||
if c == '0' then
|
||||
if len == 1 then some 0
|
||||
else
|
||||
let c := String.Internal.get s ⟨1⟩
|
||||
let c := s.get ⟨1⟩
|
||||
if c == 'x' || c == 'X' then decodeHexLitAux s ⟨2⟩ 0
|
||||
else if c == 'b' || c == 'B' then decodeBinLitAux s ⟨2⟩ 0
|
||||
else if c == 'o' || c == 'O' then decodeOctalLitAux s ⟨2⟩ 0
|
||||
@@ -903,16 +836,16 @@ def isFieldIdx? (s : Syntax) : Option Nat :=
|
||||
`n * 10^-e` if `sign` else `n * 10^e`.
|
||||
-/
|
||||
partial def decodeScientificLitVal? (s : String) : Option (Nat × Bool × Nat) :=
|
||||
let len := String.Internal.length s
|
||||
let len := s.length
|
||||
if len == 0 then none
|
||||
else
|
||||
let c := String.Internal.get s 0
|
||||
let c := s.get 0
|
||||
if c.isDigit then
|
||||
decode 0 0
|
||||
else none
|
||||
where
|
||||
decodeAfterExp (i : String.Pos) (val : Nat) (e : Nat) (sign : Bool) (exp : Nat) : Option (Nat × Bool × Nat) :=
|
||||
if String.Internal.atEnd s i then
|
||||
if s.atEnd i then
|
||||
if sign then
|
||||
some (val, sign, exp + e)
|
||||
else if exp >= e then
|
||||
@@ -920,51 +853,51 @@ where
|
||||
else
|
||||
some (val, true, e - exp)
|
||||
else
|
||||
let c := String.Internal.get s i
|
||||
let c := s.get i
|
||||
if '0' ≤ c && c ≤ '9' then
|
||||
decodeAfterExp (String.Internal.next s i) val e sign (10*exp + c.toNat - '0'.toNat)
|
||||
decodeAfterExp (s.next i) val e sign (10*exp + c.toNat - '0'.toNat)
|
||||
else if c == '_' then
|
||||
decodeAfterExp (String.Internal.next s i) val e sign exp
|
||||
decodeAfterExp (s.next i) val e sign exp
|
||||
else
|
||||
none
|
||||
|
||||
decodeExp (i : String.Pos) (val : Nat) (e : Nat) : Option (Nat × Bool × Nat) :=
|
||||
if String.Internal.atEnd s i then none else
|
||||
let c := String.Internal.get s i
|
||||
if s.atEnd i then none else
|
||||
let c := s.get i
|
||||
if c == '-' then
|
||||
decodeAfterExp (String.Internal.next s i) val e true 0
|
||||
decodeAfterExp (s.next i) val e true 0
|
||||
else if c == '+' then
|
||||
decodeAfterExp (String.Internal.next s i) val e false 0
|
||||
decodeAfterExp (s.next i) val e false 0
|
||||
else
|
||||
decodeAfterExp i val e false 0
|
||||
|
||||
decodeAfterDot (i : String.Pos) (val : Nat) (e : Nat) : Option (Nat × Bool × Nat) :=
|
||||
if String.Internal.atEnd s i then
|
||||
if s.atEnd i then
|
||||
some (val, true, e)
|
||||
else
|
||||
let c := String.Internal.get s i
|
||||
let c := s.get i
|
||||
if '0' ≤ c && c ≤ '9' then
|
||||
decodeAfterDot (String.Internal.next s i) (10*val + c.toNat - '0'.toNat) (e+1)
|
||||
decodeAfterDot (s.next i) (10*val + c.toNat - '0'.toNat) (e+1)
|
||||
else if c == '_' then
|
||||
decodeAfterDot (String.Internal.next s i) val e
|
||||
decodeAfterDot (s.next i) val e
|
||||
else if c == 'e' || c == 'E' then
|
||||
decodeExp (String.Internal.next s i) val e
|
||||
decodeExp (s.next i) val e
|
||||
else
|
||||
none
|
||||
|
||||
decode (i : String.Pos) (val : Nat) : Option (Nat × Bool × Nat) :=
|
||||
if String.Internal.atEnd s i then
|
||||
if s.atEnd i then
|
||||
none
|
||||
else
|
||||
let c := String.Internal.get s i
|
||||
let c := s.get i
|
||||
if '0' ≤ c && c ≤ '9' then
|
||||
decode (String.Internal.next s i) (10*val + c.toNat - '0'.toNat)
|
||||
decode (s.next i) (10*val + c.toNat - '0'.toNat)
|
||||
else if c == '_' then
|
||||
decode (String.Internal.next s i) val
|
||||
decode (s.next i) val
|
||||
else if c == '.' then
|
||||
decodeAfterDot (String.Internal.next s i) val 0
|
||||
decodeAfterDot (s.next i) val 0
|
||||
else if c == 'e' || c == 'E' then
|
||||
decodeExp (String.Internal.next s i) val 0
|
||||
decodeExp (s.next i) val 0
|
||||
else
|
||||
none
|
||||
|
||||
@@ -975,7 +908,7 @@ def isScientificLit? (stx : Syntax) : Option (Nat × Bool × Nat) :=
|
||||
|
||||
def isIdOrAtom? : Syntax → Option String
|
||||
| Syntax.atom _ val => some val
|
||||
| Syntax.ident _ rawVal _ _ => some (Substring.Internal.toString rawVal)
|
||||
| Syntax.ident _ rawVal _ _ => some rawVal.toString
|
||||
| _ => none
|
||||
|
||||
def toNat (stx : Syntax) : Nat :=
|
||||
@@ -984,8 +917,8 @@ def toNat (stx : Syntax) : Nat :=
|
||||
| none => 0
|
||||
|
||||
def decodeQuotedChar (s : String) (i : String.Pos) : Option (Char × String.Pos) := do
|
||||
let c := String.Internal.get s i
|
||||
let i := String.Internal.next s i
|
||||
let c := s.get i
|
||||
let i := s.next i
|
||||
if c == '\\' then pure ('\\', i)
|
||||
else if c = '\"' then pure ('\"', i)
|
||||
else if c = '\'' then pure ('\'', i)
|
||||
@@ -1012,25 +945,25 @@ the more restrictive `"\" newline whitespace*` since this simplifies the impleme
|
||||
Justification: this does not overlap with any other sequences beginning with `\`.
|
||||
-/
|
||||
def decodeStringGap (s : String) (i : String.Pos) : Option String.Pos := do
|
||||
guard <| (String.Internal.get s i).isWhitespace
|
||||
some <| String.Internal.nextWhile s Char.isWhitespace (String.Internal.next s i)
|
||||
guard <| (s.get i).isWhitespace
|
||||
some <| s.nextWhile Char.isWhitespace (s.next i)
|
||||
|
||||
partial def decodeStrLitAux (s : String) (i : String.Pos) (acc : String) : Option String := do
|
||||
let c := String.Internal.get s i
|
||||
let i := String.Internal.next s i
|
||||
let c := s.get i
|
||||
let i := s.next i
|
||||
if c == '\"' then
|
||||
pure acc
|
||||
else if String.Internal.atEnd s i then
|
||||
else if s.atEnd i then
|
||||
none
|
||||
else if c == '\\' then do
|
||||
if let some (c, i) := decodeQuotedChar s i then
|
||||
decodeStrLitAux s i (String.push acc c)
|
||||
decodeStrLitAux s i (acc.push c)
|
||||
else if let some i := decodeStringGap s i then
|
||||
decodeStrLitAux s i acc
|
||||
else
|
||||
none
|
||||
else
|
||||
decodeStrLitAux s i (String.push acc c)
|
||||
decodeStrLitAux s i (acc.push c)
|
||||
|
||||
/--
|
||||
Takes a raw string literal, counts the number of `#`'s after the `r`, and interprets it as a string.
|
||||
@@ -1039,12 +972,12 @@ The algorithm is simple: we are given `r##...#"...string..."##...#` with zero or
|
||||
By counting the number of leading `#`'s, we can extract the `...string...`.
|
||||
-/
|
||||
partial def decodeRawStrLitAux (s : String) (i : String.Pos) (num : Nat) : String :=
|
||||
let c := String.Internal.get s i
|
||||
let i := String.Internal.next s i
|
||||
let c := s.get i
|
||||
let i := s.next i
|
||||
if c == '#' then
|
||||
decodeRawStrLitAux s i (num + 1)
|
||||
else
|
||||
String.Internal.extract s i ⟨s.utf8ByteSize - (num + 1)⟩
|
||||
s.extract i ⟨s.utf8ByteSize - (num + 1)⟩
|
||||
|
||||
/--
|
||||
Takes the string literal lexical syntax parsed by the parser and interprets it as a string.
|
||||
@@ -1055,7 +988,7 @@ If it returns `none` then the string literal is ill-formed, which indicates a bu
|
||||
The function is not required to return `none` if the string literal is ill-formed.
|
||||
-/
|
||||
def decodeStrLit (s : String) : Option String :=
|
||||
if String.Internal.get s 0 == 'r' then
|
||||
if s.get 0 == 'r' then
|
||||
some <| decodeRawStrLitAux s ⟨1⟩ 0
|
||||
else
|
||||
decodeStrLitAux s ⟨1⟩ ""
|
||||
@@ -1072,7 +1005,7 @@ def isStrLit? (stx : Syntax) : Option String :=
|
||||
| _ => none
|
||||
|
||||
def decodeCharLit (s : String) : Option Char := do
|
||||
let c := String.Internal.get s ⟨1⟩
|
||||
let c := s.get ⟨1⟩
|
||||
if c == '\\' then do
|
||||
let (c, _) ← decodeQuotedChar s ⟨2⟩
|
||||
pure c
|
||||
@@ -1086,26 +1019,26 @@ def isCharLit? (stx : Syntax) : Option Char :=
|
||||
|
||||
private partial def splitNameLitAux (ss : Substring) (acc : List Substring) : List Substring :=
|
||||
let splitRest (ss : Substring) (acc : List Substring) : List Substring :=
|
||||
if Substring.Internal.front ss == '.' then
|
||||
splitNameLitAux (Substring.Internal.drop ss 1) acc
|
||||
else if Substring.Internal.isEmpty ss then
|
||||
if ss.front == '.' then
|
||||
splitNameLitAux (ss.drop 1) acc
|
||||
else if ss.isEmpty then
|
||||
acc
|
||||
else
|
||||
[]
|
||||
if Substring.Internal.isEmpty ss then []
|
||||
if ss.isEmpty then []
|
||||
else
|
||||
let curr := Substring.Internal.front ss
|
||||
let curr := ss.front
|
||||
if isIdBeginEscape curr then
|
||||
let escapedPart := Substring.Internal.takeWhile ss (!isIdEndEscape ·)
|
||||
let escapedPart := { escapedPart with stopPos := String.Pos.Internal.min ss.stopPos (String.Internal.next escapedPart.str escapedPart.stopPos) }
|
||||
if !isIdEndEscape (Substring.Internal.get escapedPart <| Substring.Internal.prev escapedPart ⟨escapedPart.bsize⟩) then []
|
||||
else splitRest (Substring.Internal.extract ss ⟨escapedPart.bsize⟩ ⟨ss.bsize⟩) (escapedPart :: acc)
|
||||
let escapedPart := ss.takeWhile (!isIdEndEscape ·)
|
||||
let escapedPart := { escapedPart with stopPos := ss.stopPos.min (escapedPart.str.next escapedPart.stopPos) }
|
||||
if !isIdEndEscape (escapedPart.get <| escapedPart.prev ⟨escapedPart.bsize⟩) then []
|
||||
else splitRest (ss.extract ⟨escapedPart.bsize⟩ ⟨ss.bsize⟩) (escapedPart :: acc)
|
||||
else if isIdFirst curr then
|
||||
let idPart := Substring.Internal.takeWhile ss isIdRest
|
||||
splitRest (Substring.Internal.extract ss ⟨idPart.bsize⟩ ⟨ss.bsize⟩) (idPart :: acc)
|
||||
let idPart := ss.takeWhile isIdRest
|
||||
splitRest (ss.extract ⟨idPart.bsize⟩ ⟨ss.bsize⟩) (idPart :: acc)
|
||||
else if curr.isDigit then
|
||||
let idPart := Substring.Internal.takeWhile ss Char.isDigit
|
||||
splitRest (Substring.Internal.extract ss ⟨idPart.bsize⟩ ⟨ss.bsize⟩) (idPart :: acc)
|
||||
let idPart := ss.takeWhile Char.isDigit
|
||||
splitRest (ss.extract ⟨idPart.bsize⟩ ⟨ss.bsize⟩) (idPart :: acc)
|
||||
else
|
||||
[]
|
||||
|
||||
@@ -1126,10 +1059,10 @@ def _root_.Substring.toName (s : Substring) : Name :=
|
||||
| [] => .anonymous
|
||||
| comps => comps.foldr (init := Name.anonymous)
|
||||
fun comp n =>
|
||||
let comp := Substring.Internal.toString comp
|
||||
if isIdBeginEscape (String.Internal.front comp) then
|
||||
Name.mkStr n (String.Internal.dropRight (String.Internal.drop comp 1) 1)
|
||||
else if (String.Internal.front comp).isDigit then
|
||||
let comp := comp.toString
|
||||
if isIdBeginEscape comp.front then
|
||||
Name.mkStr n (comp.drop 1 |>.dropRight 1)
|
||||
else if comp.front.isDigit then
|
||||
if let some k := decodeNatLitVal? comp then
|
||||
Name.mkNum n k
|
||||
else
|
||||
@@ -1147,8 +1080,8 @@ def _root_.String.toName (s : String) : Name :=
|
||||
s.toSubstring.toName
|
||||
|
||||
def decodeNameLit (s : String) : Option Name :=
|
||||
if String.Internal.get s 0 == '`' then
|
||||
match (Substring.Internal.drop s.toSubstring 1).toName with
|
||||
if s.get 0 == '`' then
|
||||
match (s.toSubstring.drop 1).toName with
|
||||
| .anonymous => none
|
||||
| name => some name
|
||||
else
|
||||
@@ -1168,7 +1101,7 @@ def isAtom : Syntax → Bool
|
||||
| _ => false
|
||||
|
||||
def isToken (token : String) : Syntax → Bool
|
||||
| atom _ val => String.Internal.trim val == String.Internal.trim token
|
||||
| atom _ val => val.trim == token.trim
|
||||
| _ => false
|
||||
|
||||
def isNone (stx : Syntax) : Bool :=
|
||||
@@ -1266,7 +1199,7 @@ end TSyntax
|
||||
def HygieneInfo.mkIdent (s : HygieneInfo) (val : Name) (canonical := false) : Ident :=
|
||||
let src := s.raw[0]
|
||||
let id := { extractMacroScopes src.getId with name := val.eraseMacroScopes }.review
|
||||
⟨Syntax.ident (SourceInfo.fromRef src canonical) (Name.Internal.Meta.toString val).toSubstring id []⟩
|
||||
⟨Syntax.ident (SourceInfo.fromRef src canonical) (toString val).toSubstring id []⟩
|
||||
|
||||
/-- Reflect a runtime datum back to surface syntax (best-effort). -/
|
||||
class Quote (α : Type) (k : SyntaxNodeKind := `term) where
|
||||
@@ -1282,13 +1215,13 @@ instance : Quote Bool := ⟨fun | true => mkCIdent ``Bool.true | false => mkCIde
|
||||
instance : Quote Char charLitKind := ⟨Syntax.mkCharLit⟩
|
||||
instance : Quote String strLitKind := ⟨Syntax.mkStrLit⟩
|
||||
instance : Quote Nat numLitKind := ⟨fun n => Syntax.mkNumLit <| toString n⟩
|
||||
instance : Quote Substring := ⟨fun s => Syntax.mkCApp ``String.toSubstring' #[quote (Substring.Internal.toString s)]⟩
|
||||
instance : Quote Substring := ⟨fun s => Syntax.mkCApp ``String.toSubstring' #[quote s.toString]⟩
|
||||
|
||||
-- in contrast to `Name.toString`, we can, and want to be, precise here
|
||||
private def getEscapedNameParts? (acc : List String) : Name → Option (List String)
|
||||
| Name.anonymous => if acc.isEmpty then none else some acc
|
||||
| Name.str n s => do
|
||||
let s ← Name.Internal.Meta.escapePart s false
|
||||
let s ← Name.escapePart s
|
||||
getEscapedNameParts? (s::acc) n
|
||||
| Name.num _ _ => none
|
||||
|
||||
@@ -1300,7 +1233,7 @@ def quoteNameMk : Name → Term
|
||||
instance : Quote Name `term where
|
||||
quote n := private
|
||||
match getEscapedNameParts? [] n with
|
||||
| some ss => ⟨mkNode `Lean.Parser.Term.quotedName #[Syntax.mkNameLit (String.Internal.append "`" (String.Internal.intercalate "." ss))]⟩
|
||||
| some ss => ⟨mkNode `Lean.Parser.Term.quotedName #[Syntax.mkNameLit ("`" ++ ".".intercalate ss)]⟩
|
||||
| none => ⟨quoteNameMk n⟩
|
||||
|
||||
instance [Quote α `term] [Quote β `term] : Quote (α × β) `term where
|
||||
@@ -1324,7 +1257,7 @@ where
|
||||
if h : i < xs.size then
|
||||
go (i+1) (args.push (quote xs[i]))
|
||||
else
|
||||
Syntax.mkCApp (Name.mkStr2 "Array" (String.Internal.append "mkArray" (toString xs.size))) args
|
||||
Syntax.mkCApp (Name.mkStr2 "Array" ("mkArray" ++ toString xs.size)) args
|
||||
termination_by xs.size - i
|
||||
decreasing_by decreasing_trivial_pre_omega
|
||||
|
||||
@@ -1482,28 +1415,28 @@ private def decodeInterpStrQuotedChar (s : String) (i : String.Pos) : Option (Ch
|
||||
match decodeQuotedChar s i with
|
||||
| some r => some r
|
||||
| none =>
|
||||
let c := String.Internal.get s i
|
||||
let i := String.Internal.next s i
|
||||
let c := s.get i
|
||||
let i := s.next i
|
||||
if c == '{' then pure ('{', i)
|
||||
else none
|
||||
|
||||
private partial def decodeInterpStrLit (s : String) : Option String :=
|
||||
let rec loop (i : String.Pos) (acc : String) : Option String :=
|
||||
let c := String.Internal.get s i
|
||||
let i := String.Internal.next s i
|
||||
let c := s.get i
|
||||
let i := s.next i
|
||||
if c == '\"' || c == '{' then
|
||||
pure acc
|
||||
else if String.Internal.atEnd s i then
|
||||
else if s.atEnd i then
|
||||
none
|
||||
else if c == '\\' then do
|
||||
if let some (c, i) := decodeInterpStrQuotedChar s i then
|
||||
loop i (String.push acc c)
|
||||
loop i (acc.push c)
|
||||
else if let some i := decodeStringGap s i then
|
||||
loop i acc
|
||||
else
|
||||
none
|
||||
else
|
||||
loop i (String.push acc c)
|
||||
loop i (acc.push c)
|
||||
loop ⟨1⟩ ""
|
||||
|
||||
partial def isInterpolatedStrLit? (stx : Syntax) : Option String :=
|
||||
@@ -1539,7 +1472,7 @@ def expandInterpolatedStr (interpStr : TSyntax interpolatedStrKind) (type : Term
|
||||
|
||||
def getDocString (stx : TSyntax `Lean.Parser.Command.docComment) : String :=
|
||||
match stx.raw[1] with
|
||||
| Syntax.atom _ val => String.Internal.extract val 0 (String.Pos.Internal.sub val.endPos ⟨2⟩)
|
||||
| Syntax.atom _ val => val.extract 0 (val.endPos - ⟨2⟩)
|
||||
| _ => ""
|
||||
|
||||
end TSyntax
|
||||
|
||||
@@ -44,11 +44,8 @@ deriving BEq, DecidableEq, Repr
|
||||
|
||||
namespace Constraint
|
||||
|
||||
private local instance : Append String where
|
||||
append := String.Internal.append
|
||||
|
||||
instance : ToString Constraint where
|
||||
toString := private fun
|
||||
toString := fun
|
||||
| ⟨none, none⟩ => "(-∞, ∞)"
|
||||
| ⟨none, some y⟩ => s!"(-∞, {y}]"
|
||||
| ⟨some x, none⟩ => s!"[{x}, ∞)"
|
||||
|
||||
@@ -124,7 +124,7 @@ theorem ofNat_natAbs (a : Int) : (a.natAbs : Int) = if 0 ≤ a then a else -a :=
|
||||
split <;> rename_i n
|
||||
· simp only [Int.ofNat_eq_coe]
|
||||
rw [if_pos (Int.natCast_nonneg n)]
|
||||
· simp
|
||||
· simp; rfl
|
||||
|
||||
theorem natAbs_dichotomy {a : Int} : 0 ≤ a ∧ a.natAbs = a ∨ a < 0 ∧ a.natAbs = -a := by
|
||||
by_cases h : 0 ≤ a
|
||||
|
||||
@@ -33,15 +33,9 @@ deriving DecidableEq, Repr
|
||||
|
||||
namespace LinearCombo
|
||||
|
||||
private def join (l : List String) : String :=
|
||||
l.foldl (init := "") (fun sofar next => String.Internal.append sofar next)
|
||||
|
||||
private local instance : Append String where
|
||||
append := String.Internal.append
|
||||
|
||||
instance : ToString LinearCombo where
|
||||
toString lc := private
|
||||
s!"{lc.const}{join <| lc.coeffs.toList.zipIdx.map fun ⟨c, i⟩ => s!" + {c} * x{i+1}"}"
|
||||
toString lc :=
|
||||
s!"{lc.const}{String.join <| lc.coeffs.toList.zipIdx.map fun ⟨c, i⟩ => s!" + {c} * x{i+1}"}"
|
||||
|
||||
instance : Inhabited LinearCombo := ⟨{const := 1}⟩
|
||||
|
||||
|
||||
@@ -141,9 +141,6 @@ unsafe axiom lcErased : Type
|
||||
/-- Marker for type dependency that has been erased by the code generator. -/
|
||||
unsafe axiom lcAny : Type
|
||||
|
||||
/-- Internal representation of `IO.RealWorld` in the compiler. -/
|
||||
unsafe axiom lcRealWorld : Type
|
||||
|
||||
/--
|
||||
Auxiliary unsafe constant used by the Compiler when erasing proofs from code.
|
||||
|
||||
@@ -1181,7 +1178,7 @@ propositional connective is `Not : Prop → Prop`.
|
||||
|
||||
export Bool (or and not)
|
||||
|
||||
set_option genCtorIdx false in
|
||||
set_option genInjectivity false in
|
||||
/--
|
||||
The natural numbers, starting at zero.
|
||||
|
||||
@@ -1781,20 +1778,6 @@ theorem Nat.ne_of_beq_eq_false : {n m : Nat} → Eq (beq n m) false → Not (Eq
|
||||
have : Eq (beq n m) false := h₁
|
||||
Nat.noConfusion h₂ (fun h₂ => absurd h₂ (ne_of_beq_eq_false this))
|
||||
|
||||
|
||||
private theorem noConfusion_of_Nat.aux : (a : Nat) → (Nat.beq a a).rec False True
|
||||
| Nat.zero => True.intro
|
||||
| Nat.succ n => noConfusion_of_Nat.aux n
|
||||
|
||||
/--
|
||||
A helper theorem to deduce `False` from `a = b` when `f a ≠ f b` for some function `f : α → Nat`
|
||||
(typically `.ctorIdx`). Used as a simpler alternative to the no-confusion theorems.
|
||||
-/
|
||||
theorem noConfusion_of_Nat {α : Sort u} (f : α → Nat) {a b : α} (h : Eq a b) :
|
||||
(Nat.beq (f a) (f b)).rec False True :=
|
||||
congrArg f h ▸ noConfusion_of_Nat.aux (f a)
|
||||
|
||||
|
||||
/--
|
||||
A decision procedure for equality of natural numbers, usually accessed via the `DecidableEq Nat`
|
||||
instance.
|
||||
@@ -1882,9 +1865,6 @@ protected theorem Nat.le_trans {n m k : Nat} : LE.le n m → LE.le m k → LE.le
|
||||
| h, Nat.le.refl => h
|
||||
| h₁, Nat.le.step h₂ => Nat.le.step (Nat.le_trans h₁ h₂)
|
||||
|
||||
protected theorem Nat.lt_of_lt_of_le {n m k : Nat} : LT.lt n m → LE.le m k → LT.lt n k :=
|
||||
Nat.le_trans
|
||||
|
||||
protected theorem Nat.lt_trans {n m k : Nat} (h₁ : LT.lt n m) : LT.lt m k → LT.lt n k :=
|
||||
Nat.le_trans (le_step h₁)
|
||||
|
||||
@@ -1988,27 +1968,6 @@ theorem Nat.ble_eq_true_of_le (h : LE.le n m) : Eq (Nat.ble n m) true :=
|
||||
theorem Nat.not_le_of_not_ble_eq_true (h : Not (Eq (Nat.ble n m) true)) : Not (LE.le n m) :=
|
||||
fun h' => absurd (Nat.ble_eq_true_of_le h') h
|
||||
|
||||
theorem Nat.lt_succ_of_le {n m : Nat} : LE.le n m → LT.lt n (succ m) := succ_le_succ
|
||||
|
||||
protected theorem Nat.lt_add_one (n : Nat) : LT.lt n (HAdd.hAdd n 1) := Nat.le_refl (succ n)
|
||||
|
||||
theorem Nat.lt_succ_self (n : Nat) : LT.lt n (succ n) := Nat.lt_add_one _
|
||||
|
||||
protected theorem Nat.lt_of_not_le {a b : Nat} (h : Not (LE.le a b)) : LT.lt b a :=
|
||||
(Nat.lt_or_ge b a).resolve_right h
|
||||
|
||||
protected theorem Nat.add_pos_right :
|
||||
{b : Nat} → (a : Nat) → (hb : LT.lt 0 b) → LT.lt 0 (HAdd.hAdd a b)
|
||||
| succ _, _, _ => Nat.zero_lt_succ _
|
||||
|
||||
protected theorem Nat.mul_pos :
|
||||
{n m : Nat} → (hn : LT.lt 0 n) → (hm : LT.lt 0 m) → LT.lt 0 (HMul.hMul n m)
|
||||
| _, succ _, ha, _ => Nat.add_pos_right _ ha
|
||||
|
||||
protected theorem Nat.pow_pos {a : Nat} : {n : Nat} → (h : LT.lt 0 a) → LT.lt 0 (HPow.hPow a n)
|
||||
| zero, _ => Nat.zero_lt_succ _
|
||||
| succ _, h => Nat.mul_pos (Nat.pow_pos h) h
|
||||
|
||||
/--
|
||||
A decision procedure for non-strict inequality of natural numbers, usually accessed via the
|
||||
`DecidableLE Nat` instance.
|
||||
@@ -2062,161 +2021,7 @@ protected def Nat.sub : (@& Nat) → (@& Nat) → Nat
|
||||
instance instSubNat : Sub Nat where
|
||||
sub := Nat.sub
|
||||
|
||||
theorem Nat.succ_sub_succ_eq_sub (n m : Nat) : Eq (HSub.hSub (succ n) (succ m)) (HSub.hSub n m) :=
|
||||
m.rec rfl (fun _ ih => congrArg pred ih)
|
||||
|
||||
theorem Nat.pred_le : ∀ (n : Nat), LE.le (Nat.pred n) n
|
||||
| zero => Nat.le.refl
|
||||
| succ _ => le_succ _
|
||||
|
||||
theorem Nat.sub_le (n m : Nat) : LE.le (HSub.hSub n m) n :=
|
||||
m.rec (Nat.le_refl _) (fun _ ih => Nat.le_trans (pred_le _) ih)
|
||||
|
||||
theorem Nat.sub_lt : ∀ {n m : Nat}, LT.lt 0 n → LT.lt 0 m → LT.lt (HSub.hSub n m) n
|
||||
| 0, _, h1, _ => absurd h1 (Nat.lt_irrefl 0)
|
||||
| Nat.succ _, 0, _, h2 => absurd h2 (Nat.lt_irrefl 0)
|
||||
| Nat.succ n, Nat.succ m, _, _ =>
|
||||
Eq.symm (succ_sub_succ_eq_sub n m) ▸
|
||||
show LT.lt (HSub.hSub n m) (succ n) from
|
||||
lt_succ_of_le (sub_le n m)
|
||||
|
||||
theorem Nat.div_rec_lemma {x y : Nat} :
|
||||
(And (LT.lt 0 y) (LE.le y x)) → LT.lt (HSub.hSub x y) x :=
|
||||
fun ⟨ypos, ylex⟩ => sub_lt (Nat.lt_of_lt_of_le ypos ylex) ypos
|
||||
|
||||
theorem Nat.div_rec_fuel_lemma {x y fuel : Nat} (hy : LT.lt 0 y) (hle : LE.le y x)
|
||||
(hfuel : LT.lt x (HAdd.hAdd fuel 1)) : LT.lt (HSub.hSub x y) fuel :=
|
||||
Nat.lt_of_lt_of_le (div_rec_lemma ⟨hy, hle⟩) (Nat.le_of_lt_succ hfuel)
|
||||
|
||||
set_option bootstrap.genMatcherCode false in
|
||||
/--
|
||||
Division of natural numbers, discarding the remainder. Division by `0` returns `0`. Usually accessed
|
||||
via the `/` operator.
|
||||
|
||||
This operation is sometimes called “floor division.”
|
||||
|
||||
This function is overridden at runtime with an efficient implementation. This definition is
|
||||
the logical model.
|
||||
|
||||
Examples:
|
||||
* `21 / 3 = 7`
|
||||
* `21 / 5 = 4`
|
||||
* `0 / 22 = 0`
|
||||
* `5 / 0 = 0`
|
||||
-/
|
||||
@[extern "lean_nat_div", irreducible]
|
||||
protected def Nat.div (x y : @& Nat) : Nat :=
|
||||
dite (LT.lt 0 y) (fun hy =>
|
||||
let rec
|
||||
go (fuel : Nat) (x : Nat) (hfuel : LT.lt x fuel) : Nat :=
|
||||
match fuel with
|
||||
| succ fuel =>
|
||||
dite (LE.le y x)
|
||||
(fun h => HAdd.hAdd (go fuel (HSub.hSub x y) (div_rec_fuel_lemma hy h hfuel)) 1)
|
||||
(fun _ => 0)
|
||||
termination_by structural fuel
|
||||
go (succ x) x (Nat.lt_succ_self _))
|
||||
(fun _ => 0)
|
||||
|
||||
instance Nat.instDiv : Div Nat := ⟨Nat.div⟩
|
||||
|
||||
set_option bootstrap.genMatcherCode false in
|
||||
/--
|
||||
The modulo operator, which computes the remainder when dividing one natural number by another.
|
||||
Usually accessed via the `%` operator. When the divisor is `0`, the result is the dividend rather
|
||||
than an error.
|
||||
|
||||
This is the core implementation of `Nat.mod`. It computes the correct result for any two closed
|
||||
natural numbers, but it does not have some convenient [definitional
|
||||
reductions](lean-manual://section/type-system) when the `Nat`s contain free variables. The wrapper
|
||||
`Nat.mod` handles those cases specially and then calls `Nat.modCore`.
|
||||
|
||||
This function is overridden at runtime with an efficient implementation. This definition is the
|
||||
logical model.
|
||||
-/
|
||||
@[extern "lean_nat_mod"]
|
||||
protected noncomputable def Nat.modCore (x y : Nat) : Nat :=
|
||||
dite (LT.lt 0 y)
|
||||
(fun hy =>
|
||||
let rec
|
||||
go (fuel : Nat) (x : Nat) (hfuel : LT.lt x fuel) : Nat :=
|
||||
match fuel with
|
||||
| succ fuel =>
|
||||
dite (LE.le y x)
|
||||
(fun h => go fuel (HSub.hSub x y) (div_rec_fuel_lemma hy h hfuel))
|
||||
(fun _ => x)
|
||||
termination_by structural fuel
|
||||
go (succ x) x (Nat.lt_succ_self _))
|
||||
(fun _ => x)
|
||||
|
||||
theorem Nat.modCoreGo_lt {fuel y : Nat} (hy : LT.lt 0 y) : (x : Nat) → (hfuel : LT.lt x fuel) →
|
||||
LT.lt (Nat.modCore.go y hy fuel x hfuel) y :=
|
||||
fuel.rec (fun _ h => absurd h (Nat.not_lt_zero _))
|
||||
(fun _ ih x _ =>
|
||||
show LT.lt (dite _ _ _) _ from
|
||||
match Nat.decLe y x with
|
||||
| .isTrue _ => ih _ _
|
||||
| .isFalse h => Nat.lt_of_not_le h)
|
||||
|
||||
theorem Nat.modCore_lt {x y : Nat} (hy : LT.lt 0 y) : LT.lt (Nat.modCore x y) y :=
|
||||
show LT.lt (dite _ _ _) y from
|
||||
match Nat.decLt 0 y with
|
||||
| .isTrue _ => Nat.modCoreGo_lt hy x (Nat.lt_succ_self _)
|
||||
| .isFalse h => absurd hy h
|
||||
|
||||
attribute [irreducible] Nat.modCore
|
||||
|
||||
set_option bootstrap.genMatcherCode false in
|
||||
/--
|
||||
The modulo operator, which computes the remainder when dividing one natural number by another.
|
||||
Usually accessed via the `%` operator. When the divisor is `0`, the result is the dividend rather
|
||||
than an error.
|
||||
|
||||
`Nat.mod` is a wrapper around `Nat.modCore` that special-cases two situations, giving better
|
||||
definitional reductions:
|
||||
* `Nat.mod 0 m` should reduce to `m`, for all terms `m : Nat`.
|
||||
* `Nat.mod n (m + n + 1)` should reduce to `n` for concrete `Nat` literals `n`.
|
||||
|
||||
These reductions help `Fin n` literals work well, because the `OfNat` instance for `Fin` uses
|
||||
`Nat.mod`. In particular, `(0 : Fin (n + 1)).val` should reduce definitionally to `0`. `Nat.modCore`
|
||||
can handle all numbers, but its definitional reductions are not as convenient.
|
||||
|
||||
This function is overridden at runtime with an efficient implementation. This definition is the
|
||||
logical model.
|
||||
|
||||
Examples:
|
||||
* `7 % 2 = 1`
|
||||
* `9 % 3 = 0`
|
||||
* `5 % 7 = 5`
|
||||
* `5 % 0 = 5`
|
||||
* `show ∀ (n : Nat), 0 % n = 0 from fun _ => rfl`
|
||||
* `show ∀ (m : Nat), 5 % (m + 6) = 5 from fun _ => rfl`
|
||||
-/
|
||||
@[extern "lean_nat_mod"]
|
||||
protected def Nat.mod : @& Nat → @& Nat → Nat
|
||||
/-
|
||||
Nat.modCore is defined with fuel and thus does not reduce with open terms very well.
|
||||
Nevertheless it is desirable for trivial `Nat.mod` calculations, namely
|
||||
* `Nat.mod 0 m` for all `m`
|
||||
* `Nat.mod n (m + n + 1)` for concrete literals `n`,
|
||||
to reduce definitionally.
|
||||
This property is desirable for `Fin n` literals, as it means `(ofNat 0 : Fin n).val = 0` by
|
||||
definition.
|
||||
-/
|
||||
| 0, _ => 0
|
||||
| n@(succ _), m => ite (LE.le m n) (Nat.modCore n m) n
|
||||
|
||||
instance Nat.instMod : Mod Nat := ⟨Nat.mod⟩
|
||||
|
||||
theorem Nat.mod_lt : (x : Nat) → {y : Nat} → (hy : LT.lt 0 y) → LT.lt (HMod.hMod x y) y
|
||||
| 0, succ _, _ => Nat.zero_lt_succ _
|
||||
| succ n, m, hm =>
|
||||
show LT.lt (ite (LE.le m (succ n)) (Nat.modCore (succ n) m) (succ n)) _ from
|
||||
match Nat.decLe m (succ n) with
|
||||
| .isTrue _ => Nat.modCore_lt hm
|
||||
| .isFalse h => Nat.lt_of_not_le h
|
||||
|
||||
attribute [gen_constructor_elims] Nat
|
||||
gen_injective_theorems% Nat
|
||||
|
||||
/--
|
||||
Gets the word size of the current platform. The word size may be 64 or 32 bits.
|
||||
@@ -2285,14 +2090,6 @@ instance {n} : LE (Fin n) where
|
||||
instance Fin.decLt {n} (a b : Fin n) : Decidable (LT.lt a b) := Nat.decLt ..
|
||||
instance Fin.decLe {n} (a b : Fin n) : Decidable (LE.le a b) := Nat.decLe ..
|
||||
|
||||
/--
|
||||
Returns `a` modulo `n` as a `Fin n`.
|
||||
|
||||
This function exists for bootstrapping purposes. Use `Fin.ofNat` instead.
|
||||
-/
|
||||
@[expose] protected def Fin.Internal.ofNat (n : Nat) (hn : LT.lt 0 n) (a : Nat) : Fin n :=
|
||||
⟨HMod.hMod a n, Nat.mod_lt _ hn⟩
|
||||
|
||||
/--
|
||||
A bitvector of the specified width.
|
||||
|
||||
@@ -2329,13 +2126,6 @@ instance : DecidableEq (BitVec w) := BitVec.decEq
|
||||
protected def BitVec.ofNatLT {w : Nat} (i : Nat) (p : LT.lt i (hPow 2 w)) : BitVec w where
|
||||
toFin := ⟨i, p⟩
|
||||
|
||||
/--
|
||||
The bitvector with value `i mod 2^n`.
|
||||
-/
|
||||
@[expose, match_pattern]
|
||||
protected def BitVec.ofNat (n : Nat) (i : Nat) : BitVec n where
|
||||
toFin := Fin.Internal.ofNat (HPow.hPow 2 n) (Nat.pow_pos (Nat.zero_lt_succ _)) i
|
||||
|
||||
/--
|
||||
Return the underlying `Nat` that represents a bitvector.
|
||||
|
||||
@@ -2355,6 +2145,7 @@ instance (x y : BitVec w) : Decidable (LE.le x y) :=
|
||||
/-- The number of distinct values representable by `UInt8`, that is, `2^8 = 256`. -/
|
||||
abbrev UInt8.size : Nat := 256
|
||||
|
||||
set_option genInjectivity false in
|
||||
/--
|
||||
Unsigned 8-bit integers.
|
||||
|
||||
@@ -2384,21 +2175,6 @@ This function is overridden at runtime with an efficient implementation.
|
||||
def UInt8.ofNatLT (n : @& Nat) (h : LT.lt n UInt8.size) : UInt8 where
|
||||
toBitVec := BitVec.ofNatLT n h
|
||||
|
||||
/--
|
||||
Converts a natural number to an 8-bit unsigned integer, wrapping on overflow.
|
||||
|
||||
This function is overridden at runtime with an efficient implementation.
|
||||
|
||||
Examples:
|
||||
* `UInt8.ofNat 5 = 5`
|
||||
* `UInt8.ofNat 255 = 255`
|
||||
* `UInt8.ofNat 256 = 0`
|
||||
* `UInt8.ofNat 259 = 3`
|
||||
* `UInt8.ofNat 32770 = 2`
|
||||
-/
|
||||
@[extern "lean_uint8_of_nat"]
|
||||
def UInt8.ofNat (n : @& Nat) : UInt8 := ⟨BitVec.ofNat 8 n⟩
|
||||
|
||||
set_option bootstrap.genMatcherCode false in
|
||||
/--
|
||||
Decides whether two 8-bit unsigned integers are equal. Usually accessed via the `DecidableEq UInt8`
|
||||
@@ -2424,55 +2200,10 @@ instance : DecidableEq UInt8 := UInt8.decEq
|
||||
instance : Inhabited UInt8 where
|
||||
default := UInt8.ofNatLT 0 (of_decide_eq_true rfl)
|
||||
|
||||
/--
|
||||
Strict inequality of 8-bit unsigned integers, defined as inequality of the corresponding
|
||||
natural numbers. Usually accessed via the `<` operator.
|
||||
-/
|
||||
protected def UInt8.lt (a b : UInt8) : Prop := LT.lt a.toBitVec b.toBitVec
|
||||
/--
|
||||
Non-strict inequality of 8-bit unsigned integers, defined as inequality of the corresponding
|
||||
natural numbers. Usually accessed via the `≤` operator.
|
||||
-/
|
||||
protected def UInt8.le (a b : UInt8) : Prop := LE.le a.toBitVec b.toBitVec
|
||||
instance : LT UInt8 := ⟨UInt8.lt⟩
|
||||
instance : LE UInt8 := ⟨UInt8.le⟩
|
||||
|
||||
/--
|
||||
Decides whether one 8-bit unsigned integer is strictly less than another. Usually accessed via the
|
||||
`DecidableLT UInt8` instance.
|
||||
|
||||
This function is overridden at runtime with an efficient implementation.
|
||||
|
||||
Examples:
|
||||
* `(if (6 : UInt8) < 7 then "yes" else "no") = "yes"`
|
||||
* `(if (5 : UInt8) < 5 then "yes" else "no") = "no"`
|
||||
* `show ¬((7 : UInt8) < 7) by decide`
|
||||
-/
|
||||
@[extern "lean_uint8_dec_lt"]
|
||||
def UInt8.decLt (a b : UInt8) : Decidable (LT.lt a b) :=
|
||||
inferInstanceAs (Decidable (LT.lt a.toBitVec b.toBitVec))
|
||||
|
||||
/--
|
||||
Decides whether one 8-bit unsigned integer is less than or equal to another. Usually accessed via the
|
||||
`DecidableLE UInt8` instance.
|
||||
|
||||
This function is overridden at runtime with an efficient implementation.
|
||||
|
||||
Examples:
|
||||
* `(if (15 : UInt8) ≤ 15 then "yes" else "no") = "yes"`
|
||||
* `(if (15 : UInt8) ≤ 5 then "yes" else "no") = "no"`
|
||||
* `(if (5 : UInt8) ≤ 15 then "yes" else "no") = "yes"`
|
||||
* `show (7 : UInt8) ≤ 7 by decide`
|
||||
-/
|
||||
@[extern "lean_uint8_dec_le"]
|
||||
def UInt8.decLe (a b : UInt8) : Decidable (LE.le a b) :=
|
||||
inferInstanceAs (Decidable (LE.le a.toBitVec b.toBitVec))
|
||||
|
||||
attribute [instance] UInt8.decLt UInt8.decLe
|
||||
|
||||
/-- The number of distinct values representable by `UInt16`, that is, `2^16 = 65536`. -/
|
||||
abbrev UInt16.size : Nat := 65536
|
||||
|
||||
set_option genInjectivity false in
|
||||
/--
|
||||
Unsigned 16-bit integers.
|
||||
|
||||
@@ -2531,6 +2262,7 @@ instance : Inhabited UInt16 where
|
||||
/-- The number of distinct values representable by `UInt32`, that is, `2^32 = 4294967296`. -/
|
||||
abbrev UInt32.size : Nat := 4294967296
|
||||
|
||||
set_option genInjectivity false in
|
||||
/--
|
||||
Unsigned 32-bit integers.
|
||||
|
||||
@@ -2636,6 +2368,7 @@ instance : Min UInt32 := minOfLe
|
||||
/-- The number of distinct values representable by `UInt64`, that is, `2^64 = 18446744073709551616`. -/
|
||||
abbrev UInt64.size : Nat := 18446744073709551616
|
||||
|
||||
set_option genInjectivity false in
|
||||
/--
|
||||
Unsigned 64-bit integers.
|
||||
|
||||
@@ -2705,6 +2438,7 @@ theorem USize.size_pos : LT.lt 0 USize.size :=
|
||||
| _, Or.inl rfl => of_decide_eq_true rfl
|
||||
| _, Or.inr rfl => of_decide_eq_true rfl
|
||||
|
||||
set_option genInjectivity false in
|
||||
/--
|
||||
Unsigned integers that are the size of a word on the platform's architecture.
|
||||
|
||||
@@ -3009,37 +2743,7 @@ def List.concat {α : Type u} : List α → α → List α
|
||||
| nil, b => cons b nil
|
||||
| cons a as, b => cons a (concat as b)
|
||||
|
||||
/--
|
||||
Returns the sequence of bytes in a character's UTF-8 encoding.
|
||||
-/
|
||||
def String.utf8EncodeChar (c : Char) : List UInt8 :=
|
||||
let v := c.val.toNat
|
||||
ite (LE.le v 0x7f)
|
||||
(List.cons (UInt8.ofNat v) List.nil)
|
||||
(ite (LE.le v 0x7ff)
|
||||
(List.cons
|
||||
(UInt8.ofNat (HAdd.hAdd (HMod.hMod (HDiv.hDiv v 64) 0x20) 0xc0))
|
||||
(List.cons
|
||||
(UInt8.ofNat (HAdd.hAdd (HMod.hMod v 0x40) 0x80))
|
||||
List.nil))
|
||||
(ite (LE.le v 0xffff)
|
||||
(List.cons
|
||||
(UInt8.ofNat (HAdd.hAdd (HMod.hMod (HDiv.hDiv v 4096) 0x10) 0xe0))
|
||||
(List.cons
|
||||
(UInt8.ofNat (HAdd.hAdd (HMod.hMod (HDiv.hDiv v 64) 0x40) 0x80))
|
||||
(List.cons
|
||||
(UInt8.ofNat (HAdd.hAdd (HMod.hMod v 0x40) 0x80))
|
||||
List.nil)))
|
||||
(List.cons
|
||||
(UInt8.ofNat (HAdd.hAdd (HMod.hMod (HDiv.hDiv v 262144) 0x08) 0xf0))
|
||||
(List.cons
|
||||
(UInt8.ofNat (HAdd.hAdd (HMod.hMod (HDiv.hDiv v 4096) 0x40) 0x80))
|
||||
(List.cons
|
||||
(UInt8.ofNat (HAdd.hAdd (HMod.hMod (HDiv.hDiv v 64) 0x40) 0x80))
|
||||
(List.cons
|
||||
(UInt8.ofNat (HAdd.hAdd (HMod.hMod v 0x40) 0x80))
|
||||
List.nil))))))
|
||||
|
||||
set_option genInjectivity false in
|
||||
/--
|
||||
A string is a sequence of Unicode code points.
|
||||
|
||||
@@ -3223,6 +2927,7 @@ def panic {α : Sort u} [Inhabited α] (msg : String) : α :=
|
||||
-- TODO: this be applied directly to `Inhabited`'s definition when we remove the above workaround
|
||||
attribute [nospecialize] Inhabited
|
||||
|
||||
set_option genInjectivity false in
|
||||
/--
|
||||
`Array α` is the type of [dynamic arrays](https://en.wikipedia.org/wiki/Dynamic_array) with elements
|
||||
from `α`. This type has special support in the runtime.
|
||||
@@ -4847,7 +4552,7 @@ abbrev scientificLitKind : SyntaxNodeKind := `scientific
|
||||
/-- `` `name `` is the node kind of name literals like `` `foo ``. -/
|
||||
abbrev nameLitKind : SyntaxNodeKind := `name
|
||||
|
||||
/-- `` `fieldIdx `` is the node kind of projection indices like the `2` in `x.2`. -/
|
||||
/-- `` `fieldIdx ` is the node kind of projection indices like the `2` in `x.2`. -/
|
||||
abbrev fieldIdxKind : SyntaxNodeKind := `fieldIdx
|
||||
|
||||
/--
|
||||
|
||||
@@ -7,7 +7,6 @@ module
|
||||
|
||||
prelude
|
||||
public import Init.NotationExtra
|
||||
import Init.Data.ToString.Name
|
||||
|
||||
public section
|
||||
|
||||
|
||||
@@ -8,7 +8,6 @@ module
|
||||
prelude
|
||||
public import Init.System.Platform
|
||||
public import Init.Data.ToString.Basic
|
||||
public import Init.Data.String.Basic
|
||||
|
||||
public section
|
||||
|
||||
|
||||
@@ -16,16 +16,15 @@ public section
|
||||
|
||||
open System
|
||||
|
||||
opaque IO.RealWorld.nonemptyType : NonemptyType.{0}
|
||||
|
||||
/--
|
||||
A representation of “the real world” that's used in `IO` monads to ensure that `IO` actions are not
|
||||
reordered.
|
||||
-/
|
||||
@[expose] def IO.RealWorld : Type := IO.RealWorld.nonemptyType.type
|
||||
/- Like <https://hackage.haskell.org/package/ghc-Prim-0.5.2.0/docs/GHC-Prim.html#t:RealWorld>.
|
||||
Makes sure we never reorder `IO` operations.
|
||||
|
||||
instance IO.RealWorld.instNonempty : Nonempty IO.RealWorld :=
|
||||
by exact IO.RealWorld.nonemptyType.property
|
||||
TODO: mark opaque -/
|
||||
@[expose] def IO.RealWorld : Type := Unit
|
||||
|
||||
/--
|
||||
A monad that can have side effects on the external world or throw exceptions of type `ε`.
|
||||
@@ -153,7 +152,7 @@ duplicate, or delete calls to this function. The side effect may even be hoisted
|
||||
causing the side effect to occur at initialization time, even if it would otherwise never be called.
|
||||
-/
|
||||
@[noinline] unsafe def unsafeBaseIO (fn : BaseIO α) : α :=
|
||||
match fn.run (unsafeCast Unit.unit) with
|
||||
match fn.run () with
|
||||
| EStateM.Result.ok a _ => a
|
||||
|
||||
/--
|
||||
|
||||
@@ -8,7 +8,6 @@ module
|
||||
|
||||
prelude
|
||||
public import Init.Data.ToString.Basic
|
||||
import Init.Data.String.Basic
|
||||
|
||||
public section
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ module
|
||||
|
||||
prelude
|
||||
public import Init.Data.Nat.Basic
|
||||
public import Init.Data.String.Bootstrap
|
||||
public import Init.Data.String.Basic
|
||||
|
||||
public section
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ Authors: Leonardo de Moura
|
||||
module
|
||||
|
||||
prelude
|
||||
public import Init.Data.String.Basic
|
||||
public import Init.Data.ToString.Basic
|
||||
|
||||
public section
|
||||
@@ -34,41 +35,13 @@ def dbgStackTrace {α : Type u} (f : Unit → α) : α := f ()
|
||||
def dbgSleep {α : Type u} (ms : UInt32) (f : Unit → α) : α := f ()
|
||||
|
||||
@[noinline] def mkPanicMessage (modName : String) (line col : Nat) (msg : String) : String :=
|
||||
String.Internal.append
|
||||
(String.Internal.append
|
||||
(String.Internal.append
|
||||
(String.Internal.append
|
||||
(String.Internal.append
|
||||
(String.Internal.append
|
||||
(String.Internal.append "PANIC at " modName)
|
||||
":")
|
||||
(toString line))
|
||||
":")
|
||||
(toString col))
|
||||
": ")
|
||||
msg
|
||||
"PANIC at " ++ modName ++ ":" ++ toString line ++ ":" ++ toString col ++ ": " ++ msg
|
||||
|
||||
@[never_extract, inline, expose] def panicWithPos {α : Sort u} [Inhabited α] (modName : String) (line col : Nat) (msg : String) : α :=
|
||||
panic (mkPanicMessage modName line col msg)
|
||||
|
||||
@[noinline, expose] def mkPanicMessageWithDecl (modName : String) (declName : String) (line col : Nat) (msg : String) : String :=
|
||||
String.Internal.append
|
||||
(String.Internal.append
|
||||
(String.Internal.append
|
||||
(String.Internal.append
|
||||
(String.Internal.append
|
||||
(String.Internal.append
|
||||
(String.Internal.append
|
||||
(String.Internal.append
|
||||
(String.Internal.append "PANIC at " declName)
|
||||
" ")
|
||||
modName)
|
||||
":")
|
||||
(toString line))
|
||||
":")
|
||||
(toString col))
|
||||
": ")
|
||||
msg
|
||||
"PANIC at " ++ declName ++ " " ++ modName ++ ":" ++ toString line ++ ":" ++ toString col ++ ": " ++ msg
|
||||
|
||||
@[never_extract, inline, expose] def panicWithPosWithDecl {α : Sort u} [Inhabited α] (modName : String) (declName : String) (line col : Nat) (msg : String) : α :=
|
||||
panic (mkPanicMessageWithDecl modName declName line col msg)
|
||||
|
||||
@@ -7,7 +7,6 @@ module
|
||||
|
||||
prelude
|
||||
public import Lean.CoreM
|
||||
public import Lean.Meta.Sorry
|
||||
public import Lean.Namespace
|
||||
public import Lean.Util.CollectAxioms
|
||||
|
||||
@@ -76,28 +75,6 @@ register_builtin_option warn.sorry : Bool := {
|
||||
descr := "warn about uses of `sorry` in declarations added to the environment"
|
||||
}
|
||||
|
||||
/--
|
||||
If the `warn.sorry` option is set to true and there are no errors in the log already,
|
||||
logs a warning if the declaration uses `sorry`.
|
||||
-/
|
||||
def warnIfUsesSorry (decl : Declaration) : CoreM Unit := do
|
||||
if warn.sorry.get (← getOptions) then
|
||||
if !(← MonadLog.hasErrors) && decl.hasSorry then
|
||||
-- Find an actual sorry expression to use for 'sorry'.
|
||||
-- That way the user can hover over it to see its type and use "go to definition" if it is a labeled sorry.
|
||||
let findSorry : StateRefT (Array (Bool × MessageData)) MetaM Unit := decl.forEachSorryM fun s => do
|
||||
let s' ← addMessageContext s
|
||||
modify fun arr => arr.push (s.isSyntheticSorry, s')
|
||||
let (_, sorries) ← findSorry |>.run #[] |>.run'
|
||||
-- Prefer reporting a synthetic sorry.
|
||||
-- These can appear without logged errors if `decl` is referring to declarations with elaboration errors;
|
||||
-- that's where a user should direct their focus.
|
||||
if let some (_, s) := sorries.find? (·.1) <|> sorries[0]? then
|
||||
logWarning <| .tagged `hasSorry m!"declaration uses '{s}'"
|
||||
else
|
||||
-- This case should not happen, but it ensures a warning will get logged no matter what.
|
||||
logWarning <| .tagged `hasSorry m!"declaration uses 'sorry'"
|
||||
|
||||
def addDecl (decl : Declaration) : CoreM Unit := do
|
||||
-- register namespaces for newly added constants; this used to be done by the kernel itself
|
||||
-- but that is incompatible with moving it to a separate task
|
||||
@@ -166,7 +143,9 @@ where
|
||||
doAdd := do
|
||||
profileitM Exception "type checking" (← getOptions) do
|
||||
withTraceNode `Kernel (return m!"{exceptEmoji ·} typechecking declarations {decl.getTopLevelNames}") do
|
||||
warnIfUsesSorry decl
|
||||
if warn.sorry.get (← getOptions) then
|
||||
if !(← MonadLog.hasErrors) && decl.hasSorry then
|
||||
logWarning <| .tagged `hasSorry m!"declaration uses 'sorry'"
|
||||
try
|
||||
let env ← (← getEnv).addDeclAux (← getOptions) decl (← read).cancelTk?
|
||||
|> ofExceptKernelException
|
||||
|
||||
@@ -165,10 +165,8 @@ def registerTagAttribute (name : Name) (descr : String)
|
||||
mkInitial := pure {}
|
||||
addImportedFn := fun _ _ => pure {}
|
||||
addEntryFn := fun (s : NameSet) n => s.insert n
|
||||
exportEntriesFnEx := fun env es _ =>
|
||||
exportEntriesFn := fun es =>
|
||||
let r : Array Name := es.foldl (fun a e => a.push e) #[]
|
||||
-- Do not export info for private defs
|
||||
let r := r.filter (env.contains (skipRealize := false))
|
||||
r.qsort Name.quickLt
|
||||
statsFn := fun s => "tag attribute" ++ Format.line ++ "number of local entries: " ++ format s.size
|
||||
asyncMode := asyncMode
|
||||
@@ -234,10 +232,8 @@ def registerParametricAttribute (impl : ParametricAttributeImpl α) : IO (Parame
|
||||
mkInitial := pure {}
|
||||
addImportedFn := fun s => impl.afterImport s *> pure {}
|
||||
addEntryFn := fun (s : NameMap α) (p : Name × α) => s.insert p.1 p.2
|
||||
exportEntriesFnEx := fun env m _ =>
|
||||
exportEntriesFn := fun m =>
|
||||
let r : Array (Name × α) := m.foldl (fun a n p => a.push (n, p)) #[]
|
||||
-- Do not export info for private defs
|
||||
let r := r.filter (env.contains (skipRealize := false) ·.1)
|
||||
r.qsort (fun a b => Name.quickLt a.1 b.1)
|
||||
statsFn := fun s => "parametric attribute" ++ Format.line ++ "number of local entries: " ++ format s.size
|
||||
}
|
||||
@@ -293,10 +289,8 @@ def registerEnumAttributes (attrDescrs : List (Name × String × α))
|
||||
mkInitial := pure {}
|
||||
addImportedFn := fun _ _ => pure {}
|
||||
addEntryFn := fun (s : NameMap α) (p : Name × α) => s.insert p.1 p.2
|
||||
exportEntriesFnEx := fun env m _ =>
|
||||
exportEntriesFn := fun m =>
|
||||
let r : Array (Name × α) := m.foldl (fun a n p => a.push (n, p)) #[]
|
||||
-- Do not export info for private defs
|
||||
let r := r.filter (env.contains (skipRealize := false) ·.1)
|
||||
r.qsort (fun a b => Name.quickLt a.1 b.1)
|
||||
statsFn := fun s => "enumeration attribute extension" ++ Format.line ++ "number of local entries: " ++ format s.size
|
||||
-- We assume (and check in `modifyState`) that, if used asynchronously, enum attributes are set
|
||||
|
||||
@@ -37,11 +37,10 @@ builtin_initialize ext : SimpleScopedEnvExtension Entry State ←
|
||||
}
|
||||
|
||||
private def isConstantReplacement? (declName : Name) : CoreM (Option Entry) := do
|
||||
let info ← getConstVal declName
|
||||
let info ← getConstInfo declName
|
||||
match info.type.eq? with
|
||||
| some (_, Expr.const fromDeclName us, Expr.const toDeclName vs) =>
|
||||
let set := Std.HashSet.ofList us
|
||||
if set.size == us.length && set.all Level.isParam && us == vs then
|
||||
| some (_, Expr.const fromDeclName us .., Expr.const toDeclName vs ..) =>
|
||||
if us == vs then
|
||||
return some { fromDeclName, toDeclName, thmName := declName }
|
||||
else
|
||||
return none
|
||||
|
||||
@@ -8,7 +8,6 @@ module
|
||||
prelude
|
||||
public import Init.Data.Array.Basic
|
||||
public import Init.System.FilePath
|
||||
import Init.Data.String.Basic
|
||||
|
||||
public section
|
||||
|
||||
|
||||
@@ -153,13 +153,14 @@ partial def lowerLet (decl : LCNF.LetDecl) (k : LCNF.Code) : M FnBody := do
|
||||
lowerCode k
|
||||
| .const name _ args =>
|
||||
let irArgs ← args.mapM lowerArg
|
||||
if let some decl ← findDecl name then
|
||||
return (← mkApplication name decl.params.size irArgs)
|
||||
if let some decl ← LCNF.getMonoDecl? name then
|
||||
return (← mkApplication name decl.params.size irArgs)
|
||||
if let some code ← tryIrDecl? name irArgs then
|
||||
return code
|
||||
let env ← Lean.getEnv
|
||||
match env.find? name with
|
||||
| some (.ctorInfo ctorVal) =>
|
||||
if isExtern env name then
|
||||
return (← mkFap name irArgs)
|
||||
|
||||
let type ← nameToIRType ctorVal.induct
|
||||
if type.isScalar then
|
||||
let var ← bindVar decl.fvarId
|
||||
@@ -243,14 +244,18 @@ where
|
||||
return .vdecl tmpVar .object (.fap name firstArgs) <|
|
||||
.vdecl var type (.ap tmpVar restArgs) (← lowerCode k)
|
||||
|
||||
mkApplication (name : Name) (numParams : Nat) (args : Array Arg) : M FnBody := do
|
||||
let numArgs := args.size
|
||||
if numArgs < numParams then
|
||||
mkPap name args
|
||||
else if numArgs == numParams then
|
||||
mkFap name args
|
||||
tryIrDecl? (name : Name) (args : Array Arg) : M (Option FnBody) := do
|
||||
if let some decl ← LCNF.getMonoDecl? name then
|
||||
let numArgs := args.size
|
||||
let numParams := decl.params.size
|
||||
if numArgs < numParams then
|
||||
return some (← mkPap name args)
|
||||
else if numArgs == numParams then
|
||||
return some (← mkFap name args)
|
||||
else
|
||||
return some (← mkOverApplication name numParams args)
|
||||
else
|
||||
mkOverApplication name numParams args
|
||||
return none
|
||||
|
||||
partial def lowerAlt (discr : VarId) (a : LCNF.Alt) : M Alt := do
|
||||
match a with
|
||||
|
||||
@@ -54,7 +54,6 @@ where fillCache : CoreM IRType := do
|
||||
-- `Int` is specified as an inductive type with two constructors that have relevant arguments,
|
||||
-- but it has the same runtime representation as `Nat` and thus needs to be special-cased here.
|
||||
| ``Int => return .tobject
|
||||
| ``lcRealWorld => return .tagged
|
||||
| _ =>
|
||||
let env ← Lean.getEnv
|
||||
let some (.inductInfo inductiveVal) := env.find? name | return .tobject
|
||||
|
||||
@@ -123,7 +123,7 @@ open Meta in
|
||||
Convert a Lean type into a LCNF type used by the code generator.
|
||||
-/
|
||||
partial def toLCNFType (type : Expr) : MetaM Expr := do
|
||||
if ← isProp type then
|
||||
if (← isProp type) then
|
||||
return erasedExpr
|
||||
let type ← whnfEta type
|
||||
match type with
|
||||
@@ -140,8 +140,6 @@ partial def toLCNFType (type : Expr) : MetaM Expr := do
|
||||
| .forallE .. => visitForall type #[]
|
||||
| .app .. => type.withApp visitApp
|
||||
| .fvar .. => visitApp type #[]
|
||||
| .proj ``Subtype 0 (.const ``IO.RealWorld.nonemptyType []) =>
|
||||
return mkConst ``lcRealWorld
|
||||
| _ => return mkConst ``lcAny
|
||||
where
|
||||
whnfEta (type : Expr) : MetaM Expr := do
|
||||
@@ -177,7 +175,7 @@ where
|
||||
for arg in args do
|
||||
if ← isProp arg <||> isPropFormer arg then
|
||||
result := mkApp result erasedExpr
|
||||
else if ← isTypeFormer arg then
|
||||
else if (← isTypeFormer arg) then
|
||||
result := mkApp result (← toLCNFType arg)
|
||||
else
|
||||
result := mkApp result (mkConst ``lcAny)
|
||||
|
||||
@@ -353,7 +353,7 @@ def instantiateValueLevelParams (c : ConstantInfo) (us : List Level) : CoreM Exp
|
||||
if us == us' then
|
||||
return r
|
||||
unless c.hasValue do
|
||||
throwError "Not a definition or theorem: {.ofConstName c.name}"
|
||||
throwError "Not a definition or theorem: {c.name}"
|
||||
let r := c.instantiateValueLevelParams! us
|
||||
modifyInstLevelValueCache fun s => s.insert c.name (us, r)
|
||||
return r
|
||||
|
||||
@@ -21,7 +21,7 @@ inductive AssocList (α : Type u) (β : Type v) where
|
||||
deriving Inhabited
|
||||
|
||||
namespace AssocList
|
||||
variable {α : Type u} {β : Type v} {δ : Type w} {m : Type w → Type w'} [Monad m]
|
||||
variable {α : Type u} {β : Type v} {δ : Type w} {m : Type w → Type w} [Monad m]
|
||||
|
||||
abbrev empty : AssocList α β :=
|
||||
nil
|
||||
|
||||
@@ -17,7 +17,6 @@ public import Init.Data.OfScientific
|
||||
public import Init.Data.Option.Coe
|
||||
public import Init.Data.Range
|
||||
import Init.Data.SInt.Basic
|
||||
import Init.Data.String.Basic
|
||||
|
||||
public section
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ This table contains for each UTF-8 byte whether we need to escape a string that
|
||||
private def escapeTable : { xs : ByteArray // xs.size = 256 } :=
|
||||
⟨ByteArray.mk #[
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,1, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
@@ -74,7 +74,6 @@ where
|
||||
else
|
||||
false
|
||||
|
||||
@[inline]
|
||||
def escape (s : String) (acc : String := "") : String :=
|
||||
-- If we don't have any characters that need to be escaped we can just append right away.
|
||||
if needEscape s then
|
||||
@@ -82,7 +81,6 @@ def escape (s : String) (acc : String := "") : String :=
|
||||
else
|
||||
acc ++ s
|
||||
|
||||
@[inline]
|
||||
def renderString (s : String) (acc : String := "") : String :=
|
||||
let acc := acc ++ "\""
|
||||
let acc := escape s acc
|
||||
@@ -109,123 +107,35 @@ end
|
||||
def pretty (j : Json) (lineWidth := 80) : String :=
|
||||
Format.pretty (render j) lineWidth
|
||||
|
||||
private inductive CompressWorkItemKind where
|
||||
| json
|
||||
| arrayElem
|
||||
protected inductive CompressWorkItem
|
||||
| json (j : Json)
|
||||
| arrayElem (j : Json)
|
||||
| arrayEnd
|
||||
| objectField
|
||||
| objectField (k : String) (j : Json)
|
||||
| objectEnd
|
||||
| comma
|
||||
|
||||
private structure CompressWorkItemQueue where
|
||||
kinds : Array CompressWorkItemKind
|
||||
values : Array Json
|
||||
objectFieldKeys : Array String
|
||||
|
||||
@[inline]
|
||||
private def CompressWorkItemQueue.pushKind (q : CompressWorkItemQueue) (kind : CompressWorkItemKind) :
|
||||
CompressWorkItemQueue := {
|
||||
q with kinds := q.kinds.push kind
|
||||
}
|
||||
|
||||
@[inline]
|
||||
private def CompressWorkItemQueue.pushValue (q : CompressWorkItemQueue) (value : Json) :
|
||||
CompressWorkItemQueue := {
|
||||
q with values := q.values.push value
|
||||
}
|
||||
|
||||
@[inline]
|
||||
private def CompressWorkItemQueue.pushObjectFieldKey (q : CompressWorkItemQueue) (objectFieldKey : String) :
|
||||
CompressWorkItemQueue := {
|
||||
q with objectFieldKeys := q.objectFieldKeys.push objectFieldKey
|
||||
}
|
||||
|
||||
@[inline]
|
||||
private def CompressWorkItemQueue.popKind (q : CompressWorkItemQueue) (h : q.kinds.size ≠ 0) :
|
||||
CompressWorkItemKind × CompressWorkItemQueue :=
|
||||
let kind := q.kinds[q.kinds.size - 1]
|
||||
let q := { q with kinds := q.kinds.pop }
|
||||
(kind, q)
|
||||
|
||||
@[inline]
|
||||
private def CompressWorkItemQueue.popValue! (q : CompressWorkItemQueue) :
|
||||
Json × CompressWorkItemQueue :=
|
||||
let value := q.values[q.values.size - 1]!
|
||||
let q := { q with values := q.values.pop }
|
||||
(value, q)
|
||||
|
||||
@[inline]
|
||||
private def CompressWorkItemQueue.popObjectFieldKey! (q : CompressWorkItemQueue) :
|
||||
String × CompressWorkItemQueue :=
|
||||
let objectFieldKey := q.objectFieldKeys[q.objectFieldKeys.size - 1]!
|
||||
let q := { q with objectFieldKeys := q.objectFieldKeys.pop }
|
||||
(objectFieldKey, q)
|
||||
|
||||
open Json.CompressWorkItem in
|
||||
partial def compress (j : Json) : String :=
|
||||
go "" {
|
||||
kinds := #[.json]
|
||||
values := #[j]
|
||||
objectFieldKeys := #[]
|
||||
}
|
||||
where
|
||||
go (acc : String) (q : CompressWorkItemQueue) : String :=
|
||||
if h : q.kinds.size = 0 then
|
||||
acc
|
||||
else
|
||||
let (kind, q) := q.popKind h
|
||||
match kind with
|
||||
| .json =>
|
||||
let (j, q) := q.popValue!
|
||||
match j with
|
||||
| null =>
|
||||
go (acc ++ "null") q
|
||||
| bool b =>
|
||||
go (acc ++ toString b) q
|
||||
| num n =>
|
||||
go (acc ++ toString n) q
|
||||
| str s =>
|
||||
go (renderString s acc) q
|
||||
| arr elems =>
|
||||
let q := q.pushKind .arrayEnd
|
||||
go (acc ++ "[") (elems.foldr (init := q) fun e acc => acc.pushKind .arrayElem |>.pushValue e)
|
||||
| obj kvs =>
|
||||
let q := q.pushKind .objectEnd
|
||||
go (acc ++ "{") (kvs.foldr (init := q) fun k j acc => acc.pushKind .objectField |>.pushObjectFieldKey k |>.pushValue j)
|
||||
| .arrayElem =>
|
||||
let (j, q) := q.popValue!
|
||||
if h : q.kinds.size = 0 then
|
||||
go acc {
|
||||
kinds := #[.comma, .json]
|
||||
values := #[j]
|
||||
objectFieldKeys := #[]
|
||||
}
|
||||
else
|
||||
let kind := q.kinds[q.kinds.size - 1]
|
||||
if kind matches .arrayEnd then
|
||||
go acc (q.pushKind .json |>.pushValue j)
|
||||
else
|
||||
go acc (q.pushKind .comma |>.pushKind .json |>.pushValue j)
|
||||
| .arrayEnd =>
|
||||
go (acc ++ "]") q
|
||||
| .objectField =>
|
||||
let (k, q) := q.popObjectFieldKey!
|
||||
let (j, q) := q.popValue!
|
||||
if h : q.kinds.size = 0 then
|
||||
go (renderString k acc ++ ":") {
|
||||
kinds := #[.comma, .json]
|
||||
values := #[j]
|
||||
objectFieldKeys := #[]
|
||||
}
|
||||
else
|
||||
let kind := q.kinds[q.kinds.size - 1]
|
||||
if kind matches .objectEnd then
|
||||
go (renderString k acc ++ ":") (q.pushKind .json |>.pushValue j)
|
||||
else
|
||||
go (renderString k acc ++ ":") (q.pushKind .comma |>.pushKind .json |>.pushValue j)
|
||||
| .objectEnd =>
|
||||
go (acc ++ "}") q
|
||||
| .comma =>
|
||||
go (acc ++ ",") q
|
||||
go "" [json j]
|
||||
where go (acc : String) : List Json.CompressWorkItem → String
|
||||
| [] => acc
|
||||
| json j :: is =>
|
||||
match j with
|
||||
| null => go (acc ++ "null") is
|
||||
| bool true => go (acc ++ "true") is
|
||||
| bool false => go (acc ++ "false") is
|
||||
| num s => go (acc ++ s.toString) is
|
||||
| str s => go (renderString s acc) is
|
||||
| arr elems => go (acc ++ "[") ((elems.map arrayElem).toListAppend (arrayEnd :: is))
|
||||
| obj kvs => go (acc ++ "{") (kvs.foldl (init := []) (fun acc k j => objectField k j :: acc) ++ [objectEnd] ++ is)
|
||||
| arrayElem j :: arrayEnd :: is => go acc (json j :: arrayEnd :: is)
|
||||
| arrayElem j :: is => go acc (json j :: comma :: is)
|
||||
| arrayEnd :: is => go (acc ++ "]") is
|
||||
| objectField k j :: objectEnd :: is => go (renderString k acc ++ ":") (json j :: objectEnd :: is)
|
||||
| objectField k j :: is => go (renderString k acc ++ ":") (json j :: comma :: is)
|
||||
| objectEnd :: is => go (acc ++ "}") is
|
||||
| comma :: is => go (acc ++ ",") is
|
||||
|
||||
instance : ToFormat Json := ⟨render⟩
|
||||
instance : ToString Json := ⟨pretty⟩
|
||||
|
||||
@@ -18,11 +18,6 @@ namespace IO.FS.Stream
|
||||
open Lean
|
||||
open IO
|
||||
|
||||
def readUTF8 (h : FS.Stream) (nBytes : Nat) : IO String := do
|
||||
let bytes ← h.read (USize.ofNat nBytes)
|
||||
let some s := String.fromUTF8? bytes | throw (IO.userError "invalid UTF-8")
|
||||
return s
|
||||
|
||||
/-- Consumes `nBytes` bytes from the stream, interprets the bytes as a utf-8 string and the string as a valid JSON object. -/
|
||||
def readJson (h : FS.Stream) (nBytes : Nat) : IO Json := do
|
||||
let bytes ← h.read (USize.ofNat nBytes)
|
||||
|
||||
@@ -296,105 +296,6 @@ instance [FromJson α] : FromJson (Notification α) where
|
||||
pure $ ⟨method, param⟩
|
||||
else throw "not a notification"
|
||||
|
||||
/--
|
||||
A variant of `Message` that has been parsed *partially*, without the payload.
|
||||
This is useful when we want to process the metadata of a `Message` without parsing and converting
|
||||
the whole thing.
|
||||
-/
|
||||
inductive MessageMetaData where
|
||||
| request (id : RequestID) (method : String)
|
||||
| notification (method : String)
|
||||
| response (id : RequestID)
|
||||
| responseError (id : RequestID) (code : ErrorCode) (message : String) (data? : Option Json)
|
||||
deriving Inhabited
|
||||
|
||||
def MessageMetaData.toMessage : MessageMetaData → Message
|
||||
| .request id method => .request id method none
|
||||
| .notification method => .notification method none
|
||||
| .response id => .response id .null
|
||||
| .responseError id code message data? => .responseError id code message data?
|
||||
|
||||
open Std.Internal.Parsec in
|
||||
open Std.Internal.Parsec.String in
|
||||
open Json.Parser in
|
||||
private def messageMetaDataParser (input : String) : Parser MessageMetaData := do
|
||||
skip
|
||||
let k ← parseStr
|
||||
skip
|
||||
match k with
|
||||
| "id" =>
|
||||
-- Request or response
|
||||
let id ← parseRequestID
|
||||
skip
|
||||
-- Skip `jsonrpc` field
|
||||
let _ ← parseStr
|
||||
skip
|
||||
let _ ← parseStr
|
||||
skip
|
||||
let k' ← parseStr
|
||||
match k' with
|
||||
| "method" =>
|
||||
skip
|
||||
let method ← parseStr
|
||||
return .request id method
|
||||
| "result" =>
|
||||
-- Response
|
||||
return .response id
|
||||
| _ =>
|
||||
fail "expected `method` or `result` field"
|
||||
| "jsonrpc" =>
|
||||
-- Notification
|
||||
-- Skip `jsonrpc` version
|
||||
let _ ← parseStr
|
||||
skip
|
||||
-- Skip `method` field name
|
||||
let _ ← parseStr
|
||||
skip
|
||||
let method ← parseStr
|
||||
return .notification method
|
||||
| "error" =>
|
||||
-- Response error
|
||||
-- Response errors are usually small, so we just parse them normally.
|
||||
match Json.parse input with
|
||||
| .ok parsed =>
|
||||
match fromJson? parsed with
|
||||
| .ok (.responseError id code message data? : Message) =>
|
||||
return .responseError id code message data?
|
||||
| .ok _ =>
|
||||
fail "expected response error message kind"
|
||||
| .error err =>
|
||||
fail err
|
||||
| .error err =>
|
||||
fail err
|
||||
| _ =>
|
||||
fail "expected `id`, `jsonrpc` or `error` field"
|
||||
where
|
||||
parseStr : Parser String := do
|
||||
let c ← peek!
|
||||
if c != '"' then
|
||||
fail "expected \""
|
||||
skip
|
||||
str
|
||||
parseRequestID : Parser RequestID := do
|
||||
(do
|
||||
let num ← Parser.num
|
||||
return .num num) <|>
|
||||
(do
|
||||
let str ← parseStr
|
||||
return .str str) <|>
|
||||
(do
|
||||
skipString "null"
|
||||
return .null)
|
||||
|
||||
/--
|
||||
Danger: For performance reasons, this function makes a number of fragile assumptions about `input`.
|
||||
Namely:
|
||||
- `input` is the output of `(toJson (v : Message)).compress`
|
||||
- `compress` yields a lexicographic ordering of JSON object keys
|
||||
-/
|
||||
def parseMessageMetaData (input : String) : Except String MessageMetaData :=
|
||||
messageMetaDataParser input |>.run input
|
||||
|
||||
end Lean.JsonRpc
|
||||
|
||||
namespace IO.FS.Stream
|
||||
|
||||
@@ -8,7 +8,6 @@ module
|
||||
prelude
|
||||
public import Init.Data.List.Impl
|
||||
public import Init.Data.Format.Syntax
|
||||
public import Init.Data.ToString.Name
|
||||
|
||||
public section
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user