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 [^]Gn) dividesGg}"

definition canonical_irreducibles where
  "canonical_irreducibles G A = (
    A  {a. a  carrier G  irreducible G a} 
    (x y. x  A  y  A  x Gy  x = y) 
    (x  carrier G. irreducible G x  (y  A. x Gy)))"

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 "... = (ainsert 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:
  "(xset_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 [^]Gk) ⊆# factor_mset G a"
    by (subst factor_mset_pow[OF assms(1)], simp)
  also have "...  (d [^] k) dividesGa"
    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  (xset_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 =
    (xset_mset R. factor_mset G (x [^] count R x))"
    using assms(2) by (subst factor_mset_prod, auto)
  also have "... =
    (xset_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 "... = (xset_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 "... = (xset_mset R.
    image_mset (assocs G) (replicate_mset (count R x) x))"
    by simp
  also have "... = image_mset (assocs G)
    (xset_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 "(xset_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  (xset_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