Skip to content

Commit

Permalink
feat(algebra/group_with_zero): Bundled monoid_with_zero_hom (#4995)
Browse files Browse the repository at this point in the history
This adds, without notation, `monoid_with_zero_hom` as a variant of `A →* B` that also satisfies `f 0 = 0`.

As part of this, this change:

* Splits up `group_with_zero` into multiple files, so that the definitions can be used in the bundled homs before any of the lemmas start pulling in dependencies
* Adds `monoid_with_zero_hom` as a base class of `ring_hom`
* Changes some `monoid_hom` objects into `monoid_with_zero_hom` objects.
* Moves some lemmas about `valuation` into `monoid_hom`, since they apply more generally
* Add automatic coercions between `monoid_with_zero_hom` and `monoid_hom`
  • Loading branch information
eric-wieser committed Nov 17, 2020
1 parent 7a70764 commit 86b0971
Show file tree
Hide file tree
Showing 22 changed files with 360 additions and 177 deletions.
6 changes: 3 additions & 3 deletions scripts/copy-mod-doc-exceptions.txt
Expand Up @@ -102,9 +102,9 @@ src/algebra/group_action_hom.lean : line 269 : ERR_LIN : Line has more than 100
src/algebra/group_power/basic.lean : line 414 : ERR_LIN : Line has more than 100 characters
src/algebra/group_power/basic.lean : line 501 : ERR_LIN : Line has more than 100 characters
src/algebra/group_power/lemmas.lean : line 536 : ERR_LIN : Line has more than 100 characters
src/algebra/group_with_zero.lean : line 295 : ERR_LIN : Line has more than 100 characters
src/algebra/group_with_zero.lean : line 316 : ERR_LIN : Line has more than 100 characters
src/algebra/group_with_zero_power.lean : line 165 : ERR_LIN : Line has more than 100 characters
src/algebra/group_with_zero/basic.lean : line 295 : ERR_LIN : Line has more than 100 characters
src/algebra/group_with_zero/basic.lean : line 316 : ERR_LIN : Line has more than 100 characters
src/algebra/group_with_zero/power.lean : line 165 : ERR_LIN : Line has more than 100 characters
src/algebra/invertible.lean : line 216 : ERR_LIN : Line has more than 100 characters
src/algebra/invertible.lean : line 224 : ERR_LIN : Line has more than 100 characters
src/algebra/invertible.lean : line 233 : ERR_LIN : Line has more than 100 characters
Expand Down
8 changes: 4 additions & 4 deletions src/algebra/field.lean
Expand Up @@ -247,15 +247,15 @@ section
variables {β γ : Type*} [division_ring α] [semiring β] [nontrivial β] [division_ring γ]
(f : α →+* β) (g : α →+* γ) {x y : α}

lemma map_ne_zero : f x ≠ 0 ↔ x ≠ 0 := (f : α →* β).map_ne_zero f.map_zero
lemma map_ne_zero : f x ≠ 0 ↔ x ≠ 0 := f.to_monoid_with_zero_hom.map_ne_zero

lemma map_eq_zero : f x = 0 ↔ x = 0 := (f : α →* β).map_eq_zero f.map_zero
lemma map_eq_zero : f x = 0 ↔ x = 0 := f.to_monoid_with_zero_hom.map_eq_zero

variables (x y)

lemma map_inv : g x⁻¹ = (g x)⁻¹ := (g : α →* γ).map_inv' g.map_zero x
lemma map_inv : g x⁻¹ = (g x)⁻¹ := g.to_monoid_with_zero_hom.map_inv' x

lemma map_div : g (x / y) = g x / g y := (g : α →* γ).map_div g.map_zero x y
lemma map_div : g (x / y) = g x / g y := g.to_monoid_with_zero_hom.map_div x y

protected lemma injective : function.injective f := f.injective_iff.2 $ λ x, f.map_eq_zero.1

Expand Down
4 changes: 2 additions & 2 deletions src/algebra/field_power.lean
Expand Up @@ -5,14 +5,14 @@ Authors: Robert Y. Lewis
Integer power operation on fields.
-/
import algebra.group_with_zero_power
import algebra.group_with_zero.power
import tactic.linarith

universe u

@[simp] lemma ring_hom.map_fpow {K L : Type*} [division_ring K] [division_ring L] (f : K →+* L) :
∀ (a : K) (n : ℤ), f (a ^ n) = f a ^ n :=
f.to_monoid_hom.map_fpow f.map_zero
f.to_monoid_with_zero_hom.map_fpow

@[simp] lemma neg_fpow_bit0 {K : Type*} [division_ring K] (x : K) (n : ℤ) :
(-x) ^ (bit0 n) = x ^ bit0 n :=
Expand Down
5 changes: 3 additions & 2 deletions src/algebra/gcd_monoid.lean
Expand Up @@ -83,8 +83,9 @@ variables [comm_cancel_monoid_with_zero α] [nontrivial α] [normalization_monoi
norm_unit_coe_units 1

/-- Chooses an element of each associate class, by multiplying by `norm_unit` -/
def normalize : α →* α :=
def normalize : monoid_with_zero_hom α α :=
{ to_fun := λ x, x * norm_unit x,
map_zero' := by simp,
map_one' := by rw [norm_unit_one, units.coe_one, mul_one],
map_mul' := λ x y,
classical.by_cases (λ hx : x = 0, by rw [hx, zero_mul, zero_mul, zero_mul]) $ λ hx,
Expand All @@ -102,7 +103,7 @@ associates.mk_eq_mk_iff_associated.2 normalize_associated

@[simp] lemma normalize_apply {x : α} : normalize x = x * norm_unit x := rfl

@[simp] lemma normalize_zero : normalize (0 : α) = 0 := by simp
@[simp] lemma normalize_zero : normalize (0 : α) = 0 := normalize.map_zero

@[simp] lemma normalize_one : normalize (1 : α) = 1 := normalize.map_one

Expand Down
2 changes: 1 addition & 1 deletion src/algebra/geom_sum.lean
Expand Up @@ -5,7 +5,7 @@ Authors: Neil Strickland
Sums of finite geometric series
-/
import algebra.group_with_zero_power
import algebra.group_with_zero.power
import algebra.big_operators.order
import algebra.big_operators.ring
import algebra.big_operators.intervals
Expand Down
137 changes: 134 additions & 3 deletions src/algebra/group/hom.lean

Large diffs are not rendered by default.

Expand Up @@ -6,6 +6,7 @@ Authors: Johan Commelin
import logic.nontrivial
import algebra.group.units_hom
import algebra.group.inj_surj
import algebra.group_with_zero.defs

/-!
# Groups with an adjoined zero element
Expand All @@ -22,8 +23,9 @@ Examples are:
## Main definitions
* `group_with_zero`
* `comm_group_with_zero`
Various lemmas about `group_with_zero` and `comm_group_with_zero`.
To reduce import dependencies, the type-classes themselves are in
`algebra.group_with_zero.defs`.
## Implementation details
Expand All @@ -44,22 +46,10 @@ division-free."

section

/-- Typeclass for expressing that a type `M₀` with multiplication and a zero satisfies
`0 * a = 0` and `a * 0 = 0` for all `a : M₀`. -/
@[protect_proj, ancestor has_mul has_zero]
class mul_zero_class (M₀ : Type*) extends has_mul M₀, has_zero M₀ :=
(zero_mul : ∀ a : M₀, 0 * a = 0)
(mul_zero : ∀ a : M₀, a * 0 = 0)

section mul_zero_class

variables [mul_zero_class M₀] {a b : M₀}

@[ematch, simp] lemma zero_mul (a : M₀) : 0 * a = 0 :=
mul_zero_class.zero_mul a

@[ematch, simp] lemma mul_zero (a : M₀) : a * 0 = 0 :=
mul_zero_class.mul_zero a

/-- Pullback a `mul_zero_class` instance along an injective function. -/
protected def function.injective.mul_zero_class [has_mul M₀'] [has_zero M₀'] (f : M₀' → M₀)
Expand Down Expand Up @@ -96,13 +86,6 @@ if ha : a = 0 then by rw [ha, zero_mul] else by rw [h ha, mul_zero]

end mul_zero_class

/-- Predicate typeclass for expressing that `a * b = 0` implies `a = 0` or `b = 0`
for all `a` and `b` of type `G₀`. -/
class no_zero_divisors (M₀ : Type*) [has_mul M₀] [has_zero M₀] : Prop :=
(eq_zero_or_eq_zero_of_mul_eq_zero : ∀ {a b : M₀}, a * b = 0 → a = 0 ∨ b = 0)

export no_zero_divisors (eq_zero_or_eq_zero_of_mul_eq_zero)

/-- Pushforward a `no_zero_divisors` instance along an injective function. -/
protected lemma function.injective.no_zero_divisors [has_mul M₀] [has_zero M₀]
[has_mul M₀'] [has_zero M₀'] [no_zero_divisors M₀']
Expand Down Expand Up @@ -157,16 +140,6 @@ end

end

/-- A type `M` is a “monoid with zero” if it is a monoid with zero element, and `0` is left
and right absorbing. -/
@[protect_proj] class monoid_with_zero (M₀ : Type*) extends monoid M₀, mul_zero_class M₀.

/-- A type `M` is a `cancel_monoid_with_zero` if it is a monoid with zero element, `0` is left
and right absorbing, and left/right multiplication by a non-zero element is injective. -/
@[protect_proj] class cancel_monoid_with_zero (M₀ : Type*) extends monoid_with_zero M₀ :=
(mul_left_cancel_of_ne_zero : ∀ {a b c : M₀}, a ≠ 0 → a * b = a * c → b = c)
(mul_right_cancel_of_ne_zero : ∀ {a b c : M₀}, b ≠ 0 → a * b = c * b → a = c)

section

variables [monoid_with_zero M₀] [nontrivial M₀] {a b : M₀}
Expand Down Expand Up @@ -203,33 +176,6 @@ protected lemma pullback_nonzero [has_zero M₀'] [has_one M₀']

end

/-- A type `M` is a commutative “monoid with zero” if it is a commutative monoid with zero
element, and `0` is left and right absorbing. -/
@[protect_proj]
class comm_monoid_with_zero (M₀ : Type*) extends comm_monoid M₀, monoid_with_zero M₀.

/-- A type `M` is a `comm_cancel_monoid_with_zero` if it is a commutative monoid with zero element,
`0` is left and right absorbing,
and left/right multiplication by a non-zero element is injective. -/
@[protect_proj] class comm_cancel_monoid_with_zero (M₀ : Type*) extends
comm_monoid_with_zero M₀, cancel_monoid_with_zero M₀.

/-- A type `G₀` is a “group with zero” if it is a monoid with zero element (distinct from `1`)
such that every nonzero element is invertible.
The type is required to come with an “inverse” function, and the inverse of `0` must be `0`.
Examples include division rings and the ordered monoids that are the
target of valuations in general valuation theory.-/
class group_with_zero (G₀ : Type*) extends monoid_with_zero G₀, has_inv G₀, nontrivial G₀ :=
(inv_zero : (0 : G₀)⁻¹ = 0)
(mul_inv_cancel : ∀ a:G₀, a ≠ 0 → a * a⁻¹ = 1)

/-- A type `G₀` is a commutative “group with zero”
if it is a commutative monoid with zero element (distinct from `1`)
such that every nonzero element is invertible.
The type is required to come with an “inverse” function, and the inverse of `0` must be `0`. -/
class comm_group_with_zero (G₀ : Type*) extends comm_monoid_with_zero G₀, group_with_zero G₀.

/-- The division operation on a group with zero element. -/
@[priority 100] -- see Note [lower instance priority]
instance group_with_zero.has_div {G₀ : Type*} [group_with_zero G₀] :
Expand Down Expand Up @@ -346,12 +292,6 @@ instance comm_cancel_monoid_with_zero.no_zero_divisors : no_zero_divisors M₀ :
⟨λ a b ab0, by { by_cases a = 0, { left, exact h }, right,
apply cancel_monoid_with_zero.mul_left_cancel_of_ne_zero h, rw [ab0, mul_zero], }⟩

lemma mul_left_cancel' (ha : a ≠ 0) (h : a * b = a * c) : b = c :=
cancel_monoid_with_zero.mul_left_cancel_of_ne_zero ha h

lemma mul_right_cancel' (hb : b ≠ 0) (h : a * b = c * b) : a = c :=
cancel_monoid_with_zero.mul_right_cancel_of_ne_zero hb h

lemma mul_left_inj' (hc : c ≠ 0) : a * c = b * c ↔ a = b := ⟨mul_right_cancel' hc, λ h, h ▸ rfl⟩

lemma mul_right_inj' (ha : a ≠ 0) : a * b = a * c ↔ b = c := ⟨mul_left_cancel' ha, λ h, h ▸ rfl⟩
Expand Down Expand Up @@ -392,12 +332,6 @@ lemma div_eq_mul_inv {a b : G₀} : a / b = a * b⁻¹ := rfl

alias div_eq_mul_inv ← division_def

@[simp] lemma inv_zero : (0 : G₀)⁻¹ = 0 :=
group_with_zero.inv_zero

@[simp] lemma mul_inv_cancel {a : G₀} (h : a ≠ 0) : a * a⁻¹ = 1 :=
group_with_zero.mul_inv_cancel a h

/-- Pullback a `group_with_zero` class along an injective function. -/
protected def function.injective.group_with_zero [has_zero G₀'] [has_mul G₀'] [has_one G₀']
[has_inv G₀'] (f : G₀' → G₀) (hf : injective f) (zero : f 0 = 0) (one : f 1 = 1)
Expand Down Expand Up @@ -941,47 +875,41 @@ hac.mul_left hbc.inv_left'

end commute

namespace monoid_hom
namespace monoid_with_zero_hom

variables [group_with_zero G₀] [group_with_zero G₀'] [monoid_with_zero M₀] [nontrivial M₀]

section monoid_with_zero

variables (f : G₀ →* M₀) (h0 : f 0 = 0) {a : G₀}

include h0
variables (f : monoid_with_zero_hom G₀ M₀) {a : G₀}

lemma map_ne_zero : f a ≠ 0 ↔ a ≠ 0 :=
⟨λ hfa ha, hfa $ ha.symm ▸ h0, λ ha, ((is_unit.mk0 a ha).map f).ne_zero⟩
⟨λ hfa ha, hfa $ ha.symm ▸ f.map_zero, λ ha, ((is_unit.mk0 a ha).map f.to_monoid_hom).ne_zero⟩

lemma map_eq_zero : f a = 0 ↔ a = 0 :=
by { classical, exact not_iff_not.1 (f.map_ne_zero h0) }
by { classical, exact not_iff_not.1 f.map_ne_zero }

end monoid_with_zero

section group_with_zero

variables (f : G₀ →* G₀') (h0 : f 0 = 0) (a b : G₀)

include h0
variables (f : monoid_with_zero_hom G₀ G₀') (a b : G₀)

/-- A monoid homomorphism between groups with zeros sending `0` to `0` sends `a⁻¹` to `(f a)⁻¹`. -/
lemma map_inv' : f a⁻¹ = (f a)⁻¹ :=
begin
classical, by_cases h : a = 0, by simp [h, h0],
classical, by_cases h : a = 0, by simp [h],
apply eq_inv_of_mul_left_eq_one,
rw [← f.map_mul, inv_mul_cancel h, f.map_one]
end

lemma map_div : f (a / b) = f a / f b :=
(f.map_mul _ _).trans $ _root_.congr_arg _ $ f.map_inv' h0 b

omit h0

@[simp] lemma map_units_inv {M G₀ : Type*} [monoid M] [group_with_zero G₀]
(f : M →* G₀) (u : units M) : f ↑u⁻¹ = (f u)⁻¹ :=
by rw [← units.coe_map, ← units.coe_map, ← units.coe_inv', map_inv]
(f.map_mul _ _).trans $ _root_.congr_arg _ $ f.map_inv' b

end group_with_zero

end monoid_hom
end monoid_with_zero_hom

@[simp] lemma monoid_hom.map_units_inv {M G₀ : Type*} [monoid M] [group_with_zero G₀]
(f : M →* G₀) (u : units M) : f ↑u⁻¹ = (f u)⁻¹ :=
by rw [← units.coe_map, ← units.coe_map, ← units.coe_inv', monoid_hom.map_inv]
1 change: 1 addition & 0 deletions src/algebra/group_with_zero/default.lean
@@ -0,0 +1 @@
import algebra.group_with_zero.basic
113 changes: 113 additions & 0 deletions src/algebra/group_with_zero/defs.lean
@@ -0,0 +1,113 @@
/-
Copyright (c) 2020 Johan Commelin. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Johan Commelin
-/
import algebra.group.defs
import logic.nontrivial

/-!
# Typeclasses for groups with an adjoined zero element
This file provides just the typeclass definitions, and the projection lemmas that expose their
members.
## Main definitions
* `group_with_zero`
* `comm_group_with_zero`
-/

set_option old_structure_cmd true

variables {M₀ G₀ M₀' G₀' : Type*}

section

/-- Typeclass for expressing that a type `M₀` with multiplication and a zero satisfies
`0 * a = 0` and `a * 0 = 0` for all `a : M₀`. -/
@[protect_proj, ancestor has_mul has_zero]
class mul_zero_class (M₀ : Type*) extends has_mul M₀, has_zero M₀ :=
(zero_mul : ∀ a : M₀, 0 * a = 0)
(mul_zero : ∀ a : M₀, a * 0 = 0)

section mul_zero_class

variables [mul_zero_class M₀] {a b : M₀}

@[ematch, simp] lemma zero_mul (a : M₀) : 0 * a = 0 :=
mul_zero_class.zero_mul a

@[ematch, simp] lemma mul_zero (a : M₀) : a * 0 = 0 :=
mul_zero_class.mul_zero a

end mul_zero_class

/-- Predicate typeclass for expressing that `a * b = 0` implies `a = 0` or `b = 0`
for all `a` and `b` of type `G₀`. -/
class no_zero_divisors (M₀ : Type*) [has_mul M₀] [has_zero M₀] : Prop :=
(eq_zero_or_eq_zero_of_mul_eq_zero : ∀ {a b : M₀}, a * b = 0 → a = 0 ∨ b = 0)

export no_zero_divisors (eq_zero_or_eq_zero_of_mul_eq_zero)

/-- A type `M` is a “monoid with zero” if it is a monoid with zero element, and `0` is left
and right absorbing. -/
@[protect_proj] class monoid_with_zero (M₀ : Type*) extends monoid M₀, mul_zero_class M₀.

/-- A type `M` is a `cancel_monoid_with_zero` if it is a monoid with zero element, `0` is left
and right absorbing, and left/right multiplication by a non-zero element is injective. -/
@[protect_proj] class cancel_monoid_with_zero (M₀ : Type*) extends monoid_with_zero M₀ :=
(mul_left_cancel_of_ne_zero : ∀ {a b c : M₀}, a ≠ 0 → a * b = a * c → b = c)
(mul_right_cancel_of_ne_zero : ∀ {a b c : M₀}, b ≠ 0 → a * b = c * b → a = c)

section cancel_monoid_with_zero

variables [cancel_monoid_with_zero M₀] {a b c : M₀}

lemma mul_left_cancel' (ha : a ≠ 0) (h : a * b = a * c) : b = c :=
cancel_monoid_with_zero.mul_left_cancel_of_ne_zero ha h

lemma mul_right_cancel' (hb : b ≠ 0) (h : a * b = c * b) : a = c :=
cancel_monoid_with_zero.mul_right_cancel_of_ne_zero hb h

end cancel_monoid_with_zero

/-- A type `M` is a commutative “monoid with zero” if it is a commutative monoid with zero
element, and `0` is left and right absorbing. -/
@[protect_proj]
class comm_monoid_with_zero (M₀ : Type*) extends comm_monoid M₀, monoid_with_zero M₀.

/-- A type `M` is a `comm_cancel_monoid_with_zero` if it is a commutative monoid with zero element,
`0` is left and right absorbing,
and left/right multiplication by a non-zero element is injective. -/
@[protect_proj] class comm_cancel_monoid_with_zero (M₀ : Type*) extends
comm_monoid_with_zero M₀, cancel_monoid_with_zero M₀.

/-- A type `G₀` is a “group with zero” if it is a monoid with zero element (distinct from `1`)
such that every nonzero element is invertible.
The type is required to come with an “inverse” function, and the inverse of `0` must be `0`.
Examples include division rings and the ordered monoids that are the
target of valuations in general valuation theory.-/
class group_with_zero (G₀ : Type*) extends monoid_with_zero G₀, has_inv G₀, nontrivial G₀ :=
(inv_zero : (0 : G₀)⁻¹ = 0)
(mul_inv_cancel : ∀ a:G₀, a ≠ 0 → a * a⁻¹ = 1)

section group_with_zero
variables [group_with_zero G₀]

@[simp] lemma inv_zero : (0 : G₀)⁻¹ = 0 :=
group_with_zero.inv_zero

@[simp] lemma mul_inv_cancel {a : G₀} (h : a ≠ 0) : a * a⁻¹ = 1 :=
group_with_zero.mul_inv_cancel a h

end group_with_zero

/-- A type `G₀` is a commutative “group with zero”
if it is a commutative monoid with zero element (distinct from `1`)
such that every nonzero element is invertible.
The type is required to come with an “inverse” function, and the inverse of `0` must be `0`. -/
class comm_group_with_zero (G₀ : Type*) extends comm_monoid_with_zero G₀, group_with_zero G₀.

end

0 comments on commit 86b0971

Please sign in to comment.