packages feed

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

module Moonlight.Homology.Pure.Topology.MacroScaffold.Compose
  ( MacroScaffoldCompositionError (..),
    StitchBoundarySide (..),
    StitchSupportSelection (..),
    StitchSupportRefinement (..),
    StitchSemantics (..),
    StitchRoute (..),
    StitchRouteKey (..),
    MacroScaffoldStitchError (..),
    composeMacroScaffoldsWithScopes,
    composeMacroScaffolds,
    stitchMacroScaffoldRoutes,
  )
where

import Control.Monad (foldM)
import Data.Function ((&))
import Data.List.NonEmpty (NonEmpty (..))
import qualified Data.List.NonEmpty as NonEmpty
import Data.Map.Strict (Map)
import qualified Data.Map.Strict as Map
import Data.Set (Set)
import qualified Data.Set as Set
import Moonlight.Homology.Pure.Carrier
  ( BasisCellRef,
  )
import Moonlight.Homology.Pure.Topology.MacroScaffold
  ( MacroScaffoldIR (..),
  )
import Moonlight.Homology.Pure.Topology.MacroScaffold.Compose.Core
  ( MacroScaffoldCompositionError (..),
  )
import Moonlight.Homology.Pure.Topology.MacroScaffold.Compose.Merge
  ( mergeScalarPotentialFields,
    mergeDirectionFields,
  )
import Moonlight.Homology.Pure.Topology.MacroScaffold.Compose.Reindex
  ( reebArcCardinality,
    scaffoldBasisRefs,
    traverseShiftedScaffolds,
  )
import Moonlight.Homology.Pure.Topology.MacroScaffold.Compose.Stitch
  ( MacroScaffoldStitchError (..),
    StitchBoundarySide (..),
    StitchRoute (..),
    StitchRouteKey (..),
    StitchSemantics (..),
    StitchSupportRefinement (..),
    StitchSupportSelection (..),
    stitchRoutePair,
    uniqueRoutePairs,
  )
import Moonlight.Homology.Pure.Topology.MacroScaffold.Reeb
  ( MorseReebScaffold (..),
  )

composeMacroScaffolds :: NonEmpty MacroScaffoldIR -> Either MacroScaffoldCompositionError MacroScaffoldIR
composeMacroScaffolds scaffolds =
  fmap fst
    ( composeMacroScaffoldsWithScopes
        (fmap (\scaffoldValue -> ((), scaffoldValue)) scaffolds)
    )

composeMacroScaffoldsWithScopes ::
  Ord label =>
  NonEmpty (label, MacroScaffoldIR) ->
  Either MacroScaffoldCompositionError (MacroScaffoldIR, Map label (Set BasisCellRef))
composeMacroScaffoldsWithScopes labeledScaffolds = do
  shiftedScaffolds <- traverseShiftedScaffolds labeledScaffolds
  scalarPotential <-
    mergeScalarPotentialFields
      (macroScaffoldScalarPotential . snd <$> shiftedScaffolds)
  directionField <-
    mergeDirectionFields
      (macroScaffoldDirectionField . snd <$> shiftedScaffolds)
  pure
    ( MacroScaffoldIR
        { macroScaffoldScalarPotential = scalarPotential,
          macroScaffoldReeb =
            MorseReebScaffold
              { morseReebNodes = NonEmpty.toList shiftedScaffolds >>= (morseReebNodes . macroScaffoldReeb . snd),
                morseReebArcs = NonEmpty.toList shiftedScaffolds >>= (morseReebArcs . macroScaffoldReeb . snd)
              },
          macroScaffoldDirectionField = directionField,
          macroScaffoldSingularities = NonEmpty.toList shiftedScaffolds >>= (macroScaffoldSingularities . snd),
          macroScaffoldHarmonicLoops = NonEmpty.toList shiftedScaffolds >>= (macroScaffoldHarmonicLoops . snd)
        },
      regionScopes shiftedScaffolds
    )

stitchMacroScaffoldRoutes ::
  (Ord route, Ord label) =>
  (route -> StitchSemantics) ->
  Map label (Set BasisCellRef) ->
  [StitchRoute route label] ->
  MacroScaffoldIR ->
  Either (MacroScaffoldStitchError label) (MacroScaffoldIR, Map (StitchRouteKey route label) (Set BasisCellRef))
stitchMacroScaffoldRoutes semanticsFor regionScopeMap routes scaffoldValue =
  let stitchedPairs = uniqueRoutePairs routes
      initialArcId = reebArcCardinality scaffoldValue
   in fmap
        (\(_, stitchedArcs, stitchScopes) ->
           ( scaffoldValue
               { macroScaffoldReeb =
                   (macroScaffoldReeb scaffoldValue)
                     { morseReebArcs =
                         morseReebArcs (macroScaffoldReeb scaffoldValue)
                           <> reverse stitchedArcs
                     }
               },
             stitchScopes
           )
        )
        ( foldM
            (stitchRoutePair semanticsFor regionScopeMap scaffoldValue)
            (initialArcId, [], Map.empty)
            stitchedPairs
        )

regionScopes :: Ord label => NonEmpty (label, MacroScaffoldIR) -> Map label (Set BasisCellRef)
regionScopes shiftedScaffolds =
  shiftedScaffolds
    & NonEmpty.toList
    & fmap (\(labelValue, scaffoldValue) -> (labelValue, Set.fromList (scaffoldBasisRefs scaffoldValue)))
    & Map.fromListWith Set.union