packages feed

moonlight-homology-0.1.0.0: src-topology/Moonlight/Homology/Pure/Topology/Graph/Algebra.hs

module Moonlight.Homology.Pure.Topology.Graph.Algebra
  ( addUndirectedAdjacency,
    connectedComponentsFromAdjacency,
  )
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.Bifunctor (second)
import Data.Foldable qualified as Foldable
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.Set qualified as Set

addUndirectedAdjacency ::
  Ord label =>
  label ->
  label ->
  Map label [label] ->
  Map label [label]
addUndirectedAdjacency sourceLabel targetLabel =
  Map.insertWith (<>) sourceLabel [targetLabel]
    . Map.insertWith (<>) targetLabel [sourceLabel]

connectedComponentsFromAdjacency :: (Ord label, Foldable adjacency) => Map label (adjacency label) -> Int
connectedComponentsFromAdjacency =
  length
    . strongComponentSets
    . AdjacencyMap.symmetricClosure
    . AdjacencyMap.fromAdjacencySets
    . fmap (second (Set.fromList . Foldable.toList))
    . Map.toAscList

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