Theory Cone_Decomposition

(* Author: Alexander Maletzky *)

section ‹Cone Decompositions›

theory Cone_Decomposition
  imports Groebner_Bases.Groebner_PM Monomial_Module Hilbert_Function
begin

subsection ‹More Properties of Reduced Gr\"obner Bases›

context pm_powerprod
begin

lemmas reduced_GB_subset_monic_Polys =
  punit.reduced_GB_subset_monic_dgrad_p_set[simplified, OF dickson_grading_varnum, where m=0, simplified dgrad_p_set_varnum]
lemmas reduced_GB_is_monomial_set_Polys =
  punit.reduced_GB_is_monomial_set_dgrad_p_set[simplified, OF dickson_grading_varnum, where m=0, simplified dgrad_p_set_varnum]
lemmas is_red_reduced_GB_monomial_lt_GB_Polys =
  punit.is_red_reduced_GB_monomial_lt_GB_dgrad_p_set[simplified, OF dickson_grading_varnum, where m=0, simplified dgrad_p_set_varnum]
lemmas reduced_GB_monomial_lt_reduced_GB_Polys =
  punit.reduced_GB_monomial_lt_reduced_GB_dgrad_p_set[simplified, OF dickson_grading_varnum, where m=0, simplified dgrad_p_set_varnum]

end

subsection ‹Quotient Ideals›

definition quot_set :: "'a set ⇒ 'a ⇒ 'a::semigroup_mult set" (infixl ‹÷› 55)
  where "quot_set A x = (*) x -` A"

lemma quot_set_iff: "a ∈ A ÷ x ⟷ x * a ∈ A"
  by (simp add: quot_set_def)

lemma quot_setI: "x * a ∈ A ⟹ a ∈ A ÷ x"
  by (simp only: quot_set_iff)

lemma quot_setD: "a ∈ A ÷ x ⟹ x * a ∈ A"
  by (simp only: quot_set_iff)

lemma quot_set_quot_set [simp]: "A ÷ x ÷ y = A ÷ x * y"
  by (rule set_eqI) (simp add: quot_set_iff mult.assoc)

lemma quot_set_one [simp]: "A ÷ (1::_::monoid_mult) = A"
  by (rule set_eqI) (simp add: quot_set_iff)

lemma ideal_quot_set_ideal [simp]: "ideal (ideal B ÷ x) = (ideal B) ÷ (x::_::comm_ring)"
proof
  show "ideal (ideal B ÷ x) ⊆ ideal B ÷ x"
  proof
    fix b
    assume "b ∈ ideal (ideal B ÷ x)"
    thus "b ∈ ideal B ÷ x"
    proof (induct b rule: ideal.span_induct')
      case base
      show ?case by (simp add: quot_set_iff ideal.span_zero)
    next
      case (step b q p)
      hence "x * b ∈ ideal B" and "x * p ∈ ideal B" by (simp_all add: quot_set_iff)
      hence "x * b + q * (x * p) ∈ ideal B"
        by (intro ideal.span_add ideal.span_scale[where c=q])
      thus ?case by (simp only: quot_set_iff algebra_simps)
    qed
  qed
qed (fact ideal.span_superset)

lemma quot_set_image_times: "inj ((*) x) ⟹ ((*) x ` A) ÷ x = A"
  by (simp add: quot_set_def inj_vimage_image_eq)

subsection ‹Direct Decompositions of Polynomial Rings›

context pm_powerprod
begin

definition normal_form :: "(('x ⇒0 nat) ⇒0 'a) set ⇒ (('x ⇒0 nat) ⇒0 'a::field) ⇒ (('x ⇒0 nat) ⇒0 'a::field)"
  where "normal_form F p = (SOME q. (punit.red (punit.reduced_GB F))** p q ∧ ¬ punit.is_red (punit.reduced_GB F) q)"

text ‹Of course, @{const normal_form} could be defined in a much more general context.›

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

context
  fixes F :: "(('x ⇒0 nat) ⇒0 'a::field) set"
  assumes F_sub: "F ⊆ P[X]"
begin

lemma normal_form:
  shows "(punit.red (punit.reduced_GB F))** p (normal_form F p)" (is ?thesis1)
    and "¬ punit.is_red (punit.reduced_GB F) (normal_form F p)" (is ?thesis2)
proof -
  from fin_X F_sub have "finite (punit.reduced_GB F)" by (rule finite_reduced_GB_Polys)
  hence "wfP (punit.red (punit.reduced_GB F))¯¯" by (rule punit.red_wf_finite)
  then obtain q where "(punit.red (punit.reduced_GB F))** p q"
    and "¬ punit.is_red (punit.reduced_GB F) q" unfolding punit.is_red_def not_not
    by (rule relation.wf_imp_nf_ex)
  hence "(punit.red (punit.reduced_GB F))** p q ∧ ¬ punit.is_red (punit.reduced_GB F) q" ..
  hence "?thesis1 ∧ ?thesis2" unfolding normal_form_def by (rule someI)
  thus ?thesis1 and ?thesis2 by simp_all
qed

lemma normal_form_unique:
  assumes "(punit.red (punit.reduced_GB F))** p q" and "¬ punit.is_red (punit.reduced_GB F) q"
  shows "normal_form F p = q"
proof (rule relation.ChurchRosser_unique_final)
  from fin_X F_sub have "punit.is_Groebner_basis (punit.reduced_GB F)" by (rule reduced_GB_is_GB_Polys)
  thus "relation.is_ChurchRosser (punit.red (punit.reduced_GB F))"
    by (simp only: punit.is_Groebner_basis_def)
next
  show "(punit.red (punit.reduced_GB F))** p (normal_form F p)" by (rule normal_form)
next
  have "¬ punit.is_red (punit.reduced_GB F) (normal_form F p)" by (rule normal_form)
  thus "relation.is_final (punit.red (punit.reduced_GB F)) (normal_form F p)"
    by (simp add: punit.is_red_def)
next
  from assms(2) show "relation.is_final (punit.red (punit.reduced_GB F)) q"
    by (simp add: punit.is_red_def)
qed fact

lemma normal_form_id_iff: "normal_form F p = p ⟷ (¬ punit.is_red (punit.reduced_GB F) p)"
proof
  assume "normal_form F p = p"
  with normal_form(2)[of p] show "¬ punit.is_red (punit.reduced_GB F) p" by simp
next
  assume "¬ punit.is_red (punit.reduced_GB F) p"
  with rtranclp.rtrancl_refl show "normal_form F p = p" by (rule normal_form_unique)
qed

lemma normal_form_normal_form: "normal_form F (normal_form F p) = normal_form F p"
  by (simp add: normal_form_id_iff normal_form)

lemma normal_form_zero: "normal_form F 0 = 0"
  by (simp add: normal_form_id_iff punit.irred_0)

lemma normal_form_map_scale: "normal_form F (c ⋅ p) = c ⋅ (normal_form F p)"
  by (intro normal_form_unique punit.is_irred_map_scale normal_form)
    (simp add: punit.map_scale_eq_monom_mult punit.red_rtrancl_mult normal_form)

lemma normal_form_uminus: "normal_form F (- p) = - normal_form F p"
  by (intro normal_form_unique punit.red_rtrancl_uminus normal_form)
      (simp add: punit.is_red_uminus normal_form)

lemma normal_form_plus_normal_form:
  "normal_form F (normal_form F p + normal_form F q) = normal_form F p + normal_form F q"
  by (intro normal_form_unique rtranclp.rtrancl_refl punit.is_irred_plus normal_form)

lemma normal_form_minus_normal_form:
  "normal_form F (normal_form F p - normal_form F q) = normal_form F p - normal_form F q"
  by (intro normal_form_unique rtranclp.rtrancl_refl punit.is_irred_minus normal_form)

lemma normal_form_ideal_Polys: "normal_form (ideal F ∩ P[X]) = normal_form F"
proof -
  let ?F = "ideal F ∩ P[X]"
  from fin_X have eq: "punit.reduced_GB ?F = punit.reduced_GB F"
  proof (rule reduced_GB_unique_Polys)
    from fin_X F_sub show "punit.is_reduced_GB (punit.reduced_GB F)"
      by (rule reduced_GB_is_reduced_GB_Polys)
  next
    from fin_X F_sub have "ideal (punit.reduced_GB F) = ideal F" by (rule reduced_GB_ideal_Polys)
    also have "… = ideal (ideal F ∩ P[X])"
    proof (intro subset_antisym ideal.span_subset_spanI)
      from ideal.span_superset[of F] F_sub have "F ⊆ ideal F ∩ P[X]" by simp
      thus "F ⊆ ideal (ideal F ∩ P[X])" using ideal.span_superset by (rule subset_trans)
    qed blast
    finally show "ideal (punit.reduced_GB F) = ideal (ideal F ∩ P[X])" .
  qed blast
  show ?thesis by (rule ext) (simp only: normal_form_def eq)
qed

lemma normal_form_diff_in_ideal: "p - normal_form F p ∈ ideal F"
proof -
  from normal_form(1) have "p - normal_form F p ∈ ideal (punit.reduced_GB F)"
    by (rule punit.red_rtranclp_diff_in_pmdl[simplified])
  also from fin_X F_sub have "… = ideal F" by (rule reduced_GB_ideal_Polys)
  finally show ?thesis .
qed

lemma normal_form_zero_iff: "normal_form F p = 0 ⟷ p ∈ ideal F"
proof
  assume "normal_form F p = 0"
  with normal_form_diff_in_ideal[of p] show "p ∈ ideal F" by simp
next
  assume "p ∈ ideal F"
  hence "p - (p - normal_form F p) ∈ ideal F" using normal_form_diff_in_ideal
    by (rule ideal.span_diff)
  also from fin_X F_sub have "… = ideal (punit.reduced_GB F)" by (rule reduced_GB_ideal_Polys[symmetric])
  finally have *: "normal_form F p ∈ ideal (punit.reduced_GB F)" by simp
  show "normal_form F p = 0"
  proof (rule ccontr)
    from fin_X F_sub have "punit.is_Groebner_basis (punit.reduced_GB F)" by (rule reduced_GB_is_GB_Polys)
    moreover note *
    moreover assume "normal_form F p ≠ 0"
    ultimately obtain g where "g ∈ punit.reduced_GB F" and "g ≠ 0"
      and a: "lpp g adds lpp (normal_form F p)" by (rule punit.GB_adds_lt[simplified])
    note this(1, 2)
    moreover from ‹normal_form F p ≠ 0› have "lpp (normal_form F p) ∈ keys (normal_form F p)"
      by (rule punit.lt_in_keys)
    ultimately have "punit.is_red (punit.reduced_GB F) (normal_form F p)"
      using a by (rule punit.is_red_addsI[simplified])
    with normal_form(2) show False ..
  qed
qed

lemma normal_form_eq_iff: "normal_form F p = normal_form F q ⟷ p - q ∈ ideal F"
proof -
  have "p - q - (normal_form F p - normal_form F q) = (p - normal_form F p) - (q - normal_form F q)"
    by simp
  also from normal_form_diff_in_ideal normal_form_diff_in_ideal have "… ∈ ideal F"
    by (rule ideal.span_diff)
  finally have *: "p - q - (normal_form F p - normal_form F q) ∈ ideal F" .
  show ?thesis
  proof
    assume "normal_form F p = normal_form F q"
    with * show "p - q ∈ ideal F" by simp
  next
    assume "p - q ∈ ideal F"
    hence "p - q - (p - q - (normal_form F p - normal_form F q)) ∈ ideal F" using *
      by (rule ideal.span_diff)
    hence "normal_form F (normal_form F p - normal_form F q) = 0" by (simp add: normal_form_zero_iff)
    thus "normal_form F p = normal_form F q" by (simp add: normal_form_minus_normal_form)
  qed
qed

lemma Polys_closed_normal_form:
  assumes "p ∈ P[X]"
  shows "normal_form F p ∈ P[X]"
proof -
  from fin_X F_sub have "punit.reduced_GB F ⊆ P[X]" by (rule reduced_GB_Polys)
  with fin_X show ?thesis using assms normal_form(1)
    by (rule punit.dgrad_p_set_closed_red_rtrancl[OF dickson_grading_varnum, where m=0, simplified dgrad_p_set_varnum])
qed

lemma image_normal_form_iff:
  "p ∈ normal_form F ` P[X] ⟷ (p ∈ P[X] ∧ ¬ punit.is_red (punit.reduced_GB F) p)"
proof
  assume "p ∈ normal_form F ` P[X]"
  then obtain q where "q ∈ P[X]" and p: "p = normal_form F q" ..
  from this(1) show "p ∈ P[X] ∧ ¬ punit.is_red (punit.reduced_GB F) p" unfolding p
    by (intro conjI Polys_closed_normal_form normal_form)
next
  assume "p ∈ P[X] ∧ ¬ punit.is_red (punit.reduced_GB F) p"
  hence "p ∈ P[X]" and "¬ punit.is_red (punit.reduced_GB F) p" by simp_all
  from this(2) have "normal_form F p = p" by (simp add: normal_form_id_iff)
  from this[symmetric] ‹p ∈ P[X]› show "p ∈ normal_form F ` P[X]" by (rule image_eqI)
qed

end

lemma direct_decomp_ideal_insert:
  fixes F and f
  defines "I ≡ ideal (insert f F)"
  defines "L ≡ (ideal F ÷ f) ∩ P[X]"
  assumes "F ⊆ P[X]" and "f ∈ P[X]"
  shows "direct_decomp (I ∩ P[X]) [ideal F ∩ P[X], (*) f ` normal_form L ` P[X]]"
    (is "direct_decomp _ ?ss")
proof (rule direct_decompI_alt)
  fix qs
  assume "qs ∈ listset ?ss"
  then obtain x y where x: "x ∈ ideal F ∩ P[X]" and y: "y ∈ (*) f ` normal_form L ` P[X]"
    and qs: "qs = [x, y]" by (rule listset_doubletonE)
  have "sum_list qs = x + y" by (simp add: qs)
  also have "… ∈ I ∩ P[X]" unfolding I_def
  proof (intro IntI ideal.span_add Polys_closed_plus)
    have "ideal F ⊆ ideal (insert f F)" by (rule ideal.span_mono) blast
    with x show "x ∈ ideal (insert f F)" and "x ∈ P[X]" by blast+
  next
    from y obtain p where "p ∈ P[X]" and y: "y = f * normal_form L p" by blast
    have "f ∈ ideal (insert f F)" by (rule ideal.span_base) simp
    hence "normal_form L p * f ∈ ideal (insert f F)" by (rule ideal.span_scale)
    thus "y ∈ ideal (insert f F)" by (simp only: mult.commute y)

    have "L ⊆ P[X]" by (simp add: L_def)
    hence "normal_form L p ∈ P[X]" using ‹p ∈ P[X]› by (rule Polys_closed_normal_form)
    with assms(4) show "y ∈ P[X]" unfolding y by (rule Polys_closed_times)
  qed
  finally show "sum_list qs ∈ I ∩ P[X]" .
next
  fix a
  assume "a ∈ I ∩ P[X]"
  hence "a ∈ I" and "a ∈ P[X]" by simp_all
  from assms(3, 4) have "insert f F ⊆ P[X]" by simp
  then obtain F0 q0 where "F0 ⊆ insert f F" and "finite F0" and q0: "⋀f0. q0 f0 ∈ P[X]"
    and a: "a = (∑f0∈F0. q0 f0 * f0)"
    using ‹a ∈ P[X]› ‹a ∈ I› unfolding I_def by (rule in_idealE_Polys) blast
  obtain q a' where a': "a' ∈ ideal F" and "a' ∈ P[X]" and "q ∈ P[X]" and a: "a = q * f + a'"
  proof (cases "f ∈ F0")
    case True
    with ‹F0 ⊆ insert f F› have "F0 - {f} ⊆ F" by blast
    show ?thesis
    proof
      have "(∑f0∈F0 - {f}. q0 f0 * f0) ∈ ideal (F0 - {f})" by (rule ideal.sum_in_spanI)
      also from ‹F0 - {f} ⊆ F› have "… ⊆ ideal F" by (rule ideal.span_mono)
      finally show "(∑f0∈F0 - {f}. q0 f0 * f0) ∈ ideal F" .
    next
      show "(∑f0∈F0 - {f}. q0 f0 * f0) ∈ P[X]"
      proof (intro Polys_closed_sum Polys_closed_times q0)
        fix f0
        assume "f0 ∈ F0 - {f}"
        also have "… ⊆ F0" by blast
        also have "… ⊆ insert f F" by fact
        also have "… ⊆ P[X]" by fact
        finally show "f0 ∈ P[X]" .
      qed
    next
      from ‹finite F0› True show "a = q0 f * f + (∑f0∈F0 - {f}. q0 f0 * f0)"
        by (simp only: a sum.remove)
    qed fact
  next
    case False
    with ‹F0 ⊆ insert f F› have "F0 ⊆ F" by blast
    show ?thesis
    proof
      have "a ∈ ideal F0" unfolding a by (rule ideal.sum_in_spanI)
      also from ‹F0 ⊆ F› have "… ⊆ ideal F" by (rule ideal.span_mono)
      finally show "a ∈ ideal F" .
    next
      show "a = 0 * f + a" by simp
    qed (fact ‹a ∈ P[X]›, fact zero_in_Polys)
  qed
  let ?a = "f * (normal_form L q)"
  have "L ⊆ P[X]" by (simp add: L_def)
  hence "normal_form L q ∈ P[X]" using ‹q ∈ P[X]› by (rule Polys_closed_normal_form)
  with assms(4) have "?a ∈ P[X]" by (rule Polys_closed_times)
  from ‹L ⊆ P[X]› have "q - normal_form L q ∈ ideal L" by (rule normal_form_diff_in_ideal)
  also have "… ⊆ ideal (ideal F ÷ f)" unfolding L_def by (rule ideal.span_mono) blast
  finally have "f * (q - normal_form L q) ∈ ideal F" by (simp add: quot_set_iff)
  with ‹a' ∈ ideal F› have "a' + f * (q - normal_form L q) ∈ ideal F" by (rule ideal.span_add)
  hence "a - ?a ∈ ideal F" by (simp add: a algebra_simps)

  define qs where "qs = [a - ?a, ?a]"
  show "∃!qs∈listset ?ss. a = sum_list qs"
  proof (intro ex1I conjI allI impI)
    have "a - ?a ∈ ideal F ∩ P[X]"
    proof
      from assms(4) ‹a ∈ P[X]› ‹normal_form L q ∈ P[X]› show "a - ?a ∈ P[X]"
        by (intro Polys_closed_minus Polys_closed_times)
    qed fact
    moreover from ‹q ∈ P[X]› have "?a ∈ (*) f ` normal_form L ` P[X]" by (intro imageI)
    ultimately show "qs ∈ listset ?ss" using qs_def by (rule listset_doubletonI)
  next
    fix qs0
    assume "qs0 ∈ listset ?ss ∧ a = sum_list qs0"
    hence "qs0 ∈ listset ?ss" and "a = sum_list qs0" by simp_all
    from this(1) obtain x y where "x ∈ ideal F ∩ P[X]" and "y ∈ (*) f ` normal_form L ` P[X]"
      and qs0: "qs0 = [x, y]" by (rule listset_doubletonE)
    from this(2) obtain a0 where "a0 ∈ P[X]" and y: "y = f * normal_form L a0" by blast
    from ‹x ∈ ideal F ∩ P[X]› have "x ∈ ideal F" by simp
    have x: "x = a - y" by (simp add: ‹a = sum_list qs0› qs0)
    have "f * (normal_form L q - normal_form L a0) = x - (a - ?a)" by (simp add: x y a algebra_simps)
    also from ‹x ∈ ideal F› ‹a - ?a ∈ ideal F› have "… ∈ ideal F" by (rule ideal.span_diff)
    finally have "normal_form L q - normal_form L a0 ∈ ideal F ÷ f" by (rule quot_setI)
    moreover from ‹L ⊆ P[X]› ‹q ∈ P[X]› ‹a0 ∈ P[X]› have "normal_form L q - normal_form L a0 ∈ P[X]"
      by (intro Polys_closed_minus Polys_closed_normal_form)
    ultimately have "normal_form L q - normal_form L a0 ∈ L" by (simp add: L_def)
    also have "… ⊆ ideal L" by (fact ideal.span_superset)
    finally have "normal_form L q - normal_form L a0 = 0" using ‹L ⊆ P[X]›
      by (simp only: normal_form_minus_normal_form flip: normal_form_zero_iff)
    thus "qs0 = qs" by (simp add: qs0 qs_def x y)
  qed (simp_all add: qs_def)
qed

corollary direct_decomp_ideal_normal_form:
  assumes "F ⊆ P[X]"
  shows "direct_decomp P[X] [ideal F ∩ P[X], normal_form F ` P[X]]"
proof -
  from assms one_in_Polys have "direct_decomp (ideal (insert 1 F) ∩ P[X]) [ideal F ∩ P[X],
                                                (*) 1 ` normal_form ((ideal F ÷ 1) ∩ P[X]) ` P[X]]"
    by (rule direct_decomp_ideal_insert)
  moreover have "ideal (insert 1 F) = UNIV"
    by (simp add: ideal_eq_UNIV_iff_contains_one ideal.span_base)
  moreover from refl have "((*) 1 ∘ normal_form F) ` P[X] = normal_form F ` P[X]"
    by (rule image_cong) simp
  ultimately show ?thesis using assms by (simp add: image_comp normal_form_ideal_Polys)
qed

end

subsection ‹Basic Cone Decompositions›

definition cone :: "((('x ⇒0 nat) ⇒0 'a) × 'x set) ⇒ (('x ⇒0 nat) ⇒0 'a::comm_semiring_0) set"
  where "cone hU = (*) (fst hU) ` P[snd hU]"

lemma coneI: "p = a * h ⟹ a ∈ P[U] ⟹ p ∈ cone (h, U)"
  by (auto simp: cone_def mult.commute[of a])

lemma coneE:
  assumes "p ∈ cone (h, U)"
  obtains a where "a ∈ P[U]" and "p = a * h"
  using assms by (auto simp: cone_def mult.commute)

lemma cone_empty: "cone (h, {}) = range (λc. c ⋅ h)"
  by (auto simp: Polys_empty map_scale_eq_times intro: coneI elim!: coneE)

lemma cone_zero [simp]: "cone (0, U) = {0}"
  by (auto simp: cone_def intro: zero_in_Polys)

lemma cone_one [simp]: "cone (1::_ ⇒0 'a::comm_semiring_1, U) = P[U]"
  by (auto simp: cone_def)

lemma zero_in_cone: "0 ∈ cone hU"
  by (auto simp: cone_def intro!: image_eqI zero_in_Polys)

corollary empty_not_in_map_cone: "{} ∉ set (map cone ps)"
  using zero_in_cone by fastforce

lemma tip_in_cone: "h ∈ cone (h::_ ⇒0 _::comm_semiring_1, U)"
  using _ one_in_Polys by (rule coneI) simp

lemma cone_closed_plus:
  assumes "a ∈ cone hU" and "b ∈ cone hU"
  shows "a + b ∈ cone hU"
proof -
  obtain h U where hU: "hU = (h, U)" using prod.exhaust by blast
  with assms have "a ∈ cone (h, U)" and "b ∈ cone (h, U)" by simp_all
  from this(1) obtain a' where "a' ∈ P[U]" and a: "a = a' * h" by (rule coneE)
  from ‹b ∈ cone (h, U)› obtain b' where "b' ∈ P[U]" and b: "b = b' * h" by (rule coneE)
  have "a + b = (a' + b') * h" by (simp only: a b algebra_simps)
  moreover from ‹a' ∈ P[U]› ‹b' ∈ P[U]› have "a' + b' ∈ P[U]" by (rule Polys_closed_plus)
  ultimately show ?thesis unfolding hU by (rule coneI)
qed

lemma cone_closed_uminus:
  assumes "(a::_ ⇒0 _::comm_ring) ∈ cone hU"
  shows "- a ∈ cone hU"
proof -
  obtain h U where hU: "hU = (h, U)" using prod.exhaust by blast
  with assms have "a ∈ cone (h, U)" by simp
  from this(1) obtain a' where "a' ∈ P[U]" and a: "a = a' * h" by (rule coneE)
  have "- a = (- a') * h" by (simp add: a)
  moreover from ‹a' ∈ P[U]› have "- a' ∈ P[U]" by (rule Polys_closed_uminus)
  ultimately show ?thesis unfolding hU by (rule coneI)
qed

lemma cone_closed_minus:
  assumes "(a::_ ⇒0 _::comm_ring) ∈ cone hU" and "b ∈ cone hU"
  shows "a - b ∈ cone hU"
proof -
  from assms(2) have "- b ∈ cone hU" by (rule cone_closed_uminus)
  with assms(1) have "a + (- b) ∈ cone hU" by (rule cone_closed_plus)
  thus ?thesis by simp
qed

lemma cone_closed_times:
  assumes "a ∈ cone (h, U)" and "q ∈ P[U]"
  shows "q * a ∈ cone (h, U)"
proof -
  from assms(1) obtain a' where "a' ∈ P[U]" and a: "a = a' * h" by (rule coneE)
  have "q * a = (q * a') * h" by (simp only: a ac_simps)
  moreover from assms(2) ‹a' ∈ P[U]› have "q * a' ∈ P[U]" by (rule Polys_closed_times)
  ultimately show ?thesis by (rule coneI)
qed

corollary cone_closed_monom_mult:
  assumes "a ∈ cone (h, U)" and "t ∈ .[U]"
  shows "punit.monom_mult c t a ∈ cone (h, U)"
proof -
  from assms(2) have "monomial c t ∈ P[U]" by (rule Polys_closed_monomial)
  with assms(1) have "monomial c t * a ∈ cone (h, U)" by (rule cone_closed_times)
  thus ?thesis by (simp only: times_monomial_left)
qed

lemma coneD:
  assumes "p ∈ cone (h, U)" and "p ≠ 0"
  shows "lpp h adds lpp (p::_ ⇒0 _::{comm_semiring_0,semiring_no_zero_divisors})"
proof -
  from assms(1) obtain a where p: "p = a * h" by (rule coneE)
  with assms(2) have "a ≠ 0" and "h ≠ 0" by auto
  hence "lpp p = lpp a + lpp h" unfolding p by (rule lp_times)
  also have "… = lpp h + lpp a" by (rule add.commute)
  finally show ?thesis by (rule addsI)
qed

lemma cone_mono_1:
  assumes "h' ∈ P[U]"
  shows "cone (h' * h, U) ⊆ cone (h, U)"
proof
  fix p
  assume "p ∈ cone (h' * h, U)"
  then obtain a' where "a' ∈ P[U]" and "p = a' * (h' * h)" by (rule coneE)
  from this(2) have "p = a' * h' * h" by (simp only: mult.assoc)
  moreover from ‹a' ∈ P[U]› assms have "a' * h' ∈ P[U]" by (rule Polys_closed_times)
  ultimately show "p ∈ cone (h, U)" by (rule coneI)
qed

lemma cone_mono_2:
  assumes "U1 ⊆ U2"
  shows "cone (h, U1) ⊆ cone (h, U2)"
proof
  from assms have "P[U1] ⊆ P[U2]" by (rule Polys_mono)
  fix p
  assume "p ∈ cone (h, U1)"
  then obtain a where "a ∈ P[U1]" and "p = a * h" by (rule coneE)
  note this(2)
  moreover from ‹a ∈ P[U1]› ‹P[U1] ⊆ P[U2]› have "a ∈ P[U2]" ..
  ultimately show "p ∈ cone (h, U2)" by (rule coneI)
qed

lemma cone_subsetD:
  assumes "cone (h1, U1) ⊆ cone (h2::_ ⇒0 'a::{comm_ring_1,ring_no_zero_divisors}, U2)"
  shows "h2 dvd h1" and "h1 ≠ 0 ⟹ U1 ⊆ U2"
proof -
  from tip_in_cone assms have "h1 ∈ cone (h2, U2)" ..
  then obtain a1' where "a1' ∈ P[U2]" and h1: "h1 = a1' * h2" by (rule coneE)
  from this(2) have "h1 = h2 * a1'" by (simp only: mult.commute)
  thus "h2 dvd h1" ..

  assume "h1 ≠ 0"
  with h1 have "a1' ≠ 0" and "h2 ≠ 0" by auto
  show "U1 ⊆ U2"
  proof
    fix x
    assume "x ∈ U1"
    hence "monomial (1::'a) (Poly_Mapping.single x 1) ∈ P[U1]" (is "?p ∈ _")
      by (intro Polys_closed_monomial PPs_closed_single)
    with refl have "?p * h1 ∈ cone (h1, U1)" by (rule coneI)
    hence "?p * h1 ∈ cone (h2, U2)" using assms ..
    then obtain a where "a ∈ P[U2]" and "?p * h1 = a * h2" by (rule coneE)
    from this(2) have "(?p * a1') * h2 = a * h2" by (simp only: h1 ac_simps)
    hence "?p * a1' = a" using ‹h2 ≠ 0› by (rule times_canc_right)
    with ‹a ∈ P[U2]› have "a1' * ?p ∈ P[U2]" by (simp add: mult.commute)
    hence "?p ∈ P[U2]" using ‹a1' ∈ P[U2]› ‹a1' ≠ 0› by (rule times_in_PolysD)
    thus "x ∈ U2" by (simp add: Polys_def PPs_def)
  qed
qed

lemma cone_subset_PolysD:
  assumes "cone (h::_ ⇒0 'a::{comm_semiring_1,semiring_no_zero_divisors}, U) ⊆ P[X]"
  shows "h ∈ P[X]" and "h ≠ 0 ⟹ U ⊆ X"
proof -
  from tip_in_cone assms show "h ∈ P[X]" ..

  assume "h ≠ 0"
  show "U ⊆ X"
  proof
    fix x
    assume "x ∈ U"
    hence "monomial (1::'a) (Poly_Mapping.single x 1) ∈ P[U]" (is "?p ∈ _")
      by (intro Polys_closed_monomial PPs_closed_single)
    with refl have "?p * h ∈ cone (h, U)" by (rule coneI)
    hence "?p * h ∈ P[X]" using assms ..
    hence "h * ?p ∈ P[X]" by (simp only: mult.commute)
    hence "?p ∈ P[X]" using ‹h ∈ P[X]› ‹h ≠ 0› by (rule times_in_PolysD)
    thus "x ∈ X" by (simp add: Polys_def PPs_def)
  qed
qed

lemma cone_subset_PolysI:
  assumes "h ∈ P[X]" and "h ≠ 0 ⟹ U ⊆ X"
  shows "cone (h, U) ⊆ P[X]"
proof (cases "h = 0")
  case True
  thus ?thesis by (simp add: zero_in_Polys)
next
  case False
  hence "U ⊆ X" by (rule assms(2))
  hence "P[U] ⊆ P[X]" by (rule Polys_mono)
  show ?thesis
  proof
    fix a
    assume "a ∈ cone (h, U)"
    then obtain q where "q ∈ P[U]" and a: "a = q * h" by (rule coneE)
    from this(1) ‹P[U] ⊆ P[X]› have "q ∈ P[X]" ..
    from this assms(1) show "a ∈ P[X]" unfolding a by (rule Polys_closed_times)
  qed
qed

lemma cone_image_times: "(*) a ` cone (h, U) = cone (a * h, U)"
  by (auto simp: ac_simps image_image intro!: image_eqI coneI elim!: coneE)

lemma cone_image_times': "(*) a ` cone hU = cone (apfst ((*) a) hU)"
proof -
  obtain h U where "hU = (h, U)" using prod.exhaust by blast
  thus ?thesis by (simp add: cone_image_times)
qed

lemma homogeneous_set_coneI:
  assumes "homogeneous h"
  shows "homogeneous_set (cone (h, U))"
proof (rule homogeneous_setI)
  fix a n
  assume "a ∈ cone (h, U)"
  then obtain q where "q ∈ P[U]" and a: "a = q * h" by (rule coneE)
  from this(1) show "hom_component a n ∈ cone (h, U)" unfolding a
  proof (induct q rule: poly_mapping_plus_induct)
    case 1
    show ?case by (simp add: zero_in_cone)
  next
    case (2 p c t)
    have "p ∈ P[U]"
    proof (intro PolysI subsetI)
      fix s
      assume "s ∈ keys p"
      moreover from 2(2) this have "s ∉ keys (monomial c t)" by auto
      ultimately have "s ∈ keys (monomial c t + p)" by (rule in_keys_plusI2)
      also from 2(4) have "… ⊆ .[U]" by (rule PolysD)
      finally show "s ∈ .[U]" .
    qed
    hence *: "hom_component (p * h) n ∈ cone (h, U)" by (rule 2(3))
    from 2(1) have "t ∈ keys (monomial c t)" by simp
    hence "t ∈ keys (monomial c t + p)" using 2(2) by (rule in_keys_plusI1)
    also from 2(4) have "… ⊆ .[U]" by (rule PolysD)
    finally have "monomial c t ∈ P[U]" by (rule Polys_closed_monomial)
    with refl have "monomial c t * h ∈ cone (h, U)" (is "?h ∈ _") by (rule coneI)
    from assms have "homogeneous ?h" by (simp add: homogeneous_times)
    hence "hom_component ?h n = (?h when n = poly_deg ?h)" by (rule hom_component_of_homogeneous)
    with ‹?h ∈ cone (h, U)› have **: "hom_component ?h n ∈ cone (h, U)"
      by (simp add: when_def zero_in_cone)
    have "hom_component ((monomial c t + p) * h) n = hom_component ?h n + hom_component (p * h) n"
      by (simp only: distrib_right hom_component_plus)
    also from ** * have "… ∈ cone (h, U)" by (rule cone_closed_plus)
    finally show ?case .
  qed
qed

lemma subspace_cone: "phull.subspace (cone hU)"
  using zero_in_cone cone_closed_plus
proof (rule phull.subspaceI)
  fix c a
  assume "a ∈ cone hU"
  moreover obtain h U where hU: "hU = (h, U)" using prod.exhaust by blast
  ultimately have "a ∈ cone (h, U)" by simp
  thus "c ⋅ a ∈ cone hU" unfolding hU punit.map_scale_eq_monom_mult using zero_in_PPs
    by (rule cone_closed_monom_mult)
qed

lemma direct_decomp_cone_insert:
  fixes h :: "_ ⇒0 'a::{comm_ring_1,ring_no_zero_divisors}"
  assumes "x ∉ U"
  shows "direct_decomp (cone (h, insert x U))
                  [cone (h, U), cone (monomial 1 (Poly_Mapping.single x (Suc 0)) * h, insert x U)]"
