Theory Poly_Lemmas

section ‹Preliminary Results›

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

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)"
  by (simp add: in_set_to_poly order_0I rsquarefree_root_order rsquarefree_set_to_poly)

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