Theory Degree_Section

(* Author: Alexander Maletzky *)

section ‹Degree Sections of Power-Products›

theory Degree_Section
  imports Polynomials.MPoly_PM
begin

definition deg_sect :: "'x set ⇒ nat ⇒ ('x::countable ⇒0 nat) set"
  where "deg_sect X d = .[X] ∩ {t. deg_pm t = d}"

definition deg_le_sect :: "'x set ⇒ nat ⇒ ('x::countable ⇒0 nat) set"
  where "deg_le_sect X d = (⋃d0≤d. deg_sect X d0)"

lemma deg_sectI: "t ∈ .[X] ⟹ deg_pm t = d ⟹ t ∈ deg_sect X d"
  by (simp add: deg_sect_def)

lemma deg_sectD:
  assumes "t ∈ deg_sect X d"
  shows "t ∈ .[X]" and "deg_pm t = d"
  using assms by (simp_all add: deg_sect_def)

lemma deg_le_sect_alt: "deg_le_sect X d = .[X] ∩ {t. deg_pm t ≤ d}"
  by (auto simp: deg_le_sect_def deg_sect_def)

lemma deg_le_sectI: "t ∈ .[X] ⟹ deg_pm t ≤ d ⟹ t ∈ deg_le_sect X d"
  by (simp add: deg_le_sect_alt)

lemma deg_le_sectD:
  assumes "t ∈ deg_le_sect X d"
  shows "t ∈ .[X]" and "deg_pm t ≤ d"
  using assms by (simp_all add: deg_le_sect_alt)

lemma deg_sect_zero [simp]: "deg_sect X 0 = {0}"
  by (auto simp: deg_sect_def zero_in_PPs)

lemma deg_sect_empty: "deg_sect {} d = (if d = 0 then {0} else {})"
  by (auto simp: deg_sect_def)

lemma deg_sect_singleton [simp]: "deg_sect {x} d = {Poly_Mapping.single x d}"
  by (auto simp: deg_sect_def deg_pm_single PPs_singleton)

lemma deg_le_sect_zero [simp]: "deg_le_sect X 0 = {0}"
  by (auto simp: deg_le_sect_def)

lemma deg_le_sect_empty [simp]: "deg_le_sect {} d = {0}"
  by (auto simp: deg_le_sect_alt varnum_eq_zero_iff)

lemma deg_le_sect_singleton: "deg_le_sect {x} d = Poly_Mapping.single x ` {..d}"
  by (auto simp: deg_le_sect_alt deg_pm_single PPs_singleton)

lemma deg_sect_mono: "X ⊆ Y ⟹ deg_sect X d ⊆ deg_sect Y d"
  by (auto simp: deg_sect_def dest: PPs_mono)

lemma deg_le_sect_mono_1: "X ⊆ Y ⟹ deg_le_sect X d ⊆ deg_le_sect Y d"
  by (auto simp: deg_le_sect_alt dest: PPs_mono)

lemma deg_le_sect_mono_2: "d1 ≤ d2 ⟹ deg_le_sect X d1 ⊆ deg_le_sect X d2"
  by (auto simp: deg_le_sect_alt)

lemma zero_in_deg_le_sect: "0 ∈ deg_le_sect n d"
  by (simp add: deg_le_sect_alt zero_in_PPs)

lemma deg_sect_disjoint: "d1 ≠ d2 ⟹ deg_sect X d1 ∩ deg_sect Y d2 = {}"
  by (auto simp: deg_sect_def)

lemma deg_le_sect_deg_sect_disjoint: "d1 < d2 ⟹ deg_le_sect Y d1 ∩ deg_sect X d2 = {}"
  by (auto simp: deg_sect_def deg_le_sect_alt)

lemma deg_sect_Suc:
  "deg_sect X (Suc d) = (⋃x∈X. (+) (Poly_Mapping.single x 1) ` deg_sect X d)" (is "?A = ?B")
