module Soat.FirstOrder.Algebra import Data.Morphism.Indexed import Data.Setoid.Indexed import public Soat.Data.Product import Soat.FirstOrder.Signature %default total %hide Control.Relation.Equivalence public export 0 algebraOver : (sig : Signature) -> (U : sig.T -> Type) -> Type algebraOver sig x = {t : sig.T} -> (op : Op sig t) -> x ^ op.arity -> x t public export record RawAlgebra (0 sig : Signature) where constructor MkRawAlgebra 0 U : sig.T -> Type sem : sig `algebraOver` U public export record RawSetoidAlgebra (0 sig : Signature) where constructor MkRawSetoidAlgebra raw : RawAlgebra sig 0 relation : IRel raw.U public export record IsAlgebra (0 sig : Signature) (0 a : RawAlgebra sig) (0 rel : IRel a.U) where constructor MkIsAlgebra equivalence : IEquivalence a.U rel semCong : {t : sig.T} -> (op : Op sig t) -> {tms, tms' : a.U ^ op.arity} -> Pointwise rel tms tms' -> rel t (a.sem op tms) (a.sem op tms') public export record Algebra (0 sig : Signature) where constructor MkAlgebra raw : RawAlgebra sig 0 relation : IRel raw.U algebra : IsAlgebra sig raw relation public export (.setoid) : Algebra sig -> ISetoid sig.T (.setoid) a = MkISetoid a.raw.U a.relation a.algebra.equivalence public export (.rawSetoid) : Algebra sig -> RawSetoidAlgebra sig (.rawSetoid) a = MkRawSetoidAlgebra a.raw a.relation public export record IsHomomorphism {0 sig : Signature} (a, b : Algebra sig) (f : (t : sig.T) -> a.raw.U t -> b.raw.U t) where constructor MkIsHomomorphism cong : (t : sig.T) -> {tm, tm' : a.raw.U t} -> a.relation t tm tm' -> b.relation t (f t tm) (f t tm') semHomo : {t : sig.T} -> (op : Op sig t) -> (tms : a.raw.U ^ op.arity) -> b.relation t (f t (a.raw.sem op tms)) (b.raw.sem op (map f tms)) public export record Homomorphism {0 sig : Signature} (a, b : Algebra sig) where constructor MkHomomorphism func : IFunc a.raw.U b.raw.U homo : IsHomomorphism a b func public export idIsHomo : {a : Algebra sig} -> IsHomomorphism a a (\_ => Basics.id) idIsHomo = MkIsHomomorphism (\_ => id) (\op, tms => (a.algebra.equivalence _).equalImpliesEq $ sym $ cong (a.raw.sem op) $ mapId tms) public export idHomo : {a : Algebra sig} -> Homomorphism a a idHomo = MkHomomorphism _ idIsHomo public export compIsHomo : {a, b, c : Algebra sig} -> {f : IFunc b.raw.U c.raw.U} -> {g : IFunc a.raw.U b.raw.U} -> IsHomomorphism b c f -> IsHomomorphism a b g -> IsHomomorphism a c (\i => f i . g i) compIsHomo fHomo gHomo = MkIsHomomorphism (\t => fHomo.cong t . gHomo.cong t) (\op, tms => (c.algebra.equivalence _).transitive (fHomo.cong _ $ gHomo.semHomo op tms) $ (c.algebra.equivalence _).transitive (fHomo.semHomo op (map g tms)) $ (c.algebra.equivalence _).equalImpliesEq $ sym $ cong (c.raw.sem op) $ mapComp tms) public export compHomo : {a, b, c : Algebra sig} -> Homomorphism b c -> Homomorphism a b -> Homomorphism a c compHomo f g = MkHomomorphism _ $ compIsHomo f.homo g.homo