packages feed

moonlight-category-0.1.0.0: bench/abstract/Algebraic/Galois.hs

{-# LANGUAGE TypeApplications #-}

module Algebraic.Galois
  ( galoisBenchmarks,
  )
where

import BenchSupport (batchWeight, sampleBatch512)
import Data.Function ((&))
import Moonlight.Category.Pure.Galois (GaloisConnection (..), OrdinalGalois (..))
import Test.Tasty.Bench (Benchmark, bench, bgroup, nf)

galoisBenchmarks :: Benchmark
galoisBenchmarks =
  bgroup
    "Galois"
    [ bench "alpha/gamma round trip batch x512" (nf galoisRoundTripBatchWeight sampleBatch512),
      bench "threshold enumeration batch x512" (nf (batchWeight galoisThresholdWeight) sampleBatch512)
    ]

newtype FineLevel = FineLevel {unFineLevel :: Int}
  deriving stock (Eq, Ord, Show)

newtype CoarseLevel = CoarseLevel {unCoarseLevel :: Int}
  deriving stock (Eq, Ord, Show)

instance GaloisConnection FineLevel CoarseLevel where
  alpha (FineLevel value) = CoarseLevel (value `div` 4)
  gamma (CoarseLevel value) = FineLevel (value * 4)

instance OrdinalGalois FineLevel CoarseLevel where
  thresholds =
    [ (FineLevel 0, CoarseLevel 0),
      (FineLevel 4, CoarseLevel 1),
      (FineLevel 8, CoarseLevel 2),
      (FineLevel 16, CoarseLevel 4)
    ]

galoisRoundTripBatchWeight :: [Int] -> Int
galoisRoundTripBatchWeight =
  sum . fmap (galoisRoundTripWeight . FineLevel)

galoisRoundTripWeight :: FineLevel -> Int
galoisRoundTripWeight fineValue =
  let coarseValue = alpha fineValue
      returnedFine = gamma coarseValue
   in unFineLevel fineValue + unCoarseLevel coarseValue + unFineLevel returnedFine

galoisThresholdWeight :: Int -> Int
galoisThresholdWeight seed =
  seed
    + ( thresholds @FineLevel @CoarseLevel
          & fmap (\(FineLevel fineValue, CoarseLevel coarseValue) -> fineValue + coarseValue + seed `mod` 3)
          & sum
      )