packages feed

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

-- | The standard simplicial spaces: simplices, their boundaries, and horns,
-- as generated simplicial sets.
module Moonlight.Category.Pure.Simplicial.Spaces
  ( standardSimplexGenerated,
    standardSimplex,
    boundarySimplexGenerated,
    boundarySimplex,
    hornSimplexGenerated,
    hornSimplex,
  )
where

import Data.Function ((&))
import Data.List (genericSplitAt)
import Data.Map.Strict qualified as Map
import Numeric.Natural (Natural)
import Moonlight.Category.Pure.Simplicial.Delta
  ( allDeltaMorphisms,
    deltaMapValues,
  )
import Moonlight.Category.Pure.Simplicial.Set
  ( GeneratedSSet,
    TruncatedNormalizedSSet,
    generatedSimplicesAtDimension,
  )
import Moonlight.Category.Pure.Simplicial.Set.Internal
  ( GeneratedSSet (generatedDegeneracyMap, generatedFaceMap),
    trustedGeneratedSSet,
    trustedTruncatedNormalizedSSet,
  )
import Moonlight.Category.Pure.Simplicial.TypeLevel (finValue)

duplicateAt :: Natural -> [a] -> Maybe [a]
duplicateAt targetIndex values =
  case genericSplitAt targetIndex values of
    (_, []) -> Nothing
    (prefix, x : suffix) -> Just (prefix <> [x, x] <> suffix)

removeAt :: Natural -> [a] -> Maybe [a]
removeAt targetIndex values =
  case genericSplitAt targetIndex values of
    (_, []) -> Nothing
    (prefix, _ : suffix) -> Just (prefix <> suffix)


simplexRows :: Natural -> Natural -> [[Natural]]
simplexRows simplexDimension domainDimension =
  deltaMapValues <$> allDeltaMorphisms domainDimension simplexDimension

availableVertexCount :: Natural -> Natural -> Natural
availableVertexCount lowerBound upperBound =
  if lowerBound > upperBound
    then 0
    else upperBound - lowerBound + 1

strictlyIncreasingRows :: Natural -> Natural -> Natural -> [[Natural]]
strictlyIncreasingRows lowerBound upperBound rowLength
  | rowLength == 0 = [[]]
  | rowLength > availableVertexCount lowerBound upperBound = []
  | otherwise =
      [lowerBound .. upperBound]
        & concatMap
          ( \headValue ->
              strictlyIncreasingRows (headValue + 1) upperBound (rowLength - 1)
                & map (headValue :)
          )

nondegenerateSimplexRows :: Natural -> Natural -> [[Natural]]
nondegenerateSimplexRows simplexDimension domainDimension =
  strictlyIncreasingRows 0 simplexDimension (domainDimension + 1)

nonemptyNondegenerateRows :: Natural -> Natural -> ([Natural] -> Bool) -> Map.Map Natural [[Natural]]
nonemptyNondegenerateRows simplexDimension truncationBound rowPredicate =
  [0 .. truncationBound]
    & fmap
      ( \dimensionValue ->
          ( dimensionValue,
            nondegenerateSimplexRows simplexDimension dimensionValue
              & filter rowPredicate
          )
      )
    & filter (not . null . snd)
    & Map.fromAscList

omitsVertex :: Natural -> [Natural] -> Bool
omitsVertex vertexValue simplexValue =
  vertexValue `notElem` simplexValue

belongsToBoundary :: Natural -> [Natural] -> Bool
belongsToBoundary simplexDimension simplexValue =
  any (`omitsVertex` simplexValue) [0 .. simplexDimension]

belongsToHorn :: Natural -> Natural -> [Natural] -> Bool
belongsToHorn simplexDimension missingFaceIndex simplexValue =
  [0 .. simplexDimension]
    & any
      (\vertexValue -> vertexValue /= missingFaceIndex && omitsVertex vertexValue simplexValue)

standardSimplexGenerated :: Natural -> Natural -> GeneratedSSet [Natural]
standardSimplexGenerated simplexDimension truncationBound =
  trustedGeneratedSSet
    truncationBound
    (simplexRows simplexDimension)
    (\_ faceIndex simplexValue -> removeAt (finValue faceIndex) simplexValue)
    (\_ degeneracyIndex simplexValue -> duplicateAt (finValue degeneracyIndex) simplexValue)

standardSimplex :: Natural -> Natural -> TruncatedNormalizedSSet [Natural]
standardSimplex simplexDimension truncationBound =
  trustedTruncatedNormalizedSSet
    truncationBound
    (nonemptyNondegenerateRows simplexDimension truncationBound (const True))
    (\_ faceIndex simplexValue -> removeAt (finValue faceIndex) simplexValue)
    (\_ degeneracyIndex simplexValue -> duplicateAt (finValue degeneracyIndex) simplexValue)

boundarySimplexGenerated :: Natural -> Natural -> GeneratedSSet [Natural]
boundarySimplexGenerated simplexDimension truncationBound =
  let baseSet = standardSimplexGenerated simplexDimension truncationBound
   in trustedGeneratedSSet
        truncationBound
        (\dimensionValue' -> filter (belongsToBoundary simplexDimension) (generatedSimplicesAtDimension baseSet dimensionValue'))
        (generatedFaceMap baseSet)
        (generatedDegeneracyMap baseSet)

boundarySimplex :: Natural -> Natural -> TruncatedNormalizedSSet [Natural]
boundarySimplex simplexDimension truncationBound =
  trustedTruncatedNormalizedSSet
    truncationBound
    (nonemptyNondegenerateRows simplexDimension truncationBound (belongsToBoundary simplexDimension))
    (\_ faceIndex simplexValue -> removeAt (finValue faceIndex) simplexValue)
    (\_ degeneracyIndex simplexValue -> duplicateAt (finValue degeneracyIndex) simplexValue)

hornSimplexGenerated :: Natural -> Natural -> Natural -> Maybe (GeneratedSSet [Natural])
hornSimplexGenerated simplexDimension missingFaceIndex truncationBound
  | simplexDimension == 0 = Nothing
  | missingFaceIndex > simplexDimension = Nothing
  | otherwise =
      let baseSet = standardSimplexGenerated simplexDimension truncationBound
       in Just
            ( trustedGeneratedSSet
                truncationBound
                (\dimensionValue' -> filter (belongsToHorn simplexDimension missingFaceIndex) (generatedSimplicesAtDimension baseSet dimensionValue'))
                (generatedFaceMap baseSet)
                (generatedDegeneracyMap baseSet)
            )

hornSimplex :: Natural -> Natural -> Natural -> Maybe (TruncatedNormalizedSSet [Natural])
hornSimplex simplexDimension missingFaceIndex truncationBound =
  if simplexDimension == 0 || missingFaceIndex > simplexDimension
    then Nothing
    else
      Just
        ( trustedTruncatedNormalizedSSet
            truncationBound
            (nonemptyNondegenerateRows simplexDimension truncationBound (belongsToHorn simplexDimension missingFaceIndex))
            (\_ faceIndex simplexValue -> removeAt (finValue faceIndex) simplexValue)
            (\_ degeneracyIndex simplexValue -> duplicateAt (finValue degeneracyIndex) simplexValue)
        )