(* $Id: CPoly_Rev.v,v 1.7 2000/11/07 16:04:06 janz Exp $ *)

Require Export CPoly_Degree.

Section Monomials.

Variable R : CRing.
Local RX := (cpoly_cring R).

Fixpoint monom [a:R; n:nat] : (cpoly_cring R) :=
  Cases n of
    O => (cpoly_linear ? a (cpoly_zero ?))
  | (S m) => (cpoly_linear ? Zero (monom a m))
  end.

Lemma monom_coeff :
  (c:R)(n:nat)(Nth_coeff n (monom c n)) [=] c.
Intros. Induction n; Intros.
Simpl. Algebra.
Simpl. Algebra.
Qed.

Lemma monom_coeff' :
  (c:R)(m,n:nat)(~m=n) -> (Nth_coeff n (monom c m)) [=] Zero.
Intros c m.
Induction m; Intros.
Elim (O_or_S n); Intros. Elim y. Clear y. Intros. Rewrite <- y.
Simpl. Algebra.
Elim (H y).
Elim (O_or_S n); Intros. Elim y. Clear y. Intros. Rewrite <- y.
Simpl. Apply Hrecm. Omega.
Rewrite <- y.
Simpl. Algebra.
Qed.

Hints Resolve monom_coeff monom_coeff' : algebra.

Lemma monom_degree :
  (a:R)(n:nat)(Degree_le n (monom a n)).
Unfold degree_le. Intros.
Cut ~n=m. Intro. Algebra. Omega.
Qed.

Lemma monom_S :
  (a:R)(n:nat)
    (monom a (S n)) [=] _X_[*](monom a n).
Intros.
Apply eq_transitive_unfolded with (cpoly_linear ? Zero (monom a n)).
Simpl. Split. Algebra. Cut (monom a n) [=] (monom a n). Auto. Algebra.
Step _X_[*](monom a n)[+](_C_ Zero).
Step_final _X_[*](monom a n)[+]Zero.
Qed.

Hints Resolve monom_S : algebra.

Lemma monom_wd_lft :
  (a,b:R)(n:nat)(a [=] b) -> (monom a n) [=] (monom b n).
Intros.
Induction n.
Simpl. Split; Auto.
Step _X_[*](monom a n).
Step_final _X_[*](monom b n).
Qed.

Hints Resolve monom_wd_lft : algebra_c.

Lemma monom_mult' :
  (a,b:R)(n:nat)
    (_C_ a)[*](monom b n) [=] (monom a[*]b n).
Intros.
Induction n.
Simpl. Split; Algebra.
Step (_C_ a)[*](_X_[*](monom b n)).
Step (_C_ a)[*]_X_[*](monom b n).
Step _X_[*](_C_ a)[*](monom b n).
Step _X_[*]((_C_ a)[*](monom b n)).
Step_final _X_[*](monom a[*]b n).
Qed.

Hints Resolve monom_mult' : algebra.

Lemma monom_mult :
  (a,b:R)(m,n:nat)
    (monom a m)[*](monom b n) [=] (monom a[*]b (plus m n)).
Intros. Induction m; Intros.
Replace (monom a (0)) with (_C_ a). Algebra. Algebra.
Step _X_[*](monom a m)[*](monom b n).
Step _X_[*]((monom a m)[*](monom b n)).
Replace (plus (S m) n) with (S (plus m n)).
Step_final _X_[*](monom a[*]b (plus m n)).
Auto.
Qed.

Lemma monom_sum :
  (p:RX)(n:nat)(Degree_le n p) ->
    p [=] (Sum (0) n [i:nat](monom (Nth_coeff i p) i)).
Intros.
Apply all_Nth_coeff_eq_imp. Intros.
Apply eq_symmetric_unfolded.
Apply eq_transitive_unfolded with
  (Sum (0) n [i0:nat](Nth_coeff i (monom (Nth_coeff i0 p) i0))).
