Skip to content
This repository was archived by the owner on Jul 24, 2024. It is now read-only.

Commit 58094b8

Browse files
committed
feat(data/polynomial): rec_on_horner
1 parent 78ce6e4 commit 58094b8

File tree

1 file changed

+129
-3
lines changed

1 file changed

+129
-3
lines changed

src/data/polynomial.lean

Lines changed: 129 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,8 @@ def X : polynomial α := single 1 1
4545
/-- coeff p n is the coefficient of X^n in p -/
4646
def coeff (p : polynomial α) := p.to_fun
4747

48+
@[simp] lemma coeff_mk (s) (f) (h) : coeff (finsupp.mk s f h : polynomial α) = f := rfl
49+
4850
instance [has_repr α] : has_repr (polynomial α) :=
4951
⟨λ p, if p = 0 then "0"
5052
else (p.support.sort (≤)).foldr
@@ -67,6 +69,8 @@ def degree (p : polynomial α) : with_bot ℕ := p.support.sup some
6769
def degree_lt_wf : well_founded (λp q : polynomial α, degree p < degree q) :=
6870
inv_image.wf degree (with_bot.well_founded_lt nat.lt_wf)
6971

72+
instance : has_well_founded (polynomial α) := ⟨_, degree_lt_wf⟩
73+
7074
/-- `nat_degree p` forces `degree p` to ℕ, by defining nat_degree 0 = 0. -/
7175
def nat_degree (p : polynomial α) : ℕ := (degree p).get_or_else 0
7276

@@ -80,7 +84,6 @@ lemma single_eq_C_mul_X : ∀{n}, single n a = C a * X^n
8084
lemma sum_C_mul_X_eq (p : polynomial α) : p.sum (λn a, C a * X^n) = p :=
8185
eq.trans (sum_congr rfl $ assume n hn, single_eq_C_mul_X.symm) (finsupp.sum_single _)
8286

83-
8487
@[elab_as_eliminator] protected lemma induction_on {M : polynomial α → Prop} (p : polynomial α)
8588
(h_C : ∀a, M (C a))
8689
(h_add : ∀p q, M p → M q → M (p + q))
@@ -542,6 +545,9 @@ end
542545
lemma eq_C_of_degree_eq_zero (h : degree p = 0) : p = C (coeff p 0) :=
543546
eq_C_of_degree_le_zero (h ▸ le_refl _)
544547

548+
lemma degree_le_zero_iff : degree p ≤ 0 ↔ p = C (coeff p 0) :=
549+
⟨eq_C_of_degree_le_zero, λ h, h.symm ▸ degree_C_le⟩
550+
545551
lemma degree_add_le (p q : polynomial α) : degree (p + q) ≤ max (degree p) (degree q) :=
546552
calc degree (p + q) = ((p + q).support).sup some : rfl
547553
... ≤ (p.support ∪ q.support).sup some : sup_mono support_add
@@ -971,6 +977,128 @@ lemma ne_zero_of_monic (h : monic p) : p ≠ 0 :=
971977

972978
end nonzero_comm_semiring
973979

