# Theory Bernstein_01

```section ‹Bernstein Polynomials over the interval [0, 1]›

theory Bernstein_01
imports "HOL-Computational_Algebra.Computational_Algebra"
"Budan_Fourier.Budan_Fourier"
"RRI_Misc"
begin

text ‹
The theorem of three circles is a statement about the Bernstein coefficients of a polynomial, the
coefficients when a polynomial is expressed as a sum of Bernstein polynomials. These coefficients
behave nicely under translations and rescaling and are the coefficients of a particular polynomial
in the [0, 1] case. We shall define the [0, 1] case now and consider the general case later,
deriving all the results by rescaling.
›

subsection ‹Definition and basic results›

definition Bernstein_Poly_01 :: "nat ⇒ nat ⇒ real poly" where
"Bernstein_Poly_01 j p = (monom (p choose j) j)
* (monom 1 (p-j) ∘⇩p [:1, -1:])"

lemma degree_Bernstein:
assumes hb: "j ≤ p"
shows "degree (Bernstein_Poly_01 j p) = p"
proof -
have ha: "monom (p choose j) j ≠ (0::real poly)" using hb by force
have hb: "monom 1 (p-j) ∘⇩p [:1, -1:] ≠ (0::real poly)"
proof
assume "monom 1 (p-j) ∘⇩p [:1, -1:] = (0::real poly)"
hence "lead_coeff (monom 1 (p - j) ∘⇩p [:1, -1:]) = (0::real)"
by simp
moreover have "lead_coeff (monom (1::real) (p - j)
∘⇩p [:1, -1:]) = (((- 1) ^ (p - j))::real)"
by (subst lead_coeff_comp, auto simp: degree_monom_eq)
ultimately show "False" by auto
qed
from ha hb show ?thesis
by (auto simp add: Bernstein_Poly_01_def degree_mult_eq
degree_monom_eq degree_pcompose)
qed

lemma coeff_gt:
assumes hb: "j > p"
shows "Bernstein_Poly_01 j p = 0"

lemma degree_Bernstein_le: "degree (Bernstein_Poly_01 j p) ≤ p"
apply (cases "j ≤ p")

lemma poly_Bernstein_nonneg:
assumes "x ≥ 0" and "1 ≥ x"
shows "poly (Bernstein_Poly_01 j p) x ≥ 0"
using assms by (simp add: poly_monom poly_pcompose Bernstein_Poly_01_def)

lemma Bernstein_symmetry:
assumes "j ≤ p"
shows "(Bernstein_Poly_01 j p) ∘⇩p [:1, -1:] = Bernstein_Poly_01 (p-j) p"
proof -
have "(Bernstein_Poly_01 j p) ∘⇩p [:1, -1:]
= ((monom (p choose j) j) * (monom 1 (p-j) ∘⇩p [:1, -1:])) ∘⇩p [:1, -1:]"
also have "... = (monom (p choose (p-j)) j *
(monom 1 (p-j) ∘⇩p [:1, -1:])) ∘⇩p [:1, -1:]"
by (fastforce simp: binomial_symmetric[OF assms])
also have "... = monom (p choose (p-j)) j ∘⇩p [:1, -1:] *
(monom 1 (p-j)) ∘⇩p ([:1, -1:] ∘⇩p [:1, -1:])"
by (force simp: pcompose_mult pcompose_assoc)
also have "... = (monom (p choose (p-j)) j ∘⇩p [:1, -1:]) * monom 1 (p-j)"
by (force simp: pcompose_pCons)
also have "... = smult (p choose (p-j)) (monom 1 j ∘⇩p [:1, -1:])
* monom 1 (p-j)"
by (simp add: assms smult_monom pcompose_smult[symmetric])
also have "... = (monom 1 j ∘⇩p [:1, -1:]) * monom (p choose (p-j)) (p-j)"
apply (subst mult_smult_left)
apply (subst mult_smult_right[symmetric])
apply (subst smult_monom)
by force
also have "... = Bernstein_Poly_01 (p-j) p" using assms
by (auto simp: Bernstein_Poly_01_def)
finally show ?thesis .
qed

subsection ‹@{term Bernstein_Poly_01} and @{term reciprocal_poly}›

lemma Bernstein_reciprocal:
"reciprocal_poly p (Bernstein_Poly_01 i p)
= smult (p choose i) ([:-1, 1:]^(p-i))"
proof cases
assume "i ≤ p"
hence "reciprocal_poly p (Bernstein_Poly_01 i p) =
reciprocal_poly (degree (Bernstein_Poly_01 i p)) (Bernstein_Poly_01 i p)"
by (auto simp: degree_Bernstein)
also have "... = reflect_poly (Bernstein_Poly_01 i p)"
by (rule reciprocal_degree)
also have "... = smult (p choose i) ([:-1, 1:]^(p-i))"
by (auto simp: Bernstein_Poly_01_def reflect_poly_simps monom_altdef
pcompose_pCons reflect_poly_pCons' hom_distribs)
finally show ?thesis .
next
assume h:"¬ i ≤ p"
hence "reciprocal_poly p (Bernstein_Poly_01 i p) = (0::real poly)"
by (auto simp: coeff_gt reciprocal_poly_def)
also have "... = smult (p choose i) ([:-1, 1:]^(p - i))" using h
by fastforce
finally show ?thesis .
qed

lemma Bernstein_reciprocal_translate:
"reciprocal_poly p (Bernstein_Poly_01 i p) ∘⇩p [:1, 1:] =
monom (p choose i) (p - i)"
by (auto simp: Bernstein_reciprocal pcompose_smult pcompose_pCons monom_altdef hom_distribs)

lemma coeff_Bernstein_sum_01: fixes b::"nat ⇒ real" assumes hi: "p ≥ i"
shows
"coeff (reciprocal_poly p
(∑x = 0..p. smult (b x) (Bernstein_Poly_01 x p)) ∘⇩p [:1, 1:])
(p - i) = (p choose i) * (b i)" (is "?L = ?R")
proof -
define P where "P ≡ (∑x = 0..p. (smult (b x) (Bernstein_Poly_01 x p)))"

have "⋀x. degree (smult (b x) (Bernstein_Poly_01 x p)) ≤ p"
proof -
fix x
show "degree (smult (b x) (Bernstein_Poly_01 x p)) ≤ p"
apply (cases "x ≤ p")
by (auto simp: degree_Bernstein coeff_gt)
qed
hence "reciprocal_poly p P =
(∑x = 0..p. reciprocal_poly p (smult (b x) (Bernstein_Poly_01 x p)))"
apply (subst P_def)
apply (rule reciprocal_sum)
by presburger
also have
"... = (∑x = 0..p. (smult (b x * (p choose x)) ([:-1, 1:]^(p-x))))"
proof (rule sum.cong)
fix x assume "x ∈ {0..p}"
hence "x ≤ p" by simp
thus "reciprocal_poly p (smult (b x) (Bernstein_Poly_01 x p)) =
smult ((b x) * (p choose x)) ([:-1, 1:]^(p-x))"
by (auto simp add: reciprocal_smult degree_Bernstein Bernstein_reciprocal)
qed (simp)
finally have
"reciprocal_poly p P =
(∑x = 0..p. (smult ((b x) * (p choose x)) ([:-1, 1:]^(p-x))))" .
hence
"(reciprocal_poly p P) ∘⇩p [:1, 1:] =
(∑x = 0..p. (smult ((b x) * (p choose x)) ([:-1, 1:]^(p-x))) ∘⇩p [:1, 1:])"
also have "... = (∑x = 0..p. (monom ((b x) * (p choose x)) (p - x)))"
proof (rule sum.cong)
fix x assume "x ∈ {0..p}"
hence "x ≤ p" by simp
thus "smult (b x * (p choose x)) ([:- 1, 1:] ^ (p - x)) ∘⇩p [:1, 1:] =
monom (b x * (p choose x)) (p - x)"
by (simp add: hom_distribs pcompose_smult pcompose_pCons monom_altdef)
qed (simp)
finally have "(reciprocal_poly p P) ∘⇩p [:1, 1:] =
(∑x = 0..p. (monom ((b x) * (p choose x)) (p - x)))" .
hence "?L = (∑x = 0..p. if p - x = p - i then b x * real (p choose x) else 0)"
by (auto simp add: P_def coeff_sum)
also have "... = (∑x = 0..p. if x = i then b x * real (p choose x) else 0)"
proof (rule sum.cong)
fix x assume "x ∈ {0..p}"
hence "x ≤ p" by simp
thus "(if p - x = p - i then b x * real (p choose x) else 0) =
(if x = i then b x * real (p choose x) else 0)" using hi
qed (simp)
also have "... = ?R" by simp
finally show ?thesis .
qed

lemma Bernstein_sum_01: assumes hP: "degree P ≤ p"
shows
"P = (∑j = 0..p. smult
(inverse (real (p choose j)) *
coeff (reciprocal_poly p P ∘⇩p [:1, 1:]) (p-j))
(Bernstein_Poly_01 j p))"
proof -
define Q where "Q ≡ reciprocal_poly p P ∘⇩p [:1, 1:]"
from hP Q_def have hQ: "degree Q ≤ p"
by (auto simp: degree_reciprocal degree_pcompose)
have "reciprocal_poly p (∑j = 0..p.
smult (inverse (real (p choose j)) * coeff Q (p-j))
(Bernstein_Poly_01 j p)) ∘⇩p [:1, 1:] = Q"
proof (rule poly_eqI)
fix n
show "coeff (reciprocal_poly p (∑j = 0..p.
smult (inverse (real (p choose j)) * coeff Q (p-j))
(Bernstein_Poly_01 j p)) ∘⇩p [:1, 1:]) n = coeff Q n"
(is "?L = ?R")
proof cases
assume hn: "n ≤ p"
hence "?L = coeff (reciprocal_poly p (∑j = 0..p.
smult (inverse (real (p choose j)) * coeff Q (p-j))
(Bernstein_Poly_01 j p)) ∘⇩p [:1, 1:]) (p - (p - n))"
by force
also have "... = (p choose (p-n)) *
(inverse (real (p choose (p-n))) *
coeff Q (p-(p-n)))"
apply (subst coeff_Bernstein_sum_01)
by auto
also have "... = ?R" using hn
by fastforce
finally show "?L = ?R" .
next
assume hn: "¬ n ≤ p"
have "degree (∑j = 0..p.
smult (inverse (real (p choose j)) * coeff Q (p - j))
(Bernstein_Poly_01 j p)) ≤ p"
proof (rule degree_sum_le)
fix q assume "q ∈ {0..p}"
hence "q ≤ p" by fastforce
thus "degree (smult (inverse (real (p choose q)) *
coeff Q (p - q)) (Bernstein_Poly_01 q p)) ≤ p"
by (auto simp add: degree_Bernstein degree_smult_le)
qed simp
hence "degree (reciprocal_poly p (∑j = 0..p.
smult (inverse (real (p choose j)) * coeff Q (p - j))
(Bernstein_Poly_01 j p)) ∘⇩p [:1, 1:]) ≤ p"
by (auto simp add: degree_pcompose degree_reciprocal)
hence "?L = 0" using hn by (auto simp add: coeff_eq_0)
thus "?L = ?R" using hQ hn by (simp add: coeff_eq_0)
qed
qed
hence "reciprocal_poly p P ∘⇩p [:1, 1:] =
reciprocal_poly p (∑j = 0..p.
smult (inverse (real (p choose j)) *
coeff (reciprocal_poly p P ∘⇩p [:1, 1:]) (p-j))
(Bernstein_Poly_01 j p)) ∘⇩p [:1, 1:]"
by (auto simp: degree_reciprocal degree_pcompose Q_def)
hence "reciprocal_poly p P ∘⇩p ([:1, 1:] ∘⇩p [:-1, 1:]) =
reciprocal_poly p (∑j = 0..p. smult (inverse (real (p choose j)) *
coeff (reciprocal_poly p P ∘⇩p [:1, 1:]) (p-j))
(Bernstein_Poly_01 j p)) ∘⇩p ([:1, 1:] ∘⇩p [:-1, 1:])"
by (auto simp: pcompose_assoc)
hence "reciprocal_poly p P = reciprocal_poly p (∑j = 0..p.
smult (inverse (real (p choose j)) *
coeff (reciprocal_poly p P ∘⇩p [:1, 1:]) (p-j)) (Bernstein_Poly_01 j p))"
by (auto simp: pcompose_pCons)
hence "reciprocal_poly p (reciprocal_poly p P) =
reciprocal_poly p (reciprocal_poly p (∑j = 0..p.
smult (inverse (real (p choose j)) *
coeff (reciprocal_poly p P ∘⇩p [:1, 1:]) (p-j)) (Bernstein_Poly_01 j p)))"
by argo
thus "P = (∑j = 0..p. smult (inverse (real (p choose j)) *
coeff (reciprocal_poly p P ∘⇩p [:1, 1:]) (p-j)) (Bernstein_Poly_01 j p))"
using hP by (auto simp: reciprocal_reciprocal degree_sum_le degree_smult_le
qed

lemma Bernstein_Poly_01_span1:
assumes hP: "degree P ≤ p"
shows "P ∈ poly_vs.span {Bernstein_Poly_01 x p | x. x ≤ p}"
proof -
have "Bernstein_Poly_01 x p
∈ poly_vs.span {Bernstein_Poly_01 x p |x. x ≤ p}"
if "x ∈ {0..p}" for x
proof -
have "∃n. Bernstein_Poly_01 x p = Bernstein_Poly_01 n p ∧ n ≤ p"
using that by force
then show
"Bernstein_Poly_01 x p ∈ poly_vs.span {Bernstein_Poly_01 n p |n. n ≤ p}"
qed
thus ?thesis
apply (subst Bernstein_sum_01[OF hP])
apply (rule poly_vs.span_sum)
apply (rule poly_vs.span_scale)
by blast
qed

lemma Bernstein_Poly_01_span:
"poly_vs.span {Bernstein_Poly_01 x p | x. x ≤ p}
= {x. degree x ≤ p}"
apply (subst monom_span[symmetric])
apply (subst poly_vs.span_eq)
by (auto simp: monom_span degree_Bernstein_le
Bernstein_Poly_01_span1 degree_monom_eq)

subsection ‹Bernstein coefficients and changes›

definition Bernstein_coeffs_01 :: "nat ⇒ real poly ⇒ real list" where
"Bernstein_coeffs_01 p P =
[(inverse (real (p choose j)) *
coeff (reciprocal_poly p P ∘⇩p [:1, 1:]) (p-j)). j ← [0..<(p+1)]]"

lemma length_Bernstein_coeffs_01: "length (Bernstein_coeffs_01 p P) = p + 1"
by (auto simp: Bernstein_coeffs_01_def)

lemma nth_default_Bernstein_coeffs_01: assumes "degree P ≤ p"
shows "nth_default 0 (Bernstein_coeffs_01 p P) i =
inverse (p choose i) * coeff (reciprocal_poly p P ∘⇩p [:1, 1:]) (p-i)"
apply (cases "p = i")
using assms by (auto simp: Bernstein_coeffs_01_def nth_default_append
nth_default_Cons Nitpick.case_nat_unfold binomial_eq_0)

lemma Bernstein_coeffs_01_sum: assumes "degree P ≤ p"
shows "P = (∑j = 0..p. smult (nth_default 0 (Bernstein_coeffs_01 p P) j)
(Bernstein_Poly_01 j p))"
apply (subst nth_default_Bernstein_coeffs_01[OF assms])
apply (subst Bernstein_sum_01[OF assms])
by argo

definition Bernstein_changes_01 :: "nat ⇒ real poly ⇒ int" where
"Bernstein_changes_01 p P = nat (changes (Bernstein_coeffs_01 p P))"

lemma Bernstein_changes_01_def':
"Bernstein_changes_01 p P = nat (changes [(inverse (real (p choose j)) *
coeff (reciprocal_poly p P ∘⇩p [:1, 1:]) (p-j)). j ← [0..<p + 1]])"

lemma Bernstein_changes_01_eq_changes:
assumes hP: "degree P ≤ p"
shows "Bernstein_changes_01 p P =
changes (coeffs ((reciprocal_poly p P) ∘⇩p [:1, 1:]))"
proof (subst Bernstein_changes_01_def')
have h:
"map (λj. inverse (real (p choose j)) *
coeff (reciprocal_poly p P ∘⇩p [:1, 1:]) (p - j)) [0..<p + 1] =
map (λj. inverse (real (p choose j)) *
nth_default 0 [nth_default 0 (coeffs (reciprocal_poly p P ∘⇩p [:1, 1:]))
(p - j). j ← [0..<p + 1]] j) [0..<p + 1]"
proof (rule map_cong)
fix x
assume "x ∈ set [0..<p+1]"
hence hx: "x ≤ p" by fastforce
moreover have 1:
"length (map (λj. nth_default 0
(coeffs (reciprocal_poly p P ∘⇩p [:1, 1:])) (p - j)) [0..<p + 1]) ≤ Suc p"
by force
moreover have "length (coeffs (reciprocal_poly p P ∘⇩p [:1, 1:])) ≤ Suc p"
proof (cases "P=0")
case False
then have "reciprocal_poly p P ∘⇩p [:1, 1:] ≠ 0"
using hP by (simp add: Missing_Polynomial.pcompose_eq_0 reciprocal_0_iff)
moreover have "Suc (degree (reciprocal_poly p P ∘⇩p [:1, 1:])) ≤ Suc p"
using hP by (auto simp: degree_pcompose degree_reciprocal)
ultimately show ?thesis
using length_coeffs_degree by force
qed (auto simp: reciprocal_0)
ultimately have h:
"nth_default 0 (map (λj. nth_default 0 (coeffs
(reciprocal_poly p P ∘⇩p [:1, 1:])) (p - j)) [0..<p + 1]) x =
nth_default 0 (coeffs (reciprocal_poly p P ∘⇩p [:1, 1:])) (p - x)"
(is "?L = ?R")
proof -
have "?L = (map (λj. nth_default 0 (coeffs
(reciprocal_poly p P ∘⇩p [:1, 1:])) (p - j)) [0..<p + 1]) ! x"
using hx by (auto simp: nth_default_nth)
also have "... =  nth_default 0
(coeffs (reciprocal_poly p P ∘⇩p [:1, 1:])) (p - [0..<p + 1] ! x)"
apply (subst nth_map)
using hx by auto
also have "... = ?R"
apply (subst nth_upt)
using hx by auto
finally show ?thesis .
qed
show "inverse (real (p choose x)) *
coeff (reciprocal_poly p P ∘⇩p [:1, 1:]) (p - x) =
inverse (real (p choose x)) *
nth_default 0 (map (λj. nth_default 0
(coeffs (reciprocal_poly p P ∘⇩p [:1, 1:])) (p - j)) [0..<p + 1]) x"
apply (subst h)
apply (subst nth_default_coeffs_eq)
by blast
qed auto

have 1:
"rev (map (λj. nth_default 0 (coeffs (reciprocal_poly p P ∘⇩p [:1, 1:]))
(p - j)) [0..<p + 1]) = map (λj. nth_default 0 (coeffs
(reciprocal_poly p P ∘⇩p [:1, 1:])) j) [0..<p + 1]"
proof (subst rev_map, rule map_cong')
have "⋀q. (q ≥ p ⟶ rev [q-p..<q+1] = map ((-) q) [0..<p+1])"
proof (induction p)
case 0
then show ?case by simp
next
case (Suc p)
have IH: "⋀q. (q ≥ p ⟶ rev [q-p..<q+1] = map ((-) q) [0..<p+1])"
using Suc.IH by blast
show ?case
proof
assume hq: "Suc p ≤ q"
then have h: "rev [q - p..<q + 1] = map ((-) (q)) [0..<p + 1]"
apply (subst IH)
using hq by auto
have "[q - Suc p..<q + 1] = (q - Suc p) # [q - p..<q + 1]"
by (simp add: Suc_diff_Suc Suc_le_lessD hq upt_conv_Cons)
hence "rev [q - Suc p..<q + 1] = rev [q - p..<q + 1] @ [q - Suc p]"
by force
also have "... = map ((-) (q)) [0..<p + 1] @ [q - Suc p]"
using h by blast
also have "... = map ((-) q) [0..<Suc p + 1]"
by force
finally show "rev [q - Suc p..<q + 1] = map ((-) q) [0..<Suc p + 1]" .
qed
qed
thus "rev [0..<p + 1] = map ((-) p) [0..<p + 1]"
by force
next
fix y
assume "y ∈ set [0..<p + 1]"
hence "y ≤ p" by fastforce
thus "nth_default 0 (coeffs (reciprocal_poly p P ∘⇩p [:1, 1:])) (p - (p - y)) =
nth_default 0 (coeffs (reciprocal_poly p P ∘⇩p [:1, 1:])) y"
by fastforce
qed

have 2: "⋀ f. f ≠ 0 ⟶ degree f ≤ p ⟶
map (nth_default 0 (coeffs f)) [0..<p + 1] =
coeffs f @ replicate (p - degree f) 0"
proof (induction p)
case 0
then show ?case by (auto simp: degree_0_iff)
next
fix f
case (Suc p)
hence IH: "(f ≠ 0 ⟶
degree f ≤ p ⟶
map (nth_default 0 (coeffs f)) [0..<p + 1] =
coeffs f @ replicate (p - degree f) 0)" by blast
then show ?case
proof (cases)
assume h': "Suc p = degree f"
hence h: "[0..<Suc p + 1] = [0..<length (coeffs f)]"
by (metis add_is_0 degree_0 length_coeffs plus_1_eq_Suc zero_neq_one)
thus ?thesis
apply (subst h)
apply (subst map_nth_default)
using h' by fastforce
next
assume h': "Suc p ≠ degree f"
show ?thesis
proof
assume hf: "f ≠ 0"
show "degree f ≤ Suc p ⟶
map (nth_default 0 (coeffs f)) [0..<Suc p + 1] =
coeffs f @ replicate (Suc p - degree f) 0"
proof
assume "degree f ≤ Suc p"
hence 1: "degree f ≤ p" using h' by fastforce
hence 2: "map (nth_default 0 (coeffs f)) [0..<p + 1] =
coeffs f @ replicate (p - degree f) 0" using IH hf by blast
have "map (nth_default 0 (coeffs f)) [0..<Suc p + 1] =
map (nth_default 0 (coeffs f)) [0..<p + 1] @
[nth_default 0 (coeffs f) (Suc p)]"
by fastforce
also have
"... = coeffs f @ replicate (p - degree f) 0 @ [coeff f (Suc p)]"
using 2
by (auto simp: nth_default_coeffs_eq)
also have "... = coeffs f @ replicate (p - degree f) 0 @ [0]"
using ‹degree f ≤ Suc p› h' le_antisym le_degree by blast
also have "... = coeffs f @ replicate (Suc p - degree f) 0" using 1
finally show "map (nth_default 0 (coeffs f)) [0..<Suc p + 1] =
coeffs f @ replicate (Suc p - degree f) 0" .
qed
qed
qed
qed

thus "int (nat (changes (map (λj. inverse (real (p choose j)) *
coeff (reciprocal_poly p P ∘⇩p [:1, 1:]) (p - j)) [0..<p + 1]))) =
changes (coeffs (reciprocal_poly p P ∘⇩p [:1, 1:]))"
proof cases
assume hP: "P = 0"
show "int (nat (changes (map (λj. inverse (real (p choose j)) *
coeff (reciprocal_poly p P ∘⇩p [:1, 1:]) (p - j)) [0..<p + 1]))) =
changes (coeffs (reciprocal_poly p P ∘⇩p [:1, 1:]))" (is "?L = ?R")
proof -
have "?L = int (nat (changes (map (λj. 0::real) [0..<p+1])))"
using hP by (auto simp: reciprocal_0 changes_nonneg)
also have "... = 0"
apply (induction p)
by (auto simp: map_replicate_trivial changes_nonneg
replicate_app_Cons_same)
also have "0 = changes ([]::real list)" by simp
also have "... = ?R" using hP by (auto simp: reciprocal_0)
finally show ?thesis .
qed
next
assume hP': "P ≠ 0"
thus ?thesis
apply (subst h)
apply (subst changes_scale)
apply auto[2]
apply (subst changes_rev[symmetric])
apply (subst 1)
apply (subst 2)
apply (simp add: pcompose_eq_0 hP reciprocal_0_iff)
using assms apply (auto simp: degree_reciprocal)[1]
by (auto simp: changes_append_replicate_0 changes_nonneg)
qed
qed

lemma Bernstein_changes_01_test: fixes P::"real poly"
assumes hP: "degree P ≤ p" and h0: "P ≠ 0"
shows "proots_count P {x. 0 < x ∧ x < 1} ≤ Bernstein_changes_01 p P ∧
even (Bernstein_changes_01 p P - proots_count P {x. 0 < x ∧ x < 1})"
proof -
let ?Q = "(reciprocal_poly p P) ∘⇩p [:1, 1:]"

have 1: "changes (coeffs ?Q) ≥ proots_count ?Q {x. 0 < x} ∧
even (changes (coeffs ?Q) - proots_count ?Q {x. 0 < x})"
apply (rule descartes_sign)
by (simp add: Missing_Polynomial.pcompose_eq_0 h0 hP reciprocal_0_iff)

have "((+) (1::real) ` Collect ((<) (0::real))) = {x. (1::real)<x}"
proof
show "{x::real. 1 < x} ⊆ (+) 1 ` Collect ((<) 0)"
proof
fix x::real assume "x ∈ {x. 1 < x}"
hence "1 < x" by simp
hence "-1 + x ∈ Collect ((<) 0)" by auto
hence "1 + (-1 + x) ∈ (+) 1 ` Collect ((<) 0)" by blast
thus "x ∈ (+) 1 ` Collect ((<) 0)" by argo
qed
qed auto
hence 2:  "proots_count P {x. 0 < x ∧ x < 1} = proots_count ?Q {x. 0 < x}"
using assms
by (auto simp: proots_pcompose reciprocal_0_iff proots_count_reciprocal')

show ?thesis
apply (subst Bernstein_changes_01_eq_changes[OF hP])
apply (subst Bernstein_changes_01_eq_changes[OF hP])
apply (subst 2)
apply (subst 2)
by (rule 1)
qed

subsection ‹Expression as a Bernstein sum›

lemma Bernstein_coeffs_01_0: "Bernstein_coeffs_01 p 0 = replicate (p+1) 0"
by (auto simp: Bernstein_coeffs_01_def reciprocal_0 map_replicate_trivial
replicate_append_same)

lemma Bernstein_coeffs_01_1: "Bernstein_coeffs_01 p 1 = replicate (p+1) 1"
proof -
have "Bernstein_coeffs_01 p 1 =
map (λj. inverse (real (p choose j)) *
coeff (∑k≤p. smult (real (p choose k)) ([:0, 1:] ^ k)) (p - j)) [0..<(p+1)]"
by (auto simp: Bernstein_coeffs_01_def reciprocal_1 monom_altdef
hom_distribs pcompose_pCons poly_0_coeff_0[symmetric] poly_binomial)
also have "... = map (λj. inverse (real (p choose j)) *
real (p choose (p - j))) [0..<(p+1)]"
by (auto simp: monom_altdef[symmetric] coeff_sum binomial)
also have "... = map (λj. 1) [0..<(p+1)]"
apply (rule map_cong)
subgoal by argo
subgoal apply (subst binomial_symmetric)
by auto
done
also have "... = replicate (p+1) 1"
by (auto simp: map_replicate_trivial replicate_append_same)
finally show ?thesis .
qed

