arithmoi-0.13.0.0: test-suite/Math/NumberTheory/SmoothNumbersTests.hs
-- |
-- Module: Math.NumberTheory.SmoothNumbersTests
-- Copyright: (c) 2018 Andrew Lelechenko
-- Licence: MIT
-- Maintainer: Andrew Lelechenko <andrew.lelechenko@gmail.com>
--
-- Tests for Math.NumberTheory.SmoothNumbersTests
--
{-# LANGUAGE TypeApplications #-}
{-# OPTIONS_GHC -fno-warn-type-defaults #-}
module Math.NumberTheory.SmoothNumbersTests
( testSuite
) where
import Prelude hiding (mod, rem)
import Test.Tasty
import Test.Tasty.HUnit
import Data.Coerce
import Data.Euclidean
import Data.List (nub)
import Data.List.Infinite (Infinite(..))
import qualified Data.List.Infinite as Inf
import Numeric.Natural
import Math.NumberTheory.Primes (Prime (..))
import qualified Math.NumberTheory.Quadratic.GaussianIntegers as G
import qualified Math.NumberTheory.Quadratic.EisensteinIntegers as E
import Math.NumberTheory.SmoothNumbers (SmoothBasis, fromList, isSmooth, smoothOver, smoothOver')
import Math.NumberTheory.TestUtils
isSmoothPropertyHelper
:: (Eq a, Num a, Euclidean a)
=> (a -> Integer)
-> Infinite a
-> Int
-> Int
-> Bool
isSmoothPropertyHelper norm primes' i1 i2 =
let primes = Inf.take i1 primes'
basis = fromList primes
in all (isSmooth basis) $ take i2 $ smoothOver' norm basis
isSmoothProperty1 :: Positive Int -> Positive Int -> Bool
isSmoothProperty1 (Positive i1) (Positive i2) =
isSmoothPropertyHelper G.norm (fmap unPrime G.primes) i1 i2
isSmoothProperty2 :: Positive Int -> Positive Int -> Bool
isSmoothProperty2 (Positive i1) (Positive i2) =
isSmoothPropertyHelper E.norm (fmap unPrime E.primes) i1 i2
smoothOverInRange :: Integral a => SmoothBasis a -> a -> a -> [a]
smoothOverInRange s lo hi
= takeWhile (<= hi)
$ dropWhile (< lo)
$ smoothOver s
smoothOverInRangeBF
:: (Eq a, Enum a, GcdDomain a)
=> SmoothBasis a
-> a
-> a
-> [a]
smoothOverInRangeBF prs lo hi
= coerce
$ filter (isSmooth prs)
$ coerce [lo..hi]
smoothOverInRangeProperty
:: (Show a, Integral a)
=> (SmoothBasis a, Positive a, Positive a)
-> ([a], [a])
smoothOverInRangeProperty (s, Positive lo', Positive diff') =
(map unwrapIntegral xs, map unwrapIntegral ys)
where
lo = WrapIntegral lo' `rem` 2^18
diff = WrapIntegral diff' `rem` 2^18
hi = lo + diff
xs = smoothOverInRange (coerce s) lo hi
ys = smoothOverInRangeBF (coerce s) lo hi
smoothNumbersAreUniqueProperty
:: (Show a, Integral a)
=> SmoothBasis a
-> Positive Int
-> Bool
smoothNumbersAreUniqueProperty s (Positive len)
= nub l == l
where
l = take len $ smoothOver s
isSmoothSpecialCase1 :: Assertion
isSmoothSpecialCase1 = assertBool "should be distinct" $ nub l == l
where
b = fromList [1+3*G.ι,6+8*G.ι]
l = take 10 $ map abs $ smoothOver' G.norm b
isSmoothSpecialCase2 :: Assertion
isSmoothSpecialCase2 = assertBool "should be smooth" $ isSmooth b 6
where
b = fromList [4, 3, 6, 10, 7::Int]
testSuite :: TestTree
testSuite = testGroup "SmoothNumbers"
[ testGroup "smoothOverInRange == smoothOverInRangeBF"
[ testEqualSmallAndQuick "Int" (smoothOverInRangeProperty @Int)
, testEqualSmallAndQuick "Word" (smoothOverInRangeProperty @Word)
, testEqualSmallAndQuick "Integer" (smoothOverInRangeProperty @Integer)
, testEqualSmallAndQuick "Natural" (smoothOverInRangeProperty @Natural)
]
, testGroup "smoothOver generates a list without duplicates"
[ testSmallAndQuick "Integer" (smoothNumbersAreUniqueProperty @Integer)
, testSmallAndQuick "Natural" (smoothNumbersAreUniqueProperty @Natural)
]
, testGroup "Quadratic rings"
[ testGroup "smoothOver generates valid smooth numbers"
[ testSmallAndQuick "Gaussian" isSmoothProperty1
, testSmallAndQuick "Eisenstein" isSmoothProperty2
]
, testCase "all distinct for base [1+3*i,6+8*i]" isSmoothSpecialCase1
, testCase "6 is smooth for base [4,3,6,10,7]" isSmoothSpecialCase2
]
]