Section GaussIntegers.
(** First we define a predicate for the algebraic numbers which are gauss integers. *)
Definition gaussInteger := [qualify a x | ('Re x \in Cint) && ('Im x \in Cint)].
(**  There follows the boilerplate to use the proof GI_subring in order to canonically provide a subring structure to the predicate gaussInteger.  *)
Fact GI_key : pred_key gaussInteger. Proof. by []. Qed.
Canonical GI_keyed := KeyedQualifier GI_key.
Canonical GI_opprPred := OpprPred GI_subring.
Canonical GI_addrPred := AddrPred GI_subring.
Canonical GI_mulrPred := MulrPred GI_subring.
Canonical GI_zmodPred := ZmodPred GI_subring.
Canonical GI_semiringPred := SemiringPred GI_subring.
Canonical GI_smulrPred := SmulrPred GI_subring.
Canonical GI_subringPred := SubringPred GI_subring.
(**  Finally, we define the type of Gauss Integer, as a sigma type of algebraic numbers. We soon prove that this is in fact a sub type.  *)
Record GI := GIof {
algGI : algC;
algGIP : algGI \is a gaussInteger }.
(** We make the defining property of GI a Hint *)
Hint Resolve algGIP : core.
(**  We provide the subtype property.  - This makes it possible to use the generic operator "val" to get an algC from a Gauss Integer.  *)
Canonical GI_subType := [subType for algGI].
Fact unitGIP (x y : GI) : y * x = 1 -> unitGI x.
Fact unitGI_out : {in [predC unitGI], invGI =1 id}.
Definition GI_comUnitRingMixin :=
ComUnitRingMixin mulGIr unitGIP unitGI_out.
Canonical GI_unitRingType := UnitRingType GI GI_comUnitRingMixin.
Canonical GI_comUnitRingType := [comUnitRingType of GI].
Fact GI_idomainAxiom (x y : GI) : x * y = 0 -> (x == 0) || (y == 0).
Canonical GI_idomainType :=
Eval hnf in IdomainType GI GI_idomainAxiom.
Fact divGI_subproof (x y : int) : x%:~R + 'i * y%:~R \is a gaussInteger.
Definition modGI (x y : GI) : GI := x - (x %/ y)%GI * y.
Notation " x %% y " := (modGI x y) : GI_scope.

Lemma modGI0 x : x %% 0 = x.