proof -
  let ?x = "Poly_Mapping.single x (Suc 0)"
  define xx where "xx = monomial (1::'a) ?x"
  show "direct_decomp (cone (h, insert x U)) [cone (h, U), cone (xx * h, insert x U)]"
    (is "direct_decomp _ ?ss")
  proof (rule direct_decompI_alt)
    fix qs
    assume "qs ∈ listset ?ss"
    then obtain a b where "a ∈ cone (h, U)" and b: "b ∈ cone (xx * h, insert x U)"
      and qs: "qs = [a, b]" by (rule listset_doubletonE)
    note this(1)
    also have "cone (h, U) ⊆ cone (h, insert x U)" by (rule cone_mono_2) blast
    finally have a: "a ∈ cone (h, insert x U)" .
    have "cone (xx * h, insert x U) ⊆ cone (h, insert x U)"
      by (rule cone_mono_1) (simp add: xx_def Polys_def PPs_closed_single)
    with b have "b ∈ cone (h, insert x U)" ..
    with a have "a + b ∈ cone (h, insert x U)" by (rule cone_closed_plus)
    thus "sum_list qs ∈ cone (h, insert x U)" by (simp add: qs)
  next
    fix a
    assume "a ∈ cone (h, insert x U)"
    then obtain q where "q ∈ P[insert x U]" and a: "a = q * h" by (rule coneE)
    define qU where "qU = except q (- .[U])"
    define qx where "qx = except q .[U]"
    have q: "q = qU + qx" by (simp only: qU_def qx_def add.commute flip: except_decomp)
    have "qU ∈ P[U]" by (rule PolysI) (simp add: qU_def keys_except)
    have x_adds: "?x adds t" if "t ∈ keys qx" for t unfolding adds_poly_mapping le_fun_def
    proof
      fix y
      show "lookup ?x y ≤ lookup t y"
      proof (cases "y = x")
        case True
        from that have "t ∈ keys q" and "t ∉ .[U]" by (simp_all add: qx_def keys_except)
        from ‹q ∈ P[insert x U]› have "keys q ⊆ .[insert x U]" by (rule PolysD)
        with ‹t ∈ keys q› have "t ∈ .[insert x U]" ..
        hence "keys t ⊆ insert x U" by (rule PPsD)
        moreover from ‹t ∉ .[U]› have "¬ keys t ⊆ U" by (simp add: PPs_def)
        ultimately have "x ∈ keys t" by blast
        thus ?thesis by (simp add: lookup_single True in_keys_iff)
      next
        case False
        thus ?thesis by (simp add: lookup_single)
      qed
    qed
    define qx' where "qx' = Poly_Mapping.map_key ((+) ?x) qx"
    have lookup_qx': "lookup qx' = (λt. lookup qx (?x + t))"
      by (rule ext) (simp add: qx'_def map_key.rep_eq)
    have "qx' * xx = punit.monom_mult 1 ?x qx'"
      by (simp only: xx_def mult.commute flip: times_monomial_left)
    also have "… = qx"
      by (auto simp: punit.lookup_monom_mult lookup_qx' add.commute[of ?x] adds_minus
              simp flip: not_in_keys_iff_lookup_eq_zero dest: x_adds intro!: poly_mapping_eqI)
    finally have qx: "qx = qx' * xx" by (rule sym)
    have "qx' ∈ P[insert x U]"
    proof (intro PolysI subsetI)
      fix t
      assume "t ∈ keys qx'"
      hence "t + ?x ∈ keys qx" by (simp only: lookup_qx' in_keys_iff not_False_eq_True add.commute)
      also have "… ⊆ keys q" by (auto simp: qx_def keys_except)
      also from ‹q ∈ P[insert x U]› have "… ⊆ .[insert x U]" by (rule PolysD)
      finally have "(t + ?x) - ?x ∈ .[insert x U]" by (rule PPs_closed_minus)
      thus "t ∈ .[insert x U]" by simp
    qed
    define qs where "qs = [qU * h, qx' * (xx * h)]"
    show "∃!qs∈listset ?ss. a = sum_list qs"
    proof (intro ex1I conjI allI impI)
      from refl ‹qU ∈ P[U]› have "qU * h ∈ cone (h, U)" by (rule coneI)
      moreover from refl ‹qx' ∈ P[insert x U]› have "qx' * (xx * h) ∈ cone (xx * h, insert x U)"
        by (rule coneI)
      ultimately show "qs ∈ listset ?ss" using qs_def by (rule listset_doubletonI)
    next
      fix qs0
      assume "qs0 ∈ listset ?ss ∧ a = sum_list qs0"
      hence "qs0 ∈ listset ?ss" and a0: "a = sum_list qs0" by simp_all
      from this(1) obtain p1 p2 where "p1 ∈ cone (h, U)" and p2: "p2 ∈ cone (xx * h, insert x U)"
        and qs0: "qs0 = [p1, p2]" by (rule listset_doubletonE)
      from this(1) obtain qU0 where "qU0 ∈ P[U]" and p1: "p1 = qU0 * h" by (rule coneE)
      from p2 obtain qx0 where p2: "p2 = qx0 * (xx * h)" by (rule coneE)
      show "qs0 = qs"
      proof (cases "h = 0")
        case True
        thus ?thesis by (simp add: qs_def qs0 p1 p2)
      next
        case False
        from a0 have "(qU - qU0) * h = (qx0 - qx') * xx * h"
          by (simp add: a qs0 p1 p2 q qx algebra_simps)
        hence eq: "qU - qU0 = (qx0 - qx') * xx" using False by (rule times_canc_right)
        have "qx0 = qx'"
        proof (rule ccontr)
          assume "qx0 ≠ qx'"
          hence "qx0 - qx' ≠ 0" by simp
          moreover have "xx ≠ 0" by (simp add: xx_def monomial_0_iff)
          ultimately have "lpp ((qx0 - qx') * xx) = lpp (qx0 - qx') + lpp xx"
            by (rule lp_times)
          also have "lpp xx = ?x" by (simp add: xx_def punit.lt_monomial)
          finally have "?x adds lpp (qU - qU0)" by (simp add: eq)
          hence "lookup ?x x ≤ lookup (lpp (qU - qU0)) x" by (simp only: adds_poly_mapping le_fun_def)
          hence "x ∈ keys (lpp (qU - qU0))" by (simp add: in_keys_iff lookup_single)
          moreover have "lpp (qU - qU0) ∈ keys (qU - qU0)"
          proof (rule punit.lt_in_keys)
            from ‹qx0 - qx' ≠ 0› ‹xx ≠ 0› show "qU - qU0 ≠ 0" unfolding eq by (rule times_not_zero)
          qed
          ultimately have "x ∈ indets (qU - qU0)" by (rule in_indetsI)
          from ‹qU ∈ P[U]› ‹qU0 ∈ P[U]› have "qU - qU0 ∈ P[U]" by (rule Polys_closed_minus)
          hence "indets (qU - qU0) ⊆ U" by (rule PolysD)
          with ‹x ∈ indets (qU - qU0)› have "x ∈ U" ..
          with assms show False ..
        qed
        moreover from this eq have "qU0 = qU" by simp
        ultimately show ?thesis by (simp only: qs_def qs0 p1 p2)
      qed
    qed (simp_all add: qs_def a q qx, simp only: algebra_simps)
  qed
qed

definition valid_decomp :: "'x set ⇒ ((('x ⇒0 nat) ⇒0 'a::zero) × 'x set) list ⇒ bool"
  where "valid_decomp X ps ⟷ ((∀(h, U)∈set ps. h ∈ P[X] ∧ h ≠ 0 ∧ U ⊆ X))"

definition monomial_decomp :: "((('x ⇒0 nat) ⇒0 'a::{one,zero}) × 'x set) list ⇒ bool"
  where "monomial_decomp ps ⟷ (∀hU∈set ps. is_monomial (fst hU) ∧ punit.lc (fst hU) = 1)"

definition hom_decomp :: "((('x ⇒0 nat) ⇒0 'a::{one,zero}) × 'x set) list ⇒ bool"
  where "hom_decomp ps ⟷ (∀hU∈set ps. homogeneous (fst hU))"

definition cone_decomp :: "(('x ⇒0 nat) ⇒0 'a) set ⇒
                            ((('x ⇒0 nat) ⇒0 'a::comm_semiring_0) × 'x set) list ⇒ bool"
  where "cone_decomp T ps ⟷ direct_decomp T (map cone ps)"

lemma valid_decompI:
  "(⋀h U. (h, U) ∈ set ps ⟹ h ∈ P[X]) ⟹ (⋀h U. (h, U) ∈ set ps ⟹ h ≠ 0) ⟹
    (⋀h U. (h, U) ∈ set ps ⟹ U ⊆ X) ⟹ valid_decomp X ps"
  unfolding valid_decomp_def by blast

lemma valid_decompD:
  assumes "valid_decomp X ps" and "(h, U) ∈ set ps"
  shows "h ∈ P[X]" and "h ≠ 0" and "U ⊆ X"
  using assms unfolding valid_decomp_def by blast+

lemma valid_decompD_finite:
  assumes "finite X" and "valid_decomp X ps" and "(h, U) ∈ set ps"
  shows "finite U"
proof -
  from assms(2, 3) have "U ⊆ X" by (rule valid_decompD)
  thus ?thesis using assms(1) by (rule finite_subset)
qed

lemma valid_decomp_Nil: "valid_decomp X []"
  by (simp add: valid_decomp_def)

lemma valid_decomp_concat:
  assumes "⋀ps. ps ∈ set pss ⟹ valid_decomp X ps"
  shows "valid_decomp X (concat pss)"
proof (rule valid_decompI)
  fix h U
  assume "(h, U) ∈ set (concat pss)"
  then obtain ps where "ps ∈ set pss" and "(h, U) ∈ set ps" unfolding set_concat ..
  from this(1) have "valid_decomp X ps" by (rule assms)
  thus "h ∈ P[X]" and "h ≠ 0" and "U ⊆ X" using ‹(h, U) ∈ set ps› by (rule valid_decompD)+
qed

corollary valid_decomp_append:
  assumes "valid_decomp X ps" and "valid_decomp X qs"
  shows "valid_decomp X (ps @ qs)"
proof -
  have "valid_decomp X (concat [ps, qs])" by (rule valid_decomp_concat) (auto simp: assms)
  thus ?thesis by simp
qed

lemma valid_decomp_map_times:
  assumes "valid_decomp X ps" and "s ∈ P[X]" and "s ≠ (0::_ ⇒0 _::semiring_no_zero_divisors)"
  shows "valid_decomp X (map (apfst ((*) s)) ps)"
proof (rule valid_decompI)
  fix h U
  assume "(h, U) ∈ set (map (apfst ((*) s)) ps)"
  then obtain x where "x ∈ set ps" and "(h, U) = apfst ((*) s) x" unfolding set_map ..
  moreover obtain a b where "x = (a, b)" using prod.exhaust by blast
  ultimately have h: "h = s * a" and "(a, U) ∈ set ps" by simp_all
  from assms(1) this(2) have "a ∈ P[X]" and "a ≠ 0" and "U ⊆ X" by (rule valid_decompD)+
  from assms(2) this(1) show "h ∈ P[X]" unfolding h by (rule Polys_closed_times)
  from assms(3) ‹a ≠ 0› show "h ≠ 0" unfolding h by (rule times_not_zero)
  from ‹U ⊆ X› show "U ⊆ X" .
qed

lemma monomial_decompI:
  "(⋀h U. (h, U) ∈ set ps ⟹ is_monomial h) ⟹ (⋀h U. (h, U) ∈ set ps ⟹ punit.lc h = 1) ⟹
    monomial_decomp ps"
  by (auto simp: monomial_decomp_def)

lemma monomial_decompD:
  assumes "monomial_decomp ps" and "(h, U) ∈ set ps"
  shows "is_monomial h" and "punit.lc h = 1"
  using assms by (auto simp: monomial_decomp_def)

lemma monomial_decomp_append_iff:
  "monomial_decomp (ps @ qs) ⟷ monomial_decomp ps ∧ monomial_decomp qs"
  by (auto simp: monomial_decomp_def)

lemma monomial_decomp_concat:
  "(⋀ps. ps ∈ set pss ⟹ monomial_decomp ps) ⟹ monomial_decomp (concat pss)"
  by (induct pss) (auto simp: monomial_decomp_def)

lemma monomial_decomp_map_times:
  assumes "monomial_decomp ps" and "is_monomial f" and "punit.lc f = (1::'a::semiring_1)"
  shows "monomial_decomp (map (apfst ((*) f)) ps)"
proof (rule monomial_decompI)
  fix h U
  assume "(h, U) ∈ set (map (apfst ((*) f)) ps)"
  then obtain x where "x ∈ set ps" and "(h, U) = apfst ((*) f) x" unfolding set_map ..
  moreover obtain a b where "x = (a, b)" using prod.exhaust by blast
  ultimately have h: "h = f * a" and "(a, U) ∈ set ps" by simp_all
  from assms(1) this(2) have "is_monomial a" and "punit.lc a = 1" by (rule monomial_decompD)+
  from this(1) have "monomial (punit.lc a) (lpp a) = a" by (rule punit.monomial_eq_itself)
  moreover define t where "t = lpp a"
  ultimately have a: "a = monomial 1 t" by (simp only: ‹punit.lc a = 1›)
  from assms(2) have "monomial (punit.lc f) (lpp f) = f" by (rule punit.monomial_eq_itself)
  moreover define s where "s = lpp f"
  ultimately have f: "f = monomial 1 s" by (simp only: assms(3))
  show "is_monomial h" by (simp add: h a f times_monomial_monomial monomial_is_monomial)
  show "punit.lc h = 1" by (simp add: h a f times_monomial_monomial)
qed

lemma monomial_decomp_monomial_in_cone:
  assumes "monomial_decomp ps" and "hU ∈ set ps" and "a ∈ cone hU"
  shows "monomial (lookup a t) t ∈ cone hU"
proof (cases "t ∈ keys a")
  case True
  obtain h U where hU: "hU = (h, U)" using prod.exhaust by blast
  with assms(2) have "(h, U) ∈ set ps" by simp
  with assms(1) have "is_monomial h" by (rule monomial_decompD)
  then obtain c s where h: "h = monomial c s" by (rule is_monomial_monomial)
  from assms(3) obtain q where "q ∈ P[U]" and "a = q * h" unfolding hU by (rule coneE)
  from this(2) have "a = h * q" by (simp only: mult.commute)
  also have "… = punit.monom_mult c s q" by (simp only: h times_monomial_left)
  finally have a: "a = punit.monom_mult c s q" .
  with True have "t ∈ keys (punit.monom_mult c s q)" by simp
  hence "t ∈ (+) s ` keys q" using punit.keys_monom_mult_subset[simplified] ..
  then obtain u where "u ∈ keys q" and t: "t = s + u" ..
  note this(1)
  also from ‹q ∈ P[U]› have "keys q ⊆ .[U]" by (rule PolysD)
  finally have "u ∈ .[U]" .
  have "monomial (lookup a t) t = monomial (lookup q u) u * h"
    by (simp add: a t punit.lookup_monom_mult h times_monomial_monomial mult.commute)
  moreover from ‹u ∈ .[U]› have "monomial (lookup q u) u ∈ P[U]" by (rule Polys_closed_monomial)
  ultimately show ?thesis unfolding hU by (rule coneI)
next
  case False
  thus ?thesis by (simp add: zero_in_cone in_keys_iff)
qed

lemma monomial_decomp_sum_list_monomial_in_cone:
  assumes "monomial_decomp ps" and "a ∈ sum_list ` listset (map cone ps)" and "t ∈ keys a"
  obtains c h U where "(h, U) ∈ set ps" and "c ≠ 0" and "monomial c t ∈ cone (h, U)"
proof -
  from assms(2) obtain qs where qs_in: "qs ∈ listset (map cone ps)" and a: "a = sum_list qs" ..
  from assms(3) keys_sum_list_subset have "t ∈ Keys (set qs)" unfolding a ..
  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: "q = qs ! i" by (metis in_set_conv_nth)
  moreover from qs_in have "length qs = length (map cone ps)" by (rule listsetD)
  ultimately have "i < length (map cone ps)" by simp
  moreover from qs_in this have "qs ! i ∈ (map cone ps) ! i" by (rule listsetD)
  ultimately have "ps ! i ∈ set ps" and "q ∈ cone (ps ! i)" by (simp_all add: q)
  with assms(1) have *: "monomial (lookup q t) t ∈ cone (ps ! i)"
    by (rule monomial_decomp_monomial_in_cone)
  obtain h U where psi: "ps ! i = (h, U)" using prod.exhaust by blast
  show ?thesis
  proof
    from ‹ps ! i ∈ set ps› show "(h, U) ∈ set ps" by (simp only: psi)
  next
    from ‹t ∈ keys q› show "lookup q t ≠ 0" by (simp add: in_keys_iff)
  next
    from * show "monomial (lookup q t) t ∈ cone (h, U)" by (simp only: psi)
  qed
qed

lemma hom_decompI: "(⋀h U. (h, U) ∈ set ps ⟹ homogeneous h) ⟹ hom_decomp ps"
  by (auto simp: hom_decomp_def)

lemma hom_decompD: "hom_decomp ps ⟹ (h, U) ∈ set ps ⟹ homogeneous h"
  by (auto simp: hom_decomp_def)

lemma hom_decomp_append_iff: "hom_decomp (ps @ qs) ⟷ hom_decomp ps ∧ hom_decomp qs"
  by (auto simp: hom_decomp_def)

lemma hom_decomp_concat: "(⋀ps. ps ∈ set pss ⟹ hom_decomp ps) ⟹ hom_decomp (concat pss)"
  by (induct pss) (auto simp: hom_decomp_def)

lemma hom_decomp_map_times:
  assumes "hom_decomp ps" and "homogeneous f"
  shows "hom_decomp (map (apfst ((*) f)) ps)"
proof (rule hom_decompI)
  fix h U
  assume "(h, U) ∈ set (map (apfst ((*) f)) ps)"
  then obtain x where "x ∈ set ps" and "(h, U) = apfst ((*) f) x" unfolding set_map ..
  moreover obtain a b where "x = (a, b)" using prod.exhaust by blast
  ultimately have h: "h = f * a" and "(a, U) ∈ set ps" by simp_all
  from assms(1) this(2) have "homogeneous a" by (rule hom_decompD)
  with assms(2) show "homogeneous h" unfolding h by (rule homogeneous_times)
qed

lemma monomial_decomp_imp_hom_decomp:
  assumes "monomial_decomp ps"
  shows "hom_decomp ps"
proof (rule hom_decompI)
  fix h U
  assume "(h, U) ∈ set ps"
  with assms have "is_monomial h" by (rule monomial_decompD)
  then obtain c t where h: "h = monomial c t" by (rule is_monomial_monomial)
  show "homogeneous h" unfolding h by (fact homogeneous_monomial)
qed

lemma cone_decompI: "direct_decomp T (map cone ps) ⟹ cone_decomp T ps"
  unfolding cone_decomp_def by blast

lemma cone_decompD: "cone_decomp T ps ⟹ direct_decomp T (map cone ps)"
  unfolding cone_decomp_def by blast

lemma cone_decomp_cone_subset:
  assumes "cone_decomp T ps" and "hU ∈ set ps"
  shows "cone hU ⊆ T"
proof
  fix p
  assume "p ∈ cone hU"
  from assms(2) obtain i where "i < length ps" and hU: "hU = ps ! i" by (metis in_set_conv_nth)
  define qs where "qs = (map 0 ps)[i := p]"
  have "sum_list qs ∈ T"
  proof (intro direct_decompD listsetI)
    from assms(1) show "direct_decomp T (map cone ps)" by (rule cone_decompD)
  next
    fix j
    assume "j < length (map cone ps)"
    with ‹i < length ps› ‹p ∈ cone hU› show "qs ! j ∈ map cone ps ! j"
      by (auto simp: qs_def nth_list_update zero_in_cone hU)
  qed (simp add: qs_def)
  also have "sum_list qs = qs ! i" by (rule sum_list_eq_nthI) (simp_all add: qs_def ‹i < length ps›)
  also from ‹i < length ps› have "… = p" by (simp add: qs_def)
  finally show "p ∈ T" .
qed

lemma cone_decomp_indets:
  assumes "cone_decomp T ps" and "T ⊆ P[X]" and "(h, U) ∈ set ps"
  shows "h ∈ P[X]" and "h ≠ (0::_ ⇒0 _::{comm_semiring_1,semiring_no_zero_divisors}) ⟹ U ⊆ X"
proof -
  from assms(1, 3) have "cone (h, U) ⊆ T" by (rule cone_decomp_cone_subset)
  hence "cone (h, U) ⊆ P[X]" using assms(2) by (rule subset_trans)
  thus "h ∈ P[X]" and "h ≠ 0 ⟹ U ⊆ X" by (rule cone_subset_PolysD)+
qed

lemma cone_decomp_closed_plus:
  assumes "cone_decomp T ps" and "a ∈ T" and "b ∈ T"
  shows "a + b ∈ T"
proof -
  from assms(1) have dd: "direct_decomp T (map cone ps)" by (rule cone_decompD)
  then obtain qsa where qsa: "qsa ∈ listset (map cone ps)" and a: "a = sum_list qsa" using assms(2)
    by (rule direct_decompE)
  from dd assms(3) obtain qsb where qsb: "qsb ∈ listset (map cone ps)" and b: "b = sum_list qsb"
    by (rule direct_decompE)
  from qsa have "length qsa = length (map cone ps)" by (rule listsetD)
  moreover from qsb have "length qsb = length (map cone ps)" by (rule listsetD)
  ultimately have "a + b = sum_list (map2 (+) qsa qsb)" by (simp only: sum_list_map2_plus a b)
  also from dd have "sum_list (map2 (+) qsa qsb) ∈ T"
  proof (rule direct_decompD)
    from qsa qsb show "map2 (+) qsa qsb ∈ listset (map cone ps)"
    proof (rule listset_closed_map2)
      fix c p1 p2
      assume "c ∈ set (map cone ps)"
      then obtain hU where c: "c = cone hU" by auto
      assume "p1 ∈ c" and "p2 ∈ c"
      thus "p1 + p2 ∈ c" unfolding c by (rule cone_closed_plus)
    qed
  qed
  finally show ?thesis .
qed

lemma cone_decomp_closed_uminus:
  assumes "cone_decomp T ps" and "(a::_ ⇒0 _::comm_ring) ∈ T"
  shows "- a ∈ T"
proof -
  from assms(1) have dd: "direct_decomp T (map cone ps)" by (rule cone_decompD)
  then obtain qsa where qsa: "qsa ∈ listset (map cone ps)" and a: "a = sum_list qsa" using assms(2)
    by (rule direct_decompE)
  from qsa have "length qsa = length (map cone ps)" by (rule listsetD)
  have "- a = sum_list (map uminus qsa)" unfolding a by (induct qsa, simp_all)
  also from dd have "… ∈ T"
  proof (rule direct_decompD)
    from qsa show "map uminus qsa ∈ listset (map cone ps)"
    proof (rule listset_closed_map)
      fix c p
      assume "c ∈ set (map cone ps)"
      then obtain hU where c: "c = cone hU" by auto
      assume "p ∈ c"
      thus "- p ∈ c" unfolding c by (rule cone_closed_uminus)
    qed
  qed
  finally show ?thesis .
qed

corollary cone_decomp_closed_minus:
  assumes "cone_decomp T ps" and "(a::_ ⇒0 _::comm_ring) ∈ T" and "b ∈ T"
  shows "a - b ∈ T"
proof -
  from assms(1, 3) have "- b ∈ T" by (rule cone_decomp_closed_uminus)
  with assms(1, 2) have "a + (- b) ∈ T" by (rule cone_decomp_closed_plus)
  thus ?thesis by simp
qed

lemma cone_decomp_Nil: "cone_decomp {0} []"
  by (auto simp: cone_decomp_def intro: direct_decompI_alt)

lemma cone_decomp_singleton: "cone_decomp (cone (t, U)) [(t, U)]"
  by (simp add: cone_decomp_def direct_decomp_singleton)

lemma cone_decomp_append:
  assumes "direct_decomp T [S1, S2]" and "cone_decomp S1 ps" and "cone_decomp S2 qs"
  shows "cone_decomp T (ps @ qs)"
proof (rule cone_decompI)
  from assms(2) have "direct_decomp S1 (map cone ps)" by (rule cone_decompD)
  with assms(1) have "direct_decomp T ([S2] @ map cone ps)" by (rule direct_decomp_direct_decomp)
  hence "direct_decomp T (S2 # map cone ps)" by simp
  moreover from assms(3) have "direct_decomp S2 (map cone qs)" by (rule cone_decompD)
  ultimately have "direct_decomp T (map cone ps @ map cone qs)" by (intro direct_decomp_direct_decomp)
  thus "direct_decomp T (map cone (ps @ qs))" by simp
qed

lemma cone_decomp_concat:
  assumes "direct_decomp T ss" and "length pss = length ss"
    and "⋀i. i < length ss ⟹ cone_decomp (ss ! i) (pss ! i)"
  shows "cone_decomp T (concat pss)"
  using assms(2, 1, 3)
proof (induct pss ss arbitrary: T rule: list_induct2)
  case Nil
  from Nil(1) show ?case by (simp add: cone_decomp_def)
next
  case (Cons ps pss s ss)
  have "0 < length (s # ss)" by simp
  hence "cone_decomp ((s # ss) ! 0) ((ps # pss) ! 0)" by (rule Cons.prems)
  hence "cone_decomp s ps" by simp
  hence *: "direct_decomp s (map cone ps)" by (rule cone_decompD)
  with Cons.prems(1) have "direct_decomp T (ss @ map cone ps)" by (rule direct_decomp_direct_decomp)
  hence 1: "direct_decomp T [sum_list ` listset ss, sum_list ` listset (map cone ps)]"
    and 2: "direct_decomp (sum_list ` listset ss) ss"
    by (auto dest: direct_decomp_appendD intro!: empty_not_in_map_cone)
  note 1
  moreover from 2 have "cone_decomp (sum_list ` listset ss) (concat pss)"
  proof (rule Cons.hyps)
    fix i
    assume "i < length ss"
    hence "Suc i < length (s # ss)" by simp
    hence "cone_decomp ((s # ss) ! Suc i) ((ps # pss) ! Suc i)" by (rule Cons.prems)
    thus "cone_decomp (ss ! i) (pss ! i)" by simp
  qed
  moreover have "cone_decomp (sum_list ` listset (map cone ps)) ps"
  proof (intro cone_decompI direct_decompI refl)
    from * show "inj_on sum_list (listset (map cone ps))"
      by (simp only: direct_decomp_def bij_betw_def)
  qed
  ultimately have "cone_decomp T (concat pss @ ps)" by (rule cone_decomp_append)
  hence "direct_decomp T (map cone (concat pss) @ map cone ps)" by (simp add: cone_decomp_def)
  hence "direct_decomp T (map cone ps @ map cone (concat pss))"
    by (auto intro: direct_decomp_perm)
  thus ?case by (simp add: cone_decomp_def)
qed

lemma cone_decomp_map_times:
  assumes "cone_decomp T ps"
  shows "cone_decomp ((*) s ` T) (map (apfst ((*) (s::_ ⇒0 _::{comm_ring_1,ring_no_zero_divisors}))) ps)"
proof (rule cone_decompI)
  from assms have "direct_decomp T (map cone ps)" by (rule cone_decompD)
  hence "direct_decomp ((*) s ` T) (map ((`) ((*) s)) (map cone ps))"
    by (rule direct_decomp_image_times) (rule times_canc_left)
  also have "map ((`) ((*) s)) (map cone ps) = map cone (map (apfst ((*) s)) ps)"
    by (simp add: cone_image_times')
  finally show "direct_decomp ((*) s ` T) (map cone (map (apfst ((*) s)) ps))" .
qed

lemma cone_decomp_perm:
  assumes "cone_decomp T ps" and "mset ps = mset qs"
  shows "cone_decomp T qs"
  using assms(1) unfolding cone_decomp_def
proof (rule direct_decomp_perm)
  from ‹mset ps = mset qs› show ‹mset (map cone ps) = mset (map cone qs)›
    by simp
qed

lemma valid_cone_decomp_subset_Polys:
  assumes "valid_decomp X ps" and "cone_decomp T ps"
  shows "T ⊆ P[X]"
proof
  fix p
  assume "p ∈ T"
  from assms(2) have "direct_decomp T (map cone ps)" by (rule cone_decompD)
  then obtain qs where "qs ∈ listset (map cone ps)" and p: "p = sum_list qs" using ‹p ∈ T›
    by (rule direct_decompE)
  from assms(1) this(1) show "p ∈ P[X]" unfolding p
  proof (induct ps arbitrary: qs)
    case Nil
    from Nil(2) show ?case by (simp add: zero_in_Polys)
  next
    case (Cons a ps)
    obtain h U where a: "a = (h, U)" using prod.exhaust by blast
    hence "(h, U) ∈ set (a # ps)" by simp
    with Cons.prems(1) have "h ∈ P[X]" and "U ⊆ X" by (rule valid_decompD)+
    hence "cone a ⊆ P[X]" unfolding a by (rule cone_subset_PolysI)
    from Cons.prems(1) have "valid_decomp X ps" by (simp add: valid_decomp_def)
    from Cons.prems(2) have "qs ∈ listset (cone a # map cone ps)" by simp
    then obtain q qs' where "q ∈ cone a" and qs': "qs' ∈ listset (map cone ps)" and qs: "qs = q # qs'"
      by (rule listset_ConsE)
    from this(1) ‹cone a ⊆ P[X]› have "q ∈ P[X]" ..
    moreover from ‹valid_decomp X ps› qs' have "sum_list qs' ∈ P[X]" by (rule Cons.hyps)
    ultimately have "q + sum_list qs' ∈ P[X]" by (rule Polys_closed_plus)
    thus ?case by (simp add: qs)
  qed
qed

lemma homogeneous_set_cone_decomp:
  assumes "cone_decomp T ps" and "hom_decomp ps"
  shows "homogeneous_set T"
proof (rule homogeneous_set_direct_decomp)
  from assms(1) show "direct_decomp T (map cone ps)" by (rule cone_decompD)
next
  fix cn
  assume "cn ∈ set (map cone ps)"
  then obtain hU where "hU ∈ set ps" and cn: "cn = cone hU" unfolding set_map ..
  moreover obtain h U where hU: "hU = (h, U)" using prod.exhaust by blast
  ultimately have "(h, U) ∈ set ps" by simp
  with assms(2) have "homogeneous h" by (rule hom_decompD)
  thus "homogeneous_set cn" unfolding cn hU by (rule homogeneous_set_coneI)
qed

lemma subspace_cone_decomp:
  assumes "cone_decomp T ps"
  shows "phull.subspace (T::(_ ⇒0 _::field) set)"
proof (rule phull.subspace_direct_decomp)
  from assms show "direct_decomp T (map cone ps)" by (rule cone_decompD)
next
  fix cn
  assume "cn ∈ set (map cone ps)"
  then obtain hU where "hU ∈ set ps" and cn: "cn = cone hU" unfolding set_map ..
  show "phull.subspace cn" unfolding cn by (rule subspace_cone)
qed

definition pos_decomp :: "((('x ⇒0 nat) ⇒0 'a) × 'x set) list ⇒ ((('x ⇒0 nat) ⇒0 'a) × 'x set) list"
    (‹(_+)› [1000] 999)
    where "pos_decomp ps = filter (λp. snd p ≠ {}) ps"

definition standard_decomp :: "nat ⇒ ((('x ⇒0 nat) ⇒0 'a::zero) × 'x set) list ⇒ bool"
  where "standard_decomp k ps ⟷ (∀(h, U)∈set (ps+). k ≤ poly_deg h ∧
                                      (∀d. k ≤ d ⟶ d ≤ poly_deg h ⟶
                                        (∃(h', U')∈set ps. poly_deg h' = d ∧ card U ≤ card U')))"

lemma pos_decomp_Nil [simp]: "[]+ = []"
  by (simp add: pos_decomp_def)

lemma pos_decomp_subset: "set (ps+) ⊆ set ps"
  by (simp add: pos_decomp_def)

lemma pos_decomp_append: "(ps @ qs)+ = ps+ @ qs+"
  by (simp add: pos_decomp_def)

lemma pos_decomp_concat: "(concat pss)+ = concat (map pos_decomp pss)"
  by (metis (mono_tags, lifting) filter_concat map_eq_conv pos_decomp_def)

lemma pos_decomp_map: "(map (apfst f) ps)+ = map (apfst f) (ps+)"
  by (metis (mono_tags, lifting) pos_decomp_def filter_cong filter_map o_apply snd_apfst)

lemma card_Diff_pos_decomp: "card {(h, U) ∈ set qs - set (qs+). P h} = card {h. (h, {}) ∈ set qs ∧ P h}"
proof -
  have "{h. (h, {}) ∈ set qs ∧ P h} = fst ` {(h, U) ∈ set qs - set (qs+). P h}"
    by (auto simp: pos_decomp_def image_Collect)
  also have "card … = card {(h, U) ∈ set qs - set (qs+). P h}"
    by (rule card_image, auto simp: pos_decomp_def intro: inj_onI)
  finally show ?thesis by (rule sym)
qed

lemma standard_decompI:
  assumes "⋀h U. (h, U) ∈ set (ps+) ⟹ k ≤ poly_deg h"
    and "⋀h U d. (h, U) ∈ set (ps+) ⟹ k ≤ d ⟹ d ≤ poly_deg h ⟹
          (∃h' U'. (h', U') ∈ set ps ∧ poly_deg h' = d ∧ card U ≤ card U')"
  shows "standard_decomp k ps"
  unfolding standard_decomp_def using assms by blast

lemma standard_decompD: "standard_decomp k ps ⟹ (h, U) ∈ set (ps+) ⟹ k ≤ poly_deg h"
  unfolding standard_decomp_def by blast

lemma standard_decompE:
  assumes "standard_decomp k ps" and "(h, U) ∈ set (ps+)" and "k ≤ d" and "d ≤ poly_deg h"
  obtains h' U' where "(h', U') ∈ set ps" and "poly_deg h' = d" and "card U ≤ card U'"
  using assms unfolding standard_decomp_def by blast

lemma standard_decomp_Nil: "ps+ = [] ⟹ standard_decomp k ps"
  by (simp add: standard_decomp_def)

lemma standard_decomp_singleton: "standard_decomp (poly_deg h) [(h, U)]"
  by (simp add: standard_decomp_def pos_decomp_def)

lemma standard_decomp_concat:
  assumes "⋀ps. ps ∈ set pss ⟹ standard_decomp k ps"
  shows "standard_decomp k (concat pss)"
proof (rule standard_decompI)
  fix h U
  assume "(h, U) ∈ set ((concat pss)+)"
  then obtain ps where "ps ∈ set pss" and *: "(h, U) ∈ set (ps+)" by (auto simp: pos_decomp_concat)
  from this(1) have "standard_decomp k ps" by (rule assms)
  thus "k ≤ poly_deg h" using * by (rule standard_decompD)

  fix d
  assume "k ≤ d" and "d ≤ poly_deg h"
  with ‹standard_decomp k ps› * obtain h' U' where "(h', U') ∈ set ps" and "poly_deg h' = d"
    and "card U ≤ card U'" by (rule standard_decompE)
  note this(2, 3)
  moreover from ‹(h', U') ∈ set ps› ‹ps ∈ set pss› have "(h', U') ∈ set (concat pss)" by auto
  ultimately show "∃h' U'. (h', U') ∈ set (concat pss) ∧ poly_deg h' = d ∧ card U ≤ card U'"
    by blast
qed

corollary standard_decomp_append:
  assumes "standard_decomp k ps" and "standard_decomp k qs"
  shows "standard_decomp k (ps @ qs)"
proof -
  have "standard_decomp k (concat [ps, qs])" by (rule standard_decomp_concat) (auto simp: assms)
  thus ?thesis by simp
qed

lemma standard_decomp_map_times:
  assumes "standard_decomp k ps" and "valid_decomp X ps" and "s ≠ (0::_ ⇒0 'a::semiring_no_zero_divisors)"
  shows "standard_decomp (k + poly_deg s) (map (apfst ((*) s)) ps)"
proof (rule standard_decompI)
  fix h U
  assume "(h, U) ∈ set ((map (apfst ((*) s)) ps)+)"
  then obtain h0 where 1: "(h0, U) ∈ set (ps+)" and h: "h = s * h0" by (fastforce simp: pos_decomp_map)
  from this(1) pos_decomp_subset have "(h0, U) ∈ set ps" ..
  with assms(2) have "h0 ≠ 0" by (rule valid_decompD)
  with assms(3) have deg_h: "poly_deg h = poly_deg s + poly_deg h0" unfolding h by (rule poly_deg_times)
  moreover from assms(1) 1 have "k ≤ poly_deg h0" by (rule standard_decompD)
  ultimately show "k + poly_deg s ≤ poly_deg h" by simp

  fix d
  assume "k + poly_deg s ≤ d" and "d ≤ poly_deg h"
  hence "k ≤ d - poly_deg s" and "d - poly_deg s ≤ poly_deg h0" by (simp_all add: deg_h)
  with assms(1) 1 obtain h' U' where 2: "(h', U') ∈ set ps" and "poly_deg h' = d - poly_deg s"
    and "card U ≤ card U'" by (rule standard_decompE)
  from assms(2) this(1) have "h' ≠ 0" by (rule valid_decompD)
  with assms(3) have deg_h': "poly_deg (s * h') = poly_deg s + poly_deg h'" by (rule poly_deg_times)
  from 2 have "(s * h', U') ∈ set (map (apfst ((*) s)) ps)" by force
  moreover from ‹k + poly_deg s ≤ d› ‹poly_deg h' = d - poly_deg s› have "poly_deg (s * h') = d"
    by (simp add: deg_h')
  ultimately show "∃h' U'. (h', U') ∈ set (map (apfst ((*) s)) ps) ∧ poly_deg h' = d ∧ card U ≤ card U'"
    using ‹card U ≤ card U'› by fastforce
qed

lemma standard_decomp_nonempty_unique:
  assumes "finite X" and "valid_decomp X ps" and "standard_decomp k ps" and "ps+ ≠ []"
  shows "k = Min (poly_deg ` fst ` set (ps+))"
proof -
  let ?A = "poly_deg ` fst ` set (ps+)"
  define m where "m = Min ?A"
  have "finite ?A" by simp
  moreover from assms(4) have "?A ≠ {}" by simp
  ultimately have "m ∈ ?A" unfolding m_def by (rule Min_in)
  then obtain h U where "(h, U) ∈ set (ps+)" and m: "m = poly_deg h" by fastforce
  have m_min: "m ≤ poly_deg h'" if "(h', U') ∈ set (ps+)" for h' U'
  proof -
    from that have "poly_deg (fst (h', U')) ∈ ?A" by (intro imageI)
    with ‹finite ?A› have "m ≤ poly_deg (fst (h', U'))" unfolding m_def by (rule Min_le)
    thus ?thesis by simp
  qed
  show ?thesis
  proof (rule linorder_cases)
    assume "k < m"
    hence "k ≤ poly_deg h" by (simp add: m)
    with assms(3) ‹(h, U) ∈ set (ps+)› le_refl obtain h' U'
      where "(h', U') ∈ set ps" and "poly_deg h' = k" and "card U ≤ card U'" by (rule standard_decompE)
    from this(2) ‹k < m› have "¬ m ≤ poly_deg h'" by simp
    with m_min have "(h', U') ∉ set (ps+)" by blast
    with ‹(h', U') ∈ set ps› have "U' = {}" by (simp add: pos_decomp_def)
    with ‹card U ≤ card U'› have "U = {} ∨ infinite U" by (simp add: card_eq_0_iff)
    thus ?thesis
    proof
      assume "U = {}"
      with ‹(h, U) ∈ set (ps+)› show ?thesis by (simp add: pos_decomp_def)
    next
      assume "infinite U"
      moreover from assms(1, 2) have "finite U"
      proof (rule valid_decompD_finite)
        from ‹(h, U) ∈ set (ps+)› show "(h, U) ∈ set ps" by (simp add: pos_decomp_def)
      qed
      ultimately show ?thesis ..
    qed
  next
    assume "m < k"
    hence "¬ k ≤ m" by simp
    moreover from assms(3) ‹(h, U) ∈ set (ps+)› have "k ≤ m" unfolding m by (rule standard_decompD)
    ultimately show ?thesis ..
  qed (simp only: m_def)
qed

lemma standard_decomp_SucE:
  assumes "finite X" and "U ⊆ X" and "h ∈ P[X]" and "h ≠ (0::_ ⇒0 'a::{comm_ring_1,ring_no_zero_divisors})"
  obtains ps where "valid_decomp X ps" and "cone_decomp (cone (h, U)) ps"
    and "standard_decomp (Suc (poly_deg h)) ps"
    and "is_monomial h ⟹ punit.lc h = 1 ⟹ monomial_decomp ps" and "homogeneous h ⟹ hom_decomp ps"
proof -
  from assms(2, 1) have "finite U" by (rule finite_subset)
  thus ?thesis using assms(2) that
  proof (induct U arbitrary: thesis rule: finite_induct)
    case empty
    from assms(3, 4) have "valid_decomp X [(h, {})]" by (simp add: valid_decomp_def)
    moreover note cone_decomp_singleton
    moreover have "standard_decomp (Suc (poly_deg h)) [(h, {})]"
      by (rule standard_decomp_Nil) (simp add: pos_decomp_def)
    ultimately show ?case by (rule empty) (simp_all add: monomial_decomp_def hom_decomp_def)
  next
    case (insert x U)
    from insert.prems(1) have "x ∈ X" and "U ⊆ X" by simp_all
    from this(2) obtain ps where 0: "valid_decomp X ps" and 1: "cone_decomp (cone (h, U)) ps"
      and 2: "standard_decomp (Suc (poly_deg h)) ps"
      and 3: "is_monomial h ⟹ punit.lc h = 1 ⟹ monomial_decomp ps"
      and 4: "homogeneous h ⟹ hom_decomp ps" by (rule insert.hyps) blast
    let ?x = "monomial (1::'a) (Poly_Mapping.single x (Suc 0))"
    have "?x ≠ 0" by (simp add: monomial_0_iff)
    with assms(4) have deg: "poly_deg (?x * h) = Suc (poly_deg h)"
      by (simp add: poly_deg_times poly_deg_monomial deg_pm_single)
    define qs where "qs = [(?x * h, insert x U)]"
    show ?case
    proof (rule insert.prems)
      from ‹x ∈ X› have "?x ∈ P[X]" by (intro Polys_closed_monomial PPs_closed_single)
      hence "?x * h ∈ P[X]" using assms(3) by (rule Polys_closed_times)
      moreover from ‹?x ≠ 0› assms(4) have "?x * h ≠ 0" by (rule times_not_zero)
      ultimately have "valid_decomp X qs" using insert.hyps(1) ‹x ∈ X› ‹U ⊆ X›
        by (simp add: qs_def valid_decomp_def)
      with 0 show "valid_decomp X (ps @ qs)" by (rule valid_decomp_append)
    next
      show "cone_decomp (cone (h, insert x U)) (ps @ qs)"
      proof (rule cone_decomp_append)
        show "direct_decomp (cone (h, insert x U)) [cone (h, U), cone (?x * h, insert x U)]"
          using insert.hyps(2) by (rule direct_decomp_cone_insert)
      next
        show "cone_decomp (cone (?x * h, insert x U)) qs"
          by (simp add: qs_def cone_decomp_singleton)
      qed (fact 1)
    next
      from standard_decomp_singleton[of "?x * h" "insert x U"]
      have "standard_decomp (Suc (poly_deg h)) qs" by (simp add: deg qs_def)
      with 2 show "standard_decomp (Suc (poly_deg h)) (ps @ qs)" by (rule standard_decomp_append)
    next
      assume "is_monomial h" and "punit.lc h = 1"
      hence "monomial_decomp ps" by (rule 3)
      moreover have "monomial_decomp qs"
      proof -
        have "is_monomial (?x * h)"
          by (metis ‹is_monomial h› is_monomial_monomial monomial_is_monomial mult.commute
              mult.right_neutral mult_single)
        thus ?thesis by (simp add: monomial_decomp_def qs_def lc_times ‹punit.lc h = 1›)
      qed
      ultimately show "monomial_decomp (ps @ qs)" by (simp only: monomial_decomp_append_iff)
    next
      assume "homogeneous h"
      hence "hom_decomp ps" by (rule 4)
      moreover from ‹homogeneous h› have "hom_decomp qs"
        by (simp add: hom_decomp_def qs_def homogeneous_times)
      ultimately show "hom_decomp (ps @ qs)" by (simp only: hom_decomp_append_iff)
    qed
  qed
qed

lemma standard_decomp_geE:
  assumes "finite X" and "valid_decomp X ps"
    and "cone_decomp (T::(('x ⇒0 nat) ⇒0 'a::{comm_ring_1,ring_no_zero_divisors}) set) ps"
    and "standard_decomp k ps" and "k ≤ d"
  obtains qs where "valid_decomp X qs" and "cone_decomp T qs" and "standard_decomp d qs"
    and "monomial_decomp ps ⟹ monomial_decomp qs" and "hom_decomp ps ⟹ hom_decomp qs"
proof -
  have "∃qs. valid_decomp X qs ∧ cone_decomp T qs ∧ standard_decomp (k + i) qs ∧
              (monomial_decomp ps ⟶ monomial_decomp qs) ∧ (hom_decomp ps ⟶ hom_decomp qs)" for i
  proof (induct i)
    case 0
    from assms(2, 3, 4) show ?case unfolding add_0_right by blast
  next
    case (Suc i)
    then obtain qs where 0: "valid_decomp X qs" and 1: "cone_decomp T qs"
      and 2: "standard_decomp (k + i) qs" and 3: "monomial_decomp ps ⟹ monomial_decomp qs"
      and 4: "hom_decomp ps ⟹ hom_decomp qs" by blast
    let ?P = "λhU. poly_deg (fst hU) ≠ k + i"
    define rs where "rs = filter (- ?P) qs"
    define ss where "ss = filter ?P qs"

    have "set rs ⊆ set qs" by (auto simp: rs_def)
    have "set ss ⊆ set qs" by (auto simp: ss_def)

    define f where "f = (λhU. SOME ps'. valid_decomp X ps' ∧ cone_decomp (cone hU) ps' ∧
                                        standard_decomp (Suc (poly_deg ((fst hU)::('x ⇒0 _) ⇒0 'a))) ps' ∧
                                        (monomial_decomp ps ⟶ monomial_decomp ps') ∧
                                        (hom_decomp ps ⟶ hom_decomp ps'))"
    have "valid_decomp X (f hU) ∧ cone_decomp (cone hU) (f hU) ∧ standard_decomp (Suc (k + i)) (f hU) ∧
          (monomial_decomp ps ⟶ monomial_decomp (f hU)) ∧ (hom_decomp ps ⟶ hom_decomp (f hU))"
      if "hU ∈ set rs" for hU
    proof -
      obtain h U where hU: "hU = (h, U)" using prod.exhaust by blast
      with that have eq: "poly_deg (fst hU) = k + i" by (simp add: rs_def)
      from that ‹set rs ⊆ set qs› have "(h, U) ∈ set qs" unfolding hU ..
      with 0 have "U ⊆ X" and "h ∈ P[X]" and "h ≠ 0" by (rule valid_decompD)+
      with assms(1) obtain ps' where "valid_decomp X ps'" and "cone_decomp (cone (h, U)) ps'"
        and "standard_decomp (Suc (poly_deg h)) ps'"
        and md: "is_monomial h ⟹ punit.lc h = 1 ⟹ monomial_decomp ps'"
        and hd: "homogeneous h ⟹ hom_decomp ps'" by (rule standard_decomp_SucE) blast
      note this(1-3)
      moreover have "monomial_decomp ps'" if "monomial_decomp ps"
      proof -
        from that have "monomial_decomp qs" by (rule 3)
        hence "is_monomial h" and "punit.lc h = 1" using ‹(h, U) ∈ set qs› by (rule monomial_decompD)+
        thus ?thesis by (rule md)
      qed
      moreover have "hom_decomp ps'" if "hom_decomp ps"
      proof -
        from that have "hom_decomp qs" by (rule 4)
        hence "homogeneous h" using ‹(h, U) ∈ set qs› by (rule hom_decompD)
        thus ?thesis by (rule hd)
      qed
      ultimately have "valid_decomp X ps' ∧ cone_decomp (cone hU) ps' ∧
          standard_decomp (Suc (poly_deg (fst hU))) ps' ∧ (monomial_decomp ps ⟶ monomial_decomp ps') ∧
          (hom_decomp ps ⟶ hom_decomp ps')" by (simp add: hU)
      thus ?thesis unfolding f_def eq by (rule someI)
    qed
    hence f1: "⋀ps. ps ∈ set (map f rs) ⟹ valid_decomp X ps"
      and f2: "⋀hU. hU ∈ set rs ⟹ cone_decomp (cone hU) (f hU)"
      and f3: "⋀ps. ps ∈ set (map f rs) ⟹ standard_decomp (Suc (k + i)) ps"
      and f4: "⋀ps'. monomial_decomp ps ⟹ ps' ∈ set (map f rs) ⟹ monomial_decomp ps'"
      and f5: "⋀ps'. hom_decomp ps ⟹ ps' ∈ set (map f rs) ⟹ hom_decomp ps'" by auto

    define rs' where "rs' = concat (map f rs)"
    show ?case unfolding add_Suc_right
    proof (intro exI conjI impI)
      have "valid_decomp X ss"
      proof (rule valid_decompI)
        fix h U
        assume "(h, U) ∈ set ss"
        hence "(h, U) ∈ set qs" using ‹set ss ⊆ set qs› ..
        with 0 show "h ∈ P[X]" and "h ≠ 0" and "U ⊆ X" by (rule valid_decompD)+
      qed
      moreover have "valid_decomp X rs'"
        unfolding rs'_def using f1 by (rule valid_decomp_concat)
      ultimately show "valid_decomp X (ss @ rs')" by (rule valid_decomp_append)
    next
      from 1 have "direct_decomp T (map cone qs)" by (rule cone_decompD)
      hence "direct_decomp T ((map cone ss) @ (map cone rs))" unfolding ss_def rs_def
        by (rule direct_decomp_split_map)
      hence ss: "cone_decomp (sum_list ` listset (map cone ss)) ss"
        and "cone_decomp (sum_list ` listset (map cone rs)) rs"
        and T: "direct_decomp T [sum_list ` listset (map cone ss), sum_list ` listset (map cone rs)]"
        by (auto simp: cone_decomp_def dest: direct_decomp_appendD intro!: empty_not_in_map_cone)
      from this(2) have "direct_decomp (sum_list ` listset (map cone rs)) (map cone rs)"
        by (rule cone_decompD)
      hence "cone_decomp (sum_list ` listset (map cone rs)) rs'" unfolding rs'_def
      proof (rule cone_decomp_concat)
        fix i
        assume *: "i < length (map cone rs)"
        hence "rs ! i ∈ set rs" by simp
        hence "cone_decomp (cone (rs ! i)) (f (rs ! i))" by (rule f2)
        with * show "cone_decomp (map cone rs ! i) (map f rs ! i)" by simp
      qed simp
      with T ss show "cone_decomp T (ss @ rs')" by (rule cone_decomp_append)
    next
      have "standard_decomp (Suc (k + i)) ss"
      proof (rule standard_decompI)
        fix h U
        assume "(h, U) ∈ set (ss+)"
        hence "(h, U) ∈ set (qs+)" and "poly_deg h ≠ k + i" by (simp_all add: pos_decomp_def ss_def)
        from 2 this(1) have "k + i ≤ poly_deg h" by (rule standard_decompD)
        with ‹poly_deg h ≠ k + i› show "Suc (k + i) ≤ poly_deg h" by simp
  
        fix d'
        assume "Suc (k + i) ≤ d'" and "d' ≤ poly_deg h"
        from this(1) have "k + i ≤ d'" and "d' ≠ k + i" by simp_all
        from 2 ‹(h, U) ∈ set (qs+)› this(1) obtain h' U'
          where "(h', U') ∈ set qs" and "poly_deg h' = d'" and "card U ≤ card U'"
          using ‹d' ≤ poly_deg h› by (rule standard_decompE)
        moreover from ‹d' ≠ k + i› this(1, 2) have "(h', U') ∈ set ss" by (simp add: ss_def)
        ultimately show "∃h' U'. (h', U') ∈ set ss ∧ poly_deg h' = d' ∧ card U ≤ card U'" by blast
      qed
      moreover have "standard_decomp (Suc (k + i)) rs'"
        unfolding rs'_def using f3 by (rule standard_decomp_concat)
      ultimately show "standard_decomp (Suc (k + i)) (ss @ rs')" by (rule standard_decomp_append)
    next
      assume *: "monomial_decomp ps"
      hence "monomial_decomp qs" by (rule 3)
      hence "monomial_decomp ss" by (simp add: monomial_decomp_def ss_def)
      moreover have "monomial_decomp rs'"
        unfolding rs'_def using f4[OF *] by (rule monomial_decomp_concat)
      ultimately show "monomial_decomp (ss @ rs')" by (simp only: monomial_decomp_append_iff)
    next
      assume *: "hom_decomp ps"
      hence "hom_decomp qs" by (rule 4)
      hence "hom_decomp ss" by (simp add: hom_decomp_def ss_def)
      moreover have "hom_decomp rs'" unfolding rs'_def using f5[OF *] by (rule hom_decomp_concat)
      ultimately show "hom_decomp (ss @ rs')" by (simp only: hom_decomp_append_iff)
    qed
  qed
  then obtain qs where 1: "valid_decomp X qs" and 2: "cone_decomp T qs"
    and "standard_decomp (k + (d - k)) qs" and 4: "monomial_decomp ps ⟹ monomial_decomp qs"
    and 5: "hom_decomp ps ⟹ hom_decomp qs" by blast
  from this(3) assms(5) have "standard_decomp d qs" by simp
  with 1 2 show ?thesis using 4 5 ..
qed

subsection ‹Splitting w.r.t. Ideals›

context
  fixes X :: "'x set"
begin

definition splits_wrt :: "(((('x ⇒0 nat) ⇒0 'a) × 'x set) list × ((('x ⇒0 nat) ⇒0 'a) × 'x set) list) ⇒
                          (('x ⇒0 nat) ⇒0 'a::comm_ring_1) set ⇒ (('x ⇒0 nat) ⇒0 'a) set ⇒ bool"
  where "splits_wrt pqs T F ⟷ cone_decomp T (fst pqs @ snd pqs) ∧
                                (∀hU∈set (fst pqs). cone hU ⊆ ideal F ∩ P[X]) ∧
                                (∀(h, U)∈set (snd pqs). cone (h, U) ⊆ P[X] ∧ cone (h, U) ∩ ideal F = {0})"

lemma splits_wrtI:
  assumes "cone_decomp T (ps @ qs)"
    and "⋀h U. (h, U) ∈ set ps ⟹ cone (h, U) ⊆ P[X]" and "⋀h U. (h, U) ∈ set ps ⟹ h ∈ ideal F"
    and "⋀h U. (h, U) ∈ set qs ⟹ cone (h, U) ⊆ P[X]"
    and "⋀h U a. (h, U) ∈ set qs ⟹ a ∈ cone (h, U) ⟹ a ∈ ideal F ⟹ a = 0"
  shows "splits_wrt (ps, qs) T F"
  unfolding splits_wrt_def fst_conv snd_conv
proof (intro conjI ballI)
  fix hU
  assume "hU ∈ set ps"
  moreover obtain h U where hU: "hU = (h, U)" using prod.exhaust by blast
  ultimately have "(h, U) ∈ set ps" by simp
  hence "cone (h, U) ⊆ P[X]" and "h ∈ ideal F" by (rule assms)+
  from _ this(1) show "cone hU ⊆ ideal F ∩ P[X]" unfolding hU
  proof (rule Int_greatest)
    show "cone (h, U) ⊆ ideal F"
    proof
      fix a
      assume "a ∈ cone (h, U)"
      then obtain a' where "a' ∈ P[U]" and a: "a = a' * h" by (rule coneE)
      from ‹h ∈ ideal F› show "a ∈ ideal F" unfolding a by (rule ideal.span_scale)
    qed
  qed
next
  fix hU
  assume "hU ∈ set qs"
  moreover obtain h U where hU: "hU = (h, U)" using prod.exhaust by blast
  ultimately have "(h, U) ∈ set qs" by simp
  hence "cone (h, U) ⊆ P[X]" and "⋀a. a ∈ cone (h, U) ⟹ a ∈ ideal F ⟹ a = 0" by (rule assms)+
  moreover have "0 ∈ cone (h, U) ∩ ideal F"
    by (simp add: zero_in_cone ideal.span_zero)
  ultimately show "case hU of (h, U) ⇒ cone (h, U) ⊆ P[X] ∧ cone (h, U) ∩ ideal F = {0}"
    by (fastforce simp: hU)
qed (fact assms)+

lemma splits_wrtI_valid_decomp:
  assumes "valid_decomp X ps" and "valid_decomp X qs" and "cone_decomp T (ps @ qs)"
    and "⋀h U. (h, U) ∈ set ps ⟹ h ∈ ideal F"
    and "⋀h U a. (h, U) ∈ set qs ⟹ a ∈ cone (h, U) ⟹ a ∈ ideal F ⟹ a = 0"
  shows "splits_wrt (ps, qs) T F"
  using assms(3) _ _ _ assms(5)
proof (rule splits_wrtI)
  fix h U
  assume "(h, U) ∈ set ps"
  thus "h ∈ ideal F" by (rule assms(4))
  from assms(1) ‹(h, U) ∈ set ps› have "h ∈ P[X]" and "U ⊆ X" by (rule valid_decompD)+
  thus "cone (h, U) ⊆ P[X]" by (rule cone_subset_PolysI)
next
  fix h U
  assume "(h, U) ∈ set qs"
  with assms(2) have "h ∈ P[X]" by (rule valid_decompD)
  moreover from assms(2) ‹(h, U) ∈ set qs› have "U ⊆ X" by (rule valid_decompD)
  ultimately show "cone (h, U) ⊆ P[X]" by (rule cone_subset_PolysI)
qed

lemma splits_wrtD:
  assumes "splits_wrt (ps, qs) T F"
  shows "cone_decomp T (ps @ qs)" and "hU ∈ set ps ⟹ cone hU ⊆ ideal F ∩ P[X]"
    and "hU ∈ set qs ⟹ cone hU ⊆ P[X]" and "hU ∈ set qs ⟹ cone hU ∩ ideal F = {0}"
  using assms by (fastforce simp: splits_wrt_def)+

lemma splits_wrt_image_sum_list_fst_subset:
  assumes "splits_wrt (ps, qs) T F"
  shows "sum_list ` listset (map cone ps) ⊆ ideal F ∩ P[X]"
proof
  fix x
  assume x_in: "x ∈ sum_list ` listset (map cone ps)"
  have "listset (map cone ps) ⊆ listset (map (λ_. ideal F ∩ P[X]) ps)"
  proof (rule listset_mono)
    fix i
    assume i: "i < length (map (λ_. ideal F ∩ P[X]) ps)"
    hence "ps ! i ∈ set ps" by simp
    with assms(1) have "cone (ps ! i) ⊆ ideal F ∩ P[X]" by (rule splits_wrtD)
    with i show "map cone ps ! i ⊆ map (λ_. ideal F ∩ P[X]) ps ! i" by simp
  qed simp
  hence "sum_list ` listset (map cone ps) ⊆ sum_list ` listset (map (λ_. ideal F ∩ P[X]) ps)"
    by (rule image_mono)
  with x_in have "x ∈ sum_list ` listset (map (λ_. ideal F ∩ P[X]) ps)" ..
  then obtain xs where xs: "xs ∈ listset (map (λ_. ideal F ∩ P[X]) ps)" and x: "x = sum_list xs" ..
  have 1: "y ∈ ideal F ∩ P[X]" if "y ∈ set xs" for y
  proof -
    from that obtain i where "i < length xs" and y: "y = xs ! i" by (metis in_set_conv_nth)
    moreover from xs have "length xs = length (map (λ_. ideal F ∩ P[X]) ps)"
      by (rule listsetD)
    ultimately have "i < length (map (λ_. ideal F ∩ P[X]) ps)" by simp
    moreover from xs this have "xs ! i ∈ (map (λ_. ideal F ∩ P[X]) ps) ! i" by (rule listsetD)
    ultimately show "y ∈ ideal F ∩ P[X]" by (simp add: y)
  qed
  show "x ∈ ideal F ∩ P[X]" unfolding x
  proof
    show "sum_list xs ∈ ideal F"
    proof (rule ideal.span_closed_sum_list[simplified])
      fix y
      assume "y ∈ set xs"
      hence "y ∈ ideal F ∩ P[X]" by (rule 1)
      thus "y ∈ ideal F" by simp
    qed
  next
    show "sum_list xs ∈ P[X]"
    proof (rule Polys_closed_sum_list)
      fix y
      assume "y ∈ set xs"
      hence "y ∈ ideal F ∩ P[X]" by (rule 1)
      thus "y ∈ P[X]" by simp
    qed
  qed
qed

lemma splits_wrt_image_sum_list_snd_subset:
  assumes "splits_wrt (ps, qs) T F"
  shows "sum_list ` listset (map cone qs) ⊆ P[X]"
proof
  fix x
  assume x_in: "x ∈ sum_list ` listset (map cone qs)"
  have "listset (map cone qs) ⊆ listset (map (λ_. P[X]) qs)"
  proof (rule listset_mono)
    fix i
    assume i: "i < length (map (λ_. P[X]) qs)"
    hence "qs ! i ∈ set qs" by simp
    with assms(1) have "cone (qs ! i) ⊆ P[X]" by (rule splits_wrtD)
    with i show "map cone qs ! i ⊆ map (λ_. P[X]) qs ! i" by simp
  qed simp
  hence "sum_list ` listset (map cone qs) ⊆ sum_list ` listset (map (λ_. P[X]) qs)"
    by (rule image_mono)
  with x_in have "x ∈ sum_list ` listset (map (λ_. P[X]) qs)" ..
  then obtain xs where xs: "xs ∈ listset (map (λ_. P[X]) qs)" and x: "x = sum_list xs" ..
  show "x ∈ P[X]" unfolding x
  proof (rule Polys_closed_sum_list)
    fix y
    assume "y ∈ set xs"
    then obtain i where "i < length xs" and y: "y = xs ! i" by (metis in_set_conv_nth)
    moreover from xs have "length xs = length (map (λ_. P[X]::(_ ⇒0 'a) set) qs)"
      by (rule listsetD)
    ultimately have "i < length (map (λ_. P[X]) qs)" by simp
    moreover from xs this have "xs ! i ∈ (map (λ_. P[X]) qs) ! i" by (rule listsetD)
    ultimately show "y ∈ P[X]" by (simp add: y)
  qed
qed

lemma splits_wrt_cone_decomp_1:
  assumes "splits_wrt (ps, qs) T F" and "monomial_decomp qs" and "is_monomial_set (F::(_ ⇒0 'a::field) set)"
        ―‹The last two assumptions are missing in the paper.›
  shows "cone_decomp (T ∩ ideal F) ps"
proof -
  from assms(1) have *: "cone_decomp T (ps @ qs)" by (rule splits_wrtD)
  hence "direct_decomp T (map cone ps @ map cone qs)" by (simp add: cone_decomp_def)
  hence 1: "direct_decomp (sum_list ` listset (map cone ps)) (map cone ps)"
    and 2: "direct_decomp T [sum_list ` listset (map cone ps), sum_list ` listset (map cone qs)]"
    by (auto dest: direct_decomp_appendD intro!: empty_not_in_map_cone)
  let ?ss = "[sum_list ` listset (map cone ps), sum_list ` listset (map cone qs)]"
  show ?thesis
  proof (intro cone_decompI direct_decompI)
    from 1 show "inj_on sum_list (listset (map cone ps))" by (simp only: direct_decomp_def bij_betw_def)
  next
    from assms(1) have "sum_list ` listset (map cone ps) ⊆ ideal F ∩ P[X]"
      by (rule splits_wrt_image_sum_list_fst_subset)
    hence sub: "sum_list ` listset (map cone ps) ⊆ ideal F" by simp
    show "sum_list ` listset (map cone ps) = T ∩ ideal F"
    proof (rule set_eqI)
      fix x
      show "x ∈ sum_list ` listset (map cone ps) ⟷ x ∈ T ∩ ideal F"
      proof
        assume x_in: "x ∈ sum_list ` listset (map cone ps)"
        show "x ∈ T ∩ ideal F"
        proof (intro IntI)
          have "map (λ_. 0) qs ∈ listset (map cone qs)" (is "?ys ∈ _")
            by (induct qs) (auto intro: listset_ConsI zero_in_cone simp del: listset.simps(2))
          hence "sum_list ?ys ∈ sum_list ` listset (map cone qs)" by (rule imageI)
          hence "0 ∈ sum_list ` listset (map cone qs)" by simp
          with x_in have "[x, 0] ∈ listset ?ss" using refl by (rule listset_doubletonI)
          with 2 have "sum_list [x, 0] ∈ T" by (rule direct_decompD)
          thus "x ∈ T" by simp
        next
          from x_in sub show "x ∈ ideal F" ..
        qed
      next
        assume "x ∈ T ∩ ideal F"
        hence "x ∈ T" and "x ∈ ideal F" by simp_all
        from 2 this(1) obtain xs where "xs ∈ listset ?ss" and x: "x = sum_list xs"
          by (rule direct_decompE)
        from this(1) obtain p q where p: "p ∈ sum_list ` listset (map cone ps)"
          and q: "q ∈ sum_list ` listset (map cone qs)" and xs: "xs = [p, q]"
          by (rule listset_doubletonE)
        from ‹x ∈ ideal F› have "p + q ∈ ideal F" by (simp add: x xs)
        moreover from p sub have "p ∈ ideal F" ..
        ultimately have "p + q - p ∈ ideal F" by (rule ideal.span_diff)
        hence "q ∈ ideal F" by simp
        have "q = 0"
        proof (rule ccontr)
          assume "q ≠ 0"
          hence "keys q ≠ {}" by simp
          then obtain t where "t ∈ keys q" by blast
          with assms(2) q obtain c h U where "(h, U) ∈ set qs" and "c ≠ 0"
            and "monomial c t ∈ cone (h, U)" by (rule monomial_decomp_sum_list_monomial_in_cone)
          moreover from assms(3) ‹q ∈ ideal F› ‹t ∈ keys q› have "monomial c t ∈ ideal F"
            by (rule punit.monomial_pmdl_field[simplified])
          ultimately have "monomial c t ∈ cone (h, U) ∩ ideal F" by simp
          also from assms(1) ‹(h, U) ∈ set qs› have "… = {0}" by (rule splits_wrtD)
          finally have "c = 0" by (simp add: monomial_0_iff)
          with ‹c ≠ 0› show False ..
        qed
        with p show "x ∈ sum_list ` listset (map cone ps)" by (simp add: x xs)
      qed
    qed
  qed
qed

text ‹Together, Theorems ‹splits_wrt_image_sum_list_fst_subset› and ‹splits_wrt_cone_decomp_1›
  imply that @{term ps} is also a cone decomposition of @{term "T ∩ ideal F ∩ P[X]"}.›

lemma splits_wrt_cone_decomp_2:
  assumes "finite X" and "splits_wrt (ps, qs) T F" and "monomial_decomp qs" and "is_monomial_set F"
    and "F ⊆ P[X]"
  shows "cone_decomp (T ∩ normal_form F ` P[X]) qs"
proof -
  from assms(2) have *: "cone_decomp T (ps @ qs)" by (rule splits_wrtD)
  hence "direct_decomp T (map cone ps @ map cone qs)" by (simp add: cone_decomp_def)
  hence 1: "direct_decomp (sum_list ` listset (map cone qs)) (map cone qs)"
    and 2: "direct_decomp T [sum_list ` listset (map cone ps), sum_list ` listset (map cone qs)]"
    by (auto dest: direct_decomp_appendD intro!: empty_not_in_map_cone)
  let ?ss = "[sum_list ` listset (map cone ps), sum_list ` listset (map cone qs)]"
  let ?G = "punit.reduced_GB F"
  from assms(1, 5) have "?G ⊆ P[X]" and G_is_GB: "punit.is_Groebner_basis ?G"
    and ideal_G: "ideal ?G = ideal F"
    by (rule reduced_GB_Polys, rule reduced_GB_is_GB_Polys, rule reduced_GB_ideal_Polys)
  show ?thesis
  proof (intro cone_decompI direct_decompI)
    from 1 show "inj_on sum_list (listset (map cone qs))" by (simp only: direct_decomp_def bij_betw_def)
  next
    from assms(2) have "sum_list ` listset (map cone ps) ⊆ ideal F ∩ P[X]"
      by (rule splits_wrt_image_sum_list_fst_subset)
    hence sub: "sum_list ` listset (map cone ps) ⊆ ideal F" by simp
    show "sum_list ` listset (map cone qs) = T ∩ normal_form F ` P[X]"
    proof (rule set_eqI)
      fix x
      show "x ∈ sum_list ` listset (map cone qs) ⟷ x ∈ T ∩ normal_form F ` P[X]"
      proof
        assume x_in: "x ∈ sum_list ` listset (map cone qs)"
        show "x ∈ T ∩ normal_form F ` P[X]"
        proof (intro IntI)
          have "map (λ_. 0) ps ∈ listset (map cone ps)" (is "?ys ∈ _")
            by (induct ps) (auto intro: listset_ConsI zero_in_cone simp del: listset.simps(2))
          hence "sum_list ?ys ∈ sum_list ` listset (map cone ps)" by (rule imageI)
          hence "0 ∈ sum_list ` listset (map cone ps)" by simp
          from this x_in have "[0, x] ∈ listset ?ss" using refl by (rule listset_doubletonI)
          with 2 have "sum_list [0, x] ∈ T" by (rule direct_decompD)
          thus "x ∈ T" by simp
        next
          from assms(2) have "sum_list ` listset (map cone qs) ⊆ P[X]"
            by (rule splits_wrt_image_sum_list_snd_subset)
          with x_in have "x ∈ P[X]" ..
          moreover have "¬ punit.is_red ?G x"
          proof
            assume "punit.is_red ?G x"
            then obtain g t where "g ∈ ?G" and "t ∈ keys x" and "g ≠ 0" and adds: "lpp g adds t"
              by (rule punit.is_red_addsE[simplified])
            from assms(3) x_in this(2) obtain c h U where "(h, U) ∈ set qs" and "c ≠ 0"
              and "monomial c t ∈ cone (h, U)" by (rule monomial_decomp_sum_list_monomial_in_cone)
            note this(3)
            moreover have "monomial c t ∈ ideal ?G"
            proof (rule punit.is_red_monomial_monomial_set_in_pmdl[simplified])
              from ‹c ≠ 0› show "is_monomial (monomial c t)" by (rule monomial_is_monomial)
            next
              from assms(1, 5, 4) show "is_monomial_set ?G" by (rule reduced_GB_is_monomial_set_Polys)
            next
              from ‹c ≠ 0› have "t ∈ keys (monomial c t)" by simp
              with ‹g ∈ ?G› ‹g ≠ 0› show "punit.is_red ?G (monomial c t)" using adds
                by (rule punit.is_red_addsI[simplified])
            qed
            ultimately have "monomial c t ∈ cone (h, U) ∩ ideal F" by (simp add: ideal_G)
            also from assms(2) ‹(h, U) ∈ set qs› have "… = {0}" by (rule splits_wrtD)
            finally have "c = 0" by (simp add: monomial_0_iff)
            with ‹c ≠ 0› show False ..
          qed
          ultimately show "x ∈ normal_form F ` P[X]"
            using assms(1, 5) by (simp add: image_normal_form_iff)
        qed
      next
        assume "x ∈ T ∩ normal_form F ` P[X]"
        hence "x ∈ T" and "x ∈ normal_form F ` P[X]" by simp_all
        from this(2) assms(1, 5) have "x ∈ P[X]" and irred: "¬ punit.is_red ?G x"
          by (simp_all add: image_normal_form_iff)
        from 2 ‹x ∈ T› obtain xs where "xs ∈ listset ?ss" and x: "x = sum_list xs"
          by (rule direct_decompE)
        from this(1) obtain p q where p: "p ∈ sum_list ` listset (map cone ps)"
          and q: "q ∈ sum_list ` listset (map cone qs)" and xs: "xs = [p, q]"
          by (rule listset_doubletonE)
        have "x = p + q" by (simp add: x xs)
        from p sub have "p ∈ ideal F" ..
        have "p = 0"
        proof (rule ccontr)
          assume "p ≠ 0"
          hence "keys p ≠ {}" by simp
          then obtain t where "t ∈ keys p" by blast
          from assms(4) ‹p ∈ ideal F› ‹t ∈ keys p› have 3: "monomial c t ∈ ideal F" for c
            by (rule punit.monomial_pmdl_field[simplified])
          have "t ∉ keys q"
          proof
            assume "t ∈ keys q"
            with assms(3) q obtain c h U where "(h, U) ∈ set qs" and "c ≠ 0"
              and "monomial c t ∈ cone (h, U)" by (rule monomial_decomp_sum_list_monomial_in_cone)
            from this(3) 3 have "monomial c t ∈ cone (h, U) ∩ ideal F" by simp
            also from assms(2) ‹(h, U) ∈ set qs› have "… = {0}" by (rule splits_wrtD)
            finally have "c = 0" by (simp add: monomial_0_iff)
            with ‹c ≠ 0› show False ..
          qed
          with ‹t ∈ keys p› have "t ∈ keys x" unfolding ‹x = p + q› by (rule in_keys_plusI1)
          have "punit.is_red ?G x"
          proof -
            note G_is_GB
            moreover from 3 have "monomial 1 t ∈ ideal ?G" by (simp only: ideal_G)
            moreover have "monomial (1::'a) t ≠ 0" by (simp add: monomial_0_iff)
            ultimately obtain g where "g ∈ ?G" and "g ≠ 0"
              and "lpp g adds lpp (monomial (1::'a) t)" by (rule punit.GB_adds_lt[simplified])
            from this(3) have "lpp g adds t" by (simp add: punit.lt_monomial)
            with ‹g ∈ ?G› ‹g ≠ 0› ‹t ∈ keys x› show ?thesis by (rule punit.is_red_addsI[simplified])
          qed
          with irred show False ..
        qed
        with q show "x ∈ sum_list ` listset (map cone qs)" by (simp add: x xs)
      qed
    qed
  qed
qed

lemma quot_monomial_ideal_monomial:
  "ideal (monomial 1 ` S) ÷ monomial 1 (Poly_Mapping.single (x::'x) (1::nat)) =
    ideal (monomial (1::'a::comm_ring_1) ` (λs. s - Poly_Mapping.single x 1) ` S)"
proof (rule set_eqI)
  let ?x = "Poly_Mapping.single x (1::nat)"
  fix a
  have "a ∈ ideal (monomial 1 ` S) ÷ monomial 1 ?x ⟷ punit.monom_mult 1 ?x a ∈ ideal (monomial (1::'a) ` S)"
    by (simp only: quot_set_iff times_monomial_left)
  also have "… ⟷ a ∈ ideal (monomial 1 ` (λs. s - ?x) ` S)"
  proof (induct a rule: poly_mapping_plus_induct)
    case 1
    show ?case by (simp add: ideal.span_zero)
  next
    case (2 a c t)
    let ?S = "monomial (1::'a) ` (λs. s - ?x) ` S"
    show ?case
    proof
      assume 0: "punit.monom_mult 1 ?x (monomial c t + a) ∈ ideal (monomial 1 ` S)"
      have "is_monomial_set (monomial (1::'a) ` S)"
        by (auto intro!: is_monomial_setI monomial_is_monomial)
      moreover from 0 have 1: "monomial c (?x + t) + punit.monom_mult 1 ?x a ∈ ideal (monomial 1 ` S)"
        by (simp add: punit.monom_mult_monomial punit.monom_mult_dist_right)
      moreover have "?x + t ∈ keys (monomial c (?x + t) + punit.monom_mult 1 ?x a)"
      proof (intro in_keys_plusI1 notI)
        from 2(1) show "?x + t ∈ keys (monomial c (?x + t))" by simp
      next
        assume "?x + t ∈ keys (punit.monom_mult 1 ?x a)"
        also have "… ⊆ (+) ?x ` keys a" by (rule punit.keys_monom_mult_subset[simplified])
        finally obtain s where "s ∈ keys a" and "?x + t = ?x + s" ..
        from this(2) have "t = s" by simp
        with ‹s ∈ keys a› 2(2) show False by simp
      qed
      ultimately obtain f where "f ∈ monomial (1::'a) ` S" and adds: "lpp f adds ?x + t"
        by (rule punit.keys_monomial_pmdl[simplified])
      from this(1) obtain s where "s ∈ S" and f: "f = monomial 1 s" ..
      from adds have "s adds ?x + t" by (simp add: f punit.lt_monomial)
      hence "s - ?x adds t"
        by (metis (no_types, lifting) add_minus_2 adds_minus adds_triv_right plus_minus_assoc_pm_nat_1)
      then obtain s' where t: "t = (s - ?x) + s'" by (rule addsE)
      from ‹s ∈ S› have "monomial 1 (s - ?x) ∈ ?S" by (intro imageI)
      also have "… ⊆ ideal ?S" by (rule ideal.span_superset)
      finally have "monomial c s' * monomial 1 (s - ?x) ∈ ideal ?S"
        by (rule ideal.span_scale)
      hence "monomial c t ∈ ideal ?S" by (simp add: times_monomial_monomial t add.commute)
      moreover have "a ∈ ideal ?S"
      proof -
        from ‹f ∈ monomial 1 ` S› have "f ∈ ideal (monomial 1 ` S)" by (rule ideal.span_base)
        hence "punit.monom_mult c (?x + t - s) f ∈ ideal (monomial 1 ` S)"
          by (rule punit.pmdl_closed_monom_mult[simplified])
        with ‹s adds ?x + t› have "monomial c (?x + t) ∈ ideal (monomial 1 ` S)"
          by (simp add: f punit.monom_mult_monomial adds_minus)
        with 1 have "monomial c (?x + t) + punit.monom_mult 1 ?x a - monomial c (?x + t) ∈ ideal (monomial 1 ` S)"
          by (rule ideal.span_diff)
        thus ?thesis by (simp add: 2(3) del: One_nat_def)
      qed
      ultimately show "monomial c t + a ∈ ideal ?S"
        by (rule ideal.span_add)
    next
      have "is_monomial_set ?S" by (auto intro!: is_monomial_setI monomial_is_monomial)
      moreover assume 1: "monomial c t + a ∈ ideal ?S"
      moreover from _ 2(2) have "t ∈ keys (monomial c t + a)"
      proof (rule in_keys_plusI1)
        from 2(1) show "t ∈ keys (monomial c t)" by simp
      qed
      ultimately obtain f where "f ∈ ?S" and adds: "lpp f adds t"
        by (rule punit.keys_monomial_pmdl[simplified])
      from this(1) obtain s where "s ∈ S" and f: "f = monomial 1 (s - ?x)" by blast
      from adds have "s - ?x adds t" by (simp add: f punit.lt_monomial)
      hence "s adds ?x + t"
        by (auto simp: adds_poly_mapping le_fun_def lookup_add lookup_minus lookup_single when_def
            split: if_splits)
      then obtain s' where t: "?x + t = s + s'" by (rule addsE)
      from ‹s ∈ S› have "monomial 1 s ∈ monomial 1 ` S" by (rule imageI)
      also have "… ⊆ ideal (monomial 1 ` S)" by (rule ideal.span_superset)
      finally have "monomial c s' * monomial 1 s ∈ ideal (monomial 1 ` S)"
        by (rule ideal.span_scale)
      hence "monomial c (?x + t) ∈ ideal (monomial 1 ` S)"
        by (simp only: t) (simp add: times_monomial_monomial add.commute)
      moreover have "punit.monom_mult 1 ?x a ∈ ideal (monomial 1 ` S)"
      proof -
        from ‹f ∈ ?S› have "f ∈ ideal ?S" by (rule ideal.span_base)
        hence "punit.monom_mult c (t - (s - ?x)) f ∈ ideal ?S"
          by (rule punit.pmdl_closed_monom_mult[simplified])
        with ‹s - ?x adds t› have "monomial c t ∈ ideal ?S"
          by (simp add: f punit.monom_mult_monomial adds_minus)
        with 1 have "monomial c t + a - monomial c t ∈ ideal ?S"
          by (rule ideal.span_diff)
        thus ?thesis by (simp add: 2(3) del: One_nat_def)
      qed
      ultimately have "monomial c (?x + t) + punit.monom_mult 1 ?x a ∈ ideal (monomial 1 ` S)"
        by (rule ideal.span_add)
      thus "punit.monom_mult 1 ?x (monomial c t + a) ∈ ideal (monomial 1 ` S)"
        by (simp add: punit.monom_mult_monomial punit.monom_mult_dist_right)
    qed
  qed
  finally show "a ∈ ideal (monomial 1 ` S) ÷ monomial 1 ?x ⟷ a ∈ ideal (monomial 1 ` (λs. s - ?x) ` S)" .
qed

lemma lem_4_2_1:
  assumes "ideal F ÷ monomial 1 t = ideal (monomial (1::'a::comm_ring_1) ` S)"
  shows "cone (monomial 1 t, U) ⊆ ideal F ⟷ 0 ∈ S"
proof
  have "monomial 1 t ∈ cone (monomial (1::'a) t, U)" by (rule tip_in_cone)
  also assume "cone (monomial 1 t, U) ⊆ ideal F"
  finally have *: "monomial 1 t * 1 ∈ ideal F" by simp
  have "is_monomial_set (monomial (1::'a) ` S)"
    by (auto intro!: is_monomial_setI monomial_is_monomial)
  moreover from * have "1 ∈ ideal (monomial (1::'a) ` S)" by (simp only: quot_set_iff flip: assms)
  moreover have "0 ∈ keys (1::_ ⇒0 'a)" by simp
  ultimately obtain g where "g ∈ monomial (1::'a) ` S" and adds: "lpp g adds 0"
    by (rule punit.keys_monomial_pmdl[simplified])
  from this(1) obtain s where "s ∈ S" and g: "g = monomial 1 s" ..
  from adds have "s adds 0" by (simp add: g punit.lt_monomial flip: single_one)
  with ‹s ∈ S› show "0 ∈ S" by (simp only: adds_zero)
next
  assume "0 ∈ S"
  hence "monomial 1 0 ∈ monomial (1::'a) ` S" by (rule imageI)
  hence "1 ∈ ideal (monomial (1::'a) ` S)" unfolding single_one by (rule ideal.span_base)
  hence eq: "ideal F ÷ monomial 1 t = UNIV" (is "_ ÷ ?t = _")
    by (simp only: assms ideal_eq_UNIV_iff_contains_one)
  show "cone (monomial 1 t, U) ⊆ ideal F"
  proof
    fix a
    assume "a ∈ cone (?t, U)"
    then obtain q where a: "a = q * ?t" by (rule coneE)
    have "q ∈ ideal F ÷ ?t" by (simp add: eq)
    thus "a ∈ ideal F" by (simp only: a quot_set_iff mult.commute)
  qed
qed

lemma lem_4_2_2:
  assumes "ideal F ÷ monomial 1 t = ideal (monomial (1::'a::comm_ring_1) ` S)"
  shows "cone (monomial 1 t, U) ∩ ideal F = {0} ⟷ S ∩ .[U] = {}"
proof
  let ?t = "monomial (1::'a) t"
  assume eq: "cone (?t, U) ∩ ideal F = {0}"
  {
    fix s
    assume "s ∈ S"
    hence "monomial 1 s ∈ monomial (1::'a) ` S" (is "?s ∈ _") by (rule imageI)
    hence "?s ∈ ideal (monomial 1 ` S)" by (rule ideal.span_base)
    also have "… = ideal F ÷ ?t" by (simp only: assms)
    finally have *: "?s * ?t ∈ ideal F" by (simp only: quot_set_iff mult.commute)
    assume "s ∈ .[U]"
    hence "?s ∈ P[U]" by (rule Polys_closed_monomial)
    with refl have "?s * ?t ∈ cone (?t, U)" by (rule coneI)
    with * have "?s * ?t ∈ cone (?t, U) ∩ ideal F" by simp
    hence False by (simp add: eq times_monomial_monomial monomial_0_iff)
  }
  thus "S ∩ .[U] = {}" by blast
next
  let ?t = "monomial (1::'a) t"
  assume eq: "S ∩ .[U] = {}"
  {
    fix a
    assume "a ∈ cone (?t, U)"
    then obtain q where "q ∈ P[U]" and a: "a = q * ?t" by (rule coneE)
    assume "a ∈ ideal F"
    have "a = 0"
    proof (rule ccontr)
      assume "a ≠ 0"
      hence "q ≠ 0" by (auto simp: a)
      from ‹a ∈ ideal F› have *: "q ∈ ideal F ÷ ?t" by (simp only: quot_set_iff a mult.commute)
      have "is_monomial_set (monomial (1::'a) ` S)"
        by (auto intro!: is_monomial_setI monomial_is_monomial)
      moreover from * have q_in: "q ∈ ideal (monomial 1 ` S)" by (simp only: assms)
      moreover from ‹q ≠ 0› have "lpp q ∈ keys q" by (rule punit.lt_in_keys)
      ultimately obtain g where "g ∈ monomial (1::'a) ` S" and adds: "lpp g adds lpp q"
        by (rule punit.keys_monomial_pmdl[simplified])
      from this(1) obtain s where "s ∈ S" and g: "g = monomial 1 s" ..
      from ‹q ≠ 0› have "lpp q ∈ keys q" by (rule punit.lt_in_keys)
      also from ‹q ∈ P[U]› have "… ⊆ .[U]" by (rule PolysD)
      finally have "lpp q ∈ .[U]" .
      moreover from adds have "s adds lpp q" by (simp add: g punit.lt_monomial)
      ultimately have "s ∈ .[U]" by (rule PPs_closed_adds)
      with eq ‹s ∈ S› show False by blast
    qed
  }
  thus "cone (?t, U) ∩ ideal F = {0}" using zero_in_cone ideal.span_zero by blast
qed

subsection ‹Function ‹split››

definition max_subset :: "'a set ⇒ ('a set ⇒ bool) ⇒ 'a set"
  where "max_subset A P = (ARG_MAX card B. B ⊆ A ∧ P B)"

lemma max_subset:
  assumes "finite A" and "B ⊆ A" and "P B"
  shows "max_subset A P ⊆ A" (is ?thesis1)
    and "P (max_subset A P)" (is ?thesis2)
    and "card B ≤ card (max_subset A P)" (is ?thesis3)
proof -
  from assms(2, 3) have "B ⊆ A ∧ P B" by simp
  moreover have "∀C. C ⊆ A ∧ P C ⟶ card C < Suc (card A)"
  proof (intro allI impI, elim conjE)
    fix C
    assume "C ⊆ A"
    with assms(1) have "card C ≤ card A" by (rule card_mono)
    thus "card C < Suc (card A)" by simp
  qed
  ultimately have "?thesis1 ∧ ?thesis2" and ?thesis3 unfolding max_subset_def
    by (rule arg_max_natI, rule arg_max_nat_le)
  thus ?thesis1 and ?thesis2 and ?thesis3 by simp_all
qed

function (domintros) split :: "('x ⇒0 nat) ⇒ 'x set ⇒ ('x ⇒0 nat) set ⇒
                                ((((('x ⇒0 nat) ⇒0 'a) × ('x set)) list) ×
                                 (((('x ⇒0 nat) ⇒0 'a::{zero,one}) × ('x set)) list))"
  where
    "split t U S =
      (if 0 ∈ S then
        ([(monomial 1 t, U)], [])
      else if S ∩ .[U] = {} then
        ([], [(monomial 1 t, U)])
      else
        let x = SOME x'. x' ∈ U - (max_subset U (λV. S ∩ .[V] = {}));
            (ps0, qs0) = split t (U - {x}) S;
            (ps1, qs1) = split (Poly_Mapping.single x 1 + t) U ((λf. f - Poly_Mapping.single x 1) ` S) in
          (ps0 @ ps1, qs0 @ qs1))"
  by auto

text ‹Function @{const split} is not executable, because this is not necessary.
  With some effort, it could be made executable, though.›

lemma split_domI':
  assumes "finite X" and "fst (snd args) ⊆ X" and "finite (snd (snd args))"
  shows "split_dom TYPE('a::{zero,one}) args"
proof -
  let ?m = "λargs'. card (fst (snd args')) + sum deg_pm (snd (snd args'))"
  from wf_measure[of ?m] assms(2, 3) show ?thesis
  proof (induct args)
    case (less args)
    obtain t U F where args: "args = (t, U, F)" using prod.exhaust by metis
    from less.prems have "U ⊆ X" and "finite F" by (simp_all only: args fst_conv snd_conv)
    from this(1) assms(1) have "finite U" by (rule finite_subset)
    have IH: "split_dom TYPE('a) (t', U', F')"
      if "U' ⊆ X" and "finite F'" and "card U' + sum deg_pm F' < card U + sum deg_pm F"
      for t' U' F'
      using less.hyps that by (simp add: args)

    define S where "S = max_subset U (λV. F ∩ .[V] = {})"
    define x where "x = (SOME x'. x' ∈ U ∧ x' ∉ S)"
    show ?case unfolding args
    proof (rule split.domintros, simp_all only: x_def[symmetric] S_def[symmetric])
      fix f
      assume "0 ∉ F" and "f ∈ F" and "f ∈ .[U]"
      from this(1) have "F ∩ .[{}] = {}" by simp
      with ‹finite U› empty_subsetI have "S ⊆ U" and "F ∩ .[S] = {}"
        unfolding S_def by (rule max_subset)+
      have "x ∈ U ∧ x ∉ S" unfolding x_def
      proof (rule someI_ex)
        from ‹f ∈ F› ‹f ∈ .[U]› ‹F ∩ .[S] = {}› have "S ≠ U" by blast
        with ‹S ⊆ U› show "∃y. y ∈ U ∧ y ∉ S" by blast
      qed
      hence "x ∈ U" and "x ∉ S" by simp_all
      {
        assume "¬ split_dom TYPE('a) (t, U - {x}, F)"
        moreover from _ ‹finite F› have "split_dom TYPE('a) (t, U - {x}, F)"
        proof (rule IH)
          from ‹U ⊆ X› show "U - {x} ⊆ X" by blast
        next
          from ‹finite U› ‹x ∈ U› have "card (U - {x}) < card U" by (rule card_Diff1_less)
          thus "card (U - {x}) + sum deg_pm F < card U + sum deg_pm F" by simp
        qed
        ultimately show False ..
      }
      {
        let ?args = "(Poly_Mapping.single x (Suc 0) + t, U, (λf. f - Poly_Mapping.single x (Suc 0)) ` F)"
        assume "¬ split_dom TYPE('a) ?args"
        moreover from ‹U ⊆ X› have "split_dom TYPE('a) ?args"
        proof (rule IH)
          from ‹finite F› show "finite ((λf. f - Poly_Mapping.single x (Suc 0)) ` F)"
            by (rule finite_imageI)
        next
          have "sum deg_pm ((λf. f - Poly_Mapping.single x (Suc 0)) ` F) ≤
                sum (deg_pm ∘ (λf. f - Poly_Mapping.single x (Suc 0))) F"
            using ‹finite F› by (rule sum_image_le) simp
          also from ‹finite F› have "… < sum deg_pm F"
          proof (rule sum_strict_mono_ex1)
            show "∀f∈F. (deg_pm ∘ (λf. f - Poly_Mapping.single x (Suc 0))) f ≤ deg_pm f"
              by (simp add: deg_pm_minus_le)
          next
            show "∃f∈F. (deg_pm ∘ (λf. f - Poly_Mapping.single x (Suc 0))) f < deg_pm f"
            proof (rule ccontr)
              assume *: "¬ (∃f∈F. (deg_pm ∘ (λf. f - Poly_Mapping.single x (Suc 0))) f < deg_pm f)"
              note ‹finite U›
              moreover from ‹x ∈ U› ‹S ⊆ U› have "insert x S ⊆ U" by (rule insert_subsetI)
              moreover have "F ∩ .[insert x S] = {}"
              proof -
                {
                  fix s
                  assume "s ∈ F"
                  with * have "¬ deg_pm (s - Poly_Mapping.single x (Suc 0)) < deg_pm s" by simp
                  with deg_pm_minus_le[of s "Poly_Mapping.single x (Suc 0)"]
                  have "deg_pm (s - Poly_Mapping.single x (Suc 0)) = deg_pm s" by simp
                  hence "keys s ∩ keys (Poly_Mapping.single x (Suc 0)) = {}"
                    by (simp only: deg_pm_minus_id_iff)
                  hence "x ∉ keys s" by simp
                  moreover assume "s ∈ .[insert x S]"
                  ultimately have "s ∈ .[S]" by (fastforce simp: PPs_def)
                  with ‹s ∈ F› ‹F ∩ .[S] = {}› have False by blast
                }
                thus ?thesis by blast
              qed
              ultimately have "card (insert x S) ≤ card S" unfolding S_def by (rule max_subset)
              moreover from ‹S ⊆ U› ‹finite U› have "finite S" by (rule finite_subset)
              ultimately show False using ‹x ∉ S› by simp
            qed
          qed
          finally show "card U + sum deg_pm ((λf. f - monomial (Suc 0) x) ` F) < card U + sum deg_pm F"
            by simp
        qed
        ultimately show False ..
      }
    qed
  qed
qed

corollary split_domI: "finite X ⟹ U ⊆ X ⟹ finite S ⟹ split_dom TYPE('a::{zero,one}) (t, U, S)"
  using split_domI'[of "(t, U, S)"] by simp

lemma split_empty:
  assumes "finite X" and "U ⊆ X"
  shows "split t U {} = ([], [(monomial (1::'a::{zero,one}) t, U)])"
proof -
  have "finite {}" ..
  with assms have "split_dom TYPE('a) (t, U, {})" by (rule split_domI)
  thus ?thesis by (simp add: split.psimps)
qed

lemma split_induct [consumes 3, case_names base1 base2 step]:
  fixes P :: "('x ⇒0 nat) ⇒ _"
  assumes "finite X" and "U ⊆ X" and "finite S"
  assumes "⋀t U S. U ⊆ X ⟹ finite S ⟹ 0 ∈ S ⟹ P t U S ([(monomial (1::'a::{zero,one}) t, U)], [])"
  assumes "⋀t U S. U ⊆ X ⟹ finite S ⟹ 0 ∉ S ⟹ S ∩ .[U] = {} ⟹ P t U S ([], [(monomial 1 t, U)])"
  assumes "⋀t U S V x ps0 ps1 qs0 qs1. U ⊆ X ⟹ finite S ⟹ 0 ∉ S ⟹ S ∩ .[U] ≠ {} ⟹ V ⊆ U ⟹
              S ∩ .[V] = {} ⟹ (⋀V'. V' ⊆ U ⟹ S ∩ .[V'] = {} ⟹ card V' ≤ card V) ⟹
              x ∈ U ⟹ x ∉ V ⟹ V = max_subset U (λV'. S ∩ .[V'] = {}) ⟹ x = (SOME x'. x' ∈ U - V) ⟹
              (ps0, qs0) = split t (U - {x}) S ⟹
              (ps1, qs1) = split (Poly_Mapping.single x 1 + t) U ((λf. f - Poly_Mapping.single x 1) ` S) ⟹
              split t U S = (ps0 @ ps1, qs0 @ qs1) ⟹
              P t (U - {x}) S (ps0, qs0) ⟹
              P (Poly_Mapping.single x 1 + t) U ((λf. f - Poly_Mapping.single x 1) ` S) (ps1, qs1) ⟹
              P t U S (ps0 @ ps1, qs0 @ qs1)"
  shows "P t U S (split t U S)"
proof -
  from assms(1-3) have "split_dom TYPE('a) (t, U, S)" by (rule split_domI)
  thus ?thesis using assms(2,3)
  proof (induct t U S rule: split.pinduct)
    case step: (1 t U F)
    from step(4) assms(1) have "finite U" by (rule finite_subset)
    define S where "S = max_subset U (λV. F ∩ .[V] = {})"
    define x where "x = (SOME x'. x' ∈ U ∧ x' ∉ S)"
    show ?case
    proof (simp add: split.psimps[OF step(1)] S_def[symmetric] x_def[symmetric] split: prod.split, intro allI conjI impI)
      assume "0 ∈ F"
      with step(4, 5) show "P t U F ([(monomial 1 t, U)], [])" by (rule assms(4))
      thus "P t U F ([(monomial 1 t, U)], [])" .
    next
      assume "0 ∉ F" and "F ∩ .[U] = {}"
      with step(4, 5) show "P t U F ([], [(monomial 1 t, U)])" by (rule assms(5))
    next
      fix ps0 qs0 ps1 qs1 :: "((_ ⇒0 'a) × _) list"
      assume "split (Poly_Mapping.single x (Suc 0) + t) U ((λf. f - Poly_Mapping.single x (Suc 0)) ` F) = (ps1, qs1)"
      hence PQ1[symmetric]: "split (Poly_Mapping.single x 1 + t) U ((λf. f - Poly_Mapping.single x 1) ` F) = (ps1, qs1)"
        by simp
      assume PQ0[symmetric]: "split t (U - {x}) F = (ps0, qs0)"
      assume "F ∩ .[U] ≠ {}" and "0 ∉ F"
      from this(2) have "F ∩ .[{}] = {}" by simp
      with ‹finite U› empty_subsetI have "S ⊆ U" and "F ∩ .[S] = {}"
        unfolding S_def by (rule max_subset)+
      have S_max: "card S' ≤ card S" if "S' ⊆ U" and "F ∩ .[S'] = {}" for S'
        using ‹finite U› that unfolding S_def by (rule max_subset)
      have "x ∈ U ∧ x ∉ S" unfolding x_def
      proof (rule someI_ex)
        from ‹F ∩ .[U] ≠ {}› ‹F ∩ .[S] = {}› have "S ≠ U" by blast
        with ‹S ⊆ U› show "∃y. y ∈ U ∧ y ∉ S" by blast
      qed
      hence "x ∈ U" and "x ∉ S" by simp_all
      from step(4, 5) ‹0 ∉ F› ‹F ∩ .[U] ≠ {}› ‹S ⊆ U› ‹F ∩ .[S] = {}› S_max ‹x ∈ U› ‹x ∉ S› S_def _ PQ0 PQ1
      show "P t U F (ps0 @ ps1, qs0 @ qs1)"
      proof (rule assms(6))
        show "P t (U - {x}) F (ps0, qs0)"
          unfolding PQ0 using ‹0 ∉ F› ‹F ∩ .[U] ≠ {}› _ _ step(5)
        proof (rule step(2))
          from ‹U ⊆ X› show "U - {x} ⊆ X" by fastforce
        qed (simp add: x_def S_def)
      next
        show "P (Poly_Mapping.single x 1 + t) U ((λf. f - Poly_Mapping.single x 1) ` F) (ps1, qs1)"
          unfolding PQ1 using ‹0 ∉ F› ‹F ∩ .[U] ≠ {}› _ refl PQ0 ‹U ⊆ X›
        proof (rule step(3))
          from ‹finite F› show "finite ((λf. f - Poly_Mapping.single x 1) ` F)" by (rule finite_imageI)
        qed (simp add: x_def S_def)
      next
        show "split t U F = (ps0 @ ps1, qs0 @ qs1)" using ‹0 ∉ F› ‹F ∩ .[U] ≠ {}›
          by (simp add: split.psimps[OF step(1)] Let_def flip: S_def x_def PQ0 PQ1 del: One_nat_def)
      qed (assumption+, simp add: x_def S_def)
    qed
  qed
qed

lemma valid_decomp_split:
  assumes "finite X" and "U ⊆ X" and "finite S" and "t ∈ .[X]"
  shows "valid_decomp X (fst ((split t U S)::(_ × (((_ ⇒0 'a::zero_neq_one) × _) list))))"
    and "valid_decomp X (snd ((split t U S)::(_ × (((_ ⇒0 'a::zero_neq_one) × _) list))))"
          (is "valid_decomp _ (snd ?s)")
proof -
  from assms have "valid_decomp X (fst ?s) ∧ valid_decomp X (snd ?s)"
  proof (induct t U S rule: split_induct)
    case (base1 t U S)
    from base1(1, 4) show ?case by (simp add: valid_decomp_def monomial_0_iff Polys_closed_monomial)
  next
    case (base2 t U S)
    from base2(1, 5) show ?case by (simp add: valid_decomp_def monomial_0_iff Polys_closed_monomial)
  next
    case (step t U S V x ps0 ps1 qs0 qs1)
    from step.hyps(8, 1) have "x ∈ X" ..
    hence "Poly_Mapping.single x 1 ∈ .[X]" by (rule PPs_closed_single)
    hence "Poly_Mapping.single x 1 + t ∈ .[X]" using step.prems by (rule PPs_closed_plus)
    with step.hyps(15, 16) step.prems show ?case by (simp add: valid_decomp_append)
  qed
  thus "valid_decomp X (fst ?s)" and "valid_decomp X (snd ?s)" by simp_all
qed

lemma monomial_decomp_split:
  assumes "finite X" and "U ⊆ X" and "finite S"
  shows "monomial_decomp (fst ((split t U S)::(_ × (((_ ⇒0 'a::zero_neq_one) × _) list))))"
    and "monomial_decomp (snd ((split t U S)::(_ × (((_ ⇒0 'a::zero_neq_one) × _) list))))"
          (is "monomial_decomp (snd ?s)")
proof -
  from assms have "monomial_decomp (fst ?s) ∧ monomial_decomp (snd ?s)"
  proof (induct t U S rule: split_induct)
    case (base1 t U S)
    from base1(1) show ?case by (simp add: monomial_decomp_def monomial_is_monomial)
  next
    case (base2 t U S)
    from base2(1) show ?case by (simp add: monomial_decomp_def monomial_is_monomial)
  next
    case (step t U S V x ps0 ps1 qs0 qs1)
    from step.hyps(15, 16) show ?case by (auto simp: monomial_decomp_def)
  qed
  thus "monomial_decomp (fst ?s)" and "monomial_decomp (snd ?s)" by simp_all
qed

lemma split_splits_wrt:
  assumes "finite X" and "U ⊆ X" and "finite S" and "t ∈ .[X]"
    and "ideal F ÷ monomial 1 t = ideal (monomial 1 ` S)"
  shows "splits_wrt (split t U S) (cone (monomial (1::'a::{comm_ring_1,ring_no_zero_divisors}) t, U)) F"
  using assms
proof (induct t U S rule: split_induct)
  case (base1 t U S)
  from base1(3) have "cone (monomial 1 t, U) ⊆ ideal F" by (simp only: lem_4_2_1 base1(5))
  show ?case
  proof (rule splits_wrtI)
    fix h0 U0
    assume "(h0, U0) ∈ set [(monomial (1::'a) t, U)]"
    hence h0: "h0 = monomial 1 t" and "U0 = U" by simp_all
    note this(1)
    also have "monomial 1 t ∈ cone (monomial (1::'a) t, U)" by (fact tip_in_cone)
    also have "… ⊆ ideal F" by fact
    finally show "h0 ∈ ideal F" .
    
    from base1(4) have "h0 ∈ P[X]" unfolding h0 by (rule Polys_closed_monomial)
    moreover from base1(1) have "U0 ⊆ X" by (simp only: ‹U0 = U›)
    ultimately show "cone (h0, U0) ⊆ P[X]" by (rule cone_subset_PolysI)
  qed (simp_all add: cone_decomp_singleton ‹U ⊆ X›)
next
  case (base2 t U S)
  from base2(4) have "cone (monomial 1 t, U) ∩ ideal F = {0}" by (simp only: lem_4_2_2 base2(6))
  show ?case
  proof (rule splits_wrtI)
    fix h0 U0
    assume "(h0, U0) ∈ set [(monomial (1::'a) t, U)]"
    hence h0: "h0 = monomial 1 t" and "U0 = U" by simp_all
    note this(1)
    also from base2(5) have "monomial 1 t ∈ P[X]" by (rule Polys_closed_monomial)
    finally have "h0 ∈ P[X]" .
    moreover from base2(1) have "U0 ⊆ X" by (simp only: ‹U0 = U›)
    ultimately show "cone (h0, U0) ⊆ P[X]" by (rule cone_subset_PolysI)
  next
    fix h0 U0 a
    assume "(h0, U0) ∈ set [(monomial (1::'a) t, U)]" and "a ∈ cone (h0, U0)"
    hence "a ∈ cone (monomial 1 t, U)" by simp
    moreover assume "a ∈ ideal F"
    ultimately have "a ∈ cone (monomial 1 t, U) ∩ ideal F" by (rule IntI)
    also have "… = {0}" by fact
    finally show "a = 0" by simp
  qed (simp_all add: cone_decomp_singleton ‹U ⊆ X›)
next
  case (step t U S V x ps0 ps1 qs0 qs1)
  let ?x = "Poly_Mapping.single x 1"
  from step.prems have 0: "splits_wrt (ps0, qs0) (cone (monomial 1 t, U - {x})) F" by (rule step.hyps)
  have 1: "splits_wrt (ps1, qs1) (cone (monomial 1 (?x + t), U)) F"
  proof (rule step.hyps)
    from step.hyps(8, 1) have "x ∈ X" ..
    hence "?x ∈ .[X]" by (rule PPs_closed_single)
    thus "?x + t ∈ .[X]" using step.prems(1) by (rule PPs_closed_plus)
  next
    have "ideal F ÷ monomial 1 (?x + t) = ideal F ÷ monomial 1 t ÷ monomial 1 ?x"
      by (simp add: times_monomial_monomial add.commute)
    also have "… = ideal (monomial 1 ` S) ÷ monomial 1 ?x" by (simp only: step.prems)
    finally show "ideal F ÷ monomial 1 (?x + t) = ideal (monomial 1 ` (λs. s - ?x) ` S)"
      by (simp only: quot_monomial_ideal_monomial)
  qed

  show ?case
  proof (rule splits_wrtI)
    from step.hyps(8) have U: "insert x U = U" by blast
    have "direct_decomp (cone (monomial (1::'a) t, insert x (U - {x})))
                      [cone (monomial 1 t, U - {x}),
                       cone (monomial 1 (monomial (Suc 0) x) * monomial 1 t, insert x (U - {x}))]"
      by (rule direct_decomp_cone_insert) simp
    hence "direct_decomp (cone (monomial (1::'a) t, U))
                      [cone (monomial 1 t, U - {x}), cone (monomial 1 (?x + t), U)]"
      by (simp add: U times_monomial_monomial)
    moreover from 0 have "cone_decomp (cone (monomial 1 t, U - {x})) (ps0 @ qs0)"
      by (rule splits_wrtD)
    moreover from 1 have "cone_decomp (cone (monomial 1 (?x + t), U)) (ps1 @ qs1)"
      by (rule splits_wrtD)
    ultimately have "cone_decomp (cone (monomial 1 t, U)) ((ps0 @ qs0) @ (ps1 @ qs1))"
      by (rule cone_decomp_append)
    thus "cone_decomp (cone (monomial 1 t, U)) ((ps0 @ ps1) @ qs0 @ qs1)"
      by (rule cone_decomp_perm) simp
  next
    fix h0 U0
    assume "(h0, U0) ∈ set (ps0 @ ps1)"
    hence "(h0, U0) ∈ set ps0 ∪ set ps1" by simp
    hence "cone (h0, U0) ⊆ ideal F ∩ P[X]"
    proof
      assume "(h0, U0) ∈ set ps0"
      with 0 show ?thesis by (rule splits_wrtD)
    next
      assume "(h0, U0) ∈ set ps1"
      with 1 show ?thesis by (rule splits_wrtD)
    qed
    hence *: "cone (h0, U0) ⊆ ideal F" and "cone (h0, U0) ⊆ P[X]" by simp_all
    from this(2) show "cone (h0, U0) ⊆ P[X]" .

    from tip_in_cone * show "h0 ∈ ideal F" ..
  next
    fix h0 U0
    assume "(h0, U0) ∈ set (qs0 @ qs1)"
    hence "(h0, U0) ∈ set qs0 ∪ set qs1" by simp
    thus "cone (h0, U0) ⊆ P[X]"
    proof
      assume "(h0, U0) ∈ set qs0"
      with 0 show ?thesis by (rule splits_wrtD)
    next
      assume "(h0, U0) ∈ set qs1"
      with 1 show ?thesis by (rule splits_wrtD)
    qed

    from ‹(h0, U0) ∈ set qs0 ∪ set qs1› have "cone (h0, U0) ∩ ideal F = {0}"
    proof
      assume "(h0, U0) ∈ set qs0"
      with 0 show ?thesis by (rule splits_wrtD)
    next
      assume "(h0, U0) ∈ set qs1"
      with 1 show ?thesis by (rule splits_wrtD)
    qed
    thus "⋀a. a ∈ cone (h0, U0) ⟹ a ∈ ideal F ⟹ a = 0" by blast
  qed
qed

lemma lem_4_5:
  assumes "finite X" and "U ⊆ X" and "t ∈ .[X]" and "F ⊆ P[X]"
    and "ideal F ÷ monomial 1 t = ideal (monomial (1::'a) ` S)"
    and "cone (monomial (1::'a::field) t', V) ⊆ cone (monomial 1 t, U) ∩ normal_form F ` P[X]"
  shows "V ⊆ U" and "S ∩ .[V] = {}"
proof -
  let ?t = "monomial (1::'a) t"
  let ?t' = "monomial (1::'a) t'"
  from assms(6) have 1: "cone (?t', V) ⊆ cone (?t, U)" and 2: "cone (?t', V) ⊆ normal_form F ` P[X]"
    by blast+
  from this(1) show "V ⊆ U" by (rule cone_subsetD) (simp add: monomial_0_iff)
  
  show "S ∩ .[V] = {}"
  proof
    let ?t = "monomial (1::'a) t"
    let ?t' = "monomial (1::'a) t'"
    show "S ∩ .[V] ⊆ {}"
    proof
      fix s
      assume "s ∈ S ∩ .[V]"
      hence "s ∈ S" and "s ∈ .[V]" by simp_all
      from this(2) have "monomial (1::'a) s ∈ P[V]" (is "?s ∈ _") by (rule Polys_closed_monomial)
      with refl have "?s * ?t ∈ cone (?t, V)" by (rule coneI)
      from tip_in_cone 1 have "?t' ∈ cone (?t, U)" ..
      then obtain s' where "s' ∈ P[U]" and t': "?t' = s' * ?t" by (rule coneE)
      note this(1)
      also from assms(2) have "P[U] ⊆ P[X]" by (rule Polys_mono)
      finally have "s' ∈ P[X]" .
      have "s' * ?s * ?t = ?s * ?t'" by (simp add: t')
      also from refl ‹?s ∈ P[V]› have "… ∈ cone (?t', V)" by (rule coneI)
      finally have "s' * ?s * ?t ∈ cone (?t', V)" .
      hence 1: "s' * ?s * ?t ∈ normal_form F ` P[X]" using 2 ..
      from ‹s ∈ S› have "?s ∈ monomial 1 ` S" by (rule imageI)
      hence "?s ∈ ideal (monomial 1 ` S)" by (rule ideal.span_base)
      hence "s' * ?s ∈ ideal (monomial 1 ` S)" by (rule ideal.span_scale)
      hence "s' * ?s ∈ ideal F ÷ ?t" by (simp only: assms(5))
      hence "s' * ?s * ?t ∈ ideal F" by (simp only: quot_set_iff mult.commute)
      hence "s' * ?s * ?t ∈ ideal F ∩ normal_form F ` P[X]" using 1 by (rule IntI)
      also from assms(1, 4) have "… ⊆ {0}"
        by (auto simp: normal_form_normal_form simp flip: normal_form_zero_iff)
      finally have "?s * ?t' = 0" by (simp add: t' ac_simps)
      thus "s ∈ {}" by (simp add: times_monomial_monomial monomial_0_iff)
    qed
  qed (fact empty_subsetI)
qed

lemma lem_4_6:
  assumes "finite X" and "U ⊆ X" and "finite S" and "t ∈ .[X]" and "F ⊆ P[X]"
    and "ideal F ÷ monomial 1 t = ideal (monomial 1 ` S)"
  assumes "cone (monomial 1 t', V) ⊆ cone (monomial 1 t, U) ∩ normal_form F ` P[X]"
  obtains V' where "(monomial 1 t, V') ∈ set (snd (split t U S))" and "card V ≤ card V'"
proof -
  let ?t = "monomial (1::'a) t"
  let ?t' = "monomial (1::'a) t'"
  from assms(7) have "cone (?t', V) ⊆ cone (?t, U)" and "cone (?t', V) ⊆ normal_form F ` P[X]"
    by blast+
  from assms(1, 2, 4, 5, 6, 7) have "V ⊆ U" and "S ∩ .[V] = {}" by (rule lem_4_5)+
  with assms(1, 2, 3) show ?thesis using that
  proof (induct t U S arbitrary: V thesis rule: split_induct)
    case (base1 t U S)
    from base1.hyps(3) have "0 ∈ S ∩ .[V]" using zero_in_PPs by (rule IntI)
    thus ?case by (simp add: base1.prems(2))
  next
    case (base2 t U S)
    show ?case
    proof (rule base2.prems)
      from base2.hyps(1) assms(1) have "finite U" by (rule finite_subset)
      thus "card V ≤ card U" using base2.prems(1) by (rule card_mono)
    qed simp
  next
    case (step t U S V0 x ps0 ps1 qs0 qs1)
    from step.prems(1, 2) have 0: "card V ≤ card V0" by (rule step.hyps)
    from step.hyps(5, 9) have "V0 ⊆ U - {x}" by blast
    then obtain V' where 1: "(monomial 1 t, V') ∈ set (snd (ps0, qs0))" and 2: "card V0 ≤ card V'"
      using step.hyps(6) by (rule step.hyps)
    show ?case
    proof (rule step.prems)
      from 1 show "(monomial 1 t, V') ∈ set (snd (ps0 @ ps1, qs0 @ qs1))" by simp
    next
      from 0 2 show "card V ≤ card V'" by (rule le_trans)
    qed
  qed
qed

lemma lem_4_7:
  assumes "finite X" and "S ⊆ .[X]" and "g ∈ punit.reduced_GB (monomial (1::'a) ` S)"
    and "cone_decomp (P[X] ∩ ideal (monomial (1::'a::field) ` S)) ps"
    and "monomial_decomp ps"
  obtains U where "(g, U) ∈ set ps"
proof -
  let ?S = "monomial (1::'a) ` S"
  let ?G = "punit.reduced_GB ?S"
  note assms(1)
  moreover from assms(2) have "?S ⊆ P[X]" by (auto intro: Polys_closed_monomial)
  moreover have "is_monomial_set ?S"
    by (auto intro!: is_monomial_setI monomial_is_monomial)
  ultimately have "is_monomial_set ?G" by (rule reduced_GB_is_monomial_set_Polys)
  hence "is_monomial g" using assms(3) by (rule is_monomial_setD)
  hence "g ≠ 0" by (rule monomial_not_0)
  moreover from assms(1) ‹?S ⊆ P[X]› have "punit.is_monic_set ?G"
    by (rule reduced_GB_is_monic_set_Polys)
  ultimately have "punit.lc g = 1" using assms(3) by (simp add: punit.is_monic_set_def)
  moreover define t where "t = lpp g"
  moreover from ‹is_monomial g› have "monomial (punit.lc g) (lpp g) = g"
    by (rule punit.monomial_eq_itself)
  ultimately have g: "g = monomial 1 t" by simp
  hence "t ∈ keys g" by simp
  from assms(3) have "g ∈ ideal ?G" by (rule ideal.span_base)
  also from assms(1) ‹?S ⊆ P[X]› have ideal_G: "… = ideal ?S" by (rule reduced_GB_ideal_Polys)
  finally have "g ∈ ideal ?S" .
  moreover from assms(3) have "g ∈ P[X]" by rule (intro reduced_GB_Polys assms(1) ‹?S ⊆ P[X]›)
  ultimately have "g ∈ P[X] ∩ ideal ?S" by simp
  with assms(4) have "g ∈ sum_list ` listset (map cone ps)"
    by (simp only: cone_decomp_def direct_decompD)
  with assms(5) obtain d h U where *: "(h, U) ∈ set ps" and "d ≠ 0" and "monomial d t ∈ cone (h, U)"
    using ‹t ∈ keys g› by (rule monomial_decomp_sum_list_monomial_in_cone)
  from this(3) zero_in_PPs have "punit.monom_mult (1 / d) 0 (monomial d t) ∈ cone (h, U)"
    by (rule cone_closed_monom_mult)
  with ‹d ≠ 0› have "g ∈ cone (h, U)" by (simp add: g punit.monom_mult_monomial)
  then obtain q where "q ∈ P[U]" and g': "g = q * h" by (rule coneE)
  from ‹g ≠ 0› have "q ≠ 0" and "h ≠ 0" by (auto simp: g')
  hence lt_g': "lpp g = lpp q + lpp h" unfolding g' by (rule lp_times)
  hence adds1: "lpp h adds t" by (simp add: t_def)
  from assms(5) * have "is_monomial h" and "punit.lc h = 1" by (rule monomial_decompD)+
  moreover from this(1) have "monomial (punit.lc h) (lpp h) = h"
    by (rule punit.monomial_eq_itself)
  moreover define s where "s = lpp h"
  ultimately have h: "h = monomial 1 s" by simp
  have "punit.lc q = punit.lc g" by (simp add: g' lc_times ‹punit.lc h = 1›)
  hence "punit.lc q = 1" by (simp only: ‹punit.lc g = 1›)
  note tip_in_cone
  also from assms(4) * have "cone (h, U) ⊆ P[X] ∩ ideal ?S" by (rule cone_decomp_cone_subset)
  also have "… ⊆ ideal ?G" by (simp add: ideal_G)
  finally have "h ∈ ideal ?G" .
  from assms(1) ‹?S ⊆ P[X]› have "punit.is_Groebner_basis ?G" by (rule reduced_GB_is_GB_Polys)
  then obtain g' where "g' ∈ ?G" and "g' ≠ 0" and adds2: "lpp g' adds lpp h"
    using ‹h ∈ ideal ?G› ‹h ≠ 0› by (rule punit.GB_adds_lt[simplified])
  from this(3) adds1 have "lpp g' adds t" by (rule adds_trans)
  with _ ‹g' ≠ 0› ‹t ∈ keys g› have "punit.is_red {g'} g"
    by (rule punit.is_red_addsI[simplified]) simp
  have "g' = g"
  proof (rule ccontr)
    assume "g' ≠ g"
    with ‹g' ∈ ?G› have "{g'} ⊆ ?G - {g}" by simp
    with ‹punit.is_red {g'} g› have red: "punit.is_red (?G - {g}) g" by (rule punit.is_red_subset)
    from assms(1) ‹?S ⊆ P[X]› have "punit.is_auto_reduced ?G" by (rule reduced_GB_is_auto_reduced_Polys)
    hence "¬ punit.is_red (?G - {g}) g" using assms(3) by (rule punit.is_auto_reducedD)
    thus False using red ..
  qed
  with adds2 have "t adds lpp h" by (simp only: t_def)
  with adds1 have "lpp h = t" by (rule adds_antisym)
  hence "lpp q = 0" using lt_g' by (simp add: t_def)
  hence "monomial (punit.lc q) 0 = q" by (rule punit.lt_eq_min_term_monomial[simplified])
  hence "g = h" by (simp add: ‹punit.lc q = 1› g')
  with * have "(g, U) ∈ set ps" by simp
  thus ?thesis ..
qed

lemma snd_splitI:
  assumes "finite X" and "U ⊆ X" and "finite S" and "0 ∉ S"
  obtains V where "V ⊆ U" and "(monomial 1 t, V) ∈ set (snd (split t U S))"
  using assms
proof (induct t U S arbitrary: thesis rule: split_induct)
  case (base1 t U S)
  from base1.prems(2) base1.hyps(3) show ?case ..
next
  case (base2 t U S)
  from subset_refl show ?case by (rule base2.prems) simp
next
  case (step t U S V0 x ps0 ps1 qs0 qs1)
  from step.hyps(3) obtain V where 1: "V ⊆ U - {x}" and 2: "(monomial 1 t, V) ∈ set (snd (ps0, qs0))"
    using step.hyps(15) by blast
  show ?case
  proof (rule step.prems)
    from 1 show "V ⊆ U" by blast
  next
    from 2 show "(monomial 1 t, V) ∈ set (snd (ps0 @ ps1, qs0 @ qs1))" by fastforce
  qed
qed

lemma fst_splitE:
  assumes "finite X" and "U ⊆ X" and "finite S" and "0 ∉ S"
    and "(monomial (1::'a) s, V) ∈ set (fst (split t U S))"
  obtains t' x where "t' ∈ .[X]" and "x ∈ X" and "V ⊆ U" and "0 ∉ (λs. s - t') ` S"
    and "s = t' + t + Poly_Mapping.single x 1"
    and "(monomial (1::'a::zero_neq_one) s, V) ∈ set (fst (split (t' + t) V ((λs. s - t') ` S)))"
    and "set (snd (split (t' + t) V ((λs. s - t') ` S))) ⊆ (set (snd (split t U S)) :: ((_ ⇒0 'a) × _) set)"
  using assms
proof (induct t U S arbitrary: thesis rule: split_induct)
  case (base1 t U S)
  from base1.prems(2) base1.hyps(3) show ?case ..
next
  case (base2 t U S)
  from base2.prems(3) show ?case by simp
next
  case (step t U S V0 x ps0 ps1 qs0 qs1)
  from step.prems(3) have "(monomial 1 s, V) ∈ set ps0 ∪ set ps1" by simp
  thus ?case
  proof
    assume "(monomial 1 s, V) ∈ set ps0"
    hence "(monomial (1::'a) s, V) ∈ set (fst (ps0, qs0))" by (simp only: fst_conv)
    with step.hyps(3) obtain t' x' where "t' ∈ .[X]" and "x' ∈ X" and "V ⊆ U - {x}"
      and "0 ∉ (λs. s - t') ` S" and "s = t' + t + Poly_Mapping.single x' 1"
      and "(monomial (1::'a) s, V) ∈ set (fst (split (t' + t) V ((λs. s - t') ` S)))"
      and "set (snd (split (t' + t) V ((λs. s - t') ` S))) ⊆ set (snd (ps0, qs0))"
      using step.hyps(15) by blast
    note this(7)
    also have "set (snd (ps0, qs0)) ⊆ set (snd (ps0 @ ps1, qs0 @ qs1))" by simp
    finally have "set (snd (split (t' + t) V ((λs. s - t') ` S))) ⊆ set (snd (ps0 @ ps1, qs0 @ qs1))" .
    from ‹V ⊆ U - {x}› have "V ⊆ U" by blast
    show ?thesis by (rule step.prems) fact+
  next
    assume "(monomial 1 s, V) ∈ set ps1"
    show ?thesis
    proof (cases "0 ∈ (λf. f - Poly_Mapping.single x 1) ` S")
      case True
      from step.hyps(2) have fin: "finite ((λf. f - Poly_Mapping.single x 1) ` S)"
        by (rule finite_imageI)
      have "split (Poly_Mapping.single x 1 + t) U ((λf. f - Poly_Mapping.single x 1) ` S) =
              ([(monomial (1::'a) (Poly_Mapping.single x 1 + t), U)], [])"
        by (simp only: split.psimps[OF split_domI, OF assms(1) step.hyps(1) fin] True if_True)
      hence "ps1 = [(monomial 1 (Poly_Mapping.single x 1 + t), U)]"
        by (simp only: step.hyps(13)[symmetric] prod.inject)
      with ‹(monomial 1 s, V) ∈ set ps1› have s: "s = Poly_Mapping.single x 1 + t" and "V = U"
        by (auto dest!: monomial_inj)
      show ?thesis
      proof (rule step.prems)
        show "0 ∈ .[X]" by (fact zero_in_PPs)
      next
        from step.hyps(8, 1) show "x ∈ X" ..
      next
        show "V ⊆ U" by (simp add: ‹V = U›)
      next
        from step.hyps(3) show "0 ∉ (λs. s - 0) ` S" by simp
      next
        show "s = 0 + t + Poly_Mapping.single x 1" by (simp add: s add.commute)
      next
        show "(monomial (1::'a) s, V) ∈ set (fst (split (0 + t) V ((λs. s - 0) ` S)))"
          using ‹(monomial 1 s, V) ∈ set ps1› by (simp add: step.hyps(14) ‹V = U›)
      next
        show "set (snd (split (0 + t) V ((λs. s - 0) ` S))) ⊆ set (snd (ps0 @ ps1, qs0 @ qs1))"
          by (simp add: step.hyps(14) ‹V = U›)
      qed
    next
      case False
      moreover from ‹(monomial 1 s, V) ∈ set ps1› have "(monomial 1 s, V) ∈ set (fst (ps1, qs1))"
        by (simp only: fst_conv)
      ultimately obtain t' x' where "t' ∈ .[X]" and "x' ∈ X" and "V ⊆ U"
        and 1: "0 ∉ (λs. s - t') ` (λf. f - Poly_Mapping.single x 1) ` S"
        and s: "s = t' + (Poly_Mapping.single x 1 + t) + Poly_Mapping.single x' 1"
        and 2: "(monomial (1::'a) s, V) ∈ set (fst (split (t' + (Poly_Mapping.single x 1 + t)) V
                                            ((λs. s - t') ` (λf. f - Poly_Mapping.single x 1) ` S)))"
        and 3: "set (snd (split (t' + (Poly_Mapping.single x 1 + t)) V ((λs. s - t') ` (λf. f - monomial 1 x) ` S))) ⊆
                  set (snd (ps1, qs1))"
        using step.hyps(16) by blast
      have eq: "(λs. s - t') ` (λf. f - Poly_Mapping.single x 1) ` S =
                (λs. s - (t' + Poly_Mapping.single x 1)) ` S"
        by (simp add: image_image add.commute diff_diff_eq)
      show ?thesis
      proof (rule step.prems)
        from step.hyps(8, 1) have "x ∈ X" ..
        hence "Poly_Mapping.single x 1 ∈ .[X]" by (rule PPs_closed_single)
        with ‹t' ∈ .[X]› show "t' + Poly_Mapping.single x 1 ∈ .[X]" by (rule PPs_closed_plus)
      next
        from 1 show "0 ∉ (λs. s - (t' + Poly_Mapping.single x 1)) ` S"
          by (simp only: eq not_False_eq_True)
      next
        show "s = t' + Poly_Mapping.single x 1 + t + Poly_Mapping.single x' 1" by (simp only: s ac_simps)
      next
        show "(monomial (1::'a) s, V) ∈ set (fst (split (t' + Poly_Mapping.single x 1 + t) V
                                                ((λs. s - (t' + Poly_Mapping.single x 1)) ` S)))"
          using 2 by (simp only: eq add.assoc)
      next
        have "set (snd (split (t' + Poly_Mapping.single x 1 + t) V ((λs. s - (t' + Poly_Mapping.single x 1)) ` S))) ⊆
              set (snd (ps1, qs1))" (is "?x ⊆ _") using 3 by (simp only: eq add.assoc)
        also have "… ⊆ set (snd (ps0 @ ps1, qs0 @ qs1))" by simp
        finally show "?x ⊆ set (snd (ps0 @ ps1, qs0 @ qs1))" .
      qed fact+
    qed
  qed
qed

lemma lem_4_8:
  assumes "finite X" and "finite S" and "S ⊆ .[X]" and "0 ∉ S"
    and "g ∈ punit.reduced_GB (monomial (1::'a) ` S)"
  obtains t U where "U ⊆ X" and "(monomial (1::'a::field) t, U) ∈ set (snd (split 0 X S))"
    and "poly_deg g = Suc (deg_pm t)"
proof -
  let ?S = "monomial (1::'a) ` S"
  let ?G = "punit.reduced_GB ?S"
  have md1: "monomial_decomp (fst ((split 0 X S)::(_ × (((_ ⇒0 'a) × _) list))))"
    and md2: "monomial_decomp (snd ((split 0 X S)::(_ × (((_ ⇒0 'a) × _) list))))"
    using assms(1) subset_refl assms(2) by (rule monomial_decomp_split)+
  from assms(3) have 0: "?S ⊆ P[X]" by (auto intro: Polys_closed_monomial)
  with assms(1) have "punit.is_auto_reduced ?G" and "punit.is_monic_set ?G"
    and ideal_G: "ideal ?G = ideal ?S" and "0 ∉ ?G"
    by (rule reduced_GB_is_auto_reduced_Polys, rule reduced_GB_is_monic_set_Polys,
        rule reduced_GB_ideal_Polys, rule reduced_GB_nonzero_Polys)
  from this(2, 4) assms(5) have "punit.lc g = 1" by (auto simp: punit.is_monic_set_def)
  have "is_monomial_set ?S" by (auto intro!: is_monomial_setI monomial_is_monomial)
  with assms(1) 0 have "is_monomial_set ?G" by (rule reduced_GB_is_monomial_set_Polys)
  hence "is_monomial g" using assms(5) by (rule is_monomial_setD)
  moreover define s where "s = lpp g"
  ultimately have g: "g = monomial 1 s" using ‹punit.lc g = 1› by (metis punit.monomial_eq_itself)
  note assms(1) subset_refl assms(2) zero_in_PPs
  moreover have "ideal ?G ÷ monomial 1 0 = ideal ?S" by (simp add: ideal_G)
  ultimately have "splits_wrt (split 0 X S) (cone (monomial (1::'a) 0, X)) ?G" by (rule split_splits_wrt)
  hence "splits_wrt (fst (split 0 X S), snd (split 0 X S)) P[X] ?G" by simp
  hence "cone_decomp (P[X] ∩ ideal ?G) (fst (split 0 X S))"
    using md2 ‹is_monomial_set ?G› by (rule splits_wrt_cone_decomp_1)
  hence "cone_decomp (P[X] ∩ ideal ?S) (fst (split 0 X S))" by (simp only: ideal_G)
  with assms(1, 3, 5) obtain U where "(g, U) ∈ set (fst (split 0 X S))" using md1 by (rule lem_4_7)
  with assms(1) subset_refl assms(2, 4) obtain t' x where "t' ∈ .[X]" and "x ∈ X" and "U ⊆ X"
    and "0 ∉ (λs. s - t') ` S" and s: "s = t' + 0 + Poly_Mapping.single x 1"
    and "(g, U) ∈ set (fst (split (t' + 0) U ((λs. s - t') ` S)))"
    and "set (snd (split (t' + 0) U ((λs. s - t') ` S))) ⊆ (set (snd (split 0 X S)) :: ((_ ⇒0 'a) × _) set)"
    unfolding g by (rule fst_splitE)
  let ?S = "(λs. s - t') ` S"
  from assms(2) have "finite ?S" by (rule finite_imageI)
  with assms(1) ‹U ⊆ X› obtain V where "V ⊆ U"
    and "(monomial (1::'a) (t' + 0), V) ∈ set (snd (split (t' + 0) U ?S))"
    using ‹0 ∉ ?S› by (rule snd_splitI)
  note this(2)
  also have "… ⊆ set (snd (split 0 X S))" by fact
  finally have "(monomial (1::'a) t', V) ∈ set (snd (split 0 X S))" by simp
  have "poly_deg g = Suc (deg_pm t')" by (simp add: g s deg_pm_plus deg_pm_single poly_deg_monomial)
  from ‹V ⊆ U› ‹U ⊆ X› have "V ⊆ X" by (rule subset_trans)
  show ?thesis by rule fact+
qed

corollary cor_4_9:
  assumes "finite X" and "finite S" and "S ⊆ .[X]"
    and "g ∈ punit.reduced_GB (monomial (1::'a::field) ` S)"
  shows "poly_deg g ≤ Suc (Max (poly_deg ` fst ` (set (snd (split 0 X S)) :: ((_ ⇒0 'a) × _) set)))"
        (is "_ ≤ Suc (Max (poly_deg ` fst ` ?S))")
proof (cases "0 ∈ S")
  case True
  hence "1 ∈ monomial (1::'a) ` S" by (rule rev_image_eqI) (simp only: single_one)
  hence "1 ∈ ideal (monomial (1::'a) ` S)" by (rule ideal.span_base)
  hence "ideal (monomial (1::'a) ` S) = UNIV" by (simp only: ideal_eq_UNIV_iff_contains_one)
  moreover from assms(3) have "monomial (1::'a) ` S ⊆ P[X]" by (auto intro: Polys_closed_monomial)
  ultimately have "punit.reduced_GB (monomial (1::'a) ` S) = {1}"
    using assms(1) by (simp only: ideal_eq_UNIV_iff_reduced_GB_eq_one_Polys)
  with assms(4) show ?thesis by simp
next
  case False
  from finite_set have fin: "finite (poly_deg ` fst ` ?S)" by (intro finite_imageI)
  obtain t U where "(monomial 1 t, U) ∈ ?S" and g: "poly_deg g = Suc (deg_pm t)"
    using assms(1-3) False assms(4) by (rule lem_4_8)
  from this(1) have "poly_deg (fst (monomial (1::'a) t, U)) ∈ poly_deg ` fst ` ?S"
    by (intro imageI)
  hence "deg_pm t ∈ poly_deg ` fst ` ?S" by (simp add: poly_deg_monomial)
  with fin have "deg_pm t ≤ Max (poly_deg ` fst ` ?S)" by (rule Max_ge)
  thus "poly_deg g ≤ Suc (Max (poly_deg ` fst ` ?S))" by (simp add: g)
qed

lemma standard_decomp_snd_split:
  assumes "finite X" and "U ⊆ X" and "finite S" and "S ⊆ .[X]" and "t ∈ .[X]"
  shows "standard_decomp (deg_pm t) (snd (split t U S) :: ((_ ⇒0 'a::field) × _) list)"
  using assms
proof (induct t U S rule: split_induct)
  case (base1 t U S)
  show ?case by (simp add: standard_decomp_Nil)
next
  case (base2 t U S)
  have "deg_pm t = poly_deg (monomial (1::'a) t)" by (simp add: poly_deg_monomial)
  thus ?case by (simp add: standard_decomp_singleton)
next
  case (step t U S V x ps0 ps1 qs0 qs1)
  from step.hyps(15) step.prems have qs0: "standard_decomp (deg_pm t) qs0" by (simp only: snd_conv)
  have "(λs. s - Poly_Mapping.single x 1) ` S ⊆ .[X]"
  proof
    fix u
    assume "u ∈ (λs. s - Poly_Mapping.single x 1) ` S"
    then obtain s where "s ∈ S" and u: "u = s - Poly_Mapping.single x 1" ..
    from this(1) step.prems(1) have "s ∈ .[X]" ..
    thus "u ∈ .[X]" unfolding u by (rule PPs_closed_minus)
  qed
  moreover from _ step.prems(2) have "Poly_Mapping.single x 1 + t ∈ .[X]"
  proof (rule PPs_closed_plus)
    from step.hyps(8, 1) have "x ∈ X" ..
    thus "Poly_Mapping.single x 1 ∈ .[X]" by (rule PPs_closed_single)
  qed
  ultimately have qs1: "standard_decomp (Suc (deg_pm t)) qs1" using step.hyps(16)
    by (simp add: deg_pm_plus deg_pm_single)
  show ?case unfolding snd_conv
  proof (rule standard_decompI)
    fix h U0
    assume "(h, U0) ∈ set ((qs0 @ qs1)+)"
    hence *: "(h, U0) ∈ set (qs0+) ∪ set (qs1+)" by (simp add: pos_decomp_append)
    thus "deg_pm t ≤ poly_deg h"
    proof
      assume "(h, U0) ∈ set (qs0+)"
      with qs0 show ?thesis by (rule standard_decompD)
    next
      assume "(h, U0) ∈ set (qs1+)"
      with qs1 have "Suc (deg_pm t) ≤ poly_deg h" by (rule standard_decompD)
      thus ?thesis by simp
    qed

    fix d
    assume d1: "deg_pm t ≤ d" and d2: "d ≤ poly_deg h"
    from * show "∃t' U'. (t', U') ∈ set (qs0 @ qs1) ∧ poly_deg t' = d ∧ card U0 ≤ card U'"
    proof
      assume "(h, U0) ∈ set (qs0+)"
      with qs0 obtain h' U' where "(h', U') ∈ set qs0" and "poly_deg h' = d" and "card U0 ≤ card U'"
        using d1 d2 by (rule standard_decompE)
      moreover from this(1) have "(h', U') ∈ set (qs0 @ qs1)" by simp
      ultimately show ?thesis by blast
    next
      assume "(h, U0) ∈ set (qs1+)"
      hence "(h, U0) ∈ set qs1" by (simp add: pos_decomp_def)
      from assms(1) step.hyps(1, 2) have "monomial_decomp (snd (split t U S) :: ((_ ⇒0 'a) × _) list)"
        by (rule monomial_decomp_split)
      hence md: "monomial_decomp (qs0 @ qs1)" by (simp add: step.hyps(14))
      moreover from ‹(h, U0) ∈ set qs1› have "(h, U0) ∈ set (qs0 @ qs1)" by simp
      ultimately have "is_monomial h" and "punit.lc h = 1" by (rule monomial_decompD)+
      moreover from this(1) have "monomial (punit.lc h) (lpp h) = h" by (rule punit.monomial_eq_itself)
      moreover define s where "s = lpp h"
      ultimately have h: "h = monomial 1 s" by simp
      from d1 have "deg_pm t = d ∨ Suc (deg_pm t) ≤ d" by auto
      thus ?thesis
      proof
        assume "deg_pm t = d"
        define F where "F = (*) (monomial 1 t) ` monomial (1::'a) ` S"
        have "F ⊆ P[X]"
        proof
          fix f
          assume "f ∈ F"
          then obtain u where "u ∈ S" and f: "f = monomial 1 (t + u)"
            by (auto simp: F_def times_monomial_monomial)
          from this(1) step.prems(1) have "u ∈ .[X]" ..
          with step.prems(2) have "t + u ∈ .[X]" by (rule PPs_closed_plus)
          thus "f ∈ P[X]" unfolding f by (rule Polys_closed_monomial)
        qed
        have "ideal F = (*) (monomial 1 t) ` ideal (monomial 1 ` S)"
          by (simp only: ideal.span_image_scale_eq_image_scale F_def)
        moreover have "inj ((*) (monomial (1::'a) t))"
          by (auto intro!: injI simp: times_monomial_left monomial_0_iff dest!: punit.monom_mult_inj_3)
        ultimately have eq: "ideal F ÷ monomial 1 t = ideal (monomial 1 ` S)"
          by (simp only: quot_set_image_times)
        with assms(1) step.hyps(1, 2) step.prems(2)
        have "splits_wrt (split t U S) (cone (monomial (1::'a) t, U)) F" by (rule split_splits_wrt)
        hence "splits_wrt (ps0 @ ps1, qs0 @ qs1) (cone (monomial 1 t, U)) F" by (simp only: step.hyps(14))
        with assms(1) have "cone_decomp (cone (monomial (1::'a) t, U) ∩ normal_form F ` P[X]) (qs0 @ qs1)"
          using md _ ‹F ⊆ P[X]›
          by (rule splits_wrt_cone_decomp_2)
              (auto intro!: is_monomial_setI monomial_is_monomial simp: F_def times_monomial_monomial)
        hence "cone (monomial 1 s, U0) ⊆ cone (monomial (1::'a) t, U) ∩ normal_form F ` P[X]"
          using ‹(h, U0) ∈ set (qs0 @ qs1)› unfolding h by (rule cone_decomp_cone_subset)
        with assms(1) step.hyps(1, 2) step.prems(2) ‹F ⊆ P[X]› eq
        obtain U' where "(monomial (1::'a) t, U') ∈ set (snd (split t U S))" and "card U0 ≤ card U'"
          by (rule lem_4_6)
        from this(1) have "(monomial 1 t, U') ∈ set (qs0 @ qs1)" by (simp add: step.hyps(14))
        show ?thesis
        proof (intro exI conjI)
          show "poly_deg (monomial (1::'a) t) = d" by (simp add: poly_deg_monomial ‹deg_pm t = d›)
        qed fact+
      next
        assume "Suc (deg_pm t) ≤ d"
        with qs1 ‹(h, U0) ∈ set (qs1+)› obtain h' U' where "(h', U') ∈ set qs1" and "poly_deg h' = d"
          and "card U0 ≤ card U'" using d2 by (rule standard_decompE)
        moreover from this(1) have "(h', U') ∈ set (qs0 @ qs1)" by simp
        ultimately show ?thesis by blast
      qed
    qed
  qed
qed

theorem standard_cone_decomp_snd_split:
  fixes F
  defines "G ≡ punit.reduced_GB F"
  defines "ss ≡ (split 0 X (lpp ` G)) :: ((_ ⇒0 'a::field) × _) list × _"
  defines "d ≡ Suc (Max (poly_deg ` fst ` set (snd ss)))"
  assumes "finite X" and "F ⊆ P[X]"
  shows "standard_decomp 0 (snd ss)" (is ?thesis1)
    and "cone_decomp (normal_form F ` P[X]) (snd ss)" (is ?thesis2)
    and "(⋀f. f ∈ F ⟹ homogeneous f) ⟹ g ∈ G ⟹ poly_deg g ≤ d"
proof -
  have "ideal G = ideal F" and "punit.is_Groebner_basis G" and "finite G" and "0 ∉ G"
    and "G ⊆ P[X]" and "punit.is_reduced_GB G" using assms(4, 5) unfolding G_def
    by (rule reduced_GB_ideal_Polys, rule reduced_GB_is_GB_Polys, rule finite_reduced_GB_Polys,
        rule reduced_GB_nonzero_Polys, rule reduced_GB_Polys, rule reduced_GB_is_reduced_GB_Polys)
  define S where "S = lpp ` G"
  note assms(4) subset_refl
  moreover from ‹finite G› have "finite S" unfolding S_def by (rule finite_imageI)
  moreover from ‹G ⊆ P[X]› have "S ⊆ .[X]" unfolding S_def by (rule PPs_closed_image_lpp)
  ultimately have "standard_decomp (deg_pm (0::'x ⇒0 nat)) (snd ss)"
    using zero_in_PPs unfolding ss_def S_def by (rule standard_decomp_snd_split)
  thus ?thesis1 by simp

  let ?S = "monomial (1::'a) ` S"
  from ‹S ⊆ .[X]› have "?S ⊆ P[X]" by (auto intro: Polys_closed_monomial)
  have "splits_wrt ss (cone (monomial 1 0, X)) ?S"
    using assms(4) subset_refl ‹finite S› zero_in_PPs unfolding ss_def S_def
    by (rule split_splits_wrt) simp
  hence "splits_wrt (fst ss, snd ss) P[X] ?S" by simp
  with assms(4) have "cone_decomp (P[X] ∩ normal_form ?S ` P[X]) (snd ss)" using _ _ ‹?S ⊆ P[X]›
  proof (rule splits_wrt_cone_decomp_2)
    from assms(4) subset_refl ‹finite S› show "monomial_decomp (snd ss)"
      unfolding ss_def S_def by (rule monomial_decomp_split)
  qed (auto intro!: is_monomial_setI monomial_is_monomial)
  moreover have "normal_form ?S ` P[X] = normal_form F ` P[X]"
    by (rule set_eqI)
        (simp add: image_normal_form_iff[OF assms(4)] assms(5) ‹?S ⊆ P[X]›,
         simp add: S_def is_red_reduced_GB_monomial_lt_GB_Polys[OF assms(4)] ‹G ⊆ P[X]› ‹0 ∉ G› flip: G_def)
  moreover from assms(4, 5) have "normal_form F ` P[X] ⊆ P[X]"
    by (auto intro: Polys_closed_normal_form)
  ultimately show ?thesis2 by (simp only: Int_absorb1)

  assume "⋀f. f ∈ F ⟹ homogeneous f"
  moreover note ‹punit.is_reduced_GB G› ‹ideal G = ideal F›
  moreover assume "g ∈ G"
  ultimately have "homogeneous g" by (rule is_reduced_GB_homogeneous)
  moreover have "lpp g ∈ keys g"
  proof (rule punit.lt_in_keys)
    from ‹g ∈ G› ‹0 ∉ G› show "g ≠ 0" by blast
  qed
  ultimately have deg_lt: "deg_pm (lpp g) = poly_deg g" by (rule homogeneousD_poly_deg)
  from ‹g ∈ G› have "monomial 1 (lpp g) ∈ ?S" unfolding S_def by (intro imageI)
  also have "… = punit.reduced_GB ?S" unfolding S_def G_def using assms(4, 5)
    by (rule reduced_GB_monomial_lt_reduced_GB_Polys[symmetric])
  finally have "monomial 1 (lpp g) ∈ punit.reduced_GB ?S" .
  with assms(4) ‹finite S› ‹S ⊆ .[X]› have "poly_deg (monomial (1::'a) (lpp g)) ≤ d"
    unfolding d_def ss_def S_def[symmetric] by (rule cor_4_9)
  thus "poly_deg g ≤ d" by (simp add: poly_deg_monomial deg_lt)
qed

subsection ‹Splitting Ideals›

qualified definition ideal_decomp_aux :: "(('x ⇒0 nat) ⇒0 'a) set ⇒ (('x ⇒0 nat) ⇒0 'a) ⇒
                                          ((('x ⇒0 nat) ⇒0 'a::field) set × ((('x ⇒0 nat) ⇒0 'a) × 'x set) list)"
  where "ideal_decomp_aux F f =
              (let J = ideal F; L = (J ÷ f) ∩ P[X]; L' = lpp ` punit.reduced_GB L in
                 ((*) f ` normal_form L ` P[X], map (apfst ((*) f)) (snd (split 0 X L'))))"

context
  assumes fin_X: "finite X"
begin

lemma ideal_decomp_aux:
  assumes "finite F" and "F ⊆ P[X]" and "f ∈ P[X]"
  shows "fst (ideal_decomp_aux F f) ⊆ ideal {f}" (is ?thesis1)
    and "ideal F ∩ fst (ideal_decomp_aux F f) = {0}" (is ?thesis2)
    and "direct_decomp (ideal (insert f F) ∩ P[X]) [fst (ideal_decomp_aux F f), ideal F ∩ P[X]]" (is ?thesis3)
    and "cone_decomp (fst (ideal_decomp_aux F f)) (snd (ideal_decomp_aux F f))" (is ?thesis4)
    and "f ≠ 0 ⟹ valid_decomp X (snd (ideal_decomp_aux F f))" (is "_ ⟹ ?thesis5")
    and "f ≠ 0 ⟹ standard_decomp (poly_deg f) (snd (ideal_decomp_aux F f))" (is "_ ⟹ ?thesis6")
    and "homogeneous f ⟹ hom_decomp (snd (ideal_decomp_aux F f))" (is "_ ⟹ ?thesis7")
proof -
  define J where "J = ideal F"
  define L where "L = (J ÷ f) ∩ P[X]"
  define S where "S = (*) f ` normal_form L ` P[X]"
  define L' where "L' = lpp ` punit.reduced_GB L"

  have eq: "ideal_decomp_aux F f = (S, map (apfst ((*) f)) (snd (split 0 X L')))"
    by (simp add: J_def ideal_decomp_aux_def Let_def L_def L'_def S_def)

  have L_sub: "L ⊆ P[X]" by (simp add: L_def)

  show ?thesis1 unfolding eq fst_conv
  proof
    fix s
    assume "s ∈ S"
    then obtain q where "s = normal_form L q * f" unfolding S_def by (elim imageE) auto
    also have "… ∈ ideal {f}" by (intro ideal.span_scale ideal.span_base singletonI)
    finally show "s ∈ ideal {f}" .
  qed

  show ?thesis2
  proof (rule set_eqI)
    fix h
    show "h ∈ ideal F ∩ fst (ideal_decomp_aux F f) ⟷ h ∈ {0}"
    proof
      assume "h ∈ ideal F ∩ fst (ideal_decomp_aux F f)"
      hence "h ∈ J" and "h ∈ S" by (simp_all add: J_def S_def eq)
      from this(2) obtain q where "q ∈ P[X]" and h: "h = f * normal_form L q" by (auto simp: S_def)
      from fin_X L_sub this(1) have "normal_form L q ∈ P[X]" by (rule Polys_closed_normal_form)
      moreover from ‹h ∈ J› have "f * normal_form L q ∈ J" by (simp add: h)
      ultimately have "normal_form L q ∈ L" by (simp add: L_def quot_set_iff)
      hence "normal_form L q ∈ ideal L" by (rule ideal.span_base)
      with normal_form_diff_in_ideal[OF fin_X L_sub] have "(q - normal_form L q) + normal_form L q ∈ ideal L"
        by (rule ideal.span_add)
      hence "normal_form L q = 0" using fin_X L_sub by (simp add: normal_form_zero_iff)
      thus "h ∈ {0}" by (simp add: h)
    next
      assume "h ∈ {0}"
      moreover have "0 ∈ (*) f ` normal_form L ` P[X]"
      proof (intro image_eqI)
        from fin_X L_sub show "0 = normal_form L 0" by (simp only: normal_form_zero)
      qed (simp_all add: zero_in_Polys)
      ultimately show "h ∈ ideal F ∩ fst (ideal_decomp_aux F f)" by (simp add: ideal.span_zero eq S_def)
    qed
  qed

  have "direct_decomp (ideal (insert f F) ∩ P[X]) [ideal F ∩ P[X], fst (ideal_decomp_aux F f)]"
    unfolding eq fst_conv S_def L_def J_def using fin_X assms(2, 3) by (rule direct_decomp_ideal_insert)
  thus ?thesis3 by (rule direct_decomp_perm) simp

  have std: "standard_decomp 0 (snd (split 0 X L') :: ((_ ⇒0 'a) × _) list)"
    and "cone_decomp (normal_form L ` P[X]) (snd (split 0 X L'))"
    unfolding L'_def using fin_X ‹L ⊆ P[X]› by (rule standard_cone_decomp_snd_split)+
  from this(2) show ?thesis4 unfolding eq fst_conv snd_conv S_def by (rule cone_decomp_map_times)

  from fin_X ‹L ⊆ P[X]› have "finite (punit.reduced_GB L)" by (rule finite_reduced_GB_Polys)
  hence "finite L'" unfolding L'_def by (rule finite_imageI)
  {
    have "monomial_decomp (snd (split 0 X L') :: ((_ ⇒0 'a) × _) list)"
      using fin_X subset_refl ‹finite L'› by (rule monomial_decomp_split)
    hence "hom_decomp (snd (split 0 X L') :: ((_ ⇒0 'a) × _) list)"
      by (rule monomial_decomp_imp_hom_decomp)
    moreover assume "homogeneous f"
    ultimately show ?thesis7 unfolding eq snd_conv by (rule hom_decomp_map_times)
  }

  have vd: "valid_decomp X (snd (split 0 X L') :: ((_ ⇒0 'a) × _) list)"
    using fin_X subset_refl ‹finite L'› zero_in_PPs by (rule valid_decomp_split)
  moreover note assms(3)
  moreover assume "f ≠ 0"
  ultimately show ?thesis5 unfolding eq snd_conv by (rule valid_decomp_map_times)

  from std vd ‹f ≠ 0› have "standard_decomp (0 + poly_deg f) (map (apfst ((*) f)) (snd (split 0 X L')))"
    by (rule standard_decomp_map_times)
  thus ?thesis6 by (simp add: eq)
qed

lemma ideal_decompE:
  fixes f0 :: "_ ⇒0 'a::field"
  assumes "finite F" and "F ⊆ P[X]" and "f0 ∈ P[X]" and "⋀f. f ∈ F ⟹ poly_deg f ≤ poly_deg f0"
  obtains T ps where "valid_decomp X ps" and "standard_decomp (poly_deg f0) ps" and "cone_decomp T ps"
    and "(⋀f. f ∈ F ⟹ homogeneous f) ⟹ hom_decomp ps"
    and "direct_decomp (ideal (insert f0 F) ∩ P[X]) [ideal {f0} ∩ P[X], T]"
  using assms(1, 2, 4)
proof (induct F arbitrary: thesis)
  case empty
  show ?case
  proof (rule empty.prems)
    show "valid_decomp X []" by (rule valid_decompI) simp_all
  next
    show "standard_decomp (poly_deg f0) []" by (rule standard_decompI) simp_all
  next
    show "cone_decomp {0} []" by (rule cone_decompI) (simp add: direct_decomp_def bij_betw_def)
  next
    have "direct_decomp (ideal {f0} ∩ P[X]) [ideal {f0} ∩ P[X]]"
      by (fact direct_decomp_singleton)
    hence "direct_decomp (ideal {f0} ∩ P[X]) [{0}, ideal {f0} ∩ P[X]]" by (rule direct_decomp_Cons_zeroI)
    thus "direct_decomp (ideal {f0} ∩ P[X]) [ideal {f0} ∩ P[X], {0}]"
      by (rule direct_decomp_perm) simp
  qed (simp add: hom_decomp_def)
next
  case (insert f F)
  from insert.prems(2) have "F ⊆ P[X]" by simp
  moreover have "poly_deg f' ≤ poly_deg f0" if "f' ∈ F" for f'
  proof -
    from that have "f' ∈ insert f F" by simp
    thus ?thesis by (rule insert.prems)
  qed
  ultimately obtain T ps where valid_ps: "valid_decomp X ps" and std_ps: "standard_decomp (poly_deg f0) ps"
    and cn_ps: "cone_decomp T ps" and dd: "direct_decomp (ideal (insert f0 F) ∩ P[X]) [ideal {f0} ∩ P[X], T]"
    and hom_ps: "(⋀f. f ∈ F ⟹ homogeneous f) ⟹ hom_decomp ps"
    using insert.hyps(3) by metis
  show ?case
  proof (cases "f = 0")
    case True
    show ?thesis
    proof (rule insert.prems)
      from dd show "direct_decomp (ideal (insert f0 (insert f F)) ∩ P[X]) [ideal {f0} ∩ P[X], T]"
        by (simp only: insert_commute[of f0] True ideal.span_insert_zero)
    next
      assume "⋀f'. f' ∈ insert f F ⟹ homogeneous f'"
      hence "⋀f. f ∈ F ⟹ homogeneous f" by blast
      thus "hom_decomp ps" by (rule hom_ps)
    qed fact+
  next
    case False
    let ?D = "ideal_decomp_aux (insert f0 F) f"
    from insert.hyps(1) have f0F_fin: "finite (insert f0 F)" by simp
    moreover from ‹F ⊆ P[X]› assms(3) have f0F_sub: "insert f0 F ⊆ P[X]" by simp
    moreover from insert.prems(2) have "f ∈ P[X]" by simp
    ultimately have eq: "ideal (insert f0 F) ∩ fst ?D = {0}" and "valid_decomp X (snd ?D)"
      and cn_D: "cone_decomp (fst ?D) (snd ?D)"
      and "standard_decomp (poly_deg f) (snd ?D)"
      and dd': "direct_decomp (ideal (insert f (insert f0 F)) ∩ P[X])
                  [fst ?D, ideal (insert f0 F) ∩ P[X]]"
      and hom_D: "homogeneous f ⟹ hom_decomp (snd ?D)"
      by (rule ideal_decomp_aux, auto intro: ideal_decomp_aux simp: False)
    note fin_X this(2-4)
    moreover have "poly_deg f ≤ poly_deg f0" by (rule insert.prems) simp
    ultimately obtain qs where valid_qs: "valid_decomp X qs" and cn_qs: "cone_decomp (fst ?D) qs"
      and std_qs: "standard_decomp (poly_deg f0) qs"
      and hom_qs: "hom_decomp (snd ?D) ⟹ hom_decomp qs" by (rule standard_decomp_geE) blast
    let ?T = "sum_list ` listset [T, fst ?D]"
    let ?ps = "ps @ qs"
    show ?thesis
    proof (rule insert.prems)
      from valid_ps valid_qs show "valid_decomp X ?ps" by (rule valid_decomp_append)
    next
      from std_ps std_qs show "standard_decomp (poly_deg f0) ?ps" by (rule standard_decomp_append)
    next
      from dd have "direct_decomp (ideal (insert f0 F) ∩ P[X]) [T, ideal {f0} ∩ P[X]]"
        by (rule direct_decomp_perm) simp
      hence "T ⊆ ideal (insert f0 F) ∩ P[X]"
        by (rule direct_decomp_Cons_subsetI) (simp add: ideal.span_zero zero_in_Polys)
      hence "T ∩ fst ?D ⊆ ideal (insert f0 F) ∩ fst ?D" by blast
      hence "T ∩ fst ?D ⊆ {0}" by (simp only: eq)
      from refl have "direct_decomp ?T [T, fst ?D]"
      proof (intro direct_decompI inj_onI)
        fix xs ys
        assume "xs ∈ listset [T, fst ?D]"
        then obtain x1 x2 where "x1 ∈ T" and "x2 ∈ fst ?D" and xs: "xs = [x1, x2]"
          by (rule listset_doubletonE)
        assume "ys ∈ listset [T, fst ?D]"
        then obtain y1 y2 where "y1 ∈ T" and "y2 ∈ fst ?D" and ys: "ys = [y1, y2]"
          by (rule listset_doubletonE)
        assume "sum_list xs = sum_list ys"
        hence "x1 - y1 = y2 - x2" by (simp add: xs ys) (metis add_diff_cancel_left add_diff_cancel_right)
        moreover from cn_ps ‹x1 ∈ T› ‹y1 ∈ T› have "x1 - y1 ∈ T" by (rule cone_decomp_closed_minus)
        moreover from cn_D ‹y2 ∈ fst ?D› ‹x2 ∈ fst ?D› have "y2 - x2 ∈ fst ?D"
          by (rule cone_decomp_closed_minus)
        ultimately have "y2 - x2 ∈ T ∩ fst ?D" by simp
        also have "… ⊆ {0}" by fact
        finally have "x2 = y2" by simp
        with ‹x1 - y1 = y2 - x2› show "xs = ys" by (simp add: xs ys)
      qed
      thus "cone_decomp ?T ?ps" using cn_ps cn_qs by (rule cone_decomp_append)
    next
      assume "⋀f'. f' ∈ insert f F ⟹ homogeneous f'"
      hence "homogeneous f" and "⋀f'. f' ∈ F ⟹ homogeneous f'" by blast+
      from this(2) have "hom_decomp ps" by (rule hom_ps)
      moreover from ‹homogeneous f› have "hom_decomp qs" by (intro hom_qs hom_D)
      ultimately show "hom_decomp (ps @ qs)" by (simp only: hom_decomp_append_iff)
    next
      from dd' have "direct_decomp (ideal (insert f0 (insert f F)) ∩ P[X])
                      [ideal (insert f0 F) ∩ P[X], fst ?D]"
        by (simp add: insert_commute direct_decomp_perm)
      hence "direct_decomp (ideal (insert f0 (insert f F)) ∩ P[X])
                      ([fst ?D] @ [ideal {f0} ∩ P[X], T])" using dd by (rule direct_decomp_direct_decomp)
      hence "direct_decomp (ideal (insert f0 (insert f F)) ∩ P[X]) ([ideal {f0} ∩ P[X]] @ [T, fst ?D])"
        by (rule direct_decomp_perm) auto
      hence "direct_decomp (ideal (insert f0 (insert f F)) ∩ P[X]) [sum_list ` listset [ideal {f0} ∩ P[X]], ?T]"
        by (rule direct_decomp_appendD)
      thus "direct_decomp (ideal (insert f0 (insert f F)) ∩ P[X]) [ideal {f0} ∩ P[X], ?T]"
        by (simp add: image_image)
    qed
  qed
qed

subsection ‹Exact Cone Decompositions›

definition exact_decomp :: "nat ⇒ ((('x ⇒0 nat) ⇒0 'a::zero) × 'x set) list ⇒ bool"
  where "exact_decomp m ps ⟷ (∀(h, U)∈set ps. h ∈ P[X] ∧ U ⊆ X) ∧
                              (∀(h, U)∈set ps. ∀(h', U')∈set ps. poly_deg h = poly_deg h' ⟶
                                          m < card U ⟶ m < card U' ⟶ (h, U) = (h', U'))"

lemma exact_decompI:
  "(⋀h U. (h, U) ∈ set ps ⟹ h ∈ P[X]) ⟹ (⋀h U. (h, U) ∈ set ps ⟹ U ⊆ X) ⟹
    (⋀h h' U U'. (h, U) ∈ set ps ⟹ (h', U') ∈ set ps ⟹ poly_deg h = poly_deg h' ⟹
            m < card U ⟹ m < card U' ⟹ (h, U) = (h', U')) ⟹
    exact_decomp m ps"
  unfolding exact_decomp_def by fastforce

lemma exact_decompD:
  assumes "exact_decomp m ps" and "(h, U) ∈ set ps"
  shows "h ∈ P[X]" and "U ⊆ X"
    and "(h', U') ∈ set ps ⟹ poly_deg h = poly_deg h' ⟹ m < card U ⟹ m < card U' ⟹
            (h, U) = (h', U')"
  using assms unfolding exact_decomp_def by fastforce+

lemma exact_decompI_zero:
  assumes "⋀h U. (h, U) ∈ set ps ⟹ h ∈ P[X]" and "⋀h U. (h, U) ∈ set ps ⟹ U ⊆ X"
    and "⋀h h' U U'. (h, U) ∈ set (ps+) ⟹ (h', U') ∈ set (ps+) ⟹ poly_deg h = poly_deg h' ⟹
              (h, U) = (h', U')"
  shows "exact_decomp 0 ps"
  using assms(1, 2)
proof (rule exact_decompI)
  fix h h' and U U' :: "'x set"
  assume "0 < card U"
  hence "U ≠ {}" by auto
  moreover assume "(h, U) ∈ set ps"
  ultimately have "(h, U) ∈ set (ps+)" by (simp add: pos_decomp_def)
  assume "0 < card U'"
  hence "U' ≠ {}" by auto
  moreover assume "(h', U') ∈ set ps"
  ultimately have "(h', U') ∈ set (ps+)" by (simp add: pos_decomp_def)
  assume "poly_deg h = poly_deg h'"
  with ‹(h, U) ∈ set (ps+)› ‹(h', U') ∈ set (ps+)› show "(h, U) = (h', U')" by (rule assms(3))
qed

lemma exact_decompD_zero:
  assumes "exact_decomp 0 ps" and "(h, U) ∈ set (ps+)" and "(h', U') ∈ set (ps+)"
    and "poly_deg h = poly_deg h'"
  shows "(h, U) = (h', U')"
proof -
  from assms(2) have "(h, U) ∈ set ps" and "U ≠ {}" by (simp_all add: pos_decomp_def)
  from assms(1) 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)
  from assms(3) have "(h', U') ∈ set ps" and "U' ≠ {}" by (simp_all add: pos_decomp_def)
  from assms(1) 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)
  show ?thesis by (rule exact_decompD) fact+
qed

lemma exact_decomp_imp_valid_decomp:
  assumes "exact_decomp m ps" and "⋀h U. (h, U) ∈ set ps ⟹ h ≠ 0"
  shows "valid_decomp X ps"
proof (rule valid_decompI)
  fix h U
  assume *: "(h, U) ∈ set ps"
  with assms(1) show "h ∈ P[X]" and "U ⊆ X" by (rule exact_decompD)+
  from * show "h ≠ 0" by (rule assms(2))
qed

lemma exact_decomp_card_X:
  assumes "valid_decomp X ps" and "card X ≤ m"
  shows "exact_decomp m ps"
proof (rule exact_decompI)
  fix h U
  assume "(h, U) ∈ set ps"
  with assms(1) show "h ∈ P[X]" and "U ⊆ X" by (rule valid_decompD)+
next
  fix h1 h2 U1 U2
  assume "(h1, U1) ∈ set ps"
  with assms(1) have "U1 ⊆ X" by (rule valid_decompD)
  with fin_X have "card U1 ≤ card X" by (rule card_mono)
  also have "… ≤ m" by (fact assms(2))
  also assume "m < card U1"
  finally show "(h1, U1) = (h2, U2)" by simp
qed

definition 𝖺 :: "((('x ⇒0 nat) ⇒0 'a::zero) × 'x set) list ⇒ nat"
  where "𝖺 ps = (LEAST k. standard_decomp k ps)"

definition 𝖻 :: "((('x ⇒0 nat) ⇒0 'a::zero) × 'x set) list ⇒ nat ⇒ nat"
  where "𝖻 ps i = (LEAST d. 𝖺 ps ≤ d ∧ (∀(h, U)∈set ps. i ≤ card U ⟶ poly_deg h < d))"

lemma 𝖺: "standard_decomp k ps ⟹ standard_decomp (𝖺 ps) ps"
  unfolding 𝖺_def by (rule LeastI)

lemma 𝖺_Nil:
  assumes "ps+ = []"
  shows "𝖺 ps = 0"
proof -
  from assms have "standard_decomp 0 ps" by (rule standard_decomp_Nil)
  thus ?thesis unfolding 𝖺_def by (rule Least_eq_0)
qed

lemma 𝖺_nonempty:
  assumes "valid_decomp X ps" and "standard_decomp k ps" and "ps+ ≠ []"
  shows "𝖺 ps = Min (poly_deg ` fst ` set (ps+))"
  using fin_X assms(1) _ assms(3)
proof (rule standard_decomp_nonempty_unique)
  from assms(2) show "standard_decomp (𝖺 ps) ps" by (rule 𝖺)
qed

lemma 𝖺_nonempty_unique:
  assumes "valid_decomp X ps" and "standard_decomp k ps" and "ps+ ≠ []"
  shows "𝖺 ps = k"
proof -
  from assms have "𝖺 ps = Min (poly_deg ` fst ` set (ps+))" by (rule 𝖺_nonempty)
  moreover from fin_X assms have "k = Min (poly_deg ` fst ` set (ps+))"
    by (rule standard_decomp_nonempty_unique)
  ultimately show ?thesis by simp
qed

lemma 𝖻:
  shows "𝖺 ps ≤ 𝖻 ps i" and "(h, U) ∈ set ps ⟹ i ≤ card U ⟹ poly_deg h < 𝖻 ps i"
proof -
  let ?A = "poly_deg ` fst ` set ps"
  define A where "A = insert (𝖺 ps) ?A"
  define m where "m = Suc (Max A)"
  from finite_set have "finite ?A" by (intro finite_imageI)
  hence "finite A" by (simp add: A_def)
  have "𝖺 ps ≤ 𝖻 ps i ∧ (∀(h', U')∈set ps. i ≤ card U' ⟶ poly_deg h' < 𝖻 ps i)" unfolding 𝖻_def
  proof (rule LeastI)
    have "𝖺 ps ∈ A" by (simp add: A_def)
    with ‹finite A› have "𝖺 ps ≤ Max A" by (rule Max_ge)
    hence "𝖺 ps ≤ m" by (simp add: m_def)
    moreover {
      fix h U
      assume "(h, U) ∈ set ps"
      hence "poly_deg (fst (h, U)) ∈ ?A" by (intro imageI)
      hence "poly_deg h ∈ A" by (simp add: A_def)
      with ‹finite A› have "poly_deg h ≤ Max A" by (rule Max_ge)
      hence "poly_deg h < m" by (simp add: m_def)
    }
    ultimately show "𝖺 ps ≤ m ∧ (∀(h, U)∈set ps. i ≤ card U ⟶ poly_deg h < m)" by blast
  qed
  thus "𝖺 ps ≤ 𝖻 ps i" and "(h, U) ∈ set ps ⟹ i ≤ card U ⟹ poly_deg h < 𝖻 ps i" by blast+
qed

lemma 𝖻_le:
  "𝖺 ps ≤ d ⟹ (⋀h' U'. (h', U') ∈ set ps ⟹ i ≤ card U' ⟹ poly_deg h' < d) ⟹ 𝖻 ps i ≤ d"
  unfolding 𝖻_def by (intro Least_le) blast

lemma 𝖻_decreasing:
  assumes "i ≤ j"
  shows "𝖻 ps j ≤ 𝖻 ps i"
proof (rule 𝖻_le)
  fix h U
  assume "(h, U) ∈ set ps"
  assume "j ≤ card U"
  with assms(1) have "i ≤ card U" by (rule le_trans)
  with ‹(h, U) ∈ set ps› show "poly_deg h < 𝖻 ps i" by (rule 𝖻)
qed (fact 𝖻)

lemma 𝖻_Nil:
  assumes "ps+ = []" and "Suc 0 ≤ i"
  shows "𝖻 ps i = 0"
  unfolding 𝖻_def
proof (rule Least_eq_0)
  from assms(1) have "𝖺 ps = 0" by (rule 𝖺_Nil)
  moreover {
    fix h and U::"'x set"
    note assms(2)
    also assume "i ≤ card U"
    finally have "U ≠ {}" by auto
    moreover assume "(h, U) ∈ set ps"
    ultimately have "(h, U) ∈ set (ps+)" by (simp add: pos_decomp_def)
    hence False by (simp add: assms)
  }
  ultimately show "𝖺 ps ≤ 0 ∧ (∀(h, U)∈set ps. i ≤ card U ⟶ poly_deg h < 0)" by blast
qed

lemma 𝖻_zero:
  assumes "ps ≠ []"
  shows "Suc (Max (poly_deg ` fst ` set ps)) ≤ 𝖻 ps 0"
proof -
  from finite_set have "finite (poly_deg ` fst ` set ps)" by (intro finite_imageI)
  moreover from assms have "poly_deg ` fst ` set ps ≠ {}" by simp
  moreover have "∀a∈poly_deg ` fst ` set ps. a < 𝖻 ps 0"
  proof
    fix d
    assume "d ∈ poly_deg ` fst ` set ps"
    then obtain p where "p ∈ set ps" and "d = poly_deg (fst p)" by blast
    moreover obtain h U where "p = (h, U)" using prod.exhaust by blast
    ultimately have "(h, U) ∈ set ps" and d: "d = poly_deg h" by simp_all
    from this(1) le0 show "d < 𝖻 ps 0" unfolding d by (rule 𝖻)
  qed
  ultimately have "Max (poly_deg ` fst ` set ps) < 𝖻 ps 0" by simp
  thus ?thesis by simp
qed

corollary 𝖻_zero_gr:
  assumes "(h, U) ∈ set ps"
  shows "poly_deg h < 𝖻 ps 0"
proof -
  have "poly_deg h ≤ Max (poly_deg ` fst ` set ps)"
  proof (rule Max_ge)
    from finite_set show "finite (poly_deg ` fst ` set ps)" by (intro finite_imageI)
  next
    from assms have "poly_deg (fst (h, U)) ∈ poly_deg ` fst ` set ps" by (intro imageI)
    thus "poly_deg h ∈ poly_deg ` fst ` set ps" by simp
  qed
  also have "… < Suc …" by simp
  also have "… ≤ 𝖻 ps 0"
  proof (rule 𝖻_zero)
    from assms show "ps ≠ []" by auto
  qed
  finally show ?thesis .
qed

lemma 𝖻_one:
  assumes "valid_decomp X ps" and "standard_decomp k ps"
  shows "𝖻 ps (Suc 0) = (if ps+ = [] then 0 else Suc (Max (poly_deg ` fst ` set (ps+))))"
proof (cases "ps+ = []")
  case True
  hence "𝖻 ps (Suc 0) = 0" using le_refl by (rule 𝖻_Nil)
  with True show ?thesis by simp
next
  case False
  with assms have aP: "𝖺 ps = Min (poly_deg ` fst ` set (ps+))" (is "_ = Min ?A") by (rule 𝖺_nonempty)
  from pos_decomp_subset finite_set have "finite (set (ps+))" by (rule finite_subset)
  hence "finite ?A" by (intro finite_imageI)
  from False have "?A ≠ {}" by simp
  have "𝖻 ps (Suc 0) = Suc (Max ?A)" unfolding 𝖻_def
  proof (rule Least_equality)
    from ‹finite ?A› ‹?A ≠ {}› have "𝖺 ps ∈ ?A" unfolding aP by (rule Min_in)
    with ‹finite ?A› have "𝖺 ps ≤ Max ?A" by (rule Max_ge)
    hence "𝖺 ps ≤ Suc (Max ?A)" by simp
    moreover {
      fix h U
      assume "(h, U) ∈ set ps"
      with fin_X assms(1) have "finite U" by (rule valid_decompD_finite)
      moreover assume "Suc 0 ≤ card U"
      ultimately have "U ≠ {}" by auto
      with ‹(h, U) ∈ set ps› have "(h, U) ∈ set (ps+)" by (simp add: pos_decomp_def)
      hence "poly_deg (fst (h, U)) ∈ ?A" by (intro imageI)
      hence "poly_deg h ∈ ?A" by (simp only: fst_conv)
      with ‹finite ?A› have "poly_deg h ≤ Max ?A" by (rule Max_ge)
      hence "poly_deg h < Suc (Max ?A)" by simp
    }
    ultimately show "𝖺 ps ≤ Suc (Max ?A) ∧ (∀(h, U)∈set ps. Suc 0 ≤ card U ⟶ poly_deg h < Suc (Max ?A))"
      by blast
  next
    fix d
    assume "𝖺 ps ≤ d ∧ (∀(h, U)∈set ps. Suc 0 ≤ card U ⟶ poly_deg h < d)"
    hence rl: "poly_deg h < d" if "(h, U) ∈ set ps" and "0 < card U" for h U using that by auto
    have "Max ?A < d" unfolding Max_less_iff[OF ‹finite ?A› ‹?A ≠ {}›]
    proof
      fix d0
      assume "d0 ∈ poly_deg ` fst ` set (ps+)"
      then obtain h U where "(h, U) ∈ set (ps+)" and d0: "d0 = poly_deg h" by auto
      from this(1) have "(h, U) ∈ set ps" and "U ≠ {}" by (simp_all add: pos_decomp_def)
      from fin_X assms(1) this(1) have "finite U" by (rule valid_decompD_finite)
      with ‹U ≠ {}› have "0 < card U" by (simp add: card_gt_0_iff)
      with ‹(h, U) ∈ set ps› show "d0 < d" unfolding d0 by (rule rl)
    qed
    thus "Suc (Max ?A) ≤ d" by simp
  qed
  with False show ?thesis by simp
qed

corollary 𝖻_one_gr:
  assumes "valid_decomp X ps" and "standard_decomp k ps" and "(h, U) ∈ set (ps+)"
  shows "poly_deg h < 𝖻 ps (Suc 0)"
proof -
  from assms(3) have "ps+ ≠ []" by auto
  with assms(1, 2) have eq: "𝖻 ps (Suc 0) = Suc (Max (poly_deg ` fst ` set (ps+)))"
    by (simp add: 𝖻_one)
  have "poly_deg h ≤ Max (poly_deg ` fst ` set (ps+))"
  proof (rule Max_ge)
    from finite_set show "finite (poly_deg ` fst ` set (ps+))" by (intro finite_imageI)
  next
    from assms(3) have "poly_deg (fst (h, U)) ∈ poly_deg ` fst ` set (ps+)" by (intro imageI)
    thus "poly_deg h ∈ poly_deg ` fst ` set (ps+)" by simp
  qed
  also have "… < 𝖻 ps (Suc 0)" by (simp add: eq)
  finally show ?thesis .
qed

lemma 𝖻_card_X:
  assumes "exact_decomp m ps" and "Suc (card X) ≤ i"
  shows "𝖻 ps i = 𝖺 ps"
  unfolding 𝖻_def
proof (rule Least_equality)
  {
    fix h U
    assume "(h, U) ∈ set ps"
    with assms(1) have "U ⊆ X" by (rule exact_decompD)
    note assms(2)
    also assume "i ≤ card U"
    finally have "card X < card U" by simp
    with fin_X have "¬ U ⊆ X" by (auto dest: card_mono leD)
    hence False using ‹U ⊆ X› ..
  }
  thus "𝖺 ps ≤ 𝖺 ps ∧ (∀(h, U)∈set ps. i ≤ card U ⟶ poly_deg h < 𝖺 ps)" by blast
qed simp

lemma lem_6_1_1:
  assumes "standard_decomp k ps" and "exact_decomp m ps" and "Suc 0 ≤ i"
    and "i ≤ card X" and "𝖻 ps (Suc i) ≤ d" and "d < 𝖻 ps i"
  obtains h U where "(h, U) ∈ set (ps+)" and "poly_deg h = d" and "card U = i"
proof -
  have "ps+ ≠ []"
  proof
    assume "ps+ = []"
    hence "𝖻 ps i = 0" using assms(3) by (rule 𝖻_Nil)
    with assms(6) show False by simp
  qed
  have eq1: "𝖻 ps (Suc (card X)) = 𝖺 ps" using assms(2) le_refl by (rule 𝖻_card_X)
  from assms(1) have std: "standard_decomp (𝖻 ps (Suc (card X))) ps" unfolding eq1 by (rule 𝖺)
  from assms(4) have "Suc i ≤ Suc (card X)" ..
  hence "𝖻 ps (Suc (card X)) ≤ 𝖻 ps (Suc i)" by (rule 𝖻_decreasing)
  hence "𝖺 ps ≤ 𝖻 ps (Suc i)" by (simp only: eq1)
  have "∃h U. (h, U) ∈ set ps ∧ i ≤ card U ∧ 𝖻 ps i ≤ Suc (poly_deg h)"
  proof (rule ccontr)
    assume *: "∄h U. (h, U) ∈ set ps ∧ i ≤ card U ∧ 𝖻 ps i ≤ Suc (poly_deg h)"
    note ‹𝖺 ps ≤ 𝖻 ps (Suc i)›
    also from assms(5, 6) have "𝖻 ps (Suc i) < 𝖻 ps i" by (rule le_less_trans)
    finally have "𝖺 ps < 𝖻 ps i" .
    hence "𝖺 ps ≤ 𝖻 ps i - 1" by simp
    hence "𝖻 ps i ≤ 𝖻 ps i - 1"
    proof (rule 𝖻_le)
      fix h U
      assume "(h, U) ∈ set ps" and "i ≤ card U"
      show "poly_deg h < 𝖻 ps i - 1"
      proof (rule ccontr)
        assume "¬ poly_deg h < 𝖻 ps i - 1"
        hence "𝖻 ps i ≤ Suc (poly_deg h)" by simp
        with * ‹(h, U) ∈ set ps› ‹i ≤ card U› show False by auto
      qed
    qed
    thus False using ‹𝖺 ps < 𝖻 ps i› by linarith
  qed
  then obtain h U where "(h, U) ∈ set ps" and "i ≤ card U" and "𝖻 ps i ≤ Suc (poly_deg h)" by blast
  from assms(3) this(2) have "U ≠ {}" by auto
  with ‹(h, U) ∈ set ps› have "(h, U) ∈ set (ps+)" by (simp add: pos_decomp_def)
  note std this
  moreover have "𝖻 ps (Suc (card X)) ≤ d" unfolding eq1 using ‹𝖺 ps ≤ 𝖻 ps (Suc i)› assms(5)
    by (rule le_trans)
  moreover have "d ≤ poly_deg h"
  proof -
    from assms(6) ‹𝖻 ps i ≤ Suc (poly_deg h)› have "d < Suc (poly_deg h)" by (rule less_le_trans)
    thus ?thesis by simp
  qed
  ultimately obtain h' U' where "(h', U') ∈ set ps" and d: "poly_deg h' = d" and "card U ≤ card U'"
    by (rule standard_decompE)
  from ‹i ≤ card U› this(3) have "i ≤ card U'" by (rule le_trans)
  with assms(3) have "U' ≠ {}" by auto
  with ‹(h', U') ∈ set ps› have "(h', U') ∈ set (ps+)" by (simp add: pos_decomp_def)
  moreover note ‹poly_deg h' = d›
  moreover have "card U' = i"
  proof (rule ccontr)
    assume "card U' ≠ i"
    with ‹i ≤ card U'› have "Suc i ≤ card U'" by simp
    with ‹(h', U') ∈ set ps› have "poly_deg h' < 𝖻 ps (Suc i)" by (rule 𝖻)
    with assms(5) show False by (simp add: d)
  qed
  ultimately show ?thesis ..
qed

corollary lem_6_1_2:
  assumes "standard_decomp k ps" and "exact_decomp 0 ps" and "Suc 0 ≤ i"
    and "i ≤ card X" and "𝖻 ps (Suc i) ≤ d" and "d < 𝖻 ps i"
  obtains h U where "{(h', U') ∈ set (ps+). poly_deg h' = d} = {(h, U)}" and "card U = i"
proof -
  from assms obtain h U where "(h, U) ∈ set (ps+)" and "poly_deg h = d" and "card U = i"
    by (rule lem_6_1_1)
  hence "{(h, U)} ⊆ {(h', U') ∈ set (ps+). poly_deg h' = d}" (is "_ ⊆ ?A") by simp
  moreover have "?A ⊆ {(h, U)}"
  proof
    fix x
    assume "x ∈ ?A"
    then obtain h' U' where "(h', U') ∈ set (ps+)" and "poly_deg h' = d" and x: "x = (h', U')"
      by blast
    note assms(2) ‹(h, U) ∈ set (ps+)› this(1)
    moreover have "poly_deg h = poly_deg h'" by (simp only: ‹poly_deg h = d› ‹poly_deg h' = d›)
    ultimately have "(h, U) = (h', U')" by (rule exact_decompD_zero)
    thus "x ∈ {(h, U)}" by (simp add: x)
  qed
  ultimately have "{(h, U)} = ?A" ..
  hence "?A = {(h, U)}" by (rule sym)
  thus ?thesis using ‹card U = i› ..
qed

corollary lem_6_1_2':
  assumes "standard_decomp k ps" and "exact_decomp 0 ps" and "Suc 0 ≤ i"
    and "i ≤ card X" and "𝖻 ps (Suc i) ≤ d" and "d < 𝖻 ps i"
  shows "card {(h', U') ∈ set (ps+). poly_deg h' = d} = 1" (is "card ?A = _")
    and "{(h', U') ∈ set (ps+). poly_deg h' = d ∧ card U' = i} = {(h', U') ∈ set (ps+). poly_deg h' = d}"
            (is "?B = _")
    and "card {(h', U') ∈ set (ps+). poly_deg h' = d ∧ card U' = i} = 1"
proof -
  from assms obtain h U where "?A = {(h, U)}" and "card U = i" by (rule lem_6_1_2)
  from this(1) show "card ?A = 1" by simp
  moreover show "?B = ?A"
  proof
    have "(h, U) ∈ ?A" by (simp add: ‹?A = {(h, U)}›)
    have "?A = {(h, U)}" by fact
    also from ‹(h, U) ∈ ?A› ‹card U = i› have "… ⊆ ?B" by simp
    finally show "?A ⊆ ?B" .
  qed blast
  ultimately show "card ?B = 1" by simp 
qed

corollary lem_6_1_3:
  assumes "standard_decomp k ps" and "exact_decomp 0 ps" and "Suc 0 ≤ i"
    and "i ≤ card X" and "(h, U) ∈ set (ps+)" and "card U = i"
  shows "𝖻 ps (Suc i) ≤ poly_deg h"
proof (rule ccontr)
  define j where "j = (LEAST j'. 𝖻 ps j' ≤ poly_deg h)"
  assume "¬ 𝖻 ps (Suc i) ≤ poly_deg h"
  hence "poly_deg h < 𝖻 ps (Suc i)" by simp
  from assms(2) le_refl have "𝖻 ps (Suc (card X)) = 𝖺 ps" by (rule 𝖻_card_X)
  also from _ assms(5) have "… ≤ poly_deg h"
  proof (rule standard_decompD)
    from assms(1) show "standard_decomp (𝖺 ps) ps" by (rule 𝖺)
  qed
  finally have "𝖻 ps (Suc (card X)) ≤ poly_deg h" .
  hence 1: "𝖻 ps j ≤ poly_deg h" unfolding j_def by (rule LeastI)
  have "Suc i < j"
  proof (rule ccontr)
    assume "¬ Suc i < j"
    hence "j ≤ Suc i" by simp
    hence "𝖻 ps (Suc i) ≤ 𝖻 ps j" by (rule 𝖻_decreasing)
    also have "… ≤ poly_deg h" by fact
    finally show False using ‹poly_deg h < 𝖻 ps (Suc i)› by simp
  qed
  hence eq: "Suc (j - 1) = j" by simp
  note assms(1, 2)
  moreover from assms(3) have "Suc 0 ≤ j - 1"
  proof (rule le_trans)
    from ‹Suc i < j› show "i ≤ j - 1" by simp
  qed
  moreover have "j - 1 ≤ card X"
  proof -
    have "j ≤ Suc (card X)" unfolding j_def by (rule Least_le) fact
    thus ?thesis by simp
  qed
  moreover from 1 have "𝖻 ps (Suc (j - 1)) ≤ poly_deg h" by (simp only: eq)
  moreover have "poly_deg h < 𝖻 ps (j - 1)"
  proof (rule ccontr)
    assume "¬ poly_deg h < 𝖻 ps (j - 1)"
    hence "𝖻 ps (j - 1) ≤ poly_deg h" by simp
    hence "j ≤ j - 1" unfolding j_def by (rule Least_le)
    also have "… < Suc (j - 1)" by simp
    finally show False by (simp only: eq)
  qed
  ultimately obtain h0 U0
    where eq1: "{(h', U'). (h', U') ∈ set (ps+) ∧ poly_deg h' = poly_deg h} = {(h0, U0)}"
    and "card U0 = j - 1" by (rule lem_6_1_2)
  from assms(5) have "(h, U) ∈ {(h', U'). (h', U') ∈ set (ps+) ∧ poly_deg h' = poly_deg h}" by simp
  hence "(h, U) ∈ {(h0, U0)}" by (simp only: eq1)
  hence "U = U0" by simp
  hence "card U = j - 1" by (simp only: ‹card U0 = j - 1›)
  hence "i = j - 1" by (simp only: assms(6))
  hence "Suc i = j" by (simp only: eq)
  with ‹Suc i < j› show False by simp
qed

qualified fun shift_list :: "((('x ⇒0 nat) ⇒0 'a::{comm_ring_1,ring_no_zero_divisors}) × 'x set) ⇒
                              'x ⇒ _ list ⇒ _ list" where
  "shift_list (h, U) x ps =
        ((punit.monom_mult 1 (Poly_Mapping.single x 1) h, U) # (h, U - {x}) # removeAll (h, U) ps)"

declare shift_list.simps[simp del]

lemma monomial_decomp_shift_list:
  assumes "monomial_decomp ps" and "hU ∈ set ps"
  shows "monomial_decomp (shift_list hU x ps)"
proof -
  let ?x = "Poly_Mapping.single x (1::nat)"
  obtain h U where hU: "hU = (h, U)" using prod.exhaust by blast
  with assms(2) have "(h, U) ∈ set ps" by simp
  with assms(1) have 1: "is_monomial h" and 2: "lcf h = 1" by (rule monomial_decompD)+
  from this(1) have "monomial (lcf h) (lpp h) = h" by (rule punit.monomial_eq_itself)
  moreover define t where "t = lpp h"
  ultimately have "h = monomial 1 t" by (simp only: 2)
  hence "is_monomial (punit.monom_mult 1 ?x h)" and "lcf (punit.monom_mult 1 ?x h) = 1"
    by (simp_all add: punit.monom_mult_monomial monomial_is_monomial)
  with assms(1) 1 2 show ?thesis by (simp add: shift_list.simps monomial_decomp_def hU)
qed

lemma hom_decomp_shift_list:
  assumes "hom_decomp ps" and "hU ∈ set ps"
  shows "hom_decomp (shift_list hU x ps)"
proof -
  let ?x = "Poly_Mapping.single x (1::nat)"
  obtain h U where hU: "hU = (h, U)" using prod.exhaust by blast
  with assms(2) have "(h, U) ∈ set ps" by simp
  with assms(1) have 1: "homogeneous h" by (rule hom_decompD)
  hence "homogeneous (punit.monom_mult 1 ?x h)" by (simp only: homogeneous_monom_mult)
  with assms(1) 1 show ?thesis by (simp add: shift_list.simps hom_decomp_def hU)
qed

lemma valid_decomp_shift_list:
  assumes "valid_decomp X ps" and "(h, U) ∈ set ps" and "x ∈ U"
  shows "valid_decomp X (shift_list (h, U) x ps)"
proof -
  let ?x = "Poly_Mapping.single x (1::nat)"
  from assms(1, 2) have "h ∈ P[X]" and "h ≠ 0" and "U ⊆ X" by (rule valid_decompD)+
  moreover from this(1) have "punit.monom_mult 1 ?x h ∈ P[X]"
  proof (intro Polys_closed_monom_mult PPs_closed_single)
    from ‹x ∈ U› ‹U ⊆ X› show "x ∈ X" ..
  qed
  moreover from ‹U ⊆ X› have "U - {x} ⊆ X" by blast
  ultimately show ?thesis
    using assms(1) ‹h ≠ 0› by (simp add: valid_decomp_def punit.monom_mult_eq_zero_iff shift_list.simps)
qed

lemma standard_decomp_shift_list:
  assumes "standard_decomp k ps" and "(h1, U1) ∈ set ps" and "(h2, U2) ∈ set ps"
    and "poly_deg h1 = poly_deg h2" and "card U2 ≤ card U1" and "(h1, U1) ≠ (h2, U2)" and "x ∈ U2"
  shows "standard_decomp k (shift_list (h2, U2) x ps)"
proof (rule standard_decompI)
  let ?p1 = "(punit.monom_mult 1 (Poly_Mapping.single x 1) h2, U2)"
  let ?p2 = "(h2, U2 - {x})"
  let ?qs = "removeAll (h2, U2) ps"
  fix h U
  assume "(h, U) ∈ set ((shift_list (h2, U2) x ps)+)"
  hence disj: "(h, U) = ?p1 ∨ ((h, U) = ?p2 ∧ U2 - {x} ≠ {}) ∨ (h, U) ∈ set (ps+)"
    by (auto simp: pos_decomp_def shift_list.simps split: if_split_asm)
  from assms(7) have "U2 ≠ {}" by blast
  with assms(3) have "(h2, U2) ∈ set (ps+)" by (simp add: pos_decomp_def)
  with assms(1) have k_le: "k ≤ poly_deg h2" by (rule standard_decompD)

  let ?x = "Poly_Mapping.single x 1"
  from disj show "k ≤ poly_deg h"
  proof (elim disjE)
    assume "(h, U) = ?p1"
    hence h: "h = punit.monom_mult (1::'a) ?x h2" by simp
    note k_le
    also have "poly_deg h2 ≤ poly_deg h" by (cases "h2 = 0") (simp_all add: h poly_deg_monom_mult)
    finally show ?thesis .
  next
    assume "(h, U) = ?p2 ∧ U2 - {x} ≠ {}"
    with k_le show ?thesis by simp
  next
    assume "(h, U) ∈ set (ps+)"
    with assms(1) show ?thesis by (rule standard_decompD)
  qed

  fix d
  assume "k ≤ d" and "d ≤ poly_deg h"
  from disj obtain h' U' where 1: "(h', U') ∈ set (?p1 # ps)" and "poly_deg h' = d"
    and "card U ≤ card U'"
  proof (elim disjE)
    assume "(h, U) = ?p1"
    hence h: "h = punit.monom_mult 1 ?x h2" and "U = U2" by simp_all
    from ‹d ≤ poly_deg h› have "d ≤ poly_deg h2 ∨ poly_deg h = d"
      by (cases "h2 = 0") (auto simp: h poly_deg_monom_mult deg_pm_single)
    thus ?thesis
    proof
      assume "d ≤ poly_deg h2"
      with assms(1) ‹(h2, U2) ∈ set (ps+)› ‹k ≤ d› obtain h' U'
        where "(h', U') ∈ set ps" and "poly_deg h' = d" and "card U2 ≤ card U'"
        by (rule standard_decompE)
      from this(1) have "(h', U') ∈ set (?p1 # ps)" by simp
      moreover note ‹poly_deg h' = d›
      moreover from ‹card U2 ≤ card U'› have "card U ≤ card U'" by (simp only: ‹U = U2›)
      ultimately show ?thesis ..
    next
      have "(h, U) ∈ set (?p1 # ps)" by (simp add: ‹(h, U) = ?p1›)
      moreover assume "poly_deg h = d"
      ultimately show ?thesis using le_refl ..
    qed
  next
    assume "(h, U) = ?p2 ∧ U2 - {x} ≠ {}"
    hence "h = h2" and U: "U = U2 - {x}" by simp_all
    from ‹d ≤ poly_deg h› this(1) have "d ≤ poly_deg h2" by simp
    with assms(1) ‹(h2, U2) ∈ set (ps+)› ‹k ≤ d› obtain h' U'
      where "(h', U') ∈ set ps" and "poly_deg h' = d" and "card U2 ≤ card U'"
      by (rule standard_decompE)
    from this(1) have "(h', U') ∈ set (?p1 # ps)" by simp
    moreover note ‹poly_deg h' = d›
    moreover from _ ‹card U2 ≤ card U'› have "card U ≤ card U'" unfolding U
      by (rule le_trans) (metis Diff_empty card_Diff1_le card.infinite finite_Diff_insert order_refl)
    ultimately show ?thesis ..
  next
    assume "(h, U) ∈ set (ps+)"
    from assms(1) this ‹k ≤ d› ‹d ≤ poly_deg h› obtain h' U'
      where "(h', U') ∈ set ps" and "poly_deg h' = d" and "card U ≤ card U'"
      by (rule standard_decompE)
    from this(1) have "(h', U') ∈ set (?p1 # ps)" by simp
    thus ?thesis using ‹poly_deg h' = d› ‹card U ≤ card U'› ..
  qed
  show "∃h' U'. (h', U') ∈ set (shift_list (h2, U2) x ps) ∧ poly_deg h' = d ∧ card U ≤ card U'"
  proof (cases "(h', U') = (h2, U2)")
    case True
    hence "h' = h2" and "U' = U2" by simp_all
    from assms(2, 6) have "(h1, U1) ∈ set (shift_list (h2, U2) x ps)" by (simp add: shift_list.simps)
    moreover from ‹poly_deg h' = d› have "poly_deg h1 = d" by (simp only: ‹h' = h2› assms(4))
    moreover from ‹card U ≤ card U'› assms(5) have "card U ≤ card U1" by (simp add: ‹U' = U2›)
    ultimately show ?thesis by blast
  next
    case False
    with 1 have "(h', U') ∈ set (shift_list (h2, U2) x ps)" by (auto simp: shift_list.simps)
    thus ?thesis using ‹poly_deg h' = d› ‹card U ≤ card U'› by blast
  qed
qed

lemma cone_decomp_shift_list:
  assumes "valid_decomp X ps" and "cone_decomp T ps" and "(h, U) ∈ set ps" and "x ∈ U"
  shows "cone_decomp T (shift_list (h, U) x ps)"
proof -
  let ?p1 = "(punit.monom_mult 1 (Poly_Mapping.single x 1) h, U)"
  let ?p2 = "(h, U - {x})"
  let ?qs = "removeAll (h, U) ps"
  from assms(3) obtain ps1 ps2 where ps: "ps = ps1 @ (h, U) # ps2" and *: "(h, U) ∉ set ps1"
    by (meson split_list_first)
  have "count_list ps2 (h, U) = 0"
  proof (rule ccontr)
    from assms(1, 3) have "h ≠ 0" by (rule valid_decompD)
    assume "count_list ps2 (h, U) ≠ 0"
    hence "1 < count_list ps (h, U)" by (simp add: ps)
    also have "… ≤ count_list (map cone ps) (cone (h, U))" by (fact count_list_map_ge)
    finally have "1 < count_list (map cone ps) (cone (h, U))" .
    with cone_decompD have "cone (h, U) = {0}"
    proof (rule direct_decomp_repeated_eq_zero)
      fix s
      assume "s ∈ set (map cone ps)"
      thus "0 ∈ s" by (auto intro: zero_in_cone)
    qed (fact assms(2))
    with tip_in_cone[of h U] have "h = 0" by simp
    with ‹h ≠ 0› show False ..
  qed
  hence **: "(h, U) ∉ set ps2" by (simp add: count_list_0_iff)
  have "mset ps = mset ((h, U) # ps1 @ ps2)" (is "mset _ = mset ?ps")
    by (simp add: ps)
  with assms(2) have "cone_decomp T ?ps" by (rule cone_decomp_perm)
  hence "direct_decomp T (map cone ?ps)" by (rule cone_decompD)
  hence "direct_decomp T (cone (h, U) # map cone (ps1 @ ps2))" by simp
  hence "direct_decomp T ((map cone (ps1 @ ps2)) @ [cone ?p1, cone ?p2])"
  proof (rule direct_decomp_direct_decomp)
    let ?x = "Poly_Mapping.single x (Suc 0)"
    have "direct_decomp (cone (h, insert x (U - {x})))
              [cone (h, U - {x}), cone (monomial (1::'a) ?x * h, insert x (U - {x}))]"
      by (rule direct_decomp_cone_insert) simp
    with assms(4) show "direct_decomp (cone (h, U)) [cone ?p1, cone ?p2]"
      by (simp add: insert_absorb times_monomial_left direct_decomp_perm)
  qed
  hence "direct_decomp T (map cone (ps1 @ ps2 @ [?p1, ?p2]))" by simp
  hence "cone_decomp T (ps1 @ ps2 @ [?p1, ?p2])" by (rule cone_decompI)
  moreover have "mset (ps1 @ ps2 @ [?p1, ?p2]) = mset (?p1 # ?p2 # (ps1 @ ps2))"
    by simp
  ultimately have "cone_decomp T (?p1 # ?p2 # (ps1 @ ps2))" by (rule cone_decomp_perm)
  also from * ** have "ps1 @ ps2 = removeAll (h, U) ps" by (simp add: remove1_append ps)
  finally show ?thesis by (simp only: shift_list.simps)
qed

subsection ‹Functions ‹shift› and ‹exact››

context
  fixes k m :: nat
begin

context
  fixes d :: nat
begin

definition shift2_inv :: "((('x ⇒0 nat) ⇒0 'a::zero) × 'x set) list ⇒ bool" where
  "shift2_inv qs ⟷ valid_decomp X qs ∧ standard_decomp k qs ∧ exact_decomp (Suc m) qs ∧
                         (∀d0<d. card {q ∈ set qs. poly_deg (fst q) = d0 ∧ m < card (snd q)} ≤ 1)"

fun shift1_inv :: "(((('x ⇒0 nat) ⇒0 'a) × 'x set) list × ((('x ⇒0 nat) ⇒0 'a::zero) × 'x set) set) ⇒ bool"
  where "shift1_inv (qs, B) ⟷ B = {q ∈ set qs. poly_deg (fst q) = d ∧ m < card (snd q)} ∧ shift2_inv qs"

lemma shift2_invI:
  "valid_decomp X qs ⟹ standard_decomp k qs ⟹ exact_decomp (Suc m) qs ⟹
    (⋀d0. d0 < d ⟹ card {q ∈ set qs. poly_deg (fst q) = d0 ∧ m < card (snd q)} ≤ 1) ⟹
    shift2_inv qs"
  by (simp add: shift2_inv_def)

lemma shift2_invD:
  assumes "shift2_inv qs"
  shows "valid_decomp X qs" and "standard_decomp k qs" and "exact_decomp (Suc m) qs"
    and "d0 < d ⟹ card {q ∈ set qs. poly_deg (fst q) = d0 ∧ m < card (snd q)} ≤ 1"
  using assms by (simp_all add: shift2_inv_def)

lemma shift1_invI:
  "B = {q ∈ set qs. poly_deg (fst q) = d ∧ m < card (snd q)} ⟹ shift2_inv qs ⟹ shift1_inv (qs, B)"
  by simp

lemma shift1_invD:
  assumes "shift1_inv (qs, B)"
  shows "B = {q ∈ set qs. poly_deg (fst q) = d ∧ m < card (snd q)}" and "shift2_inv qs"
  using assms by simp_all

declare shift1_inv.simps[simp del]

lemma shift1_inv_finite_snd:
  assumes "shift1_inv (qs, B)"
  shows "finite B"
proof (rule finite_subset)
  from assms have "B = {q ∈ set qs. poly_deg (fst q) = d ∧ m < card (snd q)}" by (rule shift1_invD)
  also have "… ⊆ set qs" by blast
  finally show "B ⊆ set qs" .
qed (fact finite_set)

lemma shift1_inv_some_snd:
  assumes "shift1_inv (qs, B)" and "1 < card B" and "(h, U) = (SOME b. b ∈ B ∧ card (snd b) = Suc m)"
  shows "(h, U) ∈ B" and "(h, U) ∈ set qs" and "poly_deg h = d" and "card U = Suc m"
proof -
  define A where "A = {q ∈ B. card (snd q) = Suc m}"
  define Y where "Y = {q ∈ set qs. poly_deg (fst q) = d ∧ Suc m < card (snd q)}"
  from assms(1) have B: "B = {q ∈ set qs. poly_deg (fst q) = d ∧ m < card (snd q)}"
    and inv2: "shift2_inv qs" by (rule shift1_invD)+
  have B': "B = A ∪ Y" by (auto simp: B A_def Y_def)
  have "finite A"
  proof (rule finite_subset)
    show "A ⊆ B" unfolding A_def by blast
  next
    from assms(1) show "finite B" by (rule shift1_inv_finite_snd)
  qed
  moreover have "finite Y"
  proof (rule finite_subset)
    show "Y ⊆ set qs" unfolding Y_def by blast
  qed (fact finite_set)
  moreover have "A ∩ Y = {}" by (auto simp: A_def Y_def)
  ultimately have "card (A ∪ Y) = card A + card Y" by (rule card_Un_disjoint)
  with assms(2) have "1 < card A + card Y" by (simp only: B')
  thm card_le_Suc0_iff_eq[OF ‹finite Y›]
  moreover have "card Y ≤ 1" unfolding One_nat_def card_le_Suc0_iff_eq[OF ‹finite Y›]
  proof (intro ballI)
    fix q1 q2 :: "(('x ⇒0 nat) ⇒0 'a) × 'x set"
    obtain h1 U1 where q1: "q1 = (h1, U1)" using prod.exhaust by blast
    obtain h2 U2 where q2: "q2 = (h2, U2)" using prod.exhaust by blast
    assume "q1 ∈ Y"
    hence "(h1, U1) ∈ set qs" and "poly_deg h1 = d" and "Suc m < card U1" by (simp_all add: q1 Y_def)
    assume "q2 ∈ Y"
    hence "(h2, U2) ∈ set qs" and "poly_deg h2 = d" and "Suc m < card U2" by (simp_all add: q2 Y_def)
    from this(2) have "poly_deg h1 = poly_deg h2" by (simp only: ‹poly_deg h1 = d›)
    from inv2 have "exact_decomp (Suc m) qs" by (rule shift2_invD)
    thus "q1 = q2" unfolding q1 q2 by (rule exact_decompD) fact+
  qed
  ultimately have "0 < card A" by simp
  hence "A ≠ {}" by auto
  then obtain a where "a ∈ A" by blast
  have "(h, U) ∈ B ∧ card (snd (h, U)) = Suc m" unfolding assms(3)
  proof (rule someI)
    from ‹a ∈ A› show "a ∈ B ∧ card (snd a) = Suc m" by (simp add: A_def)
  qed
  thus "(h, U) ∈ B" and "card U = Suc m" by simp_all
  from this(1) show "(h, U) ∈ set qs" and "poly_deg h = d" by (simp_all add: B)
qed

lemma shift1_inv_preserved:
  assumes "shift1_inv (qs, B)" and "1 < card B" and "(h, U) = (SOME b. b ∈ B ∧ card (snd b) = Suc m)"
    and "x = (SOME y. y ∈ U)"
  shows "shift1_inv (shift_list (h, U) x qs, B - {(h, U)})"
proof -
  let ?p1 = "(punit.monom_mult 1 (Poly_Mapping.single x 1) h, U)"
  let ?p2 = "(h, U - {x})"
  let ?qs = "removeAll (h, U) qs"
  let ?B = "B - {(h, U)}"
  from assms(1, 2, 3) have "(h, U) ∈ B" and "(h, U) ∈ set qs" and deg_h: "poly_deg h = d"
    and card_U: "card U = Suc m" by (rule shift1_inv_some_snd)+
  from card_U have "U ≠ {}" by auto
  then obtain y where "y ∈ U" by blast
  hence "x ∈ U" unfolding assms(4) by (rule someI)
  with card_U have card_Ux: "card (U - {x}) = m"
    by (metis card_Diff_singleton card.infinite diff_Suc_1 nat.simps(3))
  from assms(1) have B: "B = {q ∈ set qs. poly_deg (fst q) = d ∧ m < card (snd q)}"
    and inv2: "shift2_inv qs" by (rule shift1_invD)+
  from inv2 have valid_qs: "valid_decomp X qs" by (rule shift2_invD)
  hence "h ≠ 0" using ‹(h, U) ∈ set qs› by (rule valid_decompD)
  show ?thesis
  proof (intro shift1_invI shift2_invI)
    show "?B = {q ∈ set (shift_list (h, U) x qs). poly_deg (fst q) = d ∧ m < card (snd q)}" (is "_ = ?C")
    proof (rule Set.set_eqI)
      fix b
      show "b ∈ ?B ⟷ b ∈ ?C"
      proof
        assume "b ∈ ?C"
        hence "b ∈ insert ?p1 (insert ?p2 (set ?qs))" and b1: "poly_deg (fst b) = d"
          and b2: "m < card (snd b)" by (simp_all add: shift_list.simps)
        from this(1) show "b ∈ ?B"
        proof (elim insertE)
          assume "b = ?p1"
          with ‹h ≠ 0› have "poly_deg (fst b) = Suc d"
            by (simp add: poly_deg_monom_mult deg_pm_single deg_h)
          thus ?thesis by (simp add: b1)
        next
          assume "b = ?p2"
          hence "card (snd b) = m" by (simp add: card_Ux)
          with b2 show ?thesis by simp
        next
          assume "b ∈ set ?qs"
          with b1 b2 show ?thesis by (auto simp: B)
        qed
      qed (auto simp: B shift_list.simps)
    qed
  next
    from valid_qs ‹(h, U) ∈ set qs› ‹x ∈ U› show "valid_decomp X (shift_list (h, U) x qs)"
      by (rule valid_decomp_shift_list)
  next
    from inv2 have std: "standard_decomp k qs" by (rule shift2_invD)
    have "?B ≠ {}"
    proof
      assume "?B = {}"
      hence "B ⊆ {(h, U)}" by simp
      with _ have "card B ≤ card {(h, U)}" by (rule card_mono) simp
      with assms(2) show False by simp
    qed
    then obtain h' U' where "(h', U') ∈ B" and "(h', U') ≠ (h, U)" by auto
    from this(1) have "(h', U') ∈ set qs" and "poly_deg h' = d" and "Suc m ≤ card U'"
      by (simp_all add: B)
    note std this(1) ‹(h, U) ∈ set qs›
    moreover from ‹poly_deg h' = d› have "poly_deg h' = poly_deg h" by (simp only: deg_h)
    moreover from ‹Suc m ≤ card U'› have "card U ≤ card U'" by (simp only: card_U)
    ultimately show "standard_decomp k (shift_list (h, U) x qs)"
      by (rule standard_decomp_shift_list) fact+
  next
    from inv2 have exct: "exact_decomp (Suc m) qs" by (rule shift2_invD)
    show "exact_decomp (Suc m) (shift_list (h, U) x qs)"
    proof (rule exact_decompI)
      fix h' U'
      assume "(h', U') ∈ set (shift_list (h, U) x qs)"
      hence *: "(h', U') ∈ insert ?p1 (insert ?p2 (set ?qs))" by (simp add: shift_list.simps)
      thus "h' ∈ P[X]"
      proof (elim insertE)
        assume "(h', U') = ?p1"
        hence h': "h' = punit.monom_mult 1 (Poly_Mapping.single x 1) h" by simp
        from exct ‹(h, U) ∈ set qs› have "U ⊆ X" by (rule exact_decompD)
        with ‹x ∈ U› have "x ∈ X" ..
        hence "Poly_Mapping.single x 1 ∈ .[X]" by (rule PPs_closed_single)
        moreover from exct ‹(h, U) ∈ set qs› have "h ∈ P[X]" by (rule exact_decompD)
        ultimately show ?thesis unfolding h' by (rule Polys_closed_monom_mult)
      next
        assume "(h', U') = ?p2"
        hence "h' = h" by simp
        also from exct ‹(h, U) ∈ set qs› have "… ∈ P[X]" by (rule exact_decompD)
        finally show ?thesis .
      next
        assume "(h', U') ∈ set ?qs"
        hence "(h', U') ∈ set qs" by simp
        with exct show ?thesis by (rule exact_decompD)
      qed

      from * show "U' ⊆ X"
      proof (elim insertE)
        assume "(h', U') = ?p1"
        hence "U' = U" by simp
        also from exct ‹(h, U) ∈ set qs› have "… ⊆ X" by (rule exact_decompD)
        finally show ?thesis .
      next
        assume "(h', U') = ?p2"
        hence "U' = U - {x}" by simp
        also have "… ⊆ U" by blast
        also from exct ‹(h, U) ∈ set qs› have "… ⊆ X" by (rule exact_decompD)
        finally show ?thesis .
      next
        assume "(h', U') ∈ set ?qs"
        hence "(h', U') ∈ set qs" by simp
        with exct show ?thesis by (rule exact_decompD)
      qed
    next
      fix h1 h2 U1 U2
      assume "(h1, U1) ∈ set (shift_list (h, U) x qs)" and "Suc m < card U1"
      hence "(h1, U1) ∈ set qs" using card_U card_Ux by (auto simp: shift_list.simps)
      assume "(h2, U2) ∈ set (shift_list (h, U) x qs)" and "Suc m < card U2"
      hence "(h2, U2) ∈ set qs" using card_U card_Ux by (auto simp: shift_list.simps)
      assume "poly_deg h1 = poly_deg h2"
      from exct show "(h1, U1) = (h2, U2)" by (rule exact_decompD) fact+
    qed
  next
    fix d0
    assume "d0 < d"
    have "finite {q ∈ set qs. poly_deg (fst q) = d0 ∧ m < card (snd q)}" (is "finite ?A")
      by auto
    moreover have "{q ∈ set (shift_list (h, U) x qs). poly_deg (fst q) = d0 ∧ m < card (snd q)} ⊆ ?A"
      (is "?C ⊆ _")
    proof
      fix q
      assume "q ∈ ?C"
      hence "q = ?p1 ∨ q = ?p2 ∨ q ∈ set ?qs" and 1: "poly_deg (fst q) = d0" and 2: "m < card (snd q)"
        by (simp_all add: shift_list.simps)
      from this(1) show "q ∈ ?A"
      proof (elim disjE)
        assume "q = ?p1"
        with ‹h ≠ 0› have "d ≤ poly_deg (fst q)" by (simp add: poly_deg_monom_mult deg_h)
        with ‹d0 < d› show ?thesis by (simp only: 1)
      next
        assume "q = ?p2"
        hence "d ≤ poly_deg (fst q)" by (simp add: deg_h)
        with ‹d0 < d› show ?thesis by (simp only: 1)
      next
        assume "q ∈ set ?qs"
        with 1 2 show ?thesis by simp
      qed
    qed
    ultimately have "card ?C ≤ card ?A" by (rule card_mono)
    also from inv2 ‹d0 < d› have "… ≤ 1" by (rule shift2_invD)
    finally show "card ?C ≤ 1" .
  qed
qed

function (domintros) shift1 :: "(((('x ⇒0 nat) ⇒0 'a) × 'x set) list × ((('x ⇒0 nat) ⇒0 'a) × 'x set) set) ⇒
                                (((('x ⇒0 nat) ⇒0 'a) × 'x set) list ×
                                  ((('x ⇒0 nat) ⇒0 'a::{comm_ring_1,ring_no_zero_divisors}) × 'x set) set)"
  where
  "shift1 (qs, B) =
      (if 1 < card B then
        let (h, U) = SOME b. b ∈ B ∧ card (snd b) = Suc m; x = SOME y. y ∈ U in
          shift1 (shift_list (h, U) x qs, B - {(h, U)})
      else (qs, B))"
  by auto

lemma shift1_domI:
  assumes "shift1_inv args"
  shows "shift1_dom args"
proof -
  from wf_measure[of "card ∘ snd"] show ?thesis using assms
  proof (induct)
    case (less args)
    obtain qs B where args: "args = (qs, B)" using prod.exhaust by blast
    have IH: "shift1_dom (qs0, B0)" if "card B0 < card B" and "shift1_inv (qs0, B0)"
      for qs0 and B0::"((_ ⇒0 'a) × _) set"
      using _ that(2)
    proof (rule less)
      from that(1) show "((qs0, B0), args) ∈ measure (card ∘ snd)" by (simp add: args)
    qed
    from less(2) have inv: "shift1_inv (qs, B)" by (simp only: args)
    show ?case unfolding args
    proof (rule shift1.domintros)
      fix h U
      assume hU: "(h, U) = (SOME b. b ∈ B ∧ card (snd b) = Suc m)"
      define x where "x = (SOME y. y ∈ U)"
      assume "Suc 0 < card B"
      hence "1 < card B" by simp
      have "shift1_dom (shift_list (h, U) x qs, B - {(h, U)})"
      proof (rule IH)
        from inv have "finite B" by (rule shift1_inv_finite_snd)
        moreover from inv ‹1 < card B› hU have "(h, U) ∈ B" by (rule shift1_inv_some_snd)
        ultimately show "card (B - {(h, U)}) < card B" by (rule card_Diff1_less)
      next
        from inv ‹1 < card B› hU x_def show "shift1_inv (shift_list (h, U) x qs, (B - {(h, U)}))"
          by (rule shift1_inv_preserved)
      qed
      thus "shift1_dom (shift_list (SOME b. b ∈ B ∧ card (snd b) = Suc m) (SOME y. y ∈ U) qs,
                    B - {SOME b. b ∈ B ∧ card (snd b) = Suc m})" by (simp add: hU x_def)
    qed
  qed
qed

lemma shift1_induct [consumes 1, case_names base step]:
  assumes "shift1_inv args"
  assumes "⋀qs B. shift1_inv (qs, B) ⟹ card B ≤ 1 ⟹ P (qs, B) (qs, B)"
  assumes "⋀qs B h U x. shift1_inv (qs, B) ⟹ 1 < card B ⟹
            (h, U) = (SOME b. b ∈ B ∧ card (snd b) = Suc m) ⟹ x = (SOME y. y ∈ U) ⟹
            finite U ⟹ x ∈ U ⟹ card (U - {x}) = m ⟹
            P (shift_list (h, U) x qs, B - {(h, U)}) (shift1 (shift_list (h, U) x qs, B - {(h, U)})) ⟹
            P (qs, B) (shift1 (shift_list (h, U) x qs, B - {(h, U)}))"
  shows "P args (shift1 args)"
proof -
  from assms(1) have "shift1_dom args" by (rule shift1_domI)
  thus ?thesis using assms(1)
  proof (induct args rule: shift1.pinduct)
    case step: (1 qs B)
    obtain h U where hU: "(h, U) = (SOME b. b ∈ B ∧ card (snd b) = Suc m)" by (smt (z3) prod.exhaust)
    define x where "x = (SOME y. y ∈ U)"
    show ?case
    proof (simp add: shift1.psimps[OF step.hyps(1)] flip: hU x_def del: One_nat_def,
          intro conjI impI)
      let ?args = "(shift_list (h, U) x qs, B - {(h, U)})"
      assume "1 < card B"
      with step.prems have card_U: "card U = Suc m" using hU by (rule shift1_inv_some_snd)
      from card_U have "finite U" using card.infinite by fastforce
      from card_U have "U ≠ {}" by auto
      then obtain y where "y ∈ U" by blast
      hence "x ∈ U" unfolding x_def by (rule someI)
      with step.prems ‹1 < card B› hU x_def ‹finite U› show "P (qs, B) (shift1 ?args)"
      proof (rule assms(3))
        from ‹finite U› ‹x ∈ U› show "card (U - {x}) = m" by (simp add: card_U)
      next
        from ‹1 < card B› refl hU x_def show "P ?args (shift1 ?args)"
        proof (rule step.hyps)
          from step.prems ‹1 < card B› hU x_def show "shift1_inv ?args" by (rule shift1_inv_preserved)
        qed
      qed
    next
      assume "¬ 1 < card B"
      hence "card B ≤ 1" by simp
      with step.prems show "P (qs, B) (qs, B)" by (rule assms(2))
    qed
  qed
qed

lemma shift1_1:
  assumes "shift1_inv args" and "d0 ≤ d"
  shows "card {q ∈ set (fst (shift1 args)). poly_deg (fst q) = d0 ∧ m < card (snd q)} ≤ 1"
  using assms(1)
proof (induct args rule: shift1_induct)
  case (base qs B)
  from assms(2) have "d0 < d ∨ d0 = d" by auto
  thus ?case
  proof
    from base(1) have "shift2_inv qs" by (rule shift1_invD)
    moreover assume "d0 < d"
    ultimately show ?thesis unfolding fst_conv by (rule shift2_invD)
  next
    assume "d0 = d"
    from base(1) have "B = {q ∈ set (fst (qs, B)). poly_deg (fst q) = d0 ∧ m < card (snd q)}"
      unfolding fst_conv ‹d0 = d› by (rule shift1_invD)
    with base(2) show ?thesis by simp
  qed
qed

lemma shift1_2:
  "shift1_inv args ⟹
    card {q ∈ set (fst (shift1 args)). m < card (snd q)} ≤ card {q ∈ set (fst args). m < card (snd q)}"
proof (induct args rule: shift1_induct)
  case (base qs B)
  show ?case ..
next
  case (step qs B h U x)
  let ?x = "Poly_Mapping.single x (1::nat)"
  let ?p1 = "(punit.monom_mult 1 ?x h, U)"
  let ?A = "{q ∈ set qs. m < card (snd q)}"
  from step(1-3) have card_U: "card U = Suc m" and "(h, U) ∈ set qs" by (rule shift1_inv_some_snd)+
  from step(1) have "shift2_inv qs" by (rule shift1_invD)
  hence "valid_decomp X qs" by (rule shift2_invD)
  hence "h ≠ 0" using ‹(h, U) ∈ set qs› by (rule valid_decompD)
  have fin1: "finite ?A" by auto
  hence fin2: "finite (insert ?p1 ?A)" by simp
  from ‹(h, U) ∈ set qs› have hU_in: "(h, U) ∈ insert ?p1 ?A" by (simp add: card_U)
  have "?p1 ≠ (h, U)"
  proof
    assume "?p1 = (h, U)"
    hence "lpp (punit.monom_mult 1 ?x h) = lpp h" by simp
    with ‹h ≠ 0› show False by (simp add: punit.lt_monom_mult monomial_0_iff)
  qed
  let ?qs = "shift_list (h, U) x qs"
  have "{q ∈ set (fst (?qs, B - {(h, U)})). m < card (snd q)} = (insert ?p1 ?A) - {(h, U)}"
    using step(7) card_U ‹?p1 ≠ (h, U)› by (fastforce simp: shift_list.simps)
  also from fin2 hU_in have "card … = card (insert ?p1 ?A) - 1" by (simp add: card_Diff_singleton_if)
  also from fin1 have "… ≤ Suc (card ?A) - 1" by (simp add: card_insert_if)
  also have "… = card {q ∈ set (fst (qs, B)). m < card (snd q)}" by simp
  finally have "card {q ∈ set (fst (?qs, B - {(h, U)})). m < card (snd q)} ≤
                  card {q ∈ set (fst (qs, B)). m < card (snd q)}" .
  with step(8) show ?case by (rule le_trans)
qed

lemma shift1_3: "shift1_inv args ⟹ cone_decomp T (fst args) ⟹ cone_decomp T (fst (shift1 args))"
proof (induct args rule: shift1_induct)
  case (base qs B)
  from base(3) show ?case .
next
  case (step qs B h U x)
  from step.hyps(1) have "shift2_inv qs" by (rule shift1_invD)
  hence "valid_decomp X qs" by (rule shift2_invD)
  moreover from step.prems have "cone_decomp T qs" by (simp only: fst_conv)
  moreover from step.hyps(1-3) have "(h, U) ∈ set qs" by (rule shift1_inv_some_snd)
  ultimately have "cone_decomp T (fst (shift_list (h, U) x qs, B - {(h, U)}))"
    unfolding fst_conv using step.hyps(6) by (rule cone_decomp_shift_list)
  thus ?case by (rule step.hyps(8))
qed

lemma shift1_4:
  "shift1_inv args ⟹
    Max (poly_deg ` fst ` set (fst args)) ≤ Max (poly_deg ` fst ` set (fst (shift1 args)))"
proof (induct args rule: shift1_induct)
  case (base qs B)
  show ?case ..
next
  case (step qs B h U x)
  let ?x = "Poly_Mapping.single x 1"
  let ?p1 = "(punit.monom_mult 1 ?x h, U)"
  let ?qs = "shift_list (h, U) x qs"
  from step(1) have "B = {q ∈ set qs. poly_deg (fst q) = d ∧ m < card (snd q)}"
    and inv2: "shift2_inv qs" by (rule shift1_invD)+
  from this(1) have "B ⊆ set qs" by auto
  with step(2) have "set qs ≠ {}" by auto
  from finite_set have fin: "finite (poly_deg ` fst ` set ?qs)" by (intro finite_imageI)
  have "Max (poly_deg ` fst ` set (fst (qs, B))) ≤ Max (poly_deg ` fst ` set (fst (?qs, B - {(h, U)})))"
    unfolding fst_conv
  proof (rule Max.boundedI)
    from finite_set show "finite (poly_deg ` fst ` set qs)" by (intro finite_imageI)
  next
    from ‹set qs ≠ {}› show "poly_deg ` fst ` set qs ≠ {}" by simp
  next
    fix a
    assume "a ∈ poly_deg ` fst ` set qs"
    then obtain q where "q ∈ set qs" and a: "a = poly_deg (fst q)" by blast
    show "a ≤ Max (poly_deg ` fst ` set ?qs)"
    proof (cases "q = (h, U)")
      case True
      hence "a ≤ poly_deg (fst ?p1)" by (cases "h = 0") (simp_all add: a poly_deg_monom_mult)
      also from fin have "… ≤ Max (poly_deg ` fst ` set ?qs)"
      proof (rule Max_ge)
        have "?p1 ∈ set ?qs" by (simp add: shift_list.simps)
        thus "poly_deg (fst ?p1) ∈ poly_deg ` fst ` set ?qs" by (intro imageI)
      qed
      finally show ?thesis .
    next
      case False
      with ‹q ∈ set qs› have "q ∈ set ?qs" by (simp add: shift_list.simps)
      hence "a ∈ poly_deg ` fst ` set ?qs" unfolding a by (intro imageI)
      with fin show ?thesis by (rule Max_ge)
    qed
  qed
  thus ?case using step(8) by (rule le_trans)
qed

lemma shift1_5: "shift1_inv args ⟹ fst (shift1 args) = [] ⟷ fst args = []"
proof (induct args rule: shift1_induct)
  case (base qs B)
  show ?case ..
next
  case (step qs B h U x)
  let ?p1 = "(punit.monom_mult 1 (Poly_Mapping.single x 1) h, U)"
  let ?qs = "shift_list (h, U) x qs"
  from step(1) have "B = {q ∈ set qs. poly_deg (fst q) = d ∧ m < card (snd q)}"
    and inv2: "shift2_inv qs" by (rule shift1_invD)+
  from this(1) have "B ⊆ set qs" by auto
  with step(2) have "qs ≠ []" by auto
  moreover have "fst (shift1 (?qs, B - {(h, U)})) ≠ []"
    by (simp add: step.hyps(8) del: One_nat_def) (simp add: shift_list.simps)
  ultimately show ?case by simp
qed

lemma shift1_6: "shift1_inv args ⟹ monomial_decomp (fst args) ⟹ monomial_decomp (fst (shift1 args))"
proof (induct args rule: shift1_induct)
  case (base qs B)
  from base(3) show ?case .
next
  case (step qs B h U x)
  from step(1-3) have "(h, U) ∈ set qs" by (rule shift1_inv_some_snd)
  with step.prems have "monomial_decomp (fst (shift_list (h, U) x qs, B - {(h, U)}))"
    unfolding fst_conv by (rule monomial_decomp_shift_list)
  thus ?case by (rule step.hyps)
qed

lemma shift1_7: "shift1_inv args ⟹ hom_decomp (fst args) ⟹ hom_decomp (fst (shift1 args))"
proof (induct args rule: shift1_induct)
  case (base qs B)
  from base(3) show ?case .
next
  case (step qs B h U x)
  from step(1-3) have "(h, U) ∈ set qs" by (rule shift1_inv_some_snd)
  with step.prems have "hom_decomp (fst (shift_list (h, U) x qs, B - {(h, U)}))"
    unfolding fst_conv by (rule hom_decomp_shift_list)
  thus ?case by (rule step.hyps)
qed

end

lemma shift2_inv_preserved:
  assumes "shift2_inv d qs"
  shows "shift2_inv (Suc d) (fst (shift1 (qs, {q ∈ set qs. poly_deg (fst q) = d ∧ m < card (snd q)})))"
proof -
  define args where "args = (qs, {q ∈ set qs. poly_deg (fst q) = d ∧ m < card (snd q)})"
  from refl assms have inv1: "shift1_inv d args" unfolding args_def
    by (rule shift1_invI)
  hence "shift1_inv d (shift1 args)" by (induct args rule: shift1_induct)
  hence "shift1_inv d (fst (shift1 args), snd (shift1 args))" by simp
  hence "shift2_inv d (fst (shift1 args))" by (rule shift1_invD)
  hence "valid_decomp X (fst (shift1 args))" and "standard_decomp k (fst (shift1 args))"
    and "exact_decomp (Suc m) (fst (shift1 args))" by (rule shift2_invD)+
  thus "shift2_inv (Suc d) (fst (shift1 args))"
  proof (rule shift2_invI)
    fix d0
    assume "d0 < Suc d"
    hence "d0 ≤ d" by simp
    with inv1 show "card {q ∈ set (fst (shift1 args)). poly_deg (fst q) = d0 ∧ m < card (snd q)} ≤ 1"
      by (rule shift1_1)
  qed
qed

function shift2 :: "nat ⇒ nat ⇒ ((('x ⇒0 nat) ⇒0 'a) × 'x set) list ⇒
                      ((('x ⇒0 nat) ⇒0 'a::{comm_ring_1,ring_no_zero_divisors}) × 'x set) list" where
  "shift2 c d qs =
      (if c ≤ d then qs
      else shift2 c (Suc d) (fst (shift1 (qs, {q ∈ set qs. poly_deg (fst q) = d ∧ m < card (snd q)}))))"
  by auto
termination proof
  show "wf (measure (λ(c, d, _). c - d))" by (fact wf_measure)
qed simp

lemma shift2_1: "shift2_inv d qs ⟹ shift2_inv c (shift2 c d qs)"
proof (induct c d qs rule: shift2.induct)
  case IH: (1 c d qs)
  show ?case
  proof (subst shift2.simps, simp del: shift2.simps, intro conjI impI)
    assume "c ≤ d"
    show "shift2_inv c qs"
    proof (rule shift2_invI)
      from IH(2) show "valid_decomp X qs" and "standard_decomp k qs" and "exact_decomp (Suc m) qs"
        by (rule shift2_invD)+
    next
      fix d0
      assume "d0 < c"
      hence "d0 < d" using ‹c ≤ d› by (rule less_le_trans)
      with IH(2) show "card {q ∈ set qs. poly_deg (fst q) = d0 ∧ m < card (snd q)} ≤ 1"
        by (rule shift2_invD)
    qed
  next
    assume "¬ c ≤ d"
    thus "shift2_inv c (shift2 c (Suc d) (fst (shift1 (qs, {q ∈ set qs. poly_deg (fst q) = d ∧ m < card (snd q)}))))"
    proof (rule IH)
      from IH(2) show "shift2_inv (Suc d) (fst (shift1 (qs, {q ∈ set qs. poly_deg (fst q) = d ∧ m < card (snd q)})))"
        by (rule shift2_inv_preserved)
    qed
  qed
qed

lemma shift2_2:
  "shift2_inv d qs ⟹
    card {q ∈ set (shift2 c d qs). m < card (snd q)} ≤ card {q ∈ set qs. m < card (snd q)}"
proof (induct c d qs rule: shift2.induct)
  case IH: (1 c d qs)
  let ?A = "{q ∈ set (shift2 c (Suc d) (fst (shift1 (qs, {q ∈ set qs. poly_deg (fst q) = d ∧ m < card (snd q)})))). m < card (snd q)}"
  show ?case
  proof (subst shift2.simps, simp del: shift2.simps, intro impI)
    assume "¬ c ≤ d"
    hence "card ?A ≤ card {q ∈ set (fst (shift1 (qs, {q ∈ set qs. poly_deg (fst q) = d ∧ m < card (snd q)}))). m < card (snd q)}"
    proof (rule IH)
      show "shift2_inv (Suc d) (fst (shift1 (qs, {q ∈ set qs. poly_deg (fst q) = d ∧ m < card (snd q)})))"
        using IH(2) by (rule shift2_inv_preserved)
    qed
    also have "… ≤ card {q ∈ set (fst (qs, {q ∈ set qs. poly_deg (fst q) = d ∧ m < card (snd q)})). m < card (snd q)}"
      using refl IH(2) by (intro shift1_2 shift1_invI)
    finally show "card ?A ≤ card {q ∈ set qs. m < card (snd q)}" by (simp only: fst_conv)
  qed
qed

lemma shift2_3: "shift2_inv d qs ⟹ cone_decomp T qs ⟹ cone_decomp T (shift2 c d qs)"
proof (induct c d qs rule: shift2.induct)
  case IH: (1 c d qs)
  have inv2: "shift2_inv (Suc d) (fst (shift1 (qs, {q ∈ set qs. poly_deg (fst q) = d ∧ m < card (snd q)})))"
    using IH(2) by (rule shift2_inv_preserved)
  show ?case
  proof (subst shift2.simps, simp add: IH.prems del: shift2.simps, intro impI)
    assume "¬ c ≤ d"
    moreover note inv2
    moreover have "cone_decomp T (fst (shift1 (qs, {q ∈ set qs. poly_deg (fst q) = d ∧ m < card (snd q)})))"
    proof (rule shift1_3)
      from refl IH(2) show "shift1_inv d (qs, {q ∈ set qs. poly_deg (fst q) = d ∧ m < card (snd q)})"
        by (rule shift1_invI)
    qed (simp add: IH.prems)
    ultimately show "cone_decomp T (shift2 c (Suc d) (fst (shift1 (qs, {q ∈ set qs. poly_deg (fst q) = d ∧ m < card (snd q)}))))"
      by (rule IH)
  qed
qed

lemma shift2_4:
  "shift2_inv d qs ⟹ Max (poly_deg ` fst ` set qs) ≤ Max (poly_deg ` fst ` set (shift2 c d qs))"
proof (induct c d qs rule: shift2.induct)
  case IH: (1 c d qs)
  let ?args = "(qs, {q ∈ set qs. poly_deg (fst q) = d ∧ m < card (snd q)})"
  show ?case
  proof (subst shift2.simps, simp del: shift2.simps, intro impI)
    assume "¬ c ≤ d"
    have "Max (poly_deg ` fst ` set (fst ?args)) ≤ Max (poly_deg ` fst ` set (fst (shift1 ?args)))"
      using refl IH(2) by (intro shift1_4 shift1_invI)
    also from ‹¬ c ≤ d› have "… ≤ Max (poly_deg ` fst ` set (shift2 c (Suc d) (fst (shift1 ?args))))"
    proof (rule IH)
      from IH(2) show "shift2_inv (Suc d) (fst (shift1 ?args))"
        by (rule shift2_inv_preserved)
    qed
    finally show "Max (poly_deg ` fst ` set qs) ≤ Max (poly_deg ` fst ` set (shift2 c (Suc d) (fst (shift1 ?args))))"
      by (simp only: fst_conv)
  qed
qed

lemma shift2_5:
  "shift2_inv d qs ⟹ shift2 c d qs = [] ⟷ qs = []"
proof (induct c d qs rule: shift2.induct)
  case IH: (1 c d qs)
  let ?args = "(qs, {q ∈ set qs. poly_deg (fst q) = d ∧ m < card (snd q)})"
  show ?case
  proof (subst shift2.simps, simp del: shift2.simps, intro impI)
    assume "¬ c ≤ d"
    hence "shift2 c (Suc d) (fst (shift1 ?args)) = [] ⟷ fst (shift1 ?args) = []"
    proof (rule IH)
      from IH(2) show "shift2_inv (Suc d) (fst (shift1 ?args))"
        by (rule shift2_inv_preserved)
    qed
    also from refl IH(2) have "… ⟷ fst ?args = []" by (intro shift1_5 shift1_invI)
    finally show "shift2 c (Suc d) (fst (shift1 ?args)) = [] ⟷ qs = []" by (simp only: fst_conv)
  qed
qed

lemma shift2_6:
  "shift2_inv d qs ⟹ monomial_decomp qs ⟹ monomial_decomp (shift2 c d qs)"
proof (induct c d qs rule: shift2.induct)
  case IH: (1 c d qs)
  let ?args = "(qs, {q ∈ set qs. poly_deg (fst q) = d ∧ m < card (snd q)})"
  show ?case
  proof (subst shift2.simps, simp del: shift2.simps, intro conjI impI IH)
    from IH(2) show "shift2_inv (Suc d) (fst (shift1 ?args))" by (rule shift2_inv_preserved)
  next
    from refl IH(2) have "shift1_inv d ?args" by (rule shift1_invI)
    moreover from IH(3) have "monomial_decomp (fst ?args)" by simp
    ultimately show "monomial_decomp (fst (shift1 ?args))" by (rule shift1_6)
  qed
qed

lemma shift2_7:
  "shift2_inv d qs ⟹ hom_decomp qs ⟹ hom_decomp (shift2 c d qs)"
proof (induct c d qs rule: shift2.induct)
  case IH: (1 c d qs)
  let ?args = "(qs, {q ∈ set qs. poly_deg (fst q) = d ∧ m < card (snd q)})"
  show ?case
  proof (subst shift2.simps, simp del: shift2.simps, intro conjI impI IH)
    from IH(2) show "shift2_inv (Suc d) (fst (shift1 ?args))" by (rule shift2_inv_preserved)
  next
    from refl IH(2) have "shift1_inv d ?args" by (rule shift1_invI)
    moreover from IH(3) have "hom_decomp (fst ?args)" by simp
    ultimately show "hom_decomp (fst (shift1 ?args))" by (rule shift1_7)
  qed
qed

definition shift :: "((('x ⇒0 nat) ⇒0 'a) × 'x set) list ⇒
                        ((('x ⇒0 nat) ⇒0 'a::{comm_ring_1,ring_no_zero_divisors}) × 'x set) list"
  where "shift qs = shift2 (k + card {q ∈ set qs. m < card (snd q)}) k qs"

lemma shift2_inv_init:
  assumes "valid_decomp X qs" and "standard_decomp k qs" and "exact_decomp (Suc m) qs"
  shows "shift2_inv k qs"
  using assms
proof (rule shift2_invI)
  fix d0
  assume "d0 < k"
  have "{q ∈ set qs. poly_deg (fst q) = d0 ∧ m < card (snd q)} = {}"
  proof -
    {
      fix q
      assume "q ∈ set qs"
      obtain h U where q: "q = (h, U)" using prod.exhaust by blast
      assume "poly_deg (fst q) = d0" and "m < card (snd q)"
      hence "poly_deg h < k" and "m < card U" using ‹d0 < k› by (simp_all add: q)
      from this(2) have "U ≠ {}" by auto
      with ‹q ∈ set qs› have "(h, U) ∈ set (qs+)" by (simp add: q pos_decomp_def)
      with assms(2) have "k ≤ poly_deg h" by (rule standard_decompD)
      with ‹poly_deg h < k› have False by simp
    }
    thus ?thesis by blast
  qed
  thus "card {q ∈ set qs. poly_deg (fst q) = d0 ∧ m < card (snd q)} ≤ 1" by (simp only: card.empty)
qed

lemma shift:
  assumes "valid_decomp X qs" and "standard_decomp k qs" and "exact_decomp (Suc m) qs"
  shows "valid_decomp X (shift qs)" and "standard_decomp k (shift qs)" and "exact_decomp m (shift qs)"
proof -
  define c where "c = card {q ∈ set qs. m < card (snd q)}"
  define A where "A = {q ∈ set (shift qs). m < card (snd q)}"
  from assms have "shift2_inv k qs" by (rule shift2_inv_init)
  hence inv2: "shift2_inv (k + c) (shift qs)" and "card A ≤ c"
    unfolding shift_def c_def A_def by (rule shift2_1, rule shift2_2)
  from inv2 have fin: "valid_decomp X (shift qs)" and std: "standard_decomp k (shift qs)"
    and exct: "exact_decomp (Suc m) (shift qs)"
    by (rule shift2_invD)+
  show "valid_decomp X (shift qs)" and "standard_decomp k (shift qs)" by fact+
  have "finite A" by (auto simp: A_def)

  show "exact_decomp m (shift qs)"
  proof (rule exact_decompI)
    fix h U
    assume "(h, U) ∈ set (shift qs)"
    with exct show "h ∈ P[X]" and "U ⊆ X" by (rule exact_decompD)+
  next
    fix h1 h2 U1 U2
    assume 1: "(h1, U1) ∈ set (shift qs)" and 2: "(h2, U2) ∈ set (shift qs)"
    assume 3: "poly_deg h1 = poly_deg h2" and 4: "m < card U1" and 5: "m < card U2"
    from 5 have "U2 ≠ {}" by auto
    with 2 have "(h2, U2) ∈ set ((shift qs)+)" by (simp add: pos_decomp_def)
    let ?C = "{q ∈ set (shift qs). poly_deg (fst q) = poly_deg h2 ∧ m < card (snd q)}"
    define B where "B = {q ∈ A. k ≤ poly_deg (fst q) ∧ poly_deg (fst q) ≤ poly_deg h2}"
    have "Suc (poly_deg h2) - k ≤ card B"
    proof -
      have "B = (⋃d0∈{k..poly_deg h2}. {q ∈ A. poly_deg (fst q) = d0})" by (auto simp: B_def)
      also have "card … = (∑d0=k..poly_deg h2. card {q ∈ A. poly_deg (fst q) = d0})"
      proof (intro card_UN_disjoint ballI impI)
        fix d0
        from _ ‹finite A› show "finite {q ∈ A. poly_deg (fst q) = d0}" by (rule finite_subset) blast
      next
        fix d0 d1 :: nat
        assume "d0 ≠ d1"
        thus "{q ∈ A. poly_deg (fst q) = d0} ∩ {q ∈ A. poly_deg (fst q) = d1} = {}" by blast
      qed (fact finite_atLeastAtMost)
      also have "… ≥ (∑d0=k..poly_deg h2. 1)"
      proof (rule sum_mono)
        fix d0
        assume "d0 ∈ {k..poly_deg h2}"
        hence "k ≤ d0" and "d0 ≤ poly_deg h2" by simp_all
        with std ‹(h2, U2) ∈ set ((shift qs)+)› obtain h' U' where "(h', U') ∈ set (shift qs)"
          and "poly_deg h' = d0" and "card U2 ≤ card U'" by (rule standard_decompE)
        from 5 this(3) have "m < card U'" by (rule less_le_trans)
        with ‹(h', U') ∈ set (shift qs)› have "(h', U') ∈ {q ∈ A. poly_deg (fst q) = d0}"
          by (simp add: A_def ‹poly_deg h' = d0›)
        hence "{q ∈ A. poly_deg (fst q) = d0} ≠ {}" by blast
        moreover from _ ‹finite A› have "finite {q ∈ A. poly_deg (fst q) = d0}"
          by (rule finite_subset) blast
        ultimately show "1 ≤ card {q ∈ A. poly_deg (fst q) = d0}"
          by (simp add: card_gt_0_iff Suc_le_eq)
      qed
      also have "(∑d0=k..poly_deg h2. 1) = Suc (poly_deg h2) - k" by auto
      finally show ?thesis .
    qed
    also from ‹finite A› _ have "… ≤ card A" by (rule card_mono) (auto simp: B_def)
    also have "… ≤ c" by fact
    finally have "poly_deg h2 < k + c" by simp
    with inv2 have "card ?C ≤ 1" by (rule shift2_invD)
    have "finite ?C" by auto
    moreover note ‹card ?C ≤ 1›
    moreover from 1 3 4 have "(h1, U1) ∈ ?C" by simp
    moreover from 2 5 have "(h2, U2) ∈ ?C" by simp
    ultimately show "(h1, U1) = (h2, U2)" by (auto simp: card_le_Suc0_iff_eq)
  qed
qed

lemma monomial_decomp_shift:
  assumes "valid_decomp X qs" and "standard_decomp k qs" and "exact_decomp (Suc m) qs"
    and "monomial_decomp qs"
  shows "monomial_decomp (shift qs)"
proof -
  from assms(1, 2, 3) have "shift2_inv k qs" by (rule shift2_inv_init)
  thus ?thesis unfolding shift_def using assms(4) by (rule shift2_6)
qed

lemma hom_decomp_shift:
  assumes "valid_decomp X qs" and "standard_decomp k qs" and "exact_decomp (Suc m) qs"
    and "hom_decomp qs"
  shows "hom_decomp (shift qs)"
proof -
  from assms(1, 2, 3) have "shift2_inv k qs" by (rule shift2_inv_init)
  thus ?thesis unfolding shift_def using assms(4) by (rule shift2_7)
qed

lemma cone_decomp_shift:
  assumes "valid_decomp X qs" and "standard_decomp k qs" and "exact_decomp (Suc m) qs"
    and "cone_decomp T qs"
  shows "cone_decomp T (shift qs)"
proof -
  from assms(1, 2, 3) have "shift2_inv k qs" by (rule shift2_inv_init)
  thus ?thesis unfolding shift_def using assms(4) by (rule shift2_3)
qed

lemma Max_shift_ge:
  assumes "valid_decomp X qs" and "standard_decomp k qs" and "exact_decomp (Suc m) qs"
  shows "Max (poly_deg ` fst ` set qs) ≤ Max (poly_deg ` fst ` set (shift qs))"
proof -
  from assms(1-3) have "shift2_inv k qs" by (rule shift2_inv_init)
  thus ?thesis unfolding shift_def by (rule shift2_4)
qed

lemma shift_Nil_iff:
  assumes "valid_decomp X qs" and "standard_decomp k qs" and "exact_decomp (Suc m) qs"
  shows "shift qs = [] ⟷ qs = []"
proof -
  from assms(1-3) have "shift2_inv k qs" by (rule shift2_inv_init)
  thus ?thesis unfolding shift_def by (rule shift2_5)
qed

end

primrec exact_aux :: "nat ⇒ nat ⇒ ((('x ⇒0 nat) ⇒0 'a) × 'x set) list ⇒
                      ((('x ⇒0 nat) ⇒0 'a::{comm_ring_1,ring_no_zero_divisors}) × 'x set) list" where
  "exact_aux k 0 qs = qs" |
  "exact_aux k (Suc m) qs = exact_aux k m (shift k m qs)"

lemma exact_aux:
  assumes "valid_decomp X qs" and "standard_decomp k qs" and "exact_decomp m qs"
  shows "valid_decomp X (exact_aux k m qs)" (is ?thesis1)
    and "standard_decomp k (exact_aux k m qs)" (is ?thesis2)
    and "exact_decomp 0 (exact_aux k m qs)" (is ?thesis3)
proof -
  from assms have "?thesis1 ∧ ?thesis2 ∧ ?thesis3"
  proof (induct m arbitrary: qs)
    case 0
    thus ?case by simp
  next
    case (Suc m)
    let ?qs = "shift k m qs"
    have "valid_decomp X (exact_aux k m ?qs) ∧ standard_decomp k (exact_aux k m ?qs) ∧
          exact_decomp 0 (exact_aux k m ?qs)"
    proof (rule Suc)
      from Suc.prems show "valid_decomp X ?qs" and "standard_decomp k ?qs" and "exact_decomp m ?qs"
        by (rule shift)+
    qed
    thus ?case by simp
  qed
  thus ?thesis1 and ?thesis2 and ?thesis3 by simp_all
qed

lemma monomial_decomp_exact_aux:
  assumes "valid_decomp X qs" and "standard_decomp k qs" and "exact_decomp m qs" and "monomial_decomp qs"
  shows "monomial_decomp (exact_aux k m qs)"
  using assms
proof (induct m arbitrary: qs)
  case 0
  thus ?case by simp
next
  case (Suc m)
  let ?qs = "shift k m qs"
  have "monomial_decomp (exact_aux k m ?qs)"
  proof (rule Suc)
    show "valid_decomp X ?qs" and "standard_decomp k ?qs" and "exact_decomp m ?qs"
      using Suc.prems(1, 2, 3) by (rule shift)+
  next
    from Suc.prems show "monomial_decomp ?qs" by (rule monomial_decomp_shift)
  qed
  thus ?case by simp
qed

lemma hom_decomp_exact_aux:
  assumes "valid_decomp X qs" and "standard_decomp k qs" and "exact_decomp m qs" and "hom_decomp qs"
  shows "hom_decomp (exact_aux k m qs)"
  using assms
proof (induct m arbitrary: qs)
  case 0
  thus ?case by simp
next
  case (Suc m)
  let ?qs = "shift k m qs"
  have "hom_decomp (exact_aux k m ?qs)"
  proof (rule Suc)
    show "valid_decomp X ?qs" and "standard_decomp k ?qs" and "exact_decomp m ?qs"
      using Suc.prems(1, 2, 3) by (rule shift)+
  next
    from Suc.prems show "hom_decomp ?qs" by (rule hom_decomp_shift)
  qed
  thus ?case by simp
qed

lemma cone_decomp_exact_aux:
  assumes "valid_decomp X qs" and "standard_decomp k qs" and "exact_decomp m qs" and "cone_decomp T qs"
  shows "cone_decomp T (exact_aux k m qs)"
  using assms
proof (induct m arbitrary: qs)
  case 0
  thus ?case by simp
next
  case (Suc m)
  let ?qs = "shift k m qs"
  have "cone_decomp T (exact_aux k m ?qs)"
  proof (rule Suc)
    show "valid_decomp X ?qs" and "standard_decomp k ?qs" and "exact_decomp m ?qs"
      using Suc.prems(1, 2, 3) by (rule shift)+
  next
    from Suc.prems show "cone_decomp T ?qs" by (rule cone_decomp_shift)
  qed
  thus ?case by simp
qed

lemma Max_exact_aux_ge:
  assumes "valid_decomp X qs" and "standard_decomp k qs" and "exact_decomp m qs"
  shows "Max (poly_deg ` fst ` set qs) ≤ Max (poly_deg ` fst ` set (exact_aux k m qs))"
  using assms
proof (induct m arbitrary: qs)
  case 0
  thus ?case by simp
next
  case (Suc m)
  let ?qs = "shift k m qs"
  from Suc.prems have "Max (poly_deg ` fst ` set qs) ≤ Max (poly_deg ` fst ` set ?qs)"
    by (rule Max_shift_ge)
  also have "… ≤ Max (poly_deg ` fst ` set (exact_aux k m ?qs))"
  proof (rule Suc)
    from Suc.prems show "valid_decomp X ?qs" and "standard_decomp k ?qs" and "exact_decomp m ?qs"
      by (rule shift)+
  qed
  finally show ?case by simp
qed

lemma exact_aux_Nil_iff:
  assumes "valid_decomp X qs" and "standard_decomp k qs" and "exact_decomp m qs"
  shows "exact_aux k m qs = [] ⟷ qs = []"
  using assms
proof (induct m arbitrary: qs)
  case 0
  thus ?case by simp
next
  case (Suc m)
  let ?qs = "shift k m qs"
  have "exact_aux k m ?qs = [] ⟷ ?qs = []"
  proof (rule Suc)
    from Suc.prems show "valid_decomp X ?qs" and "standard_decomp k ?qs" and "exact_decomp m ?qs"
      by (rule shift)+
  qed
  also from Suc.prems have "… ⟷ qs = []" by (rule shift_Nil_iff)
  finally show ?case by simp
qed

definition exact :: "nat ⇒ ((('x ⇒0 nat) ⇒0 'a) × 'x set) list ⇒
                        ((('x ⇒0 nat) ⇒0 'a::{comm_ring_1,ring_no_zero_divisors}) × 'x set) list"
  where "exact k qs = exact_aux k (card X) qs"

lemma exact:
  assumes "valid_decomp X qs" and "standard_decomp k qs"
  shows "valid_decomp X (exact k qs)" (is ?thesis1)
    and "standard_decomp k (exact k qs)" (is ?thesis2)
    and "exact_decomp 0 (exact k qs)" (is ?thesis3)
proof -
  from assms(1) le_refl have "exact_decomp (card X) qs" by (rule exact_decomp_card_X)
  with assms show ?thesis1 and ?thesis2 and ?thesis3 unfolding exact_def by (rule exact_aux)+
qed

lemma monomial_decomp_exact:
  assumes "valid_decomp X qs" and "standard_decomp k qs" and "monomial_decomp qs"
  shows "monomial_decomp (exact k qs)"
proof -
  from assms(1) le_refl have "exact_decomp (card X) qs" by (rule exact_decomp_card_X)
  with assms(1, 2) show ?thesis unfolding exact_def using assms(3) by (rule monomial_decomp_exact_aux)
qed

lemma hom_decomp_exact:
  assumes "valid_decomp X qs" and "standard_decomp k qs" and "hom_decomp qs"
  shows "hom_decomp (exact k qs)"
proof -
  from assms(1) le_refl have "exact_decomp (card X) qs" by (rule exact_decomp_card_X)
  with assms(1, 2) show ?thesis unfolding exact_def using assms(3) by (rule hom_decomp_exact_aux)
qed

lemma cone_decomp_exact:
  assumes "valid_decomp X qs" and "standard_decomp k qs" and "cone_decomp T qs"
  shows "cone_decomp T (exact k qs)"
proof -
  from assms(1) le_refl have "exact_decomp (card X) qs" by (rule exact_decomp_card_X)
  with assms(1, 2) show ?thesis unfolding exact_def using assms(3) by (rule cone_decomp_exact_aux)
qed

lemma Max_exact_ge:
  assumes "valid_decomp X qs" and "standard_decomp k qs"
  shows "Max (poly_deg ` fst ` set qs) ≤ Max (poly_deg ` fst ` set (exact k qs))"
proof -
  from assms(1) le_refl have "exact_decomp (card X) qs" by (rule exact_decomp_card_X)
  with assms(1, 2) show ?thesis unfolding exact_def by (rule Max_exact_aux_ge)
qed

lemma exact_Nil_iff:
  assumes "valid_decomp X qs" and "standard_decomp k qs"
  shows "exact k qs = [] ⟷ qs = []"
proof -
  from assms(1) le_refl have "exact_decomp (card X) qs" by (rule exact_decomp_card_X)
  with assms(1, 2) show ?thesis unfolding exact_def by (rule exact_aux_Nil_iff)
qed

corollary 𝖻_zero_exact:
  assumes "valid_decomp X qs" and "standard_decomp k qs" and "qs ≠ []"
  shows "Suc (Max (poly_deg ` fst ` set qs)) ≤ 𝖻 (exact k qs) 0"
proof -
  from assms(1, 2) have "Max (poly_deg ` fst ` set qs) ≤ Max (poly_deg ` fst ` set (exact k qs))"
    by (rule Max_exact_ge)
  also have "Suc … ≤ 𝖻 (exact k qs) 0"
  proof (rule 𝖻_zero)
    from assms show "exact k qs ≠ []" by (simp add: exact_Nil_iff)
  qed
  finally show ?thesis by simp
qed

lemma normal_form_exact_decompE:
  assumes "F ⊆ P[X]"
  obtains qs where "valid_decomp X qs" and "standard_decomp 0 qs" and "monomial_decomp qs"
    and "cone_decomp (normal_form F ` P[X]) qs" and "exact_decomp 0 qs"
    and "⋀g. (⋀f. f ∈ F ⟹ homogeneous f) ⟹ g ∈ punit.reduced_GB F ⟹ poly_deg g ≤ 𝖻 qs 0"
proof -
  let ?G = "punit.reduced_GB F"
  let ?S = "lpp ` ?G"
  let ?N = "normal_form F ` P[X]"
  define qs::"((_ ⇒0 'a) × _) list" where "qs = snd (split 0 X ?S)"
  from fin_X assms have std: "standard_decomp 0 qs" and cn: "cone_decomp ?N qs"
    unfolding qs_def by (rule standard_cone_decomp_snd_split)+
  from fin_X assms have "finite ?G" by (rule finite_reduced_GB_Polys)
  hence "finite ?S" by (rule finite_imageI)
  with fin_X subset_refl have valid: "valid_decomp X qs" unfolding qs_def using zero_in_PPs
    by (rule valid_decomp_split)
  from fin_X subset_refl ‹finite ?S› have md: "monomial_decomp qs"
    unfolding qs_def by (rule monomial_decomp_split)
  let ?qs = "exact 0 qs"
  from valid std have "valid_decomp X ?qs" and "standard_decomp 0 ?qs" by (rule exact)+
  moreover from valid std md have "monomial_decomp ?qs" by (rule monomial_decomp_exact)
  moreover from valid std cn have "cone_decomp ?N ?qs" by (rule cone_decomp_exact)
  moreover from valid std have "exact_decomp 0 ?qs" by (rule exact)
  moreover have "poly_deg g ≤ 𝖻 ?qs 0" if "⋀f. f ∈ F ⟹ homogeneous f" and "g ∈ ?G" for g
  proof (cases "qs = []")
    case True
    from one_in_Polys have "normal_form F 1 ∈ ?N" by (rule imageI)
    also from True cn have "… = {0}" by (simp add: cone_decomp_def direct_decomp_def bij_betw_def)
    finally have "?G = {1}" using fin_X assms
      by (simp add: normal_form_zero_iff ideal_eq_UNIV_iff_reduced_GB_eq_one_Polys
                flip: ideal_eq_UNIV_iff_contains_one)
    with that(2) show ?thesis by simp
  next
    case False
    from fin_X assms that have "poly_deg g ≤ Suc (Max (poly_deg ` fst ` set qs))"
      unfolding qs_def by (rule standard_cone_decomp_snd_split)
    also from valid std False have "… ≤ 𝖻 ?qs 0" by (rule 𝖻_zero_exact)
    finally show ?thesis .
  qed
  ultimately show ?thesis ..
qed

end

end

end (* pm_powerprod *)

end (* theory *)