packages feed

moonlight-triangulation-1.4.0.2: bench/spade-compare/hs/Moonlight/Triangulation/Bench/SpadeCompare/Alpha.hs

{-# LANGUAGE DeriveAnyClass #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE DerivingStrategies #-}

-- | Matched end-to-end alpha-persistence work and its canonical receipt.
-- Input generation remains outside the timed action; Delaunay construction,
-- exact alpha births, cellular lowering, one reduction, and all critical-birth
-- Betti queries remain inside it.
module Moonlight.Triangulation.Bench.SpadeCompare.Alpha
  ( AlphaPersistenceObstruction (..)
  , AlphaPersistenceReceipt (..)
  , alphaPersistenceReceipt
  , renderAlphaPersistenceReceipt
  ) where

import Control.DeepSeq (NFData)
import Data.Bifunctor (first)
import Data.Bits (xor)
import Data.List (intercalate)
import Data.Vector (Vector)
import Data.Vector.Unboxed qualified as UnboxedVector
import Data.Word (Word64)
import GHC.Generics (Generic)
import Moonlight.Homology.Boundary
  ( degreeCardinality
  )
import Moonlight.Homology.Chain
  ( HomologicalDegree (..)
  , HomologyFailure
  , PersistencePair (..)
  )
import Moonlight.Homology.Persistence
  ( criticalBettiTableValues
  , filteredBaseComplex
  , filteredCriticalValues
  , mod2PersistentPairsWithCriticalBettiTable
  )
import Moonlight.Triangulation.Alpha
  ( AlphaFiltrationError
  , alphaFiltration
  )
import Moonlight.Triangulation.BulkLoad (delaunayGeometry)
import Moonlight.Triangulation.CellComplex
  ( DCELError
  , filteredAlphaComplex
  )
import Moonlight.Triangulation.Types
  ( BuildError
  , Point
  )

data AlphaPersistenceObstruction
  = AlphaPersistenceBuildRefused !BuildError
  | AlphaPersistenceBirthRefused !AlphaFiltrationError
  | AlphaPersistenceLoweringRefused !DCELError
  | AlphaPersistenceReductionRefused !HomologyFailure
  deriving stock (Eq, Show)

data AlphaPersistenceReceipt = AlphaPersistenceReceipt
  { alphaReceiptCriticalBirths :: !Int
  , alphaReceiptVertexCells :: !Int
  , alphaReceiptEdgeCells :: !Int
  , alphaReceiptFaceCells :: !Int
  , alphaReceiptFinitePairs :: !Int
  , alphaReceiptEssentialPairs :: !Int
  , alphaReceiptProfileChecksum :: !Word64
  }
  deriving stock (Eq, Show, Generic)
  deriving anyclass (NFData)

alphaPersistenceReceipt
  :: Vector Point
  -> Either AlphaPersistenceObstruction AlphaPersistenceReceipt
alphaPersistenceReceipt points = do
  triangulation <-
    first AlphaPersistenceBuildRefused (delaunayGeometry points)
  filtration <-
    first AlphaPersistenceBirthRefused (alphaFiltration triangulation)
  filtered <-
    first AlphaPersistenceLoweringRefused (filteredAlphaComplex filtration)
  (pairs, criticalBettiTable) <-
    first AlphaPersistenceReductionRefused
      (mod2PersistentPairsWithCriticalBettiTable filtered)
  let criticalBirths = filteredCriticalValues filtered
      finite = filteredBaseComplex filtered
      isFinitePair = maybe False (const True) . persistenceDeath
  pure
    AlphaPersistenceReceipt
      { alphaReceiptCriticalBirths = length criticalBirths
      , alphaReceiptVertexCells = degreeCardinality finite (HomologicalDegree 0)
      , alphaReceiptEdgeCells = degreeCardinality finite (HomologicalDegree 1)
      , alphaReceiptFaceCells = degreeCardinality finite (HomologicalDegree 2)
      , alphaReceiptFinitePairs = length (filter isFinitePair pairs)
      , alphaReceiptEssentialPairs = length (filter (not . isFinitePair) pairs)
      , alphaReceiptProfileChecksum =
          UnboxedVector.foldl'
            mixChecksum
            fnvOffset
            (criticalBettiTableValues criticalBettiTable)
      }

mixChecksum :: Word64 -> Int -> Word64
mixChecksum accumulator value =
  (accumulator `xor` fromIntegral value) * fnvPrime

fnvOffset :: Word64
fnvOffset = 14695981039346656037

fnvPrime :: Word64
fnvPrime = 1099511628211

renderAlphaPersistenceReceipt :: AlphaPersistenceReceipt -> String
renderAlphaPersistenceReceipt receipt =
  intercalate
    ","
    ( fmap
        show
        [ fromIntegral (alphaReceiptCriticalBirths receipt) :: Word64
        , fromIntegral (alphaReceiptVertexCells receipt)
        , fromIntegral (alphaReceiptEdgeCells receipt)
        , fromIntegral (alphaReceiptFaceCells receipt)
        , fromIntegral (alphaReceiptFinitePairs receipt)
        , fromIntegral (alphaReceiptEssentialPairs receipt)
        , alphaReceiptProfileChecksum receipt
        ]
    )