proof (rule set_eqI)
  fix t
  show "t ∈ ?A ⟷ t ∈ ?B"
  proof
    assume "t ∈ ?A"
    hence "t ∈ .[X]" and "deg_pm t = Suc d" by (rule deg_sectD)+
    from this(2) have "keys t ≠ {}" by auto
    then obtain x where "x ∈ keys t" by blast
    hence "1 ≤ lookup t x" by (simp add: in_keys_iff)
    from ‹t ∈ .[X]› have "keys t ⊆ X" by (rule PPsD)
    with ‹x ∈ keys t› have "x ∈ X" ..
    let ?s = "Poly_Mapping.single x (1::nat)"
    from ‹1 ≤ lookup t x› have "?s adds t"
      by (auto simp: lookup_single when_def intro!: adds_poly_mappingI le_funI)
    hence t: "?s + (t - ?s) = t" by (metis add.commute adds_minus)
    have "t - ?s ∈ deg_sect X d"
    proof (rule deg_sectI)
      from ‹t ∈ .[X]› show "t - ?s ∈ .[X]" by (rule PPs_closed_minus)
    next
      from deg_pm_plus[of ?s "t - ?s"] have "deg_pm t = Suc (deg_pm (t - ?s))"
        by (simp only: t deg_pm_single)
      thus "deg_pm (t - ?s) = d" by (simp add: ‹deg_pm t = Suc d›)
    qed
    hence "?s + (t - ?s) ∈ (+) ?s ` deg_sect X d" by (rule imageI)
    hence "t ∈ (+) ?s ` deg_sect X d" by (simp only: t)
    with ‹x ∈ X› show "t ∈ ?B" ..
  next
    assume "t ∈ ?B"
    then obtain x where "x ∈ X" and "t ∈ (+) (Poly_Mapping.single x 1) ` deg_sect X d" ..
    from this(2) obtain s where s: "s ∈ deg_sect X d"
      and t: "t = Poly_Mapping.single x 1 + s" (is "t = ?s + s") ..
    show "t ∈ ?A"
    proof (rule deg_sectI)
      from ‹x ∈ X› have "?s ∈ .[X]" by (rule PPs_closed_single)
      moreover from s have "s ∈ .[X]" by (rule deg_sectD)
      ultimately show "t ∈ .[X]" unfolding t by (rule PPs_closed_plus)
    next
      from s have "deg_pm s = d" by (rule deg_sectD)
      thus "deg_pm t = Suc d" by (simp add: t deg_pm_single deg_pm_plus)
    qed
  qed
qed

lemma deg_sect_insert:
  "deg_sect (insert x X) d = (⋃d0≤d. (+) (Poly_Mapping.single x (d - d0)) ` deg_sect X d0)"
    (is "?A = ?B")
proof (rule set_eqI)
  fix t
  show "t ∈ ?A ⟷ t ∈ ?B"
  proof
    assume "t ∈ ?A"
    hence "t ∈ .[insert x X]" and "deg_pm t = d" by (rule deg_sectD)+
    from this(1) obtain e tx where "tx ∈ .[X]" and t: "t = Poly_Mapping.single x e + tx"
      by (rule PPs_insertE)
    have "e + deg_pm tx = deg_pm t" by (simp add: t deg_pm_plus deg_pm_single)
    hence "e + deg_pm tx = d" by (simp only: ‹deg_pm t = d›)
    hence "deg_pm tx ∈ {..d}" and e: "e = d - deg_pm tx" by simp_all
    from ‹tx ∈ .[X]› refl have "tx ∈ deg_sect X (deg_pm tx)" by (rule deg_sectI)
    hence "t ∈ (+) (Poly_Mapping.single x (d - deg_pm tx)) ` deg_sect X (deg_pm tx)"
      unfolding t e by (rule imageI)
    with ‹deg_pm tx ∈ {..d}› show "t ∈ ?B" ..
  next
    assume "t ∈ ?B"
    then obtain d0 where "d0 ∈ {..d}" and "t ∈ (+) (Poly_Mapping.single x (d - d0)) ` deg_sect X d0" ..
    from this(2) obtain s where s: "s ∈ deg_sect X d0"
      and t: "t = Poly_Mapping.single x (d - d0) + s" (is "t = ?s + s") ..
    show "t ∈ ?A"
    proof (rule deg_sectI)
      have "?s ∈ .[insert x X]" by (rule PPs_closed_single, simp)
      from s have "s ∈ .[X]" by (rule deg_sectD)
      also have "... ⊆ .[insert x X]" by (rule PPs_mono, blast)
      finally have "s ∈ .[insert x X]" .
      with ‹?s ∈ .[insert x X]› show "t ∈ .[insert x X]" unfolding t by (rule PPs_closed_plus)
    next
      from s have "deg_pm s = d0" by (rule deg_sectD)
      moreover from ‹d0 ∈ {..d}› have "d0 ≤ d" by simp
      ultimately show "deg_pm t = d" by (simp add: t deg_pm_single deg_pm_plus)
    qed
  qed
