(* ========================================================================= *)
(* Properties of real polynomials (not canonically represented). *)
(* ========================================================================= *)
needs "Library/analysis.ml";;
prioritize_real();;
parse_as_infix("++",(16,"right"));;
parse_as_infix("**",(20,"right"));;
parse_as_infix("##",(20,"right"));;
parse_as_infix("divides",(14,"right"));;
parse_as_infix("exp",(22,"right"));;
do_list override_interface
["++",`poly_add:real list->real list->real list`;
"**",`poly_mul:real list->real list->real list`;
"##",`poly_cmul:real->real list->real list`;
"neg",`poly_neg:real list->real list`;
"exp",`poly_exp:real list -> num -> real list`;
"diff",`poly_diff:real list->real list`];;
overload_interface ("divides",`poly_divides:real list->real list->bool`);;
(* ------------------------------------------------------------------------- *)
(* Application of polynomial as a real function. *)
(* ------------------------------------------------------------------------- *)
let POLY_X = prove
(`!c x. poly [&0; &1] x = x`,
REWRITE_TAC[poly] THEN REAL_ARITH_TAC);;
(* ------------------------------------------------------------------------- *)
(* Arithmetic operations on polynomials. *)
(* ------------------------------------------------------------------------- *)
let poly_add = new_recursive_definition list_RECURSION
`([] ++ l2 = l2) /\
((CONS h t) ++ l2 =
(if l2 = [] then CONS h t
else CONS (h + HD l2) (t ++ TL l2)))`;;
let poly_cmul = new_recursive_definition list_RECURSION
`(c ## [] = []) /\
(c ## (CONS h t) = CONS (c * h) (c ## t))`;;
let poly_mul = new_recursive_definition list_RECURSION
`([] ** l2 = []) /\
((CONS h t) ** l2 =
(if t = [] then h ## l2
else (h ## l2) ++ CONS (&0) (t ** l2)))`;;
let poly_exp = new_recursive_definition num_RECURSION
`(p exp 0 = [&1]) /\
(p exp (SUC n) = p ** p exp n)`;;
(* ------------------------------------------------------------------------- *)
(* Differentiation of polynomials (needs an auxiliary function). *)
(* ------------------------------------------------------------------------- *)
(* ------------------------------------------------------------------------- *)
(* Lengths. *)
(* ------------------------------------------------------------------------- *)
(* ------------------------------------------------------------------------- *)
(* Useful clausifications. *)
(* ------------------------------------------------------------------------- *)
let POLY_ADD_CLAUSES = prove
(`([] ++ p2 = p2) /\
(p1 ++ [] = p1) /\
((CONS h1 t1) ++ (CONS h2 t2) = CONS (h1 + h2) (t1 ++ t2))`,
let POLY_MUL_CLAUSES = prove
(`([] ** p2 = []) /\
([h1] ** p2 = h1 ## p2) /\
((CONS h1 (CONS k1 t1)) ** p2 = h1 ## p2 ++ CONS (&0) (CONS k1 t1 ** p2))`,
(* ------------------------------------------------------------------------- *)
(* Various natural consequences of syntactic definitions. *)
(* ------------------------------------------------------------------------- *)
let POLY_CMUL = prove
(`!p c x. poly (c ## p) x = c * poly p x`,
LIST_INDUCT_TAC THEN ASM_REWRITE_TAC[poly;
poly_cmul] THEN
REAL_ARITH_TAC);;
(* ------------------------------------------------------------------------- *)
(* The derivative is a bit more complicated. *)
(* ------------------------------------------------------------------------- *)
let POLY_DIFF_LEMMA = prove
(`!l n x. ((\x. (x pow (SUC n)) * poly l x) diffl
((x pow n) * poly (
poly_diff_aux (SUC n) l) x))(x)`,
LIST_INDUCT_TAC THEN
REWRITE_TAC[poly;
poly_diff_aux;
REAL_MUL_RZERO;
DIFF_CONST] THEN
MAP_EVERY X_GEN_TAC [`n:num`; `x:real`] THEN
REWRITE_TAC[REAL_LDISTRIB; REAL_MUL_ASSOC] THEN
ONCE_REWRITE_TAC[GSYM(ONCE_REWRITE_RULE[REAL_MUL_SYM] (CONJUNCT2 pow))] THEN
POP_ASSUM(MP_TAC o SPECL [`SUC n`; `x:real`]) THEN
SUBGOAL_THEN `(((\x. (x pow (SUC n)) * h)) diffl
((x pow n) * &(SUC n) * h))(x)`
(fun th -> DISCH_THEN(MP_TAC o CONJ th)) THENL
[REWRITE_TAC[REAL_MUL_ASSOC] THEN ONCE_REWRITE_TAC[REAL_MUL_SYM] THEN
MP_TAC(SPEC `\x. x pow (SUC n)`
DIFF_CMUL) THEN BETA_TAC THEN
DISCH_THEN MATCH_MP_TAC THEN
MP_TAC(SPEC `SUC n`
DIFF_POW) THEN REWRITE_TAC[
SUC_SUB1] THEN
DISCH_THEN(MATCH_ACCEPT_TAC o ONCE_REWRITE_RULE[REAL_MUL_SYM]);
DISCH_THEN(MP_TAC o MATCH_MP
DIFF_ADD) THEN BETA_TAC THEN
REWRITE_TAC[REAL_MUL_ASSOC]]);;
let POLY_DIFF = prove
(`!l x. ((\x. poly l x) diffl (poly (diff l) x))(x)`,
LIST_INDUCT_TAC THEN REWRITE_TAC[
POLY_DIFF_CLAUSES] THEN
ONCE_REWRITE_TAC[SYM(ETA_CONV `\x. poly l x`)] THEN
REWRITE_TAC[poly;
DIFF_CONST] THEN
MAP_EVERY X_GEN_TAC [`x:real`] THEN
MP_TAC(SPECL [`t:(real)list`; `0`; `x:real`]
POLY_DIFF_LEMMA) THEN
REWRITE_TAC[SYM(num_CONV `1`)] THEN REWRITE_TAC[pow; REAL_MUL_LID] THEN
REWRITE_TAC[
POW_1] THEN
DISCH_THEN(MP_TAC o CONJ (SPECL [`h:real`; `x:real`]
DIFF_CONST)) THEN
DISCH_THEN(MP_TAC o MATCH_MP
DIFF_ADD) THEN BETA_TAC THEN
REWRITE_TAC[REAL_ADD_LID]);;
(* ------------------------------------------------------------------------- *)
(* Trivial consequences. *)
(* ------------------------------------------------------------------------- *)
let POLY_DIFFERENTIABLE = prove
(`!l x. (\x. poly l x) differentiable x`,
REPEAT GEN_TAC THEN REWRITE_TAC[differentiable] THEN
EXISTS_TAC `poly (diff l) x` THEN
REWRITE_TAC[
POLY_DIFF]);;
let POLY_IVT_POS = prove
(`!p a b. a < b /\ poly p a < &0 /\ poly p b > &0
==> ?x. a < x /\ x < b /\ (poly p x = &0)`,
REWRITE_TAC[
real_gt] THEN REPEAT STRIP_TAC THEN
MP_TAC(SPECL [`\x. poly p x`; `a:real`; `b:real`; `&0`]
IVT) THEN
REWRITE_TAC[
POLY_CONT] THEN
EVERY_ASSUM(fun th -> REWRITE_TAC[MATCH_MP
REAL_LT_IMP_LE th]) THEN
DISCH_THEN(X_CHOOSE_THEN `x:real` STRIP_ASSUME_TAC) THEN
EXISTS_TAC `x:real` THEN ASM_REWRITE_TAC[
REAL_LT_LE] THEN
CONJ_TAC THEN DISCH_THEN SUBST_ALL_TAC THEN
FIRST_ASSUM SUBST_ALL_TAC THEN
RULE_ASSUM_TAC(REWRITE_RULE[
REAL_LT_REFL]) THEN
FIRST_ASSUM CONTR_TAC);;
let POLY_IVT_NEG = prove
(`!p a b. a < b /\ poly p a > &0 /\ poly p b < &0
==> ?x. a < x /\ x < b /\ (poly p x = &0)`,
REPEAT STRIP_TAC THEN MP_TAC(SPEC `
poly_neg p`
POLY_IVT_POS) THEN
REWRITE_TAC[
POLY_NEG;
REAL_ARITH `(--x < &0 <=> x > &0) /\ (--x > &0 <=> x < &0)`] THEN
DISCH_THEN(MP_TAC o SPECL [`a:real`; `b:real`]) THEN
ASM_REWRITE_TAC[REAL_ARITH `(--x = &0) <=> (x = &0)`]);;
let POLY_MVT = prove
(`!p a b. a < b ==>
?x. a < x /\ x < b /\
(poly p b - poly p a = (b - a) * poly (diff p) x)`,
REPEAT STRIP_TAC THEN
MP_TAC(SPECL [`poly p`; `a:real`; `b:real`]
MVT) THEN
ASM_REWRITE_TAC[CONV_RULE(DEPTH_CONV ETA_CONV) (SPEC_ALL
POLY_CONT);
CONV_RULE(DEPTH_CONV ETA_CONV) (SPEC_ALL
POLY_DIFFERENTIABLE)] THEN
DISCH_THEN(X_CHOOSE_THEN `l:real` MP_TAC) THEN
DISCH_THEN(X_CHOOSE_THEN `x:real` STRIP_ASSUME_TAC) THEN
EXISTS_TAC `x:real` THEN ASM_REWRITE_TAC[] THEN
AP_TERM_TAC THEN MATCH_MP_TAC
DIFF_UNIQ THEN
EXISTS_TAC `poly p` THEN EXISTS_TAC `x:real` THEN
ASM_REWRITE_TAC[CONV_RULE(DEPTH_CONV ETA_CONV) (SPEC_ALL
POLY_DIFF)]);;
let POLY_MVT_ADD = prove
(`!p a x. ?y. abs(y) <= abs(x) /\
(poly p (a + x) = poly p a + x * poly (diff p) (a + y))`,
REPEAT GEN_TAC THEN
REPEAT_TCL DISJ_CASES_THEN ASSUME_TAC (SPEC `x:real`
REAL_LT_NEGTOTAL) THENL
[EXISTS_TAC `&0` THEN
ASM_REWRITE_TAC[
REAL_LE_REFL;
REAL_ADD_RID;
REAL_MUL_LZERO];
MP_TAC(SPECL [`p:real list`; `a:real`; `a + x`]
POLY_MVT) THEN
ASM_REWRITE_TAC[
REAL_LT_ADDR] THEN
DISCH_THEN(X_CHOOSE_THEN `z:real` MP_TAC) THEN
REWRITE_TAC[REAL_ARITH `(x - y = ((a + b) - a) * z) <=>
(x = y + b * z)`] THEN
STRIP_TAC THEN ASM_REWRITE_TAC[
REAL_EQ_ADD_LCANCEL] THEN
EXISTS_TAC `z - a` THEN REWRITE_TAC[REAL_ARITH `x + (y - x) = y`] THEN
MAP_EVERY UNDISCH_TAC [`&0 < x`; `a < z`; `z < a + x`] THEN
REAL_ARITH_TAC;
MP_TAC(SPECL [`p:real list`; `a + x`; `a:real`]
POLY_MVT) THEN
ASM_REWRITE_TAC[REAL_ARITH `a + x < a <=> &0 < --x`] THEN
DISCH_THEN(X_CHOOSE_THEN `z:real` MP_TAC) THEN
REWRITE_TAC[REAL_ARITH `(x - y = (a - (a + b)) * z) <=>
(x = y + b * --z)`] THEN
STRIP_TAC THEN ASM_REWRITE_TAC[
REAL_EQ_ADD_LCANCEL] THEN
EXISTS_TAC `z - a` THEN REWRITE_TAC[REAL_ARITH `x + (y - x) = y`] THEN
MAP_EVERY UNDISCH_TAC [`&0 < --x`; `a + x < z`; `z < a`] THEN
REAL_ARITH_TAC]);;
(* ------------------------------------------------------------------------- *)
(* Lemmas. *)
(* ------------------------------------------------------------------------- *)
(* ------------------------------------------------------------------------- *)
(* Lemmas for derivatives. *)
(* ------------------------------------------------------------------------- *)
(* ------------------------------------------------------------------------- *)
(* Final results for derivatives. *)
(* ------------------------------------------------------------------------- *)
let POLY_DIFF_EXP = prove
(`!p n. poly (diff (p exp (SUC n))) =
poly ((&(SUC n) ## (p exp n)) ** diff p)`,
(* ------------------------------------------------------------------------- *)
(* Key property that f(a) = 0 ==> (x - a) divides p(x). Very delicate! *)
(* ------------------------------------------------------------------------- *)
(* ------------------------------------------------------------------------- *)
(* Thanks to the finesse of the above, we can use length rather than degree. *)
(* ------------------------------------------------------------------------- *)
(* ------------------------------------------------------------------------- *)
(* Thus a nontrivial polynomial of degree n has no more than n roots. *)
(* ------------------------------------------------------------------------- *)
let POLY_ROOTS_INDEX_LEMMA = prove
(`!n. !p. ~(poly p = poly []) /\ (
LENGTH p = n)
==> ?i. !x. (poly p (x) = &0) ==> ?m. m <= n /\ (x = i m)`,
INDUCT_TAC THENL
[REWRITE_TAC[
LENGTH_EQ_NIL] THEN MESON_TAC[];
REPEAT STRIP_TAC THEN ASM_CASES_TAC `?a. poly p a = &0` THENL
[UNDISCH_TAC `?a. poly p a = &0` THEN DISCH_THEN(CHOOSE_THEN MP_TAC) THEN
GEN_REWRITE_TAC LAND_CONV [
POLY_LINEAR_DIVIDES] THEN
DISCH_THEN(DISJ_CASES_THEN MP_TAC) THENL [ASM_MESON_TAC[]; ALL_TAC] THEN
DISCH_THEN(X_CHOOSE_THEN `q:real list` SUBST_ALL_TAC) THEN
FIRST_ASSUM(UNDISCH_TAC o check is_forall o concl) THEN
UNDISCH_TAC `~(poly ([-- a; &1] ** q) = poly [])` THEN
POP_ASSUM MP_TAC THEN REWRITE_TAC[
POLY_LENGTH_MUL;
SUC_INJ] THEN
DISCH_TAC THEN ASM_CASES_TAC `poly q = poly []` THENL
[ASM_REWRITE_TAC[
POLY_MUL; poly;
REAL_MUL_RZERO;
FUN_EQ_THM];
DISCH_THEN(K ALL_TAC)] THEN
DISCH_THEN(MP_TAC o SPEC `q:real list`) THEN ASM_REWRITE_TAC[] THEN
DISCH_THEN(X_CHOOSE_TAC `i:num->real`) THEN
EXISTS_TAC `\m. if m = SUC n then (a:real) else i m` THEN
REWRITE_TAC[
POLY_MUL;
LE;
REAL_ENTIRE] THEN
X_GEN_TAC `x:real` THEN DISCH_THEN(DISJ_CASES_THEN MP_TAC) THENL
[DISCH_THEN(fun th -> EXISTS_TAC `SUC n` THEN MP_TAC th) THEN
REWRITE_TAC[poly] THEN REAL_ARITH_TAC;
DISCH_THEN(ANTE_RES_THEN MP_TAC) THEN
DISCH_THEN(X_CHOOSE_THEN `m:num` STRIP_ASSUME_TAC) THEN
EXISTS_TAC `m:num` THEN ASM_REWRITE_TAC[] THEN
COND_CASES_TAC THEN ASM_REWRITE_TAC[] THEN
UNDISCH_TAC `m:num <= n` THEN ASM_REWRITE_TAC[] THEN ARITH_TAC];
UNDISCH_TAC `~(?a. poly p a = &0)` THEN
REWRITE_TAC[
NOT_EXISTS_THM] THEN DISCH_TAC THEN ASM_REWRITE_TAC[]]]);;
let FINITE_LEMMA = prove
(`!i N P. (!x. P x ==> ?n:num. n < N /\ (x = i n))
==> ?a. !x. P x ==> x < a`,
GEN_TAC THEN ONCE_REWRITE_TAC[
RIGHT_IMP_EXISTS_THM] THEN INDUCT_TAC THENL
[REWRITE_TAC[
LT] THEN MESON_TAC[]; ALL_TAC] THEN
X_GEN_TAC `P:real->bool` THEN
POP_ASSUM(MP_TAC o SPEC `\z. P z /\ ~(z = (i:num->real) N)`) THEN
DISCH_THEN(X_CHOOSE_TAC `a:real`) THEN
EXISTS_TAC `abs(a) + abs(i(N:num)) + &1` THEN
POP_ASSUM MP_TAC THEN REWRITE_TAC[
LT] THEN
MP_TAC(REAL_ARITH `!x v. x < abs(v) + abs(x) + &1`) THEN
MP_TAC(REAL_ARITH `!u v x. x < v ==> x < abs(v) + abs(u) + &1`) THEN
MESON_TAC[]);;
(* ------------------------------------------------------------------------- *)
(* Hence get entirety and cancellation for polynomials. *)
(* ------------------------------------------------------------------------- *)
let POLY_ENTIRE_LEMMA = prove
(`!p q. ~(poly p = poly []) /\ ~(poly q = poly [])
==> ~(poly (p ** q) = poly [])`,
REPEAT GEN_TAC THEN REWRITE_TAC[
POLY_ROOTS_FINITE] THEN
DISCH_THEN(CONJUNCTS_THEN MP_TAC) THEN
DISCH_THEN(X_CHOOSE_THEN `N2:num` (X_CHOOSE_TAC `i2:num->real`)) THEN
DISCH_THEN(X_CHOOSE_THEN `N1:num` (X_CHOOSE_TAC `i1:num->real`)) THEN
EXISTS_TAC `N1 + N2:num` THEN
EXISTS_TAC `\n:num. if n < N1 then i1(n):real else i2(n - N1)` THEN
X_GEN_TAC `x:real` THEN REWRITE_TAC[
REAL_ENTIRE;
POLY_MUL] THEN
DISCH_THEN(DISJ_CASES_THEN (ANTE_RES_THEN (X_CHOOSE_TAC `n:num`))) THENL
[EXISTS_TAC `n:num` THEN ASM_REWRITE_TAC[] THEN
FIRST_ASSUM(MP_TAC o CONJUNCT1) THEN ARITH_TAC;
EXISTS_TAC `N1 + n:num` THEN ASM_REWRITE_TAC[
LT_ADD_LCANCEL] THEN
REWRITE_TAC[ARITH_RULE `~(m + n < m:num)`] THEN
AP_TERM_TAC THEN ARITH_TAC]);;
let POLY_ENTIRE = prove
(`!p q. (poly (p ** q) = poly []) <=>
(poly p = poly []) \/ (poly q = poly [])`,
let POLY_PRIME_EQ_0 = prove
(`!a. ~(poly [a ; &1] = poly [])`,
GEN_TAC THEN REWRITE_TAC[
FUN_EQ_THM; poly] THEN
DISCH_THEN(MP_TAC o SPEC `&1 - a`) THEN
REAL_ARITH_TAC);;
(* ------------------------------------------------------------------------- *)
(* Can also prove a more "constructive" notion of polynomial being trivial. *)
(* ------------------------------------------------------------------------- *)
let POLY_ZERO_LEMMA = prove
(`!h t. (poly (CONS h t) = poly []) ==> (h = &0) /\ (poly t = poly [])`,
let lemma = REWRITE_RULE[
FUN_EQ_THM; poly]
POLY_ROOTS_FINITE in
REPEAT GEN_TAC THEN REWRITE_TAC[
FUN_EQ_THM; poly] THEN
ASM_CASES_TAC `h = &0` THEN ASM_REWRITE_TAC[] THENL
[REWRITE_TAC[REAL_ADD_LID];
DISCH_THEN(MP_TAC o SPEC `&0`) THEN
POP_ASSUM MP_TAC THEN REAL_ARITH_TAC] THEN
CONV_TAC CONTRAPOS_CONV THEN
DISCH_THEN(MP_TAC o REWRITE_RULE[lemma]) THEN
DISCH_THEN(X_CHOOSE_THEN `N:num` (X_CHOOSE_TAC `i:num->real`)) THEN
MP_TAC(SPECL [`i:num->real`; `N:num`; `\x. poly t x = &0`]
FINITE_LEMMA) THEN
ASM_REWRITE_TAC[] THEN DISCH_THEN(X_CHOOSE_TAC `a:real`) THEN
DISCH_THEN(MP_TAC o SPEC `abs(a) + &1`) THEN
REWRITE_TAC[
REAL_ENTIRE; DE_MORGAN_THM] THEN CONJ_TAC THENL
[REAL_ARITH_TAC;
DISCH_THEN(MP_TAC o MATCH_MP (ASSUME `!x. (poly t x = &0) ==> x < a`)) THEN
REAL_ARITH_TAC]);;
let POLY_ZERO = prove
(`!p. (poly p = poly []) <=>
ALL (\c. c = &0) p`,
LIST_INDUCT_TAC THEN ASM_REWRITE_TAC[
ALL] THEN EQ_TAC THENL
[DISCH_THEN(MP_TAC o MATCH_MP
POLY_ZERO_LEMMA) THEN ASM_REWRITE_TAC[];
POP_ASSUM(SUBST1_TAC o SYM) THEN STRIP_TAC THEN
ASM_REWRITE_TAC[
FUN_EQ_THM; poly] THEN REAL_ARITH_TAC]);;
(* ------------------------------------------------------------------------- *)
(* Useful triviality. *)
(* ------------------------------------------------------------------------- *)
let POLY_DIFF_ZERO = prove
(`!p. (poly p = poly []) ==> (poly (diff p) = poly [])`,
REWRITE_TAC[
POLY_ZERO] THEN
LIST_INDUCT_TAC THEN REWRITE_TAC[
poly_diff;
NOT_CONS_NIL] THEN
REWRITE_TAC[
ALL;
TL] THEN
DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
SPEC_TAC(`1`,`n:num`) THEN POP_ASSUM_LIST(K ALL_TAC) THEN
SPEC_TAC(`t:real list`,`t:real list`) THEN
LIST_INDUCT_TAC THEN REWRITE_TAC[
ALL;
poly_diff_aux] THEN
REPEAT STRIP_TAC THEN ASM_REWRITE_TAC[
REAL_MUL_RZERO] THEN
FIRST_ASSUM MATCH_MP_TAC THEN ASM_REWRITE_TAC[]);;
(* ------------------------------------------------------------------------- *)
(* Basics of divisibility. *)
(* ------------------------------------------------------------------------- *)
let POLY_PRIMES = prove
(`!a p q. [a; &1] divides (p ** q) <=>
[a; &1] divides p \/ [a; &1] divides q`,
REPEAT GEN_TAC THEN REWRITE_TAC[divides;
POLY_MUL;
FUN_EQ_THM; poly] THEN
REWRITE_TAC[
REAL_MUL_RZERO;
REAL_ADD_RID;
REAL_MUL_RID] THEN EQ_TAC THENL
[DISCH_THEN(X_CHOOSE_THEN `r:real list` (MP_TAC o SPEC `--a`)) THEN
REWRITE_TAC[
REAL_ENTIRE; GSYM
real_sub;
REAL_SUB_REFL;
REAL_MUL_LZERO] THEN
DISCH_THEN DISJ_CASES_TAC THENL [DISJ1_TAC; DISJ2_TAC] THEN
(POP_ASSUM(MP_TAC o REWRITE_RULE[
POLY_LINEAR_DIVIDES]) THEN
REWRITE_TAC[
REAL_NEG_NEG] THEN
DISCH_THEN(DISJ_CASES_THEN2 SUBST_ALL_TAC
(X_CHOOSE_THEN `s:real list` SUBST_ALL_TAC)) THENL
[EXISTS_TAC `[]:real list` THEN REWRITE_TAC[poly;
REAL_MUL_RZERO];
EXISTS_TAC `s:real list` THEN GEN_TAC THEN
REWRITE_TAC[
POLY_MUL; poly] THEN REAL_ARITH_TAC]);
DISCH_THEN(DISJ_CASES_THEN(X_CHOOSE_TAC `s:real list`)) THEN
ASM_REWRITE_TAC[] THENL
[EXISTS_TAC `s ** q`; EXISTS_TAC `p ** s`] THEN
GEN_TAC THEN REWRITE_TAC[
POLY_MUL] THEN REAL_ARITH_TAC]);;
let POLY_DIVIDES_TRANS = prove
(`!p q r. p divides q /\ q divides r ==> p divides r`,
REPEAT GEN_TAC THEN REWRITE_TAC[divides] THEN
DISCH_THEN(CONJUNCTS_THEN MP_TAC) THEN
DISCH_THEN(X_CHOOSE_THEN `s:real list` ASSUME_TAC) THEN
DISCH_THEN(X_CHOOSE_THEN `t:real list` ASSUME_TAC) THEN
EXISTS_TAC `t ** s` THEN
ASM_REWRITE_TAC[
FUN_EQ_THM;
POLY_MUL; REAL_MUL_ASSOC]);;
let POLY_DIVIDES_ADD = prove
(`!p q r. p divides q /\ p divides r ==> p divides (q ++ r)`,
REPEAT GEN_TAC THEN REWRITE_TAC[divides] THEN
DISCH_THEN(CONJUNCTS_THEN MP_TAC) THEN
DISCH_THEN(X_CHOOSE_THEN `s:real list` ASSUME_TAC) THEN
DISCH_THEN(X_CHOOSE_THEN `t:real list` ASSUME_TAC) THEN
EXISTS_TAC `t ++ s` THEN
ASM_REWRITE_TAC[
FUN_EQ_THM;
POLY_ADD;
POLY_MUL] THEN
REAL_ARITH_TAC);;
let POLY_DIVIDES_SUB = prove
(`!p q r. p divides q /\ p divides (q ++ r) ==> p divides r`,
REPEAT GEN_TAC THEN REWRITE_TAC[divides] THEN
DISCH_THEN(CONJUNCTS_THEN MP_TAC) THEN
DISCH_THEN(X_CHOOSE_THEN `s:real list` ASSUME_TAC) THEN
DISCH_THEN(X_CHOOSE_THEN `t:real list` ASSUME_TAC) THEN
EXISTS_TAC `s ++ neg(t)` THEN
POP_ASSUM_LIST(MP_TAC o end_itlist CONJ) THEN
REWRITE_TAC[
FUN_EQ_THM;
POLY_ADD;
POLY_MUL;
POLY_NEG] THEN
DISCH_THEN(STRIP_ASSUME_TAC o GSYM) THEN
REWRITE_TAC[REAL_ADD_LDISTRIB;
REAL_MUL_RNEG] THEN
ASM_REWRITE_TAC[] THEN REAL_ARITH_TAC);;
let POLY_DIVIDES_SUB2 = prove
(`!p q r. p divides r /\ p divides (q ++ r) ==> p divides q`,
REPEAT STRIP_TAC THEN MATCH_MP_TAC
POLY_DIVIDES_SUB THEN
EXISTS_TAC `r:real list` THEN ASM_REWRITE_TAC[] THEN
UNDISCH_TAC `p divides (q ++ r)` THEN
REWRITE_TAC[divides;
POLY_ADD;
FUN_EQ_THM;
POLY_MUL] THEN
DISCH_THEN(X_CHOOSE_TAC `s:real list`) THEN
EXISTS_TAC `s:real list` THEN
X_GEN_TAC `x:real` THEN POP_ASSUM(MP_TAC o SPEC `x:real`) THEN
REAL_ARITH_TAC);;
(* ------------------------------------------------------------------------- *)
(* At last, we can consider the order of a root. *)
(* ------------------------------------------------------------------------- *)
let POLY_ORDER_EXISTS = prove
(`!a d. !p. (
LENGTH p = d) /\ ~(poly p = poly [])
==> ?n. ([--a; &1] exp n) divides p /\
~(([--a; &1] exp (SUC n)) divides p)`,
GEN_TAC THEN
(STRIP_ASSUME_TAC o prove_recursive_functions_exist num_RECURSION)
`(!p q. mulexp 0 p q = q) /\
(!p q n. mulexp (SUC n) p q = p ** (mulexp n p q))` THEN
SUBGOAL_THEN
`!d. !p. (
LENGTH p = d) /\ ~(poly p = poly [])
==> ?n q. (p = mulexp (n:num) [--a; &1] q) /\
~(poly q a = &0)`
MP_TAC THENL
[INDUCT_TAC THENL
[REWRITE_TAC[
LENGTH_EQ_NIL] THEN MESON_TAC[]; ALL_TAC] THEN
X_GEN_TAC `p:real list` THEN
ASM_CASES_TAC `poly p a = &0` THENL
[STRIP_TAC THEN UNDISCH_TAC `poly p a = &0` THEN
DISCH_THEN(MP_TAC o REWRITE_RULE[
POLY_LINEAR_DIVIDES]) THEN
DISCH_THEN(DISJ_CASES_THEN MP_TAC) THENL [ASM_MESON_TAC[]; ALL_TAC] THEN
DISCH_THEN(X_CHOOSE_THEN `q:real list` SUBST_ALL_TAC) THEN
UNDISCH_TAC
`!p. (
LENGTH p = d) /\ ~(poly p = poly [])
==> ?n q. (p = mulexp (n:num) [--a; &1] q) /\
~(poly q a = &0)` THEN
DISCH_THEN(MP_TAC o SPEC `q:real list`) THEN
RULE_ASSUM_TAC(REWRITE_RULE[
POLY_LENGTH_MUL;
POLY_ENTIRE;
DE_MORGAN_THM;
SUC_INJ]) THEN
ASM_REWRITE_TAC[] THEN
DISCH_THEN(X_CHOOSE_THEN `n:num`
(X_CHOOSE_THEN `s:real list` STRIP_ASSUME_TAC)) THEN
EXISTS_TAC `SUC n` THEN EXISTS_TAC `s:real list` THEN
ASM_REWRITE_TAC[];
STRIP_TAC THEN EXISTS_TAC `0` THEN EXISTS_TAC `p:real list` THEN
ASM_REWRITE_TAC[]];
DISCH_TAC THEN REPEAT GEN_TAC THEN
DISCH_THEN(ANTE_RES_THEN MP_TAC) THEN
DISCH_THEN(X_CHOOSE_THEN `n:num`
(X_CHOOSE_THEN `s:real list` STRIP_ASSUME_TAC)) THEN
EXISTS_TAC `n:num` THEN ASM_REWRITE_TAC[] THEN
REWRITE_TAC[divides] THEN CONJ_TAC THENL
[EXISTS_TAC `s:real list` THEN
SPEC_TAC(`n:num`,`n:num`) THEN INDUCT_TAC THEN
ASM_REWRITE_TAC[
poly_exp;
FUN_EQ_THM;
POLY_MUL; poly] THEN
REAL_ARITH_TAC;
DISCH_THEN(X_CHOOSE_THEN `r:real list` MP_TAC) THEN
SPEC_TAC(`n:num`,`n:num`) THEN INDUCT_TAC THEN
ASM_REWRITE_TAC[] THENL
[UNDISCH_TAC `~(poly s a = &0)` THEN CONV_TAC CONTRAPOS_CONV THEN
REWRITE_TAC[] THEN DISCH_THEN SUBST1_TAC THEN
REWRITE_TAC[poly;
poly_exp;
POLY_MUL] THEN REAL_ARITH_TAC;
REWRITE_TAC[] THEN ONCE_ASM_REWRITE_TAC[] THEN
ONCE_REWRITE_TAC[
poly_exp] THEN
REWRITE_TAC[GSYM
POLY_MUL_ASSOC;
POLY_MUL_LCANCEL] THEN
REWRITE_TAC[DE_MORGAN_THM] THEN CONJ_TAC THENL
[REWRITE_TAC[
FUN_EQ_THM] THEN
DISCH_THEN(MP_TAC o SPEC `a + &1`) THEN
REWRITE_TAC[poly] THEN REAL_ARITH_TAC;
DISCH_THEN(ANTE_RES_THEN MP_TAC) THEN REWRITE_TAC[]]]]]);;
let POLY_ORDER = prove
(`!p a. ~(poly p = poly [])
==> ?!n. ([--a; &1] exp n) divides p /\
~(([--a; &1] exp (SUC n)) divides p)`,
(* ------------------------------------------------------------------------- *)
(* Definition of order. *)
(* ------------------------------------------------------------------------- *)
let ORDER = prove
(`!p a n. ([--a; &1] exp n) divides p /\
~(([--a; &1] exp (SUC n)) divides p) <=>
(n = order a p) /\
~(poly p = poly [])`,
REPEAT GEN_TAC THEN REWRITE_TAC[order] THEN
EQ_TAC THEN STRIP_TAC THENL
[SUBGOAL_THEN `~(poly p = poly [])` ASSUME_TAC THENL
[FIRST_ASSUM(UNDISCH_TAC o check is_neg o concl) THEN
CONV_TAC CONTRAPOS_CONV THEN REWRITE_TAC[divides] THEN
DISCH_THEN SUBST1_TAC THEN EXISTS_TAC `[]:real list` THEN
REWRITE_TAC[
FUN_EQ_THM;
POLY_MUL; poly;
REAL_MUL_RZERO];
ASM_REWRITE_TAC[] THEN CONV_TAC SYM_CONV THEN
MATCH_MP_TAC
SELECT_UNIQUE THEN REWRITE_TAC[]];
ONCE_ASM_REWRITE_TAC[] THEN CONV_TAC SELECT_CONV] THEN
ASM_MESON_TAC[
POLY_ORDER]);;
let ORDER_THM = prove
(`!p a. ~(poly p = poly [])
==> ([--a; &1] exp (order a p)) divides p /\
~(([--a; &1] exp (SUC(order a p))) divides p)`,
let ORDER_UNIQUE = prove
(`!p a n. ~(poly p = poly []) /\
([--a; &1] exp n) divides p /\
~(([--a; &1] exp (SUC n)) divides p)
==> (n = order a p)`,
let ORDER_ROOT = prove
(`!p a. (poly p a = &0) <=> (poly p = poly []) \/ ~(order a p = 0)`,
REPEAT GEN_TAC THEN ASM_CASES_TAC `poly p = poly []` THEN
ASM_REWRITE_TAC[poly] THEN EQ_TAC THENL
[DISCH_THEN(MP_TAC o REWRITE_RULE[
POLY_LINEAR_DIVIDES]) THEN
ASM_CASES_TAC `p:real list = []` THENL [ASM_MESON_TAC[]; ALL_TAC] THEN
ASM_REWRITE_TAC[] THEN
DISCH_THEN(X_CHOOSE_THEN `q:real list` SUBST_ALL_TAC) THEN DISCH_TAC THEN
FIRST_ASSUM(MP_TAC o SPEC `a:real` o MATCH_MP
ORDER_THM) THEN
ASM_REWRITE_TAC[
poly_exp; DE_MORGAN_THM] THEN DISJ2_TAC THEN
REWRITE_TAC[divides] THEN EXISTS_TAC `q:real list` THEN
REWRITE_TAC[
FUN_EQ_THM;
POLY_MUL; poly] THEN REAL_ARITH_TAC;
DISCH_TAC THEN
FIRST_ASSUM(MP_TAC o SPEC `a:real` o MATCH_MP
ORDER_THM) THEN
UNDISCH_TAC `~(order a p = 0)` THEN
SPEC_TAC(`order a p`,`n:num`) THEN
INDUCT_TAC THEN ASM_REWRITE_TAC[
poly_exp;
NOT_SUC] THEN
DISCH_THEN(MP_TAC o CONJUNCT1) THEN REWRITE_TAC[divides] THEN
DISCH_THEN(X_CHOOSE_THEN `s:real list` SUBST1_TAC) THEN
REWRITE_TAC[
POLY_MUL; poly] THEN REAL_ARITH_TAC]);;
let ORDER_DIVIDES = prove
(`!p a n. ([--a; &1] exp n) divides p <=>
(poly p = poly []) \/ n <= order a p`,
let ORDER_DECOMP = prove
(`!p a. ~(poly p = poly [])
==> ?q. (poly p = poly (([--a; &1] exp (order a p)) ** q)) /\
~([--a; &1] divides q)`,
REPEAT STRIP_TAC THEN FIRST_ASSUM(MP_TAC o MATCH_MP
ORDER_THM) THEN
DISCH_THEN(CONJUNCTS_THEN2 MP_TAC ASSUME_TAC o SPEC `a:real`) THEN
DISCH_THEN(X_CHOOSE_TAC `q:real list` o REWRITE_RULE[divides]) THEN
EXISTS_TAC `q:real list` THEN ASM_REWRITE_TAC[] THEN
DISCH_THEN(X_CHOOSE_TAC `r: real list` o REWRITE_RULE[divides]) THEN
UNDISCH_TAC `~([-- a; &1] exp SUC (order a p) divides p)` THEN
ASM_REWRITE_TAC[] THEN REWRITE_TAC[divides] THEN
EXISTS_TAC `r:real list` THEN
ASM_REWRITE_TAC[
POLY_MUL;
FUN_EQ_THM;
poly_exp] THEN
REAL_ARITH_TAC);;
(* ------------------------------------------------------------------------- *)
(* Important composition properties of orders. *)
(* ------------------------------------------------------------------------- *)
let ORDER_MUL = prove
(`!a p q. ~(poly (p ** q) = poly []) ==>
(order a (p ** q) = order a p + order a q)`,
REPEAT GEN_TAC THEN
DISCH_THEN(fun th -> ASSUME_TAC th THEN MP_TAC th) THEN
REWRITE_TAC[
POLY_ENTIRE; DE_MORGAN_THM] THEN STRIP_TAC THEN
SUBGOAL_THEN `(order a p + order a q = order a (p ** q)) /\
~(poly (p ** q) = poly [])`
MP_TAC THENL [ALL_TAC; MESON_TAC[]] THEN
REWRITE_TAC[GSYM
ORDER] THEN CONJ_TAC THENL
[MP_TAC(CONJUNCT1 (SPEC `a:real`
(MATCH_MP
ORDER_THM (ASSUME `~(poly p = poly [])`)))) THEN
DISCH_THEN(X_CHOOSE_TAC `r: real list` o REWRITE_RULE[divides]) THEN
MP_TAC(CONJUNCT1 (SPEC `a:real`
(MATCH_MP
ORDER_THM (ASSUME `~(poly q = poly [])`)))) THEN
DISCH_THEN(X_CHOOSE_TAC `s: real list` o REWRITE_RULE[divides]) THEN
REWRITE_TAC[divides;
FUN_EQ_THM] THEN EXISTS_TAC `s ** r` THEN
ASM_REWRITE_TAC[
POLY_MUL;
POLY_EXP_ADD] THEN REAL_ARITH_TAC;
X_CHOOSE_THEN `r: real list` STRIP_ASSUME_TAC
(SPEC `a:real` (MATCH_MP
ORDER_DECOMP (ASSUME `~(poly p = poly [])`))) THEN
X_CHOOSE_THEN `s: real list` STRIP_ASSUME_TAC
(SPEC `a:real` (MATCH_MP
ORDER_DECOMP (ASSUME `~(poly q = poly [])`))) THEN
ASM_REWRITE_TAC[divides;
FUN_EQ_THM;
POLY_EXP_ADD;
POLY_MUL;
poly_exp] THEN
DISCH_THEN(X_CHOOSE_THEN `t:real list` STRIP_ASSUME_TAC) THEN
SUBGOAL_THEN `[--a; &1] divides (r ** s)` MP_TAC THENL
[ALL_TAC; ASM_REWRITE_TAC[
POLY_PRIMES]] THEN
REWRITE_TAC[divides] THEN EXISTS_TAC `t:real list` THEN
SUBGOAL_THEN `poly ([-- a; &1] exp (order a p) ** r ** s) =
poly ([-- a; &1] exp (order a p) ** ([-- a; &1] ** t))`
MP_TAC THENL
[ALL_TAC; MESON_TAC[
POLY_MUL_LCANCEL;
POLY_EXP_PRIME_EQ_0]] THEN
SUBGOAL_THEN `poly ([-- a; &1] exp (order a q) **
[-- a; &1] exp (order a p) ** r ** s) =
poly ([-- a; &1] exp (order a q) **
[-- a; &1] exp (order a p) **
[-- a; &1] ** t)`
MP_TAC THENL
[ALL_TAC; MESON_TAC[
POLY_MUL_LCANCEL;
POLY_EXP_PRIME_EQ_0]] THEN
REWRITE_TAC[
FUN_EQ_THM;
POLY_MUL;
POLY_ADD] THEN
FIRST_ASSUM(UNDISCH_TAC o check is_forall o concl) THEN
REWRITE_TAC[
REAL_MUL_AC]]);;
let ORDER_DIFF = prove
(`!p a. ~(poly (diff p) = poly []) /\
~(order a p = 0)
==> (order a p = SUC (order a (diff p)))`,
REPEAT GEN_TAC THEN
DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
SUBGOAL_THEN `~(poly p = poly [])` MP_TAC THENL
[ASM_MESON_TAC[
POLY_DIFF_ZERO]; ALL_TAC] THEN
DISCH_THEN(X_CHOOSE_THEN `q:real list` MP_TAC o
SPEC `a:real` o MATCH_MP
ORDER_DECOMP) THEN
SPEC_TAC(`order a p`,`n:num`) THEN
INDUCT_TAC THEN REWRITE_TAC[
NOT_SUC;
SUC_INJ] THEN
STRIP_TAC THEN MATCH_MP_TAC
ORDER_UNIQUE THEN
ASM_REWRITE_TAC[] THEN
SUBGOAL_THEN `!r. r divides (diff p) <=>
r divides (diff ([-- a; &1] exp SUC n ** q))`
(fun th -> REWRITE_TAC[th]) THENL
[GEN_TAC THEN REWRITE_TAC[divides] THEN
FIRST_ASSUM(fun th -> REWRITE_TAC[MATCH_MP
POLY_DIFF_WELLDEF th]);
ALL_TAC] THEN
CONJ_TAC THENL
[REWRITE_TAC[divides;
FUN_EQ_THM] THEN
EXISTS_TAC `[--a; &1] ** (diff q) ++ &(SUC n) ## q` THEN
REWRITE_TAC[
POLY_DIFF_MUL;
POLY_DIFF_EXP_PRIME;
POLY_ADD;
POLY_MUL;
POLY_CMUL] THEN
REWRITE_TAC[
poly_exp;
POLY_MUL] THEN REAL_ARITH_TAC;
REWRITE_TAC[
FUN_EQ_THM; divides;
POLY_DIFF_MUL;
POLY_DIFF_EXP_PRIME;
POLY_ADD;
POLY_MUL;
POLY_CMUL] THEN
DISCH_THEN(X_CHOOSE_THEN `r:real list` ASSUME_TAC) THEN
UNDISCH_TAC `~([-- a; &1] divides q)` THEN
REWRITE_TAC[divides] THEN
EXISTS_TAC `inv(&(SUC n)) ## (r ++ neg(diff q))` THEN
SUBGOAL_THEN
`poly ([--a; &1] exp n ** q) =
poly ([--a; &1] exp n ** ([-- a; &1] ** (inv (&(SUC n)) ##
(r ++ neg (diff q)))))`
MP_TAC THENL
[ALL_TAC; MESON_TAC[
POLY_MUL_LCANCEL;
POLY_EXP_PRIME_EQ_0]] THEN
REWRITE_TAC[
FUN_EQ_THM] THEN X_GEN_TAC `x:real` THEN
SUBGOAL_THEN
`!a b. (&(SUC n) * a = &(SUC n) * b) ==> (a = b)`
MATCH_MP_TAC THENL
[REWRITE_TAC[
REAL_EQ_MUL_LCANCEL; REAL_OF_NUM_EQ;
NOT_SUC]; ALL_TAC] THEN
REWRITE_TAC[
POLY_MUL;
POLY_CMUL] THEN
SUBGOAL_THEN `!a b c. &(SUC n) * a * b * inv(&(SUC n)) * c =
a * b * c`
(fun th -> REWRITE_TAC[th]) THENL
[REPEAT GEN_TAC THEN
GEN_REWRITE_TAC LAND_CONV [REAL_MUL_SYM] THEN
REWRITE_TAC[GSYM REAL_MUL_ASSOC] THEN AP_TERM_TAC THEN
AP_TERM_TAC THEN
GEN_REWRITE_TAC LAND_CONV [REAL_MUL_SYM] THEN
GEN_REWRITE_TAC RAND_CONV [GSYM
REAL_MUL_RID] THEN
REWRITE_TAC[GSYM REAL_MUL_ASSOC] THEN AP_TERM_TAC THEN
MATCH_MP_TAC
REAL_MUL_RINV THEN
REWRITE_TAC[REAL_OF_NUM_EQ;
NOT_SUC]; ALL_TAC] THEN
FIRST_ASSUM(MP_TAC o SPEC `x:real`) THEN
REWRITE_TAC[
poly_exp;
POLY_MUL;
POLY_ADD;
POLY_NEG] THEN
REAL_ARITH_TAC]);;
(* ------------------------------------------------------------------------- *)
(* Now justify the standard squarefree decomposition, i.e. f / gcd(f,f'). *)
(* ------------------------------------------------------------------------- *)
let POLY_SQUAREFREE_DECOMP_ORDER = prove
(`!p q d e r s.
~(poly (diff p) = poly []) /\
(poly p = poly (q ** d)) /\
(poly (diff p) = poly (e ** d)) /\
(poly d = poly (r ** p ++ s ** diff p))
==> !a. order a q = (if order a p = 0 then 0 else 1)`,
REPEAT STRIP_TAC THEN
SUBGOAL_THEN `order a p = order a q + order a d` MP_TAC THENL
[MATCH_MP_TAC
EQ_TRANS THEN EXISTS_TAC `order a (q ** d)` THEN
CONJ_TAC THENL
[MATCH_MP_TAC
ORDER_POLY THEN ASM_REWRITE_TAC[];
MATCH_MP_TAC
ORDER_MUL THEN
FIRST_ASSUM(fun th ->
GEN_REWRITE_TAC (RAND_CONV o LAND_CONV) [SYM th]) THEN
ASM_MESON_TAC[
POLY_DIFF_ZERO]]; ALL_TAC] THEN
ASM_CASES_TAC `order a p = 0` THEN ASM_REWRITE_TAC[] THENL
[ARITH_TAC; ALL_TAC] THEN
SUBGOAL_THEN `order a (diff p) =
order a e + order a d` MP_TAC THENL
[MATCH_MP_TAC
EQ_TRANS THEN EXISTS_TAC `order a (e ** d)` THEN
CONJ_TAC THENL
[ASM_MESON_TAC[
ORDER_POLY]; ASM_MESON_TAC[
ORDER_MUL]]; ALL_TAC] THEN
SUBGOAL_THEN `~(poly p = poly [])` ASSUME_TAC THENL
[ASM_MESON_TAC[
POLY_DIFF_ZERO]; ALL_TAC] THEN
MP_TAC(SPECL [`p:real list`; `a:real`]
ORDER_DIFF) THEN
ASM_REWRITE_TAC[] THEN
DISCH_THEN(fun th -> MP_TAC th THEN MP_TAC(AP_TERM `
PRE` th)) THEN
REWRITE_TAC[
PRE] THEN DISCH_THEN(ASSUME_TAC o SYM) THEN
SUBGOAL_THEN `order a (diff p) <= order a d` MP_TAC THENL
[SUBGOAL_THEN `([--a; &1] exp (order a (diff p))) divides d`
MP_TAC THENL [ALL_TAC; ASM_MESON_TAC[
POLY_ENTIRE;
ORDER_DIVIDES]] THEN
SUBGOAL_THEN
`([--a; &1] exp (order a (diff p))) divides p /\
([--a; &1] exp (order a (diff p))) divides (diff p)`
MP_TAC THENL
[REWRITE_TAC[
ORDER_DIVIDES;
LE_REFL] THEN DISJ2_TAC THEN
REWRITE_TAC[ASSUME `order a (diff p) =
PRE (order a p)`] THEN
ARITH_TAC;
DISCH_THEN(CONJUNCTS_THEN MP_TAC) THEN REWRITE_TAC[divides] THEN
REWRITE_TAC[ASSUME `poly d = poly (r ** p ++ s ** diff p)`] THEN
POP_ASSUM_LIST(K ALL_TAC) THEN
DISCH_THEN(X_CHOOSE_THEN `f:real list` ASSUME_TAC) THEN
DISCH_THEN(X_CHOOSE_THEN `g:real list` ASSUME_TAC) THEN
EXISTS_TAC `r ** g ++ s ** f` THEN ASM_REWRITE_TAC[] THEN
ASM_REWRITE_TAC[
FUN_EQ_THM;
POLY_MUL;
POLY_ADD] THEN ARITH_TAC];
ARITH_TAC]);;
(* ------------------------------------------------------------------------- *)
(* Define being "squarefree" --- NB with respect to real roots only. *)
(* ------------------------------------------------------------------------- *)
(* ------------------------------------------------------------------------- *)
(* Standard squarefree criterion and rephasing of squarefree decomposition. *)
(* ------------------------------------------------------------------------- *)
let RSQUAREFREE_ROOTS = prove
(`!p. rsquarefree p <=> !a. ~((poly p a = &0) /\ (poly (diff p) a = &0))`,
GEN_TAC THEN REWRITE_TAC[rsquarefree] THEN
ASM_CASES_TAC `poly p = poly []` THEN ASM_REWRITE_TAC[] THENL
[FIRST_ASSUM(SUBST1_TAC o MATCH_MP
POLY_DIFF_ZERO) THEN
ASM_REWRITE_TAC[poly;
NOT_FORALL_THM];
ASM_CASES_TAC `poly(diff p) = poly []` THEN ASM_REWRITE_TAC[] THENL
[FIRST_ASSUM(X_CHOOSE_THEN `h:real` MP_TAC o
MATCH_MP
POLY_DIFF_ISZERO) THEN
DISCH_THEN(fun th -> ASSUME_TAC th THEN MP_TAC th) THEN
DISCH_THEN(fun th -> REWRITE_TAC[MATCH_MP
ORDER_POLY th]) THEN
UNDISCH_TAC `~(poly p = poly [])` THEN ASM_REWRITE_TAC[poly] THEN
REWRITE_TAC[
FUN_EQ_THM; poly;
REAL_MUL_RZERO;
REAL_ADD_RID] THEN
DISCH_TAC THEN ASM_REWRITE_TAC[] THEN
X_GEN_TAC `a:real` THEN DISJ1_TAC THEN
MP_TAC(SPECL [`[h:real]`; `a:real`]
ORDER_ROOT) THEN
ASM_REWRITE_TAC[
FUN_EQ_THM; poly;
REAL_MUL_RZERO;
REAL_ADD_RID];
ASM_REWRITE_TAC[
ORDER_ROOT; DE_MORGAN_THM; num_CONV `1`] THEN
ASM_MESON_TAC[
ORDER_DIFF;
SUC_INJ]]]);;
let RSQUAREFREE_DECOMP = prove
(`!p a. rsquarefree p /\ (poly p a = &0)
==> ?q. (poly p = poly ([--a; &1] ** q)) /\
~(poly q a = &0)`,
REPEAT GEN_TAC THEN REWRITE_TAC[rsquarefree] THEN STRIP_TAC THEN
FIRST_ASSUM(MP_TAC o MATCH_MP
ORDER_DECOMP) THEN
DISCH_THEN(X_CHOOSE_THEN `q:real list` MP_TAC o SPEC `a:real`) THEN
FIRST_ASSUM(MP_TAC o GEN_REWRITE_RULE I [
ORDER_ROOT]) THEN
FIRST_ASSUM(DISJ_CASES_TAC o SPEC `a:real`) THEN ASM_REWRITE_TAC[] THEN
REWRITE_TAC[ARITH] THEN
DISCH_THEN(CONJUNCTS_THEN2 SUBST_ALL_TAC ASSUME_TAC) THEN
EXISTS_TAC `q:real list` THEN CONJ_TAC THENL
[REWRITE_TAC[
FUN_EQ_THM;
POLY_MUL] THEN GEN_TAC THEN
AP_THM_TAC THEN AP_TERM_TAC THEN
GEN_REWRITE_TAC (LAND_CONV o LAND_CONV o RAND_CONV) [num_CONV `1`] THEN
REWRITE_TAC[
poly_exp;
POLY_MUL] THEN
REWRITE_TAC[poly] THEN REAL_ARITH_TAC;
DISCH_TAC THEN UNDISCH_TAC `~([-- a; &1] divides q)` THEN
REWRITE_TAC[divides] THEN
UNDISCH_TAC `poly q a = &0` THEN
GEN_REWRITE_TAC LAND_CONV [
POLY_LINEAR_DIVIDES] THEN
ASM_CASES_TAC `q:real list = []` THEN ASM_REWRITE_TAC[] THENL
[EXISTS_TAC `[] : real list` THEN REWRITE_TAC[
FUN_EQ_THM] THEN
REWRITE_TAC[
POLY_MUL; poly;
REAL_MUL_RZERO];
MESON_TAC[]]]);;
let POLY_SQUAREFREE_DECOMP = prove
(`!p q d e r s.
~(poly (diff p) = poly []) /\
(poly p = poly (q ** d)) /\
(poly (diff p) = poly (e ** d)) /\
(poly d = poly (r ** p ++ s ** diff p))
==> rsquarefree q /\ (!a. (poly q a = &0) <=> (poly p a = &0))`,
REPEAT GEN_TAC THEN DISCH_THEN(fun th -> MP_TAC th THEN
ASSUME_TAC(MATCH_MP
POLY_SQUAREFREE_DECOMP_ORDER th)) THEN
DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
SUBGOAL_THEN `~(poly p = poly [])` ASSUME_TAC THENL
[ASM_MESON_TAC[
POLY_DIFF_ZERO]; ALL_TAC] THEN
DISCH_THEN(ASSUME_TAC o CONJUNCT1) THEN
UNDISCH_TAC `~(poly p = poly [])` THEN
DISCH_THEN(fun th -> MP_TAC th THEN MP_TAC th) THEN
DISCH_THEN(fun th -> ASM_REWRITE_TAC[] THEN ASSUME_TAC th) THEN
ASM_REWRITE_TAC[] THEN
REWRITE_TAC[
POLY_ENTIRE; DE_MORGAN_THM] THEN STRIP_TAC THEN
UNDISCH_TAC `poly p = poly (q ** d)` THEN
DISCH_THEN(SUBST_ALL_TAC o SYM) THEN
ASM_REWRITE_TAC[rsquarefree;
ORDER_ROOT] THEN
CONJ_TAC THEN GEN_TAC THEN COND_CASES_TAC THEN REWRITE_TAC[ARITH]);;
(* ------------------------------------------------------------------------- *)
(* Normalization of a polynomial. *)
(* ------------------------------------------------------------------------- *)
let POLY_NORMALIZE = prove
(`!p. poly (normalize p) = poly p`,
LIST_INDUCT_TAC THEN REWRITE_TAC[normalize; poly] THEN
ASM_CASES_TAC `h = &0` THEN ASM_REWRITE_TAC[] THEN
COND_CASES_TAC THEN ASM_REWRITE_TAC[poly;
FUN_EQ_THM] THEN
UNDISCH_TAC `poly (normalize t) = poly t` THEN
DISCH_THEN(SUBST1_TAC o SYM) THEN ASM_REWRITE_TAC[poly] THEN
REWRITE_TAC[
REAL_MUL_RZERO; REAL_ADD_LID]);;
(* ------------------------------------------------------------------------- *)
(* The degree of a polynomial. *)
(* ------------------------------------------------------------------------- *)
let DEGREE_ZERO = prove
(`!p. (poly p = poly []) ==> (degree p = 0)`,
REPEAT STRIP_TAC THEN REWRITE_TAC[degree] THEN
SUBGOAL_THEN `normalize p = []` SUBST1_TAC THENL
[POP_ASSUM MP_TAC THEN SPEC_TAC(`p:real list`,`p:real list`) THEN
REWRITE_TAC[
POLY_ZERO] THEN
LIST_INDUCT_TAC THEN REWRITE_TAC[normalize;
ALL] THEN
STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
SUBGOAL_THEN `normalize t = []` (fun th -> REWRITE_TAC[th]) THEN
FIRST_ASSUM MATCH_MP_TAC THEN ASM_REWRITE_TAC[];
REWRITE_TAC[
LENGTH;
PRE]]);;
(* ------------------------------------------------------------------------- *)
(* Tidier versions of finiteness of roots. *)
(* ------------------------------------------------------------------------- *)
(* ------------------------------------------------------------------------- *)
(* Crude bound for polynomial. *)
(* ------------------------------------------------------------------------- *)
(* ------------------------------------------------------------------------- *)
(* Conversions to perform operations if coefficients are rational constants. *)
(* ------------------------------------------------------------------------- *)
let POLY_DIFF_CONV =
let aux_conv0 = GEN_REWRITE_CONV I [CONJUNCT1 poly_diff_aux]
and aux_conv1 = GEN_REWRITE_CONV I [CONJUNCT2 poly_diff_aux]
and diff_conv0 = GEN_REWRITE_CONV I (butlast (CONJUNCTS POLY_DIFF_CLAUSES))
and diff_conv1 = GEN_REWRITE_CONV I [last (CONJUNCTS POLY_DIFF_CLAUSES)] in
let rec POLY_DIFF_AUX_CONV tm =
(aux_conv0 ORELSEC
(aux_conv1 THENC
LAND_CONV REAL_RAT_MUL_CONV THENC
RAND_CONV (LAND_CONV NUM_SUC_CONV THENC POLY_DIFF_AUX_CONV))) tm in
diff_conv0 ORELSEC
(diff_conv1 THENC POLY_DIFF_AUX_CONV);;
let POLY_CMUL_CONV =
let cmul_conv0 = GEN_REWRITE_CONV I [CONJUNCT1 poly_cmul]
and cmul_conv1 = GEN_REWRITE_CONV I [CONJUNCT2 poly_cmul] in
let rec POLY_CMUL_CONV tm =
(cmul_conv0 ORELSEC
(cmul_conv1 THENC
LAND_CONV REAL_RAT_MUL_CONV THENC
RAND_CONV POLY_CMUL_CONV)) tm in
POLY_CMUL_CONV;;
let POLY_ADD_CONV =
let add_conv0 = GEN_REWRITE_CONV I (butlast (CONJUNCTS POLY_ADD_CLAUSES))
and add_conv1 = GEN_REWRITE_CONV I [last (CONJUNCTS POLY_ADD_CLAUSES)] in
let rec POLY_ADD_CONV tm =
(add_conv0 ORELSEC
(add_conv1 THENC
LAND_CONV REAL_RAT_ADD_CONV THENC
RAND_CONV POLY_ADD_CONV)) tm in
POLY_ADD_CONV;;
let POLY_MUL_CONV =
let mul_conv0 = GEN_REWRITE_CONV I [CONJUNCT1 POLY_MUL_CLAUSES]
and mul_conv1 = GEN_REWRITE_CONV I [CONJUNCT1(CONJUNCT2 POLY_MUL_CLAUSES)]
and mul_conv2 = GEN_REWRITE_CONV I [CONJUNCT2(CONJUNCT2 POLY_MUL_CLAUSES)] in
let rec POLY_MUL_CONV tm =
(mul_conv0 ORELSEC
(mul_conv1 THENC POLY_CMUL_CONV) ORELSEC
(mul_conv2 THENC
LAND_CONV POLY_CMUL_CONV THENC
RAND_CONV(RAND_CONV POLY_MUL_CONV) THENC
POLY_ADD_CONV)) tm in
POLY_MUL_CONV;;
let POLY_NORMALIZE_CONV =
let pth = prove
(`normalize (CONS h t) =
(\n. if n = [] then if h = &0 then [] else [h] else CONS h n)
(normalize t)`,
REWRITE_TAC[normalize]) in
let norm_conv0 = GEN_REWRITE_CONV I [CONJUNCT1 normalize]
and norm_conv1 = GEN_REWRITE_CONV I [pth]
and norm_conv2 = GEN_REWRITE_CONV DEPTH_CONV
[
COND_CLAUSES;
NOT_CONS_NIL; EQT_INTRO(SPEC_ALL
EQ_REFL)] in
let rec POLY_NORMALIZE_CONV tm =
(norm_conv0 ORELSEC
(norm_conv1 THENC
RAND_CONV POLY_NORMALIZE_CONV THENC
BETA_CONV THENC
RATOR_CONV(RAND_CONV(RATOR_CONV(LAND_CONV REAL_RAT_EQ_CONV))) THENC
norm_conv2)) tm in
POLY_NORMALIZE_CONV;;
(* ------------------------------------------------------------------------- *)
(* Some theorems asserting that operations give non-nil results. *)
(* ------------------------------------------------------------------------- *)
(* ------------------------------------------------------------------------- *)
(* Some general lemmas. *)
(* ------------------------------------------------------------------------- *)
let POLY_ADD_SYM = prove
(`!x y . x ++ y = y ++ x`,
let lem1 = ASSUME `!y . t ++ y = y ++ t` in
let lem2 = SPEC `t':(real)list` lem1 in
LIST_INDUCT_TAC THENL
[LIST_INDUCT_TAC THENL [SIMP_TAC[
poly_add]; SIMP_TAC[
poly_add]];
LIST_INDUCT_TAC THENL
[SIMP_TAC[
poly_add];
SIMP_TAC[
POLY_ADD_CLAUSES] THEN
ONCE_REWRITE_TAC[lem2] THEN
SIMP_TAC[SPECL [`h:real`;`h':real`] REAL_ADD_SYM]
]
]);;
(* ------------------------------------------------------------------------- *)
(* Heads and tails resulting from operations. *)
(* ------------------------------------------------------------------------- *)
let HD_POLY_ADD = prove
(`!p1 p2. ~(p1 = []) /\ ~(p2 = []) ==>
HD (p1 ++ p2) = (
HD p1) + (
HD p2)`,
LIST_INDUCT_TAC THENL
[SIMP_TAC[];
LIST_INDUCT_TAC THENL
[SIMP_TAC[];
SIMP_TAC[
NOT_CONS_NIL;
poly_add] THEN
ONCE_REWRITE_TAC[ISPECL [`h':real`;`t':(real)list`]
NOT_CONS_NIL] THEN
SIMP_TAC[
HD]
]
]);;
(* ------------------------------------------------------------------------- *)
(* Additional general lemmas. *)
(* ------------------------------------------------------------------------- *)
let POLY_ADD_IDENT = prove
(`neutral (++) = []`,
let l1 = ASSUME `!x. (!y. x ++ y = y /\ y ++ x = y)
==> (!y. (CONS h t) ++ y = y /\ y ++ (CONS h t) = y)` in
let l2 = SPEC `[]:(real)list` l1 in
let l3 = SIMP_RULE[
POLY_ADD_CLAUSES] l2 in
let l4 = SPEC `[]:(real)list` l3 in
let l5 = CONJUNCT1 l4 in
let l6 = SIMP_RULE[
POLY_ADD_CLAUSES;
NOT_CONS_NIL] l5 in
let l7 = NOT_INTRO (DISCH_ALL l6) in
ONCE_REWRITE_TAC[neutral] THEN SELECT_ELIM_TAC THEN LIST_INDUCT_TAC THENL
[SIMP_TAC[];SIMP_TAC[l7]]);;
(* ------------------------------------------------------------------------- *)
(* Theorems about the lengths of lists from the polynomial operations. *)
(* ------------------------------------------------------------------------- *)
let POLY_MUL_LENGTH = prove
(`!p h t.
LENGTH (p ** (CONS h t)) >=
LENGTH p`,
let lemma01 = ASSUME `!h t'.
LENGTH (t ** CONS h t') >=
LENGTH t` in
let lemma02 = SPECL [`h':real`;`t':(real)list`] lemma01 in
let lemma03 = ONCE_REWRITE_RULE[ARITH_RULE `(x:num) >= y <=> SUC x >= SUC y`]
lemma02 in
(* ------------------------------------------------------------------------- *)
(* Expansion of a polynomial as a power sum. *)
(* ------------------------------------------------------------------------- *)
let POLY_SUM_EQUIV = prove
(`!p x.
~(p = []) ==>
poly p x = sum (0..(
PRE (
LENGTH p))) (\i. (
EL i p)*(x pow i))`,
let lem000 = ARITH_RULE `0 <= 0 + 1 /\ 0 <= (LENGTH (t:(real)list))` in
let lem001 = SPECL
[`f:num->real`;`0`;`0`;`LENGTH (t:(real)list)`]
SUM_COMBINE_R in
let lem002 = MP lem001 lem000 in
let lem003 = SPECL
[`f:num->real`;`1`;`LENGTH (t:(real)list)`]
SUM_OFFSET_0 in
let lem004 = ASSUME `~((t:(real)list) = [])` in
let lem005 = ONCE_REWRITE_RULE[GSYM LENGTH_EQ_NIL] lem004 in
let lem006 = ONCE_REWRITE_RULE[ARITH_RULE `~(x = 0) <=> (1 <= x)`] lem005 in
let lem007 = MP lem003 lem006 in
let lem017 = ARITH_RULE `1 <= (LENGTH (t:(real)list))
==> ((LENGTH t) - 1 = PRE (LENGTH t))` in
let lem018 = MP lem017 lem006 in
LIST_INDUCT_TAC THENL
[ SIMP_TAC[NOT_CONS_NIL]
;
ASM_CASES_TAC `(t:(real)list) = []` THENL
[
ASM_SIMP_TAC[POLY_CONST;LENGTH;PRE]
THEN ONCE_REWRITE_TAC[NUMSEG_CONV `0..0`]
THEN ONCE_REWRITE_TAC[SUM_SING]
THEN BETA_TAC
THEN ONCE_REWRITE_TAC[EL]
THEN ONCE_REWRITE_TAC[HD]
THEN REAL_ARITH_TAC
;
ASM_SIMP_TAC[POLY_CONST;LENGTH;PRE]
THEN ONCE_REWRITE_TAC[poly]
THEN ONCE_REWRITE_TAC[GSYM lem002]
THEN ONCE_REWRITE_TAC[ARITH_RULE `0 + 1 = 1`]
THEN ONCE_REWRITE_TAC[NUMSEG_CONV `0..0`]
THEN ONCE_REWRITE_TAC[SUM_SING]
THEN BETA_TAC
THEN SIMP_TAC[EL;HD]
THEN ONCE_REWRITE_TAC[lem007]
THEN BETA_TAC
THEN ONCE_REWRITE_TAC[GSYM ADD1]
THEN SIMP_TAC[EL;TL]
THEN ONCE_REWRITE_TAC[real_pow]
THEN ONCE_REWRITE_TAC[REAL_MUL_RID]
THEN ONCE_REWRITE_TAC[REAL_ARITH `(A:real) * B * C = B * (A * C)`]
THEN ONCE_REWRITE_TAC[NSUM_LMUL]
THEN ONCE_REWRITE_TAC[SUM_LMUL]
THEN ASM_SIMP_TAC[]
THEN SIMP_TAC[NOT_CONS_NIL]
THEN ONCE_REWRITE_TAC[lem018]
THEN SIMP_TAC[]
]]);;
(* ------------------------------------------------------------------------- *)
(* Now we're finished with polynomials... *)
(* ------------------------------------------------------------------------- *)
do_list reduce_interface
["divides",`poly_divides:real list->real list->bool`;
"exp",`poly_exp:real list -> num -> real list`;
"diff",`poly_diff:real list->real list`];;
unparse_as_infix "exp";;