{-# LANGUAGE TypeApplications, AllowAmbiguousTypes #-}
module Main where
import Algebra (Group (..))
import Data.Fin (Fin, enum)
import Data.Foldable (toList)
import Data.Functor.Const
import Data.List (nub)
import Data.Natural.Class
import Data.Peano (Peano (..))
import Data.Universe.Class
import qualified Numeric.Natural as N
import Text.Printf
import Test.SmallCheck.Series
import Test.Tasty
import Test.Tasty.SmallCheck
import Data.Fin.Permutation
main :: IO ()
main = defaultMain . askOption $ \ (SmallCheckDepth d) ->
let go :: ∀ n . Natural n => [TestTree]
go = tests @n : go @(Succ n)
in testGroup "" (take (d+1) $ go @Zero)
tests :: ∀ n . Natural n => TestTree
tests =
localOption (SmallCheckDepth (product [1..n])) $
testGroup (printf "n = %d" (n :: N.Natural))
[testGroup "universe"
[testProperty "size" $ length theUniverse == product [1..n],
testProperty "uniquity" $ nub theUniverse == theUniverse],
testProperty "mempty-preserves-apply" $ apply (mempty :: Permutation n) enum == enum,
testProperty "<>-mempty" $ \ (p :: Permutation n) -> p == p <> mempty && p == mempty <> p,
testProperty "<>-assoc" $ \ (p :: Permutation n) q r -> p <> (q <> r) == (p <> q) <> r,
testProperty "<>-preserves-apply" $ \ (p :: Permutation n) q -> (apply p . apply q) enum == apply (p <> q) enum,
testProperty "inverse" $ \ (p :: Permutation n) -> mempty == p <> invert p,
testProperty "invert . invert = id" $ \ (p :: Permutation n) -> p == (invert . invert) p,
testProperty "swap-self-inverse" $ \ m n -> let p = swap m n :: Permutation n in p == invert p]
where n :: Integral a => a
n = (fromIntegral . getConst) (reify :: Const Peano n)
theUniverse = universe @(Permutation n)
instance (Monad m, Natural n) => Serial m (Fin n) where
series = generate $ \ d -> take (d+1) (toList enum)
instance (Monad m, Natural n) => Serial m (Permutation n) where
series = generate $ \ d -> take (d+1) universe