factory 0.1.0.3 → 0.2.0.0
raw patch · 49 files changed
+938/−452 lines, 49 files
Files
- changelog +8/−1
- factory.cabal +9/−3
- src/Factory/Data/Interval.hs +4/−4
- src/Factory/Data/PrimeFactors.hs +1/−2
- src/Factory/Data/PrimeWheel.hs +37/−17
- src/Factory/Math/ArithmeticGeometricMean.hs +1/−1
- src/Factory/Math/Hyperoperation.hs +2/−2
- src/Factory/Math/Implementations/Factorial.hs +3/−3
- src/Factory/Math/Implementations/Pi/Borwein/Borwein1993.hs +2/−2
- src/Factory/Math/Implementations/Pi/Ramanujan/Chudnovsky.hs +1/−1
- src/Factory/Math/Implementations/Pi/Ramanujan/Classic.hs +1/−1
- src/Factory/Math/Implementations/Pi/Spigot/Algorithm.hs +1/−1
- src/Factory/Math/Implementations/Pi/Spigot/Gosper.hs +2/−2
- src/Factory/Math/Implementations/Pi/Spigot/Spigot.hs +3/−3
- src/Factory/Math/Implementations/Primality.hs +3/−2
- src/Factory/Math/Implementations/PrimeFactorisation.hs +6/−5
- src/Factory/Math/Implementations/Primes.hs +0/−229
- src/Factory/Math/Implementations/Primes/Algorithm.hs +63/−0
- src/Factory/Math/Implementations/Primes/SieveOfAtkin.hs +251/−0
- src/Factory/Math/Implementations/Primes/SieveOfEratosthenes.hs +157/−0
- src/Factory/Math/Implementations/Primes/TrialDivision.hs +61/−0
- src/Factory/Math/Implementations/Primes/TurnersSieve.hs +48/−0
- src/Factory/Math/Implementations/SquareRoot.hs +1/−1
- src/Factory/Math/PerfectPower.hs +100/−0
- src/Factory/Math/Pi.hs +4/−4
- src/Factory/Math/Power.hs +6/−78
- src/Factory/Math/Precision.hs +1/−1
- src/Factory/Math/Primality.hs +3/−3
- src/Factory/Math/Primes.hs +6/−3
- src/Factory/Math/Radix.hs +3/−3
- src/Factory/Math/Statistics.hs +1/−1
- src/Factory/Test/Performance/Primes.hs +2/−1
- src/Factory/Test/QuickCheck/ArithmeticGeometricMean.hs +3/−3
- src/Factory/Test/QuickCheck/Factorial.hs +6/−6
- src/Factory/Test/QuickCheck/Hyperoperation.hs +2/−2
- src/Factory/Test/QuickCheck/Interval.hs +4/−4
- src/Factory/Test/QuickCheck/MonicPolynomial.hs +2/−2
- src/Factory/Test/QuickCheck/PerfectPower.hs +52/−0
- src/Factory/Test/QuickCheck/Pi.hs +1/−1
- src/Factory/Test/QuickCheck/Polynomial.hs +6/−6
- src/Factory/Test/QuickCheck/Power.hs +3/−18
- src/Factory/Test/QuickCheck/PrimeFactorisation.hs +6/−6
- src/Factory/Test/QuickCheck/Primes.hs +39/−13
- src/Factory/Test/QuickCheck/Probability.hs +1/−1
- src/Factory/Test/QuickCheck/QuickChecks.hs +2/−0
- src/Factory/Test/QuickCheck/Radix.hs +1/−1
- src/Factory/Test/QuickCheck/SquareRoot.hs +4/−4
- src/Factory/Test/QuickCheck/Statistics.hs +3/−3
- src/Main.hs +12/−8
changelog view
@@ -35,4 +35,11 @@ 0.1.0.3 * Qualified 'Factory.Math.Implementations.Primes.trialDivision' with /NOINLINE/ pragma, to block optimization which conflicts with rewrite-rule for 'Factory.Math.Implementations.Primes.sieveOfEratosthenes' ! * Re-coded 'Factory.Data.PrimeWheel.coprimes' and 'Factory.Math.Implementations.Primes.sieveOfEratosthenes', to use a map of lists, rather than a map of lists of lists.-+0.2.0.0+ * Separately coded the special-case of a 'Factory.Data.PrimeWheel' of size zero, in 'Factory.Math.Implementations.Primes.trialDivision', to achieve better space-complexity.+ * Added 'Factory.Data.PrimeWheel.estimateOptimalSize'.+ * Split "Factory.Math.Implementations.Primes" into; "Factory.Math.Implementations.Primes.SieveOfEratosthenes", "Factory.Math.Implementations.Primes.TurnersSieve", "Factory.Math.Implementations.Primes.TrialDivision", and added a new module "Factory.Math.Implementations.Primes.SieveOfAtkin". This makes the rewrite-rules less fragile.+ * Coded 'Factory.Math.Radix.digitalRoot' more concisely.+ * Split "Factory.Math.Power" into an additional module "Factory.Math.PerfectPower".+ * Replaced '(+ 1)' and '(- 1)' with the faster calls 'succ' and 'pred'.+ * Used 'Paths_factory.version' in 'Main', rather than hard-coding it.
factory.cabal view
@@ -1,6 +1,6 @@ --Package-properties Name: factory-Version: 0.1.0.3+Version: 0.2.0.0 Cabal-Version: >= 1.6 Copyright: (C) 2011 Dr. Alistair Ward License: GPL@@ -9,7 +9,7 @@ Stability: Unstable interface, incomplete features. Synopsis: Rational arithmetic in an irrational world. Build-Type: Simple-Description: A library of number-theory functions, for; factorials, square-roots, Pi, primality-testing, prime-factorisation ...+Description: A library of number-theory functions, for; factorials, square-roots, Pi and primes. Category: Math, Number Theory Tested-With: GHC == 6.10, GHC == 6.12, GHC == 7.0 Homepage: http://functionalley.eu@@ -68,9 +68,14 @@ Factory.Math.Implementations.Pi.Spigot.Spigot Factory.Math.Implementations.Primality Factory.Math.Implementations.PrimeFactorisation- Factory.Math.Implementations.Primes+ Factory.Math.Implementations.Primes.Algorithm+ Factory.Math.Implementations.Primes.SieveOfAtkin+ Factory.Math.Implementations.Primes.SieveOfEratosthenes+ Factory.Math.Implementations.Primes.TrialDivision+ Factory.Math.Implementations.Primes.TurnersSieve Factory.Math.Implementations.SquareRoot Factory.Math.MultiplicativeOrder+ Factory.Math.PerfectPower Factory.Math.Pi Factory.Math.Power Factory.Math.Precision@@ -123,6 +128,7 @@ Factory.Test.QuickCheck.Hyperoperation Factory.Test.QuickCheck.Interval Factory.Test.QuickCheck.MonicPolynomial+ Factory.Test.QuickCheck.PerfectPower Factory.Test.QuickCheck.Pi Factory.Test.QuickCheck.Polynomial Factory.Test.QuickCheck.Power
src/Factory/Data/Interval.hs view
@@ -120,15 +120,15 @@ | otherwise = b -- | Bisect the /interval/ at the specified /end-point/; which should be between the two existing /end-points/.-splitAt' :: (Num endPoint, Ord endPoint) => endPoint -> Interval endPoint -> (Interval endPoint, Interval endPoint)+splitAt' :: (Enum endPoint, Num endPoint, Ord endPoint) => endPoint -> Interval endPoint -> (Interval endPoint, Interval endPoint) splitAt' i interval@(l, r) | any ($ i) [(< l), (>= r)] = error $ "Factory.Data.Interval.splitAt':\tunsuitable index=" ++ show i ++ " for interval=" ++ show interval ++ "."- | otherwise = ((l, i), (i + 1, r))+ | otherwise = ((l, i), (succ i, r)) -- | The length of 'toList'. {-# INLINE getLength #-}-getLength :: (Num endPoint, Ord endPoint) => Interval endPoint -> endPoint-getLength (l, r) = r + 1 - l+getLength :: (Enum endPoint, Num endPoint) => Interval endPoint -> endPoint+getLength (l, r) = succ r - l -- | Converts 'Interval' to a list by enumerating the values. {-# INLINE toList #-}
src/Factory/Data/PrimeFactors.hs view
@@ -32,7 +32,6 @@ -- * Functions insert', -- invert,--- merge, product', reduce, -- reduceSorted,@@ -90,7 +89,7 @@ * Preserves the sort-order. - * CAVEAT: this is tolerably efficient for the odd insertion; to insert a list, use '>*<'.+ * CAVEAT: this is tolerably efficient for sporadic insertion; to insert a list, use '>*<'. -} insert' :: (Ord base, Num exponent) => Data.Exponential.Exponential base exponent -> Factors base exponent -> Factors base exponent insert' e [] = [e]
src/Factory/Data/PrimeWheel.hs view
@@ -24,13 +24,15 @@ -- * Types -- ** Type-synonyms Distance,+ NPrimes, PrimeMultiples, -- Repository, -- ** Data-types- PrimeWheel(getPrimeComponents),+ PrimeWheel(getPrimeComponents, getSpokeGaps), -- * Functions+ estimateOptimalSize, -- findCoprimes,- generatePrimeMultiples,+ generateMultiples, roll, rotate, -- ** Constructors@@ -53,7 +55,7 @@ Each has a single mark on its /circumference/, which when rolled identifies multiples of that /circumference/. When the complete set is rolled, from the state where all marks are coincident, all multiples of the set of primes, are traced. - * CAVEAT: The distance required to return this state, the /circumference/ grows rapidly, with the number of primes:+ * CAVEAT: The distance required to return to this state (the wheel's /circumference/), grows rapidly with the number of primes: > zip [0 ..] . scanl (*) 1 $ [2,3,5,7,11,13,17,19,23,29,31] > [(0,1),(1,2),(2,6),(3,30),(4,210),(5,2310),(6,30030),(7,510510),(8,9699690),(9,223092870),(10,6469693230),(11,200560490130)]@@ -69,7 +71,7 @@ } deriving Show -- | The /circumference/ of the specified 'PrimeWheel'.-getCircumference :: Num n => PrimeWheel n -> n+getCircumference :: Integral i => PrimeWheel i -> i getCircumference = product . getPrimeComponents -- | The number of spokes in the specified 'PrimeWheel'.@@ -82,43 +84,61 @@ -- | Defines a container for the 'PrimeMultiples'. type Repository = Data.IntMap.IntMap (PrimeMultiples Int) +-- | The size of the /wheel/, measured by the number of primes from which it is composed.+type NPrimes = Int+ {- | * Uses a /Sieve of Eratosthenes/ (<http://en.wikipedia.org/wiki/Sieve_of_Eratosthenes>), to generate an initial sequence of primes. - * Also generates an infinite sequence of candidate primes, each of which is /coprime/ to the primes just found.+ * Also generates an infinite sequence of candidate primes, each of which is /coprime/ to the primes just found, e.g.:+ @filter ((== 1) . (gcd (2 * 3 * 5 * 7))) [11 ..] = [11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97,101,103,107,109,113,121 ..]@; NB /121/ isn't prime. * CAVEAT: the use, for efficiency, of "Data.IntMap", limits the maximum bound of this sequence, though not to a significant extent. -}-findCoprimes :: Int -> ([Int], [Int])+findCoprimes :: NPrimes -> ([Int], [Int]) findCoprimes 0 = ([], []) findCoprimes required | required < 0 = error $ "Factory.Data.PrimeWheel.findCoprimes: invalid number of coprimes; " ++ show required | otherwise = splitAt required $ 2 : sieve 3 0 Data.IntMap.empty where- sieve :: Int -> Int -> Repository -> [Int]+ sieve :: Int -> NPrimes -> Repository -> [Int] sieve candidate found repository = case Data.IntMap.lookup candidate repository of Just primeMultiples -> sieve' found . insertUniq primeMultiples $ Data.IntMap.delete candidate repository --Re-insert subsequent multiples.- Nothing -> let+ Nothing {-prime-} -> let found' = succ found (key : values) = iterate (+ gap * candidate) $ candidate ^ (2 :: Int) --Generate a sequence of prime-multiples, starting from its square.- in candidate : sieve' found' (if found' >= required then repository else Data.IntMap.insert key values repository)+ in candidate : sieve' found' (+ if found' >= required+ then repository+ else Data.IntMap.insert key values repository+ ) where gap :: Int gap = 2 --For efficiency, only sieve odd integers. - sieve' :: Int -> Repository -> [Int]+ sieve' :: NPrimes -> Repository -> [Int] sieve' = sieve $ candidate + gap --Tail-recurse. insertUniq :: PrimeMultiples Int -> Repository -> Repository- insertUniq l m = insert (dropWhile (`Data.IntMap.member` m) l) where+ insertUniq l m = insert $ dropWhile (`Data.IntMap.member` m) l where insert :: PrimeMultiples Int -> Repository insert [] = error "Factory.Data.PrimeWheel.findCoprimes.sieve.insertUniq.insert:\tnull list" insert (key : values) = Data.IntMap.insert key values m+{- |+ * The optimal number of low primes from which to build the /wheel/, grows with the number of primes required;+ the /circumference/ should be approximately the /square-root/ of the number of integers it will be required to sieve. + * CAVEAT: one greater than this is returned, which empirically seems better.+-}+estimateOptimalSize :: Integral i => i -> NPrimes+estimateOptimalSize maxPrime = succ . length . takeWhile (<= optimalCircumference) . scanl1 (*) {-circumference-} . map fromIntegral {-prevent overflow-} . fst {-primes-} $ findCoprimes 10 {-arbitrary maximum bound-} where+ optimalCircumference :: Integer+ optimalCircumference = round (sqrt $ fromIntegral maxPrime :: Double)+ {- | * Constructs a /wheel/ from the specified number of low primes. - * The optimum number of low primes from which to build the /wheel/, grows with the number of primes required;+ * The optimal number of low primes from which to build the /wheel/, grows with the number of primes required; the /circumference/ should be approximately the /square-root/ of the number of integers it will be required to sieve. * The sequence of gaps between spokes on the /wheel/ is /symmetrical under reflection/;@@ -135,7 +155,7 @@ Exploitation of this property has proved counter-productive, probably because it requires /strict evaluation/, exposing the user to the full cost of inadvertently choosing a /wheel/, which in practice, is rotated less than once. -}-mkPrimeWheel :: Integral i => Int -> PrimeWheel i+mkPrimeWheel :: Integral i => NPrimes -> PrimeWheel i mkPrimeWheel 0 = MkPrimeWheel [] [1] mkPrimeWheel nPrimes | nPrimes < 0 = error $ "Factory.Data.PrimeWheel.mkPrimeWheel: unable to construct from " ++ show nPrimes ++ " primes"@@ -168,11 +188,11 @@ > 11 [2,4,2,4,6,2,6,4] [121,143,187,209,253,319,341,407 ..] > 13 [4,2,4,6,2,6,4,2] [169,221,247,299,377,403,481,533,559 ..] -}-generatePrimeMultiples :: Integral i- => i -- ^ The /prime/.+generateMultiples :: Integral i+ => i -- ^ The number to square and multiply -> [i] -- ^ A /rolling wheel/, the track of which, delimits the gaps between /coprime/ candidates. -> [i]-generatePrimeMultiples prime = scanl (\accumulator -> (+ accumulator) . (* prime)) (prime ^ (2 :: Int))+generateMultiples i = scanl (\accumulator -> (+ accumulator) . (* i)) (i ^ (2 :: Int)) -{-# INLINE generatePrimeMultiples #-}+{-# INLINE generateMultiples #-}
src/Factory/Math/ArithmeticGeometricMean.hs view
@@ -73,7 +73,7 @@ | spread agm == 0 = repeat agm | otherwise = let simplify :: Data.Ratio.Rational -> Data.Ratio.Rational- simplify = Math.Precision.simplify (decimalDigits - 1 {-ignore single integral digit-}) --This makes a gigantic difference to performance.+ simplify = Math.Precision.simplify (pred decimalDigits {-ignore single integral digit-}) --This makes a gigantic difference to performance. findArithmeticMean :: AGM -> ArithmeticMean findArithmeticMean = (/ 2) . uncurry (+)
src/Factory/Math/Hyperoperation.hs view
@@ -69,8 +69,8 @@ -} powerTower :: (Integral base, Integral hyperExponent) => base -> hyperExponent -> base powerTower 0 hyperExponent- | odd hyperExponent = 0- | otherwise = 1+ | even hyperExponent = 1+ | otherwise = 0 powerTower _ (-1) = 0 --The only negative hyper-exponent for which there's a consistent result. powerTower base hyperExponent | base < 0 && hyperExponent > 1 = error $ "Factory.Math.Hyperoperation.powerTower:\tundefined for negative base; " ++ show base
src/Factory/Math/Implementations/Factorial.hs view
@@ -65,7 +65,7 @@ factorial algorithm n | n < 2 = 1 | otherwise = case algorithm of- Bisection -> risingFactorial 2 $ n - 1+ Bisection -> risingFactorial 2 $ pred n PrimeFactorisation -> Data.PrimeFactors.product' (recip 5) {-empirical-} 10 {-empirical-} $ primeFactors n {- |@@ -104,7 +104,7 @@ -> i -- ^ The result. risingFactorial _ 0 = 1 risingFactorial 0 _ = 0-risingFactorial x n = Data.Interval.product' (recip 2) 64 $ Data.Interval.normalise (x, (x + n) - 1)+risingFactorial x n = Data.Interval.product' (recip 2) 64 $ Data.Interval.normalise (x, pred $ x + n) -- | Returns the /falling factorial/; <http://mathworld.wolfram.com/FallingFactorial.html> fallingFactorial :: Integral i@@ -113,7 +113,7 @@ -> i -- ^ The result. fallingFactorial _ 0 = 1 fallingFactorial 0 _ = 0-fallingFactorial x n = Data.Interval.product' (recip 2) 64 $ Data.Interval.normalise (x, (x - n) + 1)+fallingFactorial x n = Data.Interval.product' (recip 2) 64 $ Data.Interval.normalise (x, succ $ x - n) {- | * Returns the ratio of two factorials.
src/Factory/Math/Implementations/Pi/Borwein/Borwein1993.hs view
@@ -42,7 +42,7 @@ series = Math.Implementations.Pi.Borwein.Series.MkSeries { Math.Implementations.Pi.Borwein.Series.terms = \squareRootAlgorithm factorialAlgorithm decimalDigits -> let simplify, squareRoot :: Data.Ratio.Rational -> Data.Ratio.Rational- simplify = Math.Precision.simplify (decimalDigits - 1 {-ignore single integral digit-}) --This makes a gigantic difference to performance.+ simplify = Math.Precision.simplify $ pred decimalDigits {-ignore single integral digit-} --This makes a gigantic difference to performance. squareRoot = simplify . Math.SquareRoot.squareRoot squareRootAlgorithm decimalDigits sqrt5, a, b, c3 :: Data.Ratio.Rational@@ -64,7 +64,7 @@ ) -} \n power -> (- Math.Implementations.Factorial.risingFactorial (3 * n + 1) (3 * n) % Math.Power.cube (Math.Factorial.factorial factorialAlgorithm n)+ Math.Implementations.Factorial.risingFactorial (succ $ 3 * n) (3 * n) % Math.Power.cube (Math.Factorial.factorial factorialAlgorithm n) ) * ( (a + b * fromIntegral n) / power )
src/Factory/Math/Implementations/Pi/Ramanujan/Chudnovsky.hs view
@@ -52,7 +52,7 @@ ) -} \n power -> (- Math.Implementations.Factorial.risingFactorial (3 * n + 1) (3 * n) % Math.Power.cube (Math.Factorial.factorial factorialAlgorithm n)+ Math.Implementations.Factorial.risingFactorial (succ $ 3 * n) (3 * n) % Math.Power.cube (Math.Factorial.factorial factorialAlgorithm n) ) * ( (13591409 + 545140134 * n) % power ) -- CAVEAT: the order in which these terms are evaluated radically affects performance.
src/Factory/Math/Implementations/Pi/Ramanujan/Classic.hs view
@@ -49,7 +49,7 @@ ) $ Math.Implementations.Factorial.primeFactors (4 * n) >/< Math.Implementations.Factorial.primeFactors n >^ 4 -} \n power -> (- Math.Implementations.Factorial.risingFactorial (n + 1) (3 * n) % Math.Power.cube (Math.Factorial.factorial factorialAlgorithm n)+ Math.Implementations.Factorial.risingFactorial (succ n) (3 * n) % Math.Power.cube (Math.Factorial.factorial factorialAlgorithm n) ) * ( (1103 + 26390 * n) % power ) -- CAVEAT: the order in which these terms are evaluated radically affects performance.
src/Factory/Math/Implementations/Pi/Spigot/Algorithm.hs view
@@ -46,5 +46,5 @@ openI Gosper = Math.Implementations.Pi.Spigot.Spigot.openI Math.Implementations.Pi.Spigot.Gosper.series openI RabinowitzWagon = Math.Implementations.Pi.Spigot.Spigot.openI Math.Implementations.Pi.Spigot.RabinowitzWagon.series - openR algorithm decimalDigits = Math.Pi.openI algorithm decimalDigits % (10 ^ (decimalDigits - 1))+ openR algorithm decimalDigits = Math.Pi.openI algorithm decimalDigits % (10 ^ pred decimalDigits)
src/Factory/Math/Implementations/Pi/Spigot/Gosper.hs view
@@ -31,8 +31,8 @@ -- | Defines a series which converges to /Pi/. series :: Integral i => Math.Implementations.Pi.Spigot.Series.Series i series = Math.Implementations.Pi.Spigot.Series.MkSeries {- Math.Implementations.Pi.Spigot.Series.baseNumerators = map (\i -> i * (2 * i - 1)) [1 ..],- Math.Implementations.Pi.Spigot.Series.baseDenominators = map ((* 3) . (\i -> (i + 1) * (i + 2))) [3, 6 ..],+ Math.Implementations.Pi.Spigot.Series.baseNumerators = map (\i -> i * pred (2 * i)) [1 ..],+ Math.Implementations.Pi.Spigot.Series.baseDenominators = map ((* 3) . (\i -> succ i * (i + 2))) [3, 6 ..], Math.Implementations.Pi.Spigot.Series.coefficients = [3, 8 ..], --5n - 2 Math.Implementations.Pi.Spigot.Series.nTerms = Math.Precision.getTermsRequired $ 1 / 13 {-empirical convergence-rate-} }
src/Factory/Math/Implementations/Pi/Spigot/Spigot.hs view
@@ -108,9 +108,9 @@ -> [(Base, I)] -- ^ Data-row. -> Pi processColumns series preDigits l- | overflowMargin > 1 = preDigits ++ nextRow [digit] --There's neither overflow, nor risk of impact from subsequent overflow.- | overflowMargin == 1 = nextRow $ preDigits ++ [digit] --There's no overflow, but risk of impact from subsequent overflow.- | otherwise = map ((`mod` decimal) . (+ 1)) preDigits ++ nextRow [0] --Overflow => propagate the excess to previously withheld preDigits.+ | overflowMargin > 1 = preDigits ++ nextRow [digit] --There's neither overflow, nor risk of impact from subsequent overflow.+ | overflowMargin == 1 = nextRow $ preDigits ++ [digit] --There's no overflow, but risk of impact from subsequent overflow.+ | otherwise = map ((`mod` decimal) . succ) preDigits ++ nextRow [0] --Overflow => propagate the excess to previously withheld preDigits. where results :: [QuotRem] results = init $ scanr carryAndDivide (0, undefined) l
src/Factory/Math/Implementations/Primality.hs view
@@ -47,6 +47,7 @@ import qualified Factory.Data.Polynomial as Data.Polynomial import qualified Factory.Data.QuotientRing as Data.QuotientRing import qualified Factory.Math.MultiplicativeOrder as Math.MultiplicativeOrder+import qualified Factory.Math.PerfectPower as Math.PerfectPower import qualified Factory.Math.Power as Math.Power import qualified Factory.Math.Primality as Math.Primality import qualified Factory.Math.PrimeFactorisation as Math.PrimeFactorisation@@ -108,7 +109,7 @@ -} isPrimeByAKS :: (Math.PrimeFactorisation.Algorithmic factorisationAlgorithm, Control.DeepSeq.NFData i, Integral i) => factorisationAlgorithm -> i -> Bool isPrimeByAKS factorisationAlgorithm n = and [- not $ Math.Power.isPerfectPower n, --Step 1.+ not $ Math.PerfectPower.isPerfectPower n, --Step 1. Math.Primality.areCoprime n `all` filter (/= n) [2 .. r], --Step 3. #if MIN_VERSION_parallel(3,0,0) and $ Control.Parallel.Strategies.parMap Control.Parallel.Strategies.rdeepseq --Benefits from '+RTS -H100M', which reduces garbage-collections.@@ -191,7 +192,7 @@ ) ( length binaryFactors --The number of times that 'two' can be factored-out from 'predecessor'. ) `any` testBases where- predecessor = primeCandidate - 1+ predecessor = pred primeCandidate binaryFactors = takeWhile ((== 0) . snd) . tail {-drop the original-} $ iterate ((`quotRem` 2) . fst) (predecessor, 0) --Factor-out powers of two. testBases | null fewestPrimeBases = let
src/Factory/Math/Implementations/PrimeFactorisation.hs view
@@ -47,6 +47,7 @@ import qualified Factory.Data.Exponential as Data.Exponential import Factory.Data.Exponential((<^)) import qualified Factory.Data.PrimeFactors as Data.PrimeFactors+import qualified Factory.Math.PerfectPower as Math.PerfectPower import qualified Factory.Math.Power as Math.Power import qualified Factory.Math.PrimeFactorisation as Math.PrimeFactorisation import qualified ToolShed.Defaultable as Defaultable@@ -112,19 +113,19 @@ Pair.mirror factoriseByFermatsMethod $ head factors where -- maybeSquareNumber :: Integral i => Maybe i- maybeSquareNumber = Math.Power.maybeSquareNumber i+ maybeSquareNumber = Math.PerfectPower.maybeSquareNumber i -- factors :: Integral i => [i] factors = map ( (- uncurry (+) &&& uncurry (-) --Construct the co-factors as the sum and difference of /larger/ and /smaller/.+ uncurry (+) &&& uncurry (-) --Construct the co-factors as the sum and difference of /larger/ and /smaller/. ) . Control.Arrow.second Data.Maybe.fromJust ) . filter (- Data.Maybe.isJust . snd --Search for a perfect square.+ Data.Maybe.isJust . snd --Search for a perfect square. ) . map (- Control.Arrow.second $ Math.Power.maybeSquareNumber {-hotspot-} . (+ negate i) --Associate the corresponding value of /smaller/.+ Control.Arrow.second $ Math.PerfectPower.maybeSquareNumber {-hotspot-} . (+ negate i) --Associate the corresponding value of /smaller/. ) . takeWhile (- (<= (i + 9) `div` 6) . fst --Terminate the search at the maximum value of /larger/.+ (<= (i + 9) `div` 6) . fst --Terminate the search at the maximum value of /larger/. ) . Math.Power.squaresFrom {-hotspot-} . ceiling $ sqrt (fromIntegral i :: Double) --Start the search at the minimum value of /larger/. {- |
− src/Factory/Math/Implementations/Primes.hs
@@ -1,229 +0,0 @@-{-- Copyright (C) 2011 Dr. Alistair Ward-- This program is free software: you can redistribute it and/or modify- it under the terms of the GNU General Public License as published by- the Free Software Foundation, either version 3 of the License, or- (at your option) any later version.-- This program is distributed in the hope that it will be useful,- but WITHOUT ANY WARRANTY; without even the implied warranty of- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the- GNU General Public License for more details.-- You should have received a copy of the GNU General Public License- along with this program. If not, see <http://www.gnu.org/licenses/>.--}-{- |- [@AUTHOR@] Dr. Alistair Ward-- [@DESCRIPTION@]-- * Generates the constant, conceptually infinite, list of /prime-numbers/ by a variety of different algorithms.-- * Based heavily on <http://www.cs.hmc.edu/~oneill/papers/Sieve-JFP.pdf>.-- * <http://www.haskell.org/haskellwiki/Prime_numbers>.-- * <http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.31.3936&rep=rep1&type=pdf>.-- * <http://larc.unt.edu/ian/pubs/sieve.pdf>.--}--module Factory.Math.Implementations.Primes(--- * Types--- ** Type-synonyms--- PrimeMultiplesQueue,--- PrimeMultiplesMap,--- Repository,--- PrimeMultiplesMapInt,--- RepositoryInt,--- ** Data-types- Algorithm(..),--- * Functions--- head',--- tail',--- turnersSieve,--- trialDivision,--- sieveOfEratosthenes,--- sieveOfEratosthenesInt,--- ** Predicates--- isIndivisible-) where--import Control.Arrow((&&&), (***))-import qualified Control.Arrow-import qualified Data.IntMap-import qualified Data.List-import qualified Data.Map-import qualified Data.Numbers.Primes-import Data.Sequence((|>))-import qualified Data.Sequence-import qualified Factory.Data.PrimeWheel as Data.PrimeWheel-import qualified Factory.Math.Power as Math.Power-import qualified Factory.Math.PrimeFactorisation as Math.PrimeFactorisation-import qualified Factory.Math.Primes as Math.Primes-import qualified ToolShed.Defaultable as Defaultable---- | The implemented methods by which the primes may be generated.-data Algorithm- = TurnersSieve -- ^ For each /prime/, the infinite list of candidates greater than its /square/, is filtered for indivisibility; <http://www.haskell.org/haskellwiki/Prime_numbers#Turner.27s_sieve_-_Trial_division>.- | TrialDivision Int -- ^ For each candidate, confirm indivisibility, by all /primes/ smaller than its /square-root/, optimised using a 'Data.PrimeWheel.PrimeWheel' (<http://en.wikipedia.org/wiki/Wheel_factorization>).- | SieveOfEratosthenes Int -- ^ The /Sieve of Eratosthenes/ (<http://en.wikipedia.org/wiki/Sieve_of_Eratosthenes>), optimised using a 'Data.PrimeWheel.PrimeWheel' (<http://en.wikipedia.org/wiki/Wheel_factorization>).- | WheelSieve Int -- ^ 'Data.Numbers.Primes.wheelSieve'.- deriving (Eq, Read, Show)--instance Defaultable.Defaultable Algorithm where- defaultValue = SieveOfEratosthenes 7 --Resulting in wheel-circumference=510510.--instance Math.Primes.Algorithmic Algorithm where- primes TurnersSieve = turnersSieve- primes (TrialDivision n) = trialDivision n- primes (SieveOfEratosthenes n) = sieveOfEratosthenes n --When (n == 0), this degenerates to the unoptimised classic form.- primes (WheelSieve n) = Data.Numbers.Primes.wheelSieve n --Has better space-complexity than 'SieveOfEratosthenes'.---- | Uses /Trial Division/, to determine whether the specified numerator is indivisible by all the specified denominators.-isIndivisible :: Integral i => i -> [i] -> Bool-isIndivisible numerator = all ((/= 0) . (numerator `mod`))---- | The 'Data.Sequence.Seq' counterpart to 'Data.List.head'.-head' :: Data.Sequence.Seq [a] -> [a]-head' = (`Data.Sequence.index` 0)---- | The 'Data.Sequence.Seq' counterpart to 'Data.List.tail'.-tail' :: Data.Sequence.Seq [a] -> Data.Sequence.Seq [a]-tail' = Data.Sequence.drop 1--{- |- * Generates the constant, conceptually infinite, list of /prime-numbers/.-- * For each /prime/, the infinite list of candidates greater than its /square/,- is filtered for indivisibility; <http://www.haskell.org/haskellwiki/Prime_numbers#Turner.27s_sieve_-_Trial_division>.--}-turnersSieve :: Integral prime => [prime]-turnersSieve = 2 : sieve [3, 5 ..] where- sieve :: Integral i => [i] -> [i]- sieve [] = []- sieve (prime : candidates) = prime : sieve (- filter (- \candidate -> any ($ candidate) [- (< Math.Power.square prime), --Unconditionally admit any candidate smaller than the square of the last prime.- (/= 0) . (`mod` prime) --Ensure indivisibility, of all subsequent candidates, by the last prime.- ]- ) candidates- )--{- |- * Generates the constant, conceptually infinite, list of /prime-numbers/.-- * For each candidate, confirm indivisibility, by all /primes/ smaller than its /square-root/.-- * The candidates to sieve, are generated by a 'Data.PrimeWheel.PrimeWheel',- of parameterised, but static, size; <http://en.wikipedia.org/wiki/Wheel_factorization>.--}-trialDivision :: Integral prime => Int -> [prime]-trialDivision n = Data.PrimeWheel.getPrimeComponents primeWheel ++ indivisible where- primeWheel = Data.PrimeWheel.mkPrimeWheel n- candidates = map fst $ Data.PrimeWheel.roll primeWheel- indivisible = uncurry (++) . Control.Arrow.second (--- filter (\candidate -> isIndivisible candidate . zipWith const indivisible . takeWhile (<= candidate) $ map Math.Power.square indivisible)- filter (\candidate -> isIndivisible candidate $ takeWhile (<= Math.PrimeFactorisation.maxBoundPrimeFactor candidate) indivisible {-recurse-})- ) $ Data.List.span (- < Math.Power.square (head candidates) --The first composite candidate, is the square of the next prime after the wheel's constituent ones.- ) candidates--{-# NOINLINE trialDivision #-} --Required to prevent optimization prior to firing of rewrite-rule ?!---- | An ordered queue of the multiples of primes.-type PrimeMultiplesQueue i = Data.Sequence.Seq (Data.PrimeWheel.PrimeMultiples i)---- | A map of the multiples of primes.-type PrimeMultiplesMap i = Data.Map.Map i (Data.PrimeWheel.PrimeMultiples i)---- | Combine a /queue/, with a /map/, to form a repository to hold prime-multiples.-type Repository i = (PrimeMultiplesQueue i, PrimeMultiplesMap i)--{- |- * A refinement of the /Sieve Of Eratosthenes/, which pre-sieves candidates, selecting only those /coprime/ to the specified short sequence of low prime-numbers.-- * The short sequence of initial primes are represented by a 'Data.PrimeWheel.PrimeWheel',- of parameterised, but static, size; <http://en.wikipedia.org/wiki/Wheel_factorization>.-- * The algorithm requires one to record multiples of previously discovered primes, allowing /composite/ candidates to be eliminated by comparison.-- * Because each /list/ of multiples, starts with the /square/ of the prime from which it was generated,- the vast majority will be larger than the maximum prime required, and the effort of constructing and storing this list, is wasted.- Many implementations solve this, by requiring specification of the maximum prime required,- thus allowing the construction of redundant lists of multiples to be avoided.-- * This implementation doesn't impose that constraint, leaving a requirement for /rapid/ storage,- which is supported by /appending/ the /list/ of prime-multiples, to a /queue/.- If a large enough candidate is ever generated, to match the /head/ of the /list/ of prime-multiples,- at the /head/ of the /queue/, then the whole /list/ of prime-multiples is dropped,- but the /tail/ of this /list/ of prime-multiples, for which there is now a high likelyhood of a subsequent match, must now be re-recorded.- A /queue/ doesn't support efficient random /insertion/, so a 'Data.Map.Map' is used for these subsequent multiples.- This solution is faster than the same algorithm using "Data.PQueue.Min".-- * CAVEAT: has linear /O(primes)/ space-complexity.--}-sieveOfEratosthenes :: Integral i => Int -> [i]-sieveOfEratosthenes = uncurry (++) . (Data.PrimeWheel.getPrimeComponents &&& start . Data.PrimeWheel.roll) . Data.PrimeWheel.mkPrimeWheel where- start :: Integral i => [Data.PrimeWheel.Distance i] -> [i]- start ~((candidate, rollingWheel) : distances) = candidate : sieve (head distances) (Data.Sequence.singleton $ Data.PrimeWheel.generatePrimeMultiples candidate rollingWheel, Data.Map.empty)-- sieve :: Integral i => Data.PrimeWheel.Distance i -> Repository i -> [i]- sieve distance@(candidate, rollingWheel) repository@(primeSquares, squareFreePrimeMultiples) = case Data.Map.lookup candidate squareFreePrimeMultiples of- Just primeMultiples -> sieve' $ Control.Arrow.second (insertUniq primeMultiples . Data.Map.delete candidate) repository --Re-insert subsequent multiples.- Nothing --Not a square-free composite.- | candidate == smallestPrimeSquare -> sieve' $ (tail' *** insertUniq subsequentPrimeMultiples) repository --Migrate subsequent prime-multiples, from 'primeSquares' to 'squareFreePrimeMultiples'.- | otherwise {-prime-} -> candidate : sieve' (Control.Arrow.first (|> Data.PrimeWheel.generatePrimeMultiples candidate rollingWheel) repository)- where- (smallestPrimeSquare : subsequentPrimeMultiples) = head' primeSquares- where--- sieve' :: Repository i -> [i]- sieve' = sieve $ Data.PrimeWheel.rotate distance --Tail-recurse.-- insertUniq :: Ord i => Data.PrimeWheel.PrimeMultiples i -> PrimeMultiplesMap i -> PrimeMultiplesMap i- insertUniq l m = insert (dropWhile (`Data.Map.member` m) l) where--- insert :: Ord i => Data.PrimeWheel.PrimeMultiples i -> PrimeMultiplesMap i- insert [] = error "Factory.Math.Implementations.Primes.sieveOfEratosthenes.sieve.insertUniq.insert:\tnull list"- insert (key : values) = Data.Map.insert key values m--{-# NOINLINE sieveOfEratosthenes #-}-{-# RULES "sieveOfEratosthenes/Int" sieveOfEratosthenes = sieveOfEratosthenesInt #-} --CAVEAT: doesn't fire when built with profiling enabled ?!---- | A specialisation of 'PrimeMultiplesMap'.-type PrimeMultiplesMapInt = Data.IntMap.IntMap (Data.PrimeWheel.PrimeMultiples Int)---- | A specialisation of 'Repository'.-type RepositoryInt = (PrimeMultiplesQueue Int, PrimeMultiplesMapInt)--{- |- * A specialisation of 'sieveOfEratosthenes', which approximately /doubles/ the speed.-- * CAVEAT: because the algorithm involves /squares/ of primes,- this implementation will overflow when finding primes greater than @ 2^16 @ on a /32-bit/ machine;- but it will exhaust the memory before that anyway.--}-sieveOfEratosthenesInt :: Int -> [Int]-sieveOfEratosthenesInt = uncurry (++) . (Data.PrimeWheel.getPrimeComponents &&& start . Data.PrimeWheel.roll) . Data.PrimeWheel.mkPrimeWheel where- start :: [Data.PrimeWheel.Distance Int] -> [Int]- start ~((candidate, rollingWheel) : distances) = candidate : sieve (head distances) (Data.Sequence.singleton $ Data.PrimeWheel.generatePrimeMultiples candidate rollingWheel, Data.IntMap.empty)-- sieve :: Data.PrimeWheel.Distance Int -> RepositoryInt -> [Int]- sieve distance@(candidate, rollingWheel) repository@(primeSquares, squareFreePrimeMultiples) = case Data.IntMap.lookup candidate squareFreePrimeMultiples of- Just primeMultiples -> sieve' $ Control.Arrow.second (insertUniq primeMultiples . Data.IntMap.delete candidate) repository- Nothing- | candidate == smallestPrimeSquare -> sieve' $ (tail' *** insertUniq subsequentPrimeMultiples) repository- | otherwise -> candidate : sieve' (Control.Arrow.first (|> Data.PrimeWheel.generatePrimeMultiples candidate rollingWheel) repository)- where- (smallestPrimeSquare : subsequentPrimeMultiples) = head' primeSquares- where- sieve' :: RepositoryInt -> [Int]- sieve' = sieve $ Data.PrimeWheel.rotate distance-- insertUniq :: Data.PrimeWheel.PrimeMultiples Int -> PrimeMultiplesMapInt -> PrimeMultiplesMapInt- insertUniq l m = insert (dropWhile (`Data.IntMap.member` m) l) where- insert :: Data.PrimeWheel.PrimeMultiples Int -> PrimeMultiplesMapInt- insert [] = error "Factory.Math.Implementations.Primes.sieveOfEratosthenesInt.sieve.insertUniq.insert:\tnull list"- insert (key : values) = Data.IntMap.insert key values m
+ src/Factory/Math/Implementations/Primes/Algorithm.hs view
@@ -0,0 +1,63 @@+{-+ Copyright (C) 2011 Dr. Alistair Ward++ This program is free software: you can redistribute it and/or modify+ it under the terms of the GNU General Public License as published by+ the Free Software Foundation, either version 3 of the License, or+ (at your option) any later version.++ This program is distributed in the hope that it will be useful,+ but WITHOUT ANY WARRANTY; without even the implied warranty of+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+ GNU General Public License for more details.++ You should have received a copy of the GNU General Public License+ along with this program. If not, see <http://www.gnu.org/licenses/>.+-}+{- |+ [@AUTHOR@] Dr. Alistair Ward++ [@DESCRIPTION@]++ * Generates the constant list of /prime-numbers/, by a variety of different algorithms.++ * <http://www.haskell.org/haskellwiki/Prime_numbers>.++ * <http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.31.3936&rep=rep1&type=pdf>.++ * <http://larc.unt.edu/ian/pubs/sieve.pdf>.+-}++module Factory.Math.Implementations.Primes.Algorithm(+-- * Types+-- ** Data-types+ Algorithm(..)+) where++import qualified Data.Numbers.Primes+import qualified Factory.Data.PrimeWheel as Data.PrimeWheel+import qualified Factory.Math.Implementations.Primes.SieveOfAtkin as Math.Implementations.Primes.SieveOfAtkin+import qualified Factory.Math.Implementations.Primes.SieveOfEratosthenes as Math.Implementations.Primes.SieveOfEratosthenes+import qualified Factory.Math.Implementations.Primes.TrialDivision as Math.Implementations.Primes.TrialDivision+import qualified Factory.Math.Implementations.Primes.TurnersSieve as Math.Implementations.Primes.TurnersSieve+import qualified Factory.Math.Primes as Math.Primes+import qualified ToolShed.Defaultable as Defaultable++-- | The implemented methods by which the primes may be generated.+data Algorithm+ = SieveOfAtkin Integer -- ^ The /Sieve of Atkin/, optimised using a 'Data.PrimeWheel.PrimeWheel' of optimal size, for primes up to the specified maximum bound; <http://en.wikipedia.org/wiki/Sieve_of_Atkin>.+ | SieveOfEratosthenes Data.PrimeWheel.NPrimes -- ^ The /Sieve of Eratosthenes/ (<http://en.wikipedia.org/wiki/Sieve_of_Eratosthenes>), optimised using a 'Data.PrimeWheel.PrimeWheel'.+ | TrialDivision Data.PrimeWheel.NPrimes -- ^ For each candidate, confirm indivisibility, by all /primes/ smaller than its /square-root/, optimised using a 'Data.PrimeWheel.PrimeWheel'.+ | TurnersSieve -- ^ For each /prime/, the infinite list of candidates greater than its /square/, is filtered for indivisibility; <http://www.haskell.org/haskellwiki/Prime_numbers#Turner.27s_sieve_-_Trial_division>.+ | WheelSieve Int -- ^ 'Data.Numbers.Primes.wheelSieve'.+ deriving (Eq, Read, Show)++instance Defaultable.Defaultable Algorithm where+ defaultValue = SieveOfEratosthenes 7 --Resulting in a wheel of circumference 510510.++instance Math.Primes.Algorithmic Algorithm where+ primes (SieveOfAtkin maxPrime) = Math.Implementations.Primes.SieveOfAtkin.sieveOfAtkin (Data.PrimeWheel.estimateOptimalSize maxPrime) $ fromIntegral maxPrime+ primes (SieveOfEratosthenes wheelSize) = Math.Implementations.Primes.SieveOfEratosthenes.sieveOfEratosthenes wheelSize+ primes (TrialDivision wheelSize) = Math.Implementations.Primes.TrialDivision.trialDivision wheelSize+ primes TurnersSieve = Math.Implementations.Primes.TurnersSieve.turnersSieve+ primes (WheelSieve wheelSize) = Data.Numbers.Primes.wheelSieve wheelSize --Has better space-complexity than 'SieveOfEratosthenes'.
+ src/Factory/Math/Implementations/Primes/SieveOfAtkin.hs view
@@ -0,0 +1,251 @@+{-# LANGUAGE CPP #-}+{-+ Copyright (C) 2011 Dr. Alistair Ward++ This program is free software: you can redistribute it and/or modify+ it under the terms of the GNU General Public License as published by+ the Free Software Foundation, either version 3 of the License, or+ (at your option) any later version.++ This program is distributed in the hope that it will be useful,+ but WITHOUT ANY WARRANTY; without even the implied warranty of+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+ GNU General Public License for more details.++ You should have received a copy of the GNU General Public License+ along with this program. If not, see <http://www.gnu.org/licenses/>.+-}+{- |+ [@AUTHOR@] Dr. Alistair Ward++ [@DESCRIPTION@]++ * Generates the constant /bounded/ list of /prime-numbers/, using the /Sieve of Atkin/; <http://en.wikipedia.org/wiki/Sieve_of_Atkin>.++ * <cr.yp.to/papers/primesieves-19990826.pdf>.++ * The implementation;+ has been optimised using a /wheel/ of static, but parameterised, size;+ has been parallelized;+ is polymorphic, but with a specialisation for type 'Int'.++ [@CAVEAT@] The 'Int'-specialisation is implemented by a /rewrite-rule/, which is /very/ fragile.+-}++module Factory.Math.Implementations.Primes.SieveOfAtkin(+-- * Types+-- ** Data-types+-- PolynomialType,+-- * Constants+-- atkinsModulus,+-- inherentPrimes,+-- nInherentPrimes,+-- squares,+-- * Functions+-- polynomialTypeLookupPeriod,+-- polynomialTypeLookup,+-- findPolynomialSolutions,+-- filterOddRepetitions,+-- generateMultiplesOfSquareTo,+-- getPrefactoredPrimes,+ sieveOfAtkin,+-- sieveOfAtkinInt+) where++import qualified Control.DeepSeq+import qualified Data.Array+import qualified Data.Array.IArray+import Data.Array.IArray((!))+--import qualified Data.Array.Unboxed+import qualified Data.IntSet+import qualified Data.List+import qualified Data.Set+import qualified Factory.Data.PrimeWheel as Data.PrimeWheel+import qualified Factory.Math.Power as Math.Power+import qualified ToolShed.ListPlus as ListPlus++#if MIN_VERSION_parallel(3,0,0)+import qualified Control.Parallel.Strategies+#endif++-- | Defines the types of /quadratic/, available to test the potential primality of a candidate integer.+data PolynomialType+ = ModFour -- ^ Suitable for primality-testing numbers meeting @(n `mod` 4 == 1)@.+ | ModSix -- ^ Suitable for primality-testing numbers meeting @(n `mod` 6 == 1)@.+ | ModTwelve -- ^ Suitable for primality-testing numbers meeting @(n `mod` 12 == 11)@.+ | None -- ^ There's no polynomial which can assess primality, because the candidate is composite.+ deriving Eq++-- | The constant modulus used to select the appropriate quadratic for a prime candidate.+atkinsModulus :: Integral i => i+atkinsModulus = foldr1 lcm [4, 6, 12] --Sure, this is always '12', but this is the reason why.++-- | The constant list of primes factored-out by the unoptimised algorithm.+inherentPrimes :: Integral i => [i]+inherentPrimes = [2, 3]++-- | The constant number of primes factored-out by the unoptimised algorithm.+nInherentPrimes :: Int+nInherentPrimes = length (inherentPrimes :: [Int])++-- | Typically the set of primes which have been built into the specified /wheel/, but never fewer than 'inherentPrimes'.+getPrefactoredPrimes :: Integral i => Data.PrimeWheel.PrimeWheel i -> [i]+getPrefactoredPrimes = max inherentPrimes . Data.PrimeWheel.getPrimeComponents++-- | The period over which the data returned by 'polynomialTypeLookup' repeats.+polynomialTypeLookupPeriod :: Integral i => Data.PrimeWheel.PrimeWheel i -> i+polynomialTypeLookupPeriod = lcm atkinsModulus . Data.PrimeWheel.getCircumference++{- |+ * Defines which, if any, of the three /quadratics/ is appropriate for the primality-test for each candidate.++ * Since this algorithm uses /modular arithmetic/, the /range/ of results repeat after a short /domain/ related to the /modulus/.+ Thus one need calculate at most one period of this cycle, but fewer if the maximum prime required falls within the first cycle of results.++ * Because the results are /bounded/, they're returned in a zero-indexed /array/, to provide efficient random access;+ the first few elements should never be required, but it makes query clearer.++ * <http://en.wikipedia.org/wiki/Sieve_of_Atkin>.+-}+polynomialTypeLookup :: (Data.Array.IArray.Ix i, Integral i)+ => Data.PrimeWheel.PrimeWheel i+ -> i -- ^ The maximum prime required.+-- -> Data.Array.Unboxed.Array i PolynomialType --Changes neither execution-time nor space ?!+ -> Data.Array.Array i PolynomialType+polynomialTypeLookup primeWheel maxPrime = Data.Array.IArray.listArray (0, pred (polynomialTypeLookupPeriod primeWheel) `min` maxPrime) $ map select [0 ..] where+-- select :: Integral i => i -> PolynomialType+ select n+ | any (+ (== 0) . (n `mod`) --Though this is merely /Trial Division/, it's only performed over a short bounded interval of numerators.+ ) primeComponents = None+ | r `elem` [1, 5] = ModFour --We actually require @(n `mod` 4 == 1)@, but this is the equivalent modulo 12, with @(r == 9)@ removed because they're all divisible by /3/.+ | r == 7 = ModSix --We actually require @(n `mod` 6 == 1)@, but this is the equivalent modulo 12, where @(r == 1)@ has been accounted for above.+ | r == 11 = ModTwelve --We require @(n `mod` 12 == 11)@.+ | otherwise = None+ where+ r = n `mod` atkinsModulus+ primeComponents = drop nInherentPrimes $ Data.PrimeWheel.getPrimeComponents primeWheel++-- | The constant, infinite list of the /squares/, of integers increasing from /1/.+squares :: Integral i => [i]+squares = map snd $ Math.Power.squaresFrom 1++{- |+ * Returns the /ordered/ list of those values with an /odd/ number of occurrences in the specified /unordered/ list.++ * CAVEAT: this is expensive in both execution-time and space.+ The typical imperative-style implementation accumulates polynomial-solutions in a /mutable array/ indexed by the candidate integer.+ This doesn't translate seamlessly to the /pure functional/ domain where /arrays/ naturally immutable,+ so we /sort/ a /list/ of polynomial-solutions, then measure the length of the solution-spans, corresponding to viable candidates.+ Regrettably, 'Data.List.sort' (implemented in /GHC/ by /mergesort/) has a time-complexity /O(n*log n)/+ which is greater than the theoretical /O(n)/ of the whole /Sieve of Atkin/;+ /GHC/'s old /qsort/-implementation is even slower :(+-}+filterOddRepetitions :: Ord a => [a] -> [a]+--filterOddRepetitions = map head . filter (foldr (const not) False) . Data.List.group . Data.List.sort --Too slow.+filterOddRepetitions = slave True . Data.List.sort where+ slave isOdd (one : remainder@(two : _))+ | one == two = slave (not isOdd) remainder+ | isOdd = one : beginSpan+ | otherwise = beginSpan+ where+ beginSpan = slave True remainder+ slave True [singleton] = [singleton]+ slave _ _ = []++{- |+ * Returns the ordered list of solutions aggregated from each of three /bivariate quadratics/; @z = f(x, y)@.++ * For a candidate integer to be prime, it is necessary but insufficient, that there are an /odd/ number of solutions of value /candidate/.++ * At most one of these three polynomials is suitable for the validation of any specific candidate /z/, depending on 'lookupPolynomialType'.+ so the three sets of solutions are mutually exclusive.+ One coordinate @(x, y)@, can have solutions in more than one of the three polynomials.++ * This algorithm exhaustively traverses the domain @(x, y)@, for resulting /z/ of the required modulus.+ Whilst it tightly constrains the bounds of the search-space, it searches the domain methodically rather than intelligently.+-}+findPolynomialSolutions :: (Control.DeepSeq.NFData i, Data.Array.IArray.Ix i, Integral i)+ => Data.PrimeWheel.PrimeWheel i+ -> i -- ^ The maximum prime-number required.+ -> [i]+findPolynomialSolutions primeWheel maxPrime = foldr1 ListPlus.merge --The lists were previously sorted, as a side-effect, by 'filterOddRepetitions'.+#if MIN_VERSION_parallel(3,0,0)+ $ Control.Parallel.Strategies.withStrategy (Control.Parallel.Strategies.parList Control.Parallel.Strategies.rdeepseq)+#endif+ [+ {-# SCC "4x^2+y^2" #-} filterOddRepetitions [+ z |+ x' <- takeWhile (<= pred maxPrime) $ map (* 4) squares,+ z <- takeWhile (<= maxPrime) $ map (+ x') oddSquares,+ lookupPolynomialType z == ModFour+ ], --Twice the length of the other two lists.+ {-# SCC "3x^2+y^2" #-} filterOddRepetitions [+ z |+ x' <- takeWhile (<= pred maxPrime) $ map (* 3) squares,+ z <- takeWhile (<= maxPrime) . map (+ x') $ if even x' then oddSelection else evenSelection,+ lookupPolynomialType z == ModSix+ ],+ {-# SCC "3x^2-y^2" #-} filterOddRepetitions [+ z |+ x2 <- takeWhile (<= maxPrime `div` 2) squares,+ z <- dropWhile (> maxPrime) . map (3 * x2 -) . takeWhile (< x2) $ if even x2 then oddSelection else evenSelection,+ lookupPolynomialType z == ModTwelve+ ]+ ] where+ (evenSquares, oddSquares) = Data.List.partition even squares++-- evenSelection, oddSelection :: Integral i => [i]+ evenSelection = selection110 evenSquares where+ selection110 (x0 : x1 : _ : xs) = x0 : x1 : selection110 xs --Effectively, those for meeting ((== 4) . (`mod` 6)).+ selection110 xs = xs+ oddSelection = selection101 oddSquares where+ selection101 (x0 : _ : x2 : xs) = x0 : x2 : selection101 xs --Effectively, those for meeting ((== 1) . (`mod` 6)).+ selection101 xs = xs++-- lookupPolynomialType :: (Data.Array.IArray.Ix i, Integral i) => i -> PolynomialType+ lookupPolynomialType = (polynomialTypeLookup primeWheel maxPrime !) . (`mod` polynomialTypeLookupPeriod primeWheel)++-- | Generates the /bounded/ list of multiples, of the /square/ of the specified prime, skipping those which aren't required.+generateMultiplesOfSquareTo :: Integral i+ => Data.PrimeWheel.PrimeWheel i -- ^ Used to generate the gaps between prime multiples of the square.+ -> i -- ^ The /prime/.+ -> i -- ^ The maximum bound.+ -> [i]+generateMultiplesOfSquareTo primeWheel prime max' = takeWhile (<= max') . scanl (\accumulator -> (+ accumulator) . (* prime2)) prime2 . cycle $ Data.PrimeWheel.getSpokeGaps primeWheel where+ prime2 = Math.Power.square prime++{- |+ * Generates the constant /bounded/ list of /prime-numbers/.++ * <http://cr.yp.to/papers/primesieves-19990826.pdf>+-}+sieveOfAtkin :: (Control.DeepSeq.NFData i, Data.Array.IArray.Ix i, Integral i)+ => Data.PrimeWheel.NPrimes -- ^ Other implementations effectively use a hard-coded value either /2/ or /3/, but /6/ seems better.+ -> i -- ^ The maximum prime required.+ -> [i] -- ^ The /bounded/ list of primes.+sieveOfAtkin wheelSize maxPrime = (prefactoredPrimes ++) . filterSquareFree Data.Set.empty . dropWhile (<= maximum prefactoredPrimes) $ findPolynomialSolutions primeWheel maxPrime where+ primeWheel = Data.PrimeWheel.mkPrimeWheel wheelSize+ prefactoredPrimes = getPrefactoredPrimes primeWheel++-- filterSquareFree :: Integral i => Data.Set.Set i -> [i] -> [i]+ filterSquareFree _ [] = []+ filterSquareFree primeMultiples (candidate : candidates)+ | Data.Set.member candidate primeMultiples = {-# SCC "delete" #-} filterSquareFree (Data.Set.delete candidate primeMultiples) candidates --Tail-recurse.+ | otherwise = {-# SCC "insert" #-} candidate : filterSquareFree (Data.Set.union primeMultiples . Data.Set.fromDistinctAscList $ generateMultiplesOfSquareTo primeWheel candidate maxPrime) candidates++{-# NOINLINE sieveOfAtkin #-}+{-# RULES "sieveOfAtkin/Int" sieveOfAtkin = sieveOfAtkinInt #-} --CAVEAT: doesn't fire when built with profiling enabled.++-- | A specialisation of 'sieveOfAtkin', which reduces both the execution-time and the space required.+sieveOfAtkinInt :: Data.PrimeWheel.NPrimes -> Int -> [Int]+sieveOfAtkinInt wheelSize maxPrime = (prefactoredPrimes ++) . filterSquareFree Data.IntSet.empty . dropWhile (<= maximum prefactoredPrimes) $ findPolynomialSolutions primeWheel maxPrime where+ primeWheel = Data.PrimeWheel.mkPrimeWheel wheelSize+ prefactoredPrimes = getPrefactoredPrimes primeWheel++ filterSquareFree :: Data.IntSet.IntSet -> [Int] -> [Int]+ filterSquareFree _ [] = []+ filterSquareFree primeMultiples (candidate : candidates)+ | Data.IntSet.member candidate primeMultiples = filterSquareFree (Data.IntSet.delete candidate primeMultiples) candidates+ | otherwise = candidate : filterSquareFree (Data.IntSet.union primeMultiples . Data.IntSet.fromDistinctAscList $ generateMultiplesOfSquareTo primeWheel candidate maxPrime) candidates+
+ src/Factory/Math/Implementations/Primes/SieveOfEratosthenes.hs view
@@ -0,0 +1,157 @@+{-+ Copyright (C) 2011 Dr. Alistair Ward++ This program is free software: you can redistribute it and/or modify+ it under the terms of the GNU General Public License as published by+ the Free Software Foundation, either version 3 of the License, or+ (at your option) any later version.++ This program is distributed in the hope that it will be useful,+ but WITHOUT ANY WARRANTY; without even the implied warranty of+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+ GNU General Public License for more details.++ You should have received a copy of the GNU General Public License+ along with this program. If not, see <http://www.gnu.org/licenses/>.+-}+{- |+ [@AUTHOR@] Dr. Alistair Ward++ [@DESCRIPTION@]++ * Generates the constant, conceptually infinite, list of /prime-numbers/, using the /Sieve of Eratosthenes/; <http://en.wikipedia.org/wiki/Sieve_of_Eratosthenes>.++ * Based on <http://www.cs.hmc.edu/~oneill/papers/Sieve-JFP.pdf>.++ * The implementation;+ has been optimised using a /wheel/ of static, but parameterised, size;+ is polymorphic, but with a specialisation for type 'Int'.++ [@CAVEAT@] The 'Int'-specialisation is implemented by a /rewrite-rule/, which is /very/ fragile.+-}++module Factory.Math.Implementations.Primes.SieveOfEratosthenes(+-- * Types+-- ** Type-synonyms+-- PrimeMultiplesQueue,+-- PrimeMultiplesMap,+-- Repository,+-- PrimeMultiplesMapInt,+-- RepositoryInt,+-- * Functions+-- head',+-- tail',+ sieveOfEratosthenes,+-- sieveOfEratosthenesInt+) where++import Control.Arrow((&&&), (***))+import qualified Control.Arrow+import qualified Data.IntMap+import qualified Data.Map+import Data.Sequence((|>))+import qualified Data.Sequence+import qualified Factory.Data.PrimeWheel as Data.PrimeWheel++-- | The 'Data.Sequence.Seq' counterpart to 'Data.List.head'.+head' :: Data.Sequence.Seq [a] -> [a]+head' = (`Data.Sequence.index` 0)++-- | The 'Data.Sequence.Seq' counterpart to 'Data.List.tail'.+tail' :: Data.Sequence.Seq [a] -> Data.Sequence.Seq [a]+tail' = Data.Sequence.drop 1++-- | An ordered queue of the multiples of primes.+type PrimeMultiplesQueue i = Data.Sequence.Seq (Data.PrimeWheel.PrimeMultiples i)++-- | A map of the multiples of primes.+type PrimeMultiplesMap i = Data.Map.Map i (Data.PrimeWheel.PrimeMultiples i)++-- | Combine a /queue/, with a /map/, to form a repository to hold prime-multiples.+type Repository i = (PrimeMultiplesQueue i, PrimeMultiplesMap i)++{- |+ * A refinement of the /Sieve Of Eratosthenes/, which pre-sieves candidates, selecting only those /coprime/ to the specified short sequence of low prime-numbers.++ * The short sequence of initial primes are represented by a 'Data.PrimeWheel.PrimeWheel',+ of parameterised, but static, size; <http://en.wikipedia.org/wiki/Wheel_factorization>.++ * The algorithm requires one to record multiples of previously discovered primes, allowing /composite/ candidates to be eliminated by comparison.++ * Because each /list/ of multiples, starts with the /square/ of the prime from which it was generated,+ the vast majority will be larger than the maximum prime ultimately demanded, and the effort of constructing and storing this list, is consequently wasted.+ Many implementations solve this, by requiring specification of the maximum prime required,+ thus allowing the construction of redundant lists of multiples to be avoided.++ * This implementation doesn't impose that constraint, leaving a requirement for /rapid/ storage,+ which is supported by /appending/ the /list/ of prime-multiples, to a /queue/.+ If a large enough candidate is ever generated, to match the /head/ of the /list/ of prime-multiples,+ at the /head/ of this /queue/, then the whole /list/ of prime-multiples is dropped from the /queue/,+ but the /tail/ of this /list/ of prime-multiples, for which there is now a high likelyhood of a subsequent match, must now be re-recorded.+ A /queue/ doesn't support efficient random /insertion/, so a 'Data.Map.Map' is used for these subsequent multiples.+ This solution is faster than just using a "Data.PQueue.Min".++ * CAVEAT: has linear /O(n)/ space-complexity.+-}+sieveOfEratosthenes :: Integral i+ => Data.PrimeWheel.NPrimes+ -> [i]+sieveOfEratosthenes = uncurry (++) . (Data.PrimeWheel.getPrimeComponents &&& start . Data.PrimeWheel.roll) . Data.PrimeWheel.mkPrimeWheel where+ start :: Integral i => [Data.PrimeWheel.Distance i] -> [i]+ start ~((candidate, rollingWheel) : distances) = candidate : sieve (head distances) (Data.Sequence.singleton $ Data.PrimeWheel.generateMultiples candidate rollingWheel, Data.Map.empty)++ sieve :: Integral i => Data.PrimeWheel.Distance i -> Repository i -> [i]+ sieve distance@(candidate, rollingWheel) repository@(primeSquares, squareFreePrimeMultiples) = case Data.Map.lookup candidate squareFreePrimeMultiples of+ Just primeMultiples -> sieve' $ Control.Arrow.second (insertUniq primeMultiples . Data.Map.delete candidate) repository --Re-insert subsequent multiples.+ Nothing --Not a square-free composite.+ | candidate == smallestPrimeSquare -> sieve' $ (tail' *** insertUniq subsequentPrimeMultiples) repository --Migrate subsequent prime-multiples, from 'primeSquares' to 'squareFreePrimeMultiples'.+ | otherwise {-prime-} -> candidate : sieve' (Control.Arrow.first (|> Data.PrimeWheel.generateMultiples candidate rollingWheel) repository)+ where+ (smallestPrimeSquare : subsequentPrimeMultiples) = head' primeSquares+ where+-- sieve' :: Repository i -> [i]+ sieve' = sieve $ Data.PrimeWheel.rotate distance --Tail-recurse.++ insertUniq :: Ord i => Data.PrimeWheel.PrimeMultiples i -> PrimeMultiplesMap i -> PrimeMultiplesMap i+ insertUniq l m = insert $ dropWhile (`Data.Map.member` m) l where+-- insert :: Ord i => Data.PrimeWheel.PrimeMultiples i -> PrimeMultiplesMap i+ insert [] = error "Factory.Math.Implementations.Primes.SieveOfEratosthenes.sieveOfEratosthenes.sieve.insertUniq.insert:\tnull list"+ insert (key : values) = Data.Map.insert key values m++{-# NOINLINE sieveOfEratosthenes #-}+{-# RULES "sieveOfEratosthenes/Int" sieveOfEratosthenes = sieveOfEratosthenesInt #-} --CAVEAT: doesn't fire when built with profiling enabled.++-- | A specialisation of 'PrimeMultiplesMap'.+type PrimeMultiplesMapInt = Data.IntMap.IntMap (Data.PrimeWheel.PrimeMultiples Int)++-- | A specialisation of 'Repository'.+type RepositoryInt = (PrimeMultiplesQueue Int, PrimeMultiplesMapInt)++{- |+ * A specialisation of 'sieveOfEratosthenes', which approximately /doubles/ the speed and reduces the space required.++ * CAVEAT: because the algorithm involves /squares/ of primes,+ this implementation will overflow when finding primes greater than @2^16@ on a /32-bit/ machine.+-}+sieveOfEratosthenesInt :: Data.PrimeWheel.NPrimes -> [Int]+sieveOfEratosthenesInt = uncurry (++) . (Data.PrimeWheel.getPrimeComponents &&& start . Data.PrimeWheel.roll) . Data.PrimeWheel.mkPrimeWheel where+ start :: [Data.PrimeWheel.Distance Int] -> [Int]+ start ~((candidate, rollingWheel) : distances) = candidate : sieve (head distances) (Data.Sequence.singleton $ Data.PrimeWheel.generateMultiples candidate rollingWheel, Data.IntMap.empty)++ sieve :: Data.PrimeWheel.Distance Int -> RepositoryInt -> [Int]+ sieve distance@(candidate, rollingWheel) repository@(primeSquares, squareFreePrimeMultiples) = case Data.IntMap.lookup candidate squareFreePrimeMultiples of+ Just primeMultiples -> sieve' $ Control.Arrow.second (insertUniq primeMultiples . Data.IntMap.delete candidate) repository+ Nothing+ | candidate == smallestPrimeSquare -> sieve' $ (tail' *** insertUniq subsequentPrimeMultiples) repository+ | otherwise -> candidate : sieve' (Control.Arrow.first (|> Data.PrimeWheel.generateMultiples candidate rollingWheel) repository)+ where+ (smallestPrimeSquare : subsequentPrimeMultiples) = head' primeSquares+ where+ sieve' :: RepositoryInt -> [Int]+ sieve' = sieve $ Data.PrimeWheel.rotate distance++ insertUniq :: Data.PrimeWheel.PrimeMultiples Int -> PrimeMultiplesMapInt -> PrimeMultiplesMapInt+ insertUniq l m = insert $ dropWhile (`Data.IntMap.member` m) l where+ insert :: Data.PrimeWheel.PrimeMultiples Int -> PrimeMultiplesMapInt+ insert [] = error "Factory.Math.Implementations.Primes.SieveOfEratosthenes.sieveOfEratosthenesInt.sieve.insertUniq.insert:\tnull list"+ insert (key : values) = Data.IntMap.insert key values m
+ src/Factory/Math/Implementations/Primes/TrialDivision.hs view
@@ -0,0 +1,61 @@+{-+ Copyright (C) 2011 Dr. Alistair Ward++ This program is free software: you can redistribute it and/or modify+ it under the terms of the GNU General Public License as published by+ the Free Software Foundation, either version 3 of the License, or+ (at your option) any later version.++ This program is distributed in the hope that it will be useful,+ but WITHOUT ANY WARRANTY; without even the implied warranty of+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+ GNU General Public License for more details.++ You should have received a copy of the GNU General Public License+ along with this program. If not, see <http://www.gnu.org/licenses/>.+-}+{- |+ [@AUTHOR@] Dr. Alistair Ward++ [@DESCRIPTION@] Generates the constant, conceptually infinite, list of /prime-numbers/, using /Trial Division/.+-}++module Factory.Math.Implementations.Primes.TrialDivision(+-- * Functions+ trialDivision+-- ** Predicates+-- isIndivisibleBy+) where++import qualified Control.Arrow+import qualified Data.List+import qualified Factory.Math.Power as Math.Power+import qualified Factory.Math.PrimeFactorisation as Math.PrimeFactorisation+import qualified Factory.Data.PrimeWheel as Data.PrimeWheel++-- | Uses /Trial Division/, to determine whether the specified candidate is indivisible by all potential denominators from the specified list.+isIndivisibleBy :: Integral i+ => i -- ^ The numerator.+ -> [i] -- ^ The denominators of which it must not be a multiple.+ -> Bool+isIndivisibleBy numerator = all ((/= 0) . (numerator `mod`)) . takeWhile (<= Math.PrimeFactorisation.maxBoundPrimeFactor numerator)++{-# INLINE isIndivisibleBy #-}++{- |+ * For each candidate, confirm indivisibility, by all /primes/ smaller than its /square-root/.++ * The candidates to sieve, are generated by a 'Data.PrimeWheel.PrimeWheel',+ of parameterised, but static, size; <http://en.wikipedia.org/wiki/Wheel_factorization>.+-}+trialDivision :: Integral prime => Data.PrimeWheel.NPrimes -> [prime]+trialDivision 0 = [2, 3] ++ filter (`isIndivisibleBy` trialDivision 0 {-recurse-}) [5 ..] --No faster than using 'Data.PrimeWheel.mkPrimeWheel 0', but apparently better space-complexity ?!+trialDivision wheelSize = Data.PrimeWheel.getPrimeComponents primeWheel ++ indivisible where+ primeWheel = Data.PrimeWheel.mkPrimeWheel wheelSize+ candidates = map fst $ Data.PrimeWheel.roll primeWheel+ indivisible = uncurry (++) . Control.Arrow.second (+ filter (`isIndivisibleBy` indivisible {-recurse-})+ ) $ Data.List.span (+ < Math.Power.square (head candidates) --The first composite candidate, is the square of the next prime after the wheel's constituent ones.+ ) candidates+
+ src/Factory/Math/Implementations/Primes/TurnersSieve.hs view
@@ -0,0 +1,48 @@+{-+ Copyright (C) 2011 Dr. Alistair Ward++ This program is free software: you can redistribute it and/or modify+ it under the terms of the GNU General Public License as published by+ the Free Software Foundation, either version 3 of the License, or+ (at your option) any later version.++ This program is distributed in the hope that it will be useful,+ but WITHOUT ANY WARRANTY; without even the implied warranty of+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+ GNU General Public License for more details.++ You should have received a copy of the GNU General Public License+ along with this program. If not, see <http://www.gnu.org/licenses/>.+-}+{- |+ [@AUTHOR@] Dr. Alistair Ward++ [@DESCRIPTION@] Generates the constant, conceptally infinite, list of /prime-numbers/, using /Turner's Sieve/; <http://www.haskell.org/haskellwiki/Prime_numbers#Turner.27s_sieve_-_Trial_division>.+-}++module Factory.Math.Implementations.Primes.TurnersSieve(+-- * Functions+ turnersSieve+) where++import qualified Factory.Math.Power as Math.Power++{- |+ * For each /prime/, the infinite list of candidates greater than its /square/,+ is filtered for indivisibility; <http://www.haskell.org/haskellwiki/Prime_numbers#Turner.27s_sieve_-_Trial_division>.++ * CAVEAT: though one can easily add a 'Data.PrimeWheel.PrimeWheel', it proved counterproductive.+-}+turnersSieve :: Integral prime => [prime]+turnersSieve = 2 : sieve [3, 5 ..] where+ sieve :: Integral i => [i] -> [i]+ sieve [] = []+ sieve (prime : candidates) = prime : sieve (+ filter (+ \candidate -> any ($ candidate) [+ (< Math.Power.square prime), --Unconditionally admit any candidate smaller than the square of the last prime.+ (/= 0) . (`mod` prime) --Ensure indivisibility, of all subsequent candidates, by the last prime discovered.+ ]+ ) candidates+ )+
src/Factory/Math/Implementations/SquareRoot.hs view
@@ -184,7 +184,7 @@ | otherwise = Math.Summation.sumR' . take terms . zipWith (*) taylorSeriesCoefficients $ iterate (* relativeError) x where relativeError :: Math.SquareRoot.Result- relativeError = (realToFrac y / Math.Power.square x) - 1 --Pedantically, this is the error in y, which is twice the magnitude of the error in x.+ relativeError = pred $ realToFrac y / Math.Power.square x --Pedantically, this is the error in y, which is twice the magnitude of the error in x. -- | Iterates from the estimated value, towards the /square-root/, a sufficient number of times to achieve the required accuracy. squareRootByIteration :: Real operand => Algorithm -> ProblemSpecification operand
+ src/Factory/Math/PerfectPower.hs view
@@ -0,0 +1,100 @@+{-+ Copyright (C) 2011 Dr. Alistair Ward++ This program is free software: you can redistribute it and/or modify+ it under the terms of the GNU General Public License as published by+ the Free Software Foundation, either version 3 of the License, or+ (at your option) any later version.++ This program is distributed in the hope that it will be useful,+ but WITHOUT ANY WARRANTY; without even the implied warranty of+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+ GNU General Public License for more details.++ You should have received a copy of the GNU General Public License+ along with this program. If not, see <http://www.gnu.org/licenses/>.+-}+{- |+ [@AUTHOR@] Dr. Alistair Ward++ [@DESCRIPTION@] Exports functions related to /perfect powers/.+-}++module Factory.Math.PerfectPower(+-- * Functions+ maybeSquareNumber,+-- ** Predicates+ isPerfectPower+-- isPerfectPowerInt+) where++import qualified Data.IntSet+import qualified Data.Set+import qualified Factory.Math.Power as Math.Power++{- |+ * Returns @(Just . sqrt)@ if the specified integer is a /square number/ (AKA /perfect square/).++ * <http://en.wikipedia.org/wiki/Square_number>.++ * <http://mathworld.wolfram.com/SquareNumber.html>.++ * @(Math.Power.square . sqrt)@ is expensive, so the modulus of the operand is tested first, in an attempt to prove it isn't a /perfect square/.+ The set of tests, and the valid moduli within each test, are ordered to maximize the rate of failure-detection.+-}+maybeSquareNumber :: Integral i => i -> Maybe i+maybeSquareNumber i+-- | i < 0 = Nothing --This function is performance-sensitive, but this test is neither strictly nor frequently required.+ | all (\(modulus, valid) -> mod i modulus `elem` valid) [+-- --Distribution of moduli amongst perfect squares Cumulative failure-detection.+ (16, [0,1,4,9]), --All moduli are equally likely. 75%+ (9, [0,1,4,7]), --Zero occurs 33%, the others only 22%. 88%+ (17, [1,2,4,8,9,13,15,16,0]), --Zero only occurs 5.8%, the others 11.8%. 94%+-- These additional tests, aren't always cost-effective.+ (13, [1,3,4,9,10,12,0]), --Zero only occurs 7.7%, the others 15.4%. 97%+ (7, [1,2,4,0]), --Zero only occurs 14.3%, the others 28.6%. 98%+ (5, [1,4,0]) --Zero only occurs 20%, the others 40%. 99%++-- ] && fromIntegral iSqrt == sqrt' = Just iSqrt --CAVEAT: erroneously True for 187598574531033120 (187598574531033121 is square).+ ] && Math.Power.square iSqrt == i = Just iSqrt+ | otherwise = Nothing+ where+ sqrt' :: Double+ sqrt' = sqrt $ fromIntegral i++ iSqrt = round sqrt'++{- |+ * An integer @(> 1)@ which can be expressed as an integral power @(> 1)@ of a smaller /natural/ number.++ * CAVEAT: /zero/ and /one/ are normally excluded from this set.++ * <http://en.wikipedia.org/wiki/Perfect_power>.++ * <http://mathworld.wolfram.com/PerfectPower.html>.++ * A generalisation of the concept of /perfect squares/, in which only the exponent '2' is significant.+-}+isPerfectPower :: Integral i => i -> Bool+isPerfectPower i+ | i < Math.Power.square 2 = False+ | otherwise = i `Data.Set.member` foldr (+ \n set -> if n `Data.Set.member` set+ then set+-- else Data.Set.union set . Data.Set.fromDistinctAscList . takeWhile (<= i) . iterate (* n) $ Math.Power.square n+ else foldr Data.Set.insert set . takeWhile (<= i) . iterate (* n) $ Math.Power.square n --Faster.+ ) Data.Set.empty [2 .. round $ sqrt (fromIntegral i :: Double)]++{-# NOINLINE isPerfectPower #-}+{-# RULES "isPerfectPower/Int" isPerfectPower = isPerfectPowerInt #-}++-- | A specialisation of 'isPerfectPower'.+isPerfectPowerInt :: Int -> Bool+isPerfectPowerInt i+ | i < Math.Power.square 2 = False+ | otherwise = i `Data.IntSet.member` foldr (+ \n set -> if n `Data.IntSet.member` set+ then set+ else foldr Data.IntSet.insert set . takeWhile (<= i) . iterate (* n) $ Math.Power.square n+ ) Data.IntSet.empty [2 .. round $ sqrt (fromIntegral i :: Double)]+
src/Factory/Math/Pi.hs view
@@ -47,13 +47,13 @@ openI _ 1 = 3 openI algorithm decimalDigits | decimalDigits <= 0 = error $ "Factory.Math.Pi.openI:\tinsufficient decimalDigits=" ++ show decimalDigits- | otherwise = round . Math.Precision.promote (openR algorithm decimalDigits) $ decimalDigits - 1+ | otherwise = round . Math.Precision.promote (openR algorithm decimalDigits) $ pred decimalDigits openS :: algorithm -> Math.Precision.DecimalDigits -> String -- ^ Returns the value of /Pi/ as a decimal 'String'. openS _ 1 = "3" openS algorithm decimalDigits | decimalDigits <= 0 = ""- | decimalDigits <= 16 = take (decimalDigits + 1) $ show (pi :: Double)+ | decimalDigits <= 16 = take (succ decimalDigits) $ show (pi :: Double) | otherwise = "3." ++ tail (show $ openI algorithm decimalDigits) --Insert a decimal point. -- | Categorises the various algorithms.@@ -83,7 +83,7 @@ ) => Algorithmic (Category agm bbp borwein ramanujan spigot) where openR algorithm decimalDigits | decimalDigits <= 0 = error $ "Factory.Math.Pi.openR:\tinsufficient decimalDigits=" ++ show decimalDigits- | decimalDigits <= 16 = Math.Precision.simplify (decimalDigits - 1) (pi :: Double)+ | decimalDigits <= 16 = Math.Precision.simplify (pred decimalDigits) (pi :: Double) | otherwise = ( case algorithm of AGM agm -> openR agm@@ -97,5 +97,5 @@ openI (Spigot spigot) decimalDigits = openI spigot decimalDigits openI algorithm decimalDigits | decimalDigits <= 0 = error $ "Factory.Math.Pi.openI:\tinsufficient decimalDigits=" ++ show decimalDigits- | otherwise = round . Math.Precision.promote (openR algorithm decimalDigits) $ decimalDigits - 1+ | otherwise = round . Math.Precision.promote (openR algorithm decimalDigits) $ pred decimalDigits
src/Factory/Math/Power.hs view
@@ -24,23 +24,17 @@ -- * Functions square, squaresFrom,- maybeSquareNumber, cube, cubeRoot,- raiseModulo,--- ** Predicates- isPerfectPower--- isPerfectPowerInt+ raiseModulo ) where -import qualified Data.IntSet-import qualified Data.Set- -- | Mainly for convenience.-{-# INLINE square #-} square :: Num n => n -> n square = (^ (2 :: Int)) +{-# INLINE square #-}+ -- | Just for convenience. cube :: Num n => n -> n cube = (^ (3 :: Int))@@ -51,10 +45,10 @@ * The initial value doesn't need to be either positive or integral. -}-squaresFrom :: Num n+squaresFrom :: (Enum n, Num n) => n -- ^ Lower bound. -> [(n, n)] -- ^ @ [(n, n^2)] @.-squaresFrom from = iterate (\(x, y) -> (x + 1, y + 2 * x + 1)) (from, square from)+squaresFrom from = iterate (\(x, y) -> (succ x, succ $ y + 2 * x)) (from, square from) -- | Just for convenience. cubeRoot :: Double -> Double@@ -77,7 +71,7 @@ raiseModulo _ _ 1 = 0 raiseModulo _ 0 modulus = 1 `mod` modulus raiseModulo base power modulus- | base < 0 = (`mod` modulus) . (if odd power then negate else id) $ raiseModulo (negate base) power modulus --Recurse.+ | base < 0 = (`mod` modulus) . (if even power then id else negate) $ raiseModulo (negate base) power modulus --Recurse. | power < 0 = error $ "Factory.Math.Power.raiseModulo:\tnegative power; " ++ show power | first `elem` [0, 1] = first | otherwise = slave power@@ -87,70 +81,4 @@ slave 1 = first slave e = (`mod` modulus) . (if r == 0 {-even-} then id else (* base)) . square $ slave q {-recurse-} where (q, r) = e `quotRem` 2--{- |- * Returns @(Just . sqrt)@ if the specified integer is a /square number/ (AKA /perfect square/).-- * <http://en.wikipedia.org/wiki/Square_number>.-- * <http://mathworld.wolfram.com/SquareNumber.html>.-- * @(square . sqrt)@ is expensive, so the modulus of the operand is tested first, in an attempt to prove it isn't a /perfect square/.- The set of tests, and the valid moduli within each test, are ordered to maximize the rate of failure-detection.--}-maybeSquareNumber :: Integral i => i -> Maybe i-maybeSquareNumber i--- | i < 0 = Nothing --This function is performance-sensitive, but this test is neither strictly nor frequently required.- | all (\(modulus, valid) -> mod i modulus `elem` valid) [--- --Distribution of moduli amongst perfect squares Cumulative failure-detection.- (16, [0,1,4,9]), --All moduli are equally likely. 75%- (9, [0,1,4,7]), --Zero occurs 33%, the others only 22%. 88%- (17, [1,2,4,8,9,13,15,16,0]), --Zero only occurs 5.8%, the others 11.8%. 94%--- These additional tests, aren't always cost-effective.- (13, [1,3,4,9,10,12,0]), --Zero only occurs 7.7%, the others 15.4%. 97%- (7, [1,2,4,0]), --Zero only occurs 14.3%, the others 28.6%. 98%- (5, [1,4,0]) --Zero only occurs 20%, the others 40%. 99%---- ] && fromIntegral iSqrt == sqrt' = Just iSqrt --CAVEAT: erroneously True for 187598574531033120 (187598574531033121 is square).- ] && square iSqrt == i = Just iSqrt- | otherwise = Nothing- where- sqrt' :: Double- sqrt' = sqrt $ fromIntegral i-- iSqrt = round sqrt'--{- |- * An integer @(> 1)@ which can be expressed as an integral power @(> 1)@ of a smaller /natural/ number.-- * CAVEAT: /zero/ and /one/ are normally excluded from this set.-- * <http://en.wikipedia.org/wiki/Perfect_power>.-- * <http://mathworld.wolfram.com/PerfectPower.html>.-- * A generalisation of the concept of /perfect squares/, in which only the exponent '2' is significant.--}-isPerfectPower :: Integral i => i -> Bool-isPerfectPower i- | i < square 2 = False- | otherwise = i `Data.Set.member` foldr (- \n set -> if n `Data.Set.member` set- then set--- else Data.Set.union set . Data.Set.fromDistinctAscList . takeWhile (<= i) . iterate (* n) $ square n- else foldr Data.Set.insert set . takeWhile (<= i) . iterate (* n) $ square n --Faster.- ) Data.Set.empty [2 .. round $ sqrt (fromIntegral i :: Double)]--{-# NOINLINE isPerfectPower #-}-{-# RULES "isPerfectPower/Int" isPerfectPower = isPerfectPowerInt #-}---- | A specialisation of 'isPerfectPower'.-isPerfectPowerInt :: Int -> Bool-isPerfectPowerInt i- | i < square 2 = False- | otherwise = i `Data.IntSet.member` foldr (- \n set -> if n `Data.IntSet.member` set- then set- else foldr Data.IntSet.insert set . takeWhile (<= i) . iterate (* n) $ square n- ) Data.IntSet.empty [2 .. round $ sqrt (fromIntegral i :: Double)]
src/Factory/Math/Precision.hs view
@@ -114,5 +114,5 @@ => DecimalDigits -- ^ The number of places after the decimal point, which are required. -> operand -> Data.Ratio.Rational-simplify decimalDigits operand = Data.Ratio.approxRational operand . recip $ 4 * 10 ^ (decimalDigits + 1) --Tolerate any error less than half the least significant digit required.+simplify decimalDigits operand = Data.Ratio.approxRational operand . recip $ 4 * 10 ^ succ decimalDigits --Tolerate any error less than half the least significant digit required.
src/Factory/Math/Primality.hs view
@@ -69,11 +69,11 @@ * TODO: confirm that all values must be tested. -} isFermatWitness :: Integral i => i -> Bool-isFermatWitness i = not . all isFermatPseudoPrime $ filter (areCoprime i) [2 .. i - 1] where- isFermatPseudoPrime base = Math.Power.raiseModulo base (i - 1) i == 1 --CAVEAT: a /Fermat Pseudo-prime/ must also be a /composite/ number.+isFermatWitness i = not . all isFermatPseudoPrime $ filter (areCoprime i) [2 .. pred i] where+ isFermatPseudoPrime base = Math.Power.raiseModulo base (pred i) i == 1 --CAVEAT: a /Fermat Pseudo-prime/ must also be a /composite/ number. {- |- * A /Carmichael number/ is an odd /composite/ number which satisfies /Fermat's little theorem/.+ * A /Carmichael number/ is an /odd/ /composite/ number which satisfies /Fermat's little theorem/. * <http://en.wikipedia.org/wiki/Carmichael_number>.
src/Factory/Math/Primes.hs view
@@ -27,16 +27,19 @@ primorial ) where +import qualified Control.DeepSeq+import qualified Data.Array.IArray+ -- | Defines the methods expected of a /prime-number/ generator. class Algorithmic algorithm where- primes :: Integral i => algorithm -> [i] -- ^ Returns the constant, conceptually infinite, list of primes.+ primes :: (Control.DeepSeq.NFData i, Data.Array.IArray.Ix i, Integral i) => algorithm -> [i] -- ^ Returns the constant, infinite, list of primes. {- |- * Returns the constant, infinite list, defining the /Primorial/.+ * Returns the constant list, defining the /Primorial/. * <http://en.wikipedia.org/wiki/Primorial>. * <http://mathworld.wolfram.com/Primorial.html>. -}-primorial :: (Integral i, Algorithmic algorithm) => algorithm -> [i]+primorial :: (Algorithmic algorithm, Control.DeepSeq.NFData i, Data.Array.IArray.Ix i, Integral i) => algorithm -> [i] primorial = scanl (*) 1 . primes
src/Factory/Math/Radix.hs view
@@ -44,7 +44,7 @@ -- | Constant random-access lookup for 'digits'. encodes :: (Data.Array.IArray.Ix index, Integral index) => Data.Array.IArray.Array index Char-encodes = Data.Array.IArray.listArray (0, fromIntegral $ length digits - 1) digits where+encodes = Data.Array.IArray.listArray (0, fromIntegral . pred $ length digits) digits where -- | Constant reverse-lookup for 'digits'. decodes :: Integral i => [(Char, i)]@@ -69,7 +69,7 @@ where fromDecimal 0 = id fromDecimal n- | remainder < 0 = fromDecimal (quotient + 1) . ((remainder - fromIntegral base) :) --This can only occur when base is negative; cf. 'divMod'.+ | remainder < 0 = fromDecimal (succ quotient) . ((remainder - fromIntegral base) :) --This can only occur when base is negative; cf. 'divMod'. | otherwise = fromDecimal quotient . (remainder :) where (quotient, remainder) = n `quotRem` fromIntegral base@@ -114,5 +114,5 @@ -- | <http://en.wikipedia.org/wiki/Digital_root>. digitalRoot :: (Data.Array.IArray.Ix decimal, Integral decimal) => decimal -> decimal-digitalRoot = head . dropWhile (> 9) . iterate (digitSum (10 :: Int))+digitalRoot = until (<= 9) (digitSum (10 :: Int))
src/Factory/Math/Statistics.hs view
@@ -103,7 +103,7 @@ | otherwise = numerator `par` (denominator `pseq` numerator `div` denominator) where [smaller, bigger] = Data.List.sort [r, n - r]- numerator = Math.Implementations.Factorial.risingFactorial (bigger + 1) (n - bigger)+ numerator = Math.Implementations.Factorial.risingFactorial (succ bigger) (n - bigger) denominator = Math.Factorial.factorial factorialAlgorithm smaller -- | The number of /permutations/ of /r/ objects taken from /n/; <http://en.wikipedia.org/wiki/Permutations>.
src/Factory/Test/Performance/Primes.hs view
@@ -26,9 +26,10 @@ ) where import qualified Control.DeepSeq+import qualified Data.Array.IArray import qualified Factory.Math.Primes as Math.Primes import qualified ToolShed.TimePure as TimePure -- | Measures the CPU-time required by 'Math.Primes.primes', to find the specified prime.-primesPerformance :: (Math.Primes.Algorithmic algorithm, Control.DeepSeq.NFData i, Integral i) => algorithm -> Int -> IO (Double, i)+primesPerformance :: (Math.Primes.Algorithmic algorithm, Control.DeepSeq.NFData i, Data.Array.IArray.Ix i, Integral i) => algorithm -> Int -> IO (Double, i) primesPerformance algorithm = TimePure.getCPUSeconds . (Math.Primes.primes algorithm !!)
src/Factory/Test/QuickCheck/ArithmeticGeometricMean.hs view
@@ -55,11 +55,11 @@ ) ( Math.ArithmeticGeometricMean.convergeToAGM squareRootAlgorithm decimalDigits' $ swap agm ) where- decimalDigits' = 1 + (decimalDigits `mod` 64)- index' = 1 + (index `mod` 8)+ decimalDigits' = succ $ decimalDigits `mod` 64+ index' = succ $ index `mod` 8 prop_bounds squareRootAlgorithm decimalDigits agm index = all ($ agm) [Math.ArithmeticGeometricMean.isValid, uncurry (/=)] ==> Test.QuickCheck.label "prop_bounds" . all (uncurry (>=)) . tail . take index' $ Math.ArithmeticGeometricMean.convergeToAGM squareRootAlgorithm decimalDigits' agm where decimalDigits' = 33 {-test is sensitive to rounding-errors-} + (decimalDigits `mod` 96)- index' = 1 + (index `mod` 5)+ index' = succ $ index `mod` 5
src/Factory/Test/QuickCheck/Factorial.hs view
@@ -52,10 +52,10 @@ prop_equivalence x n = Test.QuickCheck.label "prop_equivalence" $ Math.Implementations.Factorial.risingFactorial x n == sign * Math.Implementations.Factorial.fallingFactorial (negate x) n && Math.Implementations.Factorial.fallingFactorial x n == sign * Math.Implementations.Factorial.risingFactorial (negate x) n where sign :: Integer sign- | odd n = negate 1- | otherwise = 1+ | even n = 1+ | otherwise = negate 1 - prop_symmetry x n = Test.QuickCheck.label "prop_symmetry" $ Math.Implementations.Factorial.risingFactorial x n == Math.Implementations.Factorial.fallingFactorial (x + n - 1) n+ prop_symmetry x n = Test.QuickCheck.label "prop_symmetry" $ Math.Implementations.Factorial.risingFactorial x n == Math.Implementations.Factorial.fallingFactorial (pred $ x + n) n prop_x0 x _ = Test.QuickCheck.label "prop_x0" $ all (== 1) $ map ($ 0) [Math.Implementations.Factorial.risingFactorial x, Math.Implementations.Factorial.fallingFactorial x] @@ -63,10 +63,10 @@ prop_ratio :: Math.Implementations.Factorial.Algorithm -> Integer -> Integer -> Test.QuickCheck.Property prop_ratio algorithm i j = Test.QuickCheck.label "prop_ratio" $ n !/! d == Math.Factorial.factorial algorithm n % Math.Factorial.factorial algorithm d where- n = (i `mod` 100000) - 1- d = (j `mod` 100000) - 1+ n = pred $ i `mod` 100000+ d = pred $ j `mod` 100000 prop_consistency :: Math.Implementations.Factorial.Algorithm -> Math.Implementations.Factorial.Algorithm -> Integer -> Test.QuickCheck.Property prop_consistency l r i = l /= r ==> Test.QuickCheck.label "prop_consistency" $ Math.Factorial.factorial l n == Math.Factorial.factorial r n where- n = (i `mod` 100000) - 1+ n = pred $ i `mod` 100000
src/Factory/Test/QuickCheck/Hyperoperation.hs view
@@ -40,7 +40,7 @@ prop_rankCoincides :: Rank -> Test.QuickCheck.Property prop_rankCoincides rank = Test.QuickCheck.label "prop_rankCoincides" $ Math.Hyperoperation.hyperoperation rank' 2 2 == 4 where rank' :: Rank- rank' = 1 + (rank `mod` 1000)+ rank' = succ $ rank `mod` 1000 prop_baseCoincides :: Rank -> Integer -> Test.QuickCheck.Property prop_baseCoincides rank base = Test.QuickCheck.label "prop_baseCoincides" $ Math.Hyperoperation.hyperoperation rank' base 1 == base where@@ -56,7 +56,7 @@ hyperExponent' = abs hyperExponent prop_succ, prop_addition, prop_multiplication, prop_exponentiation :: Integer -> Integer -> Test.QuickCheck.Property- prop_succ base hyperExponent = Test.QuickCheck.label "prop_succ" $ Math.Hyperoperation.hyperoperation Math.Hyperoperation.succession base hyperExponent' == 1 + fromIntegral hyperExponent' where+ prop_succ base hyperExponent = Test.QuickCheck.label "prop_succ" $ Math.Hyperoperation.hyperoperation Math.Hyperoperation.succession base hyperExponent' == succ (fromIntegral hyperExponent') where hyperExponent' :: Math.Hyperoperation.HyperExponent hyperExponent' = abs hyperExponent
src/Factory/Test/QuickCheck/Interval.hs view
@@ -35,9 +35,9 @@ prop_product :: Data.Ratio.Ratio Integer -> Integer -> Data.Interval.Interval Integer -> Test.QuickCheck.Property prop_product ratio minLength interval = Test.QuickCheck.label "prop_product" $ Data.Interval.product' ratio' minLength' interval' == product (Data.Interval.toList interval') where interval' = Data.Interval.normalise interval- minLength' = 1 + minLength `mod` 1000- ratio' = if r > 1- then recip r- else r+ minLength' = succ $ minLength `mod` 1000+ ratio'+ | r > 1 = recip r+ | otherwise = r where r = abs ratio
src/Factory/Test/QuickCheck/MonicPolynomial.hs view
@@ -47,7 +47,7 @@ arbitrary = do polynomial <- Test.QuickCheck.arbitrary - return . Data.MonicPolynomial.mkMonicPolynomial $ ((1, Data.Polynomial.getDegree polynomial + 1) :) `Data.Polynomial.lift` polynomial+ return . Data.MonicPolynomial.mkMonicPolynomial $ ((1, succ $ Data.Polynomial.getDegree polynomial) :) `Data.Polynomial.lift` polynomial #if !(MIN_VERSION_QuickCheck(2,1,0)) coarbitrary = undefined --CAVEAT: stops warnings from ghc. #endif@@ -66,7 +66,7 @@ prop_perfectPower :: P -> Int -> Test.QuickCheck.Property prop_perfectPower polynomial power = Test.QuickCheck.label "prop_perfectPower" $ iterate (`Data.QuotientRing.quot'` polynomial) (polynomial =^ power') !! pred power' == polynomial where power' :: Int- power' = 1 + power `mod` 100+ power' = succ $ power `mod` 100 prop_isDivisibleBy :: [P] -> Test.QuickCheck.Property prop_isDivisibleBy monicPolynomials = Test.QuickCheck.label "prop_isDivisibleBy" $ all (Data.QuotientRing.isDivisibleBy (Data.Ring.product' (recip 2) {-TODO-} 10 monicPolynomials)) monicPolynomials
+ src/Factory/Test/QuickCheck/PerfectPower.hs view
@@ -0,0 +1,52 @@+{-+ Copyright (C) 2011 Dr. Alistair Ward++ This program is free software: you can redistribute it and/or modify+ it under the terms of the GNU General Public License as published by+ the Free Software Foundation, either version 3 of the License, or+ (at your option) any later version.++ This program is distributed in the hope that it will be useful,+ but WITHOUT ANY WARRANTY; without even the implied warranty of+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+ GNU General Public License for more details.++ You should have received a copy of the GNU General Public License+ along with this program. If not, see <http://www.gnu.org/licenses/>.+-}+{- |+ [@AUTHOR@] Dr. Alistair Ward++ [@DESCRIPTION@] Defines /QuickCheck/-properties for "Math.PerfectPower".+-}++module Factory.Test.QuickCheck.PerfectPower(+-- * Functions+ quickChecks+) where++import qualified Factory.Math.PerfectPower as Math.PerfectPower+import qualified Factory.Math.Power as Math.Power+import qualified Test.QuickCheck+import Test.QuickCheck((==>))++-- | Defines invariant properties.+quickChecks :: IO ()+quickChecks =+ Test.QuickCheck.quickCheck `mapM_` [prop_maybeSquareNumber, prop_rewriteRule]+ >> Test.QuickCheck.quickCheckWith Test.QuickCheck.stdArgs {Test.QuickCheck.maxSuccess = 10000} prop_notSquare+ >> Test.QuickCheck.quickCheck prop_isPerfectPower+ where+ prop_maybeSquareNumber, prop_notSquare, prop_rewriteRule :: Integer -> Test.QuickCheck.Property+ prop_maybeSquareNumber i = Test.QuickCheck.label "prop_maybeSquareNumber" $ Math.PerfectPower.maybeSquareNumber (Math.Power.square i) == Just (abs i)++ prop_notSquare i = abs i > 0 ==> Test.QuickCheck.label "prop_notSquare" $ Math.PerfectPower.maybeSquareNumber (succ $ i ^ (10 {-promote rounding-error using big number-} :: Int)) == Nothing+ prop_rewriteRule i = Test.QuickCheck.label "prop_rewriteRule" $ Math.PerfectPower.isPerfectPower i' == Math.PerfectPower.isPerfectPower (fromIntegral i' :: Int) where+ i' = abs i++ prop_isPerfectPower :: Integer -> Integer -> Test.QuickCheck.Property+ prop_isPerfectPower b e = Test.QuickCheck.label "prop_isPerfectPower" . Math.PerfectPower.isPerfectPower $ b' ^ e' where+ b' = 2 + (b `mod` 10)+ e' = 2 + (e `mod` 8)++
src/Factory/Test/QuickCheck/Pi.hs view
@@ -128,5 +128,5 @@ quickChecks = Test.QuickCheck.quickCheck prop_consistency where prop_consistency :: Testable prop_consistency l r decimalDigits = l /= r ==> Test.QuickCheck.label "prop_consistency" $ Math.Pi.openI l decimalDigits' - Math.Pi.openI r decimalDigits' <= 1 {-rounding error-} where- decimalDigits' = 1 + (decimalDigits `mod` 250)+ decimalDigits' = succ $ decimalDigits `mod` 250
src/Factory/Test/QuickCheck/Polynomial.hs view
@@ -88,30 +88,30 @@ prop_power, prop_perfectPower, prop_normalised :: Data.Polynomial.Polynomial Integer Integer -> Int -> Test.QuickCheck.Property prop_power polynomial power = Test.QuickCheck.label "prop_power" $ polynomial =^ power' == iterate (=*= polynomial) polynomial !! pred power' where power' :: Int- power' = 1 + power `mod` 100+ power' = succ $ power `mod` 100 prop_perfectPower polynomial power = polynomial' /= Data.Polynomial.zero ==> Test.QuickCheck.label "prop_perfectPower" $ iterate (`Data.QuotientRing.quot'` polynomial') (polynomial' =^ power') !! pred power' == polynomial' where polynomial' :: Data.Polynomial.Polynomial Data.Ratio.Rational Integer polynomial' = Data.Polynomial.realCoefficientsToFrac polynomial power' :: Int- power' = 1 + power `mod` 100+ power' = succ $ power `mod` 100 prop_normalised polynomial i = Test.QuickCheck.label "prop_normalised" $ all Data.Polynomial.isNormalised [ polynomial =^ power', polynomial `Data.Polynomial.mod'` modulus' ] where power' :: Int- power' = 1 + i `mod` 100+ power' = succ $ i `mod` 100 modulus' :: Integer- modulus' = 1 + fromIntegral i `mod` 100+ modulus' = succ $ fromIntegral i `mod` 100 prop_raiseModuloNormalised :: Data.Polynomial.Polynomial Integer Integer -> Integer -> Integer -> Test.QuickCheck.Property prop_raiseModuloNormalised polynomial power modulus = Test.QuickCheck.label "prop_raiseModuloNormalised" . Data.Polynomial.isNormalised $ Data.Polynomial.raiseModulo polynomial power' modulus' where power', modulus' :: Integer- power' = 1 + power `mod` 100- modulus' = 1 + modulus `mod` 100+ power' = succ $ power `mod` 100+ modulus' = succ $ modulus `mod` 100 prop_integralDomain, prop_isDivisibleBy :: [Data.Polynomial.Polynomial Integer Integer] -> Test.QuickCheck.Property prop_integralDomain polynomials = Data.Polynomial.zero `notElem` polynomials ==> Test.QuickCheck.label "prop_integralDomain" $ Data.Ring.product' (recip 2) {-TODO-} 10 polynomials /= Data.Polynomial.zero
src/Factory/Test/QuickCheck/Power.hs view
@@ -17,7 +17,7 @@ {- | [@AUTHOR@] Dr. Alistair Ward - [@DESCRIPTION@] Defines /QuickCheck/-properties for "Math.Power".+ [@DESCRIPTION@] Defines /QuickCheck/-properties "Math.Power". -} module Factory.Test.QuickCheck.Power(@@ -32,25 +32,10 @@ -- | Defines invariant properties. quickChecks :: IO ()-quickChecks =- Test.QuickCheck.quickCheck `mapM_` [prop_maybeSquareNumber, prop_rewriteRule]- >> Test.QuickCheck.quickCheckWith Test.QuickCheck.stdArgs {Test.QuickCheck.maxSuccess = 10000} prop_notSquare- >> Test.QuickCheck.quickCheck `mapM` [prop_squaresFrom, prop_isPerfectPower]- >> Test.QuickCheck.quickCheck prop_raiseModulo+quickChecks = Test.QuickCheck.quickCheck prop_squaresFrom >> Test.QuickCheck.quickCheck prop_raiseModulo where- prop_maybeSquareNumber, prop_notSquare, prop_rewriteRule :: Integer -> Test.QuickCheck.Property- prop_maybeSquareNumber i = Test.QuickCheck.label "prop_maybeSquareNumber" $ Math.Power.maybeSquareNumber (Math.Power.square i) == Just (abs i)-- prop_notSquare i = abs i > 0 ==> Test.QuickCheck.label "prop_notSquare" $ Math.Power.maybeSquareNumber (i ^ (10 {-promote rounding-error using big number-} :: Int) + 1) == Nothing- prop_rewriteRule i = Test.QuickCheck.label "prop_rewriteRule" $ Math.Power.isPerfectPower i' == Math.Power.isPerfectPower (fromIntegral i' :: Int) where- i' = abs i-- prop_squaresFrom, prop_isPerfectPower :: Integer -> Integer -> Test.QuickCheck.Property+ prop_squaresFrom :: Integer -> Integer -> Test.QuickCheck.Property prop_squaresFrom from l = Test.QuickCheck.label "prop_squaresFrom" . (\(x, y) -> y == Math.Power.square x) . Data.List.genericIndex (Math.Power.squaresFrom from) $ abs l-- prop_isPerfectPower b e = Test.QuickCheck.label "prop_isPerfectPower" . Math.Power.isPerfectPower $ b' ^ e' where- b' = 2 + (b `mod` 10)- e' = 2 + (e `mod` 8) prop_raiseModulo :: Integer -> Integer -> Integer -> Test.QuickCheck.Property prop_raiseModulo b e m = m /= 0 ==> Test.QuickCheck.label "prop_raiseModulo" $ Math.Power.raiseModulo b e' m == (b ^ e') `mod` m where
src/Factory/Test/QuickCheck/PrimeFactorisation.hs view
@@ -58,30 +58,30 @@ prop_consistency :: Integer -> Test.QuickCheck.Property prop_consistency i = Test.QuickCheck.label "prop_consistency" $ (Math.PrimeFactorisation.primeFactors Math.Implementations.PrimeFactorisation.TrialDivision i' :: Data.PrimeFactors.Factors Integer Int) == Math.PrimeFactorisation.primeFactors Math.Implementations.PrimeFactorisation.FermatsMethod i' where i' :: Integer- i' = 1 + (i `mod` 1000000)+ i' = succ $ i `mod` 1000000 prop_primeFactors, prop_smoothness, prop_eulersTotientP, prop_eulersTotientInequality :: Math.Implementations.PrimeFactorisation.Algorithm -> Integer -> Test.QuickCheck.Property prop_primeFactors algorithm i = Test.QuickCheck.label "prop_primeFactors" $ Data.PrimeFactors.product' (recip 2) {-TODO-} 10 (Math.PrimeFactorisation.primeFactors algorithm i') == i' where i' :: Integer- i' = 1 + (i `mod` 1000000)+ i' = succ $ i `mod` 1000000 prop_smoothness algorithm i = Test.QuickCheck.label "prop_smoothness" $ (Math.PrimeFactorisation.smoothness algorithm !! (2 ^ i')) <= (2 :: Integer) where i' :: Integer i' = i `mod` 20 - prop_eulersTotientP algorithm i = Test.QuickCheck.label "prop_eulersTotient" $ Math.PrimeFactorisation.eulersTotient algorithm prime == prime - 1 where+ prop_eulersTotientP algorithm i = Test.QuickCheck.label "prop_eulersTotient" $ Math.PrimeFactorisation.eulersTotient algorithm prime == pred prime where prime :: Integer prime = Data.List.genericIndex Data.Numbers.Primes.primes (i `mod` 10000) prop_eulersTotientInequality algorithm i = i `notElem` [2, 6] ==> Test.QuickCheck.label "prop_eulersTotientInequality" $ Math.PrimeFactorisation.eulersTotient algorithm i' >= floor (sqrt $ fromIntegral i' :: Double) where- i' = 1 + (i `mod` 100000)+ i' = succ $ i `mod` 100000 prop_eulersTotient, prop_lagrange, prop_multiplicativeOrder, prop_perfectPower :: Math.Implementations.PrimeFactorisation.Algorithm -> Integer -> Integer -> Test.QuickCheck.Property- prop_eulersTotient algorithm i power = Test.QuickCheck.label "prop_eulersTotient" $ Math.PrimeFactorisation.eulersTotient algorithm (base ^ power') == (base ^ (power' - 1)) * (base - 1) where+ prop_eulersTotient algorithm i power = Test.QuickCheck.label "prop_eulersTotient" $ Math.PrimeFactorisation.eulersTotient algorithm (base ^ power') == (base ^ pred power') * pred base where base :: Integer base = Data.List.genericIndex Data.Numbers.Primes.primes (i `mod` 8) - power' = 1 + (power `mod` 5)+ power' = succ $ power `mod` 5 prop_lagrange algorithm base modulus = gcd base modulus' == 1 ==> Test.QuickCheck.label "prop_lagrange" $ (Math.PrimeFactorisation.eulersTotient algorithm modulus' `rem` Math.MultiplicativeOrder.multiplicativeOrder algorithm base modulus') == 0 where modulus' :: Integer
src/Factory/Test/QuickCheck/Primes.hs view
@@ -23,6 +23,8 @@ -} module Factory.Test.QuickCheck.Primes(+-- * Constants+-- defaultAlgorithm, -- * Functions quickChecks, -- isPrime,@@ -32,20 +34,21 @@ import Control.Applicative((<$>)) import qualified Control.DeepSeq import qualified Data.Set+import qualified Factory.Data.PrimeWheel as Data.PrimeWheel import qualified Factory.Math.Implementations.Primality as Math.Implementations.Primality import qualified Factory.Math.Implementations.PrimeFactorisation as Math.Implementations.PrimeFactorisation-import qualified Factory.Math.Implementations.Primes as Math.Implementations.Primes+import qualified Factory.Math.Implementations.Primes.Algorithm as Math.Implementations.Primes.Algorithm import qualified Factory.Math.Primality as Math.Primality import qualified Factory.Math.Primes as Math.Primes import qualified Test.QuickCheck import Test.QuickCheck((==>)) import qualified ToolShed.Defaultable as Defaultable -instance Test.QuickCheck.Arbitrary Math.Implementations.Primes.Algorithm where+instance Test.QuickCheck.Arbitrary Math.Implementations.Primes.Algorithm.Algorithm where arbitrary = Test.QuickCheck.oneof [- return Math.Implementations.Primes.TurnersSieve,- Math.Implementations.Primes.TrialDivision . (`mod` 10) <$> Test.QuickCheck.arbitrary,- Math.Implementations.Primes.SieveOfEratosthenes . (`mod` 10) <$> Test.QuickCheck.arbitrary+ return Math.Implementations.Primes.Algorithm.TurnersSieve,+ Math.Implementations.Primes.Algorithm.TrialDivision . (`mod` 10) <$> Test.QuickCheck.arbitrary,+ Math.Implementations.Primes.Algorithm.SieveOfEratosthenes . (`mod` 10) <$> Test.QuickCheck.arbitrary ] #if !(MIN_VERSION_QuickCheck(2,1,0)) coarbitrary = undefined --CAVEAT: stops warnings from ghc.@@ -56,23 +59,46 @@ primalityAlgorithm :: Math.Implementations.Primality.Algorithm Math.Implementations.PrimeFactorisation.Algorithm primalityAlgorithm = Defaultable.defaultValue -upperBound :: Math.Implementations.Primes.Algorithm -> Int -> Int-upperBound algorithm i = mod i $ if algorithm == Math.Implementations.Primes.TurnersSieve+upperBound :: Math.Implementations.Primes.Algorithm.Algorithm -> Int -> Int+upperBound algorithm i = mod i $ if algorithm == Math.Implementations.Primes.Algorithm.TurnersSieve then 8192 else 65536 +defaultAlgorithm :: Math.Implementations.Primes.Algorithm.Algorithm+defaultAlgorithm = Defaultable.defaultValue+ -- | Defines invariant properties. quickChecks :: IO () quickChecks = Test.QuickCheck.quickCheck `mapM_` [prop_isPrime, prop_isComposite]- >> Test.QuickCheck.quickCheck prop_consistency where- prop_isPrime, prop_isComposite :: Math.Implementations.Primes.Algorithm -> Int -> Test.QuickCheck.Property- prop_isPrime algorithm i = Test.QuickCheck.label "prop_isPrime" . all isPrime . takeWhile (<= (upperBound algorithm i)) $ (Math.Primes.primes algorithm :: [Int])-+ >> Test.QuickCheck.quickCheck prop_consistency+ >> Test.QuickCheck.quickCheck prop_rewriteRule+ >> Test.QuickCheck.quickCheck `mapM_` [prop_sieveOfAtkin, prop_sieveOfAtkinRewrite]+ where+ prop_isPrime, prop_isComposite :: Math.Implementations.Primes.Algorithm.Algorithm -> Int -> Test.QuickCheck.Property+ prop_isPrime algorithm i = Test.QuickCheck.label "prop_isPrime" . all isPrime . takeWhile (<= upperBound algorithm i) $ (Math.Primes.primes algorithm :: [Int]) prop_isComposite algorithm i = Test.QuickCheck.label "prop_isComposite" . not . any isPrime . Data.Set.toList . Data.Set.difference ( Data.Set.fromList [2 .. upperBound algorithm i]- ) . Data.Set.fromList . takeWhile (<= (upperBound algorithm i)) $ Math.Primes.primes algorithm+ ) . Data.Set.fromList . takeWhile (<= upperBound algorithm i) $ Math.Primes.primes algorithm - prop_consistency :: Math.Implementations.Primes.Algorithm -> Math.Implementations.Primes.Algorithm -> Int -> Test.QuickCheck.Property+ prop_consistency :: Math.Implementations.Primes.Algorithm.Algorithm -> Math.Implementations.Primes.Algorithm.Algorithm -> Int -> Test.QuickCheck.Property prop_consistency l r i = l /= r ==> Test.QuickCheck.label "prop_consistency" . and . take (i `mod` 4096) $ zipWith (==) (Math.Primes.primes l) (Math.Primes.primes r :: [Int])++ prop_rewriteRule :: Data.PrimeWheel.NPrimes -> Int -> Test.QuickCheck.Property+ prop_rewriteRule wheelSize i = Test.QuickCheck.label "prop_rewriteRule" $ toInteger (Math.Primes.primes (Math.Implementations.Primes.Algorithm.SieveOfEratosthenes wheelSize') !! index :: Int) == (Math.Primes.primes (Math.Implementations.Primes.Algorithm.SieveOfEratosthenes wheelSize') !! index :: Integer) where+ wheelSize' = wheelSize `mod` 8+ index = i `mod` 131072++ prop_sieveOfAtkin, prop_sieveOfAtkinRewrite :: Int -> Test.QuickCheck.Property+ prop_sieveOfAtkin i = Test.QuickCheck.label "prop_sieveOfAtkin" $ Math.Primes.primes (Math.Implementations.Primes.Algorithm.SieveOfAtkin prime) !! index == prime where+ index = i `mod` 131072++ prime :: Integer+ prime = Math.Primes.primes defaultAlgorithm !! index++ prop_sieveOfAtkinRewrite i = Test.QuickCheck.label "prop_sieveOfAtkin'" $ Math.Primes.primes (Math.Implementations.Primes.Algorithm.SieveOfAtkin $ fromIntegral prime) !! index == prime where+ index = i `mod` 131072++ prime :: Int+ prime = Math.Primes.primes defaultAlgorithm !! index
src/Factory/Test/QuickCheck/Probability.hs view
@@ -45,7 +45,7 @@ ) where prop_normalDistribution :: System.Random.RandomGen g => g -> (Double, Double) -> Test.QuickCheck.Property prop_normalDistribution randomGen (mean, variance) = variance' /= 0 ==> Test.QuickCheck.label "prop_normalDistribution" . Pair.both . Pair.mirror (- (< (0.05 :: Double)) . abs --Tolerance.+ (< (0.1 :: Double)) . abs --Generous tolerance. ) . ( Math.Statistics.getMean &&& pred . Math.Statistics.getStandardDeviation ) . map (
src/Factory/Test/QuickCheck/QuickChecks.hs view
@@ -30,6 +30,7 @@ import qualified Factory.Test.QuickCheck.Hyperoperation import qualified Factory.Test.QuickCheck.Interval import qualified Factory.Test.QuickCheck.MonicPolynomial+import qualified Factory.Test.QuickCheck.PerfectPower import qualified Factory.Test.QuickCheck.Pi import qualified Factory.Test.QuickCheck.Polynomial import qualified Factory.Test.QuickCheck.Power@@ -49,6 +50,7 @@ >> putStrLn "Hyperoperation" >> Factory.Test.QuickCheck.Hyperoperation.quickChecks >> putStrLn "Interval" >> Factory.Test.QuickCheck.Interval.quickChecks >> putStrLn "MonicPolynomial" >> Factory.Test.QuickCheck.MonicPolynomial.quickChecks+ >> putStrLn "PerfectPower" >> Factory.Test.QuickCheck.PerfectPower.quickChecks >> putStrLn "Pi" >> Factory.Test.QuickCheck.Pi.quickChecks >> putStrLn "Polynomial" >> Factory.Test.QuickCheck.Polynomial.quickChecks >> putStrLn "Power" >> Factory.Test.QuickCheck.Power.quickChecks
src/Factory/Test/QuickCheck/Radix.hs view
@@ -42,5 +42,5 @@ base = (b `mod` 73) - 36 prop_digitalRoot (_, n) = Test.QuickCheck.label "prop_digitalRoot" $ Math.Radix.digitalRoot n' == 9 where- n' = 9 * (1 + abs n)+ n' = 9 * succ (abs n)
src/Factory/Test/QuickCheck/SquareRoot.hs view
@@ -61,7 +61,7 @@ prop_accuracy, prop_factorable, prop_perfectSquare :: Testable prop_accuracy (algorithm, decimalDigits, operand) = Test.QuickCheck.label "prop_accuracy" . (>= requiredDecimalDigits) . Math.SquareRoot.getAccuracy operand' $ Math.SquareRoot.squareRoot algorithm requiredDecimalDigits operand' where requiredDecimalDigits :: Math.Precision.DecimalDigits- requiredDecimalDigits = 1 + (decimalDigits `mod` 1024)+ requiredDecimalDigits = succ $ decimalDigits `mod` 1024 operand' :: Data.Ratio.Rational operand' = abs operand@@ -76,14 +76,14 @@ ) ) / Math.SquareRoot.squareRoot algorithm requiredDecimalDigits operand' where requiredDecimalDigits :: Math.Precision.DecimalDigits- requiredDecimalDigits = 1 + (decimalDigits `mod` 1024)+ requiredDecimalDigits = succ $ decimalDigits `mod` 1024 operand' :: Data.Ratio.Rational- operand' = 1 + abs operand+ operand' = succ $ abs operand prop_perfectSquare (algorithm, decimalDigits, operand) = Test.QuickCheck.label "prop_perfectSquare" . Math.SquareRoot.isPrecise perfectSquare $ Math.SquareRoot.squareRoot algorithm requiredDecimalDigits perfectSquare where requiredDecimalDigits :: Math.Precision.DecimalDigits- requiredDecimalDigits = 1 + (decimalDigits `mod` 32768)+ requiredDecimalDigits = succ $ decimalDigits `mod` 32768 operand', perfectSquare :: Data.Ratio.Rational operand' = (abs (Data.Ratio.numerator operand) `min` (2 ^ (32 :: Int))) % (abs (Data.Ratio.denominator operand) `min` (2 ^ (32 :: Int))) --Avoid floating-point rounding-errors in 'Math.SquareRoot.rSqrt'.
src/Factory/Test/QuickCheck/Statistics.hs view
@@ -47,10 +47,10 @@ prop_nC0 algorithm n = Test.QuickCheck.label "prop_nC0" $ Math.Statistics.nCr algorithm (abs n) 0 == 1 prop_nC1 algorithm i = Test.QuickCheck.label "prop_nC1" $ Math.Statistics.nCr algorithm n 1 == n where- n = 1 + abs i+ n = succ $ abs i prop_sum algorithm i = Test.QuickCheck.label "prop_sum" $ sum (Math.Statistics.nCr algorithm n `map` [0 .. n]) == 2 ^ n where- n = 1 + abs i+ n = succ $ abs i prop_symmetry, prop_prime :: Math.Implementations.Factorial.Algorithm -> (Integer, Integer) -> Test.QuickCheck.Property prop_symmetry algorithm (i, j) = Test.QuickCheck.label "prop_symmetry" $ Math.Statistics.nCr algorithm n r == Math.Statistics.nCr algorithm n (n - r) where@@ -64,7 +64,7 @@ prop_nP0 n = Test.QuickCheck.label "prop_nP0" $ Math.Statistics.nPr (abs n) 0 == 1 prop_nP1 i = Test.QuickCheck.label "prop_nP1" $ Math.Statistics.nPr n 1 == n where- n = 1 + abs i+ n = succ $ abs i prop_zeroVariance, prop_zeroAverageAbsoluteDeviation :: Data.Ratio.Rational -> Test.QuickCheck.Property prop_zeroVariance x = Test.QuickCheck.label "prop_zeroVariance" $ Math.Statistics.getVariance (replicate 32 x) == (0 :: Data.Ratio.Rational)
src/Main.hs view
@@ -25,7 +25,8 @@ -} module Main(--- * Type-classes+-- * Types+-- ** Type-synonyms -- CommandLineAction, -- * Functions main@@ -33,6 +34,7 @@ import qualified Data.List import qualified Data.Ratio+import qualified Data.Version import qualified Distribution.Package import qualified Distribution.Text import qualified Distribution.Version@@ -40,7 +42,7 @@ import qualified Factory.Math.Implementations.Factorial as Math.Implementations.Factorial import qualified Factory.Math.Implementations.Primality as Math.Implementations.Primality import qualified Factory.Math.Implementations.PrimeFactorisation as Math.Implementations.PrimeFactorisation-import qualified Factory.Math.Implementations.Primes as Math.Implementations.Primes+import qualified Factory.Math.Implementations.Primes.Algorithm as Math.Implementations.Primes.Algorithm import qualified Factory.Math.Implementations.SquareRoot as Math.Implementations.SquareRoot import qualified Factory.Test.CommandOptions as Test.CommandOptions import qualified Factory.Test.Performance.Factorial as Test.Performance.Factorial@@ -52,6 +54,7 @@ import qualified Factory.Test.Performance.SquareRoot as Test.Performance.SquareRoot import qualified Factory.Test.Performance.Statistics as Test.Performance.Statistics import qualified Factory.Test.QuickCheck.QuickChecks as Test.QuickCheck.QuickChecks+import qualified Paths_factory as Paths --Either local stub, or package-instance autogenerated by 'Setup.hs build'. import qualified System import qualified System.Console.GetOpt as G import qualified System.IO@@ -93,7 +96,7 @@ G.Option "" ["piPerformanceGraph"] (piPerformanceGraph `G.ReqArg` "(Math.Pi.Category, Double, Math.Precision.DecimalDigits)") "Test the performance of 'Math.Pi.openI', with an exponential precision-requirement (of the specified exponent), up to the specified limit.", G.Option "" ["primeFactorsPerformance"] (primeFactorsPerformance `G.ReqArg` "(Math.Implementations.PrimeFactorisation.Algorithm, Integer)") "Test the performance of 'Math.PrimeFactorisation.primeFactors'.", G.Option "" ["primeFactorsPerformanceGraph"] (primeFactorsPerformanceGraph `G.ReqArg` "(Math.Implementations.PrimeFactorisation.Algorithm, Int)") "Test the performance of 'Math.PrimeFactorisation.primeFactors', on the specified number of odd integers from the Fibonacci-sequence.",- G.Option "" ["primesPerformance"] (primesPerformance `G.ReqArg` "(Math.Implementations.Primes.Algorithm, Int)") "Test the performance of 'Math.Primes.primes'.",+ G.Option "" ["primesPerformance"] (primesPerformance `G.ReqArg` "(Math.Implementations.Primes.Algorithm.Algorithm, Int)") "Test the performance of 'Math.Primes.primes'.", G.Option "" ["squareRootPerformance"] (squareRootPerformance `G.ReqArg` "(Math.Implementations.SquareRoot.Algorithm, Data.Ratio.Rational, DecimalDigits)") "Test the performance of 'Math.SquareRoot.squareRoot'.", G.Option "" ["squareRootPerformanceGraph"] (squareRootPerformanceGraph `G.ReqArg` "(Math.Implementations.SquareRoot.Algorithm, Data.Ratio.Rational)") "Test the performance of 'Math.SquareRoot.squareRoot', with an exponentially increasing precision-requirement.", G.Option "" ["verbose"] (G.NoArg $ return {-to IO-monad-} . Test.CommandOptions.setVerbose) ("Provide additional information where available; default '" ++ show (Test.CommandOptions.verbose Defaultable.defaultValue) ++ "'."),@@ -106,7 +109,7 @@ packageIdentifier :: Distribution.Package.PackageIdentifier packageIdentifier = Distribution.Package.PackageIdentifier { Distribution.Package.pkgName = Distribution.Package.PackageName "factory",- Distribution.Package.pkgVersion = Distribution.Version.Version [0, 1, 0, 3] []+ Distribution.Package.pkgVersion = Distribution.Version.Version (Data.Version.versionBranch Paths.version) [] } printUsage = System.IO.hPutStrLn System.IO.stderr usage >> System.exitWith System.ExitSuccess@@ -181,15 +184,16 @@ CAVEAT: fragile. -} case algorithm of- Math.Implementations.Primes.SieveOfEratosthenes n -> Test.Performance.Primes.primesPerformance $ Math.Implementations.Primes.SieveOfEratosthenes n- _ -> Test.Performance.Primes.primesPerformance algorithm+ Math.Implementations.Primes.Algorithm.SieveOfEratosthenes wheelSize -> Test.Performance.Primes.primesPerformance $ Math.Implementations.Primes.Algorithm.SieveOfEratosthenes wheelSize+ Math.Implementations.Primes.Algorithm.SieveOfAtkin maxPrime -> Test.Performance.Primes.primesPerformance $ Math.Implementations.Primes.Algorithm.SieveOfAtkin maxPrime+ _ -> Test.Performance.Primes.primesPerformance algorithm ) index :: IO ( Double, -- Integer- Int --Exploits rewrite-rule in "Math.Implementations.Primes".+ Int --Exploits rewrite-rules in "Math.Implementations.Primes.*". ) ) >>= print >> System.exitWith System.ExitSuccess where- algorithm :: Math.Implementations.Primes.Algorithm+ algorithm :: Math.Implementations.Primes.Algorithm.Algorithm (algorithm, index) = read arg squareRootPerformance arg _ = Test.Performance.SquareRoot.squareRootPerformance algorithm operand decimalDigits >>= print >> System.exitWith System.ExitSuccess where