Theory Polynomial_Transfer
section ‹Parametricity of polynomial operations›
theory Polynomial_Transfer
imports "HOL-Computational_Algebra.Polynomial"
begin
definition rel_poly :: "('a ⇒ 'b ⇒ bool) ⇒ 'a :: zero poly ⇒ 'b :: zero poly ⇒ bool" where
"rel_poly R p q ⟷ rel_fun (=) R (coeff p) (coeff q)"
lemma left_unique_rel_poly [transfer_rule]: "left_unique R ⟹ left_unique (rel_poly R)"
unfolding left_unique_def rel_poly_def poly_eq_iff rel_fun_def by meson
lemma right_unique_rel_poly [transfer_rule]: "right_unique R ⟹ right_unique (rel_poly R)"
unfolding right_unique_def rel_poly_def poly_eq_iff rel_fun_def by meson
lemma bi_unique_rel_poly [transfer_rule]: "bi_unique R ⟹ bi_unique (rel_poly R)"
unfolding bi_unique_def rel_poly_def poly_eq_iff rel_fun_def by meson
lemma rel_poly_swap: "rel_poly R x y ⟷ rel_poly (λy x. R x y) y x"
by (auto simp: rel_poly_def rel_fun_def)
lemma coeff_transfer [transfer_rule]:
"rel_fun (rel_poly R) (rel_fun (=) R) coeff coeff"
by (auto simp: rel_fun_def rel_poly_def)
lemma map_poly_transfer:
assumes "rel_fun R S f g" "f 0 = 0" "g 0 = 0"
shows "rel_fun (rel_poly R) (rel_poly S) (map_poly f) (map_poly g)"
using assms by (auto simp: rel_fun_def rel_poly_def coeff_map_poly)
lemma map_poly_transfer':
assumes "rel_fun R S f g" "rel_poly R p q" "f 0 = 0" "g 0 = 0"
shows "rel_poly S (map_poly f p) (map_poly g q)"
using assms by (auto simp: rel_fun_def rel_poly_def coeff_map_poly)
lemma rel_poly_id: "p = q ⟹ rel_poly (=) p q"
by (auto simp: rel_poly_def)
lemma left_total_rel_poly [transfer_rule]:
assumes "left_total R" "right_unique R" "R 0 0"
shows "left_total (rel_poly R)"
unfolding left_total_def
proof
fix p :: "'a poly"
from assms have "∀x. ∃y. R x y"
unfolding left_total_def by blast
then obtain f where f: "R x (f x)" for x
by metis
have [simp]: "f 0 = 0"
using assms f[of 0] by (auto dest: right_uniqueD)
have "rel_poly R (map_poly (λx. x) p) (map_poly f p)"
by (rule map_poly_transfer'[of "(=)"] rel_funI)+ (auto intro: rel_poly_id f)
thus "∃q. rel_poly R p q"
by force
qed
lemma right_total_rel_poly [transfer_rule]:
assumes "right_total R" "left_unique R" "R 0 0"
shows "right_total (rel_poly R)"
using left_total_rel_poly[of "λx y. R y x"] assms
by (metis left_totalE left_totalI left_unique_iff rel_poly_swap right_total_def right_unique_iff)
lemma bi_total_rel_poly [transfer_rule]:
assumes "bi_total R" "bi_unique R" "R 0 0"
shows "bi_total (rel_poly R)"
using left_total_rel_poly[of R] right_total_rel_poly[of R] assms
by (simp add: bi_total_alt_def bi_unique_alt_def)
lemma zero_poly_transfer [transfer_rule]: "R 0 0 ⟹ rel_poly R 0 0"
by (auto simp: rel_fun_def rel_poly_def)
lemma one_poly_transfer [transfer_rule]: "R 0 0 ⟹ R 1 1 ⟹ rel_poly R 1 1"
by (auto simp: rel_fun_def rel_poly_def)
lemma pCons_transfer [transfer_rule]:
"rel_fun R (rel_fun (rel_poly R) (rel_poly R)) pCons pCons"
by (auto simp: rel_fun_def rel_poly_def coeff_pCons split: nat.splits)
lemma plus_poly_transfer [transfer_rule]:
"rel_fun R (rel_fun R R) (+) (+) ⟹
rel_fun (rel_poly R) (rel_fun (rel_poly R) (rel_poly R)) (+) (+)"
by (auto simp: rel_fun_def rel_poly_def)
lemma minus_poly_transfer [transfer_rule]:
"rel_fun R (rel_fun R R) (-) (-) ⟹
rel_fun (rel_poly R) (rel_fun (rel_poly R) (rel_poly R)) (-) (-)"
by (auto simp: rel_fun_def rel_poly_def)
lemma uminus_poly_transfer [transfer_rule]:
"rel_fun R R uminus uminus ⟹ rel_fun (rel_poly R) (rel_poly R) uminus uminus"
by (auto simp: rel_fun_def rel_poly_def)
lemma smult_transfer [transfer_rule]:
"rel_fun R (rel_fun R R) (*) (*) ⟹
rel_fun R (rel_fun (rel_poly R) (rel_poly R)) smult smult"
by (auto simp: rel_fun_def rel_poly_def)
lemma monom_transfer [transfer_rule]:
"R 0 0 ⟹ rel_fun R (rel_fun (=) (rel_poly R)) monom monom"
by (auto simp: rel_fun_def rel_poly_def)
lemma pderiv_transfer [transfer_rule]:
assumes "R 0 0" "rel_fun R (rel_fun R R) (+) (+)"
shows "rel_fun (rel_poly R) (rel_poly R) pderiv pderiv"
proof (rule rel_funI, goal_cases)
case (1 p q)
define f :: "nat ⇒ 'a ⇒ 'a" where
"f = (λn p. of_nat n * p)"
define g :: "nat ⇒ 'b ⇒ 'b" where
"g = (λn p. of_nat n * p)"
have plus: "R (x + y) (x' + y')" if "R x x'" "R y y'" for x x' y y'
using assms(2) that by (auto simp: rel_fun_def)
have fg: "R (f m x) (g n y)" if "m = n" "R x y" for x y m n
unfolding that(1)
by (induction n) (auto simp: f_def g_def ring_distribs intro!: assms(1) plus that)
have "rel_fun (=) R (λn. f (Suc n) (coeff p (Suc n))) (λn. g (Suc n) (coeff q (Suc n)))"
using 1 by (intro rel_funI fg) (auto simp: rel_poly_def rel_fun_def)
thus ?case
by (auto simp: rel_poly_def coeff_pderiv [abs_def] f_def g_def)
qed
lemma If_transfer':
assumes "P = P'" "P ⟹ R x x'" "¬P ⟹ R y y'"
shows "R (if P then x else y) (if P' then x' else y')"
using assms by auto
lemma nth_transfer:
assumes "list_all2 R xs ys" "i = j" "i < length xs"
shows "R (xs ! i) (ys ! j)"
using assms by (simp add: list_all2_nthD)
lemma Poly_transfer [transfer_rule]:
assumes [transfer_rule]: "R 0 0" "bi_unique R"
shows "rel_fun (list_all2 R) (rel_poly R) Poly Poly"
unfolding rel_poly_def
proof (intro rel_funI, goal_cases)
case [transfer_rule]: (1 p q i j)
show "R (coeff (Poly p) i) (coeff (Poly q) j)"
unfolding coeff_Poly_eq nth_default_def
proof (rule If_transfer')
show "(i < length p) = (j < length q)"
by transfer_prover
show "R (p ! i) (q ! j)" if "i < length p"
by (rule nth_transfer) (use 1 that in auto)
qed (use assms in auto)
qed
lemma poly_of_list_transfer [transfer_rule]:
assumes [transfer_rule]: "R 0 0" "bi_unique R"
shows "rel_fun (list_all2 R) (rel_poly R) poly_of_list poly_of_list"
unfolding poly_of_list_def by transfer_prover
lemma degree_transfer [transfer_rule]:
assumes [transfer_rule]: "R 0 0" "bi_unique R"
shows "rel_fun (rel_poly R) (=) degree degree"
proof
fix p q
assume *: "rel_poly R p q"
with assms have "coeff p i = 0 ⟷ coeff q i = 0" for i
unfolding rel_poly_def rel_fun_def bi_unique_def by metis
thus "degree p = degree q"
using antisym degree_le coeff_eq_0 by metis
qed
lemma coeffs_transfer [transfer_rule]:
assumes [transfer_rule]: "R 0 0" "bi_unique R"
shows "rel_fun (rel_poly R) (list_all2 R) coeffs coeffs"
proof
fix p q
assume [transfer_rule]: "rel_poly R p q"
have "degree p = degree q"
by transfer_prover
show "list_all2 R (coeffs p) (coeffs q)"
unfolding coeffs_def by transfer_prover
qed
lemma times_poly_transfer [transfer_rule]:
assumes [transfer_rule]: "rel_fun R (rel_fun R R) (+) (+)"
"rel_fun R (rel_fun R R) (*) (*)" "R 0 0" "bi_unique R"
shows "rel_fun (rel_poly R) (rel_fun (rel_poly R) (rel_poly R)) (*) (*)"
unfolding times_poly_def fold_coeffs_def by transfer_prover
lemma dvd_poly_transfer [transfer_rule]:
assumes [transfer_rule]: "rel_fun R (rel_fun R R) (+) (+)"
"rel_fun R (rel_fun R R) (*) (*)" "R 0 0" "bi_unique R" "bi_total R"
shows "rel_fun (rel_poly R) (rel_fun (rel_poly R) (=)) (dvd) (dvd)"
unfolding dvd_def by transfer_prover
lemma poly_transfer [transfer_rule]:
assumes [transfer_rule]: "rel_fun R (rel_fun R R) (+) (+)"
"rel_fun R (rel_fun R R) (*) (*)" "R 0 0" "bi_unique R"
shows "rel_fun (rel_poly R) (rel_fun R R) poly poly"
unfolding poly_def horner_sum_foldr by transfer_prover
lemma pcompose_transfer [transfer_rule]:
assumes [transfer_rule]: "rel_fun R (rel_fun R R) (+) (+)"
"rel_fun R (rel_fun R R) (*) (*)" "R 0 0" "bi_unique R"
shows "rel_fun (rel_poly R) (rel_fun (rel_poly R) (rel_poly R)) pcompose pcompose"
unfolding pcompose_def fold_coeffs_def by transfer_prover
lemma order_0_right: "order x 0 = Least (λ_. False)"
unfolding order_def by simp
lemma order_poly_transfer [transfer_rule]:
assumes [transfer_rule]:
"rel_fun R (rel_fun R R) (+) (+)" "rel_fun R (rel_fun R R) (*) (*)"
"rel_fun R R uminus uminus"
"R 0 0" "R 1 1" "bi_unique R" "bi_total R" "R x y" "rel_poly R p q"
shows "order x p = order y q"
unfolding order_def by transfer_prover
end