Theory Preliminaries_on_Polynomials_1

section ‹Preliminaries: Extending the Library on Multivariate Polynomials›

subsection ‹Part 1 -- Extensions Without Importing Univariate Polynomials›

theory Preliminaries_on_Polynomials_1
  imports 
    Polynomials.More_MPoly_Type
    Polynomials.MPoly_Type_Class_FMap
begin

type_synonym var = nat
type_synonym monom = "var 0 nat" 

definition substitute :: "(var  'a mpoly)  'a :: comm_semiring_1 mpoly  'a mpoly" where
  "substitute σ p = insertion σ (replace_coeff Const p)" 

lemma Const_0: "Const 0 = 0"
  by (transfer, simp add: Const0_zero)

lemma Const_1: "Const 1 = 1"
  by (transfer, simp add: Const0_one)

lemma insertion_Var: "insertion α (Var x) = α x" 
  apply transfer
  by (metis One_nat_def Var0_def insertion.abs_eq insertion_single mapping_of_inverse monom.rep_eq mult.right_neutral mult_1 power.simps(2) power_0)

lemma insertion_Const: "insertion α (Const a) = a"
  by (metis Const.abs_eq Const0_def insertion_single monom.abs_eq mult.right_neutral power_0 single_zero)

lemma insertion_power: "insertion α (p^n) = (insertion α p)^n" 
  by (induct n, auto simp: insertion_mult)

lemma insertion_monom_add: "insertion α (monom (f + g) a) = insertion α (monom f 1) * insertion α (monom g a)" 
  by (metis insertion_mult mult_1 mult_monom)

lemma insertion_uminus: "insertion α (- p) = - insertion α p"
  by (metis add_eq_0_iff insertion_add insertion_zero)

lemma insertion_sum_list: "insertion α (sum_list ps) = sum_list (map (insertion α) ps)" 
  by (induct ps, auto simp: insertion_add)

lemma coeff_uminus: "coeff (- p) m = - coeff p m"
  by (simp add: coeff_def uminus_mpoly.rep_eq)

lemma insertion_substitute: "insertion α (substitute σ p) = insertion (λ x. insertion α (σ x)) p" 
  unfolding substitute_def
proof (induct p rule: mpoly_induct)
  case (monom m a)
  show ?case 
    apply (subst replace_coeff_monom)
    subgoal by (simp add: Const_0)
    subgoal proof (induct m arbitrary: a rule: poly_mapping_induct)
      case (single k v)
      show ?case by (simp add: insertion_mult insertion_Const insertion_power)  
    next
      case (sum f g k v a)
      from sum(1)[of 1] sum(2)[of a] show ?case 
        by (simp add: insertion_monom_add insertion_mult Const_1)
    qed
    done
