packages feed

moonlight-homology-0.1.0.0: src-sequence/Moonlight/Homology/Pure/Sequence/Spectral/Support.hs

module Moonlight.Homology.Pure.Sequence.Spectral.Support
  ( SpectralWindow (..),
    SpectralRestrictionKind (..),
    SpectralRestriction (..),
    SpectralWindowCover (..),
    SpectralSupportRegistry,
    mkSpectralSupportRegistry,
    supportWindows,
    supportWindowBidegree,
    supportLookupWindow,
    supportIncomingRestrictions,
    supportWindowCover,
    supportDifferentialTargetWindow,
  )
where

import Data.Function ((&))
import Data.Kind (Type)
import qualified Data.Map.Strict as Map
import qualified Data.Set as Set
import Moonlight.Homology.Pure.Degree (HomologicalDegree)
import Moonlight.Homology.Pure.Sequence.Spectral.Bidegree
  ( Bidegree,
    bidegreeFromTotalDegree,
    targetBidegreeAfterDifferential,
  )

type SpectralWindow :: Type
data SpectralWindow = SpectralWindow
  { spectralWindowDegree :: HomologicalDegree,
    spectralWindowFiltration :: Int
  }
  deriving stock (Eq, Ord, Show)

type SpectralRestrictionKind :: Type
data SpectralRestrictionKind
  = FiltrationRestriction
  deriving stock (Eq, Ord, Show)

type SpectralRestriction :: Type
data SpectralRestriction = SpectralRestriction
  { spectralRestrictionKind :: SpectralRestrictionKind,
    spectralRestrictionSourceWindow :: SpectralWindow,
    spectralRestrictionTargetWindow :: SpectralWindow
  }
  deriving stock (Eq, Ord, Show)

type SpectralWindowCover :: Type
data SpectralWindowCover = SpectralWindowCover
  { spectralCoverWindow :: SpectralWindow,
    spectralCoverIncomingRestrictions :: [SpectralRestriction]
  }
  deriving stock (Eq, Show)

type SpectralSupportRegistry :: Type
data SpectralSupportRegistry = SpectralSupportRegistry
  { registryWindows :: [SpectralWindow],
    registryByBidegree :: Map.Map Bidegree SpectralWindow,
    registryRestrictionsByTarget :: Map.Map SpectralWindow [SpectralRestriction]
  }

mkSpectralSupportRegistry :: Map.Map HomologicalDegree [Int] -> SpectralSupportRegistry
mkSpectralSupportRegistry levelsByDegree =
  let windows =
        Map.toAscList levelsByDegree
          >>= \(degreeValue, levelsAtDegree) ->
            distinctLevels levelsAtDegree
              & fmap
                ( \filtrationDegreeValue ->
                    SpectralWindow
                      { spectralWindowDegree = degreeValue,
                        spectralWindowFiltration = filtrationDegreeValue
                      }
                )
      byBidegree =
        windows
          & fmap (\windowValue -> (supportWindowBidegree windowValue, windowValue))
          & Map.fromList
      restrictions =
        windows
          >>= \targetWindow ->
            shiftedWindow byBidegree 1 targetWindow
              & maybe
                []
                ( \sourceWindow ->
                    [ SpectralRestriction
                        { spectralRestrictionKind = FiltrationRestriction,
                          spectralRestrictionSourceWindow = sourceWindow,
                          spectralRestrictionTargetWindow = targetWindow
                        }
                    ]
                )
      restrictionsByTarget =
        restrictions
          & fmap (\restrictionValue -> (spectralRestrictionTargetWindow restrictionValue, [restrictionValue]))
          & Map.fromListWith (<>)
   in SpectralSupportRegistry
        { registryWindows = windows,
          registryByBidegree = byBidegree,
          registryRestrictionsByTarget = restrictionsByTarget
        }

supportWindows :: SpectralSupportRegistry -> [SpectralWindow]
supportWindows =
  registryWindows

supportWindowBidegree :: SpectralWindow -> Bidegree
supportWindowBidegree windowValue =
  bidegreeFromTotalDegree
    (spectralWindowFiltration windowValue)
    (spectralWindowDegree windowValue)

supportLookupWindow :: SpectralSupportRegistry -> Bidegree -> Maybe SpectralWindow
supportLookupWindow registry =
  (`Map.lookup` registryByBidegree registry)

supportIncomingRestrictions :: SpectralSupportRegistry -> SpectralWindow -> [SpectralRestriction]
supportIncomingRestrictions registry windowValue =
  Map.findWithDefault [] windowValue (registryRestrictionsByTarget registry)

supportWindowCover :: SpectralSupportRegistry -> SpectralWindow -> SpectralWindowCover
supportWindowCover registry windowValue =
  SpectralWindowCover
    { spectralCoverWindow = windowValue,
      spectralCoverIncomingRestrictions = supportIncomingRestrictions registry windowValue
    }

supportDifferentialTargetWindow :: SpectralSupportRegistry -> Int -> SpectralWindow -> Maybe SpectralWindow
supportDifferentialTargetWindow registry pageNumber windowValue =
  supportLookupWindow
    registry
    (targetBidegreeAfterDifferential pageNumber (supportWindowBidegree windowValue))

shiftedWindow :: Map.Map Bidegree SpectralWindow -> Int -> SpectralWindow -> Maybe SpectralWindow
shiftedWindow byBidegree filtrationDelta windowValue =
  Map.lookup
    ( bidegreeFromTotalDegree
        (spectralWindowFiltration windowValue + filtrationDelta)
        (spectralWindowDegree windowValue)
    )
    byBidegree

distinctLevels :: [Int] -> [Int]
distinctLevels =
  Set.toAscList . Set.fromList