Theory Dube_Bound

(* Author: Alexander Maletzky *)

section ‹Dub\'{e}'s Degree-Bound for Homogeneous Gr\"obner Bases›

theory Dube_Bound
  imports Poly_Fun Cone_Decomposition Degree_Bound_Utils
begin

context fixes n d :: nat
begin

function Dube_aux :: "nat  nat" where
  "Dube_aux j = (if j + 2 < n then
                  2 + ((Dube_aux (j + 1)) choose 2) + (i=j+3..n-1. (Dube_aux i) choose (Suc (i - j)))
                else if j + 2 = n then d2 + 2 * d else 2 * d)"
  by pat_completeness auto
termination proof
  show "wf (measure ((-) n))" by (fact wf_measure)
qed auto

definition Dube :: nat where "Dube = (if n  1  d = 0 then d else Dube_aux 1)"

lemma Dube_aux_ge_d: "d  Dube_aux j"
proof (induct j rule: Dube_aux.induct)
  case step: (1 j)
  have "j + 2 < n  j + 2 = n  n < j + 2" by auto
  show ?case
  proof (rule linorder_cases)
    assume *: "j + 2 < n"
    hence 1: "d  Dube_aux (j + 1)"
      by (rule step.hyps)+
    show ?thesis
    proof (cases "d  2")
      case True
      also from * have "2  Dube_aux j" by simp
      finally show ?thesis .
    next
      case False
      hence "2 < d" by simp
      hence "2 < Dube_aux (j + 1)" using 1 by (rule less_le_trans)
      with _ have "Dube_aux (j + 1)  Dube_aux (j + 1) choose 2" by (rule upper_le_binomial) simp
      also from * have "  Dube_aux j" by simp
      finally have "Dube_aux (j + 1)  Dube_aux j" .
      with 1 show ?thesis by (rule le_trans)
    qed
  next
    assume "j + 2 = n"
    thus ?thesis by simp
  next
    assume "n < j + 2"
    thus ?thesis by simp
  qed
qed

corollary Dube_ge_d: "d  Dube"
  by (simp add: Dube_def Dube_aux_ge_d del: Dube_aux.simps)

text ‹Dub\'{e} in citeDube1990 proves the following theorem, to obtain a short closed form for
  the degree bound. However, the proof he gives is wrong: In the last-but-one proof step of Lemma 8.1
  the sum on the right-hand-side of the inequality can be greater than 1/2 (e.g. for @{prop "n = 7"},
  @{prop "d = 2"} and @{prop "j = 1"}), rendering the value inside the big brackets negative. This is
  also true without the additional summand 2› we had to introduce in function @{const Dube_aux} to
  correct another mistake found in citeDube1990.
  Nonetheless, experiments carried out in Mathematica still suggest that the short closed form is a
  valid upper bound for @{const Dube}, even with the additional summand 2›. So, with some effort it
  might be possible to prove the theorem below; but in fact function @{const Dube} gives typically
  much better (i.e. smaller) values for concrete values of n› and d›, so it is better to stick to
  @{const Dube} instead of the closed form anyway. Asymptotically, as n› tends to infinity,
  @{const Dube} grows double exponentially, too.›

theorem "rat_of_nat Dube  2 * ((rat_of_nat d)2 / 2 + (rat_of_nat d)) ^ (2 ^ (n - 2))"
  oops

end

subsection ‹Hilbert Function and Hilbert Polynomial›

context pm_powerprod
begin

context
  fixes X :: "'x set"
  assumes fin_X: "finite X"
begin

lemma Hilbert_fun_cone_aux:
  assumes "h  P[X]" and "h  0" and "U  X" and "homogeneous (h::_ 0 'a::field)"
  shows "Hilbert_fun (cone (h, U)) z = card {t  .[U]. deg_pm t + poly_deg h = z}"
proof -
  from assms(2) have "lpp h  keys h" by (rule punit.lt_in_keys)
  with assms(4) have deg_h[symmetric]: "deg_pm (lpp h) = poly_deg h"
    by (rule homogeneousD_poly_deg)
  from assms(1, 3) have "cone (h, U)  P[X]" by (rule cone_subset_PolysI)
  with fin_X have "Hilbert_fun (cone (h, U)) z = card (lpp ` (hom_deg_set z (cone (h, U)) - {0}))"
    using subspace_cone[of "(h, U)"] by (simp only: Hilbert_fun_alt)
  also from assms(4) have "lpp ` (hom_deg_set z (cone (h, U)) - {0}) =
                            {t  lpp ` (cone (h, U) - {0}). deg_pm t = z}"
    by (intro image_lt_hom_deg_set homogeneous_set_coneI)
  also have "{t  lpp ` (cone (h, U) - {0}). deg_pm t = z} =
              (λt. t + lpp h) ` {t  .[U]. deg_pm t + poly_deg h = z}"  (is "?A = ?B")
  proof
    show "?A  ?B"
    proof
      fix t
      assume "t  ?A"
      hence "t  lpp ` (cone (h, U) - {0})" and "deg_pm t = z" by simp_all
      from this(1) obtain a where "a  cone (h, U) - {0}" and 2: "t = lpp a" ..
      from this(1) have "a  cone (h, U)" and "a  0" by simp_all
      from this(1) obtain q where "q  P[U]" and a: "a = q * h" by (rule coneE)
      from a  0 have "q  0" by (auto simp: a)
      hence t: "t = lpp q + lpp h" using assms(2) unfolding 2 a by (rule lp_times)
      hence "deg_pm (lpp q) + poly_deg h = deg_pm t" by (simp add: deg_pm_plus deg_h)
      also have " = z" by fact
      finally have "deg_pm (lpp q) + poly_deg h = z" .
      moreover from q  P[U] have "lpp q  .[U]" by (rule PPs_closed_lpp)
      ultimately have "lpp q  {t  .[U]. deg_pm t + poly_deg h = z}" by simp
      moreover have "t = lpp q + lpp h" by (simp only: t)
      ultimately show "t  ?B" by (rule rev_image_eqI)
    qed
  next
    show "?B  ?A"
    proof
      fix t
      assume "t  ?B"
      then obtain s where "s  {t  .[U]. deg_pm t + poly_deg h = z}"
        and t1: "t = s + lpp h" ..
      from this(1) have "s  .[U]" and 1: "deg_pm s + poly_deg h = z" by simp_all
      let ?q = "monomial (1::'a) s"
      have "?q  0" by (simp add: monomial_0_iff)
      hence "?q * h  0" and "lpp (?q * h) = lpp ?q + lpp h" using h  0
        by (rule times_not_zero, rule lp_times)
      hence t: "t = lpp (?q * h)" by (simp add: t1 punit.lt_monomial)
      from s  .[U] have "?q  P[U]" by (rule Polys_closed_monomial)
      with refl have "?q * h  cone (h, U)" by (rule coneI)
      moreover from _ assms(2) have "?q * h  0" by (rule times_not_zero) (simp add: monomial_0_iff)
      ultimately have "?q * h  cone (h, U) - {0}" by simp
      hence "t  lpp ` (cone (h, U) - {0})" unfolding t by (rule imageI)
      moreover have "deg_pm t = int z" by (simp add: t1) (simp add: deg_pm_plus deg_h flip: 1)
      ultimately show "t  ?A" by simp
    qed
  qed
  also have "card  = card {t  .[U]. deg_pm t + poly_deg h = z}" by (simp add: card_image)
  finally show ?thesis .
qed

lemma Hilbert_fun_cone_empty:
  assumes "h  P[X]" and "h  0" and "homogeneous (h::_ 0 'a::field)"
  shows "Hilbert_fun (cone (h, {})) z = (if poly_deg h = z then 1 else 0)"
proof -
  have "Hilbert_fun (cone (h, {})) z = card {t  .[{}::'x set]. deg_pm t + poly_deg h = z}"
    using assms(1, 2) empty_subsetI assms(3) by (rule Hilbert_fun_cone_aux)
  also have " = (if poly_deg h = z then 1 else 0)" by simp
  finally show ?thesis .
qed

lemma Hilbert_fun_cone_nonempty:
  assumes "h  P[X]" and "h  0" and "U  X" and "homogeneous (h::_ 0 'a::field)" and "U  {}"
  shows "Hilbert_fun (cone (h, U)) z =
          (if poly_deg h  z then ((z - poly_deg h) + (card U - 1)) choose (card U - 1) else 0)"
proof (cases "poly_deg h  z")
  case True
  from assms(3) fin_X have "finite U" by (rule finite_subset)
  from assms(1-4) have "Hilbert_fun (cone (h, U)) z = card {t  .[U]. deg_pm t + poly_deg h = z}"
    by (rule Hilbert_fun_cone_aux)
  also from True have "{t  .[U]. deg_pm t + poly_deg h = z} = deg_sect U (z - poly_deg h)"
    by (auto simp: deg_sect_def)
  also from finite U assms(5) have "card  = (z - poly_deg h) + (card U - 1) choose (card U - 1)"
    by (rule card_deg_sect)
  finally show ?thesis by (simp add: True)
next
  case False
  from assms(1-4) have "Hilbert_fun (cone (h, U)) z = card {t  .[U]. deg_pm t + poly_deg h = z}"
    by (rule Hilbert_fun_cone_aux)
  also from False have "{t  .[U]. deg_pm t + poly_deg h = z} = {}" by auto
  hence "card {t  .[U]. deg_pm t + poly_deg h = z} = card ({}::('x 0 nat) set)" by (rule arg_cong)
  also have " = 0" by simp
  finally show ?thesis by (simp add: False)
qed

corollary Hilbert_fun_Polys:
  assumes "X  {}"
  shows "Hilbert_fun (P[X]::(_ 0 'a::field) set) z = (z + (card X - 1)) choose (card X - 1)"
proof -
  let ?one = "1::('x 0 nat) 0 'a"
  have "Hilbert_fun (P[X]::(_ 0 'a) set) z = Hilbert_fun (cone (?one, X)) z" by simp
  also have " = (if poly_deg ?one  z then ((z - poly_deg ?one) + (card X - 1)) choose (card X - 1) else 0)"
    using one_in_Polys _ subset_refl _ assms by (rule Hilbert_fun_cone_nonempty) simp_all
  also have " = (z + (card X - 1)) choose (card X - 1)" by simp
  finally show ?thesis .
qed

lemma Hilbert_fun_cone_decomp:
  assumes "cone_decomp T ps" and "valid_decomp X ps" and "hom_decomp ps"
  shows "Hilbert_fun T z = (hUset ps. Hilbert_fun (cone hU) z)"
proof -
  note fin_X
  moreover from assms(2, 1) have "T  P[X]" by (rule valid_cone_decomp_subset_Polys)
  moreover from assms(1) have dd: "direct_decomp T (map cone ps)" by (rule cone_decompD)
  ultimately have "Hilbert_fun T z = (sset (map cone ps). Hilbert_fun s z)"
  proof (rule Hilbert_fun_direct_decomp)
    fix cn
    assume "cn  set (map cone ps)"
    then obtain hU where "hU  set ps" and cn: "cn = cone hU" unfolding set_map ..
    note this(1)
    moreover obtain h U where hU: "hU = (h, U)" using prod.exhaust by blast
    ultimately have "(h, U)  set ps" by simp
    with assms(3) have "homogeneous h" by (rule hom_decompD)
    thus "homogeneous_set cn" unfolding cn hU by (rule homogeneous_set_coneI)
    show "phull.subspace cn" unfolding cn by (fact subspace_cone)
  qed
  also have " = (hUset ps. ((λs. Hilbert_fun s z)  cone) hU)" unfolding set_map using finite_set
  proof (rule sum.reindex_nontrivial)
    fix hU1 hU2
    assume "hU1  set ps" and "hU2  set ps" and "hU1  hU2"
    with dd have "cone hU1  cone hU2 = {0}" using zero_in_cone by (rule direct_decomp_map_Int_zero)
    moreover assume "cone hU1 = cone hU2"
    ultimately show "Hilbert_fun (cone hU1) z = 0" by simp
  qed
  finally show ?thesis by simp
qed

definition Hilbert_poly :: "(nat  nat)  int  int"
  where "Hilbert_poly b =
                (λz::int. let n = card X in
                  ((z - b (Suc n) + n) gchoose n) - 1 - (i=1..n. (z - b i + i - 1) gchoose i))"

lemma poly_fun_Hilbert_poly: "poly_fun (Hilbert_poly b)"
  by (simp add: Hilbert_poly_def Let_def)

