packages feed

arithmoi 0.4.1.3 → 0.4.2.0

raw patch · 44 files changed

+2526/−122 lines, 44 filesdep +QuickCheckdep +smallcheckdep +tastydep −hspecdep ~arithmoidep ~basedep ~ghc-primnew-uploaderPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

Dependencies added: QuickCheck, smallcheck, tasty, tasty-hunit, tasty-quickcheck, tasty-smallcheck

Dependencies removed: hspec

Dependency ranges changed: arithmoi, base, ghc-prim

API changes (from Hackage documentation)

- Math.NumberTheory.Primes.Testing.Certificates: alimit :: PrimalityArgument -> Integer
- Math.NumberTheory.Primes.Testing.Certificates: aprime :: PrimalityArgument -> Integer
- Math.NumberTheory.Primes.Testing.Certificates: compo :: CompositenessArgument -> Integer
- Math.NumberTheory.Primes.Testing.Certificates: factorList :: PrimalityArgument -> [(Integer, Int, Integer, PrimalityArgument)]
- Math.NumberTheory.Primes.Testing.Certificates: fermatBase :: CompositenessArgument -> Integer
- Math.NumberTheory.Primes.Testing.Certificates: firstDivisor :: CompositenessArgument -> Integer
- Math.NumberTheory.Primes.Testing.Certificates: largeFactor :: PrimalityArgument -> Integer
- Math.NumberTheory.Primes.Testing.Certificates: secondDivisor :: CompositenessArgument -> Integer
- Math.NumberTheory.Primes.Testing.Certificates: smallFactor :: PrimalityArgument -> Integer
+ Math.NumberTheory.GaussianIntegers: (.^) :: (Integral a) => GaussianInteger -> a -> GaussianInteger
+ Math.NumberTheory.GaussianIntegers: (:+) :: !Integer -> !Integer -> GaussianInteger
+ Math.NumberTheory.GaussianIntegers: [imag] :: GaussianInteger -> !Integer
+ Math.NumberTheory.GaussianIntegers: [real] :: GaussianInteger -> !Integer
+ Math.NumberTheory.GaussianIntegers: conjugate :: GaussianInteger -> GaussianInteger
+ Math.NumberTheory.GaussianIntegers: data GaussianInteger
+ Math.NumberTheory.GaussianIntegers: divG :: GaussianInteger -> GaussianInteger -> GaussianInteger
+ Math.NumberTheory.GaussianIntegers: divModG :: GaussianInteger -> GaussianInteger -> (GaussianInteger, GaussianInteger)
+ Math.NumberTheory.GaussianIntegers: factorise :: GaussianInteger -> [(GaussianInteger, Int)]
+ Math.NumberTheory.GaussianIntegers: findPrime :: Integer -> GaussianInteger
+ Math.NumberTheory.GaussianIntegers: findPrime' :: Integer -> GaussianInteger
+ Math.NumberTheory.GaussianIntegers: gcdG :: GaussianInteger -> GaussianInteger -> GaussianInteger
+ Math.NumberTheory.GaussianIntegers: gcdG' :: GaussianInteger -> GaussianInteger -> GaussianInteger
+ Math.NumberTheory.GaussianIntegers: infixr 8 .^
+ Math.NumberTheory.GaussianIntegers: instance GHC.Classes.Eq Math.NumberTheory.GaussianIntegers.GaussianInteger
+ Math.NumberTheory.GaussianIntegers: instance GHC.Num.Num Math.NumberTheory.GaussianIntegers.GaussianInteger
+ Math.NumberTheory.GaussianIntegers: instance GHC.Show.Show Math.NumberTheory.GaussianIntegers.GaussianInteger
+ Math.NumberTheory.GaussianIntegers: isPrime :: GaussianInteger -> Bool
+ Math.NumberTheory.GaussianIntegers: modG :: GaussianInteger -> GaussianInteger -> GaussianInteger
+ Math.NumberTheory.GaussianIntegers: norm :: GaussianInteger -> Integer
+ Math.NumberTheory.GaussianIntegers: primes :: [GaussianInteger]
+ Math.NumberTheory.GaussianIntegers: quotG :: GaussianInteger -> GaussianInteger -> GaussianInteger
+ Math.NumberTheory.GaussianIntegers: quotRemG :: GaussianInteger -> GaussianInteger -> (GaussianInteger, GaussianInteger)
+ Math.NumberTheory.GaussianIntegers: remG :: GaussianInteger -> GaussianInteger -> GaussianInteger
+ Math.NumberTheory.GaussianIntegers: ι :: GaussianInteger
+ Math.NumberTheory.Primes.Counting: approxPrimeCountOverestimateLimit :: Integral a => a
+ Math.NumberTheory.Primes.Counting: nthPrimeApproxUnderestimateLimit :: Integer
+ Math.NumberTheory.Primes.Counting: nthPrimeMaxArg :: Integer
+ Math.NumberTheory.Primes.Counting: primeCountMaxArg :: Integer
+ Math.NumberTheory.Primes.Factorisation: moebius :: Integer -> Integer
+ Math.NumberTheory.Primes.Factorisation: moebiusFromCanonical :: [(a, Int)] -> Integer
+ Math.NumberTheory.Primes.Factorisation: μ :: Integer -> Integer
+ Math.NumberTheory.Primes.Testing.Certificates: [aprime, alimit] :: PrimalityArgument -> Integer
+ Math.NumberTheory.Primes.Testing.Certificates: [aprime] :: PrimalityArgument -> Integer
+ Math.NumberTheory.Primes.Testing.Certificates: [compo, fermatBase] :: CompositenessArgument -> Integer
+ Math.NumberTheory.Primes.Testing.Certificates: [compo, firstDivisor, secondDivisor] :: CompositenessArgument -> Integer
+ Math.NumberTheory.Primes.Testing.Certificates: [compo] :: CompositenessArgument -> Integer
+ Math.NumberTheory.Primes.Testing.Certificates: [factorList] :: PrimalityArgument -> [(Integer, Int, Integer, PrimalityArgument)]
+ Math.NumberTheory.Primes.Testing.Certificates: [largeFactor, smallFactor] :: PrimalityArgument -> Integer
- Math.NumberTheory.Primes.Counting: nthPrimeApprox :: Integral a => a -> a
+ Math.NumberTheory.Primes.Counting: nthPrimeApprox :: Integer -> Integer
- Math.NumberTheory.Primes.Testing.Certificates: Division :: Integer -> Integer -> PrimalityArgument
+ Math.NumberTheory.Primes.Testing.Certificates: Division :: Integer -> PrimalityArgument
- Math.NumberTheory.Primes.Testing.Certificates: Divisors :: Integer -> Integer -> Integer -> CompositenessArgument
+ Math.NumberTheory.Primes.Testing.Certificates: Divisors :: Integer -> CompositenessArgument
- Math.NumberTheory.Primes.Testing.Certificates: Fermat :: Integer -> Integer -> CompositenessArgument
+ Math.NumberTheory.Primes.Testing.Certificates: Fermat :: Integer -> CompositenessArgument
- Math.NumberTheory.Primes.Testing.Certificates: Pock :: Integer -> Integer -> Integer -> [(Integer, Int, Integer, PrimalityArgument)] -> PrimalityArgument
+ Math.NumberTheory.Primes.Testing.Certificates: Pock :: Integer -> Integer -> [(Integer, Int, Integer, PrimalityArgument)] -> PrimalityArgument

Files

