Theory Rational_Function_Interpolation
section ‹Rational Function Interpolation›
theory Rational_Function_Interpolation
imports
"Poly_Lemmas"
"Gauss_Jordan.System_Of_Equations"
"Polynomial_Interpolation.Missing_Polynomial"
begin
subsection ‹Definitions›
text ‹General condition for rational functions interpolation›
definition interpolated_rational_function where
"interpolated_rational_function p⇩A p⇩B E f⇩A f⇩B d⇩A d⇩B ≡
(∀ e ∈ E. f⇩A e * poly p⇩B e = f⇩B e * poly p⇩A e) ∧
degree p⇩A ≤ (d⇩A::real) ∧ degree p⇩B ≤ (d⇩B::real) ∧
p⇩A ≠ 0 ∧ p⇩B ≠ 0"
text ‹Interpolation condition with given exact degrees›
definition monic_interpolated_rational_function where
"monic_interpolated_rational_function p⇩A p⇩B E f⇩A f⇩B d⇩A d⇩B ≡
(∀ e ∈ E. f⇩A e * poly p⇩B e = f⇩B e * poly p⇩A e) ∧
degree p⇩A = ⌊d⇩A::real⌋ ∧ degree p⇩B = ⌊d⇩B::real⌋ ∧
monic p⇩A ∧ monic p⇩B"
lemma monic0: "¬ monic (0::'a::zero_neq_one poly)"
by simp
lemma monic_interpolated_rational_function_interpolated_rational_function:
"monic_interpolated_rational_function p⇩A p⇩B E f⇩A f⇩B d⇩A d⇩B
⟹ interpolated_rational_function p⇩A p⇩B E f⇩A f⇩B d⇩A d⇩B ∨ ¬(p⇩A ≠ 0 ∧ p⇩B ≠ 0)"
unfolding monic_interpolated_rational_function_def interpolated_rational_function_def
by linarith
definition rfi_coefficient_matrix :: "'a::field list ⇒ ('a ⇒ 'a) ⇒ nat ⇒ nat
⇒ nat ⇒ nat ⇒ 'a" where
"rfi_coefficient_matrix E f d⇩A d⇩B i j = (
if j < d⇩A then
(E ! i) ^ j
else if j < d⇩A + d⇩B then
- f (E ! i) * (E ! i) ^ (j-d⇩A)
else 0
)"
definition rfi_constant_vector :: "'a::field list ⇒ ('a ⇒ 'a) ⇒ nat ⇒ nat ⇒ (nat ⇒ 'a)" where
"rfi_constant_vector E f d⇩A d⇩B = (λ i. f (E ! i) * (E ! i) ^ d⇩B - (E ! i) ^ d⇩A)"
definition rational_function_interpolation :: "'a::field list ⇒ ('a ⇒ 'a) ⇒ nat ⇒ nat
⇒ 'm::mod_type itself ⇒ ('a,'m) vec" where
"rational_function_interpolation E f d⇩A d⇩B m =
(let solved = solve
(χ (i::'m) (j::'m). rfi_coefficient_matrix E f d⇩A d⇩B (to_nat i) (to_nat j))
(χ (i::'m). rfi_constant_vector E f d⇩A d⇩B (to_nat i))
in fst (the solved))"
definition solution_to_poly :: "('a::finite_field, 'n::mod_type) vec ⇒
nat ⇒ nat ⇒ 'a poly × 'a poly" where
"solution_to_poly S d⇩A d⇩B = (let
p = Abs_poly (λi. if i < d⇩A then S $ (from_nat i) else 0) + monom 1 d⇩A;
q = Abs_poly (λi. if i < d⇩B then S $ (from_nat (i+d⇩A)) else 0) + monom 1 d⇩B in
(p, q))"
definition interpolate_rat_fun where
"interpolate_rat_fun E f d⇩A d⇩B m =
solution_to_poly (rational_function_interpolation E f d⇩A d⇩B m) d⇩A d⇩B"
subsection ‹Preliminary Results›
lemma consecutive_sum_combine:
assumes "m ≥ n"
shows "(∑i = 0..n. f i) + (∑i = Suc n ..m. f i) = (∑i = 0..m. f i)"
proof -
from assms have "{0..n} ∪ {Suc n..m} = {0..m}"
by auto
moreover have "sum f ({0..n} ∪ {Suc n..m}) =
sum f ({0..n} - {Suc n..m}) + sum f ({Suc n..m} - {0..n}) + sum f ({0..n} ∩ {Suc n..m})"
using sum_Un2 finite_atLeastAtMost by fast
ultimately show ?thesis
by (simp add: Diff_triv)
qed
lemma poly_altdef_Abs_poly_le:
fixes x :: "'a::{comm_semiring_0, semiring_1}"
shows "poly (Abs_poly (λi. if i ≤ n then f i else 0)) x = (∑i = 0..n. f i * x ^ i)"
proof -
let ?if⇩A0 = "(λi. if i ≤ n then f i else 0)"
let ?p = "Abs_poly ?if⇩A0"
have co: "coeff ?p = ?if⇩A0"
using coeff_Abs_poly_If_le by blast
then have "∀i>n. coeff ?p i = 0"
by auto
then have de: "degree ?p ≤ n"
using degree_le by blast
have "∀i>degree ?p. ?if⇩A0 i = 0"
using co coeff_eq_0 by fastforce
then have "∀i>degree ?p. ?if⇩A0 i * x ^ i = 0"
by simp
then have "∀ i ∈ {Suc (degree ?p)..n}. (?if⇩A0 i * x ^ i) = 0"
using less_eq_Suc_le by fastforce
then have db: "(∑i = Suc (degree ?p)..n. ?if⇩A0 i * x ^ i) = 0"
by simp
have "poly ?p x = (∑i≤degree ?p. coeff ?p i * x ^ i)"
using poly_altdef by auto
also have "… = (∑i≤degree ?p. ?if⇩A0 i * x ^ i) "
using co by simp
also have "… = (∑i = 0..degree ?p. ?if⇩A0 i * x ^ i) "
using atMost_atLeast0 by simp
also have "… = (∑i = 0..degree ?p. ?if⇩A0 i * x ^ i) +
(∑i = Suc (degree ?p)..n. ?if⇩A0 i * x ^ i)"
using db by simp
also have "… = (∑i = 0..n. ?if⇩A0 i * x ^ i)"
using consecutive_sum_combine de by blast
finally show ?thesis
by simp
qed
lemma poly_altdef_Abs_poly_l:
fixes x :: "'a::{comm_semiring_0,semiring_1}"
shows "poly (Abs_poly (λi. if i < n then f i else 0)) x = (∑i<n. f i * x ^ i)"
proof (cases "n")
case 0
have p0: "Abs_poly (λi. 0) = 0"
using zero_poly_def by fastforce
show ?thesis
using 0 by (simp add: p0)
next
case (Suc m)
have "poly (Abs_poly (λi. if i ≤ m then f i else 0)) x = (∑i = 0..m. f i * x ^ i)"
using poly_altdef_Abs_poly_le by blast
moreover have "poly (Abs_poly (λi. if i ≤ m then f i else 0)) x = poly (Abs_poly (λi. if i < n then f i else 0)) x "
using Suc using less_Suc_eq_le by auto
moreover have "(∑i = 0..m. f i * x ^ i) = (∑i<n. f i * x ^ i)"
using Suc atLeast0AtMost lessThan_Suc_atMost by presburger
ultimately show ?thesis by argo
qed
lemma degree_Abs_poly_If_l:
assumes "n ≠ 0"
shows "degree (Abs_poly (λi. if i < n then f i else 0)) < n"
proof -
have "coeff (Abs_poly (λi. if i < n then f i else 0)) x = 0" if "x ≥ n" for x
using coeff_Abs_poly [of n "(λi. if i < n then f i else 0)"] using that by simp
then show ?thesis
using assms degree_lessI by blast
qed
lemma nth_less_length_in_set_eq:
shows "(∀ i < length E. f (E ! i) = g (E ! i)) ⟷ (∀ e ∈ set E. f e = g e)"
proof standard
show "∀i < length E. f (E ! i) = g (E ! i) ⟹ ∀e∈set E. f e = g e"
using in_set_conv_nth by metis
next
show "∀e∈set E. f e = g e ⟹ ∀i<length E. f (E ! i) = g (E ! i)"
by simp
qed
lemma nat_leq_real_floor: "real (i::nat) ≤ (d::real) ⟷ real i ≤ ⌊d⌋" (is "?l = ?r")
proof
assume ?l
then show ?r
using floor_mono by fastforce
next
assume ?r
then show ?l
by linarith
qed
lemma mod_type_less_function_eq:
fixes i :: "'a::mod_type"
assumes "∀ i < CARD('a) . f i = g i"
shows "f (to_nat i) = g (to_nat i)"
using assms by (simp add: to_nat_less_card)
subsection ‹On @{term "solution_to_poly"}›
lemma fst_solution_to_poly_nz:
"fst (solution_to_poly S d⇩A d⇩B) ≠ 0"
proof
assume "fst (solution_to_poly S d⇩A d⇩B) = 0"
hence "coeff (Abs_poly (λi. if i < d⇩A then S $ (from_nat i) else 0) + monom 1 d⇩A) d⇩A = 0"
unfolding solution_to_poly_def by simp
hence "coeff (Abs_poly (λi. if i < d⇩A then S $ (from_nat i) else 0)) d⇩A + 1 = 0" by simp
thus "False" by (subst (asm) coeff_Abs_poly[where n="d⇩A"]) auto
qed
lemma snd_solution_to_poly_nz:
"snd (solution_to_poly S d⇩A d⇩B) ≠ 0"
proof
assume "snd (solution_to_poly S d⇩A d⇩B) = 0"
hence "coeff (Abs_poly (λi. if i < d⇩B then S $ (from_nat (i+d⇩A)) else 0) + monom 1 d⇩B) d⇩B = 0"
unfolding solution_to_poly_def by simp
hence "coeff (Abs_poly (λi. if i < d⇩B then S $ (from_nat (i+d⇩A)) else 0)) d⇩B + 1 = 0" by simp
thus "False" by (subst (asm) coeff_Abs_poly[where n="d⇩B"]) auto
qed
lemma degree_Abs0p1: "degree (Abs_poly (λi. 0) + 1) = 0"
by (metis add_0 degree_1 zero_poly_def)
lemma degree_solution_to_poly_fst:
"degree (fst (solution_to_poly S d⇩A d⇩B)) = d⇩A"
proof (cases d⇩A)
case 0
then show ?thesis unfolding solution_to_poly_def
using degree_Abs0p1 by (simp add: one_pCons)
next
case (Suc nat)
then have "degree (Abs_poly (λi. if i < d⇩A then S $ from_nat i else 0)) < d⇩A"
using degree_Abs_poly_If_l by fast
moreover have "… = degree (monom (1::'a) d⇩A)"
by (simp add: degree_monom_eq)
ultimately show ?thesis
unfolding solution_to_poly_def
by (simp add: degree_add_eq_right)
qed
lemma degree_solution_to_poly_snd:
"degree (snd (solution_to_poly S d⇩A d⇩B)) = d⇩B"
proof (cases d⇩B)
case 0
then show ?thesis unfolding solution_to_poly_def
using degree_Abs0p1 by (simp add: one_pCons)
next
case (Suc nat)
then have "degree (Abs_poly (λi. if i < d⇩B then S $ from_nat (i + d⇩A) else 0)) < d⇩B"
using degree_Abs_poly_If_l by fast
moreover have "… = degree (monom (1::'a) d⇩B)"
by (simp add: degree_monom_eq)
ultimately show ?thesis
unfolding solution_to_poly_def
by (simp add: degree_add_eq_right)
qed
lemma monic_solution_to_poly_snd:
"monic (snd (solution_to_poly S d⇩A d⇩B))"
proof (cases d⇩B)
case 0
then show ?thesis unfolding solution_to_poly_def
by (simp add: coeff_Abs_poly degree_Abs0p1)
next
case (Suc x)
have 1: "coeff (Abs_poly (λi. if i < Suc x then S $ from_nat (i + d⇩A) else 0)) (Suc x) = 0"
by (simp add: coeff_eq_0 degree_Abs_poly_If_l)
have "degree (Abs_poly (λi. if i < d⇩B then S $ from_nat (i + d⇩A) else 0) + monom 1 d⇩B) = d⇩B"
using degree_solution_to_poly_snd unfolding solution_to_poly_def by auto
then show ?thesis
unfolding solution_to_poly_def using 1 Suc by simp
qed
lemma monic_solution_to_poly_fst:
"monic (fst (solution_to_poly S d⇩A d⇩B))"
proof (cases d⇩A)
case 0
then show ?thesis
unfolding solution_to_poly_def by (simp add: coeff_Abs_poly degree_Abs0p1)
next
case (Suc x)
have 1: "coeff (Abs_poly (λi. if i < d⇩A then S $ (from_nat i) else 0)) (Suc x) = 0"
by (simp add: Suc coeff_eq_0 degree_Abs_poly_If_l)
have "degree (Abs_poly (λi. if i < d⇩A then S $ (from_nat i) else 0) + monom 1 d⇩A) = d⇩A"
using degree_solution_to_poly_fst unfolding solution_to_poly_def by auto
then show ?thesis
unfolding solution_to_poly_def using 1 Suc by simp
qed
subsection "Correctness"
text ‹Needs the assumption that the system is consistent, because a solution exists.›
lemma rational_function_interpolation_correct_poly:
assumes
"∀ x ∈ set E. f x = f⇩A x / f⇩B x" "∀ x ∈ set E. f⇩B x ≠ 0"
"d⇩A + d⇩B ≤ length E"
"CARD('m::mod_type) = length E"
"consistent (χ (i::'m) (j::'m). rfi_coefficient_matrix E f d⇩A d⇩B (to_nat i) (to_nat j))
(χ (i::'m). rfi_constant_vector E f d⇩A d⇩B (to_nat i))"
"S = rational_function_interpolation E f d⇩A d⇩B TYPE('m)"
"p⇩A = fst (solution_to_poly S d⇩A d⇩B)"
"p⇩B = snd (solution_to_poly S d⇩A d⇩B)"
shows
"∀ e ∈ set E. f⇩A e * poly p⇩B e = f⇩B e * poly p⇩A e"
proof -
let ?coeff = "rfi_coefficient_matrix E f d⇩A d⇩B"
let ?const = "rfi_constant_vector E f d⇩A d⇩B"
let ?coeff' = "(χ (i::'m) (j::'m). ?coeff (to_nat i) (to_nat j))"
let ?const' = "(χ (i::'m). ?const (to_nat i))"
have "is_solution S ?coeff' ?const'"
by (simp add: assms(5,6) consistent_imp_is_solution_solve rational_function_interpolation_def)
then have sol: "?coeff' *v S = ?const'"
by (simp add: is_solution_def)
have const: "?const i = ?const' $ from_nat i" if "i < length E" for i
by (simp add: assms(4) that to_nat_from_nat_id)
have coeff: "?coeff i j = ?coeff' $ from_nat i $ from_nat j"
if "i < length E" "j < length E" for i j
proof -
have "to_nat (from_nat i ::'m) = i"
using that assms(4)
by (intro to_nat_from_nat_id) simp
moreover have "to_nat (from_nat j ::'m) = j"
using that assms(4,3)
by (intro to_nat_from_nat_id) simp
ultimately show ?thesis
unfolding rfi_coefficient_matrix_def
by (simp add: Let_def)
qed
have x: "(∑j < d⇩A + d⇩B. (?coeff i j) * S $ (from_nat j)) = ?const i"
(is "?l = ?r") if "i < length E" for i
proof -
have "?l = (∑j < length E. ?coeff i j * S $ (from_nat j))"
using assms(3) by (intro sum.mono_neutral_cong_left) (auto simp add:rfi_coefficient_matrix_def)
also have "... = (∑j < length E. ?coeff' $ (from_nat i) $ (from_nat j) * S $ (from_nat j))"
using coeff that by auto
also have "… = (∑j ∈ {0..< length E}. ?coeff' $ (from_nat i) $ (from_nat j) * S $ (from_nat j))"
by (intro sum.reindex_bij_betw [symmetric] bij_betwI [where g = id]) auto
also have "… = (∑j∈(UNIV::'m set). ?coeff' $ (from_nat i) $ j * S $ j)"
using bij_from_nat [where 'a = 'm] assms(3,4) by (intro sum.reindex_bij_betw) simp
also have "… = (?coeff' *v S) $ (from_nat i)"
unfolding matrix_vector_mult_def by simp
also have "… = ?const' $ (from_nat i)"
using sol by simp
finally show "?l = ?r" using const that by simp
qed
let ?p_lam = "λi. if i < d⇩A then S $ from_nat i else 0"
let ?q_lam = "λi. if i < d⇩B then S $ from_nat (i + d⇩A) else 0"
let ?p' = "Abs_poly ?p_lam + monom 1 d⇩A"
let ?q' = "Abs_poly ?q_lam + monom 1 d⇩B"
have pq: "p⇩A = ?p'" "p⇩B = ?q'"
using assms(7,8) unfolding solution_to_poly_def by auto
have "(∑j<d⇩A. S $ from_nat j * E ! i ^ j) - f (E ! i) * (∑j<d⇩B. S $ from_nat (j + d⇩A) * E ! i ^ j)
= f (E ! i) * E ! i ^ d⇩B - E ! i ^ d⇩A" if "i < length E" for i
proof -
let ?pq_lam = "(λj. (if j < d⇩A then E ! i ^ j else
if j < d⇩A + d⇩B then - f (E ! i) * E ! i ^ (j - d⇩A) else 0) * S $ from_nat j)"
have reindex: "(∑j ∈ {d⇩A..< d⇩A + d⇩B}. - f (E ! i) * E ! i ^ (j - d⇩A) * S $ from_nat j) =
(∑j ∈ {0..< d⇩B}. - f (E ! i) * E ! i ^ (j) * S $ from_nat (j+d⇩A))"
by (rule sum.reindex_bij_witness [of _ "λi. i + d⇩A" "λi. i - d⇩A"]) auto
from x have "f (E ! i) * E ! i ^ d⇩B - E ! i ^ d⇩A = (∑j<d⇩A + d⇩B. ?pq_lam j )"
unfolding rfi_coefficient_matrix_def rfi_constant_vector_def using that by simp
also have "… = (∑j ∈ {0..< d⇩A + d⇩B}. ?pq_lam j)"
using atLeast0LessThan by presburger
also have "… = (∑j ∈ {0..< d⇩A}. ?pq_lam j) + (∑j ∈ {d⇩A..< d⇩A + d⇩B}. ?pq_lam j) "
by (subst sum.atLeastLessThan_concat) auto
also have "… = (∑j ∈ {0..< d⇩A}. E ! i ^ j * S $ from_nat j) +
(∑j ∈ {d⇩A..< d⇩A + d⇩B}. - f (E ! i) * E ! i ^ (j - d⇩A) * S $ from_nat j)"
by auto
also have "… = (∑j ∈ {0..< d⇩A}. E ! i ^ j * S $ from_nat j) +
(∑j ∈ {0..< d⇩B}. - f (E ! i) * E ! i ^ (j) * S $ from_nat (j+d⇩A))"
using reindex by simp
also have "… = (∑j ∈ {0..< d⇩A}. E ! i ^ j * S $ from_nat j) +
- f (E ! i) * (∑j ∈ {0..< d⇩B}. E ! i ^ (j) * S $ from_nat (j+d⇩A))"
by (simp add: sum_distrib_left mult.commute mult.left_commute)
finally have "f (E ! i) * E ! i ^ d⇩B - E ! i ^ d⇩A = …"
by argo
moreover have "(∑j ∈ {0..< d⇩A}. E ! i ^ j * S $ from_nat j) =
(∑j<d⇩A. S $ from_nat j * E ! i ^ j)"
by (subst atLeast0LessThan) (meson mult.commute)
moreover have "(∑j ∈ {0..< d⇩B}. E ! i ^ (j) * S $ from_nat (j+d⇩A)) =
(∑j<d⇩B. S $ from_nat (j + d⇩A) * E ! i ^ j)"
by (subst atLeast0LessThan) (meson mult.commute)
ultimately show ?thesis
by simp
qed
then have "∀e ∈ set E. (∑j<d⇩A. S $ from_nat j * e ^ j) - f e * (∑j<d⇩B. S $ from_nat (j + d⇩A) * e ^ j)
= f e * e ^ d⇩B - e ^ d⇩A"
by (subst nth_less_length_in_set_eq [symmetric]) auto
then have "(∑i<d⇩A. S $ from_nat i * e ^ i) - f e * (∑i<d⇩B. S $ from_nat (i + d⇩A) * e ^ i)
= f e * e ^ d⇩B - e ^ d⇩A" if "e ∈ set E" for e
using that by blast
then have "(∑i<d⇩A. S $ from_nat i * e ^ i) + e ^ d⇩A
= f e * e ^ d⇩B + f e * (∑i<d⇩B. S $ from_nat (i + d⇩A) * e ^ i)" if "e ∈ set E" for e
using that by (simp add:field_simps)
then have "f e * ((∑i<d⇩B. S $ from_nat (i + d⇩A) * e ^ i) + e ^ d⇩B) =
(∑i<d⇩A. S $ from_nat i * e ^ i) + e ^ d⇩A" if "e ∈ set E" for e
using that by (simp add: ring_class.ring_distribs(1))
then have "f e * (poly (Abs_poly ?q_lam) e + poly (monom 1 d⇩B) e) =
poly (Abs_poly ?p_lam) e + poly (monom 1 d⇩A) e" if "e ∈ set E" for e
unfolding poly_altdef_Abs_poly_l poly_monom using that by auto
then have "f e * (poly (Abs_poly ?q_lam) e + poly (monom 1 d⇩B) e) =
poly (Abs_poly ?p_lam) e + poly (monom 1 d⇩A) e" if "e ∈ set E" for e
using that by simp
then have "f e * poly (Abs_poly ?q_lam + monom 1 d⇩B) e =
poly (Abs_poly ?p_lam + monom 1 d⇩A) e" if "e ∈ set E" for e
by (simp add: that)
then have "(f⇩A e / f⇩B e) * poly ?q' e = poly ?p' e" if "e ∈ set E" for e
using that assms(1) by simp
then have "f⇩A e * poly ?q' e = f⇩B e * poly ?p' e" if "e ∈ set E" for e
using that by (simp add: assms(2) nonzero_divide_eq_eq)
then have "∀e∈set E. f⇩A e * poly (snd (solution_to_poly S d⇩A d⇩B)) e =
f⇩B e * poly (fst (solution_to_poly S d⇩A d⇩B)) e"
unfolding solution_to_poly_def by auto
then show "∀e∈set E. f⇩A e * poly p⇩B e = f⇩B e * poly p⇩A e"
using assms(8,7) by simp
qed
lemma :
"poly p x = (∑i<degree p. coeff p i * x ^ i) + lead_coeff p * x ^ degree p"
for x :: "'a::{comm_semiring_0,semiring_1}"
unfolding poly_altdef using lessThan_Suc_atMost sum.lessThan_Suc by auto
lemma d⇩A_d⇩B_helper:
assumes
"finite A" "finite B"
"int d⇩A = ⌊(real (length E) + card A - card B)/2⌋"
"int d⇩B = ⌊(real (length E) + card B - card A)/2⌋"
"card (sym_diff A B) ≤ length E"
shows
"d⇩A + d⇩B ≤ length E"
"card (A - B) ≤ d⇩A" "card (B - A) ≤ d⇩B"
"d⇩B - card (B - A) = d⇩A - card (A - B)"
proof -
have a: "real d⇩A = of_int ⌊(real (length E) + card A - card B)/2⌋"
using assms(3) by simp
have b: "real d⇩B = of_int ⌊(real (length E) + card B - card A)/2⌋"
using assms(4) by simp
have "real d⇩A + real d⇩B ≤ (real (length E)+card A-card B)/2 + (real (length E)+card B-card A)/2"
unfolding a b by (intro add_mono) linarith+
also have "… = real (length E)" by argo
finally have "real d⇩A + real d⇩B ≤ length E" by simp
thus "d⇩A + d⇩B ≤ length E" by simp
have "real (card (A - B)) = (real (card (sym_diff A B)) + real (card A) - real (card B))/2"
unfolding card_sym_diff_finite[OF assms(1,2)] using card_sub_int_diff_finite[OF assms(1,2)]
by simp
also have "… ≤ (real (length E) + real (card A) - real (card B))/2"
using assms(5) by simp
finally have "real (card (A-B)) ≤ d⇩A"
unfolding a using nat_leq_real_floor by blast
thus c:"card (A-B) ≤ d⇩A" by auto
have "real (card (B - A)) = (real (card (sym_diff A B)) + real (card B) - real (card A))/2"
unfolding card_sym_diff_finite[OF assms(1,2)] using card_sub_int_diff_finite[OF assms(1,2)]
by simp
also have "… ≤ (real (length E) + real (card B) - real (card A))/2"
using assms(5) by simp
finally have "real (card (B-A)) ≤ d⇩B"
unfolding b using nat_leq_real_floor by blast
thus d:"card (B-A) ≤ d⇩B" by auto
have "real d⇩B - real d⇩A =
of_int ⌊(real (length E) - card B - card A)/2 + real (card B)⌋ -
of_int ⌊(real (length E) - card A - card B)/2 + real (card A)⌋"
unfolding a b by argo
also have "… = real (card B) - real (card A)"
by (simp add:algebra_simps)
also have "… = real (card (B - A)) - card (A - B)"
using card_sub_int_diff_finite[OF assms(1,2)] by simp
finally have "real d⇩B - real d⇩A = real (card (B - A)) - card (A - B)"
by simp
thus "d⇩B - card (B - A) = d⇩A - card (A - B)"
using c d by simp
qed
text "Insert the solution we know that must exist to show it's consistent"
lemma rational_function_interpolation_consistent:
fixes A B :: "'a::finite_field set"
assumes
"∀ x ∈ (set E). f x = f⇩A x / f⇩B x"
"CARD('m::mod_type) = length E"
"d⇩A + d⇩B ≤ length E"
"card (A - B) ≤ d⇩A"
"card (B - A) ≤ d⇩B"
"d⇩B - card (B - A) = d⇩A - card (A - B)"
"∀ x ∈ set E. x ∉ A" "∀ x ∈ set E. x ∉ B"
"f⇩A = (λ x ∈ set E. poly (set_to_poly A) x)"
"f⇩B = (λ x ∈ set E. poly (set_to_poly B) x)"
shows
"consistent (χ (i::'m) (j::'m). rfi_coefficient_matrix E f d⇩A d⇩B (to_nat i) (to_nat j))
(χ (i::'m). rfi_constant_vector E f d⇩A d⇩B (to_nat i))"
proof -
let ?coeff = "rfi_coefficient_matrix E f d⇩A d⇩B"
let ?const = "rfi_constant_vector E f d⇩A d⇩B"
let ?coeff' = "(χ (i::'m) (j::'m). ?coeff (to_nat i) (to_nat j))"
let ?const' = "(χ (i::'m). ?const (to_nat i))"
define sp where "sp = set_to_poly (A-B) * monom 1 (d⇩A - card (A-B))"
define sq where "sq = set_to_poly (B-A) * monom 1 (d⇩B - card (B-A))"
let ?x = "(χ (i::'m). if (to_nat i) < d⇩A then coeff sp (to_nat i) else coeff sq (to_nat i - d⇩A))"
have poly_mul_eq: "f⇩A x * poly sq x = f⇩B x * poly sp x" if "x ∈ set E" for x
proof -
have "set_to_poly A * set_to_poly (B - A) = (set_to_poly B) * set_to_poly (A - B)"
by (simp add: Un_commute set_to_poly_mult_distinct)
then have "(set_to_poly A * set_to_poly (B - A) * monom 1 (d⇩B - card (B - A)) =
(set_to_poly B) * set_to_poly (A - B) * monom 1 (d⇩A - card (A - B)))"
using assms(6) by argo
hence "poly (set_to_poly A) x * poly (set_to_poly (B - A) * monom 1 (d⇩B - card (B - A))) x =
poly (set_to_poly B) x * poly (set_to_poly (A - B) * monom 1 (d⇩A - card (A - B))) x"
by (metis (no_types, lifting) mult.commute mult.left_commute poly_mult)
thus ?thesis
using that unfolding assms sp_def sq_def by simp
qed
have x_sol_raw: "(∑j ∈ {0..<d⇩A}. e ^ j * coeff sp j ) + (∑j ∈ {0..<d⇩B}. - f e * e ^ j * (coeff sq j))
= f e * e ^ d⇩B - e ^ d⇩A" if "e ∈ set E" for e
proof -
have f⇩Az: "f⇩A e ≠ 0"
using assms (7,9) in_set_to_poly that by auto
moreover have f⇩Bz: "f⇩B e ≠ 0"
using assms (8,10) in_set_to_poly that by auto
ultimately have fz: "f e ≠ 0"
using that assms(1) by simp
have ff⇩B: "f e = f⇩A e / f⇩B e"
using that assms(1) by simp
have "lead_coeff sp = 1"
unfolding sp_def lead_coeff_mult using set_to_poly_lead_coeff lead_coeff_monom
by (auto simp add: degree_monom_eq)
moreover have "degree sp = d⇩A"
unfolding sp_def using assms(4)
by (simp add: add_diff_inverse_nat degree_monom_eq degree_mult_eq order_less_imp_not_less set_to_poly_degree)
ultimately have poly_sp: "poly sp e = (∑i<d⇩A. coeff sp i * e ^ i) + e ^ d⇩A" for e
unfolding poly_lead_coeff_extract by simp
have "lead_coeff sq = 1"
unfolding sq_def lead_coeff_mult using set_to_poly_lead_coeff lead_coeff_monom
by (auto simp add: degree_monom_eq)
moreover have "degree sq = d⇩B"
using assms(5) unfolding sq_def
by (simp add: degree_monom_eq degree_mult_eq le_eq_less_or_eq set_to_poly_degree)
ultimately have poly_sq: "poly sq e = (∑i<d⇩B. coeff sq i * e ^ i) + e ^ d⇩B" for e
unfolding poly_lead_coeff_extract by simp
have "f⇩B e * ((∑i = 0..<d⇩A. coeff sp i * e ^ i) + e ^ d⇩A) =
f⇩A e * ((∑i = 0..<d⇩B. coeff sq i * e ^ i) + e ^ d⇩B)"
using that poly_mul_eq unfolding poly_sq poly_sp lessThan_atLeast0 by simp
then have "f⇩B e * ((∑j = 0..<d⇩A. e ^ j * coeff sp j) + e ^ d⇩A) =
f⇩A e * ((∑j = 0..<d⇩B. e ^ j * coeff sq j) + e ^ d⇩B)"
by (metis (lifting) Finite_Cartesian_Product.sum_cong_aux mult.commute)
then have "(∑j = 0..<d⇩A. e ^ j * coeff sp j) + e ^ d⇩A =
f e * ((∑j = 0..<d⇩B. e ^ j * coeff sq j) + e ^ d⇩B)"
unfolding ff⇩B using f⇩Bz
by (metis (no_types, lifting) f⇩Bz nonzero_mult_div_cancel_left times_divide_eq_left)
also have "… = f e * (∑j = 0..<d⇩B. e ^ j * coeff sq j) + f e * e ^ d⇩B"
by algebra
also have "… = (∑j = 0..<d⇩B. f e * e ^ j * coeff sq j) + f e * e ^ d⇩B"
by (metis (no_types, lifting) Finite_Cartesian_Product.sum_cong_aux mult.assoc sum_distrib_left)
finally have "(∑j = 0..<d⇩A. e ^ j * coeff sp j) + e ^ d⇩A =
(∑j = 0..<d⇩B. f e * e ^ j * coeff sq j) + f e * e ^ d⇩B"
by argo
then have "(∑j = 0..<d⇩A. e ^ j * coeff sp j) =
(∑j = 0..<d⇩B. f e * e ^ j * coeff sq j) + f e * e ^ d⇩B - e ^ d⇩A"
using add_implies_diff by blast
then have "(∑j = 0..<d⇩A. e ^ j * coeff sp j) + (- (∑j = 0..<d⇩B. f e * e ^ j * coeff sq j)) =
f e * e ^ d⇩B - e ^ d⇩A"
by auto
moreover have "- (∑j = 0..<d⇩B. f e * e ^ j * (coeff sq j)) =
(∑j = 0..<d⇩B. - f e * e ^ j * coeff sq j)"
using sum_negf [symmetric] by auto
ultimately show ?thesis
by argo
qed
let ?const_lam = "λe. f e * e ^ d⇩B - e ^ d⇩A"
let ?const_lam' = "λi. ?const_lam (E ! i)"
let ?coeff_lam = "λe j.(if j < d⇩A then e ^ j
else if j < d⇩A + d⇩B
then - f e * e ^ ( j - d⇩A) else 0) *
(if j < d⇩A then coeff sp j else coeff sq (j- d⇩A))"
let ?coeff_lam' = "λi . ?coeff_lam (E ! i)"
have "(∑j ∈ {0..<length E}. ?coeff_lam e j) = ?const_lam e" if "e ∈ set E" for e
proof -
have "(∑j ∈ {0..<length E}. ?coeff_lam e j) = (∑j ∈ {0..<d⇩A + d⇩B}. ?coeff_lam e j)"
using assms(3) by (intro sum.mono_neutral_cong_right) auto
also have "… = (∑j∈{0..<d⇩A}. e^j * coeff sp j) + (∑j ∈ {0..<d⇩B}. -f e * e^j*(coeff sq j))"
proof -
have "(∑j ∈ {0..<d⇩A + d⇩B}. ?coeff_lam e j) =
(∑j ∈ {0..<d⇩A}. ?coeff_lam e j) + (∑j ∈ {d⇩A..<d⇩A + d⇩B}. ?coeff_lam e j) "
by (intro sum.atLeastLessThan_concat [symmetric]) auto
also have "… = (∑j ∈ {0..<d⇩A}. e ^ j * coeff sp j ) +
(∑j ∈ {d⇩A..<d⇩A + d⇩B}. - f e * e ^ (j - d⇩A) * (coeff sq (j-d⇩A))) "
by simp
moreover have "(∑j ∈ {d⇩A..<d⇩A + d⇩B}. - f e * e ^ (j - d⇩A) * (coeff sq (j-d⇩A))) =
(∑j ∈ {0..<d⇩B}. - f e * e ^ (j) * (coeff sq j))"
by (rule sum.reindex_bij_witness [of _ "λi. i + d⇩A" "λi. i - d⇩A"]) auto
ultimately show ?thesis
by simp
qed
also have "… = ?const_lam e"
using that x_sol_raw by simp
finally show ?thesis by simp
qed
then have "(∑j ∈ {0..<length E}. ?coeff_lam' i j) = ?const_lam' i" if "i < length E" for i
using that by simp
moreover have "(∑j∈(UNIV::'m set). ?coeff_lam i (to_nat j)) = (∑j ∈ {0..<CARD('m)}. ?coeff_lam i j)" for i
using bij_to_nat by (intro sum.reindex_bij_betw) blast
ultimately have "(∑j∈(UNIV::'m set). ?coeff_lam' i (to_nat j)) = ?const_lam' i" if "i < length E" for i
using that assms using of_nat_eq_iff[of "card top" "length E"] assms(3) by force
then have "(λi. ∑j∈(UNIV::'m set). ?coeff_lam' i (to_nat j)) (to_nat (i::'m)) = ?const_lam' (to_nat i)" for i
using mod_type_less_function_eq [of "(λi. ∑j∈(UNIV::'m set). ?coeff_lam' i (to_nat j))" ?const_lam' i]
using assms(2) assms(3) by auto
then have eval: "(λi. ∑j∈(UNIV::'m set). ?coeff_lam' (to_nat (i::'m)) (to_nat j)) =
(λ i. ?const_lam' (to_nat i))"
by simp
have "?coeff' *v ?x = ?const'"
unfolding matrix_vector_mult_def
rfi_coefficient_matrix_def
rfi_constant_vector_def
using eval by simp
then show ?thesis
unfolding consistent_def is_solution_def by auto
qed
subsection ‹Main lemma›
lemma rational_function_interpolation_correct:
assumes
"int d⇩A = ⌊(real (length E) + card A - card B)/2⌋"
"int d⇩B = ⌊(real (length E) + card B - card A)/2⌋"
"card (sym_diff A B) ≤ length E"
"∀ x ∈ set E. x ∉ A" "∀ x ∈ set E. x ∉ B"
"f⇩A = (λ x ∈ set E. poly (set_to_poly A) x)"
"f⇩B = (λ x ∈ set E. poly (set_to_poly B) x)"
"CARD('m::mod_type) = length E"
defines
"sol ≡ solution_to_poly (rational_function_interpolation E (λe. f⇩A e / f⇩B e) d⇩A d⇩B TYPE('m)) d⇩A d⇩B"
shows
"monic_interpolated_rational_function (fst sol) (snd sol) (set E) f⇩A f⇩B d⇩A d⇩B"
proof -
let ?f = "(λe. f⇩A e / f⇩B e)"
let ?S = "rational_function_interpolation E (λe. f⇩A e / f⇩B e) d⇩A d⇩B TYPE('m)"
let ?p = "fst (solution_to_poly ?S d⇩A d⇩B)"
let ?q = "snd (solution_to_poly ?S d⇩A d⇩B)"
have f:"finite A" "finite B"
using finite by blast+
note pd_pq_props = d⇩A_d⇩B_helper[OF f assms(1-3)]
have "consistent (χ (i::'m) (j::'m). rfi_coefficient_matrix E ?f d⇩A d⇩B (to_nat i) (to_nat j))
(χ (i::'m). rfi_constant_vector E ?f d⇩A d⇩B (to_nat i))"
using assms pd_pq_props
by (intro rational_function_interpolation_consistent [where A = A and B = B and f⇩A = f⇩A and f⇩B = f⇩B])
auto
then have "∀e∈set E. f⇩A e * poly ?q e = f⇩B e * poly ?p e"
using assms pd_pq_props(1) in_set_to_poly
by (intro rational_function_interpolation_correct_poly [where f = ?f and d⇩A = d⇩A and d⇩B = d⇩B and S = ?S])
auto
moreover have "real (degree ?p) = real d⇩A"
using degree_solution_to_poly_fst by auto
moreover have "real (degree ?q) = real d⇩B"
using degree_solution_to_poly_snd by auto
moreover have "monic ?q"
using monic_solution_to_poly_snd by auto
moreover have "monic ?p"
using monic_solution_to_poly_fst by auto
ultimately show ?thesis using fst_solution_to_poly_nz snd_solution_to_poly_nz
unfolding monic_interpolated_rational_function_def sol_def by force
qed
lemma interpolated_rational_function_floor_eq:
"interpolated_rational_function p⇩A p⇩B E f⇩A f⇩B d⇩A d⇩B ⟷
interpolated_rational_function p⇩A p⇩B E f⇩A f⇩B ⌊d⇩A⌋ ⌊d⇩B⌋"
unfolding interpolated_rational_function_def using nat_leq_real_floor by simp
lemma sym_diff_bound_div2_ge0:
fixes A B :: "'a :: finite set"
assumes "card (sym_diff A B) ≤ length E"
shows "(real (length E) + card A - card B)/2 ≥ 0"
proof -
have *: "finite A" "finite B" using finite by auto
have "0 ≤ real (card (sym_diff A B)) + real (card (A-B)) - (card (B-A))"
unfolding card_sym_diff_finite[OF *] by simp
also have "… ≤ real (length E) + real (card (A-B)) - (card (B-A))"
using assms(1) by simp
also have "… = (real (length E) + card A - card B)"
using card_sub_int_diff_finite [OF *] by simp
finally show ?thesis by simp
qed
text "If the degrees are reals we take the floor first"
lemma rational_function_interpolation_correct_real:
fixes d'⇩A d'⇩B:: "real"
assumes
"card (sym_diff A B) ≤ length E"
"∀ x ∈ set E. x ∉ A" "∀ x ∈ set E. x ∉ B"
"f⇩A = (λ x ∈ set E. poly (set_to_poly A) x)"
"f⇩B = (λ x ∈ set E. poly (set_to_poly B) x)"
"CARD('m::mod_type) = length E"
defines "d'⇩A ≡ (real (length E) + card A - card B)/2"
defines "d'⇩B ≡ (real (length E) + card B - card A)/2"
defines "d⇩A ≡ nat ⌊d'⇩A⌋"
defines "d⇩B ≡ nat ⌊d'⇩B⌋"
defines "sol_poly ≡ interpolate_rat_fun E (λe. f⇩A e / f⇩B e) d⇩A d⇩B TYPE('m)"
shows
"monic_interpolated_rational_function (fst sol_poly) (snd sol_poly) (set E) f⇩A f⇩B d'⇩A d'⇩B"
proof -
have e: "d'⇩A ≥ 0"
unfolding d'⇩A_def using sym_diff_bound_div2_ge0 assms(1) by auto
hence a: "int d⇩A = ⌊(real (length E) + real (card A) - real (card B)) / 2⌋"
using d'⇩A_def unfolding d⇩A_def by simp
have f: "d'⇩B ≥ 0"
unfolding d'⇩B_def using sym_diff_bound_div2_ge0 assms(1) by (metis Un_commute)
hence b: "int d⇩B = ⌊(real (length E) + real (card B) - real (card A)) / 2⌋"
using d'⇩B_def unfolding d⇩B_def by simp
have c: "monic_interpolated_rational_function (fst sol_poly) (snd sol_poly) (set E) f⇩A f⇩B d⇩A d⇩B"
unfolding sol_poly_def interpolate_rat_fun_def
by (intro rational_function_interpolation_correct [OF a b assms(1-6)])
moreover have "⌊d'⇩A⌋ = real (nat ⌊d'⇩A⌋)"
using e by (intro of_nat_nat[symmetric]) simp
moreover have "⌊d'⇩B⌋ = real (nat ⌊d'⇩B⌋)"
using f by (intro of_nat_nat[symmetric]) simp
ultimately have
"monic_interpolated_rational_function (fst sol_poly) (snd sol_poly) (set E) f⇩A f⇩B (nat ⌊d'⇩A⌋) (nat ⌊d'⇩B⌋)"
unfolding d⇩A_def d⇩B_def
by simp
thus ?thesis unfolding monic_interpolated_rational_function_def
using assms(9,10) a b d'⇩A_def d'⇩B_def floor_of_nat by simp
qed
end