Apply nth_coeff_sum with p_ := [i0:nat](monom (Nth_coeff i0 p) i0).
Elim (le_lt_dec i n); Intros.
Apply eq_transitive_unfolded with (Nth_coeff i (monom (Nth_coeff i p) i)).
Apply sum_term with a := [i0:nat](Nth_coeff i (monom (Nth_coeff i0 p) i0))
  i0 := i.
Auto with arith. Auto.
Intros. Algebra.
Algebra.
Apply eq_transitive_unfolded with Zero::R.
Apply sum_zero. Auto with arith.
Intros. Cut ~i0=i. Intro. Algebra. Omega.
Algebra.
Qed.

End Monomials.

Hints Resolve monom_coeff monom_coeff' monom_mult monom_sum : algebra.

Syntactic Definition Monom := (monom ?).


Section Poly_Reverse.

Variable R : CRing.
Local RX := (cpoly_cring R).

Definition poly_rev :=
  [n:nat; p:RX]
    (Sum (0) n [i:nat](Monom (Nth_coeff i p) (minus n i))).

Lemma poly_rev_coeff :
  (n:nat)(p:RX)(i:nat)(le i n) ->
    (Nth_coeff i (poly_rev n p)) [=] (Nth_coeff (minus n i) p).
Intros.
Unfold poly_rev.
Apply eq_transitive_unfolded with
  (Sum (0) n [i0:nat](Nth_coeff i (Monom (Nth_coeff i0 p) (minus n i0)))).
Apply nth_coeff_sum with p_ :=
  [i0:nat](Monom (Nth_coeff i0 p) (minus n i0)).
Apply eq_transitive_unfolded with
  (Nth_coeff i (Monom (Nth_coeff (minus n i) p) (minus n (minus n i)))).
Apply sum_term with i0 := (minus n i)
  a := [i0:nat](Nth_coeff i (Monom (Nth_coeff i0 p) (minus n i0))).
Auto with arith. Omega.
Intros.
Cut ~(minus n i0)=i. Intro. Algebra. Omega.
Replace (minus n (minus n i)) with i. Algebra. Omega.
Qed.

Lemma poly_rev_coeff' :
  (n:nat)(p:RX)(i:nat)(lt n i) ->
    (Nth_coeff i (poly_rev n p)) [=] Zero.
Intros.
Unfold poly_rev.
Apply eq_transitive_unfolded with
  (Sum (0) n [i0:nat](Nth_coeff i (Monom (Nth_coeff i0 p) (minus n i0)))).
Apply nth_coeff_sum with p_ :=
  [i0:nat](monom R (nth_coeff R i0 p) (minus n i0)).
Apply sum_zero. Auto with arith.
Intros.
Cut ~(minus n i0)=i. Intro. Algebra. Omega.
Qed.

Hints Resolve poly_rev_coeff poly_rev_coeff' : algebra.

Lemma poly_rev_wd :
  (n:nat)(p,p':RX)(Degree_le n p) ->
    (p [=] p') -> ((poly_rev n p) [=] (poly_rev n p')).
