aboutsummaryrefslogtreecommitdiff
path: root/mathcomp/algebra/ssralg.v
diff options
context:
space:
mode:
authorEnrico Tassi2015-03-09 11:07:53 +0100
committerEnrico Tassi2015-03-09 11:24:38 +0100
commitfc84c27eac260dffd8f2fb1cb56d599f1e3486d9 (patch)
treec16205f1637c80833a4c4598993c29fa0fd8c373 /mathcomp/algebra/ssralg.v
Initial commit
Diffstat (limited to 'mathcomp/algebra/ssralg.v')
-rw-r--r--mathcomp/algebra/ssralg.v6230
1 files changed, 6230 insertions, 0 deletions
diff --git a/mathcomp/algebra/ssralg.v b/mathcomp/algebra/ssralg.v
new file mode 100644
index 0000000..5f4592b
--- /dev/null
+++ b/mathcomp/algebra/ssralg.v
@@ -0,0 +1,6230 @@
+(* (c) Copyright Microsoft Corporation and Inria. All rights reserved. *)
+Require Import ssreflect ssrfun ssrbool eqtype ssrnat div seq choice fintype.
+Require Import finfun bigop prime binomial.
+
+(******************************************************************************)
+(* The algebraic part of the Algebraic Hierarchy, as described in *)
+(* ``Packaging mathematical structures'', TPHOLs09, by *)
+(* Francois Garillot, Georges Gonthier, Assia Mahboubi, Laurence Rideau *)
+(* *)
+(* This file defines for each Structure (Zmodule, Ring, etc ...) its type, *)
+(* its packers and its canonical properties : *)
+(* *)
+(* * Zmodule (additive abelian groups): *)
+(* zmodType == interface type for Zmodule structure. *)
+(* ZmodMixin addA addC add0x addNx == builds the mixin for a Zmodule from the *)
+(* algebraic properties of its operations. *)
+(* ZmodType V m == packs the mixin m to build a Zmodule of type *)
+(* zmodType. The carrier type V must have a *)
+(* choiceType canonical structure. *)
+(* [zmodType of V for S] == V-clone of the zmodType structure S: a copy of S *)
+(* where the sort carrier has been replaced by V, *)
+(* and which is therefore a zmodType structure on V. *)
+(* The sort carrier for S must be convertible to V. *)
+(* [zmodType of V] == clone of a canonical zmodType structure on V. *)
+(* Similar to the above, except S is inferred, but *)
+(* possibly with a syntactically different carrier. *)
+(* 0 == the zero (additive identity) of a Zmodule. *)
+(* x + y == the sum of x and y (in a Zmodule). *)
+(* - x == the opposite (additive inverse) of x. *)
+(* x - y == the difference of x and y; this is only notation *)
+(* for x + (- y). *)
+(* x *+ n == n times x, with n in nat (non-negative), i.e., *)
+(* x + (x + .. (x + x)..) (n terms); x *+ 1 is thus *)
+(* convertible to x, and x *+ 2 to x + x. *)
+(* x *- n == notation for - (x *+ n), the opposite of x *+ n. *)
+(* \sum_<range> e == iterated sum for a Zmodule (cf bigop.v). *)
+(* e`_i == nth 0 e i, when e : seq M and M has a zmodType *)
+(* structure. *)
+(* support f == 0.-support f, i.e., [pred x | f x != 0]. *)
+(* oppr_closed S <-> collective predicate S is closed under opposite. *)
+(* addr_closed S <-> collective predicate S is closed under finite *)
+(* sums (0 and x + y in S, for x, y in S). *)
+(* zmod_closed S <-> collective predicate S is closed under zmodType *)
+(* operations (0 and x - y in S, for x, y in S). *)
+(* This property coerces to oppr_pred and addr_pred. *)
+(* OpprPred oppS == packs oppS : oppr_closed S into an opprPred S *)
+(* interface structure associating this property to *)
+(* the canonical pred_key S, i.e. the k for which S *)
+(* has a Canonical keyed_pred k structure (see file *)
+(* ssrbool.v). *)
+(* AddrPred addS == packs addS : addr_closed S into an addrPred S *)
+(* interface structure associating this property to *)
+(* the canonical pred_key S (see above). *)
+(* ZmodPred oppS == packs oppS : oppr_closed S into an zmodPred S *)
+(* interface structure associating the zmod_closed *)
+(* property to the canonical pred_key S (see above), *)
+(* which must already be an addrPred. *)
+(* [zmodMixin of M by <:] == zmodType mixin for a subType whose base type is *)
+(* a zmodType and whose predicate's canonical *)
+(* pred_key is a zmodPred. *)
+(* --> Coq can be made to behave as if all predicates had canonical zmodPred *)
+(* keys by executing Import DefaultKeying GRing.DefaultPred. The required *)
+(* oppr_closed and addr_closed assumptions will be either abstracted, *)
+(* resolved or issued as separate proof obligations by the ssreflect *)
+(* plugin abstraction and Prop-irrelevance functions. *)
+(* * Ring (non-commutative rings): *)
+(* ringType == interface type for a Ring structure. *)
+(* RingMixin mulA mul1x mulx1 mulDx mulxD == builds the mixin for a Ring from *)
+(* the algebraic properties of its multiplicative *)
+(* operators; the carrier type must have a zmodType *)
+(* structure. *)
+(* RingType R m == packs the ring mixin m into a ringType. *)
+(* R^c == the converse Ring for R: R^c is convertible to R *)
+(* but when R has a canonical ringType structure *)
+(* R^c has the converse one: if x y : R^c, then *)
+(* x * y = (y : R) * (x : R). *)
+(* [ringType of R for S] == R-clone of the ringType structure S. *)
+(* [ringType of R] == clone of a canonical ringType structure on R. *)
+(* 1 == the multiplicative identity element of a Ring. *)
+(* n%:R == the ring image of an n in nat; this is just *)
+(* notation for 1 *+ n, so 1%:R is convertible to 1 *)
+(* and 2%:R to 1 + 1. *)
+(* x * y == the ring product of x and y. *)
+(* \prod_<range> e == iterated product for a ring (cf bigop.v). *)
+(* x ^+ n == x to the nth power with n in nat (non-negative), *)
+(* i.e., x * (x * .. (x * x)..) (n factors); x ^+ 1 *)
+(* is thus convertible to x, and x ^+ 2 to x * x. *)
+(* GRing.sign R b := (-1) ^+ b in R : ringType, with b : bool. *)
+(* This is a parsing-only helper notation, to be *)
+(* used for defining more specific instances. *)
+(* GRing.comm x y <-> x and y commute, i.e., x * y = y * x. *)
+(* GRing.lreg x <-> x if left-regular, i.e., *%R x is injective. *)
+(* GRing.rreg x <-> x if right-regular, i.e., *%R x is injective. *)
+(* [char R] == the characteristic of R, defined as the set of *)
+(* prime numbers p such that p%:R = 0 in R. The set *)
+(* [char p] has a most one element, and is *)
+(* implemented as a pred_nat collective predicate *)
+(* (see prime.v); thus the statement p \in [char R] *)
+(* can be read as `R has characteristic p', while *)
+(* [char R] =i pred0 means `R has characteristic 0' *)
+(* when R is a field. *)
+(* Frobenius_aut chRp == the Frobenius automorphism mapping x in R to *)
+(* x ^+ p, where chRp : p \in [char R] is a proof *)
+(* that R has (non-zero) characteristic p. *)
+(* mulr_closed S <-> collective predicate S is closed under finite *)
+(* products (1 and x * y in S for x, y in S). *)
+(* smulr_closed S <-> collective predicate S is closed under products *)
+(* and opposite (-1 and x * y in S for x, y in S). *)
+(* semiring_closed S <-> collective predicate S is closed under semiring *)
+(* operations (0, 1, x + y and x * y in S). *)
+(* subring_closed S <-> collective predicate S is closed under ring *)
+(* operations (1, x - y and x * y in S). *)
+(* MulrPred mulS == packs mulS : mulr_closed S into a mulrPred S, *)
+(* SmulrPred mulS smulrPred S, semiringPred S, or subringPred S *)
+(* SemiringPred mulS interface structure, corresponding to the above *)
+(* SubRingPred mulS properties, respectively, provided S already has *)
+(* the supplementary zmodType closure properties. *)
+(* The properties above coerce to subproperties so, *)
+(* e.g., ringS : subring_closed S can be used for *)
+(* the proof obligations of all prerequisites. *)
+(* [ringMixin of R by <:] == ringType mixin for a subType whose base type is *)
+(* a ringType and whose predicate's canonical key *)
+(* is a SubringPred. *)
+(* --> As for zmodType predicates, Import DefaultKeying GRing.DefaultPred *)
+(* turns unresolved GRing.Pred unification constraints into proof *)
+(* obligations for basic closure assumptions. *)
+(* *)
+(* * ComRing (commutative Rings): *)
+(* comRingType == interface type for commutative ring structure. *)
+(* ComRingType R mulC == packs mulC into a comRingType; the carrier type *)
+(* R must have a ringType canonical structure. *)
+(* ComRingMixin mulA mulC mul1x mulDx == builds the mixin for a Ring (i.e., a *)
+(* *non commutative* ring), using the commutativity *)
+(* to reduce the number of proof obligations. *)
+(* [comRingType of R for S] == R-clone of the comRingType structure S. *)
+(* [comRingType of R] == clone of a canonical comRingType structure on R. *)
+(* [comRingMixin of R by <:] == comutativity mixin axiom for R when it is a *)
+(* subType of a commutative ring. *)
+(* *)
+(* * UnitRing (Rings whose units have computable inverses): *)
+(* unitRingType == interface type for the UnitRing structure. *)
+(* UnitRingMixin mulVr mulrV unitP inv0id == builds the mixin for a UnitRing *)
+(* from the properties of the inverse operation and *)
+(* the boolean test for being a unit (invertible). *)
+(* The inverse of a non-unit x is constrained to be *)
+(* x itself (property inv0id). The carrier type *)
+(* must have a ringType canonical structure. *)
+(* UnitRingType R m == packs the unit ring mixin m into a unitRingType. *)
+(* WARNING: while it is possible to omit R for most of the *)
+(* XxxType functions, R MUST be explicitly given *)
+(* when UnitRingType is used with a mixin produced *)
+(* by ComUnitRingMixin, otherwise the resulting *)
+(* structure will have the WRONG sort key and will *)
+(* NOT BE USED during type inference. *)
+(* [unitRingType of R for S] == R-clone of the unitRingType structure S. *)
+(* [unitRingType of R] == clones a canonical unitRingType structure on R. *)
+(* x \is a GRing.unit <=> x is a unit (i.e., has an inverse). *)
+(* x^-1 == the ring inverse of x, if x is a unit, else x. *)
+(* x / y == x divided by y (notation for x * y^-1). *)
+(* x ^- n := notation for (x ^+ n)^-1, the inverse of x ^+ n. *)
+(* invr_closed S <-> collective predicate S is closed under inverse. *)
+(* divr_closed S <-> collective predicate S is closed under division *)
+(* (1 and x / y in S). *)
+(* sdivr_closed S <-> collective predicate S is closed under division *)
+(* and opposite (-1 and x / y in S, for x, y in S). *)
+(* divring_closed S <-> collective predicate S is closed under unitRing *)
+(* operations (1, x - y and x / y in S). *)
+(* DivrPred invS == packs invS : mulr_closed S into a divrPred S, *)
+(* SdivrPred invS sdivrPred S or divringPred S interface structure, *)
+(* DivringPred invS corresponding to the above properties, resp., *)
+(* provided S already has the supplementary ringType *)
+(* closure properties. The properties above coerce *)
+(* to subproperties, as explained above. *)
+(* [unitRingMixin of R by <:] == unitRingType mixin for a subType whose base *)
+(* type is a unitRingType and whose predicate's *)
+(* canonical key is a divringPred and whose ring *)
+(* structure is compatible with the base type's. *)
+(* *)
+(* * ComUnitRing (commutative rings with computable inverses): *)
+(* comUnitRingType == interface type for ComUnitRing structure. *)
+(* ComUnitRingMixin mulVr unitP inv0id == builds the mixin for a UnitRing (a *)
+(* *non commutative* unit ring, using commutativity *)
+(* to simplify the proof obligations; the carrier *)
+(* type must have a comRingType structure. *)
+(* WARNING: ALWAYS give an explicit type argument *)
+(* to UnitRingType along with a mixin produced by *)
+(* ComUnitRingMixin (see above). *)
+(* [comUnitRingType of R] == a comUnitRingType structure for R created by *)
+(* merging canonical comRingType and unitRingType *)
+(* structures on R. *)
+(* *)
+(* * IntegralDomain (integral, commutative, ring with partial inverses): *)
+(* idomainType == interface type for the IntegralDomain structure. *)
+(* IdomainType R mulf_eq0 == packs the integrality property into an *)
+(* idomainType integral domain structure; R must *)
+(* have a comUnitRingType canonical structure. *)
+(* [idomainType of R for S] == R-clone of the idomainType structure S. *)
+(* [idomainType of R] == clone of a canonical idomainType structure on R. *)
+(* [idomainMixin of R by <:] == mixin axiom for a idomain subType. *)
+(* *)
+(* * Field (commutative fields): *)
+(* fieldType == interface type for fields. *)
+(* GRing.Field.axiom inv == the field axiom (x != 0 -> inv x * x = 1). *)
+(* FieldUnitMixin mulVx unitP inv0id == builds a *non commutative unit ring* *)
+(* mixin, using the field axiom to simplify proof *)
+(* obligations. The carrier type must have a *)
+(* comRingType canonical structure. *)
+(* FieldMixin mulVx == builds the field mixin from the field axiom. The *)
+(* carrier type must have a comRingType structure. *)
+(* FieldIdomainMixin m == builds an *idomain* mixin from a field mixin m. *)
+(* FieldType R m == packs the field mixin M into a fieldType. The *)
+(* carrier type R must be an idomainType. *)
+(* [fieldType of F for S] == F-clone of the fieldType structure S. *)
+(* [fieldType of F] == clone of a canonical fieldType structure on F. *)
+(* [fieldMixin of R by <:] == mixin axiom for a field subType. *)
+(* *)
+(* * DecidableField (fields with a decidable first order theory): *)
+(* decFieldType == interface type for DecidableField structure. *)
+(* DecFieldMixin satP == builds the mixin for a DecidableField from the *)
+(* correctness of its satisfiability predicate. The *)
+(* carrier type must have a unitRingType structure. *)
+(* DecFieldType F m == packs the decidable field mixin m into a *)
+(* decFieldType; the carrier type F must have a *)
+(* fieldType structure. *)
+(* [decFieldType of F for S] == F-clone of the decFieldType structure S. *)
+(* [decFieldType of F] == clone of a canonical decFieldType structure on F *)
+(* GRing.term R == the type of formal expressions in a unit ring R *)
+(* with formal variables 'X_k, k : nat, and *)
+(* manifest constants x%:T, x : R. The notation of *)
+(* all the ring operations is redefined for terms, *)
+(* in scope %T. *)
+(* GRing.formula R == the type of first order formulas over R; the %T *)
+(* scope binds the logical connectives /\, \/, ~, *)
+(* ==>, ==, and != to formulae; GRing.True/False *)
+(* and GRing.Bool b denote constant formulae, and *)
+(* quantifiers are written 'forall/'exists 'X_k, f. *)
+(* GRing.Unit x tests for ring units *)
+(* GRing.If p_f t_f e_f emulates if-then-else *)
+(* GRing.Pick p_f t_f e_f emulates fintype.pick *)
+(* foldr GRing.Exists/Forall q_f xs can be used *)
+(* to write iterated quantifiers. *)
+(* GRing.eval e t == the value of term t with valuation e : seq R *)
+(* (e maps 'X_i to e`_i). *)
+(* GRing.same_env e1 e2 <-> environments e1 and e2 are extensionally equal. *)
+(* GRing.qf_form f == f is quantifier-free. *)
+(* GRing.holds e f == the intuitionistic CiC interpretation of the *)
+(* formula f holds with valuation e. *)
+(* GRing.qf_eval e f == the value (in bool) of a quantifier-free f. *)
+(* GRing.sat e f == valuation e satisfies f (only in a decField). *)
+(* GRing.sol n f == a sequence e of size n such that e satisfies f, *)
+(* if one exists, or [::] if there is no such e. *)
+(* QEdecFieldMixin wfP okP == a decidable field Mixin built from a quantifier *)
+(* eliminator p and proofs wfP : GRing.wf_QE_proj p *)
+(* and okP : GRing.valid_QE_proj p that p returns *)
+(* well-formed and valid formulae, i.e., p i (u, v) *)
+(* is a quantifier-free formula equivalent to *)
+(* 'exists 'X_i, u1 == 0 /\ ... /\ u_m == 0 /\ v1 != 0 ... /\ v_n != 0 *)
+(* *)
+(* * ClosedField (algebraically closed fields): *)
+(* closedFieldType == interface type for the ClosedField structure. *)
+(* ClosedFieldType F m == packs the closed field mixin m into a *)
+(* closedFieldType. The carrier F must have a *)
+(* decFieldType structure. *)
+(* [closedFieldType of F on S] == F-clone of a closedFieldType structure S. *)
+(* [closedFieldType of F] == clone of a canonicalclosedFieldType structure *)
+(* on F. *)
+(* *)
+(* * Lmodule (module with left multiplication by external scalars). *)
+(* lmodType R == interface type for an Lmodule structure with *)
+(* scalars of type R; R must have a ringType *)
+(* structure. *)
+(* LmodMixin scalA scal1v scalxD scalDv == builds an Lmodule mixin from the *)
+(* algebraic properties of the scaling operation; *)
+(* the module carrier type must have a zmodType *)
+(* structure, and the scalar carrier must have a *)
+(* ringType structure. *)
+(* LmodType R V m == packs the mixin v to build an Lmodule of type *)
+(* lmodType R. The carrier type V must have a *)
+(* zmodType structure. *)
+(* [lmodType R of V for S] == V-clone of an lmodType R structure S. *)
+(* [lmodType R of V] == clone of a canonical lmodType R structure on V. *)
+(* a *: v == v scaled by a, when v is in an Lmodule V and a *)
+(* is in the scalar Ring of V. *)
+(* scaler_closed S <-> collective predicate S is closed under scaling. *)
+(* linear_closed S <-> collective predicate S is closed under linear *)
+(* combinations (a *: u + v in S when u, v in S). *)
+(* submod_closed S <-> collective predicate S is closed under lmodType *)
+(* operations (0 and a *: u + v in S). *)
+(* SubmodPred scaleS == packs scaleS : scaler_closed S in a submodPred S *)
+(* interface structure corresponding to the above *)
+(* property, provided S's key is a zmodPred; *)
+(* submod_closed coerces to all the prerequisites. *)
+(* [lmodMixin of V by <:] == mixin for a subType of an lmodType, whose *)
+(* predicate's key is a submodPred. *)
+(* *)
+(* * Lalgebra (left algebra, ring with scaling that associates on the left): *)
+(* lalgType R == interface type for Lalgebra structures with *)
+(* scalars in R; R must have ringType structure. *)
+(* LalgType R V scalAl == packs scalAl : k (x y) = (k x) y into an *)
+(* Lalgebra of type lalgType R. The carrier type V *)
+(* must have both lmodType R and ringType canonical *)
+(* structures. *)
+(* R^o == the regular algebra of R: R^o is convertible to *)
+(* R, but when R has a ringType structure then R^o *)
+(* extends it to an lalgType structure by letting R *)
+(* act on itself: if x : R and y : R^o then *)
+(* x *: y = x * (y : R). *)
+(* k%:A == the image of the scalar k in an L-algebra; this *)
+(* is simply notation for k *: 1. *)
+(* [lalgType R of V for S] == V-clone the lalgType R structure S. *)
+(* [lalgType R of V] == clone of a canonical lalgType R structure on V. *)
+(* subalg_closed S <-> collective predicate S is closed under lalgType *)
+(* operations (1, a *: u + v and u * v in S). *)
+(* SubalgPred scaleS == packs scaleS : scaler_closed S in a subalgPred S *)
+(* interface structure corresponding to the above *)
+(* property, provided S's key is a subringPred; *)
+(* subalg_closed coerces to all the prerequisites. *)
+(* [lalgMixin of V by <:] == mixin axiom for a subType of an lalgType. *)
+(* *)
+(* * Algebra (ring with scaling that associates both left and right): *)
+(* algType R == type for Algebra structure with scalars in R. *)
+(* R should be a commutative ring. *)
+(* AlgType R A scalAr == packs scalAr : k (x y) = x (k y) into an Algebra *)
+(* Structure of type algType R. The carrier type A *)
+(* must have an lalgType R structure. *)
+(* CommAlgType R A == creates an Algebra structure for an A that has *)
+(* both lalgType R and comRingType structures. *)
+(* [algType R of V for S] == V-clone of an algType R structure on S. *)
+(* [algType R of V] == clone of a canonical algType R structure on V. *)
+(* [algMixin of V by <:] == mixin axiom for a subType of an algType. *)
+(* *)
+(* * UnitAlgebra (algebra with computable inverses): *)
+(* unitAlgType R == interface type for UnitAlgebra structure with *)
+(* scalars in R; R should have a unitRingType *)
+(* structure. *)
+(* [unitAlgType R of V] == a unitAlgType R structure for V created by *)
+(* merging canonical algType and unitRingType on V. *)
+(* divalg_closed S <-> collective predicate S is closed under all *)
+(* unitAlgType operations (1, a *: u + v and u / v *)
+(* are in S fo u, v in S). *)
+(* DivalgPred scaleS == packs scaleS : scaler_closed S in a divalgPred S *)
+(* interface structure corresponding to the above *)
+(* property, provided S's key is a divringPred; *)
+(* divalg_closed coerces to all the prerequisites. *)
+(* *)
+(* In addition to this structure hierarchy, we also develop a separate, *)
+(* parallel hierarchy for morphisms linking these structures: *)
+(* *)
+(* * Additive (additive functions): *)
+(* additive f <-> f of type U -> V is additive, i.e., f maps the *)
+(* Zmodule structure of U to that of V, 0 to 0, *)
+(* - to - and + to + (equivalently, binary - to -). *)
+(* := {morph f : u v / u + v}. *)
+(* {additive U -> V} == the interface type for a Structure (keyed on *)
+(* a function f : U -> V) that encapsulates the *)
+(* additive property; both U and V must have *)
+(* zmodType canonical structures. *)
+(* Additive add_f == packs add_f : additive f into an additive *)
+(* function structure of type {additive U -> V}. *)
+(* [additive of f as g] == an f-clone of the additive structure on the *)
+(* function g -- f and g must be convertible. *)
+(* [additive of f] == a clone of an existing additive structure on f. *)
+(* *)
+(* * RMorphism (ring morphisms): *)
+(* multiplicative f <-> f of type R -> S is multiplicative, i.e., f *)
+(* maps 1 and * in R to 1 and * in S, respectively, *)
+(* R ans S must have canonical ringType structures. *)
+(* rmorphism f <-> f is a ring morphism, i.e., f is both additive *)
+(* and multiplicative. *)
+(* {rmorphism R -> S} == the interface type for ring morphisms, i.e., *)
+(* a Structure that encapsulates the rmorphism *)
+(* property for functions f : R -> S; both R and S *)
+(* must have ringType structures. *)
+(* RMorphism morph_f == packs morph_f : rmorphism f into a Ring morphism *)
+(* structure of type {rmorphism R -> S}. *)
+(* AddRMorphism mul_f == packs mul_f : multiplicative f into an rmorphism *)
+(* structure of type {rmorphism R -> S}; f must *)
+(* already have an {additive R -> S} structure. *)
+(* [rmorphism of f as g] == an f-clone of the rmorphism structure of g. *)
+(* [rmorphism of f] == a clone of an existing additive structure on f. *)
+(* -> If R and S are UnitRings the f also maps units to units and inverses *)
+(* of units to inverses; if R is a field then f if a field isomorphism *)
+(* between R and its image. *)
+(* -> As rmorphism coerces to both additive and multiplicative, all *)
+(* structures for f can be built from a single proof of rmorphism f. *)
+(* -> Additive properties (raddf_suffix, see below) are duplicated and *)
+(* specialised for RMorphism (as rmorph_suffix). This allows more *)
+(* precise rewriting and cleaner chaining: although raddf lemmas will *)
+(* recognize RMorphism functions, the converse will not hold (we cannot *)
+(* add reverse inheritance rules because of incomplete backtracking in *)
+(* the Canonical Projection unification), so one would have to insert a *)
+(* /= every time one switched from additive to multiplicative rules. *)
+(* -> The property duplication also means that it is not strictly necessary *)
+(* to declare all Additive instances. *)
+(* *)
+(* * Linear (linear functions): *)
+(* scalable f <-> f of type U -> V is scalable, i.e., f morphs *)
+(* scaling on U to scaling on V, a *: _ to a *: _. *)
+(* U and V must both have lmodType R structures, *)
+(* for the same ringType R. *)
+(* scalable_for s f <-> f is scalable for scaling operator s, i.e., *)
+(* f morphs a *: _ to s a _; the range of f only *)
+(* need to be a zmodType. The scaling operator s *)
+(* should be one of *:%R (see scalable, above), *%R *)
+(* or a combination nu \; *%R or nu \; *:%R with *)
+(* nu : {rmorphism _}; otherwise some of the theory *)
+(* (e.g., the linearZ rule) will not apply. *)
+(* linear f <-> f of type U -> V is linear, i.e., f morphs *)
+(* linear combinations a *: u + v in U to similar *)
+(* linear combinations in V; U and V must both have *)
+(* lmodType R structures, for the same ringType R. *)
+(* := forall a, {morph f: u v / a *: u + v}. *)
+(* scalar f <-> f of type U -> R is a scalar function, i.e., *)
+(* f (a *: u + v) = a * f u + f v. *)
+(* linear_for s f <-> f is linear for the scaling operator s, i.e., *)
+(* f (a *: u + v) = s a (f u) + f v. The range of f *)
+(* only needs to be a zmodType, but s MUST be of *)
+(* the form described in in scalable_for paragraph *)
+(* for this predicate to type check. *)
+(* lmorphism f <-> f is both additive and scalable. This is in *)
+(* fact equivalent to linear f, although somewhat *)
+(* less convenient to prove. *)
+(* lmorphism_for s f <-> f is both additive and scalable for s. *)
+(* {linear U -> V} == the interface type for linear functions, i.e., a *)
+(* Structure that encapsulates the linear property *)
+(* for functions f : U -> V; both U and V must have *)
+(* lmodType R structures, for the same R. *)
+(* {scalar U} == the interface type for scalar functions, of type *)
+(* U -> R where U has an lmodType R structure. *)
+(* {linear U -> V | s} == the interface type for functions linear for s. *)
+(* Linear lin_f == packs lin_f : lmorphism_for s f into a linear *)
+(* function structure of type {linear U -> V | s}. *)
+(* As linear_for s f coerces to lmorphism_for s f, *)
+(* Linear can be used with lin_f : linear_for s f *)
+(* (indeed, that is the recommended usage). Note *)
+(* that as linear f, scalar f, {linear U -> V} and *)
+(* {scalar U} are simply notation for corresponding *)
+(* generic "_for" forms, Linear can be used for any *)
+(* of these special cases, transparently. *)
+(* AddLinear scal_f == packs scal_f : scalable_for s f into a *)
+(* {linear U -> V | s} structure; f must already *)
+(* have an additive structure; as with Linear, *)
+(* AddLinear can be used with lin_f : linear f, etc *)
+(* [linear of f as g] == an f-clone of the linear structure of g. *)
+(* [linear of f] == a clone of an existing linear structure on f. *)
+(* (a *: u)%Rlin == transient forms that simplify to a *: u, a * u, *)
+(* (a * u)%Rlin nu a *: u, and nu a * u, respectively, and are *)
+(* (a *:^nu u)%Rlin created by rewriting with the linearZ lemma. The *)
+(* (a *^nu u)%Rlin forms allows the RHS of linearZ to be matched *)
+(* reliably, using the GRing.Scale.law structure. *)
+(* -> Similarly to Ring morphisms, additive properties are specialized for *)
+(* linear functions. *)
+(* -> Although {scalar U} is convertible to {linear U -> R^o}, it does not *)
+(* actually use R^o, so that rewriting preserves the canonical structure *)
+(* of the range of scalar functions. *)
+(* -> The generic linearZ lemma uses a set of bespoke interface structures to *)
+(* ensure that both left-to-right and right-to-left rewriting work even in *)
+(* the presence of scaling functions that simplify non-trivially (e.g., *)
+(* idfun \; *%R). Because most of the canonical instances and projections *)
+(* are coercions the machinery will be mostly invisible (with only the *)
+(* {linear ...} structure and %Rlin notations showing), but users should *)
+(* beware that in (a *: f u)%Rlin, a actually occurs in the f u subterm. *)
+(* -> The simpler linear_LR, or more specialized linearZZ and scalarZ rules *)
+(* should be used instead of linearZ if there are complexity issues, as *)
+(* well as for explicit forward and backward application, as the main *)
+(* parameter of linearZ is a proper sub-interface of {linear fUV | s}. *)
+(* *)
+(* * LRMorphism (linear ring morphisms, i.e., algebra morphisms): *)
+(* lrmorphism f <-> f of type A -> B is a linear Ring (Algebra) *)
+(* morphism: f is both additive, multiplicative and *)
+(* scalable. A and B must both have lalgType R *)
+(* canonical structures, for the same ringType R. *)
+(* lrmorphism_for s f <-> f a linear Ring morphism for the scaling *)
+(* operator s: f is additive, multiplicative and *)
+(* scalable for s. A must be an lalgType R, but B *)
+(* only needs to have a ringType structure. *)
+(* {lrmorphism A -> B} == the interface type for linear morphisms, i.e., a *)
+(* Structure that encapsulates the lrmorphism *)
+(* property for functions f : A -> B; both A and B *)
+(* must have lalgType R structures, for the same R. *)
+(* {lrmorphism A -> B | s} == the interface type for morphisms linear for s. *)
+(* LRmorphism lrmorph_f == packs lrmorph_f : lrmorphism_for s f into a *)
+(* linear morphism structure of type *)
+(* {lrmorphism A -> B | s}. Like Linear, LRmorphism *)
+(* can be used transparently for lrmorphism f. *)
+(* AddLRmorphism scal_f == packs scal_f : scalable_for s f into a linear *)
+(* morphism structure of type *)
+(* {lrmorphism A -> B | s}; f must already have an *)
+(* {rmorphism A -> B} structure, and AddLRmorphism *)
+(* can be applied to a linear_for s f, linear f, *)
+(* scalar f, etc argument, like AddLinear. *)
+(* [lrmorphism of f] == creates an lrmorphism structure from existing *)
+(* rmorphism and linear structures on f; this is *)
+(* the preferred way of creating lrmorphism *)
+(* structures. *)
+(* -> Linear and rmorphism properties do not need to be specialized for *)
+(* as we supply inheritance join instances in both directions. *)
+(* Finally we supply some helper notation for morphisms: *)
+(* x^f == the image of x under some morphism. This *)
+(* notation is only reserved (not defined) here; *)
+(* it is bound locally in sections where some *)
+(* morphism is used heavily (e.g., the container *)
+(* morphism in the parametricity sections of poly *)
+(* and matrix, or the Frobenius section here). *)
+(* \0 == the constant null function, which has a *)
+(* canonical linear structure, and simplifies on *)
+(* application (see ssrfun.v). *)
+(* f \+ g == the additive composition of f and g, i.e., the *)
+(* function x |-> f x + g x; f \+ g is canonically *)
+(* linear when f and g are, and simplifies on *)
+(* application (see ssrfun.v). *)
+(* f \- g == the function x |-> f x - g x, canonically *)
+(* linear when f and g are, and simplifies on *)
+(* application. *)
+(* k \*: f == the function x |-> k *: f x, which is *)
+(* canonically linear when f is and simplifies on *)
+(* application (this is a shorter alternative to *)
+(* *:%R k \o f). *)
+(* GRing.in_alg A == the ring morphism that injects R into A, where A *)
+(* has an lalgType R structure; GRing.in_alg A k *)
+(* simplifies to k%:A. *)
+(* a \*o f == the function x |-> a * f x, canonically linear *)
+(* linear when f is and its codomain is an algType *)
+(* and which simplifies on application. *)
+(* a \o* f == the function x |-> f x * a, canonically linear *)
+(* linear when f is and its codomain is an lalgType *)
+(* and which simplifies on application. *)
+(* The Lemmas about these structures are contained in both the GRing module *)
+(* and in the submodule GRing.Theory, which can be imported when unqualified *)
+(* access to the theory is needed (GRing.Theory also allows the unqualified *)
+(* use of additive, linear, Linear, etc). The main GRing module should NOT be *)
+(* imported. *)
+(* Notations are defined in scope ring_scope (delimiter %R), except term *)
+(* and formula notations, which are in term_scope (delimiter %T). *)
+(* This library also extends the conventional suffixes described in library *)
+(* ssrbool.v with the following: *)
+(* 0 -- ring 0, as in addr0 : x + 0 = x. *)
+(* 1 -- ring 1, as in mulr1 : x * 1 = x. *)
+(* D -- ring addition, as in linearD : f (u + v) = f u + f v. *)
+(* B -- ring subtraction, as in opprB : - (x - y) = y - x. *)
+(* M -- ring multiplication, as in invfM : (x * y)^-1 = x^-1 * y^-1. *)
+(* Mn -- ring by nat multiplication, as in raddfMn : f (x *+ n) = f x *+ n. *)
+(* N -- ring opposite, as in mulNr : (- x) * y = - (x * y). *)
+(* V -- ring inverse, as in mulVr : x^-1 * x = 1. *)
+(* X -- ring exponentiation, as in rmorphX : f (x ^+ n) = f x ^+ n. *)
+(* Z -- (left) module scaling, as in linearZ : f (a *: v) = s *: f v. *)
+(* The operator suffixes D, B, M and X are also used for the corresponding *)
+(* operations on nat, as in natrX : (m ^ n)%:R = m%:R ^+ n. For the binary *)
+(* power operator, a trailing "n" suffix is used to indicate the operator *)
+(* suffix applies to the left-hand ring argument, as in *)
+(* expr1n : 1 ^+ n = 1 vs. expr1 : x ^+ 1 = x. *)
+(******************************************************************************)
+
+Set Implicit Arguments.
+Unset Strict Implicit.
+Unset Printing Implicit Defensive.
+
+Reserved Notation "+%R" (at level 0).
+Reserved Notation "-%R" (at level 0).
+Reserved Notation "*%R" (at level 0, format " *%R").
+Reserved Notation "*:%R" (at level 0, format " *:%R").
+Reserved Notation "n %:R" (at level 2, left associativity, format "n %:R").
+Reserved Notation "k %:A" (at level 2, left associativity, format "k %:A").
+Reserved Notation "[ 'char' F ]" (at level 0, format "[ 'char' F ]").
+
+Reserved Notation "x %:T" (at level 2, left associativity, format "x %:T").
+Reserved Notation "''X_' i" (at level 8, i at level 2, format "''X_' i").
+(* Patch for recurring Coq parser bug: Coq seg faults when a level 200 *)
+(* notation is used as a pattern. *)
+Reserved Notation "''exists' ''X_' i , f"
+ (at level 199, i at level 2, right associativity,
+ format "'[hv' ''exists' ''X_' i , '/ ' f ']'").
+Reserved Notation "''forall' ''X_' i , f"
+ (at level 199, i at level 2, right associativity,
+ format "'[hv' ''forall' ''X_' i , '/ ' f ']'").
+
+Reserved Notation "x ^f" (at level 2, left associativity, format "x ^f").
+
+Reserved Notation "\0" (at level 0).
+Reserved Notation "f \+ g" (at level 50, left associativity).
+Reserved Notation "f \- g" (at level 50, left associativity).
+Reserved Notation "a \*o f" (at level 40).
+Reserved Notation "a \o* f" (at level 40).
+Reserved Notation "a \*: f" (at level 40).
+
+Delimit Scope ring_scope with R.
+Delimit Scope term_scope with T.
+Local Open Scope ring_scope.
+
+Module Import GRing.
+
+Import Monoid.Theory.
+
+Module Zmodule.
+
+Record mixin_of (V : Type) : Type := Mixin {
+ zero : V;
+ opp : V -> V;
+ add : V -> V -> V;
+ _ : associative add;
+ _ : commutative add;
+ _ : left_id zero add;
+ _ : left_inverse zero opp add
+}.
+
+Section ClassDef.
+
+Record class_of T := Class { base : Choice.class_of T; mixin : mixin_of T }.
+Local Coercion base : class_of >-> Choice.class_of.
+
+Structure type := Pack {sort; _ : class_of sort; _ : Type}.
+Local Coercion sort : type >-> Sortclass.
+Variables (T : Type) (cT : type).
+Definition class := let: Pack _ c _ as cT' := cT return class_of cT' in c.
+Definition clone c of phant_id class c := @Pack T c T.
+Let xT := let: Pack T _ _ := cT in T.
+Notation xclass := (class : class_of xT).
+
+Definition pack m :=
+ fun bT b & phant_id (Choice.class bT) b => Pack (@Class T b m) T.
+
+Definition eqType := @Equality.Pack cT xclass xT.
+Definition choiceType := @Choice.Pack cT xclass xT.
+
+End ClassDef.
+
+Module Exports.
+Coercion base : class_of >-> Choice.class_of.
+Coercion mixin : class_of >-> mixin_of.
+Coercion sort : type >-> Sortclass.
+Bind Scope ring_scope with sort.
+Coercion eqType : type >-> Equality.type.
+Canonical eqType.
+Coercion choiceType : type >-> Choice.type.
+Canonical choiceType.
+Notation zmodType := type.
+Notation ZmodType T m := (@pack T m _ _ id).
+Notation ZmodMixin := Mixin.
+Notation "[ 'zmodType' 'of' T 'for' cT ]" := (@clone T cT _ idfun)
+ (at level 0, format "[ 'zmodType' 'of' T 'for' cT ]") : form_scope.
+Notation "[ 'zmodType' 'of' T ]" := (@clone T _ _ id)
+ (at level 0, format "[ 'zmodType' 'of' T ]") : form_scope.
+End Exports.
+
+End Zmodule.
+Import Zmodule.Exports.
+
+Definition zero V := Zmodule.zero (Zmodule.class V).
+Definition opp V := Zmodule.opp (Zmodule.class V).
+Definition add V := Zmodule.add (Zmodule.class V).
+
+Local Notation "0" := (zero _) : ring_scope.
+Local Notation "-%R" := (@opp _) : ring_scope.
+Local Notation "- x" := (opp x) : ring_scope.
+Local Notation "+%R" := (@add _) : ring_scope.
+Local Notation "x + y" := (add x y) : ring_scope.
+Local Notation "x - y" := (x + - y) : ring_scope.
+
+Definition natmul V x n := nosimpl iterop _ n +%R x (zero V).
+
+Local Notation "x *+ n" := (natmul x n) : ring_scope.
+Local Notation "x *- n" := (- (x *+ n)) : ring_scope.
+
+Local Notation "\sum_ ( i <- r | P ) F" := (\big[+%R/0]_(i <- r | P) F).
+Local Notation "\sum_ ( m <= i < n ) F" := (\big[+%R/0]_(m <= i < n) F).
+Local Notation "\sum_ ( i < n ) F" := (\big[+%R/0]_(i < n) F).
+Local Notation "\sum_ ( i 'in' A ) F" := (\big[+%R/0]_(i in A) F).
+
+Local Notation "s `_ i" := (nth 0 s i) : ring_scope.
+
+Section ZmoduleTheory.
+
+Variable V : zmodType.
+Implicit Types x y : V.
+
+Lemma addrA : @associative V +%R. Proof. by case V => T [? []]. Qed.
+Lemma addrC : @commutative V V +%R. Proof. by case V => T [? []]. Qed.
+Lemma add0r : @left_id V V 0 +%R. Proof. by case V => T [? []]. Qed.
+Lemma addNr : @left_inverse V V V 0 -%R +%R. Proof. by case V => T [? []]. Qed.
+
+Lemma addr0 : @right_id V V 0 +%R.
+Proof. by move=> x; rewrite addrC add0r. Qed.
+Lemma addrN : @right_inverse V V V 0 -%R +%R.
+Proof. by move=> x; rewrite addrC addNr. Qed.
+Definition subrr := addrN.
+
+Canonical add_monoid := Monoid.Law addrA add0r addr0.
+Canonical add_comoid := Monoid.ComLaw addrC.
+
+Lemma addrCA : @left_commutative V V +%R. Proof. exact: mulmCA. Qed.
+Lemma addrAC : @right_commutative V V +%R. Proof. exact: mulmAC. Qed.
+Lemma addrACA : @interchange V +%R +%R. Proof. exact: mulmACA. Qed.
+
+Lemma addKr : @left_loop V V -%R +%R.
+Proof. by move=> x y; rewrite addrA addNr add0r. Qed.
+Lemma addNKr : @rev_left_loop V V -%R +%R.
+Proof. by move=> x y; rewrite addrA addrN add0r. Qed.
+Lemma addrK : @right_loop V V -%R +%R.
+Proof. by move=> x y; rewrite -addrA addrN addr0. Qed.
+Lemma addrNK : @rev_right_loop V V -%R +%R.
+Proof. by move=> x y; rewrite -addrA addNr addr0. Qed.
+Definition subrK := addrNK.
+Lemma addrI : @right_injective V V V +%R.
+Proof. move=> x; exact: can_inj (addKr x). Qed.
+Lemma addIr : @left_injective V V V +%R.
+Proof. move=> y; exact: can_inj (addrK y). Qed.
+Lemma opprK : @involutive V -%R.
+Proof. by move=> x; apply: (@addIr (- x)); rewrite addNr addrN. Qed.
+Lemma oppr_inj : @injective V V -%R.
+Proof. exact: inv_inj opprK. Qed.
+Lemma oppr0 : -0 = 0 :> V.
+Proof. by rewrite -[-0]add0r subrr. Qed.
+Lemma oppr_eq0 x : (- x == 0) = (x == 0).
+Proof. by rewrite (inv_eq opprK) oppr0. Qed.
+
+Lemma subr0 x : x - 0 = x. Proof. by rewrite oppr0 addr0. Qed.
+Lemma sub0r x : 0 - x = - x. Proof. by rewrite add0r. Qed.
+
+Lemma opprD : {morph -%R: x y / x + y : V}.
+Proof.
+by move=> x y; apply: (@addrI (x + y)); rewrite addrA subrr addrAC addrK subrr.
+Qed.
+
+Lemma opprB x y : - (x - y) = y - x.
+Proof. by rewrite opprD addrC opprK. Qed.
+
+Lemma subr_eq x y z : (x - z == y) = (x == y + z).
+Proof. exact: can2_eq (subrK z) (addrK z) x y. Qed.
+
+Lemma subr_eq0 x y : (x - y == 0) = (x == y).
+Proof. by rewrite subr_eq add0r. Qed.
+
+Lemma addr_eq0 x y : (x + y == 0) = (x == - y).
+Proof. by rewrite -[x == _]subr_eq0 opprK. Qed.
+
+Lemma eqr_opp x y : (- x == - y) = (x == y).
+Proof. exact: can_eq opprK x y. Qed.
+
+Lemma eqr_oppLR x y : (- x == y) = (x == - y).
+Proof. exact: inv_eq opprK x y. Qed.
+
+Lemma mulr0n x : x *+ 0 = 0. Proof. by []. Qed.
+Lemma mulr1n x : x *+ 1 = x. Proof. by []. Qed.
+Lemma mulr2n x : x *+ 2 = x + x. Proof. by []. Qed.
+
+Lemma mulrS x n : x *+ n.+1 = x + x *+ n.
+Proof. by case: n => //=; rewrite addr0. Qed.
+
+Lemma mulrSr x n : x *+ n.+1 = x *+ n + x.
+Proof. by rewrite addrC mulrS. Qed.
+
+Lemma mulrb x (b : bool) : x *+ b = (if b then x else 0).
+Proof. by case: b. Qed.
+
+Lemma mul0rn n : 0 *+ n = 0 :> V.
+Proof. by elim: n => // n IHn; rewrite mulrS add0r. Qed.
+
+Lemma mulNrn x n : (- x) *+ n = x *- n.
+Proof. by elim: n => [|n IHn]; rewrite ?oppr0 // !mulrS opprD IHn. Qed.
+
+Lemma mulrnDl n : {morph (fun x => x *+ n) : x y / x + y}.
+Proof.
+move=> x y; elim: n => [|n IHn]; rewrite ?addr0 // !mulrS.
+by rewrite addrCA -!addrA -IHn -addrCA.
+Qed.
+
+Lemma mulrnDr x m n : x *+ (m + n) = x *+ m + x *+ n.
+Proof.
+elim: m => [|m IHm]; first by rewrite add0r.
+by rewrite !mulrS IHm addrA.
+Qed.
+
+Lemma mulrnBl n : {morph (fun x => x *+ n) : x y / x - y}.
+Proof.
+move=> x y; elim: n => [|n IHn]; rewrite ?subr0 // !mulrS -!addrA; congr(_ + _).
+by rewrite addrC IHn -!addrA opprD [_ - y]addrC.
+Qed.
+
+Lemma mulrnBr x m n : n <= m -> x *+ (m - n) = x *+ m - x *+ n.
+Proof.
+elim: m n => [|m IHm] [|n le_n_m]; rewrite ?subr0 // {}IHm //.
+by rewrite mulrSr mulrS opprD addrA addrK.
+Qed.
+
+Lemma mulrnA x m n : x *+ (m * n) = x *+ m *+ n.
+Proof.
+by rewrite mulnC; elim: n => //= n IHn; rewrite mulrS mulrnDr IHn.
+Qed.
+
+Lemma mulrnAC x m n : x *+ m *+ n = x *+ n *+ m.
+Proof. by rewrite -!mulrnA mulnC. Qed.
+
+Lemma sumrN I r P (F : I -> V) :
+ (\sum_(i <- r | P i) - F i = - (\sum_(i <- r | P i) F i)).
+Proof. by rewrite (big_morph _ opprD oppr0). Qed.
+
+Lemma sumrB I r (P : pred I) (F1 F2 : I -> V) :
+ \sum_(i <- r | P i) (F1 i - F2 i)
+ = \sum_(i <- r | P i) F1 i - \sum_(i <- r | P i) F2 i.
+Proof. by rewrite -sumrN -big_split /=. Qed.
+
+Lemma sumrMnl I r P (F : I -> V) n :
+ \sum_(i <- r | P i) F i *+ n = (\sum_(i <- r | P i) F i) *+ n.
+Proof. by rewrite (big_morph _ (mulrnDl n) (mul0rn _)). Qed.
+
+Lemma sumrMnr x I r P (F : I -> nat) :
+ \sum_(i <- r | P i) x *+ F i = x *+ (\sum_(i <- r | P i) F i).
+Proof. by rewrite (big_morph _ (mulrnDr x) (erefl _)). Qed.
+
+Lemma sumr_const (I : finType) (A : pred I) (x : V) :
+ \sum_(i in A) x = x *+ #|A|.
+Proof. by rewrite big_const -iteropE. Qed.
+
+Lemma telescope_sumr n m (f : nat -> V) : n <= m ->
+ \sum_(n <= k < m) (f k.+1 - f k) = f m - f n.
+Proof.
+rewrite leq_eqVlt => /predU1P[-> | ]; first by rewrite subrr big_geq.
+case: m => // m lenm; rewrite sumrB big_nat_recr // big_nat_recl //=.
+by rewrite addrC opprD addrA subrK addrC.
+Qed.
+
+Section ClosedPredicates.
+
+Variable S : predPredType V.
+
+Definition addr_closed := 0 \in S /\ {in S &, forall u v, u + v \in S}.
+Definition oppr_closed := {in S, forall u, - u \in S}.
+Definition subr_2closed := {in S &, forall u v, u - v \in S}.
+Definition zmod_closed := 0 \in S /\ subr_2closed.
+
+Lemma zmod_closedN : zmod_closed -> oppr_closed.
+Proof. by case=> S0 SB y Sy; rewrite -sub0r !SB. Qed.
+
+Lemma zmod_closedD : zmod_closed -> addr_closed.
+Proof.
+by case=> S0 SB; split=> // y z Sy Sz; rewrite -[z]opprK -[- z]sub0r !SB.
+Qed.
+
+End ClosedPredicates.
+
+End ZmoduleTheory.
+
+Implicit Arguments addrI [[V] x1 x2].
+Implicit Arguments addIr [[V] x1 x2].
+Implicit Arguments oppr_inj [[V] x1 x2].
+
+Module Ring.
+
+Record mixin_of (R : zmodType) : Type := Mixin {
+ one : R;
+ mul : R -> R -> R;
+ _ : associative mul;
+ _ : left_id one mul;
+ _ : right_id one mul;
+ _ : left_distributive mul +%R;
+ _ : right_distributive mul +%R;
+ _ : one != 0
+}.
+
+Definition EtaMixin R one mul mulA mul1x mulx1 mul_addl mul_addr nz1 :=
+ let _ := @Mixin R one mul mulA mul1x mulx1 mul_addl mul_addr nz1 in
+ @Mixin (Zmodule.Pack (Zmodule.class R) R) _ _
+ mulA mul1x mulx1 mul_addl mul_addr nz1.
+
+Section ClassDef.
+
+Record class_of (R : Type) : Type := Class {
+ base : Zmodule.class_of R;
+ mixin : mixin_of (Zmodule.Pack base R)
+}.
+Local Coercion base : class_of >-> Zmodule.class_of.
+
+Structure type := Pack {sort; _ : class_of sort; _ : Type}.
+Local Coercion sort : type >-> Sortclass.
+Variables (T : Type) (cT : type).
+Definition class := let: Pack _ c _ as cT' := cT return class_of cT' in c.
+Definition clone c of phant_id class c := @Pack T c T.
+Let xT := let: Pack T _ _ := cT in T.
+Notation xclass := (class : class_of xT).
+
+
+Definition pack b0 (m0 : mixin_of (@Zmodule.Pack T b0 T)) :=
+ fun bT b & phant_id (Zmodule.class bT) b =>
+ fun m & phant_id m0 m => Pack (@Class T b m) T.
+
+Definition eqType := @Equality.Pack cT xclass xT.
+Definition choiceType := @Choice.Pack cT xclass xT.
+Definition zmodType := @Zmodule.Pack cT xclass xT.
+
+End ClassDef.
+
+Module Exports.
+Coercion base : class_of >-> Zmodule.class_of.
+Coercion mixin : class_of >-> mixin_of.
+Coercion sort : type >-> Sortclass.
+Bind Scope ring_scope with sort.
+Coercion eqType : type >-> Equality.type.
+Canonical eqType.
+Coercion choiceType : type >-> Choice.type.
+Canonical choiceType.
+Coercion zmodType : type >-> Zmodule.type.
+Canonical zmodType.
+Notation ringType := type.
+Notation RingType T m := (@pack T _ m _ _ id _ id).
+Notation RingMixin := Mixin.
+Notation "[ 'ringType' 'of' T 'for' cT ]" := (@clone T cT _ idfun)
+ (at level 0, format "[ 'ringType' 'of' T 'for' cT ]") : form_scope.
+Notation "[ 'ringType' 'of' T ]" := (@clone T _ _ id)
+ (at level 0, format "[ 'ringType' 'of' T ]") : form_scope.
+End Exports.
+
+End Ring.
+Import Ring.Exports.
+
+Definition one (R : ringType) : R := Ring.one (Ring.class R).
+Definition mul (R : ringType) : R -> R -> R := Ring.mul (Ring.class R).
+Definition exp R x n := nosimpl iterop _ n (@mul R) x (one R).
+Notation sign R b := (exp (- one R) (nat_of_bool b)) (only parsing).
+Definition comm R x y := @mul R x y = mul y x.
+Definition lreg R x := injective (@mul R x).
+Definition rreg R x := injective ((@mul R)^~ x).
+
+Local Notation "1" := (one _) : ring_scope.
+Local Notation "- 1" := (- (1)) : ring_scope.
+Local Notation "n %:R" := (1 *+ n) : ring_scope.
+Local Notation "*%R" := (@mul _).
+Local Notation "x * y" := (mul x y) : ring_scope.
+Local Notation "x ^+ n" := (exp x n) : ring_scope.
+
+Local Notation "\prod_ ( i <- r | P ) F" := (\big[*%R/1]_(i <- r | P) F).
+Local Notation "\prod_ ( i | P ) F" := (\big[*%R/1]_(i | P) F).
+Local Notation "\prod_ ( i 'in' A ) F" := (\big[*%R/1]_(i in A) F).
+Local Notation "\prod_ ( m <= i < n ) F" := (\big[*%R/1%R]_(m <= i < n) F%R).
+
+(* The ``field'' characteristic; the definition, and many of the theorems, *)
+(* has to apply to rings as well; indeed, we need the Frobenius automorphism *)
+(* results for a non commutative ring in the proof of Gorenstein 2.6.3. *)
+Definition char (R : Ring.type) of phant R : nat_pred :=
+ [pred p | prime p & p%:R == 0 :> R].
+
+Local Notation "[ 'char' R ]" := (char (Phant R)) : ring_scope.
+
+(* Converse ring tag. *)
+Definition converse R : Type := R.
+Local Notation "R ^c" := (converse R) (at level 2, format "R ^c") : type_scope.
+
+Section RingTheory.
+
+Variable R : ringType.
+Implicit Types x y : R.
+
+Lemma mulrA : @associative R *%R. Proof. by case R => T [? []]. Qed.
+Lemma mul1r : @left_id R R 1 *%R. Proof. by case R => T [? []]. Qed.
+Lemma mulr1 : @right_id R R 1 *%R. Proof. by case R => T [? []]. Qed.
+Lemma mulrDl : @left_distributive R R *%R +%R.
+Proof. by case R => T [? []]. Qed.
+Lemma mulrDr : @right_distributive R R *%R +%R.
+Proof. by case R => T [? []]. Qed.
+Lemma oner_neq0 : 1 != 0 :> R. Proof. by case R => T [? []]. Qed.
+Lemma oner_eq0 : (1 == 0 :> R) = false. Proof. exact: negbTE oner_neq0. Qed.
+
+Lemma mul0r : @left_zero R R 0 *%R.
+Proof.
+by move=> x; apply: (addIr (1 * x)); rewrite -mulrDl !add0r mul1r.
+Qed.
+Lemma mulr0 : @right_zero R R 0 *%R.
+Proof.
+by move=> x; apply: (addIr (x * 1)); rewrite -mulrDr !add0r mulr1.
+Qed.
+Lemma mulrN x y : x * (- y) = - (x * y).
+Proof. by apply: (addrI (x * y)); rewrite -mulrDr !subrr mulr0. Qed.
+Lemma mulNr x y : (- x) * y = - (x * y).
+Proof. by apply: (addrI (x * y)); rewrite -mulrDl !subrr mul0r. Qed.
+Lemma mulrNN x y : (- x) * (- y) = x * y.
+Proof. by rewrite mulrN mulNr opprK. Qed.
+Lemma mulN1r x : -1 * x = - x.
+Proof. by rewrite mulNr mul1r. Qed.
+Lemma mulrN1 x : x * -1 = - x.
+Proof. by rewrite mulrN mulr1. Qed.
+
+Canonical mul_monoid := Monoid.Law mulrA mul1r mulr1.
+Canonical muloid := Monoid.MulLaw mul0r mulr0.
+Canonical addoid := Monoid.AddLaw mulrDl mulrDr.
+
+Lemma mulr_suml I r P (F : I -> R) x :
+ (\sum_(i <- r | P i) F i) * x = \sum_(i <- r | P i) F i * x.
+Proof. exact: big_distrl. Qed.
+
+Lemma mulr_sumr I r P (F : I -> R) x :
+ x * (\sum_(i <- r | P i) F i) = \sum_(i <- r | P i) x * F i.
+Proof. exact: big_distrr. Qed.
+
+Lemma mulrBl x y z : (y - z) * x = y * x - z * x.
+Proof. by rewrite mulrDl mulNr. Qed.
+
+Lemma mulrBr x y z : x * (y - z) = x * y - x * z.
+Proof. by rewrite mulrDr mulrN. Qed.
+
+Lemma mulrnAl x y n : (x *+ n) * y = (x * y) *+ n.
+Proof. by elim: n => [|n IHn]; rewrite ?mul0r // !mulrS mulrDl IHn. Qed.
+
+Lemma mulrnAr x y n : x * (y *+ n) = (x * y) *+ n.
+Proof. by elim: n => [|n IHn]; rewrite ?mulr0 // !mulrS mulrDr IHn. Qed.
+
+Lemma mulr_natl x n : n%:R * x = x *+ n.
+Proof. by rewrite mulrnAl mul1r. Qed.
+
+Lemma mulr_natr x n : x * n%:R = x *+ n.
+Proof. by rewrite mulrnAr mulr1. Qed.
+
+Lemma natrD m n : (m + n)%:R = m%:R + n%:R :> R.
+Proof. exact: mulrnDr. Qed.
+
+Lemma natrB m n : n <= m -> (m - n)%:R = m%:R - n%:R :> R.
+Proof. exact: mulrnBr. Qed.
+
+Definition natr_sum := big_morph (natmul 1) natrD (mulr0n 1).
+
+Lemma natrM m n : (m * n)%:R = m%:R * n%:R :> R.
+Proof. by rewrite mulrnA -mulr_natr. Qed.
+
+Lemma expr0 x : x ^+ 0 = 1. Proof. by []. Qed.
+Lemma expr1 x : x ^+ 1 = x. Proof. by []. Qed.
+Lemma expr2 x : x ^+ 2 = x * x. Proof. by []. Qed.
+
+Lemma exprS x n : x ^+ n.+1 = x * x ^+ n.
+Proof. by case: n => //; rewrite mulr1. Qed.
+
+Lemma expr0n n : 0 ^+ n = (n == 0%N)%:R :> R.
+Proof. by case: n => // n; rewrite exprS mul0r. Qed.
+
+Lemma expr1n n : 1 ^+ n = 1 :> R.
+Proof. by elim: n => // n IHn; rewrite exprS mul1r. Qed.
+
+Lemma exprD x m n : x ^+ (m + n) = x ^+ m * x ^+ n.
+Proof. by elim: m => [|m IHm]; rewrite ?mul1r // !exprS -mulrA -IHm. Qed.
+
+Lemma exprSr x n : x ^+ n.+1 = x ^+ n * x.
+Proof. by rewrite -addn1 exprD expr1. Qed.
+
+Lemma commr_sym x y : comm x y -> comm y x. Proof. by []. Qed.
+Lemma commr_refl x : comm x x. Proof. by []. Qed.
+
+Lemma commr0 x : comm x 0.
+Proof. by rewrite /comm mulr0 mul0r. Qed.
+
+Lemma commr1 x : comm x 1.
+Proof. by rewrite /comm mulr1 mul1r. Qed.
+
+Lemma commrN x y : comm x y -> comm x (- y).
+Proof. by move=> com_xy; rewrite /comm mulrN com_xy mulNr. Qed.
+
+Lemma commrN1 x : comm x (-1).
+Proof. apply: commrN; exact: commr1. Qed.
+
+Lemma commrD x y z : comm x y -> comm x z -> comm x (y + z).
+Proof. by rewrite /comm mulrDl mulrDr => -> ->. Qed.
+
+Lemma commrMn x y n : comm x y -> comm x (y *+ n).
+Proof.
+rewrite /comm => com_xy.
+by elim: n => [|n IHn]; rewrite ?commr0 // mulrS commrD.
+Qed.
+
+Lemma commrM x y z : comm x y -> comm x z -> comm x (y * z).
+Proof. by move=> com_xy; rewrite /comm mulrA com_xy -!mulrA => ->. Qed.
+
+Lemma commr_nat x n : comm x n%:R.
+Proof. by apply: commrMn; exact: commr1. Qed.
+
+Lemma commrX x y n : comm x y -> comm x (y ^+ n).
+Proof.
+rewrite /comm => com_xy.
+by elim: n => [|n IHn]; rewrite ?commr1 // exprS commrM.
+Qed.
+
+Lemma exprMn_comm x y n : comm x y -> (x * y) ^+ n = x ^+ n * y ^+ n.
+Proof.
+move=> com_xy; elim: n => /= [|n IHn]; first by rewrite mulr1.
+by rewrite !exprS IHn !mulrA; congr (_ * _); rewrite -!mulrA -commrX.
+Qed.
+
+Lemma commr_sign x n : comm x ((-1) ^+ n).
+Proof. exact: (commrX n (commrN1 x)). Qed.
+
+Lemma exprMn_n x m n : (x *+ m) ^+ n = x ^+ n *+ (m ^ n) :> R.
+Proof.
+elim: n => [|n IHn]; first by rewrite mulr1n.
+rewrite exprS IHn -mulr_natr -mulrA -commr_nat mulr_natr -mulrnA -expnSr.
+by rewrite -mulr_natr mulrA -exprS mulr_natr.
+Qed.
+
+Lemma exprM x m n : x ^+ (m * n) = x ^+ m ^+ n.
+Proof.
+elim: m => [|m IHm]; first by rewrite expr1n.
+by rewrite mulSn exprD IHm exprS exprMn_comm //; exact: commrX.
+Qed.
+
+Lemma exprAC x m n : (x ^+ m) ^+ n = (x ^+ n) ^+ m.
+Proof. by rewrite -!exprM mulnC. Qed.
+
+Lemma expr_mod n x i : x ^+ n = 1 -> x ^+ (i %% n) = x ^+ i.
+Proof.
+move=> xn1; rewrite {2}(divn_eq i n) exprD mulnC exprM xn1.
+by rewrite expr1n mul1r.
+Qed.
+
+Lemma expr_dvd n x i : x ^+ n = 1 -> n %| i -> x ^+ i = 1.
+Proof.
+by move=> xn1 dvd_n_i; rewrite -(expr_mod i xn1) (eqnP dvd_n_i).
+Qed.
+
+Lemma natrX n k : (n ^ k)%:R = n%:R ^+ k :> R.
+Proof. by rewrite exprMn_n expr1n. Qed.
+
+Lemma signr_odd n : (-1) ^+ (odd n) = (-1) ^+ n :> R.
+Proof.
+elim: n => //= n IHn; rewrite exprS -{}IHn.
+by case/odd: n; rewrite !mulN1r ?opprK.
+Qed.
+
+Lemma signr_eq0 n : ((-1) ^+ n == 0 :> R) = false.
+Proof. by rewrite -signr_odd; case: odd; rewrite ?oppr_eq0 oner_eq0. Qed.
+
+Lemma mulr_sign (b : bool) x : (-1) ^+ b * x = (if b then - x else x).
+Proof. by case: b; rewrite ?mulNr mul1r. Qed.
+
+Lemma signr_addb b1 b2 : (-1) ^+ (b1 (+) b2) = (-1) ^+ b1 * (-1) ^+ b2 :> R.
+Proof. by rewrite mulr_sign; case: b1 b2 => [] []; rewrite ?opprK. Qed.
+
+Lemma signrE (b : bool) : (-1) ^+ b = 1 - b.*2%:R :> R.
+Proof. by case: b; rewrite ?subr0 // opprD addNKr. Qed.
+
+Lemma signrN b : (-1) ^+ (~~ b) = - (-1) ^+ b :> R.
+Proof. by case: b; rewrite ?opprK. Qed.
+
+Lemma mulr_signM (b1 b2 : bool) x1 x2 :
+ ((-1) ^+ b1 * x1) * ((-1) ^+ b2 * x2) = (-1) ^+ (b1 (+) b2) * (x1 * x2).
+Proof.
+by rewrite signr_addb -!mulrA; congr (_ * _); rewrite !mulrA commr_sign.
+Qed.
+
+Lemma exprNn x n : (- x) ^+ n = (-1) ^+ n * x ^+ n :> R.
+Proof. by rewrite -mulN1r exprMn_comm // /comm mulN1r mulrN mulr1. Qed.
+
+Lemma sqrrN x : (- x) ^+ 2 = x ^+ 2.
+Proof. exact: mulrNN. Qed.
+
+Lemma sqrr_sign n : ((-1) ^+ n) ^+ 2 = 1 :> R.
+Proof. by rewrite exprAC sqrrN !expr1n. Qed.
+
+Lemma signrMK n : @involutive R ( *%R ((-1) ^+ n)).
+Proof. by move=> x; rewrite mulrA -expr2 sqrr_sign mul1r. Qed.
+
+Lemma mulrI_eq0 x y : lreg x -> (x * y == 0) = (y == 0).
+Proof. by move=> reg_x; rewrite -{1}(mulr0 x) (inj_eq reg_x). Qed.
+
+Lemma lreg_neq0 x : lreg x -> x != 0.
+Proof. by move=> reg_x; rewrite -[x]mulr1 mulrI_eq0 ?oner_eq0. Qed.
+
+Lemma mulrI0_lreg x : (forall y, x * y = 0 -> y = 0) -> lreg x.
+Proof.
+move=> reg_x y z eq_xy_xz; apply/eqP; rewrite -subr_eq0 [y - z]reg_x //.
+by rewrite mulrBr eq_xy_xz subrr.
+Qed.
+
+Lemma lregN x : lreg x -> lreg (- x).
+Proof. by move=> reg_x y z; rewrite !mulNr => /oppr_inj/reg_x. Qed.
+
+Lemma lreg1 : lreg (1 : R).
+Proof. by move=> x y; rewrite !mul1r. Qed.
+
+Lemma lregM x y : lreg x -> lreg y -> lreg (x * y).
+Proof. by move=> reg_x reg_y z t; rewrite -!mulrA => /reg_x/reg_y. Qed.
+
+Lemma lregX x n : lreg x -> lreg (x ^+ n).
+Proof.
+by move=> reg_x; elim: n => [|n]; [exact: lreg1 | rewrite exprS; exact: lregM].
+Qed.
+
+Lemma lreg_sign n : lreg ((-1) ^+ n : R).
+Proof. by apply: lregX; apply: lregN; apply: lreg1. Qed.
+
+Lemma prodr_const (I : finType) (A : pred I) (x : R) :
+ \prod_(i in A) x = x ^+ #|A|.
+Proof. by rewrite big_const -iteropE. Qed.
+
+Lemma prodrXr x I r P (F : I -> nat) :
+ \prod_(i <- r | P i) x ^+ F i = x ^+ (\sum_(i <- r | P i) F i).
+Proof. by rewrite (big_morph _ (exprD _) (erefl _)). Qed.
+
+Lemma prodrN (I : finType) (A : pred I) (F : I -> R) :
+ \prod_(i in A) - F i = (- 1) ^+ #|A| * \prod_(i in A) F i.
+Proof.
+rewrite -sum1_card; elim/big_rec3: _ => [|i x n _ _ ->]; first by rewrite mulr1.
+by rewrite exprS !mulrA mulN1r !mulNr commrX //; apply: commrN1.
+Qed.
+
+Lemma prodrMn n (I : finType) (A : pred I) (F : I -> R) :
+ \prod_(i in A) (F i *+ n) = \prod_(i in A) F i *+ n ^ #|A|.
+Proof.
+rewrite -sum1_card; elim/big_rec3: _ => // i x m _ _ ->.
+by rewrite mulrnAr mulrnAl expnS mulrnA.
+Qed.
+
+Lemma natr_prod I r P (F : I -> nat) :
+ (\prod_(i <- r | P i) F i)%:R = \prod_(i <- r | P i) (F i)%:R :> R.
+Proof. exact: (big_morph _ natrM). Qed.
+
+Lemma exprDn_comm x y n (cxy : comm x y) :
+ (x + y) ^+ n = \sum_(i < n.+1) (x ^+ (n - i) * y ^+ i) *+ 'C(n, i).
+Proof.
+elim: n => [|n IHn]; rewrite big_ord_recl mulr1 ?big_ord0 ?addr0 //=.
+rewrite exprS {}IHn /= mulrDl !big_distrr /= big_ord_recl mulr1 subn0.
+rewrite !big_ord_recr /= !binn !subnn !mul1r !subn0 bin0 !exprS -addrA.
+congr (_ + _); rewrite addrA -big_split /=; congr (_ + _).
+apply: eq_bigr => i _; rewrite !mulrnAr !mulrA -exprS -subSn ?(valP i) //.
+by rewrite subSS (commrX _ (commr_sym cxy)) -mulrA -exprS -mulrnDr.
+Qed.
+
+Lemma exprBn_comm x y n (cxy : comm x y) :
+ (x - y) ^+ n =
+ \sum_(i < n.+1) ((-1) ^+ i * x ^+ (n - i) * y ^+ i) *+ 'C(n, i).
+Proof.
+rewrite exprDn_comm; last exact: commrN.
+by apply: eq_bigr => i _; congr (_ *+ _); rewrite -commr_sign -mulrA -exprNn.
+Qed.
+
+Lemma subrXX_comm x y n (cxy : comm x y) :
+ x ^+ n - y ^+ n = (x - y) * (\sum_(i < n) x ^+ (n.-1 - i) * y ^+ i).
+Proof.
+case: n => [|n]; first by rewrite big_ord0 mulr0 subrr.
+rewrite mulrBl !big_distrr big_ord_recl big_ord_recr /= subnn mulr1 mul1r.
+rewrite subn0 -!exprS opprD -!addrA; congr (_ + _); rewrite addrA -sumrB.
+rewrite big1 ?add0r // => i _; rewrite !mulrA -exprS -subSn ?(valP i) //.
+by rewrite subSS (commrX _ (commr_sym cxy)) -mulrA -exprS subrr.
+Qed.
+
+Lemma exprD1n x n : (x + 1) ^+ n = \sum_(i < n.+1) x ^+ i *+ 'C(n, i).
+Proof.
+rewrite addrC (exprDn_comm n (commr_sym (commr1 x))).
+by apply: eq_bigr => i _; rewrite expr1n mul1r.
+Qed.
+
+Lemma subrX1 x n : x ^+ n - 1 = (x - 1) * (\sum_(i < n) x ^+ i).
+Proof.
+rewrite -!(opprB 1) mulNr -{1}(expr1n n).
+rewrite (subrXX_comm _ (commr_sym (commr1 x))); congr (- (_ * _)).
+by apply: eq_bigr => i _; rewrite expr1n mul1r.
+Qed.
+
+Lemma sqrrD1 x : (x + 1) ^+ 2 = x ^+ 2 + x *+ 2 + 1.
+Proof.
+rewrite exprD1n !big_ord_recr big_ord0 /= add0r.
+by rewrite addrC addrA addrAC.
+Qed.
+
+Lemma sqrrB1 x : (x - 1) ^+ 2 = x ^+ 2 - x *+ 2 + 1.
+Proof. by rewrite -sqrrN opprB addrC sqrrD1 sqrrN mulNrn. Qed.
+
+Lemma subr_sqr_1 x : x ^+ 2 - 1 = (x - 1) * (x + 1).
+Proof. by rewrite subrX1 !big_ord_recr big_ord0 /= addrAC add0r. Qed.
+
+Definition Frobenius_aut p of p \in [char R] := fun x => x ^+ p.
+
+Section FrobeniusAutomorphism.
+
+Variable p : nat.
+Hypothesis charFp : p \in [char R].
+
+Lemma charf0 : p%:R = 0 :> R. Proof. by apply/eqP; case/andP: charFp. Qed.
+Lemma charf_prime : prime p. Proof. by case/andP: charFp. Qed.
+Hint Resolve charf_prime.
+
+Lemma mulrn_char x : x *+ p = 0. Proof. by rewrite -mulr_natl charf0 mul0r. Qed.
+
+Lemma natr_mod_char n : (n %% p)%:R = n%:R :> R.
+Proof. by rewrite {2}(divn_eq n p) natrD mulrnA mulrn_char add0r. Qed.
+
+Lemma dvdn_charf n : (p %| n)%N = (n%:R == 0 :> R).
+Proof.
+apply/idP/eqP=> [/dvdnP[n' ->]|n0]; first by rewrite natrM charf0 mulr0.
+apply/idPn; rewrite -prime_coprime // => /eqnP pn1.
+have [a _ /dvdnP[b]] := Bezoutl n (prime_gt0 charf_prime).
+move/(congr1 (fun m => m%:R : R))/eqP.
+by rewrite natrD !natrM charf0 n0 !mulr0 pn1 addr0 oner_eq0.
+Qed.
+
+Lemma charf_eq : [char R] =i (p : nat_pred).
+Proof.
+move=> q; apply/andP/eqP=> [[q_pr q0] | ->]; last by rewrite charf0.
+by apply/eqP; rewrite eq_sym -dvdn_prime2 // dvdn_charf.
+Qed.
+
+Lemma bin_lt_charf_0 k : 0 < k < p -> 'C(p, k)%:R = 0 :> R.
+Proof. by move=> lt0kp; apply/eqP; rewrite -dvdn_charf prime_dvd_bin. Qed.
+
+Local Notation "x ^f" := (Frobenius_aut charFp x).
+
+Lemma Frobenius_autE x : x^f = x ^+ p. Proof. by []. Qed.
+Local Notation fE := Frobenius_autE.
+
+Lemma Frobenius_aut0 : 0^f = 0.
+Proof. by rewrite fE -(prednK (prime_gt0 charf_prime)) exprS mul0r. Qed.
+
+Lemma Frobenius_aut1 : 1^f = 1.
+Proof. by rewrite fE expr1n. Qed.
+
+Lemma Frobenius_autD_comm x y (cxy : comm x y) : (x + y)^f = x^f + y^f.
+Proof.
+have defp := prednK (prime_gt0 charf_prime).
+rewrite !fE exprDn_comm // big_ord_recr subnn -defp big_ord_recl /= defp.
+rewrite subn0 mulr1 mul1r bin0 binn big1 ?addr0 // => i _.
+by rewrite -mulr_natl bin_lt_charf_0 ?mul0r //= -{2}defp ltnS (valP i).
+Qed.
+
+Lemma Frobenius_autMn x n : (x *+ n)^f = x^f *+ n.
+Proof.
+elim: n => [|n IHn]; first exact: Frobenius_aut0.
+rewrite !mulrS Frobenius_autD_comm ?IHn //; exact: commrMn.
+Qed.
+
+Lemma Frobenius_aut_nat n : (n%:R)^f = n%:R.
+Proof. by rewrite Frobenius_autMn Frobenius_aut1. Qed.
+
+Lemma Frobenius_autM_comm x y : comm x y -> (x * y)^f = x^f * y^f.
+Proof. by exact: exprMn_comm. Qed.
+
+Lemma Frobenius_autX x n : (x ^+ n)^f = x^f ^+ n.
+Proof. by rewrite !fE -!exprM mulnC. Qed.
+
+Lemma Frobenius_autN x : (- x)^f = - x^f.
+Proof.
+apply/eqP; rewrite -subr_eq0 opprK addrC.
+by rewrite -(Frobenius_autD_comm (commrN _)) // subrr Frobenius_aut0.
+Qed.
+
+Lemma Frobenius_autB_comm x y : comm x y -> (x - y)^f = x^f - y^f.
+Proof.
+by move/commrN/Frobenius_autD_comm->; rewrite Frobenius_autN.
+Qed.
+
+End FrobeniusAutomorphism.
+
+Lemma exprNn_char x n : [char R].-nat n -> (- x) ^+ n = - (x ^+ n).
+Proof.
+pose p := pdiv n; have [|n_gt1 charRn] := leqP n 1; first by case: (n) => [|[]].
+have charRp: p \in [char R] by rewrite (pnatPpi charRn) // pi_pdiv.
+have /p_natP[e ->]: p.-nat n by rewrite -(eq_pnat _ (charf_eq charRp)).
+elim: e => // e IHe; rewrite expnSr !exprM {}IHe.
+by rewrite -Frobenius_autE Frobenius_autN.
+Qed.
+
+Section Char2.
+
+Hypothesis charR2 : 2 \in [char R].
+
+Lemma addrr_char2 x : x + x = 0. Proof. by rewrite -mulr2n mulrn_char. Qed.
+
+Lemma oppr_char2 x : - x = x.
+Proof. by apply/esym/eqP; rewrite -addr_eq0 addrr_char2. Qed.
+
+Lemma subr_char2 x y : x - y = x + y. Proof. by rewrite oppr_char2. Qed.
+
+Lemma addrK_char2 x : involutive (+%R^~ x).
+Proof. by move=> y; rewrite /= -subr_char2 addrK. Qed.
+
+Lemma addKr_char2 x : involutive (+%R x).
+Proof. by move=> y; rewrite -{1}[x]oppr_char2 addKr. Qed.
+
+End Char2.
+
+Canonical converse_eqType := [eqType of R^c].
+Canonical converse_choiceType := [choiceType of R^c].
+Canonical converse_zmodType := [zmodType of R^c].
+
+Definition converse_ringMixin :=
+ let mul' x y := y * x in
+ let mulrA' x y z := esym (mulrA z y x) in
+ let mulrDl' x y z := mulrDr z x y in
+ let mulrDr' x y z := mulrDl y z x in
+ @Ring.Mixin converse_zmodType
+ 1 mul' mulrA' mulr1 mul1r mulrDl' mulrDr' oner_neq0.
+Canonical converse_ringType := RingType R^c converse_ringMixin.
+
+Section ClosedPredicates.
+
+Variable S : predPredType R.
+
+Definition mulr_2closed := {in S &, forall u v, u * v \in S}.
+Definition mulr_closed := 1 \in S /\ mulr_2closed.
+Definition smulr_closed := -1 \in S /\ mulr_2closed.
+Definition semiring_closed := addr_closed S /\ mulr_closed.
+Definition subring_closed := [/\ 1 \in S, subr_2closed S & mulr_2closed].
+
+Lemma smulr_closedM : smulr_closed -> mulr_closed.
+Proof. by case=> SN1 SM; split=> //; rewrite -[1]mulr1 -mulrNN SM. Qed.
+
+Lemma smulr_closedN : smulr_closed -> oppr_closed S.
+Proof. by case=> SN1 SM x Sx; rewrite -mulN1r SM. Qed.
+
+Lemma semiring_closedD : semiring_closed -> addr_closed S. Proof. by case. Qed.
+
+Lemma semiring_closedM : semiring_closed -> mulr_closed. Proof. by case. Qed.
+
+Lemma subring_closedB : subring_closed -> zmod_closed S.
+Proof. by case=> S1 SB _; split; rewrite // -(subrr 1) SB. Qed.
+
+Lemma subring_closedM : subring_closed -> smulr_closed.
+Proof.
+by case=> S1 SB SM; split; rewrite ?(zmod_closedN (subring_closedB _)).
+Qed.
+
+Lemma subring_closed_semi : subring_closed -> semiring_closed.
+Proof.
+by move=> ringS; split; [apply/zmod_closedD/subring_closedB | case: ringS].
+Qed.
+
+End ClosedPredicates.
+
+End RingTheory.
+
+Section RightRegular.
+
+Variable R : ringType.
+Implicit Types x y : R.
+Let Rc := converse_ringType R.
+
+Lemma mulIr_eq0 x y : rreg x -> (y * x == 0) = (y == 0).
+Proof. exact: (@mulrI_eq0 Rc). Qed.
+
+Lemma mulIr0_rreg x : (forall y, y * x = 0 -> y = 0) -> rreg x.
+Proof. exact: (@mulrI0_lreg Rc). Qed.
+
+Lemma rreg_neq0 x : rreg x -> x != 0.
+Proof. exact: (@lreg_neq0 Rc). Qed.
+
+Lemma rregN x : rreg x -> rreg (- x).
+Proof. exact: (@lregN Rc). Qed.
+
+Lemma rreg1 : rreg (1 : R).
+Proof. exact: (@lreg1 Rc). Qed.
+
+Lemma rregM x y : rreg x -> rreg y -> rreg (x * y).
+Proof. by move=> reg_x reg_y; exact: (@lregM Rc). Qed.
+
+Lemma revrX x n : (x : Rc) ^+ n = (x : R) ^+ n.
+Proof. by elim: n => // n IHn; rewrite exprS exprSr IHn. Qed.
+
+Lemma rregX x n : rreg x -> rreg (x ^+ n).
+Proof. by move/(@lregX Rc x n); rewrite revrX. Qed.
+
+End RightRegular.
+
+Module Lmodule.
+
+Structure mixin_of (R : ringType) (V : zmodType) : Type := Mixin {
+ scale : R -> V -> V;
+ _ : forall a b v, scale a (scale b v) = scale (a * b) v;
+ _ : left_id 1 scale;
+ _ : right_distributive scale +%R;
+ _ : forall v, {morph scale^~ v: a b / a + b}
+}.
+
+Section ClassDef.
+
+Variable R : ringType.
+
+Structure class_of V := Class {
+ base : Zmodule.class_of V;
+ mixin : mixin_of R (Zmodule.Pack base V)
+}.
+Local Coercion base : class_of >-> Zmodule.class_of.
+
+Structure type (phR : phant R) := Pack {sort; _ : class_of sort; _ : Type}.
+Local Coercion sort : type >-> Sortclass.
+Variable (phR : phant R) (T : Type) (cT : type phR).
+Definition class := let: Pack _ c _ as cT' := cT return class_of cT' in c.
+Definition clone c of phant_id class c := @Pack phR T c T.
+Let xT := let: Pack T _ _ := cT in T.
+Notation xclass := (class : class_of xT).
+
+
+Definition pack b0 (m0 : mixin_of R (@Zmodule.Pack T b0 T)) :=
+ fun bT b & phant_id (Zmodule.class bT) b =>
+ fun m & phant_id m0 m => Pack phR (@Class T b m) T.
+
+Definition eqType := @Equality.Pack cT xclass xT.
+Definition choiceType := @Choice.Pack cT xclass xT.
+Definition zmodType := @Zmodule.Pack cT xclass xT.
+
+End ClassDef.
+
+Module Import Exports.
+Coercion base : class_of >-> Zmodule.class_of.
+Coercion mixin : class_of >-> mixin_of.
+Coercion sort : type >-> Sortclass.
+Bind Scope ring_scope with sort.
+Coercion eqType : type >-> Equality.type.
+Canonical eqType.
+Coercion choiceType : type >-> Choice.type.
+Canonical choiceType.
+Coercion zmodType : type >-> Zmodule.type.
+Canonical zmodType.
+Notation lmodType R := (type (Phant R)).
+Notation LmodType R T m := (@pack _ (Phant R) T _ m _ _ id _ id).
+Notation LmodMixin := Mixin.
+Notation "[ 'lmodType' R 'of' T 'for' cT ]" := (@clone _ (Phant R) T cT _ idfun)
+ (at level 0, format "[ 'lmodType' R 'of' T 'for' cT ]") : form_scope.
+Notation "[ 'lmodType' R 'of' T ]" := (@clone _ (Phant R) T _ _ id)
+ (at level 0, format "[ 'lmodType' R 'of' T ]") : form_scope.
+End Exports.
+
+End Lmodule.
+Import Lmodule.Exports.
+
+Definition scale (R : ringType) (V : lmodType R) :=
+ Lmodule.scale (Lmodule.class V).
+
+Local Notation "*:%R" := (@scale _ _).
+Local Notation "a *: v" := (scale a v) : ring_scope.
+
+Section LmoduleTheory.
+
+Variables (R : ringType) (V : lmodType R).
+Implicit Types (a b c : R) (u v : V).
+
+Local Notation "*:%R" := (@scale R V).
+
+Lemma scalerA a b v : a *: (b *: v) = a * b *: v.
+Proof. by case: V v => ? [] ? []. Qed.
+
+Lemma scale1r : @left_id R V 1 *:%R.
+Proof. by case: V => ? [] ? []. Qed.
+
+Lemma scalerDr a : {morph *:%R a : u v / u + v}.
+Proof. by case: V a => ? [] ? []. Qed.
+
+Lemma scalerDl v : {morph *:%R^~ v : a b / a + b}.
+Proof. by case: V v => ? [] ? []. Qed.
+
+Lemma scale0r v : 0 *: v = 0.
+Proof. by apply: (addIr (1 *: v)); rewrite -scalerDl !add0r. Qed.
+
+Lemma scaler0 a : a *: 0 = 0 :> V.
+Proof. by rewrite -{1}(scale0r 0) scalerA mulr0 scale0r. Qed.
+
+Lemma scaleNr a v : - a *: v = - (a *: v).
+Proof. by apply: (addIr (a *: v)); rewrite -scalerDl !addNr scale0r. Qed.
+
+Lemma scaleN1r v : (- 1) *: v = - v.
+Proof. by rewrite scaleNr scale1r. Qed.
+
+Lemma scalerN a v : a *: (- v) = - (a *: v).
+Proof. by apply: (addIr (a *: v)); rewrite -scalerDr !addNr scaler0. Qed.
+
+Lemma scalerBl a b v : (a - b) *: v = a *: v - b *: v.
+Proof. by rewrite scalerDl scaleNr. Qed.
+
+Lemma scalerBr a u v : a *: (u - v) = a *: u - a *: v.
+Proof. by rewrite scalerDr scalerN. Qed.
+
+Lemma scaler_nat n v : n%:R *: v = v *+ n.
+Proof.
+elim: n => /= [|n ]; first by rewrite scale0r.
+by rewrite !mulrS scalerDl ?scale1r => ->.
+Qed.
+
+Lemma scaler_sign (b : bool) v: (-1) ^+ b *: v = (if b then - v else v).
+Proof. by case: b; rewrite ?scaleNr scale1r. Qed.
+
+Lemma signrZK n : @involutive V ( *:%R ((-1) ^+ n)).
+Proof. by move=> u; rewrite scalerA -expr2 sqrr_sign scale1r. Qed.
+
+Lemma scalerMnl a v n : a *: v *+ n = (a *+ n) *: v.
+Proof.
+elim: n => [|n IHn]; first by rewrite !mulr0n scale0r.
+by rewrite !mulrSr IHn scalerDl.
+Qed.
+
+Lemma scalerMnr a v n : a *: v *+ n = a *: (v *+ n).
+Proof.
+elim: n => [|n IHn]; first by rewrite !mulr0n scaler0.
+by rewrite !mulrSr IHn scalerDr.
+Qed.
+
+Lemma scaler_suml v I r (P : pred I) F :
+ (\sum_(i <- r | P i) F i) *: v = \sum_(i <- r | P i) F i *: v.
+Proof. exact: (big_morph _ (scalerDl v) (scale0r v)). Qed.
+
+Lemma scaler_sumr a I r (P : pred I) (F : I -> V) :
+ a *: (\sum_(i <- r | P i) F i) = \sum_(i <- r | P i) a *: F i.
+Proof. exact: big_endo (scalerDr a) (scaler0 a) I r P F. Qed.
+
+Section ClosedPredicates.
+
+Variable S : predPredType V.
+
+Definition scaler_closed := forall a, {in S, forall v, a *: v \in S}.
+Definition linear_closed := forall a, {in S &, forall u v, a *: u + v \in S}.
+Definition submod_closed := 0 \in S /\ linear_closed.
+
+Lemma linear_closedB : linear_closed -> subr_2closed S.
+Proof. by move=> Slin u v Su Sv; rewrite addrC -scaleN1r Slin. Qed.
+
+Lemma submod_closedB : submod_closed -> zmod_closed S.
+Proof. by case=> S0 /linear_closedB. Qed.
+
+Lemma submod_closedZ : submod_closed -> scaler_closed.
+Proof. by case=> S0 Slin a v Sv; rewrite -[a *: v]addr0 Slin. Qed.
+
+End ClosedPredicates.
+
+End LmoduleTheory.
+
+Module Lalgebra.
+
+Definition axiom (R : ringType) (V : lmodType R) (mul : V -> V -> V) :=
+ forall a u v, a *: mul u v = mul (a *: u) v.
+
+Section ClassDef.
+
+Variable R : ringType.
+
+Record class_of (T : Type) : Type := Class {
+ base : Ring.class_of T;
+ mixin : Lmodule.mixin_of R (Zmodule.Pack base T);
+ ext : @axiom R (Lmodule.Pack _ (Lmodule.Class mixin) T) (Ring.mul base)
+}.
+Definition base2 R m := Lmodule.Class (@mixin R m).
+Local Coercion base : class_of >-> Ring.class_of.
+Local Coercion base2 : class_of >-> Lmodule.class_of.
+
+Structure type (phR : phant R) := Pack {sort; _ : class_of sort; _ : Type}.
+Local Coercion sort : type >-> Sortclass.
+Variable (phR : phant R) (T : Type) (cT : type phR).
+Definition class := let: Pack _ c _ as cT' := cT return class_of cT' in c.
+Definition clone c of phant_id class c := @Pack phR T c T.
+Let xT := let: Pack T _ _ := cT in T.
+Notation xclass := (class : class_of xT).
+
+Definition pack T b0 mul0 (axT : @axiom R (@Lmodule.Pack R _ T b0 T) mul0) :=
+ fun bT b & phant_id (Ring.class bT) (b : Ring.class_of T) =>
+ fun mT m & phant_id (@Lmodule.class R phR mT) (@Lmodule.Class R T b m) =>
+ fun ax & phant_id axT ax =>
+ Pack (Phant R) (@Class T b m ax) T.
+
+Definition eqType := @Equality.Pack cT xclass xT.
+Definition choiceType := @Choice.Pack cT xclass xT.
+Definition zmodType := @Zmodule.Pack cT xclass xT.
+Definition ringType := @Ring.Pack cT xclass xT.
+Definition lmodType := @Lmodule.Pack R phR cT xclass xT.
+Definition lmod_ringType := @Lmodule.Pack R phR ringType xclass xT.
+
+End ClassDef.
+
+Module Exports.
+Coercion base : class_of >-> Ring.class_of.
+Coercion base2 : class_of >-> Lmodule.class_of.
+Coercion sort : type >-> Sortclass.
+Bind Scope ring_scope with sort.
+Coercion eqType : type >-> Equality.type.
+Canonical eqType.
+Coercion choiceType : type >-> Choice.type.
+Canonical choiceType.
+Coercion zmodType : type >-> Zmodule.type.
+Canonical zmodType.
+Coercion ringType : type >-> Ring.type.
+Canonical ringType.
+Coercion lmodType : type >-> Lmodule.type.
+Canonical lmodType.
+Canonical lmod_ringType.
+Notation lalgType R := (type (Phant R)).
+Notation LalgType R T a := (@pack _ (Phant R) T _ _ a _ _ id _ _ id _ id).
+Notation "[ 'lalgType' R 'of' T 'for' cT ]" := (@clone _ (Phant R) T cT _ idfun)
+ (at level 0, format "[ 'lalgType' R 'of' T 'for' cT ]")
+ : form_scope.
+Notation "[ 'lalgType' R 'of' T ]" := (@clone _ (Phant R) T _ _ id)
+ (at level 0, format "[ 'lalgType' R 'of' T ]") : form_scope.
+End Exports.
+
+End Lalgebra.
+Import Lalgebra.Exports.
+
+(* Scalar injection (see the definition of in_alg A below). *)
+Local Notation "k %:A" := (k *: 1) : ring_scope.
+
+(* Regular ring algebra tag. *)
+Definition regular R : Type := R.
+Local Notation "R ^o" := (regular R) (at level 2, format "R ^o") : type_scope.
+
+Section LalgebraTheory.
+
+Variables (R : ringType) (A : lalgType R).
+Implicit Types x y : A.
+
+Lemma scalerAl k (x y : A) : k *: (x * y) = k *: x * y.
+Proof. by case: A k x y => ? []. Qed.
+
+Lemma mulr_algl a x : a%:A * x = a *: x.
+Proof. by rewrite -scalerAl mul1r. Qed.
+
+Canonical regular_eqType := [eqType of R^o].
+Canonical regular_choiceType := [choiceType of R^o].
+Canonical regular_zmodType := [zmodType of R^o].
+Canonical regular_ringType := [ringType of R^o].
+
+Definition regular_lmodMixin :=
+ let mkMixin := @Lmodule.Mixin R regular_zmodType (@mul R) in
+ mkMixin (@mulrA R) (@mul1r R) (@mulrDr R) (fun v a b => mulrDl a b v).
+
+Canonical regular_lmodType := LmodType R R^o regular_lmodMixin.
+Canonical regular_lalgType := LalgType R R^o (@mulrA regular_ringType).
+
+Section ClosedPredicates.
+
+Variable S : predPredType A.
+
+Definition subalg_closed := [/\ 1 \in S, linear_closed S & mulr_2closed S].
+
+Lemma subalg_closedZ : subalg_closed -> submod_closed S.
+Proof. by case=> S1 Slin _; split; rewrite // -(subrr 1) linear_closedB. Qed.
+
+Lemma subalg_closedBM : subalg_closed -> subring_closed S.
+Proof. by case=> S1 Slin SM; split=> //; apply: linear_closedB. Qed.
+
+End ClosedPredicates.
+
+End LalgebraTheory.
+
+(* Morphism hierarchy. *)
+
+Module Additive.
+
+Section ClassDef.
+
+Variables U V : zmodType.
+
+Definition axiom (f : U -> V) := {morph f : x y / x - y}.
+
+Structure map (phUV : phant (U -> V)) := Pack {apply; _ : axiom apply}.
+Local Coercion apply : map >-> Funclass.
+
+Variables (phUV : phant (U -> V)) (f g : U -> V) (cF : map phUV).
+Definition class := let: Pack _ c as cF' := cF return axiom cF' in c.
+Definition clone fA of phant_id g (apply cF) & phant_id fA class :=
+ @Pack phUV f fA.
+
+End ClassDef.
+
+Module Exports.
+Notation additive f := (axiom f).
+Coercion apply : map >-> Funclass.
+Notation Additive fA := (Pack (Phant _) fA).
+Notation "{ 'additive' fUV }" := (map (Phant fUV))
+ (at level 0, format "{ 'additive' fUV }") : ring_scope.
+Notation "[ 'additive' 'of' f 'as' g ]" := (@clone _ _ _ f g _ _ idfun id)
+ (at level 0, format "[ 'additive' 'of' f 'as' g ]") : form_scope.
+Notation "[ 'additive' 'of' f ]" := (@clone _ _ _ f f _ _ id id)
+ (at level 0, format "[ 'additive' 'of' f ]") : form_scope.
+End Exports.
+
+End Additive.
+Include Additive.Exports. (* Allows GRing.additive to resolve conflicts. *)
+
+(* Lifted additive operations. *)
+Section LiftedZmod.
+Variables (U : Type) (V : zmodType).
+Definition null_fun_head (phV : phant V) of U : V := let: Phant := phV in 0.
+Definition add_fun_head t (f g : U -> V) x := let: tt := t in f x + g x.
+Definition sub_fun_head t (f g : U -> V) x := let: tt := t in f x - g x.
+End LiftedZmod.
+
+(* Lifted multiplication. *)
+Section LiftedRing.
+Variables (R : ringType) (T : Type).
+Implicit Type f : T -> R.
+Definition mull_fun_head t a f x := let: tt := t in a * f x.
+Definition mulr_fun_head t a f x := let: tt := t in f x * a.
+End LiftedRing.
+
+(* Lifted linear operations. *)
+Section LiftedScale.
+Variables (R : ringType) (U : Type) (V : lmodType R) (A : lalgType R).
+Definition scale_fun_head t a (f : U -> V) x := let: tt := t in a *: f x.
+Definition in_alg_head (phA : phant A) k : A := let: Phant := phA in k%:A.
+End LiftedScale.
+
+Notation null_fun V := (null_fun_head (Phant V)) (only parsing).
+(* The real in_alg notation is declared after GRing.Theory so that at least *)
+(* in Coq 8.2 it gets precedence when GRing.Theory is not imported. *)
+Local Notation in_alg_loc A := (in_alg_head (Phant A)) (only parsing).
+
+Local Notation "\0" := (null_fun _) : ring_scope.
+Local Notation "f \+ g" := (add_fun_head tt f g) : ring_scope.
+Local Notation "f \- g" := (sub_fun_head tt f g) : ring_scope.
+Local Notation "a \*: f" := (scale_fun_head tt a f) : ring_scope.
+Local Notation "x \*o f" := (mull_fun_head tt x f) : ring_scope.
+Local Notation "x \o* f" := (mulr_fun_head tt x f) : ring_scope.
+
+Section AdditiveTheory.
+
+Section Properties.
+
+Variables (U V : zmodType) (k : unit) (f : {additive U -> V}).
+
+Lemma raddfB : {morph f : x y / x - y}. Proof. exact: Additive.class. Qed.
+
+Lemma raddf0 : f 0 = 0.
+Proof. by rewrite -[0]subr0 raddfB subrr. Qed.
+
+Lemma raddf_eq0 x : injective f -> (f x == 0) = (x == 0).
+Proof. by move=> /inj_eq <-; rewrite raddf0. Qed.
+
+Lemma raddfN : {morph f : x / - x}.
+Proof. by move=> x /=; rewrite -sub0r raddfB raddf0 sub0r. Qed.
+
+Lemma raddfD : {morph f : x y / x + y}.
+Proof. by move=> x y; rewrite -[y]opprK raddfB -raddfN. Qed.
+
+Lemma raddfMn n : {morph f : x / x *+ n}.
+Proof. by elim: n => [|n IHn] x /=; rewrite ?raddf0 // !mulrS raddfD IHn. Qed.
+
+Lemma raddfMNn n : {morph f : x / x *- n}.
+Proof. by move=> x /=; rewrite raddfN raddfMn. Qed.
+
+Lemma raddf_sum I r (P : pred I) E :
+ f (\sum_(i <- r | P i) E i) = \sum_(i <- r | P i) f (E i).
+Proof. exact: (big_morph f raddfD raddf0). Qed.
+
+Lemma can2_additive f' : cancel f f' -> cancel f' f -> additive f'.
+Proof. by move=> fK f'K x y /=; apply: (canLR fK); rewrite raddfB !f'K. Qed.
+
+Lemma bij_additive :
+ bijective f -> exists2 f' : {additive V -> U}, cancel f f' & cancel f' f.
+Proof. by case=> f' fK f'K; exists (Additive (can2_additive fK f'K)). Qed.
+
+Fact locked_is_additive : additive (locked_with k (f : U -> V)).
+Proof. by case: k f => [] []. Qed.
+Canonical locked_additive := Additive locked_is_additive.
+
+End Properties.
+
+Section RingProperties.
+
+Variables (R S : ringType) (f : {additive R -> S}).
+
+Lemma raddfMnat n x : f (n%:R * x) = n%:R * f x.
+Proof. by rewrite !mulr_natl raddfMn. Qed.
+
+Lemma raddfMsign n x : f ((-1) ^+ n * x) = (-1) ^+ n * f x.
+Proof. by rewrite !(mulr_sign, =^~ signr_odd) (fun_if f) raddfN. Qed.
+
+Variables (U : lmodType R) (V : lmodType S) (h : {additive U -> V}).
+
+Lemma raddfZnat n u : h (n%:R *: u) = n%:R *: h u.
+Proof. by rewrite !scaler_nat raddfMn. Qed.
+
+Lemma raddfZsign n u : h ((-1) ^+ n *: u) = (-1) ^+ n *: h u.
+Proof. by rewrite !(scaler_sign, =^~ signr_odd) (fun_if h) raddfN. Qed.
+
+End RingProperties.
+
+Section AddFun.
+
+Variables (U V W : zmodType) (f g : {additive V -> W}) (h : {additive U -> V}).
+
+Fact idfun_is_additive : additive (@idfun U).
+Proof. by []. Qed.
+Canonical idfun_additive := Additive idfun_is_additive.
+
+Fact comp_is_additive : additive (f \o h).
+Proof. by move=> x y /=; rewrite !raddfB. Qed.
+Canonical comp_additive := Additive comp_is_additive.
+
+Fact opp_is_additive : additive (-%R : U -> U).
+Proof. by move=> x y; rewrite /= opprD. Qed.
+Canonical opp_additive := Additive opp_is_additive.
+
+Fact null_fun_is_additive : additive (\0 : U -> V).
+Proof. by move=> /=; rewrite subr0. Qed.
+Canonical null_fun_additive := Additive null_fun_is_additive.
+
+Fact add_fun_is_additive : additive (f \+ g).
+Proof.
+by move=> x y /=; rewrite !raddfB addrCA -!addrA addrCA -opprD.
+Qed.
+Canonical add_fun_additive := Additive add_fun_is_additive.
+
+Fact sub_fun_is_additive : additive (f \- g).
+Proof.
+by move=> x y /=; rewrite !raddfB addrAC -!addrA -!opprD addrAC addrA.
+Qed.
+Canonical sub_fun_additive := Additive sub_fun_is_additive.
+
+End AddFun.
+
+Section MulFun.
+
+Variables (R : ringType) (U : zmodType).
+Variables (a : R) (f : {additive U -> R}).
+
+Fact mull_fun_is_additive : additive (a \*o f).
+Proof. by move=> x y /=; rewrite raddfB mulrBr. Qed.
+Canonical mull_fun_additive := Additive mull_fun_is_additive.
+
+Fact mulr_fun_is_additive : additive (a \o* f).
+Proof. by move=> x y /=; rewrite raddfB mulrBl. Qed.
+Canonical mulr_fun_additive := Additive mulr_fun_is_additive.
+
+End MulFun.
+
+Section ScaleFun.
+
+Variables (R : ringType) (U : zmodType) (V : lmodType R).
+Variables (a : R) (f : {additive U -> V}).
+
+Canonical scale_additive := Additive (@scalerBr R V a).
+Canonical scale_fun_additive := [additive of a \*: f as f \; *:%R a].
+
+End ScaleFun.
+
+End AdditiveTheory.
+
+Module RMorphism.
+
+Section ClassDef.
+
+Variables R S : ringType.
+
+Definition mixin_of (f : R -> S) :=
+ {morph f : x y / x * y}%R * (f 1 = 1) : Prop.
+
+Record class_of f : Prop := Class {base : additive f; mixin : mixin_of f}.
+Local Coercion base : class_of >-> additive.
+
+Structure map (phRS : phant (R -> S)) := Pack {apply; _ : class_of apply}.
+Local Coercion apply : map >-> Funclass.
+Variables (phRS : phant (R -> S)) (f g : R -> S) (cF : map phRS).
+
+Definition class := let: Pack _ c as cF' := cF return class_of cF' in c.
+
+Definition clone fM of phant_id g (apply cF) & phant_id fM class :=
+ @Pack phRS f fM.
+
+Definition pack (fM : mixin_of f) :=
+ fun (bF : Additive.map phRS) fA & phant_id (Additive.class bF) fA =>
+ Pack phRS (Class fA fM).
+
+Canonical additive := Additive.Pack phRS class.
+
+End ClassDef.
+
+Module Exports.
+Notation multiplicative f := (mixin_of f).
+Notation rmorphism f := (class_of f).
+Coercion base : rmorphism >-> Additive.axiom.
+Coercion mixin : rmorphism >-> multiplicative.
+Coercion apply : map >-> Funclass.
+Notation RMorphism fM := (Pack (Phant _) fM).
+Notation AddRMorphism fM := (pack fM id).
+Notation "{ 'rmorphism' fRS }" := (map (Phant fRS))
+ (at level 0, format "{ 'rmorphism' fRS }") : ring_scope.
+Notation "[ 'rmorphism' 'of' f 'as' g ]" := (@clone _ _ _ f g _ _ idfun id)
+ (at level 0, format "[ 'rmorphism' 'of' f 'as' g ]") : form_scope.
+Notation "[ 'rmorphism' 'of' f ]" := (@clone _ _ _ f f _ _ id id)
+ (at level 0, format "[ 'rmorphism' 'of' f ]") : form_scope.
+Coercion additive : map >-> Additive.map.
+Canonical additive.
+End Exports.
+
+End RMorphism.
+Include RMorphism.Exports.
+
+Section RmorphismTheory.
+
+Section Properties.
+
+Variables (R S : ringType) (k : unit) (f : {rmorphism R -> S}).
+
+Lemma rmorph0 : f 0 = 0. Proof. exact: raddf0. Qed.
+Lemma rmorphN : {morph f : x / - x}. Proof. exact: raddfN. Qed.
+Lemma rmorphD : {morph f : x y / x + y}. Proof. exact: raddfD. Qed.
+Lemma rmorphB : {morph f: x y / x - y}. Proof. exact: raddfB. Qed.
+Lemma rmorphMn n : {morph f : x / x *+ n}. Proof. exact: raddfMn. Qed.
+Lemma rmorphMNn n : {morph f : x / x *- n}. Proof. exact: raddfMNn. Qed.
+Lemma rmorph_sum I r (P : pred I) E :
+ f (\sum_(i <- r | P i) E i) = \sum_(i <- r | P i) f (E i).
+Proof. exact: raddf_sum. Qed.
+Lemma rmorphMsign n : {morph f : x / (- 1) ^+ n * x}.
+Proof. exact: raddfMsign. Qed.
+
+Lemma rmorphismP : rmorphism f. Proof. exact: RMorphism.class. Qed.
+Lemma rmorphismMP : multiplicative f. Proof. exact: rmorphismP. Qed.
+Lemma rmorph1 : f 1 = 1. Proof. by case: rmorphismMP. Qed.
+Lemma rmorphM : {morph f: x y / x * y}. Proof. by case: rmorphismMP. Qed.
+
+Lemma rmorph_prod I r (P : pred I) E :
+ f (\prod_(i <- r | P i) E i) = \prod_(i <- r | P i) f (E i).
+Proof. exact: (big_morph f rmorphM rmorph1). Qed.
+
+Lemma rmorphX n : {morph f: x / x ^+ n}.
+Proof. by elim: n => [|n IHn] x; rewrite ?rmorph1 // !exprS rmorphM IHn. Qed.
+
+Lemma rmorph_nat n : f n%:R = n%:R. Proof. by rewrite rmorphMn rmorph1. Qed.
+Lemma rmorphN1 : f (- 1) = (- 1). Proof. by rewrite rmorphN rmorph1. Qed.
+
+Lemma rmorph_sign n : f ((- 1) ^+ n) = (- 1) ^+ n.
+Proof. by rewrite rmorphX rmorphN1. Qed.
+
+Lemma rmorph_char p : p \in [char R] -> p \in [char S].
+Proof. by rewrite !inE -rmorph_nat => /andP[-> /= /eqP->]; rewrite rmorph0. Qed.
+
+Lemma rmorph_eq_nat x n : injective f -> (f x == n%:R) = (x == n%:R).
+Proof. by move/inj_eq <-; rewrite rmorph_nat. Qed.
+
+Lemma rmorph_eq1 x : injective f -> (f x == 1) = (x == 1).
+Proof. exact: rmorph_eq_nat 1%N. Qed.
+
+Lemma can2_rmorphism f' : cancel f f' -> cancel f' f -> rmorphism f'.
+Proof.
+move=> fK f'K; split; first exact: can2_additive fK f'K.
+by split=> [x y|]; apply: (canLR fK); rewrite /= (rmorphM, rmorph1) ?f'K.
+Qed.
+
+Lemma bij_rmorphism :
+ bijective f -> exists2 f' : {rmorphism S -> R}, cancel f f' & cancel f' f.
+Proof. by case=> f' fK f'K; exists (RMorphism (can2_rmorphism fK f'K)). Qed.
+
+Fact locked_is_multiplicative : multiplicative (locked_with k (f : R -> S)).
+Proof. by case: k f => [] [? []]. Qed.
+Canonical locked_rmorphism := AddRMorphism locked_is_multiplicative.
+
+End Properties.
+
+Section Projections.
+
+Variables (R S T : ringType) (f : {rmorphism S -> T}) (g : {rmorphism R -> S}).
+
+Fact idfun_is_multiplicative : multiplicative (@idfun R).
+Proof. by []. Qed.
+Canonical idfun_rmorphism := AddRMorphism idfun_is_multiplicative.
+
+Fact comp_is_multiplicative : multiplicative (f \o g).
+Proof. by split=> [x y|] /=; rewrite ?rmorph1 ?rmorphM. Qed.
+Canonical comp_rmorphism := AddRMorphism comp_is_multiplicative.
+
+End Projections.
+
+Section InAlgebra.
+
+Variables (R : ringType) (A : lalgType R).
+
+Fact in_alg_is_rmorphism : rmorphism (in_alg_loc A).
+Proof.
+split=> [x y|]; first exact: scalerBl.
+by split=> [x y|] /=; rewrite ?scale1r // -scalerAl mul1r scalerA.
+Qed.
+Canonical in_alg_additive := Additive in_alg_is_rmorphism.
+Canonical in_alg_rmorphism := RMorphism in_alg_is_rmorphism.
+
+Lemma in_algE a : in_alg_loc A a = a%:A. Proof. by []. Qed.
+
+End InAlgebra.
+
+End RmorphismTheory.
+
+Module Scale.
+
+Section ScaleLaw.
+
+Structure law (R : ringType) (V : zmodType) (s : R -> V -> V) := Law {
+ op : R -> V -> V;
+ _ : op = s;
+ _ : op (-1) =1 -%R;
+ _ : forall a, additive (op a)
+}.
+
+Definition mul_law R := Law (erefl *%R) (@mulN1r R) (@mulrBr R).
+Definition scale_law R U := Law (erefl *:%R) (@scaleN1r R U) (@scalerBr R U).
+
+Variables (R : ringType) (V : zmodType) (s : R -> V -> V) (s_law : law s).
+Local Notation s_op := (op s_law).
+
+Lemma opE : s_op = s. Proof. by case: s_law. Qed.
+Lemma N1op : s_op (-1) =1 -%R. Proof. by case: s_law. Qed.
+Fact opB a : additive (s_op a). Proof. by case: s_law. Qed.
+Definition op_additive a := Additive (opB a).
+
+Variables (aR : ringType) (nu : {rmorphism aR -> R}).
+Fact comp_opE : nu \; s_op = nu \; s. Proof. exact: congr1 opE. Qed.
+Fact compN1op : (nu \; s_op) (-1) =1 -%R.
+Proof. by move=> v; rewrite /= rmorphN1 N1op. Qed.
+Definition comp_law : law (nu \; s) := Law comp_opE compN1op (fun a => opB _).
+
+End ScaleLaw.
+
+End Scale.
+
+Module Linear.
+
+Section ClassDef.
+
+Variables (R : ringType) (U : lmodType R) (V : zmodType) (s : R -> V -> V).
+Implicit Type phUV : phant (U -> V).
+
+Local Coercion Scale.op : Scale.law >-> Funclass.
+Definition axiom (f : U -> V) (s_law : Scale.law s) of s = s_law :=
+ forall a, {morph f : u v / a *: u + v >-> s a u + v}.
+Definition mixin_of (f : U -> V) :=
+ forall a, {morph f : v / a *: v >-> s a v}.
+
+Record class_of f : Prop := Class {base : additive f; mixin : mixin_of f}.
+Local Coercion base : class_of >-> additive.
+
+Lemma class_of_axiom f s_law Ds : @axiom f s_law Ds -> class_of f.
+Proof.
+move=> fL; have fB: additive f.
+ by move=> x y /=; rewrite -scaleN1r addrC fL Ds Scale.N1op addrC.
+by split=> // a v /=; rewrite -[a *: v](addrK v) fB fL addrK Ds.
+Qed.
+
+Structure map (phUV : phant (U -> V)) := Pack {apply; _ : class_of apply}.
+Local Coercion apply : map >-> Funclass.
+
+Variables (phUV : phant (U -> V)) (f g : U -> V) (cF : map phUV).
+Definition class := let: Pack _ c as cF' := cF return class_of cF' in c.
+Definition clone fL of phant_id g (apply cF) & phant_id fL class :=
+ @Pack phUV f fL.
+
+Definition pack (fZ : mixin_of f) :=
+ fun (bF : Additive.map phUV) fA & phant_id (Additive.class bF) fA =>
+ Pack phUV (Class fA fZ).
+
+Canonical additive := Additive.Pack phUV class.
+
+(* Support for right-to-left rewriting with the generic linearZ rule. *)
+Notation mapUV := (map (Phant (U -> V))).
+Definition map_class := mapUV.
+Definition map_at (a : R) := mapUV.
+Structure map_for a s_a := MapFor {map_for_map : mapUV; _ : s a = s_a}.
+Definition unify_map_at a (f : map_at a) := MapFor f (erefl (s a)).
+Structure wrapped := Wrap {unwrap : mapUV}.
+Definition wrap (f : map_class) := Wrap f.
+
+End ClassDef.
+
+Module Exports.
+Canonical Scale.mul_law.
+Canonical Scale.scale_law.
+Canonical Scale.comp_law.
+Canonical Scale.op_additive.
+Delimit Scope linear_ring_scope with linR.
+Notation "a *: u" := (@Scale.op _ _ *:%R _ a u) : linear_ring_scope.
+Notation "a * u" := (@Scale.op _ _ *%R _ a u) : linear_ring_scope.
+Notation "a *:^ nu u" := (@Scale.op _ _ (nu \; *:%R) _ a u)
+ (at level 40, nu at level 1, format "a *:^ nu u") : linear_ring_scope.
+Notation "a *^ nu u" := (@Scale.op _ _ (nu \; *%R) _ a u)
+ (at level 40, nu at level 1, format "a *^ nu u") : linear_ring_scope.
+Notation scalable_for s f := (mixin_of s f).
+Notation scalable f := (scalable_for *:%R f).
+Notation linear_for s f := (axiom f (erefl s)).
+Notation linear f := (linear_for *:%R f).
+Notation scalar f := (linear_for *%R f).
+Notation lmorphism_for s f := (class_of s f).
+Notation lmorphism f := (lmorphism_for *:%R f).
+Coercion class_of_axiom : axiom >-> lmorphism_for.
+Coercion base : lmorphism_for >-> Additive.axiom.
+Coercion mixin : lmorphism_for >-> scalable.
+Coercion apply : map >-> Funclass.
+Notation Linear fL := (Pack (Phant _) fL).
+Notation AddLinear fZ := (pack fZ id).
+Notation "{ 'linear' fUV | s }" := (map s (Phant fUV))
+ (at level 0, format "{ 'linear' fUV | s }") : ring_scope.
+Notation "{ 'linear' fUV }" := {linear fUV | *:%R}
+ (at level 0, format "{ 'linear' fUV }") : ring_scope.
+Notation "{ 'scalar' U }" := {linear U -> _ | *%R}
+ (at level 0, format "{ 'scalar' U }") : ring_scope.
+Notation "[ 'linear' 'of' f 'as' g ]" := (@clone _ _ _ _ _ f g _ _ idfun id)
+ (at level 0, format "[ 'linear' 'of' f 'as' g ]") : form_scope.
+Notation "[ 'linear' 'of' f ]" := (@clone _ _ _ _ _ f f _ _ id id)
+ (at level 0, format "[ 'linear' 'of' f ]") : form_scope.
+Coercion additive : map >-> Additive.map.
+Canonical additive.
+(* Support for right-to-left rewriting with the generic linearZ rule. *)
+Coercion map_for_map : map_for >-> map.
+Coercion unify_map_at : map_at >-> map_for.
+Canonical unify_map_at.
+Coercion unwrap : wrapped >-> map.
+Coercion wrap : map_class >-> wrapped.
+Canonical wrap.
+End Exports.
+
+End Linear.
+Include Linear.Exports.
+
+Section LinearTheory.
+
+Variable R : ringType.
+
+Section GenericProperties.
+
+Variables (U : lmodType R) (V : zmodType) (s : R -> V -> V) (k : unit).
+Variable f : {linear U -> V | s}.
+
+Lemma linear0 : f 0 = 0. Proof. exact: raddf0. Qed.
+Lemma linearN : {morph f : x / - x}. Proof. exact: raddfN. Qed.
+Lemma linearD : {morph f : x y / x + y}. Proof. exact: raddfD. Qed.
+Lemma linearB : {morph f : x y / x - y}. Proof. exact: raddfB. Qed.
+Lemma linearMn n : {morph f : x / x *+ n}. Proof. exact: raddfMn. Qed.
+Lemma linearMNn n : {morph f : x / x *- n}. Proof. exact: raddfMNn. Qed.
+Lemma linear_sum I r (P : pred I) E :
+ f (\sum_(i <- r | P i) E i) = \sum_(i <- r | P i) f (E i).
+Proof. exact: raddf_sum. Qed.
+
+Lemma linearZ_LR : scalable_for s f. Proof. by case: f => ? []. Qed.
+Lemma linearP a : {morph f : u v / a *: u + v >-> s a u + v}.
+Proof. by move=> u v /=; rewrite linearD linearZ_LR. Qed.
+
+Fact locked_is_scalable : scalable_for s (locked_with k (f : U -> V)).
+Proof. by case: k f => [] [? []]. Qed.
+Canonical locked_linear := AddLinear locked_is_scalable.
+
+End GenericProperties.
+
+Section BidirectionalLinearZ.
+
+Variables (U : lmodType R) (V : zmodType) (s : R -> V -> V).
+
+(* The general form of the linearZ lemma uses some bespoke interfaces to *)
+(* allow right-to-left rewriting when a composite scaling operation such as *)
+(* conjC \; *%R has been expanded, say in a^* * f u. This redex is matched *)
+(* by using the Scale.law interface to recognize a "head" scaling operation *)
+(* h (here *%R), stow away its "scalar" c, then reconcile h c and s a, once *)
+(* s is known, that is, once the Linear.map structure for f has been found. *)
+(* In general, s and a need not be equal to h and c; indeed they need not *)
+(* have the same type! The unification is performed by the unify_map_at *)
+(* default instance for the Linear.map_for U s a h_c sub-interface of *)
+(* Linear.map; the h_c pattern uses the Scale.law structure to insure it is *)
+(* inferred when rewriting right-to-left. *)
+(* The wrap on the rhs allows rewriting f (a *: b *: u) into a *: b *: f u *)
+(* with rewrite !linearZ /= instead of rewrite linearZ /= linearZ /=. *)
+(* Without it, the first rewrite linearZ would produce *)
+(* (a *: apply (map_for_map (@check_map_at .. a f)) (b *: u)%R)%Rlin *)
+(* and matching the second rewrite LHS would bypass the unify_map_at default *)
+(* instance for b, reuse the one for a, and subsequently fail to match the *)
+(* b *: u argument. The extra wrap / unwrap ensures that this can't happen. *)
+(* In the RL direction, the wrap / unwrap will be inserted on the redex side *)
+(* as needed, without causing unnecessary delta-expansion: using an explicit *)
+(* identity function would have Coq normalize the redex to head normal, then *)
+(* reduce the identity to expose the map_for_map projection, and the *)
+(* expanded Linear.map structure would then be exposed in the result. *)
+(* Most of this machinery will be invisible to a casual user, because all *)
+(* the projections and default instances involved are declared as coercions. *)
+
+Variables (S : ringType) (h : S -> V -> V) (h_law : Scale.law h).
+
+Lemma linearZ c a (h_c := Scale.op h_law c) (f : Linear.map_for U s a h_c) u :
+ f (a *: u) = h_c (Linear.wrap f u).
+Proof. by rewrite linearZ_LR; case: f => f /= ->. Qed.
+
+End BidirectionalLinearZ.
+
+Section LmodProperties.
+
+Variables (U V : lmodType R) (f : {linear U -> V}).
+
+Lemma linearZZ : scalable f. Proof. exact: linearZ_LR. Qed.
+Lemma linearPZ : linear f. Proof. exact: linearP. Qed.
+
+Lemma can2_linear f' : cancel f f' -> cancel f' f -> linear f'.
+Proof. by move=> fK f'K a x y /=; apply: (canLR fK); rewrite linearP !f'K. Qed.
+
+Lemma bij_linear :
+ bijective f -> exists2 f' : {linear V -> U}, cancel f f' & cancel f' f.
+Proof. by case=> f' fK f'K; exists (Linear (can2_linear fK f'K)). Qed.
+
+End LmodProperties.
+
+Section ScalarProperties.
+
+Variable (U : lmodType R) (f : {scalar U}).
+
+Lemma scalarZ : scalable_for *%R f. Proof. exact: linearZ_LR. Qed.
+Lemma scalarP : scalar f. Proof. exact: linearP. Qed.
+
+End ScalarProperties.
+
+Section LinearLmod.
+
+Variables (W U : lmodType R) (V : zmodType) (s : R -> V -> V).
+Variables (f : {linear U -> V | s}) (h : {linear W -> U}).
+
+Lemma idfun_is_scalable : scalable (@idfun U). Proof. by []. Qed.
+Canonical idfun_linear := AddLinear idfun_is_scalable.
+
+Lemma opp_is_scalable : scalable (-%R : U -> U).
+Proof. by move=> a v /=; rewrite scalerN. Qed.
+Canonical opp_linear := AddLinear opp_is_scalable.
+
+Lemma comp_is_scalable : scalable_for s (f \o h).
+Proof. by move=> a v /=; rewrite !linearZ_LR. Qed.
+Canonical comp_linear := AddLinear comp_is_scalable.
+
+Variables (s_law : Scale.law s) (g : {linear U -> V | Scale.op s_law}).
+Let Ds : s =1 Scale.op s_law. Proof. by rewrite Scale.opE. Qed.
+
+Lemma null_fun_is_scalable : scalable_for (Scale.op s_law) (\0 : U -> V).
+Proof. by move=> a v /=; rewrite raddf0. Qed.
+Canonical null_fun_linear := AddLinear null_fun_is_scalable.
+
+Lemma add_fun_is_scalable : scalable_for s (f \+ g).
+Proof. by move=> a u; rewrite /= !linearZ_LR !Ds raddfD. Qed.
+Canonical add_fun_linear := AddLinear add_fun_is_scalable.
+
+Lemma sub_fun_is_scalable : scalable_for s (f \- g).
+Proof. by move=> a u; rewrite /= !linearZ_LR !Ds raddfB. Qed.
+Canonical sub_fun_linear := AddLinear sub_fun_is_scalable.
+
+End LinearLmod.
+
+Section LinearLalg.
+
+Variables (A : lalgType R) (U : lmodType R).
+
+Variables (a : A) (f : {linear U -> A}).
+
+Fact mulr_fun_is_scalable : scalable (a \o* f).
+Proof. by move=> k x /=; rewrite linearZ scalerAl. Qed.
+Canonical mulr_fun_linear := AddLinear mulr_fun_is_scalable.
+
+End LinearLalg.
+
+End LinearTheory.
+
+Module LRMorphism.
+
+Section ClassDef.
+
+Variables (R : ringType) (A : lalgType R) (B : ringType) (s : R -> B -> B).
+
+Record class_of (f : A -> B) : Prop :=
+ Class {base : rmorphism f; mixin : scalable_for s f}.
+Local Coercion base : class_of >-> rmorphism.
+Definition base2 f (fLM : class_of f) := Linear.Class fLM (mixin fLM).
+Local Coercion base2 : class_of >-> lmorphism.
+
+Structure map (phAB : phant (A -> B)) := Pack {apply; _ : class_of apply}.
+Local Coercion apply : map >-> Funclass.
+
+Variables (phAB : phant (A -> B)) (f : A -> B) (cF : map phAB).
+Definition class := let: Pack _ c as cF' := cF return class_of cF' in c.
+
+Definition clone :=
+ fun (g : RMorphism.map phAB) fM & phant_id (RMorphism.class g) fM =>
+ fun (h : Linear.map s phAB) fZ &
+ phant_id (Linear.mixin (Linear.class h)) fZ =>
+ Pack phAB (@Class f fM fZ).
+
+Definition pack (fZ : scalable_for s f) :=
+ fun (g : RMorphism.map phAB) fM & phant_id (RMorphism.class g) fM =>
+ Pack phAB (Class fM fZ).
+
+Canonical additive := Additive.Pack phAB class.
+Canonical rmorphism := RMorphism.Pack phAB class.
+Canonical linear := Linear.Pack phAB class.
+Canonical join_rmorphism := @RMorphism.Pack _ _ phAB linear class.
+Canonical join_linear := @Linear.Pack R A B s phAB rmorphism class.
+
+End ClassDef.
+
+Module Exports.
+Notation lrmorphism_for s f := (class_of s f).
+Notation lrmorphism f := (lrmorphism_for *:%R f).
+Coercion base : lrmorphism_for >-> RMorphism.class_of.
+Coercion base2 : lrmorphism_for >-> lmorphism_for.
+Coercion apply : map >-> Funclass.
+Notation LRMorphism f_lrM := (Pack (Phant _) (Class f_lrM f_lrM)).
+Notation AddLRMorphism fZ := (pack fZ id).
+Notation "{ 'lrmorphism' fAB | s }" := (map s (Phant fAB))
+ (at level 0, format "{ 'lrmorphism' fAB | s }") : ring_scope.
+Notation "{ 'lrmorphism' fAB }" := {lrmorphism fAB | *:%R}
+ (at level 0, format "{ 'lrmorphism' fAB }") : ring_scope.
+Notation "[ 'lrmorphism' 'of' f ]" := (@clone _ _ _ _ _ f _ _ id _ _ id)
+ (at level 0, format "[ 'lrmorphism' 'of' f ]") : form_scope.
+Coercion additive : map >-> Additive.map.
+Canonical additive.
+Coercion rmorphism : map >-> RMorphism.map.
+Canonical rmorphism.
+Coercion linear : map >-> Linear.map.
+Canonical linear.
+Canonical join_rmorphism.
+Canonical join_linear.
+End Exports.
+
+End LRMorphism.
+Include LRMorphism.Exports.
+
+Section LRMorphismTheory.
+
+Variables (R : ringType) (A B : lalgType R) (C : ringType) (s : R -> C -> C).
+Variables (k : unit) (f : {lrmorphism A -> B}) (g : {lrmorphism B -> C | s}).
+
+Definition idfun_lrmorphism := [lrmorphism of @idfun A].
+Definition comp_lrmorphism := [lrmorphism of g \o f].
+Definition locked_lrmorphism := [lrmorphism of locked_with k (f : A -> B)].
+
+Lemma rmorph_alg a : f a%:A = a%:A.
+Proof. by rewrite linearZ rmorph1. Qed.
+
+Lemma lrmorphismP : lrmorphism f. Proof. exact: LRMorphism.class. Qed.
+
+Lemma can2_lrmorphism f' : cancel f f' -> cancel f' f -> lrmorphism f'.
+Proof.
+move=> fK f'K; split; [exact: (can2_rmorphism fK) | exact: (can2_linear fK)].
+Qed.
+
+Lemma bij_lrmorphism :
+ bijective f -> exists2 f' : {lrmorphism B -> A}, cancel f f' & cancel f' f.
+Proof.
+by case/bij_rmorphism=> f' fK f'K; exists (AddLRMorphism (can2_linear fK f'K)).
+Qed.
+
+End LRMorphismTheory.
+
+Module ComRing.
+
+Definition RingMixin R one mul mulA mulC mul1x mul_addl :=
+ let mulx1 := Monoid.mulC_id mulC mul1x in
+ let mul_addr := Monoid.mulC_dist mulC mul_addl in
+ @Ring.EtaMixin R one mul mulA mul1x mulx1 mul_addl mul_addr.
+
+Section ClassDef.
+
+Record class_of R :=
+ Class {base : Ring.class_of R; mixin : commutative (Ring.mul base)}.
+Local Coercion base : class_of >-> Ring.class_of.
+
+Structure type := Pack {sort; _ : class_of sort; _ : Type}.
+Local Coercion sort : type >-> Sortclass.
+Variable (T : Type) (cT : type).
+Definition class := let: Pack _ c _ as cT' := cT return class_of cT' in c.
+Definition clone c of phant_id class c := @Pack T c T.
+Let xT := let: Pack T _ _ := cT in T.
+Notation xclass := (class : class_of xT).
+
+Definition pack mul0 (m0 : @commutative T T mul0) :=
+ fun bT b & phant_id (Ring.class bT) b =>
+ fun m & phant_id m0 m => Pack (@Class T b m) T.
+
+Definition eqType := @Equality.Pack cT xclass xT.
+Definition choiceType := @Choice.Pack cT xclass xT.
+Definition zmodType := @Zmodule.Pack cT xclass xT.
+Definition ringType := @Ring.Pack cT xclass xT.
+
+End ClassDef.
+
+Module Exports.
+Coercion base : class_of >-> Ring.class_of.
+Implicit Arguments mixin [R].
+Coercion mixin : class_of >-> commutative.
+Coercion sort : type >-> Sortclass.
+Bind Scope ring_scope with sort.
+Coercion eqType : type >-> Equality.type.
+Canonical eqType.
+Coercion choiceType : type >-> Choice.type.
+Canonical choiceType.
+Coercion zmodType : type >-> Zmodule.type.
+Canonical zmodType.
+Coercion ringType : type >-> Ring.type.
+Canonical ringType.
+Notation comRingType := type.
+Notation ComRingType T m := (@pack T _ m _ _ id _ id).
+Notation ComRingMixin := RingMixin.
+Notation "[ 'comRingType' 'of' T 'for' cT ]" := (@clone T cT _ idfun)
+ (at level 0, format "[ 'comRingType' 'of' T 'for' cT ]") : form_scope.
+Notation "[ 'comRingType' 'of' T ]" := (@clone T _ _ id)
+ (at level 0, format "[ 'comRingType' 'of' T ]") : form_scope.
+End Exports.
+
+End ComRing.
+Import ComRing.Exports.
+
+Section ComRingTheory.
+
+Variable R : comRingType.
+Implicit Types x y : R.
+
+Lemma mulrC : @commutative R R *%R. Proof. by case: R => T []. Qed.
+Canonical mul_comoid := Monoid.ComLaw mulrC.
+Lemma mulrCA : @left_commutative R R *%R. Proof. exact: mulmCA. Qed.
+Lemma mulrAC : @right_commutative R R *%R. Proof. exact: mulmAC. Qed.
+Lemma mulrACA : @interchange R *%R *%R. Proof. exact: mulmACA. Qed.
+
+Lemma exprMn n : {morph (fun x => x ^+ n) : x y / x * y}.
+Proof. move=> x y; apply: exprMn_comm; exact: mulrC. Qed.
+
+Lemma prodrXl n I r (P : pred I) (F : I -> R) :
+ \prod_(i <- r | P i) F i ^+ n = (\prod_(i <- r | P i) F i) ^+ n.
+Proof. by rewrite (big_morph _ (exprMn n) (expr1n _ n)). Qed.
+
+Lemma prodr_undup_exp_count (I : eqType) r (P : pred I) (F : I -> R) :
+ \prod_(i <- undup r | P i) F i ^+ count_mem i r = \prod_(i <- r | P i) F i.
+Proof. exact: big_undup_iterop_count. Qed.
+
+Lemma exprDn x y n :
+ (x + y) ^+ n = \sum_(i < n.+1) (x ^+ (n - i) * y ^+ i) *+ 'C(n, i).
+Proof. by rewrite exprDn_comm //; exact: mulrC. Qed.
+
+Lemma exprBn x y n :
+ (x - y) ^+ n =
+ \sum_(i < n.+1) ((-1) ^+ i * x ^+ (n - i) * y ^+ i) *+ 'C(n, i).
+Proof. by rewrite exprBn_comm //; exact: mulrC. Qed.
+
+Lemma subrXX x y n :
+ x ^+ n - y ^+ n = (x - y) * (\sum_(i < n) x ^+ (n.-1 - i) * y ^+ i).
+Proof. by rewrite -subrXX_comm //; exact: mulrC. Qed.
+
+Lemma sqrrD x y : (x + y) ^+ 2 = x ^+ 2 + x * y *+ 2 + y ^+ 2.
+Proof. by rewrite exprDn !big_ord_recr big_ord0 /= add0r mulr1 mul1r. Qed.
+
+Lemma sqrrB x y : (x - y) ^+ 2 = x ^+ 2 - x * y *+ 2 + y ^+ 2.
+Proof. by rewrite sqrrD mulrN mulNrn sqrrN. Qed.
+
+Lemma subr_sqr x y : x ^+ 2 - y ^+ 2 = (x - y) * (x + y).
+Proof. by rewrite subrXX !big_ord_recr big_ord0 /= add0r mulr1 mul1r. Qed.
+
+Lemma subr_sqrDB x y : (x + y) ^+ 2 - (x - y) ^+ 2 = x * y *+ 4.
+Proof.
+rewrite sqrrD sqrrB -!(addrAC _ (y ^+ 2)) opprB.
+by rewrite addrC addrA subrK -mulrnDr.
+Qed.
+
+Section FrobeniusAutomorphism.
+
+Variables (p : nat) (charRp : p \in [char R]).
+
+Lemma Frobenius_aut_is_rmorphism : rmorphism (Frobenius_aut charRp).
+Proof.
+split=> [x y|]; first exact: Frobenius_autB_comm (mulrC _ _).
+split=> [x y|]; first exact: Frobenius_autM_comm (mulrC _ _).
+exact: Frobenius_aut1.
+Qed.
+
+Canonical Frobenius_aut_additive := Additive Frobenius_aut_is_rmorphism.
+Canonical Frobenius_aut_rmorphism := RMorphism Frobenius_aut_is_rmorphism.
+
+End FrobeniusAutomorphism.
+
+Lemma exprDn_char x y n : [char R].-nat n -> (x + y) ^+ n = x ^+ n + y ^+ n.
+Proof.
+pose p := pdiv n; have [|n_gt1 charRn] := leqP n 1; first by case: (n) => [|[]].
+have charRp: p \in [char R] by rewrite (pnatPpi charRn) ?pi_pdiv.
+have{charRn} /p_natP[e ->]: p.-nat n by rewrite -(eq_pnat _ (charf_eq charRp)).
+by elim: e => // e IHe; rewrite !expnSr !exprM IHe -Frobenius_autE rmorphD.
+Qed.
+
+Lemma rmorph_comm (S : ringType) (f : {rmorphism R -> S}) x y :
+ comm (f x) (f y).
+Proof. by red; rewrite -!rmorphM mulrC. Qed.
+
+Section ScaleLinear.
+
+Variables (U V : lmodType R) (b : R) (f : {linear U -> V}).
+
+Lemma scale_is_scalable : scalable ( *:%R b : V -> V).
+Proof. by move=> a v /=; rewrite !scalerA mulrC. Qed.
+Canonical scale_linear := AddLinear scale_is_scalable.
+
+Lemma scale_fun_is_scalable : scalable (b \*: f).
+Proof. by move=> a v /=; rewrite !linearZ. Qed.
+Canonical scale_fun_linear := AddLinear scale_fun_is_scalable.
+
+End ScaleLinear.
+
+End ComRingTheory.
+
+Module Algebra.
+
+Section Mixin.
+
+Variables (R : ringType) (A : lalgType R).
+
+Definition axiom := forall k (x y : A), k *: (x * y) = x * (k *: y).
+
+Lemma comm_axiom : phant A -> commutative (@mul A) -> axiom.
+Proof. by move=> _ commA k x y; rewrite commA scalerAl commA. Qed.
+
+End Mixin.
+
+Section ClassDef.
+
+Variable R : ringType.
+
+Record class_of (T : Type) : Type := Class {
+ base : Lalgebra.class_of R T;
+ mixin : axiom (Lalgebra.Pack _ base T)
+}.
+Local Coercion base : class_of >-> Lalgebra.class_of.
+
+Structure type (phR : phant R) := Pack {sort; _ : class_of sort; _ : Type}.
+Local Coercion sort : type >-> Sortclass.
+Variable (phR : phant R) (T : Type) (cT : type phR).
+Definition class := let: Pack _ c _ as cT' := cT return class_of cT' in c.
+Definition clone c of phant_id class c := @Pack phR T c T.
+Let xT := let: Pack T _ _ := cT in T.
+Notation xclass := (class : class_of xT).
+
+Definition pack b0 (ax0 : @axiom R b0) :=
+ fun bT b & phant_id (@Lalgebra.class R phR bT) b =>
+ fun ax & phant_id ax0 ax => Pack phR (@Class T b ax) T.
+
+Definition eqType := @Equality.Pack cT xclass xT.
+Definition choiceType := @Choice.Pack cT xclass xT.
+Definition zmodType := @Zmodule.Pack cT xclass xT.
+Definition ringType := @Ring.Pack cT xclass xT.
+Definition lmodType := @Lmodule.Pack R phR cT xclass xT.
+Definition lalgType := @Lalgebra.Pack R phR cT xclass xT.
+
+End ClassDef.
+
+Module Exports.
+Coercion base : class_of >-> Lalgebra.class_of.
+Coercion sort : type >-> Sortclass.
+Bind Scope ring_scope with sort.
+Coercion eqType : type >-> Equality.type.
+Canonical eqType.
+Coercion choiceType : type >-> Choice.type.
+Canonical choiceType.
+Coercion zmodType : type >-> Zmodule.type.
+Canonical zmodType.
+Coercion ringType : type >-> Ring.type.
+Canonical ringType.
+Coercion lmodType : type >-> Lmodule.type.
+Canonical lmodType.
+Coercion lalgType : type >-> Lalgebra.type.
+Canonical lalgType.
+Notation algType R := (type (Phant R)).
+Notation AlgType R A ax := (@pack _ (Phant R) A _ ax _ _ id _ id).
+Notation CommAlgType R A := (AlgType R A (comm_axiom (Phant A) (@mulrC _))).
+Notation "[ 'algType' R 'of' T 'for' cT ]" := (@clone _ (Phant R) T cT _ idfun)
+ (at level 0, format "[ 'algType' R 'of' T 'for' cT ]")
+ : form_scope.
+Notation "[ 'algType' R 'of' T ]" := (@clone _ (Phant R) T _ _ id)
+ (at level 0, format "[ 'algType' R 'of' T ]") : form_scope.
+End Exports.
+
+End Algebra.
+Import Algebra.Exports.
+
+Section AlgebraTheory.
+
+Variables (R : comRingType) (A : algType R).
+Implicit Types (k : R) (x y : A).
+
+Lemma scalerAr k x y : k *: (x * y) = x * (k *: y).
+Proof. by case: A k x y => T []. Qed.
+
+Lemma scalerCA k x y : k *: x * y = x * (k *: y).
+Proof. by rewrite -scalerAl scalerAr. Qed.
+
+Lemma mulr_algr a x : x * a%:A = a *: x.
+Proof. by rewrite -scalerAr mulr1. Qed.
+
+Lemma exprZn k x n : (k *: x) ^+ n = k ^+ n *: x ^+ n.
+Proof.
+elim: n => [|n IHn]; first by rewrite !expr0 scale1r.
+by rewrite !exprS IHn -scalerA scalerAr scalerAl.
+Qed.
+
+Lemma scaler_prod I r (P : pred I) (F : I -> R) (G : I -> A) :
+ \prod_(i <- r | P i) (F i *: G i) =
+ \prod_(i <- r | P i) F i *: \prod_(i <- r | P i) G i.
+Proof.
+elim/big_rec3: _ => [|i x a _ _ ->]; first by rewrite scale1r.
+by rewrite -scalerAl -scalerAr scalerA.
+Qed.
+
+Lemma scaler_prodl (I : finType) (S : pred I) (F : I -> A) k :
+ \prod_(i in S) (k *: F i) = k ^+ #|S| *: \prod_(i in S) F i.
+Proof. by rewrite scaler_prod prodr_const. Qed.
+
+Lemma scaler_prodr (I : finType) (S : pred I) (F : I -> R) x :
+ \prod_(i in S) (F i *: x) = \prod_(i in S) F i *: x ^+ #|S|.
+Proof. by rewrite scaler_prod prodr_const. Qed.
+
+Canonical regular_comRingType := [comRingType of R^o].
+Canonical regular_algType := CommAlgType R R^o.
+
+Variables (U : lmodType R) (a : A) (f : {linear U -> A}).
+
+Lemma mull_fun_is_scalable : scalable (a \*o f).
+Proof. by move=> k x /=; rewrite linearZ scalerAr. Qed.
+Canonical mull_fun_linear := AddLinear mull_fun_is_scalable.
+
+End AlgebraTheory.
+
+Module UnitRing.
+
+Record mixin_of (R : ringType) : Type := Mixin {
+ unit : pred R;
+ inv : R -> R;
+ _ : {in unit, left_inverse 1 inv *%R};
+ _ : {in unit, right_inverse 1 inv *%R};
+ _ : forall x y, y * x = 1 /\ x * y = 1 -> unit x;
+ _ : {in [predC unit], inv =1 id}
+}.
+
+Definition EtaMixin R unit inv mulVr mulrV unitP inv_out :=
+ let _ := @Mixin R unit inv mulVr mulrV unitP inv_out in
+ @Mixin (Ring.Pack (Ring.class R) R) unit inv mulVr mulrV unitP inv_out.
+
+Section ClassDef.
+
+Record class_of (R : Type) : Type := Class {
+ base : Ring.class_of R;
+ mixin : mixin_of (Ring.Pack base R)
+}.
+Local Coercion base : class_of >-> Ring.class_of.
+
+Structure type := Pack {sort; _ : class_of sort; _ : Type}.
+Local Coercion sort : type >-> Sortclass.
+Variables (T : Type) (cT : type).
+Definition class := let: Pack _ c _ as cT' := cT return class_of cT' in c.
+Definition clone c of phant_id class c := @Pack T c T.
+Let xT := let: Pack T _ _ := cT in T.
+Notation xclass := (class : class_of xT).
+
+Definition pack b0 (m0 : mixin_of (@Ring.Pack T b0 T)) :=
+ fun bT b & phant_id (Ring.class bT) b =>
+ fun m & phant_id m0 m => Pack (@Class T b m) T.
+
+Definition eqType := @Equality.Pack cT xclass xT.
+Definition choiceType := @Choice.Pack cT xclass xT.
+Definition zmodType := @Zmodule.Pack cT xclass xT.
+Definition ringType := @Ring.Pack cT xclass xT.
+
+End ClassDef.
+
+Module Exports.
+Coercion base : class_of >-> Ring.class_of.
+Coercion mixin : class_of >-> mixin_of.
+Coercion sort : type >-> Sortclass.
+Bind Scope ring_scope with sort.
+Coercion eqType : type >-> Equality.type.
+Canonical eqType.
+Coercion choiceType : type >-> Choice.type.
+Canonical choiceType.
+Coercion zmodType : type >-> Zmodule.type.
+Canonical zmodType.
+Coercion ringType : type >-> Ring.type.
+Canonical ringType.
+Notation unitRingType := type.
+Notation UnitRingType T m := (@pack T _ m _ _ id _ id).
+Notation UnitRingMixin := EtaMixin.
+Notation "[ 'unitRingType' 'of' T 'for' cT ]" := (@clone T cT _ idfun)
+ (at level 0, format "[ 'unitRingType' 'of' T 'for' cT ]") : form_scope.
+Notation "[ 'unitRingType' 'of' T ]" := (@clone T _ _ id)
+ (at level 0, format "[ 'unitRingType' 'of' T ]") : form_scope.
+End Exports.
+
+End UnitRing.
+Import UnitRing.Exports.
+
+Definition unit {R : unitRingType} :=
+ [qualify a u : R | UnitRing.unit (UnitRing.class R) u].
+Fact unit_key R : pred_key (@unit R). Proof. by []. Qed.
+Canonical unit_keyed R := KeyedQualifier (@unit_key R).
+Definition inv {R : unitRingType} : R -> R := UnitRing.inv (UnitRing.class R).
+
+Local Notation "x ^-1" := (inv x).
+Local Notation "x / y" := (x * y^-1).
+Local Notation "x ^- n" := ((x ^+ n)^-1).
+
+Section UnitRingTheory.
+
+Variable R : unitRingType.
+Implicit Types x y : R.
+
+Lemma divrr : {in unit, right_inverse 1 (@inv R) *%R}.
+Proof. by case: R => T [? []]. Qed.
+Definition mulrV := divrr.
+
+Lemma mulVr : {in unit, left_inverse 1 (@inv R) *%R}.
+Proof. by case: R => T [? []]. Qed.
+
+Lemma invr_out x : x \isn't a unit -> x^-1 = x.
+Proof. by case: R x => T [? []]. Qed.
+
+Lemma unitrP x : reflect (exists y, y * x = 1 /\ x * y = 1) (x \is a unit).
+Proof.
+apply: (iffP idP) => [Ux | []]; last by case: R x => T [? []].
+by exists x^-1; rewrite divrr ?mulVr.
+Qed.
+
+Lemma mulKr : {in unit, left_loop (@inv R) *%R}.
+Proof. by move=> x Ux y; rewrite mulrA mulVr ?mul1r. Qed.
+
+Lemma mulVKr : {in unit, rev_left_loop (@inv R) *%R}.
+Proof. by move=> x Ux y; rewrite mulrA mulrV ?mul1r. Qed.
+
+Lemma mulrK : {in unit, right_loop (@inv R) *%R}.
+Proof. by move=> x Ux y; rewrite -mulrA divrr ?mulr1. Qed.
+
+Lemma mulrVK : {in unit, rev_right_loop (@inv R) *%R}.
+Proof. by move=> x Ux y; rewrite -mulrA mulVr ?mulr1. Qed.
+Definition divrK := mulrVK.
+
+Lemma mulrI : {in @unit R, right_injective *%R}.
+Proof. by move=> x Ux; exact: can_inj (mulKr Ux). Qed.
+
+Lemma mulIr : {in @unit R, left_injective *%R}.
+Proof. by move=> x Ux; exact: can_inj (mulrK Ux). Qed.
+
+(* Due to noncommutativity, fractions are inverted. *)
+Lemma telescope_prodr n m (f : nat -> R) :
+ (forall k, n < k < m -> f k \is a unit) -> n < m ->
+ \prod_(n <= k < m) (f k / f k.+1) = f n / f m.
+Proof.
+move=> Uf /subnK-Dm; do [rewrite -{}Dm; move: {m}(m - _)%N => m] in Uf *.
+rewrite unlock /index_iota -addSnnS addnK /= -mulrA; congr (_ * _).
+have{Uf}: all [preim f of unit] (iota n.+1 m).
+ by apply/allP=> k; rewrite mem_iota addnC => /Uf.
+elim: m n => [|m IHm] n /=; first by rewrite mulr1.
+by rewrite -mulrA addSnnS => /andP[/mulKr-> /IHm].
+Qed.
+
+Lemma commrV x y : comm x y -> comm x y^-1.
+Proof.
+have [Uy cxy | /invr_out-> //] := boolP (y \in unit).
+by apply: (canLR (mulrK Uy)); rewrite -mulrA cxy mulKr.
+Qed.
+
+Lemma unitrE x : (x \is a unit) = (x / x == 1).
+Proof.
+apply/idP/eqP=> [Ux | xx1]; first exact: divrr.
+by apply/unitrP; exists x^-1; rewrite -commrV.
+Qed.
+
+Lemma invrK : involutive (@inv R).
+Proof.
+move=> x; case Ux: (x \in unit); last by rewrite !invr_out ?Ux.
+rewrite -(mulrK Ux _^-1) -mulrA commrV ?mulKr //.
+by apply/unitrP; exists x; rewrite divrr ?mulVr.
+Qed.
+
+Lemma invr_inj : injective (@inv R).
+Proof. exact: inv_inj invrK. Qed.
+
+Lemma unitrV x : (x^-1 \in unit) = (x \in unit).
+Proof. by rewrite !unitrE invrK commrV. Qed.
+
+Lemma unitr1 : 1 \in @unit R.
+Proof. by apply/unitrP; exists 1; rewrite mulr1. Qed.
+
+Lemma invr1 : 1^-1 = 1 :> R.
+Proof. by rewrite -{2}(mulVr unitr1) mulr1. Qed.
+
+Lemma div1r x : 1 / x = x^-1. Proof. by rewrite mul1r. Qed.
+Lemma divr1 x : x / 1 = x. Proof. by rewrite invr1 mulr1. Qed.
+
+Lemma natr_div m d :
+ d %| m -> d%:R \is a @unit R -> (m %/ d)%:R = m%:R / d%:R :> R.
+Proof.
+by rewrite dvdn_eq => /eqP def_m unit_d; rewrite -{2}def_m natrM mulrK.
+Qed.
+
+Lemma unitr0 : (0 \is a @unit R) = false.
+Proof.
+by apply/unitrP=> [[x [_]]]; apply/eqP; rewrite mul0r eq_sym oner_neq0.
+Qed.
+
+Lemma invr0 : 0^-1 = 0 :> R.
+Proof. by rewrite invr_out ?unitr0. Qed.
+
+Lemma unitrN1 : -1 \is a @unit R.
+Proof. by apply/unitrP; exists (-1); rewrite mulrNN mulr1. Qed.
+
+Lemma invrN1 : (-1)^-1 = -1 :> R.
+Proof. by rewrite -{2}(divrr unitrN1) mulN1r opprK. Qed.
+
+Lemma invr_sign n : ((-1) ^- n) = (-1) ^+ n :> R.
+Proof. by rewrite -signr_odd; case: (odd n); rewrite (invr1, invrN1). Qed.
+
+Lemma unitrMl x y : y \is a unit -> (x * y \is a unit) = (x \is a unit).
+Proof.
+move=> Uy; wlog Ux: x y Uy / x \is a unit => [WHxy|].
+ by apply/idP/idP=> Ux; first rewrite -(mulrK Uy x); rewrite WHxy ?unitrV.
+rewrite Ux; apply/unitrP; exists (y^-1 * x^-1).
+by rewrite -!mulrA mulKr ?mulrA ?mulrK ?divrr ?mulVr.
+Qed.
+
+Lemma unitrMr x y : x \is a unit -> (x * y \is a unit) = (y \is a unit).
+Proof.
+move=> Ux; apply/idP/idP=> [Uxy | Uy]; last by rewrite unitrMl.
+by rewrite -(mulKr Ux y) unitrMl ?unitrV.
+Qed.
+
+Lemma invrM : {in unit &, forall x y, (x * y)^-1 = y^-1 * x^-1}.
+Proof.
+move=> x y Ux Uy; have Uxy: (x * y \in unit) by rewrite unitrMl.
+by apply: (mulrI Uxy); rewrite divrr ?mulrA ?mulrK ?divrr.
+Qed.
+
+Lemma unitrM_comm x y :
+ comm x y -> (x * y \is a unit) = (x \is a unit) && (y \is a unit).
+Proof.
+move=> cxy; apply/idP/andP=> [Uxy | [Ux Uy]]; last by rewrite unitrMl.
+suffices Ux: x \in unit by rewrite unitrMr in Uxy.
+apply/unitrP; case/unitrP: Uxy => z [zxy xyz]; exists (y * z).
+rewrite mulrA xyz -{1}[y]mul1r -{1}zxy cxy -!mulrA (mulrA x) (mulrA _ z) xyz.
+by rewrite mul1r -cxy.
+Qed.
+
+Lemma unitrX x n : x \is a unit -> x ^+ n \is a unit.
+Proof.
+by move=> Ux; elim: n => [|n IHn]; rewrite ?unitr1 // exprS unitrMl.
+Qed.
+
+Lemma unitrX_pos x n : n > 0 -> (x ^+ n \in unit) = (x \in unit).
+Proof.
+case: n => // n _; rewrite exprS unitrM_comm; last exact: commrX.
+by case Ux: (x \is a unit); rewrite // unitrX.
+Qed.
+
+Lemma exprVn x n : x^-1 ^+ n = x ^- n.
+Proof.
+elim: n => [|n IHn]; first by rewrite !expr0 ?invr1.
+case Ux: (x \is a unit); first by rewrite exprSr exprS IHn -invrM // unitrX.
+by rewrite !invr_out ?unitrX_pos ?Ux.
+Qed.
+
+Lemma exprB m n x : n <= m -> x \is a unit -> x ^+ (m - n) = x ^+ m / x ^+ n.
+Proof. by move/subnK=> {2}<- Ux; rewrite exprD mulrK ?unitrX. Qed.
+
+Lemma invr_neq0 x : x != 0 -> x^-1 != 0.
+Proof.
+move=> nx0; case Ux: (x \is a unit); last by rewrite invr_out ?Ux.
+by apply/eqP=> x'0; rewrite -unitrV x'0 unitr0 in Ux.
+Qed.
+
+Lemma invr_eq0 x : (x^-1 == 0) = (x == 0).
+Proof. by apply: negb_inj; apply/idP/idP; move/invr_neq0; rewrite ?invrK. Qed.
+
+Lemma invr_eq1 x : (x^-1 == 1) = (x == 1).
+Proof. by rewrite (inv_eq invrK) invr1. Qed.
+
+Lemma rev_unitrP (x y : R^c) : y * x = 1 /\ x * y = 1 -> x \is a unit.
+Proof. by case=> [yx1 xy1]; apply/unitrP; exists y. Qed.
+
+Definition converse_unitRingMixin :=
+ @UnitRing.Mixin _ ((unit : pred_class) : pred R^c) _
+ mulrV mulVr rev_unitrP invr_out.
+Canonical converse_unitRingType := UnitRingType R^c converse_unitRingMixin.
+Canonical regular_unitRingType := [unitRingType of R^o].
+
+Section ClosedPredicates.
+
+Variables S : predPredType R.
+
+Definition invr_closed := {in S, forall x, x^-1 \in S}.
+Definition divr_2closed := {in S &, forall x y, x / y \in S}.
+Definition divr_closed := 1 \in S /\ divr_2closed.
+Definition sdivr_closed := -1 \in S /\ divr_2closed.
+Definition divring_closed := [/\ 1 \in S, subr_2closed S & divr_2closed].
+
+Lemma divr_closedV : divr_closed -> invr_closed.
+Proof. by case=> S1 Sdiv x Sx; rewrite -[x^-1]mul1r Sdiv. Qed.
+
+Lemma divr_closedM : divr_closed -> mulr_closed S.
+Proof.
+by case=> S1 Sdiv; split=> // x y Sx Sy; rewrite -[y]invrK -[y^-1]mul1r !Sdiv.
+Qed.
+
+Lemma sdivr_closed_div : sdivr_closed -> divr_closed.
+Proof. by case=> SN1 Sdiv; split; rewrite // -(divrr unitrN1) Sdiv. Qed.
+
+Lemma sdivr_closedM : sdivr_closed -> smulr_closed S.
+Proof.
+by move=> Sdiv; have [_ SM] := divr_closedM (sdivr_closed_div Sdiv); case: Sdiv.
+Qed.
+
+Lemma divring_closedBM : divring_closed -> subring_closed S.
+Proof. by case=> S1 SB Sdiv; split=> //; case: divr_closedM. Qed.
+
+Lemma divring_closed_div : divring_closed -> sdivr_closed.
+Proof.
+case=> S1 SB Sdiv; split; rewrite ?zmod_closedN //.
+exact/subring_closedB/divring_closedBM.
+Qed.
+
+End ClosedPredicates.
+
+End UnitRingTheory.
+
+Implicit Arguments invr_inj [[R] x1 x2].
+
+Section UnitRingMorphism.
+
+Variables (R S : unitRingType) (f : {rmorphism R -> S}).
+
+Lemma rmorph_unit x : x \in unit -> f x \in unit.
+Proof.
+case/unitrP=> y [yx1 xy1]; apply/unitrP.
+by exists (f y); rewrite -!rmorphM // yx1 xy1 rmorph1.
+Qed.
+
+Lemma rmorphV : {in unit, {morph f: x / x^-1}}.
+Proof.
+move=> x Ux; rewrite /= -[(f x)^-1]mul1r.
+by apply: (canRL (mulrK (rmorph_unit Ux))); rewrite -rmorphM mulVr ?rmorph1.
+Qed.
+
+Lemma rmorph_div x y : y \in unit -> f (x / y) = f x / f y.
+Proof. by move=> Uy; rewrite rmorphM rmorphV. Qed.
+
+End UnitRingMorphism.
+
+Module ComUnitRing.
+
+Section Mixin.
+
+Variables (R : comRingType) (unit : pred R) (inv : R -> R).
+Hypothesis mulVx : {in unit, left_inverse 1 inv *%R}.
+Hypothesis unitPl : forall x y, y * x = 1 -> unit x.
+
+Fact mulC_mulrV : {in unit, right_inverse 1 inv *%R}.
+Proof. by move=> x Ux /=; rewrite mulrC mulVx. Qed.
+
+Fact mulC_unitP x y : y * x = 1 /\ x * y = 1 -> unit x.
+Proof. case=> yx _; exact: unitPl yx. Qed.
+
+Definition Mixin := UnitRingMixin mulVx mulC_mulrV mulC_unitP.
+
+End Mixin.
+
+Section ClassDef.
+
+Record class_of (R : Type) : Type := Class {
+ base : ComRing.class_of R;
+ mixin : UnitRing.mixin_of (Ring.Pack base R)
+}.
+Local Coercion base : class_of >-> ComRing.class_of.
+Definition base2 R m := UnitRing.Class (@mixin R m).
+Local Coercion base2 : class_of >-> UnitRing.class_of.
+
+Structure type := Pack {sort; _ : class_of sort; _ : Type}.
+Local Coercion sort : type >-> Sortclass.
+Variables (T : Type) (cT : type).
+Definition class := let: Pack _ c _ as cT' := cT return class_of cT' in c.
+Let xT := let: Pack T _ _ := cT in T.
+Notation xclass := (class : class_of xT).
+
+Definition pack :=
+ fun bT b & phant_id (ComRing.class bT) (b : ComRing.class_of T) =>
+ fun mT m & phant_id (UnitRing.class mT) (@UnitRing.Class T b m) =>
+ Pack (@Class T b m) T.
+
+Definition eqType := @Equality.Pack cT xclass xT.
+Definition choiceType := @Choice.Pack cT xclass xT.
+Definition zmodType := @Zmodule.Pack cT xclass xT.
+Definition ringType := @Ring.Pack cT xclass xT.
+Definition comRingType := @ComRing.Pack cT xclass xT.
+Definition unitRingType := @UnitRing.Pack cT xclass xT.
+Definition com_unitRingType := @UnitRing.Pack comRingType xclass xT.
+
+End ClassDef.
+
+Module Import Exports.
+Coercion base : class_of >-> ComRing.class_of.
+Coercion mixin : class_of >-> UnitRing.mixin_of.
+Coercion base2 : class_of >-> UnitRing.class_of.
+Coercion sort : type >-> Sortclass.
+Bind Scope ring_scope with sort.
+Coercion eqType : type >-> Equality.type.
+Canonical eqType.
+Coercion choiceType : type >-> Choice.type.
+Canonical choiceType.
+Coercion zmodType : type >-> Zmodule.type.
+Canonical zmodType.
+Coercion ringType : type >-> Ring.type.
+Canonical ringType.
+Coercion comRingType : type >-> ComRing.type.
+Canonical comRingType.
+Coercion unitRingType : type >-> UnitRing.type.
+Canonical unitRingType.
+Canonical com_unitRingType.
+Notation comUnitRingType := type.
+Notation ComUnitRingMixin := Mixin.
+Notation "[ 'comUnitRingType' 'of' T ]" := (@pack T _ _ id _ _ id)
+ (at level 0, format "[ 'comUnitRingType' 'of' T ]") : form_scope.
+End Exports.
+
+End ComUnitRing.
+Import ComUnitRing.Exports.
+
+Module UnitAlgebra.
+
+Section ClassDef.
+
+Variable R : ringType.
+
+Record class_of (T : Type) : Type := Class {
+ base : Algebra.class_of R T;
+ mixin : GRing.UnitRing.mixin_of (Ring.Pack base T)
+}.
+Definition base2 R m := UnitRing.Class (@mixin R m).
+Local Coercion base : class_of >-> Algebra.class_of.
+Local Coercion base2 : class_of >-> UnitRing.class_of.
+
+Structure type (phR : phant R) := Pack {sort; _ : class_of sort; _ : Type}.
+Local Coercion sort : type >-> Sortclass.
+Variable (phR : phant R) (T : Type) (cT : type phR).
+Definition class := let: Pack _ c _ as cT' := cT return class_of cT' in c.
+Let xT := let: Pack T _ _ := cT in T.
+Notation xclass := (class : class_of xT).
+
+Definition pack :=
+ fun bT b & phant_id (@Algebra.class R phR bT) (b : Algebra.class_of R T) =>
+ fun mT m & phant_id (UnitRing.mixin (UnitRing.class mT)) m =>
+ Pack (Phant R) (@Class T b m) T.
+
+Definition eqType := @Equality.Pack cT xclass xT.
+Definition choiceType := @Choice.Pack cT xclass xT.
+Definition zmodType := @Zmodule.Pack cT xclass xT.
+Definition ringType := @Ring.Pack cT xclass xT.
+Definition unitRingType := @UnitRing.Pack cT xclass xT.
+Definition lmodType := @Lmodule.Pack R phR cT xclass xT.
+Definition lalgType := @Lalgebra.Pack R phR cT xclass xT.
+Definition algType := @Algebra.Pack R phR cT xclass xT.
+Definition lmod_unitRingType := @Lmodule.Pack R phR unitRingType xclass xT.
+Definition lalg_unitRingType := @Lalgebra.Pack R phR unitRingType xclass xT.
+Definition alg_unitRingType := @Algebra.Pack R phR unitRingType xclass xT.
+
+End ClassDef.
+
+Module Exports.
+Coercion base : class_of >-> Algebra.class_of.
+Coercion base2 : class_of >-> UnitRing.class_of.
+Coercion sort : type >-> Sortclass.
+Bind Scope ring_scope with sort.
+Coercion eqType : type >-> Equality.type.
+Canonical eqType.
+Coercion choiceType : type >-> Choice.type.
+Canonical choiceType.
+Coercion zmodType : type >-> Zmodule.type.
+Canonical zmodType.
+Coercion ringType : type >-> Ring.type.
+Canonical ringType.
+Coercion unitRingType : type >-> UnitRing.type.
+Canonical unitRingType.
+Coercion lmodType : type >-> Lmodule.type.
+Canonical lmodType.
+Coercion lalgType : type >-> Lalgebra.type.
+Canonical lalgType.
+Coercion algType : type >-> Algebra.type.
+Canonical algType.
+Canonical lmod_unitRingType.
+Canonical lalg_unitRingType.
+Canonical alg_unitRingType.
+Notation unitAlgType R := (type (Phant R)).
+Notation "[ 'unitAlgType' R 'of' T ]" := (@pack _ (Phant R) T _ _ id _ _ id)
+ (at level 0, format "[ 'unitAlgType' R 'of' T ]") : form_scope.
+End Exports.
+
+End UnitAlgebra.
+Import UnitAlgebra.Exports.
+
+Section ComUnitRingTheory.
+
+Variable R : comUnitRingType.
+Implicit Types x y : R.
+
+Lemma unitrM x y : (x * y \in unit) = (x \in unit) && (y \in unit).
+Proof. by apply: unitrM_comm; exact: mulrC. Qed.
+
+Lemma unitrPr x : reflect (exists y, x * y = 1) (x \in unit).
+Proof.
+by apply: (iffP (unitrP x)) => [[y []] | [y]]; exists y; rewrite // mulrC.
+Qed.
+
+Lemma expr_div_n x y n : (x / y) ^+ n = x ^+ n / y ^+ n.
+Proof. by rewrite exprMn exprVn. Qed.
+
+Canonical regular_comUnitRingType := [comUnitRingType of R^o].
+Canonical regular_unitAlgType := [unitAlgType R of R^o].
+
+End ComUnitRingTheory.
+
+Section UnitAlgebraTheory.
+
+Variable (R : comUnitRingType) (A : unitAlgType R).
+Implicit Types (k : R) (x y : A).
+
+Lemma scaler_injl : {in unit, @right_injective R A A *:%R}.
+Proof.
+move=> k Uk x1 x2 Hx1x2.
+by rewrite -[x1]scale1r -(mulVr Uk) -scalerA Hx1x2 scalerA mulVr // scale1r.
+Qed.
+
+Lemma scaler_unit k x : k \in unit -> (k *: x \in unit) = (x \in unit).
+Proof.
+move=> Uk; apply/idP/idP=> [Ukx | Ux]; apply/unitrP; last first.
+ exists (k^-1 *: x^-1).
+ by rewrite -!scalerAl -!scalerAr !scalerA !mulVr // !mulrV // scale1r.
+exists (k *: (k *: x)^-1); split.
+ apply: (mulrI Ukx).
+ by rewrite mulr1 mulrA -scalerAr mulrV // -scalerAl mul1r.
+apply: (mulIr Ukx).
+by rewrite mul1r -mulrA -scalerAl mulVr // -scalerAr mulr1.
+Qed.
+
+Lemma invrZ k x : k \in unit -> x \in unit -> (k *: x)^-1 = k^-1 *: x^-1.
+Proof.
+move=> Uk Ux; have Ukx: (k *: x \in unit) by rewrite scaler_unit.
+apply: (mulIr Ukx).
+by rewrite mulVr // -scalerAl -scalerAr scalerA !mulVr // scale1r.
+Qed.
+
+Section ClosedPredicates.
+
+Variables S : predPredType A.
+
+Definition divalg_closed := [/\ 1 \in S, linear_closed S & divr_2closed S].
+
+Lemma divalg_closedBdiv : divalg_closed -> divring_closed S.
+Proof. by case=> S1 /linear_closedB. Qed.
+
+Lemma divalg_closedZ : divalg_closed -> subalg_closed S.
+Proof. by case=> S1 Slin Sdiv; split=> //; have [] := @divr_closedM A S. Qed.
+
+End ClosedPredicates.
+
+End UnitAlgebraTheory.
+
+(* Interface structures for algebraically closed predicates. *)
+Module Pred.
+
+Structure opp V S := Opp {opp_key : pred_key S; _ : @oppr_closed V S}.
+Structure add V S := Add {add_key : pred_key S; _ : @addr_closed V S}.
+Structure mul R S := Mul {mul_key : pred_key S; _ : @mulr_closed R S}.
+Structure zmod V S := Zmod {zmod_add : add S; _ : @oppr_closed V S}.
+Structure semiring R S := Semiring {semiring_add : add S; _ : @mulr_closed R S}.
+Structure smul R S := Smul {smul_opp : opp S; _ : @mulr_closed R S}.
+Structure div R S := Div {div_mul : mul S; _ : @invr_closed R S}.
+Structure submod R V S :=
+ Submod {submod_zmod : zmod S; _ : @scaler_closed R V S}.
+Structure subring R S := Subring {subring_zmod : zmod S; _ : @mulr_closed R S}.
+Structure sdiv R S := Sdiv {sdiv_smul : smul S; _ : @invr_closed R S}.
+Structure subalg (R : ringType) (A : lalgType R) S :=
+ Subalg {subalg_ring : subring S; _ : @scaler_closed R A S}.
+Structure divring R S :=
+ Divring {divring_ring : subring S; _ : @invr_closed R S}.
+Structure divalg (R : ringType) (A : unitAlgType R) S :=
+ Divalg {divalg_ring : divring S; _ : @scaler_closed R A S}.
+
+Section Subtyping.
+
+Ltac done := case=> *; assumption.
+Fact zmod_oppr R S : @zmod R S -> oppr_closed S. Proof. by []. Qed.
+Fact semiring_mulr R S : @semiring R S -> mulr_closed S. Proof. by []. Qed.
+Fact smul_mulr R S : @smul R S -> mulr_closed S. Proof. by []. Qed.
+Fact submod_scaler R V S : @submod R V S -> scaler_closed S. Proof. by []. Qed.
+Fact subring_mulr R S : @subring R S -> mulr_closed S. Proof. by []. Qed.
+Fact sdiv_invr R S : @sdiv R S -> invr_closed S. Proof. by []. Qed.
+Fact subalg_scaler R A S : @subalg R A S -> scaler_closed S. Proof. by []. Qed.
+Fact divring_invr R S : @divring R S -> invr_closed S. Proof. by []. Qed.
+Fact divalg_scaler R A S : @divalg R A S -> scaler_closed S. Proof. by []. Qed.
+
+Definition zmod_opp R S (addS : @zmod R S) :=
+ Opp (add_key (zmod_add addS)) (zmod_oppr addS).
+Definition semiring_mul R S (ringS : @semiring R S) :=
+ Mul (add_key (semiring_add ringS)) (semiring_mulr ringS).
+Definition smul_mul R S (mulS : @smul R S) :=
+ Mul (opp_key (smul_opp mulS)) (smul_mulr mulS).
+Definition subring_semi R S (ringS : @subring R S) :=
+ Semiring (zmod_add (subring_zmod ringS)) (subring_mulr ringS).
+Definition subring_smul R S (ringS : @subring R S) :=
+ Smul (zmod_opp (subring_zmod ringS)) (subring_mulr ringS).
+Definition sdiv_div R S (divS : @sdiv R S) :=
+ Div (smul_mul (sdiv_smul divS)) (sdiv_invr divS).
+Definition subalg_submod R A S (algS : @subalg R A S) :=
+ Submod (subring_zmod (subalg_ring algS)) (subalg_scaler algS).
+Definition divring_sdiv R S (ringS : @divring R S) :=
+ Sdiv (subring_smul (divring_ring ringS)) (divring_invr ringS).
+Definition divalg_alg R A S (algS : @divalg R A S) :=
+ Subalg (divring_ring (divalg_ring algS)) (divalg_scaler algS).
+
+End Subtyping.
+
+Section Extensionality.
+(* This could be avoided by exploiting the Coq 8.4 eta-convertibility. *)
+
+Lemma opp_ext (U : zmodType) S k (kS : @keyed_pred U S k) :
+ oppr_closed kS -> oppr_closed S.
+Proof. by move=> oppS x; rewrite -!(keyed_predE kS); apply: oppS. Qed.
+
+Lemma add_ext (U : zmodType) S k (kS : @keyed_pred U S k) :
+ addr_closed kS -> addr_closed S.
+Proof.
+by case=> S0 addS; split=> [|x y]; rewrite -!(keyed_predE kS) //; apply: addS.
+Qed.
+
+Lemma mul_ext (R : ringType) S k (kS : @keyed_pred R S k) :
+ mulr_closed kS -> mulr_closed S.
+Proof.
+by case=> S1 mulS; split=> [|x y]; rewrite -!(keyed_predE kS) //; apply: mulS.
+Qed.
+
+Lemma scale_ext (R : ringType) (U : lmodType R) S k (kS : @keyed_pred U S k) :
+ scaler_closed kS -> scaler_closed S.
+Proof. by move=> linS a x; rewrite -!(keyed_predE kS); apply: linS. Qed.
+
+Lemma inv_ext (R : unitRingType) S k (kS : @keyed_pred R S k) :
+ invr_closed kS -> invr_closed S.
+Proof. by move=> invS x; rewrite -!(keyed_predE kS); apply: invS. Qed.
+
+End Extensionality.
+
+Module Default.
+Definition opp V S oppS := @Opp V S (DefaultPredKey S) oppS.
+Definition add V S addS := @Add V S (DefaultPredKey S) addS.
+Definition mul R S mulS := @Mul R S (DefaultPredKey S) mulS.
+Definition zmod V S addS oppS := @Zmod V S (add addS) oppS.
+Definition semiring R S addS mulS := @Semiring R S (add addS) mulS.
+Definition smul R S oppS mulS := @Smul R S (opp oppS) mulS.
+Definition div R S mulS invS := @Div R S (mul mulS) invS.
+Definition submod R V S addS oppS linS := @Submod R V S (zmod addS oppS) linS.
+Definition subring R S addS oppS mulS := @Subring R S (zmod addS oppS) mulS.
+Definition sdiv R S oppS mulS invS := @Sdiv R S (smul oppS mulS) invS.
+Definition subalg R A S addS oppS mulS linS :=
+ @Subalg R A S (subring addS oppS mulS) linS.
+Definition divring R S addS oppS mulS invS :=
+ @Divring R S (subring addS oppS mulS) invS.
+Definition divalg R A S addS oppS mulS invS linS :=
+ @Divalg R A S (divring addS oppS mulS invS) linS.
+End Default.
+
+Module Exports.
+
+Notation oppr_closed := oppr_closed.
+Notation addr_closed := addr_closed.
+Notation mulr_closed := mulr_closed.
+Notation zmod_closed := zmod_closed.
+Notation smulr_closed := smulr_closed.
+Notation invr_closed := invr_closed.
+Notation divr_closed := divr_closed.
+Notation linear_closed := linear_closed.
+Notation submod_closed := submod_closed.
+Notation semiring_closed := semiring_closed.
+Notation subring_closed := subring_closed.
+Notation sdivr_closed := sdivr_closed.
+Notation subalg_closed := subalg_closed.
+Notation divring_closed := divring_closed.
+Notation divalg_closed := divalg_closed.
+
+Coercion zmod_closedD : zmod_closed >-> addr_closed.
+Coercion zmod_closedN : zmod_closed >-> oppr_closed.
+Coercion smulr_closedN : smulr_closed >-> oppr_closed.
+Coercion smulr_closedM : smulr_closed >-> mulr_closed.
+Coercion divr_closedV : divr_closed >-> invr_closed.
+Coercion divr_closedM : divr_closed >-> mulr_closed.
+Coercion submod_closedZ : submod_closed >-> scaler_closed.
+Coercion submod_closedB : submod_closed >-> zmod_closed.
+Coercion semiring_closedD : semiring_closed >-> addr_closed.
+Coercion semiring_closedM : semiring_closed >-> mulr_closed.
+Coercion subring_closedB : subring_closed >-> zmod_closed.
+Coercion subring_closedM : subring_closed >-> smulr_closed.
+Coercion subring_closed_semi : subring_closed >-> semiring_closed.
+Coercion sdivr_closedM : sdivr_closed >-> smulr_closed.
+Coercion sdivr_closed_div : sdivr_closed >-> divr_closed.
+Coercion subalg_closedZ : subalg_closed >-> submod_closed.
+Coercion subalg_closedBM : subalg_closed >-> subring_closed.
+Coercion divring_closedBM : divring_closed >-> subring_closed.
+Coercion divring_closed_div : divring_closed >-> sdivr_closed.
+Coercion divalg_closedZ : divalg_closed >-> subalg_closed.
+Coercion divalg_closedBdiv : divalg_closed >-> divring_closed.
+
+Coercion opp_key : opp >-> pred_key.
+Coercion add_key : add >-> pred_key.
+Coercion mul_key : mul >-> pred_key.
+Coercion zmod_opp : zmod >-> opp.
+Canonical zmod_opp.
+Coercion zmod_add : zmod >-> add.
+Coercion semiring_add : semiring >-> add.
+Coercion semiring_mul : semiring >-> mul.
+Canonical semiring_mul.
+Coercion smul_opp : smul >-> opp.
+Coercion smul_mul : smul >-> mul.
+Canonical smul_mul.
+Coercion div_mul : div >-> mul.
+Coercion submod_zmod : submod >-> zmod.
+Coercion subring_zmod : subring >-> zmod.
+Coercion subring_semi : subring >-> semiring.
+Canonical subring_semi.
+Coercion subring_smul : subring >-> smul.
+Canonical subring_smul.
+Coercion sdiv_smul : sdiv >-> smul.
+Coercion sdiv_div : sdiv >-> div.
+Canonical sdiv_div.
+Coercion subalg_submod : subalg >-> submod.
+Canonical subalg_submod.
+Coercion subalg_ring : subalg >-> subring.
+Coercion divring_ring : divring >-> subring.
+Coercion divring_sdiv : divring >-> sdiv.
+Canonical divring_sdiv.
+Coercion divalg_alg : divalg >-> subalg.
+Canonical divalg_alg.
+Coercion divalg_ring : divalg >-> divring.
+
+Notation opprPred := opp.
+Notation addrPred := add.
+Notation mulrPred := mul.
+Notation zmodPred := zmod.
+Notation semiringPred := semiring.
+Notation smulrPred := smul.
+Notation divrPred := div.
+Notation submodPred := submod.
+Notation subringPred := subring.
+Notation sdivrPred := sdiv.
+Notation subalgPred := subalg.
+Notation divringPred := divring.
+Notation divalgPred := divalg.
+
+Definition OpprPred U S k kS NkS := Opp k (@opp_ext U S k kS NkS).
+Definition AddrPred U S k kS DkS := Add k (@add_ext U S k kS DkS).
+Definition MulrPred R S k kS MkS := Mul k (@mul_ext R S k kS MkS).
+Definition ZmodPred U S k kS NkS := Zmod k (@opp_ext U S k kS NkS).
+Definition SemiringPred R S k kS MkS := Semiring k (@mul_ext R S k kS MkS).
+Definition SmulrPred R S k kS MkS := Smul k (@mul_ext R S k kS MkS).
+Definition DivrPred R S k kS VkS := Div k (@inv_ext R S k kS VkS).
+Definition SubmodPred R U S k kS ZkS := Submod k (@scale_ext R U S k kS ZkS).
+Definition SubringPred R S k kS MkS := Subring k (@mul_ext R S k kS MkS).
+Definition SdivrPred R S k kS VkS := Sdiv k (@inv_ext R S k kS VkS).
+Definition SubalgPred (R : ringType) (A : lalgType R) S k kS ZkS :=
+ Subalg k (@scale_ext R A S k kS ZkS).
+Definition DivringPred R S k kS VkS := Divring k (@inv_ext R S k kS VkS).
+Definition DivalgPred (R : ringType) (A : unitAlgType R) S k kS ZkS :=
+ Divalg k (@scale_ext R A S k kS ZkS).
+
+End Exports.
+
+End Pred.
+Import Pred.Exports.
+
+Module DefaultPred.
+
+Canonical Pred.Default.opp.
+Canonical Pred.Default.add.
+Canonical Pred.Default.mul.
+Canonical Pred.Default.zmod.
+Canonical Pred.Default.semiring.
+Canonical Pred.Default.smul.
+Canonical Pred.Default.div.
+Canonical Pred.Default.submod.
+Canonical Pred.Default.subring.
+Canonical Pred.Default.sdiv.
+Canonical Pred.Default.subalg.
+Canonical Pred.Default.divring.
+Canonical Pred.Default.divalg.
+
+End DefaultPred.
+
+Section ZmodulePred.
+
+Variables (V : zmodType) (S : predPredType V).
+
+Section Add.
+
+Variables (addS : addrPred S) (kS : keyed_pred addS).
+
+Lemma rpred0D : addr_closed kS.
+Proof.
+by split=> [|x y]; rewrite !keyed_predE; case: addS => _ [_]//; apply.
+Qed.
+
+Lemma rpred0 : 0 \in kS.
+Proof. by case: rpred0D. Qed.
+
+Lemma rpredD : {in kS &, forall u v, u + v \in kS}.
+Proof. by case: rpred0D. Qed.
+
+Lemma rpred_sum I r (P : pred I) F :
+ (forall i, P i -> F i \in kS) -> \sum_(i <- r | P i) F i \in kS.
+Proof. by move=> IH; elim/big_ind: _; [exact: rpred0 | exact: rpredD |]. Qed.
+
+Lemma rpredMn n : {in kS, forall u, u *+ n \in kS}.
+Proof. by move=> u Su; rewrite -(card_ord n) -sumr_const rpred_sum. Qed.
+
+End Add.
+
+Section Opp.
+
+Variables (oppS : opprPred S) (kS : keyed_pred oppS).
+
+Lemma rpredNr : oppr_closed kS.
+Proof. by move=> x; rewrite !keyed_predE; case: oppS => _; apply. Qed.
+
+Lemma rpredN : {mono -%R: u / u \in kS}.
+Proof. by move=> u; apply/idP/idP=> /rpredNr; rewrite ?opprK; apply. Qed.
+
+End Opp.
+
+Section Sub.
+
+Variables (subS : zmodPred S) (kS : keyed_pred subS).
+
+Lemma rpredB : {in kS &, forall u v, u - v \in kS}.
+Proof. by move=> u v Su Sv; rewrite /= rpredD ?rpredN. Qed.
+
+Lemma rpredMNn n : {in kS, forall u, u *- n \in kS}.
+Proof. by move=> u Su; rewrite /= rpredN rpredMn. Qed.
+
+Lemma rpredDr x y : x \in kS -> (y + x \in kS) = (y \in kS).
+Proof.
+move=> Sx; apply/idP/idP=> [Sxy | /rpredD-> //].
+by rewrite -(addrK x y) rpredB.
+Qed.
+
+Lemma rpredDl x y : x \in kS -> (x + y \in kS) = (y \in kS).
+Proof. by rewrite addrC; apply: rpredDr. Qed.
+
+Lemma rpredBr x y : x \in kS -> (y - x \in kS) = (y \in kS).
+Proof. by rewrite -rpredN; apply: rpredDr. Qed.
+
+Lemma rpredBl x y : x \in kS -> (x - y \in kS) = (y \in kS).
+Proof. by rewrite -(rpredN _ y); apply: rpredDl. Qed.
+
+End Sub.
+
+End ZmodulePred.
+
+Section RingPred.
+
+Variables (R : ringType) (S : predPredType R).
+
+Lemma rpredMsign (oppS : opprPred S) (kS : keyed_pred oppS) n x :
+ ((-1) ^+ n * x \in kS) = (x \in kS).
+Proof. by rewrite -signr_odd mulr_sign; case: ifP => // _; rewrite rpredN. Qed.
+
+Section Mul.
+
+Variables (mulS : mulrPred S) (kS : keyed_pred mulS).
+
+Lemma rpred1M : mulr_closed kS.
+Proof.
+by split=> [|x y]; rewrite !keyed_predE; case: mulS => _ [_] //; apply.
+Qed.
+
+Lemma rpred1 : 1 \in kS.
+Proof. by case: rpred1M. Qed.
+
+Lemma rpredM : {in kS &, forall u v, u * v \in kS}.
+Proof. by case: rpred1M. Qed.
+
+Lemma rpred_prod I r (P : pred I) F :
+ (forall i, P i -> F i \in kS) -> \prod_(i <- r | P i) F i \in kS.
+Proof. by move=> IH; elim/big_ind: _; [exact: rpred1 | exact: rpredM |]. Qed.
+
+Lemma rpredX n : {in kS, forall u, u ^+ n \in kS}.
+Proof. by move=> u Su; rewrite -(card_ord n) -prodr_const rpred_prod. Qed.
+
+End Mul.
+
+Lemma rpred_nat (rngS : semiringPred S) (kS : keyed_pred rngS) n : n%:R \in kS.
+Proof. by rewrite rpredMn ?rpred1. Qed.
+
+Lemma rpredN1 (mulS : smulrPred S) (kS : keyed_pred mulS) : -1 \in kS.
+Proof. by rewrite rpredN rpred1. Qed.
+
+Lemma rpred_sign (mulS : smulrPred S) (kS : keyed_pred mulS) n :
+ (-1) ^+ n \in kS.
+Proof. by rewrite rpredX ?rpredN1. Qed.
+
+End RingPred.
+
+Section LmodPred.
+
+Variables (R : ringType) (V : lmodType R) (S : predPredType V).
+
+Lemma rpredZsign (oppS : opprPred S) (kS : keyed_pred oppS) n u :
+ ((-1) ^+ n *: u \in kS) = (u \in kS).
+Proof. by rewrite -signr_odd scaler_sign fun_if if_arg rpredN if_same. Qed.
+
+Lemma rpredZnat (addS : addrPred S) (kS : keyed_pred addS) n :
+ {in kS, forall u, n%:R *: u \in kS}.
+Proof. by move=> u Su; rewrite /= scaler_nat rpredMn. Qed.
+
+Lemma rpredZ (linS : submodPred S) (kS : keyed_pred linS) : scaler_closed kS.
+Proof. by move=> a u; rewrite !keyed_predE; case: {kS}linS => _; apply. Qed.
+
+End LmodPred.
+
+Section UnitRingPred.
+
+Variable R : unitRingType.
+
+Section Div.
+
+Variables (S : predPredType R) (divS : divrPred S) (kS : keyed_pred divS).
+
+Lemma rpredVr x : x \in kS -> x^-1 \in kS.
+Proof. by rewrite !keyed_predE; case: divS x. Qed.
+
+Lemma rpredV x : (x^-1 \in kS) = (x \in kS).
+Proof. by apply/idP/idP=> /rpredVr; rewrite ?invrK. Qed.
+
+Lemma rpred_div : {in kS &, forall x y, x / y \in kS}.
+Proof. by move=> x y Sx Sy; rewrite /= rpredM ?rpredV. Qed.
+
+Lemma rpredXN n : {in kS, forall x, x ^- n \in kS}.
+Proof. by move=> x Sx; rewrite /= rpredV rpredX. Qed.
+
+Lemma rpredMl x y : x \in kS -> x \is a unit-> (x * y \in kS) = (y \in kS).
+Proof.
+move=> Sx Ux; apply/idP/idP=> [Sxy | /(rpredM Sx)-> //].
+by rewrite -(mulKr Ux y); rewrite rpredM ?rpredV.
+Qed.
+
+Lemma rpredMr x y : x \in kS -> x \is a unit -> (y * x \in kS) = (y \in kS).
+Proof.
+move=> Sx Ux; apply/idP/idP=> [Sxy | /rpredM-> //].
+by rewrite -(mulrK Ux y); rewrite rpred_div.
+Qed.
+
+Lemma rpred_divr x y : x \in kS -> x \is a unit -> (y / x \in kS) = (y \in kS).
+Proof. by rewrite -rpredV -unitrV; apply: rpredMr. Qed.
+
+Lemma rpred_divl x y : x \in kS -> x \is a unit -> (x / y \in kS) = (y \in kS).
+Proof. by rewrite -(rpredV y); apply: rpredMl. Qed.
+
+End Div.
+
+Fact unitr_sdivr_closed : @sdivr_closed R unit.
+Proof. by split=> [|x y Ux Uy]; rewrite ?unitrN1 // unitrMl ?unitrV. Qed.
+
+Canonical unit_opprPred := OpprPred unitr_sdivr_closed.
+Canonical unit_mulrPred := MulrPred unitr_sdivr_closed.
+Canonical unit_divrPred := DivrPred unitr_sdivr_closed.
+Canonical unit_smulrPred := SmulrPred unitr_sdivr_closed.
+Canonical unit_sdivrPred := SdivrPred unitr_sdivr_closed.
+
+Implicit Type x : R.
+
+Lemma unitrN x : (- x \is a unit) = (x \is a unit). Proof. exact: rpredN. Qed.
+
+Lemma invrN x : (- x)^-1 = - x^-1.
+Proof.
+have [Ux | U'x] := boolP (x \is a unit); last by rewrite !invr_out ?unitrN.
+by rewrite -mulN1r invrM ?unitrN1 // invrN1 mulrN1.
+Qed.
+
+Lemma invr_signM n x : ((-1) ^+ n * x)^-1 = (-1) ^+ n * x^-1.
+Proof. by rewrite -signr_odd !mulr_sign; case: ifP => // _; rewrite invrN. Qed.
+
+Lemma divr_signM (b1 b2 : bool) x1 x2:
+ ((-1) ^+ b1 * x1) / ((-1) ^+ b2 * x2) = (-1) ^+ (b1 (+) b2) * (x1 / x2).
+Proof. by rewrite invr_signM mulr_signM. Qed.
+
+End UnitRingPred.
+
+(* Reification of the theory of rings with units, in named style *)
+Section TermDef.
+
+Variable R : Type.
+
+Inductive term : Type :=
+| Var of nat
+| Const of R
+| NatConst of nat
+| Add of term & term
+| Opp of term
+| NatMul of term & nat
+| Mul of term & term
+| Inv of term
+| Exp of term & nat.
+
+Inductive formula : Type :=
+| Bool of bool
+| Equal of term & term
+| Unit of term
+| And of formula & formula
+| Or of formula & formula
+| Implies of formula & formula
+| Not of formula
+| Exists of nat & formula
+| Forall of nat & formula.
+
+End TermDef.
+
+Bind Scope term_scope with term.
+Bind Scope term_scope with formula.
+Arguments Scope Add [_ term_scope term_scope].
+Arguments Scope Opp [_ term_scope].
+Arguments Scope NatMul [_ term_scope nat_scope].
+Arguments Scope Mul [_ term_scope term_scope].
+Arguments Scope Mul [_ term_scope term_scope].
+Arguments Scope Inv [_ term_scope].
+Arguments Scope Exp [_ term_scope nat_scope].
+Arguments Scope Equal [_ term_scope term_scope].
+Arguments Scope Unit [_ term_scope].
+Arguments Scope And [_ term_scope term_scope].
+Arguments Scope Or [_ term_scope term_scope].
+Arguments Scope Implies [_ term_scope term_scope].
+Arguments Scope Not [_ term_scope].
+Arguments Scope Exists [_ nat_scope term_scope].
+Arguments Scope Forall [_ nat_scope term_scope].
+
+Implicit Arguments Bool [R].
+Prenex Implicits Const Add Opp NatMul Mul Exp Bool Unit And Or Implies Not.
+Prenex Implicits Exists Forall.
+
+Notation True := (Bool true).
+Notation False := (Bool false).
+
+Local Notation "''X_' i" := (Var _ i) : term_scope.
+Local Notation "n %:R" := (NatConst _ n) : term_scope.
+Local Notation "x %:T" := (Const x) : term_scope.
+Local Notation "0" := 0%:R%T : term_scope.
+Local Notation "1" := 1%:R%T : term_scope.
+Local Infix "+" := Add : term_scope.
+Local Notation "- t" := (Opp t) : term_scope.
+Local Notation "t - u" := (Add t (- u)) : term_scope.
+Local Infix "*" := Mul : term_scope.
+Local Infix "*+" := NatMul : term_scope.
+Local Notation "t ^-1" := (Inv t) : term_scope.
+Local Notation "t / u" := (Mul t u^-1) : term_scope.
+Local Infix "^+" := Exp : term_scope.
+Local Infix "==" := Equal : term_scope.
+Local Infix "/\" := And : term_scope.
+Local Infix "\/" := Or : term_scope.
+Local Infix "==>" := Implies : term_scope.
+Local Notation "~ f" := (Not f) : term_scope.
+Local Notation "x != y" := (Not (x == y)) : term_scope.
+Local Notation "''exists' ''X_' i , f" := (Exists i f) : term_scope.
+Local Notation "''forall' ''X_' i , f" := (Forall i f) : term_scope.
+
+Section Substitution.
+
+Variable R : Type.
+
+Fixpoint tsubst (t : term R) (s : nat * term R) :=
+ match t with
+ | 'X_i => if i == s.1 then s.2 else t
+ | _%:T | _%:R => t
+ | t1 + t2 => tsubst t1 s + tsubst t2 s
+ | - t1 => - tsubst t1 s
+ | t1 *+ n => tsubst t1 s *+ n
+ | t1 * t2 => tsubst t1 s * tsubst t2 s
+ | t1^-1 => (tsubst t1 s)^-1
+ | t1 ^+ n => tsubst t1 s ^+ n
+ end%T.
+
+Fixpoint fsubst (f : formula R) (s : nat * term R) :=
+ match f with
+ | Bool _ => f
+ | t1 == t2 => tsubst t1 s == tsubst t2 s
+ | Unit t1 => Unit (tsubst t1 s)
+ | f1 /\ f2 => fsubst f1 s /\ fsubst f2 s
+ | f1 \/ f2 => fsubst f1 s \/ fsubst f2 s
+ | f1 ==> f2 => fsubst f1 s ==> fsubst f2 s
+ | ~ f1 => ~ fsubst f1 s
+ | ('exists 'X_i, f1) => 'exists 'X_i, if i == s.1 then f1 else fsubst f1 s
+ | ('forall 'X_i, f1) => 'forall 'X_i, if i == s.1 then f1 else fsubst f1 s
+ end%T.
+
+End Substitution.
+
+Section EvalTerm.
+
+Variable R : unitRingType.
+
+(* Evaluation of a reified term into R a ring with units *)
+Fixpoint eval (e : seq R) (t : term R) {struct t} : R :=
+ match t with
+ | ('X_i)%T => e`_i
+ | (x%:T)%T => x
+ | (n%:R)%T => n%:R
+ | (t1 + t2)%T => eval e t1 + eval e t2
+ | (- t1)%T => - eval e t1
+ | (t1 *+ n)%T => eval e t1 *+ n
+ | (t1 * t2)%T => eval e t1 * eval e t2
+ | t1^-1%T => (eval e t1)^-1
+ | (t1 ^+ n)%T => eval e t1 ^+ n
+ end.
+
+Definition same_env (e e' : seq R) := nth 0 e =1 nth 0 e'.
+
+Lemma eq_eval e e' t : same_env e e' -> eval e t = eval e' t.
+Proof. by move=> eq_e; elim: t => //= t1 -> // t2 ->. Qed.
+
+Lemma eval_tsubst e t s :
+ eval e (tsubst t s) = eval (set_nth 0 e s.1 (eval e s.2)) t.
+Proof.
+case: s => i u; elim: t => //=; do 2?[move=> ? -> //] => j.
+by rewrite nth_set_nth /=; case: (_ == _).
+Qed.
+
+(* Evaluation of a reified formula *)
+Fixpoint holds (e : seq R) (f : formula R) {struct f} : Prop :=
+ match f with
+ | Bool b => b
+ | (t1 == t2)%T => eval e t1 = eval e t2
+ | Unit t1 => eval e t1 \in unit
+ | (f1 /\ f2)%T => holds e f1 /\ holds e f2
+ | (f1 \/ f2)%T => holds e f1 \/ holds e f2
+ | (f1 ==> f2)%T => holds e f1 -> holds e f2
+ | (~ f1)%T => ~ holds e f1
+ | ('exists 'X_i, f1)%T => exists x, holds (set_nth 0 e i x) f1
+ | ('forall 'X_i, f1)%T => forall x, holds (set_nth 0 e i x) f1
+ end.
+
+Lemma same_env_sym e e' : same_env e e' -> same_env e' e.
+Proof. exact: fsym. Qed.
+
+(* Extensionality of formula evaluation *)
+Lemma eq_holds e e' f : same_env e e' -> holds e f -> holds e' f.
+Proof.
+pose sv := set_nth (0 : R).
+have eq_i i v e1 e2: same_env e1 e2 -> same_env (sv e1 i v) (sv e2 i v).
+ by move=> eq_e j; rewrite !nth_set_nth /= eq_e.
+elim: f e e' => //=.
+- by move=> t1 t2 e e' eq_e; rewrite !(eq_eval _ eq_e).
+- by move=> t e e' eq_e; rewrite (eq_eval _ eq_e).
+- by move=> f1 IH1 f2 IH2 e e' eq_e; move/IH2: (eq_e); move/IH1: eq_e; tauto.
+- by move=> f1 IH1 f2 IH2 e e' eq_e; move/IH2: (eq_e); move/IH1: eq_e; tauto.
+- by move=> f1 IH1 f2 IH2 e e' eq_e f12; move/IH1: (same_env_sym eq_e); eauto.
+- by move=> f1 IH1 e e'; move/same_env_sym; move/IH1; tauto.
+- by move=> i f1 IH1 e e'; move/(eq_i i)=> eq_e [x f_ex]; exists x; eauto.
+by move=> i f1 IH1 e e'; move/(eq_i i); eauto.
+Qed.
+
+(* Evaluation and substitution by a constant *)
+Lemma holds_fsubst e f i v :
+ holds e (fsubst f (i, v%:T)%T) <-> holds (set_nth 0 e i v) f.
+Proof.
+elim: f e => //=; do [
+ by move=> *; rewrite !eval_tsubst
+| move=> f1 IHf1 f2 IHf2 e; move: (IHf1 e) (IHf2 e); tauto
+| move=> f IHf e; move: (IHf e); tauto
+| move=> j f IHf e].
+- case eq_ji: (j == i); first rewrite (eqP eq_ji).
+ by split=> [] [x f_x]; exists x; rewrite set_set_nth eqxx in f_x *.
+ split=> [] [x f_x]; exists x; move: f_x; rewrite set_set_nth eq_sym eq_ji;
+ have:= IHf (set_nth 0 e j x); tauto.
+case eq_ji: (j == i); first rewrite (eqP eq_ji).
+ by split=> [] f_ x; move: (f_ x); rewrite set_set_nth eqxx.
+split=> [] f_ x; move: (IHf (set_nth 0 e j x)) (f_ x);
+ by rewrite set_set_nth eq_sym eq_ji; tauto.
+Qed.
+
+(* Boolean test selecting terms in the language of rings *)
+Fixpoint rterm (t : term R) :=
+ match t with
+ | _^-1 => false
+ | t1 + t2 | t1 * t2 => rterm t1 && rterm t2
+ | - t1 | t1 *+ _ | t1 ^+ _ => rterm t1
+ | _ => true
+ end%T.
+
+(* Boolean test selecting formulas in the theory of rings *)
+Fixpoint rformula (f : formula R) :=
+ match f with
+ | Bool _ => true
+ | t1 == t2 => rterm t1 && rterm t2
+ | Unit t1 => false
+ | f1 /\ f2 | f1 \/ f2 | f1 ==> f2 => rformula f1 && rformula f2
+ | ~ f1 | ('exists 'X__, f1) | ('forall 'X__, f1) => rformula f1
+ end%T.
+
+(* Upper bound of the names used in a term *)
+Fixpoint ub_var (t : term R) :=
+ match t with
+ | 'X_i => i.+1
+ | t1 + t2 | t1 * t2 => maxn (ub_var t1) (ub_var t2)
+ | - t1 | t1 *+ _ | t1 ^+ _ | t1^-1 => ub_var t1
+ | _ => 0%N
+ end%T.
+
+(* Replaces inverses in the term t by fresh variables, accumulating the *)
+(* substitution. *)
+Fixpoint to_rterm (t : term R) (r : seq (term R)) (n : nat) {struct t} :=
+ match t with
+ | t1^-1 =>
+ let: (t1', r1) := to_rterm t1 r n in
+ ('X_(n + size r1), rcons r1 t1')
+ | t1 + t2 =>
+ let: (t1', r1) := to_rterm t1 r n in
+ let: (t2', r2) := to_rterm t2 r1 n in
+ (t1' + t2', r2)
+ | - t1 =>
+ let: (t1', r1) := to_rterm t1 r n in
+ (- t1', r1)
+ | t1 *+ m =>
+ let: (t1', r1) := to_rterm t1 r n in
+ (t1' *+ m, r1)
+ | t1 * t2 =>
+ let: (t1', r1) := to_rterm t1 r n in
+ let: (t2', r2) := to_rterm t2 r1 n in
+ (Mul t1' t2', r2)
+ | t1 ^+ m =>
+ let: (t1', r1) := to_rterm t1 r n in
+ (t1' ^+ m, r1)
+ | _ => (t, r)
+ end%T.
+
+Lemma to_rterm_id t r n : rterm t -> to_rterm t r n = (t, r).
+Proof.
+elim: t r n => //.
+- by move=> t1 IHt1 t2 IHt2 r n /= /andP[rt1 rt2]; rewrite {}IHt1 // IHt2.
+- by move=> t IHt r n /= rt; rewrite {}IHt.
+- by move=> t IHt r n m /= rt; rewrite {}IHt.
+- by move=> t1 IHt1 t2 IHt2 r n /= /andP[rt1 rt2]; rewrite {}IHt1 // IHt2.
+- by move=> t IHt r n m /= rt; rewrite {}IHt.
+Qed.
+
+(* A ring formula stating that t1 is equal to 0 in the ring theory. *)
+(* Also applies to non commutative rings. *)
+Definition eq0_rform t1 :=
+ let m := ub_var t1 in
+ let: (t1', r1) := to_rterm t1 [::] m in
+ let fix loop r i := match r with
+ | [::] => t1' == 0
+ | t :: r' =>
+ let f := 'X_i * t == 1 /\ t * 'X_i == 1 in
+ 'forall 'X_i, (f \/ 'X_i == t /\ ~ ('exists 'X_i, f)) ==> loop r' i.+1
+ end%T
+ in loop r1 m.
+
+(* Transformation of a formula in the theory of rings with units into an *)
+(* equivalent formula in the sub-theory of rings. *)
+Fixpoint to_rform f :=
+ match f with
+ | Bool b => f
+ | t1 == t2 => eq0_rform (t1 - t2)
+ | Unit t1 => eq0_rform (t1 * t1^-1 - 1)
+ | f1 /\ f2 => to_rform f1 /\ to_rform f2
+ | f1 \/ f2 => to_rform f1 \/ to_rform f2
+ | f1 ==> f2 => to_rform f1 ==> to_rform f2
+ | ~ f1 => ~ to_rform f1
+ | ('exists 'X_i, f1) => 'exists 'X_i, to_rform f1
+ | ('forall 'X_i, f1) => 'forall 'X_i, to_rform f1
+ end%T.
+
+(* The transformation gives a ring formula. *)
+Lemma to_rform_rformula f : rformula (to_rform f).
+Proof.
+suffices eq0_ring t1: rformula (eq0_rform t1) by elim: f => //= => f1 ->.
+rewrite /eq0_rform; move: (ub_var t1) => m; set tr := _ m.
+suffices: all rterm (tr.1 :: tr.2).
+ case: tr => {t1} t1 r /= /andP[t1_r].
+ by elim: r m => [|t r IHr] m; rewrite /= ?andbT // => /andP[->]; exact: IHr.
+have: all rterm [::] by [].
+rewrite {}/tr; elim: t1 [::] => //=.
+- move=> t1 IHt1 t2 IHt2 r.
+ move/IHt1; case: to_rterm => {t1 r IHt1} t1 r /= /andP[t1_r].
+ move/IHt2; case: to_rterm => {t2 r IHt2} t2 r /= /andP[t2_r].
+ by rewrite t1_r t2_r.
+- by move=> t1 IHt1 r /IHt1; case: to_rterm.
+- by move=> t1 IHt1 n r /IHt1; case: to_rterm.
+- move=> t1 IHt1 t2 IHt2 r.
+ move/IHt1; case: to_rterm => {t1 r IHt1} t1 r /= /andP[t1_r].
+ move/IHt2; case: to_rterm => {t2 r IHt2} t2 r /= /andP[t2_r].
+ by rewrite t1_r t2_r.
+- move=> t1 IHt1 r.
+ by move/IHt1; case: to_rterm => {t1 r IHt1} t1 r /=; rewrite all_rcons.
+- by move=> t1 IHt1 n r /IHt1; case: to_rterm.
+Qed.
+
+(* Correctness of the transformation. *)
+Lemma to_rformP e f : holds e (to_rform f) <-> holds e f.
+Proof.
+suffices{e f} equal0_equiv e t1 t2:
+ holds e (eq0_rform (t1 - t2)) <-> (eval e t1 == eval e t2).
+- elim: f e => /=; try tauto.
+ + move=> t1 t2 e.
+ by split; [move/equal0_equiv/eqP | move/eqP/equal0_equiv].
+ + move=> t1 e; rewrite unitrE; exact: equal0_equiv.
+ + move=> f1 IHf1 f2 IHf2 e; move: (IHf1 e) (IHf2 e); tauto.
+ + move=> f1 IHf1 f2 IHf2 e; move: (IHf1 e) (IHf2 e); tauto.
+ + move=> f1 IHf1 f2 IHf2 e; move: (IHf1 e) (IHf2 e); tauto.
+ + move=> f1 IHf1 e; move: (IHf1 e); tauto.
+ + by move=> n f1 IHf1 e; split=> [] [x] /IHf1; exists x.
+ + by move=> n f1 IHf1 e; split=> Hx x; apply/IHf1.
+rewrite -(add0r (eval e t2)) -(can2_eq (subrK _) (addrK _)).
+rewrite -/(eval e (t1 - t2)); move: (t1 - t2)%T => {t1 t2} t.
+have sub_var_tsubst s t0: s.1 >= ub_var t0 -> tsubst t0 s = t0.
+ elim: t0 {t} => //=.
+ - by move=> n; case: ltngtP.
+ - by move=> t1 IHt1 t2 IHt2; rewrite geq_max => /andP[/IHt1-> /IHt2->].
+ - by move=> t1 IHt1 /IHt1->.
+ - by move=> t1 IHt1 n /IHt1->.
+ - by move=> t1 IHt1 t2 IHt2; rewrite geq_max => /andP[/IHt1-> /IHt2->].
+ - by move=> t1 IHt1 /IHt1->.
+ - by move=> t1 IHt1 n /IHt1->.
+pose fix rsub t' m r : term R :=
+ if r is u :: r' then tsubst (rsub t' m.+1 r') (m, u^-1)%T else t'.
+pose fix ub_sub m r : Prop :=
+ if r is u :: r' then ub_var u <= m /\ ub_sub m.+1 r' else true.
+suffices{t} rsub_to_r t r0 m: m >= ub_var t -> ub_sub m r0 ->
+ let: (t', r) := to_rterm t r0 m in
+ [/\ take (size r0) r = r0,
+ ub_var t' <= m + size r, ub_sub m r & rsub t' m r = t].
+- have:= rsub_to_r t [::] _ (leqnn _); rewrite /eq0_rform.
+ case: (to_rterm _ _ _) => [t1' r1] [//|_ _ ub_r1 def_t].
+ rewrite -{2}def_t {def_t}.
+ elim: r1 (ub_var t) e ub_r1 => [|u r1 IHr1] m e /= => [_|[ub_u ub_r1]].
+ by split=> /eqP.
+ rewrite eval_tsubst /=; set y := eval e u; split=> t_eq0.
+ apply/IHr1=> //; apply: t_eq0.
+ rewrite nth_set_nth /= eqxx -(eval_tsubst e u (m, Const _)).
+ rewrite sub_var_tsubst //= -/y.
+ case Uy: (y \in unit); [left | right]; first by rewrite mulVr ?divrr.
+ split=> [|[z]]; first by rewrite invr_out ?Uy.
+ rewrite nth_set_nth /= eqxx.
+ rewrite -!(eval_tsubst _ _ (m, Const _)) !sub_var_tsubst // -/y => yz1.
+ by case/unitrP: Uy; exists z.
+ move=> x def_x; apply/IHr1=> //; suff ->: x = y^-1 by []; move: def_x.
+ rewrite nth_set_nth /= eqxx -(eval_tsubst e u (m, Const _)).
+ rewrite sub_var_tsubst //= -/y; case=> [[xy1 yx1] | [xy nUy]].
+ by rewrite -[y^-1]mul1r -[1]xy1 mulrK //; apply/unitrP; exists x.
+ rewrite invr_out //; apply/unitrP=> [[z yz1]]; case: nUy; exists z.
+ rewrite nth_set_nth /= eqxx -!(eval_tsubst _ _ (m, _%:T)%T).
+ by rewrite !sub_var_tsubst.
+have rsub_id r t0 n: ub_var t0 <= n -> rsub t0 n r = t0.
+ by elim: r n => //= t1 r IHr n let0n; rewrite IHr ?sub_var_tsubst ?leqW.
+have rsub_acc r s t1 m1:
+ ub_var t1 <= m1 + size r -> rsub t1 m1 (r ++ s) = rsub t1 m1 r.
+ elim: r t1 m1 => [|t1 r IHr] t2 m1 /=; first by rewrite addn0; apply: rsub_id.
+ by move=> letmr; rewrite IHr ?addSnnS.
+elim: t r0 m => /=; try do [
+ by move=> n r m hlt hub; rewrite take_size (ltn_addr _ hlt) rsub_id
+| by move=> n r m hlt hub; rewrite leq0n take_size rsub_id
+| move=> t1 IHt1 t2 IHt2 r m; rewrite geq_max; case/andP=> hub1 hub2 hmr;
+ case: to_rterm {IHt1 hub1 hmr}(IHt1 r m hub1 hmr) => t1' r1;
+ case=> htake1 hub1' hsub1 <-;
+ case: to_rterm {IHt2 hub2 hsub1}(IHt2 r1 m hub2 hsub1) => t2' r2 /=;
+ rewrite geq_max; case=> htake2 -> hsub2 /= <-;
+ rewrite -{1 2}(cat_take_drop (size r1) r2) htake2; set r3 := drop _ _;
+ rewrite size_cat addnA (leq_trans _ (leq_addr _ _)) //;
+ split=> {hsub2}//;
+ first by [rewrite takel_cat // -htake1 size_take geq_min leqnn orbT];
+ rewrite -(rsub_acc r1 r3 t1') {hub1'}// -{htake1}htake2 {r3}cat_take_drop;
+ by elim: r2 m => //= u r2 IHr2 m; rewrite IHr2
+| do [ move=> t1 IHt1 r m; do 2!move/IHt1=> {IHt1}IHt1
+ | move=> t1 IHt1 n r m; do 2!move/IHt1=> {IHt1}IHt1];
+ case: to_rterm IHt1 => t1' r1 [-> -> hsub1 <-]; split=> {hsub1}//;
+ by elim: r1 m => //= u r1 IHr1 m; rewrite IHr1].
+move=> t1 IH r m letm /IH {IH} /(_ letm) {letm}.
+case: to_rterm => t1' r1 /= [def_r ub_t1' ub_r1 <-].
+rewrite size_rcons addnS leqnn -{1}cats1 takel_cat ?def_r; last first.
+ by rewrite -def_r size_take geq_min leqnn orbT.
+elim: r1 m ub_r1 ub_t1' {def_r} => /= [|u r1 IHr1] m => [_|[->]].
+ by rewrite addn0 eqxx.
+by rewrite -addSnnS => /IHr1 IH /IH[_ _ ub_r1 ->].
+Qed.
+
+(* Boolean test selecting formulas which describe a constructible set, *)
+(* i.e. formulas without quantifiers. *)
+
+(* The quantifier elimination check. *)
+Fixpoint qf_form (f : formula R) :=
+ match f with
+ | Bool _ | _ == _ | Unit _ => true
+ | f1 /\ f2 | f1 \/ f2 | f1 ==> f2 => qf_form f1 && qf_form f2
+ | ~ f1 => qf_form f1
+ | _ => false
+ end%T.
+
+(* Boolean holds predicate for quantifier free formulas *)
+Definition qf_eval e := fix loop (f : formula R) : bool :=
+ match f with
+ | Bool b => b
+ | t1 == t2 => (eval e t1 == eval e t2)%bool
+ | Unit t1 => eval e t1 \in unit
+ | f1 /\ f2 => loop f1 && loop f2
+ | f1 \/ f2 => loop f1 || loop f2
+ | f1 ==> f2 => (loop f1 ==> loop f2)%bool
+ | ~ f1 => ~~ loop f1
+ |_ => false
+ end%T.
+
+(* qf_eval is equivalent to holds *)
+Lemma qf_evalP e f : qf_form f -> reflect (holds e f) (qf_eval e f).
+Proof.
+elim: f => //=; try by move=> *; exact: idP.
+- move=> t1 t2 _; exact: eqP.
+- move=> f1 IHf1 f2 IHf2 /= /andP[/IHf1[] f1T]; last by right; case.
+ by case/IHf2; [left | right; case].
+- move=> f1 IHf1 f2 IHf2 /= /andP[/IHf1[] f1F]; first by do 2 left.
+ by case/IHf2; [left; right | right; case].
+- move=> f1 IHf1 f2 IHf2 /= /andP[/IHf1[] f1T]; last by left.
+ by case/IHf2; [left | right; move/(_ f1T)].
+by move=> f1 IHf1 /IHf1[]; [right | left].
+Qed.
+
+Implicit Type bc : seq (term R) * seq (term R).
+
+(* Quantifier-free formula are normalized into DNF. A DNF is *)
+(* represented by the type seq (seq (term R) * seq (term R)), where we *)
+(* separate positive and negative literals *)
+
+(* DNF preserving conjunction *)
+Definition and_dnf bcs1 bcs2 :=
+ \big[cat/nil]_(bc1 <- bcs1)
+ map (fun bc2 => (bc1.1 ++ bc2.1, bc1.2 ++ bc2.2)) bcs2.
+
+(* Computes a DNF from a qf ring formula *)
+Fixpoint qf_to_dnf (f : formula R) (neg : bool) {struct f} :=
+ match f with
+ | Bool b => if b (+) neg then [:: ([::], [::])] else [::]
+ | t1 == t2 => [:: if neg then ([::], [:: t1 - t2]) else ([:: t1 - t2], [::])]
+ | f1 /\ f2 => (if neg then cat else and_dnf) [rec f1, neg] [rec f2, neg]
+ | f1 \/ f2 => (if neg then and_dnf else cat) [rec f1, neg] [rec f2, neg]
+ | f1 ==> f2 => (if neg then and_dnf else cat) [rec f1, ~~ neg] [rec f2, neg]
+ | ~ f1 => [rec f1, ~~ neg]
+ | _ => if neg then [:: ([::], [::])] else [::]
+ end%T where "[ 'rec' f , neg ]" := (qf_to_dnf f neg).
+
+(* Conversely, transforms a DNF into a formula *)
+Definition dnf_to_form :=
+ let pos_lit t := And (t == 0) in let neg_lit t := And (t != 0) in
+ let cls bc := Or (foldr pos_lit True bc.1 /\ foldr neg_lit True bc.2) in
+ foldr cls False.
+
+(* Catenation of dnf is the Or of formulas *)
+Lemma cat_dnfP e bcs1 bcs2 :
+ qf_eval e (dnf_to_form (bcs1 ++ bcs2))
+ = qf_eval e (dnf_to_form bcs1 \/ dnf_to_form bcs2).
+Proof.
+by elim: bcs1 => //= bc1 bcs1 IH1; rewrite -orbA; congr orb; rewrite IH1.
+Qed.
+
+(* and_dnf is the And of formulas *)
+Lemma and_dnfP e bcs1 bcs2 :
+ qf_eval e (dnf_to_form (and_dnf bcs1 bcs2))
+ = qf_eval e (dnf_to_form bcs1 /\ dnf_to_form bcs2).
+Proof.
+elim: bcs1 => [|bc1 bcs1 IH1] /=; first by rewrite /and_dnf big_nil.
+rewrite /and_dnf big_cons -/(and_dnf bcs1 bcs2) cat_dnfP /=.
+rewrite {}IH1 /= andb_orl; congr orb.
+elim: bcs2 bc1 {bcs1} => [|bc2 bcs2 IH] bc1 /=; first by rewrite andbF.
+rewrite {}IH /= andb_orr; congr orb => {bcs2}.
+suffices aux (l1 l2 : seq (term R)) g : let redg := foldr (And \o g) True in
+ qf_eval e (redg (l1 ++ l2)) = qf_eval e (redg l1 /\ redg l2)%T.
++ by rewrite 2!aux /= 2!andbA -andbA -andbCA andbA andbCA andbA.
+by elim: l1 => [| t1 l1 IHl1] //=; rewrite -andbA IHl1.
+Qed.
+
+Lemma qf_to_dnfP e :
+ let qev f b := qf_eval e (dnf_to_form (qf_to_dnf f b)) in
+ forall f, qf_form f && rformula f -> qev f false = qf_eval e f.
+Proof.
+move=> qev; have qevT f: qev f true = ~~ qev f false.
+ rewrite {}/qev; elim: f => //=; do [by case | move=> f1 IH1 f2 IH2 | ].
+ - by move=> t1 t2; rewrite !andbT !orbF.
+ - by rewrite and_dnfP cat_dnfP negb_and -IH1 -IH2.
+ - by rewrite and_dnfP cat_dnfP negb_or -IH1 -IH2.
+ - by rewrite and_dnfP cat_dnfP /= negb_or IH1 -IH2 negbK.
+ by move=> t1 ->; rewrite negbK.
+rewrite /qev; elim=> //=; first by case.
+- by move=> t1 t2 _; rewrite subr_eq0 !andbT orbF.
+- move=> f1 IH1 f2 IH2; rewrite andbCA -andbA andbCA andbA; case/andP.
+ by rewrite and_dnfP /= => /IH1-> /IH2->.
+- move=> f1 IH1 f2 IH2; rewrite andbCA -andbA andbCA andbA; case/andP.
+ by rewrite cat_dnfP /= => /IH1-> => /IH2->.
+- move=> f1 IH1 f2 IH2; rewrite andbCA -andbA andbCA andbA; case/andP.
+ by rewrite cat_dnfP /= [qf_eval _ _]qevT -implybE => /IH1 <- /IH2->.
+by move=> f1 IH1 /IH1 <-; rewrite -qevT.
+Qed.
+
+Lemma dnf_to_form_qf bcs : qf_form (dnf_to_form bcs).
+Proof.
+by elim: bcs => //= [[clT clF] _ ->] /=; elim: clT => //=; elim: clF.
+Qed.
+
+Definition dnf_rterm cl := all rterm cl.1 && all rterm cl.2.
+
+Lemma qf_to_dnf_rterm f b : rformula f -> all dnf_rterm (qf_to_dnf f b).
+Proof.
+set ok := all dnf_rterm.
+have cat_ok bcs1 bcs2: ok bcs1 -> ok bcs2 -> ok (bcs1 ++ bcs2).
+ by move=> ok1 ok2; rewrite [ok _]all_cat; exact/andP.
+have and_ok bcs1 bcs2: ok bcs1 -> ok bcs2 -> ok (and_dnf bcs1 bcs2).
+ rewrite /and_dnf unlock; elim: bcs1 => //= cl1 bcs1 IH1; rewrite -andbA.
+ case/and3P=> ok11 ok12 ok1 ok2; rewrite cat_ok ?{}IH1 {bcs1 ok1}//.
+ elim: bcs2 ok2 => //= cl2 bcs2 IH2 /andP[ok2 /IH2->].
+ by rewrite /dnf_rterm !all_cat ok11 ok12 /= !andbT.
+elim: f b => //=; [ by do 2!case | | | | | by auto | | ];
+ try by repeat case/andP || intro; case: ifP; auto.
+by rewrite /dnf_rterm => ?? [] /= ->.
+Qed.
+
+Lemma dnf_to_rform bcs : rformula (dnf_to_form bcs) = all dnf_rterm bcs.
+Proof.
+elim: bcs => //= [[cl1 cl2] bcs ->]; rewrite {2}/dnf_rterm /=; congr (_ && _).
+by congr andb; [elim: cl1 | elim: cl2] => //= t cl ->; rewrite andbT.
+Qed.
+
+Section If.
+
+Variables (pred_f then_f else_f : formula R).
+
+Definition If := (pred_f /\ then_f \/ ~ pred_f /\ else_f)%T.
+
+Lemma If_form_qf :
+ qf_form pred_f -> qf_form then_f -> qf_form else_f -> qf_form If.
+Proof. by move=> /= -> -> ->. Qed.
+
+Lemma If_form_rf :
+ rformula pred_f -> rformula then_f -> rformula else_f -> rformula If.
+Proof. by move=> /= -> -> ->. Qed.
+
+Lemma eval_If e :
+ let ev := qf_eval e in ev If = (if ev pred_f then ev then_f else ev else_f).
+Proof. by rewrite /=; case: ifP => _; rewrite ?orbF. Qed.
+
+End If.
+
+Section Pick.
+
+Variables (I : finType) (pred_f then_f : I -> formula R) (else_f : formula R).
+
+Definition Pick :=
+ \big[Or/False]_(p : {ffun pred I})
+ ((\big[And/True]_i (if p i then pred_f i else ~ pred_f i))
+ /\ (if pick p is Some i then then_f i else else_f))%T.
+
+Lemma Pick_form_qf :
+ (forall i, qf_form (pred_f i)) ->
+ (forall i, qf_form (then_f i)) ->
+ qf_form else_f ->
+ qf_form Pick.
+Proof.
+move=> qfp qft qfe; have mA := (big_morph qf_form) true andb.
+rewrite mA // big1 //= => p _.
+rewrite mA // big1 => [|i _]; first by case: pick.
+by rewrite fun_if if_same /= qfp.
+Qed.
+
+Lemma eval_Pick e (qev := qf_eval e) :
+ let P i := qev (pred_f i) in
+ qev Pick = (if pick P is Some i then qev (then_f i) else qev else_f).
+Proof.
+move=> P; rewrite ((big_morph qev) false orb) //= big_orE /=.
+apply/existsP/idP=> [[p] | true_at_P].
+ rewrite ((big_morph qev) true andb) //= big_andE /=.
+ case/andP=> /forallP-eq_p_P.
+ rewrite (@eq_pick _ _ P) => [|i]; first by case: pick.
+ by move/(_ i): eq_p_P => /=; case: (p i) => //=; move/negbTE.
+exists [ffun i => P i] => /=; apply/andP; split.
+ rewrite ((big_morph qev) true andb) //= big_andE /=.
+ by apply/forallP=> i; rewrite /= ffunE; case Pi: (P i) => //=; apply: negbT.
+rewrite (@eq_pick _ _ P) => [|i]; first by case: pick true_at_P.
+by rewrite ffunE.
+Qed.
+
+End Pick.
+
+Section MultiQuant.
+
+Variable f : formula R.
+Implicit Types (I : seq nat) (e : seq R).
+
+Lemma foldExistsP I e :
+ (exists2 e', {in [predC I], same_env e e'} & holds e' f)
+ <-> holds e (foldr Exists f I).
+Proof.
+elim: I e => /= [|i I IHi] e.
+ by split=> [[e' eq_e] |]; [apply: eq_holds => i; rewrite eq_e | exists e].
+split=> [[e' eq_e f_e'] | [x]]; last set e_x := set_nth 0 e i x.
+ exists e'`_i; apply/IHi; exists e' => // j.
+ by have:= eq_e j; rewrite nth_set_nth /= !inE; case: eqP => // ->.
+case/IHi=> e' eq_e f_e'; exists e' => // j.
+by have:= eq_e j; rewrite nth_set_nth /= !inE; case: eqP.
+Qed.
+
+Lemma foldForallP I e :
+ (forall e', {in [predC I], same_env e e'} -> holds e' f)
+ <-> holds e (foldr Forall f I).
+Proof.
+elim: I e => /= [|i I IHi] e.
+ by split=> [|f_e e' eq_e]; [exact | apply: eq_holds f_e => i; rewrite eq_e].
+split=> [f_e' x | f_e e' eq_e]; first set e_x := set_nth 0 e i x.
+ apply/IHi=> e' eq_e; apply: f_e' => j.
+ by have:= eq_e j; rewrite nth_set_nth /= !inE; case: eqP.
+move/IHi: (f_e e'`_i); apply=> j.
+by have:= eq_e j; rewrite nth_set_nth /= !inE; case: eqP => // ->.
+Qed.
+
+End MultiQuant.
+
+End EvalTerm.
+
+Prenex Implicits dnf_rterm.
+
+Module IntegralDomain.
+
+Definition axiom (R : ringType) :=
+ forall x y : R, x * y = 0 -> (x == 0) || (y == 0).
+
+Section ClassDef.
+
+Record class_of (R : Type) : Type :=
+ Class {base : ComUnitRing.class_of R; mixin : axiom (Ring.Pack base R)}.
+Local Coercion base : class_of >-> ComUnitRing.class_of.
+
+Structure type := Pack {sort; _ : class_of sort; _ : Type}.
+Local Coercion sort : type >-> Sortclass.
+Variable (T : Type) (cT : type).
+Definition class := let: Pack _ c _ as cT' := cT return class_of cT' in c.
+Definition clone c of phant_id class c := @Pack T c T.
+Let xT := let: Pack T _ _ := cT in T.
+Notation xclass := (class : class_of xT).
+
+Definition pack b0 (m0 : axiom (@Ring.Pack T b0 T)) :=
+ fun bT b & phant_id (ComUnitRing.class bT) b =>
+ fun m & phant_id m0 m => Pack (@Class T b m) T.
+
+Definition eqType := @Equality.Pack cT xclass xT.
+Definition choiceType := @Choice.Pack cT xclass xT.
+Definition zmodType := @Zmodule.Pack cT xclass xT.
+Definition ringType := @Ring.Pack cT xclass xT.
+Definition comRingType := @ComRing.Pack cT xclass xT.
+Definition unitRingType := @UnitRing.Pack cT xclass xT.
+Definition comUnitRingType := @ComUnitRing.Pack cT xclass xT.
+
+End ClassDef.
+
+Module Exports.
+Coercion base : class_of >-> ComUnitRing.class_of.
+Implicit Arguments mixin [R x y].
+Coercion mixin : class_of >-> axiom.
+Coercion sort : type >-> Sortclass.
+Bind Scope ring_scope with sort.
+Coercion eqType : type >-> Equality.type.
+Canonical eqType.
+Coercion choiceType : type >-> Choice.type.
+Canonical choiceType.
+Coercion zmodType : type >-> Zmodule.type.
+Canonical zmodType.
+Coercion ringType : type >-> Ring.type.
+Canonical ringType.
+Coercion comRingType : type >-> ComRing.type.
+Canonical comRingType.
+Coercion unitRingType : type >-> UnitRing.type.
+Canonical unitRingType.
+Coercion comUnitRingType : type >-> ComUnitRing.type.
+Canonical comUnitRingType.
+Notation idomainType := type.
+Notation IdomainType T m := (@pack T _ m _ _ id _ id).
+Notation "[ 'idomainType' 'of' T 'for' cT ]" := (@clone T cT _ idfun)
+ (at level 0, format "[ 'idomainType' 'of' T 'for' cT ]") : form_scope.
+Notation "[ 'idomainType' 'of' T ]" := (@clone T _ _ id)
+ (at level 0, format "[ 'idomainType' 'of' T ]") : form_scope.
+End Exports.
+
+End IntegralDomain.
+Import IntegralDomain.Exports.
+
+Section IntegralDomainTheory.
+
+Variable R : idomainType.
+Implicit Types x y : R.
+
+Lemma mulf_eq0 x y : (x * y == 0) = (x == 0) || (y == 0).
+Proof.
+apply/eqP/idP; first by case: R x y => T [].
+by case/pred2P=> ->; rewrite (mulr0, mul0r).
+Qed.
+
+Lemma prodf_eq0 (I : finType) (P : pred I) (F : I -> R) :
+ reflect (exists2 i, P i & (F i == 0)) (\prod_(i | P i) F i == 0).
+Proof.
+apply: (iffP idP) => [|[i Pi /eqP Fi0]]; last first.
+ by rewrite (bigD1 i) //= Fi0 mul0r.
+elim: (index_enum _) => [|i r IHr]; first by rewrite big_nil oner_eq0.
+rewrite big_cons /=; have [Pi | _] := ifP; last exact: IHr.
+by rewrite mulf_eq0; case/orP=> // Fi0; exists i.
+Qed.
+
+Lemma prodf_seq_eq0 I r (P : pred I) (F : I -> R) :
+ (\prod_(i <- r | P i) F i == 0) = has (fun i => P i && (F i == 0)) r.
+Proof. by rewrite (big_morph _ mulf_eq0 (oner_eq0 _)) big_has_cond. Qed.
+
+Lemma mulf_neq0 x y : x != 0 -> y != 0 -> x * y != 0.
+Proof. move=> x0 y0; rewrite mulf_eq0; exact/norP. Qed.
+
+Lemma prodf_neq0 (I : finType) (P : pred I) (F : I -> R) :
+ reflect (forall i, P i -> (F i != 0)) (\prod_(i | P i) F i != 0).
+Proof.
+by rewrite (sameP (prodf_eq0 _ _) exists_inP) negb_exists_in; exact: forall_inP.
+Qed.
+
+Lemma prodf_seq_neq0 I r (P : pred I) (F : I -> R) :
+ (\prod_(i <- r | P i) F i != 0) = all (fun i => P i ==> (F i != 0)) r.
+Proof.
+rewrite prodf_seq_eq0 -all_predC; apply: eq_all => i /=.
+by rewrite implybE negb_and.
+Qed.
+
+Lemma expf_eq0 x n : (x ^+ n == 0) = (n > 0) && (x == 0).
+Proof.
+elim: n => [|n IHn]; first by rewrite oner_eq0.
+by rewrite exprS mulf_eq0 IHn andKb.
+Qed.
+
+Lemma sqrf_eq0 x : (x ^+ 2 == 0) = (x == 0). Proof. exact: expf_eq0. Qed.
+
+Lemma expf_neq0 x m : x != 0 -> x ^+ m != 0.
+Proof. by move=> x_nz; rewrite expf_eq0; apply/nandP; right. Qed.
+
+Lemma natf_neq0 n : (n%:R != 0 :> R) = [char R]^'.-nat n.
+Proof.
+have [-> | /prod_prime_decomp->] := posnP n; first by rewrite eqxx.
+rewrite !big_seq; elim/big_rec: _ => [|[p e] s /=]; first by rewrite oner_eq0.
+case/mem_prime_decomp=> p_pr _ _; rewrite pnat_mul pnat_exp eqn0Ngt orbC => <-.
+by rewrite natrM natrX mulf_eq0 expf_eq0 negb_or negb_and pnatE ?inE p_pr.
+Qed.
+
+Lemma natf0_char n : n > 0 -> n%:R == 0 :> R -> exists p, p \in [char R].
+Proof.
+move=> n_gt0 nR_0; exists (pdiv n`_[char R]).
+apply: pnatP (pdiv_dvd _); rewrite ?part_pnat // ?pdiv_prime //.
+by rewrite ltn_neqAle eq_sym partn_eq1 // -natf_neq0 nR_0 /=.
+Qed.
+
+Lemma charf'_nat n : [char R]^'.-nat n = (n%:R != 0 :> R).
+Proof.
+have [-> | n_gt0] := posnP n; first by rewrite eqxx.
+apply/idP/idP => [|nz_n]; last first.
+ by apply/pnatP=> // p p_pr p_dvd_n; apply: contra nz_n => /dvdn_charf <-.
+apply: contraL => n0; have [// | p charRp] := natf0_char _ n0.
+have [p_pr _] := andP charRp; rewrite (eq_pnat _ (eq_negn (charf_eq charRp))).
+by rewrite p'natE // (dvdn_charf charRp) n0.
+Qed.
+
+Lemma charf0P : [char R] =i pred0 <-> (forall n, (n%:R == 0 :> R) = (n == 0)%N).
+Proof.
+split=> charF0 n; last by rewrite !inE charF0 andbC; case: eqP => // ->.
+have [-> | n_gt0] := posnP; first exact: eqxx.
+by apply/negP; case/natf0_char=> // p; rewrite charF0.
+Qed.
+
+Lemma eqf_sqr x y : (x ^+ 2 == y ^+ 2) = (x == y) || (x == - y).
+Proof. by rewrite -subr_eq0 subr_sqr mulf_eq0 subr_eq0 addr_eq0. Qed.
+
+Lemma mulfI x : x != 0 -> injective ( *%R x).
+Proof.
+move=> nz_x y z; rewrite -[x * z]add0r; move/(canLR (addrK _))/eqP.
+rewrite -mulrN -mulrDr mulf_eq0 (negbTE nz_x) /=.
+by move/eqP/(canRL (subrK _)); rewrite add0r.
+Qed.
+
+Lemma mulIf x : x != 0 -> injective ( *%R^~ x).
+Proof. by move=> nz_x y z; rewrite -!(mulrC x); exact: mulfI. Qed.
+
+Lemma sqrf_eq1 x : (x ^+ 2 == 1) = (x == 1) || (x == -1).
+Proof. by rewrite -subr_eq0 subr_sqr_1 mulf_eq0 subr_eq0 addr_eq0. Qed.
+
+Lemma expfS_eq1 x n :
+ (x ^+ n.+1 == 1) = (x == 1) || (\sum_(i < n.+1) x ^+ i == 0).
+Proof. by rewrite -![_ == 1]subr_eq0 subrX1 mulf_eq0. Qed.
+
+Lemma lregP x : reflect (lreg x) (x != 0).
+Proof. by apply: (iffP idP) => [/mulfI | /lreg_neq0]. Qed.
+
+Lemma rregP x : reflect (rreg x) (x != 0).
+Proof. by apply: (iffP idP) => [/mulIf | /rreg_neq0]. Qed.
+
+Canonical regular_idomainType := [idomainType of R^o].
+
+End IntegralDomainTheory.
+
+Implicit Arguments lregP [[R] [x]].
+Implicit Arguments rregP [[R] [x]].
+
+Module Field.
+
+Definition mixin_of (F : unitRingType) := forall x : F, x != 0 -> x \in unit.
+
+Lemma IdomainMixin R : mixin_of R -> IntegralDomain.axiom R.
+Proof.
+move=> m x y xy0; apply/norP=> [[]] /m Ux /m.
+by rewrite -(unitrMr _ Ux) xy0 unitr0.
+Qed.
+
+Section Mixins.
+
+Variables (R : comRingType) (inv : R -> R).
+
+Definition axiom := forall x, x != 0 -> inv x * x = 1.
+Hypothesis mulVx : axiom.
+Hypothesis inv0 : inv 0 = 0.
+
+Fact intro_unit (x y : R) : y * x = 1 -> x != 0.
+Proof.
+by move=> yx1; apply: contraNneq (oner_neq0 R) => x0; rewrite -yx1 x0 mulr0.
+Qed.
+
+Fact inv_out : {in predC (predC1 0), inv =1 id}.
+Proof. by move=> x /negbNE/eqP->. Qed.
+
+Definition UnitMixin := ComUnitRing.Mixin mulVx intro_unit inv_out.
+
+Lemma Mixin : mixin_of (UnitRing.Pack (UnitRing.Class UnitMixin) R).
+Proof. by []. Qed.
+
+End Mixins.
+
+Section ClassDef.
+
+Record class_of (F : Type) : Type := Class {
+ base : IntegralDomain.class_of F;
+ mixin : mixin_of (UnitRing.Pack base F)
+}.
+Local Coercion base : class_of >-> IntegralDomain.class_of.
+
+Structure type := Pack {sort; _ : class_of sort; _ : Type}.
+Local Coercion sort : type >-> Sortclass.
+Variable (T : Type) (cT : type).
+Definition class := let: Pack _ c _ as cT' := cT return class_of cT' in c.
+Definition clone c of phant_id class c := @Pack T c T.
+Let xT := let: Pack T _ _ := cT in T.
+Notation xclass := (class : class_of xT).
+
+Definition pack b0 (m0 : mixin_of (@UnitRing.Pack T b0 T)) :=
+ fun bT b & phant_id (IntegralDomain.class bT) b =>
+ fun m & phant_id m0 m => Pack (@Class T b m) T.
+
+Definition eqType := @Equality.Pack cT xclass xT.
+Definition choiceType := @Choice.Pack cT xclass xT.
+Definition zmodType := @Zmodule.Pack cT xclass xT.
+Definition ringType := @Ring.Pack cT xclass xT.
+Definition comRingType := @ComRing.Pack cT xclass xT.
+Definition unitRingType := @UnitRing.Pack cT xclass xT.
+Definition comUnitRingType := @ComUnitRing.Pack cT xclass xT.
+Definition idomainType := @IntegralDomain.Pack cT xclass xT.
+
+End ClassDef.
+
+Module Exports.
+Coercion base : class_of >-> IntegralDomain.class_of.
+Implicit Arguments mixin [F x].
+Coercion mixin : class_of >-> mixin_of.
+Coercion sort : type >-> Sortclass.
+Bind Scope ring_scope with sort.
+Coercion eqType : type >-> Equality.type.
+Canonical eqType.
+Coercion choiceType : type >-> Choice.type.
+Canonical choiceType.
+Coercion zmodType : type >-> Zmodule.type.
+Canonical zmodType.
+Coercion ringType : type >-> Ring.type.
+Canonical ringType.
+Coercion comRingType : type >-> ComRing.type.
+Canonical comRingType.
+Coercion unitRingType : type >-> UnitRing.type.
+Canonical unitRingType.
+Coercion comUnitRingType : type >-> ComUnitRing.type.
+Canonical comUnitRingType.
+Coercion idomainType : type >-> IntegralDomain.type.
+Canonical idomainType.
+Notation fieldType := type.
+Notation FieldType T m := (@pack T _ m _ _ id _ id).
+Notation FieldUnitMixin := UnitMixin.
+Notation FieldIdomainMixin := IdomainMixin.
+Notation FieldMixin := Mixin.
+Notation "[ 'fieldType' 'of' T 'for' cT ]" := (@clone T cT _ idfun)
+ (at level 0, format "[ 'fieldType' 'of' T 'for' cT ]") : form_scope.
+Notation "[ 'fieldType' 'of' T ]" := (@clone T _ _ id)
+ (at level 0, format "[ 'fieldType' 'of' T ]") : form_scope.
+End Exports.
+
+End Field.
+Import Field.Exports.
+
+Section FieldTheory.
+
+Variable F : fieldType.
+Implicit Types x y : F.
+
+Lemma fieldP : Field.mixin_of F. Proof. by case: F => T []. Qed.
+
+Lemma unitfE x : (x \in unit) = (x != 0).
+Proof. by apply/idP/idP=> [/(memPn _)-> | /fieldP]; rewrite ?unitr0. Qed.
+
+Lemma mulVf x : x != 0 -> x^-1 * x = 1.
+Proof. by rewrite -unitfE; exact: mulVr. Qed.
+Lemma divff x : x != 0 -> x / x = 1.
+Proof. by rewrite -unitfE; exact: divrr. Qed.
+Definition mulfV := divff.
+Lemma mulKf x : x != 0 -> cancel ( *%R x) ( *%R x^-1).
+Proof. by rewrite -unitfE; exact: mulKr. Qed.
+Lemma mulVKf x : x != 0 -> cancel ( *%R x^-1) ( *%R x).
+Proof. by rewrite -unitfE; exact: mulVKr. Qed.
+Lemma mulfK x : x != 0 -> cancel ( *%R^~ x) ( *%R^~ x^-1).
+Proof. by rewrite -unitfE; exact: mulrK. Qed.
+Lemma mulfVK x : x != 0 -> cancel ( *%R^~ x^-1) ( *%R^~ x).
+Proof. by rewrite -unitfE; exact: divrK. Qed.
+Definition divfK := mulfVK.
+
+Lemma invfM : {morph @inv F : x y / x * y}.
+Proof.
+move=> x y; case: (eqVneq x 0) => [-> |nzx]; first by rewrite !(mul0r, invr0).
+case: (eqVneq y 0) => [-> |nzy]; first by rewrite !(mulr0, invr0).
+by rewrite mulrC invrM ?unitfE.
+Qed.
+
+Lemma invf_div x y : (x / y)^-1 = y / x.
+Proof. by rewrite invfM invrK mulrC. Qed.
+
+Lemma expfB_cond m n x : (x == 0) + n <= m -> x ^+ (m - n) = x ^+ m / x ^+ n.
+Proof.
+move/subnK=> <-; rewrite addnA addnK !exprD.
+have [-> | nz_x] := altP eqP; first by rewrite !mulr0 !mul0r.
+by rewrite mulfK ?expf_neq0.
+Qed.
+
+Lemma expfB m n x : n < m -> x ^+ (m - n) = x ^+ m / x ^+ n.
+Proof. by move=> lt_n_m; apply: expfB_cond; case: eqP => // _; apply: ltnW. Qed.
+
+Lemma prodfV I r (P : pred I) (E : I -> F) :
+ \prod_(i <- r | P i) (E i)^-1 = (\prod_(i <- r | P i) E i)^-1.
+Proof. by rewrite (big_morph _ invfM (invr1 F)). Qed.
+
+Lemma prodf_div I r (P : pred I) (E D : I -> F) :
+ \prod_(i <- r | P i) (E i / D i) =
+ \prod_(i <- r | P i) E i / \prod_(i <- r | P i) D i.
+Proof. by rewrite big_split prodfV. Qed.
+
+Lemma telescope_prodf n m (f : nat -> F) :
+ (forall k, n < k < m -> f k != 0) -> n < m ->
+ \prod_(n <= k < m) (f k.+1 / f k) = f m / f n.
+Proof.
+move=> nz_f ltnm; apply: invr_inj; rewrite prodf_div !invf_div -prodf_div.
+by apply: telescope_prodr => // k /nz_f; rewrite unitfE.
+Qed.
+
+Lemma addf_div x1 y1 x2 y2 :
+ y1 != 0 -> y2 != 0 -> x1 / y1 + x2 / y2 = (x1 * y2 + x2 * y1) / (y1 * y2).
+Proof. by move=> nzy1 nzy2; rewrite invfM mulrDl !mulrA mulrAC !mulfK. Qed.
+
+Lemma mulf_div x1 y1 x2 y2 : (x1 / y1) * (x2 / y2) = (x1 * x2) / (y1 * y2).
+Proof. by rewrite mulrACA -invfM. Qed.
+
+
+Lemma char0_natf_div :
+ [char F] =i pred0 -> forall m d, d %| m -> (m %/ d)%:R = m%:R / d%:R :> F.
+Proof.
+move/charf0P=> char0F m [|d] d_dv_m; first by rewrite divn0 invr0 mulr0.
+by rewrite natr_div // unitfE char0F.
+Qed.
+
+Section FieldMorphismInj.
+
+Variables (R : ringType) (f : {rmorphism F -> R}).
+
+Lemma fmorph_eq0 x : (f x == 0) = (x == 0).
+Proof.
+have [-> | nz_x] := altP (x =P _); first by rewrite rmorph0 eqxx.
+apply/eqP; move/(congr1 ( *%R (f x^-1)))/eqP.
+by rewrite -rmorphM mulVf // mulr0 rmorph1 ?oner_eq0.
+Qed.
+
+Lemma fmorph_inj : injective f.
+Proof.
+move=> x y eqfxy; apply/eqP; rewrite -subr_eq0 -fmorph_eq0 rmorphB //.
+by rewrite eqfxy subrr.
+Qed.
+
+Lemma fmorph_eq1 x : (f x == 1) = (x == 1).
+Proof. by rewrite -(inj_eq fmorph_inj) rmorph1. Qed.
+
+Lemma fmorph_char : [char R] =i [char F].
+Proof. by move=> p; rewrite !inE -fmorph_eq0 rmorph_nat. Qed.
+
+End FieldMorphismInj.
+
+Section FieldMorphismInv.
+
+Variables (R : unitRingType) (f : {rmorphism F -> R}).
+
+Lemma fmorph_unit x : (f x \in unit) = (x != 0).
+Proof.
+have [-> |] := altP (x =P _); first by rewrite rmorph0 unitr0.
+by rewrite -unitfE; exact: rmorph_unit.
+Qed.
+
+Lemma fmorphV : {morph f: x / x^-1}.
+Proof.
+move=> x; have [-> | nz_x] := eqVneq x 0; first by rewrite !(invr0, rmorph0).
+by rewrite rmorphV ?unitfE.
+Qed.
+
+Lemma fmorph_div : {morph f : x y / x / y}.
+Proof. by move=> x y; rewrite rmorphM fmorphV. Qed.
+
+End FieldMorphismInv.
+
+Canonical regular_fieldType := [fieldType of F^o].
+
+Section ModuleTheory.
+
+Variable V : lmodType F.
+Implicit Types (a : F) (v : V).
+
+Lemma scalerK a : a != 0 -> cancel ( *:%R a : V -> V) ( *:%R a^-1).
+Proof. by move=> nz_a v; rewrite scalerA mulVf // scale1r. Qed.
+
+Lemma scalerKV a : a != 0 -> cancel ( *:%R a^-1 : V -> V) ( *:%R a).
+Proof. by rewrite -invr_eq0 -{3}[a]invrK; exact: scalerK. Qed.
+
+Lemma scalerI a : a != 0 -> injective ( *:%R a : V -> V).
+Proof. move=> nz_a; exact: can_inj (scalerK nz_a). Qed.
+
+Lemma scaler_eq0 a v : (a *: v == 0) = (a == 0) || (v == 0).
+Proof.
+have [-> | nz_a] := altP (a =P _); first by rewrite scale0r eqxx.
+by rewrite (can2_eq (scalerK nz_a) (scalerKV nz_a)) scaler0.
+Qed.
+
+Lemma rpredZeq S (modS : submodPred S) (kS : keyed_pred modS) a v :
+ (a *: v \in kS) = (a == 0) || (v \in kS).
+Proof.
+have [-> | nz_a] := altP eqP; first by rewrite scale0r rpred0.
+by apply/idP/idP; first rewrite -{2}(scalerK nz_a v); apply: rpredZ.
+Qed.
+
+End ModuleTheory.
+
+Lemma char_lalg (A : lalgType F) : [char A] =i [char F].
+Proof. by move=> p; rewrite inE -scaler_nat scaler_eq0 oner_eq0 orbF. Qed.
+
+Section Predicates.
+
+Context (S : pred_class) (divS : @divrPred F S) (kS : keyed_pred divS).
+
+Lemma fpredMl x y : x \in kS -> x != 0 -> (x * y \in kS) = (y \in kS).
+Proof. by rewrite -!unitfE; exact: rpredMl. Qed.
+
+Lemma fpredMr x y : x \in kS -> x != 0 -> (y * x \in kS) = (y \in kS).
+Proof. by rewrite -!unitfE; exact: rpredMr. Qed.
+
+Lemma fpred_divl x y : x \in kS -> x != 0 -> (x / y \in kS) = (y \in kS).
+Proof. by rewrite -!unitfE; exact: rpred_divl. Qed.
+
+Lemma fpred_divr x y : x \in kS -> x != 0 -> (y / x \in kS) = (y \in kS).
+Proof. by rewrite -!unitfE; exact: rpred_divr. Qed.
+
+End Predicates.
+
+End FieldTheory.
+
+Implicit Arguments fmorph_inj [[F] [R] x1 x2].
+
+Module DecidableField.
+
+Definition axiom (R : unitRingType) (s : seq R -> pred (formula R)) :=
+ forall e f, reflect (holds e f) (s e f).
+
+Record mixin_of (R : unitRingType) : Type :=
+ Mixin { sat : seq R -> pred (formula R); satP : axiom sat}.
+
+Section ClassDef.
+
+Record class_of (F : Type) : Type :=
+ Class {base : Field.class_of F; mixin : mixin_of (UnitRing.Pack base F)}.
+Local Coercion base : class_of >-> Field.class_of.
+
+Structure type := Pack {sort; _ : class_of sort; _ : Type}.
+Local Coercion sort : type >-> Sortclass.
+Variable (T : Type) (cT : type).
+Definition class := let: Pack _ c _ as cT' := cT return class_of cT' in c.
+Definition clone c of phant_id class c := @Pack T c T.
+Let xT := let: Pack T _ _ := cT in T.
+Notation xclass := (class : class_of xT).
+
+Definition pack b0 (m0 : mixin_of (@UnitRing.Pack T b0 T)) :=
+ fun bT b & phant_id (Field.class bT) b =>
+ fun m & phant_id m0 m => Pack (@Class T b m) T.
+
+Definition eqType := @Equality.Pack cT xclass xT.
+Definition choiceType := @Choice.Pack cT xclass xT.
+Definition zmodType := @Zmodule.Pack cT xclass xT.
+Definition ringType := @Ring.Pack cT xclass xT.
+Definition comRingType := @ComRing.Pack cT xclass xT.
+Definition unitRingType := @UnitRing.Pack cT xclass xT.
+Definition comUnitRingType := @ComUnitRing.Pack cT xclass xT.
+Definition idomainType := @IntegralDomain.Pack cT xclass xT.
+Definition fieldType := @Field.Pack cT xclass xT.
+
+End ClassDef.
+
+Module Exports.
+Coercion base : class_of >-> Field.class_of.
+Coercion mixin : class_of >-> mixin_of.
+Coercion sort : type >-> Sortclass.
+Bind Scope ring_scope with sort.
+Coercion eqType : type >-> Equality.type.
+Canonical eqType.
+Coercion choiceType : type >-> Choice.type.
+Canonical choiceType.
+Coercion zmodType : type >-> Zmodule.type.
+Canonical zmodType.
+Coercion ringType : type >-> Ring.type.
+Canonical ringType.
+Coercion comRingType : type >-> ComRing.type.
+Canonical comRingType.
+Coercion unitRingType : type >-> UnitRing.type.
+Canonical unitRingType.
+Coercion comUnitRingType : type >-> ComUnitRing.type.
+Canonical comUnitRingType.
+Coercion idomainType : type >-> IntegralDomain.type.
+Canonical idomainType.
+Coercion fieldType : type >-> Field.type.
+Canonical fieldType.
+Notation decFieldType := type.
+Notation DecFieldType T m := (@pack T _ m _ _ id _ id).
+Notation DecFieldMixin := Mixin.
+Notation "[ 'decFieldType' 'of' T 'for' cT ]" := (@clone T cT _ idfun)
+ (at level 0, format "[ 'decFieldType' 'of' T 'for' cT ]") : form_scope.
+Notation "[ 'decFieldType' 'of' T ]" := (@clone T _ _ id)
+ (at level 0, format "[ 'decFieldType' 'of' T ]") : form_scope.
+End Exports.
+
+End DecidableField.
+Import DecidableField.Exports.
+
+Section DecidableFieldTheory.
+
+Variable F : decFieldType.
+
+Definition sat := DecidableField.sat (DecidableField.class F).
+
+Lemma satP : DecidableField.axiom sat.
+Proof. exact: DecidableField.satP. Qed.
+
+Fact sol_subproof n f :
+ reflect (exists s, (size s == n) && sat s f)
+ (sat [::] (foldr Exists f (iota 0 n))).
+Proof.
+apply: (iffP (satP _ _)) => [|[s]]; last first.
+ case/andP=> /eqP sz_s /satP f_s; apply/foldExistsP.
+ exists s => // i; rewrite !inE mem_iota -leqNgt add0n => le_n_i.
+ by rewrite !nth_default ?sz_s.
+case/foldExistsP=> e e0 f_e; set s := take n (set_nth 0 e n 0).
+have sz_s: size s = n by rewrite size_take size_set_nth leq_max leqnn.
+exists s; rewrite sz_s eqxx; apply/satP; apply: eq_holds f_e => i.
+case: (leqP n i) => [le_n_i | lt_i_n].
+ by rewrite -e0 ?nth_default ?sz_s // !inE mem_iota -leqNgt.
+by rewrite nth_take // nth_set_nth /= eq_sym eqn_leq leqNgt lt_i_n.
+Qed.
+
+Definition sol n f :=
+ if sol_subproof n f is ReflectT sP then xchoose sP else nseq n 0.
+
+Lemma size_sol n f : size (sol n f) = n.
+Proof.
+rewrite /sol; case: sol_subproof => [sP | _]; last exact: size_nseq.
+by case/andP: (xchooseP sP) => /eqP.
+Qed.
+
+Lemma solP n f : reflect (exists2 s, size s = n & holds s f) (sat (sol n f) f).
+Proof.
+rewrite /sol; case: sol_subproof => [sP | sPn].
+ case/andP: (xchooseP sP) => _ ->; left.
+ by case: sP => s; case/andP; move/eqP=> <-; move/satP; exists s.
+apply: (iffP (satP _ _)); first by exists (nseq n 0); rewrite ?size_nseq.
+by case=> s sz_s; move/satP=> f_s; case: sPn; exists s; rewrite sz_s eqxx.
+Qed.
+
+Lemma eq_sat f1 f2 :
+ (forall e, holds e f1 <-> holds e f2) -> sat^~ f1 =1 sat^~ f2.
+Proof. by move=> eqf12 e; apply/satP/satP; case: (eqf12 e). Qed.
+
+Lemma eq_sol f1 f2 :
+ (forall e, holds e f1 <-> holds e f2) -> sol^~ f1 =1 sol^~ f2.
+Proof.
+rewrite /sol => /eq_sat eqf12 n.
+do 2![case: sol_subproof] => //= [f1s f2s | ns1 [s f2s] | [s f1s] []].
+- by apply: eq_xchoose => s; rewrite eqf12.
+- by case: ns1; exists s; rewrite -eqf12.
+by exists s; rewrite eqf12.
+Qed.
+
+End DecidableFieldTheory.
+
+Implicit Arguments satP [[F] [e] [f]].
+Implicit Arguments solP [[F] [n] [f]].
+
+Section QE_Mixin.
+
+Variable F : Field.type.
+Implicit Type f : formula F.
+
+Variable proj : nat -> seq (term F) * seq (term F) -> formula F.
+(* proj is the elimination of a single existential quantifier *)
+
+(* The elimination projector is well_formed. *)
+Definition wf_QE_proj :=
+ forall i bc (bc_i := proj i bc),
+ dnf_rterm bc -> qf_form bc_i && rformula bc_i.
+
+(* The elimination projector is valid *)
+Definition valid_QE_proj :=
+ forall i bc (ex_i_bc := ('exists 'X_i, dnf_to_form [:: bc])%T) e,
+ dnf_rterm bc -> reflect (holds e ex_i_bc) (qf_eval e (proj i bc)).
+
+Hypotheses (wf_proj : wf_QE_proj) (ok_proj : valid_QE_proj).
+
+Let elim_aux f n := foldr Or False (map (proj n) (qf_to_dnf f false)).
+
+Fixpoint quantifier_elim f :=
+ match f with
+ | f1 /\ f2 => (quantifier_elim f1) /\ (quantifier_elim f2)
+ | f1 \/ f2 => (quantifier_elim f1) \/ (quantifier_elim f2)
+ | f1 ==> f2 => (~ quantifier_elim f1) \/ (quantifier_elim f2)
+ | ~ f => ~ quantifier_elim f
+ | ('exists 'X_n, f) => elim_aux (quantifier_elim f) n
+ | ('forall 'X_n, f) => ~ elim_aux (~ quantifier_elim f) n
+ | _ => f
+ end%T.
+
+Lemma quantifier_elim_wf f :
+ let qf := quantifier_elim f in rformula f -> qf_form qf && rformula qf.
+Proof.
+suffices aux_wf f0 n : let qf := elim_aux f0 n in
+ rformula f0 -> qf_form qf && rformula qf.
+- by elim: f => //=; do ?[ move=> f1 IH1 f2 IH2;
+ case/andP=> rf1 rf2;
+ case/andP:(IH1 rf1)=> -> ->;
+ case/andP:(IH2 rf2)=> -> -> //
+ | move=> n f1 IH rf1;
+ case/andP: (IH rf1)=> qff rf;
+ rewrite aux_wf ].
+rewrite /elim_aux => rf.
+suffices or_wf fs : let ofs := foldr Or False fs in
+ all (@qf_form F) fs && all (@rformula F) fs -> qf_form ofs && rformula ofs.
+- apply: or_wf.
+ suffices map_proj_wf bcs: let mbcs := map (proj n) bcs in
+ all dnf_rterm bcs -> all (@qf_form _) mbcs && all (@rformula _) mbcs.
+ by apply: map_proj_wf; exact: qf_to_dnf_rterm.
+ elim: bcs => [|bc bcs ihb] bcsr //= /andP[rbc rbcs].
+ by rewrite andbAC andbA wf_proj //= andbC ihb.
+elim: fs => //= g gs ihg; rewrite -andbA => /and4P[-> qgs -> rgs] /=.
+by apply: ihg; rewrite qgs rgs.
+Qed.
+
+Lemma quantifier_elim_rformP e f :
+ rformula f -> reflect (holds e f) (qf_eval e (quantifier_elim f)).
+Proof.
+pose rc e n f := exists x, qf_eval (set_nth 0 e n x) f.
+have auxP f0 e0 n0: qf_form f0 && rformula f0 ->
+ reflect (rc e0 n0 f0) (qf_eval e0 (elim_aux f0 n0)).
++ rewrite /elim_aux => cf; set bcs := qf_to_dnf f0 false.
+ apply: (@iffP (rc e0 n0 (dnf_to_form bcs))); last first.
+ - by case=> x; rewrite -qf_to_dnfP //; exists x.
+ - by case=> x; rewrite qf_to_dnfP //; exists x.
+ have: all dnf_rterm bcs by case/andP: cf => _; exact: qf_to_dnf_rterm.
+ elim: {f0 cf}bcs => [|bc bcs IHbcs] /=; first by right; case.
+ case/andP=> r_bc /IHbcs {IHbcs}bcsP.
+ have f_qf := dnf_to_form_qf [:: bc].
+ case: ok_proj => //= [ex_x|no_x].
+ left; case: ex_x => x /(qf_evalP _ f_qf); rewrite /= orbF => bc_x.
+ by exists x; rewrite /= bc_x.
+ apply: (iffP bcsP) => [[x bcs_x] | [x]] /=.
+ by exists x; rewrite /= bcs_x orbT.
+ case/orP => [bc_x|]; last by exists x.
+ by case: no_x; exists x; apply/(qf_evalP _ f_qf); rewrite /= bc_x.
+elim: f e => //.
+- move=> b e _; exact: idP.
+- move=> t1 t2 e _; exact: eqP.
+- move=> f1 IH1 f2 IH2 e /= /andP[/IH1[] f1e]; last by right; case.
+ by case/IH2; [left | right; case].
+- move=> f1 IH1 f2 IH2 e /= /andP[/IH1[] f1e]; first by do 2!left.
+ by case/IH2; [left; right | right; case].
+- move=> f1 IH1 f2 IH2 e /= /andP[/IH1[] f1e]; last by left.
+ by case/IH2; [left | right; move/(_ f1e)].
+- by move=> f IHf e /= /IHf[]; [right | left].
+- move=> n f IHf e /= rf; have rqf := quantifier_elim_wf rf.
+ by apply: (iffP (auxP _ _ _ rqf)) => [] [x]; exists x; exact/IHf.
+move=> n f IHf e /= rf; have rqf := quantifier_elim_wf rf.
+case: auxP => // [f_x|no_x]; first by right=> no_x; case: f_x => x /IHf[].
+by left=> x; apply/IHf=> //; apply/idPn=> f_x; case: no_x; exists x.
+Qed.
+
+Definition proj_sat e f := qf_eval e (quantifier_elim (to_rform f)).
+
+Lemma proj_satP : DecidableField.axiom proj_sat.
+Proof.
+move=> e f; have fP := quantifier_elim_rformP e (to_rform_rformula f).
+by apply: (iffP fP); move/to_rformP.
+Qed.
+
+Definition QEdecFieldMixin := DecidableField.Mixin proj_satP.
+
+End QE_Mixin.
+
+Module ClosedField.
+
+(* Axiom == all non-constant monic polynomials have a root *)
+Definition axiom (R : ringType) :=
+ forall n (P : nat -> R), n > 0 ->
+ exists x : R, x ^+ n = \sum_(i < n) P i * (x ^+ i).
+
+Section ClassDef.
+
+Record class_of (F : Type) : Type :=
+ Class {base : DecidableField.class_of F; _ : axiom (Ring.Pack base F)}.
+Local Coercion base : class_of >-> DecidableField.class_of.
+
+Structure type := Pack {sort; _ : class_of sort; _ : Type}.
+Local Coercion sort : type >-> Sortclass.
+Variable (T : Type) (cT : type).
+Definition class := let: Pack _ c _ as cT' := cT return class_of cT' in c.
+Definition clone c of phant_id class c := @Pack T c T.
+Let xT := let: Pack T _ _ := cT in T.
+Notation xclass := (class : class_of xT).
+
+Definition pack b0 (m0 : axiom (@Ring.Pack T b0 T)) :=
+ fun bT b & phant_id (DecidableField.class bT) b =>
+ fun m & phant_id m0 m => Pack (@Class T b m) T.
+
+(* There should eventually be a constructor from polynomial resolution *)
+(* that builds the DecidableField mixin using QE. *)
+
+Definition eqType := @Equality.Pack cT xclass xT.
+Definition choiceType := @Choice.Pack cT xclass xT.
+Definition zmodType := @Zmodule.Pack cT xclass xT.
+Definition ringType := @Ring.Pack cT xclass xT.
+Definition comRingType := @ComRing.Pack cT xclass xT.
+Definition unitRingType := @UnitRing.Pack cT xclass xT.
+Definition comUnitRingType := @ComUnitRing.Pack cT xclass xT.
+Definition idomainType := @IntegralDomain.Pack cT xclass xT.
+Definition fieldType := @Field.Pack cT xclass xT.
+Definition decFieldType := @DecidableField.Pack cT class xT.
+
+End ClassDef.
+
+Module Exports.
+Coercion base : class_of >-> DecidableField.class_of.
+Coercion sort : type >-> Sortclass.
+Bind Scope ring_scope with sort.
+Coercion eqType : type >-> Equality.type.
+Canonical eqType.
+Coercion choiceType : type >-> Choice.type.
+Canonical choiceType.
+Coercion zmodType : type >-> Zmodule.type.
+Canonical zmodType.
+Coercion ringType : type >-> Ring.type.
+Canonical ringType.
+Coercion comRingType : type >-> ComRing.type.
+Canonical comRingType.
+Coercion unitRingType : type >-> UnitRing.type.
+Canonical unitRingType.
+Coercion comUnitRingType : type >-> ComUnitRing.type.
+Canonical comUnitRingType.
+Coercion idomainType : type >-> IntegralDomain.type.
+Canonical idomainType.
+Coercion fieldType : type >-> Field.type.
+Canonical fieldType.
+Coercion decFieldType : type >-> DecidableField.type.
+Canonical decFieldType.
+Notation closedFieldType := type.
+Notation ClosedFieldType T m := (@pack T _ m _ _ id _ id).
+Notation "[ 'closedFieldType' 'of' T 'for' cT ]" := (@clone T cT _ idfun)
+ (at level 0, format "[ 'closedFieldType' 'of' T 'for' cT ]") : form_scope.
+Notation "[ 'closedFieldType' 'of' T ]" := (@clone T _ _ id)
+ (at level 0, format "[ 'closedFieldType' 'of' T ]") : form_scope.
+End Exports.
+
+End ClosedField.
+Import ClosedField.Exports.
+
+Section ClosedFieldTheory.
+
+Variable F : closedFieldType.
+
+Lemma solve_monicpoly : ClosedField.axiom F.
+Proof. by case: F => ? []. Qed.
+
+End ClosedFieldTheory.
+
+Module SubType.
+
+Section Zmodule.
+
+Variables (V : zmodType) (S : predPredType V).
+Variables (subS : zmodPred S) (kS : keyed_pred subS).
+Variable U : subType (mem kS).
+
+Let inU v Sv : U := Sub v Sv.
+Let zeroU := inU (rpred0 kS).
+
+Let oppU (u : U) := inU (rpredNr (valP u)).
+Let addU (u1 u2 : U) := inU (rpredD (valP u1) (valP u2)).
+
+Fact addA : associative addU.
+Proof. by move=> u1 u2 u3; apply: val_inj; rewrite !SubK addrA. Qed.
+Fact addC : commutative addU.
+Proof. by move=> u1 u2; apply: val_inj; rewrite !SubK addrC. Qed.
+Fact add0 : left_id zeroU addU.
+Proof. by move=> u; apply: val_inj; rewrite !SubK add0r. Qed.
+Fact addN : left_inverse zeroU oppU addU.
+Proof. by move=> u; apply: val_inj; rewrite !SubK addNr. Qed.
+
+Definition zmodMixin of phant U := ZmodMixin addA addC add0 addN.
+
+End Zmodule.
+
+Section Ring.
+
+Variables (R : ringType) (S : predPredType R).
+Variables (ringS : subringPred S) (kS : keyed_pred ringS).
+
+Definition cast_zmodType (V : zmodType) T (VeqT : V = T :> Type) :=
+ let cast mV := let: erefl in _ = T := VeqT return Zmodule.class_of T in mV in
+ Zmodule.Pack (cast (Zmodule.class V)) T.
+
+Variable (T : subType (mem kS)) (V : zmodType) (VeqT: V = T :> Type).
+
+Let inT x Sx : T := Sub x Sx.
+Let oneT := inT (rpred1 kS).
+Let mulT (u1 u2 : T) := inT (rpredM (valP u1) (valP u2)).
+Let T' := cast_zmodType VeqT.
+
+Hypothesis valM : {morph (val : T' -> R) : x y / x - y}.
+
+Let val0 : val (0 : T') = 0.
+Proof. by rewrite -(subrr (0 : T')) valM subrr. Qed.
+Let valD : {morph (val : T' -> R): x y / x + y}.
+Proof.
+by move=> u v; rewrite -{1}[v]opprK -[- v]sub0r !valM val0 sub0r opprK.
+Qed.
+
+Fact mulA : @associative T' mulT.
+Proof. by move=> u1 u2 u3; apply: val_inj; rewrite !SubK mulrA. Qed.
+Fact mul1l : left_id oneT mulT.
+Proof. by move=> u; apply: val_inj; rewrite !SubK mul1r. Qed.
+Fact mul1r : right_id oneT mulT.
+Proof. by move=> u; apply: val_inj; rewrite !SubK mulr1. Qed.
+Fact mulDl : @left_distributive T' T' mulT +%R.
+Proof. by move=> u1 u2 u3; apply: val_inj; rewrite !(SubK, valD) mulrDl. Qed.
+Fact mulDr : @right_distributive T' T' mulT +%R.
+Proof. by move=> u1 u2 u3; apply: val_inj; rewrite !(SubK, valD) mulrDr. Qed.
+Fact nz1 : oneT != 0 :> T'.
+Proof.
+by apply: contraNneq (oner_neq0 R) => eq10; rewrite -val0 -eq10 SubK.
+Qed.
+
+Definition ringMixin := RingMixin mulA mul1l mul1r mulDl mulDr nz1.
+
+End Ring.
+
+Section Lmodule.
+
+Variables (R : ringType) (V : lmodType R) (S : predPredType V).
+Variables (linS : submodPred S) (kS : keyed_pred linS).
+Variables (W : subType (mem kS)) (Z : zmodType) (ZeqW : Z = W :> Type).
+
+Let scaleW a (w : W) := (Sub _ : _ -> W) (rpredZ a (valP w)).
+Let W' := cast_zmodType ZeqW.
+
+Hypothesis valD : {morph (val : W' -> V) : x y / x + y}.
+
+Fact scaleA a b (w : W') : scaleW a (scaleW b w) = scaleW (a * b) w.
+Proof. by apply: val_inj; rewrite !SubK scalerA. Qed.
+Fact scale1 : left_id 1 scaleW.
+Proof. by move=> w; apply: val_inj; rewrite !SubK scale1r. Qed.
+Fact scaleDr : @right_distributive R W' scaleW +%R.
+Proof. by move=> a w w2; apply: val_inj; rewrite !(SubK, valD) scalerDr. Qed.
+Fact scaleDl w : {morph (scaleW^~ w : R -> W') : a b / a + b}.
+Proof. by move=> a b; apply: val_inj; rewrite !(SubK, valD) scalerDl. Qed.
+
+Definition lmodMixin := LmodMixin scaleA scale1 scaleDr scaleDl.
+
+End Lmodule.
+
+Lemma lalgMixin (R : ringType) (A : lalgType R) (B : lmodType R) (f : B -> A) :
+ phant B -> injective f -> scalable f ->
+ forall mulB, {morph f : x y / mulB x y >-> x * y} -> Lalgebra.axiom mulB.
+Proof.
+by move=> _ injf fZ mulB fM a x y; apply: injf; rewrite !(fZ, fM) scalerAl.
+Qed.
+
+Lemma comRingMixin (R : comRingType) (T : ringType) (f : T -> R) :
+ phant T -> injective f -> {morph f : x y / x * y} -> commutative (@mul T).
+Proof. by move=> _ inj_f fM x y; apply: inj_f; rewrite !fM mulrC. Qed.
+
+Lemma algMixin (R : comRingType) (A : algType R) (B : lalgType R) (f : B -> A) :
+ phant B -> injective f -> {morph f : x y / x * y} -> scalable f ->
+ @Algebra.axiom R B.
+Proof.
+by move=> _ inj_f fM fZ a x y; apply: inj_f; rewrite !(fM, fZ) scalerAr.
+Qed.
+
+Section UnitRing.
+
+Definition cast_ringType (Q : ringType) T (QeqT : Q = T :> Type) :=
+ let cast rQ := let: erefl in _ = T := QeqT return Ring.class_of T in rQ in
+ Ring.Pack (cast (Ring.class Q)) T.
+
+Variables (R : unitRingType) (S : predPredType R).
+Variables (ringS : divringPred S) (kS : keyed_pred ringS).
+
+Variables (T : subType (mem kS)) (Q : ringType) (QeqT : Q = T :> Type).
+
+Let inT x Sx : T := Sub x Sx.
+Let invT (u : T) := inT (rpredVr (valP u)).
+Let unitT := [qualify a u : T | val u \is a unit].
+Let T' := cast_ringType QeqT.
+
+Hypothesis val1 : val (1 : T') = 1.
+Hypothesis valM : {morph (val : T' -> R) : x y / x * y}.
+
+Fact mulVr :
+ {in (unitT : predPredType T'), left_inverse (1 : T') invT (@mul T')}.
+Proof. by move=> u Uu; apply: val_inj; rewrite val1 valM SubK mulVr. Qed.
+
+Fact mulrV : {in unitT, right_inverse (1 : T') invT (@mul T')}.
+Proof. by move=> u Uu; apply: val_inj; rewrite val1 valM SubK mulrV. Qed.
+
+Fact unitP (u v : T') : v * u = 1 /\ u * v = 1 -> u \in unitT.
+Proof.
+by case=> vu1 uv1; apply/unitrP; exists (val v); rewrite -!valM vu1 uv1.
+Qed.
+
+Fact unit_id : {in [predC unitT], invT =1 id}.
+Proof. by move=> u /invr_out def_u1; apply: val_inj; rewrite SubK. Qed.
+
+Definition unitRingMixin := UnitRingMixin mulVr mulrV unitP unit_id.
+
+End UnitRing.
+
+Lemma idomainMixin (R : idomainType) (T : ringType) (f : T -> R) :
+ phant T -> injective f -> f 0 = 0 -> {morph f : u v / u * v} ->
+ @IntegralDomain.axiom T.
+Proof.
+move=> _ injf f0 fM u v uv0.
+by rewrite -!(inj_eq injf) !f0 -mulf_eq0 -fM uv0 f0.
+Qed.
+
+Lemma fieldMixin (F : fieldType) (K : unitRingType) (f : K -> F) :
+ phant K -> injective f -> f 0 = 0 -> {mono f : u / u \in unit} ->
+ @Field.mixin_of K.
+Proof. by move=> _ injf f0 fU u; rewrite -fU unitfE -f0 inj_eq. Qed.
+
+Module Exports.
+
+Notation "[ 'zmodMixin' 'of' U 'by' <: ]" := (zmodMixin (Phant U))
+ (at level 0, format "[ 'zmodMixin' 'of' U 'by' <: ]") : form_scope.
+Notation "[ 'ringMixin' 'of' R 'by' <: ]" :=
+ (@ringMixin _ _ _ _ _ _ (@erefl Type R%type) (rrefl _))
+ (at level 0, format "[ 'ringMixin' 'of' R 'by' <: ]") : form_scope.
+Notation "[ 'lmodMixin' 'of' U 'by' <: ]" :=
+ (@lmodMixin _ _ _ _ _ _ _ (@erefl Type U%type) (rrefl _))
+ (at level 0, format "[ 'lmodMixin' 'of' U 'by' <: ]") : form_scope.
+Notation "[ 'lalgMixin' 'of' A 'by' <: ]" :=
+ ((lalgMixin (Phant A) val_inj (rrefl _)) *%R (rrefl _))
+ (at level 0, format "[ 'lalgMixin' 'of' A 'by' <: ]") : form_scope.
+Notation "[ 'comRingMixin' 'of' R 'by' <: ]" :=
+ (comRingMixin (Phant R) val_inj (rrefl _))
+ (at level 0, format "[ 'comRingMixin' 'of' R 'by' <: ]") : form_scope.
+Notation "[ 'algMixin' 'of' A 'by' <: ]" :=
+ (algMixin (Phant A) val_inj (rrefl _) (rrefl _))
+ (at level 0, format "[ 'algMixin' 'of' A 'by' <: ]") : form_scope.
+Notation "[ 'unitRingMixin' 'of' R 'by' <: ]" :=
+ (@unitRingMixin _ _ _ _ _ _ (@erefl Type R%type) (erefl _) (rrefl _))
+ (at level 0, format "[ 'unitRingMixin' 'of' R 'by' <: ]") : form_scope.
+Notation "[ 'idomainMixin' 'of' R 'by' <: ]" :=
+ (idomainMixin (Phant R) val_inj (erefl _) (rrefl _))
+ (at level 0, format "[ 'idomainMixin' 'of' R 'by' <: ]") : form_scope.
+Notation "[ 'fieldMixin' 'of' F 'by' <: ]" :=
+ (fieldMixin (Phant F) val_inj (erefl _) (frefl _))
+ (at level 0, format "[ 'fieldMixin' 'of' F 'by' <: ]") : form_scope.
+
+End Exports.
+
+End SubType.
+
+Module Theory.
+
+Definition addrA := addrA.
+Definition addrC := addrC.
+Definition add0r := add0r.
+Definition addNr := addNr.
+Definition addr0 := addr0.
+Definition addrN := addrN.
+Definition subrr := subrr.
+Definition addrCA := addrCA.
+Definition addrAC := addrAC.
+Definition addrACA := addrACA.
+Definition addKr := addKr.
+Definition addNKr := addNKr.
+Definition addrK := addrK.
+Definition addrNK := addrNK.
+Definition subrK := subrK.
+Definition addrI := @addrI.
+Definition addIr := @addIr.
+Implicit Arguments addrI [[V] x1 x2].
+Implicit Arguments addIr [[V] x1 x2].
+Definition opprK := opprK.
+Definition oppr_inj := @oppr_inj.
+Implicit Arguments oppr_inj [[V] x1 x2].
+Definition oppr0 := oppr0.
+Definition oppr_eq0 := oppr_eq0.
+Definition opprD := opprD.
+Definition opprB := opprB.
+Definition subr0 := subr0.
+Definition sub0r := sub0r.
+Definition subr_eq := subr_eq.
+Definition subr_eq0 := subr_eq0.
+Definition addr_eq0 := addr_eq0.
+Definition eqr_opp := eqr_opp.
+Definition eqr_oppLR := eqr_oppLR.
+Definition sumrN := sumrN.
+Definition sumrB := sumrB.
+Definition sumrMnl := sumrMnl.
+Definition sumrMnr := sumrMnr.
+Definition sumr_const := sumr_const.
+Definition telescope_sumr := telescope_sumr.
+Definition mulr0n := mulr0n.
+Definition mulr1n := mulr1n.
+Definition mulr2n := mulr2n.
+Definition mulrS := mulrS.
+Definition mulrSr := mulrSr.
+Definition mulrb := mulrb.
+Definition mul0rn := mul0rn.
+Definition mulNrn := mulNrn.
+Definition mulrnDl := mulrnDl.
+Definition mulrnDr := mulrnDr.
+Definition mulrnBl := mulrnBl.
+Definition mulrnBr := mulrnBr.
+Definition mulrnA := mulrnA.
+Definition mulrnAC := mulrnAC.
+Definition mulrA := mulrA.
+Definition mul1r := mul1r.
+Definition mulr1 := mulr1.
+Definition mulrDl := mulrDl.
+Definition mulrDr := mulrDr.
+Definition oner_neq0 := oner_neq0.
+Definition oner_eq0 := oner_eq0.
+Definition mul0r := mul0r.
+Definition mulr0 := mulr0.
+Definition mulrN := mulrN.
+Definition mulNr := mulNr.
+Definition mulrNN := mulrNN.
+Definition mulN1r := mulN1r.
+Definition mulrN1 := mulrN1.
+Definition mulr_suml := mulr_suml.
+Definition mulr_sumr := mulr_sumr.
+Definition mulrBl := mulrBl.
+Definition mulrBr := mulrBr.
+Definition mulrnAl := mulrnAl.
+Definition mulrnAr := mulrnAr.
+Definition mulr_natl := mulr_natl.
+Definition mulr_natr := mulr_natr.
+Definition natrD := natrD.
+Definition natrB := natrB.
+Definition natr_sum := natr_sum.
+Definition natrM := natrM.
+Definition natrX := natrX.
+Definition expr0 := expr0.
+Definition exprS := exprS.
+Definition expr1 := expr1.
+Definition expr2 := expr2.
+Definition expr0n := expr0n.
+Definition expr1n := expr1n.
+Definition exprD := exprD.
+Definition exprSr := exprSr.
+Definition commr_sym := commr_sym.
+Definition commr_refl := commr_refl.
+Definition commr0 := commr0.
+Definition commr1 := commr1.
+Definition commrN := commrN.
+Definition commrN1 := commrN1.
+Definition commrD := commrD.
+Definition commrMn := commrMn.
+Definition commrM := commrM.
+Definition commr_nat := commr_nat.
+Definition commrX := commrX.
+Definition exprMn_comm := exprMn_comm.
+Definition commr_sign := commr_sign.
+Definition exprMn_n := exprMn_n.
+Definition exprM := exprM.
+Definition exprAC := exprAC.
+Definition expr_mod := expr_mod.
+Definition expr_dvd := expr_dvd.
+Definition signr_odd := signr_odd.
+Definition signr_eq0 := signr_eq0.
+Definition mulr_sign := mulr_sign.
+Definition signr_addb := signr_addb.
+Definition signrN := signrN.
+Definition signrE := signrE.
+Definition mulr_signM := mulr_signM.
+Definition exprNn := exprNn.
+Definition sqrrN := sqrrN.
+Definition sqrr_sign := sqrr_sign.
+Definition signrMK := signrMK.
+Definition mulrI_eq0 := mulrI_eq0.
+Definition lreg_neq0 := lreg_neq0.
+Definition mulrI0_lreg := mulrI0_lreg.
+Definition lregN := lregN.
+Definition lreg1 := lreg1.
+Definition lregM := lregM.
+Definition lregX := lregX.
+Definition lreg_sign := lreg_sign.
+Definition lregP {R x} := @lregP R x.
+Definition mulIr_eq0 := mulIr_eq0.
+Definition mulIr0_rreg := mulIr0_rreg.
+Definition rreg_neq0 := rreg_neq0.
+Definition rregN := rregN.
+Definition rreg1 := rreg1.
+Definition rregM := rregM.
+Definition revrX := revrX.
+Definition rregX := rregX.
+Definition rregP {R x} := @rregP R x.
+Definition exprDn_comm := exprDn_comm.
+Definition exprBn_comm := exprBn_comm.
+Definition subrXX_comm := subrXX_comm.
+Definition exprD1n := exprD1n.
+Definition subrX1 := subrX1.
+Definition sqrrD1 := sqrrD1.
+Definition sqrrB1 := sqrrB1.
+Definition subr_sqr_1 := subr_sqr_1.
+Definition charf0 := charf0.
+Definition charf_prime := charf_prime.
+Definition mulrn_char := mulrn_char.
+Definition dvdn_charf := dvdn_charf.
+Definition charf_eq := charf_eq.
+Definition bin_lt_charf_0 := bin_lt_charf_0.
+Definition Frobenius_autE := Frobenius_autE.
+Definition Frobenius_aut0 := Frobenius_aut0.
+Definition Frobenius_aut1 := Frobenius_aut1.
+Definition Frobenius_autD_comm := Frobenius_autD_comm.
+Definition Frobenius_autMn := Frobenius_autMn.
+Definition Frobenius_aut_nat := Frobenius_aut_nat.
+Definition Frobenius_autM_comm := Frobenius_autM_comm.
+Definition Frobenius_autX := Frobenius_autX.
+Definition Frobenius_autN := Frobenius_autN.
+Definition Frobenius_autB_comm := Frobenius_autB_comm.
+Definition exprNn_char := exprNn_char.
+Definition addrr_char2 := addrr_char2.
+Definition oppr_char2 := oppr_char2.
+Definition addrK_char2 := addrK_char2.
+Definition addKr_char2 := addKr_char2.
+Definition prodr_const := prodr_const.
+Definition mulrC := mulrC.
+Definition mulrCA := mulrCA.
+Definition mulrAC := mulrAC.
+Definition mulrACA := mulrACA.
+Definition exprMn := exprMn.
+Definition prodrXl := prodrXl.
+Definition prodrXr := prodrXr.
+Definition prodrN := prodrN.
+Definition prodrMn := prodrMn.
+Definition natr_prod := natr_prod.
+Definition prodr_undup_exp_count := prodr_undup_exp_count.
+Definition exprDn := exprDn.
+Definition exprBn := exprBn.
+Definition subrXX := subrXX.
+Definition sqrrD := sqrrD.
+Definition sqrrB := sqrrB.
+Definition subr_sqr := subr_sqr.
+Definition subr_sqrDB := subr_sqrDB.
+Definition exprDn_char := exprDn_char.
+Definition mulrV := mulrV.
+Definition divrr := divrr.
+Definition mulVr := mulVr.
+Definition invr_out := invr_out.
+Definition unitrP {R x} := @unitrP R x.
+Definition mulKr := mulKr.
+Definition mulVKr := mulVKr.
+Definition mulrK := mulrK.
+Definition mulrVK := mulrVK.
+Definition divrK := divrK.
+Definition mulrI := mulrI.
+Definition mulIr := mulIr.
+Definition telescope_prodr := telescope_prodr.
+Definition commrV := commrV.
+Definition unitrE := unitrE.
+Definition invrK := invrK.
+Definition invr_inj := @invr_inj.
+Implicit Arguments invr_inj [[R] x1 x2].
+Definition unitrV := unitrV.
+Definition unitr1 := unitr1.
+Definition invr1 := invr1.
+Definition divr1 := divr1.
+Definition div1r := div1r.
+Definition natr_div := natr_div.
+Definition unitr0 := unitr0.
+Definition invr0 := invr0.
+Definition unitrN1 := unitrN1.
+Definition unitrN := unitrN.
+Definition invrN1 := invrN1.
+Definition invrN := invrN.
+Definition invr_sign := invr_sign.
+Definition unitrMl := unitrMl.
+Definition unitrMr := unitrMr.
+Definition invrM := invrM.
+Definition invr_eq0 := invr_eq0.
+Definition invr_eq1 := invr_eq1.
+Definition invr_neq0 := invr_neq0.
+Definition unitrM_comm := unitrM_comm.
+Definition unitrX := unitrX.
+Definition unitrX_pos := unitrX_pos.
+Definition exprVn := exprVn.
+Definition exprB := exprB.
+Definition invr_signM := invr_signM.
+Definition divr_signM := divr_signM.
+Definition rpred0D := rpred0D.
+Definition rpred0 := rpred0.
+Definition rpredD := rpredD.
+Definition rpredNr := rpredNr.
+Definition rpred_sum := rpred_sum.
+Definition rpredMn := rpredMn.
+Definition rpredN := rpredN.
+Definition rpredB := rpredB.
+Definition rpredMNn := rpredMNn.
+Definition rpredDr := rpredDr.
+Definition rpredDl := rpredDl.
+Definition rpredBr := rpredBr.
+Definition rpredBl := rpredBl.
+Definition rpredMsign := rpredMsign.
+Definition rpred1M := rpred1M.
+Definition rpred1 := rpred1.
+Definition rpredM := rpredM.
+Definition rpred_prod := rpred_prod.
+Definition rpredX := rpredX.
+Definition rpred_nat := rpred_nat.
+Definition rpredN1 := rpredN1.
+Definition rpred_sign := rpred_sign.
+Definition rpredZsign := rpredZsign.
+Definition rpredZnat := rpredZnat.
+Definition rpredZ := rpredZ.
+Definition rpredVr := rpredVr.
+Definition rpredV := rpredV.
+Definition rpred_div := rpred_div.
+Definition rpredXN := rpredXN.
+Definition rpredZeq := rpredZeq.
+Definition char_lalg := char_lalg.
+Definition rpredMr := rpredMr.
+Definition rpredMl := rpredMl.
+Definition rpred_divr := rpred_divr.
+Definition rpred_divl := rpred_divl.
+Definition eq_eval := eq_eval.
+Definition eval_tsubst := eval_tsubst.
+Definition eq_holds := eq_holds.
+Definition holds_fsubst := holds_fsubst.
+Definition unitrM := unitrM.
+Definition unitrPr {R x} := @unitrPr R x.
+Definition expr_div_n := expr_div_n.
+Definition mulf_eq0 := mulf_eq0.
+Definition prodf_eq0 := prodf_eq0.
+Definition prodf_seq_eq0 := prodf_seq_eq0.
+Definition mulf_neq0 := mulf_neq0.
+Definition prodf_neq0 := prodf_neq0.
+Definition prodf_seq_neq0 := prodf_seq_neq0.
+Definition expf_eq0 := expf_eq0.
+Definition sqrf_eq0 := sqrf_eq0.
+Definition expf_neq0 := expf_neq0.
+Definition natf_neq0 := natf_neq0.
+Definition natf0_char := natf0_char.
+Definition charf'_nat := charf'_nat.
+Definition charf0P := charf0P.
+Definition eqf_sqr := eqf_sqr.
+Definition mulfI := mulfI.
+Definition mulIf := mulIf.
+Definition sqrf_eq1 := sqrf_eq1.
+Definition expfS_eq1 := expfS_eq1.
+Definition fieldP := fieldP.
+Definition unitfE := unitfE.
+Definition mulVf := mulVf.
+Definition mulfV := mulfV.
+Definition divff := divff.
+Definition mulKf := mulKf.
+Definition mulVKf := mulVKf.
+Definition mulfK := mulfK.
+Definition mulfVK := mulfVK.
+Definition divfK := divfK.
+Definition invfM := invfM.
+Definition invf_div := invf_div.
+Definition expfB_cond := expfB_cond.
+Definition expfB := expfB.
+Definition prodfV := prodfV.
+Definition prodf_div := prodf_div.
+Definition telescope_prodf := telescope_prodf.
+Definition addf_div := addf_div.
+Definition mulf_div := mulf_div.
+Definition char0_natf_div := char0_natf_div.
+Definition fpredMr := fpredMr.
+Definition fpredMl := fpredMl.
+Definition fpred_divr := fpred_divr.
+Definition fpred_divl := fpred_divl.
+Definition satP {F e f} := @satP F e f.
+Definition eq_sat := eq_sat.
+Definition solP {F n f} := @solP F n f.
+Definition eq_sol := eq_sol.
+Definition size_sol := size_sol.
+Definition solve_monicpoly := solve_monicpoly.
+Definition raddf0 := raddf0.
+Definition raddf_eq0 := raddf_eq0.
+Definition raddfN := raddfN.
+Definition raddfD := raddfD.
+Definition raddfB := raddfB.
+Definition raddf_sum := raddf_sum.
+Definition raddfMn := raddfMn.
+Definition raddfMNn := raddfMNn.
+Definition raddfMnat := raddfMnat.
+Definition raddfMsign := raddfMsign.
+Definition can2_additive := can2_additive.
+Definition bij_additive := bij_additive.
+Definition rmorph0 := rmorph0.
+Definition rmorphN := rmorphN.
+Definition rmorphD := rmorphD.
+Definition rmorphB := rmorphB.
+Definition rmorph_sum := rmorph_sum.
+Definition rmorphMn := rmorphMn.
+Definition rmorphMNn := rmorphMNn.
+Definition rmorphismP := rmorphismP.
+Definition rmorphismMP := rmorphismMP.
+Definition rmorph1 := rmorph1.
+Definition rmorph_eq1 := rmorph_eq1.
+Definition rmorphM := rmorphM.
+Definition rmorphMsign := rmorphMsign.
+Definition rmorph_nat := rmorph_nat.
+Definition rmorph_eq_nat := rmorph_eq_nat.
+Definition rmorph_prod := rmorph_prod.
+Definition rmorphX := rmorphX.
+Definition rmorphN1 := rmorphN1.
+Definition rmorph_sign := rmorph_sign.
+Definition rmorph_char := rmorph_char.
+Definition can2_rmorphism := can2_rmorphism.
+Definition bij_rmorphism := bij_rmorphism.
+Definition rmorph_comm := rmorph_comm.
+Definition rmorph_unit := rmorph_unit.
+Definition rmorphV := rmorphV.
+Definition rmorph_div := rmorph_div.
+Definition fmorph_eq0 := fmorph_eq0.
+Definition fmorph_inj := @fmorph_inj.
+Implicit Arguments fmorph_inj [[F] [R] x1 x2].
+Definition fmorph_eq1 := fmorph_eq1.
+Definition fmorph_char := fmorph_char.
+Definition fmorph_unit := fmorph_unit.
+Definition fmorphV := fmorphV.
+Definition fmorph_div := fmorph_div.
+Definition scalerA := scalerA.
+Definition scale1r := scale1r.
+Definition scalerDr := scalerDr.
+Definition scalerDl := scalerDl.
+Definition scaler0 := scaler0.
+Definition scale0r := scale0r.
+Definition scaleNr := scaleNr.
+Definition scaleN1r := scaleN1r.
+Definition scalerN := scalerN.
+Definition scalerBl := scalerBl.
+Definition scalerBr := scalerBr.
+Definition scaler_nat := scaler_nat.
+Definition scalerMnl := scalerMnl.
+Definition scalerMnr := scalerMnr.
+Definition scaler_suml := scaler_suml.
+Definition scaler_sumr := scaler_sumr.
+Definition scaler_eq0 := scaler_eq0.
+Definition scalerK := scalerK.
+Definition scalerKV := scalerKV.
+Definition scalerI := scalerI.
+Definition scalerAl := scalerAl.
+Definition mulr_algl := mulr_algl.
+Definition scaler_sign := scaler_sign.
+Definition signrZK := signrZK.
+Definition scalerCA := scalerCA.
+Definition scalerAr := scalerAr.
+Definition mulr_algr := mulr_algr.
+Definition exprZn := exprZn.
+Definition scaler_prodl := scaler_prodl.
+Definition scaler_prodr := scaler_prodr.
+Definition scaler_prod := scaler_prod.
+Definition scaler_injl := scaler_injl.
+Definition scaler_unit := scaler_unit.
+Definition invrZ := invrZ.
+Definition raddfZnat := raddfZnat.
+Definition raddfZsign := raddfZsign.
+Definition in_algE := in_algE.
+Definition linear0 := linear0.
+Definition linearN := linearN.
+Definition linearD := linearD.
+Definition linearB := linearB.
+Definition linear_sum := linear_sum.
+Definition linearMn := linearMn.
+Definition linearMNn := linearMNn.
+Definition linearP := linearP.
+Definition linearZ_LR := linearZ_LR.
+Definition linearZ := linearZ.
+Definition linearPZ := linearPZ.
+Definition linearZZ := linearZZ.
+Definition scalarP := scalarP.
+Definition scalarZ := scalarZ.
+Definition can2_linear := can2_linear.
+Definition bij_linear := bij_linear.
+Definition rmorph_alg := rmorph_alg.
+Definition lrmorphismP := lrmorphismP.
+Definition can2_lrmorphism := can2_lrmorphism.
+Definition bij_lrmorphism := bij_lrmorphism.
+
+Notation null_fun V := (null_fun V) (only parsing).
+Notation in_alg A := (in_alg_loc A).
+
+End Theory.
+
+Notation in_alg A := (in_alg_loc A).
+
+End GRing.
+
+Export Zmodule.Exports Ring.Exports Lmodule.Exports Lalgebra.Exports.
+Export Additive.Exports RMorphism.Exports Linear.Exports LRMorphism.Exports.
+Export ComRing.Exports Algebra.Exports UnitRing.Exports UnitAlgebra.Exports.
+Export ComUnitRing.Exports IntegralDomain.Exports Field.Exports.
+Export DecidableField.Exports ClosedField.Exports.
+Export Pred.Exports SubType.Exports.
+Notation QEdecFieldMixin := QEdecFieldMixin.
+
+Notation "0" := (zero _) : ring_scope.
+Notation "-%R" := (@opp _) : ring_scope.
+Notation "- x" := (opp x) : ring_scope.
+Notation "+%R" := (@add _).
+Notation "x + y" := (add x y) : ring_scope.
+Notation "x - y" := (add x (- y)) : ring_scope.
+Notation "x *+ n" := (natmul x n) : ring_scope.
+Notation "x *- n" := (opp (x *+ n)) : ring_scope.
+Notation "s `_ i" := (seq.nth 0%R s%R i) : ring_scope.
+Notation support := 0.-support.
+
+Notation "1" := (one _) : ring_scope.
+Notation "- 1" := (opp 1) : ring_scope.
+
+Notation "n %:R" := (natmul 1 n) : ring_scope.
+Notation "[ 'char' R ]" := (char (Phant R)) : ring_scope.
+Notation Frobenius_aut chRp := (Frobenius_aut chRp).
+Notation "*%R" := (@mul _).
+Notation "x * y" := (mul x y) : ring_scope.
+Notation "x ^+ n" := (exp x n) : ring_scope.
+Notation "x ^-1" := (inv x) : ring_scope.
+Notation "x ^- n" := (inv (x ^+ n)) : ring_scope.
+Notation "x / y" := (mul x y^-1) : ring_scope.
+
+Notation "*:%R" := (@scale _ _).
+Notation "a *: m" := (scale a m) : ring_scope.
+Notation "k %:A" := (scale k 1) : ring_scope.
+Notation "\0" := (null_fun _) : ring_scope.
+Notation "f \+ g" := (add_fun_head tt f g) : ring_scope.
+Notation "f \- g" := (sub_fun_head tt f g) : ring_scope.
+Notation "a \*: f" := (scale_fun_head tt a f) : ring_scope.
+Notation "x \*o f" := (mull_fun_head tt x f) : ring_scope.
+Notation "x \o* f" := (mulr_fun_head tt x f) : ring_scope.
+
+Notation "\sum_ ( i <- r | P ) F" :=
+ (\big[+%R/0%R]_(i <- r | P%B) F%R) : ring_scope.
+Notation "\sum_ ( i <- r ) F" :=
+ (\big[+%R/0%R]_(i <- r) F%R) : ring_scope.
+Notation "\sum_ ( m <= i < n | P ) F" :=
+ (\big[+%R/0%R]_(m <= i < n | P%B) F%R) : ring_scope.
+Notation "\sum_ ( m <= i < n ) F" :=
+ (\big[+%R/0%R]_(m <= i < n) F%R) : ring_scope.
+Notation "\sum_ ( i | P ) F" :=
+ (\big[+%R/0%R]_(i | P%B) F%R) : ring_scope.
+Notation "\sum_ i F" :=
+ (\big[+%R/0%R]_i F%R) : ring_scope.
+Notation "\sum_ ( i : t | P ) F" :=
+ (\big[+%R/0%R]_(i : t | P%B) F%R) (only parsing) : ring_scope.
+Notation "\sum_ ( i : t ) F" :=
+ (\big[+%R/0%R]_(i : t) F%R) (only parsing) : ring_scope.
+Notation "\sum_ ( i < n | P ) F" :=
+ (\big[+%R/0%R]_(i < n | P%B) F%R) : ring_scope.
+Notation "\sum_ ( i < n ) F" :=
+ (\big[+%R/0%R]_(i < n) F%R) : ring_scope.
+Notation "\sum_ ( i 'in' A | P ) F" :=
+ (\big[+%R/0%R]_(i in A | P%B) F%R) : ring_scope.
+Notation "\sum_ ( i 'in' A ) F" :=
+ (\big[+%R/0%R]_(i in A) F%R) : ring_scope.
+
+Notation "\prod_ ( i <- r | P ) F" :=
+ (\big[*%R/1%R]_(i <- r | P%B) F%R) : ring_scope.
+Notation "\prod_ ( i <- r ) F" :=
+ (\big[*%R/1%R]_(i <- r) F%R) : ring_scope.
+Notation "\prod_ ( m <= i < n | P ) F" :=
+ (\big[*%R/1%R]_(m <= i < n | P%B) F%R) : ring_scope.
+Notation "\prod_ ( m <= i < n ) F" :=
+ (\big[*%R/1%R]_(m <= i < n) F%R) : ring_scope.
+Notation "\prod_ ( i | P ) F" :=
+ (\big[*%R/1%R]_(i | P%B) F%R) : ring_scope.
+Notation "\prod_ i F" :=
+ (\big[*%R/1%R]_i F%R) : ring_scope.
+Notation "\prod_ ( i : t | P ) F" :=
+ (\big[*%R/1%R]_(i : t | P%B) F%R) (only parsing) : ring_scope.
+Notation "\prod_ ( i : t ) F" :=
+ (\big[*%R/1%R]_(i : t) F%R) (only parsing) : ring_scope.
+Notation "\prod_ ( i < n | P ) F" :=
+ (\big[*%R/1%R]_(i < n | P%B) F%R) : ring_scope.
+Notation "\prod_ ( i < n ) F" :=
+ (\big[*%R/1%R]_(i < n) F%R) : ring_scope.
+Notation "\prod_ ( i 'in' A | P ) F" :=
+ (\big[*%R/1%R]_(i in A | P%B) F%R) : ring_scope.
+Notation "\prod_ ( i 'in' A ) F" :=
+ (\big[*%R/1%R]_(i in A) F%R) : ring_scope.
+
+Canonical add_monoid.
+Canonical add_comoid.
+Canonical mul_monoid.
+Canonical mul_comoid.
+Canonical muloid.
+Canonical addoid.
+
+Canonical locked_additive.
+Canonical locked_rmorphism.
+Canonical locked_linear.
+Canonical locked_lrmorphism.
+Canonical idfun_additive.
+Canonical idfun_rmorphism.
+Canonical idfun_linear.
+Canonical idfun_lrmorphism.
+Canonical comp_additive.
+Canonical comp_rmorphism.
+Canonical comp_linear.
+Canonical comp_lrmorphism.
+Canonical opp_additive.
+Canonical opp_linear.
+Canonical scale_additive.
+Canonical scale_linear.
+Canonical null_fun_additive.
+Canonical null_fun_linear.
+Canonical scale_fun_additive.
+Canonical scale_fun_linear.
+Canonical add_fun_additive.
+Canonical add_fun_linear.
+Canonical sub_fun_additive.
+Canonical sub_fun_linear.
+Canonical mull_fun_additive.
+Canonical mull_fun_linear.
+Canonical mulr_fun_additive.
+Canonical mulr_fun_linear.
+Canonical Frobenius_aut_additive.
+Canonical Frobenius_aut_rmorphism.
+Canonical in_alg_additive.
+Canonical in_alg_rmorphism.
+
+Notation "R ^c" := (converse R) (at level 2, format "R ^c") : type_scope.
+Canonical converse_eqType.
+Canonical converse_choiceType.
+Canonical converse_zmodType.
+Canonical converse_ringType.
+Canonical converse_unitRingType.
+
+Notation "R ^o" := (regular R) (at level 2, format "R ^o") : type_scope.
+Canonical regular_eqType.
+Canonical regular_choiceType.
+Canonical regular_zmodType.
+Canonical regular_ringType.
+Canonical regular_lmodType.
+Canonical regular_lalgType.
+Canonical regular_comRingType.
+Canonical regular_algType.
+Canonical regular_unitRingType.
+Canonical regular_comUnitRingType.
+Canonical regular_unitAlgType.
+Canonical regular_idomainType.
+Canonical regular_fieldType.
+
+Canonical unit_keyed.
+Canonical unit_opprPred.
+Canonical unit_mulrPred.
+Canonical unit_smulrPred.
+Canonical unit_divrPred.
+Canonical unit_sdivrPred.
+
+Bind Scope term_scope with term.
+Bind Scope term_scope with formula.
+
+Notation "''X_' i" := (Var _ i) : term_scope.
+Notation "n %:R" := (NatConst _ n) : term_scope.
+Notation "0" := 0%:R%T : term_scope.
+Notation "1" := 1%:R%T : term_scope.
+Notation "x %:T" := (Const x) : term_scope.
+Infix "+" := Add : term_scope.
+Notation "- t" := (Opp t) : term_scope.
+Notation "t - u" := (Add t (- u)) : term_scope.
+Infix "*" := Mul : term_scope.
+Infix "*+" := NatMul : term_scope.
+Notation "t ^-1" := (Inv t) : term_scope.
+Notation "t / u" := (Mul t u^-1) : term_scope.
+Infix "^+" := Exp : term_scope.
+Infix "==" := Equal : term_scope.
+Notation "x != y" := (GRing.Not (x == y)) : term_scope.
+Infix "/\" := And : term_scope.
+Infix "\/" := Or : term_scope.
+Infix "==>" := Implies : term_scope.
+Notation "~ f" := (Not f) : term_scope.
+Notation "''exists' ''X_' i , f" := (Exists i f) : term_scope.
+Notation "''forall' ''X_' i , f" := (Forall i f) : term_scope.
+
+(* Lifting Structure from the codomain of finfuns. *)
+Section FinFunZmod.
+
+Variable (aT : finType) (rT : zmodType).
+Implicit Types f g : {ffun aT -> rT}.
+
+Definition ffun_zero := [ffun a : aT => (0 : rT)].
+Definition ffun_opp f := [ffun a => - f a].
+Definition ffun_add f g := [ffun a => f a + g a].
+
+Fact ffun_addA : associative ffun_add.
+Proof. by move=> f1 f2 f3; apply/ffunP=> a; rewrite !ffunE addrA. Qed.
+Fact ffun_addC : commutative ffun_add.
+Proof. by move=> f1 f2; apply/ffunP=> a; rewrite !ffunE addrC. Qed.
+Fact ffun_add0 : left_id ffun_zero ffun_add.
+Proof. by move=> f; apply/ffunP=> a; rewrite !ffunE add0r. Qed.
+Fact ffun_addN : left_inverse ffun_zero ffun_opp ffun_add.
+Proof. by move=> f; apply/ffunP=> a; rewrite !ffunE addNr. Qed.
+
+Definition ffun_zmodMixin :=
+ Zmodule.Mixin ffun_addA ffun_addC ffun_add0 ffun_addN.
+Canonical ffun_zmodType := Eval hnf in ZmodType _ ffun_zmodMixin.
+
+Section Sum.
+
+Variables (I : Type) (r : seq I) (P : pred I) (F : I -> {ffun aT -> rT}).
+
+Lemma sum_ffunE x : (\sum_(i <- r | P i) F i) x = \sum_(i <- r | P i) F i x.
+Proof. by elim/big_rec2: _ => // [|i _ y _ <-]; rewrite !ffunE. Qed.
+
+Lemma sum_ffun :
+ \sum_(i <- r | P i) F i = [ffun x => \sum_(i <- r | P i) F i x].
+Proof. by apply/ffunP=> i; rewrite sum_ffunE ffunE. Qed.
+
+End Sum.
+
+Lemma ffunMnE f n x : (f *+ n) x = f x *+ n.
+Proof. by rewrite -[n]card_ord -!sumr_const sum_ffunE. Qed.
+
+End FinFunZmod.
+Canonical exp_zmodType (M : zmodType) n := [zmodType of M ^ n].
+
+Section FinFunRing.
+
+(* As rings require 1 != 0 in order to lift a ring structure over finfuns *)
+(* we need evidence that the domain is non-empty. *)
+
+Variable (aT : finType) (R : ringType) (a : aT).
+
+Definition ffun_one : {ffun aT -> R} := [ffun => 1].
+Definition ffun_mul (f g : {ffun aT -> R}) := [ffun x => f x * g x].
+
+Fact ffun_mulA : associative ffun_mul.
+Proof. by move=> f1 f2 f3; apply/ffunP=> i; rewrite !ffunE mulrA. Qed.
+Fact ffun_mul_1l : left_id ffun_one ffun_mul.
+Proof. by move=> f; apply/ffunP=> i; rewrite !ffunE mul1r. Qed.
+Fact ffun_mul_1r : right_id ffun_one ffun_mul.
+Proof. by move=> f; apply/ffunP=> i; rewrite !ffunE mulr1. Qed.
+Fact ffun_mul_addl : left_distributive ffun_mul (@ffun_add _ _).
+Proof. by move=> f1 f2 f3; apply/ffunP=> i; rewrite !ffunE mulrDl. Qed.
+Fact ffun_mul_addr : right_distributive ffun_mul (@ffun_add _ _).
+Proof. by move=> f1 f2 f3; apply/ffunP=> i; rewrite !ffunE mulrDr. Qed.
+Fact ffun1_nonzero : ffun_one != 0.
+Proof. by apply/eqP => /ffunP/(_ a)/eqP; rewrite !ffunE oner_eq0. Qed.
+
+Definition ffun_ringMixin :=
+ RingMixin ffun_mulA ffun_mul_1l ffun_mul_1r ffun_mul_addl ffun_mul_addr
+ ffun1_nonzero.
+Definition ffun_ringType :=
+ Eval hnf in RingType {ffun aT -> R} ffun_ringMixin.
+
+End FinFunRing.
+
+Section FinFunComRing.
+
+Variable (aT : finType) (R : comRingType) (a : aT).
+
+Fact ffun_mulC : commutative (@ffun_mul aT R).
+Proof. by move=> f1 f2; apply/ffunP=> i; rewrite !ffunE mulrC. Qed.
+
+Definition ffun_comRingType :=
+ Eval hnf in ComRingType (ffun_ringType R a) ffun_mulC.
+
+End FinFunComRing.
+
+Section FinFunLmod.
+
+Variable (R : ringType) (aT : finType) (rT : lmodType R).
+
+Implicit Types f g : {ffun aT -> rT}.
+
+Definition ffun_scale k f := [ffun a => k *: f a].
+
+Fact ffun_scaleA k1 k2 f :
+ ffun_scale k1 (ffun_scale k2 f) = ffun_scale (k1 * k2) f.
+Proof. by apply/ffunP=> a; rewrite !ffunE scalerA. Qed.
+Fact ffun_scale1 : left_id 1 ffun_scale.
+Proof. by move=> f; apply/ffunP=> a; rewrite !ffunE scale1r. Qed.
+Fact ffun_scale_addr k : {morph (ffun_scale k) : x y / x + y}.
+Proof. by move=> f g; apply/ffunP=> a; rewrite !ffunE scalerDr. Qed.
+Fact ffun_scale_addl u : {morph (ffun_scale)^~ u : k1 k2 / k1 + k2}.
+Proof. by move=> k1 k2; apply/ffunP=> a; rewrite !ffunE scalerDl. Qed.
+
+Definition ffun_lmodMixin :=
+ LmodMixin ffun_scaleA ffun_scale1 ffun_scale_addr ffun_scale_addl.
+Canonical ffun_lmodType :=
+ Eval hnf in LmodType R {ffun aT -> rT} ffun_lmodMixin.
+
+End FinFunLmod.
+Canonical exp_lmodType (R : ringType) (M : lmodType R) n :=
+ [lmodType R of M ^ n].
+
+(* External direct product. *)
+Section PairZmod.
+
+Variables M1 M2 : zmodType.
+
+Definition opp_pair (x : M1 * M2) := (- x.1, - x.2).
+Definition add_pair (x y : M1 * M2) := (x.1 + y.1, x.2 + y.2).
+
+Fact pair_addA : associative add_pair.
+Proof. by move=> x y z; congr (_, _); apply: addrA. Qed.
+
+Fact pair_addC : commutative add_pair.
+Proof. by move=> x y; congr (_, _); apply: addrC. Qed.
+
+Fact pair_add0 : left_id (0, 0) add_pair.
+Proof. by case=> x1 x2; congr (_, _); apply: add0r. Qed.
+
+Fact pair_addN : left_inverse (0, 0) opp_pair add_pair.
+Proof. by move=> x; congr (_, _); apply: addNr. Qed.
+
+Definition pair_zmodMixin := ZmodMixin pair_addA pair_addC pair_add0 pair_addN.
+Canonical pair_zmodType := Eval hnf in ZmodType (M1 * M2) pair_zmodMixin.
+
+End PairZmod.
+
+Section PairRing.
+
+Variables R1 R2 : ringType.
+
+Definition mul_pair (x y : R1 * R2) := (x.1 * y.1, x.2 * y.2).
+
+Fact pair_mulA : associative mul_pair.
+Proof. by move=> x y z; congr (_, _); apply: mulrA. Qed.
+
+Fact pair_mul1l : left_id (1, 1) mul_pair.
+Proof. by case=> x1 x2; congr (_, _); apply: mul1r. Qed.
+
+Fact pair_mul1r : right_id (1, 1) mul_pair.
+Proof. by case=> x1 x2; congr (_, _); apply: mulr1. Qed.
+
+Fact pair_mulDl : left_distributive mul_pair +%R.
+Proof. by move=> x y z; congr (_, _); apply: mulrDl. Qed.
+
+Fact pair_mulDr : right_distributive mul_pair +%R.
+Proof. by move=> x y z; congr (_, _); apply: mulrDr. Qed.
+
+Fact pair_one_neq0 : (1, 1) != 0 :> R1 * R2.
+Proof. by rewrite xpair_eqE oner_eq0. Qed.
+
+Definition pair_ringMixin :=
+ RingMixin pair_mulA pair_mul1l pair_mul1r pair_mulDl pair_mulDr pair_one_neq0.
+Canonical pair_ringType := Eval hnf in RingType (R1 * R2) pair_ringMixin.
+
+End PairRing.
+
+Section PairComRing.
+
+Variables R1 R2 : comRingType.
+
+Fact pair_mulC : commutative (@mul_pair R1 R2).
+Proof. by move=> x y; congr (_, _); apply: mulrC. Qed.
+
+Canonical pair_comRingType := Eval hnf in ComRingType (R1 * R2) pair_mulC.
+
+End PairComRing.
+
+Section PairLmod.
+
+Variables (R : ringType) (V1 V2 : lmodType R).
+
+Definition scale_pair a (v : V1 * V2) : V1 * V2 := (a *: v.1, a *: v.2).
+
+Fact pair_scaleA a b u : scale_pair a (scale_pair b u) = scale_pair (a * b) u.
+Proof. by congr (_, _); apply: scalerA. Qed.
+
+Fact pair_scale1 u : scale_pair 1 u = u.
+Proof. by case: u => u1 u2; congr (_, _); apply: scale1r. Qed.
+
+Fact pair_scaleDr : right_distributive scale_pair +%R.
+Proof. by move=> a u v; congr (_, _); apply: scalerDr. Qed.
+
+Fact pair_scaleDl u : {morph scale_pair^~ u: a b / a + b}.
+Proof. by move=> a b; congr (_, _); apply: scalerDl. Qed.
+
+Definition pair_lmodMixin :=
+ LmodMixin pair_scaleA pair_scale1 pair_scaleDr pair_scaleDl.
+Canonical pair_lmodType := Eval hnf in LmodType R (V1 * V2) pair_lmodMixin.
+
+End PairLmod.
+
+Section PairLalg.
+
+Variables (R : ringType) (A1 A2 : lalgType R).
+
+Fact pair_scaleAl a (u v : A1 * A2) : a *: (u * v) = (a *: u) * v.
+Proof. by congr (_, _); apply: scalerAl. Qed.
+Canonical pair_lalgType := Eval hnf in LalgType R (A1 * A2) pair_scaleAl.
+
+End PairLalg.
+
+Section PairAlg.
+
+Variables (R : comRingType) (A1 A2 : algType R).
+
+Fact pair_scaleAr a (u v : A1 * A2) : a *: (u * v) = u * (a *: v).
+Proof. by congr (_, _); apply: scalerAr. Qed.
+Canonical pair_algType := Eval hnf in AlgType R (A1 * A2) pair_scaleAr.
+
+End PairAlg.
+
+Section PairUnitRing.
+
+Variables R1 R2 : unitRingType.
+
+Definition pair_unitr :=
+ [qualify a x : R1 * R2 | (x.1 \is a GRing.unit) && (x.2 \is a GRing.unit)].
+Definition pair_invr x :=
+ if x \is a pair_unitr then (x.1^-1, x.2^-1) else x.
+
+Lemma pair_mulVl : {in pair_unitr, left_inverse 1 pair_invr *%R}.
+Proof.
+rewrite /pair_invr=> x; case: ifP => // /andP[Ux1 Ux2] _.
+by congr (_, _); apply: mulVr.
+Qed.
+
+Lemma pair_mulVr : {in pair_unitr, right_inverse 1 pair_invr *%R}.
+Proof.
+rewrite /pair_invr=> x; case: ifP => // /andP[Ux1 Ux2] _.
+by congr (_, _); apply: mulrV.
+Qed.
+
+Lemma pair_unitP x y : y * x = 1 /\ x * y = 1 -> x \is a pair_unitr.
+Proof.
+case=> [[y1x y2x] [x1y x2y]]; apply/andP.
+by split; apply/unitrP; [exists y.1 | exists y.2].
+Qed.
+
+Lemma pair_invr_out : {in [predC pair_unitr], pair_invr =1 id}.
+Proof. by rewrite /pair_invr => x /negPf/= ->. Qed.
+
+Definition pair_unitRingMixin :=
+ UnitRingMixin pair_mulVl pair_mulVr pair_unitP pair_invr_out.
+Canonical pair_unitRingType :=
+ Eval hnf in UnitRingType (R1 * R2) pair_unitRingMixin.
+
+End PairUnitRing.
+
+Canonical pair_comUnitRingType (R1 R2 : comUnitRingType) :=
+ Eval hnf in [comUnitRingType of R1 * R2].
+
+Canonical pair_unitAlgType (R : comUnitRingType) (A1 A2 : unitAlgType R) :=
+ Eval hnf in [unitAlgType R of A1 * A2].
+
+(* begin hide *)
+
+(* Testing subtype hierarchy
+Section Test0.
+
+Variables (T : choiceType) (S : predPredType T).
+
+Inductive B := mkB x & x \in S.
+Definition vB u := let: mkB x _ := u in x.
+
+Canonical B_subType := [subType for vB].
+Definition B_eqMixin := [eqMixin of B by <:].
+Canonical B_eqType := EqType B B_eqMixin.
+Definition B_choiceMixin := [choiceMixin of B by <:].
+Canonical B_choiceType := ChoiceType B B_choiceMixin.
+
+End Test0.
+
+Section Test1.
+
+Variables (R : unitRingType) (S : pred R).
+Variables (ringS : divringPred S) (kS : keyed_pred ringS).
+
+Definition B_zmodMixin := [zmodMixin of B kS by <:].
+Canonical B_zmodType := ZmodType (B kS) B_zmodMixin.
+Definition B_ringMixin := [ringMixin of B kS by <:].
+Canonical B_ringType := RingType (B kS) B_ringMixin.
+Definition B_unitRingMixin := [unitRingMixin of B kS by <:].
+Canonical B_unitRingType := UnitRingType (B kS) B_unitRingMixin.
+
+End Test1.
+
+Section Test2.
+
+Variables (R : comUnitRingType) (A : unitAlgType R) (S : pred A).
+Variables (algS : divalgPred S) (kS : keyed_pred algS).
+
+Definition B_lmodMixin := [lmodMixin of B kS by <:].
+Canonical B_lmodType := LmodType R (B kS) B_lmodMixin.
+Definition B_lalgMixin := [lalgMixin of B kS by <:].
+Canonical B_lalgType := LalgType R (B kS) B_lalgMixin.
+Definition B_algMixin := [algMixin of B kS by <:].
+Canonical B_algType := AlgType R (B kS) B_algMixin.
+Canonical B_unitAlgType := [unitAlgType R of B kS].
+
+End Test2.
+
+Section Test3.
+
+Variables (F : fieldType) (S : pred F).
+Variables (ringS : divringPred S) (kS : keyed_pred ringS).
+
+Definition B_comRingMixin := [comRingMixin of B kS by <:].
+Canonical B_comRingType := ComRingType (B kS) B_comRingMixin.
+Canonical B_comUnitRingType := [comUnitRingType of B kS].
+Definition B_idomainMixin := [idomainMixin of B kS by <:].
+Canonical B_idomainType := IdomainType (B kS) B_idomainMixin.
+Definition B_fieldMixin := [fieldMixin of B kS by <:].
+Canonical B_fieldType := FieldType (B kS) B_fieldMixin.
+
+End Test3.
+
+*)
+
+(* end hide *)