MathClasses.interfaces.abstract_algebra

Require Export
  canonical_names util decision propholds workarounds setoid_tactics.


Class Setoid A {Ae : Equiv A} : Prop := setoid_eq :> Equivalence (@equiv A Ae).

Class StrongSetoid A {Ae : Equiv A} `{Aap : Apart A} : Prop :=
  { strong_setoid_irreflexive :> Irreflexive (≶)
  ; strong_setoid_symmetric :> Symmetric (≶)
  ; strong_setoid_cotrans :> CoTransitive (≶)
  ; tight_apart : x y, ¬x y x = y }.

Arguments tight_apart {A Ae Aap StrongSetoid} _ _.

Section setoid_morphisms.
  Context {A B} {Ae : Equiv A} {Aap : Apart A} {Be : Equiv B} {Bap : Apart B} (f : A B).

  Class Setoid_Morphism :=
    { setoidmor_a : Setoid A
    ; setoidmor_b : Setoid B
    ; sm_proper :> Proper ((=) ==> (=)) f }.

  Class StrongSetoid_Morphism :=
    { strong_setoidmor_a : StrongSetoid A
    ; strong_setoidmor_b : StrongSetoid B
    ; strong_extensionality : x y, f x f y x y }.
End setoid_morphisms.

Arguments sm_proper {A B Ae Be f Setoid_Morphism} _ _ _.
Hint Extern 4 (?f _ = ?f _) ⇒ eapply (sm_proper (f:=f)).

Section setoid_binary_morphisms.
  Context {A B C} {Ae: Equiv A} {Aap: Apart A}
    {Be: Equiv B} {Bap : Apart B} {Ce: Equiv C} {Cap : Apart C} (f : A B C).

  Class StrongSetoid_BinaryMorphism :=
    { strong_binary_setoidmor_a : StrongSetoid A
    ; strong_binary_setoidmor_b : StrongSetoid B
    ; strong_binary_setoidmor_c : StrongSetoid C
    ; strong_binary_extensionality : x₁ y₁ x₂ y₂, f x₁ y₁ f x₂ y₂ x₁ x₂ y₁ y₂ }.
End setoid_binary_morphisms.

Section upper_classes.
  Context A {Ae : Equiv A}.

  Class SemiGroup {Aop: SgOp A} : Prop :=
    { sg_setoid :> Setoid A
    ; sg_ass :> Associative (&)
    ; sg_op_proper :> Proper ((=) ==> (=) ==> (=)) (&) }.

  Class CommutativeSemiGroup {Aop : SgOp A} : Prop :=
    { comsg_setoid :> @SemiGroup Aop
    ; comsg_ass :> Commutative (&) }.

  Class SemiLattice {Aop : SgOp A} : Prop :=
    { semilattice_sg :> @CommutativeSemiGroup Aop
    ; semilattice_idempotent :> BinaryIdempotent (&)}.

  Class Monoid {Aop : SgOp A} {Aunit : MonUnit A} : Prop :=
    { monoid_semigroup :> SemiGroup
    ; monoid_left_id :> LeftIdentity (&) mon_unit
    ; monoid_right_id :> RightIdentity (&) mon_unit }.

  Class CommutativeMonoid {Aop Aunit} : Prop :=
    { commonoid_mon :> @Monoid Aop Aunit
    ; commonoid_commutative :> Commutative (&) }.

  Class Group {Aop Aunit} {Anegate : Negate A} : Prop :=
    { group_monoid :> @Monoid Aop Aunit
    ; negate_proper :> Setoid_Morphism (-)
    ; negate_l :> LeftInverse (&) (-) mon_unit
    ; negate_r :> RightInverse (&) (-) mon_unit }.

  Class BoundedSemiLattice {Aop Aunit} : Prop :=
    { bounded_semilattice_mon :> @CommutativeMonoid Aop Aunit
    ; bounded_semilattice_idempotent :> BinaryIdempotent (&)}.

  Class AbGroup {Aop Aunit Anegate} : Prop :=
    { abgroup_group :> @Group Aop Aunit Anegate
    ; abgroup_commutative :> Commutative (&) }.

  Context {Aplus : Plus A} {Amult : Mult A} {Azero : Zero A} {Aone : One A}.

  Class SemiRing : Prop :=
    { semiplus_monoid :> @CommutativeMonoid plus_is_sg_op zero_is_mon_unit
    ; semimult_monoid :> @CommutativeMonoid mult_is_sg_op one_is_mon_unit
    ; semiring_distr :> LeftDistribute (.*.) (+)
    ; semiring_left_absorb :> LeftAbsorb (.*.) 0 }.

  Context {Anegate : Negate A}.

  Class Ring : Prop :=
    { ring_group :> @AbGroup plus_is_sg_op zero_is_mon_unit _
    ; ring_monoid :> @CommutativeMonoid mult_is_sg_op one_is_mon_unit
    ; ring_dist :> LeftDistribute (.*.) (+) }.


  Class IntegralDomain : Prop :=
    { intdom_ring : Ring
    ; intdom_nontrivial : PropHolds (1 0)
    ; intdom_nozeroes :> NoZeroDivisors A }.

  Class Field {Aap: Apart A} {Arecip: Recip A} : Prop :=
    { field_ring :> Ring
    ; field_strongsetoid :> StrongSetoid A
    ; field_plus_ext :> StrongSetoid_BinaryMorphism (+)
    ; field_mult_ext :> StrongSetoid_BinaryMorphism (.*.)
    ; field_nontrivial : PropHolds (1 0)
    ; recip_proper :> Setoid_Morphism (//)
    ; recip_inverse : x, `x // x = 1 }.

  Class DecField {Adec_recip : DecRecip A} : Prop :=
    { decfield_ring :> Ring
    ; decfield_nontrivial : PropHolds (1 0)
    ; dec_recip_proper :> Setoid_Morphism (/)
    ; dec_recip_0 : /0 = 0
    ; dec_recip_inverse : x, x 0 x / x = 1 }.