lemma Hilbert_fun_eq_Hilbert_poly_plus_card:
  assumes "X  {}" and "valid_decomp X ps" and "hom_decomp ps" and "cone_decomp T ps"
    and "standard_decomp k ps" and "exact_decomp X 0 ps" and "𝖻 ps (Suc 0)  d"
  shows "int (Hilbert_fun T d) = card {h::_ 0 'a::field. (h, {})  set ps  poly_deg h = d} + Hilbert_poly (𝖻 ps) d"
proof -
  define n where "n = card X"
  with assms(1) have "0 < n" using fin_X by (simp add: card_gt_0_iff)
  hence "1  n" and "Suc 0  n" by simp_all
  from pos_decomp_subset have eq0: "(set ps - set (ps+))  set (ps+) = set ps" by blast
  have "set ps - set (ps+)  set ps" by blast
  hence fin2: "finite (set ps - set (ps+))" using finite_set by (rule finite_subset)

  have "(hUset ps - set (ps+). Hilbert_fun (cone hU) d) =
        ((h, U)set ps - set (ps+). if poly_deg h = d then 1 else 0)"
    using refl
  proof (rule sum.cong)
    fix x
    assume "x  set ps - set (ps+)"
    moreover obtain h U where x: "x = (h, U)" using prod.exhaust by blast
    ultimately have "U = {}" and "(h, U)  set ps" by (simp_all add: pos_decomp_def)
    from assms(2) this(2) have "h  P[X]" and "h  0" by (rule valid_decompD)+
    moreover from assms(3) (h, U)  set ps have "homogeneous h" by (rule hom_decompD)
    ultimately show "Hilbert_fun (cone x) d = (case x of (h, U)  if poly_deg h = d then 1 else 0)"
      by (simp add: x U = {} Hilbert_fun_cone_empty split del: if_split)
  qed
  also from fin2 have " = ((h, U){(h', U')  set ps - set (ps+). poly_deg h' = d}. 1)"
    by (rule sum.mono_neutral_cong_right) (auto split: if_splits)
  also have " = card {(h, U)  set ps - set (ps+). poly_deg h = d}" by auto
  also have " = card {h. (h, {})  set ps  poly_deg h = d}" by (fact card_Diff_pos_decomp)
  finally have eq1: "(hUset ps - set (ps+). Hilbert_fun (cone hU) d) =
                      card {h. (h, {})  set ps  poly_deg h = d}" .

  let ?f = "λa b. (int d) - a + b gchoose b"
  have "int (hUset (ps+). Hilbert_fun (cone hU) d) = (hUset (ps+). int (Hilbert_fun (cone hU) d))"
    by (simp add: int_sum prod.case_distrib)
  also have " = ((h, U)(i{1..n}. {(h, U)  set (ps+). card U = i}). ?f (poly_deg h) (card U - 1))"
  proof (rule sum.cong)
    show "set (ps+) = (i{1..n}. {(h, U). (h, U)  set (ps+)  card U = i})"
    proof (rule Set.set_eqI, rule)
      fix x
      assume "x  set (ps+)"
      moreover obtain h U where x: "x = (h, U)" using prod.exhaust by blast
      ultimately have "(h, U)  set (ps+)" by simp
      hence "(h, U)  set ps" and "U  {}" by (simp_all add: pos_decomp_def)
      from fin_X assms(6) this(1) have "U  X" by (rule exact_decompD)
      hence "finite U" using fin_X by (rule finite_subset)
      with U  {} have "0 < card U" by (simp add: card_gt_0_iff)
      moreover from fin_X U  X have "card U  n" unfolding n_def by (rule card_mono)
      ultimately have "card U  {1..n}" by simp
      moreover from (h, U)  set (ps+) have "(h, U)  {(h', U'). (h', U')  set (ps+)  card U' = card U}"
        by simp
      ultimately show "x  (i{1..n}. {(h, U). (h, U)  set (ps+)  card U = i})" by (simp add: x)
    qed blast
  next
    fix x
    assume "x  (i{1..n}. {(h, U). (h, U)  set (ps+)  card U = i})"
    then obtain j where "j  {1..n}" and "x  {(h, U). (h, U)  set (ps+)  card U = j}" ..
    from this(2) obtain h U where "(h, U)  set (ps+)" and "card U = j" and x: "x = (h, U)" by blast
    from fin_X assms(2, 5) this(1) have "poly_deg h < 𝖻 ps (Suc 0)" by (rule 𝖻_one_gr)
    also have "  d" by fact
    finally have "poly_deg h < d" .
    hence int1: "int (d - poly_deg h) = int d - int (poly_deg h)" by simp
    from card U = j j  {1..n} have "0 < card U" by simp
    hence int2: "int (card U - Suc 0) = int (card U) - 1" by simp
    from (h, U)  set (ps+) have "(h, U)  set ps" using pos_decomp_subset ..
    with assms(2) have "h  P[X]" and "h  0" and "U  X" by (rule valid_decompD)+
    moreover from assms(3) (h, U)  set ps have "homogeneous h" by (rule hom_decompD)
    moreover from 0 < card U have "U  {}" by auto
    ultimately have "Hilbert_fun (cone (h, U)) d =
                (if poly_deg h  d then (d - poly_deg h + (card U - 1)) choose (card U - 1) else 0)"
      by (rule Hilbert_fun_cone_nonempty)
    also from poly_deg h < d have " = (d - poly_deg h + (card U - 1)) choose (card U - 1)" by simp
    finally
    have "int (Hilbert_fun (cone (h, U)) d) = (int d - int (poly_deg h) + (int (card U - 1))) gchoose (card U - 1)"
      by (simp add: int_binomial int1 int2)
    thus "int (Hilbert_fun (cone x) d) =
          (case x of (h, U)  int d - int (poly_deg h) + (int (card U - 1)) gchoose (card U - 1))"
      by (simp add: x)
  qed
  also have " = (j=1..n. (h, U){(h', U')  set (ps+). card U' = j}. ?f (poly_deg h) (card U - 1))"
  proof (intro sum.UNION_disjoint ballI)
    fix j
    have "{(h, U). (h, U)  set (ps+)  card U = j}  set (ps+)" by blast
    thus "finite {(h, U). (h, U)  set (ps+)  card U = j}" using finite_set by (rule finite_subset)
  qed blast+
  also from refl have " = (j=1..n. ?f (𝖻 ps (Suc j)) j - ?f (𝖻 ps j) j)"
  proof (rule sum.cong)
    fix j
    assume "j  {1..n}"
    hence "Suc 0  j" and "0 < j" and "j  n" by simp_all
    from fin_X this(1) have "𝖻 ps j  𝖻 ps (Suc 0)" by (rule 𝖻_decreasing)
    also have "  d" by fact
    finally have "𝖻 ps j  d" .
    from fin_X have "𝖻 ps (Suc j)  𝖻 ps j" by (rule 𝖻_decreasing) simp
    hence "𝖻 ps (Suc j)  d" using 𝖻 ps j  d by (rule le_trans)
    from 0 < j have int_j: "int (j - Suc 0) = int j - 1" by simp
    have "((h, U){(h', U'). (h', U')  set (ps+)  card U' = j}. ?f (poly_deg h) (card U - 1)) =
         ((h, U)(d0{𝖻 ps (Suc j)..int (𝖻 ps j) - 1}. {(h', U'). (h', U')  set (ps+)  int (poly_deg h') = d0  card U' = j}).
            ?f (poly_deg h) (card U - 1))"
      using _ refl
    proof (rule sum.cong)
      show "{(h', U'). (h', U')  set (ps+)  card U' = j} =
            (d0{𝖻 ps (Suc j)..int (𝖻 ps j) - 1}. {(h', U'). (h', U')  set (ps+)  int (poly_deg h') = d0  card U' = j})"
      proof (rule Set.set_eqI, rule)
        fix x
        assume "x  {(h', U'). (h', U')  set (ps+)  card U' = j}"
        moreover obtain h U where x: "x = (h, U)" using prod.exhaust by blast
        ultimately have "(h, U)  set (ps+)" and "card U = j" by simp_all
        with fin_X assms(5, 6) Suc 0  j j  n have "𝖻 ps (Suc j)  poly_deg h"
          unfolding n_def by (rule lem_6_1_3)
        moreover from fin_X have "poly_deg h < 𝖻 ps j"
        proof (rule 𝖻)
          from (h, U)  set (ps+) show "(h, U)  set ps" using pos_decomp_subset ..
        next
          show "j  card U" by (simp add: card U = j)
        qed
        ultimately have "poly_deg h  {𝖻 ps (Suc j)..int (𝖻 ps j) - 1}" by simp
        moreover have "(h, U)  {(h', U'). (h', U')  set (ps+)  poly_deg h' = poly_deg h  card U' = card U}"
          using (h, U)  set (ps+) by simp
        ultimately show "x  (d0{𝖻 ps (Suc j)..int (𝖻 ps j) - 1}.
                                {(h', U'). (h', U')  set (ps+)  int (poly_deg h') = d0  card U' = j})"
          by (simp add: x card U = j)
      qed blast
    qed
    also have " = (d0=𝖻 ps (Suc j)..int (𝖻 ps j) - 1.
                        (h, U){(h', U'). (h', U')  set (ps+)  poly_deg h' = d0  card U' = j}.
                            ?f (poly_deg h) (card U - 1))"
    proof (intro sum.UNION_disjoint ballI)
      fix d0::int
      have "{(h', U'). (h', U')  set (ps+)  poly_deg h' = d0  card U' = j}  set (ps+)" by blast
      thus "finite {(h', U'). (h', U')  set (ps+)  poly_deg h' = d0  card U' = j}"
        using finite_set by (rule finite_subset)
    qed blast+
    also from refl have " = (d0=𝖻 ps (Suc j)..int (𝖻 ps j) - 1. ?f d0 (j - 1))"
    proof (rule sum.cong)
      fix d0
      assume "d0  {𝖻 ps (Suc j)..int (𝖻 ps j) - 1}"
      hence "𝖻 ps (Suc j)  d0" and "d0 < int (𝖻 ps j)" by simp_all
      hence "𝖻 ps (Suc j)  nat d0" and "nat d0 < 𝖻 ps j" by simp_all
      have "((h, U){(h', U'). (h', U')  set (ps+)  poly_deg h' = d0  card U' = j}. ?f (poly_deg h) (card U - 1)) =
            ((h, U){(h', U'). (h', U')  set (ps+)  poly_deg h' = d0  card U' = j}. ?f d0 (j - 1))"
        using refl by (rule sum.cong) auto
      also have " = card {(h', U'). (h', U')  set (ps+)  poly_deg h' = nat d0  card U' = j} * ?f d0 (j - 1)"
        using 𝖻 ps (Suc j)  d0 by (simp add: int_eq_iff)
      also have " = ?f d0 (j - 1)"
        using fin_X assms(5, 6) Suc 0  j j  n 𝖻 ps (Suc j)  nat d0 nat d0 < 𝖻 ps j
        by (simp only: n_def lem_6_1_2'(3))
      finally show "((h, U){(h', U'). (h', U')  set (ps+)  poly_deg h' = d0  card U' = j}.
                      ?f (poly_deg h) (card U - 1)) = ?f d0 (j - 1)" .
    qed
    also have " = (d0(-) (int d) ` {𝖻 ps (Suc j)..int (𝖻 ps j) - 1}. d0 + int (j - 1) gchoose (j - 1))"
    proof -
      have "inj_on ((-) (int d)) {𝖻 ps (Suc j)..int (𝖻 ps j) - 1}" by (auto simp: inj_on_def)
      thus ?thesis by (simp only: sum.reindex o_def)
    qed
    also have " = (d0{0..int d - (𝖻 ps (Suc j))}-{0..int d - 𝖻 ps j}. d0 + int (j - 1) gchoose (j - 1))"
      using _ refl
    proof (rule sum.cong)
      have "(-) (int d) ` {𝖻 ps (Suc j)..int (𝖻 ps j) - 1} = {int d - (int (𝖻 ps j) - 1)..int d - int (𝖻 ps (Suc j))}"
        by (simp only: image_diff_atLeastAtMost)
      also have " = {0..int d - int (𝖻 ps (Suc j))} - {0..int d - int (𝖻 ps j)}"
      proof -
        from 𝖻 ps j  d have "int (𝖻 ps j) - 1  int d" by simp
        thus ?thesis by auto
      qed
      finally show "(-) (int d) ` {𝖻 ps (Suc j)..int (𝖻 ps j) - 1} =
                    {0..int d - int (𝖻 ps (Suc j))} - {0..int d - int (𝖻 ps j)}" .
    qed
    also have " = (d0=0..int d - (𝖻 ps (Suc j)). d0 + int (j - 1) gchoose (j - 1)) -
                    (d0=0..int d - 𝖻 ps j. d0 + int (j - 1) gchoose (j - 1))"
      by (rule sum_diff) (auto simp: 𝖻 ps (Suc j)  𝖻 ps j)
    also from 𝖻 ps (Suc j)  d 𝖻 ps j  d have " = ?f (𝖻 ps (Suc j)) j - ?f (𝖻 ps j) j"
      by (simp add: gchoose_rising_sum, simp add: int_j ac_simps 0 < j)
    finally show "((h, U){(h', U'). (h', U')  set (ps+)  card U' = j}. ?f (poly_deg h) (card U - 1)) =
                    ?f (𝖻 ps (Suc j)) j - ?f (𝖻 ps j) j" .
  qed
  also have " = (j=1..n. ?f (𝖻 ps (Suc j)) j) - (j=1..n. ?f (𝖻 ps j) j)"
    by (fact sum_subtractf)
  also have " = ?f (𝖻 ps (Suc n)) n + (j=1..n-1. ?f (𝖻 ps (Suc j)) j) - (j=1..n. ?f (𝖻 ps j) j)"
    by (simp only: sum_tail_nat[OF 0 < n 1  n])
  also have " = ?f (𝖻 ps (Suc n)) n - ?f (𝖻 ps 1) 1 +
                  ((j=1..n-1. ?f (𝖻 ps (Suc j)) j) - (j=1..n-1. ?f (𝖻 ps (Suc j)) (Suc j)))"
    by (simp only: sum.atLeast_Suc_atMost[OF 1  n] sum_atLeast_Suc_shift[OF 0 < n 1  n])
  also have " = ?f (𝖻 ps (Suc n)) n - ?f (𝖻 ps 1) 1 -
                  (j=1..n-1. ?f (𝖻 ps (Suc j)) (Suc j) - ?f (𝖻 ps (Suc j)) j)"
    by (simp only: sum_subtractf)
  also have " = ?f (𝖻 ps (Suc n)) n - 1 - ((int d - 𝖻 ps (Suc 0)) gchoose (Suc 0)) -
                  (j=1..n-1. (int d - 𝖻 ps (Suc j) + j) gchoose (Suc j))"
  proof -
    have "?f (𝖻 ps 1) 1 = 1 + ((int d - 𝖻 ps (Suc 0)) gchoose (Suc 0))"
      by (simp add: plus_Suc_gbinomial)
    moreover from refl have "(j=1..n-1. ?f (𝖻 ps (Suc j)) (Suc j) - ?f (𝖻 ps (Suc j)) j) =
                              (j=1..n-1. (int d - 𝖻 ps (Suc j) + j) gchoose (Suc j))"
      by (rule sum.cong) (simp add: plus_Suc_gbinomial)
    ultimately show ?thesis by (simp only:)
  qed
  also have " = ?f (𝖻 ps (Suc n)) n - 1 - (j=0..n-1. (int d - 𝖻 ps (Suc j) + j) gchoose (Suc j))"
    by (simp only: sum.atLeast_Suc_atMost[OF le0], simp)
  also have " = ?f (𝖻 ps (Suc n)) n - 1 - (j=Suc 0..Suc (n-1). (int d - 𝖻 ps j + j - 1) gchoose j)"
    by (simp only: sum.shift_bounds_cl_Suc_ivl, simp add: ac_simps)
  also have " = Hilbert_poly (𝖻 ps) d" using 0 < n by (simp add: Hilbert_poly_def Let_def n_def)
  finally have eq2: "int (hUset (ps+). Hilbert_fun (cone hU) d) = Hilbert_poly (𝖻 ps) (int d)" .

  from assms(4, 2, 3) have "Hilbert_fun T d = (hUset ps. Hilbert_fun (cone hU) d)"
    by (rule Hilbert_fun_cone_decomp)
  also have " = (hU(set ps - set (ps+))  set (ps+). Hilbert_fun (cone hU) d)" by (simp only: eq0)
  also have " = (hUset ps - set (ps+). Hilbert_fun (cone hU) d) + (hUset (ps+). Hilbert_fun (cone hU) d)"
    using fin2 finite_set by (rule sum.union_disjoint) blast
  also have " = card {h. (h, {})  set ps  poly_deg h = d} + (hUset (ps+). Hilbert_fun (cone hU) d)"
    by (simp only: eq1)
  also have "int  = card {h. (h, {})  set ps  poly_deg h = d} + Hilbert_poly (𝖻 ps) d"
    by (simp only: eq2 int_plus)
  finally show ?thesis .
qed

corollary Hilbert_fun_eq_Hilbert_poly:
  assumes "X  {}" and "valid_decomp X ps" and "hom_decomp ps" and "cone_decomp T ps"
    and "standard_decomp k ps" and "exact_decomp X 0 ps" and "𝖻 ps 0  d"
  shows "int (Hilbert_fun (T::(_ 0 'a::field) set) d) = Hilbert_poly (𝖻 ps) d"
proof -
  from fin_X have "𝖻 ps (Suc 0)  𝖻 ps 0" using le0 by (rule 𝖻_decreasing)
  also have "  d" by fact
  finally have "𝖻 ps (Suc 0)  d" .
  with assms(1-6) have "int (Hilbert_fun T d) =
                int (card {h. (h, {})  set ps  poly_deg h = d}) + Hilbert_poly (𝖻 ps) (int d)"
    by (rule Hilbert_fun_eq_Hilbert_poly_plus_card)
  also have " = Hilbert_poly (𝖻 ps) (int d)"
  proof -
    have eq: "{h. (h, {})  set ps  poly_deg h = d} = {}"
    proof -
      {
        fix h
        assume "(h, {})  set ps" and "poly_deg h = d"
        from fin_X this(1) le0 have "poly_deg h < 𝖻 ps 0" by (rule 𝖻)
        with assms(7) have False by (simp add: poly_deg h = d)
      }
      thus ?thesis by blast
    qed
    show ?thesis by (simp add: eq)
  qed
  finally show ?thesis .
qed

subsection ‹Dub\'{e}'s Bound›

context
  fixes f :: "('x 0 nat) 0 'a::field"
  fixes F
  assumes n_gr_1: "1 < card X" and fin_F: "finite F" and F_sub: "F  P[X]" and f_in: "f  F"
    and hom_F: "f'. f'  F  homogeneous f'" and f_max: "f'. f'  F  poly_deg f'  poly_deg f"
    and d_gr_0: "0 < poly_deg f" and ideal_f_neq: "ideal {f}  ideal F"
begin

private abbreviation (input) "n  card X"
private abbreviation (input) "d  poly_deg f"

lemma f_in_Polys: "f  P[X]"
  using f_in F_sub ..

lemma hom_f: "homogeneous f"
  using f_in by (rule hom_F)

lemma f_not_0: "f  0"
  using d_gr_0 by auto

lemma X_not_empty: "X  {}"
  using n_gr_1 by auto

lemma n_gr_0: "0 < n"
  using 1 < n by simp

corollary int_n_minus_1 [simp]: "int (n - Suc 0) = int n - 1"
  using n_gr_0 by simp

lemma int_n_minus_2 [simp]: "int (n - Suc (Suc 0)) = int n - 2"
  using n_gr_1 by simp

lemma cone_f_X_sub: "cone (f, X)  P[X]"
proof -
  have "cone (f, X) = cone (f * 1, X)" by simp
  also from f_in_Polys have "  cone (1, X)" by (rule cone_mono_1)
  finally show ?thesis by simp
qed

lemma ideal_Int_Polys_eq_cone: "ideal {f}  P[X] = cone (f, X)"
proof (intro subset_antisym subsetI)
  fix p
  assume "p  ideal {f}  P[X]"
  hence "p  ideal {f}" and "p  P[X]" by simp_all
  have "finite {f}" by simp
  then obtain q where "p = (f'{f}. q f' * f')" using p  ideal {f}
    by (rule ideal.span_finiteE)
  hence p: "p = q f * f" by simp
  with p  P[X] have "f * q f  P[X]" by (simp only: mult.commute)
  hence "q f  P[X]" using f_in_Polys f_not_0 by (rule times_in_PolysD)
  with p show "p  cone (f, X)" by (rule coneI)
next
  fix p
  assume "p  cone (f, X)"
  then obtain q where "q  P[X]" and p: "p = q * f" by (rule coneE)
  have "f  ideal {f}" by (rule ideal.span_base) simp
  with q  P[X] f_in_Polys show "p  ideal {f}  P[X]"
    unfolding p by (intro IntI ideal.span_scale Polys_closed_times)
qed

private definition P_ps where
  "P_ps = (SOME x. valid_decomp X (snd x)  standard_decomp d (snd x) 
                        exact_decomp X 0 (snd x)  cone_decomp (fst x) (snd x)  hom_decomp (snd x) 
                        direct_decomp (ideal F  P[X]) [ideal {f}  P[X], fst x])"

