packages feed

moonlight-homology-0.1.0.0: src-topology/Moonlight/Homology/Pure/Topology/MacroScaffold/Compose/Reindex.hs

module Moonlight.Homology.Pure.Topology.MacroScaffold.Compose.Reindex
  ( traverseShiftedScaffolds,
    scaffoldBasisRefs,
    reebArcCardinality,
  )
where

import Control.Monad (foldM)
import Data.Bifunctor (first)
import Data.List.NonEmpty (NonEmpty (..))
import Data.Map.Strict (Map)
import qualified Data.Map.Strict as Map
import Moonlight.Homology.Pure.Chain
  ( HomologicalDegree,
    RepresentativeChain (..),
  )
import Moonlight.Homology.Pure.Carrier
  ( BasisCellRef (..),
    CellCarrier,
    CellCarrierError,
    carrierCells,
    carrierDegree,
    mkCellCarrier,
  )
import Moonlight.Homology.Pure.Topology.MacroScaffold
  ( MacroScaffoldIR (..),
  )
import Moonlight.Homology.Pure.Topology.MacroScaffold.Compose.Core
  ( MacroScaffoldCompositionError (..),
    ScaffoldOffsets (..),
    zeroScaffoldOffsets,
  )
import Moonlight.Homology.Pure.Topology.MacroScaffold.Direction
  ( DirectionField,
    DirectionFieldEncoding (..),
    directionFieldCarrier,
    directionFieldEncoding,
    directionFieldSymmetryOrder,
    mkDirectionField,
  )
import Moonlight.Homology.Pure.Topology.MacroScaffold.HarmonicLoop
  ( HarmonicLoop (..),
    HarmonicLoopId (..),
  )
import Moonlight.Homology.Pure.Topology.MacroScaffold.Potential
  ( ScalarPotentialField,
    mkScalarPotentialField,
    scalarPotentialCarrier,
    scalarPotentialNormalization,
    scalarPotentialSamples,
  )
import Moonlight.Homology.Pure.Topology.MacroScaffold.Reeb
  ( MorseReebArc (..),
    MorseReebNode (..),
    MorseReebScaffold (..),
    ReebArcId (..),
    ReebNodeId (..),
  )
import Moonlight.Homology.Pure.Topology.MacroScaffold.Singularity
  ( Singularity (..),
    SingularityId (..),
  )

traverseShiftedScaffolds ::
  NonEmpty (label, MacroScaffoldIR) ->
  Either MacroScaffoldCompositionError (NonEmpty (label, MacroScaffoldIR))
traverseShiftedScaffolds ((firstLabel, firstScaffold) :| remainingScaffolds) = do
  shiftedFirst <- reindexScaffold zeroScaffoldOffsets firstScaffold
  (_, shiftedRest) <-
    foldM
      reindexStep
      (advanceOffsets zeroScaffoldOffsets firstScaffold, [])
      remainingScaffolds
  pure ((firstLabel, shiftedFirst) :| shiftedRest)
  where
    reindexStep ::
      (ScaffoldOffsets, [(label, MacroScaffoldIR)]) ->
      (label, MacroScaffoldIR) ->
      Either MacroScaffoldCompositionError (ScaffoldOffsets, [(label, MacroScaffoldIR)])
    reindexStep (offsets, shiftedScaffolds) (labelValue, scaffoldValue) = do
      shiftedScaffold <- reindexScaffold offsets scaffoldValue
      pure
        ( advanceOffsets offsets scaffoldValue,
          shiftedScaffolds <> [(labelValue, shiftedScaffold)]
        )

scaffoldBasisRefs :: MacroScaffoldIR -> [BasisCellRef]
scaffoldBasisRefs scaffoldValue =
  carrierCells (scalarPotentialCarrier (macroScaffoldScalarPotential scaffoldValue))
    <> Map.keys (scalarPotentialSamples (macroScaffoldScalarPotential scaffoldValue))
    <> carrierCells (directionFieldCarrier (macroScaffoldDirectionField scaffoldValue))
    <> directionEncodingBasisRefs (directionFieldEncoding (macroScaffoldDirectionField scaffoldValue))
    <> fmap morseReebNodeAnchor (morseReebNodes (macroScaffoldReeb scaffoldValue))
    <> (morseReebArcs (macroScaffoldReeb scaffoldValue) >>= morseReebArcSupport)
    <> fmap singularityAnchor (macroScaffoldSingularities scaffoldValue)
    <> (macroScaffoldHarmonicLoops scaffoldValue >>= representativeBasisRefs . harmonicLoopCycle)
    <> (macroScaffoldHarmonicLoops scaffoldValue >>= representativeBasisRefs . harmonicLoopCocycle)

reebArcCardinality :: MacroScaffoldIR -> Int
reebArcCardinality s = maxIdCardinality (unReebArcId . morseReebArcId) (morseReebArcs (macroScaffoldReeb s))