lemma Bernstein_coeffs_01_x: assumes "p ≠ 0"
shows "Bernstein_coeffs_01 p (monom 1 1) = [i/p. i ← [0..<(p+1)]]"
proof -
have
"Bernstein_coeffs_01 p (monom 1 1) = map (λj. inverse (real (p choose j)) *
coeff (monom 1 (p - Suc 0) ∘⇩p [:1, 1:]) (p - j)) [0..<(p+1)]"
using assms by (auto simp: Bernstein_coeffs_01_def reciprocal_monom)
also have
"... = map (λj. inverse (real (p choose j)) *
(∑k≤p - Suc 0. coeff (monom (real (p -  1 choose k)) k) (p - j))) [0..<(p+1)]"
by (auto simp: monom_altdef hom_distribs pcompose_pCons poly_binomial coeff_sum)
also have"... = map (λj. inverse (real (p choose j)) *
real (p -  1 choose (p - j))) [0..<(p+1)]"
by auto
also have "... = map (λj. j/p) [0..<(p+1)]"
proof (rule map_cong)
fix x assume "x ∈ set [0..<(p+1)]"
hence "x ≤ p" by force
thus "inverse (real (p choose x)) * real (p - 1 choose (p - x)) =
real x / real p"
proof (cases "x = 0")
show "x = 0 ⟹ ?thesis"
using assms by fastforce
assume 1: "x ≤ p" and 2: "x ≠ 0"
hence "p - x ≤ p - 1" by force
hence "(p - 1 choose (p - x)) = (p - 1 choose (x - 1))"
apply (subst binomial_symmetric)
using 1 2 by auto
hence "x * (p choose x) = p * (p - 1 choose (p - x))"
using 2 times_binomial_minus1_eq by simp
hence "real x * real (p choose x) = real p * real (p - 1 choose (p - x))"
by (metis of_nat_mult)
thus ?thesis using 1 2
by (auto simp: divide_simps)
qed
qed blast
finally show ?thesis .
qed

assumes "degree P ≤ p" and "degree Q ≤ p"
shows "nth_default 0 (Bernstein_coeffs_01 p (P + Q)) i =
nth_default 0 (Bernstein_coeffs_01 p P) i +
nth_default 0 (Bernstein_coeffs_01 p Q) i"
using assms by (auto simp: nth_default_Bernstein_coeffs_01 degree_add_le