next
  case (sum p1 p2 m a)
  then show ?case 
    apply (subst replace_coeff_add)
    subgoal by (simp add: Const_0)
    subgoal by (transfer', simp add: Const0_def single_add)
    by (simp add: insertion_add)
qed

lemma Const_add: "Const (x + y) = Const x + Const y" 
  by (transfer, auto simp: Const0_def single_add)

lemma substitute_add[simp]: "substitute σ (p + q) = substitute σ p + substitute σ q" 
  unfolding substitute_def insertion_add[symmetric] 
  by (subst replace_coeff_add, auto simp: Const_0 Const_add)

lemma Const_sum: "Const (sum f A) = sum (Const o f) A"
  by (metis Const_0 Const_add sum_comp_morphism)

lemma Const_sum_list: "Const (sum_list (map f xs)) = sum_list (map (Const o f) xs)"
  by (induct xs, auto simp: Const_0 Const_add)

lemma Const_0_eq[simp]: "Const x = 0  x = 0" 
  by (smt (verit) Const.abs_eq Const0_def coeff_monom monom.abs_eq single_zero when_def zero_mpoly_def)

lemma Const_sum_any: "Const (Sum_any f) = Sum_any (Const o f)"
  unfolding Sum_any.expand_set Const_sum o_def
  by (intro sum.cong[OF _ refl], auto simp: Const_0)

lemma Const_mult: "Const (x * y) = Const x * Const y"
  by (metis Const.abs_eq Const0_def monom.abs_eq smult_conv_mult smult_monom)

lemma Const_power: "Const (x ^ e) = Const x ^ e" 
  by (induct e, auto simp: Const_1 Const_mult)

lemma lookup_replace_Const: "lookup (mapping_of (replace_coeff Const p)) l = Const (lookup (mapping_of p) l)" 
  by (metis Const_0 coeff_def coeff_replace_coeff)

lemma replace_coeff_mult: "replace_coeff Const (p * q) = replace_coeff Const p * replace_coeff Const q" 
  apply (subst coeff_eq[symmetric], intro ext, subst coeff_replace_coeff, rule Const_0)
  apply (unfold coeff_def)
  apply (unfold times_mpoly.rep_eq)
  apply (unfold Poly_Mapping.lookup_mult)
  apply (unfold Const_sum_any o_def Const_mult lookup_replace_Const)
  apply (unfold when_def if_distrib Const_0)
  by auto


lemma substitute_mult[simp]: "substitute σ (p * q) = substitute σ p * substitute σ q" 
  unfolding substitute_def insertion_mult[symmetric] replace_coeff_mult ..

lemma replace_coeff_Var[simp]: "replace_coeff Const (Var x) = Var x"
  by (metis Const_0 Const_1 Var.abs_eq Var0_def monom.abs_eq replace_coeff_monom)

lemma replace_coeff_Const[simp]: "replace_coeff Const (Const c) = Const (Const c)" 
  by (metis Const.abs_eq Const0_def Const_0 monom.abs_eq replace_coeff_monom)

lemma substitute_Var[simp]: "substitute σ (Var x) = σ x" 
  unfolding substitute_def by (simp add: insertion_Var)

lemma substitute_Const[simp]: "substitute σ (Const c) = Const c" 
  unfolding substitute_def by (simp add: insertion_Const)

lemma substitute_0[simp]: "substitute σ 0 = 0" 
  using substitute_Const[of σ 0, unfolded Const_0] .

lemma substitute_1[simp]: "substitute σ 1 = 1" 
  using substitute_Const[of σ 1, unfolded Const_1] .

lemma substitute_power[simp]: "substitute σ (p^e) = (substitute σ p)^e" 
  by (induct e, auto)

lemma substitute_monom[simp]: "substitute σ (monom (monomial e x) c) = Const c * (σ x)^e" 
  by (simp add: replace_coeff_monom substitute_def)

lemma substitute_sum_list: "substitute σ (sum_list (map f xs)) = sum_list (map (substitute σ o f) xs)"
  by (induct xs, auto)

lemma substitute_sum: "substitute σ (sum f xs) = sum (substitute σ o f) xs"
  by (induct xs rule: infinite_finite_induct, auto)

lemma substitute_prod: "substitute σ (prod f xs) = prod (substitute σ o f) xs"
  by (induct xs rule: infinite_finite_induct, auto)

definition vars_list where "vars_list = sorted_list_of_set o vars" 

lemma set_vars_list[simp]: "set (vars_list p) = vars p" 
  unfolding vars_list_def o_def using vars_finite[of p] by auto

lift_definition mpoly_coeff_filter :: "('a :: zero  bool)  'a mpoly  'a mpoly" is
  "λ f p. Poly_Mapping.mapp (λ m c. c when f c) p" .

lemma mpoly_coeff_filter: "coeff (mpoly_coeff_filter f p) m = (coeff p m when f (coeff p m))" 
  unfolding coeff_def by transfer (simp add: in_keys_iff mapp.rep_eq)

lemma total_degree_add: assumes "total_degree p  d" "total_degree q  d" 
  shows "total_degree (p + q)  d" 
  using assms
proof transfer
  fix d and p q :: "(nat 0 nat) 0 'a" 
  let ?exp = "λ p. Max (insert (0 :: nat) ((λm. sum (lookup m) (keys m)) ` keys p))" 
  assume d: "?exp p  d" "?exp q  d" 
  have "?exp (p + q)  Max (insert (0 :: nat) ((λm. sum (lookup m) (keys m)) ` (keys p  keys q)))" 
    using Poly_Mapping.keys_add[of p q]
    by (intro Max_mono, auto)
  also have " = max (?exp p) (?exp q)" 
    by (subst Max_Un[symmetric], auto simp: image_Un)
  also have "  d" using d by auto
  finally show "?exp (p + q)  d" .
qed

lemma total_degree_Var[simp]: "total_degree (Var x :: 'a :: comm_semiring_1 mpoly) = Suc 0" 
  by (transfer, auto simp: Var0_def)

lemma total_degree_Const[simp]: "total_degree (Const x) = 0" 
  by (transfer, auto simp: Const0_def)

lemma total_degree_Const_mult: assumes "total_degree p  d"
  shows "total_degree (Const x * p)  d" 
  using assms
proof (transfer, goal_cases)
  case (1 p d x)
  have sub: "keys (Const0 x * p)  keys p" 
    by (rule order.trans[OF keys_mult], auto simp: Const0_def)
  show ?case
    by (rule order.trans[OF _ 1], rule Max_mono, insert sub, auto)
qed

lemma vars_0[simp]: "vars 0 = {}" 
  unfolding vars_def by (simp add: zero_mpoly.rep_eq)

lemma vars_1[simp]: "vars 1 = {}"
  unfolding vars_def by (simp add: one_mpoly.rep_eq)

lemma vars_Var[simp]: "vars (Var x :: 'a :: comm_semiring_1 mpoly) = {x}" 
  unfolding vars_def by (transfer, auto simp: Var0_def)

lemma vars_Const[simp]: "vars (Const c) = {}" 
  unfolding vars_def by (transfer, auto simp: Const0_def)

lemma coeff_sum_list: "coeff (sum_list ps) m = (pps. coeff p m)"  
  by (induct ps, auto simp: coeff_add[symmetric]) 
    (metis coeff_monom monom_zero zero_when)

lemma coeff_Const_mult: "coeff (Const c * p) m = c * coeff p m" 
  by (metis Const.abs_eq Const0_def add_0 coeff_monom_mult monom.abs_eq)

lemma coeff_Const: "coeff (Const c) m = (if m = 0 then (c :: 'a :: comm_semiring_1) else 0)"
  by (simp add: Const.rep_eq Const0_def coeff_def lookup_single_not_eq)

lemma coeff_Var: "coeff (Var x) m = (if m = monomial 1 x then 1 :: 'a :: comm_semiring_1 else 0)"
  by (simp add: Var.rep_eq Var0_def coeff_def lookup_single_not_eq)



text ‹list-based representations, so that polynomials can be converted to first-order terms›

lift_definition monom_list :: "'a :: comm_semiring_1 mpoly  (monom × 'a) list"
  is "λ p. map (λ m. (m, lookup p m)) (sorted_list_of_set (keys p))" .

lift_definition var_list :: "monom  (var × nat) list"
  is "λ m. map (λ x. (x, lookup m x)) (sorted_list_of_set (keys m))" .

lemma monom_list: "p = ( (m, c)  monom_list p. monom m c)" 
  apply transfer
  subgoal for p
    apply (subst poly_mapping_sum_monomials[symmetric])
    apply (subst distinct_sum_list_conv_Sum)
     apply (unfold distinct_map, simp add: inj_on_def)
     apply (meson in_keys_iff monomial_inj)
    apply (unfold set_map image_comp o_def split)
    apply (subst set_sorted_list_of_set, force)
    by (smt (verit, best) finite_keys lookup_eq_zero_in_keys_contradict monomial_inj o_def sum.cong sum.reindex_nontrivial)
  done

lemma monom_list_coeff: "(m,c)  set (monom_list p)  coeff p m = c" 
  unfolding coeff_def by (transfer, auto)

lemma monom_list_keys: "(m,c)  set (monom_list p)  keys m  vars p" 
  unfolding vars_def by (transfer, auto)


lemma var_list: "monom m c = Const (c :: 'a :: comm_semiring_1) * ( (x, e)  var_list m. (Var x)^e)" 
proof transfer
  fix m :: monom and c :: 'a
  have set: "set (sorted_list_of_set (keys m)) = keys m" 
    by (subst set_sorted_list_of_set, force+)
  have id: "((x, y)map (λx. (x, lookup m x)) (sorted_list_of_set (keys m)). Var0 x ^ y)
    = ( x  keys m. Var0 x ^ lookup m x)" (is "?r1 = ?r2")
    apply (unfold map_map o_def split)
    apply (subst prod.distinct_set_conv_list[symmetric])
    by auto
  have "monomial c m = Const0 c * monomial 1 m"
    by (simp add: Const0_one monomial_mp)
  also have "monomial (1 :: 'a) m = ?r1" unfolding id 
  proof (induction m rule: poly_mapping_induct)
    case (single k v)
    then show ?case by (auto simp: Var0_power mult_single)    
  next
    case (sum f g k v)
    have id: "monomial (1 :: 'a) (f + g) = monomial 1 f * monomial 1 g" 
      by (simp add: mult_single)
    have keys: "keys (f + g) = keys f  keys g" "keys f  keys g = {}" 
       apply (intro keys_plus_ninv_comm_monoid_add) 
      using sum(3-4) by simp
    show ?case unfolding id sum(1-2) unfolding keys(1)
      apply (subst prod.union_disjoint, force, force, rule keys)
      apply (intro arg_cong2[of _ _ _ _ "(*)"] prod.cong refl)
       apply (insert keys(2), simp add: disjoint_iff in_keys_iff lookup_add)
      by (metis add_cancel_left_left disjoint_iff_not_equal in_keys_iff plus_poly_mapping.rep_eq)
  qed
  finally show "monomial c m = Const0 c * ?r1" .
qed

lemma var_list_keys: "(x,e)  set (var_list m)  x  keys m" 
  by (transfer, auto)

lemma vars_substitute: assumes " x. vars (σ x)  V" 
  shows "vars (substitute σ p)  V" 
proof -
  define mcs where "mcs = monom_list p" 
  show ?thesis unfolding monom_list[of p, folded mcs_def]
  proof (induct mcs)
    case (Cons mc mcs)
    obtain m c where mc: "mc = (m,c)" by force
    define xes where "xes = var_list m" 
    have monom: "vars (substitute σ (monom m c))  V" unfolding var_list[of m, folded xes_def]
    proof (induct xes)
      case (Cons xe xes)
      obtain x e where xe: "xe = (x,e)" by force
      from assms have "vars (σ x)  V" .
      hence x: "vars ((σ x)^e)  V" 
      proof (induct e)
        case (Suc e)
        then show ?case 
          by (simp, intro order.trans[OF vars_mult], auto)
      qed force
      have id: "substitute σ (Const c * (axe # xes. case a of (x, a)  Var x ^ a))
        = σ x ^ e * (Const c * substitute σ ((x, y)xes. Var x ^ y))" unfolding xe
        by (simp add: ac_simps)
      show ?case unfolding id 
        apply (rule order.trans[OF vars_mult])
        using Cons x by auto
    qed force
    show ?case unfolding mc 
      apply simp
      apply (rule order.trans[OF vars_add])
      using monom Cons by auto
  qed force
qed

lemma insertion_monom_nonneg: assumes " x. α x  0" and c: "(c :: 'a :: {linordered_nonzero_semiring,ordered_semiring_0})  0" 
  shows "insertion α (monom m c)  0" 
proof -
  define xes where "xes = var_list m" 
  show ?thesis unfolding var_list[of m c, folded xes_def]
  proof (induct xes)
    case Nil
    thus ?case using c by (auto simp: insertion_Const)
  next
    case (Cons xe xes)
    obtain x e where xe: "xe = (x,e)" by force
    have id: "insertion α (Const c * (axe # xes. case a of (x, a)  Var x ^ a))
      = α x ^ e * insertion α (Const c * (axes. case a of (x, a)  Var x ^ a))" 
      unfolding xe
      by (simp add: insertion_mult insertion_power insertion_Var algebra_simps)
    show ?case unfolding id
    proof (intro mult_nonneg_nonneg Cons)
      show "0  α x ^ e" using assms(1)[of x]
        by (induct e, auto)
    qed
  qed
qed 

lemma insertion_nonneg: assumes " x. α x  (0 :: 'a :: linordered_idom)" 
  and " m. coeff p m  0"  
shows "insertion α p  0" 
proof -
  define mcs where "mcs = monom_list p" 
  from monom_list[of p] have p: "p = ((m, c) mcs. monom m c)" unfolding mcs_def by auto
  have mcs: "(m,c)  set mcs  c  0" for m c 
    using monom_list_coeff assms(2) unfolding mcs_def by auto
  show ?thesis using mcs unfolding p
  proof (induct mcs)
    case Nil
    thus ?case by (auto simp: insertion_Const)
  next
    case (Cons mc mcs)
    obtain m c where mc: "mc = (m,c)" by force
    with Cons have "c  0" by auto
    from insertion_monom_nonneg[OF assms(1) this]
    have m: "0  insertion α (monom m c)" by auto
    from Cons(1)[OF Cons(2)] 
    have IH: "0  insertion α (amcs. case a of (a, b)  monom a b)" by force
    show ?case unfolding mc using IH m
      by (auto simp: insertion_add)
  qed
qed 

lemma vars_sumlist: "vars (sum_list ps)   (vars ` set ps)" 
  by (induct ps, insert vars_add, auto)

lemma coefficients_of_linear_poly: assumes linear: "total_degree (p :: 'a :: comm_semiring_1 mpoly)  1"  
  shows " c a vs. p = Const c + (ivs. Const (a i) * Var i)
      distinct vs  set vs = vars p  sorted_list_of_set (vars p) = vs  ( v  set vs. a v  0)
      ( i. a i = coeff p (monomial 1 i))  (c = coeff p 0)" 
proof -
  have sum_zero: "( x. x  set xs  x = 0)  sum_list (xs :: 'a list) = 0" for xs by (induct xs, auto)
  define a :: "var  'a" where "a i = coeff p (monomial 1 i)" for i
  define vs where "vs = sorted_list_of_set (vars p)" 
  define c where "c = coeff p 0" 
  define q where "q = Const c + (i vs. Const (a i) * Var i)" 
  show ?thesis
  proof (intro exI[of _ vs] exI[of _ a] exI[of _ c] conjI ballI vs_def[symmetric] c_def allI a_def, 
      unfold q_def[symmetric])
    show "set vs = vars p" and dist: "distinct vs" 
      using sorted_list_of_set[of "vars p", folded vs_def] vars_finite[of p] by auto    
    show "p = q" 
      unfolding coeff_eq[symmetric]
    proof (intro ext)
      fix m
      have "coeff q m = coeff (Const c) m + (xvs. a x * coeff (Var x) m)" 
        unfolding q_def coeff_add[symmetric] coeff_sum_list map_map o_def coeff_Const_mult ..
      also have " = coeff p m" 
      proof (cases "m = 0")
        case True
        thus ?thesis by (simp add: coeff_Const coeff_Var monomial_0_iff c_def)
      next
        case False
        from False have "coeff (Const (coeff p 0)) m + (xvs. a x * coeff (Var x) m) 
        = (xvs. a x * coeff (Var x) m)" unfolding coeff_Const by simp
        also have " = coeff p m" 
        proof (cases " i  set vs. m = monomial 1 i")
          case True
          then obtain i where i: "i  set vs" and m: "m = monomial 1 i" by auto
          from split_list[OF i] obtain bef aft where id: "vs = bef @ i # aft" by auto
          from id dist have i: "i  set bef" "i  set aft" by auto
          have [simp]: "(monomial (Suc 0) i = monomial (Suc 0) j) = (i = j)" for i j :: var
            using monomial_inj by fastforce
          show ?thesis 
            apply (subst id, unfold coeff_Var m, simp)
            apply (subst sum_zero, use i in force)
            apply (subst sum_zero, use i in force)
            by (simp add: a_def)
        next
          case mon: False
          hence one: "(xvs. a x * coeff (Var x) m) = 0" 
            by (intro sum_zero, auto simp: coeff_Var)
          have two: "coeff p m = 0" 
          proof (rule ccontr)
            assume n0: "coeff p m  0" 
            show False
            proof (cases " i. m = monomial 1 i")
              case True
              with mon obtain i where i: "i  set vs" and m: "m = monomial 1 i" by auto
              from n0 m have "i  vars p" unfolding vars_def coeff_def 
                by (metis UN_I in_keys_iff lookup_single_eq one_neq_zero)
              with i set vs = vars p show False by auto
            next
              case False
              have "sum (lookup m) (keys m)  total_degree p" using n0 unfolding coeff_def
                apply transfer
                by transfer (metis (no_types, lifting) Max_ge finite.insertI finite_imageI finite_keys image_eqI in_keys_iff insertCI)
              also have "  1" using linear .
              finally have linear: "sum (lookup m) (keys m)  1" by auto
              consider (single) x where "keys m = {x}" | (null) "keys m = {}" | 
                (two) x y k where "keys m = {x,y}  k" and "x  y" by blast
              thus False
              proof cases
                case null
                hence "m = 0" by simp
                with m  0 show False by simp
              next
                case (single x)
                with linear have "lookup m x  1" by auto
                moreover from single have nz: "lookup m x  0"
                  by (metis in_keys_iff insertI1)
                ultimately have "lookup m x = 1" by auto
                with single have "m = monomial 1 x"
                  by (metis Diff_cancel Diff_eq_empty_iff keys_subset_singleton_imp_monomial)
                with False show False by auto
              next
                case (two x y k)
                define k' where "k' = k - {x,y}" 
                have "keys m = insert x (insert y k')" "x  y" "x  k'" "y  k'" "finite k'" 
                  unfolding k'_def using two finite_keys[of m] by auto
                hence "lookup m x + lookup m y  sum (lookup m) (keys m)" by simp
                also have "  1" by fact
                finally have "lookup m x = 0  lookup m y = 0" by auto
                with two show False by blast
              qed
            qed
          qed
          from one two show ?thesis by simp
        qed
        finally show ?thesis by (simp add: c_def)
      qed
      finally show "coeff p m = coeff q m" ..
    qed
  
    fix v
    assume v: "v  set vs" 
    hence "v  vars p" using set vs = vars p by auto
    hence vq: "v  vars q" unfolding p = q .
    from split_list[OF v] obtain bef aft where vs: "vs = bef @ v # aft" by auto
    with dist have vba: "v  set bef" "v  set aft" by auto
    show "a v  0" 
    proof
      assume a0: "a v = 0" 
      have "v  vars p" by fact
      also have "p = q" by fact
      also have "vars q  vars (sum_list (map (λ x. Const (a x) * Var x) bef))  
         vars (Const (a v) * Var v)
          vars (sum_list (map (λ x. Const (a x) * Var x) aft))" 
        unfolding q_def vs apply simp
        apply (rule order.trans[OF vars_add], simp)
        apply (rule order.trans[OF vars_add])
        by (insert vars_add, blast)
      also have "vars (Const (a v) * Var v) = {}" unfolding a0 Const_0 by simp
      finally obtain list where v: "v  vars (sum_list (map (λ x. Const (a x) * Var x) list))"   
        and not_v: "v  set list" using vba by auto
      from set_mp[OF vars_sumlist v] obtain x where "x  set list" and "v  vars (Const (a x) * Var x)" 
        by auto
      with vars_mult[of "Const (a x)" "Var x"] not_v show False by auto
    qed
  qed
qed

text ‹Introduce notion for degree of monom›
definition degree_monom :: "(var 0 nat)  nat" where
  "degree_monom m = sum (lookup m) (keys m)" 

lemma total_degree_alt_def: "total_degree p = Max (insert 0 (degree_monom ` keys (mapping_of p)))"
  unfolding degree_monom_def
  by transfer' simp

lemma degree_monon_le_total_degree: assumes "coeff p m  0" 
  shows "degree_monom m  total_degree p"
  using assms unfolding total_degree_alt_def by (simp add: coeff_keys)

lemma degree_monom_eq_total_degree: assumes "p  0" 
  shows " m. coeff p m  0  degree_monom m = total_degree p" 
proof (cases "total_degree p = 0")
  case False
  thus ?thesis unfolding total_degree_alt_def
    by (metis (full_types) Max_in coeff_keys empty_not_insert finite_imageI finite_insert finite_keys image_iff insertE)
next  
  case True
  from assms obtain m where "coeff p m  0"
    using coeff_all_0 by auto
  with degree_monon_le_total_degree[OF this] True show ?thesis by auto
qed

lemma degree_add_leI: "degree p x  d  degree q x  d  degree (p + q) x  d"  
  apply transfer
  subgoal for p x d q using Poly_Mapping.keys_add[of p q]
    by (intro Max.boundedI, auto)
  done

lemma degree_sum_leI: assumes " i. i  A  degree (p i) x  d" 
  shows "degree (sum p A) x  d" 
  using assms 
  by (induct A rule: infinite_finite_induct, auto intro: degree_add_leI)

lemma total_degree_sum_leI: assumes " i. i  A  total_degree (p i)  d" 
  shows "total_degree (sum p A)  d" 
  using assms 
  by (induct A rule: infinite_finite_induct, auto intro: total_degree_add)

lemma total_degree_monom: assumes "c  0"  
  shows "total_degree (monom m c) = degree_monom m"
  unfolding total_degree_alt_def using assms by auto

lemma degree_Var[simp]: "degree (Var x :: 'a :: comm_semiring_1 mpoly) x = 1" 
  by (transfer, unfold Var0_def, simp)

lemma Var_neq_0[simp]: "Var x  (0 :: 'a :: comm_semiring_1 mpoly)" 
proof
  assume "Var x = (0 :: 'a mpoly)" 
  from arg_cong[OF this, of "λ p. degree p x"]
  show False by simp
qed

lemma degree_Const[simp]: "degree (Const c) x = 0" 
  by transfer (auto simp: Const0_def)

lemma vars_add_subI: "vars p  A  vars q  A  vars (p + q)  A" 
  by (metis le_supI subset_trans vars_add)

lemma vars_mult_subI: "vars p  A  vars q  A  vars (p * q)  A" 
  by (metis le_supI subset_trans vars_mult)

lemma vars_eqI: assumes "vars (p :: 'a :: comm_ring_1 mpoly)  V"
  " v. v  V   a b. insertion a p  insertion (a(v := b)) p" 
shows "vars p = V" 
proof (rule ccontr)
  assume "¬ ?thesis" 
  with assms obtain v where "v  V" and not: "v  vars p" by auto
  from assms(2)[OF this(1)] obtain a b where "insertion a p  insertion (a(v := b)) p" by auto
  moreover have "insertion a p = insertion (a(v := b)) p" 
    by (rule insertion_irrelevant_vars, insert not, auto) 
  ultimately show False by auto
qed


end