980+
section comm_semiring
981+
variables [comm_semiring α] [decidable_eq α] {p q : polynomial α}
982+
983+
/-- `dix_X p` return a polynomial `q` such that `q * X + C (p.coeff 0) = p`.
984+
It can be used in a semiring where the usual division algorithm is not possible -/
985+
def div_X (p : polynomial α) : polynomial α :=
986+
{ to_fun := λ n, p.coeff (n + 1),
987+
support := ⟨(p.support.filter (> 0)).1.map (λ n, n - 1),
988+
multiset.nodup_map_on begin
989+
simp only [finset.mem_def.symm, finset.mem_erase, finset.mem_filter],
990+
assume x hx y hy hxy,
991+
rwa [← @add_right_cancel_iff _ _ 1, nat.sub_add_cancel hx.2,
992+
nat.sub_add_cancel hy.2] at hxy
993+
end
994+
(p.support.filter (> 0)).2⟩,
995+
mem_support_to_fun := λ n,
996+
suffices (∃ (a : ℕ), (¬coeff p a = 0 ∧ a > 0) ∧ a - 1 = n) ↔
997+
¬coeff p (n + 1) = 0,
998+
by simpa [finset.mem_def.symm, apply_eq_coeff],
999+
⟨λ ⟨a, ha⟩, by rw [← ha.2, nat.sub_add_cancel ha.1.2]; exact ha.1.1,
1000+
λ h, ⟨n + 1, ⟨h, nat.succ_pos _⟩, nat.succ_sub_one _⟩⟩ }
1001+
1002+
lemma div_X_mul_X_add (p : polynomial α) : div_X p * X + C (p.coeff 0) = p :=
1003+
polynomial.ext.2 $ λ n,
1004+
nat.cases_on n
1005+
(by simp)
1006+
(by simp [coeff_C, nat.succ_ne_zero, coeff_mul_X, div_X])
1007+
1008+
@[simp] lemma div_X_C (a : α) : div_X (C a) = 0 :=
1009+
polynomial.ext.2 $ λ n, by cases n; simp [div_X, coeff_C]; simp [coeff]
1010+
1011+
lemma div_X_eq_zero_iff : div_X p = 0 ↔ p = C (p.coeff 0) :=
1012+
⟨λ h, by simpa [eq_comm, h] using div_X_mul_X_add p,
1013+
λ h, by rw [h, div_X_C]⟩
1014+
1015+
lemma div_X_add : div_X (p + q) = div_X p + div_X q :=
1016+
polynomial.ext.2 $ by simp [div_X]
1017+
1018+
def nonzero_comm_semiring.of_polynomial_ne (h : p ≠ q) : nonzero_comm_semiring α :=
1019+
{ zero_ne_one := λ h01 : 0 = 1, h $
1020+
by rw [← mul_one p, ← mul_one q, ← C_1, ← h01, C_0, mul_zero, mul_zero],
1021+
..show comm_semiring α, by apply_instance }
1022+
1023+
lemma degree_lt_degree_mul_X (hp : p ≠ 0) : p.degree < (p * X).degree :=
1024+
by letI := nonzero_comm_semiring.of_polynomial_ne hp; exact
1025+
have leading_coeff p * leading_coeff X ≠ 0, by simpa,
1026+
by erw [degree_mul_eq' this, degree_eq_nat_degree hp,
1027+
degree_X, ← with_bot.coe_one, ← with_bot.coe_add, with_bot.coe_lt_coe];
1028+
exact nat.lt_succ_self _
1029+
1030+
lemma degree_div_X_lt (hp0 : p ≠ 0) : (div_X p).degree < p.degree :=
1031+
by letI := nonzero_comm_semiring.of_polynomial_ne hp0; exact
1032+
calc (div_X p).degree < (div_X p * X + C (p.coeff 0)).degree :
1033+
if h : degree p ≤ 0
1034+
then begin
1035+
have h' : C (p.coeff 0) ≠ 0, by rwa [← eq_C_of_degree_le_zero h],
1036+
rw [eq_C_of_degree_le_zero h, div_X_C, degree_zero, zero_mul, zero_add],
1037+
exact lt_of_le_of_ne lattice.bot_le (ne.symm (mt degree_eq_bot.1 $
1038+
by simp [h'])),
1039+
end
1040+
else
1041+
have hXp0 : div_X p ≠ 0,
1042+
by simpa [div_X_eq_zero_iff, -not_le, degree_le_zero_iff] using h,
1043+
have leading_coeff (div_X p) * leading_coeff X ≠ 0, by simpa,
1044+
have degree (C (p.coeff 0)) < degree (div_X p * X),
1045+
from calc degree (C (p.coeff 0)) ≤ 0 : degree_C_le
1046+
... < 1 : dec_trivial
1047+
... = degree (X : polynomial α) : degree_X.symm
1048+
... ≤ degree (div_X p * X) :
1049+
by rw [← zero_add (degree X), degree_mul_eq' this];
1050+
exact add_le_add'
1051+
(by rw [zero_le_degree_iff, ne.def, div_X_eq_zero_iff];
1052+
exact λ h0, h (h0.symm ▸ degree_C_le))
1053+
(le_refl _),
1054+
by rw [add_comm, degree_add_eq_of_degree_lt this];
1055+
exact degree_lt_degree_mul_X hXp0
1056+
... = p.degree : by rw div_X_mul_X_add
1057+
1058+
@[elab_as_eliminator] def rec_on_horner
1059+
{M : polynomial α → Sort*} : Π (p : polynomial α),
1060+
M 0
1061+
(Π p a, coeff p 0 = 0 → a ≠ 0 → M p → M (p + C a)) →
1062+
(Π p, p ≠ 0 → M p → M (p * X)) →
1063+
M p
1064+
| p := λ M0 MC MX,
1065+
if hp : p = 0 then eq.rec_on hp.symm M0
1066+
else
1067+
have wf : degree (div_X p) < degree p,
1068+
from degree_div_X_lt hp,
1069+
by rw [← div_X_mul_X_add p] at *;
1070+
exact
1071+
if hcp0 : coeff p 0 = 0
1072+
then by rw [hcp0, C_0, add_zero];
1073+
exact MX _ (λ h : div_X p = 0, by simpa [h, hcp0] using hp)
1074+
(rec_on_horner _ M0 MC MX)
1075+
else MC _ _ (coeff_mul_X_zero _) hcp0 (if hpX0 : div_X p = 0
1076+
then show M (div_X p * X), by rw [hpX0, zero_mul]; exact M0
1077+
else MX (div_X p) hpX0 (rec_on_horner _ M0 MC MX))
1078+
using_well_founded {dec_tac := tactic.assumption}
1079+
1080+
@[elab_as_eliminator] lemma degree_pos_induction_on
1081+
{P : polynomial α → Prop} (p : polynomial α) (h0 : 0 < degree p)
1082+
(hC : ∀ {a}, a ≠ 0 → P (C a * X))
1083+
(hX : ∀ {p}, 0 < degree p → P p → P (p * X))
1084+
(hadd : ∀ {p} {a}, 0 < degree p → P p → P (p + C a)) : P p :=
1085+
rec_on_horner p
1086+
(λ h, by rw degree_zero at h; exact absurd h dec_trivial)
1087+
(λ p a _ _ ih h0,
1088+
have 0 < degree p,
1089+
from lt_of_not_ge (λ h, (not_lt_of_ge degree_C_le) $
1090+
by rwa [eq_C_of_degree_le_zero h, ← C_add] at h0),
1091+
hadd this (ih this))
1092+
(λ p _ ih h0',
1093+
if h0 : 0 < degree p
1094+
then hX h0 (ih h0)
1095+
else by rw [eq_C_of_degree_le_zero (le_of_not_gt h0)] at *;
1096+
exact hC (λ h : coeff p 0 = 0,
1097+
by simpa [h, not_lt.2 (@lattice.bot_le ( ℕ) _ _)] using h0'))
1098+
h0
1099+
1100+
end comm_semiring
1101+
9741102
section comm_ring
9751103
variables [comm_ring α] [decidable_eq α] {p q : polynomial α}
9761104
instance : comm_ring (polynomial α) := finsupp.to_comm_ring
@@ -1045,8 +1173,6 @@ calc degree (p - q) = degree (erase (nat_degree q) p + -erase (nat_degree q) q)
10451173
: degree_neg (erase (nat_degree q) q) ▸ degree_add_le _ _
10461174
... < degree p : max_lt_iff.2 ⟨hd' ▸ degree_erase_lt hp0, hd.symm ▸ degree_erase_lt hq0⟩
10471175

1048-
instance : has_well_founded (polynomial α) := ⟨_, degree_lt_wf⟩
1049-
10501176
lemma ne_zero_of_ne_zero_of_monic (hp : p ≠ 0) (hq : monic q) : q ≠ 0
10511177
| h := begin
10521178
rw [h, monic.def, leading_coeff_zero] at hq,

0 commit comments

Comments
 (0)