End upper_classes.

Hint Extern 4 (PropHolds (1 0)) ⇒ eapply @intdom_nontrivial : typeclass_instances.
Hint Extern 5 (PropHolds (1 0)) ⇒ eapply @field_nontrivial : typeclass_instances.
Hint Extern 5 (PropHolds (1 0)) ⇒ eapply @decfield_nontrivial : typeclass_instances.

Hint Extern 10 (Ring _) ⇒ apply @intdom_ring : typeclass_instances.

Arguments recip_inverse {A Ae Aplus Amult Azero Aone Anegate Aap Arecip Field} _.
Arguments dec_recip_inverse {A Ae Aplus Amult Azero Aone Anegate Adec_recip DecField} _ _.
Arguments dec_recip_0 {A Ae Aplus Amult Azero Aone Anegate Adec_recip DecField}.
Arguments sg_op_proper {A Ae Aop SemiGroup} _ _ _ _ _ _.

Section lattice.
  Context A `{Ae: Equiv A} {Ajoin: Join A} {Ameet: Meet A} `{Abottom : Bottom A}.

  Class JoinSemiLattice : Prop :=
    join_semilattice :> @SemiLattice A Ae join_is_sg_op.
  Class BoundedJoinSemiLattice : Prop :=
    bounded_join_semilattice :> @BoundedSemiLattice A Ae join_is_sg_op bottom_is_mon_unit.
  Class MeetSemiLattice : Prop :=
    meet_semilattice :> @SemiLattice A Ae meet_is_sg_op.

  Class Lattice : Prop :=
    { lattice_join :> JoinSemiLattice
    ; lattice_meet :> MeetSemiLattice
    ; join_meet_absorption :> Absorption (⊔) (⊓)
    ; meet_join_absorption :> Absorption (⊓) (⊔)}.

  Class DistributiveLattice : Prop :=
    { distr_lattice_lattice :> Lattice
    ; join_meet_distr_l :> LeftDistribute (⊔) (⊓) }.
End lattice.

Class Category O `{!Arrows O} `{ x y: O, Equiv (x y)} `{!CatId O} `{!CatComp O}: Prop :=
  { arrow_equiv :> x y, Setoid (x y)
  ; comp_proper :> x y z, Proper ((=) ==> (=) ==> (=)) (comp x y z)
  ; comp_assoc :> ArrowsAssociative O
  ; id_l :> x y, LeftIdentity (comp x y y) cat_id
  ; id_r :> x y, RightIdentity (comp x x y) cat_id }.

Arguments comp_assoc {O arrows eq CatId CatComp Category w x y z} _ _ _ : rename.

