Compare commits

..

1 Commits

Author SHA1 Message Date
Leonardo de Moura
dc58ef43ae doc: grind attribute modifiers 2025-08-30 09:02:00 -07:00
1288 changed files with 7281 additions and 12747 deletions

View File

@@ -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

View File

@@ -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",

View File

@@ -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

View File

@@ -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
------------

View File

@@ -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

View File

@@ -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

View File

@@ -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 `α`,

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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 :=

View File

@@ -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. -/

View File

@@ -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))

View File

@@ -10,6 +10,7 @@ public import Init.NotationExtra
public section
namespace Bool
/--

View File

@@ -7,6 +7,5 @@ module
prelude
public import Init.Data.ByteArray.Basic
public import Init.Data.ByteArray.Extra
public section

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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. -/

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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 ()

View File

@@ -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

View File

@@ -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

View File

@@ -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 -/

View File

@@ -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 -/

View File

@@ -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)

View File

@@ -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

View File

@@ -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]

View File

@@ -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

View File

@@ -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

View File

@@ -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)

View File

@@ -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

View File

@@ -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

View File

@@ -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`."

View File

@@ -7,7 +7,6 @@ module
prelude
public import Init.System.IO
import Init.Data.ByteArray.Extra
public section
universe u

View File

@@ -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]

View File

@@ -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

View File

@@ -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)

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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 :=

View File

@@ -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`

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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 [*]

View File

@@ -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

View File

@@ -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"

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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) :

View File

@@ -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

View File

@@ -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.
-/

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -7,7 +7,6 @@ module
prelude
public import Init.NotationExtra
meta import Init.Data.String.Basic
public section

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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}, ∞)"

View File

@@ -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

View File

@@ -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}

View File

@@ -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
/--

View File

@@ -7,7 +7,6 @@ module
prelude
public import Init.NotationExtra
import Init.Data.ToString.Name
public section

View File

@@ -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

View File

@@ -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
/--

View File

@@ -8,7 +8,6 @@ module
prelude
public import Init.Data.ToString.Basic
import Init.Data.String.Basic
public section

View File

@@ -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

View File

@@ -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)

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -8,7 +8,6 @@ module
prelude
public import Init.Data.Array.Basic
public import Init.System.FilePath
import Init.Data.String.Basic
public section

View File

@@ -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

View File

@@ -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

View File

@@ -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)

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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)

View File

@@ -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

View File

@@ -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