Theory Poly_Lemmas

section ‹Preliminary Results›

theory Poly_Lemmas
  imports
    "HOL-Computational_Algebra.Polynomial"
    "Polynomial_Interpolation.Missing_Polynomial"
begin

text "Taken from Budan-Fourier.BF-Misc"
lemma order_linear[simp]: "order x [:-y, 1:] = (if x=y then 1 else 0)"
  by (auto simp add:order_power_n_n[where n=1,simplified] order_0I)

subsection "On Polynomial Roots"

lemma proots_empty: "proots p = {#}  p = 0  (x. poly p x  0)"
proof standard
  show "proots p = {#}  p = 0  (x. poly p x  0)"
    using order_root count_empty count_proots by metis
next
  have "(x. poly p x  0)  proots p = {#}"
    by (simp add: multiset_eqI order_root)
  then show "p = 0  (x. poly p x  0)  proots p = {#}"
    by auto
qed

lemma proots_element: "x ∈# proots p  p = 0  poly p x = 0"
  by (cases "p = 0") auto

lemma proots_diff:
  assumes "p  0" "q  0"
  shows "set_mset (proots p - proots q) = {x. order x p > order x q}" (is "?L = ?R")
proof -
  have "?L = {x. count (proots p) x > count (proots q) x}"
    by (rule set_mset_diff)
  also have " = ?R"
    using count_proots assms by simp
  finally show ?thesis by simp
qed

subsection ‹On @{term "rsquarefree"}

text ‹The following fact is an improved version of @{thm "rsquarefree_root_order"}, 
which does not require the assumption that @{term "p  0"}.›

lemma rsquarefree_root_order': "rsquarefree p  poly p x = 0  order x p = 1"
  using rsquarefree_root_order rsquarefree_def by auto

lemma rsquarefree_single_root[simp]: "rsquarefree [:-x,1:]"
proof -
  have "[:-x,1:]  0"
    by simp
  then show ?thesis
    unfolding rsquarefree_def by auto
qed

lemma rsquarefree_mul:
  assumes "rsquarefree p" "rsquarefree q"
    " x. poly p x  0  poly q x  0"
  shows "rsquarefree(p * q)"
proof -
  have 11: "p  0" "q  0"
    using assms rsquarefree_def by auto
  then have 1: "p * q  0"
    by simp

  have "(x. order x p = 0  order x p = 1)"
    "(x. order x q = 0  order x q = 1)"
    using assms rsquarefree_def by auto
  then have 2: "(x. order x (p * q) = 0  order x (p * q) = 1)"
    using 11 1 order_mult assms(3)
    by (metis comm_monoid_add_class.add_0 less_one order_gt_0_iff verit_sum_simplify)

  show ?thesis unfolding rsquarefree_def
    using 1 2  by auto
qed


subsection ‹On Symmetric Differences›

lemma card_sym_diff_finite:
  assumes "finite A" "finite B"
  shows "card (sym_diff A B) = card (A-B) + card (B-A)"
proof -
  have "(A-B)  (B-A) = {}"
    by blast
  then show ?thesis
    using assms card_Un_disjoint[of "(A-B)" "(B-A)"] by fast
qed

lemma card_add_diff_finite:
  assumes "finite A" "finite B"
  shows "card A + card (B-A) = card B + card (A-B)"
  using assms
proof -
  from assms have fi: "finite (A  B)"
    by simp

  have "card (B-A) = card B - card (A  B)"
    using fi card_Diff_subset_Int by (metis inf_commute)
  also have "card (A-B) = card A - card (A  B)"
    using fi card_Diff_subset_Int by blast
  moreover have "card A + (card B - card (A  B)) = card B + (card A - card (A  B))"
    using assms by (metis Nat.diff_add_assoc add.commute card_mono inf.cobounded1 inf.cobounded2)
  ultimately show ?thesis by argo
qed

lemma card_sub_int_diff_finite:
  assumes "finite A" "finite B"
  shows "int (card A) - card B = int (card (A-B)) - card (B-A)"
  using assms card_add_diff_finite by fastforce

lemma card_sub_int_diff_finite_real:
  assumes "finite A" "finite B"
  shows "real (card A) - card B = real (card (A-B)) - card (B-A)"
  using assms card_add_diff_finite by fastforce

subsection ‹Characteristic Polynomial›

text ‹The characteristic polynomial associated to a set:›
definition set_to_poly :: "'a::finite_field set  'a poly" where
  "set_to_poly A   a  A. [:-a,1:]"

lemma set_to_poly_correct: "{x. poly (set_to_poly A) x = 0} = A"
proof (induct A rule: infinite_finite_induct)
  case (infinite A)
  then show ?case by simp
next
  case empty
  then show ?case unfolding set_to_poly_def by simp
next
  case (insert x F)
  have "set_to_poly (insert x F) = set_to_poly F * [:-x,1:]"
    unfolding set_to_poly_def by (simp add: insert.hyps(2))
  also have "{xa. poly (set_to_poly F * [:-x,1:]) xa = 0} =
      {xa. poly (set_to_poly F) xa = 0}  {xa. poly ([:-x,1:]) xa = 0}"
    by auto
  moreover have 2: "{xa. poly (set_to_poly F) xa = 0} = F"
    by (simp add: insert.hyps(3))
  moreover have 3: "{xa. poly ([:-x,1:]) xa = 0} = {x}"
    by auto
  ultimately have "{xa. poly (set_to_poly (insert x F)) xa = 0} = F  {x}"
     by simp
  then show ?case by simp