Changes view
@@ -1,3 +1,18 @@+0.4.2.0:+    This release supports GHC 7.6, 7.8 and 8.0.++    Add new cabal flag check-bounds, which replaces all unsafe array functions with safe ones.++    Add basic functions on Gaussian integers.+    Add Moebius mu-function.++    Forbid non-positive moduli in Math.NumberTheory.Moduli.++    Fix out-of-bounds error in Math.NumberTheory.Primes.Heap, Math.NumberTheory.Primes.Sieve and Math.NumberTheory.MoebiusInversion.+    Fix 32-bit build.+    Fix binaryGCD on negative numbers.+    Fix highestPower (various issues).+ 0.4.1.0:     Add integerLog10 variants at Bas van Dijk's request and expose     Math.NumberTheory.Powers.Integer, with an added integerWordPower.
Math/NumberTheory/GCD.hs view
@@ -83,10 +83,13 @@ binaryGCDImpl a 0 = abs a binaryGCDImpl 0 b = abs b binaryGCDImpl a b =-    case shiftToOddCount a of+    case shiftToOddCount a' of       (!za, !oa) ->-        case shiftToOddCount b of+        case shiftToOddCount b' of           (!zb, !ob) -> gcdOdd (abs oa) (abs ob) `shiftL` min za zb+    where+      a' = abs a+      b' = abs b  {-# SPECIALISE extendedGCD :: Int -> Int -> (Int, Int, Int),                               Word -> Word -> (Word, Word, Word),@@ -95,16 +98,21 @@ -- | Calculate the greatest common divisor of two numbers and coefficients --   for the linear combination. -----   Satisfies:+--   For signed types satisfies: -- -- > case extendedGCD a b of -- >   (d, u, v) -> u*a + v*b == d--- >--- > d == gcd a b+-- >                && d == gcd a b -----   and, for signed types,+--   For unsigned and bounded types the property above holds, but since @u@ and @v@ must also be unsigned,+--   the result may look weird. E. g., on 64-bit architecture ----- >+-- > extendedGCD (2 :: Word) (3 :: Word) == (1, 2^64-1, 1)+--+--   For unsigned and unbounded types (like 'Numeric.Natural.Natural') the result is undefined.+--+--   For signed types we also have+-- -- > abs u < abs b || abs b <= 1 -- > -- > abs v < abs a || abs a <= 1
+ Math/NumberTheory/GaussianIntegers.hs view
@@ -0,0 +1,238 @@+-- |+-- Module:      Math.NumberTheory.GaussianIntegers+-- Copyright:   (c) 2016 Chris Fredrickson+-- Licence:     MIT+-- Maintainer:  Chris Fredrickson <chris.p.fredrickson@gmail.com>+-- Stability:   Provisional+-- Portability: Non-portable (GHC extensions)+--+-- This module exports functions for manipulating Gaussian integers, including+-- computing their prime factorisations.+--++{-# LANGUAGE BangPatterns #-}+module Math.NumberTheory.GaussianIntegers (+    GaussianInteger((:+)),+    ι,+    real,+    imag,+    conjugate,+    norm,+    divModG,+    divG,+    modG,+    quotRemG,+    quotG,+    remG,+    (.^),+    isPrime,+    primes,+    gcdG,+    gcdG',+    findPrime,+    findPrime',+    factorise,+) where++import qualified Math.NumberTheory.Moduli as Moduli+import qualified Math.NumberTheory.Powers as Powers+import qualified Math.NumberTheory.Primes.Factorisation as Factorisation+import qualified Math.NumberTheory.Primes.Sieve as Sieve+import qualified Math.NumberTheory.Primes.Testing as Testing++infix 6 :++infixr 8 .^+-- |A Gaussian integer is a+bi, where a and b are both integers.+data GaussianInteger = (:+) { real :: !Integer, imag :: !Integer } deriving (Eq)++-- |The imaginary unit, where+--+-- > ι .^ 2 == -1+ι :: GaussianInteger+ι = 0 :+ 1++instance Show GaussianInteger where+    show (a :+ b)+        | b == 0     = show a+        | a == 0     = s ++ b'+        | otherwise  = show a ++ op ++ b'+        where+            b' = if abs b == 1 then "ι" else show (abs b) ++ "*ι"+            op = if b > 0 then "+" else "-"+            s  = if b > 0 then "" else "-"++instance Num GaussianInteger where+    (+) (a :+ b) (c :+ d) = (a + c) :+ (b + d)+    (*) (a :+ b) (c :+ d) = (a * c - b * d) :+ (a * d + b * c)+    abs z@(a :+ b)+        | a == 0 && b == 0 =   z             -- origin+        | a >  0 && b >= 0 =   z             -- first quadrant: (0, inf) x [0, inf)i+        | a <= 0 && b >  0 =   b  :+ (-a)    -- second quadrant: (-inf, 0] x (0, inf)i+        | a <  0 && b <= 0 = (-a) :+ (-b)    -- third quadrant: (-inf, 0) x (-inf, 0]i+        | otherwise        = (-b) :+   a     -- fourth quadrant: [0, inf) x (-inf, 0)i+    negate (a :+ b) = (-a) :+ (-b)+    fromInteger n = n :+ 0+    signum z@(a :+ b)+        | a == 0 && b == 0 = z               -- hole at origin+        | otherwise        = z `divG` abs z++-- |Simultaneous 'quot' and 'rem'.+quotRemG :: GaussianInteger -> GaussianInteger -> (GaussianInteger, GaussianInteger)+quotRemG = divHelper quot++-- |Gaussian integer division, truncating toward zero.+quotG :: GaussianInteger -> GaussianInteger -> GaussianInteger+n `quotG` d = q where (q,_) = quotRemG n d++-- |Gaussian integer remainder, satisfying+--+-- > (x `quotG` y)*y + (x `remG` y) == x+remG :: GaussianInteger -> GaussianInteger -> GaussianInteger+n `remG`  d = r where (_,r) = quotRemG n d++-- |Simultaneous 'div' and 'mod'.+divModG :: GaussianInteger -> GaussianInteger -> (GaussianInteger, GaussianInteger)+divModG = divHelper div++-- |Gaussian integer division, truncating toward negative infinity.+divG :: GaussianInteger -> GaussianInteger -> GaussianInteger+n `divG` d = q where (q,_) = divModG n d++-- |Gaussian integer remainder, satisfying+--+-- > (x `divG` y)*y + (x `modG` y) == x+modG :: GaussianInteger -> GaussianInteger -> GaussianInteger+n `modG` d = r where (_,r) = divModG n d++divHelper :: (Integer -> Integer -> Integer) -> GaussianInteger -> GaussianInteger -> (GaussianInteger, GaussianInteger)+divHelper divide g h =+    let nr :+ ni = g * conjugate h+        denom = norm h+        q = divide nr denom :+ divide ni denom+        p = h * q+    in (q, g - p)++-- |Conjugate a Gaussian integer.+conjugate :: GaussianInteger -> GaussianInteger+conjugate (r :+ i) = r :+ (-i)++-- |The square of the magnitude of a Gaussian integer.+norm :: GaussianInteger -> Integer+norm (x :+ y) = x * x + y * y++-- |Compute whether a given Gaussian integer is prime.+isPrime :: GaussianInteger -> Bool+isPrime g@(x :+ y)+    | x == 0 && y /= 0 = abs y `mod` 4 == 3 && Testing.isPrime y+    | y == 0 && x /= 0 = abs x `mod` 4 == 3 && Testing.isPrime x+    | otherwise        = Testing.isPrime $ norm g++-- |An infinite list of the Gaussian primes. Uses primes in Z to exhaustively+-- generate all Gaussian primes, but not quite in order of ascending magnitude.+primes :: [GaussianInteger]+primes = [ g+         | p <- Sieve.primes+         , g <- if p `mod` 4 == 3+                then [p :+ 0]+                else+                    if p == 2+                    then [1 :+ 1]+                    else let x :+ y = findPrime' p+                         in [x :+ y, y :+ x]+         ]++-- |Compute the GCD of two Gaussian integers. Enforces the precondition that each+-- integer must be in the first quadrant (or zero).+gcdG :: GaussianInteger -> GaussianInteger -> GaussianInteger+gcdG g h = gcdG' (abs g) (abs h)++-- |Compute the GCD of two Gauss integers. Does not check the precondition.+gcdG' :: GaussianInteger -> GaussianInteger -> GaussianInteger+gcdG' g h+    | h == 0    = g --done recursing+    | otherwise = gcdG' h (abs (g `modG` h))++-- |Find a Gaussian integer whose norm is the given prime number.+-- Checks the precondition that p is prime and that p `mod` 4 /= 3.+findPrime :: Integer -> GaussianInteger+findPrime p+    | p == 2 || (p `mod` 4 == 1 && Testing.isPrime p) = findPrime' p+    | otherwise = error "p must be prime, and not congruent to 3 (mod 4)"++-- |Find a Gaussian integer whose norm is the given prime number. Does not+-- check the precondition.+findPrime' :: Integer -> GaussianInteger+findPrime' p =+    let (Just c) = Moduli.sqrtModP (-1) p+        k  = Powers.integerSquareRoot p+        bs = [1 .. k]+        asbs = map (\b' -> ((b' * c) `mod` p, b')) bs+        (a, b) = head [ (a', b') | (a', b') <- asbs, a' <= k]+    in a :+ b++-- |Raise a Gaussian integer to a given power.+(.^) :: (Integral a) => GaussianInteger -> a -> GaussianInteger+a .^ e+    | e < 0 && norm a == 1 =+        case a of+            1    :+ 0 -> 1+            (-1) :+ 0 -> if even e then 1 else (-1)+            0    :+ 1 -> (0 :+ (-1)) .^ (abs e `mod` 4)+            _         -> (0 :+ 1) .^ (abs e `mod` 4)+    | e < 0     = error "Cannot exponentiate non-unit Gaussian Int to negative power"+    | a == 0    = 0+    | e == 0    = 1+    | even e    = s * s+    | otherwise = a * a .^ (e - 1)+    where+    s = a .^ div e 2++-- |Compute the prime factorization of a Gaussian integer. This is unique up to units (+/- 1, +/- i).+factorise :: GaussianInteger -> [(GaussianInteger, Int)]+factorise g+    | g == 0    = error "0 has no prime factorisation"+    | g == 1    = []+    | otherwise =+        let helper :: [(Integer, Int)] -> GaussianInteger -> [(GaussianInteger, Int)] -> [(GaussianInteger, Int)]+            helper [] g' fs = (if g' == 1 then [] else [(g', 1)]) ++ fs    -- include the unit, if it isn't 1+            helper ((!p, !e) : pt) g' fs+                | p `mod` 4 == 3 =+                    -- prime factors congruent to 3 mod 4 are simple.+                    let pow = div e 2+                        gp = fromInteger p+                    in helper pt (g' `divG` (gp .^ pow)) ((gp, pow) : fs)+                | otherwise      =+                    -- general case: for every prime factor of the magnitude+                    -- squared, find a Gaussian prime whose magnitude squared+                    -- is that prime. Then find out how many times the original+                    -- number is divisible by that Gaussian prime and its+                    -- conjugate. The order that the prime factors are+                    -- processed doesn't really matter, but it is reversed so+                    -- that the Gaussian primes will be in order of increasing+                    -- magnitude.+                    let gp = findPrime' p+                        (!gNext, !facs) = trialDivide g' [gp, abs $ conjugate gp] []+                    in helper pt gNext (facs ++ fs)+        in helper (reverse . Factorisation.factorise $ norm g) g []++-- Divide a Gaussian integer by a set of (relatively prime) Gaussian integers,+-- as many times as possible, and return the final quotient as well as a count+-- of how many times each factor divided the original.+trialDivide :: GaussianInteger -> [GaussianInteger] -> [(GaussianInteger, Int)] -> (GaussianInteger, [(GaussianInteger, Int)])+trialDivide g [] fs = (g, fs)+trialDivide g (pf : pft) fs+    | g `modG` pf == 0 =+        let (cnt, g') = countEvenDivisions g pf+        in trialDivide g' pft ((pf, cnt) : fs)+    | otherwise    = trialDivide g pft fs++-- Divide a Gaussian integer by a possible factor, and return how many times+-- the factor divided it evenly, as well as the result of dividing the original+-- that many times.+countEvenDivisions :: GaussianInteger -> GaussianInteger -> (Int, GaussianInteger)+countEvenDivisions g pf = helper g 0+    where+    helper :: GaussianInteger -> Int -> (Int, GaussianInteger)+    helper g' acc+        | g' `modG` pf == 0 = helper (g' `divG` pf) (1 + acc)+        | otherwise     = (acc, g')
Math/NumberTheory/Logarithms.hs view
@@ -36,10 +36,10 @@  import Data.Bits import Data.Array.Unboxed-import Data.Array.Base (unsafeAt)  import Math.NumberTheory.Logarithms.Internal import Math.NumberTheory.Powers.Integer+import Math.NumberTheory.Unsafe #if __GLASGOW_HASKELL__ < 707 import Math.NumberTheory.Utils  (isTrue#) #endif
Math/NumberTheory/Moduli.hs view
@@ -34,52 +34,50 @@  #include "MachDeps.h" -#if __GLASGOW_HASKELL__ < 709+#if __GLASGOW_HASKELL__ < 709 || WORD_SIZE_IN_BITS == 32 import Data.Word #endif import Data.Bits import Data.Array.Unboxed-import Data.Array.Base (unsafeAt)-import Data.Maybe (fromJust) import Data.List (nub) import Control.Monad (foldM, liftM2)  import Math.NumberTheory.Utils (shiftToOddCount, splitOff) import Math.NumberTheory.GCD (extendedGCD) import Math.NumberTheory.Primes.Heap (sieveFrom)+import Math.NumberTheory.Unsafe+ -- Guesstimated startup time for the Heap algorithm is lower than -- the cost to sieve an entire chunk. --- | Invert a number relative to a modulus.+-- | Invert a number relative to a positive modulus. --   If @number@ and @modulus@ are coprime, the result is --   @Just inverse@ where ----- >    (number * inverse) `mod` (abs modulus) == 1--- >    0 <= inverse < abs modulus+-- >    (number * inverse) `mod` modulus == 1+-- >    0 <= inverse < modulus -----   unless @modulus == 0@ and @abs number == 1@, in which case the---   result is @Just number@.---   If @gcd number modulus > 1@, the result is @Nothing@.+--   If @number `mod` modulus == 0@ or @gcd number modulus > 1@, the result is @Nothing@. invertMod :: Integer -> Integer -> Maybe Integer-invertMod k 0 = if k == 1 || k == (-1) then Just k else Nothing-invertMod k m = wrap $ go False 1 0 m' k'+invertMod k m+  | m <= 0 = error "Math.NumberTheory.Moduli.invertMod: non-positive modulus"+  | otherwise = wrap $ go False 1 0 m k'   where-    m' = abs m-    k' | r < 0     = r+m'+    k' | r < 0     = r+m        | otherwise = r          where-           r = k `rem` m'-    wrap x = case (x*k') `rem` m' of+           r = k `rem` m+    wrap x = case (x*k') `rem` m of                1 -> Just x                _ -> Nothing-    -- Calculate modular inverse of k' modulo m' by continued fraction expansion-    -- of m'/k', say [a_0,a_1,...,a_s]. Let the convergents be p_j/q_j.+    -- Calculate modular inverse of k' modulo m by continued fraction expansion+    -- of m/k', say [a_0,a_1,...,a_s]. Let the convergents be p_j/q_j.     -- Starting from j = -2, the arguments of go are-    -- (p_j/q_j) > m'/k', p_{j+1}, p_j, and n, d with n/d = [a_{j+2},...,a_s].-    -- Since m'/k' = p_s/q_s, and p_j*q_{j+1} - p_{j+1}*q_j = (-1)^(j+1), we have-    -- p_{s-1}*k' - q_{s-1}*m' = (-1)^s * gcd m' k', so if the inverse exists,+    -- (p_j/q_j) > m/k', p_{j+1}, p_j, and n, d with n/d = [a_{j+2},...,a_s].+    -- Since m/k' = p_s/q_s, and p_j*q_{j+1} - p_{j+1}*q_j = (-1)^(j+1), we have+    -- p_{s-1}*k' - q_{s-1}*m = (-1)^s * gcd m k', so if the inverse exists,     -- it is either p_{s-1} or -p_{s-1}, depending on whether s is even or odd.-    go !b _ po _ 0 = if b then po else (m'-po)+    go !b _ po _ 0 = if b then po else (m-po)     go b !pn po n d = case n `quotRem` d of                         (q,r) -> go (not b) (q*pn+po) pn d r @@ -161,7 +159,7 @@ -- -- > powerMod base exponent modulus -----   calculates @(base ^ exponent) \`mod\` modulus@ by repeated squaring and reduction.+--   calculates @(base ^ exponent) \`mod\` modulus@ by repeated squaring and reduction. Modulus must be positive. --   If @exponent < 0@ and @base@ is invertible modulo @modulus@, @(inverse ^ |exponent|) \`mod\` modulus@ --   is calculated. This function does some input checking and sanitation before calling the unsafe worker. {-# RULES@@ -176,18 +174,17 @@   #-} powerModImpl :: (Integral a, Bits a) => Integer -> a -> Integer -> Integer powerModImpl base expo md-  | md == 0     = base ^ expo-  | md' == 1    = 0+  | md <= 0     = error "Math.NumberTheory.Moduli.powerMod: non-positive modulus"+  | md == 1     = 0   | expo == 0   = 1   | bse' == 1   = 1-  | expo < 0    = case invertMod bse' md' of-                    Just i  -> powerMod'Impl i (negate expo) md'+  | expo < 0    = case invertMod bse' md of+                    Just i  -> powerMod'Impl i (negate expo) md                     Nothing -> error "Math.NumberTheory.Moduli.powerMod: Base isn't invertible with respect to modulus"   | bse' == 0   = 0-  | otherwise   = powerMod'Impl bse' expo md'+  | otherwise   = powerMod'Impl bse' expo md     where-      md' = abs md-      bse' = if base < 0 || md' <= base then base `mod` md' else base+      bse' = if base < 0 || md <= base then base `mod` md else base  -- | Modular power worker without input checking. --   Assumes all arguments strictly positive and modulus greater than 1.@@ -213,21 +210,20 @@ -- | Specialised version of 'powerMod' for 'Integer' exponents. --   Reduces the number of shifts of the exponent since shifting --   large 'Integer's is expensive. Call this function directly---   if you don't want or can't rely on rewrite rules.+--   if you don't want or can't rely on rewrite rules. Modulus must be positive. powerModInteger :: Integer -> Integer -> Integer -> Integer powerModInteger base ex mdl-  | mdl == 0    = base ^ ex-  | mdl' == 1   = 0+  | mdl <= 0     = error "Math.NumberTheory.Moduli.powerModInteger: non-positive modulus"+  | mdl == 1    = 0   | ex == 0     = 1-  | ex < 0      = case invertMod bse' mdl' of-                    Just i  -> powerModInteger' i (negate ex) mdl'+  | ex < 0      = case invertMod bse' mdl of+                    Just i  -> powerModInteger' i (negate ex) mdl                     Nothing -> error "Math.NumberTheory.Moduli.powerMod: Base isn't invertible with respect to modulus"   | bse' == 0   = 0   | bse' == 1   = 1-  | otherwise   = powerModInteger' bse' ex mdl'+  | otherwise   = powerModInteger' bse' ex mdl     where-      mdl' = abs mdl-      bse' = if base < 0 || mdl' <= base then base `mod` mdl' else base+      bse' = if base < 0 || mdl <= base then base `mod` mdl else base  -- | Specialised worker without input checks. Makes the same assumptions --   as the general version 'powerMod''.@@ -322,7 +318,7 @@                         _      -> []  -- | @sqrtModP' square prime@ finds a square root of @square@ modulo---   prime. @prime@ /must/ be a (positive) prime, and @sqaure@ /must/ be a+--   prime. @prime@ /must/ be a (positive) prime, and @square@ /must/ be a positive --   quadratic residue modulo @prime@, i.e. @'jacobi square prime == 1@. --   The precondition is /not/ checked. sqrtModP' :: Integer -> Integer -> Integer@@ -333,7 +329,7 @@  -- | @tonelliShanks square prime@ calculates a square root of @square@ --   modulo @prime@, where @prime@ is a prime of the form @4*k + 1@ and---   @square@ is a quadratic residue modulo @prime@, using the+--   @square@ is a positive quadratic residue modulo @prime@, using the --   Tonelli-Shanks algorithm. --   No checks on the input are performed. tonelliShanks :: Integer -> Integer -> Integer@@ -366,15 +362,15 @@ sqrtModPP :: Integer -> (Integer,Int) -> Maybe Integer sqrtModPP n (2,e) = sqM2P n e sqrtModPP n (prime,expo) = case sqrtModP n prime of-                             Just r -> Just $ fixup r+                             Just r -> fixup r                              _      -> Nothing   where     fixup r = let diff' = r*r-n               in if diff' == 0-                   then r+                   then Just r                    else case splitOff prime diff' of-                          (e,q) | expo <= e -> r-                                | otherwise -> hoist (fromJust $ invertMod (2*r) prime) r (q `mod` prime) (prime^e)+                          (e,q) | expo <= e -> Just r+                                | otherwise -> fmap (\inv -> hoist inv r (q `mod` prime) (prime^e)) (invertMod (2*r) prime)                       --     hoist inv root elim pp         | diff' == 0    = root'@@ -418,13 +414,17 @@ -- | @sqrtModF n primePowers@ calculates a square root of @n@ modulo --   @product [p^k | (p,k) <- primePowers]@ if one exists and all primes --   are distinct.+--   The list must be non-empty, @n@ must be coprime with all primes. sqrtModF :: Integer -> [(Integer,Int)] -> Maybe Integer+sqrtModF _ []  = Nothing sqrtModF n pps = do roots <- mapM (sqrtModPP n) pps                     chineseRemainder $ zip roots (map (uncurry (^)) pps)  -- | @sqrtModFList n primePowers@ calculates all square roots of @n@ modulo --   @product [p^k | (p,k) <- primePowers]@ if all primes are distinct.+--   The list must be non-empty, @n@ must be coprime with all primes. sqrtModFList :: Integer -> [(Integer,Int)] -> [Integer]+sqrtModFList _ []  = [] sqrtModFList n pps = map fst $ foldl1 (liftM2 comb) cs   where     ms :: [Integer]@@ -439,6 +439,7 @@ --   square roots of @n@ modulo @prime^expo@. The same restriction --   as in 'sqrtModPP' applies to the arguments. sqrtModPPList :: Integer -> (Integer,Int) -> [Integer]+sqrtModPPList n (2,1) = [n `mod` 2] sqrtModPPList n (2,expo)     = case sqM2P n expo of         Just r -> let m = 1 `shiftL` (expo-1)@@ -458,13 +459,14 @@ -- > r ≡ r_k (mod m_k) -- > -----   if all moduli are pairwise coprime. If not all moduli are---   pairwise coprime, the result is @Nothing@ regardless of whether+--   if all moduli are positive and pairwise coprime. Otherwise+--   the result is @Nothing@ regardless of whether --   a solution exists. chineseRemainder :: [(Integer,Integer)] -> Maybe Integer chineseRemainder remainders = foldM addRem 0 remainders   where     !modulus = product (map snd remainders)+    addRem acc (_,1) = Just acc     addRem acc (r,m) = do         let cf = modulus `quot` m         inv <- invertMod cf m@@ -489,21 +491,21 @@                         Int -> Bool,                         Word -> Bool   #-}-evenI :: (Integral a, Bits a) => a -> Bool+evenI :: Integral a => a -> Bool evenI n = fromIntegral n .&. 1 == (0 :: Int)  {-# SPECIALISE rem4 :: Integer -> Int,                        Int -> Int,                        Word -> Int   #-}-rem4 :: (Integral a, Bits a) => a -> Int+rem4 :: Integral a => a -> Int rem4 n = fromIntegral n .&. 3  {-# SPECIALISE rem8 :: Integer -> Int,                        Int -> Int,                        Word -> Int   #-}-rem8 :: (Integral a, Bits a) => a -> Int+rem8 :: Integral a => a -> Int rem8 n = fromIntegral n .&. 7  jac2 :: UArray Int Int
Math/NumberTheory/MoebiusInversion.hs view
@@ -15,10 +15,11 @@     ) where  import Data.Array.ST-import Data.Array.Base+import Control.Monad import Control.Monad.ST  import Math.NumberTheory.Powers.Squares+import Math.NumberTheory.Unsafe  -- | @totientSum n@ is, for @n > 0@, the sum of @[totient k | k <- [1 .. n]]@, --   computed via generalised Moebius inversion.@@ -69,7 +70,7 @@ --   Since the function arguments are used as array indices, the domain of --   @f@ is restricted to 'Int'. -----   The value @f n@ is then computed by @generalInversion g n@). Note that when+--   The value @f n@ is then computed by @generalInversion g n@. Note that when --   many values of @f@ are needed, there are far more efficient methods, this --   method is only appropriate to compute isolated values of @f@. generalInversion :: (Int -> Integer) -> Int -> Integer@@ -90,7 +91,8 @@         small <- newArray_ (0,mk0) :: ST s (STArray s Int Integer)         unsafeWrite small 0 0         unsafeWrite small 1 $! (fun 1)-        unsafeWrite small 2 $! (fun 2 - fun 1)+        when (mk0 >= 2) $+            unsafeWrite small 2 $! (fun 2 - fun 1)         let calcit switch change i                 | mk0 < i   = return (switch,change)                 | i == change = calcit (switch+1) (change + 4*switch+6) i
Math/NumberTheory/MoebiusInversion/Int.hs view
@@ -16,11 +16,11 @@     ) where  import Data.Array.ST-import Data.Array.Base+import Control.Monad import Control.Monad.ST  import Math.NumberTheory.Powers.Squares-+import Math.NumberTheory.Unsafe  -- | @totientSum n@ is, for @n > 0@, the sum of @[totient k | k <- [1 .. n]]@, --   computed via generalised Moebius inversion.@@ -71,11 +71,12 @@ --   That bears the risk of overflow, however, so be sure to use it only when it's --   safe. -----   The value @f n@ is then computed by @generalInversion g n@). Note that when+--   The value @f n@ is then computed by @generalInversion g n@. Note that when --   many values of @f@ are needed, there are far more efficient methods, this --   method is only appropriate to compute isolated values of @f@. generalInversion :: (Int -> Int) -> Int -> Int generalInversion fun n+    | n < 1     = error "Moebius inversion only defined on positive domain"     | n == 1    = fun 1     | n == 2    = fun 2 - fun 1     | n == 3    = fun 3 - 2*fun 1@@ -91,7 +92,8 @@         small <- newArray_ (0,mk0) :: ST s (STUArray s Int Int)         unsafeWrite small 0 0         unsafeWrite small 1 (fun 1)-        unsafeWrite small 2 (fun 2 - fun 1)+        when (mk0 >= 2) $+            unsafeWrite small 2 (fun 2 - fun 1)         let calcit switch change i                 | mk0 < i   = return (switch,change)                 | i == change = calcit (switch+1) (change + 4*switch+6) i
Math/NumberTheory/Powers/Cubes.hs view
@@ -21,7 +21,6 @@ #include "MachDeps.h"  import Data.Array.Unboxed-import Data.Array.Base import Data.Array.ST  import Data.Bits@@ -34,6 +33,7 @@ import GHC.Integer.GMP.Internals  import Math.NumberTheory.Logarithms.Internal (integerLog2#)+import Math.NumberTheory.Unsafe #if __GLASGOW_HASKELL__ < 707 import Math.NumberTheory.Utils (isTrue#) #endif@@ -61,9 +61,9 @@ --   that is, the largest integer @r@ such that @r^3 <= n@. --   The precondition @n >= 0@ is not checked. {-# RULES-"integerCubeRoot'/Int"  integerCubeRoot' = cubeRootInt'-"integerCubeRoot'/Word" integerCubeRoot' = cubeRootWord-"integerCubeRoot'/Igr"  integerCubeRoot' = cubeRootIgr+"integerCubeRoot'/Int"     integerCubeRoot' = cubeRootInt'+"integerCubeRoot'/Word"    integerCubeRoot' = cubeRootWord+"integerCubeRoot'/Integer" integerCubeRoot' = cubeRootIgr   #-} {-# INLINE [1] integerCubeRoot' #-} integerCubeRoot' :: Integral a => a -> a
Math/NumberTheory/Powers/Fourth.hs view
@@ -26,7 +26,6 @@  import Data.Array.Unboxed import Data.Array.ST-import Data.Array.Base (unsafeAt, unsafeWrite)  import Data.Bits #if __GLASGOW_HASKELL__ < 705@@ -34,6 +33,7 @@ #endif  import Math.NumberTheory.Logarithms.Internal (integerLog2#)+import Math.NumberTheory.Unsafe #if __GLASGOW_HASKELL__ < 707 import Math.NumberTheory.Utils (isTrue#) #endif@@ -41,6 +41,10 @@ -- | Calculate the integer fourth root of a nonnegative number, --   that is, the largest integer @r@ with @r^4 <= n@. --   Throws an error on negaitve input.+{-# SPECIALISE integerFourthRoot :: Int -> Int,+                                    Integer -> Integer,+                                    Word -> Word+  #-} integerFourthRoot :: Integral a => a -> a integerFourthRoot n     | n < 0     = error "integerFourthRoot: negative argument"@@ -50,9 +54,9 @@ --   that is, the largest integer @r@ with @r^4 <= n@. --   The condition is /not/ checked. {-# RULES-"integerFourthRoot'/Int"  integerFourthRoot' = biSqrtInt-"integerFourthRoot'/Word" integerFourthRoot' = biSqrtWord-"integerFourthRoot'/Igr"  integerFourthRoot' = biSqrtIgr+"integerFourthRoot'/Int"     integerFourthRoot' = biSqrtInt+"integerFourthRoot'/Word"    integerFourthRoot' = biSqrtWord+"integerFourthRoot'/Integer" integerFourthRoot' = biSqrtIgr   #-} {-# INLINE [1] integerFourthRoot' #-} integerFourthRoot' :: Integral a => a -> a
Math/NumberTheory/Powers/General.hs view
@@ -162,14 +162,17 @@ --   of the prime exponents if some have been found, otherwise by trying --   prime exponents recursively. highestPower :: Integral a => a -> (a, Int)-highestPower n-  | abs n <= 1  = (n,3)-  | n < 0       = case integerHighPower (toInteger $ negate n) of+highestPower n'+  | abs n <= 1  = (n', 3)+  | n < 0       = case integerHighPower (negate n) of                     (r,e) -> case shiftToOddCount e of                                (k, o) -> (negate $ fromInteger (sqr k r), o)-  | otherwise   = case integerHighPower (toInteger n) of+  | otherwise   = case integerHighPower n of                     (r,e) -> (fromInteger r, e)     where+      n :: Integer+      n = toInteger n'+       sqr :: Int -> Integer -> Integer       sqr 0 m = m       sqr k m = sqr (k-1) (m*m)@@ -199,7 +202,8 @@ newtonK :: Integral a => a -> a -> a -> a newtonK k n a = go (step a)   where-    step m = ((k-1)*m + n `quot` (m^(k-1))) `quot` k+    -- Beware integer overflow in m^(k-1)+    step m = ((k-1)*m + fromInteger (toInteger n `quot` (toInteger m^(k-1)))) `quot` k     go m       | l < m     = go l       | otherwise = m@@ -321,13 +325,14 @@                           | otherwise -> go (Set.fromDistinctAscList $ takeWhile (<= mx) $ take (k+1) (iterate (*2) 1)) o iops   where     mset k st = fst (Set.split (mx+1) (Set.mapMonotonic (*k) st))+    -- unP p m = (k, m / p ^ k), where k is as large as possible such that p ^ k still divides m     unP :: Int -> Int -> (Int,Int)     unP p m = goP 0 m       where         goP :: Int -> Int -> (Int,Int)-        goP !i j = case m `quotRem` p of+        goP !i j = case j `quotRem` p of                      (q,r) | r == 0 -> goP (i+1) q-                           | otherwise -> (0,j)+                           | otherwise -> (i,j)     iops :: [Int]     iops = 3:5:prs     prs :: [Int]@@ -343,5 +348,6 @@       | otherwise =         case unP p m of           (0,_) -> go st m ps-          (k,r) -> go (Set.unions (st:take k (iterate (mset p) st))) r ps+          -- iterate f x = [x, f x, f (f x)...]+          (k,r) -> go (Set.unions (take (k + 1) (iterate (mset p) st))) r ps     go st m [] = go st m [m+1]
Math/NumberTheory/Powers/Squares.hs view
@@ -29,7 +29,6 @@  import Data.Array.Unboxed import Data.Array.ST-import Data.Array.Base (unsafeAt, unsafeWrite)  import Data.Bits #if __GLASGOW_HASKELL__ < 705@@ -37,6 +36,7 @@ #endif  import Math.NumberTheory.Logarithms.Internal (integerLog2#)+import Math.NumberTheory.Unsafe #if __GLASGOW_HASKELL__ < 707 import Math.NumberTheory.Utils (isTrue#) #endif
Math/NumberTheory/Primes/Counting.hs view
@@ -11,10 +11,14 @@ module Math.NumberTheory.Primes.Counting     ( -- * Exact functions       primeCount+    , primeCountMaxArg     , nthPrime+    , nthPrimeMaxArg       -- * Approximations     , approxPrimeCount+    , approxPrimeCountOverestimateLimit     , nthPrimeApprox+    , nthPrimeApproxUnderestimateLimit     ) where  import Math.NumberTheory.Primes.Counting.Impl
Math/NumberTheory/Primes/Counting/Approximate.hs view
@@ -12,24 +12,37 @@ {-# OPTIONS_HADDOCK hide #-} module Math.NumberTheory.Primes.Counting.Approximate     ( approxPrimeCount+    , approxPrimeCountOverestimateLimit     , nthPrimeApprox+    , nthPrimeApproxUnderestimateLimit     ) where --- | @'approxPrimeCount' n@ gives (for @n > 0@) an+-- For prime p = 3742914359 we have+--   approxPrimeCount p = 178317879+--         primeCount p = 178317880++-- | Following property holds:+--+-- > approxPrimeCount n >= primeCount n || n >= approxPrimeCountOverestimateLimit+approxPrimeCountOverestimateLimit :: Integral a => a+approxPrimeCountOverestimateLimit = 3742914359++-- | @'approxPrimeCount' n@ gives an --   approximation of the number of primes not exceeding --   @n@. The approximation is fairly good for @n@ large enough.---   The number of primes should be slightly overestimated---   (so it is suitable for allocation of storage) and is---   never underestimated for @n <= 10^12@. approxPrimeCount :: Integral a => a -> a-approxPrimeCount = truncate . appi . fromIntegral+approxPrimeCount = truncate . max 0 . appi . fromIntegral --- | @'nthPrimeApprox' n@ gives (for @n > 0@) an+-- | Following property holds:+--+-- > nthPrimeApprox n <= nthPrime n || n >= nthPrimeApproxUnderestimateLimit+nthPrimeApproxUnderestimateLimit :: Integer+nthPrimeApproxUnderestimateLimit = 1000000000000++-- | @'nthPrimeApprox' n@ gives an --   approximation to the n-th prime. The approximation---   is fairly good for @n@ large enough. Dual to---   @'approxPrimeCount'@, this estimate should err---   on the low side (and does for @n < 10^12@).-nthPrimeApprox :: Integral a => a -> a+--   is fairly good for @n@ large enough.+nthPrimeApprox :: Integer -> Integer nthPrimeApprox = max 1 . truncate . nthApp . fromIntegral . max 3  -- Basically the approximation of the prime count by Li(x),
Math/NumberTheory/Primes/Counting/Impl.hs view
@@ -13,7 +13,12 @@ {-# OPTIONS_GHC -fspec-constr-count=24 #-} #endif {-# OPTIONS_HADDOCK hide #-}-module Math.NumberTheory.Primes.Counting.Impl (primeCount, nthPrime) where+module Math.NumberTheory.Primes.Counting.Impl+    ( primeCount+    , primeCountMaxArg+    , nthPrime+    , nthPrimeMaxArg+    ) where  #include "MachDeps.h" @@ -23,8 +28,8 @@ import Math.NumberTheory.Powers.Squares import Math.NumberTheory.Powers.Cubes import Math.NumberTheory.Logarithms+import Math.NumberTheory.Unsafe -import Data.Array.Base import Data.Array.ST #if !MIN_VERSION_array(0,5,0)     hiding (unsafeThaw)@@ -39,10 +44,14 @@ #define COUNT_T Int #endif +-- | Maximal allowed argument of 'primeCount'. Currently 8e18.+primeCountMaxArg :: Integer+primeCountMaxArg = 8000000000000000000+ -- | @'primeCount' n == &#960;(n)@ is the number of (positive) primes not exceeding @n@. -- --   For efficiency, the calculations are done on 64-bit signed integers, therefore @n@ must---   not exceed @8 * 10^18@.+--   not exceed 'primeCountMaxArg'. -- --   Requires @/O/(n^0.5)@ space, the time complexity is roughly @/O/(n^0.7)@. --   For small bounds, @'primeCount' n@ simply counts the primes not exceeding @n@,@@ -51,7 +60,7 @@ --   <http://en.wikipedia.org/wiki/Prime_counting_function#Algorithms_for_evaluating_.CF.80.28x.29>. primeCount :: Integer -> Integer primeCount n-    | n > 8000000000000000000   = error $ "primeCount: can't handle bound " ++ show n+    | n > primeCountMaxArg = error $ "primeCount: can't handle bound " ++ show n     | n < 2     = 0     | n < 1000  = fromIntegral . length . takeWhile (<= n) . primeList . primeSieve $ max 242 n     | n < 30000 = runST $ do@@ -69,15 +78,19 @@             !pdf = sieveCount ub cs sr         in phn1 - pdf +-- | Maximal allowed argument of 'nthPrime'. Currently 1.5e17.+nthPrimeMaxArg :: Integer+nthPrimeMaxArg = 150000000000000000+ -- | @'nthPrime' n@ calculates the @n@-th prime. Numbering of primes is --   @1@-based, so @'nthPrime' 1 == 2@. -- --   Requires @/O/((n*log n)^0.5)@ space, the time complexity is roughly @/O/((n*log n)^0.7@.---   The argument must be strictly positive, and must not exceed @1.5 * 10^17@.+--   The argument must be strictly positive, and must not exceed 'nthPrimeMaxArg'. nthPrime :: Integer -> Integer nthPrime n     | n < 1         = error "Prime indexing starts at 1"-    | n > 150000000000000000    = error $ "nthPrime: can't handle index " ++ show n+    | n > nthPrimeMaxArg = error $ "nthPrime: can't handle index " ++ show n     | n < 200000    = nthPrimeCt n     | ct0 < n       = tooLow n p0 (n-ct0) approxGap     | otherwise     = tooHigh n p0 (ct0-n) approxGap
Math/NumberTheory/Primes/Factorisation.hs view
@@ -48,6 +48,10 @@     , carmichaelSieve     , sieveCarmichael     , carmichaelFromCanonical+      -- * Moebius function+    , moebius+    , μ+    , moebiusFromCanonical       -- * Divisors     , divisors     , tau@@ -101,7 +105,7 @@ φ = totient  -- | Calculates the Carmichael function for a positive integer, that is,---   the (smallest) exponent of the group of units in @&8484;/(n)@.+--   the (smallest) exponent of the group of units in @&#8484;/(n)@. carmichael :: Integer -> Integer carmichael n     | n < 1     = error "Carmichael function only defined for positive numbers"@@ -111,6 +115,17 @@ -- | Alias of 'carmichael' for people who prefer Greek letters. λ :: Integer -> Integer λ = carmichael++-- | Calculates the Moebius function for a positive integer.+moebius :: Integer -> Integer+moebius n+    | n < 1     = error "Carmichael function only defined for positive numbers"+    | n == 1    = 1+    | otherwise = moebiusFromCanonical (factorise' n)++-- | Alias of 'moebius' for people who prefer Greek letters.+μ :: Integer -> Integer+μ = moebius  -- | @'divisors' n@ is the set of all (positive) divisors of @n@. --   @'divisors' 0@ is an error because we can't create the set of all 'Integer's.
Math/NumberTheory/Primes/Factorisation/Montgomery.hs view
@@ -46,7 +46,6 @@ #if __GLASGOW_HASKELL__ < 705 import GHC.Word     -- Moved to GHC.Types #endif-import Data.Array.Base  import System.Random import Control.Monad.State.Strict@@ -63,6 +62,7 @@ import Math.NumberTheory.Primes.Sieve.Eratosthenes import Math.NumberTheory.Primes.Sieve.Indexing import Math.NumberTheory.Primes.Testing.Probabilistic+import Math.NumberTheory.Unsafe import Math.NumberTheory.Utils  -- | @'factorise' n@ produces the prime factorisation of @n@, including
Math/NumberTheory/Primes/Factorisation/Utils.hs view
@@ -13,6 +13,7 @@     ( ppTotient     , totientFromCanonical     , carmichaelFromCanonical+    , moebiusFromCanonical     , divisorsFromCanonical     , tauFromCanonical     , divisorSumFromCanonical@@ -49,6 +50,15 @@     go !acc ((p,1):pps) = go (lcm acc (p-1)) pps     go acc ((p,k):pps)  = go ((lcm acc (p-1))*integerPower p (k-1)) pps     go acc []           = acc++-- | Calculate the Moebius function from the canonical factorisation.+moebiusFromCanonical :: [(a, Int)] -> Integer+moebiusFromCanonical = go 1+  where+  go acc []            = acc+  go acc ((_, 1) : xs) = go (negate acc) xs+  go acc ((_, 0) : xs) = go acc xs          -- Should not really happen+  go _   _             = 0                  -- Short circuit for powers > 1  -- | The set of divisors, efficiently calculated from the canonical factorisation. divisorsFromCanonical :: [(Integer,Int)] -> Set Integer
Math/NumberTheory/Primes/Heap.hs view
@@ -22,7 +22,6 @@ module Math.NumberTheory.Primes.Heap (primes, sieveFrom) where  import Data.Array.Unboxed-import Data.Array.Base (unsafeAt, unsafeRead, unsafeWrite) import Data.Array.ST import Control.Monad.ST import Data.List (foldl')@@ -30,6 +29,8 @@ import Data.Word #endif +import Math.NumberTheory.Unsafe+ #ifndef SH_SIZE #define SH_SIZE 31 #endif@@ -331,12 +332,14 @@     | r < m     = down (a-1)     | otherwise = up a       where-        a = min 5758 ((192*r) `quot` 1001 - 1)+        a = max 0 (min 5758 ((192*r) `quot` 1001 - 1))         m = remainders `unsafeAt` a         down k+            | k < 0                         = 0             | r < (remainders `unsafeAt` k) = down (k-1)             | otherwise                     = k         up k+            | k+1 > 5759                        = 5759             | r < (remainders `unsafeAt` (k+1)) = k             | otherwise                         = up (k+1) 
Math/NumberTheory/Primes/Sieve/Eratosthenes.hs view
@@ -35,18 +35,18 @@ #include "MachDeps.h"  import Control.Monad.ST-import Data.Array.Base import Data.Array.ST #if !MIN_VERSION_array(0,5,0)                      hiding (unsafeFreeze, unsafeThaw, castSTUArray) #endif import Control.Monad (when) import Data.Bits-#if __GLASGOW_HASKELL__ < 709+#if __GLASGOW_HASKELL__ < 709 || WORD_SIZE_IN_BITS == 32 import Data.Word #endif  import Math.NumberTheory.Powers.Squares (integerSquareRoot)+import Math.NumberTheory.Unsafe import Math.NumberTheory.Utils import Math.NumberTheory.Primes.Counting.Approximate import Math.NumberTheory.Primes.Sieve.Indexing@@ -97,7 +97,7 @@ -- | Compact store of primality flags. data PrimeSieve = PS !Integer {-# UNPACK #-} !(UArray Int Bool) --- | Sieve primes up to (and including) a bound.+-- | Sieve primes up to (and including) a bound (or 7, if bound is smaller). --   For small enough bounds, this is more efficient than --   using the segmented sieve. --
Math/NumberTheory/Primes/Sieve/Indexing.hs view
@@ -21,9 +21,10 @@     ) where  import Data.Array.Unboxed-import Data.Array.Base (unsafeAt) import Data.Bits +import Math.NumberTheory.Unsafe+ -- Auxiliary stuff, conversion between number and index, -- remainders modulo 30 and related things. @@ -33,7 +34,9 @@ --   #-} {-# INLINE idxPr #-} idxPr :: Integral a => a -> (Int,Int)-idxPr n0 = (fromIntegral bytes0, rm3)+idxPr n0+    | n0 < 7    = (0, 0)+    | otherwise = (fromIntegral bytes0, rm3)   where     n = if (fromIntegral n0 .&. 1 == (1 :: Int))             then n0 else (n0-1)
Math/NumberTheory/Primes/Sieve/Misc.hs view
@@ -31,7 +31,6 @@     ) where  import Control.Monad.ST-import Data.Array.Base (unsafeRead, unsafeWrite, unsafeAt) import Data.Array.ST import Data.Array.Unboxed import Control.Monad (when)@@ -44,6 +43,7 @@ import Math.NumberTheory.Primes.Sieve.Indexing import Math.NumberTheory.Primes.Factorisation.Montgomery import Math.NumberTheory.Primes.Factorisation.Utils+import Math.NumberTheory.Unsafe import Math.NumberTheory.Utils  -- | A compact store of smallest prime factors.@@ -149,7 +149,7 @@                                                  | otherwise -> tdLoop j (integerSquareRoot' j) (ix+1)           where             p = toPrim ix-            pix = unsafeAt sve ix+            pix = unsafeAt sve $ fromIntegral p     curve n = stdGenFactorisation (Just (bound*(bound+2))) (mkStdGen $ fromIntegral n `xor` 0xdecaf00d) Nothing n  -- | @'totientSieve' n@ creates a store of the totients of the numbers not exceeding @n@.
+ Math/NumberTheory/Unsafe.hs view
@@ -0,0 +1,73 @@+-- |+-- Module:      Math.NumberTheory.Unsafe+-- Copyright:   (c) 2016 Andrew Lelechenko+-- Licence:     MIT+-- Maintainer:  Andrew Lelechenko <andrew.lelechenko@gmail.com>+-- Stability:   Provisional+--+-- Layer to switch between safe and unsafe arrays.+--++{-# LANGUAGE CPP #-}++module Math.NumberTheory.Unsafe+  ( UArray+  , bounds+  , castSTUArray+  , unsafeAt+  , unsafeFreeze+  , unsafeNewArray_+  , unsafeRead+  , unsafeThaw+  , unsafeWrite+  ) where++#ifdef CheckBounds++import Data.Array.Base+  ( UArray+  , castSTUArray+  )+import Data.Array.IArray+  ( IArray+  , bounds+  , (!)+  )+import Data.Array.MArray+#if !MIN_VERSION_array(0,5,0)+  hiding (unsafeFreeze, unsafeThaw)+#endif++unsafeAt :: (IArray a e, Ix i) => a i e -> i -> e+unsafeAt = (!)++unsafeFreeze :: (Ix i, MArray a e m, IArray b e) => a i e -> m (b i e)+unsafeFreeze = freeze++unsafeNewArray_ :: (Ix i, MArray a e m) => (i, i) -> m (a i e)+unsafeNewArray_ = newArray_++unsafeRead :: (MArray a e m, Ix i) => a i e -> i -> m e+unsafeRead = readArray++unsafeThaw :: (Ix i, IArray a e, MArray b e m) => a i e -> m (b i e)+unsafeThaw = thaw++unsafeWrite :: (MArray a e m, Ix i) => a i e -> i -> e -> m ()+unsafeWrite = writeArray++#else++import Data.Array.Base+  ( UArray+  , bounds+  , castSTUArray+  , unsafeAt+  , unsafeFreeze+  , unsafeNewArray_+  , unsafeRead+  , unsafeThaw+  , unsafeWrite+  )++#endif
Math/NumberTheory/Utils.hs view
@@ -63,7 +63,7 @@ "shiftToOddCount/Integer"   shiftToOddCount = shiftOCInteger   #-} {-# INLINE [1] shiftToOddCount #-}-shiftToOddCount :: (Integral a, Bits a) => a -> (Int, a)+shiftToOddCount :: Integral a => a -> (Int, a) shiftToOddCount n = case shiftOCInteger (fromIntegral n) of                       (z, o) -> (z, fromInteger o) @@ -125,7 +125,7 @@ "shiftToOdd/Integer"   shiftToOdd = shiftOInteger   #-} {-# INLINE [1] shiftToOdd #-}-shiftToOdd :: (Integral a, Bits a) => a -> a+shiftToOdd :: Integral a => a -> a shiftToOdd n = fromInteger (shiftOInteger (fromIntegral n))  -- | Specialised version for @'Int'@.
arithmoi.cabal view
@@ -1,5 +1,5 @@ name                : arithmoi-version             : 0.4.1.3+version             : 0.4.2.0 cabal-version       : >= 1.10 author              : Daniel Fischer copyright           : (c) 2011 Daniel Fischer@@ -27,12 +27,12 @@  category            : Math, Algorithms, Number Theory -tested-with         : GHC == 7.4.2, GHC==7.6.3, GHC==7.8.3+tested-with         : GHC==7.6.3, GHC==7.8.4, GHC==7.10.3, GHC==8.0.1  extra-source-files  : Changes, TODO -flag llvm-    description         : Compile the library with the LLVM backend+flag check-bounds+    description         : Replace unsafe array operations with safe ones     default             : False     manual              : True @@ -40,7 +40,7 @@     default-language: Haskell2010     build-depends       : base >= 4 && < 5                           , array >= 0.3 && < 0.6-                          , ghc-prim < 0.5+                          , ghc-prim < 0.6                           , integer-gmp < 1.1                           , containers >= 0.3 && < 0.6                           , random >= 1.0 && < 1.2@@ -51,6 +51,7 @@                           Math.NumberTheory.MoebiusInversion                           Math.NumberTheory.MoebiusInversion.Int                           Math.NumberTheory.Lucas+                          Math.NumberTheory.GaussianIntegers                           Math.NumberTheory.GCD                           Math.NumberTheory.GCD.LowLevel                           Math.NumberTheory.Powers@@ -68,6 +69,7 @@                           Math.NumberTheory.Primes.Testing.Certificates                           Math.NumberTheory.Primes.Heap     other-modules       : Math.NumberTheory.Utils+                          Math.NumberTheory.Unsafe                           Math.NumberTheory.Logarithms.Internal                           Math.NumberTheory.Primes.Counting.Impl                           Math.NumberTheory.Primes.Counting.Approximate@@ -83,9 +85,9 @@     other-extensions          : BangPatterns      ghc-options         : -O2 -Wall-    if flag(llvm)-        ghc-options     : -fllvm     ghc-prof-options    : -O2 -auto+    if flag(check-bounds)+        cpp-options     : -DCheckBounds  source-repository head   type:     git@@ -105,9 +107,31 @@   type:                 exitcode-stdio-1.0   hs-source-dirs:       test-suite   ghc-options:          -Wall-  main-is:              Spec.hs+  main-is:              Test.hs   default-language: Haskell2010-  build-depends:        base-                        ,hspec-                        ,arithmoi-+  build-depends:        base >= 4 && < 5+                        , arithmoi >= 0.4 && < 0.5+                        , tasty >= 0.10 && < 0.12+                        , tasty-smallcheck >= 0.8 && < 0.9+                        , tasty-quickcheck >= 0.8 && < 0.9+                        , tasty-hunit >= 0.9 && < 0.10+                        , QuickCheck >= 2.8 && < 2.9+                        , smallcheck >= 1.1 && < 1.2+  other-modules :   Math.NumberTheory.GaussianIntegersTests+                  , Math.NumberTheory.GCDTests+                  , Math.NumberTheory.GCD.LowLevelTests+                  , Math.NumberTheory.LogarithmsTests+                  , Math.NumberTheory.LucasTests+                  , Math.NumberTheory.ModuliTests+                  , Math.NumberTheory.Powers.CubesTests+                  , Math.NumberTheory.MoebiusInversionTests+                  , Math.NumberTheory.MoebiusInversion.IntTests+                  , Math.NumberTheory.Powers.FourthTests+                  , Math.NumberTheory.Powers.GeneralTests+                  , Math.NumberTheory.Powers.IntegerTests+                  , Math.NumberTheory.Powers.SquaresTests+                  , Math.NumberTheory.PrimesTests+                  , Math.NumberTheory.Primes.CountingTests+                  , Math.NumberTheory.Primes.HeapTests+                  , Math.NumberTheory.Primes.SieveTests+                  , Math.NumberTheory.TestUtils
+ test-suite/Math/NumberTheory/GCD/LowLevelTests.hs view
@@ -0,0 +1,74 @@+-- |+-- Module:      Math.NumberTheory.GCD.LowLevelTests+-- Copyright:   (c) 2016 Andrew Lelechenko+-- Licence:     MIT+-- Maintainer:  Andrew Lelechenko <andrew.lelechenko@gmail.com>+-- Stability:   Provisional+--+-- Tests for Math.NumberTheory.GCD.LowLevel+--++{-# LANGUAGE CPP       #-}+{-# LANGUAGE MagicHash #-}++{-# OPTIONS_GHC -fno-warn-type-defaults #-}++module Math.NumberTheory.GCD.LowLevelTests+  ( testSuite+  ) where++import Test.Tasty++#if MIN_VERSION_base(4,8,0)+#else+import Data.Word+#endif++import GHC.Exts++import Math.NumberTheory.GCD.LowLevel+import Math.NumberTheory.TestUtils++-- | Check that 'gcdInt' matches 'gcd'.+gcdIntProperty :: Int -> Int -> Bool+gcdIntProperty a b = gcdInt a b == gcd a b++-- | Check that 'gcdWord' matches 'gcd'.+gcdWordProperty :: Word -> Word -> Bool+gcdWordProperty a b = gcdWord a b == gcd a b++-- | Check that 'gcdInt#' matches 'gcd'.+gcdIntProperty# :: Int -> Int -> Bool+gcdIntProperty# a@(I# a') b@(I# b') = I# (gcdInt# a' b') == gcd a b++-- | Check that 'gcdWord#' matches 'gcd'.+gcdWordProperty# :: Word -> Word -> Bool+gcdWordProperty# a@(W# a') b@(W# b') = W# (gcdWord# a' b') == gcd a b++-- | Check that numbers are coprime iff their gcd equals to 1.+coprimeIntProperty :: Int -> Int -> Bool+coprimeIntProperty a b = coprimeInt a b == (gcd a b == 1)++-- | Check that numbers are coprime iff their gcd equals to 1.+coprimeWordProperty :: Word -> Word -> Bool+coprimeWordProperty a b = coprimeWord a b == (gcd a b == 1)++-- | Check that numbers are coprime iff their gcd equals to 1.+coprimeIntProperty# :: Int -> Int -> Bool+coprimeIntProperty# a@(I# a') b@(I# b') = coprimeInt# a' b' == (gcd a b == 1)++-- | Check that numbers are coprime iff their gcd equals to 1.+coprimeWordProperty# :: Word -> Word -> Bool+coprimeWordProperty# a@(W# a') b@(W# b') = coprimeWord# a' b' == (gcd a b == 1)++testSuite :: TestTree+testSuite = testGroup "LowLevel"+  [ testSmallAndQuick "gcdInt"       gcdIntProperty+  , testSmallAndQuick "gcdWord"      gcdWordProperty+  , testSmallAndQuick "gcdInt#"      gcdIntProperty#+  , testSmallAndQuick "gcdWord#"     gcdWordProperty#+  , testSmallAndQuick "coprimeInt"   coprimeIntProperty+  , testSmallAndQuick "coprimeWord"  coprimeWordProperty+  , testSmallAndQuick "coprimeInt#"  coprimeIntProperty#+  , testSmallAndQuick "coprimeWord#" coprimeWordProperty#+  ]
+ test-suite/Math/NumberTheory/GCDTests.hs view
@@ -0,0 +1,50 @@+-- |+-- Module:      Math.NumberTheory.GCDTests+-- Copyright:   (c) 2016 Andrew Lelechenko+-- Licence:     MIT+-- Maintainer:  Andrew Lelechenko <andrew.lelechenko@gmail.com>+-- Stability:   Provisional+--+-- Tests for Math.NumberTheory.GCD+--++{-# LANGUAGE ScopedTypeVariables #-}++{-# OPTIONS_GHC -fno-warn-type-defaults #-}++module Math.NumberTheory.GCDTests+  ( testSuite+  ) where++import Test.Tasty++import Data.Bits++import Math.NumberTheory.GCD+import Math.NumberTheory.TestUtils++-- | Check that 'binaryGCD' matches 'gcd'.+binaryGCDProperty :: (Integral a, Bits a) => AnySign a -> AnySign a -> Bool+binaryGCDProperty (AnySign a) (AnySign b) = binaryGCD a b == gcd a b++-- | Check that 'extendedGCD' is consistent with documentation.+extendedGCDProperty :: forall a. Integral a => AnySign a -> AnySign a -> Bool+extendedGCDProperty (AnySign a) (AnySign b) =+  u * a + v * b == d+  && d == gcd a b+  -- (-1) >= 0 is true for unsigned types+  && (abs u < abs b || abs b <= 1 || (-1 :: a) >= 0)+  && (abs v < abs a || abs a <= 1 || (-1 :: a) >= 0)+  where+    (d, u, v) = extendedGCD a b++-- | Check that numbers are coprime iff their gcd equals to 1.+coprimeProperty :: (Integral a, Bits a) => AnySign a -> AnySign a -> Bool+coprimeProperty (AnySign a) (AnySign b) = coprime a b == (gcd a b == 1)++testSuite :: TestTree+testSuite = testGroup "GCD"+  [ testSameIntegralProperty "binaryGCD"   binaryGCDProperty+  , testSameIntegralProperty "extendedGCD" extendedGCDProperty+  , testSameIntegralProperty "coprime"     coprimeProperty+  ]
+ test-suite/Math/NumberTheory/GaussianIntegersTests.hs view
@@ -0,0 +1,79 @@+{-# OPTIONS_GHC -fno-warn-type-defaults #-}++-- |+-- Module:      Math.NumberTheory.GaussianIntegersTests+-- Copyright:   (c) 2016 Chris Fredrickson+-- Licence:     MIT+-- Maintainer:  Chris Fredrickson <chris.p.fredrickson@gmail.com>+-- Stability:   Provisional+--+-- Tests for Math.NumberTheory.GaussianIntegers+--++module Math.NumberTheory.GaussianIntegersTests+  ( testSuite+  ) where++import Test.Tasty+import Test.Tasty.HUnit++import Math.NumberTheory.GaussianIntegers+import Math.NumberTheory.TestUtils++-- | Number is zero or is equal to the product of its factors.+factoriseProperty :: Integer -> Integer -> Bool+factoriseProperty x y+  =  x == 0 && y == 0+  || g == g'+  where+    g = x :+ y+    factors = factorise g+    g' = product $ map (uncurry (.^)) factors++-- | Number is prime iff it is non-zero+--   and has exactly one (non-unit) factor.+isPrimeProperty :: Integer -> Integer -> Bool+isPrimeProperty x y+  =  x == 0 && y == 0+  || isPrime g && n == 1+  || not (isPrime g) && n /= 1+  where+    g = x :+ y+    factors = factorise g+    nonUnitFactors = filter (\(p, _) -> norm p /= 1) factors+    -- Count factors taking into account multiplicity+    n = sum $ map snd nonUnitFactors++-- | The list of primes should include only primes.+primesGeneratesPrimesProperty :: NonNegative Int -> Bool+primesGeneratesPrimesProperty (NonNegative i) = isPrime (primes !! i)++-- | signum and abs should satisfy: z == signum z * abs z+signumAbsProperty :: Integer -> Integer -> Bool+signumAbsProperty x y = z == signum z * abs z+  where+    z = x :+ y++-- | abs maps a Gaussian integer to its associate in first quadrant.+absProperty :: Integer -> Integer -> Bool+absProperty x y = isOrigin || (inFirstQuadrant && isAssociate)+  where+    z = x :+ y+    z'@(x' :+ y') = abs z+    isOrigin = z' == 0 && z == 0+    inFirstQuadrant = x' > 0 && y' >= 0     -- first quadrant includes the positive real axis, but not the origin or the positive imaginary axis+    isAssociate = z' `elem` map (\e -> z * (0 :+ 1) .^ e) [0 .. 3]++-- | a special case that tests rounding/truncating in GCD.+gcdGSpecialCase1 :: Assertion+gcdGSpecialCase1 = assertEqual "gcdG" 1 $ gcdG (12 :+ 23) (23 :+ 34)++testSuite :: TestTree+testSuite = testGroup "GaussianIntegers"+  [ testSmallAndQuick "factorise"         factoriseProperty+  , testSmallAndQuick "isPrime"           isPrimeProperty+  , testSmallAndQuick "primes"            primesGeneratesPrimesProperty+  , testSmallAndQuick "signumAbsProperty" signumAbsProperty+  , testSmallAndQuick "absProperty"       absProperty+  , testCase          "gcdG (12 :+ 23) (23 :+ 34)" gcdGSpecialCase1+  ]
+ test-suite/Math/NumberTheory/LogarithmsTests.hs view
@@ -0,0 +1,112 @@+-- |+-- Module:      Math.NumberTheory.LogarithmsTests+-- Copyright:   (c) 2016 Andrew Lelechenko+-- Licence:     MIT+-- Maintainer:  Andrew Lelechenko <andrew.lelechenko@gmail.com>+-- Stability:   Provisional+--+-- Tests for Math.NumberTheory.Logarithms+--++{-# LANGUAGE CPP       #-}++{-# OPTIONS_GHC -fno-warn-type-defaults #-}++module Math.NumberTheory.LogarithmsTests+  ( testSuite+  ) where++import Test.Tasty++#if MIN_VERSION_base(4,8,0)+#else+import Data.Word+#endif++import Math.NumberTheory.Logarithms+import Math.NumberTheory.TestUtils++-- | Check that 'integerLogBase' returns the largest integer @l@ such that @b@ ^ @l@ <= @n@ and @b@ ^ (@l@+1) > @n@.+integerLogBaseProperty :: Positive Integer -> Positive Integer -> Bool+integerLogBaseProperty (Positive b) (Positive n) = b == 1 || b ^ l <= n && b ^ (l + 1) > n+  where+    l = toInteger $ integerLogBase b n++-- | Check that 'integerLog2' returns the largest integer @l@ such that 2 ^ @l@ <= @n@ and 2 ^ (@l@+1) > @n@.+integerLog2Property :: Positive Integer -> Bool+integerLog2Property (Positive n) = 2 ^ l <= n && 2 ^ (l + 1) > n+  where+    l = toInteger $ integerLog2 n++-- | Check that 'integerLog10' returns the largest integer @l@ such that 10 ^ @l@ <= @n@ and 10 ^ (@l@+1) > @n@.+integerLog10Property :: Positive Integer -> Bool+integerLog10Property (Positive n) = 10 ^ l <= n && 10 ^ (l + 1) > n+  where+    l = toInteger $ integerLog10 n++-- | Check that 'intLog2' returns the largest integer @l@ such that 2 ^ @l@ <= @n@ and 2 ^ (@l@+1) > @n@.+intLog2Property :: Positive Int -> Bool+intLog2Property (Positive n) = 2 ^ l <= n && (2 ^ (l + 1) > n || n > maxBound `div` 2)+  where+    l = intLog2 n++-- | Check that 'wordLog2' returns the largest integer @l@ such that 2 ^ @l@ <= @n@ and 2 ^ (@l@+1) > @n@.+wordLog2Property :: Positive Word -> Bool+wordLog2Property (Positive n) = 2 ^ l <= n && (2 ^ (l + 1) > n || n > maxBound `div` 2)+  where+    l = wordLog2 n++-- | Check that 'integerLogBase'' returns the largest integer @l@ such that @b@ ^ @l@ <= @n@ and @b@ ^ (@l@+1) > @n@.+integerLogBase'Property :: Positive Integer -> Positive Integer -> Bool+integerLogBase'Property (Positive b) (Positive n) = b == 1 || b ^ l <= n && b ^ (l + 1) > n+  where+    l = toInteger $ integerLogBase' b n++-- | Check that 'integerLogBase'' returns the largest integer @l@ such that @b@ ^ @l@ <= @n@ and @b@ ^ (@l@+1) > @n@ for @b@ > 32 and @n@ >= @b@ ^ 2.+integerLogBase'Property2 :: Positive Integer -> Positive Integer -> Bool+integerLogBase'Property2 (Positive b') (Positive n') = b ^ l <= n && b ^ (l + 1) > n+  where+    b = b' + 32+    n = n' + b ^ 2 - 1+    l = toInteger $ integerLogBase' b n++-- | Check that 'integerLog2'' returns the largest integer @l@ such that 2 ^ @l@ <= @n@ and 2 ^ (@l@+1) > @n@.+integerLog2'Property :: Positive Integer -> Bool+integerLog2'Property (Positive n) = 2 ^ l <= n && 2 ^ (l + 1) > n+  where+    l = toInteger $ integerLog2' n++-- | Check that 'integerLog10'' returns the largest integer @l@ such that 10 ^ @l@ <= @n@ and 10 ^ (@l@+1) > @n@.+integerLog10'Property :: Positive Integer -> Bool+integerLog10'Property (Positive n) = 10 ^ l <= n && 10 ^ (l + 1) > n+  where+    l = toInteger $ integerLog10' n++-- | Check that 'intLog2'' returns the largest integer @l@ such that 2 ^ @l@ <= @n@ and 2 ^ (@l@+1) > @n@.+intLog2'Property :: Positive Int -> Bool+intLog2'Property (Positive n) = 2 ^ l <= n && (2 ^ (l + 1) > n || n > maxBound `div` 2)+  where+    l = intLog2' n++-- | Check that 'wordLog2'' returns the largest integer @l@ such that 2 ^ @l@ <= @n@ and 2 ^ (@l@+1) > @n@.+wordLog2'Property :: Positive Word -> Bool+wordLog2'Property (Positive n) = 2 ^ l <= n && (2 ^ (l + 1) > n || n > maxBound `div` 2)+  where+    l = wordLog2' n++testSuite :: TestTree+testSuite = testGroup "Logarithms"+  [ testSmallAndQuick "integerLogBase"  integerLogBaseProperty+  , testSmallAndQuick "integerLog2"     integerLog2Property+  , testSmallAndQuick "integerLog10"    integerLog10Property+  , testSmallAndQuick "intLog2"         intLog2Property+  , testSmallAndQuick "wordLog2"        wordLog2Property++  , testSmallAndQuick "integerLogBase'" integerLogBase'Property+  , testSmallAndQuick "integerLogBase' with base > 32 and n >= base ^ 2"+      integerLogBase'Property2+  , testSmallAndQuick "integerLog2'"    integerLog2'Property+  , testSmallAndQuick "integerLog10'"   integerLog10'Property+  , testSmallAndQuick "intLog2'"        intLog2'Property+  , testSmallAndQuick "wordLog2'"       wordLog2'Property+  ]
+ test-suite/Math/NumberTheory/LucasTests.hs view
@@ -0,0 +1,104 @@+-- |+-- Module:      Math.NumberTheory.LucasTests+-- Copyright:   (c) 2016 Andrew Lelechenko+-- Licence:     MIT+-- Maintainer:  Andrew Lelechenko <andrew.lelechenko@gmail.com>+-- Stability:   Provisional+--+-- Tests for Math.NumberTheory.Lucas+--++{-# LANGUAGE CPP       #-}++{-# OPTIONS_GHC -fno-warn-type-defaults #-}++module Math.NumberTheory.LucasTests+  ( testSuite+  ) where++import Test.Tasty+import Test.Tasty.HUnit++import Math.NumberTheory.Lucas+import Math.NumberTheory.TestUtils++-- | Check that 'fibonacci' matches the definition of Fibonacci sequence.+fibonacciProperty1 :: AnySign Int -> Bool+fibonacciProperty1 (AnySign n) = fibonacci n + fibonacci (n + 1) == fibonacci (n +2)++-- | Check that 'fibonacci' for negative indices is correctly defined.+fibonacciProperty2 :: NonNegative Int -> Bool+fibonacciProperty2 (NonNegative n) = fibonacci n == (if even n then negate else id) (fibonacci (- n))++-- | Check that 'fibonacciPair' is a pair of consequent 'fibonacci'.+fibonacciPairProperty :: AnySign Int -> Bool+fibonacciPairProperty (AnySign n) = fibonacciPair n == (fibonacci n, fibonacci (n + 1))++-- | Check that 'fibonacci 0' is 0.+fibonacciSpecialCase0 :: Assertion+fibonacciSpecialCase0 = assertEqual "fibonacci" (fibonacci 0) 0++-- | Check that 'fibonacci 1' is 1.+fibonacciSpecialCase1 :: Assertion+fibonacciSpecialCase1 = assertEqual "fibonacci" (fibonacci 1) 1+++-- | Check that 'lucas' matches the definition of Lucas sequence.+lucasProperty1 :: AnySign Int -> Bool+lucasProperty1 (AnySign n) = lucas n + lucas (n + 1) == lucas (n +2)++-- | Check that 'lucas' for negative indices is correctly defined.+lucasProperty2 :: NonNegative Int -> Bool+lucasProperty2 (NonNegative n) = lucas n == (if odd n then negate else id) (lucas (- n))++-- | Check that 'lucasPair' is a pair of consequent 'lucas'.+lucasPairProperty :: AnySign Int -> Bool+lucasPairProperty (AnySign n) = lucasPair n == (lucas n, lucas (n + 1))++-- | Check that 'lucas 0' is 2.+lucasSpecialCase0 :: Assertion+lucasSpecialCase0 = assertEqual "lucas" (lucas 0) 2++-- | Check that 'lucas 1' is 1.+lucasSpecialCase1 :: Assertion+lucasSpecialCase1 = assertEqual "lucas" (lucas 1) 1++-- | Check that 'generalLucas' matches its definition.+generalLucasProperty1 :: AnySign Integer -> AnySign Integer -> NonNegative Int -> Bool+generalLucasProperty1 (AnySign p) (AnySign q) (NonNegative n) = un1 == un1' && vn1 == vn1' && un2 == p * un1 - q * un && vn2 == p * vn1 - q * vn+  where+    (un, un1, vn, vn1) = generalLucas p q n+    (un1', un2, vn1', vn2) = generalLucas p q (n + 1)++-- | Check that 'generalLucas' 1 (-1) is 'fibonacciPair' plus 'lucasPair'.+generalLucasProperty2 :: NonNegative Int -> Bool+generalLucasProperty2 (NonNegative n) = (un, un1) == fibonacciPair n && (vn, vn1) == lucasPair n+  where+    (un, un1, vn, vn1) = generalLucas 1 (-1) n++-- | Check that 'generalLucas' p _ 0 is (0, 1, 2, p).+generalLucasProperty3 :: AnySign Integer -> AnySign Integer -> Bool+generalLucasProperty3 (AnySign p) (AnySign q) = generalLucas p q 0 == (0, 1, 2, p)++testSuite :: TestTree+testSuite = testGroup "Lucas"+  [ testGroup "fibonacci"+    [ testSmallAndQuick "matches definition"  fibonacciProperty1+    , testSmallAndQuick "negative indices"    fibonacciProperty2+    , testSmallAndQuick "pair"                fibonacciPairProperty+    , testCase          "fibonacci 0"         fibonacciSpecialCase0+    , testCase          "fibonacci 1"         fibonacciSpecialCase1+    ]+  , testGroup "lucas"+    [ testSmallAndQuick "matches definition"  lucasProperty1+    , testSmallAndQuick "negative indices"    lucasProperty2+    , testSmallAndQuick "pair"                lucasPairProperty+    , testCase          "lucas 0"             lucasSpecialCase0+    , testCase          "lucas 1"             lucasSpecialCase1+    ]+  , testGroup "generalLucas"+    [ testSmallAndQuick "matches definition"  generalLucasProperty1+    , testSmallAndQuick "generalLucas 1 (-1)" generalLucasProperty2+    , testSmallAndQuick "generalLucas _ _ 0"  generalLucasProperty3+    ]+  ]
+ test-suite/Math/NumberTheory/ModuliTests.hs view
@@ -0,0 +1,222 @@+-- |+-- Module:      Math.NumberTheory.ModuliTests+-- Copyright:   (c) 2016 Andrew Lelechenko+-- Licence:     MIT+-- Maintainer:  Andrew Lelechenko <andrew.lelechenko@gmail.com>+-- Stability:   Provisional+--+-- Tests for Math.NumberTheory.Moduli+--++{-# LANGUAGE CPP          #-}+{-# LANGUAGE ViewPatterns #-}++{-# OPTIONS_GHC -fno-warn-type-defaults #-}++module Math.NumberTheory.ModuliTests+  ( testSuite+  ) where++import Test.Tasty++import Control.Arrow+import Data.Bits+import Data.List (tails, nub)+import Data.Maybe++import Math.NumberTheory.Moduli+import Math.NumberTheory.TestUtils++toOdd :: Num a => a -> a+toOdd n = n * 2 + 1++unwrapPP :: (Prime, Power Int) -> (Integer, Int)+unwrapPP (Prime p, Power e) = (p, e)++-- | Check that 'jacobi' matches 'jacobi''.+jacobiProperty1 :: (Integral a, Bits a) => AnySign a -> NonNegative a -> Bool+jacobiProperty1 (AnySign a) (NonNegative (toOdd -> n)) = n == 1 && j == 1 || n > 1 && j == j'+  where+    j = jacobi a n+    j' = jacobi' a n++-- https://en.wikipedia.org/wiki/Jacobi_symbol#Properties, item 2+jacobiProperty2 :: (Integral a, Bits a) => AnySign a -> NonNegative a -> Bool+jacobiProperty2 (AnySign a) (NonNegative (toOdd -> n)) = jacobi a n == jacobi (a + n) n++-- https://en.wikipedia.org/wiki/Jacobi_symbol#Properties, item 3+jacobiProperty3 :: (Integral a, Bits a) => AnySign a -> NonNegative a -> Bool+jacobiProperty3 (AnySign a) (NonNegative (toOdd -> n)) = j == 0 && g /= 1 || abs j == 1 && g == 1+  where+    j = jacobi a n+    g = gcd a n++-- https://en.wikipedia.org/wiki/Jacobi_symbol#Properties, item 4+jacobiProperty4 :: (Integral a, Bits a) => AnySign a -> AnySign a -> NonNegative a -> Bool+jacobiProperty4 (AnySign a) (AnySign b) (NonNegative (toOdd -> n)) = jacobi (a * b) n == jacobi a n * jacobi b n++jacobiProperty4_Integer :: AnySign Integer -> AnySign Integer -> NonNegative Integer -> Bool+jacobiProperty4_Integer = jacobiProperty4++-- https://en.wikipedia.org/wiki/Jacobi_symbol#Properties, item 5+jacobiProperty5 :: (Integral a, Bits a) => AnySign a -> NonNegative a -> NonNegative a -> Bool+jacobiProperty5 (AnySign a) (NonNegative (toOdd -> m)) (NonNegative (toOdd -> n)) = jacobi a (m * n) == jacobi a m * jacobi a n++jacobiProperty5_Integer :: AnySign Integer -> NonNegative Integer -> NonNegative Integer -> Bool+jacobiProperty5_Integer = jacobiProperty5++-- https://en.wikipedia.org/wiki/Jacobi_symbol#Properties, item 6+jacobiProperty6 :: (Integral a, Bits a) => NonNegative a -> NonNegative a -> Bool+jacobiProperty6 (NonNegative (toOdd -> m)) (NonNegative (toOdd -> n)) = gcd m n /= 1 || jacobi m n * jacobi n m == (if m `mod` 4 == 1 || n `mod` 4 == 1 then 1 else -1)++-- | Check that 'invertMod' inverts numbers modulo.+invertModProperty :: AnySign Integer -> Positive Integer -> Bool+invertModProperty (AnySign k) (Positive m) = case invertMod k m of+  Nothing  -> k `mod` m == 0 || gcd k m > 1+  Just inv -> gcd k m == 1+      && k * inv `mod` m == 1 && 0 <= inv && inv < m++-- | Check that the result of 'powerMod' is between 0 and modulo (non-inclusive).+powerModProperty1 :: (Integral a, Bits a) => AnySign a -> AnySign Integer -> Positive Integer -> Bool+powerModProperty1 (AnySign e) (AnySign b) (Positive m)+  =  e < 0 && isNothing (invertMod b m)+  || (0 <= pm && pm < m)+  where+    pm = powerMod b e m++-- | Check that 'powerMod' is multiplicative by first argument.+powerModProperty2 :: (Integral a, Bits a) => AnySign a -> AnySign Integer -> AnySign Integer -> Positive Integer -> Bool+powerModProperty2 (AnySign e) (AnySign b1) (AnySign b2) (Positive m)+  =  e < 0 && (isNothing (invertMod b1 m) || isNothing (invertMod b2 m))+  || pm1 * pm2 `mod` m == pm12+  where+    pm1  = powerMod b1  e m+    pm2  = powerMod b2  e m+    pm12 = powerMod (b1 * b2) e m++-- | Check that 'powerMod' is additive by second argument.+powerModProperty3 :: (Integral a, Bits a) => AnySign a -> AnySign a -> AnySign Integer -> Positive Integer -> Bool+powerModProperty3 (AnySign e1) (AnySign e2) (AnySign b) (Positive m)+  =  (e1 < 0 || e2 < 0) && isNothing (invertMod b m)+  || pm1 * pm2 `mod` m == pm12+  where+    pm1  = powerMod b e1 m+    pm2  = powerMod b e2 m+    pm12 = powerMod b (e1 + e2) m++-- | Specialized to trigger 'powerModInteger'.+powerModProperty1_Integer :: AnySign Integer -> AnySign Integer -> Positive Integer -> Bool+powerModProperty1_Integer = powerModProperty1++-- | Specialized to trigger 'powerModInteger'.+powerModProperty2_Integer :: AnySign Integer -> AnySign Integer -> AnySign Integer -> Positive Integer -> Bool+powerModProperty2_Integer = powerModProperty2++-- | Specialized to trigger 'powerModInteger'.+powerModProperty3_Integer :: AnySign Integer -> AnySign Integer -> AnySign Integer -> Positive Integer -> Bool+powerModProperty3_Integer = powerModProperty3++-- | Check that 'powerMod' matches 'powerMod''.+powerMod'Property :: (Integral a, Bits a) => Positive a -> Positive Integer -> Positive Integer -> Bool+powerMod'Property (Positive e) (Positive b) (Positive m) = m == 1 || powerMod' b e m == powerMod b e m++-- | Specialized to trigger 'powerModInteger''.+powerMod'Property_Integer :: Positive Integer -> Positive Integer -> Positive Integer -> Bool+powerMod'Property_Integer = powerMod'Property++-- | Check that 'chineseRemainder' is defined iff modulos are coprime.+--   Also check that the result is a solution of input modular equations.+chineseRemainderProperty :: [(Integer, Positive Integer)] -> Bool+chineseRemainderProperty rms' = case chineseRemainder rms of+  Nothing -> not areCoprime+  Just n  -> areCoprime && map (n `mod`) ms == zipWith mod rs ms+  where+    rms = map (second getPositive) rms'+    (rs, ms) = unzip rms+    areCoprime = all (== 1) [ gcd m1 m2 | (m1 : m2s) <- tails ms, m2 <- m2s ]++-- | Check that 'chineseRemainder' matches 'chineseRemainder2'.+chineseRemainder2Property :: Integer -> Positive Integer -> Integer -> Positive Integer -> Bool+chineseRemainder2Property r1 (Positive m1) r2 (Positive m2) = gcd m1 m2 /= 1+  || Just (chineseRemainder2 (r1, m1) (r2, m2)) == chineseRemainder [(r1, m1), (r2, m2)]++-- | Check that 'sqrtMod' is defined iff a quadratic residue exists.+--   Also check that the result is a solution of input modular equation.+sqrtModPProperty :: AnySign Integer -> Prime -> Bool+sqrtModPProperty (AnySign n) (Prime p) = case sqrtModP n p of+  Nothing -> jacobi n p == -1+  Just rt -> (p == 2 || jacobi n p /= -1) && rt ^ 2 `mod` p == n `mod` p++sqrtModPListProperty :: AnySign Integer -> Prime -> Bool+sqrtModPListProperty (AnySign n) (Prime p) = all (\rt -> rt ^ 2 `mod` p == n `mod` p) (sqrtModPList n p)++sqrtModP'Property :: Positive Integer -> Prime -> Bool+sqrtModP'Property (Positive n) (Prime p) = (p /= 2 && jacobi n p /= 1) || rt ^ 2 `mod` p == n `mod` p+  where+    rt = sqrtModP' n p++tonelliShanksProperty :: Positive Integer -> Prime -> Bool+tonelliShanksProperty (Positive n) (Prime p) = p `mod` 4 /= 1 || jacobi n p /= 1 || rt ^ 2 `mod` p == n `mod` p+  where+    rt = tonelliShanks n p++sqrtModPPProperty :: AnySign Integer -> (Prime, Power Int) -> Bool+sqrtModPPProperty (AnySign n) (Prime p, Power e) = gcd n p > 1 || case sqrtModPP n (p, e) of+  Nothing -> True+  Just rt -> rt ^ 2 `mod` (p ^ e) == n `mod` (p ^ e)++sqrtModPPListProperty :: AnySign Integer -> (Prime, Power Int) -> Bool+sqrtModPPListProperty (AnySign n) (Prime p, Power e) = gcd n p > 1+  || all (\rt -> rt ^ 2 `mod` (p ^ e) == n `mod` (p ^ e)) (sqrtModPPList n (p, e))++sqrtModFProperty :: AnySign Integer -> [(Prime, Power Int)] -> Bool+sqrtModFProperty (AnySign n) (map unwrapPP -> pes) = case sqrtModF n pes of+  Nothing -> True+  Just rt -> all (\(p, e) -> rt ^ 2 `mod` (p ^ e) == n `mod` (p ^ e)) pes++sqrtModFListProperty :: AnySign Integer -> [(Prime, Power Int)] -> Bool+sqrtModFListProperty (AnySign n) (map unwrapPP -> pes)+  = nub ps /= ps || all+    (\rt -> all (\(p, e) -> rt ^ 2 `mod` (p ^ e) == n `mod` (p ^ e)) pes)+    (sqrtModFList n pes)+  where+    ps = map fst pes++testSuite :: TestTree+testSuite = testGroup "Moduli"+  [ testGroup "jacobi"+    [ testSameIntegralProperty "matches jacobi'"              jacobiProperty1+    , testSameIntegralProperty "same modulo n"                jacobiProperty2+    , testSameIntegralProperty "consistent with gcd"          jacobiProperty3+    , testSmallAndQuick        "multiplicative 1"             jacobiProperty4_Integer+    , testSmallAndQuick        "multiplicative 2"             jacobiProperty5_Integer+    , testSameIntegralProperty "law of quadratic reciprocity" jacobiProperty6+    ]+  , testSmallAndQuick "invertMod" invertModProperty+  , testGroup "powerMod"+    [ testGroup "generic"+      [ testIntegralProperty "bounded between 0 and m"  powerModProperty1+      , testIntegralProperty "multiplicative by base"   powerModProperty2+      , testSameIntegralProperty "additive by exponent" powerModProperty3+      , testIntegralProperty "matches powerMod'"        powerMod'Property+      ]+    , testGroup "Integer"+      [ testSmallAndQuick "bounded between 0 and m" powerModProperty1_Integer+      , testSmallAndQuick "multiplicative by base"  powerModProperty2_Integer+      , testSmallAndQuick "additive by exponent"    powerModProperty3_Integer+      , testSmallAndQuick "matches powerMod'"       powerMod'Property_Integer+      ]+    ]+    , testSmallAndQuick "chineseRemainder"  chineseRemainderProperty+    , testSmallAndQuick "chineseRemainder2" chineseRemainder2Property+    , testGroup "sqrtMod"+      [ testSmallAndQuick "sqrtModP"      sqrtModPProperty+      , testSmallAndQuick "sqrtModPList"  sqrtModPListProperty+      , testSmallAndQuick "sqrtModP'"     sqrtModP'Property+      , testSmallAndQuick "tonelliShanks" tonelliShanksProperty+      , testSmallAndQuick "sqrtModPP"     sqrtModPPProperty+      , testSmallAndQuick "sqrtModPPList" sqrtModPPListProperty+      , testSmallAndQuick "sqrtModF"      sqrtModFProperty+      , testSmallAndQuick "sqrtModFList"  sqrtModFListProperty+      ]+  ]
+ test-suite/Math/NumberTheory/MoebiusInversion/IntTests.hs view
@@ -0,0 +1,45 @@+-- |+-- Module:      Math.NumberTheory.MoebiusInversion.IntTests+-- Copyright:   (c) 2016 Andrew Lelechenko+-- Licence:     MIT+-- Maintainer:  Andrew Lelechenko <andrew.lelechenko@gmail.com>+-- Stability:   Provisional+--+-- Tests for Math.NumberTheory.MoebiusInversion.Int+--++{-# OPTIONS_GHC -fno-warn-type-defaults #-}++module Math.NumberTheory.MoebiusInversion.IntTests+  ( testSuite+  ) where++import Test.Tasty+import Test.Tasty.HUnit+import Test.Tasty.QuickCheck as QC hiding (Positive)++import Math.NumberTheory.MoebiusInversion.Int+import Math.NumberTheory.Primes.Factorisation+import Math.NumberTheory.TestUtils++totientSumProperty :: Positive Int -> Bool+totientSumProperty (Positive n) = toInteger (totientSum n) == sum (map totient [1 .. toInteger n])++totientSumSpecialCase1 :: Assertion+totientSumSpecialCase1 = assertEqual "totientSum" 4496 (totientSum 121)++generalInversionProperty :: (Int -> Int) -> Positive Int -> Bool+generalInversionProperty g (Positive n)+  =  g n == sum [f (n `quot` k) | k <- [1 .. n]]+  && f n == sum [fromInteger (moebius (toInteger k)) * g (n `quot` k) | k <- [1 .. n]]+  where+    f = generalInversion g++testSuite :: TestTree+testSuite = testGroup "Int"+  [ testGroup "totientSum"+    [ testSmallAndQuick "matches definitions" totientSumProperty+    , testCase          "special case 1"      totientSumSpecialCase1+    ]+  , QC.testProperty "generalInversion" generalInversionProperty+  ]
+ test-suite/Math/NumberTheory/MoebiusInversionTests.hs view
@@ -0,0 +1,45 @@+-- |+-- Module:      Math.NumberTheory.MoebiusInversionTests+-- Copyright:   (c) 2016 Andrew Lelechenko+-- Licence:     MIT+-- Maintainer:  Andrew Lelechenko <andrew.lelechenko@gmail.com>+-- Stability:   Provisional+--+-- Tests for Math.NumberTheory.MoebiusInversion+--++{-# OPTIONS_GHC -fno-warn-type-defaults #-}++module Math.NumberTheory.MoebiusInversionTests+  ( testSuite+  ) where++import Test.Tasty+import Test.Tasty.HUnit+import Test.Tasty.QuickCheck as QC hiding (Positive)++import Math.NumberTheory.MoebiusInversion+import Math.NumberTheory.Primes.Factorisation+import Math.NumberTheory.TestUtils++totientSumProperty :: Positive Int -> Bool+totientSumProperty (Positive n) = totientSum n == sum (map totient [1 .. toInteger n])++totientSumSpecialCase1 :: Assertion+totientSumSpecialCase1 = assertEqual "totientSum" 4496 (totientSum 121)++generalInversionProperty :: (Int -> Integer) -> Positive Int -> Bool+generalInversionProperty g (Positive n)+  =  g n == sum [f (n `quot` k) | k <- [1 .. n]]+  && f n == sum [moebius (toInteger k) * g (n `quot` k) | k <- [1 .. n]]+  where+    f = generalInversion g++testSuite :: TestTree+testSuite = testGroup "MoebiusInversion"+  [ testGroup "totientSum"+    [ testSmallAndQuick "matches definitions" totientSumProperty+    , testCase          "special case 1"      totientSumSpecialCase1+    ]+  , QC.testProperty "generalInversion" generalInversionProperty+  ]
+ test-suite/Math/NumberTheory/Powers/CubesTests.hs view
@@ -0,0 +1,154 @@+-- |+-- Module:      Math.NumberTheory.Powers.CubesTests+-- Copyright:   (c) 2016 Andrew Lelechenko+-- Licence:     MIT+-- Maintainer:  Andrew Lelechenko <andrew.lelechenko@gmail.com>+-- Stability:   Provisional+--+-- Tests for Math.NumberTheory.Powers.Cubes+--++{-# LANGUAGE CPP #-}++{-# OPTIONS_GHC -fno-warn-type-defaults #-}++module Math.NumberTheory.Powers.CubesTests+  ( testSuite+  ) where++import Test.Tasty+import Test.Tasty.HUnit++import Data.Maybe+#if MIN_VERSION_base(4,8,0)+#else+import Data.Word+#endif+++import Math.NumberTheory.Powers.Cubes+import Math.NumberTheory.TestUtils++#include "MachDeps.h"++-- | Check that 'integerCubeRoot' returns the largest integer @m@ with @m^3 <= n@.+--+-- (m + 1) ^ 3 /= n && cond+-- means+-- (m + 1) ^ 3 > n+-- but without overflow for bounded types+integerCubeRootProperty :: Integral a => AnySign a -> Bool+integerCubeRootProperty (AnySign n) = m ^ 3 <= n && (m + 1) ^ 3 /= n && cond+  where+    m = integerCubeRoot n+    cond+      | m == -1   = n == -1+      | m < 0     = (m + 1) ^ 2 <= n `div` (m + 1)+      | otherwise = (m + 1) ^ 2 >= n `div` (m + 1)++-- | Specialized to trigger 'cubeRootInt''.+integerCubeRootProperty_Int :: AnySign Int -> Bool+integerCubeRootProperty_Int = integerCubeRootProperty++-- | Specialized to trigger 'cubeRootWord'.+integerCubeRootProperty_Word :: AnySign Word -> Bool+integerCubeRootProperty_Word = integerCubeRootProperty++-- | Specialized to trigger 'cubeRootIgr'.+integerCubeRootProperty_Integer :: AnySign Integer -> Bool+integerCubeRootProperty_Integer = integerCubeRootProperty++-- | Check that 'integerCubeRoot' returns the largest integer @m@ with @m^3 <= n@, , where @n@ has form @k@^3-1.+integerCubeRootProperty2 :: Integral a => AnySign a -> Bool+integerCubeRootProperty2 (AnySign k) = m ^ 3 <= n && (m + 1) ^ 3 /= n && cond+  where+    n = k ^ 3 - 1+    m = integerCubeRoot n+    cond+      | m == -1   = n == -1+      | m < 0     = (m + 1) ^ 2 <= n `div` (m + 1)+      | otherwise = (m + 1) ^ 2 >= n `div` (m + 1)++-- | Specialized to trigger 'cubeRootInt''.+integerCubeRootProperty2_Int :: AnySign Int -> Bool+integerCubeRootProperty2_Int = integerCubeRootProperty2++-- | Specialized to trigger 'cubeRootWord'.+integerCubeRootProperty2_Word :: AnySign Word -> Bool+integerCubeRootProperty2_Word = integerCubeRootProperty2++#if WORD_SIZE_IN_BITS == 64++-- | Check that 'integerCubeRoot' of 2^63-1 is 2^21-1, not 2^21.+integerCubeRootSpecialCase1_Int :: Assertion+integerCubeRootSpecialCase1_Int =+  assertEqual "integerCubeRoot" (integerCubeRoot (maxBound :: Int)) (2 ^ 21 - 1)++-- | Check that 'integerCubeRoot' of 2^63-1 is 2^21-1, not 2^21.+integerCubeRootSpecialCase1_Word :: Assertion+integerCubeRootSpecialCase1_Word =+  assertEqual "integerCubeRoot" (integerCubeRoot (maxBound `div` 2 :: Word)) (2 ^ 21 - 1)++-- | Check that 'integerCubeRoot' of 2^64-1 is 2642245.+integerCubeRootSpecialCase2 :: Assertion+integerCubeRootSpecialCase2 =+  assertEqual "integerCubeRoot" (integerCubeRoot (maxBound :: Word)) 2642245++#endif++-- | Check that 'integerCubeRoot'' returns the largest integer @m@ with @m^3 <= n@.+integerCubeRoot'Property :: Integral a => NonNegative a -> Bool+integerCubeRoot'Property (NonNegative n) = m ^ 3 <= n && (m + 1) ^ 3 /= n && (m + 1) ^ 2 >= n `div` (m + 1)+  where+    m = integerCubeRoot' n++-- | Check that the number 'isCube' iff its 'integerCubeRoot' is exact.+isCubeProperty :: Integral a => AnySign a -> Bool+isCubeProperty (AnySign n) = (n /= m ^ 3 && not t) || (n == m ^ 3 && t)+  where+    t = isCube n+    m = integerCubeRoot n++-- | Check that the number 'isCube'' iff its 'integerCubeRoot'' is exact.+isCube'Property :: Integral a => NonNegative a -> Bool+isCube'Property (NonNegative n) = (n /= m ^ 3 && not t) || (n == m ^ 3 && t)+  where+    t = isCube' n+    m = integerCubeRoot' n++-- | Check that 'exactCubeRoot' returns an exact integer cubic root+-- and is consistent with 'isCube'.+exactCubeRootProperty :: Integral a => AnySign a -> Bool+exactCubeRootProperty (AnySign n) = case exactCubeRoot n of+  Nothing -> not (isCube n)+  Just m  -> isCube n && n == m ^ 3++-- | Check that 'isPossibleCube' is consistent with 'exactCubeRoot'.+isPossibleCubeProperty :: Integral a => NonNegative a -> Bool+isPossibleCubeProperty (NonNegative n) = t || not t && isNothing m+  where+    t = isPossibleCube n+    m = exactCubeRoot n++testSuite :: TestTree+testSuite = testGroup "Cubes"+  [ testGroup "integerCubeRoot"+    [ testIntegralProperty "generic"         integerCubeRootProperty+    , testSmallAndQuick    "generic Int"     integerCubeRootProperty_Int+    , testSmallAndQuick    "generic Word"    integerCubeRootProperty_Word+    , testSmallAndQuick    "generic Integer" integerCubeRootProperty_Integer++    , testIntegralProperty "almost cube"      integerCubeRootProperty2+    , testSmallAndQuick    "almost cube Int"  integerCubeRootProperty2_Int+    , testSmallAndQuick    "almost cube Word" integerCubeRootProperty2_Word++    , testCase             "maxBound :: Int"      integerCubeRootSpecialCase1_Int+    , testCase             "maxBound / 2 :: Word" integerCubeRootSpecialCase1_Word+    , testCase             "maxBound :: Word"     integerCubeRootSpecialCase2+    ]+  , testIntegralProperty "integerCubeRoot'" integerCubeRoot'Property+  , testIntegralProperty "isCube"           isCubeProperty+  , testIntegralProperty "isCube'"          isCube'Property+  , testIntegralProperty "exactCubeRoot"    exactCubeRootProperty+  , testIntegralProperty "isPossibleCube"   isPossibleCubeProperty+  ]
+ test-suite/Math/NumberTheory/Powers/FourthTests.hs view
@@ -0,0 +1,145 @@+-- |+-- Module:      Math.NumberTheory.Powers.FourthTests+-- Copyright:   (c) 2016 Andrew Lelechenko+-- Licence:     MIT+-- Maintainer:  Andrew Lelechenko <andrew.lelechenko@gmail.com>+-- Stability:   Provisional+--+-- Tests for Math.NumberTheory.Powers.Fourth+--++{-# LANGUAGE CPP #-}++{-# OPTIONS_GHC -fno-warn-type-defaults #-}++module Math.NumberTheory.Powers.FourthTests+  ( testSuite+  ) where++import Test.Tasty+import Test.Tasty.HUnit++import Data.Maybe+#if MIN_VERSION_base(4,8,0)+#else+import Data.Word+#endif++import Math.NumberTheory.Powers.Fourth+import Math.NumberTheory.TestUtils++#include "MachDeps.h"++-- | Check that 'integerFourthRoot' returns the largest integer @m@ with @m^4 <= n@.+--+-- (m + 1) ^ 4 /= n && (m + 1) ^ 3 >= n `div` (m + 1)+-- means+-- (m + 1) ^ 4 > n+-- but without overflow for bounded types+integerFourthRootProperty :: Integral a => NonNegative a -> Bool+integerFourthRootProperty (NonNegative n) = m >= 0 && m ^ 4 <= n && (m + 1) ^ 4 /= n && (m + 1) ^ 3 >= n `div` (m + 1)+  where+    m = integerFourthRoot n++-- | Specialized to trigger 'biSqrtInt'.+integerFourthRootProperty_Int :: NonNegative Int -> Bool+integerFourthRootProperty_Int = integerFourthRootProperty++-- | Specialized to trigger 'biSqrtWord'.+integerFourthRootProperty_Word :: NonNegative Word -> Bool+integerFourthRootProperty_Word = integerFourthRootProperty++-- | Specialized to trigger 'biSqrtIgr'.+integerFourthRootProperty_Integer :: NonNegative Integer -> Bool+integerFourthRootProperty_Integer = integerFourthRootProperty++-- | Check that 'integerFourthRoot' returns the largest integer @m@ with @m^4 <= n@, , where @n@ has form @k@^4-1.+integerFourthRootProperty2 :: Integral a => NonNegative a -> Bool+integerFourthRootProperty2 (NonNegative k) = n < 0 || m >= 0 && m ^ 4 <= n && (m + 1) ^ 4 /= n && (m + 1) ^ 3 >= n `div` (m + 1)+  where+    n = k ^ 4 - 1+    m = integerFourthRoot n++-- | Specialized to trigger 'biSqrtInt.+integerFourthRootProperty2_Int :: NonNegative Int -> Bool+integerFourthRootProperty2_Int = integerFourthRootProperty2++-- | Specialized to trigger 'biSqrtWord'.+integerFourthRootProperty2_Word :: NonNegative Word -> Bool+integerFourthRootProperty2_Word = integerFourthRootProperty2++#if WORD_SIZE_IN_BITS == 64++-- | Check that 'integerFourthRoot' of 2^60-1 is 2^15-1, not 2^15.+integerFourthRootSpecialCase1_Int :: Assertion+integerFourthRootSpecialCase1_Int =+  assertEqual "integerFourthRoot" (integerFourthRoot (maxBound `div` 8 :: Int)) (2 ^ 15 - 1)++-- | Check that 'integerFourthRoot' of 2^60-1 is 2^15-1, not 2^15.+integerFourthRootSpecialCase1_Word :: Assertion+integerFourthRootSpecialCase1_Word =+  assertEqual "integerFourthRoot" (integerFourthRoot (maxBound `div` 16 :: Word)) (2 ^ 15 - 1)++-- | Check that 'integerFourthRoot' of 2^64-1 is 2^16-1, not 2^16.+integerFourthRootSpecialCase2 :: Assertion+integerFourthRootSpecialCase2 =+  assertEqual "integerFourthRoot" (integerFourthRoot (maxBound :: Word)) (2 ^ 16 - 1)++#endif++-- | Check that 'integerFourthRoot'' returns the largest integer @m@ with @m^4 <= n@.+integerFourthRoot'Property :: Integral a => NonNegative a -> Bool+integerFourthRoot'Property (NonNegative n) = m >= 0 && m ^ 4 <= n && (m + 1) ^ 4 /= n && (m + 1) ^ 3 >= n `div` (m + 1)+  where+    m = integerFourthRoot' n++-- | Check that the number 'isFourthPower' iff its 'integerFourthRoot' is exact.+isFourthPowerProperty :: Integral a => AnySign a -> Bool+isFourthPowerProperty (AnySign n) = (n < 0 && not t) || (n /= m ^ 4 && not t) || (n == m ^ 4 && t)+  where+    t = isFourthPower n+    m = integerFourthRoot n++-- | Check that the number 'isFourthPower'' iff its 'integerFourthRoot'' is exact.+isFourthPower'Property :: Integral a => NonNegative a -> Bool+isFourthPower'Property (NonNegative n) = (n /= m ^ 4 && not t) || (n == m ^ 4 && t)+  where+    t = isFourthPower' n+    m = integerFourthRoot' n++-- | Check that 'exactFourthRoot' returns an exact integer root of fourth power+-- and is consistent with 'isFourthPower'.+exactFourthRootProperty :: Integral a => AnySign a -> Bool+exactFourthRootProperty (AnySign n) = case exactFourthRoot n of+  Nothing -> not (isFourthPower n)+  Just m  -> isFourthPower n && n == m ^ 4++-- | Check that 'isPossibleFourthPower' is consistent with 'exactFourthRoot'.+isPossibleFourthPowerProperty :: Integral a => NonNegative a -> Bool+isPossibleFourthPowerProperty (NonNegative n) = t || not t && isNothing m+  where+    t = isPossibleFourthPower n+    m = exactFourthRoot n++testSuite :: TestTree+testSuite = testGroup "Fourth"+  [ testGroup "integerFourthRoot"+    [ testIntegralProperty "generic"         integerFourthRootProperty+    , testSmallAndQuick    "generic Int"     integerFourthRootProperty_Int+    , testSmallAndQuick    "generic Word"    integerFourthRootProperty_Word+    , testSmallAndQuick    "generic Integer" integerFourthRootProperty_Integer++    , testIntegralProperty "almost Fourth"      integerFourthRootProperty2+    , testSmallAndQuick    "almost Fourth Int"  integerFourthRootProperty2_Int+    , testSmallAndQuick    "almost Fourth Word" integerFourthRootProperty2_Word++    , testCase             "maxBound / 8 :: Int"   integerFourthRootSpecialCase1_Int+    , testCase             "maxBound / 16 :: Word" integerFourthRootSpecialCase1_Word+    , testCase             "maxBound :: Word"      integerFourthRootSpecialCase2+    ]+  , testIntegralProperty "integerFourthRoot'"    integerFourthRoot'Property+  , testIntegralProperty "isFourthPower"         isFourthPowerProperty+  , testIntegralProperty "isFourthPower'"        isFourthPower'Property+  , testIntegralProperty "exactFourthRoot"       exactFourthRootProperty+  , testIntegralProperty "isPossibleFourthPower" isPossibleFourthPowerProperty+  ]
+ test-suite/Math/NumberTheory/Powers/GeneralTests.hs view
@@ -0,0 +1,128 @@+-- |+-- Module:      Math.NumberTheory.Powers.GeneralTests+-- Copyright:   (c) 2016 Andrew Lelechenko+-- Licence:     MIT+-- Maintainer:  Andrew Lelechenko <andrew.lelechenko@gmail.com>+-- Stability:   Provisional+--+-- Tests for Math.NumberTheory.Powers.General+--++{-# LANGUAGE CPP #-}++{-# OPTIONS_GHC -fno-warn-type-defaults #-}++module Math.NumberTheory.Powers.GeneralTests+  ( testSuite+  ) where++import Test.Tasty+import Test.Tasty.HUnit++import Math.NumberTheory.Powers.General+import Math.NumberTheory.TestUtils++-- | Check that 'integerRoot' @pow@ returns the largest integer @m@ with @m^pow <= n@.+integerRootProperty :: (Integral a, Integral b) => AnySign a -> Power b -> Bool+integerRootProperty (AnySign n) (Power pow) = (even pow && n < 0)+  || (toInteger root ^ pow <= toInteger n && toInteger n < toInteger (root + 1) ^ pow)+    where+      root = integerRoot pow n++-- | Check that the number 'isKthPower' iff its 'integerRoot' is exact.+isKthPowerProperty :: (Integral a, Integral b) => AnySign a -> Power b -> Bool+isKthPowerProperty (AnySign n) (Power pow) = (even pow && n < 0 && not t) || (n /= root ^ pow && not t) || (n == root ^ pow && t)+  where+    t = isKthPower pow n+    root = integerRoot pow n++-- | Check that 'exactRoot' returns an exact integer root+-- and is consistent with 'isKthPower'.+exactRootProperty :: (Integral a, Integral b) => AnySign a -> Power b -> Bool+exactRootProperty (AnySign n) (Power pow) = case exactRoot pow n of+  Nothing   -> not (isKthPower pow n)+  Just root -> isKthPower pow n && n == root ^ pow++-- | Check that 'isPerfectPower' is consistent with 'highestPower'.+isPerfectPowerProperty :: Integral a => AnySign a -> Bool+isPerfectPowerProperty (AnySign n) = (k > 1 && t) || (k == 1 && not t)+  where+    t = isPerfectPower n+    (_, k) = highestPower n++-- | Check that the first component of 'highestPower' is square-free.+highestPowerProperty :: Integral a => AnySign a -> Bool+highestPowerProperty (AnySign n) = (n `elem` [-1, 0, 1] && k == 3) || (b ^ k == n && b' == b && k' == 1)+  where+    (b, k) = highestPower n+    (b', k') = highestPower b++-- | Check that 'largePFPower' is consistent with documentation.+largePFPowerProperty :: Positive Integer -> Integer -> Bool+largePFPowerProperty (Positive bd) n = bd == 1 || b == 0 || d' /= 0 || n <= b * d * d || any (\p -> gcd n p > 1) [2..bd] || b ^ k == n+  where+    (b, k) = largePFPower bd n+    (d, d') = bd `quotRem` b++highestPowerSpecialCases :: [Assertion]+highestPowerSpecialCases =+  -- Freezes before d44a13b.+  [ a ( 1013582159576576+      , 1013582159576576+      , 1)+  -- Freezes before d44a13b.+  , a ( 1013582159576576 ^ 7+      , 1013582159576576+      , 7)++  , a ( -2 ^ 63 :: Int+      , -2 :: Int+      , 63)++  , a ( (2 ^ 63 - 1) ^ 21+      , 2 ^ 63 - 1+      , 21)++  , a ( 576116746989720969230211509779286598589421531472851155101032940901763389787901933902294777750323196846498573545522289802689311975294763847414975335235584+      , 576116746989720969230211509779286598589421531472851155101032940901763389787901933902294777750323196846498573545522289802689311975294763847414975335235584+      , 1)++  , a ( -340282366920938463500268095579187314689+      , -340282366920938463500268095579187314689+      , 1)++  , a ( 268398749 :: Int+      , 268398749 :: Int+      , 1)++  , a ( 118372752099 :: Int+      , 118372752099 :: Int+      , 1)++  , a ( 1409777209 :: Int+      , 37547 :: Int+      , 2)++  , a ( -6277101735386680764856636523970481806547819498980467802113+      , -18446744073709551617+      , 3)++  , a ( -18446744073709551619 ^ 5+      , -18446744073709551619+      , 5)+  ]+  where+    a (n, b, k) = assertEqual "highestPower" (b, k) (highestPower n)++testSuite :: TestTree+testSuite = testGroup "General"+  [ testIntegral2Property "integerRoot"    integerRootProperty+  , testIntegral2Property "isKthPower"     isKthPowerProperty+  , testIntegral2Property "exactRoot"      exactRootProperty+  , testIntegralProperty  "isPerfectPower" isPerfectPowerProperty+  , testGroup "highestPower"+    ( testIntegralProperty  "highestPower"   highestPowerProperty+    : zipWith (\i a -> testCase ("special case " ++ show i) a) [1..] highestPowerSpecialCases+    )+  , testSmallAndQuick     "largePFPower"   largePFPowerProperty+  ]
+ test-suite/Math/NumberTheory/Powers/IntegerTests.hs view
@@ -0,0 +1,41 @@+-- |+-- Module:      Math.NumberTheory.Powers.IntegerTests+-- Copyright:   (c) 2016 Andrew Lelechenko+-- Licence:     MIT+-- Maintainer:  Andrew Lelechenko <andrew.lelechenko@gmail.com>+-- Stability:   Provisional+--+-- Tests for Math.NumberTheory.Powers.Integer+--++{-# LANGUAGE CPP #-}++{-# OPTIONS_GHC -fno-warn-type-defaults #-}++module Math.NumberTheory.Powers.IntegerTests+  ( testSuite+  ) where++import Test.Tasty++#if MIN_VERSION_base(4,8,0)+#else+import Data.Word+#endif++import Math.NumberTheory.Powers.Integer+import Math.NumberTheory.TestUtils++-- | Check that 'integerPower' == '^'.+integerPowerProperty :: Integer -> Power Int -> Bool+integerPowerProperty a (Power b) = integerPower a b == a ^ b++-- | Check that 'integerWordPower' == '^'.+integerWordPowerProperty :: Integer -> Power Word -> Bool+integerWordPowerProperty a (Power b) = integerWordPower a b == a ^ b++testSuite :: TestTree+testSuite = testGroup "Integer"+  [ testSmallAndQuick "integerPower"     integerPowerProperty+  , testSmallAndQuick "integerWordPower" integerWordPowerProperty+  ]
+ test-suite/Math/NumberTheory/Powers/SquaresTests.hs view
@@ -0,0 +1,155 @@+-- |+-- Module:      Math.NumberTheory.Powers.SquaresTests+-- Copyright:   (c) 2016 Andrew Lelechenko+-- Licence:     MIT+-- Maintainer:  Andrew Lelechenko <andrew.lelechenko@gmail.com>+-- Stability:   Provisional+--+-- Tests for Math.NumberTheory.Powers.Squares+--++{-# LANGUAGE CPP #-}++{-# OPTIONS_GHC -fno-warn-type-defaults #-}++module Math.NumberTheory.Powers.SquaresTests+  ( testSuite+  ) where++import Test.Tasty+import Test.Tasty.HUnit++import Data.Maybe+#if MIN_VERSION_base(4,8,0)+#else+import Data.Word+#endif++import Math.NumberTheory.Powers.Squares+import Math.NumberTheory.TestUtils++#include "MachDeps.h"++-- | Check that 'integerSquareRoot' returns the largest integer @m@ with @m*m <= n@.+--+-- (m + 1) ^ 2 /= n && m + 1 >= n `div` (m + 1)+-- means+-- (m + 1) ^ 2 > n+-- but without overflow for bounded types+integerSquareRootProperty :: Integral a => NonNegative a -> Bool+integerSquareRootProperty (NonNegative n) = m >=0 && m * m <= n && (m + 1) ^ 2 /= n && m + 1 >= n `div` (m + 1)+  where+    m = integerSquareRoot n++-- | Specialized to trigger 'isqrtInt''.+integerSquareRootProperty_Int :: NonNegative Int -> Bool+integerSquareRootProperty_Int = integerSquareRootProperty++-- | Specialized to trigger 'isqrtWord'.+integerSquareRootProperty_Word :: NonNegative Word -> Bool+integerSquareRootProperty_Word = integerSquareRootProperty++-- | Check that 'integerSquareRoot' returns the largest integer @m@ with @m*m <= n@, where @n@ has form @k@^2-1.+integerSquareRootProperty2 :: Integral a => NonNegative a -> Bool+integerSquareRootProperty2 (NonNegative k) = n < 0+  || m >=0 && m * m <= n && (m + 1) ^ 2 /= n && m + 1 >= n `div` (m + 1)+  where+    n = k ^ 2 - 1+    m = integerSquareRoot n++-- | Specialized to trigger 'isqrtInt''.+integerSquareRootProperty2_Int :: NonNegative Int -> Bool+integerSquareRootProperty2_Int = integerSquareRootProperty2++-- | Specialized to trigger 'isqrtWord'.+integerSquareRootProperty2_Word :: NonNegative Word -> Bool+integerSquareRootProperty2_Word = integerSquareRootProperty2++#if WORD_SIZE_IN_BITS == 64++-- | Check that 'integerSquareRoot' of 2^62-1 is 2^31-1, not 2^31.+integerSquareRootSpecialCase1_Int :: Assertion+integerSquareRootSpecialCase1_Int =+  assertEqual "integerSquareRoot" (integerSquareRoot (maxBound `div` 2 :: Int)) (2 ^ 31 - 1)++-- | Check that 'integerSquareRoot' of 2^62-1 is 2^31-1, not 2^31.+integerSquareRootSpecialCase1_Word :: Assertion+integerSquareRootSpecialCase1_Word =+  assertEqual "integerSquareRoot" (integerSquareRoot (maxBound `div` 4 :: Word)) (2 ^ 31 - 1)++-- | Check that 'integerSquareRoot' of 2^64-1 is 2^32-1, not 2^32.+integerSquareRootSpecialCase2 :: Assertion+integerSquareRootSpecialCase2 =+  assertEqual "integerSquareRoot" (integerSquareRoot (maxBound :: Word)) (2 ^ 32 - 1)++#endif++-- | Check that 'integerSquareRoot'' returns the largest integer @r@ with @r*r <= n@.+integerSquareRoot'Property :: Integral a => NonNegative a -> Bool+integerSquareRoot'Property (NonNegative n) = m >=0 && m * m <= n && (m + 1) ^ 2 /= n && m + 1 >= n `div` (m + 1)+  where+    m = integerSquareRoot' n++-- | Check that the number 'isSquare' iff its 'integerSquareRoot' is exact.+isSquareProperty :: Integral a => AnySign a -> Bool+isSquareProperty (AnySign n) = (n < 0 && not t) || (n /= m * m && not t) || (n == m * m && t)+  where+    t = isSquare n+    m = integerSquareRoot n++-- | Check that the number 'isSquare'' iff its 'integerSquareRoot'' is exact.+isSquare'Property :: Integral a => NonNegative a -> Bool+isSquare'Property (NonNegative n) = (n /= m * m && not t) || (n == m * m && t)+  where+    t = isSquare' n+    m = integerSquareRoot' n++-- | Check that 'exactSquareRoot' returns an exact integer square root+-- and is consistent with 'isSquare'.+exactSquareRootProperty :: Integral a => AnySign a -> Bool+exactSquareRootProperty (AnySign n) = case exactSquareRoot n of+  Nothing -> not (isSquare n)+  Just m  -> isSquare n && n == m * m++-- | Check that 'isPossibleSquare' is consistent with 'exactSquareRoot'+-- and that 'isPossibleSquare2' is a refinement of 'isPossibleSquare'.+isPossibleSquareProperty :: Integral a => NonNegative a -> Bool+isPossibleSquareProperty (NonNegative n) = t || not t && not t2 && isNothing m+  where+    t = isPossibleSquare n+    t2 = isPossibleSquare2 n+    m = exactSquareRoot n++-- | Check that 'isPossibleSquare2'' is consistent with 'exactSquareRoot'.+isPossibleSquare2Property :: Integral a => NonNegative a -> Bool+isPossibleSquare2Property (NonNegative n) = t || not t && isNothing m+  where+    t = isPossibleSquare2 n+    m = exactSquareRoot n+++testSuite :: TestTree+testSuite = testGroup "Squares"+  [ testGroup "integerSquareRoor"+    [ testIntegralProperty "generic"          integerSquareRootProperty+    , testSmallAndQuick    "generic Int"      integerSquareRootProperty_Int+    , testSmallAndQuick    "generic Word"     integerSquareRootProperty_Word++    , testIntegralProperty "almost square"      integerSquareRootProperty2+    , testSmallAndQuick    "almost square Int"  integerSquareRootProperty2_Int+    , testSmallAndQuick    "almost square Word" integerSquareRootProperty2_Word++#if WORD_SIZE_IN_BITS == 64+    , testCase             "maxBound / 2 :: Int"  integerSquareRootSpecialCase1_Int+    , testCase             "maxBound / 4 :: Word" integerSquareRootSpecialCase1_Word+    , testCase             "maxBound :: Word"     integerSquareRootSpecialCase2+#endif+    ]++  , testIntegralProperty "integerSquareRoot'" integerSquareRoot'Property+  , testIntegralProperty "isSquare"           isSquareProperty+  , testIntegralProperty "isSquare'"          isSquare'Property+  , testIntegralProperty "exactSquareRoot"    exactSquareRootProperty+  , testIntegralProperty "isPossibleSquare"   isPossibleSquareProperty+  , testIntegralProperty "isPossibleSquare2"  isPossibleSquare2Property+  ]
+ test-suite/Math/NumberTheory/Primes/CountingTests.hs view
@@ -0,0 +1,148 @@+-- |+-- Module:      Math.NumberTheory.Primes.CountingTests+-- Copyright:   (c) 2016 Andrew Lelechenko+-- Licence:     MIT+-- Maintainer:  Andrew Lelechenko <andrew.lelechenko@gmail.com>+-- Stability:   Provisional+--+-- Tests for Math.NumberTheory.Primes.Counting+--++{-# OPTIONS_GHC -fno-warn-type-defaults #-}++module Math.NumberTheory.Primes.CountingTests+  ( testSuite+  ) where++import Test.Tasty+import Test.Tasty.HUnit++import Math.NumberTheory.Primes.Counting+import Math.NumberTheory.Primes.Testing+import Math.NumberTheory.TestUtils++-- | https://en.wikipedia.org/wiki/Prime-counting_function#Table_of_.CF.80.28x.29.2C_x_.2F_ln_x.2C_and_li.28x.29+table :: [(Integer, Integer)]+table =+  [ (10^1,   4)+  , (10^2,   25)+  , (10^3,   168)+  , (10^4,   1229)+  , (10^5,   9592)+  , (10^6,   78498)+  , (10^7,   664579)+  , (10^8,   5761455)+  , (10^9,   50847534)+  , (10^10,  455052511)+  , (10^11,  4118054813)+  , (10^12,  37607912018)+  , (10^13,  346065536839)+  -- , (10^14,  3204941750802)+  -- , (10^15,  29844570422669)+  -- , (10^16,  279238341033925)+  -- , (10^17,  2623557157654233)+  -- , (10^18,  24739954287740860)+  -- , (10^19,  234057667276344607)+  -- , (10^20,  2220819602560918840)+  ]++-- | Check that values of 'primeCount' are non-negative.+primeCountProperty1 :: Integer -> Bool+primeCountProperty1 n = n > primeCountMaxArg+  || n >  0 && primeCount n >= 0+  || n <= 0 && primeCount n == 0++-- | Check that 'primeCount' is monotonically increasing function.+primeCountProperty2 :: Positive Integer -> Positive Integer -> Bool+primeCountProperty2 (Positive n1) (Positive n2)+  =  n1 > primeCountMaxArg+  || n2 > primeCountMaxArg+  || n1 <= n2 && p1 <= p2+  || n1 >  n2 && p1 >= p2+  where+    p1 = primeCount n1+    p2 = primeCount n2++-- | Check that 'primeCount' is strictly increasing iff an argument is prime.+primeCountProperty3 :: Positive Integer -> Bool+primeCountProperty3 (Positive n)+  =  isPrime n && primeCount (n - 1) + 1 == primeCount n+  || not (isPrime n) && primeCount (n - 1) == primeCount n++-- | Check tabulated values.+primeCountSpecialCases :: [Assertion]+primeCountSpecialCases = map a table+  where+  a (n, m) = assertEqual "primeCount" m (primeCount n)+++-- | Check that values of 'nthPrime' are positive.+nthPrimeProperty1 :: Positive Integer -> Bool+nthPrimeProperty1 (Positive n) = n > nthPrimeMaxArg+  || nthPrime n > 0++-- | Check that 'nthPrime' is monotonically increasing function.+nthPrimeProperty2 :: Positive Integer -> Positive Integer -> Bool+nthPrimeProperty2 (Positive n1) (Positive n2)+  =  n1 > nthPrimeMaxArg+  || n2 > nthPrimeMaxArg+  || n1 <= n2 && p1 <= p2+  || n1 >  n2 && p1 >= p2+  where+    p1 = nthPrime n1+    p2 = nthPrime n2++-- | Check that values of 'nthPrime' are prime.+nthPrimeProperty3 :: Positive Integer -> Bool+nthPrimeProperty3 (Positive n) = isPrime $ nthPrime n++-- | Check tabulated values.+nthPrimeSpecialCases :: [Assertion]+nthPrimeSpecialCases = map a table+  where+  a (n, m) = assertBool "nthPrime" $ n > nthPrime m+++-- | Check that values of 'approxPrimeCount' are non-negative.+approxPrimeCountProperty1 :: Integral a => AnySign a -> Bool+approxPrimeCountProperty1 (AnySign a) = approxPrimeCount a >= 0++-- | Check that 'approxPrimeCount' is consistent with 'approxPrimeCountOverestimateLimit'.+approxPrimeCountProperty2 :: Integral a => Positive a -> Bool+approxPrimeCountProperty2 (Positive a) = a >= approxPrimeCountOverestimateLimit+  || toInteger (approxPrimeCount a) >= primeCount (toInteger a)+++-- | Check that values of 'nthPrimeApprox' are positive.+nthPrimeApproxProperty1 :: AnySign Integer -> Bool+nthPrimeApproxProperty1 (AnySign a) = nthPrimeApprox a > 0++-- | Check that 'nthPrimeApprox' is consistent with 'nthPrimeApproxUnderestimateLimit'.+nthPrimeApproxProperty2 :: Positive Integer -> Bool+nthPrimeApproxProperty2 (Positive a) = a >= nthPrimeApproxUnderestimateLimit+  || toInteger (nthPrimeApprox a) <= nthPrime (toInteger a)+++testSuite :: TestTree+testSuite = testGroup "Counting"+  [ testGroup "primeCount"+    ( testSmallAndQuick "non-negative"        primeCountProperty1+    : testSmallAndQuick "monotonic"           primeCountProperty2+    : testSmallAndQuick "increases on primes" primeCountProperty3+    : zipWith (\i a -> testCase ("special case " ++ show i) a) [1..] primeCountSpecialCases+    )+  , testGroup "nthPrime"+    ( testSmallAndQuick "positive"  nthPrimeProperty1+    : testSmallAndQuick "monotonic" nthPrimeProperty2+    : testSmallAndQuick "is prime"  nthPrimeProperty3+    : zipWith (\i a -> testCase ("special case " ++ show i) a) [1..] nthPrimeSpecialCases+    )+  , testGroup "approxPrimeCount"+    [ testIntegralProperty "non-negative"             approxPrimeCountProperty1+    , testIntegralProperty "overestimates primeCount" approxPrimeCountProperty2+    ]+  , testGroup "nthPrimeApprox"+    [ testSmallAndQuick "positive"                nthPrimeApproxProperty1+    , testSmallAndQuick "underestimates nthPrime" nthPrimeApproxProperty2+    ]+  ]
+ test-suite/Math/NumberTheory/Primes/HeapTests.hs view
@@ -0,0 +1,67 @@+-- |+-- Module:      Math.NumberTheory.Primes.HeapTests+-- Copyright:   (c) 2016 Andrew Lelechenko+-- Licence:     MIT+-- Maintainer:  Andrew Lelechenko <andrew.lelechenko@gmail.com>+-- Stability:   Provisional+--+-- Tests for Math.NumberTheory.Primes.Heap+--++{-# LANGUAGE CPP #-}++{-# OPTIONS_GHC -fno-warn-type-defaults #-}++module Math.NumberTheory.Primes.HeapTests+  ( testSuite+  ) where++import Prelude hiding (words)++import Test.Tasty+import Test.Tasty.HUnit++#if MIN_VERSION_base(4,8,0)+#else+import Data.Word+#endif++import Math.NumberTheory.Primes.Heap+import Math.NumberTheory.Primes.Testing+import Math.NumberTheory.TestUtils++-- | Check that 'primes' over different integral types matches with 'isPrime'.+primesProperty1 :: Assertion+primesProperty1 = do+  assertEqual "ints  == integers" (trim ints)  (trim integers)+  assertEqual "words == integers" (trim words) (trim integers)+  assertEqual "naive == integers" (trim naive) (trim integers)+  where+    trim :: Integral a => [a] -> [Integer]+    trim = map toInteger . take 100000++    ints     = primes :: [Int]+    words    = primes :: [Word]+    integers = primes :: [Integer]+    naive    = filter isPrime [1..] :: [Integer]++-- | Check that 'sieveFrom' over different integral types matches with 'isPrime'.+sieveFromProperty1 :: NonNegative Integer -> Bool+sieveFromProperty1 (NonNegative lowBound)+  =  trim ints  == trim integers+  && trim words == trim integers+  && trim naive == trim integers+  where+    trim :: Integral a => [a] -> [Integer]+    trim = map toInteger . take 1000++    ints     = sieveFrom (fromInteger lowBound) :: [Int]+    words    = sieveFrom (fromInteger lowBound) :: [Word]+    integers = sieveFrom lowBound               :: [Integer]+    naive    = filter isPrime [lowBound..]      :: [Integer]++testSuite :: TestTree+testSuite = testGroup "Heap"+  [ testCase          "primes"    primesProperty1+  , testSmallAndQuick "sieveFrom" sieveFromProperty1+  ]
+ test-suite/Math/NumberTheory/Primes/SieveTests.hs view
@@ -0,0 +1,69 @@+-- |+-- Module:      Math.NumberTheory.Primes.SieveTests+-- Copyright:   (c) 2016 Andrew Lelechenko+-- Licence:     MIT+-- Maintainer:  Andrew Lelechenko <andrew.lelechenko@gmail.com>+-- Stability:   Provisional+--+-- Tests for Math.NumberTheory.Primes.Sieve+--++{-# LANGUAGE CPP #-}++{-# OPTIONS_GHC -fno-warn-type-defaults #-}++module Math.NumberTheory.Primes.SieveTests+  ( testSuite+  ) where++import Prelude hiding (words)++import Test.Tasty+import Test.Tasty.HUnit++import Math.NumberTheory.Primes.Sieve+import qualified Math.NumberTheory.Primes.Heap as H+import Math.NumberTheory.TestUtils++-- | Check that both 'primes' produce the same.+primesProperty1 :: Assertion+primesProperty1 = do+  assertEqual "Sieve == Heap" (trim primes) (trim H.primes)+  where+    trim = take 100000++-- | Check that both 'sieveFrom' produce the same.+sieveFromProperty1 :: AnySign Integer -> Bool+sieveFromProperty1 (AnySign lowBound)+  = trim (sieveFrom lowBound) == trim (H.sieveFrom lowBound)+  where+    trim = take 1000++-- | Check that 'primeList' from 'primeSieve' matches truncated 'primes'.+primeSieveProperty1 :: AnySign Integer -> Bool+primeSieveProperty1 (AnySign highBound)+  = primeList (primeSieve highBound) == takeWhile (<= (highBound `max` 7)) primes++-- | Check that 'primeList' from 'psieveList' matches 'primes'.+psieveListProperty1 :: Assertion+psieveListProperty1 = do+  assertEqual "primes == primeList . psieveList" (trim primes) (trim $ concatMap primeList psieveList)+  where+    trim = take 100000++-- | Check that 'primeList' from 'psieveFrom' matches 'sieveFrom'.+psieveFromProperty1 :: AnySign Integer -> Bool+psieveFromProperty1 (AnySign lowBound)+  = trim (sieveFrom lowBound) == trim (filter (>= lowBound) (concatMap primeList $ psieveFrom lowBound))+  where+    trim = take 1000+++testSuite :: TestTree+testSuite = testGroup "Sieve"+  [ testCase          "primes"     primesProperty1+  , testSmallAndQuick "sieveFrom"  sieveFromProperty1+  , testSmallAndQuick "primeSieve" primeSieveProperty1+  , testCase          "psieveList" psieveListProperty1+  , testSmallAndQuick "psieveFrom" psieveFromProperty1+  ]
+ test-suite/Math/NumberTheory/PrimesTests.hs view
@@ -0,0 +1,40 @@+-- |+-- Module:      Math.NumberTheory.PrimesTests+-- Copyright:   (c) 2016 Andrew Lelechenko+-- Licence:     MIT+-- Maintainer:  Andrew Lelechenko <andrew.lelechenko@gmail.com>+-- Stability:   Provisional+--+-- Tests for Math.NumberTheory.Primes+--++{-# OPTIONS_GHC -fno-warn-type-defaults #-}++module Math.NumberTheory.PrimesTests+  ( testSuite+  ) where++import Test.Tasty+import Test.Tasty.HUnit++import Math.NumberTheory.Primes+import Math.NumberTheory.TestUtils++primesSumWonk :: Int -> Int+primesSumWonk upto = sum . takeWhile (< upto) . map fromInteger . primeList $ primeSieve (toInteger upto)++primesSum :: Int -> Int+primesSum upto = sum . takeWhile (< upto) . map fromInteger $ primes++primesSumProperty :: NonNegative Int -> Bool+primesSumProperty (NonNegative n) = primesSumWonk n == primesSum n+++sieveFactorSpecialCase1 :: Assertion+sieveFactorSpecialCase1 = assertEqual "sieveFactor" [(29, 1), (73, 1)] $ sieveFactor (factorSieve 2048) (29*73)++testSuite :: TestTree+testSuite = testGroup "Primes"+  [ testSmallAndQuick "primesSum"   primesSumProperty+  , testCase          "sieveFactor" sieveFactorSpecialCase1+  ]
+ test-suite/Math/NumberTheory/TestUtils.hs view
@@ -0,0 +1,226 @@+-- |+-- Module:      Math.NumberTheory.TestUtils+-- Copyright:   (c) 2016 Andrew Lelechenko+-- Licence:     MIT+-- Maintainer:  Andrew Lelechenko <andrew.lelechenko@gmail.com>+-- Stability:   Provisional+-- Portability: Non-portable (GHC extensions)+--+-- Utils to test Math.NumberTheory+--++{-# LANGUAGE ConstraintKinds            #-}+{-# LANGUAGE CPP                        #-}+{-# LANGUAGE DataKinds                  #-}+{-# LANGUAGE DeriveFoldable             #-}+{-# LANGUAGE DeriveFunctor              #-}+{-# LANGUAGE DeriveTraversable          #-}+{-# LANGUAGE FlexibleContexts           #-}+{-# LANGUAGE FlexibleInstances          #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE KindSignatures             #-}+{-# LANGUAGE MultiParamTypeClasses      #-}+{-# LANGUAGE RankNTypes                 #-}+{-# LANGUAGE ScopedTypeVariables        #-}+{-# LANGUAGE TypeFamilies               #-}+{-# LANGUAGE TypeOperators              #-}+{-# LANGUAGE UndecidableInstances       #-}++#if __GLASGOW_HASKELL__ >= 800+{-# LANGUAGE UndecidableSuperClasses    #-}++{-# OPTIONS_GHC -fconstraint-solver-iterations=0 #-}+#endif++{-# OPTIONS_GHC -fno-warn-orphans #-}+{-# OPTIONS_GHC -fno-warn-type-defaults #-}++module Math.NumberTheory.TestUtils+  ( module Math.NumberTheory.TestUtils+  , module Test.SmallCheck.Series+  , Large(..)+  ) where++import Test.Tasty+import Test.Tasty.SmallCheck as SC+import Test.Tasty.QuickCheck as QC hiding (Positive, NonNegative, generate, getNonNegative)++import Test.SmallCheck.Series (Positive(..), NonNegative(..), Serial(..), Series, generate)++import Control.Applicative+import Data.Bits+#if MIN_VERSION_base(4,8,0)+#else+import Data.Foldable (Foldable)+import Data.Traversable (Traversable)+import Data.Word+#endif+import GHC.Exts++import Math.NumberTheory.Primes++newtype AnySign a = AnySign { getAnySign :: a }+  deriving (Eq, Ord, Read, Show, Num, Enum, Bounded, Integral, Real, Functor, Foldable, Traversable, Arbitrary)++instance (Monad m, Serial m a) => Serial m (AnySign a) where+  series = AnySign <$> series++instance (Num a, Ord a, Arbitrary a) => Arbitrary (Positive a) where+  arbitrary = Positive <$> (arbitrary `suchThat` (> 0))+  shrink (Positive x) = Positive <$> filter (> 0) (shrink x)++instance (Num a, Ord a, Arbitrary a) => Arbitrary (NonNegative a) where+  arbitrary = NonNegative <$> (arbitrary `suchThat` (>= 0))+  shrink (NonNegative x) = NonNegative <$> filter (>= 0) (shrink x)++instance (Num a, Bounded a) => Bounded (Positive a) where+  minBound = Positive 1+  maxBound = Positive (maxBound :: a)++instance (Num a, Bounded a) => Bounded (NonNegative a) where+  minBound = NonNegative 0+  maxBound = NonNegative (maxBound :: a)++newtype Huge a = Huge { getHuge :: a }+  deriving (Eq, Ord, Enum, Bounded, Show, Num, Real, Integral)++instance (Num a, Arbitrary a) => Arbitrary (Huge a) where+  arbitrary = do+    Positive l <- arbitrary+    ds <- vector l+    return $ Huge $ foldl1 (\acc n -> acc * 2^63 + n) ds++newtype Power a = Power { getPower :: a }+  deriving (Eq, Ord, Enum, Bounded, Show, Num, Real, Integral)++instance (Monad m, Num a, Ord a, Serial m a) => Serial m (Power a) where+  series = Power <$> series `suchThatSerial` (> 0)++instance (Num a, Ord a, Integral a, Arbitrary a) => Arbitrary (Power a) where+  arbitrary = Power <$> (getSmall <$> arbitrary) `suchThat` (> 0)+  shrink (Power x) = Power <$> filter (> 0) (shrink x)++newtype Prime = Prime { getPrime :: Integer }+  deriving (Eq, Ord, Show)++instance Arbitrary Prime where+  arbitrary = Prime <$> arbitrary `suchThat` (\p -> p > 0 && isPrime p)++instance Monad m => Serial m Prime where+  series = Prime <$> series `suchThatSerial` (\p -> p > 0 && isPrime p)++instance Monad m => Serial m Word where+  series =+    generate (\d -> if d >= 0 then pure 0 else empty) <|> nats+    where+      nats = generate $ \d -> if d > 0 then [1 .. fromInteger (toInteger d)] else empty++suchThatSerial :: Series m a -> (a -> Bool) -> Series m a+suchThatSerial s p = s >>= \x -> if p x then pure x else empty+++-- https://www.cs.ox.ac.uk/projects/utgp/school/andres.pdf, p. 21+-- :k Compose = (k1 -> Constraint) -> (k2 -> k1) -> (k2 -> Constraint)+class    (f (g x)) => (f `Compose` g) x+instance (f (g x)) => (f `Compose` g) x++type family ConcatMap (w :: * -> Constraint) (cs :: [*]) :: Constraint+#if __GLASGOW_HASKELL__ >= 708+  where+    ConcatMap w '[] = ()+    ConcatMap w (c ': cs) = (w c, ConcatMap w cs)+#else+type instance ConcatMap w '[] = ()+type instance ConcatMap w (c ': cs) = (w c, ConcatMap w cs)+#endif++type family Matrix (as :: [* -> Constraint]) (w :: * -> *) (bs :: [*]) :: Constraint+#if __GLASGOW_HASKELL__ >= 708+  where+    Matrix '[] w bs = ()+    Matrix (a ': as) w bs = (ConcatMap (a `Compose` w) bs, Matrix as w bs)+#else+type instance Matrix '[] w bs = ()+type instance Matrix (a ': as) w bs = (ConcatMap (a `Compose` w) bs, Matrix as w bs)+#endif++type TestableIntegral wrapper =+  ( Matrix '[Arbitrary, Show, Serial IO] wrapper '[Int, Word, Integer]+  , Matrix '[Bounded, Integral] wrapper '[Int, Word]+  , Num (wrapper Integer)+  )+++testIntegralProperty+  :: forall wrapper bool. (TestableIntegral wrapper, SC.Testable IO bool, QC.Testable bool)+  => String -> (forall a. (Integral a, Bits a) => wrapper a -> bool) -> TestTree+testIntegralProperty name f = testGroup name+  [ SC.testProperty "smallcheck Int"     (f :: wrapper Int     -> bool)+  , SC.testProperty "smallcheck Word"    (f :: wrapper Word    -> bool)+  , SC.testProperty "smallcheck Integer" (f :: wrapper Integer -> bool)+  , QC.testProperty "quickcheck Int"     (f :: wrapper Int     -> bool)+  , QC.testProperty "quickcheck Word"    (f :: wrapper Word    -> bool)+  , QC.testProperty "quickcheck Integer" (f :: wrapper Integer -> bool)+  , QC.testProperty "quickcheck Large Int"     ((f :: wrapper Int     -> bool) . getLarge)+  , QC.testProperty "quickcheck Large Word"    ((f :: wrapper Word    -> bool) . getLarge)+  , QC.testProperty "quickcheck Huge  Integer" ((f :: wrapper Integer -> bool) . getHuge)+  ]++testSameIntegralProperty+  :: forall wrapper1 wrapper2 bool. (TestableIntegral wrapper1, TestableIntegral wrapper2, SC.Testable IO bool, QC.Testable bool)+  => String -> (forall a. (Integral a, Bits a) => wrapper1 a -> wrapper2 a -> bool) -> TestTree+testSameIntegralProperty name f = testGroup name+  [ SC.testProperty "smallcheck Int"     (f :: wrapper1 Int     -> wrapper2 Int     -> bool)+  , SC.testProperty "smallcheck Word"    (f :: wrapper1 Word    -> wrapper2 Word    -> bool)+  , SC.testProperty "smallcheck Integer" (f :: wrapper1 Integer -> wrapper2 Integer -> bool)+  , QC.testProperty "quickcheck Int"     (f :: wrapper1 Int     -> wrapper2 Int     -> bool)+  , QC.testProperty "quickcheck Word"    (f :: wrapper1 Word    -> wrapper2 Word    -> bool)+  , QC.testProperty "quickcheck Integer" (f :: wrapper1 Integer -> wrapper2 Integer -> bool)+  , QC.testProperty "quickcheck Large Int"     (\(Large a) (Large b) -> (f :: wrapper1 Int     -> wrapper2 Int     -> bool) a b)+  , QC.testProperty "quickcheck Large Word"    (\(Large a) (Large b) -> (f :: wrapper1 Word    -> wrapper2 Word    -> bool) a b)+  , QC.testProperty "quickcheck Huge  Integer" (\(Huge  a) (Huge  b) -> (f :: wrapper1 Integer -> wrapper2 Integer -> bool) a b)+  ]++testIntegral2Property+  :: forall wrapper1 wrapper2 bool. (TestableIntegral wrapper1, TestableIntegral wrapper2, SC.Testable IO bool, QC.Testable bool)+  => String -> (forall a1 a2. (Integral a1, Integral a2, Bits a1, Bits a2) => wrapper1 a1 -> wrapper2 a2 -> bool) -> TestTree+testIntegral2Property name f = testGroup name+  [ SC.testProperty "smallcheck Int Int"         (f :: wrapper1 Int     -> wrapper2 Int     -> bool)+  , SC.testProperty "smallcheck Int Word"        (f :: wrapper1 Int     -> wrapper2 Word    -> bool)+  , SC.testProperty "smallcheck Int Integer"     (f :: wrapper1 Int     -> wrapper2 Integer -> bool)+  , SC.testProperty "smallcheck Word Int"        (f :: wrapper1 Word    -> wrapper2 Int     -> bool)+  , SC.testProperty "smallcheck Word Word"       (f :: wrapper1 Word    -> wrapper2 Word    -> bool)+  , SC.testProperty "smallcheck Word Integer"    (f :: wrapper1 Word    -> wrapper2 Integer -> bool)+  , SC.testProperty "smallcheck Integer Int"     (f :: wrapper1 Integer -> wrapper2 Int     -> bool)+  , SC.testProperty "smallcheck Integer Word"    (f :: wrapper1 Integer -> wrapper2 Word    -> bool)+  , SC.testProperty "smallcheck Integer Integer" (f :: wrapper1 Integer -> wrapper2 Integer -> bool)++  , QC.testProperty "quickcheck Int Int"         (f :: wrapper1 Int     -> wrapper2 Int     -> bool)+  , QC.testProperty "quickcheck Int Word"        (f :: wrapper1 Int     -> wrapper2 Word    -> bool)+  , QC.testProperty "quickcheck Int Integer"     (f :: wrapper1 Int     -> wrapper2 Integer -> bool)+  , QC.testProperty "quickcheck Word Int"        (f :: wrapper1 Word    -> wrapper2 Int     -> bool)+  , QC.testProperty "quickcheck Word Word"       (f :: wrapper1 Word    -> wrapper2 Word    -> bool)+  , QC.testProperty "quickcheck Word Integer"    (f :: wrapper1 Word    -> wrapper2 Integer -> bool)+  , QC.testProperty "quickcheck Integer Int"     (f :: wrapper1 Integer -> wrapper2 Int     -> bool)+  , QC.testProperty "quickcheck Integer Word"    (f :: wrapper1 Integer -> wrapper2 Word    -> bool)+  , QC.testProperty "quickcheck Integer Integer" (f :: wrapper1 Integer -> wrapper2 Integer -> bool)++  , QC.testProperty "quickcheck Large Int Int"         ((f :: wrapper1 Int     -> wrapper2 Int     -> bool) . getLarge)+  , QC.testProperty "quickcheck Large Int Word"        ((f :: wrapper1 Int     -> wrapper2 Word    -> bool) . getLarge)+  , QC.testProperty "quickcheck Large Int Integer"     ((f :: wrapper1 Int     -> wrapper2 Integer -> bool) . getLarge)+  , QC.testProperty "quickcheck Large Word Int"        ((f :: wrapper1 Word    -> wrapper2 Int     -> bool) . getLarge)+  , QC.testProperty "quickcheck Large Word Word"       ((f :: wrapper1 Word    -> wrapper2 Word    -> bool) . getLarge)+  , QC.testProperty "quickcheck Large Word Integer"    ((f :: wrapper1 Word    -> wrapper2 Integer -> bool) . getLarge)+  , QC.testProperty "quickcheck Huge  Integer Int"     ((f :: wrapper1 Integer -> wrapper2 Int     -> bool) . getHuge)+  , QC.testProperty "quickcheck Huge  Integer Word"    ((f :: wrapper1 Integer -> wrapper2 Word    -> bool) . getHuge)+  , QC.testProperty "quickcheck Huge  Integer Integer" ((f :: wrapper1 Integer -> wrapper2 Integer -> bool) . getHuge)+  ]++testSmallAndQuick+  :: SC.Testable IO a+  => QC.Testable a+  => String -> a -> TestTree+testSmallAndQuick name f = testGroup name+  [ SC.testProperty "smallcheck" f+  , QC.testProperty "quickcheck" f+  ]
− test-suite/Spec.hs
@@ -1,1 +0,0 @@-{-# OPTIONS_GHC -F -pgmF hspec-discover #-}
+ test-suite/Test.hs view
@@ -0,0 +1,66 @@+import Test.Tasty++import qualified Math.NumberTheory.GCDTests as GCD+import qualified Math.NumberTheory.GCD.LowLevelTests as GCDLowLevel++import qualified Math.NumberTheory.LogarithmsTests as Logarithms++import qualified Math.NumberTheory.LucasTests as Lucas++import qualified Math.NumberTheory.ModuliTests as Moduli++import qualified Math.NumberTheory.MoebiusInversionTests as MoebiusInversion+import qualified Math.NumberTheory.MoebiusInversion.IntTests as MoebiusInversionInt++import qualified Math.NumberTheory.Powers.CubesTests as Cubes+import qualified Math.NumberTheory.Powers.FourthTests as Fourth+import qualified Math.NumberTheory.Powers.GeneralTests as General+import qualified Math.NumberTheory.Powers.IntegerTests as Integer+import qualified Math.NumberTheory.Powers.SquaresTests as Squares++import qualified Math.NumberTheory.PrimesTests as Primes+import qualified Math.NumberTheory.Primes.CountingTests as Counting+import qualified Math.NumberTheory.Primes.HeapTests as Heap+import qualified Math.NumberTheory.Primes.SieveTests as Sieve++import qualified Math.NumberTheory.GaussianIntegersTests as Gaussian++main :: IO ()+main = defaultMain tests++tests :: TestTree+tests = testGroup "All"+  [ testGroup "Powers"+    [ Cubes.testSuite+    , Fourth.testSuite+    , General.testSuite+    , Integer.testSuite+    , Squares.testSuite+    ]+  , testGroup "GCD"+    [ GCD.testSuite+    , GCDLowLevel.testSuite+    ]+  , testGroup "Logarithms"+    [ Logarithms.testSuite+    ]+  , testGroup "Lucas"+    [ Lucas.testSuite+    ]+  , testGroup "Moduli"+    [ Moduli.testSuite+    ]+  , testGroup "MoebiusInversion"+    [ MoebiusInversion.testSuite+    , MoebiusInversionInt.testSuite+    ]+  , testGroup "Primes"+    [ Primes.testSuite+    , Counting.testSuite+    , Heap.testSuite+    , Sieve.testSuite+    ]+  , testGroup "Gaussian"+    [ Gaussian.testSuite+    ]+  ]