packages feed

moonlight-category-0.1.0.0: src-simplicial/Moonlight/Category/Pure/Simplicial/Homotopy.hs

-- | Homotopy-flavoured queries over nerves: connected components and
-- core\/automorphism groupoids.
module Moonlight.Category.Pure.Simplicial.Homotopy
  ( pi0Nerve,
    CoreGroupoid,
    CoreGroupoidObject,
    CoreGroupoidMorphism,
    AutomorphismGroupoid,
    AutomorphismGroupoidObject,
    AutomorphismGroupoidMorphism,
    forgetCoreGroupoidObject,
    forgetCoreGroupoidMorphism,
    forgetAutomorphismGroupoidObject,
    forgetAutomorphismGroupoidMorphism,
    coreGroupoidOfNerve,
    coreGroupoidObjects,
    coreGroupoidMorphisms,
    coreGroupoidMorphismsBetween,
    automorphismGroupoidOfNerve,
    automorphismGroupoidObjects,
    automorphismGroupAt,
  )
where

import Algebra.Graph.AdjacencyMap qualified as AdjacencyMap
import Algebra.Graph.AdjacencyMap.Algorithm qualified as AdjacencyMapAlgorithm
import Algebra.Graph.NonEmpty.AdjacencyMap qualified as NonEmptyAdjacencyMap
import Data.Function ((&))
import Data.List qualified as List
import Data.List.NonEmpty qualified as NonEmpty
import Data.Map.Strict (Map)
import Data.Map.Strict qualified as Map
import Data.Maybe (mapMaybe)
import Data.Set (Set)
import Data.Set qualified as Set
import Moonlight.Category.Pure.Category (Category (..))
import Moonlight.Category.Pure.FiniteComposable (FiniteComposableCategory (..))
import Moonlight.Category.Pure.Invertibility
  ( AutomorphismGroupoid,
    AutomorphismGroupoidMorphism,
    AutomorphismGroupoidObject,
    CoreGroupoid,
    CoreGroupoidMorphism,
    CoreGroupoidObject,
    automorphismGroupoid,
    automorphismGroupAt,
    automorphismGroupoidObjects,
    coreGroupoid,
    coreGroupoidObjects,
    coreGroupoidMorphisms,
    coreGroupoidMorphismsBetween,
    forgetAutomorphismGroupoidMorphism,
    forgetAutomorphismGroupoidObject,
    forgetCoreGroupoidMorphism,
    forgetCoreGroupoidObject,
  )

adjacencyFromEdges :: Ord a => [a] -> [(a, a)] -> Map a (Set a)
adjacencyFromEdges vertices edges =
  let vertexAdjacency =
        foldr
          (\vertex -> Map.insertWith Set.union vertex Set.empty)
          Map.empty
          vertices
      edgeAdjacency =
        foldr
          (\(sourceVertex, targetVertex) ->
             Map.insertWith Set.union sourceVertex (Set.singleton targetVertex)
               . Map.insertWith Set.union targetVertex (Set.singleton sourceVertex)
          )
          vertexAdjacency
          edges
   in edgeAdjacency

pi0Nerve :: (FiniteComposableCategory c, Ord (Ob c)) => c -> [[Ob c]]
pi0Nerve categoryValue =
  let objects = enumerateObjects categoryValue
      undirectedEdges =
        enumerateMorphisms categoryValue
          & mapMaybe
            ( \morphism ->
                case (source categoryValue morphism, target categoryValue morphism) of
                  (Right sourceObject, Right targetObject) -> Just (sourceObject, targetObject)
                  _ -> Nothing
            )
   in componentsFromAdjacency (adjacencyFromEdges objects undirectedEdges)
        & fmap Set.toAscList

coreGroupoidOfNerve ::
  (FiniteComposableCategory c, Ord (Ob c), Ord (Mor c)) =>
  c ->
  CoreGroupoid c
coreGroupoidOfNerve =
  coreGroupoid

automorphismGroupoidOfNerve :: 
  (FiniteComposableCategory c, Ord (Ob c), Ord (Mor c)) =>
  c ->
  AutomorphismGroupoid c
automorphismGroupoidOfNerve =
  automorphismGroupoid

componentsFromAdjacency :: Ord vertex => Map vertex (Set vertex) -> [Set vertex]
componentsFromAdjacency =
  strongComponentSets
    . AdjacencyMap.symmetricClosure
    . AdjacencyMap.fromAdjacencySets
    . Map.toAscList

strongComponentSets :: Ord vertex => AdjacencyMap.AdjacencyMap vertex -> [Set vertex]
strongComponentSets graph =
  List.sortOn
    Set.lookupMin
    ( fmap
        (Set.fromList . NonEmpty.toList . NonEmptyAdjacencyMap.vertexList1)
        (AdjacencyMap.vertexList (AdjacencyMapAlgorithm.scc graph))
    )