Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
| Download
Try doing some basic maths questions in the Lean Theorem Prover. Functions, real numbers, equivalence relations and groups. Click on README.md and then on "Open in CoCalc with one click".
Project: Xena
Views: 18536License: APACHE
/- Copyright (c) 2018 Johannes Hölzl. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Johannes Hölzl, Jens Wagemaker Associated and irreducible elements. -/ import algebra.group data.multiset variables {α : Type*} {β : Type*} {γ : Type*} {δ : Type*} open lattice /-- is unit -/ def is_unit [monoid α] (a : α) : Prop := ∃u:units α, a = u @[simp] lemma is_unit_unit [monoid α] (u : units α) : is_unit (u : α) := ⟨u, rfl⟩ theorem is_unit.mk0 [division_ring α] (x : α) (hx : x ≠ 0) : is_unit x := is_unit_unit (units.mk0 x hx) lemma is_unit.map [monoid α] [monoid β] (f : α →* β) {x : α} (h : is_unit x) : is_unit (f x) := by rcases h with ⟨y, rfl⟩; exact is_unit_unit (units.map f y) lemma is_unit.map' [monoid α] [monoid β] (f : α → β) {x : α} (h : is_unit x) [is_monoid_hom f] : is_unit (f x) := h.map (monoid_hom.of f) @[simp] theorem is_unit_zero_iff [semiring α] : is_unit (0 : α) ↔ (0:α) = 1 := ⟨λ ⟨⟨_, a, (a0 : 0 * a = 1), _⟩, rfl⟩, by rwa zero_mul at a0, λ h, begin haveI := subsingleton_of_zero_eq_one _ h, refine ⟨⟨0, 0, _, _⟩, rfl⟩; apply subsingleton.elim end⟩ @[simp] theorem not_is_unit_zero [nonzero_comm_ring α] : ¬ is_unit (0 : α) := mt is_unit_zero_iff.1 zero_ne_one @[simp] theorem is_unit_one [monoid α] : is_unit (1:α) := ⟨1, rfl⟩ theorem is_unit_of_mul_one [comm_monoid α] (a b : α) (h : a * b = 1) : is_unit a := ⟨units.mk_of_mul_eq_one a b h, rfl⟩ theorem is_unit_iff_exists_inv [comm_monoid α] {a : α} : is_unit a ↔ ∃ b, a * b = 1 := ⟨by rintro ⟨⟨a, b, hab, _⟩, rfl⟩; exact ⟨b, hab⟩, λ ⟨b, hab⟩, is_unit_of_mul_one _ b hab⟩ theorem is_unit_iff_exists_inv' [comm_monoid α] {a : α} : is_unit a ↔ ∃ b, b * a = 1 := by simp [is_unit_iff_exists_inv, mul_comm] lemma is_unit_pow [monoid α] {a : α} (n : ℕ) : is_unit a → is_unit (a ^ n) := λ ⟨u, hu⟩, ⟨u ^ n, by simp *⟩ @[simp] theorem units.is_unit_mul_units [monoid α] (a : α) (u : units α) : is_unit (a * u) ↔ is_unit a := iff.intro (assume ⟨v, hv⟩, have is_unit (a * ↑u * ↑u⁻¹), by existsi v * u⁻¹; rw [hv, units.coe_mul], by rwa [mul_assoc, units.mul_inv, mul_one] at this) (assume ⟨v, hv⟩, hv.symm ▸ ⟨v * u, (units.coe_mul v u).symm⟩) theorem is_unit_of_mul_is_unit_left {α} [comm_monoid α] {x y : α} (hu : is_unit (x * y)) : is_unit x := let ⟨z, hz⟩ := is_unit_iff_exists_inv.1 hu in is_unit_iff_exists_inv.2 ⟨y * z, by rwa ← mul_assoc⟩ theorem is_unit_of_mul_is_unit_right {α} [comm_monoid α] {x y : α} (hu : is_unit (x * y)) : is_unit y := @is_unit_of_mul_is_unit_left _ _ y x $ by rwa mul_comm theorem is_unit_iff_dvd_one [comm_semiring α] {x : α} : is_unit x ↔ x ∣ 1 := ⟨by rintro ⟨u, rfl⟩; exact ⟨_, u.mul_inv.symm⟩, λ ⟨y, h⟩, ⟨⟨x, y, h.symm, by rw [h, mul_comm]⟩, rfl⟩⟩ theorem is_unit_iff_forall_dvd [comm_semiring α] {x : α} : is_unit x ↔ ∀ y, x ∣ y := is_unit_iff_dvd_one.trans ⟨λ h y, dvd.trans h (one_dvd _), λ h, h _⟩ theorem mul_dvd_of_is_unit_left [comm_semiring α] {x y z : α} (h : is_unit x) : x * y ∣ z ↔ y ∣ z := ⟨dvd_trans (dvd_mul_left _ _), dvd_trans $ by simpa using mul_dvd_mul_right (is_unit_iff_dvd_one.1 h) y⟩ theorem mul_dvd_of_is_unit_right [comm_semiring α] {x y z : α} (h : is_unit y) : x * y ∣ z ↔ x ∣ z := by rw [mul_comm, mul_dvd_of_is_unit_left h] @[simp] lemma unit_mul_dvd_iff [comm_semiring α] {a b : α} {u : units α} : (u : α) * a ∣ b ↔ a ∣ b := mul_dvd_of_is_unit_left (is_unit_unit _) @[simp] lemma mul_unit_dvd_iff [comm_semiring α] {a b : α} {u : units α} : a * u ∣ b ↔ a ∣ b := mul_dvd_of_is_unit_right (is_unit_unit _) theorem is_unit_of_dvd_unit {α} [comm_semiring α] {x y : α} (xy : x ∣ y) (hu : is_unit y) : is_unit x := is_unit_iff_dvd_one.2 $ dvd_trans xy $ is_unit_iff_dvd_one.1 hu @[simp] theorem is_unit_nat {n : ℕ} : is_unit n ↔ n = 1 := iff.intro (assume ⟨u, hu⟩, match n, u, hu, nat.units_eq_one u with _, _, rfl, rfl := rfl end) (assume h, h.symm ▸ ⟨1, rfl⟩) theorem is_unit_int {n : ℤ} : is_unit n ↔ n.nat_abs = 1 := ⟨λ ⟨u, hu⟩, (int.units_eq_one_or u).elim (by simp *) (by simp *), λ h, is_unit_iff_dvd_one.2 ⟨n, by rw [← int.nat_abs_mul_self, h]; refl⟩⟩ lemma is_unit_of_dvd_one [comm_semiring α] : ∀a ∣ 1, is_unit (a:α) | a ⟨b, eq⟩ := ⟨units.mk_of_mul_eq_one a b eq.symm, rfl⟩ lemma dvd_and_not_dvd_iff [integral_domain α] {x y : α} : x ∣ y ∧ ¬y ∣ x ↔ x ≠ 0 ∧ ∃ d : α, ¬ is_unit d ∧ y = x * d := ⟨λ ⟨⟨d, hd⟩, hyx⟩, ⟨λ hx0, by simpa [hx0] using hyx, ⟨d, mt is_unit_iff_dvd_one.1 (λ ⟨e, he⟩, hyx ⟨e, by rw [hd, mul_assoc, ← he, mul_one]⟩), hd⟩⟩, λ ⟨hx0, d, hdu, hdx⟩, ⟨⟨d, hdx⟩, λ ⟨e, he⟩, hdu (is_unit_of_dvd_one _ ⟨e, (domain.mul_left_inj hx0).1 $ by conv {to_lhs, rw [he, hdx]};simp [mul_assoc]⟩)⟩⟩ lemma pow_dvd_pow_iff [integral_domain α] {x : α} {n m : ℕ} (h0 : x ≠ 0) (h1 : ¬ is_unit x) : x ^ n ∣ x ^ m ↔ n ≤ m := begin split, { intro h, rw [← not_lt], intro hmn, apply h1, have : x * x ^ m ∣ 1 * x ^ m, { rw [← pow_succ, one_mul], exact dvd_trans (pow_dvd_pow _ (nat.succ_le_of_lt hmn)) h }, rwa [mul_dvd_mul_iff_right, ← is_unit_iff_dvd_one] at this, apply pow_ne_zero m h0 }, { apply pow_dvd_pow } end /-- prime element of a semiring -/ def prime [comm_semiring α] (p : α) : Prop := p ≠ 0 ∧ ¬ is_unit p ∧ (∀a b, p ∣ a * b → p ∣ a ∨ p ∣ b) namespace prime lemma ne_zero [comm_semiring α] {p : α} (hp : prime p) : p ≠ 0 := hp.1 lemma not_unit [comm_semiring α] {p : α} (hp : prime p) : ¬ is_unit p := hp.2.1 lemma div_or_div [comm_semiring α] {p : α} (hp : prime p) {a b : α} (h : p ∣ a * b) : p ∣ a ∨ p ∣ b := hp.2.2 a b h end prime @[simp] lemma not_prime_zero [comm_semiring α] : ¬ prime (0 : α) := λ h, h.ne_zero rfl @[simp] lemma not_prime_one [comm_semiring α] : ¬ prime (1 : α) := λ h, h.not_unit is_unit_one lemma exists_mem_multiset_dvd_of_prime [comm_semiring α] {s : multiset α} {p : α} (hp : prime p) : p ∣ s.prod → ∃a∈s, p ∣ a := multiset.induction_on s (assume h, (hp.not_unit $ is_unit_of_dvd_one _ h).elim) $ assume a s ih h, have p ∣ a * s.prod, by simpa using h, match hp.div_or_div this with | or.inl h := ⟨a, multiset.mem_cons_self a s, h⟩ | or.inr h := let ⟨a, has, h⟩ := ih h in ⟨a, multiset.mem_cons_of_mem has, h⟩ end /-- `irreducible p` states that `p` is non-unit and only factors into units. We explicitly avoid stating that `p` is non-zero, this would require a semiring. Assuming only a monoid allows us to reuse irreducible for associated elements. -/ @[class] def irreducible [monoid α] (p : α) : Prop := ¬ is_unit p ∧ ∀a b, p = a * b → is_unit a ∨ is_unit b namespace irreducible lemma not_unit [monoid α] {p : α} (hp : irreducible p) : ¬ is_unit p := hp.1 lemma is_unit_or_is_unit [monoid α] {p : α} (hp : irreducible p) {a b : α} (h : p = a * b) : is_unit a ∨ is_unit b := hp.2 a b h end irreducible @[simp] theorem not_irreducible_one [monoid α] : ¬ irreducible (1 : α) := by simp [irreducible] @[simp] theorem not_irreducible_zero [semiring α] : ¬ irreducible (0 : α) | ⟨hn0, h⟩ := have is_unit (0:α) ∨ is_unit (0:α), from h 0 0 ((mul_zero 0).symm), this.elim hn0 hn0 theorem irreducible.ne_zero [semiring α] : ∀ {p:α}, irreducible p → p ≠ 0 | _ hp rfl := not_irreducible_zero hp theorem of_irreducible_mul {α} [monoid α] {x y : α} : irreducible (x * y) → is_unit x ∨ is_unit y | ⟨_, h⟩ := h _ _ rfl theorem irreducible_or_factor {α} [monoid α] (x : α) (h : ¬ is_unit x) : irreducible x ∨ ∃ a b, ¬ is_unit a ∧ ¬ is_unit b ∧ a * b = x := begin haveI := classical.dec, refine or_iff_not_imp_right.2 (λ H, _), simp [h, irreducible] at H ⊢, refine λ a b h, classical.by_contradiction $ λ o, _, simp [not_or_distrib] at o, exact H _ o.1 _ o.2 h.symm end lemma irreducible_of_prime [integral_domain α] {p : α} (hp : prime p) : irreducible p := ⟨hp.not_unit, λ a b hab, (show a * b ∣ a ∨ a * b ∣ b, from hab ▸ hp.div_or_div (hab ▸ (dvd_refl _))).elim (λ ⟨x, hx⟩, or.inr (is_unit_iff_dvd_one.2 ⟨x, (domain.mul_left_inj (show a ≠ 0, from λ h, by simp [*, prime] at *)).1 $ by conv {to_lhs, rw hx}; simp [mul_comm, mul_assoc, mul_left_comm]⟩)) (λ ⟨x, hx⟩, or.inl (is_unit_iff_dvd_one.2 ⟨x, (domain.mul_left_inj (show b ≠ 0, from λ h, by simp [*, prime] at *)).1 $ by conv {to_lhs, rw hx}; simp [mul_comm, mul_assoc, mul_left_comm]⟩))⟩ lemma succ_dvd_or_succ_dvd_of_succ_sum_dvd_mul [integral_domain α] {p : α} (hp : prime p) {a b : α} {k l : ℕ} : p ^ k ∣ a → p ^ l ∣ b → p ^ ((k + l) + 1) ∣ a * b → p ^ (k + 1) ∣ a ∨ p ^ (l + 1) ∣ b := λ ⟨x, hx⟩ ⟨y, hy⟩ ⟨z, hz⟩, have h : p ^ (k + l) * (x * y) = p ^ (k + l) * (p * z), by simpa [mul_comm, _root_.pow_add, hx, hy, mul_assoc, mul_left_comm] using hz, have hp0: p ^ (k + l) ≠ 0, from pow_ne_zero _ hp.ne_zero, have hpd : p ∣ x * y, from ⟨z, by rwa [domain.mul_left_inj hp0] at h⟩, (hp.div_or_div hpd).elim (λ ⟨d, hd⟩, or.inl ⟨d, by simp [*, _root_.pow_succ, mul_comm, mul_left_comm, mul_assoc]⟩) (λ ⟨d, hd⟩, or.inr ⟨d, by simp [*, _root_.pow_succ, mul_comm, mul_left_comm, mul_assoc]⟩) def associated [monoid α] (x y : α) : Prop := ∃u:units α, x * u = y local infix ` ~ᵤ ` : 50 := associated namespace associated @[refl] protected theorem refl [monoid α] (x : α) : x ~ᵤ x := ⟨1, by simp⟩ @[symm] protected theorem symm [monoid α] : ∀{x y : α}, x ~ᵤ y → y ~ᵤ x | x _ ⟨u, rfl⟩ := ⟨u⁻¹, by rw [mul_assoc, units.mul_inv, mul_one]⟩ @[trans] protected theorem trans [monoid α] : ∀{x y z : α}, x ~ᵤ y → y ~ᵤ z → x ~ᵤ z | x _ _ ⟨u, rfl⟩ ⟨v, rfl⟩ := ⟨u * v, by rw [units.coe_mul, mul_assoc]⟩ protected def setoid (α : Type*) [monoid α] : setoid α := { r := associated, iseqv := ⟨associated.refl, λa b, associated.symm, λa b c, associated.trans⟩ } end associated local attribute [instance] associated.setoid theorem unit_associated_one [monoid α] {u : units α} : (u : α) ~ᵤ 1 := ⟨u⁻¹, units.mul_inv u⟩ theorem associated_one_iff_is_unit [monoid α] {a : α} : (a : α) ~ᵤ 1 ↔ is_unit a := iff.intro (assume h, let ⟨c, h⟩ := h.symm in h ▸ ⟨c, one_mul _⟩) (assume ⟨c, h⟩, associated.symm ⟨c, by simp [h]⟩) theorem associated_zero_iff_eq_zero [comm_semiring α] (a : α) : a ~ᵤ 0 ↔ a = 0 := iff.intro (assume h, let ⟨u, h⟩ := h.symm in by simpa using h.symm) (assume h, h ▸ associated.refl a) theorem associated_one_of_mul_eq_one [comm_monoid α] {a : α} (b : α) (hab : a * b = 1) : a ~ᵤ 1 := show (units.mk_of_mul_eq_one a b hab : α) ~ᵤ 1, from unit_associated_one theorem associated_one_of_associated_mul_one [comm_monoid α] {a b : α} : a * b ~ᵤ 1 → a ~ᵤ 1 | ⟨u, h⟩ := associated_one_of_mul_eq_one (b * u) $ by simpa [mul_assoc] using h lemma associated_mul_mul [comm_monoid α] {a₁ a₂ b₁ b₂ : α} : a₁ ~ᵤ b₁ → a₂ ~ᵤ b₂ → (a₁ * a₂) ~ᵤ (b₁ * b₂) | ⟨c₁, h₁⟩ ⟨c₂, h₂⟩ := ⟨c₁ * c₂, by simp [h₁.symm, h₂.symm, mul_assoc, mul_comm, mul_left_comm]⟩ theorem associated_of_dvd_dvd [integral_domain α] {a b : α} (hab : a ∣ b) (hba : b ∣ a) : a ~ᵤ b := begin haveI := classical.dec_eq α, rcases hab with ⟨c, rfl⟩, rcases hba with ⟨d, a_eq⟩, by_cases ha0 : a = 0, { simp [*] at * }, have : a * 1 = a * (c * d), { simpa [mul_assoc] using a_eq }, have : 1 = (c * d), from eq_of_mul_eq_mul_left ha0 this, exact ⟨units.mk_of_mul_eq_one c d (this.symm), by rw [units.mk_of_mul_eq_one, units.val_coe]⟩ end lemma exists_associated_mem_of_dvd_prod [integral_domain α] {p : α} (hp : prime p) {s : multiset α} : (∀ r ∈ s, prime r) → p ∣ s.prod → ∃ q ∈ s, p ~ᵤ q := multiset.induction_on s (by simp [mt is_unit_iff_dvd_one.2 hp.not_unit]) (λ a s ih hs hps, begin rw [multiset.prod_cons] at hps, cases hp.div_or_div hps with h h, { use [a, by simp], cases h with u hu, cases ((irreducible_of_prime (hs a (multiset.mem_cons.2 (or.inl rfl)))).2 p u hu).resolve_left hp.not_unit with v hv, exact ⟨v, by simp [hu, hv]⟩ }, { rcases ih (λ r hr, hs _ (multiset.mem_cons.2 (or.inr hr))) h with ⟨q, hq₁, hq₂⟩, exact ⟨q, multiset.mem_cons.2 (or.inr hq₁), hq₂⟩ } end) lemma dvd_iff_dvd_of_rel_left [comm_semiring α] {a b c : α} (h : a ~ᵤ b) : a ∣ c ↔ b ∣ c := let ⟨u, hu⟩ := h in hu ▸ mul_unit_dvd_iff.symm @[simp] lemma dvd_mul_unit_iff [comm_semiring α] {a b : α} {u : units α} : a ∣ b * u ↔ a ∣ b := ⟨λ ⟨d, hd⟩, ⟨d * (u⁻¹ : units α), by simp [(mul_assoc _ _ _).symm, hd.symm]⟩, λ h, dvd.trans h (by simp)⟩ lemma dvd_iff_dvd_of_rel_right [comm_semiring α] {a b c : α} (h : b ~ᵤ c) : a ∣ b ↔ a ∣ c := let ⟨u, hu⟩ := h in hu ▸ dvd_mul_unit_iff.symm lemma eq_zero_iff_of_associated [comm_semiring α] {a b : α} (h : a ~ᵤ b) : a = 0 ↔ b = 0 := ⟨λ ha, let ⟨u, hu⟩ := h in by simp [hu.symm, ha], λ hb, let ⟨u, hu⟩ := h.symm in by simp [hu.symm, hb]⟩ lemma ne_zero_iff_of_associated [comm_semiring α] {a b : α} (h : a ~ᵤ b) : a ≠ 0 ↔ b ≠ 0 := by haveI := classical.dec; exact not_iff_not.2 (eq_zero_iff_of_associated h) lemma prime_of_associated [comm_semiring α] {p q : α} (h : p ~ᵤ q) (hp : prime p) : prime q := ⟨(ne_zero_iff_of_associated h).1 hp.ne_zero, let ⟨u, hu⟩ := h in ⟨λ ⟨v, hv⟩, hp.not_unit ⟨v * u⁻¹, by simp [hv.symm, hu.symm]⟩, hu ▸ by { simp [mul_unit_dvd_iff], intros a b, exact hp.div_or_div }⟩⟩ lemma prime_iff_of_associated [comm_semiring α] {p q : α} (h : p ~ᵤ q) : prime p ↔ prime q := ⟨prime_of_associated h, prime_of_associated h.symm⟩ lemma is_unit_iff_of_associated [monoid α] {a b : α} (h : a ~ᵤ b) : is_unit a ↔ is_unit b := ⟨let ⟨u, hu⟩ := h in λ ⟨v, hv⟩, ⟨v * u, by simp [hv, hu.symm]⟩, let ⟨u, hu⟩ := h.symm in λ ⟨v, hv⟩, ⟨v * u, by simp [hv, hu.symm]⟩⟩ lemma irreducible_of_associated [comm_semiring α] {p q : α} (h : p ~ᵤ q) (hp : irreducible p) : irreducible q := ⟨mt (is_unit_iff_of_associated h).2 hp.1, let ⟨u, hu⟩ := h in λ a b hab, have hpab : p = a * (b * (u⁻¹ : units α)), from calc p = (p * u) * (u ⁻¹ : units α) : by simp ... = _ : by rw hu; simp [hab, mul_assoc], (hp.2 _ _ hpab).elim or.inl (λ ⟨v, hv⟩, or.inr ⟨v * u, by simp [hv.symm]⟩)⟩ lemma irreducible_iff_of_associated [comm_semiring α] {p q : α} (h : p ~ᵤ q) : irreducible p ↔ irreducible q := ⟨irreducible_of_associated h, irreducible_of_associated h.symm⟩ lemma associated_mul_left_cancel [integral_domain α] {a b c d : α} (h : a * b ~ᵤ c * d) (h₁ : a ~ᵤ c) (ha : a ≠ 0) : b ~ᵤ d := let ⟨u, hu⟩ := h in let ⟨v, hv⟩ := associated.symm h₁ in ⟨u * (v : units α), (domain.mul_left_inj ha).1 begin rw [← hv, mul_assoc c (v : α) d, mul_left_comm c, ← hu], simp [hv.symm, mul_assoc, mul_comm, mul_left_comm] end⟩ lemma associated_mul_right_cancel [integral_domain α] {a b c d : α} : a * b ~ᵤ c * d → b ~ᵤ d → b ≠ 0 → a ~ᵤ c := by rw [mul_comm a, mul_comm c]; exact associated_mul_left_cancel def associates (α : Type*) [monoid α] : Type* := quotient (associated.setoid α) namespace associates open associated protected def mk {α : Type*} [monoid α] (a : α) : associates α := ⟦ a ⟧ instance [monoid α] : inhabited (associates α) := ⟨⟦1⟧⟩ theorem mk_eq_mk_iff_associated [monoid α] {a b : α} : associates.mk a = associates.mk b ↔ a ~ᵤ b := iff.intro quotient.exact quot.sound theorem quotient_mk_eq_mk [monoid α] (a : α) : ⟦ a ⟧ = associates.mk a := rfl theorem quot_mk_eq_mk [monoid α] (a : α) : quot.mk setoid.r a = associates.mk a := rfl theorem forall_associated [monoid α] {p : associates α → Prop} : (∀a, p a) ↔ (∀a, p (associates.mk a)) := iff.intro (assume h a, h _) (assume h a, quotient.induction_on a h) instance [monoid α] : has_one (associates α) := ⟨⟦ 1 ⟧⟩ theorem one_eq_mk_one [monoid α] : (1 : associates α) = associates.mk 1 := rfl instance [monoid α] : has_bot (associates α) := ⟨1⟩ section comm_monoid variable [comm_monoid α] instance : has_mul (associates α) := ⟨λa' b', quotient.lift_on₂ a' b' (λa b, ⟦ a * b ⟧) $ assume a₁ a₂ b₁ b₂ ⟨c₁, h₁⟩ ⟨c₂, h₂⟩, quotient.sound $ ⟨c₁ * c₂, by simp [h₁.symm, h₂.symm, mul_assoc, mul_comm, mul_left_comm]⟩⟩ theorem mk_mul_mk {x y : α} : associates.mk x * associates.mk y = associates.mk (x * y) := rfl instance : comm_monoid (associates α) := { one := 1, mul := (*), mul_one := assume a', quotient.induction_on a' $ assume a, show ⟦a * 1⟧ = ⟦ a ⟧, by simp, one_mul := assume a', quotient.induction_on a' $ assume a, show ⟦1 * a⟧ = ⟦ a ⟧, by simp, mul_assoc := assume a' b' c', quotient.induction_on₃ a' b' c' $ assume a b c, show ⟦a * b * c⟧ = ⟦a * (b * c)⟧, by rw [mul_assoc], mul_comm := assume a' b', quotient.induction_on₂ a' b' $ assume a b, show ⟦a * b⟧ = ⟦b * a⟧, by rw [mul_comm] } instance : preorder (associates α) := { le := λa b, ∃c, a * c = b, le_refl := assume a, ⟨1, by simp⟩, le_trans := assume a b c ⟨f₁, h₁⟩ ⟨f₂, h₂⟩, ⟨f₁ * f₂, h₂ ▸ h₁ ▸ (mul_assoc _ _ _).symm⟩} instance : has_dvd (associates α) := ⟨(≤)⟩ @[simp] lemma mk_one : associates.mk (1 : α) = 1 := rfl lemma mk_pow (a : α) (n : ℕ) : associates.mk (a ^ n) = (associates.mk a) ^ n := by induction n; simp [*, pow_succ, associates.mk_mul_mk.symm] lemma dvd_eq_le : ((∣) : associates α → associates α → Prop) = (≤) := rfl theorem prod_mk {p : multiset α} : (p.map associates.mk).prod = associates.mk p.prod := multiset.induction_on p (by simp; refl) $ assume a s ih, by simp [ih]; refl theorem rel_associated_iff_map_eq_map {p q : multiset α} : multiset.rel associated p q ↔ p.map associates.mk = q.map associates.mk := by rw [← multiset.rel_eq]; simp [multiset.rel_map_left, multiset.rel_map_right, mk_eq_mk_iff_associated] theorem mul_eq_one_iff {x y : associates α} : x * y = 1 ↔ (x = 1 ∧ y = 1) := iff.intro (quotient.induction_on₂ x y $ assume a b h, have a * b ~ᵤ 1, from quotient.exact h, ⟨quotient.sound $ associated_one_of_associated_mul_one this, quotient.sound $ associated_one_of_associated_mul_one $ by rwa [mul_comm] at this⟩) (by simp {contextual := tt}) theorem prod_eq_one_iff {p : multiset (associates α)} : p.prod = 1 ↔ (∀a ∈ p, (a:associates α) = 1) := multiset.induction_on p (by simp) (by simp [mul_eq_one_iff, or_imp_distrib, forall_and_distrib] {contextual := tt}) theorem coe_unit_eq_one : ∀u:units (associates α), (u : associates α) = 1 | ⟨u, v, huv, hvu⟩ := by rw [mul_eq_one_iff] at huv; exact huv.1 theorem is_unit_iff_eq_one (a : associates α) : is_unit a ↔ a = 1 := iff.intro (assume ⟨u, h⟩, h.symm ▸ coe_unit_eq_one _) (assume h, h.symm ▸ is_unit_one) theorem is_unit_mk {a : α} : is_unit (associates.mk a) ↔ is_unit a := calc is_unit (associates.mk a) ↔ a ~ᵤ 1 : by rw [is_unit_iff_eq_one, one_eq_mk_one, mk_eq_mk_iff_associated] ... ↔ is_unit a : associated_one_iff_is_unit section order theorem mul_mono {a b c d : associates α} (h₁ : a ≤ b) (h₂ : c ≤ d) : a * c ≤ b * d := let ⟨x, hx⟩ := h₁, ⟨y, hy⟩ := h₂ in ⟨x * y, by simp [hx.symm, hy.symm, mul_comm, mul_assoc, mul_left_comm]⟩ theorem one_le {a : associates α} : 1 ≤ a := ⟨a, one_mul a⟩ theorem prod_le_prod {p q : multiset (associates α)} (h : p ≤ q) : p.prod ≤ q.prod := begin haveI := classical.dec_eq (associates α), haveI := classical.dec_eq α, suffices : p.prod ≤ (p + (q - p)).prod, { rwa [multiset.add_sub_of_le h] at this }, suffices : p.prod * 1 ≤ p.prod * (q - p).prod, { simpa }, exact mul_mono (le_refl p.prod) one_le end theorem le_mul_right {a b : associates α} : a ≤ a * b := ⟨b, rfl⟩ theorem le_mul_left {a b : associates α} : a ≤ b * a := by rw [mul_comm]; exact le_mul_right end order end comm_monoid instance [has_zero α] [monoid α] : has_zero (associates α) := ⟨⟦ 0 ⟧⟩ instance [has_zero α] [monoid α] : has_top (associates α) := ⟨0⟩ section comm_semiring variables [comm_semiring α] @[simp] theorem mk_zero_eq (a : α) : associates.mk a = 0 ↔ a = 0 := ⟨assume h, (associated_zero_iff_eq_zero a).1 $ quotient.exact h, assume h, h.symm ▸ rfl⟩ @[simp] theorem mul_zero : ∀(a : associates α), a * 0 = 0 := by rintros ⟨a⟩; show associates.mk (a * 0) = associates.mk 0; rw [mul_zero] @[simp] protected theorem zero_mul : ∀(a : associates α), 0 * a = 0 := by rintros ⟨a⟩; show associates.mk (0 * a) = associates.mk 0; rw [zero_mul] theorem mk_eq_zero_iff_eq_zero {a : α} : associates.mk a = 0 ↔ a = 0 := calc associates.mk a = 0 ↔ (a ~ᵤ 0) : mk_eq_mk_iff_associated ... ↔ a = 0 : associated_zero_iff_eq_zero a theorem dvd_of_mk_le_mk {a b : α} : associates.mk a ≤ associates.mk b → a ∣ b | ⟨c', hc'⟩ := (quotient.induction_on c' $ assume c hc, let ⟨d, hd⟩ := (quotient.exact hc).symm in ⟨(↑d⁻¹) * c, calc b = (a * c) * ↑d⁻¹ : by rw [← hd, mul_assoc, units.mul_inv, mul_one] ... = a * (↑d⁻¹ * c) : by ac_refl⟩) hc' theorem mk_le_mk_of_dvd {a b : α} : a ∣ b → associates.mk a ≤ associates.mk b := assume ⟨c, hc⟩, ⟨associates.mk c, by simp [hc]; refl⟩ theorem mk_le_mk_iff_dvd_iff {a b : α} : associates.mk a ≤ associates.mk b ↔ a ∣ b := iff.intro dvd_of_mk_le_mk mk_le_mk_of_dvd def prime (p : associates α) : Prop := p ≠ 0 ∧ p ≠ 1 ∧ (∀a b, p ≤ a * b → p ≤ a ∨ p ≤ b) lemma prime.ne_zero {p : associates α} (hp : prime p) : p ≠ 0 := hp.1 lemma prime.ne_one {p : associates α} (hp : prime p) : p ≠ 1 := hp.2.1 lemma prime.le_or_le {p : associates α} (hp : prime p) {a b : associates α} (h : p ≤ a * b) : p ≤ a ∨ p ≤ b := hp.2.2 a b h lemma exists_mem_multiset_le_of_prime {s : multiset (associates α)} {p : associates α} (hp : prime p) : p ≤ s.prod → ∃a∈s, p ≤ a := multiset.induction_on s (assume ⟨d, eq⟩, (hp.ne_one (mul_eq_one_iff.1 eq).1).elim) $ assume a s ih h, have p ≤ a * s.prod, by simpa using h, match hp.le_or_le this with | or.inl h := ⟨a, multiset.mem_cons_self a s, h⟩ | or.inr h := let ⟨a, has, h⟩ := ih h in ⟨a, multiset.mem_cons_of_mem has, h⟩ end lemma prime_mk (p : α) : prime (associates.mk p) ↔ _root_.prime p := begin rw [associates.prime, _root_.prime, forall_associated], transitivity, { apply and_congr, refl, apply and_congr, refl, apply forall_congr, assume a, exact forall_associated }, apply and_congr, { rw [(≠), mk_zero_eq] }, apply and_congr, { rw [(≠), ← is_unit_iff_eq_one, is_unit_mk], }, apply forall_congr, assume a, apply forall_congr, assume b, rw [mk_mul_mk, mk_le_mk_iff_dvd_iff, mk_le_mk_iff_dvd_iff, mk_le_mk_iff_dvd_iff] end end comm_semiring section integral_domain variable [integral_domain α] instance : partial_order (associates α) := { le_antisymm := assume a' b', quotient.induction_on₂ a' b' $ assume a b ⟨f₁', h₁⟩ ⟨f₂', h₂⟩, (quotient.induction_on₂ f₁' f₂' $ assume f₁ f₂ h₁ h₂, let ⟨c₁, h₁⟩ := quotient.exact h₁, ⟨c₂, h₂⟩ := quotient.exact h₂ in quotient.sound $ associated_of_dvd_dvd (h₁ ▸ dvd_mul_of_dvd_left (dvd_mul_right _ _) _) (h₂ ▸ dvd_mul_of_dvd_left (dvd_mul_right _ _) _)) h₁ h₂ .. associates.preorder } instance : lattice.order_bot (associates α) := { bot := 1, bot_le := assume a, one_le, .. associates.partial_order } instance : lattice.order_top (associates α) := { top := 0, le_top := assume a, ⟨0, mul_zero a⟩, .. associates.partial_order } theorem zero_ne_one : (0 : associates α) ≠ 1 := assume h, have (0 : α) ~ᵤ 1, from quotient.exact h, have (0 : α) = 1, from ((associated_zero_iff_eq_zero 1).1 this.symm).symm, zero_ne_one this theorem mul_eq_zero_iff {x y : associates α} : x * y = 0 ↔ x = 0 ∨ y = 0 := iff.intro (quotient.induction_on₂ x y $ assume a b h, have a * b = 0, from (associated_zero_iff_eq_zero _).1 (quotient.exact h), have a = 0 ∨ b = 0, from mul_eq_zero_iff_eq_zero_or_eq_zero.1 this, this.imp (assume h, h.symm ▸ rfl) (assume h, h.symm ▸ rfl)) (by simp [or_imp_distrib] {contextual := tt}) theorem prod_eq_zero_iff {s : multiset (associates α)} : s.prod = 0 ↔ (0 : associates α) ∈ s := multiset.induction_on s (by simp; exact zero_ne_one.symm) $ assume a s, by simp [mul_eq_zero_iff, @eq_comm _ 0 a] {contextual := tt} theorem irreducible_mk_iff (a : α) : irreducible (associates.mk a) ↔ irreducible a := begin simp [irreducible, is_unit_mk], apply and_congr iff.rfl, split, { assume h x y eq, have : is_unit (associates.mk x) ∨ is_unit (associates.mk y), from h _ _ (by rw [eq]; refl), simpa [is_unit_mk] }, { refine assume h x y, quotient.induction_on₂ x y (assume x y eq, _), rcases quotient.exact eq.symm with ⟨u, eq⟩, have : a = x * (y * u), by rwa [mul_assoc, eq_comm] at eq, show is_unit (associates.mk x) ∨ is_unit (associates.mk y), simpa [is_unit_mk] using h _ _ this } end lemma eq_of_mul_eq_mul_left : ∀(a b c : associates α), a ≠ 0 → a * b = a * c → b = c := begin rintros ⟨a⟩ ⟨b⟩ ⟨c⟩ ha h, rcases quotient.exact' h with ⟨u, hu⟩, have hu : a * (b * ↑u) = a * c, { rwa [← mul_assoc] }, exact quotient.sound' ⟨u, eq_of_mul_eq_mul_left (mt (mk_zero_eq a).2 ha) hu⟩ end lemma le_of_mul_le_mul_left (a b c : associates α) (ha : a ≠ 0) : a * b ≤ a * c → b ≤ c | ⟨d, hd⟩ := ⟨d, eq_of_mul_eq_mul_left a _ _ ha $ by rwa ← mul_assoc⟩ lemma one_or_eq_of_le_of_prime : ∀(p m : associates α), prime p → m ≤ p → (m = 1 ∨ m = p) | _ m ⟨hp0, hp1, h⟩ ⟨d, rfl⟩ := match h m d (le_refl _) with | or.inl h := classical.by_cases (assume : m = 0, by simp [this]) $ assume : m ≠ 0, have m * d ≤ m * 1, by simpa using h, have d ≤ 1, from associates.le_of_mul_le_mul_left m d 1 ‹m ≠ 0› this, have d = 1, from lattice.bot_unique this, by simp [this] | or.inr h := classical.by_cases (assume : d = 0, by simp [this] at hp0; contradiction) $ assume : d ≠ 0, have d * m ≤ d * 1, by simpa [mul_comm] using h, or.inl $ lattice.bot_unique $ associates.le_of_mul_le_mul_left d m 1 ‹d ≠ 0› this end end integral_domain end associates