Skip to content

Commit bedd394

Browse files
committed
feat: IsBotOneClass and IsBotZeroClass (leanprover-community#38730)
We create typeclasses expressing that `0` or `1` is a bottom element in a type. We use this to unify and generalize various theorems which are currently stated for canonically ordered monoids. This has provisionally left us with a bunch of unnecessary aliases; these will be deprecated in a follow-up PR (tentatively leanprover-community#38663). See [Zulip](https://leanprover.zulipchat.com/#narrow/channel/287929-mathlib4/topic/Typeclass.20for.20IsBot.200/near/586314552).
1 parent ea11ccc commit bedd394

17 files changed

Lines changed: 235 additions & 164 deletions

File tree

Mathlib.lean

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1007,6 +1007,7 @@ public import Mathlib.Algebra.Order.Interval.Set.Instances
10071007
public import Mathlib.Algebra.Order.Interval.Set.Monoid
10081008
public import Mathlib.Algebra.Order.Interval.Set.SuccPred
10091009
public import Mathlib.Algebra.Order.Invertible
1010+
public import Mathlib.Algebra.Order.IsBotOne
10101011
public import Mathlib.Algebra.Order.Kleene
10111012
public import Mathlib.Algebra.Order.Module.Algebra
10121013
public import Mathlib.Algebra.Order.Module.Archimedean

Mathlib/Algebra/Order/Field/Canonical.lean

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ abbrev CanonicallyOrderedAdd.toLinearOrderedCommGroupWithZero :
2323
LinearOrderedCommGroupWithZero α where
2424
bot := 0
2525
bot_le _ := zero_le
26-
zero_le _ := zero_le
26+
isBot_zero _ := zero_le
2727
mul_lt_mul_of_pos_left _a ha _b _c hbc :=
2828
have : PosMulStrictMono α := PosMulReflectLT.toPosMulStrictMono _
2929
mul_lt_mul_of_pos_left hbc ha

Mathlib/Algebra/Order/GroupWithZero/Canonical.lean

Lines changed: 28 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,7 @@ variable {α β : Type*}
3838

3939
/-- A linearly ordered commutative monoid with a zero element. -/
4040
class LinearOrderedCommMonoidWithZero (α : Type*) extends CommMonoidWithZero α, LinearOrder α,
41-
PosMulStrictMono α, OrderBot α where
42-
protected zero_le (a : α) : 0 ≤ a
41+
PosMulStrictMono α, OrderBot α, IsBotZeroClass α where
4342

4443
/-- A linearly ordered commutative group with a zero element. -/
4544
class LinearOrderedCommGroupWithZero (α : Type*) extends LinearOrderedCommMonoidWithZero α,
@@ -52,20 +51,6 @@ variable [LinearOrderedCommMonoidWithZero α] {a b : α} {n : ℕ}
5251
The following facts are true more generally in a (linearly) ordered commutative monoid.
5352
-/
5453

55-
@[simp] lemma zero_le' : 0 ≤ a := LinearOrderedCommMonoidWithZero.zero_le _
56-
@[simp] lemma not_lt_zero' : ¬a < 0 := zero_le'.not_gt
57-
@[simp] lemma le_zero_iff : a ≤ 0 ↔ a = 0 := by simp [le_antisymm_iff]
58-
59-
lemma zero_lt_iff : 0 < a ↔ a ≠ 0 := by simp [lt_iff_le_and_ne, eq_comm]
60-
lemma ne_zero_of_lt (h : b < a) : a ≠ 0 := fun h1 ↦ not_lt_zero' <| show b < 0 from h1 ▸ h
61-
62-
/-- See also `bot_eq_zero` and `bot_eq_zero'` for canonically ordered monoids. -/
63-
lemma bot_eq_zero'' : (⊥ : α) = 0 := eq_of_forall_ge_iff fun _ ↦ by simp
64-
65-
-- See note [lower instance priority]
66-
instance (priority := 100) LinearOrderedCommMonoidWithZero.toZeroLeOneClass : ZeroLEOneClass α where
67-
zero_le_one := zero_le'
68-
6954
-- See note [lower instance priority]
7055
instance (priority := 100) LinearOrderedCommMonoidWithZero.toMulPosStrictMono :
7156
MulPosStrictMono α := posMulStrictMono_iff_mulPosStrictMono.1 inferInstance
@@ -78,12 +63,12 @@ instance (priority := 100) LinearOrderedCommMonoidWithZero.toIsOrderedMonoid :
7863
· simp
7964
obtain rfl | hab := hab.eq_or_lt
8065
· simp
81-
· exact (mul_lt_mul_of_pos_right hab <| zero_lt_iff.2 hc).le
66+
· exact (mul_lt_mul_of_pos_right hab hc.pos).le
8267

8368
-- See note [lower instance priority]
8469
instance (priority := 100) : IsCancelMulZero α where
85-
mul_left_cancel_of_ne_zero ha := (strictMono_mul_left_of_pos <| zero_lt_iff.2 ha).injective
86-
mul_right_cancel_of_ne_zero ha := (strictMono_mul_right_of_pos <| zero_lt_iff.2 ha).injective
70+
mul_left_cancel_of_ne_zero ha := (strictMono_mul_left_of_pos ha.pos).injective
71+
mul_right_cancel_of_ne_zero ha := (strictMono_mul_right_of_pos ha.pos).injective
8772

8873
/-- Pullback a `LinearOrderedCommMonoidWithZero` under an injective map.
8974
See note [reducible non-instances]. -/
@@ -100,7 +85,7 @@ abbrev Function.Injective.linearOrderedCommMonoidWithZero {β : Type*} [Zero β]
10085
__ := hf.linearOrder f le lt hinf hsup compare
10186
__ := hf.commMonoidWithZero f zero one mul npow
10287
__ := Function.Injective.posMulStrictMono f zero mul lt
103-
zero_le _ := le.1 <| zero ▸ zero_le'
88+
isBot_zero _ := le.1 <| zero ▸ zero_le
10489
bot_le _ := le.1 <| bot ▸ bot_le
10590

10691
instance (priority := 100) LinearOrderedCommMonoidWithZero.toIsMulTorsionFree :
@@ -109,17 +94,18 @@ instance (priority := 100) LinearOrderedCommMonoidWithZero.toIsMulTorsionFree :
10994

11095
instance instLinearOrderedAddCommMonoidWithTopAdditiveOrderDual :
11196
LinearOrderedAddCommMonoidWithTop (Additive αᵒᵈ) where
112-
top_add' a := by ext; simp [bot_eq_zero'']
113-
isAddLeftRegular_of_ne_top := by simp +contextual [IsRegular.of_ne_zero, bot_eq_zero'']
97+
top_add' a := by ext; simp [bot_eq_zero]
98+
isAddLeftRegular_of_ne_top := by simp +contextual [IsRegular.of_ne_zero, bot_eq_zero]
11499

115100
instance instLinearOrderedAddCommMonoidWithTopOrderDualAdditive :
116101
LinearOrderedAddCommMonoidWithTop (Additive α)ᵒᵈ where
117-
top_add' a := by ext; simp; simp [bot_eq_zero'' (α := α)]
118-
isAddLeftRegular_of_ne_top := by simp; simp +contextual [bot_eq_zero'', IsRegular.of_ne_zero]
102+
top_add' a := by ext; simp; simp [bot_eq_zero (α := α)]
103+
isAddLeftRegular_of_ne_top := by simp; simp +contextual [bot_eq_zero, IsRegular.of_ne_zero]
119104

120105
variable [NoZeroDivisors α]
121106

122-
lemma pow_pos_iff (hn : n ≠ 0) : 0 < a ^ n ↔ 0 < a := by simp_rw [zero_lt_iff, pow_ne_zero_iff hn]
107+
lemma pow_pos_iff (hn : n ≠ 0) : 0 < a ^ n ↔ 0 < a := by
108+
simp_rw [pos_iff_ne_zero, pow_ne_zero_iff hn]
123109

124110
end LinearOrderedCommMonoidWithZero
125111

@@ -128,35 +114,35 @@ variable [LinearOrderedCommGroupWithZero α] {a b c d : α} {m n : ℕ}
128114

129115
@[simp]
130116
theorem Units.zero_lt (u : αˣ) : (0 : α) < u :=
131-
zero_lt_iff.2 u.ne_zero
117+
u.ne_zero.pos
132118

133119
theorem mul_inv_lt_of_lt_mul₀ (h : a < b * c) : a * c⁻¹ < b := by
134120
contrapose! h
135-
simpa only [inv_inv] using mul_inv_le_of_le_mul₀ zero_le' zero_le' h
121+
simpa only [inv_inv] using mul_inv_le_of_le_mul₀ zero_le zero_le h
136122

137123
theorem inv_mul_lt_of_lt_mul₀ (h : a < b * c) : b⁻¹ * a < c := by
138124
rw [mul_comm] at *
139125
exact mul_inv_lt_of_lt_mul₀ h
140126

141127
theorem lt_of_mul_lt_mul_of_le₀ (h : a * b < c * d) (hc : 0 < c) (hh : c ≤ a) : b < d := by
142128
have ha : a ≠ 0 := ne_of_gt (lt_of_lt_of_le hc hh)
143-
rw [← inv_le_inv₀ (zero_lt_iff.2 ha) hc] at hh
129+
rw [← inv_le_inv₀ ha.pos hc] at hh
144130
simpa [inv_mul_cancel_left₀ ha, inv_mul_cancel_left₀ hc.ne']
145-
using mul_lt_mul_of_le_of_lt_of_nonneg_of_pos hh h zero_le' (inv_pos.2 hc)
131+
using mul_lt_mul_of_le_of_lt_of_nonneg_of_pos hh h zero_le (inv_pos.2 hc)
146132

147133
instance : LinearOrderedAddCommGroupWithTop (Additive αᵒᵈ) where
148134
top_add' := by simp
149-
neg_top := by ext; simp [bot_eq_zero'']
135+
neg_top := by ext; simp [bot_eq_zero]
150136
add_neg_cancel_of_ne_top := by
151-
simp +contextual [bot_eq_zero'', Additive.ext_iff, OrderDual.ext_iff, -Additive.toMul_eq_top,
137+
simp +contextual [bot_eq_zero, Additive.ext_iff, OrderDual.ext_iff, -Additive.toMul_eq_top,
152138
-ofDual_eq_zero]
153139

154140
instance : LinearOrderedAddCommGroupWithTop (Additive α)ᵒᵈ where
155141
top_add' := by simp
156-
neg_top := by ext; simp; simp [bot_eq_zero'']
142+
neg_top := by ext; simp; simp [bot_eq_zero]
157143
add_neg_cancel_of_ne_top := by
158144
simp
159-
simp +contextual [bot_eq_zero'', Additive.ext_iff, OrderDual.ext_iff, -Additive.toMul_eq_top,
145+
simp +contextual [bot_eq_zero, Additive.ext_iff, OrderDual.ext_iff, -Additive.toMul_eq_top,
160146
-ofDual_eq_zero]
161147

162148
-- Counterexample with monoid for the backward direction:
@@ -171,7 +157,7 @@ lemma denselyOrdered_iff_denselyOrdered_units_and_nontrivial_units :
171157
refine ⟨Units.mk0 z (ne_zero_of_lt hz.1), by simp [← Units.val_lt_val, hz]⟩
172158
· refine ⟨fun x y h ↦ ?_⟩
173159
lift y to αˣ using (ne_zero_of_lt h).isUnit
174-
obtain rfl | hx := (zero_le' (a := x)).eq_or_lt
160+
obtain rfl | hx := eq_zero_or_pos x
175161
· obtain ⟨z, hz⟩ := exists_one_lt' (α := αˣ)
176162
exact ⟨(y * z⁻¹ : αˣ), by simp, Units.val_lt_val.mpr <| by simp [hz]⟩
177163
· lift x to αˣ using hx.ne'.isUnit
@@ -201,7 +187,7 @@ instance instLinearOrderedCommMonoidWithZeroMultiplicativeOrderDual
201187
zero := .ofAdd <| .toDual ⊤
202188
zero_mul := @top_add _ (_)
203189
mul_zero := @add_top _ (_)
204-
zero_le _ := (le_top : _ ≤ ⊤)
190+
isBot_zero _ := (le_top : _ ≤ ⊤)
205191
mul_lt_mul_of_pos_left := by
206192
simpa [← ofAdd_add, ← toDual_add]
207193
using fun a ha b c hbc ↦ add_right_strictMono_of_ne_top (by simpa using ha.ne') hbc
@@ -214,7 +200,7 @@ theorem ofAdd_toDual_eq_zero_iff [LinearOrderedAddCommMonoidWithTop α]
214200
theorem ofDual_toAdd_eq_top_iff [LinearOrderedAddCommMonoidWithTop α]
215201
(x : Multiplicative αᵒᵈ) : OrderDual.ofDual x.toAdd = ⊤ ↔ x = 0 := Iff.rfl
216202

217-
@[deprecated bot_eq_zero'' (since := "2025-11-17")]
203+
@[deprecated bot_eq_zero (since := "2025-11-17")]
218204
theorem ofAdd_bot [LinearOrderedAddCommMonoidWithTop α] :
219205
Multiplicative.ofAdd ⊥ = (0 : Multiplicative αᵒᵈ) := rfl
220206

@@ -255,7 +241,11 @@ instance instOrderBot : OrderBot (WithZero α) := inferInstanceAs <| OrderBot (W
255241
instance instBoundedOrder [OrderTop α] : BoundedOrder (WithZero α) :=
256242
inferInstanceAs <| BoundedOrder (WithBot α)
257243

258-
@[simp] lemma zero_le (a : WithZero α) : 0 ≤ a := bot_le (a := a)
244+
instance : IsBotZeroClass (WithZero α) where
245+
isBot_zero _ := bot_le
246+
247+
-- TODO: deprecate
248+
lemma zero_le (a : WithZero α) : 0 ≤ a := by simp
259249

260250
/-- There is a general version `le_zero_iff`, but this lemma does not require a `PartialOrder`. -/
261251
@[simp]
@@ -521,7 +511,7 @@ instance instCanonicallyOrderedAdd [AddZeroClass α] [Preorder α] [CanonicallyO
521511

522512
instance instLinearOrderedCommMonoidWithZero [CommMonoid α] [LinearOrder α]
523513
[IsOrderedCancelMonoid α] : LinearOrderedCommMonoidWithZero (WithZero α) where
524-
zero_le := WithZero.zero_le
514+
isBot_zero := WithZero.zero_le
525515
mul_lt_mul_of_pos_left
526516
| (a : α), _, 0, (c : α), _ => by simp [← WithZero.coe_mul]
527517
| (a : α), _, (b : α), (c : α), hbc => by norm_cast at *; exact mul_lt_mul_right hbc _

Mathlib/Algebra/Order/GroupWithZero/Range.lean

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ instance : IsOrderedMonoid (ValueGroup₀ f) :=
4747
Function.Injective.isOrderedMonoid embedding (map_mul _) embedding_strictMono.le_iff_le
4848

4949
instance : LinearOrderedCommGroupWithZero (ValueGroup₀ f) where
50-
zero_le := by simp
50+
isBot_zero _ := by simp
5151
mul_lt_mul_of_pos_left a ha b c hbc := by
5252
simp only [← (embedding_strictMono (f := f)).lt_iff_lt, map_mul] at *
5353
exact (mul_lt_mul_iff_of_pos_left ha).mpr hbc
Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
/-
2+
Copyright (c) 2026 Violeta Hernández Palacios. All rights reserved.
3+
Released under Apache 2.0 license as described in the file LICENSE.
4+
Authors: Violeta Hernández Palacios
5+
-/
6+
module
7+
8+
public import Mathlib.Algebra.Order.ZeroLEOne
9+
public import Mathlib.Tactic.ToAdditive
10+
public import Mathlib.Order.Max
11+
public import Mathlib.Order.BoundedOrder.Basic
12+
13+
/-!
14+
# Typeclasses expressing `IsBot 1` and `IsBot 0`
15+
-/
16+
17+
public section
18+
19+
/-- A typeclass expressing that the `0` of a type is a bottom element. In a partial `OrderBot`, this
20+
is equivalent to `⊥ = 0`. -/
21+
class IsBotZeroClass (α : Type*) [LE α] [Zero α] : Prop where
22+
isBot_zero : IsBot (0 : α)
23+
24+
/-- A typeclass expressing that the `1` of a type is a bottom element. In a partial `OrderBot`, this
25+
is equivalent to `⊥ = 1`. -/
26+
@[to_additive existing]
27+
class IsBotOneClass (α : Type*) [LE α] [One α] : Prop where
28+
isBot_one : IsBot (1 : α)
29+
30+
variable {α : Type*} {a b : α}
31+
32+
section LE
33+
variable [LE α] [One α] [IsBotOneClass α]
34+
35+
@[to_additive]
36+
theorem isBot_one : IsBot (1 : α) :=
37+
IsBotOneClass.isBot_one
38+
39+
@[to_additive (attr := simp) zero_le]
40+
theorem one_le {a : α} : 1 ≤ a :=
41+
isBot_one a
42+
43+
-- TODO: deprecate
44+
alias zero_le' := zero_le
45+
46+
variable (α) in
47+
/-- Create an `OrderBot` instance, setting `1` as the bottom element. -/
48+
@[to_additive (attr := implicit_reducible)
49+
/-- Create an `OrderBot` instance, setting `0` as the bottom element. -/]
50+
def IsBotOneClass.toOrderBot : OrderBot α where
51+
bot := 1
52+
bot_le _ := one_le
53+
54+
end LE
55+
56+
-- See note [lower instance priority]
57+
instance (priority := 100) [LE α] [Zero α] [One α] [IsBotZeroClass α] : ZeroLEOneClass α where
58+
zero_le_one := zero_le
59+
60+
section Preorder
61+
variable [Preorder α] [One α] [IsBotOneClass α]
62+
63+
@[to_additive (attr := simp) not_lt_zero]
64+
theorem not_lt_one : ¬ a < 1 := one_le.not_gt
65+
66+
@[deprecated (since := "2025-12-03")] alias not_neg := not_lt_zero
67+
68+
-- TODO: deprecate
69+
alias not_lt_zero' := not_lt_zero
70+
71+
@[to_additive] -- `(attr := simp)` cannot be used here because `a` cannot be inferred by `simp`.
72+
theorem one_lt_of_gt (h : a < b) : 1 < b :=
73+
one_le.trans_lt h
74+
75+
@[to_additive] alias LT.lt.one_lt := one_lt_of_gt
76+
77+
@[to_additive]
78+
theorem ne_one_of_lt (h : a < b) : b ≠ 1 :=
79+
h.one_lt.ne'
80+
81+
@[to_additive] alias LT.lt.ne_one := ne_one_of_lt
82+
83+
end Preorder
84+
85+
section PartialOrder
86+
variable [PartialOrder α] [One α] [IsBotOneClass α]
87+
88+
-- Not `simp`, as different types might have a different preferred form.
89+
@[to_additive]
90+
theorem bot_eq_one [OrderBot α] : (⊥ : α) = 1 := isBot_one.eq_bot.symm
91+
92+
-- TODO: deprecate
93+
alias bot_eq_zero'' := bot_eq_zero
94+
95+
@[to_additive (attr := simp)]
96+
theorem le_one_iff_eq_one : a ≤ 1 ↔ a = 1 :=
97+
one_le.ge_iff_eq'
98+
99+
-- TODO: deprecate
100+
alias le_zero_iff := nonpos_iff_eq_zero
101+
102+
@[to_additive] alias ⟨eq_one_of_le_one, _⟩ := le_one_iff_eq_one
103+
@[to_additive] alias LE.le.eq_one := eq_one_of_le_one
104+
105+
@[to_additive]
106+
theorem one_lt_iff_ne_one : 1 < a ↔ a ≠ 1 :=
107+
one_le.lt_iff_ne.trans ne_comm
108+
109+
-- TODO: deprecate
110+
alias zero_lt_iff := pos_iff_ne_zero
111+
112+
@[to_additive] alias ⟨_, one_lt_of_ne_one⟩ := one_lt_iff_ne_one
113+
@[to_additive] alias Ne.one_lt := one_lt_of_ne_one
114+
115+
@[to_additive]
116+
theorem eq_one_or_one_lt (a : α) : a = 11 < a := one_le.eq_or_lt'
117+
118+
@[to_additive]
119+
lemma one_notMem_iff {s : Set α} : 1 ∉ s ↔ ∀ x ∈ s, 1 < x :=
120+
let := IsBotOneClass.toOrderBot α
121+
bot_notMem_iff
122+
123+
@[deprecated (since := "2026-02-17")] alias NE.ne.pos := Ne.pos
124+
@[deprecated (since := "2026-02-17")] alias NE.ne.one_lt := Ne.one_lt
125+
126+
end PartialOrder
127+
128+
section LinearOrder
129+
variable [LinearOrder α] [One α] [IsBotOneClass α]
130+
131+
@[to_additive]
132+
theorem one_min (a : α) : min 1 a = 1 :=
133+
min_eq_left one_le
134+
135+
@[to_additive]
136+
theorem min_one (a : α) : min a 1 = 1 :=
137+
min_eq_right one_le
138+
139+
end LinearOrder
140+
141+
namespace NeZero
142+
variable [Zero α]
143+
144+
theorem of_gt [Preorder α] [IsBotZeroClass α] (h : a < b) : NeZero b :=
145+
⟨h.ne_zero⟩
146+
147+
theorem pos [PartialOrder α] [IsBotZeroClass α] (a : α) [NeZero a] : 0 < a :=
148+
NeZero.out.pos
149+
150+
-- 1 < p is still an often-used `Fact`, due to `Nat.Prime` implying it, and it implying `Nontrivial`
151+
-- on `ZMod`'s ring structure. We cannot just set this to be any `x < y`, else that becomes a
152+
-- metavariable and it will hugely slow down typeclass inference.
153+
instance (priority := 10) of_gt' [Preorder α] [IsBotZeroClass α] [One α]
154+
[Fact (1 < a)] : NeZero a := of_gt <| @Fact.out (1 < a) _
155+
156+
theorem of_ge [PartialOrder α] [IsBotZeroClass α] [NeZero a] (h : a ≤ b) : NeZero b :=
157+
⟨((pos a).trans_le h).ne_zero⟩
158+
159+
end NeZero

0 commit comments

Comments
 (0)