qed

lemma deg_le_sect_Suc: "deg_le_sect X (Suc d) = deg_le_sect X d ∪ deg_sect X (Suc d)"
  by (simp add: deg_le_sect_def atMost_Suc Un_commute)

lemma deg_le_sect_Suc_2:
  "deg_le_sect X (Suc d) = insert 0 (⋃x∈X. (+) (Poly_Mapping.single x 1) ` deg_le_sect X d)"
    (is "?A = ?B")
proof -
  have eq1: "{Suc 0..Suc d} = Suc ` {..d}" by (simp add: image_Suc_atMost)
  have "insert 0 {1..Suc d} = {..Suc d}" by fastforce
  hence "?A = (⋃d0∈insert 0 {1..Suc d}. deg_sect X d0)" by (simp add: deg_le_sect_def)
  also have "... = insert 0 (⋃d0≤d. deg_sect X (Suc d0))" by (simp add: eq1)
  also have "... = insert 0 (⋃d0≤d. (⋃x∈X. (+) (Poly_Mapping.single x 1) ` deg_sect X d0))"
    by (simp only: deg_sect_Suc)
  also have "... = insert 0 (⋃x∈X. (+) (Poly_Mapping.single x 1) ` (⋃d0≤d. deg_sect X d0))"
    by fastforce
  also have "... = ?B" by (simp only: deg_le_sect_def)
  finally show ?thesis .
qed

lemma finite_deg_sect:
  assumes "finite X"
  shows "finite ((deg_sect X d)::('x::countable ⇒0 nat) set)"
proof (induct d)
  case 0
  show ?case by simp
next
  case (Suc d)
  with assms show ?case by (simp add: deg_sect_Suc)
qed

corollary finite_deg_le_sect: "finite X ⟹ finite ((deg_le_sect X d)::('x::countable ⇒0 nat) set)"
  by (simp add: deg_le_sect_def finite_deg_sect)

lemma keys_subset_deg_le_sectI:
  assumes "p ∈ P[X]" and "poly_deg p ≤ d"
  shows "keys p ⊆ deg_le_sect X d"
proof
  fix t
  assume "t ∈ keys p"
  also from assms(1) have "... ⊆ .[X]" by (rule PolysD)
  finally have "t ∈ .[X]" .
  from ‹t ∈ keys p› have "deg_pm t ≤ poly_deg p" by (rule poly_deg_max_keys)
  from this assms(2) have "deg_pm t ≤ d" by (rule le_trans)
  with ‹t ∈ .[X]› show "t ∈ deg_le_sect X d" by (rule deg_le_sectI)
qed