maxIdCardinality :: (a -> Int) -> [a] -> Int
maxIdCardinality extractId = foldr (\v acc -> max acc (extractId v + 1)) 0

reebNodeCardinality :: MacroScaffoldIR -> Int
reebNodeCardinality s = maxIdCardinality (unReebNodeId . morseReebNodeId) (morseReebNodes (macroScaffoldReeb s))

singularityCardinality :: MacroScaffoldIR -> Int
singularityCardinality s = maxIdCardinality (unSingularityId . singularityId) (macroScaffoldSingularities s)

harmonicLoopCardinality :: MacroScaffoldIR -> Int
harmonicLoopCardinality s = maxIdCardinality (unHarmonicLoopId . harmonicLoopId) (macroScaffoldHarmonicLoops s)

reindexScaffold :: ScaffoldOffsets -> MacroScaffoldIR -> Either MacroScaffoldCompositionError MacroScaffoldIR
reindexScaffold offsets scaffoldValue = do
  scalarPotential <- reindexScalarPotential offsets (macroScaffoldScalarPotential scaffoldValue)
  directionField <- reindexDirectionField offsets (macroScaffoldDirectionField scaffoldValue)
  pure
    MacroScaffoldIR
      { macroScaffoldScalarPotential = scalarPotential,
        macroScaffoldReeb = reindexReebScaffold offsets (macroScaffoldReeb scaffoldValue),
        macroScaffoldDirectionField = directionField,
        macroScaffoldSingularities = fmap (reindexSingularity offsets) (macroScaffoldSingularities scaffoldValue),
        macroScaffoldHarmonicLoops = fmap (reindexHarmonicLoop offsets) (macroScaffoldHarmonicLoops scaffoldValue)
      }

reindexScalarPotential :: ScaffoldOffsets -> ScalarPotentialField -> Either MacroScaffoldCompositionError ScalarPotentialField
reindexScalarPotential offsets scalarPotential = do
  carrierValue <- reindexCarrier InvalidComposedScalarPotentialCarrier offsets (scalarPotentialCarrier scalarPotential)
  first
    InvalidComposedScalarPotential
    ( mkScalarPotentialField
        carrierValue
        (scalarPotentialNormalization scalarPotential)
        (Map.fromAscList (reindexAssociation offsets <$> Map.toAscList (scalarPotentialSamples scalarPotential)))
    )

reindexDirectionField :: ScaffoldOffsets -> DirectionField -> Either MacroScaffoldCompositionError DirectionField
reindexDirectionField offsets directionField = do
  carrierValue <- reindexCarrier InvalidComposedDirectionCarrier offsets (directionFieldCarrier directionField)
  first
    InvalidComposedDirectionField
    ( mkDirectionField
        carrierValue
        (directionFieldSymmetryOrder directionField)
        (reindexDirectionEncoding offsets (directionFieldEncoding directionField))
    )

reindexCarrier ::
  (CellCarrierError -> MacroScaffoldCompositionError) ->
  ScaffoldOffsets ->
  CellCarrier ->
  Either MacroScaffoldCompositionError CellCarrier
reindexCarrier liftError offsets carrierValue =
  first
    liftError
    (mkCellCarrier (carrierDegree carrierValue) (reindexBasisCellRef offsets <$> carrierCells carrierValue))

reindexAssociation :: ScaffoldOffsets -> (BasisCellRef, value) -> (BasisCellRef, value)
reindexAssociation offsets (basisCellRef, value) =
  (reindexBasisCellRef offsets basisCellRef, value)

reindexDirectionEncoding :: ScaffoldOffsets -> DirectionFieldEncoding -> DirectionFieldEncoding
reindexDirectionEncoding offsets encodingValue =
  case encodingValue of
    DirectionAngleEncoding phaseMap ->
      DirectionAngleEncoding (Map.fromAscList (reindexAssociation offsets <$> Map.toAscList phaseMap))
    DirectionCochainEncoding coefficientMap ->
      DirectionCochainEncoding (Map.fromAscList (reindexAssociation offsets <$> Map.toAscList coefficientMap))

reindexReebScaffold :: ScaffoldOffsets -> MorseReebScaffold -> MorseReebScaffold
reindexReebScaffold offsets reebValue =
  MorseReebScaffold
    { morseReebNodes = reindexReebNode offsets <$> morseReebNodes reebValue,
      morseReebArcs = reindexReebArc offsets <$> morseReebArcs reebValue
    }

reindexReebNode :: ScaffoldOffsets -> MorseReebNode -> MorseReebNode
reindexReebNode offsets nodeValue =
  nodeValue
    { morseReebNodeId = offsetReebNodeId (soNodeOffset offsets) (morseReebNodeId nodeValue),
      morseReebNodeAnchor = reindexBasisCellRef offsets (morseReebNodeAnchor nodeValue)
    }

