FiniteCategories-0.2.0.0: src/Math/FiniteCategory.hs
{-# LANGUAGE MultiParamTypeClasses, FunctionalDependencies #-}
{-| Module : FiniteCategories
Description : A 'FiniteCategory' is a 'Category' where the objects can be enumerated.
Copyright : Guillaume Sabbagh 2022
License : GPL-3
Maintainer : guillaumesabbagh@protonmail.com
Stability : experimental
Portability : portable
A 'FiniteCategory' is a 'Category' where the objects can be enumerated.
This module exports Math.Category so that you only have to import one of them.
-}
module Math.FiniteCategory
(
-- * FiniteCategory
FiniteCategory(..),
-- ** Morphism enumeration
arrows,
arFrom,
arTo,
arFrom2,
arTo2,
identities,
-- ** Morphism predicates
isEpic,
isMonic,
-- ** Object predicates
isTerminal,
isInitial,
-- ** Find special objects
terminalObjects,
initialObjects,
-- * Generated finite category
-- ** Generator enumeration
genArrows,
genArFrom,
genArTo,
genArFrom2,
genArTo2,
-- ** Helper
bruteForceDecompose,
module Math.Category
)
where
import Data.WeakSet (Set)
import qualified Data.WeakSet as Set
import Data.WeakSet.Safe
import Data.List (elemIndex)
import Math.Category
import Control.Monad (join)
-- | A 'FiniteCategory' is a 'Category' which allows to enumerate its objects.
--
-- It is assumed that the set of objects of the category is finite.
class (Category c m o) => FiniteCategory c m o | c -> m, m -> o where
-- | `ob` should return a set of objects.
ob :: c -> Set o
-- | `arrows` returns the set of all unique morphisms of a category.
arrows :: (FiniteCategory c m o, Morphism m o) => c -> Set m
arrows c = join $ ar c <$> ob c <*> ob c
-- | `arTo` returns the set of morphisms going to a specified target.
arTo :: (FiniteCategory c m o, Morphism m o) => c -> o -> Set m
arTo c t = join $ (\s -> ar c s t) <$> ob c
-- | `arTo2` same as `arTo` but for multiple targets.
arTo2 :: (FiniteCategory c m o, Morphism m o) => c -> Set o -> Set m
arTo2 c ts = join $ ar c <$> ob c <*> ts
-- | `arFrom` returns the list of unique morphisms going from a specified source.
arFrom :: (FiniteCategory c m o, Morphism m o) => c -> o -> Set m
arFrom c s = join $ ar c s <$> ob c
-- | `arFrom2` same as `arFrom` but for multiple sources.
arFrom2 :: (FiniteCategory c m o, Morphism m o) => c -> Set o -> Set m
arFrom2 c ss = join $ ar c <$> ss <*> ob c
-- | Same as `arrows` but only returns the generators. @genArrows c@ should be included in @arrows c@.
genArrows :: (FiniteCategory c m o, Morphism m o) => c -> Set m
genArrows c = join $ genAr c <$> ob c <*> ob c
-- | Same as `arTo` but only returns the generators. @genArTo c t@ should be included in @arTo c t@.
genArTo :: (FiniteCategory c m o, Morphism m o) => c -> o -> Set m
genArTo c t = join $ (\s -> genAr c s t) <$> ob c
-- | Same as `arTo2` but only returns the generators. @genArTo2 c (set [t])@ should be included in @arTo2 c (set [t])@.
genArTo2 :: (FiniteCategory c m o, Morphism m o) => c -> Set o -> Set m
genArTo2 c ts = join $ (genAr c) <$> ob c <*> ts
-- | Same as `arFrom` but only returns the generators. @genArFrom c s@ should be included in @arFrom c s@.
genArFrom :: (FiniteCategory c m o, Morphism m o) => c -> o -> Set m
genArFrom c s = join $ (genAr c s) <$> ob c
-- | Same as `arFrom2` but only returns the generators. @genArFrom2 c (set [s])@ should be included in @arFrom2 c (set [s])@.
genArFrom2 :: (FiniteCategory c m o, Morphism m o) => c -> Set o -> Set m
genArFrom2 c ss = join $ genAr c <$> ss <*> ob c
-- | `identities` returns all the identities of a category.
identities :: (FiniteCategory c m o, Morphism m o) => c -> Set m
identities c = identity c <$> ob c
-- | Return wether an object is initial in the category.
isInitial :: (FiniteCategory c m o, Morphism m o, Eq m, Eq o) => c -> o -> Bool
isInitial cat obj = let
morphisms t = setToList $ ar cat obj t
condition t = (not.null $ morphisms t) && (null.tail $ morphisms t) -- we avoid the usage of cardinal to test that the size of (ar cat obj t) is 1 for speed purposes
in
Set.and $ condition <$> ob cat
-- | Return the set of intial objects in a category.
initialObjects :: (FiniteCategory c m o, Morphism m o, Eq m, Eq o) => c -> Set o
initialObjects cat = Set.filter (isInitial cat) (ob cat)
-- | Return wether an object is terminal in the category.
isTerminal :: (FiniteCategory c m o, Morphism m o, Eq m, Eq o) => c -> o -> Bool
isTerminal cat obj = let
morphisms s = setToList $ ar cat s obj
condition s = (not.null $ morphisms s) && (null.tail $ morphisms s) -- we avoid the usage of cardinal to test that the size of (ar cat s obj) is 1 for speed purposes
in
Set.and $ condition <$> ob cat
-- | Return the set of terminal objects in a category.
terminalObjects :: (FiniteCategory c m o, Morphism m o, Eq m, Eq o) => c -> Set o
terminalObjects cat = Set.filter (isTerminal cat) (ob cat)
-- | Return wether a morphism is a monomorphism.
isMonic :: (FiniteCategory c m o, Morphism m o, Eq m, Eq o) => c -> m -> Bool
isMonic c f = and [f @ g /= f @ h || g == h| x <- setToList $ ob c, g <- setToList $ ar c x (source f), h <- setToList $ ar c x (source f)]
-- | Return wether a morphism is an epimorphism.
isEpic :: (FiniteCategory c m o, Morphism m o, Eq m, Eq o) => c -> m -> Bool
isEpic c f = and [g @ f /= h @ f || g == h | x <- setToList $ ob c, g <- setToList $ ar c (target f) x, h <- setToList $ ar c (target f) x]
-- | Helper function for `bruteForceDecompose`.
bruteForce :: (FiniteCategory c m o, Morphism m o, Eq m) => c -> m -> [[m]] -> [m]
bruteForce c m l = if index == Nothing then bruteForce c m (concat (pathToAugmentedPaths <$> l)) else l !! i where
index = elemIndex m (compose <$> l)
Just i = index
leavingMorph path = (setToList.(genArFrom c)) $ target.head $ path
pathToAugmentedPaths path = (leavingMorph path) >>= (\x -> [(x:path)] )
-- | If `genAr` is implemented, we can find the decomposition of a morphism by bruteforce search (we compose every arrow until we get the morphism we want).
--
-- This method is meant to be used temporarly until a proper decompose method is implemented. (It is very slow.)
bruteForceDecompose :: (FiniteCategory c m o, Morphism m o, Eq m) => c -> m -> [m]
bruteForceDecompose c m = bruteForce c m ((:[]) <$> (setToList $ genArFrom c (source m)))