Unfold RX. Intros.
Apply all_Nth_coeff_eq_imp. Intros.
Elim (le_lt_dec i n); Intros.
Step (Nth_coeff (minus n i) p).
Step_final (Nth_coeff (minus n i) p').
Step_final Zero::R.
Qed.

Hints Resolve poly_rev_wd : algebra_c.

Lemma poly_rev_rev :
  (n:nat)(p:RX)(Degree_le n p) ->
    (poly_rev n (poly_rev n p)) [=] p.
Unfold RX. Intros.
Apply all_Nth_coeff_eq_imp. Intros.
Elim (le_lt_dec i n); Intros.
Step (Nth_coeff (minus n i) (poly_rev n p)).
Pattern 2 i. Replace i with (minus n (minus n i)).
Apply poly_rev_coeff.
Omega.
Omega.
Unfold degree_le in H.
Step_final Zero::R.
Qed.

Hints Resolve poly_rev_rev : algebra.

Lemma poly_rev_degree_le :
  (n:nat)(p:RX)(Degree_le n (poly_rev n p)).
Unfold degree_le. Algebra.
Qed.

Lemma poly_rev_degree :
  (n:nat)(p:RX)(p!Zero [#] Zero) -> (Degree n (poly_rev n p)).
Unfold degree_le. Unfold degree. Intros. Split.
Step_ap_lft (Nth_coeff (minus n n) p).
Replace (minus n n) with (0).
Step_ap_lft p!Zero.
Auto with arith.
Apply poly_rev_degree_le.
Qed.

Lemma poly_rev_monom :
  (c:R)(m,n:nat)(le m n) ->
    (poly_rev n (Monom c m)) [=] (Monom c (minus n m)).
Intros.
Apply all_Nth_coeff_eq_imp. Intros.
Elim (le_lt_dec i n); Intros.
Step (Nth_coeff (minus n i) (Monom c m)).
Elim (eq_nat_dec m (minus n i)); Intros.
Cut i=(minus n m). Intro.
Rewrite <- y0. Rewrite H0. Step_final c.
Omega.
Cut ~(minus n m)=i. Intro.
Step_final Zero::R.
Omega.
Cut ~(minus n m)=i. Intro.
Step_final Zero::R.
Omega.
Qed.

Hints Resolve poly_rev_monom : algebra.

Lemma poly_rev_zero :
  (n:nat)(poly_rev n Zero) [=] Zero::RX.
Intros.
Apply all_Nth_coeff_eq_imp. Intros.
Elim (le_lt_dec i n); Intros.
Step (Nth_coeff (minus n i) Zero)::R.
Step_final Zero::R.
Step_final Zero::R.
Qed.

Hints Resolve poly_rev_zero : algebra.

Lemma poly_rev_plus :
  (p1,p2:RX)(n:nat)
    (poly_rev n p1[+]p2) [=] (poly_rev n p1)[+](poly_rev n p2).
Intros.
Apply all_Nth_coeff_eq_imp. Intros.
Elim (le_lt_dec i n); Intros.
Step (Nth_coeff (minus n i) p1[+]p2).
Unfold RX.
Step (Nth_coeff (minus n i) p1)[+](Nth_coeff (minus n i) p2).
Step_final (Nth_coeff i (poly_rev n p1))[+](Nth_coeff i (poly_rev n p2)).
Step Zero::R.
Step Zero[+]Zero::R.
Step_final (Nth_coeff i (poly_rev n p1))[+](Nth_coeff i (poly_rev n p2)).
Qed.

Hints Resolve poly_rev_plus : algebra.

Lemma poly_rev_minus :
  (p1,p2:RX)(n:nat)
    (poly_rev n p1[-]p2) [=] (poly_rev n p1)[-](poly_rev n p2).
Intros.
Apply all_Nth_coeff_eq_imp. Intros.
Elim (le_lt_dec i n); Intros.
Step (Nth_coeff (minus n i) p1[-]p2).
Unfold RX.
Step (Nth_coeff (minus n i) p1)[-](Nth_coeff (minus n i) p2).
Step_final (Nth_coeff i (poly_rev n p1))[-](Nth_coeff i (poly_rev n p2)).
Step Zero::R.
Step Zero[-]Zero::R.
Step_final (Nth_coeff i (poly_rev n p1))[-](Nth_coeff i (poly_rev n p2)).
Qed.

Hints Resolve poly_rev_minus : algebra.

Lemma poly_rev_sum0 :
  (a_:nat->RX)(l,n:nat)
    (poly_rev n (Sum0 l a_)) [=] (Sum0 l [i:nat](poly_rev n (a_ i))).
Intros.
Induction l.
Replace (Sum0 (0) a_) with Zero::RX.
Replace (Sum0 (0) [i:nat](poly_rev n (a_ i))) with Zero::RX.
Algebra. Auto. Auto.
Replace (Sum0 (S l) a_) with (Sum0 l a_)[+](a_ l).
Replace (Sum0 (S l) [i:nat](poly_rev n (a_ i))) with
  (Sum0 l [i:nat](poly_rev n (a_ i)))[+](poly_rev n (a_ l)).
Step (poly_rev n (Sum0 l a_))[+](poly_rev n (a_ l)).
Apply bin_op_wd_unfolded. Auto. Algebra.
Auto. Auto.
Qed.

Hints Resolve poly_rev_sum0 : algebra.

Lemma poly_rev_sum :
  (a_:nat->RX)(k,l,n:nat)
    (poly_rev n (Sum k l a_)) [=] (Sum k l [i:nat](poly_rev n (a_ i))).
Intros.
Unfold sum. Unfold sum1.
Step (poly_rev n (Sum0 (S l) a_))[-](poly_rev n (Sum0 k a_)).
Apply cg_minus_wd; Apply poly_rev_sum0.
Qed.

Lemma poly_rev_mult :
  (n1,n2:nat)(p1,p2:RX)(Degree_le n1 p1) -> (Degree_le n2 p2) ->
    (poly_rev (plus n1 n2) p1[*]p2) [=] (poly_rev n1 p1)[*](poly_rev n2 p2).
Intros.
Cut (Degree_le (plus n1 n2) p1[*]p2). Intro.
Cut p1[*]p2 [=]
  (Sum (0) n2 [i2:nat](Sum (0) n1 [i1:nat]
    (Monom (Nth_coeff i1 p1)[*](Nth_coeff i2 p2) (plus i1 i2)))). Intro.
Cut (poly_rev (plus n1 n2) p1[*]p2) [=]
  (Sum (0) n2 [i2:nat](Sum (0) n1 [i1:nat]
    (Monom (Nth_coeff i1 p1)[*](Nth_coeff i2 p2)
      (minus (plus n1 n2) (plus i1 i2))))). Intro.
Cut (poly_rev n1 p1) [=]
  (Sum (0) n1 [i1:nat](Monom (Nth_coeff i1 p1) (minus n1 i1))). Intro.
Cut (poly_rev n2 p2) [=]
  (Sum (0) n2 [i2:nat](Monom (Nth_coeff i2 p2) (minus n2 i2))). Intro.
Cut (poly_rev n1 p1)[*](poly_rev n2 p2) [=]
  (Sum (0) n2 [i2:nat](Sum (0) n1 [i1:nat]
    (Monom (Nth_coeff i1 p1)[*](Nth_coeff i2 p2)
      (minus (plus n1 n2) (plus i1 i2))))). Intro.
Step_final (Sum (0) n2 [i2:nat](Sum (0) n1 [i1:nat]
  (Monom (Nth_coeff i1 p1)[*](Nth_coeff i2 p2)
    (minus (plus n1 n2) (plus i1 i2))))).
Step (Sum (0) n1 [i1:nat](Monom (Nth_coeff i1 p1) (minus n1 i1)))[*]
  (Sum (0) n2 [i2:nat](Monom (Nth_coeff i2 p2) (minus n2 i2))).
Apply eq_transitive_unfolded with
  (Sum (0) n2 [i2:nat]
    ((Sum (0) n1 [i1:nat](Monom (Nth_coeff i1 p1) (minus n1 i1)))[*]
      (Monom (Nth_coeff i2 p2) (minus n2 i2)))).
Apply eq_symmetric_unfolded.
Apply mult_distr_sum_lft with f :=
  [i2:nat](Monom (Nth_coeff i2 p2) (minus n2 i2)).
Apply sum_wd'. Auto with arith. Intro i2. Intros.
Step (Monom (Nth_coeff i2 p2) (minus n2 i2))[*]
  (Sum (0) n1 [i1:nat](Monom (Nth_coeff i1 p1) (minus n1 i1))).
Apply eq_transitive_unfolded with
  (Sum (0) n1 [i1:nat](Monom (Nth_coeff i2 p2) (minus n2 i2))[*]
    (Monom (Nth_coeff i1 p1) (minus n1 i1))).
Apply eq_symmetric_unfolded.
Apply mult_distr_sum_lft with f :=
  [i1:nat](Monom (Nth_coeff i1 p1) (minus n1 i1)).
Apply sum_wd'. Auto with arith. Intro i1. Intros.
Step (Monom (Nth_coeff i1 p1) (minus n1 i1))[*]
  (Monom (Nth_coeff i2 p2) (minus n2 i2)).
Step (Monom (Nth_coeff i1 p1)[*](Nth_coeff i2 p2)
  (plus (minus n1 i1) (minus n2 i2))).
Replace (plus (minus n1 i1) (minus n2 i2)) with
  (minus (plus n1 n2) (plus i1 i2)).
Algebra.
Omega.
Unfold poly_rev. Algebra.
Unfold poly_rev. Algebra.
Step (poly_rev (plus n1 n2)
  (Sum (0) n2 [i2:nat](Sum (0) n1 [i1:nat]
    (Monom (Nth_coeff i1 p1)[*](Nth_coeff i2 p2) (plus i1 i2))))).
Apply eq_transitive_unfolded with
  (Sum (0) n2 [i2:nat](poly_rev (plus n1 n2) (Sum (0) n1 [i1:nat]
    (Monom (Nth_coeff i1 p1)[*](Nth_coeff i2 p2) (plus i1 i2))))).
Apply poly_rev_sum with a_ :=
  [i2:nat](Sum (0) n1 [i1:nat]
    (Monom (Nth_coeff i1 p1)[*](Nth_coeff i2 p2) (plus i1 i2))).
Apply sum_wd'. Auto with arith. Intro i2. Intros.
Apply eq_transitive_unfolded with
  (Sum (0) n1 [i1:nat](poly_rev (plus n1 n2)
    (Monom (Nth_coeff i1 p1)[*](Nth_coeff i2 p2) (plus i1 i2)))).
Apply poly_rev_sum with a_ :=
  [i1:nat](Monom (Nth_coeff i1 p1)[*](Nth_coeff i2 p2) (plus i1 i2)).
Apply sum_wd'. Auto with arith. Intro i1. Intros.
Apply poly_rev_monom. Omega.
Step (Sum (0) n1 [i1:nat](Monom (Nth_coeff i1 p1) i1))[*]
  (Sum (0) n2 [i2:nat](Monom (Nth_coeff i2 p2) i2)).
Apply eq_transitive_unfolded with
  (Sum (0) n2 [i2:nat](Sum (0) n1 [i1:nat](Monom (Nth_coeff i1 p1) i1))[*]
    (Monom (Nth_coeff i2 p2) i2)).
Apply eq_symmetric_unfolded.
Apply mult_distr_sum_lft with f := [i2:nat](Monom (Nth_coeff i2 p2) i2).
Apply sum_wd'. Auto with arith. Intro i2. Intros.
Step (Monom (Nth_coeff i2 p2) i2)[*]
  (Sum (0) n1 [i1:nat](Monom (Nth_coeff i1 p1) i1)).
Apply eq_transitive_unfolded with
  (Sum (0) n1 [i1:nat](Monom (Nth_coeff i2 p2) i2)[*]
    (Monom (Nth_coeff i1 p1) i1)).
Apply eq_symmetric_unfolded.
Apply mult_distr_sum_lft with f := [i1:nat](Monom (Nth_coeff i1 p1) i1).
Apply sum_wd'. Auto with arith. Intro i1. Intros.
Step_final (Monom (Nth_coeff i1 p1) i1)[*](Monom (Nth_coeff i2 p2) i2).
Unfold RX. Apply Degree_le_mult; Auto.
Qed.

End Poly_Reverse.

Hints Resolve poly_rev_wd : algebra_c.
Hints Resolve poly_rev_rev poly_rev_mult : algebra.

Syntactic Definition Rev := (poly_rev ?).


