lean4-htt/src/Init/Data/Order/PackageFactories.lean
Markus Himmel 8a9cb6def0
feat: Slice.posGE and Slice.posGT (#12301)
This PR introduces the functions `(String|Slice).posGE` and
`(String|Slice).posGT` will full verification and deprecates
`Slice.findNextPos` in favor of `Slice.posGT`.

The KMP implementation is adapted to use these two new functions.

Various useful string and order lemmas are added along the way.

Also add a `simp` attribute to `Std.le_refl` and fix the resulting
fallout (yes, this would have been better as a separate PR).
2026-02-04 09:45:44 +00:00

810 lines
32 KiB
Text
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/-
Copyright (c) 2025 Lean FRO, LLC. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Paul Reichert
-/
module
prelude
public import Init.Data.Order.LemmasExtra
namespace Std
/-!
## Instance packages and factories for them
Instance packages are classes with the sole purpose to bundle together multiple smaller classes.
They should not be used as hypotheses, but they make it more convenient to define multiple instances
at once.
-/
section Preorder
/--
This class entails `LE α`, `LT α` and `BEq α` instances as well as proofs that these operations
represent the same preorder structure on `α`.
-/
public class PreorderPackage (α : Type u) extends
LE α, LT α, BEq α, LawfulOrderLT α, LawfulOrderBEq α, IsPreorder α where
decidableLE : DecidableLE α
decidableLT : DecidableLT α
public instance [PreorderPackage α] : DecidableLE α := PreorderPackage.decidableLE
public instance [PreorderPackage α] : DecidableLT α := PreorderPackage.decidableLT
namespace FactoryInstances
public scoped instance beqOfDecidableLE {α : Type u} [LE α] [DecidableLE α] :
BEq α where
beq a b := a ≤ b ∧ b ≤ a
public instance instLawfulOrderBEqOfDecidableLE {α : Type u} [LE α] [DecidableLE α] :
LawfulOrderBEq α where
beq_iff_le_and_ge := by simp [BEq.beq]
/-- If `LT` can be characterized in terms of a decidable `LE`, then `LT` is decidable either. -/
@[expose]
public def decidableLTOfLE {α : Type u} [LE α] {_ : LT α} [DecidableLE α] [LawfulOrderLT α] :
DecidableLT α :=
fun a b =>
haveI := iff_iff_eq.mp <| LawfulOrderLT.lt_iff a b
if h : a ≤ b ∧ ¬ b ≤ a then .isTrue (this ▸ h) else .isFalse (this ▸ h)
end FactoryInstances
/--
This structure contains all the data needed to create a `PreorderPackage α` instance. Its fields
are automatically provided if possible. For the detailed rules how the fields are inferred, see
`PreorderPackage.ofLE`.
-/
public structure Packages.PreorderOfLEArgs (α : Type u) where
le : LE α := by infer_instance
decidableLE : DecidableLE α := by infer_instance
lt :
let := le
LT α := by
extract_lets
first
| infer_instance
| exact _root_.Classical.Order.instLT
beq :
let := le; let := decidableLE
BEq α := by
extract_lets
first
| infer_instance
| exact _root_.Std.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
| 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`."
decidableLT :
let := le; let := decidableLE; let := lt; haveI := lt_iff
have := lt_iff
DecidableLT α := by
extract_lets
haveI := @_root_.Std.LawfulOrderLT.mk (lt_iff := by assumption) ..
first
| infer_instance
| exact _root_.Std.FactoryInstances.decidableLTOfLE
| fail "Failed to automatically derive that `LT` is decidable. \
Please ensure that a `DecidableLT` instance can be synthesized or \
manually provide the field `decidableLT`."
beq_iff_le_and_ge :
let := le; let := decidableLE; let := beq
∀ a b : α, a == b ↔ a ≤ b ∧ b ≤ a := by
extract_lets
first
| exact _root_.Std.LawfulOrderBEq.beq_iff_le_and_ge
| fail "Failed to automatically prove that the `LE` and `BEq` instances are compatible. \
Please ensure that a `LawfulOrderBEq` instance can be synthesized or \
manually provide the field `beq_iff_le_and_ge`."
le_refl :
let := le
∀ a : α, a ≤ a := by
extract_lets
first
| exact _root_.Std.Refl.refl (r := (· ≤ ·))
| fail "Failed to automatically prove that the `LE` instance is reflexive. \
Please ensure that a `Refl` instance can be synthesized or \
manually provide the field `le_refl`."
le_trans :
let := le
∀ 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
| 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`."
/--
Use this factory to conveniently define a preorder on a type `α` and all the associated operations
and instances given an `LE α` instance.
Creates a `PreorderPackage α` instance. Such an instance entails `LE α`, `LT α` and
`BEq α` instances as well as an `IsPreorder α` instance and `LawfulOrder*` instances proving the
compatibility of the operations with the preorder.
In the presence of `LE α`, `DecidableLE α`, `Refl (· ≤ ·)` and `Trans (· ≤ ·) (· ≤ ·) (· ≤ ·)`
instances, no arguments are required and the factory can be used as in this example:
```lean
public instance : PreorderPackage X := .ofLE X
```
If not all of these instances are available via typeclass synthesis, it is necessary to explicitly
provide some arguments:
```lean
public instance : PreorderPackage X := .ofLE X {
le_refl := sorry
le_trans := sorry }
```
It is also possible to do all of this by hand, without resorting to `PreorderPackage`. This can
be useful if, say, one wants to avoid specifying an `LT α` instance, which is not possible with
`PreorderPackage`.
**How the arguments are filled**
Lean tries to fill all of the fields of the `args : Packages.PreorderOfLEArgs α` parameter
automatically. If it fails, it is necessary to provide some of the fields manually.
* For the data-carrying typeclasses `LE`, `LT` and `BEq`, existing instances are always preferred.
If no existing instances can be synthesized, it is attempted to derive an instance from the `LE`
instance.
* Some proof obligations can be filled automatically if the data-carrying typeclasses have been
derived from the `LE` instance. For example: If the `beq` field is omitted and no `BEq α` instance
can be synthesized, it is derived from the `LE α` instance. In this case, `beq_iff_le_and_ge` can
be omitted because Lean can infer that `BEq α` and `LE α` are compatible.
* Other proof obligations, namely `le_refl` and `le_trans`, can be omitted if `Refl` and `Trans`
instances can be synthesized.
-/
@[expose]
public def PreorderPackage.ofLE (α : Type u)
(args : Packages.PreorderOfLEArgs α := by exact {}) : PreorderPackage α where
toLE := args.le
decidableLE := args.decidableLE
toLT := args.lt
toBEq := args.beq
toLawfulOrderLT := @LawfulOrderLT.mk (lt_iff := args.lt_iff)
decidableLT := args.decidableLT
toLawfulOrderBEq := @LawfulOrderBEq.mk (beq_iff_le_and_ge := args.beq_iff_le_and_ge)
le_refl := args.le_refl
le_trans := args.le_trans
end Preorder
section PartialOrder
/--
This class entails `LE α`, `LT α` and `BEq α` instances as well as proofs that these operations
represent the same partial order structure on `α`.
-/
public class PartialOrderPackage (α : Type u) extends
PreorderPackage α, IsPartialOrder α
/--
This structure contains all the data needed to create a `PartialOrderPakckage α` instance. Its
fields are automatically provided if possible. For the detailed rules how the fields are inferred,
see `PartialOrderPackage.ofLE`.
-/
public structure Packages.PartialOrderOfLEArgs (α : Type u) extends Packages.PreorderOfLEArgs α where
le_antisymm :
let := le
∀ a b : α, a ≤ b → b ≤ a → a = b := by
extract_lets
first
| exact _root_.Std.Antisymm.antisymm
| fail "Failed to automatically prove that the `LE` instance is antisymmetric. \
Please ensure that a `Antisymm` instance can be synthesized or \
manually provide the field `le_antisymm`."
/-
Use this factory to conveniently define a partial order on a type `α` and all the associated
operations and instances given an `LE α` instance.
Creates a `PartialOrderPackage α` instance. Such an instance entails `LE α`, `LT α` and
`BEq α` instances as well as an `IsPartialOrder α` instance and `LawfulOrder*` instances proving the
compatibility of the operations with the preorder.
In the presence of `LE α`, `DecidableLE α`, `Refl (· ≤ ·)`, `Trans (· ≤ ·) (· ≤ ·) (· ≤ ·)`
and `Antisymm (· ≤ ·)` instances, no arguments are required and the factory can be used as in this
example:
```lean
public instance : PartialOrderPackage X := .ofLE X
```
If not all of these instances are available via typeclass synthesis, it is necessary to explicitly
provide some arguments:
```lean
public instance : PartialOrderPackage X := .ofLE X {
le_refl := sorry
le_trans := sorry
le_antisymm := sorry }
```
It is also possible to do all of this by hand, without resorting to `PartialOrderPackage`. This can
be useful if, say, one wants to avoid specifying an `LT α` instance, which is not possible with
`PartialOrderPackage`.
**How the arguments are filled**
Lean tries to fill all of the fields of the `args : Packages.PartialOrderOfLEArgs α` parameter
automatically. If it fails, it is necessary to provide some of the fields manually.
* For the data-carrying typeclasses `LE`, `LT` and `BEq`, existing instances are always preferred.
If no existing instances can be synthesized, it is attempted to derive an instance from the `LE`
instance.
* Some proof obligations can be filled automatically if the data-carrying typeclasses have been
derived from the `LE` instance. For example: If the `beq` field is omitted and no `BEq α` instance
can be synthesized, it is derived from the `LE α` instance. In this case, `beq_iff_le_and_ge` can be
omitted because Lean can infer that `BEq α` and `LE α` are compatible.
* Other proof obligations, namely `le_refl`, `le_trans` and `le_antisymm`, can be omitted if `Refl`,
`Trans` and `Antisymm` instances can be synthesized.
-/
@[expose]
public def PartialOrderPackage.ofLE (α : Type u)
(args : Packages.PartialOrderOfLEArgs α := by exact {}) : PartialOrderPackage α where
toPreorderPackage := .ofLE α args.toPreorderOfLEArgs
le_antisymm := args.le_antisymm
end PartialOrder
namespace FactoryInstances
public scoped instance instOrdOfDecidableLE {α : Type u} [LE α] [DecidableLE α] :
Ord α where
compare a b := if a ≤ b then if b ≤ a then .eq else .lt else .gt
theorem isLE_compare {α : Type u} [LE α] [DecidableLE α] {a b : α} :
(compare a b).isLE ↔ a ≤ b := by
simp only [compare]
split
· split <;> simp_all
· simp_all
theorem isGE_compare {α : Type u} [LE α] [DecidableLE α]
(le_total : ∀ a b : α, a ≤ b b ≤ a) {a b : α} :
(compare a b).isGE ↔ b ≤ a := by
simp only [compare]
split
· split <;> simp_all
· specialize le_total a b
simp_all
public instance instLawfulOrderOrdOfDecidableLE {α : Type u} [LE α] [DecidableLE α]
[Total (α := α) (· ≤ ·)] :
LawfulOrderOrd α where
isLE_compare _ _ := by exact isLE_compare
isGE_compare _ _ := by exact isGE_compare (le_total := Total.total)
end FactoryInstances
/--
This class entails `LE α`, `LT α`, `BEq α` and `Ord α` instances as well as proofs that these
operations represent the same linear preorder structure on `α`.
-/
public class LinearPreorderPackage (α : Type u) extends
PreorderPackage α, Ord α, LawfulOrderOrd α, IsLinearPreorder α
/--
This structure contains all the data needed to create a `LinearPreorderPackage α` instance. Its fields
are automatically provided if possible. For the detailed rules how the fields are inferred, see
`LinearPreorderPackage.ofLE`.
-/
public structure Packages.LinearPreorderOfLEArgs (α : Type u) extends
PreorderOfLEArgs α where
ord :
let := le; let := decidableLE
Ord α := by
extract_lets
first
| infer_instance
| exact _root_.Std.FactoryInstances.instOrdOfDecidableLE
le_total :
∀ a b : α, a ≤ b b ≤ a := by
first
| exact _root_.Std.Total.total
| fail "Failed to automatically prove that the `LE` instance is total. \
Please ensure that a `Total` instance can be synthesized or \
manually provide the field `le_total`."
le_refl a := (by simpa using le_total a a)
isLE_compare :
let := le; let := decidableLE; let := ord
∀ a b : α, (compare a b).isLE ↔ a ≤ b := by
extract_lets
first
| exact _root_.Std.LawfulOrderOrd.isLE_compare
| fail "Failed to automatically prove that `(compare a b).isLE` is equivalent to `a ≤ b`. \
Please ensure that a `LawfulOrderOrd` instance can be synthesized or \
manually provide the field `isLE_compare`."
isGE_compare :
let := le; let := decidableLE; have := le_total; let := ord
∀ a b : α, (compare a b).isGE ↔ b ≤ a := by
extract_lets
first
| exact _root_.Std.LawfulOrderOrd.isGE_compare
| fail "Failed to automatically prove that `(compare a b).isGE` is equivalent to `b ≤ a`. \
Please ensure that a `LawfulOrderOrd` instance can be synthesized or \
manually provide the field `isGE_compare`."
/--
Use this factory to conveniently define a linear preorder on a type `α` and all the associated
operations and instances given an `LE α` instance.
Creates a `LinearPreorderPackage α` instance. Such an instance entails `LE α`, `LT α`, `BEq α` and
`Ord α` instances as well as an `IsLinearPreorder α` instance and `LawfulOrder*` instances proving
the compatibility of the operations with the linear preorder.
In the presence of `LE α`, `DecidableLE α`, `Total (· ≤ ·)` and `Trans (· ≤ ·) (· ≤ ·) (· ≤ ·)`
instances, no arguments are required and the factory can be used as in this example:
```lean
public instance : LinearPreorderPackage X := .ofLE X
```
If not all of these instances are available via typeclass synthesis, it is necessary to explicitly
provide some arguments:
```lean
public instance : LinearPreorderPackage X := .ofLE X {
le_total := sorry
le_trans := sorry }
```
It is also possible to do all of this by hand, without resorting to `LinearPreorderPackage`. This
can be useful if, say, one wants to avoid specifying an `LT α` instance, which is not possible with
`LinearPreorderPackage`.
**How the arguments are filled**
Lean tries to fill all of the fields of the `args : Packages.LinearPreorderOfLEArgs α` parameter
automatically. If it fails, it is necessary to provide some of the fields manually.
* For the data-carrying typeclasses `LE`, `LT`, `BEq` and `Ord`, existing instances are always
preferred. If no existing instances can be synthesized, it is attempted to derive an instance from
the `LE` instance.
* Some proof obligations can be filled automatically if the data-carrying typeclasses have been
derived from the `LE` instance. For example: If the `beq` field is omitted and no `BEq α` instance
can be synthesized, it is derived from the `LE α` instance. In this case, `beq_iff_le_and_ge` can be
omitted because Lean can infer that `BEq α` and `LE α` are compatible.
* Other proof obligations, namely `le_total` and `le_trans`, can be omitted if `Total` and `Trans`
instances can be synthesized.
-/
@[expose]
public def LinearPreorderPackage.ofLE (α : Type u)
(args : Packages.LinearPreorderOfLEArgs α := by exact {}) : LinearPreorderPackage α where
toPreorderPackage := .ofLE α args.toPreorderOfLEArgs
toOrd := letI := args.le; args.ord
le_total := args.le_total
isLE_compare := args.isLE_compare
isGE_compare := args.isGE_compare
/--
This class entails `LE α`, `LT α`, `BEq α`, `Ord α`, `Min α` and `Max α` instances as well as proofs
that these operations represent the same linear order structure on `α`.
-/
public class LinearOrderPackage (α : Type u) extends
LinearPreorderPackage α, PartialOrderPackage α, Min α, Max α,
LawfulOrderMin α, LawfulOrderMax α, IsLinearOrder α
/--
This structure contains all the data needed to create a `LinearOrderPackage α` instance. Its fields
are automatically provided if possible. For the detailed rules how the fields are inferred, see
`LinearOrderPackage.ofLE`.
-/
public structure Packages.LinearOrderOfLEArgs (α : Type u) extends
LinearPreorderOfLEArgs α, PartialOrderOfLEArgs α where
min :
let := le; let := decidableLE
Min α := by
extract_lets
first
| infer_instance
| exact _root_.Min.leftLeaningOfLE _
max :
let := le; let := decidableLE
Max α := by
extract_lets
first
| infer_instance
| exact _root_.Max.leftLeaningOfLE _
min_eq :
let := le; let := decidableLE; let := min
∀ a b : α, Min.min a b = if a ≤ b then a else b := by
extract_lets
first
| exact fun a b => _root_.Std.min_eq_if (a := a) (b := b)
| fail "Failed to automatically prove that `min` is left-leaning. \
Please ensure that a `LawfulOrderLeftLeaningMin` instance can be synthesized or \
manually provide the field `min_eq`."
max_eq :
let := le; let := decidableLE; let := max
∀ 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)
| 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`."
/--
Use this factory to conveniently define a linear order on a type `α` and all the associated
operations and instances given an `LE α` instance.
Creates a `LinearOrderPackage α` instance. Such an instance entails `LE α`, `LT α`, `BEq α`,
`Ord α`, `Min α` and `Max α` instances as well as an `IsLinearOrder α` instance and `LawfulOrder*`
instances proving the compatibility of the operations with the linear order.
In the presence of `LE α`, `DecidableLE α`, `Total (· ≤ ·)`, `Trans (· ≤ ·) (· ≤ ·) (· ≤ ·)` and
`Antisymm (· ≤ ·)` instances, no arguments are required and the factory can be used as in this
example:
```lean
public instance : LinearOrderPackage X := .ofLE X
```
If not all of these instances are available via typeclass synthesis, it is necessary to explicitly
provide some arguments:
```lean
public instance : LinearOrderPackage X := .ofLE X {
le_total := sorry
le_trans := sorry
le_antisymm := sorry }
```
It is also possible to do all of this by hand, without resorting to `LinearOrderPackage`. This
can be useful if, say, one wants to avoid specifying an `LT α` instance, which is not possible with
`LinearOrderPackage`.
**How the arguments are filled**
Lean tries to fill all of the fields of the `args : Packages.LinearOrderOfLEArgs α` parameter
automatically. If it fails, it is necessary to provide some of the fields manually.
* For the data-carrying typeclasses `LE`, `LT`, `BEq`, `Ord`, `Min` and `Max`, existing instances
are always preferred. If no existing instances can be synthesized, it is attempted to derive an
instance from the `LE` instance.
* Some proof obligations can be filled automatically if the data-carrying typeclasses have been
derived from the `LE` instance. For example: If the `beq` field is omitted and no `BEq α` instance
can be synthesized, it is derived from the `LE α` instance. In this case, `beq_iff_le_and_ge` can be
omitted because Lean can infer that `BEq α` and `LE α` are compatible.
* Other proof obligations, namely `le_total`, `le_trans` and `le_antisymm`, can be omitted if
`Total`, `Trans` and `Antisymm` instances can be synthesized.
-/
@[expose]
public def LinearOrderPackage.ofLE (α : Type u)
(args : Packages.LinearOrderOfLEArgs α := by exact {}) : LinearOrderPackage α where
toLinearPreorderPackage := .ofLE α args.toLinearPreorderOfLEArgs
le_antisymm := (PartialOrderPackage.ofLE α args.toPartialOrderOfLEArgs).le_antisymm
toMin := args.min
toMax := args.max
toLawfulOrderMin := by
letI := LinearPreorderPackage.ofLE α args.toLinearPreorderOfLEArgs
letI := args.decidableLE; letI := args.min
haveI : LawfulOrderLeftLeaningMin α := .of_eq args.min_eq
infer_instance
toLawfulOrderMax := by
letI := LinearPreorderPackage.ofLE α args.toLinearPreorderOfLEArgs
letI := args.decidableLE; letI := args.max
haveI : LawfulOrderLeftLeaningMax α := .of_eq args.max_eq
infer_instance
section LinearPreorder
namespace FactoryInstances
attribute [scoped instance] LE.ofOrd
attribute [scoped instance] LT.ofOrd
attribute [scoped instance] BEq.ofOrd
public theorem _root_.Std.OrientedCmp.of_gt_iff_lt {α : Type u} {cmp : αα → Ordering}
(h : ∀ a b : α, cmp a b = .gt ↔ cmp b a = .lt) : OrientedCmp cmp where
eq_swap {a b} := by
cases h' : cmp a b
· apply Eq.symm
simp [h, h']
· cases h'' : cmp b a
· simp [← h, h'] at h''
· simp
· simp [h, h'] at h''
· apply Eq.symm
simp [← h, h']
end FactoryInstances
/--
This structure contains all the data needed to create a `LinearPreorderPackage α` instance.
Its fields are automatically provided if possible. For the detailed rules how the fields are
inferred, see `LinearPreorderPackage.ofOrd`.
-/
public structure Packages.LinearPreorderOfOrdArgs (α : Type u) where
ord : Ord α := by infer_instance
transOrd : TransOrd α := by infer_instance
le :
let := ord
LE α := by
extract_lets
first
| infer_instance
| exact _root_.LE.ofOrd _
lawfulOrderOrd :
let := ord; let := transOrd; let := le
LawfulOrderOrd α := by
extract_lets
first
| infer_instance
| fail "Failed to automatically derive a `LawfulOrderOrd` instance. \
Please ensure that the instance can be synthesized or \
manually provide the field `lawfulOrderOrd`."
decidableLE :
let := ord; let := le; have := lawfulOrderOrd
DecidableLE α := by
extract_lets
first
| infer_instance
| exact _root_.DecidableLE.ofOrd _
| fail "Failed to automatically derive that `LE` is decidable.\
Please ensure that a `DecidableLE` instance can be synthesized or \
manually provide the field `decidableLE`."
lt :
let := ord
LT α := by
extract_lets
first
| infer_instance
| exact LT.ofOrd _
lt_iff :
let := ord; let := le; have := lawfulOrderOrd; let := lt
∀ a b : α, a < b ↔ compare a b = .lt := by
extract_lets
first
| exact fun _ _ => _root_.Std.compare_eq_lt.symm
| fail "Failed to automatically derive that `LT` and `Ord` are compatible. \
Please ensure that a `LawfulOrderLT` instance can be synthesized or \
manually provide the field `lt_iff`."
decidableLT :
let := ord; let := lt; let := le; have := lawfulOrderOrd; have := lt_iff
DecidableLT α := by
extract_lets
first
| infer_instance
| exact _root_DecidableLT.ofOrd _
| fail "Failed to automatically derive that `LT` is decidable. \
Please ensure that a `DecidableLT` instance can be synthesized or \
manually provide the field `decidableLT`."
beq :
let := ord; BEq α := by
extract_lets
first
| infer_instance
| exact _root_.BEq.ofOrd _
beq_iff :
let := ord; let := le; have := lawfulOrderOrd; let := beq
∀ a b : α, a == b ↔ compare a b = .eq := by
extract_lets
first
| exact fun _ _ => Std.compare_eq_eq.symm
| fail "Failed to automatically derive that `BEq` and `Ord` are compatible. \
Please ensure that a `LawfulOrderBEq` instance can be synthesized or \
manually provide the field `beq_iff`."
/--
Use this factory to conveniently define a linear preorder on a type `α` and all the associated
operations and instances given an `Ord α` instance.
Creates a `LinearPreorderPackage α` instance. Such an instance entails `LE α`, `LT α`, `BEq α` and
`Ord α` instances as well as an `IsLinearPreorder α` instance and `LawfulOrder*` instances proving
the compatibility of the operations with the linear preorder.
In the presence of `Ord α` and `TransOrd α` instances, no arguments are required and the factory can
be used as in this example:
```lean
public instance : LinearPreorderPackage X := .ofOrd X
```
If not all of these instances are available via typeclass synthesis, it is necessary to explicitly
provide some arguments:
```lean
public instance : LinearPreorderPackage X := .ofOrd X {
ord := sorry
transOrd := sorry }
```
It is also possible to do all of this by hand, without resorting to `LinearPreorderPackage`. This
can be useful if, say, one wants to avoid specifying an `LT α` instance, which is not possible with
`LinearPreorderPackage`.
**How the arguments are filled**
Lean tries to fill all of the fields of the `args : Packages.LinearPreorderOfOrdArgs α` parameter
automatically. If it fails, it is necessary to provide some of the fields manually.
* For the data-carrying typeclasses `LE`, `LT`, `BEq` and `Ord`, existing instances are always
preferred. If no existing instances can be synthesized, it is attempted to derive an instance from
the `Ord` instance.
* Some proof obligations can be filled automatically if the data-carrying typeclasses have been
derived from the `Ord` instance. For example: If the `beq` field is omitted and no `BEq α` instance
can be synthesized, it is derived from the `Ord α` instance. In this case, `beq_iff`
can be omitted because Lean can infer that `BEq α` and `Ord α` are compatible.
* Other proof obligations, for example `transOrd`, can be omitted if a matching instance can be
synthesized.
-/
@[expose]
public def LinearPreorderPackage.ofOrd (α : Type u)
(args : Packages.LinearPreorderOfOrdArgs α := by exact {}) : LinearPreorderPackage α :=
letI := args.ord
haveI := args.transOrd
letI := args.le
haveI := args.lawfulOrderOrd
{ toOrd := args.ord
toLE := args.le
toLT := args.lt
toBEq := args.beq
toLawfulOrderOrd := args.lawfulOrderOrd
lt_iff a b := by
cases h : compare a b
all_goals simp [h, ← args.lawfulOrderOrd.isLE_compare a _, ← args.lawfulOrderOrd.isGE_compare a _,
args.lt_iff]
beq_iff_le_and_ge a b := by
simp [args.beq_iff, Ordering.eq_eq_iff_isLE_and_isGE, isLE_compare,
isGE_compare]
decidableLE := args.decidableLE
decidableLT := args.decidableLT
le_refl a := by simp
le_total a b := by cases h : compare a b <;> simp [h, ← isLE_compare (a := a), ← isGE_compare (a := a)]
le_trans a b c := by simpa [← isLE_compare] using TransOrd.isLE_trans }
end LinearPreorder
section LinearOrder
namespace FactoryInstances
public scoped instance instMinOfOrd {α : Type u} [Ord α] :
Min α where
min a b := if (compare a b).isLE then a else b
public scoped instance instMaxOfOrd {α : Type u} [Ord α] :
Max α where
max a b := if (compare b a).isLE then a else b
public instance instLawfulOrderLeftLeaningMinOfOrd {α : Type u} [Ord α] [LE α] [LawfulOrderOrd α] :
LawfulOrderLeftLeaningMin α where
min_eq_left a b := by simp +contextual only [← Std.isLE_compare, min, ↑reduceIte, implies_true]
min_eq_right a b := by
simp +contextual only [← Std.isLE_compare, min, Bool.false_eq_true, ↑reduceIte, implies_true]
public instance instLawfulOrderLeftLeaningMaxOfOrd {α : Type u} [Ord α] [LE α] [LawfulOrderOrd α] :
LawfulOrderLeftLeaningMax α where
max_eq_left a b := by simp +contextual only [← Std.isLE_compare, max, ↑reduceIte, implies_true]
max_eq_right a b := by
simp +contextual only [← Std.isLE_compare, max, Bool.false_eq_true, ↑reduceIte, implies_true]
end FactoryInstances
/--
This structure contains all the data needed to create a `LinearOrderPackage α` instance.
Its fields are automatically provided if possible. For the detailed rules how the fields are
inferred, see `LinearOrderPackage.ofOrd`.
-/
public structure Packages.LinearOrderOfOrdArgs (α : Type u) extends
LinearPreorderOfOrdArgs α where
eq_of_compare :
let := ord; let := le
∀ a b : α, compare a b = .eq → a = b := by
extract_lets
first
| exact fun _ _ => _root_.Std.LawfulEqOrd.eq_of_compare
| fail "Failed to derive a `LawfulEqOrd` instance. \
Please make sure that it can be synthesized or \
manually provide the field `eq_of_compare`."
min :
let := ord
Min α := by
extract_lets
first
| infer_instance
| exact _root_.Std.FactoryInstances.instMinOfOrd
max :
let := ord
Max α := by
extract_lets
first
| infer_instance
| exact _root_.Std.FactoryInstances.instMaxOfOrd
min_eq :
let := ord; let := le; let := min; have := lawfulOrderOrd
∀ a b : α, Min.min a b = if (compare a b).isLE then a else b := by
extract_lets
first
| exact fun a b => _root_.Std.min_eq_if_isLE_compare (a := a) (b := b)
| fail "Failed to automatically prove that `min` is left-leaning. \
Please ensure that a `LawfulOrderLeftLeaningMin` instance can be synthesized or \
manually provide the field `min_eq`."
max_eq :
let := ord; let := le; let := max; have := lawfulOrderOrd
∀ 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)
| 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`."
/--
Use this factory to conveniently define a linear order on a type `α` and all the associated
operations and instances given an `Ord α` instance.
Creates a `LinearOrderPackage α` instance. Such an instance entails `LE α`, `LT α`, `BEq α`,
`Ord α`, `Min α` and `Max α` instances as well as an `IsLinearOrder α` instance and `LawfulOrder*`
instances proving the compatibility of the operations with the linear order.
In the presence of `Ord α`, `TransOrd α` and `LawfulEqOrd α` instances, no arguments are required
and the factory can be used as in this
example:
```lean
public instance : LinearOrderPackage X := .ofLE X
```
If not all of these instances are available via typeclass synthesis, it is necessary to explicitly
provide some arguments:
```lean
public instance : LinearOrderPackage X := .ofLE X {
transOrd := sorry
eq_of_compare := sorry }
```
It is also possible to do all of this by hand, without resorting to `LinearOrderPackage`. This
can be useful if, say, one wants to avoid specifying an `LT α` instance, which is not possible with
`LinearOrderPackage`.
**How the arguments are filled**
Lean tries to fill all of the fields of the `args : Packages.LinearOrderOfLEArgs α` parameter
automatically. If it fails, it is necessary to provide some of the fields manually.
* For the data-carrying typeclasses `LE`, `LT`, `BEq`, `Ord`, `Min` and `Max`, existing instances
are always preferred. If no existing instances can be synthesized, it is attempted to derive an
instance from the `Ord` instance.
* Some proof obligations can be filled automatically if the data-carrying typeclasses have been
derived from the `Ord` instance. For example: If the `beq` field is omitted and no `BEq α` instance
can be synthesized, it is derived from the `LE α` instance. In this case, `beq_iff`
can be omitted because Lean can infer that `BEq α` and `Ord α` are compatible.
* Other proof obligations, such as `transOrd`, can be omitted if matching instances can be
synthesized.
-/
@[expose]
public def LinearOrderPackage.ofOrd (α : Type u)
(args : Packages.LinearOrderOfOrdArgs α := by exact {}) : LinearOrderPackage α :=
letI := LinearPreorderPackage.ofOrd α args.toLinearPreorderOfOrdArgs
haveI : LawfulEqOrd α := ⟨args.eq_of_compare _ _⟩
letI : Min α := args.min
letI : Max α := args.max
{ toMin := args.min
toMax := args.max,
le_antisymm := Antisymm.antisymm
toLawfulOrderMin := by
haveI : LawfulOrderLeftLeaningMin α := .of_eq (by simpa [isLE_compare] using args.min_eq)
infer_instance
toLawfulOrderMax := by
haveI : LawfulOrderLeftLeaningMax α := .of_eq (by simpa [isGE_compare] using args.max_eq)
infer_instance }
end LinearOrder
end Std