Skip to content

Commit

Permalink
feat(algebra/ordered_ring): more granular typeclasses for `with_top α…
Browse files Browse the repository at this point in the history
…` and `with_bot α` (#7845)

`with_top α` and `with_bot α` now inherit the following typeclasses from `α` with suitable assumptions:

* `mul_zero_one_class`
* `semigroup_with_zero`
* `monoid_with_zero`
* `comm_monoid_with_zero`

These were all split out of the existing `canonically_ordered_comm_semiring`, with their proofs unchanged.
The same instances are added for `with_bot`.

It is not possible to split further, as `distrib'` requires `add_eq_zero_iff`, and `canonically_ordered_comm_semiring` is the smallest typeclass that provides both this lemma and `mul_zero_class`.

With these instances in place, we can now show `comm_monoid_with_zero ereal`.
  • Loading branch information
eric-wieser committed Jun 10, 2021
1 parent 079b8a1 commit 49f5a15
Show file tree
Hide file tree
Showing 3 changed files with 184 additions and 47 deletions.
184 changes: 139 additions & 45 deletions src/algebra/ordered_ring.lean
Expand Up @@ -1346,6 +1346,12 @@ by simp only [pos_iff_ne_zero, ne.def, mul_eq_zero, not_or_distrib]

end canonically_ordered_semiring

/-! ### Structures involving `*` and `0` on `with_top` and `with_bot`
The main results of this section are `with_top.canonically_ordered_comm_semiring` and
`with_bot.comm_monoid_with_zero`.
-/

namespace with_top

instance [nonempty α] : nontrivial (with_top α) :=
Expand Down Expand Up @@ -1402,27 +1408,67 @@ begin
{ simp [← coe_mul] }
end

end mul_zero_class
lemma mul_lt_top [partial_order α] {a b : with_top α} (ha : a < ⊤) (hb : b < ⊤) : a * b < ⊤ :=
begin
lift a to α using ne_top_of_lt ha,
lift b to α using ne_top_of_lt hb,
simp only [← coe_mul, coe_lt_top]
end

section no_zero_divisors
end mul_zero_class

variables [mul_zero_class α] [no_zero_divisors α]
/-- `nontrivial α` is needed here as otherwise we have `1 * ⊤ = ⊤` but also `= 0 * ⊤ = 0`. -/
instance [mul_zero_one_class α] [nontrivial α] : mul_zero_one_class (with_top α) :=
{ mul := (*),
one := 1,
zero := 0,
one_mul := λ a, match a with
| none := show ((1:α) : with_top α) * ⊤ = ⊤, by simp [-with_top.coe_one]
| (some a) := show ((1:α) : with_top α) * a = a, by simp [coe_mul.symm, -with_top.coe_one]
end,
mul_one := λ a, match a with
| none := show ⊤ * ((1:α) : with_top α) = ⊤, by simp [-with_top.coe_one]
| (some a) := show ↑a * ((1:α) : with_top α) = a, by simp [coe_mul.symm, -with_top.coe_one]
end,
.. with_top.mul_zero_class }

instance : no_zero_divisors (with_top α) :=
instance [mul_zero_class α] [no_zero_divisors α] : no_zero_divisors (with_top α) :=
⟨λ a b, by cases a; cases b; dsimp [mul_def]; split_ifs;
simp [*, none_eq_top, some_eq_coe, mul_eq_zero] at *⟩

end no_zero_divisors
instance [semigroup_with_zero α] [no_zero_divisors α] : semigroup_with_zero (with_top α) :=
{ mul := (*),
zero := 0,
mul_assoc := λ a b c, begin
cases a,
{ by_cases hb : b = 0; by_cases hc : c = 0;
simp [*, none_eq_top] },
cases b,
{ by_cases ha : a = 0; by_cases hc : c = 0;
simp [*, none_eq_top, some_eq_coe] },
cases c,
{ by_cases ha : a = 0; by_cases hb : b = 0;
simp [*, none_eq_top, some_eq_coe] },
simp [some_eq_coe, coe_mul.symm, mul_assoc]
end,
.. with_top.mul_zero_class }

instance [monoid_with_zero α] [no_zero_divisors α] [nontrivial α] : monoid_with_zero (with_top α) :=
{ .. with_top.mul_zero_one_class, .. with_top.semigroup_with_zero }

instance [comm_monoid_with_zero α] [no_zero_divisors α] [nontrivial α] :
comm_monoid_with_zero (with_top α) :=
{ mul := (*),
zero := 0,
mul_comm := λ a b, begin
by_cases ha : a = 0, { simp [ha] },
by_cases hb : b = 0, { simp [hb] },
simp [ha, hb, mul_def, option.bind_comm a b, mul_comm]
end,
.. with_top.monoid_with_zero }

variables [canonically_ordered_comm_semiring α]

private lemma comm (a b : with_top α) : a * b = b * a :=
begin
by_cases ha : a = 0, { simp [ha] },
by_cases hb : b = 0, { simp [hb] },
simp [ha, hb, mul_def, option.bind_comm a b, mul_comm]
end

private lemma distrib' (a b c : with_top α) : (a + b) * c = a * c + b * c :=
begin
cases c,
Expand All @@ -1434,43 +1480,91 @@ begin
repeat { refl <|> exact congr_arg some (add_mul _ _ _) } }
end

