packages feed

moonlight-homology-0.1.0.0: src-laws/Moonlight/Homology/Effect/Laws.hs

module Moonlight.Homology.Effect.Laws
  ( BlockSchurHomologyAgreement (..),
    BlockSchurHomologyAgreementFailure (..),
    checkBlockSchurHomologyAgreement,
    checkBoundaryNilpotence,
    checkReductionLeftInverse,
    checkReductionHomotopy,
    checkReductionProjectionChainMap,
    checkReductionInclusionChainMap,
    mkReductionChecksFromSamples,
    normalizeCombination,
  )
where

import Data.Bifunctor (first)
import Data.Function ((&))
import Data.Kind (Type)
import Moonlight.Core (Ring)
import Moonlight.Homology.Pure.Backend
  ( HomologyBackend,
    HomologyBackendTag,
    homologyBackendTag,
    runHomologyBackend,
  )
import Moonlight.Homology.Pure.Failure (HomologyFailure (..), HomologyLaw (..))
import Moonlight.Homology.Pure.Group (HomologyGroup)
import Moonlight.Homology.Pure.LinearCombination qualified as LC
import Moonlight.Homology.Pure.Reductions
  ( ChainHomotopy (..),
    ChainMap (..),
    Reduction (..),
    ReductionChecks (..),
    ReductionLawContext (..),
    ReductionViolation (..),
  )
import Moonlight.Homology.Pure.Topology.BlockSchur
  ( BlockSchurReduction (..),
  )

type BlockSchurHomologyAgreement :: Type -> Type
data BlockSchurHomologyAgreement groupCoefficient = BlockSchurHomologyAgreement
  { bshaBackend :: !HomologyBackendTag,
    bshaGroupsByDegree :: ![(Int, HomologyGroup groupCoefficient)]
  }
  deriving stock (Eq, Show)

type BlockSchurHomologyAgreementFailure :: Type -> Type
data BlockSchurHomologyAgreementFailure groupCoefficient
  = BlockSchurOriginalBackendFailed !HomologyBackendTag !HomologyFailure
  | BlockSchurReducedBackendFailed !HomologyBackendTag !HomologyFailure
  | BlockSchurHomologyMismatch
      !HomologyBackendTag
      ![(Int, HomologyGroup groupCoefficient)]
      ![(Int, HomologyGroup groupCoefficient)]
  deriving stock (Eq, Show)

checkBlockSchurHomologyAgreement ::
  Eq groupCoefficient =>
  HomologyBackend coefficient groupCoefficient ->
  BlockSchurReduction coefficient ->
  Either (BlockSchurHomologyAgreementFailure groupCoefficient) (BlockSchurHomologyAgreement groupCoefficient)
checkBlockSchurHomologyAgreement backend reduction = do
  let backendTag = homologyBackendTag backend
  originalGroups <-
    first (BlockSchurOriginalBackendFailed backendTag) $
      homologyGroupsByDegree <$> runHomologyBackend backend (bsrOriginalComplex reduction)
  reducedGroups <-
    first (BlockSchurReducedBackendFailed backendTag) $
      homologyGroupsByDegree <$> runHomologyBackend backend (bsrReducedComplex reduction)
  if originalGroups == reducedGroups
    then
      Right
        BlockSchurHomologyAgreement
          { bshaBackend = backendTag,
            bshaGroupsByDegree = originalGroups
          }
    else Left (BlockSchurHomologyMismatch backendTag originalGroups reducedGroups)

normalizeCombination :: (Eq r, Ring r, Ord basis) => [(r, basis)] -> [(r, basis)]
normalizeCombination =
  LC.normalizeWith LC.ringArithmetic

composeCombination ::
  (Eq r, Ring r, Ord targetBasis) =>
  (sourceBasis -> [(r, targetBasis)]) ->
  [(r, sourceBasis)] ->
  [(r, targetBasis)]
composeCombination mapping combination =
  LC.composeWith LC.ringArithmetic mapping combination

checkBoundaryNilpotence ::
  (Eq r, Ring r, Ord basis) =>
  (basis -> [(r, basis)]) ->
  [basis] ->
  Either HomologyFailure ()
checkBoundaryNilpotence boundaryOf basisElements =
  LC.checkLawWith
    LC.ringArithmetic
    ChainNilpotenceLaw
    basisElements
    (const [])
    (composeCombination boundaryOf . boundaryOf)

checkReductionLeftInverse ::
  (Eq r, Ring r, Ord smallBasis) =>
  Reduction large small r largeBasis smallBasis ->
  [smallBasis] ->
  Either HomologyFailure ()
checkReductionLeftInverse reduction smallBasisElements =
  LC.checkLawWith
    LC.ringArithmetic
    ReductionLeftInverseLaw
    smallBasisElements
    (LC.identityWith LC.ringArithmetic)
    ( \smallBasisValue ->
        runChainMap (inclusion reduction) smallBasisValue
          & composeCombination (runChainMap (projection reduction))
    )

