Theory Finite_Fields.Finite_Fields_Factorization_Ext
subsection "Factorization"
theory Finite_Fields_Factorization_Ext
  imports Finite_Fields_Preliminary_Results
begin
text ‹This section contains additional results building on top of the development in
@{theory "HOL-Algebra.Divisibility"} about factorization in a @{locale "factorial_monoid"}.›
definition factor_mset where "factor_mset G x =
  (THE f. (∃ as. f = fmset G as ∧ wfactors G as x ∧ set as ⊆ carrier G))"
text ‹In @{theory "HOL-Algebra.Divisibility"} it is already verified that the multiset representing
the factorization of an element of a factorial monoid into irreducible factors is well-defined.
With these results it is then possible to define @{term "factor_mset"} and show its properties,
without referring to a factorization in list form first.›
definition multiplicity where
  "multiplicity G d g = Max {(n::nat). (d [^]⇘G⇙ n) divides⇘G⇙ g}"
definition canonical_irreducibles where
  "canonical_irreducibles G A = (
    A ⊆ {a. a ∈ carrier G ∧ irreducible G a} ∧
    (∀x y. x ∈ A ⟶ y ∈ A ⟶ x ∼⇘G⇙ y ⟶ x = y) ∧
    (∀x ∈ carrier G. irreducible G x ⟶ (∃y ∈ A. x ∼⇘G⇙ y)))"
text ‹A set of irreducible elements that contains exactly one element from each equivalence class
of an irreducible element formed by association, is called a set of
@{term "canonical_irreducibles"}. An example is the set of monic irreducible polynomials as
representatives of all irreducible polynomials.›
context factorial_monoid
begin
lemma assoc_as_fmset_eq:
  assumes "wfactors G as a"
    and "wfactors G bs b"
    and "a ∈ carrier G"
    and "b ∈ carrier G"
    and "set as ⊆ carrier G"
    and "set bs ⊆ carrier G"
  shows "a ∼ b ⟷ (fmset G as = fmset G bs)"