private lemma assoc (a b c : with_top α) : (a * b) * c = a * (b * c) :=
begin
cases a,
{ by_cases hb : b = 0; by_cases hc : c = 0;
simp [*, none_eq_top] },
cases b,
{ by_cases ha : a = 0; by_cases hc : c = 0;
simp [*, none_eq_top, some_eq_coe] },
cases c,
{ by_cases ha : a = 0; by_cases hb : b = 0;
simp [*, none_eq_top, some_eq_coe] },
simp [some_eq_coe, coe_mul.symm, mul_assoc]
end

-- `nontrivial α` is needed here as otherwise
-- we have `1 * ⊤ = ⊤` but also `= 0 * ⊤ = 0`.
private lemma one_mul' [nontrivial α] : ∀a : with_top α, 1 * a = a
| none := show ((1:α) : with_top α) * ⊤ = ⊤, by simp [-with_top.coe_one]
| (some a) := show ((1:α) : with_top α) * a = a, by simp [coe_mul.symm, -with_top.coe_one]
/-- This instance requires `canonically_ordered_comm_semiring` as it is the smallest class
that derives from both `non_assoc_non_unital_semiring` and `canonically_ordered_add_monoid`, both
of which are required for distributivity. -/
instance [nontrivial α] : comm_semiring (with_top α) :=
{ right_distrib := distrib',
left_distrib := assume a b c, by rw [mul_comm, distrib', mul_comm b, mul_comm c]; refl,
.. with_top.add_comm_monoid, .. with_top.comm_monoid_with_zero,}

instance [nontrivial α] : canonically_ordered_comm_semiring (with_top α) :=
{ one := (1 : α),
right_distrib := distrib',
left_distrib := assume a b c, by rw [comm, distrib', comm b, comm c]; refl,
mul_assoc := assoc,
mul_comm := comm,
one_mul := one_mul',
mul_one := assume a, by rw [comm, one_mul'],
.. with_top.add_comm_monoid, .. with_top.mul_zero_class,
{ .. with_top.comm_semiring,
.. with_top.canonically_ordered_add_monoid,
.. with_top.no_zero_divisors, .. with_top.nontrivial }
.. with_top.no_zero_divisors, }

end with_top

namespace with_bot

instance [nonempty α] : nontrivial (with_bot α) :=
option.nontrivial

variable [decidable_eq α]

section has_mul

variables [has_zero α] [has_mul α]

instance : mul_zero_class (with_bot α) :=
with_top.mul_zero_class

lemma mul_def {a b : with_bot α} :
a * b = if a = 0 ∨ b = 0 then 0 else a.bind (λa, b.bind $ λb, ↑(a * b)) := rfl

@[simp] lemma mul_bot {a : with_bot α} (h : a ≠ 0) : a * ⊥ = ⊥ :=
with_top.mul_top h

@[simp] lemma bot_mul {a : with_bot α} (h : a ≠ 0) : ⊥ * a = ⊥ :=
with_top.top_mul h

@[simp] lemma bot_mul_bot : (⊥ * ⊥ : with_bot α) = ⊥ :=
with_top.top_mul_top

end has_mul

section mul_zero_class

variables [mul_zero_class α]

lemma mul_lt_top [nontrivial α] {a b : with_top α} (ha : a < ⊤) (hb : b < ⊤) : a * b < ⊤ :=
@[norm_cast] lemma coe_mul {a b : α} : (↑(a * b) : with_bot α) = a * b :=
decidable.by_cases (assume : a = 0, by simp [this]) $ assume ha,
decidable.by_cases (assume : b = 0, by simp [this]) $ assume hb,
by { simp [*, mul_def], refl }

lemma mul_coe {b : α} (hb : b ≠ 0) {a : with_bot α} : a * b = a.bind (λa:α, ↑(a * b)) :=
with_top.mul_coe hb

@[simp] lemma mul_eq_bot_iff {a b : with_bot α} : a * b = ⊥ ↔ (a ≠ 0 ∧ b = ⊥) ∨ (a = ⊥ ∧ b ≠ 0) :=
with_top.mul_eq_top_iff

lemma bot_lt_mul [partial_order α] {a b : with_bot α} (ha : ⊥ < a) (hb : ⊥ < b) : ⊥ < a * b :=
begin
lift a to α using ne_top_of_lt ha,
lift b to α using ne_top_of_lt hb,
simp only [← coe_mul, coe_lt_top]
lift a to α using ne_bot_of_gt ha,
lift b to α using ne_bot_of_gt hb,
simp only [← coe_mul, bot_lt_coe],
end

end with_top
end mul_zero_class

/-- `nontrivial α` is needed here as otherwise we have `1 * ⊥ = ⊥` but also `= 0 * ⊥ = 0`. -/
instance [mul_zero_one_class α] [nontrivial α] : mul_zero_one_class (with_bot α) :=
with_top.mul_zero_one_class

instance [mul_zero_class α] [no_zero_divisors α] : no_zero_divisors (with_bot α) :=
with_top.no_zero_divisors

instance [semigroup_with_zero α] [no_zero_divisors α] : semigroup_with_zero (with_bot α) :=
with_top.semigroup_with_zero

instance [monoid_with_zero α] [no_zero_divisors α] [nontrivial α] : monoid_with_zero (with_bot α) :=
with_top.monoid_with_zero

instance [comm_monoid_with_zero α] [no_zero_divisors α] [nontrivial α] :
comm_monoid_with_zero (with_bot α) :=
with_top.comm_monoid_with_zero

instance [canonically_ordered_comm_semiring α] [nontrivial α] : comm_semiring (with_bot α) :=
with_top.comm_semiring

end with_bot
42 changes: 40 additions & 2 deletions src/data/real/ereal.lean
Expand Up @@ -23,6 +23,9 @@ to a group structure. Our choice is that `⊥ + ⊤ = ⊤ + ⊥ = ⊤`.
An ad hoc subtraction is then defined by `x - y = x + (-y)`. It does not have nice properties,
but it is sometimes convenient to have.
An ad hoc multiplication is defined, for which `ereal` is a `comm_monoid_with_zero`.
This does not distribute with addition, as `⊤ = ⊤ - ⊥ = 1*⊤ - 1*⊤ ≠ (1 - 1) * ⊤ = 0 * ⊤ = 0`.
`ereal` is a `complete_linear_order`; this is deduced by type class inference from
the fact that `with_top (with_bot L)` is a complete linear order if `L` is
a conditionally complete linear order.
Expand All @@ -49,7 +52,7 @@ See https://isabelle.in.tum.de/dist/library/HOL/HOL-Library/Extended_Real.html
open_locale ennreal nnreal

/-- ereal : The type `[-∞, ∞]` -/
@[derive [order_bot, order_top,
@[derive [order_bot, order_top, comm_monoid_with_zero,
has_Sup, has_Inf, complete_linear_order, linear_ordered_add_comm_monoid_with_top]]
def ereal := with_top (with_bot ℝ)

Expand Down Expand Up @@ -288,7 +291,7 @@ begin
{ simp [lt_top_iff_ne_top, with_top.add_eq_top, h1.ne, (h2.trans_le le_top).ne] }
end

@[simp] lemma ad_eq_top_iff {x y : ereal} : x + y = ⊤ ↔ x = ⊤ ∨ y = ⊤ :=
@[simp] lemma add_eq_top_iff {x y : ereal} : x + y = ⊤ ↔ x = ⊤ ∨ y = ⊤ :=
begin
rcases x.cases with rfl|⟨x, rfl⟩|rfl; rcases y.cases with rfl|⟨x, rfl⟩|rfl;
simp [← ereal.coe_add],
Expand Down Expand Up @@ -393,6 +396,13 @@ protected noncomputable def sub (x y : ereal) : ereal := x + (-y)

noncomputable instance : has_sub ereal := ⟨ereal.sub⟩

@[simp] lemma top_sub (x : ereal) : ⊤ - x = ⊤ := top_add x
@[simp] lemma sub_bot (x : ereal) : x - ⊥ = ⊤ := add_top x

@[simp] lemma bot_sub_top : (⊥ : ereal) - ⊤ = ⊥ := rfl
@[simp] lemma bot_sub_coe (x : ℝ) : (⊥ : ereal) - x = ⊥ := rfl
@[simp] lemma coe_sub_bot (x : ℝ) : (x : ereal) - ⊤ = ⊥ := rfl

@[simp] lemma sub_zero (x : ereal) : x - 0 = x := by { change x + (-0) = x, simp }
@[simp] lemma zero_sub (x : ereal) : 0 - x = - x := by { change 0 + (-x) = - x, simp }

Expand Down Expand Up @@ -430,4 +440,32 @@ begin
{ simpa using h'y }
end

/-! ### Multiplication -/

@[simp] lemma coe_one : ((1 : ℝ) : ereal) = 1 := rfl

@[simp, norm_cast] lemma coe_mul (x y : ℝ) : ((x * y : ℝ) : ereal) = (x : ereal) * (y : ereal) :=
eq.trans (with_bot.coe_eq_coe.mpr with_bot.coe_mul) with_top.coe_mul

@[simp] lemma mul_top (x : ereal) (h : x ≠ 0) : x * ⊤ = ⊤ := with_top.mul_top h
@[simp] lemma top_mul (x : ereal) (h : x ≠ 0) : ⊤ * x = ⊤ := with_top.top_mul h

@[simp] lemma bot_mul_bot : (⊥ : ereal) * ⊥ = ⊥ := rfl
@[simp] lemma bot_mul_coe (x : ℝ) (h : x ≠ 0) : (⊥ : ereal) * x = ⊥ :=
with_top.coe_mul.symm.trans $
with_bot.coe_eq_coe.mpr $ with_bot.bot_mul $ function.injective.ne (@option.some.inj _) h
@[simp] lemma coe_mul_bot (x : ℝ) (h : x ≠ 0) : (x : ereal) * ⊥ = ⊥ :=
with_top.coe_mul.symm.trans $
with_bot.coe_eq_coe.mpr $ with_bot.mul_bot $ function.injective.ne (@option.some.inj _) h

@[simp] lemma to_real_one : to_real 1 = 1 := rfl

lemma to_real_mul : ∀ {x y : ereal}, to_real (x * y) = to_real x * to_real y
| ⊤ y := by by_cases hy : y = 0; simp [hy]
| x ⊤ := by by_cases hx : x = 0; simp [hx]
| (x : ℝ) (y : ℝ) := by simp [← ereal.coe_mul]
| ⊥ (y : ℝ) := by by_cases hy : y = 0; simp [hy]
| (x : ℝ) ⊥ := by by_cases hx : x = 0; simp [hx]
| ⊥ ⊥ := by simp

end ereal
5 changes: 5 additions & 0 deletions src/order/bounded_lattice.lean
Expand Up @@ -469,6 +469,11 @@ lemma bot_lt_some [has_lt α] (a : α) : (⊥ : with_bot α) < some a :=

lemma bot_lt_coe [has_lt α] (a : α) : (⊥ : with_bot α) < a := bot_lt_some a

instance : can_lift (with_bot α) α :=
{ coe := coe,
cond := λ r, r ≠ ⊥,
prf := λ x hx, ⟨option.get $ option.ne_none_iff_is_some.1 hx, option.some_get _⟩ }

instance [preorder α] : preorder (with_bot α) :=
{ le := λ o₁ o₂ : option α, ∀ a ∈ o₁, ∃ b ∈ o₂, a ≤ b,
lt := (<),
Expand Down

0 comments on commit 49f5a15

Please sign in to comment.