checkReductionHomotopy ::
  (Eq r, Ring r, Ord largeBasis) =>
  (largeBasis -> [(r, largeBasis)]) ->
  Reduction large small r largeBasis smallBasis ->
  [largeBasis] ->
  Either HomologyFailure ()
checkReductionHomotopy boundaryOf reduction largeBasisElements =
  LC.checkLawWith
    LC.ringArithmetic
    ReductionHomotopyLaw
    largeBasisElements
    ( \largeBasisValue ->
        LC.subtractWith
          LC.ringArithmetic
          (LC.identityWith LC.ringArithmetic largeBasisValue)
          ( runChainMap (projection reduction) largeBasisValue
              & composeCombination (runChainMap (inclusion reduction))
          )
    )
    ( \largeBasisValue ->
        LC.addWith
          LC.ringArithmetic
          (runChainHomotopy (homotopy reduction) largeBasisValue & composeCombination boundaryOf)
          (boundaryOf largeBasisValue & composeCombination (runChainHomotopy (homotopy reduction)))
    )

checkReductionProjectionChainMap ::
  (Eq r, Ring r, Ord smallBasis) =>
  (largeBasis -> [(r, largeBasis)]) ->
  (smallBasis -> [(r, smallBasis)]) ->
  Reduction large small r largeBasis smallBasis ->
  [largeBasis] ->
  Either HomologyFailure ()
checkReductionProjectionChainMap largeBoundaryOf smallBoundaryOf reduction largeBasisElements =
  LC.checkLawWith
    LC.ringArithmetic
    ReductionProjectionChainMapLaw
    largeBasisElements
    ( \largeBasisValue ->
        runChainMap (projection reduction) largeBasisValue
          & composeCombination smallBoundaryOf
    )
    ( \largeBasisValue ->
        largeBoundaryOf largeBasisValue
          & composeCombination (runChainMap (projection reduction))
    )

checkReductionInclusionChainMap ::
  (Eq r, Ring r, Ord largeBasis) =>
  (largeBasis -> [(r, largeBasis)]) ->
  (smallBasis -> [(r, smallBasis)]) ->
  Reduction large small r largeBasis smallBasis ->
  [smallBasis] ->
  Either HomologyFailure ()
checkReductionInclusionChainMap largeBoundaryOf smallBoundaryOf reduction smallBasisElements =
  LC.checkLawWith
    LC.ringArithmetic
    ReductionInclusionChainMapLaw
    smallBasisElements
    ( \smallBasisValue ->
        runChainMap (inclusion reduction) smallBasisValue
          & composeCombination largeBoundaryOf
    )
    ( \smallBasisValue ->
        smallBoundaryOf smallBasisValue
          & composeCombination (runChainMap (inclusion reduction))
    )

mkReductionChecksFromSamples ::
  (Eq r, Ring r, Ord largeBasis, Ord smallBasis) =>
  ReductionLawContext largeBasis smallBasis r ->
  ReductionChecks largeBasis smallBasis r
mkReductionChecksFromSamples lawContext =
  ReductionChecks
    { checkProjectionInclusionIdentity = \projectionMap inclusionMap ->
        Reduction
          { projection = projectionMap,
            inclusion = inclusionMap,
            homotopy = ChainHomotopy (const [])
          }
          & (\reduction -> checkReductionLeftInverse reduction (sampledSmallBasis lawContext))
          & first ProjectionInclusionIdentityViolation,
      checkInclusionProjectionHomotopy = \projectionMap inclusionMap homotopyMap ->
        Reduction
          { projection = projectionMap,
            inclusion = inclusionMap,
            homotopy = homotopyMap
          }
          & (\reduction -> checkReductionHomotopy (largeBoundary lawContext) reduction (sampledLargeBasis lawContext))
          & first InclusionProjectionHomotopyViolation,
      checkProjectionChainMap = \projectionMap ->
        Reduction
          { projection = projectionMap,
            inclusion = ChainMap (const []),
            homotopy = ChainHomotopy (const [])
          }
          & (\reduction -> checkReductionProjectionChainMap (largeBoundary lawContext) (smallBoundary lawContext) reduction (sampledLargeBasis lawContext))
          & first ProjectionChainMapViolation,
      checkInclusionChainMap = \inclusionMap ->
        Reduction
          { projection = ChainMap (const []),
            inclusion = inclusionMap,
            homotopy = ChainHomotopy (const [])
          }
          & (\reduction -> checkReductionInclusionChainMap (largeBoundary lawContext) (smallBoundary lawContext) reduction (sampledSmallBasis lawContext))
          & first InclusionChainMapViolation
    }

homologyGroupsByDegree :: [HomologyGroup groupCoefficient] -> [(Int, HomologyGroup groupCoefficient)]
homologyGroupsByDegree =
  zip [0 ..]