factory-0.0.0.2: src/Factory/Test/QuickCheck/PrimeFactorisation.hs
{-# LANGUAGE CPP #-}
{-# OPTIONS_GHC -fno-warn-orphans #-}
{-
Copyright (C) 2011 Dr. Alistair Ward
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
-}
{- |
[@AUTHOR@] Dr. Alistair Ward
[@DESCRIPTION@] Implements 'Test.QuickCheck.Arbitrary' and defines /QuickCheck/-properties for "Math.PrimeFactorisation".
-}
module Factory.Test.QuickCheck.PrimeFactorisation(
-- * Functions
quickChecks
) where
import qualified Data.List
import qualified Data.Numbers.Primes
import qualified Factory.Data.PrimeFactors as Data.PrimeFactors
import qualified Factory.Data.Exponential as Data.Exponential
import qualified Factory.Math.Implementations.PrimeFactorisation as Math.Implementations.PrimeFactorisation
import qualified Factory.Math.MultiplicativeOrder as Math.MultiplicativeOrder
import qualified Factory.Math.PrimeFactorisation as Math.PrimeFactorisation
import qualified Test.QuickCheck
import Test.QuickCheck((==>))
instance Test.QuickCheck.Arbitrary Math.Implementations.PrimeFactorisation.Algorithm where
arbitrary = Test.QuickCheck.oneof [
Test.QuickCheck.elements [
Math.Implementations.PrimeFactorisation.TrialDivision,
Math.Implementations.PrimeFactorisation.FermatsMethod
]
]
#if !(MIN_VERSION_QuickCheck(2,1,0))
coarbitrary = undefined --CAVEAT: stops warnings from ghc.
#endif
-- | Defines invariant properties.
quickChecks :: IO ()
quickChecks =
Test.QuickCheck.quickCheck prop_consistency
>> Test.QuickCheck.quickCheck `mapM_` [prop_primeFactors, prop_smoothness, prop_eulersTotientP, prop_eulersTotientInequality]
>> Test.QuickCheck.quickCheck `mapM_` [prop_eulersTotient, prop_lagrange, prop_multiplicativeOrder, prop_perfectPower]
where
prop_consistency :: Integer -> Test.QuickCheck.Property
prop_consistency i = Test.QuickCheck.label "prop_consistency" $ (Math.PrimeFactorisation.primeFactors Math.Implementations.PrimeFactorisation.TrialDivision i' :: Data.PrimeFactors.Factors Integer Int) == Math.PrimeFactorisation.primeFactors Math.Implementations.PrimeFactorisation.FermatsMethod i' where
i' :: Integer
i' = 1 + (i `mod` 1000000)
prop_primeFactors, prop_smoothness, prop_eulersTotientP, prop_eulersTotientInequality :: Math.Implementations.PrimeFactorisation.Algorithm -> Integer -> Test.QuickCheck.Property
prop_primeFactors algorithm i = Test.QuickCheck.label "prop_primeFactors" $ Data.PrimeFactors.product' (recip 2) {-TODO-} 10 (Math.PrimeFactorisation.primeFactors algorithm i') == i' where
i' :: Integer
i' = 1 + (i `mod` 1000000)
prop_smoothness algorithm i = Test.QuickCheck.label "prop_smoothness" $ (Math.PrimeFactorisation.smoothness algorithm !! (2 ^ i')) <= (2 :: Integer) where
i' :: Integer
i' = i `mod` 20
prop_eulersTotientP algorithm i = Test.QuickCheck.label "prop_eulersTotient" $ Math.PrimeFactorisation.eulersTotient algorithm prime == prime - 1 where
prime :: Integer
prime = Data.List.genericIndex Data.Numbers.Primes.primes (i `mod` 10000)
prop_eulersTotientInequality algorithm i = i `notElem` [2, 6] ==> Test.QuickCheck.label "prop_eulersTotientInequality" $ Math.PrimeFactorisation.eulersTotient algorithm i' >= floor (sqrt $ fromIntegral i' :: Double) where
i' = 1 + (i `mod` 100000)
prop_eulersTotient, prop_lagrange, prop_multiplicativeOrder, prop_perfectPower :: Math.Implementations.PrimeFactorisation.Algorithm -> Integer -> Integer -> Test.QuickCheck.Property
prop_eulersTotient algorithm i power = Test.QuickCheck.label "prop_eulersTotient" $ Math.PrimeFactorisation.eulersTotient algorithm (base ^ power') == (base ^ (power' - 1)) * (base - 1) where
base :: Integer
base = Data.List.genericIndex Data.Numbers.Primes.primes (i `mod` 8)
power' = 1 + (power `mod` 5)
prop_lagrange algorithm base modulus = gcd base modulus' == 1 ==> Test.QuickCheck.label "prop_lagrange" $ (Math.PrimeFactorisation.eulersTotient algorithm modulus' `rem` Math.MultiplicativeOrder.multiplicativeOrder algorithm base modulus') == 0 where
modulus' :: Integer
modulus' = 2 + abs modulus
prop_multiplicativeOrder algorithm base modulus = gcd base modulus' == 1 ==> Test.QuickCheck.label "prop_multiplicativeOrder" $ (
base ^ Math.MultiplicativeOrder.multiplicativeOrder algorithm base modulus'
) `mod` modulus' == 1 where
modulus' :: Integer
modulus' = 2 + abs modulus
prop_perfectPower algorithm b e = Test.QuickCheck.label "prop_perfectPower" $ foldr1 gcd (
map Data.Exponential.getExponent . Math.PrimeFactorisation.primeFactors algorithm $ (2 + b `mod` 10 :: Integer) ^ (2 + e `mod` 5)
) > 1