reindexReebArc :: ScaffoldOffsets -> MorseReebArc -> MorseReebArc
reindexReebArc offsets arcValue =
  arcValue
    { morseReebArcId = offsetReebArcId (soArcOffset offsets) (morseReebArcId arcValue),
      morseReebArcSource = offsetReebNodeId (soNodeOffset offsets) (morseReebArcSource arcValue),
      morseReebArcTarget = offsetReebNodeId (soNodeOffset offsets) (morseReebArcTarget arcValue),
      morseReebArcSupport = reindexBasisCellRef offsets <$> morseReebArcSupport arcValue
    }

reindexSingularity :: ScaffoldOffsets -> Singularity -> Singularity
reindexSingularity offsets singularityValue =
  singularityValue
    { singularityId = offsetSingularityId (soSingularityOffset offsets) (singularityId singularityValue),
      singularityAnchor = reindexBasisCellRef offsets (singularityAnchor singularityValue),
      singularityReebNode = offsetReebNodeId (soNodeOffset offsets) <$> singularityReebNode singularityValue,
      singularityIncidentArcs = offsetReebArcId (soArcOffset offsets) <$> singularityIncidentArcs singularityValue
    }

reindexHarmonicLoop :: ScaffoldOffsets -> HarmonicLoop -> HarmonicLoop
reindexHarmonicLoop offsets harmonicLoopValue =
  harmonicLoopValue
    { harmonicLoopId = offsetHarmonicLoopId (soLoopOffset offsets) (harmonicLoopId harmonicLoopValue),
      harmonicLoopCycle = reindexRepresentative offsets (harmonicLoopCycle harmonicLoopValue),
      harmonicLoopCocycle = reindexRepresentative offsets (harmonicLoopCocycle harmonicLoopValue),
      harmonicLoopSupport = offsetReebArcId (soArcOffset offsets) <$> harmonicLoopSupport harmonicLoopValue
    }

reindexRepresentative ::
  ScaffoldOffsets ->
  RepresentativeChain coefficient BasisCellRef ->
  RepresentativeChain coefficient BasisCellRef
reindexRepresentative offsets representativeValue =
  representativeValue
    { representativeTerms =
        fmap
          (\(coefficientValue, basisCellRef) -> (coefficientValue, reindexBasisCellRef offsets basisCellRef))
          (representativeTerms representativeValue)
    }

reindexBasisCellRef :: ScaffoldOffsets -> BasisCellRef -> BasisCellRef
reindexBasisCellRef offsets basisCellRef =
  let degreeValue = cellDegree basisCellRef
      indexOffset = Map.findWithDefault 0 degreeValue (soBasisOffsets offsets)
   in basisCellRef
        { cellIndex = cellIndex basisCellRef + indexOffset
        }

advanceOffsets :: ScaffoldOffsets -> MacroScaffoldIR -> ScaffoldOffsets
advanceOffsets offsets scaffoldValue =
  offsets
    { soBasisOffsets = Map.unionWith (+) (soBasisOffsets offsets) (basisCardinalities scaffoldValue),
      soNodeOffset = soNodeOffset offsets + reebNodeCardinality scaffoldValue,
      soArcOffset = soArcOffset offsets + reebArcCardinality scaffoldValue,
      soSingularityOffset = soSingularityOffset offsets + singularityCardinality scaffoldValue,
      soLoopOffset = soLoopOffset offsets + harmonicLoopCardinality scaffoldValue
    }

basisCardinalities :: MacroScaffoldIR -> Map HomologicalDegree Int
basisCardinalities scaffoldValue =
  Map.fromListWith max
    ( fmap
        (\basisCellRef -> (cellDegree basisCellRef, cellIndex basisCellRef + 1))
        (scaffoldBasisRefs scaffoldValue)
    )

directionEncodingBasisRefs :: DirectionFieldEncoding -> [BasisCellRef]
directionEncodingBasisRefs encodingValue =
  case encodingValue of
    DirectionAngleEncoding phaseMap -> Map.keys phaseMap
    DirectionCochainEncoding coefficientMap -> Map.keys coefficientMap

representativeBasisRefs :: RepresentativeChain coefficient BasisCellRef -> [BasisCellRef]
representativeBasisRefs = fmap snd . representativeTerms

offsetReebNodeId :: Int -> ReebNodeId -> ReebNodeId
offsetReebNodeId nodeOffset (ReebNodeId nodeIdValue) =
  ReebNodeId (nodeIdValue + nodeOffset)

offsetReebArcId :: Int -> ReebArcId -> ReebArcId
offsetReebArcId arcOffset (ReebArcId arcIdValue) =
  ReebArcId (arcIdValue + arcOffset)

offsetSingularityId :: Int -> SingularityId -> SingularityId
offsetSingularityId singularityOffset (SingularityId singularityIdValue) =
  SingularityId (singularityIdValue + singularityOffset)

offsetHarmonicLoopId :: Int -> HarmonicLoopId -> HarmonicLoopId
offsetHarmonicLoopId loopOffset (HarmonicLoopId loopIdValue) =
  HarmonicLoopId (loopIdValue + loopOffset)