lemma binomial_symmetric_plus: "(n + k) choose n = (n + k) choose k"
  by (metis add_diff_cancel_left' binomial_symmetric le_add1)

lemma card_deg_sect:
  assumes "finite X" and "X ≠ {}"
  shows "card (deg_sect X d) = (d + (card X - 1)) choose (card X - 1)"
  using assms
proof (induct X arbitrary: d)
  case empty
  thus ?case by simp
next
  case (insert x X)
  from insert(1, 2) have eq1: "card (insert x X) = Suc (card X)" by simp
  show ?case
  proof (cases "X = {}")
    case True
    thus ?thesis by simp
  next
    case False
    with insert.hyps(1) have "0 < card X" by (simp add: card_gt_0_iff)
    let ?f = "λd0. Poly_Mapping.single x (d - d0)"
    from False have eq2: "card (deg_sect X d0) = d0 + (card X - 1) choose (card X - 1)" for d0
      by (rule insert.hyps)
    have "finite {..d}" by simp
    moreover from insert.hyps(1) have "∀d0∈{..d}. finite ((+) (?f d0) ` deg_sect X d0)"
      by (simp add: finite_deg_sect)
    moreover have "∀d0∈{..d}. ∀d1∈{..d}. d0 ≠ d1 ⟶
                          ((+) (?f d0) ` deg_sect X d0) ∩ ((+) (?f d1) ` deg_sect X d1) = {}"
    proof (intro ballI impI, rule ccontr)
      fix d1 d2 :: nat
      assume "d1 ≠ d2"
      assume "((+) (?f d1) ` deg_sect X d1) ∩ ((+) (?f d2) ` deg_sect X d2) ≠ {}"
      then obtain t where "t ∈ ((+) (?f d1) ` deg_sect X d1) ∩ ((+) (?f d2) ` deg_sect X d2)"
        by blast
      hence t1: "t ∈ (+) (?f d1) ` deg_sect X d1" and t2: "t ∈ (+) (?f d2) ` deg_sect X d2" by simp_all
      from t1 obtain s1 where "s1 ∈ deg_sect X d1" and s1: "t = ?f d1 + s1" ..
      from this(1) have "s1 ∈ .[X]" by (rule deg_sectD)
      hence "keys s1 ⊆ X" by (rule PPsD)
      with insert.hyps(2) have eq3: "lookup s1 x = 0" by (auto simp: in_keys_iff)
      from t2 obtain s2 where "s2 ∈ deg_sect X d2" and s2: "t = ?f d2 + s2" ..
      from this(1) have "s2 ∈ .[X]" by (rule deg_sectD)
      hence "keys s2 ⊆ X" by (rule PPsD)
      with insert.hyps(2) have eq4: "lookup s2 x = 0" by (auto simp: in_keys_iff)
      from s2 have "lookup (?f d1 + s1) x = lookup (?f d2 + s2) x" by (simp only: s1)
      hence "d - d1 = d - d2" by (simp add: lookup_add eq3 eq4)
      moreover assume "d1 ∈ {..d}" and "d2 ∈ {..d}"
      ultimately have "d1 = d2" by simp
      with ‹d1 ≠ d2› show False ..
    qed
    ultimately have "card (deg_sect (insert x X) d) =
                       (∑d0≤d. card ((+) (monomial (d - d0) x) ` deg_sect X d0))"
      unfolding deg_sect_insert by (rule card_UN_disjoint)
    also from refl have "... = (∑d0≤d. card (deg_sect X d0))"
    proof (rule sum.cong)
      fix d0
      have "inj_on ((+) (monomial (d - d0) x)) (deg_sect X d0)" by (rule, rule add_left_imp_eq)
      thus "card ((+) (monomial (d - d0) x) ` deg_sect X d0) = card (deg_sect X d0)"
        by (rule card_image)
    qed
    also have "... = (∑d0≤d. (card X - 1) + d0 choose (card X - 1))" by (simp only: eq2 add.commute)
    also have "... = (∑d0≤d. (card X - 1) + d0 choose d0)" by (simp only: binomial_symmetric_plus)
    also have "... = Suc ((card X - 1) + d) choose d" by (rule sum_choose_lower)
    also from ‹0 < card X› have "... = d + (card (insert x X) - 1) choose d"
      by (simp add: eq1 add.commute)
    also have "... = d + (card (insert x X) - 1) choose (card (insert x X) - 1)"
      by (fact binomial_symmetric_plus)
    finally show ?thesis .
  qed
qed

corollary card_deg_sect_Suc:
  assumes "finite X"
  shows "card (deg_sect X (Suc d)) = (d + card X) choose (Suc d)"
proof (cases "X = {}")
  case True
  thus ?thesis by (simp add: deg_sect_empty)
next
  case False
  with assms have "0 < card X" by (simp add: card_gt_0_iff)
  from assms False have "card (deg_sect X (Suc d)) = (Suc d + (card X - 1)) choose (card X - 1)"
    by (rule card_deg_sect)
  also have "... = (Suc d + (card X - 1)) choose (Suc d)" by (rule sym, rule binomial_symmetric_plus)
  also from ‹0 < card X› have "... = (d + card X) choose (Suc d)" by simp
  finally show ?thesis .
qed

corollary card_deg_le_sect:
  assumes "finite X"
  shows "card (deg_le_sect X d) = (d + card X) choose card X"
proof (induct d)
  case 0
  show ?case by simp
next
  case (Suc d)
  from assms have "finite (deg_le_sect X d)" by (rule finite_deg_le_sect)
  moreover from assms have "finite (deg_sect X (Suc d))" by (rule finite_deg_sect)
  moreover from lessI have "deg_le_sect X d ∩ deg_sect X (Suc d) = {}"
    by (rule deg_le_sect_deg_sect_disjoint)
  ultimately have "card (deg_le_sect X (Suc d)) = card (deg_le_sect X d) + card (deg_sect X (Suc d))"
    unfolding deg_le_sect_Suc by (rule card_Un_disjoint)
  also from assms have "... = (Suc d + card X) choose Suc d"
    by (simp add: Suc.hyps card_deg_sect_Suc binomial_symmetric_plus[of d])
  also have "... = (Suc d + card X) choose card X" by (rule binomial_symmetric_plus)
  finally show ?case .
qed

end (* theory *)