(************************************************************************)
(*         *      The Rocq Prover / The Rocq Development Team           *)
(*  v      *         Copyright INRIA, CNRS and contributors             *)
(* <O___,, * (see version control and CREDITS file for authors & dates) *)
(*   \VV/  **************************************************************)
(*    //   *    This file is distributed under the terms of the         *)
(*         *     GNU Lesser General Public License Version 2.1          *)
(*         *     (see LICENSE file for the text of the license)         *)
(************************************************************************)
Require Ring.
Set Implicit Arguments.
(* Set Universe Polymorphism. *)
Section MakeFieldPol.
(* Field elements : R *)
Variable R:Type.
Declare Scope R_scope.
Bind Scope R_scope with R.
Delimit Scope R_scope with ring.
Local Open Scope R_scope.
Variable (rO rI : R) (radd rmul rsub: R->R->R) (ropp : R->R).
Variable (rdiv : R->R->R) (rinv : R->R).
Variable req : R -> R -> Prop.
Notation "0" := rO : R_scope.
Notation "1" := rI : R_scope.
Infix "+" := radd : R_scope.
Infix "-" := rsub : R_scope.
Infix "*" := rmul : R_scope.
Infix "/" := rdiv : R_scope.
Notation "- x" := (ropp x) : R_scope.
Notation "/ x" := (rinv x) : R_scope.
Infix "==" := req (at level 70, no associativity) : R_scope.
(* Equality properties *)
Variable Rsth : Equivalence req.
Variable Reqe : ring_eq_ext radd rmul ropp req.
Variable SRinv_ext : forall p q, p == q ->  / p == / q.
(* Field properties *)
Record almost_field_theory : Prop := mk_afield {
AF_AR : almost_ring_theory rO rI radd rmul rsub ropp req;
AF_1_neq_0 : ~ 1 == 0;
AFdiv_def : forall p q, p / q == p * / q;
AFinv_l : forall p, ~ p == 0 ->  / p * p == 1
}.
Section AlmostField.
Variable AFth : almost_field_theory.
Let ARth := (AF_AR AFth).
Let rI_neq_rO := (AF_1_neq_0 AFth).
Let rdiv_def := (AFdiv_def AFth).
Let rinv_l := (AFinv_l AFth).
Add Morphism radd with signature (req ==> req ==> req) as radd_ext.
(* Power coefficients : Cpow *)
Variable Cpow : Type.
Variable Cp_phi : N -> Cpow.
Variable rpow : R -> Cpow -> R.
Variable pow_th : power_theory rI rmul req Cp_phi rpow.
(* sign function *)
Variable get_sign : C -> option C.
Variable get_sign_spec : sign_theory copp ceqb get_sign.
Variable cdiv:C -> C -> C*C.
Variable cdiv_th : div_theory req cadd cmul phi cdiv.
Let rpow_pow := (rpow_pow_N pow_th).
(* Polynomial expressions : (PExpr C) *)
Declare Scope PE_scope.
Bind Scope PE_scope with PExpr.
Delimit Scope PE_scope with poly.
Notation NPEeval := (PEeval rO rI radd rmul rsub ropp phi Cp_phi rpow).
Notation "P @ l" := (NPEeval l P) (at level 10, no associativity).
Arguments PEc _ _%_coef.
Notation "0" := (PEc 0) : PE_scope.
Notation "1" := (PEc 1) : PE_scope.
Infix "+" := PEadd : PE_scope.
Infix "-" := PEsub : PE_scope.
Infix "*" := PEmul : PE_scope.
Notation "- e" := (PEopp e) : PE_scope.
Infix "^" := PEpow : PE_scope.
Definition NPEequiv e e' := forall l, e@l == e'@l.
Infix "===" := NPEequiv (at level 70, no associativity) : PE_scope.
Instance NPEequiv_eq : Equivalence NPEequiv.
Instance NPEeval_ext : Proper (eq ==> NPEequiv ==> req) NPEeval.
Notation Nnorm :=
(norm_subst cO cI cadd cmul csub copp ceqb cdiv).
Notation NPphi_dev :=
(Pphi_dev rO rI radd rmul rsub ropp cO cI ceqb phi get_sign).
Notation NPphi_pow :=
(Pphi_pow rO rI radd rmul rsub ropp cO cI ceqb phi Cp_phi rpow get_sign).
(* add abstract semi-ring to help with some proofs *)
Add Ring Rring : (ARth_SRth ARth).
(* additional ring properties *)

(* Specifications: *)
Lemma rsub_0_l r : 0 - r == - r.
Lemma rsub_0_r r : r - 0 == r.
(***************************************************************************  Properties of division  ***************************************************************************)
Theorem rdiv_simpl p q : ~ q == 0 ->  q * (p / q) == p.
Instance rdiv_ext: Proper (req ==> req ==> req) rdiv.
Lemma rmul_reg_l p q1 q2 :
~ p == 0 -> p * q1 == p * q2 -> q1 == q2.
Theorem field_is_integral_domain r1 r2 :
~ r1 == 0 -> ~ r2 == 0 -> ~ r1 * r2 == 0.
Theorem ropp_neq_0 r :
~ -(1) == 0 -> ~ r == 0 -> ~ -r == 0.
Theorem rdiv_r_r r : ~ r == 0 -> r / r == 1.
Theorem rdiv1 r : r == r / 1.
Theorem rdiv2 a b c d :
~ b == 0 ->
~ d == 0 ->
a / b + c / d == (a * d + c * b) / (b * d).
Theorem rdiv2b a b c d e :
~ (b*e) == 0 ->
~ (d*e) == 0 ->
a / (b*e) + c / (d*e) == (a * d + c * b) / (b * (d * e)).
Theorem rdiv5 a b : - (a / b) == - a / b.
Theorem rdiv3b a b c d e :
~ (b * e) == 0 ->
~ (d * e) == 0 ->
a / (b*e) - c / (d*e) == (a * d - c * b) / (b * (d * e)).
Theorem rdiv6 a b :
~ a == 0 -> ~ b == 0 ->  / (a / b) == b / a.
Theorem rdiv4 a b c d :
~ b == 0 ->
~ d == 0 ->
(a / b) * (c / d) == (a * c) / (b * d).
Theorem rdiv4b a b c d e f :
~ b * e == 0 ->
~ d * f == 0 ->
((a * f) / (b * e)) * ((c * e) / (d * f)) == (a * c) / (b * d).
Theorem rdiv7 a b c d :
~ b == 0 ->
~ c == 0 ->
~ d == 0 ->
(a / b) / (c / d) == (a * d) / (b * c).
Theorem rdiv7b a b c d e f :
~ b * f == 0 ->
~ c * e == 0 ->
~ d * f == 0 ->
((a * e) / (b * f)) / ((c * e) / (d * f)) == (a * d) / (b * c).
Theorem rinv_nz a : ~ a == 0 -> ~ /a == 0.
Theorem rdiv8 a b : ~ b == 0 -> a == 0 ->  a / b == 0.
Theorem cross_product_eq a b c d :
~ b == 0 -> ~ d == 0 -> a * d == c * b -> a / b == c / d.