packages feed

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)))