{-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TypeApplications #-} module Math.NumberTheory.Primes.SequenceTests ( testSuite ) where import Test.Tasty import Test.Tasty.HUnit import Data.Bits import Data.Maybe import Data.Proxy import Numeric.Natural import Math.NumberTheory.Primes import Math.NumberTheory.Primes.Counting (nthPrime, primeCount) import Math.NumberTheory.TestUtils nextPrimeProperty :: (Bits a, Integral a, UniqueFactorisation a) => AnySign a -> Bool nextPrimeProperty (AnySign n) = unPrime (nextPrime n) >= n precPrimeProperty :: (Bits a, Integral a, UniqueFactorisation a) => Positive a -> Bool precPrimeProperty (Positive n) = n <= 2 || unPrime (precPrime n) <= n toEnumProperty :: forall a. (Enum (Prime a), Integral a) => Proxy a -> Int -> Bool toEnumProperty _ n = n <= 0 || unPrime (toEnum n :: Prime a) == fromInteger (unPrime (nthPrime n)) fromEnumProperty :: (Enum (Prime a), Integral a) => Prime a -> Bool fromEnumProperty p = fromEnum p == fromInteger (primeCount (toInteger (unPrime p))) succProperty :: (Enum a, Enum (Prime a), Num a, UniqueFactorisation a) => Prime a -> Bool succProperty p = all (isNothing . isPrime) [unPrime p + 1 .. unPrime (succ p) - 1] predProperty :: (Enum a, Enum (Prime a), Ord a, Num a, UniqueFactorisation a) => Prime a -> Bool predProperty p = unPrime p <= 2 || all (isNothing . isPrime) [unPrime (pred p) + 1 .. unPrime p - 1] enumFrom2To2 :: Assertion enumFrom2To2 = assertEqual "should be equal" [two] [two..two] where two = minBound :: Prime Word enumFrom65500To65600 :: Assertion enumFrom65500To65600 = assertEqual "should be equal" [65519, 65521, 65537, 65539, 65543, 65551, 65557, 65563, 65579, 65581, 65587, 65599] (map unPrime [low..high]) where low = nextPrime (65500 :: Word) high = precPrime (65600 :: Word) enumFrom2To100000 :: Assertion enumFrom2To100000 = assertEqual "should be equal" (takeWhile (<= high) [low..]) [low..high] where low = minBound :: Prime Word high = precPrime (100000 :: Word) enumFromProperty :: (Ord a, Enum (Prime a)) => Prime a -> Prime a -> Bool enumFromProperty p q = [p..q] == takeWhile (<= q) [p..] enumFromToProperty :: (Eq a, Enum a, Enum (Prime a), UniqueFactorisation a) => Prime a -> Prime a -> Bool enumFromToProperty p q = [p..q] == mapMaybe isPrime [unPrime p .. unPrime q] enumFromThenProperty :: (Show a, Ord a, Enum (Prime a)) => Prime a -> Prime a -> Prime a -> Bool enumFromThenProperty p q r = case p `compare` q of LT -> enumFromThenTo p q r == takeWhile (<= r) (enumFromThen p q) EQ -> True GT -> enumFromThenTo p q r == takeWhile (>= r) (enumFromThen p q) enumFromThenToProperty :: (Ord a, Enum a, Enum (Prime a), UniqueFactorisation a, Show a) => Prime a -> Prime a -> Prime a -> Bool enumFromThenToProperty p q r | p == q && q <= r = True | otherwise = [p, q .. r] == mapMaybe isPrime [unPrime p, unPrime q .. unPrime r] testSuite :: TestTree testSuite = testGroup "Sequence" [ testIntegralPropertyNoLarge "nextPrime" nextPrimeProperty , testIntegralPropertyNoLarge "precPrime" precPrimeProperty , testGroup "toEnum" [ testSmallAndQuick "Int" (toEnumProperty (Proxy @Int)) , testSmallAndQuick "Word" (toEnumProperty (Proxy @Word)) , testSmallAndQuick "Integer" (toEnumProperty (Proxy @Integer)) , testSmallAndQuick "Natural" (toEnumProperty (Proxy @Natural)) ] , testGroup "fromEnum" [ testSmallAndQuick "Int" (fromEnumProperty @Int) , testSmallAndQuick "Word" (fromEnumProperty @Word) , testSmallAndQuick "Integer" (fromEnumProperty @Integer) , testSmallAndQuick "Natural" (fromEnumProperty @Natural) ] , testGroup "succ" [ testSmallAndQuick "Int" (succProperty @Int) , testSmallAndQuick "Word" (succProperty @Word) , testSmallAndQuick "Integer" (succProperty @Integer) , testSmallAndQuick "Natural" (succProperty @Natural) ] , testGroup "pred" [ testSmallAndQuick "Int" (predProperty @Int) , testSmallAndQuick "Word" (predProperty @Word) , testSmallAndQuick "Integer" (predProperty @Integer) , testSmallAndQuick "Natural" (predProperty @Natural) ] , testCase "[2..2] == [2]" enumFrom2To2 , testCase "[65500..65600]" enumFrom65500To65600 , testCase "[2..100000]" enumFrom2To100000 , testGroup "enumFrom" [ testSmallAndQuick "Int" (enumFromProperty @Int) , testSmallAndQuick "Word" (enumFromProperty @Word) , testSmallAndQuick "Integer" (enumFromProperty @Integer) , testSmallAndQuick "Natural" (enumFromProperty @Natural) ] , testGroup "enumFromTo" [ testSmallAndQuick "Int" (enumFromToProperty @Int) , testSmallAndQuick "Word" (enumFromToProperty @Word) , testSmallAndQuick "Integer" (enumFromToProperty @Integer) , testSmallAndQuick "Natural" (enumFromToProperty @Natural) ] , testGroup "enumFromThen" [ testSmallAndQuick "Int" (enumFromThenProperty @Int) , testSmallAndQuick "Word" (enumFromThenProperty @Word) , testSmallAndQuick "Integer" (enumFromThenProperty @Integer) , testSmallAndQuick "Natural" (enumFromThenProperty @Natural) ] , testGroup "enumFromThenTo" [ testSmallAndQuick "Int" (enumFromThenToProperty @Int) , testSmallAndQuick "Word" (enumFromThenToProperty @Word) , testSmallAndQuick "Integer" (enumFromThenToProperty @Integer) , testSmallAndQuick "Natural" (enumFromThenToProperty @Natural) ] ]