private definition P where "P = fst P_ps"

private definition ps where "ps = snd P_ps"

lemma
  shows valid_ps: "valid_decomp X ps" (is ?thesis1)
    and std_ps: "standard_decomp d ps" (is ?thesis2)
    and ext_ps: "exact_decomp X 0 ps" (is ?thesis3)
    and cn_ps: "cone_decomp P ps" (is ?thesis4)
    and hom_ps: "hom_decomp ps" (is ?thesis5)
    and decomp_F: "direct_decomp (ideal F  P[X]) [ideal {f}  P[X], P]" (is ?thesis6)
proof -
  note fin_X
  moreover from fin_F have "finite (F - {f})" by simp
  moreover from F_sub have "F - {f}  P[X]" by blast
  ultimately obtain P' ps' where 1: "valid_decomp X ps'" and 2: "standard_decomp d ps'"
    and 3: "cone_decomp P' ps'" and 40: "(f'. f'  F - {f}  homogeneous f')  hom_decomp ps'"
    and 50: "direct_decomp (ideal (insert f (F - {f}))  P[X]) [ideal {f}  P[X], P']"
    using f_in_Polys f_max by (rule ideal_decompE) blast+
  have 4: "hom_decomp ps'" by (intro 40 hom_F) simp
  from 50 f_in have 5: "direct_decomp (ideal F  P[X]) [ideal {f}  P[X], P']"
    by (simp add: insert_absorb)
  let ?ps = "exact X (poly_deg f) ps'"
  from fin_X 1 2 have "valid_decomp X ?ps" and "standard_decomp d ?ps" and "exact_decomp X 0 ?ps"
    by (rule exact)+
  moreover from fin_X 1 2 3 have "cone_decomp P' ?ps" by (rule cone_decomp_exact)
  moreover from fin_X 1 2 4 have "hom_decomp ?ps" by (rule hom_decomp_exact)
  ultimately have "valid_decomp X (snd (P', ?ps))  standard_decomp d (snd (P', ?ps)) 
                    exact_decomp X 0 (snd (P', ?ps))  cone_decomp (fst (P', ?ps)) (snd (P', ?ps)) 
                    hom_decomp (snd (P', ?ps)) 
                    direct_decomp (ideal F  P[X]) [ideal {f}  P[X], fst (P', ?ps)]"
    using 5 by simp
  hence "?thesis1  ?thesis2  ?thesis3  ?thesis4  ?thesis5  ?thesis6"
    unfolding P_def ps_def P_ps_def by (rule someI)
  thus ?thesis1 and ?thesis2 and ?thesis3 and ?thesis4 and ?thesis5 and ?thesis6 by simp_all
qed

lemma P_sub: "P  P[X]"
  using valid_ps cn_ps by (rule valid_cone_decomp_subset_Polys)

lemma ps_not_Nil: "ps+  []"
proof
  assume "ps+ = []"
  have "Keys P  (hUset ps. keys (fst hU))" (is "_  ?A")
  proof
    fix t
    assume "t  Keys P"
    then obtain p where "p  P" and "t  keys p" by (rule in_KeysE)
    from cn_ps have "direct_decomp P (map cone ps)" by (rule cone_decompD)
    then obtain qs where qs: "qs  listset (map cone ps)" and p: "p = sum_list qs" using p  P
      by (rule direct_decompE)
    from t  keys p keys_sum_list_subset have "t  Keys (set qs)" unfolding p ..
    then obtain q where "q  set qs" and "t  keys q" by (rule in_KeysE)
    from this(1) obtain i where "i < length qs" and "q = qs ! i" by (metis in_set_conv_nth)
    with qs have "i < length ps" and "q  (map cone ps) ! i" by (simp_all add: listsetD del: nth_map)
    hence "q  cone (ps ! i)" by simp
    obtain h U where eq: "ps ! i = (h, U)" using prod.exhaust by blast
    from i < length ps this[symmetric] have "(h, U)  set ps" by simp
    have "U = {}"
    proof (rule ccontr)
      assume "U  {}"
      with (h, U)  set ps have "(h, U)  set (ps+)" by (simp add: pos_decomp_def)
      with ps+ = [] show False by simp
    qed
    with q  cone (ps ! i) have "q  range (λc. c  h)" by (simp only: eq cone_empty)
    then obtain c where "q = c  h" ..
    also have "keys   keys h" by (fact keys_map_scale_subset)
    finally have "t  keys h" using t  keys q ..
    hence "t  keys (fst (h, U))" by simp
    with (h, U)  set ps show "t  ?A" ..
  qed
  moreover from finite_set finite_keys have "finite ?A" by (rule finite_UN_I)
  ultimately have "finite (Keys P)" by (rule finite_subset)

  have "qideal F. q  P[X]  q  0  ¬ lpp f adds lpp q"
  proof (rule ccontr)
    assume "¬ (qideal F. q  P[X]  q  0  ¬ lpp f adds lpp q)"
    hence adds: "lpp f adds lpp q" if "q  ideal F" and "q  P[X]" and "q  0" for q
      using that by blast
    from fin_X _ F_sub have "ideal {f} = ideal F"
    proof (rule punit.pmdl_eqI_adds_lt_dgrad_p_set[simplified, OF dickson_grading_varnum,
          where m=0, simplified dgrad_p_set_varnum])
      from f_in_Polys show "{f}  P[X]" by simp
    next
      from f_in have "{f}  F" by simp
      thus "ideal {f}  ideal F" by (rule ideal.span_mono)
    next
      fix q
      assume "q  ideal F" and "q  P[X]" and "q  0"
      hence "lpp f adds lpp q" by (rule adds)
      with f_not_0 show "g{f}. g  0  lpp g adds lpp q" by blast
    qed
    with ideal_f_neq show False ..
  qed
  then obtain q0 where "q0  ideal F" and "q0  P[X]" and "q0  0"
    and nadds_q0: "¬ lpp f adds lpp q0" by blast
  define q where "q = hom_component q0 (deg_pm (lpp q0))"
  from hom_F q0  ideal F have "q  ideal F" unfolding q_def by (rule homogeneous_ideal)
  from homogeneous_set_Polys q0  P[X] have "q  P[X]" unfolding q_def by (rule homogeneous_setD)
  from q0  0 have "q  0" and "lpp q = lpp q0" unfolding q_def by (rule hom_component_lpp)+
  from nadds_q0 this(2) have nadds_q: "¬ lpp f adds lpp q" by simp
  have hom_q: "homogeneous q" by (simp only: q_def homogeneous_hom_component)
  from nadds_q obtain x where x: "¬ lookup (lpp f) x  lookup (lpp q) x"
    by (auto simp add: adds_poly_mapping le_fun_def)
  obtain y where "y  X" and "y  x"
  proof -
    from n_gr_1 have "2  n" by simp
    then obtain Y where "Y  X" and "card Y = 2" by (rule card_geq_ex_subset)
    from this(2) obtain u v where "u  v" and "Y = {u, v}" by (rule card_2_E)
    from this obtain y where "y  Y" and "y  x" by blast
    from this(1) Y  X have "y  X" ..
    thus ?thesis using y  x ..
  qed
  define q' where "q' = (λk. punit.monom_mult 1 (Poly_Mapping.single y k) q)"
  have inj1: "inj q'" by (auto intro!: injI simp: q'_def q  0 dest: punit.monom_mult_inj_2 monomial_inj)
  have q'_in: "q' k  ideal F  P[X]" for k unfolding q'_def using q  ideal F q  P[X] y  X
    by (intro IntI punit.pmdl_closed_monom_mult[simplified] Polys_closed_monom_mult PPs_closed_single)
  have lpp_q': "lpp (q' k) = Poly_Mapping.single y k + lpp q" for k
    using q  0 by (simp add: q'_def punit.lt_monom_mult)
  have inj2: "inj_on (deg_pm  lpp) (range q')"
    by (auto intro!: inj_onI simp: lpp_q' deg_pm_plus deg_pm_single dest: monomial_inj)
  have "(deg_pm  lpp) ` range q'  deg_pm ` Keys P"
  proof
    fix d
    assume "d  (deg_pm  lpp) ` range q'"
    then obtain k where d: "d = deg_pm (lpp (q' k))" (is "_ = deg_pm ?t") by auto
    from hom_q have hom_q': "homogeneous (q' k)" by (simp add: q'_def homogeneous_monom_mult)
    from q  0 have "q' k  0" by (simp add: q'_def punit.monom_mult_eq_zero_iff)
    hence "?t  keys (q' k)" by (rule punit.lt_in_keys)
    with hom_q' have deg_q': "d = poly_deg (q' k)" unfolding d by (rule homogeneousD_poly_deg)
    from decomp_F q'_in obtain qs where "qs  listset [ideal {f}  P[X], P]" and "q' k = sum_list qs"
      by (rule direct_decompE)
    moreover from this(1) obtain f0 p0 where f0: "f0  ideal {f}  P[X]" and p0: "p0  P"
      and "qs = [f0, p0]" by (rule listset_doubletonE)
    ultimately have q': "q' k = f0 + p0" by simp
    define f1 where "f1 = hom_component f0 d"
    define p1 where "p1 = hom_component p0 d"
    from hom_q have "homogeneous (q' k)" by (simp add: q'_def homogeneous_monom_mult)
    hence "q' k = hom_component (q' k) d" by (simp add: hom_component_of_homogeneous deg_q')
    also have " = f1 + p1" by (simp only: q' hom_component_plus f1_def p1_def)
    finally have "q' k = f1 + p1" .
    have "keys p1  {}"
    proof
      assume "keys p1 = {}"
      with q' k = f1 + p1 q' k  0 have t: "?t = lpp f1" and "f1  0" by simp_all
      from f0 have "f0  ideal {f}" by simp
      with _ have "f1  ideal {f}" unfolding f1_def by (rule homogeneous_ideal) (simp add: hom_f)
      with punit.is_Groebner_basis_singleton obtain g where "g  {f}" and "lpp g adds lpp f1"
        using f1  0 by (rule punit.GB_adds_lt[simplified])
      hence "lpp f adds ?t" by (simp add: t)
      hence "lookup (lpp f) x  lookup ?t x" by (simp add: adds_poly_mapping le_fun_def)
      also have " = lookup (lpp q) x" by (simp add: lpp_q' lookup_add lookup_single y  x)
      finally have "lookup (lpp f) x  lookup (lpp q) x" .
      with x show False ..
    qed
    then obtain t where "t  keys p1" by blast
    hence "d = deg_pm t" by (simp add: p1_def keys_hom_component)
    from cn_ps hom_ps have "homogeneous_set P" by (intro homogeneous_set_cone_decomp)
    hence "p1  P" using p0  P unfolding p1_def by (rule homogeneous_setD)
    with t  keys p1 have "t  Keys P" by (rule in_KeysI)
    with d = deg_pm t show "d  deg_pm ` Keys P" by (rule image_eqI)
  qed
  moreover from inj1 inj2 have "infinite ((deg_pm  lpp) ` range q')"
    by (simp add: finite_image_iff o_def)
  ultimately have "infinite (deg_pm ` Keys P)" by (rule infinite_super)
  hence "infinite (Keys P)" by blast
  thus False using finite (Keys P) ..
qed

private definition N where "N = normal_form F ` P[X]"

private definition qs where "qs = (SOME qs'. valid_decomp X qs'  standard_decomp 0 qs' 
                                    monomial_decomp qs'  cone_decomp N qs'  exact_decomp X 0 qs' 
                                    (gpunit.reduced_GB F. poly_deg g  𝖻 qs' 0))"

private definition "aa  𝖻 ps"
private definition "bb  𝖻 qs"
private abbreviation (input) "cc  (λi. aa i + bb i)"

lemma
  shows valid_qs: "valid_decomp X qs" (is ?thesis1)
    and std_qs: "standard_decomp 0 qs" (is ?thesis2)
    and mon_qs: "monomial_decomp qs" (is ?thesis3)
    and hom_qs: "hom_decomp qs" (is ?thesis6)
    and cn_qs: "cone_decomp N qs" (is ?thesis4)
    and ext_qs: "exact_decomp X 0 qs" (is ?thesis5)
    and deg_RGB: "g  punit.reduced_GB F  poly_deg g  bb 0"
proof -
  from fin_X F_sub obtain qs' where 1: "valid_decomp X qs'" and 2: "standard_decomp 0 qs'"
    and 3: "monomial_decomp qs'" and 4: "cone_decomp (normal_form F ` P[X]) qs'"
    and 5: "exact_decomp X 0 qs'"
    and 60: "g. (f. f  F  homogeneous f)  g  punit.reduced_GB F  poly_deg g  𝖻 qs' 0"
    by (rule normal_form_exact_decompE) blast
  from hom_F have "g. g  punit.reduced_GB F  poly_deg g  𝖻 qs' 0" by (rule 60)
  with 1 2 3 4 5 have "valid_decomp X qs'  standard_decomp 0 qs' 
                        monomial_decomp qs'  cone_decomp N qs'  exact_decomp X 0 qs' 
                        (gpunit.reduced_GB F. poly_deg g  𝖻 qs' 0)" by (simp add: N_def)
  hence "?thesis1  ?thesis2  ?thesis3  ?thesis4  ?thesis5  (gpunit.reduced_GB F. poly_deg g  bb 0)"
    unfolding qs_def bb_def by (rule someI)
  thus ?thesis1 and ?thesis2 and ?thesis3 and ?thesis4 and ?thesis5
    and "g  punit.reduced_GB F  poly_deg g  bb 0" by simp_all
  from ?thesis3 show ?thesis6 by (rule monomial_decomp_imp_hom_decomp)
qed

lemma N_sub: "N  P[X]"
  using valid_qs cn_qs by (rule valid_cone_decomp_subset_Polys)

lemma decomp_Polys: "direct_decomp P[X] [ideal {f}  P[X], P, N]"
proof -
  from fin_X F_sub have "direct_decomp P[X] [ideal F  P[X], N]" unfolding N_def
    by (rule direct_decomp_ideal_normal_form)
  hence "direct_decomp P[X] ([N] @ [ideal {f}  P[X], P])" using decomp_F
    by (rule direct_decomp_direct_decomp)
  hence "direct_decomp P[X] ([ideal {f}  P[X], P] @ [N])"
    by (rule direct_decomp_perm) simp   
  thus ?thesis by simp
qed

lemma aa_Suc_n [simp]: "aa (Suc n) = d"
proof -
  from fin_X ext_ps le_refl have "aa (Suc n) = 𝖺 ps" unfolding aa_def by (rule 𝖻_card_X)
  also from fin_X valid_ps std_ps ps_not_Nil have " = d" by (rule 𝖺_nonempty_unique)
  finally show ?thesis .
qed

lemma bb_Suc_n [simp]: "bb (Suc n) = 0"
proof -
  from fin_X ext_qs le_refl have "bb (Suc n) = 𝖺 qs" unfolding bb_def by (rule 𝖻_card_X)
  also from std_qs have " = 0" unfolding 𝖺_def[OF fin_X] by (rule Least_eq_0)
  finally show ?thesis .
qed

lemma Hilbert_fun_X:
  assumes "d  z"
  shows "Hilbert_fun (P[X]::(_ 0 'a) set) z =
            ((z - d) + (n - 1)) choose (n - 1) + Hilbert_fun P z + Hilbert_fun N z"
proof -
  define ss where "ss = [ideal {f}  P[X], P, N]"
  have "homogeneous_set A  phull.subspace A" if "A  set ss" for A
  proof -
    from that have "A = ideal {f}  P[X]  A = P  A = N" by (simp add: ss_def)
    thus ?thesis
    proof (elim disjE)
      assume A: "A = ideal {f}  P[X]"
      show ?thesis unfolding A
        by (intro conjI homogeneous_set_IntI phull.subspace_inter homogeneous_set_homogeneous_ideal
            homogeneous_set_Polys subspace_ideal subspace_Polys) (simp add: hom_f)
    next
      assume A: "A = P"
      from cn_ps hom_ps show ?thesis unfolding A
        by (intro conjI homogeneous_set_cone_decomp subspace_cone_decomp)
    next
      assume A: "A = N"
      from cn_qs hom_qs show ?thesis unfolding A
        by (intro conjI homogeneous_set_cone_decomp subspace_cone_decomp)
    qed
  qed
  hence 1: "A. A  set ss  homogeneous_set A" and 2: "A. A  set ss  phull.subspace A"
    by simp_all
  have "Hilbert_fun (P[X]::(_ 0 'a) set) z = (pset ss. Hilbert_fun p z)"
    using fin_X subset_refl decomp_Polys unfolding ss_def
  proof (rule Hilbert_fun_direct_decomp)
    fix A
    assume "A  set [ideal {f}  P[X], P, N]"
    hence "A  set ss" by (simp only: ss_def)
    thus "homogeneous_set A" and "phull.subspace A" by (rule 1, rule 2)
  qed
  also have " = (pset ss. count_list ss p * Hilbert_fun p z)"
    using refl
  proof (rule sum.cong)
    fix p
    assume "p  set ss"
    hence "count_list ss p  0" by (simp only: count_list_0_iff not_not)
    hence "count_list ss p = 1  1 < count_list ss p" by auto
    thus "Hilbert_fun p z = count_list ss p * Hilbert_fun p z"
    proof
      assume "1 < count_list ss p"
      with decomp_Polys have "p = {0}" unfolding ss_def[symmetric] using phull.subspace_0
        by (rule direct_decomp_repeated_eq_zero) (rule 2)
      thus ?thesis by simp
    qed simp
  qed
  also have " = sum_list (map (λp. Hilbert_fun p z) ss)"
    by (rule sym) (rule sum_list_map_eq_sum_count)
  also have " = Hilbert_fun (cone (f, X)) z + Hilbert_fun P z + Hilbert_fun N z"
    by (simp add: ss_def ideal_Int_Polys_eq_cone)
  also have "Hilbert_fun (cone (f, X)) z = (z - d + (n - 1)) choose (n - 1)"
    using f_not_0 f_in_Polys fin_X hom_f X_not_empty by (simp add: Hilbert_fun_cone_nonempty assms)
  finally show ?thesis .
qed

lemma dube_eq_0:
  "(λz::int. (z + int n - 1) gchoose (n - 1)) =
    (λz::int. ((z - d + n - 1) gchoose (n - 1)) + Hilbert_poly aa z + Hilbert_poly bb z)"
    (is "?f = ?g")
proof (rule poly_fun_eqI_ge)
  fix z::int
  let ?z = "nat z"
  assume "max (aa 0) (bb 0)  z"
  hence "aa 0  nat z" and "bb 0  nat z" and "0  z" by simp_all
  from this(3) have int_z: "int ?z = z" by simp
  have "d  aa 0" unfolding aa_Suc_n[symmetric] using fin_X le0 unfolding aa_def by (rule 𝖻_decreasing)
  hence "d  ?z" using aa 0  nat z by (rule le_trans)
  hence int_zd: "int (?z - d) = z - int d" using int_z by linarith
  from d  ?z have "Hilbert_fun (P[X]::(_ 0 'a) set) ?z =
                      ((?z - d) + (n - 1)) choose (n - 1) + Hilbert_fun P ?z + Hilbert_fun N ?z"
    by (rule Hilbert_fun_X)
  also have "int  = (z - d + (n - 1)) gchoose (n - 1) + Hilbert_poly aa z + Hilbert_poly bb z"
    using X_not_empty valid_ps hom_ps cn_ps std_ps ext_ps aa 0  nat z
          valid_qs hom_qs cn_qs std_qs ext_qs bb 0  nat z 0  z
    by (simp add: Hilbert_fun_eq_Hilbert_poly int_z aa_def bb_def int_binomial int_zd)
  finally show "?f z = ?g z" using fin_X X_not_empty 0  z
    by (simp add: Hilbert_fun_Polys int_binomial) smt
qed (simp_all add: poly_fun_Hilbert_poly)

corollary dube_eq_1:
  "(λz::int. (z + int n - 1) gchoose (n - 1)) =
    (λz::int. ((z - d + n - 1) gchoose (n - 1)) + ((z - d + n) gchoose n) + ((z + n) gchoose n) - 2 -
           (i=1..n. ((z - aa i + i - 1) gchoose i) + ((z - bb i + i - 1) gchoose i)))"
  by (simp only: dube_eq_0) (auto simp: Hilbert_poly_def Let_def sum.distrib)

lemma dube_eq_2:
  assumes "j < n"
  shows "(λz::int. (z + int n - int j - 1) gchoose (n - j - 1)) =
          (λz::int. ((z - d + n - int j - 1) gchoose (n - j - 1)) + ((z - d + n - j) gchoose (n - j)) +
                    ((z + n - j) gchoose (n - j)) - 2 -
                    (i=Suc j..n. ((z - aa i + i - j - 1) gchoose (i - j)) + ((z - bb i + i - j - 1) gchoose (i - j))))"
    (is "?f = ?g")
proof -
  let ?h = "λz i. ((z + (int i - aa i - 1)) gchoose i) + ((z + (int i - bb i - 1)) gchoose i)"
  let ?hj = "λz i. ((z + (int i - aa i - 1) - j) gchoose (i - j)) + ((z + (int i - bb i - 1) - j) gchoose (i - j))"
  from assms have 1: "j  n - Suc 0" and 2: "j  n" by simp_all

  have eq1: "(bw_diff ^^ j) (λz. i=1..j. ?h z i) = (λ_. if j = 0 then 0 else 2)"
  proof (cases j)
    case 0
    thus ?thesis by simp
  next
    case (Suc j0)
    hence "j  0" by simp
    have "(λz::int. i = 1..j. ?h z i) = (λz::int. (i = 1..j0. ?h z i) + ?h z j)"
      by (simp add: j = Suc j0)
    moreover have "(bw_diff ^^ j)  = (λz::int. (i = 1..j0. (bw_diff ^^ j) (λz. ?h z i) z) + 2)"
      by (simp add: bw_diff_gbinomial_pow)
    moreover have "(i = 1..j0. (bw_diff ^^ j) (λz. ?h z i) z) = (i = 1..j0. 0)" for z::int
      using refl
    proof (rule sum.cong)
      fix i
      assume "i  {1..j0}"
      hence "¬ j  i" by (simp add: j = Suc j0)
      thus "(bw_diff ^^ j) (λz. ?h z i) z = 0" by (simp add: bw_diff_gbinomial_pow)
    qed
    ultimately show ?thesis by (simp add: j  0)
  qed

  have eq2: "(bw_diff ^^ j) (λz. i=Suc j..n. ?h z i) = (λz. (i=Suc j..n. ?hj z i))"
  proof -
    have "(bw_diff ^^ j) (λz. i=Suc j..n. ?h z i) = (λz. i=Suc j..n. (bw_diff ^^ j) (λz. ?h z i) z)"
      by simp
    also have " = (λz. (i=Suc j..n. ?hj z i))"
    proof (intro ext sum.cong)
      fix z i
      assume "i  {Suc j..n}"
      hence "j  i" by simp
      thus "(bw_diff ^^ j) (λz. ?h z i) z = ?hj z i" by (simp add: bw_diff_gbinomial_pow)
    qed (fact refl)
    finally show ?thesis .
  qed

  from 1 have "?f = (bw_diff ^^ j) (λz::int. (z + (int n - 1)) gchoose (n - 1))"
    by (simp add: bw_diff_gbinomial_pow) (simp only: algebra_simps)
  also have " = (bw_diff ^^ j) (λz::int. (z + int n - 1) gchoose (n - 1))"
    by (simp only: algebra_simps)
  also have " = (bw_diff ^^ j)
          (λz::int. ((z - d + n - 1) gchoose (n - 1)) + ((z - d + n) gchoose n) + ((z + n) gchoose n) - 2 -
            (i=1..n. ((z - aa i + i - 1) gchoose i) + ((z - bb i + i - 1) gchoose i)))"
    by (simp only: dube_eq_1)
  also have " = (bw_diff ^^ j)
          (λz::int. ((z + (int n - d - 1)) gchoose (n - 1)) + ((z + (int n - d)) gchoose n) +
                    ((z + n) gchoose n) - 2 - (i=1..n. ?h z i))"
    by (simp only: algebra_simps)
  also have " = (λz::int. ((z + (int n - d - 1) - j) gchoose (n - 1 - j)) +
            ((z + (int n - d) - j) gchoose (n - j)) + ((z + n - j) gchoose (n - j)) - (if j = 0 then 2 else 0) -
            (bw_diff ^^ j) (λz. i=1..n. ?h z i) z)"
    using 1 2 by (simp add: bw_diff_const_pow bw_diff_gbinomial_pow del: bw_diff_sum_pow)
  also from j  n have "(λz. i=1..n. ?h z i) = (λz. (i=1..j. ?h z i) + (i=Suc j..n. ?h z i))"
    by (simp add: sum_split_nat_ivl)
  also have "(bw_diff ^^ j)  = (λz. (bw_diff ^^ j) (λz. i=1..j. ?h z i) z + (bw_diff ^^ j) (λz. i=Suc j..n. ?h z i) z)"
    by (simp only: bw_diff_plus_pow)
  also have " = (λz. (if j = 0 then 0 else 2) + (i=Suc j..n. ?hj z i))"
    by (simp only: eq1 eq2)
  finally show ?thesis by (simp add: algebra_simps)
qed

lemma dube_eq_3:
  assumes "j < n"
  shows "(1::int) = (- 1)^(n - Suc j) * ((int d - 1) gchoose (n - Suc j)) +
                    (- 1)^(n - j) * ((int d - 1) gchoose (n - j)) - 1 -
                    (i=Suc j..n. (- 1)^(i - j) * ((int (aa i) gchoose (i - j)) + (int (bb i) gchoose (i - j))))"
proof -
  from assms have 1: "int (n - Suc j) = int n - j - 1" and 2: "int (n - j) = int n - j" by simp_all
  from assms have "int n - int j - 1 = int (n - j - 1)" by simp
  hence eq1: "int n - int j - 1 gchoose (n - Suc j) = 1" by simp
  from assms have "int n - int j = int (n - j)" by simp
  hence eq2: "int n - int j gchoose (n - j) = 1" by simp
  have eq3: "int n - d - j - 1 gchoose (n - Suc j) = (- 1)^(n - Suc j) * (int d - 1 gchoose (n - Suc j))"
    by (simp add: gbinomial_int_negated_upper[of "int n - d - j - 1"] 1)
  have eq4: "int n - d - j gchoose (n - j) = (- 1)^(n - j) * (int d - 1 gchoose (n - j))"
    by (simp add: gbinomial_int_negated_upper[of "int n - d - j"] 2)
  have eq5: "(i = Suc j..n. int i - aa i - j - 1 gchoose (i - j) + (int i - bb i - j - 1 gchoose (i - j))) =
        (i=Suc j..n. (- 1)^(i - j) * ((int (aa i) gchoose (i - j)) + (int (bb i) gchoose (i - j))))"
    using refl
  proof (rule sum.cong)
    fix i
    assume "i  {Suc j..n}"
    hence "j  i" by simp
    hence 3: "int (i - j) = int i - j" by simp
    show "int i - aa i - j - 1 gchoose (i - j) + (int i - bb i - j - 1 gchoose (i - j)) =
          (- 1)^(i - j) * ((int (aa i) gchoose (i - j)) + (int (bb i) gchoose (i - j)))"
      by (simp add: gbinomial_int_negated_upper[of "int i - aa i - j - 1"]
            gbinomial_int_negated_upper[of "int i - bb i - j - 1"] 3 distrib_left)
  qed
  from fun_cong[OF dube_eq_2, OF assms, of 0] show ?thesis by (simp add: eq1 eq2 eq3 eq4 eq5)
qed

lemma dube_aux_1:
  assumes "(h, {})  set ps  set qs"
  shows "poly_deg h < max (aa 1) (bb 1)"
proof (rule ccontr)
  define z where "z = poly_deg h"
  assume "¬ z < max (aa 1) (bb 1)"

  let ?S = "λA. {h. (h, {})  A  poly_deg h = z}"
  have fin: "finite (?S A)" if "finite A" for A::"((('x 0 nat) 0 'a) × 'x set) set"
  proof -
    have "(λt. (t, {})) ` ?S A  A" by blast
    hence "finite ((λt. (t, {}::'x set)) ` ?S A)" using that by (rule finite_subset)
    moreover have "inj_on (λt. (t, {}::'x set)) (?S A)" by (rule inj_onI) simp
    ultimately show ?thesis by (rule finite_imageD)
  qed
  from finite_set have 1: "finite (?S (set ps))" by (rule fin)
  from finite_set have 2: "finite (?S (set qs))" by (rule fin)

  from ¬ z < max (aa 1) (bb 1) have "aa 1  z" and "bb 1  z" by simp_all
  have "d  aa 1" unfolding aa_Suc_n[symmetric] aa_def using fin_X by (rule 𝖻_decreasing) simp
  hence "d  z" using aa 1  z by (rule le_trans)
  hence eq: "int (z - d) = int z - int d" by simp
  from d  z have "Hilbert_fun (P[X]::(_ 0 'a) set) z =
                        ((z - d) + (n - 1)) choose (n - 1) + Hilbert_fun P z + Hilbert_fun N z"
    by (rule Hilbert_fun_X)
  also have "int  = ((int z - d + (n - 1)) gchoose (n - 1) + Hilbert_poly aa z + Hilbert_poly bb z) +
                        (int (card (?S (set ps))) + int (card (?S (set qs))))"
    using X_not_empty valid_ps hom_ps cn_ps std_ps ext_ps aa 1  z
          valid_qs hom_qs cn_qs std_qs ext_qs bb 1  z
    by (simp add: Hilbert_fun_eq_Hilbert_poly_plus_card aa_def bb_def int_binomial eq)
  finally have "((int z - d + n - 1) gchoose (n - 1) + Hilbert_poly aa z + Hilbert_poly bb z) +
                  (int (card (?S (set ps))) + int (card (?S (set qs)))) = int z + n - 1 gchoose (n - 1)"
    using fin_X X_not_empty by (simp add: Hilbert_fun_Polys int_binomial algebra_simps)
  also have " = (int z - d + n - 1) gchoose (n - 1) + Hilbert_poly aa z + Hilbert_poly bb z"
    by (fact dube_eq_0[THEN fun_cong])
  finally have "int (card (?S (set ps))) + int (card (?S (set qs))) = 0" by simp
  hence "card (?S (set ps)) = 0" and "card (?S (set qs)) = 0" by simp_all
  with 1 2 have "?S (set ps  set qs) = {}" by auto
  moreover from assms have "h  ?S (set ps  set qs)" by (simp add: z_def)
  ultimately have "h  {}" by (rule subst)
  thus False by simp
qed

lemma
  shows aa_n: "aa n = d" and bb_n: "bb n = 0" and bb_0: "bb 0  max (aa 1) (bb 1)"
proof -
  let ?j = "n - Suc 0"
  from n_gr_0 have "?j < n" and eq1: "Suc ?j = n" and eq2: "n - ?j = 1" by simp_all
  from this(1) have "(1::int) = (- 1)^(n - Suc ?j) * ((int d - 1) gchoose (n - Suc ?j)) +
                    (- 1)^(n - ?j) * ((int d - 1) gchoose (n - ?j)) - 1 -
                    (i=Suc ?j..n. (- 1)^(i - ?j) * ((int (aa i) gchoose (i - ?j)) + (int (bb i) gchoose (i - ?j))))"
    by (rule dube_eq_3)
  hence eq: "aa n + bb n = d" by (simp add: eq1 eq2)
  hence "aa n  d" by simp
  moreover have "d  aa n" unfolding aa_Suc_n[symmetric] aa_def using fin_X by (rule 𝖻_decreasing) simp
  ultimately show "aa n = d" by (rule antisym)
  with eq show "bb n = 0" by simp

  have "bb 0 = 𝖻 qs 0" by (simp only: bb_def)
  also from fin_X have "  max (aa 1) (bb 1)" (is "_  ?m")
  proof (rule 𝖻_le)
    from fin_X ext_qs have "𝖺 qs = bb (Suc n)" by (simp add: 𝖻_card_X bb_def)
    also have "  bb 1" unfolding bb_def using fin_X by (rule 𝖻_decreasing) simp
    also have "  ?m" by (rule max.cobounded2)
    finally show "𝖺 qs  ?m" .
  next
    fix h U
    assume "(h, U)  set qs"
    show "poly_deg h < ?m"
    proof (cases "card U = 0")
      case True
      from fin_X valid_qs (h, U)  set qs have "finite U" by (rule valid_decompD_finite)
      with True have "U = {}" by simp
      with (h, U)  set qs have "(h, {})  set ps  set qs" by simp
      thus ?thesis by (rule dube_aux_1)
    next
      case False
      hence "1  card U" by simp
      with fin_X (h, U)  set qs have "poly_deg h < bb 1" unfolding bb_def by (rule 𝖻)
      also have "  ?m" by (rule max.cobounded2)
      finally show ?thesis .
    qed
  qed
  finally show "bb 0  ?m" .
qed

lemma dube_eq_4:
  assumes "j < n"
  shows "(1::int) = 2 * (- 1)^(n - Suc j) * ((int d - 1) gchoose (n - Suc j)) - 1 -
                    (i=Suc j..n-1. (- 1)^(i - j) * ((int (aa i) gchoose (i - j)) + (int (bb i) gchoose (i - j))))"
proof -
  from assms have "Suc j  n" and "0 < n" and 1: "Suc (n - Suc j) = n - j" by simp_all
  have 2: "(- 1) ^ (n - Suc j) = - ((- (1::int)) ^ (n - j))" by (simp flip: 1)
  from assms have "(1::int) = (- 1)^(n - Suc j) * ((int d - 1) gchoose (n - Suc j)) +
                    (- 1)^(n - j) * ((int d - 1) gchoose (n - j)) - 1 -
                    (i=Suc j..n. (- 1)^(i - j) * ((int (aa i) gchoose (i - j)) + (int (bb i) gchoose (i - j))))"
    by (rule dube_eq_3)
  also have " = (- 1)^(n - Suc j) * ((int d - 1) gchoose (n - Suc j)) +
                    (- 1)^(n - j) * ((int d - 1) gchoose (n - j)) - 1 -
                    (- 1)^(n - j) * ((int (aa n) gchoose (n - j)) + (int (bb n) gchoose (n - j))) -
                    (i=Suc j..n-1. (- 1)^(i - j) * ((int (aa i) gchoose (i - j)) + (int (bb i) gchoose (i - j))))"
    using 0 < n Suc j  n by (simp only: sum_tail_nat)
  also have " = (- 1)^(n - Suc j) * ((int d - 1) gchoose (n - Suc j)) +
                    (- 1)^(n - j) * (((int d - 1) gchoose (n - j)) - (int d gchoose (n - j))) - 1 -
                    (i=Suc j..n-1. (- 1)^(i - j) * ((int (aa i) gchoose (i - j)) + (int (bb i) gchoose (i - j))))"
    using assms by (simp add: aa_n bb_n gbinomial_0_left right_diff_distrib)
  also have "(- 1)^(n - j) * (((int d - 1) gchoose (n - j)) - (int d gchoose (n - j))) =
              (- 1)^(n - Suc j) * (((int d - 1 + 1) gchoose (Suc (n - Suc j))) - ((int d - 1) gchoose (Suc (n - Suc j))))"
    by (simp add: 1 2 flip: mult_minus_right)
  also have " = (- 1)^(n - Suc j) * ((int d - 1) gchoose (n - Suc j))"
    by (simp only: gbinomial_int_Suc_Suc, simp)
  finally show ?thesis by simp
qed

lemma cc_Suc:
  assumes "j < n - 1"
  shows "int (cc (Suc j)) = 2 + 2 * (- 1)^(n - j) * ((int d - 1) gchoose (n - Suc j)) +
                   (i=j+2..n-1. (- 1)^(i - j) * ((int (aa i) gchoose (i - j)) + (int (bb i) gchoose (i - j))))"
proof -
  from assms have "j < n" and "Suc j  n - 1" by simp_all
  hence "n - j = Suc (n - Suc j)" by simp
  hence eq: "(- 1) ^ (n - Suc j) = - ((- (1::int)) ^ (n - j))" by simp
  from j < n have "(1::int) = 2 * (- 1)^(n - Suc j) * ((int d - 1) gchoose (n - Suc j)) - 1 -
             (i=Suc j..n-1. (- 1)^(i - j) * ((int (aa i) gchoose (i - j)) + (int (bb i) gchoose (i - j))))"
    by (rule dube_eq_4)
  also have " = cc (Suc j) - 2 * (- 1)^(n - j) * ((int d - 1) gchoose (n - Suc j)) - 1 -
             (i=j+2..n-1. (- 1)^(i - j) * ((int (aa i) gchoose (i - j)) + (int (bb i) gchoose (i - j))))"
    using Suc j  n - 1 by (simp add: sum.atLeast_Suc_atMost eq)
  finally show ?thesis by simp
qed

lemma cc_n_minus_1: "cc (n - 1) = 2 * d"
proof -
  let ?j = "n - 2"
  from n_gr_1 have 1: "Suc ?j = n - 1" and "?j < n - 1" and 2: "Suc (n - 1) = n"
    and 3: "n - (n - Suc 0) = Suc 0" and 4: "n - ?j = 2"
    by simp_all
  have "int (cc (n - 1)) = int (cc (Suc ?j))" by (simp only: 1)
  also from ?j < n - 1 have " = 2 + 2 * (- 1) ^ (n - ?j) * (int d - 1 gchoose (n - Suc ?j)) +
         (i = ?j+2..n-1. (- 1) ^ (i - ?j) * (int (aa i) gchoose (i - ?j) + (int (bb i) gchoose (i - ?j))))"
    by (rule cc_Suc)
  also have " = int (2 * d)" by (simp add: 1 2 3 4)
  finally show ?thesis by (simp only: int_int_eq)
qed

text ‹Since the case @{prop "n = 2"} is settled, we can concentrate on @{prop "2 < n"} now.›

context
  assumes n_gr_2: "2 < n"
begin

lemma cc_n_minus_2: "cc (n - 2)  d2 + 2 * d"
proof -
  let ?j = "n - 3"
  from n_gr_2 have 1: "Suc ?j = n - 2" and "?j < n - 1" and 2: "Suc (n - 2) = n - Suc 0"
    and 3: "n - (n - 2) = 2" and 4: "n - ?j = 3"
    by simp_all
  have "int (cc (n - 2)) = int (cc (Suc ?j))" by (simp only: 1)
  also from ?j < n - 1 have " = 2 + 2 * (- 1) ^ (n - ?j) * (int d - 1 gchoose (n - Suc ?j)) +
         (i = ?j+2..n-1. (- 1) ^ (i - ?j) * (int (aa i) gchoose (i - ?j) + (int (bb i) gchoose (i - ?j))))"
    by (rule cc_Suc)
  also have " = (2 - 2 * (int d - 1 gchoose 2)) + ((int (aa (n - 1)) gchoose 2) + (int (bb (n - 1)) gchoose 2))"
    by (simp add: 1 2 3 4)
  also have "  (2 - 2 * (int d - 1 gchoose 2)) + (2 * int d gchoose 2)"
  proof (rule add_left_mono)
    have "int (aa (n - 1)) gchoose 2 + (int (bb (n - 1)) gchoose 2)  int (aa (n - 1)) + int (bb (n - 1)) gchoose 2"
      by (rule gbinomial_int_plus_le) simp_all
    also have " = int (2 * d) gchoose 2"  by (simp flip: cc_n_minus_1)
    also have " = 2 * int d gchoose 2"  by (simp add: int_ops(7))
    finally show "int (aa (n - 1)) gchoose 2 + (int (bb (n - 1)) gchoose 2)  2 * int d gchoose 2" .
  qed
  also have " = 2 - fact 2 * (int d - 1 gchoose 2) + (2 * int d gchoose 2)" by (simp only: fact_2)
  also have " = 2 - (int d - 1) * (int d - 2) + (2 * int d gchoose 2)"
    by (simp only: gbinomial_int_mult_fact) (simp add: numeral_2_eq_2 prod.atLeast0_lessThan_Suc)
  also have " = 2 - (int d - 1) * (int d - 2) + int d * (2 * int d - 1)"
    by (simp add: gbinomial_prod_rev numeral_2_eq_2 prod.atLeast0_lessThan_Suc)
  also have " = int (d2 + 2 * d)" by (simp add: power2_eq_square) (simp only: algebra_simps)
  finally show ?thesis by (simp only: int_int_eq)
qed

lemma cc_Suc_le:
  assumes "j < n - 3"
  shows "int (cc (Suc j))  2 + (int (cc (j + 2)) gchoose 2) + (i=j+4..n-1. int (cc i) gchoose (i - j))"
            ―‹Could be proved without coercing to @{typ int}, because everything is non-negative.›
proof -
  let ?f = "λi j. (int (aa i) gchoose (i - j)) + (int (bb i) gchoose (i - j))"
  let ?S = "λx y. (i=j+x..n-y. (- 1)^(i - j) * ?f i j)"
  let ?S3 = "λx y. (i=j+x..n-y. (int (cc i) gchoose (i - j)))"
  have ie1: "int (aa i) gchoose k + (int (bb i) gchoose k)  int (cc i) gchoose k" if "0 < k" for i k
  proof -
    from that have "int (aa i) gchoose k + (int (bb i) gchoose k)  int (aa i) + int (bb i) gchoose k"
      by (rule gbinomial_int_plus_le) simp_all
    also have " = int (cc i) gchoose k" by simp
    finally show ?thesis .
  qed
  from d_gr_0 have "0  int d - 1" by simp
  from assms have "0 < n - Suc j" by simp
  have f_nonneg: "0  ?f i j" for i by (simp add: gbinomial_int_nonneg)

  show ?thesis
  proof (cases "n = j + 4")
    case True
    hence j: "j = n - 4" by simp
    have 1: "n - Suc j = 3" and "j < n - 1" and 2: "Suc (n - 3) = Suc (Suc j)" and 3: "n - (n - 3) = 3"
      and 4: "n - j = 4" and 5: "n - Suc 0 = Suc (Suc (Suc j))" and 6: "n - 2 = Suc (Suc j)"
      by (simp_all add: True)
    from j < n - 1 have "int (cc (Suc j)) = 2 + 2 * (- 1) ^ (n - j) * (int d - 1 gchoose (n - Suc j)) +
           (i = j+2..n-1. (- 1) ^ (i - j) * (int (aa i) gchoose (i - j) + (int (bb i) gchoose (i - j))))"
      by (rule cc_Suc)
    also have " = (2 + ((int (aa (n - 2)) gchoose 2) + (int (bb (n - 2)) gchoose 2))) +
                    (2 * (int d - 1 gchoose 3) - ((int (aa (n - 1)) gchoose 3) + (int (bb (n - 1)) gchoose 3)))"
      by (simp add: 1 2 3 4 5 6)
    also have "  (2 + ((int (aa (n - 2)) gchoose 2) + (int (bb (n - 2)) gchoose 2))) + 0"
    proof (rule add_left_mono)
      from cc_n_minus_1 have eq1: "int (aa (n - 1)) + int (bb (n - 1)) = 2 * int d" by simp
      hence ie2: "int (aa (n - 1))  2 * int d" by simp
      from 0  int d - 1 have "int d - 1 gchoose 3  int d gchoose 3" by (rule gbinomial_int_mono) simp
      hence "2 * (int d - 1 gchoose 3)  2 * (int d gchoose 3)" by simp
      also from _ ie2 have "  int (aa (n - 1)) gchoose 3 + (2 * int d - int (aa (n - 1)) gchoose 3)"
        by (rule binomial_int_ineq_3) simp
      also have " = int (aa (n - 1)) gchoose 3 + (int (bb (n - 1)) gchoose 3)" by (simp flip: eq1)
      finally show "2 * (int d - 1 gchoose 3) - (int (aa (n - 1)) gchoose 3 + (int (bb (n - 1)) gchoose 3))  0"
        by simp
    qed
    also have " = 2 + ((int (aa (n - 2)) gchoose 2) + (int (bb (n - 2)) gchoose 2))" by simp
    also from ie1 have "  2 + (int (cc (n - 2)) gchoose 2)" by (rule add_left_mono) simp
    also have " = 2 + (int (cc (j + 2)) gchoose 2) + ?S3 4 1" by (simp add: True)
    finally show ?thesis .
  next
    case False
    with assms have "j + 4  n - 1" by simp
    from n_gr_1 have "0 < n - 1" by simp
    from assms have "j + 2  n - 1" and "j + 2  n - 2" by simp_all
    hence "n - j = Suc (n - Suc j)" by simp
    hence 1: "(- 1) ^ (n - Suc j) = - ((- (1::int)) ^ (n - j))" by simp
    from assms have "j < n - 1" by simp
    hence "int (cc (Suc j)) = 2 + 2 * (- 1)^(n - j) * ((int d - 1) gchoose (n - Suc j)) + ?S 2 1"
      by (rule cc_Suc)
    also have " = 2 * (- 1)^(n - j) * ((int d - 1) gchoose (n - Suc j)) +
                    (- 1)^(n - Suc j) * ((int (aa (n - 1)) gchoose (n - Suc j)) + (int (bb (n - 1)) gchoose (n - Suc j))) +
                    (2 + ?S 2 2)"
      using 0 < n - 1 j + 2  n - 1 by (simp only: sum_tail_nat) (simp flip: numeral_2_eq_2)
    also have "  (int (cc (n - 1)) gchoose (n - Suc j)) + (2 + ?S 2 2)"
    proof (rule add_right_mono)
      have rl: "x - y  x" if "0  y" for x y :: int using that by simp
      have "2 * (- 1)^(n - j) * ((int d - 1) gchoose (n - Suc j)) +
                    (- 1)^(n - Suc j) * ((int (aa (n - 1)) gchoose (n - Suc j)) + (int (bb (n - 1)) gchoose (n - Suc j))) =
              (-1)^(n - j) * (2 * ((int d - 1) gchoose (n - Suc j)) -
                    (int (aa (n - 1)) gchoose (n - Suc j)) - (int (bb (n - 1)) gchoose (n - Suc j)))"
        by (simp only: 1 algebra_simps)
      also have "  (int (cc (n - 1))) gchoose (n - Suc j)"
      proof (cases "even (n - j)")
        case True
        hence "(- 1) ^ (n - j) * (2 * (int d - 1 gchoose (n - Suc j)) - (int (aa (n - 1)) gchoose (n - Suc j)) -
                (int (bb (n - 1)) gchoose (n - Suc j))) =
              2 * (int d - 1 gchoose (n - Suc j)) - ((int (aa (n - 1)) gchoose (n - Suc j)) +
                                                     (int (bb (n - 1)) gchoose (n - Suc j)))"
          by simp
        also have "  2 * (int d - 1 gchoose (n - Suc j))" by (rule rl) (simp add: gbinomial_int_nonneg)
        also have " = (int d - 1 gchoose (n - Suc j)) + (int d - 1 gchoose (n - Suc j))" by simp
        also have "  (int d - 1) + (int d - 1) gchoose (n - Suc j)"
          using 0 < n - Suc j 0  int d - 1 0  int d - 1 by (rule gbinomial_int_plus_le)
        also have "  2 * int d gchoose (n - Suc j)"
        proof (rule gbinomial_int_mono)
          from 0  int d - 1 show "0  int d - 1 + (int d - 1)" by simp
        qed simp
        also have " = int (cc (n - 1)) gchoose (n - Suc j)" by (simp only: cc_n_minus_1) simp
        finally show ?thesis .
      next
        case False
        hence "(- 1) ^ (n - j) * (2 * (int d - 1 gchoose (n - Suc j)) - (int (aa (n - 1)) gchoose (n - Suc j)) -
                (int (bb (n - 1)) gchoose (n - Suc j))) =
              ((int (aa (n - 1)) gchoose (n - Suc j)) + (int (bb (n - 1)) gchoose (n - Suc j))) -
                2 * (int d - 1 gchoose (n - Suc j))"
          by simp
        also have "  (int (aa (n - 1)) gchoose (n - Suc j)) + (int (bb (n - 1)) gchoose (n - Suc j))"
          by (rule rl) (simp add: gbinomial_int_nonneg d_gr_0)
        also from 0 < n - Suc j have "  int (cc (n - 1)) gchoose (n - Suc j)" by (rule ie1)
        finally show ?thesis .
      qed
      finally show "2 * (- 1)^(n - j) * ((int d - 1) gchoose (n - Suc j)) +
                    (- 1)^(n - Suc j) * ((int (aa (n - 1)) gchoose (n - Suc j)) + (int (bb (n - 1)) gchoose (n - Suc j))) 
                    (int (cc (n - 1))) gchoose (n - Suc j)" .
    qed
    also have " = 2 + (int (cc (n - 1)) gchoose ((n - 1) - j)) + ((int (aa (j + 2)) gchoose 2) +
                    (int (bb (j + 2)) gchoose 2)) + ?S 3 2"
      using j + 2  n - 2 by (simp add: sum.atLeast_Suc_atMost numeral_3_eq_3)
    also have "  2 + (int (cc (n - 1)) gchoose ((n - 1) - j)) + ((int (aa (j + 2)) gchoose 2) +
                    (int (bb (j + 2)) gchoose 2)) + ?S3 4 2"
    proof (rule add_left_mono)
      from j + 4  n - 1 have "j + 3  n - 2" by simp
      hence "?S 3 2 = ?S 4 2 - ?f (j + 3) j" by (simp add: sum.atLeast_Suc_atMost add.commute)
      hence "?S 3 2  ?S 4 2" using f_nonneg[of "j + 3"] by simp
      also have "  ?S3 4 2"
      proof (rule sum_mono)
        fix i
        assume "i  {j + 4..n - 2}"
        hence "0 < i - j" by simp
        from f_nonneg[of i] have "(- 1)^(i - j) * ?f i j  ?f i j"
          by (smt minus_one_mult_self mult_cancel_right1 pos_zmult_eq_1_iff_lemma zero_less_mult_iff)
        also from 0 < i - j have "  int (cc i) gchoose (i - j)" by (rule ie1)
        finally show "(- 1)^(i - j) * ?f i j  int (cc i) gchoose (i - j)" .
      qed
      finally show "?S 3 2  ?S3 4 2" .
    qed
    also have " = ((int (aa (j + 2)) gchoose 2) + (int (bb (j + 2)) gchoose 2)) + (2 + ?S3 4 1)"
      using 0 < n - 1 j + 4  n - 1 by (simp only: sum_tail_nat) (simp flip: numeral_2_eq_2)
    also from ie1 have "  int (cc (j + 2)) gchoose 2 + (2 + ?S3 4 1)"
      by (rule add_right_mono) simp
    also have " = 2 + (int (cc (j + 2)) gchoose 2) + ?S3 4 1" by (simp only: ac_simps)
    finally show ?thesis .
  qed
qed

corollary cc_le:
  assumes "0 < j" and "j < n - 2"
  shows "cc j  2 + (cc (j + 1) choose 2) + (i=j+3..n-1. cc i choose (Suc (i - j)))"
proof -
  define j0 where "j0 = j - 1"
  with assms have j: "j = Suc j0" and "j0 < n - 3" by simp_all
  have "int (cc j) = int (cc (Suc j0))" by (simp only: j)
  also have "  2 + (int (cc (j0 + 2)) gchoose 2) + (i=j0+4..n-1. int (cc i) gchoose (i - j0))"
    using j0 < n - 3 by (rule cc_Suc_le)
  also have " = 2 + (int (cc (j + 1)) gchoose 2) + (i=j0+4..n-1. int (cc i) gchoose (i - j0))"
    by (simp add: j)
  also have "(i=j0+4..n-1. int (cc i) gchoose (i - j0)) = int (i=j+3..n-1. cc i choose (Suc (i - j)))"
    unfolding int_sum
  proof (rule sum.cong)
    fix i
    assume "i  {j + 3..n - 1}"
    hence "Suc j0 < i" by (simp add: j)
    hence "i - j0 = Suc (i - j)" by (simp add: j)
    thus "int (cc i) gchoose (i - j0) = int (cc i choose (Suc (i - j)))" by (simp add: int_binomial)
  qed (simp add: j)
  finally have "int (cc j)  int (2 + (cc (j + 1) choose 2) + (i = j + 3..n - 1. cc i choose (Suc (i - j))))"
    by (simp only: int_plus int_binomial)
  thus ?thesis by (simp only: zle_int)
qed

corollary cc_le_Dube_aux: "0 < j  j + 1  n  cc j  Dube_aux n d j"
proof (induct j rule: Dube_aux.induct[where n=n])
  case step: (1 j)
  from step.prems(2) have "j + 2 < n  j + 2 = n  j + 1 = n" by auto
  thus ?case
  proof (elim disjE)
    assume *: "j + 2 < n"
    moreover have "0 < j + 1" by simp
    moreover from * have "j + 1 + 1  n" by simp
    ultimately have "cc (j + 1)  Dube_aux n d (j + 1)" by (rule step.hyps)
    hence 1: "cc (j + 1) choose 2  Dube_aux n d (j + 1) choose 2"
      by (rule Binomial_Int.binomial_mono)
    have 2: "(i = j + 3..n - 1. cc i choose Suc (i - j)) 
              (i = j + 3..n - 1. Dube_aux n d i choose Suc (i - j))"
    proof (rule sum_mono)
      fix i::nat
      note *
      moreover assume "i  {j + 3..n - 1}"
      moreover from this 2 < n have "0 < i" and "i + 1  n" by auto
      ultimately have "cc i  Dube_aux n d i" by (rule step.hyps)
      thus "cc i choose Suc (i - j)  Dube_aux n d i choose Suc (i - j)"
        by (rule Binomial_Int.binomial_mono)
    qed
    from * have "j < n - 2" by simp
    with step.prems(1) have "cc j  2 + (cc (j + 1) choose 2) + (i = j + 3..n - 1. cc i choose Suc (i - j))"
      by (rule cc_le)
    also from * 1 2 have "  Dube_aux n d j" by simp
    finally show ?thesis .
  next
    assume "j + 2 = n"
    hence "j = n - 2" and "Dube_aux n d j = d2 + 2 * d" by simp_all
    thus ?thesis by (simp only: cc_n_minus_2)
  next
    assume "j + 1 = n"
    hence "j = n - 1" and "Dube_aux n d j = 2 * d" by simp_all
    thus ?thesis by (simp only: cc_n_minus_1)
  qed
qed

end

lemma Dube_aux:
  assumes "g  punit.reduced_GB F"
  shows "poly_deg g  Dube_aux n d 1"
proof (cases "n = 2")
  case True
  from assms have "poly_deg g  bb 0" by (rule deg_RGB)
  also have "  max (aa 1) (bb 1)" by (fact bb_0)
  also have "  cc (n - 1)" by (simp add: True)
  also have " = 2 * d" by (fact cc_n_minus_1)
  also have " = Dube_aux n d 1" by (simp add: True)
  finally show ?thesis .
next
  case False
  with 1 < n have "2 < n" and "1 + 1  n" by simp_all
  from assms have "poly_deg g  bb 0" by (rule deg_RGB)
  also have "  max (aa 1) (bb 1)" by (fact bb_0)
  also have "  cc 1" by simp
  also from 2 < n _ 1 + 1  n have "  Dube_aux n d 1" by (rule cc_le_Dube_aux) simp
  finally show ?thesis .
qed

end

theorem Dube:
  assumes "finite F" and "F  P[X]" and "f. f  F  homogeneous f" and "g  punit.reduced_GB F"
  shows "poly_deg g  Dube (card X) (maxdeg F)"
proof (cases "F  {0}")
  case True
  hence "F = {}  F = {0}" by blast
  with assms(4) show ?thesis by (auto simp: punit.reduced_GB_empty punit.reduced_GB_singleton)
next
  case False
  hence "F - {0}  {}" by simp
  hence "F  {}" by blast
  hence "poly_deg ` F  {}" by simp
  from assms(1) have fin1: "finite (poly_deg ` F)" by (rule finite_imageI)
  from assms(1) have "finite (F - {0})" by simp
  hence fin: "finite (poly_deg ` (F - {0}))" by (rule finite_imageI)
  moreover from F - {0}  {} have *: "poly_deg ` (F - {0})  {}" by simp
  ultimately have "maxdeg (F - {0})  poly_deg ` (F - {0})" unfolding maxdeg_def by (rule Max_in)
  then obtain f where "f  F - {0}" and md1: "maxdeg (F - {0}) = poly_deg f" ..
  note this(2)
  moreover have "maxdeg (F - {0})  maxdeg F"
    unfolding maxdeg_def using image_mono * fin1 by (rule Max_mono) blast
  ultimately have "poly_deg f  maxdeg F" by simp
  from f  F - {0} have "f  F" and "f  0" by simp_all
  from this(1) assms(2) have "f  P[X]" ..
  have f_max: "poly_deg f'  poly_deg f" if "f'  F" for f'
  proof (cases "f' = 0")
    case True
    thus ?thesis by simp
  next
    case False
    with that have "f'  F - {0}" by simp
    hence "poly_deg f'  poly_deg ` (F - {0})" by (rule imageI)
    with fin show "poly_deg f'  poly_deg f" unfolding md1[symmetric] maxdeg_def by (rule Max_ge)
  qed
  have "maxdeg F  poly_deg f" unfolding maxdeg_def using fin1 poly_deg ` F  {}
  proof (rule Max.boundedI)
    fix d
    assume "d  poly_deg ` F"
    then obtain f' where "f'  F" and "d = poly_deg f'" ..
    note this(2)
    also from f'  F have "poly_deg f'  poly_deg f" by (rule f_max)
    finally show "d  poly_deg f" .
  qed
  with poly_deg f  maxdeg F have md: "poly_deg f = maxdeg F" by (rule antisym)
  show ?thesis
  proof (cases "ideal {f} = ideal F")
    case True
    note assms(4)
    also have "punit.reduced_GB F = punit.reduced_GB {f}"
      using punit.finite_reduced_GB_finite punit.reduced_GB_is_reduced_GB_finite
      by (rule punit.reduced_GB_unique) (simp_all add: punit.reduced_GB_pmdl_finite[simplified] True)
    also have "  {punit.monic f}" by (simp add: punit.reduced_GB_singleton)
    finally have "g  {punit.monic f}" .
    hence "poly_deg g = poly_deg (punit.monic f)" by simp
    also from poly_deg_monom_mult_le[where c="1 / lcf f" and t=0 and p=f] have "  poly_deg f"
      by (simp add: punit.monic_def)
    also have " = maxdeg F" by (fact md)
    also have "  Dube (card X) (maxdeg F)" by (fact Dube_ge_d)
    finally show ?thesis .
  next
    case False
    show ?thesis
    proof (cases "poly_deg f = 0")
      case True
      hence "monomial (lookup f 0) 0 = f" by (rule poly_deg_zero_imp_monomial)
      moreover define c where "c = lookup f 0"
      ultimately have f: "f = monomial c 0" by simp
      with f  0 have "c  0" by (simp add: monomial_0_iff)
      from f  F have "f  ideal F" by (rule ideal.span_base)
      hence "punit.monom_mult (1 / c) 0 f  ideal F" by (rule punit.pmdl_closed_monom_mult[simplified])
      with c  0 have "ideal F = UNIV"
        by (simp add: f punit.monom_mult_monomial ideal_eq_UNIV_iff_contains_one)
      with assms(1) have "punit.reduced_GB F = {1}"
        by (simp only: ideal_eq_UNIV_iff_reduced_GB_eq_one_finite)
      with assms(4) show ?thesis by simp
    next
      case False
      hence "0 < poly_deg f" by simp
      have "card X  1  1 < card X" by auto
      thus ?thesis
      proof
        note fin_X
        moreover assume "card X  1"
        moreover note assms(2)
        moreover from f  F have "f  ideal F" by (rule ideal.span_base)
        ultimately have "poly_deg g  poly_deg f"
          using f  0 assms(4) by (rule deg_reduced_GB_univariate_le)
        also have "  Dube (card X) (maxdeg F)" unfolding md by (fact Dube_ge_d)
        finally show ?thesis .
      next
        assume "1 < card X"
        hence "poly_deg g  Dube_aux (card X) (poly_deg f) 1"
          using assms(1, 2) f  F assms(3) f_max 0 < poly_deg f ideal {f}  ideal F assms(4)
          by (rule Dube_aux)
        also from 1 < card X 0 < poly_deg f have " = Dube (card X) (maxdeg F)"
          by (simp add: Dube_def md)
        finally show ?thesis .
      qed
    qed
  qed
qed

corollary Dube_is_hom_GB_bound:
  "finite F  F  P[X]  is_hom_GB_bound F (Dube (card X) (maxdeg F))"
  by (intro is_hom_GB_boundI Dube)

end

corollary Dube_indets:
  assumes "finite F" and "f. f  F  homogeneous f" and "g  punit.reduced_GB F"
  shows "poly_deg g  Dube (card ((indets ` F))) (maxdeg F)"
  using _ assms(1) _ assms(2, 3)
proof (rule Dube)
  from assms show "finite ((indets ` F))" by (simp add: finite_indets)
next
  show "F  P[(indets ` F)]" by (auto simp: Polys_alt)
qed

corollary Dube_is_hom_GB_bound_indets:
  "finite F  is_hom_GB_bound F (Dube (card ((indets ` F))) (maxdeg F))"
  by (intro is_hom_GB_boundI Dube_indets)

end (* pm_powerprod *)

hide_const (open) pm_powerprod.𝖺 pm_powerprod.𝖻

context extended_ord_pm_powerprod
begin

lemma Dube_is_GB_cofactor_bound:
  assumes "finite X" and "finite F" and "F  P[X]"
  shows "is_GB_cofactor_bound F (Dube (Suc (card X)) (maxdeg F))"
  using assms(1, 3)
proof (rule hom_GB_bound_is_GB_cofactor_bound)
  let ?F = "homogenize None ` extend_indets ` F"
  let ?X = "insert None (Some ` X)"
  from assms(1) have "finite ?X" by simp
  moreover from assms(2) have "finite ?F" by (intro finite_imageI)
  moreover have "?F  P[?X]"
  proof
    fix f'
    assume "f'  ?F"
    then obtain f where "f  F" and f': "f' = homogenize None (extend_indets f)" by blast
    from this(1) assms(3) have "f  P[X]" ..
    hence "extend_indets f  P[Some ` X]" by (auto simp: Polys_alt indets_extend_indets)
    thus "f'  P[?X]" unfolding f' by (rule homogenize_in_Polys)
  qed
  ultimately have "extended_ord.is_hom_GB_bound ?F (Dube (card ?X) (maxdeg ?F))"
    by (rule extended_ord.Dube_is_hom_GB_bound)
  moreover have "maxdeg ?F = maxdeg F"
  proof -
    have "maxdeg ?F = maxdeg (extend_indets ` F)"
      by (auto simp: indets_extend_indets intro: maxdeg_homogenize)
    also have " = maxdeg F" by (simp add: maxdeg_def image_image)
    finally show "maxdeg ?F = maxdeg F" .
  qed
  moreover from assms(1) have "card ?X = card X + 1" by (simp add: card_image)
  ultimately show "extended_ord.is_hom_GB_bound ?F (Dube (Suc (card X)) (maxdeg F))" by simp
qed

lemma Dube_is_GB_cofactor_bound_explicit:
  assumes "finite X" and "finite F" and "F  P[X]"
  obtains G where "punit.is_Groebner_basis G" and "ideal G = ideal F" and "G  P[X]"
    and "g. g  G  q. g = (fF. q f * f) 
                            (f. q f  P[X]  poly_deg (q f * f)  Dube (Suc (card X)) (maxdeg F) 
                              (f  F  q f = 0))"
proof -
  from assms have "is_GB_cofactor_bound F (Dube (Suc (card X)) (maxdeg F))"
    (is "is_GB_cofactor_bound _ ?b") by (rule Dube_is_GB_cofactor_bound)
  moreover note assms(3)
  ultimately obtain G where "punit.is_Groebner_basis G" and "ideal G = ideal F" and "G  P[X]"
    and 1: "g. g  G  F' q. finite F'  F'  F  g = (fF'. q f * f) 
                              (f. q f  P[X]  poly_deg (q f * f)  ?b  (f  F'  q f = 0))"
    by (rule is_GB_cofactor_boundE_Polys) blast
  from this(1-3) show ?thesis
  proof
    fix g
    assume "g  G"
    hence "F' q. finite F'  F'  F  g = (fF'. q f * f) 
                              (f. q f  P[X]  poly_deg (q f * f)  ?b  (f  F'  q f = 0))"
      by (rule 1)
    then obtain F' q where "F'  F" and g: "g = (fF'. q f * f)" and "f. q f  P[X]"
      and "f. poly_deg (q f * f)  ?b" and 2: "f. f  F'  q f = 0" by blast
    show "q. g = (fF. q f * f)  (f. q f  P[X]  poly_deg (q f * f)  ?b  (f  F  q f = 0))"
    proof (intro exI allI conjI impI)
      from assms(2) F'  F have "(fF'. q f * f) = (fF. q f * f)"
      proof (intro sum.mono_neutral_left ballI)
        fix f
        assume "f  F - F'"
        hence "f  F'" by simp
        hence "q f = 0" by (rule 2)
        thus "q f * f = 0" by simp
      qed
      thus "g = (fF. q f * f)" by (simp only: g)
    next
      fix f
      assume "f  F"
      with F'  F have "f  F'" by blast
      thus "q f = 0" by (rule 2)
    qed fact+
  qed
qed

corollary Dube_is_GB_cofactor_bound_indets:
  assumes "finite F"
  shows "is_GB_cofactor_bound F (Dube (Suc (card ((indets ` F)))) (maxdeg F))"
  using _ assms _
proof (rule Dube_is_GB_cofactor_bound)
  from assms show "finite ((indets ` F))" by (simp add: finite_indets)
next
  show "F  P[(indets ` F)]" by (auto simp: Polys_alt)
qed

end (* extended_ord_pm_powerprod *)

end (* theory *)