gasp-1.4.0.0: Algebra/Category/Laws.hs
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE FunctionalDependencies #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE EmptyCase #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE ConstrainedClassMethods #-}
{-# LANGUAGE DefaultSignatures #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE QuantifiedConstraints #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE StandaloneKindSignatures #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE PolyKinds #-}
module Algebra.Category.Laws where
import qualified Algebra.CategoryRecords as R
-- import Algebra.CategoryRecords (MonoidalRec(MonoidalRec))
import Algebra.Category
import Algebra.Category.Op
import Algebra.Classes (nameLaw, TestEqual(..), product)
import Algebra.Category.Objects
import Data.Kind
import Data.Constraint
import Test.QuickCheck
import Prelude (Show(..),($))
law_id_comp :: forall {k} (f :: k -> k -> Type) a b. (Category f, TestEqual (f a b), O2 f a b) => f a b -> Property
law_id_comp n = nameLaw "id/comp" (id . n =.= n)
forallMorphism' :: forall f x i. TestableCat x i (Obj f) f -> (forall a b. (O2 f a b, TT f a b) => f a b -> Property) -> Property
forallMorphism' (TestableCat {..}) p
= genObj (\t1 ->
genObj (\t2 ->
genMorph' t1 t2 (\f -> p f)))
law_comp_id :: forall {k} (f :: k -> k -> Type) a b. (Category f, TestEqual (f a b), O2 f a b) => f a b -> Property
law_comp_id n = nameLaw "comp/id" (n . id =.= n)
law_comp_assoc :: forall {k} (f :: k -> k -> Type) a b c d. (Category f, TestEqual (f a d), O4 f a b c d) => f c d -> f b c -> f a b -> Property
law_comp_assoc n m o = nameLaw "comp/assoc" (n . (m . o) =.= (n . m) . o)
laws_category :: forall f x i. (Category f) => TestableCat x i (Obj f) f -> Property
laws_category tc@TestableCat {..}
= product [forallMorphism' @f tc (\f -> property (law_id_comp f))
,forallMorphism' @f tc (\f -> property (law_comp_id f))
,genObj $ \t1 -> genObj $ \t2 -> genObj $ \t3 -> genObj $ \t4 ->
genMorph t1 t2 $ \ h -> genMorph t2 t3 $ \ g -> genMorph t3 t4 $ \ f ->
(f . (g . h) =.= (f . g) . h) \\ getTestable t1 t4]
type TT f x y = TestEqual (f x y)
type GenObj obj o f = ((forall a. obj a => o a -> Property) -> Property)
data TestableCat x i obj f = forall o. TestableCat
{genObj :: GenObj obj o f
,genMorph' :: forall a b. o a -> o b -> (TT f a b => f a b -> Property) -> Property
,genMorph :: forall a b. o a -> o b -> (f a b -> Property) -> Property
,getTestable :: forall a b. o a -> o b -> Dict (TT f a b)
,getTestable' :: forall a. o a -> Dict (TT f a a)
,(×) :: forall a b. o a -> o b -> o (a `x` b)
,unitObj :: o i
}
testableCat :: forall f x i o obj. GenObj obj o f -> (forall a b. o a -> o b -> (f a b -> Property) -> Property) -> ( forall a b. o a -> o b -> Dict (TT f a b)) -> (forall a b. o a -> o b -> o (x a b)) -> o i -> TestableCat x i obj f
testableCat genObj genMorph getTestable (×) unitObj = TestableCat{..}
where genMorph' :: forall a b. o a -> o b -> (TT f a b => f a b -> Property) -> Property
genMorph' a b k = genMorph a b $ \f -> k f \\ getTestable a b
getTestable' :: forall a. o a -> Dict (TT f a a)
getTestable' a = getTestable a a
law_parallel_composition :: forall {k} {cat :: k -> k -> Type}
{x :: k -> k -> k} {a :: k} {c :: k} {b1 :: k} {b2 :: k}
{b3 :: k} {d :: k} {i :: k} obj.
(obj (x a c), obj (x b1 b2), obj (x b3 d), obj a,
obj b1, obj b3, obj c, obj b2, obj d, Category cat, Obj cat ~ obj,
TestEqual (cat (x a c) (x b3 d))) =>
R.MonoidalRec x i obj cat -> cat b1 b3 -> cat b2 d -> cat a b1 -> cat c b2 -> Property
law_parallel_composition R.MonoidalRec{..} e f g h = nameLaw "cross-comp" ((e ⊗ f) ∘ (g ⊗ h) =.= (e ∘ g) ⊗ (f ∘ h))
law_assoc_inv :: forall {k} (a::k) (b::k) (c::k) x i obj (cat :: k -> k -> Type) o.
(obj a, obj b, obj c, Con' x obj, TestEqual (cat (x (x a b) c) (x (x a b) c)), Category cat, Obj cat ~ obj)
=> R.MonoidalRec x i obj cat -> o a -> o b -> o c -> Property
law_assoc_inv R.MonoidalRec{..} _ _ _ = nameLaw "assoc-inv" (assoc_ @a @b @c ∘ assoc =.= id)
law_unitorR_inv :: forall {k} (cat :: k -> k -> Type) x i {b :: k} {con :: k -> Constraint} {o}.
(Monoidal x i cat, Obj cat ~ con, Con' x con, con ~ Obj cat, con b, con i,
TestEqual (cat (x b i) (x b i))) =>
o b -> Property
law_unitorR_inv _ = nameLaw "unitor-inv" ((unitorR :: b `cat` (b `x` i)) ∘ unitorR_ =.= id)
law_unitorL_inv :: forall {k} {cat :: k -> k -> Type}
{x :: k -> k -> k} {b :: k} {i :: k} {con :: k -> Constraint} {o}.
(Category cat, Obj cat ~ con, Con' x con, con ~ Obj cat, con b, con i,
TestEqual (cat (x i b) (x i b))) =>
R.MonoidalRec x i con cat -> o b -> Property
law_unitorL_inv R.MonoidalRec{..} _ = nameLaw "unitor_-inv" (unitorL @b ∘ unitorL_ =.= id)
law_monoidal_triangle :: forall {k} (cat :: k -> k -> Type) (x :: k -> k -> k) (i :: k) a c obj o. (obj ~ Obj cat, Monoidal x i cat, obj a, obj c, obj i, Con' x obj, TestEqual (cat (x a c) (x a (x i c))))
=> o a -> o c -> Property
law_monoidal_triangle _ _ = nameLaw "monoidal-triangle"
((assoc . (unitorR ⊗ id)) =.= ((id ⊗ unitorL) :: (cat (x a c) (x a (x i c)))))
law_monoidal_pentagon :: forall {k} (cat :: k -> k -> Type) (x :: k -> k -> k) (i :: k) a b c d obj o.
(obj ~ Obj cat, Monoidal x i cat, obj a, obj b, obj c, obj d, Con' x obj, (TestEqual (cat (x (x (x a b) c) d) (x a (x b (x c d))))))
=> o a -> o b -> o c -> o d -> Property
law_monoidal_pentagon _ _ _ _ = nameLaw "monoidal-pentagon"
(assoc . assoc =.= ((id ⊗ assoc) . assoc . (assoc ⊗ id)
:: (cat (x (x (x a b) c) d) (x a (x b (x c d))))))
laws_monoidal :: forall {k} (cat :: k -> k -> Type) x i (obj :: k -> Constraint).
(obj ~ Obj cat, Con' x obj, Monoidal x i cat, obj i)
=> TestableCat x i obj cat -> Property
laws_monoidal t@TestableCat{..} = product
[ laws_category t
, genObj $ \t1 -> genObj $ \t2 -> genObj $ \t3 ->
genObj $ \t4 -> genObj $ \t5 -> genObj $ \t6 ->
genMorph t1 t2 $ \e -> genMorph t2 t3 $ \f ->
genMorph t4 t5 $ \g -> genMorph t5 t6 $ \h ->
law_parallel_composition m f h e g
\\ getTestable (t1 × t4) (t3 × t6)
, genObj $ \a -> genObj $ \b -> genObj $ \c -> law_assoc_inv m a b c
\\ getTestable' ((a × b) × c)
, genObj $ \a -> genObj $ \b -> genObj $ \c -> law_assoc_inv mOp a b c
\\ getTestable' ((a × b) × c)
, genObj $ \a -> law_unitorR_inv @cat @x a \\ getTestable' (a × unitObj)
, genObj $ \a -> law_unitorR_inv @(Op cat) @x a \\ getTestable' (a × unitObj)
, genObj $ \a -> law_unitorL_inv m a \\ getTestable' (unitObj × a)
, genObj $ \a -> law_unitorL_inv mOp a \\ getTestable' (unitObj × a)
, genObj $ \a -> genObj $ \b -> law_monoidal_triangle @cat @x a b
\\ getTestable (a × b) (a × (unitObj × b))
, genObj $ \a -> genObj $ \b -> genObj $ \c -> genObj $ \d ->
law_monoidal_pentagon @cat @x a b c d
\\ getTestable (((a × b) × c) × d) (a × (b × (c × d)))
]
where m :: R.MonoidalRec x i obj cat
m@R.MonoidalRec{} = monoidalRec @x
mOp :: R.MonoidalRec x i obj (Op cat)
mOp = monoidalRec @x
-- running the test on the op category mean that we test the reverse compositions.
law_swap_inv :: forall {k} (a::k) (b::k) x i obj (cat :: k -> k -> Type) o.
(obj ~ Obj cat, Braided x i cat, Con' x obj, obj a, obj b, TestEqual (cat (x b a) (x b a)))
=> R.BraidedRec x i obj cat -> o a -> o b -> Property
law_swap_inv R.BraidedRec{..} _ _ = nameLaw "swap-inv" (swap_ @a @b ∘ swap =.= id)
law_braided_hexagon1 :: forall {k} (cat :: k -> k -> Type) x i a b c obj o.
(obj ~ Obj cat, Braided x i cat, obj a, obj b, obj c, Con' x obj, (TestEqual (cat (x (x a b) c) (x b (x c a)))))
=> o a -> o b -> o c -> Property
law_braided_hexagon1 _ _ _ = nameLaw "braided-hexagon-1"
(assoc . swap . assoc =.= ((id ⊗ swap) . assoc . (swap ⊗ id)
:: cat ((a `x` b) `x` c) (b `x` (c `x` a))))
law_braided_hexagon2 :: forall {k} (cat :: k -> k -> Type) x i a b c obj o.
(obj ~ Obj cat, Braided x i cat, obj a, obj b, obj c, Con' x obj, (TestEqual (cat (x a (x b c)) (x (x c a) b))))
=> o a -> o b -> o c -> Property
law_braided_hexagon2 _ _ _ = nameLaw "braided-hexagon-2"
(assoc_ . swap . assoc_ =.= ((swap ⊗ id) . assoc_ . (id ⊗ swap)
:: cat (a `x` (b `x` c)) ((c `x` a) `x` b)))
law_braided_triangle :: forall {k} (cat :: k -> k -> Type) (x :: k -> k -> k) (i :: k) a obj o. (obj ~ Obj cat, Braided x i cat, obj a, obj i, Con' x obj, TestEqual (cat (x a i) a))
=> o a -> Property
law_braided_triangle _ = nameLaw "monoidal-triangle"
(unitorL_ . swap =.= (unitorR_ :: (cat (x a i) a)))
laws_braided :: forall {k} {x :: k -> k -> k}
{obj :: k -> Constraint}
{i :: k}
(cat :: k -> k -> Type).
(obj ~ Obj cat, Con' x obj, Braided x i cat, obj i)
=> TestableCat x i obj cat -> Property
laws_braided t@TestableCat{..} = product
[ laws_monoidal t
, genObj $ \a -> genObj $ \b -> law_swap_inv m a b \\ getTestable' (b × a)
, genObj $ \a -> genObj $ \b -> law_swap_inv mOp a b \\ getTestable' (b × a)
, genObj $ \a -> law_braided_triangle @cat @x a \\ getTestable (a × unitObj) a
, genObj $ \a -> genObj $ \b -> genObj $ \c ->
law_braided_hexagon1 @cat @x a b c \\ getTestable ((a × b) × c) (b × (c × a))
, genObj $ \a -> genObj $ \b -> genObj $ \c ->
law_braided_hexagon2 @cat @x a b c \\ getTestable (a × (b × c)) ((c × a) × b)
]
where m :: R.BraidedRec x i obj cat
m@R.BraidedRec{} = braidedRec @x
mOp :: R.BraidedRec x i obj (Op cat)
mOp = braidedRec @x
-- running the test on the op category mean that we test the reverse compositions.
law_swap_invol :: forall {k} (a::k) (b::k) x i obj (cat :: k -> k -> Type) o.
(obj ~ Obj cat, Braided x i cat, Con' x obj, obj a, obj b, TestEqual (cat (x b a) (x b a)))
=> R.BraidedRec x i obj cat -> o a -> o b -> Property
law_swap_invol R.BraidedRec{..} _ _ = nameLaw "swap-invol" (swap @a @b ∘ swap =.= id)
laws_symmetric :: forall {k} {x :: k -> k -> k}
{obj :: k -> Constraint}
{i :: k}
(cat :: k -> k -> Type).
(obj ~ Obj cat, Con' x obj, Braided x i cat, obj i)
=> TestableCat x i obj cat -> Property
laws_symmetric t@TestableCat{..} = product
[ laws_braided t
, genObj $ \a -> genObj $ \b -> law_swap_invol m a b
\\ getTestable' (b × a)
]
where m :: R.BraidedRec x i obj cat
m@R.BraidedRec{} = braidedRec @x
law_dup_commut :: forall {k} {cat :: k -> k -> Type}
{x :: k -> k -> k} {a :: k}
{b :: k} {i :: k} obj.
(obj a, obj b, Category cat, Obj cat ~ obj,
TestEqual (cat a (x b b)), Cartesian x i cat, Con' x obj) =>
R.CartesianRec x i obj cat -> cat a b -> Property
law_dup_commut R.CartesianRec{..} f = nameLaw "dup/cross" ((f ⊗ f) . dup =.= dup . f)
law_projections :: forall {k} {con :: k -> Constraint} {x :: k -> k -> k}
{b :: k} {c :: k} {cat :: k -> k -> Type} {i :: k} {p}.
(con (x b c), con b, con c, Obj cat (x b c), Con' x con,
TestEqual (cat (x b c) (x b c)), Category cat) =>
R.CartesianRec x i con cat -> p b -> p c -> Property
law_projections R.CartesianRec{..} _ _ = nameLaw "projections" (exl ▵ exr =.= id @k @cat @(b `x` c))
laws_cartesian_extra :: forall {k} (x :: k -> k -> k)
{obj :: k -> Constraint}
(i :: k )
(cat :: k -> k -> Type).
(obj ~ Obj cat, Con' x obj, Cartesian x i cat, obj i)
=> TestableCat x i obj cat -> Property
laws_cartesian_extra t@TestableCat{..} = product
[ genObj $ \t1 -> genObj $ \t2 -> genMorph t1 t2 $ \f -> law_dup_commut m f \\ getTestable t1 (t2 × t2)
, genObj $ \t1 -> genObj $ \t2 -> law_projections m t1 t2 \\ getTestable' (t1 × t2)
]
where m :: R.CartesianRec x i obj cat
m@R.CartesianRec{..} = cartesianRec
laws_cartesian :: forall {k} (x :: k -> k -> k)
{obj :: k -> Constraint}
(i :: k )
(cat :: k -> k -> Type).
(obj ~ Obj cat, Con' x obj, Cartesian x i cat, obj i)
=> TestableCat x i obj cat -> Property
laws_cartesian t@TestableCat{..} = product
[ laws_symmetric t , laws_cartesian_extra t]
laws_cocartesian :: forall {k} {x :: k -> k -> k}
{obj :: k -> Constraint}
{i :: k}
{cat :: k -> k -> Type}.
(obj ~ Obj cat, Con' x obj, CoCartesian x i cat, obj i)
=> TestableCat x i obj cat -> Property
laws_cocartesian t = laws_cartesian (opTestable t)
opTestable :: TestableCat x i obj cat -> TestableCat x i obj (Op cat)
opTestable TestableCat{..} = testableCat
genObj (\a b k -> genMorph b a $ \f -> k (Op f))
(\a b -> Dict \\ getTestable b a)
(×) unitObj
laws_bicartesian :: forall {k} {x :: k -> k -> k}
{obj :: k -> Constraint}
{i :: k}
(cat :: k -> k -> Type).
(obj ~ Obj cat, Con' x obj, BiCartesian x i cat, obj i)
=> TestableCat x i obj cat -> Property
laws_bicartesian t = product [ laws_symmetric t
, laws_cartesian_extra t
, laws_cartesian_extra (opTestable t)]