Section morphism_classes.
  Context {A B} {Ae : Equiv A} {Be : Equiv B}.

  Class SemiGroup_Morphism {Aop Bop} (f : A B) :=
    { sgmor_a : @SemiGroup A Ae Aop
    ; sgmor_b : @SemiGroup B Be Bop
    ; sgmor_setmor :> Setoid_Morphism f
    ; preserves_sg_op : x y, f (x & y) = f x & f y }.

  Class JoinSemiLattice_Morphism {Ajoin Bjoin} (f : A B) :=
    { join_slmor_a : @JoinSemiLattice A Ae Ajoin
    ; join_slmor_b : @JoinSemiLattice B Be Bjoin
    ; join_slmor_sgmor :> @SemiGroup_Morphism join_is_sg_op join_is_sg_op f }.

  Class MeetSemiLattice_Morphism {Ameet Bmeet} (f : A B) :=
    { meet_slmor_a : @MeetSemiLattice A Ae Ameet
    ; meet_slmor_b : @MeetSemiLattice B Be Bmeet
    ; meet_slmor_sgmor :> @SemiGroup_Morphism meet_is_sg_op meet_is_sg_op f }.

  Class Monoid_Morphism {Aunit Bunit Aop Bop} (f : A B) :=
    { monmor_a : @Monoid A Ae Aop Aunit
    ; monmor_b : @Monoid B Be Bop Bunit
    ; monmor_sgmor :> SemiGroup_Morphism f
    ; preserves_mon_unit : f mon_unit = mon_unit }.

  Class BoundedJoinSemiLattice_Morphism {Abottom Bbottom Ajoin Bjoin} (f : A B) :=
    { bounded_join_slmor_a : @BoundedJoinSemiLattice A Ae Ajoin Abottom
    ; bounded_join_slmor_b : @BoundedJoinSemiLattice B Be Bjoin Bbottom
    ; bounded_join_slmor_monmor :> @Monoid_Morphism bottom_is_mon_unit bottom_is_mon_unit join_is_sg_op join_is_sg_op f }.

  Class SemiRing_Morphism {Aplus Amult Azero Aone Bplus Bmult Bzero Bone} (f : A B) :=
    { semiringmor_a : @SemiRing A Ae Aplus Amult Azero Aone
    ; semiringmor_b : @SemiRing B Be Bplus Bmult Bzero Bone
    ; semiringmor_plus_mor :> @Monoid_Morphism zero_is_mon_unit zero_is_mon_unit plus_is_sg_op plus_is_sg_op f
    ; semiringmor_mult_mor :> @Monoid_Morphism one_is_mon_unit one_is_mon_unit mult_is_sg_op mult_is_sg_op f }.

  Class Lattice_Morphism {Ajoin Ameet Bjoin Bmeet} (f : A B) :=
    { latticemor_a : @Lattice A Ae Ajoin Ameet
    ; latticemor_b : @Lattice B Be Bjoin Bmeet
    ; latticemor_join_mor :> JoinSemiLattice_Morphism f
    ; latticemor_meet_mor :> MeetSemiLattice_Morphism f }.

  Context {Aap : Apart A} {Bap : Apart B}.
  Class StrongSemiRing_Morphism {Aplus Amult Azero Aone Bplus Bmult Bzero Bone} (f : A B) :=
    { strong_semiringmor_sr_mor :> @SemiRing_Morphism Aplus Amult Azero Aone Bplus Bmult Bzero Bone f
    ; strong_semiringmor_strong_mor :> StrongSetoid_Morphism f }.
End morphism_classes.

Section jections.
  Context {A B} {Ae : Equiv A} {Aap : Apart A}
    {Be : Equiv B} {Bap : Apart B} (f : A B) `{inv : !Inverse f}.

  Class StrongInjective : Prop :=
    { strong_injective : x y, x y f x f y
    ; strong_injective_mor : StrongSetoid_Morphism f }.

  Class Injective : Prop :=
    { injective : x y, f x = f y x = y
    ; injective_mor : Setoid_Morphism f }.

  Class Surjective : Prop :=
    { surjective : f (f ⁻¹) = id
    ; surjective_mor : Setoid_Morphism f }.

  Class Bijective : Prop :=
    { bijective_injective :> Injective
    ; bijective_surjective :> Surjective }.
End jections.