qed

lemma in_set_to_poly: "poly (set_to_poly A) x = 0  x  A"
  using set_to_poly_correct
  by auto

lemma set_to_poly_not0[simp]: "set_to_poly A  0"
  unfolding set_to_poly_def by auto

lemma set_to_poly_empty[simp]: "set_to_poly {} = 1"
  unfolding set_to_poly_def by simp

lemma set_to_poly_inj: "inj set_to_poly"
  by (metis injI set_to_poly_correct)

lemma rsquarefree_set_to_poly: "rsquarefree (set_to_poly A)"
proof (induct A rule: infinite_finite_induct)
  case (infinite A)
  then show ?case by simp
next
  case empty
  then show ?case
    by (simp add: rsquarefree_def set_to_poly_def)
next
  case (insert x F)
  then have 1: "set_to_poly (insert x F) = set_to_poly F * [:-x,1:]"
    by (simp add: set_to_poly_def)

  have "rsquarefree [:-x,1:]"
    using rsquarefree_single_root by simp
  also have "poly (set_to_poly F) x  0"
    using insert by (simp add: in_set_to_poly)
  moreover have "poly ([:-x,1:]) x = 0"
    using insert by simp
  ultimately have "rsquarefree( set_to_poly F * [:-x,1:])"
    using insert(3) rsquarefree_mul by fastforce

  then show ?case using 1
    by simp
qed

lemma set_to_poly_insert:
  assumes"x  A"
  shows "set_to_poly (insert x A) = set_to_poly A * [:-x,1:]"
  using assms set_to_poly_def by (simp add: set_to_poly_def)

lemma set_to_poly_mult: "set_to_poly X * set_to_poly Y = set_to_poly (X  Y) * set_to_poly (X  Y)"
  by (simp add: prod.union_inter set_to_poly_def)

lemma set_to_poly_mult_distinct:
  assumes "X  Y = {}"
  shows "set_to_poly X * set_to_poly Y = set_to_poly (X  Y)"
  by (simp add: set_to_poly_mult assms)

lemma set_to_poly_degree:
  "degree (set_to_poly A) = card A"
proof (induct A rule: infinite_finite_induct)
  case (infinite A)
  then show ?case by auto
next
  case empty
  then show ?case by auto
next
  case (insert x F)
  have "[:-x, 1:]  0" and "set_to_poly F  0"
    using set_to_poly_not0 by auto
  then have "degree (set_to_poly F * [:-x, 1:]) = degree (set_to_poly F) + degree [:-x, 1:]"
    using degree_mult_eq by blast
  also have "set_to_poly (insert x F) = set_to_poly F * [:-x, 1:]"
    using insert set_to_poly_insert by simp
  ultimately show ?case using insert
    by simp
qed

lemma set_to_poly_order:
  "order x (set_to_poly A) = (if x  A then 1 else 0)"
proof (cases "x  A")
  case True
  then show ?thesis
    by (simp add: in_set_to_poly rsquarefree_root_order' rsquarefree_set_to_poly)
next
  case False
  then show ?thesis using in_set_to_poly order_root
    by auto
qed

lemma set_to_poly_lead_coeff: "lead_coeff (set_to_poly A) = 1"
proof (induct A rule: infinite_finite_induct)
  case (infinite A)
  then show ?case by auto
next
  case empty
  then show ?case by auto
next
  case (insert x A)
  then have ins: "set_to_poly (insert x A) = set_to_poly A * [:-x,1:] "
    unfolding set_to_poly_def by simp
  then show ?case
    unfolding ins lead_coeff_mult using insert by simp
qed

lemma degree_sub_lead_coeff:
  assumes "degree p > 0"
  shows "degree (p - monom (lead_coeff p) (degree p)) < degree p"
  using assms by (simp add: coeff_eq_0 degree_lessI)

lemma remove_lead_from_monic:
  fixes p q :: "'a :: field poly"
  assumes "monic p"
  assumes "degree p > 0"
  shows "degree (p - monom 1 (degree p)) < degree p"
  using degree_sub_lead_coeff[OF assms(2)] assms(1) by simp

lemma poly_eqI_degree_monic:
  fixes p q :: "'a :: field poly"
  assumes "degree p = degree q"
  assumes "degree p  card A"
  assumes "monic p" "monic q"
  assumes "x. x  A  poly p x = poly q x"
  shows "p = q"
proof (cases "degree p > 0")
  case True
  have "degree (p - monom 1 (degree p)) < card A"
    using remove_lead_from_monic[OF assms(3)] True assms(2) by simp
  moreover have "degree (q - monom 1 (degree q)) < card A"
    using remove_lead_from_monic[OF assms(4)] True assms(1,2) by simp
  ultimately have "p - monom 1 (degree p) = q - monom 1 (degree q)"
    using assms(1,5) by (intro poly_eqI_degree[of A]) auto
  thus ?thesis using assms(1) by simp
next
  case False
  hence "degree p = 0" "degree q = 0" using assms(1) by auto
  thus "p = q" using assms(3,4) monic_degree_0 by blast
qed

end