proof -
  have "a ∼ b ⟷ (a divides b ∧ b divides a)"
    by (simp add:associated_def)
  also have "... ⟷
    (fmset G as ⊆# fmset G bs ∧ fmset G bs ⊆# fmset G as)"
    using divides_as_fmsubset assms by blast
  also have "... ⟷ (fmset G as = fmset G bs)" by auto
  finally show ?thesis by simp
qed
lemma factor_mset_aux_1:
  assumes "a ∈ carrier G" "set as ⊆ carrier G" "wfactors G as a"
  shows "factor_mset G a = fmset G as"
proof -
  define H where "H = {as. wfactors G as a ∧ set as ⊆ carrier G}"
  have b:"as ∈ H"
    using H_def assms by simp
  have c: "x ∈ H ⟹ y ∈ H ⟹ fmset G x = fmset G y" for x y
    unfolding H_def using assoc_as_fmset_eq
    using associated_refl assms by blast
  have "factor_mset G a = (THE f. ∃as ∈ H. f= fmset G as)"
    by (simp add:factor_mset_def H_def, metis)
  also have "... = fmset G as"
    using b c
    by (intro the1_equality) blast+
  finally have "factor_mset G a = fmset G as" by simp
  thus ?thesis
    using b unfolding H_def by auto
qed
lemma factor_mset_aux:
  assumes "a ∈ carrier G"
  shows "∃as. factor_mset G a = fmset G as ∧ wfactors G as a ∧
    set as ⊆ carrier G"
proof -
  obtain as where as_def: "wfactors G as a" "set as ⊆ carrier G"
    using wfactors_exist assms by blast
  thus ?thesis using factor_mset_aux_1 assms by blast
qed
lemma factor_mset_set:
  assumes "a ∈ carrier G"
  assumes "x ∈# factor_mset G a"
  obtains y where
    "y ∈ carrier G"
    "irreducible G y"
    "assocs G y = x"
proof -
  obtain as where as_def:
    "factor_mset G a = fmset G as"
    "wfactors G as a" "set as ⊆ carrier G"
    using factor_mset_aux assms by blast
  hence "x ∈# fmset G as"
    using assms by simp
  hence "x ∈ assocs G ` set as"
    using assms as_def by (simp add:fmset_def)
  hence "∃y. y ∈ set as ∧ x = assocs G y"
    by auto
  moreover have "y ∈ carrier G ∧ irreducible G y"
    if "y ∈ set as" for y
    using as_def that wfactors_def
    by (simp add: wfactors_def) auto
  ultimately show ?thesis
    using that by blast
qed
lemma factor_mset_mult:
  assumes "a ∈ carrier G" "b ∈ carrier G"
  shows "factor_mset G (a ⊗ b) = factor_mset G a + factor_mset G b"
proof -
  obtain as where as_def:
    "factor_mset G a = fmset G as"
    "wfactors G as a" "set as ⊆ carrier G"
    using factor_mset_aux assms by blast
  obtain bs where bs_def:
    "factor_mset G b = fmset G bs"
    "wfactors G bs b" "set bs ⊆ carrier G"
    using factor_mset_aux assms(2) by blast
  have "a ⊗ b ∈ carrier G" using assms by auto
  then obtain cs where cs_def:
    "factor_mset G (a ⊗ b) = fmset G cs"
    "wfactors G cs (a ⊗ b)"
    "set cs ⊆ carrier G"
    using factor_mset_aux assms by blast
  have "fmset G cs = fmset G as + fmset G bs"
    using as_def bs_def cs_def assms
    by (intro  mult_wfactors_fmset[where a="a" and b="b"]) auto
  thus ?thesis
    using as_def bs_def cs_def by auto
qed
lemma factor_mset_unit: "factor_mset G 𝟭 = {#}"
proof -
  have "factor_mset G 𝟭 = factor_mset G (𝟭 ⊗ 𝟭)"
    by simp
  also have "... = factor_mset G 𝟭 + factor_mset G 𝟭"
    by (intro factor_mset_mult, auto)
  finally show "factor_mset G 𝟭 = {#}"
    by simp
qed
lemma factor_mset_irred:
  assumes "x ∈ carrier G" "irreducible G x"
  shows "factor_mset G x = image_mset (assocs G) {#x#}"
proof -
  have "wfactors G [x] x"
    using assms by (simp add:wfactors_def)
  hence "factor_mset G x = fmset G [x]"
    using factor_mset_aux_1 assms by simp
  also have "... = image_mset (assocs G) {#x#}"
    by (simp add:fmset_def)
  finally show ?thesis by simp
qed
lemma factor_mset_divides:
  assumes "a ∈ carrier G" "b ∈ carrier G"
  shows "a divides b ⟷ factor_mset G a ⊆# factor_mset G b"
proof -
  obtain as where as_def:
    "factor_mset G a = fmset G as"
    "wfactors G as a" "set as ⊆ carrier G"
    using factor_mset_aux assms by blast
  obtain bs where bs_def:
    "factor_mset G b = fmset G bs"
    "wfactors G bs b" "set bs ⊆ carrier G"
    using factor_mset_aux assms(2) by blast
  hence "a divides b ⟷ fmset G as ⊆# fmset G bs"
    using as_def bs_def assms
    by (intro divides_as_fmsubset) auto
  also have "... ⟷ factor_mset G a ⊆# factor_mset G b"
    using as_def bs_def by simp
  finally show ?thesis by simp
qed
lemma factor_mset_sim:
  assumes "a ∈ carrier G" "b ∈ carrier G"
  shows "a ∼ b ⟷ factor_mset G a = factor_mset G b"
  using factor_mset_divides assms
  by (simp add:associated_def) auto
lemma factor_mset_prod:
  assumes "finite A"
  assumes "f ` A ⊆ carrier G"
  shows "factor_mset G (⨂a ∈ A. f a) =
    (∑a ∈ A. factor_mset G (f a))"
  using assms
proof (induction A rule:finite_induct)
  case empty
  then show ?case by (simp add:factor_mset_unit)
next
  case (insert x F)
  have "factor_mset G (finprod G f (insert x F)) =
    factor_mset G (f x ⊗ finprod G f F)"
    using insert by (subst finprod_insert) auto
  also have "... = factor_mset G (f x) + factor_mset G (finprod G f F)"
    using insert by (intro factor_mset_mult finprod_closed) auto
  also have
    "... = factor_mset G (f x) + (∑a ∈ F. factor_mset G (f a))"
    using insert by simp
  also have "... = (∑a∈insert x F. factor_mset G (f a))"
    using insert by simp
  finally show ?case by simp
qed
lemma factor_mset_pow:
  assumes "a ∈ carrier G"
  shows "factor_mset G (a [^] n) = repeat_mset n (factor_mset G a)"
proof (induction n)
  case 0
  then show ?case by (simp add:factor_mset_unit)
next
  case (Suc n)
  have "factor_mset G (a [^] Suc n) = factor_mset G (a [^] n ⊗ a)"
    by simp
  also have "... = factor_mset G (a [^] n) + factor_mset G a"
    using assms by (intro factor_mset_mult) auto
  also have "... = repeat_mset n (factor_mset G a) + factor_mset G a"
    using Suc by simp
  also have "... = repeat_mset (Suc n) (factor_mset G a)"
    by simp
  finally show ?case by simp
qed
lemma image_mset_sum:
  assumes "finite F"
  shows
    "image_mset h (∑x ∈ F. f x) = (∑x ∈ F. image_mset h (f x))"
  using assms
  by (induction F rule:finite_induct, simp, simp)
lemma decomp_mset:
  "(∑x∈set_mset R. replicate_mset (count R x) x) = R"
  by (rule multiset_eqI, simp add:count_sum count_eq_zero_iff)
lemma factor_mset_count:
  assumes "a ∈ carrier G" "d ∈ carrier G" "irreducible G d"
  shows "count (factor_mset G a) (assocs G d) = multiplicity G d a"
proof -
  have a:
    "count (factor_mset G a) (assocs G d) ≥ m ⟷ d [^] m divides a"
    (is "?lhs ⟷ ?rhs") for m
  proof -
    have "?lhs ⟷ replicate_mset m (assocs G d) ⊆# factor_mset G a"
      by (simp add:count_le_replicate_mset_subset_eq)
    also have "... ⟷ factor_mset G (d [^] m) ⊆# factor_mset G a"
      using assms(2,3) by (simp add:factor_mset_pow factor_mset_irred)
    also have "... ⟷ ?rhs"
      using assms(1,2) by (subst factor_mset_divides) auto
    finally show ?thesis by simp
  qed
  define M where "M = {(m::nat). d [^] m divides a}"
  have M_alt: "M = {m. m ≤ count (factor_mset G a) (assocs G d)}"
    using a by (simp add:M_def)
  hence "Max M = count (factor_mset G a) (assocs G d)"
    by (intro Max_eqI, auto)
  thus ?thesis
    unfolding multiplicity_def M_def by auto
qed
lemma multiplicity_ge_iff:
  assumes "d ∈ carrier G" "irreducible G d" "a ∈ carrier G"
  shows "multiplicity G d a ≥ k ⟷ d [^] k divides a"
    (is "?lhs ⟷ ?rhs")
proof -
  have "?lhs ⟷ count (factor_mset G a) (assocs G d) ≥ k"
    using factor_mset_count[OF assms(3,1,2)] by simp
  also have "... ⟷ replicate_mset k (assocs G d) ⊆# factor_mset G a"
    by (subst count_le_replicate_mset_subset_eq, simp)
  also have "... ⟷
    repeat_mset k (factor_mset G d) ⊆# factor_mset G a"
    by (subst factor_mset_irred[OF assms(1,2)], simp)
  also have "... ⟷ factor_mset G (d [^]⇘G⇙ k) ⊆# factor_mset G a"
    by (subst factor_mset_pow[OF assms(1)], simp)
  also have "... ⟷ (d [^] k) divides⇘G⇙ a"
    using assms(1) factor_mset_divides[OF _ assms(3)] by simp
  finally show ?thesis by simp
qed
lemma multiplicity_gt_0_iff:
  assumes "d ∈ carrier G" "irreducible G d" "a ∈ carrier G"
  shows "multiplicity G d a > 0 ⟷ d divides a"
  using multiplicity_ge_iff[OF assms(1,2,3), where k="1"] assms
  by auto
lemma factor_mset_count_2:
  assumes "a ∈ carrier G"
  assumes "⋀z. z ∈ carrier G ⟹ irreducible G z ⟹ y ≠ assocs G z"
  shows "count (factor_mset G a) y = 0"
  using factor_mset_set [OF assms(1)] assms(2) by (metis count_inI)
lemma factor_mset_choose:
  assumes "a ∈ carrier G" "set_mset R ⊆ carrier G"
  assumes "image_mset (assocs G) R = factor_mset G a"
  shows "a ∼ (⨂x∈set_mset R. x [^] count R x)" (is "a ∼ ?rhs")
proof -
  have b:"irreducible G x" if a:"x ∈# R" for x
  proof -
    have x_carr: "x ∈ carrier G"
      using a assms(2) by auto
    have "assocs G x ∈ assocs G ` set_mset R"
      using a by simp
    hence "assocs G x ∈# factor_mset G a"
      using assms(3) a in_image_mset by metis
    then obtain z where z_def:
      "z ∈ carrier G" "irreducible G z" "assocs G x = assocs G z"
      using factor_mset_set assms(1) by metis
    have "z ∼ x" using z_def(1,3) assocs_eqD x_carr by simp
    thus ?thesis using z_def(1,2) x_carr irreducible_cong by simp
  qed
  have "factor_mset G ?rhs =
    (∑x∈set_mset R. factor_mset G (x [^] count R x))"
    using assms(2) by (subst factor_mset_prod, auto)
  also have "... =
    (∑x∈set_mset R. repeat_mset (count R x) (factor_mset G x))"
    using assms(2) by (intro sum.cong, auto simp add:factor_mset_pow)
  also have "... = (∑x∈set_mset R.
    repeat_mset (count R x) (image_mset (assocs G) {#x#}))"
    using assms(2) b by (intro sum.cong, auto simp add:factor_mset_irred)
  also have "... = (∑x∈set_mset R.
    image_mset (assocs G) (replicate_mset (count R x) x))"
    by simp
  also have "... = image_mset (assocs G)
    (∑x∈set_mset R. (replicate_mset (count R x) x))"
    by (simp add: image_mset_sum)
  also have "... = image_mset (assocs G) R"
    by (simp add:decomp_mset)
  also have "... = factor_mset G a"
    using assms by simp
  finally have "factor_mset G ?rhs = factor_mset G a" by simp
  moreover have "(⨂x∈set_mset R. x [^] count R x) ∈ carrier G"
    using assms(2) by (intro finprod_closed, auto)
  ultimately show ?thesis
    using assms(1) by (subst factor_mset_sim) auto
qed
lemma divides_iff_mult_mono:
  assumes "a ∈ carrier G" "b ∈ carrier G"
  assumes "canonical_irreducibles G R"
  assumes "⋀d. d ∈ R ⟹ multiplicity G d a ≤ multiplicity G d b"
  shows "a divides b"
proof -
  have "count (factor_mset G a) d ≤ count (factor_mset G b) d" for d
  proof (cases "∃y ∈ carrier G. irreducible G y ∧ d = assocs G y")
    case True
    then obtain y where y_def:
      "irreducible G y" "y ∈ carrier G" "d = assocs G y"
      by blast
    then obtain z where z_def: "z ∈ R" "y ∼ z"
      using assms(3) unfolding canonical_irreducibles_def by metis
    have z_more: "irreducible G z" "z ∈ carrier G"
      using z_def(1) assms(3)
      unfolding canonical_irreducibles_def by auto
    have "y ∈ assocs G z" using z_def(2) z_more(2) y_def(2)
      by (simp add: closure_ofI2)
    hence d_def: "d = assocs G z"
      using y_def(2,3) z_more(2) assocs_repr_independence
      by blast
    have "count (factor_mset G a) d = multiplicity G z a"
      unfolding d_def
      by (intro factor_mset_count[OF assms(1) z_more(2,1)])
    also have "... ≤ multiplicity G z b"
      using assms(4) z_def(1) by simp
    also have "... = count (factor_mset G b) d"
      unfolding d_def
      by (intro factor_mset_count[symmetric, OF assms(2) z_more(2,1)])
    finally show ?thesis by simp
  next
    case False
    have "count (factor_mset G a) d = 0" using False
      by (intro factor_mset_count_2[OF assms(1)], simp)
    moreover have "count (factor_mset G b) d = 0" using False
      by (intro factor_mset_count_2[OF assms(2)], simp)
    ultimately show ?thesis by simp
  qed
  hence "factor_mset G a ⊆# factor_mset G b"
    unfolding subseteq_mset_def by simp
  thus ?thesis using factor_mset_divides assms(1,2) by simp
qed
lemma count_image_mset_inj:
  assumes "inj_on f R" "x ∈ R" "set_mset A ⊆ R"
  shows "count (image_mset f A) (f x) = count A x"
proof (cases "x ∈# A")
  case True
  hence "(f y = f x ∧ y ∈# A) = (y = x)" for y
    by (meson assms(1) assms(3) inj_onD subsetD)
  hence "(f -` {f x} ∩ set_mset A) = {x}"
    by (simp add:set_eq_iff)
  thus ?thesis
    by (subst count_image_mset, simp)
next
  case False
  hence "x ∉ set_mset A" by simp
  hence "f x ∉ f ` set_mset A" using assms
    by (simp add: inj_on_image_mem_iff)
  hence "count (image_mset f A) (f x) = 0"
    by (simp add:count_eq_zero_iff)
  thus ?thesis by (metis count_inI False)
qed
text ‹Factorization of an element from a @{locale "factorial_monoid"} using a selection of representatives
from each equivalence class formed by @{term "(∼)"}.›
lemma split_factors:
  assumes "canonical_irreducibles G R"
  assumes "a ∈ carrier G"
  shows
    "finite {d. d ∈ R ∧ multiplicity G d a > 0}"
    "a ∼ (⨂d∈{d. d ∈ R ∧ multiplicity G d a > 0}.
          d [^] multiplicity G d a)" (is "a ∼ ?rhs")
proof -
  have r_1: "R ⊆ {x. x ∈ carrier G ∧ irreducible G x}"
    using assms(1) unfolding canonical_irreducibles_def by simp
  have r_2: "⋀x y. x ∈ R ⟹ y ∈ R ⟹ x ∼ y ⟹ x = y"
    using assms(1) unfolding canonical_irreducibles_def by simp
  have assocs_inj: "inj_on (assocs G) R"
    using r_1 r_2 assocs_eqD by (intro inj_onI, blast)
  define R' where
    "R' = (∑d∈ {d. d ∈ R ∧ multiplicity G d a > 0}.
    replicate_mset (multiplicity G d a) d)"
  have "count (factor_mset G a) (assocs G x) > 0"
    if "x ∈ R" "0 < multiplicity G x a" for x
    using assms r_1 r_2 that
    by (subst factor_mset_count[OF assms(2)]) auto
  hence "assocs G ` {d ∈ R. 0 < multiplicity G d a}
    ⊆ set_mset (factor_mset G a)"
    by (intro image_subsetI, simp)
  hence a:"finite (assocs G ` {d ∈ R. 0 < multiplicity G d a})"
    using finite_subset by auto
  show "finite {d ∈ R. 0 < multiplicity G d a}"
    using assocs_inj inj_on_subset[OF assocs_inj]
    by (intro finite_imageD[OF a], simp)
  hence count_R':
    "count R' d = (if d ∈ R then multiplicity G d a else 0)"
    for d
    by (auto simp add:R'_def count_sum)
  have set_R': "set_mset R' = {d ∈ R. 0 < multiplicity G d a}"
    unfolding set_mset_def using count_R' by auto
  have "count (image_mset (assocs G) R') x =
    count (factor_mset G a) x" for x
  proof (cases "∃x'. x' ∈ R ∧ x = assocs G x'")
    case True
    then obtain x' where x'_def: "x' ∈ R" "x = assocs G x'"
      by blast
    have "count (image_mset (assocs G) R') x = count R' x'"
      using assocs_inj inj_on_subset[OF assocs_inj] x'_def
      by (subst x'_def(2), subst count_image_mset_inj[OF assocs_inj])
        (auto simp:set_R')
    also have "... = multiplicity G x' a"
      using count_R' x'_def by simp
    also have "... = count (factor_mset G a) (assocs G x')"
      using x'_def(1) r_1
      by (subst factor_mset_count[OF assms(2)]) auto
    also have "... = count (factor_mset G a) x"
      using x'_def(2) by simp
    finally show ?thesis by simp
  next
    case False
    have a:"x ≠ assocs G z"
      if a1: "z ∈ carrier G" and a2: "irreducible G z" for z
    proof -
      obtain v where v_def: "v ∈ R" "z ∼ v"
        using a1 a2 assms(1)
        unfolding canonical_irreducibles_def by auto
      hence "z ∈ assocs G v"
        using a1 r_1 v_def(1) by (simp add: closure_ofI2)
      hence "assocs G z = assocs G v"
        using a1 r_1 v_def(1)  assocs_repr_independence
        by auto
      moreover have "x ≠ assocs G v"
        using False v_def(1) by simp
      ultimately show ?thesis by simp
    qed
    have "count (image_mset (assocs G) R') x = 0"
      using False count_R' by (simp add: count_image_mset) auto
    also have "... = count (factor_mset G a) x"
      using a
      by (intro factor_mset_count_2[OF assms(2), symmetric]) auto
    finally show ?thesis by simp
  qed
  hence "image_mset (assocs G) R' = factor_mset G a"
    by (rule multiset_eqI)
  moreover have "set_mset R' ⊆ carrier G"
    using r_1 by (auto simp add:set_R')
  ultimately have "a ∼ (⨂x∈set_mset R'. x [^] count R' x)"
    using assms(2) by (intro factor_mset_choose, auto)
  also have "... = ?rhs"
    using set_R' assms r_1 r_2
    by (intro finprod_cong', auto simp add:count_R')
  finally show "a ∼ ?rhs" by simp
qed
end
end