packages feed

arithmoi 0.7.0.0 → 0.8.0.0

raw patch · 100 files changed

+4687/−2679 lines, 100 filesdep +deepseqdep −mtldep −natsdep ~QuickCheckdep ~basedep ~smallcheckPVP ok

version bump matches the API change (PVP)

Dependencies added: deepseq

Dependencies removed: mtl, nats

Dependency ranges changed: QuickCheck, base, smallcheck, tasty, transformers

API changes (from Hackage documentation)

- Math.NumberTheory.ArithmeticFunctions.Moebius: instance Data.Semigroup.Semigroup Math.NumberTheory.ArithmeticFunctions.Moebius.Moebius
- Math.NumberTheory.GCD: splitIntoCoprimes :: (Integral a, Eq b, Num b) => [(a, b)] -> [(a, b)]
- Math.NumberTheory.GaussianIntegers: (.^) :: (Integral a) => GaussianInteger -> a -> GaussianInteger
- Math.NumberTheory.GaussianIntegers: (:+) :: !Integer -> !Integer -> GaussianInteger
- Math.NumberTheory.GaussianIntegers: [imag] :: GaussianInteger -> !Integer
- Math.NumberTheory.GaussianIntegers: [real] :: GaussianInteger -> !Integer
- Math.NumberTheory.GaussianIntegers: conjugate :: GaussianInteger -> GaussianInteger
- Math.NumberTheory.GaussianIntegers: data GaussianInteger
- Math.NumberTheory.GaussianIntegers: divG :: GaussianInteger -> GaussianInteger -> GaussianInteger
- Math.NumberTheory.GaussianIntegers: divModG :: GaussianInteger -> GaussianInteger -> (GaussianInteger, GaussianInteger)
- Math.NumberTheory.GaussianIntegers: factorise :: GaussianInteger -> [(GaussianInteger, Int)]
- Math.NumberTheory.GaussianIntegers: findPrime :: Integer -> GaussianInteger
- Math.NumberTheory.GaussianIntegers: findPrime' :: Integer -> GaussianInteger
- Math.NumberTheory.GaussianIntegers: gcdG :: GaussianInteger -> GaussianInteger -> GaussianInteger
- Math.NumberTheory.GaussianIntegers: gcdG' :: GaussianInteger -> GaussianInteger -> GaussianInteger
- Math.NumberTheory.GaussianIntegers: infixr 8 .^
- Math.NumberTheory.GaussianIntegers: instance GHC.Classes.Eq Math.NumberTheory.GaussianIntegers.GaussianInteger
- Math.NumberTheory.GaussianIntegers: instance GHC.Num.Num Math.NumberTheory.GaussianIntegers.GaussianInteger
- Math.NumberTheory.GaussianIntegers: instance GHC.Show.Show Math.NumberTheory.GaussianIntegers.GaussianInteger
- Math.NumberTheory.GaussianIntegers: isPrime :: GaussianInteger -> Bool
- Math.NumberTheory.GaussianIntegers: modG :: GaussianInteger -> GaussianInteger -> GaussianInteger
- Math.NumberTheory.GaussianIntegers: norm :: GaussianInteger -> Integer
- Math.NumberTheory.GaussianIntegers: primes :: [GaussianInteger]
- Math.NumberTheory.GaussianIntegers: quotG :: GaussianInteger -> GaussianInteger -> GaussianInteger
- Math.NumberTheory.GaussianIntegers: quotRemG :: GaussianInteger -> GaussianInteger -> (GaussianInteger, GaussianInteger)
- Math.NumberTheory.GaussianIntegers: remG :: GaussianInteger -> GaussianInteger -> GaussianInteger
- Math.NumberTheory.GaussianIntegers: ι :: GaussianInteger
- Math.NumberTheory.Moduli.Jacobi: instance Data.Semigroup.Semigroup Math.NumberTheory.Moduli.Jacobi.JacobiSymbol
- Math.NumberTheory.Powers.Squares.Internal: isqrtA :: Integral a => a -> a
- Math.NumberTheory.Powers.Squares.Internal: karatsubaSqrt :: Integer -> (Integer, Integer)
- Math.NumberTheory.Prefactored: instance (GHC.Real.Integral a, Math.NumberTheory.UniqueFactorisation.UniqueFactorisation a) => GHC.Num.Num (Math.NumberTheory.Prefactored.Prefactored a)
- Math.NumberTheory.Prefactored: instance Math.NumberTheory.UniqueFactorisation.UniqueFactorisation a => Math.NumberTheory.UniqueFactorisation.UniqueFactorisation (Math.NumberTheory.Prefactored.Prefactored a)
- Math.NumberTheory.Primes.Factorisation: carmichaelSieve :: Integer -> CarmichaelSieve
- Math.NumberTheory.Primes.Factorisation: data CarmichaelSieve
- Math.NumberTheory.Primes.Factorisation: data FactorSieve
- Math.NumberTheory.Primes.Factorisation: data TotientSieve
- Math.NumberTheory.Primes.Factorisation: factorSieve :: Integer -> FactorSieve
- Math.NumberTheory.Primes.Factorisation: sieveCarmichael :: CarmichaelSieve -> Integer -> Integer
- Math.NumberTheory.Primes.Factorisation: sieveFactor :: FactorSieve -> Integer -> [(Integer, Int)]
- Math.NumberTheory.Primes.Factorisation: sieveTotient :: TotientSieve -> Integer -> Integer
- Math.NumberTheory.Primes.Factorisation: totientSieve :: Integer -> TotientSieve
- Math.NumberTheory.Primes.Heap: primes :: Integral a => [a]
- Math.NumberTheory.Primes.Heap: sieveFrom :: Integral a => a -> [a]
- Math.NumberTheory.Primes.Testing: data FactorSieve
- Math.NumberTheory.Primes.Testing: fsIsPrime :: FactorSieve -> Integer -> Bool
- Math.NumberTheory.UniqueFactorisation: instance Math.NumberTheory.UniqueFactorisation.UniqueFactorisation Math.NumberTheory.GaussianIntegers.GaussianInteger
- Math.NumberTheory.Zeta: approximateValue :: Floating a => ExactPi -> a
- Math.NumberTheory.Zeta: zetas :: (Floating a, Ord a) => a -> [a]
- Math.NumberTheory.Zeta: zetasEven :: [ExactPi]
+ Math.NumberTheory.ArithmeticFunctions: ramanujan :: Integer -> Integer
+ Math.NumberTheory.ArithmeticFunctions: ramanujanA :: ArithmeticFunction Integer Integer
+ Math.NumberTheory.ArithmeticFunctions.Moebius: instance GHC.Base.Semigroup Math.NumberTheory.ArithmeticFunctions.Moebius.Moebius
+ Math.NumberTheory.Euclidean: WrappedIntegral :: a -> WrappedIntegral a
+ Math.NumberTheory.Euclidean: [unWrappedIntegral] :: WrappedIntegral a -> a
+ Math.NumberTheory.Euclidean: class (Eq a, Num a) => Euclidean a
+ Math.NumberTheory.Euclidean: coprime :: Euclidean a => a -> a -> Bool
+ Math.NumberTheory.Euclidean: div :: Euclidean a => a -> a -> a
+ Math.NumberTheory.Euclidean: divMod :: Euclidean a => a -> a -> (a, a)
+ Math.NumberTheory.Euclidean: extendedGCD :: Euclidean a => a -> a -> (a, a, a)
+ Math.NumberTheory.Euclidean: gcd :: Euclidean a => a -> a -> a
+ Math.NumberTheory.Euclidean: instance GHC.Classes.Eq a => GHC.Classes.Eq (Math.NumberTheory.Euclidean.WrappedIntegral a)
+ Math.NumberTheory.Euclidean: instance GHC.Classes.Ord a => GHC.Classes.Ord (Math.NumberTheory.Euclidean.WrappedIntegral a)
+ Math.NumberTheory.Euclidean: instance GHC.Enum.Enum a => GHC.Enum.Enum (Math.NumberTheory.Euclidean.WrappedIntegral a)
+ Math.NumberTheory.Euclidean: instance GHC.Num.Num a => GHC.Num.Num (Math.NumberTheory.Euclidean.WrappedIntegral a)
+ Math.NumberTheory.Euclidean: instance GHC.Real.Integral a => GHC.Real.Integral (Math.NumberTheory.Euclidean.WrappedIntegral a)
+ Math.NumberTheory.Euclidean: instance GHC.Real.Integral a => Math.NumberTheory.Euclidean.Euclidean (Math.NumberTheory.Euclidean.WrappedIntegral a)
+ Math.NumberTheory.Euclidean: instance GHC.Real.Real a => GHC.Real.Real (Math.NumberTheory.Euclidean.WrappedIntegral a)
+ Math.NumberTheory.Euclidean: instance GHC.Show.Show a => GHC.Show.Show (Math.NumberTheory.Euclidean.WrappedIntegral a)
+ Math.NumberTheory.Euclidean: instance Math.NumberTheory.Euclidean.Euclidean GHC.Integer.Type.Integer
+ Math.NumberTheory.Euclidean: instance Math.NumberTheory.Euclidean.Euclidean GHC.Natural.Natural
+ Math.NumberTheory.Euclidean: instance Math.NumberTheory.Euclidean.Euclidean GHC.Types.Int
+ Math.NumberTheory.Euclidean: instance Math.NumberTheory.Euclidean.Euclidean GHC.Types.Word
+ Math.NumberTheory.Euclidean: lcm :: Euclidean a => a -> a -> a
+ Math.NumberTheory.Euclidean: mod :: Euclidean a => a -> a -> a
+ Math.NumberTheory.Euclidean: newtype WrappedIntegral a
+ Math.NumberTheory.Euclidean: quot :: Euclidean a => a -> a -> a
+ Math.NumberTheory.Euclidean: quotRem :: Euclidean a => a -> a -> (a, a)
+ Math.NumberTheory.Euclidean: rem :: Euclidean a => a -> a -> a
+ Math.NumberTheory.Euclidean.Coprimes: data Coprimes a b
+ Math.NumberTheory.Euclidean.Coprimes: insert :: (Euclidean a, Eq b, Num b) => a -> b -> Coprimes a b -> Coprimes a b
+ Math.NumberTheory.Euclidean.Coprimes: instance (GHC.Classes.Eq a, GHC.Classes.Eq b) => GHC.Classes.Eq (Math.NumberTheory.Euclidean.Coprimes.Coprimes a b)
+ Math.NumberTheory.Euclidean.Coprimes: instance (GHC.Show.Show a, GHC.Show.Show b) => GHC.Show.Show (Math.NumberTheory.Euclidean.Coprimes.Coprimes a b)
+ Math.NumberTheory.Euclidean.Coprimes: instance (Math.NumberTheory.Euclidean.Euclidean a, GHC.Classes.Eq b, GHC.Num.Num b) => GHC.Base.Monoid (Math.NumberTheory.Euclidean.Coprimes.Coprimes a b)
+ Math.NumberTheory.Euclidean.Coprimes: instance (Math.NumberTheory.Euclidean.Euclidean a, GHC.Classes.Eq b, GHC.Num.Num b) => GHC.Base.Semigroup (Math.NumberTheory.Euclidean.Coprimes.Coprimes a b)
+ Math.NumberTheory.Euclidean.Coprimes: singleton :: (Eq a, Num a, Eq b, Num b) => a -> b -> Coprimes a b
+ Math.NumberTheory.Euclidean.Coprimes: splitIntoCoprimes :: (Euclidean a, Eq b, Num b) => [(a, b)] -> Coprimes a b
+ Math.NumberTheory.Euclidean.Coprimes: unCoprimes :: Coprimes a b -> [(a, b)]
+ Math.NumberTheory.Moduli.Class: data MultMod m
+ Math.NumberTheory.Moduli.Class: instance GHC.Classes.Eq (Math.NumberTheory.Moduli.Class.MultMod m)
+ Math.NumberTheory.Moduli.Class: instance GHC.Classes.Ord (Math.NumberTheory.Moduli.Class.MultMod m)
+ Math.NumberTheory.Moduli.Class: instance GHC.TypeNats.KnownNat m => GHC.Base.Monoid (Math.NumberTheory.Moduli.Class.MultMod m)
+ Math.NumberTheory.Moduli.Class: instance GHC.TypeNats.KnownNat m => GHC.Base.Semigroup (Math.NumberTheory.Moduli.Class.MultMod m)
+ Math.NumberTheory.Moduli.Class: instance GHC.TypeNats.KnownNat m => GHC.Enum.Bounded (Math.NumberTheory.Moduli.Class.MultMod m)
+ Math.NumberTheory.Moduli.Class: instance GHC.TypeNats.KnownNat m => GHC.Show.Show (Math.NumberTheory.Moduli.Class.MultMod m)
+ Math.NumberTheory.Moduli.Class: invertGroup :: KnownNat m => MultMod m -> MultMod m
+ Math.NumberTheory.Moduli.Class: isMultElement :: KnownNat m => Mod m -> Maybe (MultMod m)
+ Math.NumberTheory.Moduli.Class: multElement :: MultMod m -> Mod m
+ Math.NumberTheory.Moduli.DiscreteLogarithm: discreteLogarithm :: KnownNat m => PrimitiveRoot m -> MultMod m -> Natural
+ Math.NumberTheory.Moduli.Equations: solveLinear :: KnownNat m => Mod m -> Mod m -> [Mod m]
+ Math.NumberTheory.Moduli.Equations: solveQuadratic :: KnownNat m => Mod m -> Mod m -> Mod m -> [Mod m]
+ Math.NumberTheory.Moduli.Jacobi: instance GHC.Base.Semigroup Math.NumberTheory.Moduli.Jacobi.JacobiSymbol
+ Math.NumberTheory.Moduli.PrimitiveRoot: data PrimitiveRoot m
+ Math.NumberTheory.Moduli.PrimitiveRoot: getGroup :: PrimitiveRoot m -> CyclicGroup Natural
+ Math.NumberTheory.Moduli.PrimitiveRoot: groupSize :: (Euclidean a, Ord a, UniqueFactorisation a) => CyclicGroup a -> Prefactored a
+ Math.NumberTheory.Moduli.PrimitiveRoot: instance Control.DeepSeq.NFData (Math.NumberTheory.Primes.Types.Prime a) => Control.DeepSeq.NFData (Math.NumberTheory.Moduli.PrimitiveRoot.CyclicGroup a)
+ Math.NumberTheory.Moduli.PrimitiveRoot: instance GHC.Classes.Eq (Math.NumberTheory.Moduli.PrimitiveRoot.PrimitiveRoot m)
+ Math.NumberTheory.Moduli.PrimitiveRoot: instance GHC.Classes.Eq (Math.NumberTheory.Primes.Types.Prime a) => GHC.Classes.Eq (Math.NumberTheory.Moduli.PrimitiveRoot.CyclicGroup a)
+ Math.NumberTheory.Moduli.PrimitiveRoot: instance GHC.Generics.Generic (Math.NumberTheory.Moduli.PrimitiveRoot.CyclicGroup a)
+ Math.NumberTheory.Moduli.PrimitiveRoot: instance GHC.TypeNats.KnownNat m => GHC.Show.Show (Math.NumberTheory.Moduli.PrimitiveRoot.PrimitiveRoot m)
+ Math.NumberTheory.Moduli.PrimitiveRoot: unPrimitiveRoot :: PrimitiveRoot m -> MultMod m
+ Math.NumberTheory.Moduli.Sqrt: sqrtsMod :: KnownNat m => Mod m -> [Mod m]
+ Math.NumberTheory.Moduli.Sqrt: sqrtsModFactorisation :: Integer -> [(Prime Integer, Word)] -> [Integer]
+ Math.NumberTheory.Moduli.Sqrt: sqrtsModPrime :: Integer -> Prime Integer -> [Integer]
+ Math.NumberTheory.Moduli.Sqrt: sqrtsModPrimePower :: Integer -> Prime Integer -> Word -> [Integer]
+ Math.NumberTheory.Prefactored: instance (GHC.Classes.Eq a, GHC.Num.Num a, Math.NumberTheory.UniqueFactorisation.UniqueFactorisation a) => Math.NumberTheory.UniqueFactorisation.UniqueFactorisation (Math.NumberTheory.Prefactored.Prefactored a)
+ Math.NumberTheory.Prefactored: instance (Math.NumberTheory.Euclidean.Euclidean a, GHC.Classes.Ord a) => GHC.Num.Num (Math.NumberTheory.Prefactored.Prefactored a)
+ Math.NumberTheory.Quadratic.EisensteinIntegers: (:+) :: !Integer -> !Integer -> EisensteinInteger
+ Math.NumberTheory.Quadratic.EisensteinIntegers: [imag] :: EisensteinInteger -> !Integer
+ Math.NumberTheory.Quadratic.EisensteinIntegers: [real] :: EisensteinInteger -> !Integer
+ Math.NumberTheory.Quadratic.EisensteinIntegers: associates :: EisensteinInteger -> [EisensteinInteger]
+ Math.NumberTheory.Quadratic.EisensteinIntegers: conjugate :: EisensteinInteger -> EisensteinInteger
+ Math.NumberTheory.Quadratic.EisensteinIntegers: data EisensteinInteger
+ Math.NumberTheory.Quadratic.EisensteinIntegers: divideByThree :: EisensteinInteger -> (Int, EisensteinInteger)
+ Math.NumberTheory.Quadratic.EisensteinIntegers: factorise :: EisensteinInteger -> [(EisensteinInteger, Int)]
+ Math.NumberTheory.Quadratic.EisensteinIntegers: findPrime :: Integer -> EisensteinInteger
+ Math.NumberTheory.Quadratic.EisensteinIntegers: ids :: [EisensteinInteger]
+ Math.NumberTheory.Quadratic.EisensteinIntegers: instance GHC.Classes.Eq Math.NumberTheory.Quadratic.EisensteinIntegers.EisensteinInteger
+ Math.NumberTheory.Quadratic.EisensteinIntegers: instance GHC.Classes.Ord Math.NumberTheory.Quadratic.EisensteinIntegers.EisensteinInteger
+ Math.NumberTheory.Quadratic.EisensteinIntegers: instance GHC.Generics.Generic Math.NumberTheory.Quadratic.EisensteinIntegers.EisensteinInteger
+ Math.NumberTheory.Quadratic.EisensteinIntegers: instance GHC.Num.Num Math.NumberTheory.Quadratic.EisensteinIntegers.EisensteinInteger
+ Math.NumberTheory.Quadratic.EisensteinIntegers: instance GHC.Show.Show Math.NumberTheory.Quadratic.EisensteinIntegers.EisensteinInteger
+ Math.NumberTheory.Quadratic.EisensteinIntegers: instance Math.NumberTheory.Euclidean.Euclidean Math.NumberTheory.Quadratic.EisensteinIntegers.EisensteinInteger
+ Math.NumberTheory.Quadratic.EisensteinIntegers: isPrime :: EisensteinInteger -> Bool
+ Math.NumberTheory.Quadratic.EisensteinIntegers: norm :: EisensteinInteger -> Integer
+ Math.NumberTheory.Quadratic.EisensteinIntegers: primes :: [EisensteinInteger]
+ Math.NumberTheory.Quadratic.EisensteinIntegers: ω :: EisensteinInteger
+ Math.NumberTheory.Quadratic.GaussianIntegers: (.^) :: (Integral a) => GaussianInteger -> a -> GaussianInteger
+ Math.NumberTheory.Quadratic.GaussianIntegers: (:+) :: !Integer -> !Integer -> GaussianInteger
+ Math.NumberTheory.Quadratic.GaussianIntegers: [imag] :: GaussianInteger -> !Integer
+ Math.NumberTheory.Quadratic.GaussianIntegers: [real] :: GaussianInteger -> !Integer
+ Math.NumberTheory.Quadratic.GaussianIntegers: conjugate :: GaussianInteger -> GaussianInteger
+ Math.NumberTheory.Quadratic.GaussianIntegers: data GaussianInteger
+ Math.NumberTheory.Quadratic.GaussianIntegers: factorise :: GaussianInteger -> [(GaussianInteger, Int)]
+ Math.NumberTheory.Quadratic.GaussianIntegers: findPrime :: Integer -> GaussianInteger
+ Math.NumberTheory.Quadratic.GaussianIntegers: findPrime' :: Integer -> GaussianInteger
+ Math.NumberTheory.Quadratic.GaussianIntegers: gcdG :: GaussianInteger -> GaussianInteger -> GaussianInteger
+ Math.NumberTheory.Quadratic.GaussianIntegers: gcdG' :: GaussianInteger -> GaussianInteger -> GaussianInteger
+ Math.NumberTheory.Quadratic.GaussianIntegers: infixr 8 .^
+ Math.NumberTheory.Quadratic.GaussianIntegers: instance Control.DeepSeq.NFData Math.NumberTheory.Quadratic.GaussianIntegers.GaussianInteger
+ Math.NumberTheory.Quadratic.GaussianIntegers: instance GHC.Classes.Eq Math.NumberTheory.Quadratic.GaussianIntegers.GaussianInteger
+ Math.NumberTheory.Quadratic.GaussianIntegers: instance GHC.Classes.Ord Math.NumberTheory.Quadratic.GaussianIntegers.GaussianInteger
+ Math.NumberTheory.Quadratic.GaussianIntegers: instance GHC.Generics.Generic Math.NumberTheory.Quadratic.GaussianIntegers.GaussianInteger
+ Math.NumberTheory.Quadratic.GaussianIntegers: instance GHC.Num.Num Math.NumberTheory.Quadratic.GaussianIntegers.GaussianInteger
+ Math.NumberTheory.Quadratic.GaussianIntegers: instance GHC.Show.Show Math.NumberTheory.Quadratic.GaussianIntegers.GaussianInteger
+ Math.NumberTheory.Quadratic.GaussianIntegers: instance Math.NumberTheory.Euclidean.Euclidean Math.NumberTheory.Quadratic.GaussianIntegers.GaussianInteger
+ Math.NumberTheory.Quadratic.GaussianIntegers: isPrime :: GaussianInteger -> Bool
+ Math.NumberTheory.Quadratic.GaussianIntegers: norm :: GaussianInteger -> Integer
+ Math.NumberTheory.Quadratic.GaussianIntegers: primes :: [GaussianInteger]
+ Math.NumberTheory.Quadratic.GaussianIntegers: ι :: GaussianInteger
+ Math.NumberTheory.Recurrencies: partition :: Num a => [a]
+ Math.NumberTheory.Recurrencies.Bilinear: euler :: forall a. Integral a => [a]
+ Math.NumberTheory.Recurrencies.Bilinear: eulerPolyAt1 :: forall a. Integral a => [Ratio a]
+ Math.NumberTheory.SmoothNumbers: instance GHC.Classes.Eq a => GHC.Classes.Eq (Math.NumberTheory.SmoothNumbers.SmoothBasis a)
+ Math.NumberTheory.UniqueFactorisation: instance GHC.Classes.Eq Math.NumberTheory.UniqueFactorisation.EisensteinPrime
+ Math.NumberTheory.UniqueFactorisation: instance GHC.Show.Show Math.NumberTheory.UniqueFactorisation.EisensteinPrime
+ Math.NumberTheory.UniqueFactorisation: instance Math.NumberTheory.UniqueFactorisation.UniqueFactorisation Math.NumberTheory.Quadratic.EisensteinIntegers.EisensteinInteger
+ Math.NumberTheory.UniqueFactorisation: instance Math.NumberTheory.UniqueFactorisation.UniqueFactorisation Math.NumberTheory.Quadratic.GaussianIntegers.GaussianInteger
+ Math.NumberTheory.Zeta: intertwine :: [a] -> [a] -> [a]
+ Math.NumberTheory.Zeta: skipEvens :: [a] -> [a]
+ Math.NumberTheory.Zeta: skipOdds :: [a] -> [a]
+ Math.NumberTheory.Zeta: suminf :: (Floating a, Ord a) => a -> [a] -> a
+ Math.NumberTheory.Zeta.Dirichlet: betas :: (Floating a, Ord a) => a -> [a]
+ Math.NumberTheory.Zeta.Dirichlet: betasEven :: forall a. (Floating a, Ord a) => a -> [a]
+ Math.NumberTheory.Zeta.Dirichlet: betasOdd :: [ExactPi]
+ Math.NumberTheory.Zeta.Riemann: zetas :: (Floating a, Ord a) => a -> [a]
+ Math.NumberTheory.Zeta.Riemann: zetasEven :: [ExactPi]
+ Math.NumberTheory.Zeta.Riemann: zetasOdd :: forall a. (Floating a, Ord a) => a -> [a]
- Math.NumberTheory.ArithmeticFunctions.SieveBlock: SieveBlockConfig :: a -> (Word -> Word -> a) -> (a -> a -> a) -> SieveBlockConfig a
+ Math.NumberTheory.ArithmeticFunctions.SieveBlock: SieveBlockConfig :: a -> Word -> Word -> a -> a -> a -> a -> SieveBlockConfig a
- Math.NumberTheory.Moduli.Class: getNatVal :: KnownNat m => Mod m -> Natural
+ Math.NumberTheory.Moduli.Class: getNatVal :: Mod m -> Natural
- Math.NumberTheory.Moduli.Class: getVal :: KnownNat m => Mod m -> Integer
+ Math.NumberTheory.Moduli.Class: getVal :: Mod m -> Integer
- Math.NumberTheory.Moduli.PrimitiveRoot: cyclicGroupToModulo :: (Integral a, UniqueFactorisation a) => CyclicGroup a -> Prefactored a
+ Math.NumberTheory.Moduli.PrimitiveRoot: cyclicGroupToModulo :: (Euclidean a, Ord a, UniqueFactorisation a) => CyclicGroup a -> Prefactored a
- Math.NumberTheory.Moduli.PrimitiveRoot: isPrimitiveRoot :: KnownNat n => Mod n -> Bool
+ Math.NumberTheory.Moduli.PrimitiveRoot: isPrimitiveRoot :: KnownNat n => Mod n -> Maybe (PrimitiveRoot n)
- Math.NumberTheory.Prefactored: fromFactors :: Integral a => [(a, Word)] -> Prefactored a
+ Math.NumberTheory.Prefactored: fromFactors :: Num a => Coprimes a Word -> Prefactored a
- Math.NumberTheory.Prefactored: fromValue :: a -> Prefactored a
+ Math.NumberTheory.Prefactored: fromValue :: (Eq a, Num a) => a -> Prefactored a
- Math.NumberTheory.Primes.Sieve: primeList :: PrimeSieve -> [Integer]
+ Math.NumberTheory.Primes.Sieve: primeList :: forall a. Integral a => PrimeSieve -> [a]
- Math.NumberTheory.Primes.Sieve: primes :: [Integer]
+ Math.NumberTheory.Primes.Sieve: primes :: (Ord a, Num a) => [a]
- Math.NumberTheory.SmoothNumbers: fromList :: Integral a => [a] -> Maybe (SmoothBasis a)
+ Math.NumberTheory.SmoothNumbers: fromList :: Euclidean a => [a] -> Maybe (SmoothBasis a)
- Math.NumberTheory.SmoothNumbers: fromSet :: Integral a => Set a -> Maybe (SmoothBasis a)
+ Math.NumberTheory.SmoothNumbers: fromSet :: Euclidean a => Set a -> Maybe (SmoothBasis a)
- Math.NumberTheory.SmoothNumbers: smoothOverInRange :: Integral a => SmoothBasis a -> a -> a -> [a]
+ Math.NumberTheory.SmoothNumbers: smoothOverInRange :: forall a. Integral a => SmoothBasis a -> a -> a -> [a]
- Math.NumberTheory.SmoothNumbers: smoothOverInRangeBF :: Integral a => SmoothBasis a -> a -> a -> [a]
+ Math.NumberTheory.SmoothNumbers: smoothOverInRangeBF :: forall a. Integral a => SmoothBasis a -> a -> a -> [a]
- Math.NumberTheory.UniqueFactorisation: isPrime :: UniqueFactorisation a => a -> Maybe (Prime a)
+ Math.NumberTheory.UniqueFactorisation: isPrime :: (UniqueFactorisation a, Eq a, Num a) => a -> Maybe (Prime a)

Files

Changes view
@@ -1,3 +1,64 @@+0.8.0.0+    This release supports GHC 7.10, 8.0, 8.2, 8.4 and 8.6.++    Breaking changes:++        Stop reporting units (1, -1, i, -i) as a part of factorisation+        for integers and Gaussian integers (#101). Now `factorise (-2)`+        is `[(2, 1)]` and not `[(-1, 1), (2, 1)]`.++        Deprecate an old interface of 'Math.NumberTheory.Moduli.Sqrt'+        and roll out a new one, more robust and type safe (#87).++        Deprecate 'Math.NumberTheory.GCD' and 'Math.NumberTheory.GCD.LowLevel' (#80).+        Use 'Math.NumberTheory.Euclidean' instead (#128).+        Move 'splitIntoCoprimes' to 'Math.NumberTheory.Euclidean.Coprimes'.++        Change types of 'splitIntoCoprimes', 'fromFactors' and 'prefFactors'+        using newtype 'Coprimes' (#89).++        Redesign API to modular square roots (#108)++        Deprecate 'jacobi'' (#103).++        Sort Gaussian primes by norm (#124).++        Deprecate 'Math.NumberTheory.GaussianIntegers' in favor of+        'Math.NumberTheory.Quadratic.GaussianIntegers'.++    New features:++        Implement Ramanujan tau function (#112):++        > map ramanujan [1..10]+        [1,-24,252,-1472,4830,-6048,-16744,84480,-113643,-115920]++        Implement partition function (#115):++        > take 10 partition+        [1,1,2,3,5,7,11,15,22,30]++        Add the Dirichlet beta function on non-negative integer arguments (#120).+        E. g.,++        > take 5 $ Math.NumberTheory.Zeta.Dirichlet.betas 1e-15+        [0.5,0.7853981633974483,0.9159655941772191,0.9689461462593693,0.9889445517411055]++        Solve linear and quadratic congruences (#129).++        Support Eisenstein integers (#121).++        Implement discrete logarithm (#88).++    Improvements:++        Make return type of 'primes' and 'primeList' polymorphic instead of+        being limited to 'Integer' only (#109).++        Speed up factorisation of Gaussian integers (#116).++        Speed up computation of primitive roots for prime powers (#127).+ 0.7.0.0     This release supports GHC 7.8, 7.10, 8.0, 8.2 and 8.4. 
Math/NumberTheory/ArithmeticFunctions/Class.hs view
@@ -25,11 +25,6 @@ import Data.Semigroup #endif -#if MIN_VERSION_base(4,8,0)-#else-import Data.Word-#endif- import Math.NumberTheory.UniqueFactorisation  -- | A typical arithmetic function operates on the canonical factorisation of
Math/NumberTheory/ArithmeticFunctions/Mertens.hs view
@@ -17,9 +17,6 @@   ) where  import qualified Data.Vector.Unboxed as U-#if __GLASGOW_HASKELL__ < 709-import Data.Word-#endif  import Math.NumberTheory.Powers.Cubes import Math.NumberTheory.Powers.Squares@@ -27,8 +24,8 @@  -- | Compute individual values of Mertens function in O(n^(2/3)) time and space. ----- > > map (mertens . (10 ^)) [0..9]--- > [1,-1,1,2,-23,-48,212,1037,1928,-222]+-- >>> map (mertens . (10 ^)) [0..9]+-- [1,-1,1,2,-23,-48,212,1037,1928,-222] -- -- The implementation follows Theorem 3.1 from <https://arxiv.org/pdf/1610.08551.pdf Computations of the Mertens function and improved bounds on the Mertens conjecture> by G. Hurst, excluding segmentation of sieves. mertens :: Word -> Int
Math/NumberTheory/ArithmeticFunctions/Moebius.hs view
@@ -126,8 +126,8 @@ -- -- Based on the sieving algorithm from p. 3 of <https://arxiv.org/pdf/1610.08551.pdf Computations of the Mertens function and improved bounds on the Mertens conjecture> by G. Hurst. It is approximately 5x faster than 'Math.NumberTheory.ArithmeticFunctions.SieveBlock.sieveBlockUnboxed'. ----- > > sieveBlockMoebius 1 10--- > [MoebiusP, MoebiusN, MoebiusN, MoebiusZ, MoebiusN, MoebiusP, MoebiusN, MoebiusZ, MoebiusZ, MoebiusP]+-- >>> sieveBlockMoebius 1 10+-- [MoebiusP, MoebiusN, MoebiusN, MoebiusZ, MoebiusN, MoebiusP, MoebiusN, MoebiusZ, MoebiusZ, MoebiusP] sieveBlockMoebius   :: Word   -> Word
Math/NumberTheory/ArithmeticFunctions/SieveBlock.hs view
@@ -32,9 +32,6 @@ import qualified Data.Vector as V import qualified Data.Vector.Mutable as MV import GHC.Exts-#if __GLASGOW_HASKELL__ < 709-import Data.Monoid-#endif  import Math.NumberTheory.ArithmeticFunctions.Class import Math.NumberTheory.ArithmeticFunctions.Moebius (sieveBlockMoebius)@@ -58,8 +55,8 @@ -- -- This is a thin wrapper over 'sieveBlock', read more details there. ----- > > runFunctionOverBlock carmichaelA 1 10--- > [1,1,2,2,4,2,6,2,6,4]+-- >>> runFunctionOverBlock carmichaelA 1 10+-- [1,1,2,2,4,2,6,2,6,4] runFunctionOverBlock   :: ArithmeticFunction Word a   -> Word@@ -82,8 +79,13 @@ -- -- For example, following code lists smallest prime factors: ----- > > sieveBlock (SieveBlockConfig maxBound min (\p _ -> p) 2 10)--- > [2,3,2,5,2,7,2,3,2,11]+-- >>> sieveBlock (SieveBlockConfig maxBound (\p _ -> p) min) 2 10+-- [2,3,2,5,2,7,2,3,2,11]+--+-- And this is how to factorise all numbers in a block:+--+-- >>> sieveBlock (SieveBlockConfig [] (\p k -> [(p,k)]) (++)) 2 10+-- [[(2,1)],[(3,1)],[(2,2)],[(5,1)],[(2,1),(3,1)],[(7,1)],[(2,3)],[(3,2)],[(2,1),(5,1)],[(11,1)]] sieveBlock   :: SieveBlockConfig a   -> Word
Math/NumberTheory/ArithmeticFunctions/SieveBlock/Unboxed.hs view
@@ -76,8 +76,8 @@ -- -- For example, here is an analogue of divisor function 'tau': ----- > > sieveBlockUnboxed (SieveBlockConfig 1 (*) (\_ a -> a + 1) 1 10)--- > [1,2,2,3,2,4,2,4,3,4]+-- >>> sieveBlockUnboxed (SieveBlockConfig 1 (\_ a -> a + 1) (*)) 1 10+-- [1,2,2,3,2,4,2,4,3,4] sieveBlockUnboxed   :: V.Unbox a   => SieveBlockConfig a
Math/NumberTheory/ArithmeticFunctions/Standard.hs view
@@ -26,6 +26,7 @@   , sigma, sigmaA   , totient, totientA   , jordan, jordanA+  , ramanujan, ramanujanA   , moebius, moebiusA, Moebius(..), runMoebius   , liouville, liouvilleA     -- * Additive functions@@ -51,12 +52,6 @@  import Numeric.Natural -#if MIN_VERSION_base(4,8,0)-#else-import Data.Foldable-import Data.Word-#endif- -- | Create a multiplicative function from the function on prime's powers. See examples below. multiplicative :: Num a => (Prime n -> Word -> a) -> ArithmeticFunction n a multiplicative f = ArithmeticFunction ((Product .) . f) getProduct@@ -154,6 +149,27 @@ jordanHelper pa 2 = (pa - 1) * pa jordanHelper pa k = (pa - 1) * pa ^ wordToInt (k - 1) {-# INLINE jordanHelper #-}++ramanujan :: Integer -> Integer+ramanujan = runFunction ramanujanA++-- | Calculates the <https://en.wikipedia.org/wiki/Ramanujan_tau_function Ramanujan tau function>+--   of a positive number @n@, using formulas given <http://www.numbertheory.org/php/tau.html here>+ramanujanA :: ArithmeticFunction Integer Integer+ramanujanA = multiplicative $ \(unPrime -> p) -> ramanujanHelper p++ramanujanHelper :: Integer -> Word -> Integer+ramanujanHelper _ 0 = 1+ramanujanHelper 2 1 = -24+ramanujanHelper p 1 = (65 * sigmaHelper (p ^ (11 :: Int)) 1 + 691 * sigmaHelper (p ^ (5 :: Int)) 1 - 691 * 252 * 2 * sum [sigma 5 k * sigma 5 (p-k) | k <- [1..(p `quot` 2)]]) `quot` 756+ramanujanHelper p k = sum $ zipWith3 (\a b c -> a * b * c) paPowers tpPowers binomials+  where pa = p ^ (11 :: Int)+        tp = ramanujanHelper p 1+        paPowers = iterate (* (-pa)) 1+        binomials = scanl (\acc j -> acc * (k' - 2 * j) * (k' - 2 * j - 1) `quot` (k' - j) `quot` (j + 1)) 1 [0 .. k' `quot` 2 - 1]+        k' = fromIntegral k+        tpPowers = reverse $ take (length binomials) $ iterate (* tp^(2::Int)) (if even k then 1 else tp)+{-# INLINE ramanujanHelper #-}  moebius :: UniqueFactorisation n => n -> Moebius moebius = runFunction moebiusA
Math/NumberTheory/Curves/Montgomery.hs view
@@ -33,10 +33,11 @@  import Data.Proxy import GHC.Exts-import GHC.Integer.GMP.Internals import GHC.Integer.Logarithms import GHC.TypeNats.Compat +import Math.NumberTheory.Utils (recipMod)+ -- | We use the Montgomery form of elliptic curve: -- b Y² = X³ + a X² + X (mod n). -- See Eq. (10.3.1.1) at p. 260 of <http://www.ams.org/journals/mcom/1987-48-177/S0025-5718-1987-0866113-7/S0025-5718-1987-0866113-7.pdf Speeding the Pollard and Elliptic Curve Methods of Factorization> by P. L. Montgomery.@@ -90,9 +91,7 @@ -- by K. Gaj, S. Kwon et al. newPoint :: Integer -> Integer -> Maybe SomePoint newPoint s n = do-    a24denRecip <- case recipModInteger a24den n of-      0 -> Nothing-      t -> Just t+    a24denRecip <- recipMod a24den n     a24 <- case a24num * a24denRecip `rem` n of       -- (a+2)/4 = 0 corresponds to singular curve with A = -2       0 -> Nothing
+ Math/NumberTheory/Euclidean.hs view
@@ -0,0 +1,165 @@+-- |+-- Module:      Math.NumberTheory.Euclidean+-- Copyright:   (c) 2018 Alexandre Rodrigues Baldé+-- Licence:     MIT+-- Maintainer:  Alexandre Rodrigues Baldé <alexandrer_b@outlook.com>+-- Stability:   Provisional+-- Portability: Non-portable (GHC extensions)+--+-- This module exports a class to represent Euclidean domains.+--++{-# LANGUAGE BangPatterns               #-}+{-# LANGUAGE FlexibleInstances          #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE MagicHash                  #-}+{-# LANGUAGE ScopedTypeVariables        #-}++module Math.NumberTheory.Euclidean+  ( Euclidean(..)+  , WrappedIntegral(..)+  ) where++import Prelude hiding (divMod, div, gcd, lcm, mod, quotRem, quot, rem)+import qualified Prelude as P++import GHC.Exts+import GHC.Integer.GMP.Internals+import Numeric.Natural++-- | A class to represent a Euclidean domain,+-- which is basically an 'Integral' without 'toInteger'.+class (Eq a, Num a) => Euclidean a where+  -- | When restriced to a subring of the Euclidean domain @a@ isomorphic to+  -- @Integer@, this function should match @quotRem@ for Integers.+  quotRem :: a -> a -> (a, a)+  -- | When restriced to a subring of the Euclidean domain @a@ isomorphic to+  -- @Integer@, this function should match @divMod@ for Integers.+  divMod  :: a -> a -> (a, a)++  quot :: a -> a -> a+  quot x y = fst (quotRem x y)++  rem :: a -> a -> a+  rem x y = snd (quotRem x y)++  div :: a -> a -> a+  div x y = fst (divMod x y)++  mod :: a -> a -> a+  mod x y = snd (divMod x y)++  -- | @'gcd' x y@ is the greatest number that divides both @x@ and @y@.+  gcd :: a -> a -> a+  gcd x y =  gcd' (abs x) (abs y)+    where+      gcd' :: a -> a -> a+      gcd' a 0  =  a+      gcd' a b  =  gcd' b (abs (a `mod` b))++  -- | @'lcm' x y@ is the smallest number that both @x@ and @y@ divide.+  lcm :: a -> a -> a+  lcm _ 0 =  0+  lcm 0 _ =  0+  lcm x y =  abs ((x `quot` (gcd x y)) * y)++  -- | Test whether two numbers are coprime .+  coprime :: a -> a -> Bool+  coprime x y = gcd x y == 1++  -- | Calculate the greatest common divisor of two numbers and coefficients+  --   for the linear combination.+  --+  --   For signed types satisfies:+  --+  -- > case extendedGCD a b of+  -- >   (d, u, v) -> u*a + v*b == d+  -- >                && d == gcd a b+  --+  --   For unsigned and bounded types the property above holds, but since @u@ and @v@ must also be unsigned,+  --   the result may look weird. E. g., on 64-bit architecture+  --+  -- > extendedGCD (2 :: Word) (3 :: Word) == (1, 2^64-1, 1)+  --+  --   For unsigned and unbounded types (like 'Numeric.Natural.Natural') the result is undefined.+  --+  --   For signed types we also have+  --+  -- > abs u < abs b || abs b <= 1+  -- >+  -- > abs v < abs a || abs a <= 1+  --+  --   (except if one of @a@ and @b@ is 'minBound' of a signed type).+  extendedGCD :: a -> a -> (a, a, a)+  extendedGCD a b = (d, x * signum a, y * signum b)+    where+      (d, x, y) = eGCD 0 1 1 0 (abs a) (abs b)+      eGCD !n1 o1 !n2 o2 r s+        | s == 0    = (r, o1, o2)+        | otherwise = case r `quotRem` s of+                        (q, t) -> eGCD (o1 - q*n1) n1 (o2 - q*n2) n2 s t++coprimeIntegral :: Integral a => a -> a -> Bool+coprimeIntegral x y = (odd x || odd y) && P.gcd x y == 1++-- | Wrapper around 'Integral', which has an 'Eucledian' instance.+newtype WrappedIntegral a = WrappedIntegral { unWrappedIntegral :: a }+  deriving (Eq, Ord, Show, Num, Integral, Real, Enum)++instance Integral a => Euclidean (WrappedIntegral a) where+  quotRem = P.quotRem+  divMod  = P.divMod+  quot    = P.quot+  rem     = P.rem+  div     = P.div+  mod     = P.mod+  gcd     = P.gcd+  lcm     = P.lcm+  coprime = coprimeIntegral++instance Euclidean Int where+  quotRem = P.quotRem+  divMod  = P.divMod+  quot    = P.quot+  rem     = P.rem+  div     = P.div+  mod     = P.mod+  gcd (I# x) (I# y) = I# (gcdInt x y)+  lcm     = P.lcm+  coprime = coprimeIntegral++instance Euclidean Word where+  quotRem = P.quotRem+  divMod  = P.divMod+  quot    = P.quot+  rem     = P.rem+  div     = P.div+  mod     = P.mod+  gcd (W# x) (W# y) = W# (gcdWord x y)+  lcm     = P.lcm+  coprime = coprimeIntegral++instance Euclidean Integer where+  quotRem = P.quotRem+  divMod  = P.divMod+  quot    = P.quot+  rem     = P.rem+  div     = P.div+  mod     = P.mod+  gcd     = gcdInteger+  lcm     = lcmInteger+  coprime = coprimeIntegral+  -- Blocked by GHC bug+  -- https://ghc.haskell.org/trac/ghc/ticket/15350+  -- extendedGCD = gcdExtInteger++instance Euclidean Natural where+  quotRem = P.quotRem+  divMod  = P.divMod+  quot    = P.quot+  rem     = P.rem+  div     = P.div+  mod     = P.mod+  gcd     = P.gcd+  lcm     = P.lcm+  coprime = coprimeIntegral
+ Math/NumberTheory/Euclidean/Coprimes.hs view
@@ -0,0 +1,124 @@+-- |+-- Module:      Math.NumberTheory.Euclidean.Coprimes+-- Copyright:   (c) 2017-2018 Andrew Lelechenko+-- Licence:     MIT+-- Maintainer:  Andrew Lelechenko <andrew.lelechenko@gmail.com>+--+-- Container for pairwise coprime numbers.++{-# LANGUAGE CPP                 #-}+{-# LANGUAGE ScopedTypeVariables #-}++module Math.NumberTheory.Euclidean.Coprimes+  ( splitIntoCoprimes+  , Coprimes+  , unCoprimes+  , singleton+  , insert+  ) where++import Prelude hiding (gcd, quot, rem)+import Data.Coerce+import Data.List (tails, mapAccumL)+#if __GLASGOW_HASKELL__ < 803+import Data.Semigroup+#endif++import Math.NumberTheory.Euclidean++-- | A list of pairwise coprime numbers+-- with their multiplicities.+newtype Coprimes a b = Coprimes {+  unCoprimes :: [(a, b)] -- ^ Unwrap.+  }+  deriving (Eq, Show)++doPair :: (Euclidean a, Eq b, Num b) => a -> b -> a -> b -> (a, a, [(a, b)])+doPair x xm y ym = case gcd x y of+  1 -> (x, y, [])+  g -> (x', y', concat rests)+    where+      (x', g', xgs) = doPair (x `quot` g) xm g (xm + ym)+      xgs' = if g' == 1 then xgs else ((g', xm + ym) : xgs)++      (y', rests) = mapAccumL go (y `quot` g) xgs'+      go w (t, tm) = (w', if t' == 1 then acc else (t', tm) : acc)+        where+          (w', t', acc) = doPair w ym t tm++_propDoPair :: (Euclidean a, Integral b) => a -> b -> a -> b -> Bool+_propDoPair x xm y ym+  =  x `rem` x' == 0+  && y `rem` y' == 0+  && coprime x' y'+  && all (coprime x') (map fst rest)+  && all (coprime y') (map fst rest)+  && all (/= 1) (map fst rest)+  && and [ coprime s t | (s, _) : ts <- tails rest, (t, _) <- ts ]+  && (x ^ xm) * (y ^ ym) == (x' ^ xm) * (y' ^ ym) * product (map (\(r, k) -> r ^ k) rest)+  where+    (x', y', rest) = doPair x xm y ym++insertInternal+  :: forall a b.+     (Euclidean a, Eq b, Num b)+  => a+  -> b+  -> Coprimes a b+  -> (Coprimes a b, Coprimes a b)+insertInternal 0   _ = const (Coprimes [(0, 1)], Coprimes [])+insertInternal xx xm = coerce (go ([], []) xx)+  where+    go :: ([(a, b)], [(a, b)]) -> a -> [(a, b)] -> ([(a, b)], [(a, b)])+    go (old, new) 1 rest = (rest ++ old, new)+    go (old, new) x [] = (old, (x, xm) : new)+    go _ _ ((0, _) : _) = ([(0, 1)], [])+    go (old, new) x ((y, ym) : rest)+      | y' == 1   = go (old, xys ++ new) x' rest+      | otherwise = go ((y', ym) : old, xys ++ new) x' rest+      where+        (x', y', xys) = doPair x xm y ym++-- | Wrap a non-zero number with its multiplicity into 'Coprimes'.+--+-- >>> singleton 210 1+-- Coprimes {unCoprimes = [(210,1)]}+singleton :: (Eq a, Num a, Eq b, Num b) => a -> b -> Coprimes a b+singleton 0 0 = Coprimes []+singleton 1 _ = Coprimes []+singleton a b = Coprimes [(a, b)]++-- | Add a non-zero number with its multiplicity to 'Coprimes'.+--+-- >>> insert 360 1 (singleton 210 1)+-- Coprimes {unCoprimes = [(7,1),(5,2),(3,3),(2,4)]}+-- >>> insert 2 4 (insert 7 1 (insert 5 2 (singleton 4 3)))+-- Coprimes {unCoprimes = [(7,1),(5,2),(2,10)]}+insert :: (Euclidean a, Eq b, Num b) => a -> b -> Coprimes a b -> Coprimes a b+insert x xm ys = Coprimes $ unCoprimes zs <> unCoprimes ws+  where+    (zs, ws) = insertInternal x xm ys++instance (Euclidean a, Eq b, Num b) => Semigroup (Coprimes a b) where+  (Coprimes xs) <> ys = Coprimes $ unCoprimes zs <> foldMap unCoprimes wss+    where+      (zs, wss) = mapAccumL (\vs (x, xm) -> insertInternal x xm vs) ys xs++instance (Euclidean a, Eq b, Num b) => Monoid (Coprimes a b) where+  mempty  = Coprimes []+  mappend = (<>)++-- | The input list is assumed to be a factorisation of some number+-- into a list of powers of (possibly, composite) non-zero factors. The output+-- list is a factorisation of the same number such that all factors+-- are coprime. Such transformation is crucial to continue factorisation+-- (lazily, in parallel or concurrent fashion) without+-- having to merge multiplicities of primes, which occurs more than in one+-- composite factor.+--+-- >>> splitIntoCoprimes [(140, 1), (165, 1)]+-- Coprimes {unCoprimes = [(28,1),(33,1),(5,2)]}+-- >>> splitIntoCoprimes [(360, 1), (210, 1)]+-- Coprimes {unCoprimes = [(7,1),(5,2),(3,3),(2,4)]}+splitIntoCoprimes :: (Euclidean a, Eq b, Num b) => [(a, b)] -> Coprimes a b+splitIntoCoprimes = foldl (\acc (x, xm) -> insert x xm acc) mempty
Math/NumberTheory/GCD.hs view
@@ -21,19 +21,23 @@ -- When using this module, always compile with optimisations turned on to -- benefit from GHC's primops and the rewrite rules. -{-# LANGUAGE BangPatterns #-}-{-# LANGUAGE CPP          #-}-{-# LANGUAGE LambdaCase   #-}-{-# LANGUAGE MagicHash    #-}+{-# LANGUAGE BangPatterns        #-}+{-# LANGUAGE CPP                 #-}+{-# LANGUAGE LambdaCase          #-}+{-# LANGUAGE MagicHash           #-} +{-# OPTIONS_GHC -fno-warn-unused-imports #-}+{-# OPTIONS_GHC -fno-warn-deprecations   #-}+ module Math.NumberTheory.GCD     ( binaryGCD     , extendedGCD     , coprime-    , splitIntoCoprimes     ) where  import Data.Bits+import Data.Semigroup+ import GHC.Word import GHC.Int @@ -80,6 +84,8 @@ binaryGCD :: (Integral a, Bits a) => a -> a -> a binaryGCD = binaryGCDImpl +{-# DEPRECATED binaryGCD "Use 'Math.NumberTheory.Euclidean.gcd'" #-}+ #if WORD_SIZE_IN_BITS < 64 {-# SPECIALISE binaryGCDImpl :: Word64 -> Word64 -> Word64,                                 Int64 -> Int64 -> Int64 #-}@@ -136,6 +142,7 @@       | s == 0    = (r, o1, o2)       | otherwise = case r `quotRem` s of                       (q, t) -> eGCD (o1 - q*n1) n1 (o2 - q*n2) n2 s t+{-# DEPRECATED extendedGCD "Use 'Math.NumberTheory.Euclidean.extendedGCD'" #-}  {-# RULES "coprime/Int"       coprime = coprimeInt@@ -170,6 +177,7 @@ --   Relies on twos complement or sign and magnitude representaion for signed types. coprime :: (Integral a, Bits a) => a -> a -> Bool coprime = coprimeImpl+{-# DEPRECATED coprime "Use 'Math.NumberTheory.Euclidean.coprime'" #-}  -- Separate implementation to give the rules a chance to fire by not inlining -- before phase 1, and yet have a specialisation for the types without rules@@ -251,37 +259,3 @@  cw32 :: Word32 -> Word32 -> Bool cw32 (W32# x#) (W32# y#) = coprimeWord# x# y#---- | The input list is assumed to be a factorisation of some number--- into a list of powers of (possibly, composite) non-zero factors. The output--- list is a factorisation of the same number such that all factors--- are coprime. Such transformation is crucial to continue factorisation--- (lazily, in parallel or concurrent fashion) without--- having to merge multiplicities of primes, which occurs more than in one--- composite factor.------ > > splitIntoCoprimes [(140, 1), (165, 1)]--- > [(5,2),(28,1),(33,1)]--- > > splitIntoCoprimes [(360, 1), (210, 1)]--- > [(2,4),(3,3),(5,2),(7,1)]-splitIntoCoprimes :: (Integral a, Eq b, Num b) => [(a, b)] -> [(a, b)]-splitIntoCoprimes xs = if any ((== 0) . fst) ys then [(0, 1)] else go ys-  where-    ys = filter (/= (0, 0)) xs--    go = \case-      [] -> []-      ((1,  _) : rest) -> go rest-      ((x, xm) : rest) -> case popSuchThat (\(r, _) -> gcd x r /= 1) rest of-        Nothing            -> (x, xm) : go rest-        Just ((y, ym), zs) -> let g = gcd x y in-          go ((g, xm + ym) : (x `quot` g, xm) : (y `quot` g, ym) : zs)--popSuchThat :: (a -> Bool) -> [a] -> Maybe (a, [a])-popSuchThat predicate = go-  where-    go = \case-      [] -> Nothing-      (x : xs)-        | predicate x -> Just (x, xs)-        | otherwise   -> fmap (fmap (x :)) (go xs)
Math/NumberTheory/GCD/LowLevel.hs view
@@ -31,6 +31,9 @@  import Math.NumberTheory.Utils +{-# DEPRECATED gcdInt, gcdWord, gcdInt#, gcdWord# "Use Math.NumberTheory.Euclidean.gcd" #-}+{-# DEPRECATED coprimeInt, coprimeWord, coprimeInt#, coprimeWord# "Math.NumberTheory.Euclidean." #-}+ -- | Greatest common divisor of two 'Int's, calculated with the binary gcd algorithm. gcdInt :: Int -> Int -> Int gcdInt (I# a#) (I# b#) = I# (gcdInt# a# b#)
Math/NumberTheory/GaussianIntegers.hs view
@@ -10,226 +10,9 @@ -- computing their prime factorisations. -- -{-# LANGUAGE BangPatterns #-}--module Math.NumberTheory.GaussianIntegers (-    GaussianInteger((:+)),-    ι,-    real,-    imag,-    conjugate,-    norm,-    divModG,-    divG,-    modG,-    quotRemG,-    quotG,-    remG,-    (.^),-    isPrime,-    primes,-    gcdG,-    gcdG',-    findPrime,-    findPrime',-    factorise,-) where--import qualified Math.NumberTheory.Moduli as Moduli-import qualified Math.NumberTheory.Powers as Powers-import qualified Math.NumberTheory.Primes.Factorisation as Factorisation-import qualified Math.NumberTheory.Primes.Sieve as Sieve-import qualified Math.NumberTheory.Primes.Testing as Testing--infix 6 :+-infixr 8 .^--- |A Gaussian integer is a+bi, where a and b are both integers.-data GaussianInteger = (:+) { real :: !Integer, imag :: !Integer } deriving (Eq)---- |The imaginary unit, where------ > ι .^ 2 == -1-ι :: GaussianInteger-ι = 0 :+ 1--instance Show GaussianInteger where-    show (a :+ b)-        | b == 0     = show a-        | a == 0     = s ++ b'-        | otherwise  = show a ++ op ++ b'-        where-            b' = if abs b == 1 then "ι" else show (abs b) ++ "*ι"-            op = if b > 0 then "+" else "-"-            s  = if b > 0 then "" else "-"--instance Num GaussianInteger where-    (+) (a :+ b) (c :+ d) = (a + c) :+ (b + d)-    (*) (a :+ b) (c :+ d) = (a * c - b * d) :+ (a * d + b * c)-    abs z@(a :+ b)-        | a == 0 && b == 0 =   z             -- origin-        | a >  0 && b >= 0 =   z             -- first quadrant: (0, inf) x [0, inf)i-        | a <= 0 && b >  0 =   b  :+ (-a)    -- second quadrant: (-inf, 0] x (0, inf)i-        | a <  0 && b <= 0 = (-a) :+ (-b)    -- third quadrant: (-inf, 0) x (-inf, 0]i-        | otherwise        = (-b) :+   a     -- fourth quadrant: [0, inf) x (-inf, 0)i-    negate (a :+ b) = (-a) :+ (-b)-    fromInteger n = n :+ 0-    signum z@(a :+ b)-        | a == 0 && b == 0 = z               -- hole at origin-        | otherwise        = z `divG` abs z---- |Simultaneous 'quot' and 'rem'.-quotRemG :: GaussianInteger -> GaussianInteger -> (GaussianInteger, GaussianInteger)-quotRemG = divHelper quot---- |Gaussian integer division, truncating toward zero.-quotG :: GaussianInteger -> GaussianInteger -> GaussianInteger-n `quotG` d = q where (q,_) = quotRemG n d---- |Gaussian integer remainder, satisfying------ > (x `quotG` y)*y + (x `remG` y) == x-remG :: GaussianInteger -> GaussianInteger -> GaussianInteger-n `remG`  d = r where (_,r) = quotRemG n d---- |Simultaneous 'div' and 'mod'.-divModG :: GaussianInteger -> GaussianInteger -> (GaussianInteger, GaussianInteger)-divModG = divHelper div---- |Gaussian integer division, truncating toward negative infinity.-divG :: GaussianInteger -> GaussianInteger -> GaussianInteger-n `divG` d = q where (q,_) = divModG n d---- |Gaussian integer remainder, satisfying------ > (x `divG` y)*y + (x `modG` y) == x-modG :: GaussianInteger -> GaussianInteger -> GaussianInteger-n `modG` d = r where (_,r) = divModG n d--divHelper :: (Integer -> Integer -> Integer) -> GaussianInteger -> GaussianInteger -> (GaussianInteger, GaussianInteger)-divHelper divide g h =-    let nr :+ ni = g * conjugate h-        denom = norm h-        q = divide nr denom :+ divide ni denom-        p = h * q-    in (q, g - p)---- |Conjugate a Gaussian integer.-conjugate :: GaussianInteger -> GaussianInteger-conjugate (r :+ i) = r :+ (-i)---- |The square of the magnitude of a Gaussian integer.-norm :: GaussianInteger -> Integer-norm (x :+ y) = x * x + y * y---- |Compute whether a given Gaussian integer is prime.-isPrime :: GaussianInteger -> Bool-isPrime g@(x :+ y)-    | x == 0 && y /= 0 = abs y `mod` 4 == 3 && Testing.isPrime y-    | y == 0 && x /= 0 = abs x `mod` 4 == 3 && Testing.isPrime x-    | otherwise        = Testing.isPrime $ norm g---- |An infinite list of the Gaussian primes. Uses primes in Z to exhaustively--- generate all Gaussian primes, but not quite in order of ascending magnitude.-primes :: [GaussianInteger]-primes = [ g-         | p <- Sieve.primes-         , g <- if p `mod` 4 == 3-                then [p :+ 0]-                else-                    if p == 2-                    then [1 :+ 1]-                    else let x :+ y = findPrime' p-                         in [x :+ y, y :+ x]-         ]---- |Compute the GCD of two Gaussian integers. Enforces the precondition that each--- integer must be in the first quadrant (or zero).-gcdG :: GaussianInteger -> GaussianInteger -> GaussianInteger-gcdG g h = gcdG' (abs g) (abs h)---- |Compute the GCD of two Gauss integers. Does not check the precondition.-gcdG' :: GaussianInteger -> GaussianInteger -> GaussianInteger-gcdG' g h-    | h == 0    = g --done recursing-    | otherwise = gcdG' h (abs (g `modG` h))---- |Find a Gaussian integer whose norm is the given prime number.--- Checks the precondition that p is prime and that p `mod` 4 /= 3.-findPrime :: Integer -> GaussianInteger-findPrime p-    | p == 2 || (p `mod` 4 == 1 && Testing.isPrime p) = findPrime' p-    | otherwise = error "p must be prime, and not congruent to 3 (mod 4)"---- |Find a Gaussian integer whose norm is the given prime number. Does not--- check the precondition.-findPrime' :: Integer -> GaussianInteger-findPrime' p =-    let (Just c) = Moduli.sqrtModP (-1) p-        k  = Powers.integerSquareRoot p-        bs = [1 .. k]-        asbs = map (\b' -> ((b' * c) `mod` p, b')) bs-        (a, b) = head [ (a', b') | (a', b') <- asbs, a' <= k]-    in a :+ b---- |Raise a Gaussian integer to a given power.-(.^) :: (Integral a) => GaussianInteger -> a -> GaussianInteger-a .^ e-    | e < 0 && norm a == 1 =-        case a of-            1    :+ 0 -> 1-            (-1) :+ 0 -> if even e then 1 else (-1)-            0    :+ 1 -> (0 :+ (-1)) .^ (abs e `mod` 4)-            _         -> (0 :+ 1) .^ (abs e `mod` 4)-    | e < 0     = error "Cannot exponentiate non-unit Gaussian Int to negative power"-    | a == 0    = 0-    | e == 0    = 1-    | even e    = s * s-    | otherwise = a * a .^ (e - 1)-    where-    s = a .^ div e 2---- |Compute the prime factorisation of a Gaussian integer. This is unique up to units (+/- 1, +/- i).-factorise :: GaussianInteger -> [(GaussianInteger, Int)]-factorise g = helper (Factorisation.factorise $ norm g) g-    where-    helper [] g' = if g' == 1 then [] else [(g', 1)] -- include the unit, if it isn't 1-    helper ((!p, !e) : pt) g' =-        -- For a given prime factor p of the magnitude squared...-        let (!g'', !facs) = if p `mod` 4 == 3-            then-                -- if the p is congruent to 3 (mod 4), then g' is divisible by-                -- p^(e/2).-                let pow = div e 2-                    gp = fromInteger p-                in (g' `divG` (gp .^ pow), [(gp, pow)])-            else-                -- otherwise: find a Gaussian prime gp for which `norm gp ==-                -- p`. Then do trial divisions to find out how many times g' is-                -- divisible by gp or its conjugate.-                let gp = findPrime' p-                in trialDivide g' [gp, abs $ conjugate gp]-        in facs ++ helper pt g''---- Divide a Gaussian integer by a set of (relatively prime) Gaussian integers,--- as many times as possible, and return the final quotient as well as a count--- of how many times each factor divided the original.-trialDivide :: GaussianInteger -> [GaussianInteger] -> (GaussianInteger, [(GaussianInteger, Int)])-trialDivide = helper []-    where-    helper fs g [] = (g, fs)-    helper fs g (pf : pft)-        | g `modG` pf == 0 =-            let (cnt, g') = countEvenDivisions g pf-            in helper ((pf, cnt) : fs) g' pft-        | otherwise        = helper fs g pft+module Math.NumberTheory.GaussianIntegers+  {-# DEPRECATED "Use Math.NumberTheory.Quadratic.GaussianIntegers instead" #-}+  ( module Math.NumberTheory.Quadratic.GaussianIntegers+  ) where --- Divide a Gaussian integer by a possible factor, and return how many times--- the factor divided it evenly, as well as the result of dividing the original--- that many times.-countEvenDivisions :: GaussianInteger -> GaussianInteger -> (Int, GaussianInteger)-countEvenDivisions g pf = helper g 0-    where-    helper :: GaussianInteger -> Int -> (Int, GaussianInteger)-    helper g' acc-        | g' `modG` pf == 0 = helper (g' `divG` pf) (1 + acc)-        | otherwise     = (acc, g')+import Math.NumberTheory.Quadratic.GaussianIntegers
Math/NumberTheory/Moduli.hs view
@@ -12,11 +12,15 @@ module Math.NumberTheory.Moduli   ( module Math.NumberTheory.Moduli.Class   , module Math.NumberTheory.Moduli.Chinese+  , module Math.NumberTheory.Moduli.DiscreteLogarithm   , module Math.NumberTheory.Moduli.Jacobi+  , module Math.NumberTheory.Moduli.PrimitiveRoot   , module Math.NumberTheory.Moduli.Sqrt   ) where  import Math.NumberTheory.Moduli.Chinese import Math.NumberTheory.Moduli.Class+import Math.NumberTheory.Moduli.DiscreteLogarithm import Math.NumberTheory.Moduli.Jacobi+import Math.NumberTheory.Moduli.PrimitiveRoot import Math.NumberTheory.Moduli.Sqrt
Math/NumberTheory/Moduli/Chinese.hs view
@@ -17,9 +17,9 @@   ) where  import Control.Monad (foldM)-import GHC.Integer.GMP.Internals -import Math.NumberTheory.GCD (extendedGCD)+import Math.NumberTheory.Euclidean (extendedGCD)+import Math.NumberTheory.Utils (recipMod)  -- | Given a list @[(r_1,m_1), ..., (r_n,m_n)]@ of @(residue,modulus)@ --   pairs, @chineseRemainder@ calculates the solution to the simultaneous@@ -52,8 +52,3 @@ chineseRemainder2 (r1, md1) (r2,md2)     = case extendedGCD md1 md2 of         (_,u,v) -> ((1 - u*md1)*r1 + (1 - v*md2)*r2) `mod` (md1*md2)--recipMod :: Integer -> Integer -> Maybe Integer-recipMod x m = case recipModInteger x m of-  0 -> Nothing-  y -> Just y
Math/NumberTheory/Moduli/Class.hs view
@@ -9,7 +9,6 @@ -- Safe modular arithmetic with modulo on type level. -- -{-# LANGUAGE CPP                        #-} {-# LANGUAGE DataKinds                  #-} {-# LANGUAGE GADTs                      #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-}@@ -29,6 +28,11 @@   , invertMod   , powMod   , (^%)+  -- * Multiplicative group+  , MultMod+  , multElement+  , isMultElement+  , invertGroup   -- * Unknown modulo   , SomeMod(..)   , modulo@@ -40,19 +44,12 @@  import Data.Proxy import Data.Ratio+import Data.Semigroup import Data.Type.Equality import GHC.Integer.GMP.Internals import GHC.TypeNats.Compat -#if __GLASGOW_HASKELL__ < 709-import Data.Word-import Numeric.Natural (Natural)--powModNatural :: Natural -> Natural -> Natural -> Natural-powModNatural b e m = fromInteger $ powModInteger (toInteger b) (toInteger e) (toInteger m)-#else import GHC.Natural (Natural, powModNatural)-#endif  -- | Wrapper for residues modulo @m@. --@@ -60,10 +57,11 @@ -- The modulo is stored on type level, so it is impossible, for example, to add up by mistake -- residues with different moduli. ----- > > (3 :: Mod 10) + (4 :: Mod 12)--- > error: Couldn't match type ‘12’ with ‘10’...--- > > (3 :: Mod 10) + 8--- > (1 `modulo` 10)+-- >>> :set -XDataKinds+-- >>> (3 :: Mod 10) + (4 :: Mod 12)+-- error: Couldn't match type ‘12’ with ‘10’...+-- >>> (3 :: Mod 10) + 8+-- (1 `modulo` 10) -- -- Note that modulo cannot be negative. newtype Mod (m :: Nat) = Mod Natural@@ -128,33 +126,36 @@ {-# INLINE getNatMod #-}  -- | The canonical representative of the residue class, always between 0 and @m-1@ inclusively.-getVal :: KnownNat m => Mod m -> Integer+getVal :: Mod m -> Integer getVal (Mod x) = toInteger x {-# INLINE getVal #-}  -- | The canonical representative of the residue class, always between 0 and @m-1@ inclusively.-getNatVal :: KnownNat m => Mod m -> Natural+getNatVal :: Mod m -> Natural getNatVal (Mod x) = x {-# INLINE getNatVal #-}  -- | Computes the modular inverse, if the residue is coprime with the modulo. ----- > > invertMod (3 :: Mod 10)--- > Just (7 `modulo` 10) -- because 3 * 7 = 1 :: Mod 10--- > > invertMod (4 :: Mod 10)--- > Nothing+-- >>> :set -XDataKinds+-- >>> invertMod (3 :: Mod 10)+-- Just (7 `modulo` 10) -- because 3 * 7 = 1 :: Mod 10+-- >>> invertMod (4 :: Mod 10)+-- Nothing invertMod :: KnownNat m => Mod m -> Maybe (Mod m) invertMod mx   = if y <= 0     then Nothing     else Just $ Mod $ fromInteger y   where+    -- first argument of recipModInteger is guaranteed to be positive     y = recipModInteger (getVal mx) (getMod mx) {-# INLINABLE invertMod #-}  -- | Drop-in replacement for '^', with much better performance. ----- > > powMod (3 :: Mod 10) 4+-- >>> :set -XDataKinds+-- >>> powMod (3 :: Mod 10) 4 -- > (1 `modulo` 10) powMod :: (KnownNat m, Integral a) => Mod m -> a -> Mod m powMod mx a@@ -185,18 +186,51 @@ -- of type classes in Core. -- {-# RULES "^%Mod" forall (x :: KnownNat m => Mod m) p. x ^ p = x ^% p #-} +-- | This type represents elements of the multiplicative group mod m, i.e.+-- those elements which are coprime to m. Use @toMultElement@ to construct.+newtype MultMod m = MultMod { multElement :: Mod m }+  deriving (Eq, Ord, Show)++instance KnownNat m => Semigroup (MultMod m) where+  MultMod a <> MultMod b = MultMod (a * b)+  stimes k a@(MultMod a')+    | k >= 0 = MultMod (powMod a' k)+    | otherwise = invertGroup $ stimes (-k) a+  -- ^ This Semigroup is in fact a group, so @stimes@ can be called with a negative first argument.++instance KnownNat m => Monoid (MultMod m) where+  mempty = MultMod 1+  mappend = (<>)++instance KnownNat m => Bounded (MultMod m) where+  minBound = MultMod 1+  maxBound = MultMod (-1)++-- | Attempt to construct a multiplicative group element.+isMultElement :: KnownNat m => Mod m -> Maybe (MultMod m)+isMultElement a = if getNatVal a `gcd` getNatMod a == 1+                     then Just $ MultMod a+                     else Nothing++-- | For elements of the multiplicative group, we can safely perform the inverse+-- without needing to worry about failure.+invertGroup :: KnownNat m => MultMod m -> MultMod m+invertGroup (MultMod a) = case invertMod a of+                            Just b -> MultMod b+                            Nothing -> error "Math.NumberTheory.Moduli.invertGroup: failed to invert element"+ -- | This type represents residues with unknown modulo and rational numbers. -- One can freely combine them in arithmetic expressions, but each operation -- will spend time on modulo's recalculation: ----- > > 2 `modulo` 10 + 4 `modulo` 15--- > (1 `modulo` 5)--- > > 2 `modulo` 10 * 4 `modulo` 15--- > (3 `modulo` 5)--- > > 2 `modulo` 10 + fromRational (3 % 7)--- > (1 `modulo` 10)--- > > 2 `modulo` 10 * fromRational (3 % 7)--- > (8 `modulo` 10)+-- >>> 2 `modulo` 10 + 4 `modulo` 15+-- (1 `modulo` 5)+-- >>> 2 `modulo` 10 * 4 `modulo` 15+-- (3 `modulo` 5)+-- >>> 2 `modulo` 10 + fromRational (3 % 7)+-- (1 `modulo` 10)+-- >>> 2 `modulo` 10 * fromRational (3 % 7)+-- (8 `modulo` 10) -- -- If performance is crucial, it is recommended to extract @Mod m@ for further processing -- by pattern matching. E. g.,@@ -286,12 +320,12 @@  -- | Computes the inverse value, if it exists. ----- > > invertSomeMod (3 `modulo` 10)--- > Just (7 `modulo` 10) -- because 3 * 7 = 1 :: Mod 10--- > > invertMod (4 `modulo` 10)--- > Nothing--- > > invertSomeMod (fromRational (2 % 5))--- > Just 5 % 2+-- >>> invertSomeMod (3 `modulo` 10)+-- Just (7 `modulo` 10) -- because 3 * 7 = 1 :: Mod 10+-- >>> invertMod (4 `modulo` 10)+-- Nothing+-- >>> invertSomeMod (fromRational (2 % 5))+-- Just 5 % 2 invertSomeMod :: SomeMod -> Maybe SomeMod invertSomeMod = \case   SomeMod m -> fmap SomeMod (invertMod m)@@ -307,8 +341,8 @@ -- | Drop-in replacement for '^', with much better performance. -- When -O is enabled, there is a rewrite rule, which specialises '^' to 'powSomeMod'. ----- > > powSomeMod (3 `modulo` 10) 4--- > (1 `modulo` 10)+-- >>> powSomeMod (3 `modulo` 10) 4+-- (1 `modulo` 10) powSomeMod :: Integral a => SomeMod -> a -> SomeMod powSomeMod (SomeMod m) a = SomeMod (m ^% a) powSomeMod (InfMod  r) a = InfMod  (r ^  a)
+ Math/NumberTheory/Moduli/DiscreteLogarithm.hs view
@@ -0,0 +1,123 @@+-- |+-- Module:       Math.NumberTheory.Moduli.DiscreteLogarithm+-- Copyright:    (c) 2018 Bhavik Mehta+-- License:      MIT+-- Maintainer:   Andrew Lelechenko <andrew.lelechenko@gmail.com>+-- Stability:    Provisional+-- Portability:  Non-portable+--++{-# LANGUAGE BangPatterns        #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE ViewPatterns        #-}++module Math.NumberTheory.Moduli.DiscreteLogarithm+  ( discreteLogarithm+  ) where++import qualified Data.IntMap.Strict as M+import Data.Maybe                             (maybeToList)+import Data.Proxy+import Numeric.Natural                        (Natural)+import GHC.Integer.GMP.Internals              (recipModInteger, powModInteger)+import GHC.TypeNats.Compat++import Math.NumberTheory.Moduli.Chinese       (chineseRemainder2)+import Math.NumberTheory.Moduli.Class         (KnownNat, MultMod(..), Mod, getVal)+import Math.NumberTheory.Moduli.Equations     (solveLinear)+import Math.NumberTheory.Moduli.PrimitiveRoot (PrimitiveRoot(..), CyclicGroup(..))+import Math.NumberTheory.Powers.Squares       (integerSquareRoot)+import Math.NumberTheory.UniqueFactorisation  (unPrime)++-- | Computes the discrete logarithm. Currently uses a combination of the baby-step+-- giant-step method and Pollard's rho algorithm, with Bach reduction.+discreteLogarithm :: KnownNat m => PrimitiveRoot m -> MultMod m -> Natural+discreteLogarithm a b = discreteLogarithm' (getGroup a) (multElement $ unPrimitiveRoot a) (multElement b)++discreteLogarithm'+  :: KnownNat m+  => CyclicGroup Natural  -- ^ group structure (must be the multiplicative group mod m)+  -> Mod m                -- ^ a+  -> Mod m                -- ^ b+  -> Natural              -- ^ result+discreteLogarithm' cg a b =+  case cg of+    CG2                                    -> 0+       -- the only valid input was a=1, b=1+    CG4                                    -> if b == 1 then 0 else 1+       -- the only possible input here is a=3 with b = 1 or 3+    CGOddPrimePower       (unPrime -> p) k -> discreteLogarithmPP p k (getVal a) (getVal b)+    CGDoubleOddPrimePower (unPrime -> p) k -> discreteLogarithmPP p k (getVal a `rem` p^k) (getVal b `rem` p^k)+       -- we have the isomorphism t -> t `rem` p^k from (Z/2p^kZ)* -> (Z/p^kZ)*++-- Implementation of Bach reduction (https://www2.eecs.berkeley.edu/Pubs/TechRpts/1984/CSD-84-186.pdf)+{-# INLINE discreteLogarithmPP #-}+discreteLogarithmPP :: Integer -> Word -> Integer -> Integer -> Natural+discreteLogarithmPP p 1 a b = discreteLogarithmPrime p a b+discreteLogarithmPP p k a b = fromInteger result+  where+    baseSol    = toInteger $ discreteLogarithmPrime p (a `rem` p) (b `rem` p)+    thetaA     = theta p pkMinusOne a+    thetaB     = theta p pkMinusOne b+    pkMinusOne = p^(k-1)+    c          = (recipModInteger thetaA pkMinusOne * thetaB) `rem` pkMinusOne+    result     = chineseRemainder2 (baseSol, p-1) (c, pkMinusOne)++-- compute the homomorphism theta given in https://math.stackexchange.com/a/1864495/418148+{-# INLINE theta #-}+theta :: Integer -> Integer -> Integer -> Integer+theta p pkMinusOne a = (numerator `quot` pk) `rem` pkMinusOne+  where+    pk           = pkMinusOne * p+    p2kMinusOne  = pkMinusOne * pk+    numerator    = (powModInteger a (pk - pkMinusOne) p2kMinusOne - 1) `rem` p2kMinusOne++-- TODO: Use Pollig-Hellman to reduce the problem further into groups of prime order.+-- While Bach reduction simplifies the problem into groups of the form (Z/pZ)*, these+-- have non-prime order, and the Pollig-Hellman algorithm can reduce the problem into+-- smaller groups of prime order.+-- In addition, the gcd check before solveLinear is applied in Pollard below will be+-- made redundant, since n would be prime.+discreteLogarithmPrime :: Integer -> Integer -> Integer -> Natural+discreteLogarithmPrime p a b+  | p < 100000000 = fromIntegral $ discreteLogarithmPrimeBSGS (fromInteger p) (fromInteger a) (fromInteger b)+  | otherwise     = discreteLogarithmPrimePollard p a b++discreteLogarithmPrimeBSGS :: Int -> Int -> Int -> Int+discreteLogarithmPrimeBSGS p a b = head [i*m + j | (v,i) <- zip giants [0..m-1], j <- maybeToList (M.lookup v table)]+  where+    m        = integerSquareRoot (p - 2) + 1 -- simple way of ceiling (sqrt (p-1))+    babies   = iterate (.* a) 1+    table    = M.fromList (zip babies [0..m-1])+    aInv     = recipModInteger (toInteger a) (toInteger p)+    bigGiant = fromInteger $ powModInteger aInv (toInteger m) (toInteger p)+    giants   = iterate (.* bigGiant) b+    x .* y   = x * y `rem` p++-- TODO: Use more advanced walks, in order to reduce divisions, cf+-- https://maths-people.anu.edu.au/~brent/pd/rpb231.pdf+-- This will slightly improve the expected time to collision, and can reduce the+-- number of divisions performed.+discreteLogarithmPrimePollard :: Integer -> Integer -> Integer -> Natural+discreteLogarithmPrimePollard p a b =+  case concatMap runPollard [(x,y) | x <- [0..n], y <- [0..n]] of+    (t:_)  -> fromInteger t+    []     -> error ("discreteLogarithm: pollard's rho failed, please report this as a bug. inputs " ++ show [p,a,b])+  where+    n                 = p-1 -- order of the cyclic group+    halfN             = n `quot` 2+    mul2 m            = if m < halfN then m * 2 else m * 2 - n+    sqrtN             = integerSquareRoot n+    step (xi,!ai,!bi) = case xi `rem` 3 of+                          0 -> (xi*xi `rem` p, mul2 ai, mul2 bi)+                          1 -> ( a*xi `rem` p,    ai+1,      bi)+                          _ -> ( b*xi `rem` p,      ai,    bi+1)+    initialise (x,y)  = (powModInteger a x n * powModInteger b y n `rem` n, x, y)+    begin t           = go (step t) (step (step t))+    check t           = powModInteger a t p == b+    go tort@(xi,ai,bi) hare@(x2i,a2i,b2i)+      | xi == x2i, gcd (bi - b2i) n < sqrtN = case someNatVal (fromInteger n) of+        SomeNat (Proxy :: Proxy n) -> map getVal $ solveLinear (fromInteger (bi - b2i) :: Mod n) (fromInteger (ai - a2i))+      | xi == x2i                           = []+      | otherwise                           = go (step tort) (step (step hare))+    runPollard        = filter check . begin . initialise
+ Math/NumberTheory/Moduli/Equations.hs view
@@ -0,0 +1,137 @@+-- |+-- Module:      Math.NumberTheory.Moduli.Equations+-- Copyright:   (c) 2018 Andrew Lelechenko+-- Licence:     MIT+-- Maintainer:  Andrew Lelechenko <andrew.lelechenko@gmail.com>+-- Stability:   Provisional+-- Portability: Non-portable (GHC extensions)+--+-- Polynomial modular equations.+--++{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE ViewPatterns        #-}++module Math.NumberTheory.Moduli.Equations+  ( solveLinear+  , solveQuadratic+  ) where++import GHC.Integer.GMP.Internals++import Math.NumberTheory.Moduli.Chinese+import Math.NumberTheory.Moduli.Class+import Math.NumberTheory.Moduli.Sqrt+import Math.NumberTheory.UniqueFactorisation+import Math.NumberTheory.Utils (recipMod)++-------------------------------------------------------------------------------+-- Linear equations++-- | Find all solutions of ax + b ≡ 0 (mod m).+--+-- >>> :set -XDataKinds+-- >>> solveLinear (6 :: Mod 10) 4 -- solving 6x + 4 ≡ 0 (mod 10)+-- [(1 `modulo` 10),(6 `modulo` 10)]+solveLinear+  :: KnownNat m+  => Mod m   -- ^ a+  -> Mod m   -- ^ b+  -> [Mod m] -- ^ list of x+solveLinear a b = map fromInteger $ solveLinear' (getMod a) (getVal a) (getVal b)++solveLinear' :: Integer -> Integer -> Integer -> [Integer]+solveLinear' m a b = case solveLinearCoprime m' (a `quot` d) (b `quot` d) of+  Nothing -> []+  Just x  -> map (\i -> x + m' * i) [0 .. d - 1]+  where+    d = m `gcd` a `gcd` b+    m' = m `quot` d++solveLinearCoprime :: Integer -> Integer -> Integer -> Maybe Integer+solveLinearCoprime 1 _ _ = Just 0+solveLinearCoprime m a b = (\a1 -> negate b * a1 `mod` m) <$> recipMod a m++-------------------------------------------------------------------------------+-- Quadratic equations++-- | Find all solutions of ax² + bx + c ≡ 0 (mod m).+--+-- >>> :set -XDataKinds+-- >>> solveQuadratic (1 :: Mod 32) 0 (-17) -- solving x² - 17 ≡ 0 (mod 32)+-- [(9 `modulo` 32),(25 `modulo` 32),(7 `modulo` 32),(23 `modulo` 32)]+solveQuadratic+  :: KnownNat m+  => Mod m   -- ^ a+  -> Mod m   -- ^ b+  -> Mod m   -- ^ c+  -> [Mod m] -- ^ list of c+solveQuadratic a b c+  = map fromInteger+  $ fst+  $ combine+  $ map (\(p, n) -> (solveQuadraticPrimePower a' b' c' p n, unPrime p ^ n))+  $ factorise+  $ getMod a+  where+    a' = getVal a+    b' = getVal b+    c' = getVal c++    combine :: [([Integer], Integer)] -> ([Integer], Integer)+    combine = foldl+      (\(xs, xm) (ys, ym) -> ([ chineseRemainder2 (x, xm) (y, ym) | x <- xs, y <- ys ], xm * ym))+      ([0], 1)++solveQuadraticPrimePower+  :: Integer+  -> Integer+  -> Integer+  -> Prime Integer+  -> Word+  -> [Integer]+solveQuadraticPrimePower a b c p = go+  where+    go :: Word -> [Integer]+    go 0 = [0]+    go 1 = solveQuadraticPrime a b c p+    go k = concatMap (liftRoot k) (go (k - 1))++    -- Hensel lifting+    -- https://en.wikipedia.org/wiki/Hensel%27s_lemma#Hensel_lifting+    liftRoot :: Word -> Integer -> [Integer]+    liftRoot k r = case recipMod (2 * a * r + b) pk of+      Nothing -> case fr of+        0 -> map (\i -> r + pk `quot` p' * i) [0 .. p' - 1]+        _ -> []+      Just invDeriv -> [(r - fr * invDeriv) `mod` pk]+      where+        pk = p' ^ k+        fr = (a * r * r + b * r + c) `mod` pk++    p' :: Integer+    p' = unPrime p++solveQuadraticPrime+  :: Integer+  -> Integer+  -> Integer+  -> Prime Integer+  -> [Integer]+solveQuadraticPrime a b c (unPrime -> 2 :: Integer)+  = case (even c, even (a + b)) of+    (True, True) -> [0, 1]+    (True, _)    -> [0]+    (_, False)   -> [1]+    _            -> []+solveQuadraticPrime a b c p+  | a `mod` p' == 0+  = solveLinear' p' b c+  | otherwise+  = map (\n -> n * recipModInteger (2 * a) p' `mod` p')+  $ map (subtract b)+  $ sqrtsModPrime (b * b - 4 * a * c) p+    where+      p' :: Integer+      p' = unPrime p+
Math/NumberTheory/Moduli/Jacobi.hs view
@@ -1,36 +1,38 @@ -- | -- Module:      Math.NumberTheory.Moduli.Jacobi--- Copyright:   (c) 2011 Daniel Fischer, 2017 Andrew Lelechenko+-- Copyright:   (c) 2011 Daniel Fischer, 2017-2018 Andrew Lelechenko -- Licence:     MIT -- Maintainer:  Andrew Lelechenko <andrew.lelechenko@gmail.com> -- Stability:   Provisional -- Portability: Non-portable (GHC extensions) ----- Jacobi symbol.+-- <https://en.wikipedia.org/wiki/Jacobi_symbol Jacobi symbol>+-- is a generalization of the Legendre symbol, useful for primality+-- testing and integer factorization. -- -{-# LANGUAGE CPP        #-}-{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE CPP          #-}+{-# LANGUAGE LambdaCase   #-} +{-# OPTIONS_GHC -fno-warn-deprecations  #-}+ module Math.NumberTheory.Moduli.Jacobi   ( JacobiSymbol(..)   , jacobi   , jacobi'   ) where -import Data.Array.Unboxed import Data.Bits #if __GLASGOW_HASKELL__ < 803 import Data.Semigroup #endif-#if __GLASGOW_HASKELL__ < 709-import Data.Word-#endif+import Numeric.Natural -import Math.NumberTheory.Unsafe import Math.NumberTheory.Utils --- | Type for result of 'jacobi'.+-- | Represents three possible values of+-- <https://en.wikipedia.org/wiki/Jacobi_symbol Jacobi symbol>. data JacobiSymbol = MinusOne | Zero | One   deriving (Eq, Ord, Show) @@ -50,103 +52,73 @@   Zero     -> Zero   One      -> MinusOne --- | Jacobi symbol of two numbers.---   The \"denominator\" must be odd and positive, this condition is checked.+-- | <https://en.wikipedia.org/wiki/Jacobi_symbol Jacobi symbol> of two arguments.+-- The lower argument (\"denominator\") must be odd and positive,+-- this condition is checked. -----   If both numbers have a common prime factor, the result---   is @0@, otherwise it is &#177;1.+-- If arguments have a common factor, the result+-- is 'Zero', otherwise it is 'MinusOne' or 'One'.+--+-- >>> jacobi 1001 9911+-- Zero -- arguments have a common factor 11+-- >>> jacobi 1001 9907+-- MinusOne {-# SPECIALISE jacobi :: Integer -> Integer -> JacobiSymbol,+                         Natural -> Natural -> JacobiSymbol,                          Int -> Int -> JacobiSymbol,                          Word -> Word -> JacobiSymbol   #-} jacobi :: (Integral a, Bits a) => a -> a -> JacobiSymbol+jacobi _ 1 = One jacobi a b-  | b < 0       = error "Math.NumberTheory.Moduli.jacobi: negative denominator"-  | evenI b     = error "Math.NumberTheory.Moduli.jacobi: even denominator"-  | b == 1      = One-  | otherwise   = jacobi' a b   -- b odd, > 1+  | b < 0     = error "Math.NumberTheory.Moduli.jacobi: negative denominator"+  | evenI b   = error "Math.NumberTheory.Moduli.jacobi: even denominator"+  | otherwise = jacobi' a b   -- b odd, > 1 --- Invariant: b > 1 and odd--- | Jacobi symbol of two numbers without validity check of---   the \"denominator\".-{-# SPECIALISE jacobi' :: Integer -> Integer -> JacobiSymbol,-                          Int -> Int -> JacobiSymbol,-                          Word -> Word -> JacobiSymbol-  #-} jacobi' :: (Integral a, Bits a) => a -> a -> JacobiSymbol+jacobi' 0 _ = Zero+jacobi' 1 _ = One jacobi' a b-  | a == 0      = Zero-  | a == 1      = One-  | a < 0       = let n | rem4 b == 1 = One-                        | otherwise   = MinusOne-                      -- Blech, minBound may pose problems-                      (z,o) = shiftToOddCount (abs $ toInteger a)-                      s | evenI z || unsafeAt jac2 (rem8 b) == 1 = n-                        | otherwise                              = negJS n-                  in s <> jacobi' (fromInteger o) b-  | a >= b      = case a `rem` b of-                    0 -> Zero-                    r -> jacPS One r b-  | evenI a     = case shiftToOddCount a of-                    (z,o) -> let r | rem4 o .&. rem4 b == 1 = One-                                   | otherwise              = MinusOne-                                 s | evenI z || unsafeAt jac2 (rem8 b) == 1 = r-                                   | otherwise                              = negJS r-                             in jacOL s b o-  | otherwise   = case rem4 a .&. rem4 b of-                    3 -> jacOL MinusOne b a-                    _ -> jacOL One      b a+  | a < 0     = let n = if rem4is3 b then MinusOne else One+                    (z, o) = shiftToOddCount (negate a)+                    s = if evenI z || rem8is1or7 b then n else negJS n+                in s <> jacobi' o b+  | a >= b    = case a `rem` b of+                  0 -> Zero+                  r -> jacPS One r b+  | evenI a   = case shiftToOddCount a of+                  (z, o) -> let r = if rem4is3 o && rem4is3 b then MinusOne else One+                                s = if evenI z || rem8is1or7 b then r else negJS r+                            in jacOL s b o+  | otherwise = jacOL (if rem4is3 a && rem4is3 b then MinusOne else One) b a+{-# DEPRECATED jacobi' "Use 'jacobi' instead" #-}  -- numerator positive and smaller than denominator-{-# SPECIALISE jacPS :: JacobiSymbol -> Integer -> Integer -> JacobiSymbol,-                        JacobiSymbol -> Int -> Int -> JacobiSymbol,-                        JacobiSymbol -> Word -> Word -> JacobiSymbol-  #-} jacPS :: (Integral a, Bits a) => JacobiSymbol -> a -> a -> JacobiSymbol-jacPS j a b-  | evenI a     = case shiftToOddCount a of-                    (z,o) | evenI z || unsafeAt jac2 (rem8 b) == 1 ->-                              jacOL (if rem4 o .&. rem4 b == 3 then (negJS j) else j) b o-                          | otherwise ->-                              jacOL (if rem4 o .&. rem4 b == 3 then j else (negJS j)) b o-  | otherwise   = jacOL (if rem4 a .&. rem4 b == 3 then (negJS j) else j) b a+jacPS !acc a b+  | evenI a = case shiftToOddCount a of+    (z, o)+      | evenI z || rem8is1or7 b -> jacOL (if rem4is3 o && rem4is3 b then negJS acc else acc) b o+      | otherwise               -> jacOL (if rem4is3 o && rem4is3 b then acc else negJS acc) b o+  | otherwise = jacOL (if rem4is3 a && rem4is3 b then negJS acc else acc) b a  -- numerator odd, positive and larger than denominator-{-# SPECIALISE jacOL :: JacobiSymbol -> Integer -> Integer -> JacobiSymbol,-                        JacobiSymbol -> Int -> Int -> JacobiSymbol,-                        JacobiSymbol -> Word -> Word -> JacobiSymbol-  #-} jacOL :: (Integral a, Bits a) => JacobiSymbol -> a -> a -> JacobiSymbol-jacOL j a b-  | b == 1    = j-  | otherwise = case a `rem` b of-                 0 -> Zero-                 r -> jacPS j r b+jacOL !acc _ 1 = acc+jacOL !acc a b = case a `rem` b of+  0 -> Zero+  r -> jacPS acc r b  -- Utilities --- For large Integers, going via Int is much faster than bit-fiddling--- on the Integer, so we do that.-{-# SPECIALISE evenI :: Integer -> Bool,-                        Int -> Bool,-                        Word -> Bool-  #-}-evenI :: Integral a => a -> Bool-evenI n = fromIntegral n .&. 1 == (0 :: Int)--{-# SPECIALISE rem4 :: Integer -> Int,-                       Int -> Int,-                       Word -> Int-  #-}-rem4 :: Integral a => a -> Int-rem4 n = fromIntegral n .&. 3+-- Sadly, GHC do not optimise `Prelude.even` to a bit test automatically.+evenI :: Bits a => a -> Bool+evenI n = not (n `testBit` 0) -{-# SPECIALISE rem8 :: Integer -> Int,-                       Int -> Int,-                       Word -> Int-  #-}-rem8 :: Integral a => a -> Int-rem8 n = fromIntegral n .&. 7+-- For an odd input @n@ test whether n `rem` 4 == 1+rem4is3 :: Bits a => a -> Bool+rem4is3 n = n `testBit` 1 -jac2 :: UArray Int Int-jac2 = array (0,7) [(0,0),(1,1),(2,0),(3,-1),(4,0),(5,-1),(6,0),(7,1)]+-- For an odd input @n@ test whether (n `rem` 8) `elem` [1, 7]+rem8is1or7 :: Bits a => a -> Bool+rem8is1or7 n = n `testBit` 1 == n `testBit` 2
Math/NumberTheory/Moduli/PrimitiveRoot.hs view
@@ -10,6 +10,7 @@ --  {-# LANGUAGE CPP                  #-}+{-# LANGUAGE DeriveGeneric        #-} {-# LANGUAGE FlexibleContexts     #-} {-# LANGUAGE LambdaCase           #-} {-# LANGUAGE StandaloneDeriving   #-}@@ -17,27 +18,38 @@ {-# LANGUAGE UndecidableInstances #-}  module Math.NumberTheory.Moduli.PrimitiveRoot-  ( isPrimitiveRoot-    -- * Cyclic groups-  , CyclicGroup(..)+  ( -- * Cyclic groups+    CyclicGroup(..)   , cyclicGroupFromModulo   , cyclicGroupToModulo+  , groupSize+    -- * Primitive roots+  , PrimitiveRoot+  , unPrimitiveRoot+  , getGroup+  , isPrimitiveRoot   , isPrimitiveRoot'   ) where -#if !(MIN_VERSION_base(4,8,0))-import Control.Applicative-import Data.Word+#if __GLASGOW_HASKELL__ < 803+import Data.Semigroup #endif  import Math.NumberTheory.ArithmeticFunctions (totient)-import Math.NumberTheory.Moduli (Mod, getNatMod, getNatVal, KnownNat)+import qualified Math.NumberTheory.Euclidean as E+import Math.NumberTheory.Euclidean.Coprimes as Coprimes (singleton)+import Math.NumberTheory.Moduli.Class (getNatMod, getNatVal, KnownNat, Mod, MultMod, isMultElement) import Math.NumberTheory.Powers.General (highestPower) import Math.NumberTheory.Powers.Modular import Math.NumberTheory.Prefactored import Math.NumberTheory.UniqueFactorisation import Math.NumberTheory.Utils.FromIntegral +import Control.DeepSeq+import Control.Monad (guard)+import GHC.Generics+import Numeric.Natural+ -- | A multiplicative group of residues is called cyclic, -- if there is a primitive root @g@, -- whose powers generates all elements.@@ -50,18 +62,22 @@   -- ^ Residues modulo @p@^@k@ for __odd__ prime @p@.   | CGDoubleOddPrimePower (Prime a) Word   -- ^ Residues modulo 2@p@^@k@ for __odd__ prime @p@.+  deriving (Generic) +instance NFData (Prime a) => NFData (CyclicGroup a)++deriving instance Eq   (Prime a) => Eq   (CyclicGroup a) deriving instance Show (Prime a) => Show (CyclicGroup a)  -- | Check whether a multiplicative group of residues, -- characterized by its modulo, is cyclic and, if yes, return its form. ----- > > cyclicGroupFromModulo 4--- > Just CG4--- > > cyclicGroupFromModulo (2 * 13 ^ 3)--- > Just (CGDoubleOddPrimePower (PrimeNat 13) 3)--- > > cyclicGroupFromModulo (4 * 13)--- > Nothing+-- >>> cyclicGroupFromModulo 4+-- Just CG4+-- >>> cyclicGroupFromModulo (2 * 13 ^ 3)+-- Just (CGDoubleOddPrimePower (PrimeNat 13) 3)+-- >>> cyclicGroupFromModulo (4 * 13)+-- Nothing cyclicGroupFromModulo   :: (Ord a, Integral a, UniqueFactorisation a)   => a@@ -88,61 +104,86 @@ -- | Extract modulo and its factorisation from -- a cyclic multiplicative group of residues. ----- > > cyclicGroupToModulo CG4--- > Prefactored {prefValue = 4, prefFactors = [(2, 2)]}--- > > cyclicGroupToModulo (CGDoubleOddPrimePower (PrimeNat 13) 3)--- > Prefactored {prefValue = 4394, prefFactors = [(2, 1), (13, 3)]}+-- >>> cyclicGroupToModulo CG4+-- Prefactored {prefValue = 4, prefFactors = Coprimes {unCoprimes = fromList [(2,2)]}}+--+-- >>> :set -XTypeFamilies+-- >>> cyclicGroupToModulo (CGDoubleOddPrimePower (PrimeNat 13) 3)+-- Prefactored {prefValue = 4394, prefFactors = Coprimes {unCoprimes = fromList [(2,1),(13,3)]}} cyclicGroupToModulo-  :: (Integral a, UniqueFactorisation a)+  :: (E.Euclidean a, Ord a, UniqueFactorisation a)   => CyclicGroup a   -> Prefactored a cyclicGroupToModulo = fromFactors . \case-  CG2                       -> [(2, 1)]-  CG4                       -> [(2, 2)]-  CGOddPrimePower p k       -> [(unPrime p, k)]-  CGDoubleOddPrimePower p k -> [(2, 1), (unPrime p, k)]+  CG2                       -> Coprimes.singleton 2 1+  CG4                       -> Coprimes.singleton 2 2+  CGOddPrimePower p k       -> Coprimes.singleton (unPrime p) k+  CGDoubleOddPrimePower p k -> Coprimes.singleton 2 1+                            <> Coprimes.singleton (unPrime p) k +-- | 'PrimitiveRoot m' is a type which is only inhabited by primitive roots of n.+data PrimitiveRoot m = PrimitiveRoot+  { unPrimitiveRoot :: MultMod m -- ^ Extract primitive root value.+  , getGroup        :: CyclicGroup Natural -- ^ Get cyclic group structure.+  }+  deriving (Eq, Show)+ -- | 'isPrimitiveRoot'' @cg@ @a@ checks whether @a@ is -- a <https://en.wikipedia.org/wiki/Primitive_root_modulo_n primitive root> -- of a given cyclic multiplicative group of residues @cg@. ----- > > let Just cg = cyclicGroupFromModulo 13--- > > isPrimitiveRoot cg 1--- > False--- > > isPrimitiveRoot cg 2--- > True+-- >>> let Just cg = cyclicGroupFromModulo 13+-- >>> isPrimitiveRoot' cg 1+-- False+-- >>> isPrimitiveRoot' cg 2+-- True isPrimitiveRoot'   :: (Integral a, UniqueFactorisation a)   => CyclicGroup a   -> a   -> Bool-isPrimitiveRoot' cg r = r /= 0 && gcd r (prefValue m) == 1 && all (/= 1) exps+-- https://en.wikipedia.org/wiki/Primitive_root_modulo_n#Finding_primitive_roots+isPrimitiveRoot' cg r =+  case cg of+    CG2                       -> r == 1+    CG4                       -> r == 3+    CGOddPrimePower p k       -> oddPrimePowerTest (unPrime p) k r+    CGDoubleOddPrimePower p k -> doubleOddPrimePowerTest (unPrime p) k r   where-    -- https://en.wikipedia.org/wiki/Primitive_root_modulo_n#Finding_primitive_roots-    m    = cyclicGroupToModulo cg-    phi  = totient m-    pows = map (\pk -> prefValue phi `quot` unPrime (fst pk)) (factorise phi)-    exps = map (\p -> powMod r p (prefValue m)) pows+    oddPrimeTest p g              = let phi  = totient p+                                        pows = map (\pk -> phi `quot` unPrime (fst pk)) (factorise phi)+                                        exps = map (\x -> powMod g x p) pows+                                     in g /= 0 && gcd g p == 1 && all (/= 1) exps+    oddPrimePowerTest p 1 g       = oddPrimeTest p (g `mod` p)+    oddPrimePowerTest p _ g       = oddPrimeTest p (g `mod` p) && powMod g (p-1) (p*p) /= 1+    doubleOddPrimePowerTest p k g = odd g && oddPrimePowerTest p k g  -- | Check whether a given modular residue is -- a <https://en.wikipedia.org/wiki/Primitive_root_modulo_n primitive root>. ----- > > isPrimitiveRoot (1 :: Mod 13)--- > False--- > > isPrimitiveRoot (2 :: Mod 13)--- > True+-- >>> :set -XDataKinds+-- >>> isPrimitiveRoot (1 :: Mod 13)+-- False+-- >>> isPrimitiveRoot (2 :: Mod 13)+-- True -- -- Here is how to list all primitive roots: ----- > > filter isPrimitiveRoot [minBound .. maxBound] :: [Mod 13]--- > [(2 `modulo` 13), (6 `modulo` 13), (7 `modulo` 13), (11 `modulo` 13)]+-- >>> mapMaybe isPrimitiveRoot [minBound .. maxBound] :: [Mod 13]+-- [(2 `modulo` 13), (6 `modulo` 13), (7 `modulo` 13), (11 `modulo` 13)] -- -- This function is a convenient wrapper around 'isPrimitiveRoot''. The latter -- provides better control and performance, if you need them. isPrimitiveRoot   :: KnownNat n   => Mod n-  -> Bool-isPrimitiveRoot r = case cyclicGroupFromModulo (getNatMod r) of-  Nothing -> False-  Just cg -> isPrimitiveRoot' cg (getNatVal r)+  -> Maybe (PrimitiveRoot n)+isPrimitiveRoot r = do+  r' <- isMultElement r+  cg <- cyclicGroupFromModulo (getNatMod r)+  guard $ isPrimitiveRoot' cg (getNatVal r)+  return $ PrimitiveRoot r' cg++-- | Calculate the size of a given cyclic group.+groupSize :: (E.Euclidean a, Ord a, UniqueFactorisation a) => CyclicGroup a -> Prefactored a+groupSize = totient . cyclicGroupToModulo
Math/NumberTheory/Moduli/Sqrt.hs view
@@ -10,86 +10,160 @@ --  {-# LANGUAGE BangPatterns #-}+{-# LANGUAGE ViewPatterns #-} {-# LANGUAGE CPP          #-}  module Math.NumberTheory.Moduli.Sqrt-  ( sqrtModP-  , sqrtModPList-  , sqrtModP'-  , tonelliShanks-  , sqrtModPP-  , sqrtModPPList-  , sqrtModF-  , sqrtModFList+  ( -- * New interface+    sqrtsMod+  , sqrtsModFactorisation+  , sqrtsModPrimePower+  , sqrtsModPrime+    -- * Old interface+  , Old.sqrtModP+  , Old.sqrtModPList+  , Old.sqrtModP'+  , Old.tonelliShanks+  , Old.sqrtModPP+  , Old.sqrtModPPList+  , Old.sqrtModF+  , Old.sqrtModFList   ) where +import Control.Arrow hiding (loop) import Control.Monad (liftM2) import Data.Bits-import Data.List (nub)-#if __GLASGOW_HASKELL__ < 709-import Data.Word-#endif-import GHC.Integer.GMP.Internals  import Math.NumberTheory.Moduli.Chinese+import Math.NumberTheory.Moduli.Class (Mod, getVal, getMod, KnownNat) import Math.NumberTheory.Moduli.Jacobi+import Math.NumberTheory.Powers.Modular (powMod)+import qualified Math.NumberTheory.Primes.Factorisation as F (factorise)+import Math.NumberTheory.Primes.Types import Math.NumberTheory.Primes.Sieve (sieveFrom)-import Math.NumberTheory.Utils (shiftToOddCount, splitOff)+import Math.NumberTheory.Utils (shiftToOddCount, splitOff, recipMod)+import Math.NumberTheory.Utils.FromIntegral --- | @sqrtModP n prime@ calculates a modular square root of @n@ modulo @prime@---   if that exists. The second argument /must/ be a (positive) prime, otherwise---   the computation may not terminate and if it does, may yield a wrong result.---   The precondition is /not/ checked.+import qualified Math.NumberTheory.Moduli.SqrtOld as Old++-- | List all modular square roots. -----   If @prime@ is a prime and @n@ a quadratic residue modulo @prime@, the result---   is @Just r@ where @r^2 ≡ n (mod prime)@, if @n@ is a quadratic nonresidue,---   the result is @Nothing@.-sqrtModP :: Integer -> Integer -> Maybe Integer-sqrtModP n 2 = Just (n `mod` 2)-sqrtModP n prime = case jacobi' n prime of-                     MinusOne -> Nothing-                     Zero     -> Just 0-                     One      -> Just (sqrtModP' (n `mod` prime) prime)+-- >>> :set -XDataKinds+-- >>> sqrtsMod (1 :: Mod 60)+-- > [(1 `modulo` 60),(49 `modulo` 60),(41 `modulo` 60),(29 `modulo` 60),(31 `modulo` 60),(19 `modulo` 60),(11 `modulo` 60),(59 `modulo` 60)]+sqrtsMod :: KnownNat m => Mod m -> [Mod m]+sqrtsMod a = map fromInteger $ sqrtsModFactorisation (getVal a) (factorise (getMod a))+  where+    factorise = map (PrimeNat . integerToNatural *** intToWord) . F.factorise --- | @sqrtModPList n prime@ computes the list of all square roots of @n@---   modulo @prime@. @prime@ /must/ be a (positive) prime.---   The precondition is /not/ checked.-sqrtModPList :: Integer -> Integer -> [Integer]-sqrtModPList n prime-    | prime == 2    = [n `mod` 2]-    | otherwise     = case sqrtModP n prime of-                        Just 0 -> [0]-                        Just r -> [r,prime-r] -- The group of units in Z/(p) is cyclic-                        _      -> []+-- | List all square roots modulo a number, which factorisation is passed as a second argument.+--+-- >>> sqrtsModFactorisation 1 (factorise 60)+-- [1,49,41,29,31,19,11,59]+sqrtsModFactorisation :: Integer -> [(Prime Integer, Word)] -> [Integer]+sqrtsModFactorisation _ []  = [0]+sqrtsModFactorisation n pps = map fst $ foldl1 (liftM2 comb) cs+  where+    ms :: [Integer]+    ms = map (\(PrimeNat p, pow) -> toInteger p ^ pow) pps +    rs :: [[Integer]]+    rs = map (\(p, pow) -> sqrtsModPrimePower n p pow) pps++    cs :: [[(Integer, Integer)]]+    cs = zipWith (\l m -> map (\x -> (x, m)) l) rs ms++    comb t1@(_, m1) t2@(_, m2) = (chineseRemainder2 t1 t2, m1 * m2)++-- | List all square roots modulo power of a prime.+--+-- >>> sqrtsModPrimePower 7 (fromJust (isPrime 3)) 2+-- [4,5]+-- >>> sqrtsModPrimePower 9 (fromJust (isPrime 3)) 3+-- [3,12,21,24,6,15]+sqrtsModPrimePower :: Integer -> Prime Integer -> Word -> [Integer]+sqrtsModPrimePower nn p 1 = sqrtsModPrime nn p+sqrtsModPrimePower nn (PrimeNat (toInteger -> prime)) expo = let primeExpo = prime ^ expo in+  case splitOff prime (nn `mod` primeExpo) of+    (_, 0) -> [0, prime ^ ((expo + 1) `quot` 2) .. primeExpo - 1]+    (kk, n)+      | odd kk    -> []+      | otherwise -> case (if prime == 2 then sqM2P n expo' else sqrtModPP' n prime expo') of+        Nothing -> []+        Just r  -> let rr = r * prime ^ k in+          if prime == 2 && k + 1 == t+          then go rr os+          else go rr os ++ go (primeExpo - rr) os+      where+        k = intToWord kk `quot` 2+        t = (if prime == 2 then expo - k - 1 else expo - k) `max` ((expo + 1) `quot` 2)+        expo' = expo - 2 * k+        os = [0, prime ^ t .. primeExpo - 1]++        -- equivalent to map ((`mod` primeExpo) . (+ r)) rs,+        -- but avoids division+        go r rs = map (+ r) ps ++ map (+ (r - primeExpo)) qs+          where+            (ps, qs) = span (< primeExpo - r) rs++-- | List all square roots by prime modulo.+--+-- >>> sqrtsModPrime 1 (fromJust (isPrime 5))+-- [1,4]+-- >>> sqrtsModPrime 0 (fromJust (isPrime 5))+-- [0]+-- >>> sqrtsModPrime 2 (fromJust (isPrime 5))+-- []+sqrtsModPrime :: Integer -> Prime Integer -> [Integer]+sqrtsModPrime n (PrimeNat 2) = [n `mod` 2]+sqrtsModPrime n (PrimeNat (toInteger -> prime)) = case jacobi n prime of+  MinusOne -> []+  Zero     -> [0]+  One      -> let r = sqrtModP' (n `mod` prime) prime in [r, prime - r]++-------------------------------------------------------------------------------+-- Internals+ -- | @sqrtModP' square prime@ finds a square root of @square@ modulo --   prime. @prime@ /must/ be a (positive) prime, and @square@ /must/ be a positive --   quadratic residue modulo @prime@, i.e. @'jacobi square prime == 1@.---   The precondition is /not/ checked. sqrtModP' :: Integer -> Integer -> Integer sqrtModP' square prime     | prime == 2    = square-    | rem4 prime == 3 = powModInteger square ((prime + 1) `quot` 4) prime+    | rem4 prime == 3 = powMod square ((prime + 1) `quot` 4) prime+    | square `mod` prime == prime - 1+                    = sqrtOfMinusOne prime     | otherwise     = tonelliShanks square prime +-- | p must be of form 4k + 1+sqrtOfMinusOne :: Integer -> Integer+sqrtOfMinusOne p+  = head+  $ filter (\n -> n /= 1 && n /= p - 1)+  $ map (\n -> powMod n k p)+    [2..p-2]+  where+    k = (p - 1) `quot` 4+ -- | @tonelliShanks square prime@ calculates a square root of @square@ --   modulo @prime@, where @prime@ is a prime of the form @4*k + 1@ and --   @square@ is a positive quadratic residue modulo @prime@, using the --   Tonelli-Shanks algorithm.---   No checks on the input are performed. tonelliShanks :: Integer -> Integer -> Integer tonelliShanks square prime = loop rc t1 generator log2   where     (log2,q) = shiftToOddCount (prime-1)     nonSquare = findNonSquare prime-    generator = powModInteger nonSquare q prime-    rc = powModInteger square ((q+1) `quot` 2) prime-    t1 = powModInteger square q prime+    generator = powMod nonSquare q prime+    rc = powMod square ((q+1) `quot` 2) prime+    t1 = powMod square q prime     msqr x = (x*x) `rem` prime     msquare 0 x = x     msquare k x = msquare (k-1) (msqr x)     findPeriod per 1 = per     findPeriod per x = findPeriod (per+1) (msqr x)++    loop :: Integer -> Integer -> Integer -> Int -> Integer     loop !r t c m         | t == 1    = r         | otherwise = loop nextR nextT nextC nextM@@ -100,26 +174,22 @@             nextC = msqr b             nextT = (t*nextC) `rem` prime --- | @sqrtModPP n (prime,expo)@ calculates a square root of @n@---   modulo @prime^expo@ if one exists. @prime@ /must/ be a---   (positive) prime. @expo@ must be positive, @n@ must be coprime---   to @prime@-sqrtModPP :: Integer -> (Integer,Int) -> Maybe Integer-sqrtModPP n (2,e) = sqM2P n e-sqrtModPP n (prime,expo) = case sqrtModP n prime of-                             Just r -> fixup r-                             _      -> Nothing+-- | prime must be odd, n must be coprime with prime+sqrtModPP' :: Integer -> Integer -> Word -> Maybe Integer+sqrtModPP' n prime expo = case sqrtsModPrime n (PrimeNat (fromInteger prime)) of+                            []    -> Nothing+                            r : _ -> fixup r   where     fixup r = let diff' = r*r-n               in if diff' == 0                    then Just r                    else case splitOff prime diff' of-                          (e,q) | expo <= e -> Just r+                          (e,q) | expo <= intToWord e -> Just r                                 | otherwise -> fmap (\inv -> hoist inv r (q `mod` prime) (prime^e)) (recipMod (2*r) prime)      hoist inv root elim pp         | diff' == 0    = root'-        | expo <= ex    = root'+        | expo <= intToWord ex    = root'         | otherwise     = hoist inv root' (nelim `mod` prime) (prime^ex)           where             root' = (root + (inv*(prime-elim))*pp) `mod` (prime*pp)@@ -127,8 +197,8 @@             (ex, nelim) = splitOff prime diff'  -- dirty, dirty-sqM2P :: Integer -> Int -> Maybe Integer-sqM2P n e+sqM2P :: Integer -> Word -> Maybe Integer+sqM2P n (wordToInt -> e)     | e < 2     = Just (n `mod` 2)     | n' == 0   = Just 0     | odd k     = Nothing@@ -136,9 +206,9 @@       where         mdl = 1 `shiftL` e         n' = n `mod` mdl-        (k,s) = shiftToOddCount n'+        (k, s) = shiftToOddCount n'         k2 = k `quot` 2-        e2 = e-k+        e2 = e - k         solve _ 1 = Just 1         solve 1 _ = Just 1         solve r _@@ -154,60 +224,12 @@                         d = x'*x' - r                         pw' = if d == 0 then e2 else fst (shiftToOddCount d) --- | @sqrtModF n primePowers@ calculates a square root of @n@ modulo---   @product [p^k | (p,k) <- primePowers]@ if one exists and all primes---   are distinct.---   The list must be non-empty, @n@ must be coprime with all primes.-sqrtModF :: Integer -> [(Integer,Int)] -> Maybe Integer-sqrtModF _ []  = Nothing-sqrtModF n pps = do roots <- mapM (sqrtModPP n) pps-                    chineseRemainder $ zip roots (map (uncurry (^)) pps)---- | @sqrtModFList n primePowers@ calculates all square roots of @n@ modulo---   @product [p^k | (p,k) <- primePowers]@ if all primes are distinct.---   The list must be non-empty, @n@ must be coprime with all primes.-sqrtModFList :: Integer -> [(Integer,Int)] -> [Integer]-sqrtModFList _ []  = []-sqrtModFList n pps = map fst $ foldl1 (liftM2 comb) cs-  where-    ms :: [Integer]-    ms = map (uncurry (^)) pps-    rs :: [[Integer]]-    rs = map (sqrtModPPList n) pps-    cs :: [[(Integer,Integer)]]-    cs = zipWith (\l m -> map (\x -> (x,m)) l) rs ms-    comb t1@(_,m1) t2@(_,m2) = (chineseRemainder2 t1 t2,m1*m2)---- | @sqrtModPPList n (prime,expo)@ calculates the list of all---   square roots of @n@ modulo @prime^expo@. The same restriction---   as in 'sqrtModPP' applies to the arguments.-sqrtModPPList :: Integer -> (Integer,Int) -> [Integer]-sqrtModPPList n (2,1) = [n `mod` 2]-sqrtModPPList n (2,expo)-    = case sqM2P n expo of-        Just r -> let m = 1 `shiftL` (expo-1)-                  in nub [r, (r+m) `mod` (2*m), (m-r) `mod` (2*m), 2*m-r]-        _ -> []-sqrtModPPList n pe@(prime,expo)-    = case sqrtModPP n pe of-        Just 0 -> [0]-        Just r -> [prime^expo - r, r] -- The group of units in Z/(p^e) is cyclic-        _      -> []--+------------------------------------------------------------------------------- -- Utilities -{-# SPECIALISE rem4 :: Integer -> Int,-                       Int -> Int,-                       Word -> Int-  #-} rem4 :: Integral a => a -> Int rem4 n = fromIntegral n .&. 3 -{-# SPECIALISE rem8 :: Integer -> Int,-                       Int -> Int,-                       Word -> Int-  #-} rem8 :: Integral a => a -> Int rem8 n = fromIntegral n .&. 7 @@ -218,12 +240,7 @@       where         primelist = [3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67]                         ++ sieveFrom (68 + n `rem` 4) -- prevent sharing-        search (p:ps) = case jacobi' p n of+        search (p:ps) = case jacobi p n of           MinusOne -> p           _        -> search ps         search _ = error "Should never have happened, prime list exhausted."--recipMod :: Integer -> Integer -> Maybe Integer-recipMod x m = case recipModInteger x m of-  0 -> Nothing-  y -> Just y
+ Math/NumberTheory/Moduli/SqrtOld.hs view
@@ -0,0 +1,234 @@+-- |+-- Module:      Math.NumberTheory.Moduli.Sqrt+-- Copyright:   (c) 2011 Daniel Fischer+-- Licence:     MIT+-- Maintainer:  Andrew Lelechenko <andrew.lelechenko@gmail.com>+-- Stability:   Provisional+-- Portability: Non-portable (GHC extensions)+--+-- Modular square roots.+--++{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE CPP          #-}++module Math.NumberTheory.Moduli.SqrtOld+  ( sqrtModP+  , sqrtModPList+  , sqrtModP'+  , tonelliShanks+  , sqrtModPP+  , sqrtModPPList+  , sqrtModF+  , sqrtModFList+  ) where++import Control.Monad (liftM2)+import Data.Bits+import Data.List (nub)+#if __GLASGOW_HASKELL__ < 709+import Data.Word+#endif+import GHC.Integer.GMP.Internals++import Math.NumberTheory.Moduli.Chinese+import Math.NumberTheory.Moduli.Jacobi+import Math.NumberTheory.Primes.Sieve (sieveFrom)+import Math.NumberTheory.Utils (shiftToOddCount, splitOff)++{-# DEPRECATED sqrtModP, sqrtModP', sqrtModPList, tonelliShanks "Use 'Math.NumberTheory.Moduli.Sqrt.sqrtsModPrime' instead" #-}+{-# DEPRECATED sqrtModPP, sqrtModPPList "Use 'Math.NumberTheory.Moduli.Sqrt.sqrtsModPrimePower' instead" #-}+{-# DEPRECATED sqrtModF, sqrtModFList "Use 'Math.NumberTheory.Moduli.Sqrt.sqrtsModFactorisation' or 'Math.NumberTheory.Moduli.Sqrt.sqrtsMod' instead" #-}+++-- | @sqrtModP n prime@ calculates a modular square root of @n@ modulo @prime@+--   if that exists. The second argument /must/ be a (positive) prime, otherwise+--   the computation may not terminate and if it does, may yield a wrong result.+--   The precondition is /not/ checked.+--+--   If @prime@ is a prime and @n@ a quadratic residue modulo @prime@, the result+--   is @Just r@ where @r^2 ≡ n (mod prime)@, if @n@ is a quadratic nonresidue,+--   the result is @Nothing@.+sqrtModP :: Integer -> Integer -> Maybe Integer+sqrtModP n 2 = Just (n `mod` 2)+sqrtModP n prime = case jacobi n prime of+                     MinusOne -> Nothing+                     Zero     -> Just 0+                     One      -> Just (sqrtModP' (n `mod` prime) prime)++-- | @sqrtModPList n prime@ computes the list of all square roots of @n@+--   modulo @prime@. @prime@ /must/ be a (positive) prime.+--   The precondition is /not/ checked.+sqrtModPList :: Integer -> Integer -> [Integer]+sqrtModPList n prime+    | prime == 2    = [n `mod` 2]+    | otherwise     = case sqrtModP n prime of+                        Just 0 -> [0]+                        Just r -> [r,prime-r] -- The group of units in Z/(p) is cyclic+                        _      -> []++-- | @sqrtModP' square prime@ finds a square root of @square@ modulo+--   prime. @prime@ /must/ be a (positive) prime, and @square@ /must/ be a positive+--   quadratic residue modulo @prime@, i.e. @'jacobi square prime == 1@.+--   The precondition is /not/ checked.+sqrtModP' :: Integer -> Integer -> Integer+sqrtModP' square prime+    | prime == 2    = square+    | rem4 prime == 3 = powModInteger square ((prime + 1) `quot` 4) prime+    | otherwise     = tonelliShanks square prime++-- | @tonelliShanks square prime@ calculates a square root of @square@+--   modulo @prime@, where @prime@ is a prime of the form @4*k + 1@ and+--   @square@ is a positive quadratic residue modulo @prime@, using the+--   Tonelli-Shanks algorithm.+--   No checks on the input are performed.+tonelliShanks :: Integer -> Integer -> Integer+tonelliShanks square prime = loop rc t1 generator log2+  where+    (log2,q) = shiftToOddCount (prime-1)+    nonSquare = findNonSquare prime+    generator = powModInteger nonSquare q prime+    rc = powModInteger square ((q+1) `quot` 2) prime+    t1 = powModInteger square q prime+    msqr x = (x*x) `rem` prime+    msquare 0 x = x+    msquare k x = msquare (k-1) (msqr x)+    findPeriod per 1 = per+    findPeriod per x = findPeriod (per+1) (msqr x)+    loop !r t c m+        | t == 1    = r+        | otherwise = loop nextR nextT nextC nextM+          where+            nextM = findPeriod 0 t+            b     = msquare (m - 1 - nextM) c+            nextR = (r*b) `rem` prime+            nextC = msqr b+            nextT = (t*nextC) `rem` prime++-- | @sqrtModPP n (prime,expo)@ calculates a square root of @n@+--   modulo @prime^expo@ if one exists. @prime@ /must/ be a+--   (positive) prime. @expo@ must be positive, @n@ must be coprime+--   to @prime@+sqrtModPP :: Integer -> (Integer,Int) -> Maybe Integer+sqrtModPP n (2,e) = sqM2P n e+sqrtModPP n (prime,expo) = case sqrtModP n prime of+                             Just r -> fixup r+                             _      -> Nothing+  where+    fixup r = let diff' = r*r-n+              in if diff' == 0+                   then Just r+                   else case splitOff prime diff' of+                          (e,q) | expo <= e -> Just r+                                | otherwise -> fmap (\inv -> hoist inv r (q `mod` prime) (prime^e)) (recipMod (2*r) prime)++    hoist inv root elim pp+        | diff' == 0    = root'+        | expo <= ex    = root'+        | otherwise     = hoist inv root' (nelim `mod` prime) (prime^ex)+          where+            root' = (root + (inv*(prime-elim))*pp) `mod` (prime*pp)+            diff' = root'*root' - n+            (ex, nelim) = splitOff prime diff'++-- dirty, dirty+sqM2P :: Integer -> Int -> Maybe Integer+sqM2P n e+    | e < 2     = Just (n `mod` 2)+    | n' == 0   = Just 0+    | odd k     = Nothing+    | otherwise = fmap ((`mod` mdl) . (`shiftL` k2)) $ solve s e2+      where+        mdl = 1 `shiftL` e+        n' = n `mod` mdl+        (k,s) = shiftToOddCount n'+        k2 = k `quot` 2+        e2 = e-k+        solve _ 1 = Just 1+        solve 1 _ = Just 1+        solve r _+            | rem4 r == 3   = Nothing  -- otherwise r ≡ 1 (mod 4)+            | rem8 r == 5   = Nothing  -- otherwise r ≡ 1 (mod 8)+            | otherwise     = fixup r (fst $ shiftToOddCount (r-1))+              where+                fixup x pw+                    | pw >= e2  = Just x+                    | otherwise = fixup x' pw'+                      where+                        x' = x + (1 `shiftL` (pw-1))+                        d = x'*x' - r+                        pw' = if d == 0 then e2 else fst (shiftToOddCount d)++-- | @sqrtModF n primePowers@ calculates a square root of @n@ modulo+--   @product [p^k | (p,k) <- primePowers]@ if one exists and all primes+--   are distinct.+--   The list must be non-empty, @n@ must be coprime with all primes.+sqrtModF :: Integer -> [(Integer,Int)] -> Maybe Integer+sqrtModF _ []  = Nothing+sqrtModF n pps = do roots <- mapM (sqrtModPP n) pps+                    chineseRemainder $ zip roots (map (uncurry (^)) pps)++-- | @sqrtModFList n primePowers@ calculates all square roots of @n@ modulo+--   @product [p^k | (p,k) <- primePowers]@ if all primes are distinct.+--   The list must be non-empty, @n@ must be coprime with all primes.+sqrtModFList :: Integer -> [(Integer,Int)] -> [Integer]+sqrtModFList _ []  = []+sqrtModFList n pps = map fst $ foldl1 (liftM2 comb) cs+  where+    ms :: [Integer]+    ms = map (uncurry (^)) pps+    rs :: [[Integer]]+    rs = map (sqrtModPPList n) pps+    cs :: [[(Integer,Integer)]]+    cs = zipWith (\l m -> map (\x -> (x,m)) l) rs ms+    comb t1@(_,m1) t2@(_,m2) = (chineseRemainder2 t1 t2,m1*m2)++-- | @sqrtModPPList n (prime,expo)@ calculates the list of all+--   square roots of @n@ modulo @prime^expo@. The same restriction+--   as in 'sqrtModPP' applies to the arguments.+sqrtModPPList :: Integer -> (Integer,Int) -> [Integer]+sqrtModPPList n (2,1) = [n `mod` 2]+sqrtModPPList n (2,expo)+    = case sqM2P n expo of+        Just r -> let m = 1 `shiftL` (expo-1)+                  in nub [r, (r+m) `mod` (2*m), (m-r) `mod` (2*m), 2*m-r]+        _ -> []+sqrtModPPList n pe@(prime,expo)+    = case sqrtModPP n pe of+        Just 0 -> [0]+        Just r -> [prime^expo - r, r] -- The group of units in Z/(p^e) is cyclic+        _      -> []+++-- Utilities++{-# SPECIALISE rem4 :: Integer -> Int,+                       Int -> Int,+                       Word -> Int+  #-}+rem4 :: Integral a => a -> Int+rem4 n = fromIntegral n .&. 3++{-# SPECIALISE rem8 :: Integer -> Int,+                       Int -> Int,+                       Word -> Int+  #-}+rem8 :: Integral a => a -> Int+rem8 n = fromIntegral n .&. 7++findNonSquare :: Integer -> Integer+findNonSquare n+    | rem8 n == 5 || rem8 n == 3  = 2+    | otherwise = search primelist+      where+        primelist = [3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67]+                        ++ sieveFrom (68 + n `rem` 4) -- prevent sharing+        search (p:ps) = case jacobi p n of+          MinusOne -> p+          _        -> search ps+        search _ = error "Should never have happened, prime list exhausted."++recipMod :: Integer -> Integer -> Maybe Integer+recipMod x m = case recipModInteger x m of+  0 -> Nothing+  y -> Just y
Math/NumberTheory/Powers/Cubes.hs view
@@ -197,24 +197,17 @@ appCuRt :: Integer -> Integer appCuRt (S# i#) = case double2Int# (int2Double# i# **## (1.0## /## 3.0##)) of                     r# -> S# r#-#if __GLASGOW_HASKELL__ < 709-appCuRt n@(J# s# _)-    | isTrue# (s# <# THRESH#)   = floor (fromInteger n ** (1.0/3.0) :: Double)-#else appCuRt n@(Jp# bn#)     | isTrue# ((sizeofBigNat# bn#) <# THRESH#) =           floor (fromInteger n ** (1.0/3.0) :: Double)-#endif     | otherwise = case integerLog2# n of                     l# -> case (l# `quotInt#` 3#) -# 51# of                             h# -> case shiftRInteger n (3# *# h#) of                                     m -> case floor (fromInteger m ** (1.0/3.0) :: Double) of                                            r -> shiftLInteger r h#-#if __GLASGOW_HASKELL__ >= 709 -- There's already handling for negative in integerCubeRoot, -- but integerCubeRoot' is exported directly too. appCuRt _ = error "integerCubeRoot': negative argument"-#endif  -- not very discriminating, but cheap, so it's an overall gain cr512 :: UArray Int Bool
Math/NumberTheory/Powers/Fourth.hs view
@@ -138,24 +138,17 @@ -- About 48 bits should be correct for large Integers. appBiSqrt :: Integer -> Integer appBiSqrt (S# i#) = S# (double2Int# (sqrtDouble# (sqrtDouble# (int2Double# i#))))-#if __GLASGOW_HASKELL__ < 709-appBiSqrt n@(J# s# _)-    | isTrue# (s# <# THRESH#)   = floor (sqrt . sqrt $ fromInteger n :: Double)-#else appBiSqrt n@(Jp# bn#)     | isTrue# ((sizeofBigNat# bn#) <# THRESH#) =           floor (sqrt . sqrt $ fromInteger n :: Double)-#endif     | otherwise = case integerLog2# n of                     l# -> case uncheckedIShiftRA# l# 2# -# 47# of                             h# -> case shiftRInteger n (4# *# h#) of                                     m -> case floor (sqrt $ sqrt $ fromInteger m :: Double) of                                             r -> shiftLInteger r h#-#if __GLASGOW_HASKELL__ >= 709 -- There's already a check for negative in integerFourthRoot, -- but integerFourthRoot' is exported directly too. appBiSqrt _ = error "integerFourthRoot': negative argument"-#endif   biSqRes256 :: UArray Int Bool
Math/NumberTheory/Powers/Modular.hs view
@@ -14,29 +14,25 @@  module Math.NumberTheory.Powers.Modular   ( powMod-#if __GLASGOW_HASKELL__ > 709   , powModWord   , powModInt-#endif   ) where  import qualified GHC.Integer.GMP.Internals as GMP (powModInteger) -#if __GLASGOW_HASKELL__ > 709 import GHC.Exts (Word(..)) import GHC.Natural (powModNatural) import qualified GHC.Integer.GMP.Internals as GMP (powModWord) import Math.NumberTheory.Utils.FromIntegral-#endif  -- | @powMod@ @b@ @e@ @m@ computes (@b^e@) \`mod\` @m@ in effective way. -- An exponent @e@ must be non-negative, a modulo @m@ must be positive. -- Otherwise the behaviour of @powMod@ is undefined. ----- > > powMod 2 3 5--- > 3--- > > powMod 3 12345678901234567890 1001--- > 1+-- >>> powMod 2 3 5+-- 3+-- >>> powMod 3 12345678901234567890 1001+-- 1 -- -- See also 'Math.NumberTheory.Moduli.Class.powMod' and 'Math.NumberTheory.Moduli.Class.powSomeMod'. --@@ -46,12 +42,12 @@ -- need both to fit into machine word and to handle large moduli, -- take a look at 'powModInt' and 'powModWord'. ----- > > powMod 3 101 (2^60-1 :: Integer)--- > 1018105167100379328 -- correct--- > > powMod 3 101 (2^60-1 :: Int64)--- > 1115647832265427613 -- incorrect due to overflow--- > > powModInt 3 101 (2^60-1 :: Int)--- > 1018105167100379328 -- correct+-- >>> powMod 3 101 (2^60-1 :: Integer)+-- 1018105167100379328 -- correct+-- >>> powMod 3 101 (2^60-1 :: Int64)+-- 1115647832265427613 -- incorrect due to overflow+-- >>> powModInt 3 101 (2^60-1 :: Int)+-- 1018105167100379328 -- correct powMod :: (Integral a, Integral b) => a -> b -> a -> a powMod x y m   | m <= 0    = error "powModInt: non-positive modulo"@@ -71,7 +67,6 @@ powModInteger :: Integer -> Integer -> Integer -> Integer powModInteger b e m = GMP.powModInteger (b `mod` m) e m -#if __GLASGOW_HASKELL__ > 709 {-# RULES "powMod/Natural" powMod = powModNatural "powMod/Word"    powMod = powModWord@@ -80,18 +75,17 @@  -- | Specialised version of 'powMod', able to handle large moduli correctly. ----- > > powModWord 3 101 (2^60-1)--- > 1018105167100379328+-- >>> powModWord 3 101 (2^60-1)+-- 1018105167100379328 powModWord :: Word -> Word -> Word -> Word powModWord (W# x) (W# y) (W# m) = W# (GMP.powModWord x y m)  -- | Specialised version of 'powMod', able to handle large moduli correctly. ----- > > powModInt 3 101 (2^60-1)--- > 1018105167100379328+-- >> powModInt 3 101 (2^60-1)+-- 1018105167100379328 powModInt :: Int -> Int -> Int -> Int powModInt x y m   | m <= 0 = error "powModInt: non-positive modulo"   | y <  0 = error "powModInt: negative exponent"   | otherwise = wordToInt $ powModWord (intToWord (x `mod` m)) (intToWord y) (intToWord m)-#endif
Math/NumberTheory/Powers/Squares.hs view
@@ -29,9 +29,6 @@ import Data.Array.ST  import Data.Bits-#if __GLASGOW_HASKELL__ < 709-import Data.Word        -- Moved to GHC.Types-#endif  import Math.NumberTheory.Unsafe 
Math/NumberTheory/Powers/Squares/Internal.hs view
@@ -14,6 +14,8 @@ {-# LANGUAGE CPP              #-} {-# LANGUAGE FlexibleContexts #-} +{-# OPTIONS_HADDOCK hide #-}+ module Math.NumberTheory.Powers.Squares.Internal   ( karatsubaSqrt   , isqrtA@@ -66,24 +68,17 @@ -- for large Integers. appSqrt :: Integer -> Integer appSqrt (S# i#) = S# (double2Int# (sqrtDouble# (int2Double# i#)))-#if __GLASGOW_HASKELL__ < 709-appSqrt n@(J# s# _)-    | isTrue# (s# <# THRESH#) = floor (sqrt $ fromInteger n :: Double)-#else appSqrt n@(Jp# bn#)     | isTrue# ((sizeofBigNat# bn#) <# THRESH#) =           floor (sqrt $ fromInteger n :: Double)-#endif     | otherwise = case integerLog2# n of                     l# -> case uncheckedIShiftRA# l# 1# -# 47# of                             h# -> case shiftRInteger n (2# *# h#) of                                     m -> case floor (sqrt $ fromInteger m :: Double) of                                             r -> shiftLInteger r h#-#if __GLASGOW_HASKELL__ >= 709 -- There's already a check for negative in integerSquareRoot, -- but integerSquareRoot' is exported directly too. appSqrt _ = error "integerSquareRoot': negative argument"-#endif   -- Integer square root with remainder, using the Karatsuba Square Root
Math/NumberTheory/Prefactored.hs view
@@ -9,9 +9,11 @@ -- Type for numbers, accompanied by their factorisation. -- -{-# LANGUAGE CPP          #-}-{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE CPP           #-}+{-# LANGUAGE TypeFamilies  #-} +{-# OPTIONS_GHC -fno-warn-unused-imports #-}+ module Math.NumberTheory.Prefactored   ( Prefactored(prefValue, prefFactors)   , fromValue@@ -20,13 +22,11 @@  import Control.Arrow -import Math.NumberTheory.GCD (splitIntoCoprimes)-import Math.NumberTheory.UniqueFactorisation+import Data.Semigroup -#if MIN_VERSION_base(4,8,0)-#else-import Data.Word-#endif+import Math.NumberTheory.Euclidean+import Math.NumberTheory.Euclidean.Coprimes+import Math.NumberTheory.UniqueFactorisation  -- | A container for a number and its pairwise coprime (but not neccessarily prime) -- factorisation.@@ -36,43 +36,44 @@ -- -- For instance, let @p@ and @q@ be big primes: ----- > > let p, q :: Integer--- > >     p = 1000000000000000000000000000057--- > >     q = 2000000000000000000000000000071+-- >>> let p, q :: Integer+-- >>>     p = 1000000000000000000000000000057+-- >>>     q = 2000000000000000000000000000071 -- -- It would be  difficult to compute prime factorisation of their product -- as is: -- 'factorise' would take ages. Things become different if we simply -- change types of @p@ and @q@ to prefactored ones: ----- > > let p, q :: Prefactored Integer--- > >     p = 1000000000000000000000000000057--- > >     q = 2000000000000000000000000000071+-- >>> let p, q :: Prefactored Integer+-- >>>     p = 1000000000000000000000000000057+-- >>>     q = 2000000000000000000000000000071 -- -- Now prime factorisation is done instantly: ----- > > factorise (p * q)--- > [(PrimeNat 1000000000000000000000000000057, 1), (PrimeNat 2000000000000000000000000000071, 1)]--- > > factorise (p^2 * q^3)--- > [(PrimeNat 1000000000000000000000000000057, 2), (PrimeNat 2000000000000000000000000000071, 3)]+-- >>> factorise (p * q)+-- [(PrimeNat 1000000000000000000000000000057, 1), (PrimeNat 2000000000000000000000000000071, 1)]+-- >>> factorise (p^2 * q^3)+-- [(PrimeNat 1000000000000000000000000000057, 2), (PrimeNat 2000000000000000000000000000071, 3)] -- -- Moreover, we can instantly compute 'totient' and its iterations. -- It works fine, because output of 'totient' is also prefactored. ----- > > prefValue $ totient (p^2 * q^3)--- > 8000000000000000000000000001752000000000000000000000000151322000000000000000000000006445392000000000000000000000135513014000000000000000000001126361040--- > > prefValue $ totient $ totient (p^2 * q^3)--- > 2133305798262843681544648472180210822742702690942899511234131900112583590230336435053688694839034890779375223070157301188739881477320529552945446912000+-- >>> prefValue $ totient (p^2 * q^3)+-- 8000000000000000000000000001752000000000000000000000000151322000000000000000000000006445392000000000000000000000135513014000000000000000000001126361040+-- >>> prefValue $ totient $ totient (p^2 * q^3)+-- 2133305798262843681544648472180210822742702690942899511234131900112583590230336435053688694839034890779375223070157301188739881477320529552945446912000 -- -- Let us look under the hood: ----- > > prefFactors $ totient (p^2 * q^3)--- > [(2, 4), (41666666666666666666666666669, 1), (3, 3), (111111111111111111111111111115, 1),--- > (1000000000000000000000000000057, 1), (2000000000000000000000000000071, 2)]--- > > prefFactors $ totient $ totient (p^2 * q^3)--- > [(2, 22), (39521, 1), (5, 3), (199937, 1), (3, 8), (6046667, 1), (227098769, 1),--- > (85331809838489, 1), (361696272343, 1), (22222222222222222222222222223, 1),--- > (41666666666666666666666666669, 1), (2000000000000000000000000000071, 1)]+-- >>> prefFactors $ totient (p^2 * q^3)+-- Coprimes {unCoprimes = fromList [(2,4),(3,3),+--   (41666666666666666666666666669,1),(111111111111111111111111111115,1),+--   (1000000000000000000000000000057,1),(2000000000000000000000000000071,2)]}+-- >>> prefFactors $ totient $ totient (p^2 * q^3)+-- Coprimes {unCoprimes = fromList [(2,22),(3,8),(5,3),(39521,1),(199937,1),(6046667,1),+--   (227098769,1),(361696272343,1),(85331809838489,1),(22222222222222222222222222223,1),+--   (41666666666666666666666666669,1),(2000000000000000000000000000071,1)]} -- -- Pairwise coprimality of factors is crucial, because it allows -- us to process them independently, possibly even@@ -84,47 +85,46 @@ data Prefactored a = Prefactored   { prefValue   :: a     -- ^ Number itself.-  , prefFactors :: [(a, Word)]+  , prefFactors :: Coprimes a Word     -- ^ List of pairwise coprime (but not neccesarily prime) factors,     -- accompanied by their multiplicities.   } deriving (Show)  -- | Create 'Prefactored' from a given number. ----- > > fromValue 123--- > Prefactored {prefValue = 123, prefFactors = [(123, 1)]}-fromValue :: a -> Prefactored a-fromValue a = Prefactored a [(a, 1)]+-- >>> fromValue 123+-- Prefactored {prefValue = 123, prefFactors = Coprimes {unCoprimes = fromList [(123,1)]}}+fromValue :: (Eq a, Num a) => a -> Prefactored a+fromValue a = Prefactored a (singleton a 1)  -- | Create 'Prefactored' from a given list of pairwise coprime -- (but not neccesarily prime) factors with multiplicities.--- If you cannot ensure coprimality, use 'splitIntoCoprimes'. ----- > > fromFactors (splitIntoCoprimes [(140, 1), (165, 1)])--- > Prefactored {prefValue = 23100, prefFactors = [(5, 2), (28, 1), (33, 1)]}--- > > fromFactors (splitIntoCoprimes [(140, 2), (165, 3)])--- > Prefactored {prefValue = 88045650000, prefFactors = [(5, 5), (28, 2), (33, 3)]}-fromFactors :: Integral a => [(a, Word)] -> Prefactored a-fromFactors as = Prefactored (product (map (uncurry (^)) as)) (splitIntoCoprimes as)+-- >>> fromFactors (splitIntoCoprimes [(140, 1), (165, 1)])+-- Prefactored {prefValue = 23100, prefFactors = Coprimes {unCoprimes = fromList [(5,2),(28,1),(33,1)]}}+-- >>> fromFactors (splitIntoCoprimes [(140, 2), (165, 3)])+-- Prefactored {prefValue = 88045650000, prefFactors = Coprimes {unCoprimes = fromList [(5,5),(28,2),(33,3)]}}+fromFactors :: Num a => Coprimes a Word -> Prefactored a+fromFactors as = Prefactored (product (map (uncurry (^)) (unCoprimes as))) as -instance (Integral a, UniqueFactorisation a) => Num (Prefactored a) where+instance (Euclidean a, Ord a) => Num (Prefactored a) where   Prefactored v1 _ + Prefactored v2 _     = fromValue (v1 + v2)   Prefactored v1 _ - Prefactored v2 _     = fromValue (v1 - v2)   Prefactored v1 f1 * Prefactored v2 f2-    = Prefactored (v1 * v2) (splitIntoCoprimes (f1 ++ f2))+    = Prefactored (v1 * v2) (f1 <> f2)   negate (Prefactored v f) = Prefactored (negate v) f   abs (Prefactored v f)    = Prefactored (abs v) f-  signum (Prefactored v _) = Prefactored (signum v) []+  signum (Prefactored v _) = Prefactored (signum v) mempty   fromInteger n = fromValue (fromInteger n)  type instance Prime (Prefactored a) = Prime a -instance UniqueFactorisation a => UniqueFactorisation (Prefactored a) where+instance (Eq a, Num a, UniqueFactorisation a) => UniqueFactorisation (Prefactored a) where   unPrime p = fromValue (unPrime p)   factorise (Prefactored _ f)-    = concatMap (\(x, xm) -> map (second (* xm)) (factorise x)) f-  isPrime (Prefactored _ f) = case f of+    = concatMap (\(x, xm) -> map (second (* xm)) (factorise x)) (unCoprimes f)+  isPrime (Prefactored _ f) = case unCoprimes f of     [(n, 1)] -> isPrime n     _        -> Nothing
Math/NumberTheory/Primes.hs view
@@ -15,5 +15,5 @@  import Math.NumberTheory.Primes.Sieve import Math.NumberTheory.Primes.Counting-import Math.NumberTheory.Primes.Testing hiding (FactorSieve)+import Math.NumberTheory.Primes.Testing import Math.NumberTheory.Primes.Factorisation
Math/NumberTheory/Primes/Counting/Impl.hs view
@@ -8,7 +8,11 @@ -- -- Number of primes not exceeding @n@, @&#960;(n)@, and @n@-th prime. ---{-# LANGUAGE CPP, BangPatterns, FlexibleContexts #-}+{-# LANGUAGE BangPatterns        #-}+{-# LANGUAGE CPP                 #-}+{-# LANGUAGE FlexibleContexts    #-}+{-# LANGUAGE ScopedTypeVariables #-}+ {-# OPTIONS_GHC -fspec-constr-count=24 #-} {-# OPTIONS_HADDOCK hide #-} module Math.NumberTheory.Primes.Counting.Impl@@ -140,14 +144,18 @@ -- highSieve a surp gap = error "Oh shit"  sieveCount :: COUNT_T -> COUNT_T -> COUNT_T -> Integer-sieveCount ub cr sr = runST $ do+sieveCount ub cr sr = runST (sieveCountST ub cr sr)++sieveCountST :: forall s. COUNT_T -> COUNT_T -> COUNT_T -> ST s Integer+sieveCountST ub cr sr = do     let psieves = psieveFrom (fromIntegral cr)         pisr = approxPrimeCount sr         picr = approxPrimeCount cr         diff = pisr - picr         size = fromIntegral (diff + diff `quot` 50) + 30     store <- unsafeNewArray_ (0,size-1) :: ST s (STUArray s Int COUNT_T)-    let feed voff !wi !ri uar sves+    let feed :: COUNT_T -> Int -> Int -> UArray Int Bool -> [PrimeSieve] -> ST s Integer+        feed voff !wi !ri uar sves           | ri == sieveBits = case sves of                                 (PS vO ba : more) -> feed (fromInteger vO) wi 0 ba more                                 _ -> error "prime stream ended prematurely"@@ -160,6 +168,7 @@           | otherwise = feed voff wi (ri+1) uar sves             where               pval = voff + toPrim ri+        eat :: Integer -> Integer -> COUNT_T -> Int -> Int -> STUArray s Int Bool -> [PrimeSieve] -> ST s Integer         eat !acc !btw voff !wi !si stu sves             | si == sieveBits =                 case sves of@@ -198,7 +207,10 @@       _ -> error "No primes sieved"  calc :: COUNT_T -> COUNT_T -> Integer-calc lim plim = runST $ do+calc lim plim = runST (calcST lim plim)++calcST :: forall s. COUNT_T -> COUNT_T -> ST s Integer+calcST lim plim = do     !parr <- sieveTo (fromIntegral plim)     (plo,phi) <- getBounds parr     !pct <- countFromTo plo phi parr@@ -206,7 +218,8 @@     unsafeWrite ar1 0 lim     unsafeWrite ar1 1 1     !ar2 <- unsafeNewArray_ (0,end-1)-    let go cap pix old new+    let go :: Int -> Int -> STUArray s Int COUNT_T -> STUArray s Int COUNT_T -> ST s Integer+        go cap pix old new             | pix == 2  =   coll cap old             | otherwise = do                 isp <- unsafeRead parr pix@@ -216,6 +229,7 @@                         !ncap <- treat cap n old new                         go ncap (pix-1) new old                     else go cap (pix-1) old new+        coll :: Int -> STUArray s Int COUNT_T -> ST s Integer         coll stop ar =             let cgo !acc i                     | i < stop  = do
Math/NumberTheory/Primes/Factorisation.hs view
@@ -23,10 +23,6 @@     , stepFactorisation     , factorise'     , defaultStdGenFactorisation'-      -- *** Factor sieves-    , FactorSieve-    , factorSieve-    , sieveFactor       -- *** Trial division     , trialDivisionTo       -- ** Partial factorisation@@ -35,19 +31,10 @@     , curveFactorisation       -- *** Single curve worker     , montgomeryFactorisation-      -- * Totients-    , TotientSieve-    , totientSieve-    , sieveTotient-      -- * Carmichael function-    , CarmichaelSieve-    , carmichaelSieve-    , sieveCarmichael     ) where  import Math.NumberTheory.Primes.Factorisation.Montgomery import Math.NumberTheory.Primes.Factorisation.TrialDivision-import Math.NumberTheory.Primes.Sieve.Misc  -- $algorithm --
Math/NumberTheory/Primes/Factorisation/Certified.hs view
@@ -18,12 +18,10 @@   ) where  import System.Random-import Control.Monad.State.Strict-#if __GLASGOW_HASKELL__ < 709-import Control.Applicative-#endif+import Control.Monad.Trans.State.Strict import Data.Maybe import Data.Bits+import Data.Traversable  import Math.NumberTheory.Moduli.Class import Math.NumberTheory.Primes.Factorisation.Montgomery
Math/NumberTheory/Primes/Factorisation/Montgomery.hs view
@@ -50,12 +50,8 @@   ) where  import Control.Arrow+import Control.Monad.Trans.State.Lazy import System.Random-import Control.Monad.State.Lazy-#if __GLASGOW_HASKELL__ < 709-import Control.Applicative-import Data.Word-#endif import Data.Bits import Data.IntMap (IntMap) import qualified Data.IntMap as IM@@ -64,11 +60,12 @@ #if __GLASGOW_HASKELL__ < 803 import Data.Semigroup #endif+import Data.Traversable  import GHC.TypeNats.Compat  import Math.NumberTheory.Curves.Montgomery-import Math.NumberTheory.GCD (splitIntoCoprimes)+import Math.NumberTheory.Euclidean.Coprimes (splitIntoCoprimes, unCoprimes) import Math.NumberTheory.Moduli.Class import Math.NumberTheory.Powers.General     (highestPower, largePFPower) import Math.NumberTheory.Powers.Squares     (integerSquareRoot')@@ -78,16 +75,15 @@ import Math.NumberTheory.Unsafe import Math.NumberTheory.Utils --- | @'factorise' n@ produces the prime factorisation of @n@, including---   a factor of @(-1)@ if @n < 0@. @'factorise' 0@ is an error and the---   factorisation of @1@ is empty. Uses a 'StdGen' produced in an arbitrary---   manner from the bit-pattern of @n@.+-- | @'factorise' n@ produces the prime factorisation of @n@. @'factorise' 0@ is+--   an error and the factorisation of @1@ is empty. Uses a 'StdGen' produced in+--   an arbitrary manner from the bit-pattern of @n@. factorise :: Integer -> [(Integer,Int)] factorise n-    | n < 0     = (-1,1):factorise (-n)-    | n == 0    = error "0 has no prime factorisation"-    | n == 1    = []-    | otherwise = factorise' n+    | abs n == 1 = []+    | n < 0      = factorise (-n)+    | n == 0     = error "0 has no prime factorisation"+    | otherwise  = factorise' n  -- | Like 'factorise', but without input checking, hence @n > 1@ is required. factorise' :: Integer -> [(Integer,Int)]@@ -221,7 +217,7 @@             SomeMod sm -> case montgomeryFactorisation b1 b2 sm of               Nothing -> workFact m b1 b2 (count - 1)               Just d  -> do-                let cs = splitIntoCoprimes [(d, 1), (m `quot` d, 1)]+                let cs = unCoprimes $ splitIntoCoprimes [(d, 1), (m `quot` d, 1)]                 -- Since all @cs@ are coprime, we can factor each of                 -- them and just concat results, without summing up                 -- powers of the same primes in different elements.
− Math/NumberTheory/Primes/Heap.hs
@@ -1,366 +0,0 @@--- |--- Module:      Math.NumberTheory.Primes.Heap--- Copyright:   (c) 2011 Daniel Fischer--- Licence:     MIT--- Maintainer:  Daniel Fischer <daniel.is.fischer@googlemail.com>--- Stability:   Provisional--- Portability: Non-portable (GHC extensions)------ Prime generation using a priority queue for the composites.--- The algorithm is basically the one described in--- <http://www.cs.hmc.edu/~oneill/papers/Sieve-JFP.pdf>, but--- it uses a more efficient heap for the priority queue and a--- larger wheel, thus it is faster (in particular, the speed--- penalty for @'Integer'@ is much smaller) and uses less memory.--- It is nevertheless very slow compared to a bit sieve.--- This module is mainly intended for comparison and verification.-{-# LANGUAGE BangPatterns, CPP, MonoLocalBinds #-}-{-# OPTIONS_GHC -funbox-strict-fields #-}-{-# OPTIONS_GHC -fno-float-in -fno-spec-constr -fno-full-laziness #-}-module Math.NumberTheory.Primes.Heap {-# DEPRECATED "Use Math.NumberTheory.Primes.Sieve instead" #-} (primes, sieveFrom) where--import Data.Array.Unboxed-import Data.Array.ST-import Control.Monad.ST-import Data.List (foldl')-#if __GLASGOW_HASKELL__ < 709-import Data.Word-#endif--import Math.NumberTheory.Unsafe--#ifndef SH_SIZE-#define SH_SIZE 31-#endif---- Composites to eliminate, components are--- composite, multiple of prime--- prime--- index of step to find next multiple of prime-data Del a = D !a !a {-# UNPACK #-} !Int--step :: Integral a => Int -> a--- {-# INLINE step #-}-step i = fromIntegral (steps `unsafeAt` i)---- Priority queue as baby heap--- Invariant: left subheap one larger than right or both--- have the same size (and of course, heap property)-data Hipp a-    = E-    | H !a !a {-# UNPACK #-} !Int !(Hipp a) !(Hipp a)----- push composite-data down the heap-{-# SPECIALISE push :: Int -> Int -> Int -> Hipp Int -> Hipp Int #-}-{-# SPECIALISE push :: Word -> Word -> Int -> Hipp Word -> Hipp Word #-}-{-# SPECIALISE push :: Integer -> Integer -> Int -> Hipp Integer -> Hipp Integer #-}-push :: Integral a => a -> a -> Int -> Hipp a -> Hipp a-push !c !p !w = go-  where-    less = (< c)-    go (H hc hp hw l r)-        | less hc   = H hc hp hw (go r) l-        | otherwise = H c p w (push hc hp hw r) l-    go _ = H c p w E E---- bubble down increased top to regain heap invariant-{-# SPECIALISE bubble :: Hipp Int -> Hipp Int #-}-{-# SPECIALISE bubble :: Hipp Word -> Hipp Word #-}-{-# SPECIALISE bubble :: Hipp Integer -> Hipp Integer #-}-bubble :: Integral a => Hipp a -> Hipp a-bubble h@(H c p w l r) =-    case r of-        E -> case l of-                E -> h-                H lc lp lw ll lr-                    | lc < c -> H lc lp lw (H c p w ll lr) r-                    | otherwise -> h-        H rc rp rw rl rr ->-          case l of-            H lc lp lw ll lr-                | lc < c -> if lc < rc-                              then H lc lp lw (mkHipp c p w ll lr) r-                              else H rc rp rw l (mkHipp c p w rl rr)-                | rc < c -> H rc rp rw l (mkHipp c p w rl rr)-                | otherwise -> h-            _ -> error "Heap invariant violated, left smaller than right!"-bubble h = h---- join two heaps and composite-data-{-# SPECIALISE-    mkHipp :: Int -> Int -> Int -> Hipp Int -> Hipp Int -> Hipp Int,-              Integer -> Integer -> Int -> Hipp Integer -> Hipp Integer -> Hipp Integer,-              Word -> Word -> Int -> Hipp Word -> Hipp Word -> Hipp Word-  #-}-mkHipp :: Integral a => a -> a -> Int -> Hipp a -> Hipp a -> Hipp a-mkHipp !c !p !w = go-  where-    less = (< c)-    go l r =-      case r of-        E -> case l of-                E -> H c p w l r-                H lc lp lw _ _-                    | less lc -> H lc lp lw (H c p w E E) E-                    | otherwise -> H c p w l r-        H rc rp rw rl rr ->-          case l of-            H lc lp lw ll lr-                | less lc -> if lc < rc-                                then H lc lp lw (go ll lr) r-                                else H rc rp rw l (go rl rr)-                | less rc -> H rc rp rw l (go rl rr)-                | otherwise -> H c p w l r-            _ -> error "Heap invariant violated, left smaller than right!"---- increase the top of the heap and re-heap-{-# SPECIALISE inc :: Hipp Int -> Hipp Int #-}-{-# SPECIALISE inc :: Hipp Word -> Hipp Word #-}-{-# SPECIALISE inc :: Hipp Integer -> Hipp Integer #-}-inc :: Integral a => Hipp a -> Hipp a-inc (H c p i l r)-  = {-# SCC "incBubble" #-} bubble (H (c+p*step i) p (nextIndex i) l r)-inc h   = h---- while top of heap equals composite, increase and re-heap-{-# SPECIALISE adjust :: Int -> Hipp Int -> Hipp Int #-}-{-# SPECIALISE adjust :: Word -> Hipp Word -> Hipp Word #-}-{-# SPECIALISE adjust :: Integer -> Hipp Integer -> Hipp Integer #-}-adjust :: Integral a => a -> Hipp a -> Hipp a-adjust cm h@(H v _ _ _ _)-    | cm == v   = adjust cm (inc h)-adjust _ h      = h---- build a heap from a sorted list of Del's-{-# SPECIALISE buildH :: [Del Int] -> Hipp Int #-}-{-# SPECIALISE buildH :: [Del Word] -> Hipp Word #-}-{-# SPECIALISE buildH :: [Del Integer] -> Hipp Integer #-}-buildH :: Integral a => [Del a] -> Hipp a-buildH [] = E-buildH (D s p w : tl) = H s p w l r-      where-        (ll,rl) = goSplit [] [] tl-        goSplit xs ys [] = (reverse ys, reverse xs)-        goSplit xs ys (d:ds) = goSplit ys (d:xs) ds-        l = buildH ll-        r = buildH rl---- Simple sieve pushing each prime immediately onto the heap,--- feeds the feeder, runs at about fourth root of the main sieve.-{-# SPECIALISE simpleSieve :: Hipp Int -> Int -> Int -> [Del Int] #-}-{-# SPECIALISE simpleSieve :: Hipp Word -> Word -> Int -> [Del Word] #-}-{-# SPECIALISE simpleSieve :: Hipp Integer -> Integer -> Int -> [Del Integer] #-}-simpleSieve :: Integral a => Hipp a -> a -> Int -> [Del a]-simpleSieve h@(H nc _ _ _ _) cd !i-  | cd < nc   = D s cd i : simpleSieve ({-# SCC "simplePush" #-} push s cd i h) (cd + step i) (nextIndex i)-    | otherwise = simpleSieve (adjust cd h) (cd + step i) (nextIndex i)-      where-        s = cd*cd-simpleSieve _ _ _ = []  -- would violate an invariant---- Feeder sieve, produces composites at the rate of the progress of the main sieve,--- hence primes at about the square root of it, thus needs about fourth root heap--- space. The two-step feeding makes the feeder produce faster and hence the main--- sieve (since we have only one O(n^0.5) heap and not two.--- Using two heaps, one small for multiples of small primes which change often--- and one for multiples of larger primes which are less frequently updated--- speeds things up.-{-# SPECIALISE feederSieve :: [Del Int] -> Hipp Int -> Hipp Int -> Int -> Int -> [Del Int] #-}-{-# SPECIALISE feederSieve :: [Del Word] -> Hipp Word -> Hipp Word -> Word -> Int -> [Del Word] #-}-{-# SPECIALISE feederSieve :: [Del Integer] -> Hipp Integer -> Hipp Integer -> Integer -> Int -> [Del Integer] #-}-feederSieve :: Integral a => [Del a] -> Hipp a -> Hipp a -> a -> Int -> [Del a]-feederSieve dls@((D s p u):ds) sh@(H sc _ _ _ _) lh@(H lc _ _ _ _) cd i-    | cd == sc  = feederSieve dls (adjust cd (inc sh)) (adjust cd lh) cd' j-    | cd == lc  = feederSieve dls sh (adjust cd (inc lh)) cd' j-    | cd == s   = feederSieve ds sh (push (s + p*step u) p (nextIndex u) lh) cd' j-    | otherwise = D (cd*cd) cd i : feederSieve dls sh lh cd' j-      where-        !cd' = cd + step i-        !j   = nextIndex i-feederSieve _ _ _ _ _ = []  -- invariant violated---- Build the feeder sieve, arguments are--- first prime whose multiples have to be eliminated--- index of step for this prime.-{-# SPECIALISE feeder :: Int -> Int -> [Del Int] #-}-{-# SPECIALISE feeder :: Word -> Int -> [Del Word] #-}-{-# SPECIALISE feeder :: Integer -> Int -> [Del Integer] #-}-feeder :: Integral a => a -> Int -> [Del a]-feeder p i = feederSieve lrg sh lh p i-      where-        (sml,D s lp w : lrg) = splitAt SH_SIZE (D q p i : {-# SCC "simple" #-} simpleSieve (H q p i E E) (p+step i) (nextIndex i))-        sh = buildH sml-        lh = H s lp w E E-        q  = p*p---- The main sieve. Code almost identical to feederSieve, but we don't construct the Del,--- which gains some performance.-{-# SPECIALISE primeSieve :: [Del Int] -> Hipp Int -> Hipp Int -> Int -> Int -> [Int] #-}-{-# SPECIALISE primeSieve :: [Del Word] -> Hipp Word -> Hipp Word -> Word -> Int -> [Word] #-}-{-# SPECIALISE primeSieve :: [Del Integer] -> Hipp Integer -> Hipp Integer -> Integer -> Int -> [Integer] #-}-primeSieve :: Integral a => [Del a] -> Hipp a -> Hipp a -> a -> Int -> [a]-primeSieve dls@((D s p u):ds) sh@(H sc _ _ _ _) lh@(H lc _ _ _ _) cd i-    | cd == sc  = primeSieve dls ({-# SCC "adjSmall" #-} adjust cd (inc sh)) ({-# SCC "adjLarge" #-}adjust cd lh) cd' j-    | cd == lc  = primeSieve dls sh (adjust cd (inc lh)) cd' j-    | cd == s   = primeSieve ds sh (push (s + p*step u) p (nextIndex u) lh) cd' j-    | otherwise = cd : primeSieve dls sh lh cd' j-      where-        !cd' = cd + step i-        !j   = nextIndex i-primeSieve _ _ _ _ _ = []   -- invariant violated---- | A list of primes. The sieve does not handle overflow, hence for---   bounded types, garbage occurs near @'maxBound'@. If primes that---   large are requested, use------ @---   'map' 'fromInteger' $ 'takeWhile' (<= 'fromIntegral' 'maxBound') 'primes'--- @------   instead. Checking for overflow would be slower. The sieve is specialised---   for @'Int'@, @'Word'@ and @'Integer'@, since these are the most commonly---   used. For the fixed-width @Int@ or @Word@ types, sieving at one of the---   specialised types and converting is faster.---   To ensure sharing of the list of primes, bind it to a monomorphic variable,---   to make sure that it is not shared, use @'sieveFrom'@ with different---   arguments.-{-# SPECIALISE primes :: [Int] #-}-{-# SPECIALISE primes :: [Word] #-}-{-# SPECIALISE primes :: [Integer] #-}-primes :: Integral a => [a]-primes = 2:3:5:7:11:13:sieve 17 0---- | @'sieveFrom' n@ generates the list of primes @>= n@.---   The remarks about overflow and performance in the documentation---   of @'primes'@ apply here too.-{-# SPECIALISE sieveFrom :: Int -> [Int] #-}-{-# SPECIALISE sieveFrom :: Word -> [Word] #-}-{-# SPECIALISE sieveFrom :: Integer -> [Integer] #-}-sieveFrom :: Integral a => a -> [a]-sieveFrom from-    | fromIntegral from < (32768 :: Integer)-        = dropWhile (< from) (foldr ((:) . fromIntegral) (sieve sp si) wheelPrimes)-    | otherwise-        = primeSieve dls sh lh start (nextIndex i0)-      where-        -- trick the compiler into not CAFing feeder 17 0-        sp  | odd from  = 17-            | otherwise = fromIntegral (remainders `unsafeAt` 0)-        si  | even from = 0-            | otherwise = (steps `unsafeAt` 0)-2-        (q, r)      = (from - 18) `quotRem` 30030-        i0          = findIx (fromIntegral r + 17)-        -- last number coprime to all wheel primes < from-        before      = 30030*q + fromIntegral (remainders `unsafeAt` i0)-        -- first candidate-        !start       = before + step i0-        (sml, lrg)  = splitAt SH_SIZE (feeder sp si)-        !sh          = foldl' pushD E [findMulIx p | D _ p _ <- sml]-        (lh, dls)   = {-# SCC "munch" #-} munch E lrg-        pushD h (c, p, i) = push c p i h-        findMulIx p = ((p*mp), p, (nextIndex ip))-          where-            fpq         = before `quot` p-            (qq, qr)    = (fpq-17) `quotRem` 30030-            !ip         = findIx (fromIntegral qr + 17)-            !mp         = 30030*qq + fromIntegral (remainders `unsafeAt` ip) + step ip-        munch !h dels@(D s p _ : ds)-            | before < s    = (h,dels)-            | otherwise     = munch h' ds-              where-                !(!c, pr, i)    = findMulIx p-                h'          = push c pr i h-        munch h [] = (h,[])---- Build main sieve.-{-# SPECIALISE sieve :: Int -> Int -> [Int] #-}-{-# SPECIALISE sieve :: Word -> Int -> [Word] #-}-{-# SPECIALISE sieve :: Integer -> Int -> [Integer] #-}-sieve :: Integral a => a -> Int -> [a]-sieve p i = primeSieve lrg sh lh p i-      where-        (sml,D s lp j : lrg) = splitAt SH_SIZE (feeder p i)-        !sh = buildH sml-        lh = H s lp j E E---- next step index, we have 5760 numbers coprime to all wheel--- primes in [1 .. product wheelPrimes]-{-# INLINE nextIndex #-}-nextIndex :: Int -> Int-nextIndex 5759 = 0-nextIndex i = i+1---- The six smallest primes, that makes the supporting arrays small enough--- and avoids enough composites to get acceptable speed (for sufficiently--- generous values of acceptable).-wheelPrimes :: [Int]-wheelPrimes = 2:3:5:7:11:13:[]---- index of largest coprime <= r-findIx :: Int -> Int-findIx r-    | 30030 < r = 5759-    | r == m    = a-    | r < m     = down (a-1)-    | otherwise = up a-      where-        a = max 0 (min 5758 ((192*r) `quot` 1001 - 1))-        m = remainders `unsafeAt` a-        down k-            | k < 0                         = 0-            | r < (remainders `unsafeAt` k) = down (k-1)-            | otherwise                     = k-        up k-            | k+1 > 5759                        = 5759-            | r < (remainders `unsafeAt` (k+1)) = k-            | otherwise                         = up (k+1)---- array of numbers coprime to all wheel primes in wheel range-remainders :: UArray Int Int-remainders = runSTUArray $ do-    sar <- newArray (0,30029) True :: ST s (STUArray s Int Bool)-    let n2 30030 = return ()-        n2 i = unsafeWrite sar i False >> n2 (i+2)-        n3 30033 = return ()-        n3 i = unsafeWrite sar i False >> n3 (i+6)-        n5 30035 = return ()-        n5 i = unsafeWrite sar i False-                >> unsafeWrite sar (i+20) False >> n5 (i+30)-        n7 30037 = return ()-        n7 i = unsafeWrite sar i False >> n7 (i+14)-        n11 30041 = return ()-        n11 i = unsafeWrite sar i False >> n11 (i+22)-        n13 30043 = return ()-        n13 i = unsafeWrite sar i False >> n13 (i+26)-    n2 0-    n3 3-    n5 5-    n7 7-    n11 11-    n13 13-    rar <- newArray_ (0,5759) :: ST s (STUArray s Int Int)-    let loop 30031 _ = unsafeWrite rar 5759 30031 >> return rar-        loop i !r = do-            c <- unsafeRead sar i-            if c-                then do-                    unsafeWrite rar r i-                    loop (i+2) (r+1)-                else loop (i+2) r-    loop 17 0---- distance from one coprime remainder to the next-steps :: UArray Int Int-steps = runSTUArray $ do-    sar <- newArray_ (0,5759) :: ST s (STUArray s Int Int)-    let loop 5759 p = do-            unsafeWrite sar 5759 (30047-p)-            return sar-        loop i p = do-            let !j = i+1-                !n = remainders `unsafeAt` j-            unsafeWrite sar i (n-p)-            loop j n-    loop 0 17-
Math/NumberTheory/Primes/Sieve/Eratosthenes.hs view
@@ -8,7 +8,12 @@ -- -- Sieve ---{-# LANGUAGE CPP, BangPatterns, FlexibleContexts #-}+{-# LANGUAGE BangPatterns        #-}+{-# LANGUAGE CPP                 #-}+{-# LANGUAGE FlexibleContexts    #-}+{-# LANGUAGE LambdaCase          #-}+{-# LANGUAGE ScopedTypeVariables #-}+ {-# OPTIONS_GHC -fspec-constr-count=8 #-} {-# OPTIONS_HADDOCK hide #-} module Math.NumberTheory.Primes.Sieve.Eratosthenes@@ -23,9 +28,7 @@     , countFromTo     , countAll     , countToNth-    , sieveBytes     , sieveBits-    , sieveWords     , sieveRange     , sieveTo     ) where@@ -34,15 +37,18 @@  import Control.Monad.ST import Data.Array.ST+import Data.Array.Unboxed+import Data.Proxy import Control.Monad (when) import Data.Bits-#if __GLASGOW_HASKELL__ < 709 || WORD_SIZE_IN_BITS == 32+#if WORD_SIZE_IN_BITS == 32 import Data.Word #endif  import Math.NumberTheory.Powers.Squares (integerSquareRoot) import Math.NumberTheory.Unsafe import Math.NumberTheory.Utils+import Math.NumberTheory.Utils.FromIntegral import Math.NumberTheory.Primes.Counting.Approximate import Math.NumberTheory.Primes.Sieve.Indexing @@ -106,25 +112,62 @@  -- | Generate a list of primes for consumption from a --   'PrimeSieve'.-primeList :: PrimeSieve -> [Integer]-primeList (PS 0 bs) = 2:3:5:[toPrim i | let (lo,hi) = bounds bs-                                      , i <- [lo .. hi]-                                      , unsafeAt bs i-                                      ]-primeList (PS vO bs) = [vO + toPrim i-                            | let (lo,hi) = bounds bs-                            , i <- [lo .. hi]-                            , unsafeAt bs i-                            ]+primeList :: forall a. Integral a => PrimeSieve -> [a]+primeList ps@(PS v _)+  | doesNotFit (Proxy :: Proxy a) v+              = [] -- has an overflow already happened?+  | v == 0    = takeWhileIncreasing $ 2 : 3 : 5 : primeListInternal ps+  | otherwise = takeWhileIncreasing $ primeListInternal ps --- | List of primes.---   Since the sieve uses unboxed arrays, overflow occurs at some point.---   On 64-bit systems, that point is beyond the memory limits, on---   32-bit systems, it is at about @1.7*10^18@.-primes :: [Integer]-primes = 2:3:5:concat [[vO + toPrim i | i <- [0 .. li], unsafeAt bs i]-                                | PS vO bs <- psieveList, let (_,li) = bounds bs]+primeListInternal :: Num a => PrimeSieve -> [a]+primeListInternal (PS v0 bs)+  = map ((+ fromInteger v0) . toPrim)+  $ filter (unsafeAt bs) [lo..hi]+  where+    (lo, hi) = bounds bs +-- | Returns true if integer is beyond representation range of type a.+doesNotFit :: forall a. Integral a => Proxy a -> Integer -> Bool+doesNotFit _ v = toInteger (fromInteger v :: a) /= v++-- | Extracts the longest strictly increasing prefix of the list+-- (possibly infinite).+takeWhileIncreasing :: Ord a => [a] -> [a]+takeWhileIncreasing = \case+  []     -> []+  x : xs -> x : foldr go (const []) xs x+    where+      go :: Ord a => a -> (a -> [a]) -> a -> [a]+      go y f z = if z < y then y : f y else []++-- | Ascending list of primes.+--+-- >>> take 10 primes+-- [2, 3, 5, 7, 11, 13, 17, 19, 23, 29]+--+-- 'primes' is a polymorphic list, so the results of computations are not retained in memory.+-- Make it monomorphic to take advantages of memoization. Compare+--+-- >>> :set +s+-- >>> primes !! 1000000 :: Int+-- 15485867+-- (5.32 secs, 6,945,267,496 bytes)+-- >>> primes !! 1000000 :: Int+-- 15485867+-- (5.19 secs, 6,945,267,496 bytes)+--+-- against+--+-- >>> let primes' = primes :: [Int]+-- >>> primes' !! 1000000 :: Int+-- 15485867+-- (5.29 secs, 6,945,269,856 bytes)+-- >>> primes' !! 1000000 :: Int+-- 15485867+-- (0.02 secs, 336,232 bytes)+primes :: (Ord a, Num a) => [a]+primes = takeWhileIncreasing $ 2 : 3 : 5 : concatMap primeListInternal psieveList+ -- | List of primes in the form of a list of 'PrimeSieve's, more compact than --   'primes', thus it may be better to use @'psieveList' >>= 'primeList'@ --   than keeping the list of primes alive during the entire run.@@ -134,7 +177,7 @@     plim = 4801     -- prime #647, 644 of them to use     sqlim = plim*plim     cache = runSTUArray $ do-        sieve <- sieveTo 4801+        sieve <- sieveTo (4801 :: Integer)         new <- unsafeNewArray_ (0,1287) :: ST s (STUArray s Int CacheWord)         let fill j indx               | 1279 < indx = return new    -- index of 4801 = 159*30 + 31 ~> 159*8+7@@ -335,7 +378,7 @@ psieveFrom :: Integer -> [PrimeSieve] psieveFrom n = makeSieves plim sqlim bitOff valOff cache     where-      k0 = max 0 (n-7) `quot` 30+      k0 = ((n `max` 7) - 7) `quot` 30 -- beware arithmetic underflow       valOff = 30*k0       bitOff = 8*k0       start = valOff+7@@ -403,7 +446,7 @@                       bnd = bd0 + bd0 `quot` 32 + 37                       !sv = primeSieve bnd                   in countToNth (n-3) [sv]-  | otherwise   = countToNth (n-3) (psieveFrom (fromIntegral $ fromInteger n .&. (7 :: Int)))+  | otherwise   = countToNth (n-3) (psieveFrom (intToInteger $ fromInteger n .&. (7 :: Int)))  -- find the n-th set bit in a list of PrimeSieves, -- aka find the (n+3)-rd prime@@ -456,3 +499,72 @@              | otherwise ->                let !na = a `shiftR` 1                in go bs na (msk `uncheckedShiftR` na) ix wd++{-# INLINE delta #-}+delta :: Int -> Int+delta i = unsafeAt deltas i++deltas :: UArray Int Int+deltas = listArray (0,7) [4,2,4,2,4,6,2,6]++{-# INLINE tau #-}+tau :: Int -> Int+tau i = unsafeAt taus i++taus :: UArray Int Int+taus = listArray (0,63)+        [  7,  4,  7,  4,  7, 12,  3, 12+        , 12,  6, 11,  6, 12, 18,  5, 18+        , 14,  7, 13,  7, 14, 21,  7, 21+        , 18,  9, 19,  9, 18, 27,  9, 27+        , 20, 10, 21, 10, 20, 30, 11, 30+        , 25, 12, 25, 12, 25, 36, 13, 36+        , 31, 15, 31, 15, 31, 47, 15, 47+        , 33, 17, 33, 17, 33, 49, 17, 49+        ]++{-# INLINE byte #-}+byte :: Int -> Int+byte i = unsafeAt startByte i++startByte :: UArray Int Int+startByte = listArray (0,7) [1,3,5,9,11,17,27,31]++{-# INLINE idx #-}+idx :: Int -> Int+idx i = unsafeAt startIdx i++startIdx :: UArray Int Int+startIdx = listArray (0,7) [4,7,4,4,7,4,7,7]++{-# INLINE mu #-}+mu :: Int -> Int+mu i = unsafeAt mArr i++{-# INLINE nu #-}+nu :: Int -> Int+nu i = unsafeAt nArr i++mArr :: UArray Int Int+mArr = listArray (0,63)+        [ 1,  2,  2,  3,  4,  5,  6,  7+        , 2,  3,  4,  6,  6,  8, 10, 11+        , 2,  4,  5,  7,  8,  9, 12, 13+        , 3,  6,  7,  9, 10, 12, 16, 17+        , 4,  6,  8, 10, 11, 14, 18, 19+        , 5,  8,  9, 12, 14, 17, 22, 23+        , 6, 10, 12, 16, 18, 22, 27, 29+        , 7, 11, 13, 17, 19, 23, 29, 31+        ]++nArr :: UArray Int Int+nArr = listArray (0,63)+        [ 4, 3, 7, 6, 2, 1, 5, 0+        , 3, 7, 5, 0, 6, 2, 4, 1+        , 7, 5, 4, 1, 0, 6, 3, 2+        , 6, 0, 1, 4, 5, 7, 2, 3+        , 2, 6, 0, 5, 7, 3, 1, 4+        , 1, 2, 6, 7, 3, 4, 0, 5+        , 5, 4, 3, 2, 1, 0, 7, 6+        , 0, 1, 2, 3, 4, 5, 6, 7+        ]
Math/NumberTheory/Primes/Sieve/Indexing.hs view
@@ -6,18 +6,13 @@ -- Stability:   Provisional -- Portability: Non-portable (GHC extensions) --+-- Auxiliary stuff, conversion between number and index,+-- remainders modulo 30 and related things. {-# OPTIONS_HADDOCK hide #-} module Math.NumberTheory.Primes.Sieve.Indexing     ( idxPr     , toPrim-    , toIdx     , rho-    , delta-    , tau-    , byte-    , idx-    , mu-    , nu     ) where  import Data.Array.Unboxed@@ -25,13 +20,6 @@  import Math.NumberTheory.Unsafe --- Auxiliary stuff, conversion between number and index,--- remainders modulo 30 and related things.---- {-# SPECIALISE idxPr :: Integer -> (Int,Int),---                         Int -> (Int,Int),---                         Word -> (Int,Int)---   #-} {-# INLINE idxPr #-} idxPr :: Integral a => a -> (Int,Int) idxPr n0@@ -45,99 +33,16 @@     rm2 = rm1 `quot` 3     rm3 = min 7 (if rm2 > 5 then rm2-1 else rm2) --- {-# SPECIALISE toPrim :: Int -> Integer,---                          Int -> Int,---                          Int -> Word,---                          Int -> Word16---     #-} {-# INLINE toPrim #-}-toPrim :: Integral a => Int -> a+toPrim :: Num a => Int -> a toPrim ix = 30*fromIntegral k + fromIntegral (rho i)   where     i = ix .&. 7     k = ix `shiftR` 3 --- Assumes n >= 7, gcd n 30 == 1-{-# INLINE toIdx #-}-toIdx :: Integral a => a -> Int-toIdx n = 8*fromIntegral q+r2-  where-    (q,r) = (n-7) `quotRem` 30-    r1 = fromIntegral r `quot` 3-    r2 = min 7 (if r1 > 5 then r1-1 else r1)- {-# INLINE rho #-} rho :: Int -> Int rho i = unsafeAt residues i  residues :: UArray Int Int residues = listArray (0,7) [7,11,13,17,19,23,29,31]--{-# INLINE delta #-}-delta :: Int -> Int-delta i = unsafeAt deltas i--deltas :: UArray Int Int-deltas = listArray (0,7) [4,2,4,2,4,6,2,6]--{-# INLINE tau #-}-tau :: Int -> Int-tau i = unsafeAt taus i--taus :: UArray Int Int-taus = listArray (0,63)-        [  7,  4,  7,  4,  7, 12,  3, 12-        , 12,  6, 11,  6, 12, 18,  5, 18-        , 14,  7, 13,  7, 14, 21,  7, 21-        , 18,  9, 19,  9, 18, 27,  9, 27-        , 20, 10, 21, 10, 20, 30, 11, 30-        , 25, 12, 25, 12, 25, 36, 13, 36-        , 31, 15, 31, 15, 31, 47, 15, 47-        , 33, 17, 33, 17, 33, 49, 17, 49-        ]--{-# INLINE byte #-}-byte :: Int -> Int-byte i = unsafeAt startByte i--startByte :: UArray Int Int-startByte = listArray (0,7) [1,3,5,9,11,17,27,31]--{-# INLINE idx #-}-idx :: Int -> Int-idx i = unsafeAt startIdx i--startIdx :: UArray Int Int-startIdx = listArray (0,7) [4,7,4,4,7,4,7,7]--{-# INLINE mu #-}-mu :: Int -> Int-mu i = unsafeAt mArr i--{-# INLINE nu #-}-nu :: Int -> Int-nu i = unsafeAt nArr i--mArr :: UArray Int Int-mArr = listArray (0,63)-        [ 1,  2,  2,  3,  4,  5,  6,  7-        , 2,  3,  4,  6,  6,  8, 10, 11-        , 2,  4,  5,  7,  8,  9, 12, 13-        , 3,  6,  7,  9, 10, 12, 16, 17-        , 4,  6,  8, 10, 11, 14, 18, 19-        , 5,  8,  9, 12, 14, 17, 22, 23-        , 6, 10, 12, 16, 18, 22, 27, 29-        , 7, 11, 13, 17, 19, 23, 29, 31-        ]--nArr :: UArray Int Int-nArr = listArray (0,63)-        [ 4, 3, 7, 6, 2, 1, 5, 0-        , 3, 7, 5, 0, 6, 2, 4, 1-        , 7, 5, 4, 1, 0, 6, 3, 2-        , 6, 0, 1, 4, 5, 7, 2, 3-        , 2, 6, 0, 5, 7, 3, 1, 4-        , 1, 2, 6, 7, 3, 4, 0, 5-        , 5, 4, 3, 2, 1, 0, 7, 6-        , 0, 1, 2, 3, 4, 5, 6, 7-        ]
− Math/NumberTheory/Primes/Sieve/Misc.hs
@@ -1,407 +0,0 @@--- |--- Module:      Math.NumberTheory.Primes.Sieve.Misc--- Copyright:   (c) 2011 Daniel Fischer--- Licence:     MIT--- Maintainer:  Daniel Fischer <daniel.is.fischer@googlemail.com>--- Stability:   Provisional--- Portability: Non-portable (GHC extensions)----{-# LANGUAGE BangPatterns        #-}-{-# LANGUAGE FlexibleContexts    #-}-{-# LANGUAGE MonoLocalBinds      #-}-{-# LANGUAGE ScopedTypeVariables #-}-{-# OPTIONS_GHC -fspec-constr-count=8 #-}-{-# OPTIONS_HADDOCK hide #-}-module Math.NumberTheory.Primes.Sieve.Misc-    ( -- * Types-      FactorSieve-    , TotientSieve-    , CarmichaelSieve-      -- * Functions-      -- ** Smallest prime factors-    , factorSieve-    , sieveFactor-    , fsBound-    , fsPrimeTest-      -- ** Totients-    , totientSieve-    , sieveTotient-      -- ** Carmichael-    , carmichaelSieve-    , sieveCarmichael-    ) where--import Control.Monad.ST-import Data.Array.ST-import Data.Array.Unboxed-import Control.Monad (when)-import Data.Bits-import GHC.Word--import System.Random--import Math.NumberTheory.Powers.Squares (integerSquareRoot')-import Math.NumberTheory.Primes.Sieve.Indexing-import Math.NumberTheory.Primes.Factorisation.Montgomery-import Math.NumberTheory.Unsafe-import Math.NumberTheory.Utils--{-# DEPRECATED FactorSieve, TotientSieve, CarmichaelSieve, factorSieve, sieveFactor, fsBound, fsPrimeTest, totientSieve, sieveTotient, carmichaelSieve, sieveCarmichael "Use new interface for sieves, provided by \"Math.NumberTheory.ArithmeticFunctions.SieveBlock\"" #-}--{--IMPORTANT NOTICE: Not all sieves use the same layout!--FactorSieve:--   To remain as efficient as possible, FactorSieve omits only even numbers.-   To relate an odd number x to its index i:--       i = (x `div` 2) - 1-       x = i * 2 + 3--TotientSieve, CarmichaelSieve:--   These sieves use a (2,3,5) wheel optimization, sacrificing performance to save-   more memory. The only indices stored are those coprime to 2, 3, and 5.-   To relate such an integer x to its index i:--       i = toIdx x-       x = toPrim i--}---- | A compact store of smallest prime factors.-data FactorSieve = FS {-# UNPACK #-} !Word {-# UNPACK #-} !(UArray Int Word16)---- | A compact store of totients.-data TotientSieve = TS {-# UNPACK #-} !Word {-# UNPACK #-} !(UArray Int Word)---- | A compact store of values of the Carmichael function.-data CarmichaelSieve = CS {-# UNPACK #-} !Word {-# UNPACK #-} !(UArray Int Word)---- | @'factorSieve' n@ creates a store of smallest prime factors of the numbers not exceeding @n@.---   If you need to factorise many smallish numbers, this can give a big speedup since it avoids---   many superfluous divisions. However, a too large sieve leads to a slowdown due to cache misses.---   The prime factors are stored as 'Word16' for compactness, so @n@ must be---   smaller than @2^32@.-factorSieve :: Integer -> FactorSieve-factorSieve bound-  | 4294967295 < bound  = error "factorSieve: overflow"-  | bound < 8   = FS 7 (array (0,2) [(0,0),(1,0),(2,0)])-  | otherwise   = FS bnd fSieve-    where-      bnd = fromInteger bound-      ibnd = fromInteger ((bound - 3) `quot` 2)-      svbd = (fromInteger (integerSquareRoot' bound) - 1) `quot` 2-      fSieve = runSTUArray $ do-          sieve <- newArray (0,ibnd) 0 :: ST s (STUArray s Int Word16)-          let sift i-                  | i < svbd = do-                      sp <- unsafeRead sieve i-                      when (sp == 0) (mark (2*i+3) (2*i*(i+3)+3))-                      sift (i+1)-                  | otherwise = return sieve-              mark p j-                  | j > ibnd    = return ()-                  | otherwise   = do-                      sp <- unsafeRead sieve j-                      when (sp == 0) (unsafeWrite sieve j $ fromIntegral p)-                      mark p (j+p)-          sift 0---- | @'fsBound' sieve@ tells the limit to which the sieve stores the smallest prime factors.-fsBound :: FactorSieve -> Word-fsBound (FS b _) = b---- | @'fsPrimeTest' sieve n@ checks in the sieve whether @n@ is prime. If @n@ is larger---   than the sieve can handle, an error is raised.-fsPrimeTest :: FactorSieve -> Integer -> Bool-fsPrimeTest fs@(FS bnd sve) n-    | n < 0     = fsPrimeTest fs (-n)-    | n < 2     = False-    | fromInteger n .&. (1 :: Int) == 0 = n == 2-    | n <= fromIntegral bnd = sve `unsafeAt` (fromInteger (n `shiftR` 1) - 1) == 0-    | otherwise = error "Out of bounds"---- | @'sieveFactor' fs n@ finds the prime factorisation of @n@ using the 'FactorSieve' @fs@.---   For negative @n@, a factor of @-1@ is included with multiplicity @1@.---   After stripping any present factors @2@, the remaining cofactor @c@ (if larger---   than @1@) is factorised with @fs@. This is most efficient of course if @c@ does not---   exceed the bound with which @fs@ was constructed. If it does, trial division is performed---   until either the cofactor falls below the bound or the sieve is exhausted. In the latter---   case, the elliptic curve method is used to finish the factorisation.-sieveFactor :: FactorSieve -> Integer -> [(Integer,Int)]-sieveFactor (FS bnd sve) = check-  where-    bound = fromIntegral bnd-    check 0 = error "0 has no prime factorisation"-    check 1 = []-    check n-      | n < 0       = (-1,1) : check (-n)-      | n <= bound  = go2w (fromIntegral n)     -- avoid expensive Integer ops if possible-      | fromInteger n .&. (1 :: Int) == 1 = sieveLoop n-      | otherwise   = go2 n-    go2w n-        | n .&. 1 == 1 = intLoop ((n-3) `shiftR` 1)-        | otherwise = case shiftToOddCount n of-                        (k,m) -> (2,k) : if m == 1 then [] else intLoop ((m-3) `shiftR` 1)-    go2 n = case shiftToOddCount n of-              (k,m) -> (2,k) : if m == 1 then [] else sieveLoop m-    sieveLoop n-        | bound < n  = tdLoop n (integerSquareRoot' n) 0-        | otherwise = intLoop (fromIntegral (n `shiftR` 1)-1)-    intLoop :: Word -> [(Integer,Int)]-    intLoop !n = case unsafeAt sve (fromIntegral n) of-                  0 -> [(2*fromIntegral n+3,1)]-                  p -> let p' = fromIntegral p in countLoop p' (n `quot` p' - 1) 1-    countLoop !p !i !c-        = case unsafeAt sve (fromIntegral i) of-            0 | p-3 == 2*i -> [(fromIntegral p,c+1)]-              | otherwise  -> (fromIntegral p,c) : (2*fromIntegral i+3,1) : []-            q | fromIntegral q == p -> countLoop p (i `quot` p - 1) (c+1)-              | otherwise -> (fromIntegral p, c) : intLoop i-    lstIdx = snd (bounds sve)-    tdLoop n sr ix-        | lstIdx < ix   = curve n-        | sr < p        = [(n,1)]-        | pix /= 0      = tdLoop n sr (ix+1)    -- not a prime-        | otherwise     = case splitOff p n of-                            (0,_) -> tdLoop n sr (ix+1)-                            (k,m) -> (p,k) : case m of-                                               1 -> []-                                               j | j <= bound -> intLoop (fromIntegral (j `shiftR` 1) - 1)-                                                 | otherwise -> tdLoop j (integerSquareRoot' j) (ix+1)-          where-            p = fromIntegral $ 2 * ix + 3-            pix = unsafeAt sve ix-    curve n = stdGenFactorisation (Just (bound*(bound+2))) (mkStdGen $ fromIntegral n `xor` 0xdecaf00d) Nothing n---- | @'totientSieve' n@ creates a store of the totients of the numbers not exceeding @n@.---   A 'TotientSieve' only stores values for numbers coprime to @30@ to reduce space usage.---   The maximal admissible value for @n@ is @'fromIntegral' ('maxBound' :: 'Word')@.-totientSieve :: Integer -> TotientSieve-totientSieve bound-  | fromIntegral (maxBound :: Word) < bound  = error "totientSieve: overflow"-  | bound < 8   = TS 7 (array (0,0) [(0,6)])-  | otherwise   = TS bnd (totSieve bnd)-    where-      bnd = fromInteger bound---- | @'sieveTotient' ts n@ finds the totient @&#960;(n)@, i.e. the number of integers @k@ with---   @1 <= k <= n@ and @'gcd' n k == 1@, in other words, the order of the group of units---   in @&#8484;/(n)@, using the 'TotientSieve' @ts@.---   First, factors of @2, 3@ and @5@ are handled individually, if the remaining---   cofactor of @n@ is within the sieve range, its totient is looked up, otherwise---   the calculation falls back on factorisation, first by trial division and---   if necessary, elliptic curves.-sieveTotient :: TotientSieve -> Integer -> Integer-sieveTotient (TS bnd sve) = check-  where-    bound = fromIntegral bnd-    check n-        | n < 1     = error "Totient only defined for positive numbers"-        | n == 1    = 1-        | otherwise = go2 n-    go2 n = case shiftToOddCount n of-              (0,_) -> go3 1 n-              (k,m) -> let tt = (shiftL 1 (k-1)) in if m == 1 then tt else go3 tt m-    go3 !tt n = case splitOff 3 n of-                  (0,_) -> go5 tt n-                  (k,m) -> let nt = tt*(2*3^(k-1)) in if m == 1 then nt else go5 nt m-    go5 !tt n = case splitOff 5 n of-                  (0,_) -> sieveLoop tt n-                  (k,m) -> let nt = tt*(4*5^(k-1)) in if m == 1 then nt else sieveLoop nt m-    sieveLoop !tt n-        | bound < n = tdLoop tt n (integerSquareRoot' n) 0-        | otherwise = case unsafeAt sve (toIdx n) of-                        nt -> tt*fromIntegral nt-    lstIdx = snd (bounds sve)-    tdLoop !tt n sr ix-        | lstIdx < ix   = curve tt n-        | sr < p'       = tt*(n-1)      -- n is a prime-        | pix /= p-1    = tdLoop tt n sr (ix+1)    -- not a prime, next-        | otherwise     = case splitOff p' n of-                            (0,_) -> tdLoop tt n sr (ix+1)-                            (k,m) -> let nt = tt*ppTotient (p',k)-                                     in case m of-                                          1 -> nt-                                          j | j <= bound -> nt*fromIntegral (unsafeAt sve (toIdx j))-                                            | otherwise  -> tdLoop nt j (integerSquareRoot' j) (ix+1)-          where-            p = toPrim ix-            p' = fromIntegral p-            pix = unsafeAt sve ix-    curve tt n = tt * totientFromCanonical (stdGenFactorisation (Just (bound*(bound+2))) (mkStdGen $ fromIntegral n `xor` 0xdecaf00d) Nothing n)---- | Calculate the totient from the canonical factorisation.-totientFromCanonical :: [(Integer,Int)] -> Integer-totientFromCanonical = product . map ppTotient---- | Totient of a prime power.-ppTotient :: (Integer, Int) -> Integer-ppTotient (p, 1) = p - 1-ppTotient (p, k) = (p - 1) * p ^ (k - 1)---- | @'carmichaelSieve' n@ creates a store of values of the Carmichael function---   for numbers not exceeding @n@.---   Like a 'TotientSieve', a 'CarmichaelSieve' only stores values for numbers coprime to @30@---   to reduce space usage. The maximal admissible value for @n@ is @'fromIntegral' ('maxBound' :: 'Word')@.-carmichaelSieve :: Integer -> CarmichaelSieve-carmichaelSieve bound-  | fromIntegral (maxBound :: Word) < bound  = error "carmichaelSieve: overflow"-  | bound < 8   = CS 7 (array (0,0) [(0,6)])-  | otherwise   = CS bnd (carSieve bnd)-    where-      bnd = fromInteger bound---- | @'sieveCarmichael' cs n@ finds the value of @&#955;(n)@ (or @&#968;(n)@), the smallest positive---   integer @e@ such that for all @a@ with @gcd a n == 1@ the congruence @a^e &#8801; 1 (mod n)@ holds,---   in other words, the (smallest) exponent of the group of units in @&#8484;/(n)@.---   The strategy is analogous to 'sieveTotient'.-sieveCarmichael :: CarmichaelSieve -> Integer -> Integer-sieveCarmichael (CS bnd sve) = check-  where-    bound = fromIntegral bnd-    check n-        | n < 1     = error "Carmichael function only defined for positive numbers"-        | n == 1    = 1-        | otherwise = go2 n-    go2 n = case shiftToOddCount n of-              (0,_) -> go3 1 n-              (k,m) -> let tt = case k of-                                  1 -> 1-                                  2 -> 2-                                  _ -> (shiftL 1 (k-2))-                       in if m == 1 then tt else go3 tt m-    go3 !tt n = case splitOff 3 n of-                  (0,_) -> go5 tt n-                  (k,1) | tt == 1   -> 2*3^(k-1)-                        | otherwise -> tt*3^(k-1)-                  (k,m) | tt == 1   -> go5 (2*3^(k-1)) m-                        | otherwise -> go5 (tt*3^(k-1)) m-    go5 !tt n = case splitOff 5 n of-                  (0,_) -> sieveLoop tt n-                  (k,m) -> let tt' = case fromInteger tt .&. (3 :: Int) of-                                       0 -> tt-                                       2 -> 2*tt-                                       _ -> 4*tt-                               nt = tt'*5^(k-1)-                           in if m == 1 then nt else sieveLoop nt m-    sieveLoop !tt n-        | bound < n = tdLoop tt n (integerSquareRoot' n) 0-        | otherwise = case unsafeAt sve (toIdx n) of-                        nt -> tt `lcm` fromIntegral nt-    lstIdx = snd (bounds sve)-    tdLoop !tt n sr ix-        | lstIdx < ix   = curve tt n-        | sr < p'       = tt `lcm` (n-1)      -- n is a prime-        | pix /= p-1    = tdLoop tt n sr (ix+1)    -- not a prime, next-        | otherwise     = case splitOff p' n of-                            (0,_) -> tdLoop tt n sr (ix+1)-                            (k,m) -> let nt = (lcm tt (p'-1))*p'^(k-1)-                                     in case m of-                                          1 -> nt-                                          j | j <= bound -> nt `lcm` fromIntegral (unsafeAt sve (toIdx j))-                                            | otherwise  -> tdLoop nt j (integerSquareRoot' j) (ix+1)-          where-            p = toPrim ix-            p' = fromIntegral p-            pix = unsafeAt sve ix-    curve tt n = tt `lcm` carmichaelFromCanonical (stdGenFactorisation (Just (bound*(bound+2))) (mkStdGen $ fromIntegral n `xor` 0xdecaf00d) Nothing n)---- | Calculate the Carmichael function from the factorisation.---   Requires that the list of prime factors is strictly ascending.-carmichaelFromCanonical :: [(Integer, Int)] -> Integer-carmichaelFromCanonical = go2-  where-    go2 ((2, k) : ps) = let acc = case k of-                                  1 -> 1-                                  2 -> 2-                                  _ -> 1 `shiftL` (k-2)-                        in go acc ps-    go2 ps = go 1 ps-    go !acc ((p, 1) : pps) = go (lcm acc (p - 1)) pps-    go acc ((p, k) : pps)  = go ((lcm acc (p - 1)) * p ^ (k - 1)) pps-    go acc []              = acc---- NOTE: This is a legacy implementation of FactorSieve which uses the---       same (2,3,5) wheel optimization as the other sieves.---       It is still used to generate the other sieves.-spfSieve :: Word -> ST s (STUArray s Int Word)-spfSieve bound = do-  let (octs,lidx) = idxPr bound-      !mxidx = 8*octs+lidx-      mxval :: Word-      mxval = 30*fromIntegral octs + fromIntegral (rho lidx)-      !mxsve = integerSquareRoot' mxval-      (kr,r) = idxPr mxsve-      !svbd = 8*kr+r-  ar <- newArray (0,mxidx) 0-  let start k i = 8*(k*(30*k+2*rho i) + byte i) + idx i-      tick p stp off j ix-        | mxidx < ix    = return ()-        | otherwise = do-          s <- unsafeRead ar ix-          when (s == 0) (unsafeWrite ar ix p)-          tick p stp off ((j+1) .&. 7) (ix + stp*delta j + tau (off+j))-      sift ix-        | svbd < ix = return ar-        | otherwise = do-          e <- unsafeRead ar ix-          when (e == 0)  (do let i = ix .&. 7-                                 k = ix `shiftR` 3-                                 !off = i `shiftL` 3-                                 !stp = ix - i-                                 !p = toPrim ix-                             tick p stp off i (start k i))-          sift (ix+1)-  sift 0--totSieve :: Word -> UArray Int Word-totSieve bound = runSTUArray $ do-    ar <- spfSieve bound-    (_,lst) <- getBounds ar-    let tot ix-          | lst < ix    = return ar-          | otherwise   = do-            p <- unsafeRead ar ix-            if p == 0-                then unsafeWrite ar ix (toPrim ix - 1)-                else do let !n = toPrim ix-                            (tp,m) = unFact p (n `quot` p)-                        case m of-                          1 -> unsafeWrite ar ix tp-                          _ -> do-                            tm <- unsafeRead ar (toIdx m)-                            unsafeWrite ar ix (tp*tm)-            tot (ix+1)-    tot 0--carSieve :: Word -> UArray Int Word-carSieve bound = runSTUArray $ do-    ar <- spfSieve bound-    (_,lst) <- getBounds ar-    let car ix-          | lst < ix    = return ar-          | otherwise   = do-            p <- unsafeRead ar ix-            if p == 0-                then unsafeWrite ar ix (toPrim ix - 1)-                else do let !n = toPrim ix-                            (tp,m) = unFact p (n `quot` p)-                        case m of-                          1 -> unsafeWrite ar ix tp-                          _ -> do-                            tm <- unsafeRead ar (toIdx m)-                            unsafeWrite ar ix (lcm tp tm)-            car (ix+1)-    car 0---- Find the p-part of the totient of (p*m) and the cofactor--- of the p-power in m.-{-# INLINE unFact #-}-unFact :: Word -> Word -> (Word,Word)-unFact p m = go (p-1) m-  where-    go !tt k = case k `quotRem` p of-                 (q,0) -> go (p*tt) q-                 _ -> (tt,k)
Math/NumberTheory/Primes/Testing.hs view
@@ -19,9 +19,6 @@     , millerRabinV     , isStrongFermatPP     , isFermatPP-      -- * Using a sieve-    , FactorSieve-    , fsIsPrime       -- * Trial division     , trialDivisionPrimeTo     ) where@@ -29,15 +26,3 @@ import Math.NumberTheory.Primes.Testing.Probabilistic import Math.NumberTheory.Primes.Testing.Certified import Math.NumberTheory.Primes.Factorisation.TrialDivision-import Math.NumberTheory.Primes.Sieve.Misc--{-# DEPRECATED fsIsPrime "Use new interface for sieves, provided by Math.NumberTheory.ArithmeticFunctions.SieveBlock" #-}---- | Test primality using a 'FactorSieve'. If @n@ is out of bounds---   of the sieve, fall back to 'isPrime'.-fsIsPrime :: FactorSieve -> Integer -> Bool-fsIsPrime fs n-    | n < 0     = fsIsPrime fs (-n)-    | n <= fromIntegral (fsBound fs)    = fsPrimeTest fs n-    | otherwise = isPrime n-
Math/NumberTheory/Primes/Testing/Certificates/Internal.hs view
@@ -30,9 +30,6 @@     ) where  import Data.List-#if __GLASGOW_HASKELL__ < 709-import Data.Word-#endif import Data.Bits import Data.Maybe import GHC.Integer.GMP.Internals
Math/NumberTheory/Primes/Testing/Probabilistic.hs view
@@ -156,7 +156,7 @@       square = isPossibleSquare2 n && r*r == n       r = integerSquareRoot n       d = find True 5-      find !pos cd = case jacobi' (n `rem` cd) cd of+      find !pos cd = case jacobi (n `rem` cd) cd of                        MinusOne -> if pos then cd else (-cd)                        Zero     -> if cd == n then 1 else 0                        One      -> find (not pos) (cd+2)@@ -187,16 +187,10 @@           v2n1  = ((un1 - (2*q)*un)*vn-qn) `rem` n           q2n   = (qn*qn) `rem` n           q2n1  = (qn*qn*q) `rem` n-#if __GLASGOW_HASKELL__ < 709-testLucas n q (J# s# ba#) = test (s# -# 1#)-  where-    test j# = case indexWordArray# ba# j# of-#else testLucas n q (Jp# bn#) = test (s# -# 1#)   where     s# = sizeofBigNat# bn#     test j# = case indexBigNat# bn# j# of-#endif                 0## -> test (j# -# 1#)                 w# -> look (j# -# 1#) (W# w#) (WORD_SIZE_IN_BITS - 1)     look j# w i@@ -205,11 +199,7 @@     go k# w i un un1 vn qn       | i < 0       = if isTrue# (k# <# 0#)                          then (un,vn,qn)-#if __GLASGOW_HASKELL__ < 709-                         else go (k# -# 1#) (W# (indexWordArray# ba# k#)) (WORD_SIZE_IN_BITS - 1) un un1 vn qn-#else                          else go (k# -# 1#) (W# (indexBigNat# bn# k#)) (WORD_SIZE_IN_BITS - 1) un un1 vn qn-#endif       | testBit w i = go k# w (i-1) u2n1 u2n2 v2n1 q2n1       | otherwise   = go k# w (i-1) u2n u2n1 v2n q2n         where@@ -220,7 +210,5 @@           v2n1  = ((un1 - (2*q)*un)*vn-qn) `rem` n           q2n   = (qn*qn) `rem` n           q2n1  = (qn*qn*q) `rem` n-#if __GLASGOW_HASKELL__ >= 709 -- Listed as a precondition of lucasTest testLucas _ _ _ = error "lucasTest: negative argument"-#endif
Math/NumberTheory/Primes/Types.hs view
@@ -10,8 +10,9 @@ -- Should not be exposed to users. -- -{-# LANGUAGE CPP          #-}-{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE CPP           #-}+{-# LANGUAGE TypeFamilies  #-}+{-# LANGUAGE DeriveGeneric #-}  module Math.NumberTheory.Primes.Types   ( Prime@@ -19,23 +20,24 @@   , PrimeNat(..)   ) where -#if MIN_VERSION_base(4,8,0)-#else-import Data.Word-#endif- import Numeric.Natural+import GHC.Generics+import Control.DeepSeq  newtype Prm = Prm { unPrm :: Word }-  deriving (Eq, Ord)+  deriving (Eq, Ord, Generic) +instance NFData Prm+ instance Show Prm where   showsPrec d (Prm p) r = (if d > 10 then "(" ++ s ++ ")" else s) ++ r     where       s = "Prm " ++ show p  newtype PrimeNat = PrimeNat { unPrimeNat :: Natural }-  deriving (Eq, Ord)+  deriving (Eq, Ord, Generic)++instance NFData PrimeNat  instance Show PrimeNat where   showsPrec d (PrimeNat p) r = (if d > 10 then "(" ++ s ++ ")" else s) ++ r
+ Math/NumberTheory/Quadratic/EisensteinIntegers.hs view
@@ -0,0 +1,315 @@+-- |+-- Module:      Math.NumberTheory.EisensteinIntegers+-- Copyright:   (c) 2018 Alexandre Rodrigues Baldé+-- Licence:     MIT+-- Maintainer:  Alexandre Rodrigues Baldé <alexandrer_b@outlook.com>+-- Stability:   Provisional+-- Portability: Non-portable (GHC extensions)+--+-- This module exports functions for manipulating Eisenstein integers, including+-- computing their prime factorisations.+--++{-# LANGUAGE BangPatterns   #-}+{-# LANGUAGE DeriveGeneric  #-}+{-# LANGUAGE RankNTypes     #-}++module Math.NumberTheory.Quadratic.EisensteinIntegers+  ( EisensteinInteger(..)+  , ω+  , conjugate+  , norm+  , associates+  , ids++  , divideByThree++  -- * Primality functions+  , factorise+  , findPrime+  , isPrime+  , primes+  ) where++import Data.List                                       (mapAccumL, partition)+import Data.Maybe                                      (fromMaybe)+import Data.Ord                                        (comparing)+import GHC.Generics                                    (Generic)++import qualified Math.NumberTheory.Euclidean            as ED+import Math.NumberTheory.Moduli.Sqrt+import qualified Math.NumberTheory.Primes.Factorisation as Factorisation+import Math.NumberTheory.Primes.Types                   (PrimeNat(..))+import qualified Math.NumberTheory.Primes.Sieve         as Sieve+import qualified Math.NumberTheory.Primes.Testing       as Testing+import Math.NumberTheory.Utils                          (mergeBy)+import Math.NumberTheory.Utils.FromIntegral             (integerToNatural)++infix 6 :+++-- | An Eisenstein integer is a + bω, where a and b are both integers.+data EisensteinInteger = (:+) { real :: !Integer, imag :: !Integer }+    deriving (Eq, Ord, Generic)++-- | The imaginary unit for Eisenstein integers, where+--+-- > ω == (-1/2) + ((sqrt 3)/2)ι == exp(2*pi*ι/3)+-- and ι is the usual imaginary unit with ι² == -1.+ω :: EisensteinInteger+ω = 0 :+ 1++instance Show EisensteinInteger where+    show (a :+ b)+        | b == 0     = show a+        | a == 0     = s ++ b'+        | otherwise  = show a ++ op ++ b'+        where+            b' = if abs b == 1 then "ω" else show (abs b) ++ "*ω"+            op = if b > 0 then "+" else "-"+            s  = if b > 0 then "" else "-"++instance Num EisensteinInteger where+    (+) (a :+ b) (c :+ d) = (a + c) :+ (b + d)+    (*) (a :+ b) (c :+ d) = (a * c - b * d) :+ (b * (c - d) + a * d)+    abs = fst . absSignum+    negate (a :+ b) = (-a) :+ (-b)+    fromInteger n = n :+ 0+    signum = snd . absSignum++-- | Returns an @EisensteinInteger@'s sign, and its associate in the first+-- sextant.+absSignum :: EisensteinInteger -> (EisensteinInteger, EisensteinInteger)+absSignum z@(a :+ b)+    | a == 0 && b == 0                                  = (z, 0)            -- origin+    | a > b && b >= 0                                   = (z, 1)            -- first sextant: 0 ≤ Arg(η) < π/3+    | b >= a && a > 0                                   = ((-ω) * z, 1 + ω) -- second sextant: π/3 ≤ Arg(η) < 2π/3+    | b > 0 && 0 >= a                                   = ((-1 - ω) * z, ω) -- third sextant: 2π/3 ≤ Arg(η) < π+    | a < b && b <= 0                                   = (- z, -1)         -- fourth sextant: -π < Arg(η) < -2π/3 or Arg(η) = π+    | b <= a && a < 0                                   = (ω * z, -1 - ω)   -- fifth sextant: -2π/3 ≤ Arg(η) < -π/3+    | otherwise                                         = ((1 + ω) * z, -ω) -- sixth sextant: -π/3 ≤ Arg(η) < 0++-- | List of all Eisenstein units, counterclockwise across all sextants,+-- starting with @1@.+ids :: [EisensteinInteger]+ids = take 6 (iterate ((1 + ω) *) 1)++-- | Produce a list of an @EisensteinInteger@'s associates.+associates :: EisensteinInteger -> [EisensteinInteger]+associates e = map (e *) ids++-- | Takes an Eisenstein prime whose norm is of the form @3k + 1@ with @k@+-- a nonnegative integer, and return its primary associate.+-- * Does *not* check for this precondition.+-- * @head@ will fail when supplied a number unsatisfying it.+primary :: EisensteinInteger -> EisensteinInteger+primary = head . filter (\p -> p `ED.mod` 3 == 2) . associates++instance ED.Euclidean EisensteinInteger where+  quotRem = divHelper quot+  divMod  = divHelper div++-- | Function that does most of the underlying work for @divMod@ and+-- @quotRem@, apart from choosing the specific integer division algorithm.+-- This is instead done by the calling function (either @divMod@ which uses+-- @div@, or @quotRem@, which uses @quot@.)+divHelper+    :: (Integer -> Integer -> Integer)+    -> EisensteinInteger+    -> EisensteinInteger+    -> (EisensteinInteger, EisensteinInteger)+divHelper divide g h =+    let nr :+ ni = g * conjugate h+        denom = norm h+        q = divide nr denom :+ divide ni denom+        p = h * q+    in (q, g - p)++-- | Conjugate a Eisenstein integer.+conjugate :: EisensteinInteger -> EisensteinInteger+conjugate (a :+ b) = (a - b) :+ (-b)++-- | The square of the magnitude of a Eisenstein integer.+norm :: EisensteinInteger -> Integer+norm (a :+ b) = a*a - a * b + b*b++-- | Checks if a given @EisensteinInteger@ is prime. @EisensteinInteger@s+-- whose norm is a prime congruent to @0@ or @1@ modulo 3 are prime.+-- See <http://thekeep.eiu.edu/theses/2467 Bandara, Sarada, "An Exposition of the Eisenstein Integers" (2016)>,+-- page 12.+isPrime :: EisensteinInteger -> Bool+isPrime e | e == 0                     = False+          -- Special case, @1 - ω@ is the only Eisenstein prime with norm @3@,+          --  and @abs (1 - ω) = 2 + ω@.+          | a' == 2 && b' == 1         = True+          | b' == 0 && a' `mod` 3 == 2 = Testing.isPrime a'+          | nE `mod` 3 == 1            = Testing.isPrime nE+          | otherwise = False+  where nE       = norm e+        a' :+ b' = abs e++-- | Remove @1 - ω@ factors from an @EisensteinInteger@, and calculate that+-- prime's multiplicity in the number's factorisation.+divideByThree :: EisensteinInteger -> (Int, EisensteinInteger)+divideByThree = go 0+  where+    go :: Int -> EisensteinInteger -> (Int, EisensteinInteger)+    go !n z@(a :+ b) | r1 == 0 && r2 == 0 = go (n + 1) (q1 :+ q2)+                      | otherwise          = (n, abs z)+      where+        -- @(a + a - b) :+ (a + b)@ is @z * (2 :+ 1)@, and @z * (2 :+ 1)/3@+        -- is the same as @z / (1 :+ (-1))@.+        (q1, r1) = divMod (a + a - b) 3+        (q2, r2) = divMod (a + b) 3++-- | Find an Eisenstein integer whose norm is the given prime number+-- in the form @3k + 1@ using a modification of the+-- <http://www.ams.org/journals/mcom/1972-26-120/S0025-5718-1972-0314745-6/S0025-5718-1972-0314745-6.pdf Hermite-Serret algorithm>.+--+-- The maintainer <https://github.com/cartazio/arithmoi/pull/121#issuecomment-415010647 Andrew Lelechenko>+-- derived the following:+-- * Each prime of form @3n+1@ is actually of form @6k+1@.+-- * One has @(z+3k)^2 ≡ z^2 + 6kz + 9k^2 ≡ z^2 + (6k+1)z - z + 9k^2 ≡ z^2 - z + 9k^2 (mod 6k+1)@.+--+-- * The goal is to solve @z^2 - z + 1 ≡ 0 (mod 6k+1)@. One has:+-- @z^2 - z + 9k^2 ≡ 9k^2 - 1 (mod 6k+1)@+-- @(z+3k)^2 ≡ 9k^2-1 (mod 6k+1)@+-- @z+3k = sqrtMod(9k^2-1)@+-- @z = sqrtMod(9k^2-1) - 3k@+--+-- * For example, let @p = 7@, then @k = 1@. Square root of @9*1^2-1 modulo 7@ is @1@.+-- * And @z = 1 - 3*1 = -2 ≡ 5 (mod 7)@.+-- * Truly, @norm (5 :+ 1) = 25 - 5 + 1 = 21 ≡ 0 (mod 7)@.+findPrime :: Integer -> EisensteinInteger+findPrime p = case sqrtsModPrime (9*k*k - 1) (PrimeNat . integerToNatural $ p) of+    []    -> error "findPrime: argument must be prime p = 6k + 1"+    z : _ -> ED.gcd (p :+ 0) ((z - 3 * k) :+ 1)+    where+        k :: Integer+        k = p `div` 6++-- | An infinite list of Eisenstein primes. Uses primes in Z to exhaustively+-- generate all Eisenstein primes in order of ascending magnitude.+-- * Every prime is in the first sextant, so the list contains no associates.+-- * Eisenstein primes from the whole complex plane can be generated by+-- applying @associates@ to each prime in this list.+primes :: [EisensteinInteger]+primes = (2 :+ 1) : mergeBy (comparing norm) l r+  where (leftPrimes, rightPrimes) = partition (\p -> p `mod` 3 == 2) Sieve.primes+        rightPrimes' = filter (\prime -> prime `mod` 3 == 1) $ tail rightPrimes+        l = [p :+ 0 | p <- leftPrimes]+        r = [g | p <- rightPrimes', let x :+ y = findPrime p, g <- [x :+ y, x :+ (x - y)]]++-- | Compute the prime factorisation of a Eisenstein integer. This is unique+-- up to units (+/- 1, +/- ω, +/- ω²).+-- * Unit factors are not included in the result.+-- * All prime factors are primary i.e. @e ≡ 2 (modE 3)@, for an Eisenstein+-- prime factor @e@.+--+-- * This function works by factorising the norm of an Eisenstein integer+-- and then, for each prime factor, finding the Eisenstein prime whose norm+-- is said prime factor with @findPrime@.+--+-- * This is only possible because the norm function of the Euclidean Domain of+-- Eisenstein integers is multiplicative: @norm (e1 * e2) == norm e1 * norm e2@+-- for any two @EisensteinInteger@s @e1, e2@.+--+-- * In the previously mentioned work <http://thekeep.eiu.edu/theses/2467 Bandara, Sarada, "An Exposition of the Eisenstein Integers" (2016)>,+-- in Theorem 8.4 in Chapter 8, a way is given to express any Eisenstein+-- integer @μ@ as @(-1)^a * ω^b * (1 - ω)^c * product [π_i^a_i | i <- [1..N]]@+-- where @a, b, c, a_i@ are nonnegative integers, @N > 1@ is an integer and+-- @π_i@ are primary primes (for a primary Eisenstein prime @p@,+-- @p ≡ 2 (modE 3)@, see @primary@ above).+--+-- * Aplying @norm@ to both sides of Theorem 8.4:+--    @norm μ = norm ((-1)^a * ω^b * (1 - ω)^c * product [ π_i^a_i | i <- [1..N]])@+-- == @norm μ = norm ((-1)^a) * norm (ω^b) * norm ((1 - ω)^c) * norm (product [ π_i^a_i | i <- [1..N]])@+-- == @norm μ = (norm (-1))^a * (norm ω)^b * (norm (1 - ω))^c * product [ norm (π_i^a_i) | i <- [1..N]]@+-- == @norm μ = (norm (-1))^a * (norm ω)^b * (norm (1 - ω))^c * product [ (norm π_i)^a_i) | i <- [1..N]]@+-- == @norm μ = 1^a * 1^b * 3^c * product [ (norm π_i)^a_i) | i <- [1..N]]@+-- == @norm μ = 3^c * product [ (norm π_i)^a_i) | i <- [1..N]]@+-- where @a, b, c, a_i@ are nonnegative integers, and @N > 1@ is an integer.+--+-- * The remainder of the Eisenstein integer factorisation problem is about+-- finding appropriate @[e_i | i <- [1..M]@ such that+-- @(nub . map norm) [e_i | i <- [1..N]] == [π_i | i <- [1..N]]@+-- where @ 1 < N <= M@ are integers, @nub@ removes duplicates and @==@+-- is equality on sets.+--+-- * The reason @M >= N@ is because the prime factors of an Eisenstein integer+-- may include a prime factor and its conjugate, meaning the number may have+-- more Eisenstein prime factors than its norm has integer prime factors.+factorise :: EisensteinInteger -> [(EisensteinInteger, Int)]+factorise g = concat $+              snd $+              mapAccumL go (abs g) (Factorisation.factorise $ norm g)+  where+    go :: EisensteinInteger -> (Integer, Int) -> (EisensteinInteger, [(EisensteinInteger, Int)])+    go z (3, e) | e == n    = (q, [(2 :+ 1, e)])+                | otherwise = error $ "3 is a prime factor of the norm of z\+                                      \ == " ++ show z ++ " with multiplicity\+                                      \ " ++ show e ++ " but (1 - ω) only\+                                      \ divides z " ++ show n ++ "times."+      where+        -- Remove all @1 :+ (-1)@ (which is associated to @2 :+ 1@) factors+        -- from the argument.+        (n, q) = divideByThree z+    go z (p, e) | p `mod` 3 == 2 =+                    let e' = e `quot` 2 in (z `quotI` (p ^ e'), [(p :+ 0, e')])++                -- The @`mod` 3 == 0@ case need not be verified because the+                -- only Eisenstein primes whose norm are a multiple of 3+                -- are @1 - ω@ and its associates, which have already been+                -- removed by the above @go z (3, e)@ pattern match.+                -- This @otherwise@ is mandatorily @`mod` 3 == 1@.+                | otherwise   = (z', filter ((> 0) . snd) [(gp, k), (gp', k')])+      where+        gp@(x :+ y)      = primary $ findPrime p+        -- @gp'@ is @gp@'s conjugate.+        gp'              = primary $ abs $ x :+ (x - y)+        (k, k', z') = divideByPrime gp gp' p e z++        quotI (a :+ b) n = (a `quot` n :+ b `quot` n)++-- | Remove @p@ and @conjugate p@ factors from the argument, where+-- @p@ is an Eisenstein prime.+divideByPrime+    :: EisensteinInteger   -- ^ Eisenstein prime @p@+    -> EisensteinInteger   -- ^ Conjugate of @p@+    -> Integer             -- ^ Precomputed norm of @p@, of form @4k + 1@+    -> Int                 -- ^ Expected number of factors (either @p@ or @conjugate p@)+                           --   in Eisenstein integer @z@+    -> EisensteinInteger   -- ^ Eisenstein integer @z@+    -> ( Int               -- Multiplicity of factor @p@ in @z@+       , Int               -- Multiplicity of factor @conjigate p@ in @z@+       , EisensteinInteger -- Remaining Eisenstein integer+       )+divideByPrime p p' np k = go k 0+    where+        go :: Int -> Int -> EisensteinInteger -> (Int, Int, EisensteinInteger)+        go 0 d z = (d, d, z)+        go c d z | c >= 2, Just z' <- z `quotEvenI` np = go (c - 2) (d + 1) z'+        go c d z = (d + d1, d + d2, z'')+            where+                (d1, z') = go1 c 0 z+                d2 = c - d1+                z'' = head $ drop d2+                    $ iterate (\g -> fromMaybe err $ (g * p) `quotEvenI` np) z'++        go1 :: Int -> Int -> EisensteinInteger -> (Int, EisensteinInteger)+        go1 0 d z = (d, z)+        go1 c d z+            | Just z' <- (z * p') `quotEvenI` np+            = go1 (c - 1) (d + 1) z'+            | otherwise+            = (d, z)++        err = error $ "divideByPrime: malformed arguments" ++ show (p, np, k)++-- | Divide an Eisenstein integer by an even integer.+quotEvenI :: EisensteinInteger -> Integer -> Maybe EisensteinInteger+quotEvenI (x :+ y) n+    | xr == 0 , yr == 0 = Just (xq :+ yq)+    | otherwise         = Nothing+  where+    (xq, xr) = x `quotRem` n+    (yq, yr) = y `quotRem` n
+ Math/NumberTheory/Quadratic/GaussianIntegers.hs view
@@ -0,0 +1,254 @@+-- |+-- Module:      Math.NumberTheory.GaussianIntegers+-- Copyright:   (c) 2016 Chris Fredrickson, Google Inc.+-- Licence:     MIT+-- Maintainer:  Chris Fredrickson <chris.p.fredrickson@gmail.com>+-- Stability:   Provisional+-- Portability: Non-portable (GHC extensions)+--+-- This module exports functions for manipulating Gaussian integers, including+-- computing their prime factorisations.+--++{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE DeriveGeneric #-}++module Math.NumberTheory.Quadratic.GaussianIntegers (+    GaussianInteger(..),+    ι,+    conjugate,+    norm,+    (.^),+    isPrime,+    primes,+    gcdG,+    gcdG',+    findPrime,+    findPrime',+    factorise,+) where++import Control.DeepSeq (NFData)+import Data.List (mapAccumL, partition)+import Data.Maybe (fromMaybe)+import Data.Ord (comparing)+import GHC.Generics+++import qualified Math.NumberTheory.Euclidean as ED+import Math.NumberTheory.Moduli.Sqrt+import Math.NumberTheory.Powers (integerSquareRoot)+import Math.NumberTheory.Primes.Types (PrimeNat(..))+import qualified Math.NumberTheory.Primes.Factorisation as Factorisation+import qualified Math.NumberTheory.Primes.Sieve as Sieve+import qualified Math.NumberTheory.Primes.Testing as Testing+import Math.NumberTheory.Utils              (mergeBy)+import Math.NumberTheory.Utils.FromIntegral (integerToNatural)++infix 6 :++infixr 8 .^+-- |A Gaussian integer is a+bi, where a and b are both integers.+data GaussianInteger = (:+) { real :: !Integer, imag :: !Integer }+    deriving (Eq, Ord, Generic)++instance NFData GaussianInteger++-- |The imaginary unit, where+--+-- > ι .^ 2 == -1+ι :: GaussianInteger+ι = 0 :+ 1++instance Show GaussianInteger where+    show (a :+ b)+        | b == 0     = show a+        | a == 0     = s ++ b'+        | otherwise  = show a ++ op ++ b'+        where+            b' = if abs b == 1 then "ι" else show (abs b) ++ "*ι"+            op = if b > 0 then "+" else "-"+            s  = if b > 0 then "" else "-"++instance Num GaussianInteger where+    (+) (a :+ b) (c :+ d) = (a + c) :+ (b + d)+    (*) (a :+ b) (c :+ d) = (a * c - b * d) :+ (a * d + b * c)+    abs = fst . absSignum+    negate (a :+ b) = (-a) :+ (-b)+    fromInteger n = n :+ 0+    signum = snd . absSignum++absSignum :: GaussianInteger -> (GaussianInteger, GaussianInteger)+absSignum z@(a :+ b)+    | a == 0 && b == 0 =   (z, 0)              -- origin+    | a >  0 && b >= 0 =   (z, 1)              -- first quadrant: (0, inf) x [0, inf)i+    | a <= 0 && b >  0 =   (b  :+ (-a), ι)     -- second quadrant: (-inf, 0] x (0, inf)i+    | a <  0 && b <= 0 = ((-a) :+ (-b), -1)    -- third quadrant: (-inf, 0) x (-inf, 0]i+    | otherwise        = ((-b) :+   a, -ι)     -- fourth quadrant: [0, inf) x (-inf, 0)i++instance ED.Euclidean GaussianInteger where+    quotRem = divHelper quot+    divMod  = divHelper div++divHelper+    :: (Integer -> Integer -> Integer)+    -> GaussianInteger+    -> GaussianInteger+    -> (GaussianInteger, GaussianInteger)+divHelper divide g h =+    let nr :+ ni = g * conjugate h+        denom = norm h+        q = divide nr denom :+ divide ni denom+        p = h * q+    in (q, g - p)++-- |Conjugate a Gaussian integer.+conjugate :: GaussianInteger -> GaussianInteger+conjugate (r :+ i) = r :+ (-i)++-- |The square of the magnitude of a Gaussian integer.+norm :: GaussianInteger -> Integer+norm (x :+ y) = x * x + y * y++-- |Compute whether a given Gaussian integer is prime.+isPrime :: GaussianInteger -> Bool+isPrime g@(x :+ y)+    | x == 0 && y /= 0 = abs y `mod` 4 == 3 && Testing.isPrime y+    | y == 0 && x /= 0 = abs x `mod` 4 == 3 && Testing.isPrime x+    | otherwise        = Testing.isPrime $ norm g++-- |An infinite list of the Gaussian primes. Uses primes in Z to exhaustively+-- generate all Gaussian primes (up to associates), in order of ascending+-- magnitude.+primes :: [GaussianInteger]+primes = (1 :+ 1): mergeBy (comparing norm) l r+  where (leftPrimes, rightPrimes) = partition (\p -> p `mod` 4 == 3) (tail Sieve.primes)+        l = [p :+ 0 | p <- leftPrimes]+        r = [g | p <- rightPrimes, let x :+ y = findPrime p, g <- [x :+ y, y :+ x]]+++-- | Compute the GCD of two Gaussian integers. Result is always+-- in the first quadrant.+gcdG :: GaussianInteger -> GaussianInteger -> GaussianInteger+gcdG = ED.gcd+{-# DEPRECATED gcdG "Use 'Math.NumberTheory.Euclidean.gcd' instead." #-}++gcdG' :: GaussianInteger -> GaussianInteger -> GaussianInteger+gcdG' = ED.gcd+{-# DEPRECATED gcdG' "Use 'Math.NumberTheory.Euclidean.gcd' instead." #-}++-- |Find a Gaussian integer whose norm is the given prime number+-- of form 4k + 1 using+-- <http://www.ams.org/journals/mcom/1972-26-120/S0025-5718-1972-0314745-6/S0025-5718-1972-0314745-6.pdf Hermite-Serret algorithm>.+findPrime :: Integer -> GaussianInteger+findPrime p = case sqrtsModPrime (-1) (PrimeNat . integerToNatural $ p) of+    []    -> error "findPrime: an argument must be prime p = 4k + 1"+    z : _ -> go p z -- Effectively we calculate gcdG' (p :+ 0) (z :+ 1)+    where+        sqrtp :: Integer+        sqrtp = integerSquareRoot p++        go :: Integer -> Integer -> GaussianInteger+        go g h+            | g <= sqrtp = g :+ h+            | otherwise  = go h (g `mod` h)++findPrime' :: Integer -> GaussianInteger+findPrime' = findPrime+{-# DEPRECATED findPrime' "Use 'findPrime' instead." #-}++-- |Raise a Gaussian integer to a given power.+(.^) :: (Integral a) => GaussianInteger -> a -> GaussianInteger+a .^ e+    | e < 0 && norm a == 1 =+        case a of+            1    :+ 0 -> 1+            (-1) :+ 0 -> if even e then 1 else (-1)+            0    :+ 1 -> (0 :+ (-1)) .^ (abs e `mod` 4)+            _         -> (0 :+ 1) .^ (abs e `mod` 4)+    | e < 0     = error "Cannot exponentiate non-unit Gaussian Int to negative power"+    | a == 0    = 0+    | e == 0    = 1+    | even e    = s * s+    | otherwise = a * a .^ (e - 1)+    where+    s = a .^ div e 2+{-# DEPRECATED (.^) "Use (^) instead." #-}++-- |Compute the prime factorisation of a Gaussian integer. This is unique up to units (+/- 1, +/- i).+-- Unit factors are not included in the result.+factorise :: GaussianInteger -> [(GaussianInteger, Int)]+factorise g = concat $ snd $ mapAccumL go g (Factorisation.factorise $ norm g)+    where+        go :: GaussianInteger -> (Integer, Int) -> (GaussianInteger, [(GaussianInteger, Int)])+        go z (2, e) = (divideByTwo z, [(1 :+ 1, e)])+        go z (p, e)+            | p `mod` 4 == 3+            = let e' = e `quot` 2 in (z `quotI` (p ^ e'), [(p :+ 0, e')])+            | otherwise+            = (z', filter ((> 0) . snd) [(gp, k), (gp', k')])+                where+                    gp = findPrime p+                    (k, k', z') = divideByPrime gp p e z+                    gp' = abs (conjugate gp)++-- | Remove all (1:+1) factors from the argument,+-- avoiding complex division.+divideByTwo :: GaussianInteger -> GaussianInteger+divideByTwo z@(x :+ y)+    | even x, even y+    = divideByTwo $ z `quotI` 2+    | odd x, odd y+    = (x - y) `quot` 2 :+ (x + y) `quot` 2+    | otherwise+    = z++-- | Remove p and conj p factors from the argument,+-- avoiding complex division.+divideByPrime+    :: GaussianInteger   -- ^ Gaussian prime p+    -> Integer           -- ^ Precomputed norm of p, of form 4k + 1+    -> Int               -- ^ Expected number of factors (either p or conj p)+                         --   in Gaussian integer z+    -> GaussianInteger   -- ^ Gaussian integer z+    -> ( Int             -- Multiplicity of factor p in z+       , Int             -- Multiplicity of factor conj p in z+       , GaussianInteger -- Remaining Gaussian integer+       )+divideByPrime p np k = go k 0+    where+        go :: Int -> Int -> GaussianInteger -> (Int, Int, GaussianInteger)+        go 0 d z = (d, d, z)+        go c d z+            | c >= 2+            , Just z' <- z `quotEvenI` np+            = go (c - 2) (d + 1) z'+        go c d z = (d + d1, d + d2, z'')+            where+                (d1, z') = go1 c 0 z+                d2 = c - d1+                z'' = head $ drop d2+                    $ iterate (\g -> fromMaybe err $ (g * p) `quotEvenI` np) z'++        go1 :: Int -> Int -> GaussianInteger -> (Int, GaussianInteger)+        go1 0 d z = (d, z)+        go1 c d z+            | Just z' <- (z * conjugate p) `quotEvenI` np+            = go1 (c - 1) (d + 1) z'+            | otherwise+            = (d, z)++        err = error $ "divideByPrime: malformed arguments" ++ show (p, np, k)++quotI :: GaussianInteger -> Integer -> GaussianInteger+quotI (x :+ y) n = (x `quot` n :+ y `quot` n)++quotEvenI :: GaussianInteger -> Integer -> Maybe GaussianInteger+quotEvenI (x :+ y) n+    | xr == 0+    , yr == 0+    = Just (xq :+ yq)+    | otherwise+    = Nothing+    where+        (xq, xr) = x `quotRem` n+        (yq, yr) = y `quotRem` n
+ Math/NumberTheory/Recurrencies.hs view
@@ -0,0 +1,18 @@+-- |+-- Module:      Math.NumberTheory.Recurrencies+-- Copyright:   (c) 2018 Alexandre Rodrigues Baldé+-- Licence:     MIT+-- Maintainer:  Alexandre Rodrigues Baldé <alexandrer_b@outlook.com>+-- Stability:   Provisional+-- Portability: Non-portable (GHC extensions)+--++module Math.NumberTheory.Recurrencies+    ( module Math.NumberTheory.Recurrencies.Linear+    , module Math.NumberTheory.Recurrencies.Bilinear+    , module Math.NumberTheory.Recurrencies.Pentagonal+    ) where++import Math.NumberTheory.Recurrencies.Bilinear+import Math.NumberTheory.Recurrencies.Linear+import Math.NumberTheory.Recurrencies.Pentagonal (partition)
Math/NumberTheory/Recurrencies/Bilinear.hs view
@@ -14,25 +14,26 @@ -- Top-level definitions in this module are polymorphic, so the results of computations are not retained in memory. -- Make them monomorphic to take advantages of memoization. Compare ----- > > :set +s--- > > binomial !! 1000 !! 1000 :: Integer--- > 1--- > (0.01 secs, 1,385,512 bytes)--- > > binomial !! 1000 !! 1000 :: Integer--- > 1--- > (0.01 secs, 1,381,616 bytes)+-- >>> :set +s+-- >>> binomial !! 1000 !! 1000 :: Integer+-- 1+-- (0.01 secs, 1,385,512 bytes)+-- >>> binomial !! 1000 !! 1000 :: Integer+-- 1+-- (0.01 secs, 1,381,616 bytes) -- -- against ----- > > let binomial' = binomial :: [[Integer]]--- > > binomial' !! 1000 !! 1000 :: Integer--- > 1--- > (0.01 secs, 1,381,696 bytes)--- > > binomial' !! 1000 !! 1000 :: Integer--- > 1--- > (0.01 secs, 391,152 bytes)+-- >>> let binomial' = binomial :: [[Integer]]+-- >>> binomial' !! 1000 !! 1000 :: Integer+-- 1+-- (0.01 secs, 1,381,696 bytes)+-- >>> binomial' !! 1000 !! 1000 :: Integer+-- 1+-- (0.01 secs, 391,152 bytes) -{-# LANGUAGE CPP #-}+{-# LANGUAGE CPP                 #-}+{-# LANGUAGE ScopedTypeVariables #-}  module Math.NumberTheory.Recurrencies.Bilinear   ( binomial@@ -42,24 +43,21 @@   , eulerian1   , eulerian2   , bernoulli+  , euler+  , eulerPolyAt1   ) where  import Data.List import Data.Ratio import Numeric.Natural -#if MIN_VERSION_base(4,8,0)-#else-import Data.Word-#endif- import Math.NumberTheory.Recurrencies.Linear (factorial)  -- | Infinite zero-based table of binomial coefficients (also known as Pascal triangle): -- @binomial !! n !! k == n! \/ k! \/ (n - k)!@. ----- > > take 5 (map (take 5) binomial)--- > [[1],[1,1],[1,2,1],[1,3,3,1],[1,4,6,4,1]]+-- >>> take 5 (map (take 5) binomial)+-- [[1],[1,1],[1,2,1],[1,3,3,1],[1,4,6,4,1]] -- -- Complexity: @binomial !! n !! k@ is O(n) bits long, its computation -- takes O(k n) time and forces thunks @binomial !! n !! i@ for @0 <= i <= k@.@@ -77,8 +75,8 @@  -- | Infinite zero-based table of <https://en.wikipedia.org/wiki/Stirling_numbers_of_the_first_kind Stirling numbers of the first kind>. ----- > > take 5 (map (take 5) stirling1)--- > [[1],[0,1],[0,1,1],[0,2,3,1],[0,6,11,6,1]]+-- >>> take 5 (map (take 5) stirling1)+-- [[1],[0,1],[0,1,1],[0,2,3,1],[0,6,11,6,1]] -- -- Complexity: @stirling1 !! n !! k@ is O(n ln n) bits long, its computation -- takes O(k n^2 ln n) time and forces thunks @stirling1 !! i !! j@ for @0 <= i <= n@ and @max(0, k - n + i) <= j <= k@.@@ -95,8 +93,8 @@  -- | Infinite zero-based table of <https://en.wikipedia.org/wiki/Stirling_numbers_of_the_second_kind Stirling numbers of the second kind>. ----- > > take 5 (map (take 5) stirling2)--- > [[1],[0,1],[0,1,1],[0,1,3,1],[0,1,7,6,1]]+-- >>> take 5 (map (take 5) stirling2)+-- [[1],[0,1],[0,1,1],[0,1,3,1],[0,1,7,6,1]] -- -- Complexity: @stirling2 !! n !! k@ is O(n ln n) bits long, its computation -- takes O(k n^2 ln n) time and forces thunks @stirling2 !! i !! j@ for @0 <= i <= n@ and @max(0, k - n + i) <= j <= k@.@@ -114,8 +112,8 @@ -- | Infinite one-based table of <https://en.wikipedia.org/wiki/Lah_number Lah numbers>. -- @lah !! n !! k@ equals to lah(n + 1, k + 1). ----- > > take 5 (map (take 5) lah)--- > [[1],[2,1],[6,6,1],[24,36,12,1],[120,240,120,20,1]]+-- >>> take 5 (map (take 5) lah)+-- [[1],[2,1],[6,6,1],[24,36,12,1],[120,240,120,20,1]] -- -- Complexity: @lah !! n !! k@ is O(n ln n) bits long, its computation -- takes O(k n ln n) time and forces thunks @lah !! n !! i@ for @0 <= i <= k@.@@ -131,8 +129,8 @@  -- | Infinite zero-based table of <https://en.wikipedia.org/wiki/Eulerian_number Eulerian numbers of the first kind>. ----- > > take 5 (map (take 5) eulerian1)--- > [[],[1],[1,1],[1,4,1],[1,11,11,1]]+-- >>> take 5 (map (take 5) eulerian1)+-- [[],[1],[1,1],[1,4,1],[1,11,11,1]] -- -- Complexity: @eulerian1 !! n !! k@ is O(n ln n) bits long, its computation -- takes O(k n^2 ln n) time and forces thunks @eulerian1 !! i !! j@ for @0 <= i <= n@ and @max(0, k - n + i) <= j <= k@.@@ -148,8 +146,8 @@  -- | Infinite zero-based table of <https://en.wikipedia.org/wiki/Eulerian_number#Eulerian_numbers_of_the_second_kind Eulerian numbers of the second kind>. ----- > > take 5 (map (take 5) eulerian2)--- > [[],[1],[1,2],[1,8,6],[1,22,58,24]]+-- >>> take 5 (map (take 5) eulerian2)+-- [[],[1],[1,2],[1,8,6],[1,22,58,24]] -- -- Complexity: @eulerian2 !! n !! k@ is O(n ln n) bits long, its computation -- takes O(k n^2 ln n) time and forces thunks @eulerian2 !! i !! j@ for @0 <= i <= n@ and @max(0, k - n + i) <= j <= k@.@@ -167,20 +165,61 @@ -- computed via <https://en.wikipedia.org/wiki/Bernoulli_number#Connection_with_Stirling_numbers_of_the_second_kind connection> -- with 'stirling2'. ----- > > take 5 bernoulli--- > [1 % 1,(-1) % 2,1 % 6,0 % 1,(-1) % 30]+-- >>> take 5 bernoulli+-- [1 % 1,(-1) % 2,1 % 6,0 % 1,(-1) % 30] -- -- Complexity: @bernoulli !! n@ is O(n ln n) bits long, its computation -- takes O(n^3 ln n) time and forces thunks @stirling2 !! i !! j@ for @0 <= i <= n@ and @0 <= j <= i@. -- -- One could also consider 'Math.Combinat.Numbers.bernoulli' to compute stand-alone values. bernoulli :: Integral a => [Ratio a]-bernoulli = map f stirling2-  where-    f = sum . zipWith4 (\sgn denom fact stir -> sgn * fact * stir % denom) (cycle [1, -1]) [1..] factorial+bernoulli = helperForB_E_EP id (map recip [1..]) {-# SPECIALIZE bernoulli :: [Ratio Int] #-} {-# SPECIALIZE bernoulli :: [Rational] #-} +-- | Infinite zero-based list of <https://en.wikipedia.org/wiki/Euler_number Euler numbers>.+-- The algorithm used was derived from <http://www.emis.ams.org/journals/JIS/VOL4/CHEN/AlgBE2.pdf Algorithms for Bernoulli numbers and Euler numbers>+-- by Kwang-Wu Chen, second formula of the Corollary in page 7.+-- Sequence <https://oeis.org/A122045 A122045> in OEIS.+--+-- >>> take 10 euler' :: [Rational]+-- [1 % 1,0 % 1,(-1) % 1,0 % 1,5 % 1,0 % 1,(-61) % 1,0 % 1,1385 % 1,0 % 1]+euler' :: forall a . Integral a => [Ratio a]+euler' = tail $ helperForB_E_EP tail as+  where+    as :: [Ratio a]+    as = zipWith3+        (\sgn frac ones -> (sgn * ones) % frac)+        (cycle [1, 1, 1, 1, -1, -1, -1, -1])+        (dups (iterate (2 *) 1))+        (cycle [1, 1, 1, 0])++    dups :: forall x . [x] -> [x]+    dups = foldr (\n list -> n : n : list) []+{-# SPECIALIZE euler' :: [Ratio Int]     #-}+{-# SPECIALIZE euler' :: [Rational]      #-}++-- | The same sequence as @euler'@, but with type @[a]@ instead of @[Ratio a]@+-- as the denominators in @euler'@ are always @1@.+--+-- >>> take 10 euler :: [Integer]+-- [1, 0, -1, 0, 5, 0, -61, 0, 1385, 0]+euler :: forall a . Integral a => [a]+euler = map numerator euler'++-- | Infinite zero-based list of the @n@-th order Euler polynomials evaluated at @1@.+-- The algorithm used was derived from <http://www.emis.ams.org/journals/JIS/VOL4/CHEN/AlgBE2.pdf Algorithms for Bernoulli numbers and Euler numbers>+-- by Kwang-Wu Chen, third formula of the Corollary in page 7.+-- Element-by-element division of sequences <https://oeis.org/A198631 A1986631>+-- and <https://oeis.org/A006519 A006519> in OEIS.+--+-- >>> take 10 eulerPolyAt1 :: [Rational]+-- [1 % 1,1 % 2,0 % 1,(-1) % 4,0 % 1,1 % 2,0 % 1,(-17) % 8,0 % 1,31 % 2]+eulerPolyAt1 :: forall a . Integral a => [Ratio a]+eulerPolyAt1 = tail $ helperForB_E_EP tail (map recip (iterate (2 *) 1))+{-# SPECIALIZE eulerPolyAt1 :: [Ratio Int]     #-}+{-# SPECIALIZE eulerPolyAt1 :: [Rational]      #-}+ ------------------------------------------------------------------------------- -- Utils @@ -195,3 +234,22 @@       []       -> let v = f m y a in [v]       (z : zs) -> let v = f m y z in (v : go (succ m) z zs) {-# INLINE zipIndexedListWithTail #-}++-- | Helper for common code in @bernoulli, euler, eulerPolyAt1. All three+-- sequences rely on @stirling2@ and have the same general structure of+-- zipping four lists together with multiplication, with one of those lists+-- being the sublists in @stirling2@, and two of them being the factorial+-- sequence and @cycle [1, -1]@. The remaining list is passed to+-- @helperForB_E_EP@ as an argument.+--+-- Note: This function has a @([Ratio a] -> [Ratio a])@ argument because+-- @bernoulli !! n@ will use, for all nonnegative @n@, every element in+-- @stirling2 !! n@, while @euler, eulerPolyAt1@ only use+-- @tail $ stirling2 !! n@. As such, this argument serves to pass @id@+-- in the former case, and @tail@ in the latter.+helperForB_E_EP :: Integral a => ([Ratio a] -> [Ratio a]) -> [Ratio a] -> [Ratio a]+helperForB_E_EP g xs = map (f . g) stirling2+  where+    f = sum . zipWith4 (\sgn fact x stir -> sgn * fact * x * stir) (cycle [1, -1]) factorial xs+{-# SPECIALIZE helperForB_E_EP :: ([Ratio Int] -> [Ratio Int]) -> [Ratio Int] -> [Ratio Int] #-}+{-# SPECIALIZE helperForB_E_EP :: ([Rational] -> [Rational]) -> [Rational] -> [Rational]     #-}
Math/NumberTheory/Recurrencies/Linear.hs view
@@ -23,15 +23,10 @@ import Data.Bits import Numeric.Natural -#if MIN_VERSION_base(4,8,0)-#else-import Data.Word-#endif- -- | Infinite zero-based table of factorials. ----- > > take 5 factorial--- > [1,1,2,6,24]+-- >>> take 5 factorial+-- [1,1,2,6,24] -- -- The time-and-space behaviour of 'factorial' is similar to described in -- "Math.NumberTheory.Recurrencies.Bilinear#memory".
+ Math/NumberTheory/Recurrencies/Pentagonal.hs view
@@ -0,0 +1,96 @@+-- |+-- Module:      Math.NumberTheory.Recurrencies.Pentagonal+-- Copyright:   (c) 2018 Alexandre Rodrigues Baldé+-- Licence:     MIT+-- Maintainer:  Alexandre Rodrigues Baldé <alexandrer_b@outlook.com>+-- Stability:   Provisional+-- Portability: Non-portable (GHC extensions)+--+-- Values of <https://en.wikipedia.org/wiki/Partition_(number_theory)#Partition_function partition function>.+--++{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE RankNTypes   #-}++module Math.NumberTheory.Recurrencies.Pentagonal+  ( partition+  , pentagonalSigns+  , pents+  ) where++import qualified Data.IntMap as IM+import Numeric.Natural       (Natural)++-- | Infinite list of generalized pentagonal numbers.+-- Example:+--+-- >>> take 10 pents+-- [0, 1, 2, 5, 7, 12 ,15, 22, 26, 35]+pents :: (Enum a, Num a) => [a]+pents = interleave (scanl (\acc n -> acc + 3 * n - 1) 0 [1..])+                   (scanl (\acc n -> acc + 3 * n - 2) 1 [2..])+  where+    interleave :: [a] -> [a] -> [a]+    interleave (n : ns) (m : ms) = n : m : interleave ns ms+    interleave _ _ = []++-- | When calculating the @n@-th partition number @p(n)@ using the sum+-- @p(n) = p(n-1) + p(n-2) - p(n-5) - p(n-7) + p(n-11) + ...@, the signs of each+-- term alternate every two terms, starting with a positive sign.+-- @pentagonalSigns@ takes a list of numbers and produces such an alternated+-- sequence.+-- Examples:+--+-- >>> pentagonalSigns [1..5]+-- [1, 2, -3, -4, 5]+--+-- >>> pentagonalSigns [1..6]+-- [1, 2, -3, -4, 5, 6]+pentagonalSigns :: Num a => [a] -> [a]+pentagonalSigns = zipWith (*) (cycle [1, 1, -1, -1])++-- [Implementation notes for partition function]+--+-- @p(n) = p(n-1) + p(n-2) - p(n-5) - p(n-7) + p(n-11) + ...@, where @p(0) = 1@+-- and @p(k) = 0@ for a negative integer @k@. Uses a @Map@ from the+-- @containers@ package to memoize previous results.+--+-- Example: calculating @partition !! 10@, assuming the memoization map is+-- filled and called @dict :: Integral a => Map a a@.+--+-- * @tail [0, 1, 2, 5, 7, 12 ,15, 22, 26, 35, ..] == [1, 2, 5, 7, 12 ,15, 22, 26, 35, 40, ..]@.+-- * @takeWhile (\m -> 10 - m >= 0) [1, 2, 5, 7, 12 ,15, 22, 26, 35, 40, ..] == [1, 2, 5, 7]@.+-- * @map (\m -> dict ! fromIntegral (10 - m)) [1, 2, 5, 7] == [dict ! 9, dict ! 8, dict ! 5, dict ! 3] == [30, 22, 7, 3]@+-- * @pentagonalSigns [30, 22, 7, 3] == [30, 22, 7, 3] == [30, 22, -7, -3]@+-- * @sum [30, 22, -7, -3] == 42@+--+-- Notes:+-- 1. @tail@ is applied to @pents@ because otherwise the calculation of+-- @p(n)@ would involve a duplicated @p(n-1)@ term (see the above example).+-- 2. Calculating @partition !! k@, where @k@ is any index equal or higher+-- than @maxBound :: Int@ results in undefined behavior.++-- | Infinite zero-based table of <https://oeis.org/A000041 partition numbers>.+--+-- >>> take 10 partition+-- [1, 1, 2, 3, 5, 7, 11, 15, 22, 30]+--+-- >>> :set -XDataKinds+-- >>> partition !! 1000 :: Mod 1000+-- (991 `modulo` 1000)+partition :: Num a => [a]+partition = 1 : go (IM.singleton 0 1) 1+  where+    go :: Num a => IM.IntMap a -> Int -> [a]+    go dict !n =+        let n' = (sum .+                  pentagonalSigns .+                  map (\m -> dict IM.! (n - m)) .+                  takeWhile (\m -> n >= m) .+                  tail) (pents :: [Int])+            dict' = IM.insert n n' dict+        in n' : go dict' (n + 1)+{-# SPECIALIZE partition :: [Int]     #-}+{-# SPECIALIZE partition :: [Word]    #-}+{-# SPECIALIZE partition :: [Integer] #-}+{-# SPECIALIZE partition :: [Natural] #-}
Math/NumberTheory/SmoothNumbers.hs view
@@ -12,6 +12,8 @@ -- over a set {3, 4}, and 24 is not. -- +{-# LANGUAGE ScopedTypeVariables #-}+ module Math.NumberTheory.SmoothNumbers   ( -- * Create a smooth basis     SmoothBasis@@ -24,68 +26,77 @@   , smoothOverInRangeBF   ) where -import Data.List (sort, nub)+import Prelude hiding (div, mod, gcd)+import Data.Coerce+import Data.List (nub) import qualified Data.Set as S+import Math.NumberTheory.Euclidean import Math.NumberTheory.Primes.Sieve (primes)  -- | An abstract representation of a smooth basis. -- It consists of a set of coprime numbers ≥2.-newtype SmoothBasis a = SmoothBasis { unSmoothBasis :: [a] } deriving Show+newtype SmoothBasis a = SmoothBasis { unSmoothBasis :: [a] } deriving (Eq, Show)  -- | Build a 'SmoothBasis' from a set of coprime numbers ≥2. ----- > > fromSet (Set.fromList [2, 3])--- > Just (SmoothBasis [2, 3])--- > > fromSet (Set.fromList [2, 4]) -- should be coprime--- > Nothing--- > > fromSet (Set.fromList [1, 3]) -- should be >= 2--- > Nothing-fromSet :: Integral a => S.Set a -> Maybe (SmoothBasis a)+-- >>> import qualified Data.Set as Set+-- >>> fromSet (Set.fromList [2, 3])+-- Just (SmoothBasis [2, 3])+-- >>> fromSet (Set.fromList [2, 4]) -- should be coprime+-- Nothing+-- >>> fromSet (Set.fromList [1, 3]) -- should be >= 2+-- Nothing+fromSet :: Euclidean a => S.Set a -> Maybe (SmoothBasis a) fromSet s = if isValid l then Just (SmoothBasis l) else Nothing where l = S.elems s  -- | Build a 'SmoothBasis' from a list of coprime numbers ≥2. ----- > > fromList [2, 3]--- > Just (SmoothBasis [2, 3])--- > > fromList [2, 2]--- > Just (SmoothBasis [2])--- > > fromList [2, 4] -- should be coprime--- > Nothing--- > > fromList [1, 3] -- should be >= 2--- > Nothing-fromList :: Integral a => [a] -> Maybe (SmoothBasis a)-fromList l = if isValid l' then Just (SmoothBasis l') else Nothing where l' = nub $ sort l+-- >>> fromList [2, 3]+-- Just (SmoothBasis [2, 3])+-- >>> fromList [2, 2]+-- Just (SmoothBasis [2])+-- >>> fromList [2, 4] -- should be coprime+-- Nothing+-- >>> fromList [1, 3] -- should be >= 2+-- Nothing+fromList :: Euclidean a => [a] -> Maybe (SmoothBasis a)+fromList l = if isValid l' then Just (SmoothBasis l') else Nothing+  where+    l' = nub l  -- | Build a 'SmoothBasis' from a list of primes below given bound. ----- > > fromSmoothUpperBound 10--- > Just (SmoothBasis [2, 3, 5, 7])--- > > fromSmoothUpperBound 1--- > Nothing+-- >>> fromSmoothUpperBound 10+-- Just (SmoothBasis [2, 3, 5, 7])+-- >>> fromSmoothUpperBound 1+-- Nothing fromSmoothUpperBound :: Integral a => a -> Maybe (SmoothBasis a) fromSmoothUpperBound n = if (n < 2)                          then Nothing-                         else Just $ SmoothBasis $ map fromInteger $ takeWhile (<= nI) primes-                         where nI = toInteger n+                         else Just $ SmoothBasis $ takeWhile (<= n) primes  -- | Generate an infinite ascending list of -- <https://en.wikipedia.org/wiki/Smooth_number smooth numbers> -- over a given smooth basis. ----- > > take 10 (smoothOver (fromJust (fromList [2, 5])))--- > [1, 2, 4, 5, 8, 10, 16, 20, 25, 32]+-- >>> import Data.Maybe+-- >>> take 10 (smoothOver (fromJust (fromList [2, 5])))+-- [1, 2, 4, 5, 8, 10, 16, 20, 25, 32] smoothOver :: Integral a => SmoothBasis a -> [a] smoothOver pl = foldr (\p l -> mergeListLists $ iterate (map (p*)) l) [1] (unSmoothBasis pl)-                where-                      {-# INLINE mergeListLists #-}-                      mergeListLists      = foldr go1 []-                        where go1 (h:t) b = h:(go2 t b)-                              go1 _     b = b+  where+    {-# INLINE mergeListLists #-}+    mergeListLists      = foldr go1 []+      where+        go1 :: Ord a => [a] -> [a] -> [a]+        go1 (h:t) b = h:(go2 t b)+        go1 _     b = b -                              go2 a@(ah:at) b@(bh:bt)-                                | bh < ah   = bh : (go2 a bt)-                                | otherwise = ah : (go2 at b) -- no possibility of duplicates-                              go2 a b = if null a then b else a+        go2 :: Ord a => [a] -> [a] -> [a]+        go2 a@(ah:at) b@(bh:bt)+          | bh < ah   = bh : (go2 a bt)+          | otherwise = ah : (go2 at b) -- no possibility of duplicates+        go2 a b = if null a then b else a  -- | Generate an ascending list of -- <https://en.wikipedia.org/wiki/Smooth_number smooth numbers>@@ -95,10 +106,15 @@ -- for short, but distant ranges; -- consider using 'smoothOverInRangeBF' in such cases. ----- > > smoothOverInRange (fromJust (fromList [2, 5])) 100 200--- > [100, 125, 128, 160, 200]-smoothOverInRange   :: Integral a => SmoothBasis a -> a -> a -> [a]-smoothOverInRange s lo hi = takeWhile (<= hi) $ dropWhile (< lo) (smoothOver s)+-- >>> import Data.Maybe+-- >>> smoothOverInRange (fromJust (fromList [2, 5])) 100 200+-- [100, 125, 128, 160, 200]+smoothOverInRange :: forall a. Integral a => SmoothBasis a -> a -> a -> [a]+smoothOverInRange s lo hi+  = takeWhile (<= hi)+  $ dropWhile (< lo)+  $ coerce+  $ smoothOver (coerce s :: SmoothBasis (WrappedIntegral a))  -- | Generate an ascending list of -- <https://en.wikipedia.org/wiki/Smooth_number smooth numbers>@@ -110,21 +126,27 @@ -- -- Suffix BF stands for the brute force algorithm, involving a lot of divisions. ----- > > smoothOverInRangeBF (fromJust (fromList [2, 5])) 100 200--- > [100, 125, 128, 160, 200]-smoothOverInRangeBF :: Integral a => SmoothBasis a -> a -> a -> [a]-smoothOverInRangeBF prs lo hi = filter (mf prs') [lo..hi]-                                where mf []     n    = (n == 1) -- mf means manually factor-                                      mf pl@(p:ps) n = if (mod n p == 0)-                                                       then mf pl (div n p)-                                                       else mf ps n-                                      prs'           = unSmoothBasis prs+-- >>> import Data.Maybe+-- >>> smoothOverInRangeBF (fromJust (fromList [2, 5])) 100 200+-- [100, 125, 128, 160, 200]+smoothOverInRangeBF :: forall a. Integral a => SmoothBasis a -> a -> a -> [a]+smoothOverInRangeBF prs lo hi+  = coerce+  $ filter (mf prs')+  $ coerce [lo..hi]+  where+    mf :: [WrappedIntegral a] -> WrappedIntegral a -> Bool+    mf _         0 = False+    mf []        n = n == 1 -- mf means manually factor+    mf pl@(p:ps) n = if mod n p == 0+                     then mf pl (div n p)+                     else mf ps n+    prs'           = coerce $ unSmoothBasis prs  -- | isValid assumes that the list is sorted and unique and then checks if the list is suitable to be a SmoothBasis.-isValid :: (Integral a) => [a] -> Bool-isValid pl = if (length pl == 0) then False else v' pl-             where v' []        = True-                   v' (x:xs)    = if (x < 2 || (not $ rpl x xs)) then False else v' xs-                   rpl _ []     = True  -- rpl means relatively prime to the rest of the list-                   rpl n (x:xs) = if (gcd n x > 1) then False else rpl n xs-+isValid :: Euclidean a => [a] -> Bool+isValid pl = length pl /= 0 && v' pl+  where+    v' :: Euclidean a => [a] -> Bool+    v' []     = True+    v' (x:xs) = x /= 0 && abs x /= 1 && abs x == x && all (coprime x) xs && v' xs
Math/NumberTheory/UniqueFactorisation.hs view
@@ -9,8 +9,9 @@ -- An abstract type class for unique factorisation domains. -- -{-# LANGUAGE CPP          #-}-{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE CPP               #-}+{-# LANGUAGE TypeFamilies      #-}+{-# LANGUAGE DefaultSignatures #-}  module Math.NumberTheory.UniqueFactorisation   ( Prime@@ -20,15 +21,11 @@ import Control.Arrow import Data.Coerce -#if MIN_VERSION_base(4,8,0)-#else-import Data.Word-#endif--import Math.NumberTheory.Primes.Factorisation as F (factorise')+import qualified Math.NumberTheory.Primes.Factorisation as F (factorise) import Math.NumberTheory.Primes.Testing.Probabilistic as T (isPrime) import Math.NumberTheory.Primes.Types (Prime, Prm(..), PrimeNat(..))-import qualified Math.NumberTheory.GaussianIntegers as G+import qualified Math.NumberTheory.Quadratic.EisensteinIntegers as E+import qualified Math.NumberTheory.Quadratic.GaussianIntegers as G import Math.NumberTheory.Utils.FromIntegral  import Numeric.Natural@@ -43,8 +40,10 @@ class UniqueFactorisation a where   unPrime   :: Prime a -> a   factorise :: a -> [(Prime a, Word)]-   isPrime   :: a -> Maybe (Prime a)++  default isPrime :: (Eq a, Num a) => a -> Maybe (Prime a)+  isPrime 0 = Nothing   isPrime n = case factorise n of     [(p, 1)] -> Just p     _        -> Nothing@@ -53,34 +52,21 @@  instance UniqueFactorisation Int where   unPrime   = coerce wordToInt-  factorise m' = if m <= 1-                then []-                else map (coerce integerToWord *** intToWord) . F.factorise' . intToInteger $ m-                  where-                    m = abs m'-  isPrime n = if T.isPrime (toInteger n) then Just (coerce $ intToWord $ abs n) else Nothing+  factorise = map (coerce integerToWord *** intToWord) . F.factorise . intToInteger  instance UniqueFactorisation Word where-  unPrime     = coerce-  factorise m = if m <= 1-                  then []-                  else map (coerce integerToWord *** intToWord) . F.factorise' . wordToInteger $ m+  unPrime   = coerce+  factorise = map (coerce integerToWord *** intToWord) . F.factorise . wordToInteger   isPrime n = if T.isPrime (toInteger n) then Just (coerce n) else Nothing  instance UniqueFactorisation Integer where-  unPrime      = coerce naturalToInteger-  factorise m' = if m <= 1-                then []-                else map (coerce integerToNatural *** intToWord) . F.factorise' $ m-                  where-                    m = abs m'+  unPrime   = coerce naturalToInteger+  factorise = map (coerce integerToNatural *** intToWord) . F.factorise   isPrime n = if T.isPrime n then Just (coerce $ integerToNatural $ abs n) else Nothing  instance UniqueFactorisation Natural where   unPrime   = coerce-  factorise m = if m <= 1-                  then []-                  else map (coerce integerToNatural *** intToWord) . F.factorise' . naturalToInteger $ m+  factorise = map (coerce integerToNatural *** intToWord) . F.factorise . naturalToInteger   isPrime n = if T.isPrime (toInteger n) then Just (coerce n) else Nothing  newtype GaussianPrime = GaussianPrime { _unGaussianPrime :: G.GaussianInteger }@@ -90,4 +76,15 @@   unPrime = coerce    factorise 0 = []-  factorise g = map (coerce *** intToWord) $ filter (\(h, _) -> abs h /= 1) $ G.factorise g+  factorise g = map (coerce *** intToWord) $ G.factorise g++newtype EisensteinPrime = EisensteinPrime { _unEisensteinPrime :: E.EisensteinInteger }+  deriving (Eq, Show)++type instance Prime E.EisensteinInteger = EisensteinPrime++instance UniqueFactorisation E.EisensteinInteger where+  unPrime = coerce++  factorise 0 = []+  factorise e = map (coerce *** intToWord) $ E.factorise e
Math/NumberTheory/Utils.hs view
@@ -6,7 +6,7 @@ -- Stability:   Provisional -- Portability: Non-portable (GHC extensions) ----- Some utilities for bit twiddling.+-- Some utilities, mostly for bit twiddling. -- {-# LANGUAGE CPP, MagicHash, UnboxedTuples, BangPatterns #-} {-# OPTIONS_HADDOCK hide #-}@@ -21,6 +21,10 @@     , uncheckedShiftR     , splitOff     , splitOff#++    , mergeBy++    , recipMod     ) where  #include "MachDeps.h"@@ -29,23 +33,10 @@  import GHC.Integer import GHC.Integer.GMP.Internals+import GHC.Natural  import Data.Bits -#if WORD_SIZE_IN_BITS == 64-#define m5 0x5555555555555555-#define m3 0x3333333333333333-#define mf 0x0F0F0F0F0F0F0F0F-#define m1 0x0101010101010101-#define sd 56-#else-#define m5 0x55555555-#define m3 0x33333333-#define mf 0x0F0F0F0F-#define m1 0x01010101-#define sd 24-#endif- uncheckedShiftR :: Word -> Int -> Word uncheckedShiftR (W# w#) (I# i#) = W# (uncheckedShiftRL# w# i#) @@ -56,6 +47,7 @@ "shiftToOddCount/Int"       shiftToOddCount = shiftOCInt "shiftToOddCount/Word"      shiftToOddCount = shiftOCWord "shiftToOddCount/Integer"   shiftToOddCount = shiftOCInteger+"shiftToOddCount/Natural"   shiftToOddCount = shiftOCNatural   #-} {-# INLINE [1] shiftToOddCount #-} shiftToOddCount :: Integral a => a -> (Int, a)@@ -82,25 +74,25 @@       (# z#, w# #)         | isTrue# (z# ==# 0#) -> (0, n)         | otherwise -> (I# z#, S# (word2Int# w#))-#if __GLASGOW_HASKELL__ < 709-shiftOCInteger n@(J# _ ba#) = case count 0# 0# of-#else shiftOCInteger n@(Jp# bn#) = case bigNatZeroCount bn# of                                  0#  -> (0, n)                                  z#  -> (I# z#, n `shiftRInteger` z#) shiftOCInteger n@(Jn# bn#) = case bigNatZeroCount bn# of-#endif                                  0#  -> (0, n)                                  z#  -> (I# z#, n `shiftRInteger` z#)-#if __GLASGOW_HASKELL__ < 709-  where-    count a# i# =-          case indexWordArray# ba# i# of-             0## -> count (a# +# WORD_SIZE_IN_BITS#) (i# +# 1#)-             w#  -> a# +# trailZeros# w#-#endif -#if __GLASGOW_HASKELL__ >= 709+-- | Specialised version for @'Natural'@.+--   Precondition: argument nonzero (not checked).+shiftOCNatural :: Natural -> (Int, Natural)+shiftOCNatural n@(NatS# i#) =+    case shiftToOddCount# i# of+      (# z#, w# #)+        | isTrue# (z# ==# 0#) -> (0, n)+        | otherwise -> (I# z#, NatS# w#)+shiftOCNatural n@(NatJ# bn#) = case bigNatZeroCount bn# of+                                 0#  -> (0, n)+                                 z#  -> (I# z#, NatJ# (bn# `shiftRBigNat` z#))+ -- | Count trailing zeros in a @'BigNat'@. --   Precondition: argument nonzero (not checked, Integer invariant). bigNatZeroCount :: BigNat -> Int#@@ -109,8 +101,7 @@     count a# i# =           case indexBigNat# bn# i# of             0## -> count (a# +# WORD_SIZE_IN_BITS#) (i# +# 1#)-            w#  -> a# +# trailZeros# w#-#endif+            w#  -> a# +# word2Int# (ctz# w#)  -- | Remove factors of @2@. If @n = 2^k*m@ with @m@ odd, the result is @m@. --   Precondition: argument not @0@ (not checked).@@ -137,33 +128,21 @@ --   Precondition: argument nonzero (not checked). shiftOInteger :: Integer -> Integer shiftOInteger (S# i#) = S# (word2Int# (shiftToOdd# (int2Word# i#)))-#if __GLASGOW_HASKELL__ < 709-shiftOInteger n@(J# _ ba#) = case count 0# 0# of-#else shiftOInteger n@(Jn# bn#) = case bigNatZeroCount bn# of                                  0#  -> n                                  z#  -> n `shiftRInteger` z# shiftOInteger n@(Jp# bn#) = case bigNatZeroCount bn# of-#endif                                  0#  -> n                                  z#  -> n `shiftRInteger` z#-#if __GLASGOW_HASKELL__ < 709-  where-    count a# i# =-          case indexWordArray# ba# i# of-            0## -> count (a# +# WORD_SIZE_IN_BITS#) (i# +# 1#)-            w#  -> a# +# trailZeros# w#-#endif  -- | Shift argument right until the result is odd. --   Precondition: argument not @0@, not checked. shiftToOdd# :: Word# -> Word#-shiftToOdd# w# = case trailZeros# w# of-                   k# -> uncheckedShiftRL# w# k#+shiftToOdd# w# = uncheckedShiftRL# w# (word2Int# (ctz# w#))  -- | Like @'shiftToOdd#'@, but count the number of places to shift too. shiftToOddCount# :: Word# -> (# Int#, Word# #)-shiftToOddCount# w# = case trailZeros# w# of+shiftToOddCount# w# = case word2Int# (ctz# w#) of                         k# -> (# k#, uncheckedShiftRL# w# k# #)  -- | Number of 1-bits in a @'Word#'@.@@ -179,20 +158,7 @@ bitCountInt :: Int -> Int bitCountInt = popCount --- | Number of trailing zeros in a @'Word#'@, wrong for @0@.-{-# INLINE trailZeros# #-}-trailZeros# :: Word# -> Int#-trailZeros# w =-    case xor# w (w `minusWord#` 1##) `uncheckedShiftRL#` 1# of-      v0 ->-        case v0 `minusWord#` (uncheckedShiftRL# v0 1# `and#` m5##) of-          v1 ->-            case (v1 `and#` m3##) `plusWord#` (uncheckedShiftRL# v1 2# `and#` m3##) of-              v2 ->-                case (v2 `plusWord#` uncheckedShiftRL# v2 4#) `and#` mf## of-                  v3 -> word2Int# (uncheckedShiftRL# (v3 `timesWord#` m1##) sd#)--splitOff :: Integer -> Integer -> (Int, Integer)+splitOff :: Integral a => a -> a -> (Int, a) splitOff _ 0 = (0, 0) -- prevent infinite loop splitOff p n = go 0 n   where@@ -211,3 +177,21 @@       (# q, 0## #) -> go (k +# 1#) q       _            -> (# k, m #) {-# INLINABLE splitOff# #-}++-- | Merges two ordered lists into an ordered list. Checks for neither its+-- precondition or postcondition.+mergeBy :: (a -> a -> Ordering) -> [a] -> [a] -> [a]+mergeBy cmp = loop+  where+    loop [] ys  = ys+    loop xs []  = xs+    loop (x:xs) (y:ys)+      = case cmp x y of+         GT -> y : loop (x:xs) ys+         _  -> x : loop xs (y:ys)++-- | Work around https://ghc.haskell.org/trac/ghc/ticket/14085+recipMod :: Integer -> Integer -> Maybe Integer+recipMod x m = case recipModInteger (x `mod` m) m of+  0 -> Nothing+  y -> Just y
Math/NumberTheory/Utils/FromIntegral.hs view
@@ -22,9 +22,6 @@   ) where  import Numeric.Natural-#if __GLASGOW_HASKELL__ < 709-import Data.Word-#endif  wordToInt :: Word -> Int wordToInt = fromIntegral
Math/NumberTheory/Zeta.hs view
@@ -1,115 +1,21 @@ -- | -- Module:      Math.NumberTheory.Zeta--- Copyright:   (c) 2016 Andrew Lelechenko+-- Copyright:   (c) 2018 Andrew Lelechenko -- Licence:     MIT -- Maintainer:  Andrew Lelechenko <andrew.lelechenko@gmail.com> -- Stability:   Provisional -- Portability: Non-portable (GHC extensions) ----- Riemann zeta-function.+-- Interface to work with Riemann zeta-function and Dirichlet beta-function.  {-# LANGUAGE ScopedTypeVariables #-}  module Math.NumberTheory.Zeta-  ( zetas-  , zetasEven-  , approximateValue+  ( module Math.NumberTheory.Zeta.Dirichlet+  , module Math.NumberTheory.Zeta.Riemann+  , module Math.NumberTheory.Zeta.Utils   ) where -import Data.ExactPi-import Data.Ratio--import Math.NumberTheory.Recurrencies.Bilinear (bernoulli)-import Math.NumberTheory.Recurrencies.Linear (factorial)---- | Infinite sequence of exact values of Riemann zeta-function at even arguments, starting with @ζ(0)@.--- Note that due to numerical errors convertation to 'Double' may return values below 1:------ > > approximateValue (zetasEven !! 25) :: Double--- > 0.9999999999999996------ Use your favorite type for long-precision arithmetic. For instance, 'Data.Number.Fixed.Fixed' works fine:------ > > approximateValue (zetasEven !! 25) :: Fixed Prec50--- > 1.00000000000000088817842111574532859293035196051773----zetasEven :: [ExactPi]-zetasEven = zipWith Exact [0, 2 ..] $ zipWith (*) (skipOdds bernoulli) cs-  where-    cs = (- 1 % 2) : zipWith (\i f -> i * (-4) / fromInteger (2 * f * (2 * f - 1))) cs [1..]--skipOdds :: [a] -> [a]-skipOdds (x : _ : xs) = x : skipOdds xs-skipOdds xs = xs--zetasEven' :: Floating a => [a]-zetasEven' = map approximateValue zetasEven--zetasOdd :: forall a. (Floating a, Ord a) => a -> [a]-zetasOdd eps = (1 / 0) : zets-  where-    zets :: [a] -- [zeta(3), zeta(5), zeta(7)...]-    zets = zipWith (*) zs (tail (iterate (* (- pi * pi)) 1))--    zs :: [a] -- [zeta(3) / (-pi^2), zeta(5) / pi^4, zeta(7) / (-pi^6)...]-    zs = zipWith (\w f -> negate (w / (1 + f))) ws fourth--    ys :: [a] -- [(1 - 1/4) * zeta(3) / (-pi^2), (1 - 1/4^2) * zeta(5) / pi^4...]-    ys = zipWith (*) zs fourth-    yss :: [[a]] -- [[], [ys !! 0], [ys !! 1, ys !! 0], [ys !! 2, ys !! 1, ys !! 0]...]-    yss = scanl (flip (:)) [] ys--    xs :: [a] -- first summand of RHS in (57) for m=[1..]-    xs = map (sum . zipWith (flip (/)) factorial2) yss--    ws :: [a] -- RHS in (57) for m=[1..]-    ws = zipWith (+) xs cs--    rs :: [a] -- [1, 1/2, 1/3, 1/4...]-    rs = map (\n -> recip (fromInteger n)) [1..]-    rss :: [[a]] -- [[1, 1/2, 1/3...], [1/2, 1/3, 1/4...], [1/3, 1/4...]]-    rss = iterate tail rs--    factorial2 :: [a] -- [2!, 4!, 6!..]-    factorial2 = map fromInteger $ tail $ skipOdds factorial--    fourth :: [a] -- [1 - 1/4, 1 - 1/4^2, 1 - 1/4^3...]-    fourth = tail $ map (1 -) $ iterate (/ 4) 1--    as :: [a] -- [zeta(0), zeta(2)/4, zeta(2*2)/4^2, zeta(2*3)/4^3...]-    as = zipWith (/) zetasEven' (iterate (* 4) 1)--    bs :: [a] -- map (+ log 2) [b(1), b(2), b(3)...],-              -- where b(m) = \sum_{n=0}^\infty zeta(2n) / 4^n / (n + m)-    bs = map ((+ log 2) . suminf eps . zipWith (*) as) rss--    cs :: [a] -- second summand of RHS in (57) for m = [1..]-    cs = zipWith (\b f -> b / f) bs factorial2--suminf :: (Floating a, Ord a) => a -> [a] -> a-suminf eps = sum . takeWhile ((>= eps / 111) . abs)---- | Infinite sequence of approximate (up to given precision)--- values of Riemann zeta-function at integer arguments, starting with @ζ(0)@.--- Computations for odd arguments are performed in accordance to--- <https://cr.yp.to/bib/2000/borwein.pdf Computational strategies for the Riemann zeta function>--- by J. M. Borwein, D. M. Bradley, R. E. Crandall, formula (57).------ > > take 5 (zetas 1e-14) :: [Double]--- > [-0.5,Infinity,1.6449340668482262,1.2020569031595942,1.0823232337111381]------ Beware to force evaluation of @zetas !! 1@, if the type @a@ does not support infinite values--- (for instance, 'Data.Number.Fixed.Fixed').----zetas :: (Floating a, Ord a) => a -> [a]-zetas eps = e : o : scanl1 f (intertwine es os)-  where-    e : es = zetasEven'-    o : os = zetasOdd eps--    intertwine (x : xs) (y : ys) = x : y : intertwine xs ys-    intertwine      xs       ys  = xs ++ ys--    -- Cap-and-floor to improve numerical stability:-    -- 0 < zeta(n + 1) - 1 < (zeta(n) - 1) / 2-    f x y = 1 `max` (y `min` (1 + (x - 1) / 2))+import Math.NumberTheory.Zeta.Dirichlet+import Math.NumberTheory.Zeta.Riemann+import Math.NumberTheory.Zeta.Utils
+ Math/NumberTheory/Zeta/Dirichlet.hs view
@@ -0,0 +1,171 @@+-- |+-- Module:      Math.NumberTheory.Zeta.Dirichlet+-- Copyright:   (c) 2018 Alexandre Rodrigues Baldé+-- Licence:     MIT+-- Maintainer:  Alexandre Rodrigues Baldé <alexandrer_b@outlook.com>+-- Stability:   Provisional+-- Portability: Non-portable (GHC extensions)+--+-- Dirichlet beta-function.++{-# LANGUAGE ScopedTypeVariables #-}++module Math.NumberTheory.Zeta.Dirichlet+  ( betas+  , betasEven+  , betasOdd+  ) where++import Data.ExactPi                     (ExactPi (..), approximateValue)+import Data.List                        (zipWith4)+import Data.Ratio                       ((%))++import Math.NumberTheory.Recurrencies   (euler, eulerPolyAt1, factorial)+import Math.NumberTheory.Zeta.Riemann   (zetasOdd)+import Math.NumberTheory.Zeta.Utils     (intertwine, skipEvens, skipOdds,+                                         suminf)++-- | Infinite sequence of exact values of Dirichlet beta-function at odd arguments, starting with @β(1)@.+--+-- > > approximateValue (betasOdd !! 25) :: Double+-- > 0.9999999999999987+--+-- Using 'Data.Number.Fixed.Fixed':+--+-- > > approximateValue (betasOdd !! 25) :: Fixed Prec50+-- > 0.99999999999999999999999960726927497384196726751694z+--+betasOdd :: [ExactPi]+betasOdd = zipWith Exact [1, 3 ..] $ zipWith4+                                     (\sgn denom eul twos -> sgn * (eul % (twos * denom)))+                                     (cycle [1, -1])+                                     (skipOdds factorial)+                                     (skipOdds euler)+                                     (iterate (4 *) 4)++-- | @betasOdd@, but with @forall a . Floating a => a@ instead of @ExactPi@s.+-- Used in @betasEven@.+betasOdd' :: Floating a => [a]+betasOdd' = map approximateValue betasOdd++-- | Infinite sequence of approximate values of the Dirichlet @β@ function at+-- positive even integer arguments, starting with @β(0)@.+betasEven :: forall a. (Floating a, Ord a) => a -> [a]+betasEven eps = (1 / 2) : bets+  where+    bets :: [a]+    bets = zipWith3 (\r1 r2 r3 -> (r1 + (negate r2) + r3)) rhs1 rhs2 rhs3++    -- [1!, 3!, 5!..]+    factorial1AsInteger :: [Integer]+    factorial1AsInteger = skipEvens factorial++    -- [1!, 3!, 5!..]+    factorial1 :: [a]+    factorial1 = map fromInteger factorial1AsInteger++    -- [2^1 * 1!, 2^3 * 3!, 2^5 * 5!, 2^7 * 7! ..]+    denoms :: [a]+    denoms = zipWith+             (\pow fac -> fromInteger $ pow * fac)+             factorial1AsInteger+             (iterate (4 *) 2)++    -- First term of the right hand side of (12).+    rhs1 = zipWith+           (\sgn piFrac -> sgn * piFrac * log 2)+           (cycle [1, -1])+           (zipWith (\p f -> p / f) (iterate ((pi * pi) *) pi) denoms)++    -- [1 - (1 / (2^2)), 1 - (1 / (2^4)), 1 - (1 / (2^6)), ..]+    second :: [a]+    second = map (1 -) $ (iterate (/ 4) (1/4))++    -- [- (1 - (1 / (2^2))) * zeta(3), (1 - (1 / (2^4))) * zeta(5), - (1 - (1 / (2^6))) * zeta(7), ..]+    zets :: [a]+    zets = zipWith3+           (\sgn twosFrac z -> sgn * twosFrac * z)+           (cycle [-1, 1])+           second+           (tail $ zetasOdd eps)++    -- [pi / (2^1 * 1!), pi^3 / (2^3 * 3!), pi^5 / (2^5 * 5!), ..]+    pisAndFacs :: [a]+    pisAndFacs = zipWith3+                 (\p pow fac -> p / (pow * fac))+                 (iterate ((pi * pi) *) pi)+                 (iterate (4 *) 2)+                 factorial1++    -- [[], [pisAndFacs !! 0], [pisAndFacs !! 1, pisAndFacs !! 0], [pisAndFacs !! 2, pisAndFacs !! 1, pisAndFacs !! 0]...]+    pisAndFacs' :: [[a]]+    pisAndFacs' = scanl (flip (:)) [] pisAndFacs++    -- Second summand of RHS in (12) for k = [1 ..]+    rhs2 :: [a]+    rhs2 = zipWith (*) (cycle [-1, 1]) $ map (sum . zipWith (*) zets) pisAndFacs'++    -- [pi^3 / (2^4), pi^5 / (2^6), pi^7 / (2^8) ..]+    -- Second factor of third addend in RHS of (12).+    pis :: [a]+    pis = zipWith+          (\p f -> p / f)+          (iterate ((pi * pi) *) (pi ^^ (3 :: Integer)))+          (iterate (4 *) 16)++    -- [[3!, 5!, 7! ..], [5!, 7! ..] ..]+    oddFacs :: [[a]]+    oddFacs = iterate tail (tail factorial1)++    -- [1, 4, 16 ..]+    fours :: [a]+    fours = iterate (4 *) 1++    -- [[3! * 2^0, 5! * 2^2, 7! * 2^4 ..], [5! * 2^0, 7! * 2^2, 9! * 2^4 ..] ..]+    infSumDenoms :: [[a]]+    infSumDenoms = map (zipWith (*) fours) oddFacs++    -- [pi^0, pi^2, pi^4, pi^6 ..]+    pis2 :: [a]+    pis2 = iterate ((pi * pi) *) 1++    -- [pi^0 * E_1(1), - pi^2 * E_3(1), pi^4 * E_5(1) ..]+    infSumNum :: [a]+    infSumNum = zipWith3+                (\sgn p eulerP -> sgn * p * eulerP)+                (cycle [1, -1])+                pis2+                (map fromRational . skipEvens $ eulerPolyAt1)++    -- [     [ pi^0 * E_1(1)  (-1) * pi^2 * E_3(1)   ]      [ (-1) * pi^2 * E_3(1)  pi^4 * E_5(1)    ]      [ pi^4 * E_5(1)  (-1) * pi^6 * E_7(1)    ]  ]+    -- | sum | -------------, -------------------- ..|, sum | --------------------, ------------- .. |, sum | -------------, -------------------- .. |..|+    -- [     [       3!                 5!           ]      [          5!                 7!         ]      [       7!                9!             ]  ]+    infSum :: [a]+    infSum = map (suminf eps . zipWith (/) infSumNum) infSumDenoms++    -- Third summand of the right hand side of (12).+    rhs3 :: [a]+    rhs3 = zipWith3+           (\sgn p inf -> sgn * p * inf)+           (cycle [-1, 1])+           pis+           infSum++-- | Infinite sequence of approximate (up to given precision)+-- values of Dirichlet beta-function at integer arguments, starting with @β(0)@.+-- The algorithm used to compute @β@ for even arguments was derived from+-- <https://arxiv.org/pdf/0910.5004.pdf An Euler-type formula for β(2n) and closed-form expressions for a class of zeta series>+-- by F. M. S. Lima, formula (12).+--+-- > > take 5 (betas 1e-14) :: [Double]+-- > [0.5,0.7853981633974483,0.9159655941772191,0.9689461462593693,0.988944551741105]+betas :: (Floating a, Ord a) => a -> [a]+betas eps = e : o : scanl1 f (intertwine es os)+  where+    e : es = betasEven eps+    o : os = betasOdd'++    -- Cap-and-floor to improve numerical stability:+    -- 1 > beta(n + 1) - 1 > (beta(n) - 1) / 2+    -- A similar method is used in @Math.NumberTheory.Zeta.Riemann.zetas@.+    f x y = 1 `min` (y `max` (1 + (x - 1) / 2))
+ Math/NumberTheory/Zeta/Riemann.hs view
@@ -0,0 +1,106 @@+-- |+-- Module:      Math.NumberTheory.Zeta.Riemann+-- Copyright:   (c) 2016 Andrew Lelechenko+-- Licence:     MIT+-- Maintainer:  Andrew Lelechenko <andrew.lelechenko@gmail.com>+-- Stability:   Provisional+-- Portability: Non-portable (GHC extensions)+--+-- Riemann zeta-function.++{-# LANGUAGE ScopedTypeVariables #-}++module Math.NumberTheory.Zeta.Riemann+  ( zetas+  , zetasEven+  , zetasOdd+  ) where++import Data.ExactPi                     (ExactPi (..), approximateValue)+import Data.Ratio                       ((%))++import Math.NumberTheory.Recurrencies   (bernoulli, factorial)+import Math.NumberTheory.Zeta.Utils     (intertwine, skipOdds, suminf)++-- | Infinite sequence of exact values of Riemann zeta-function at even arguments, starting with @ζ(0)@.+-- Note that due to numerical errors conversion to 'Double' may return values below 1:+--+-- >>> approximateValue (zetasEven !! 25) :: Double+-- 0.9999999999999996+--+-- Use your favorite type for long-precision arithmetic. For instance, 'Data.Number.Fixed.Fixed' works fine:+--+-- >>> import Data.Number.Fixed+-- >>> approximateValue (zetasEven !! 25) :: Fixed Prec50+-- 1.00000000000000088817842111574532859293035196051773+--+zetasEven :: [ExactPi]+zetasEven = zipWith Exact [0, 2 ..] $ zipWith (*) (skipOdds bernoulli) cs+  where+    cs = (- 1 % 2) : zipWith (\i f -> i * (-4) / fromInteger (2 * f * (2 * f - 1))) cs [1..]++zetasEven' :: Floating a => [a]+zetasEven' = map approximateValue zetasEven++zetasOdd :: forall a. (Floating a, Ord a) => a -> [a]+zetasOdd eps = (1 / 0) : zets+  where+    zets :: [a] -- [zeta(3), zeta(5), zeta(7)...]+    zets = zipWith (*) zs (tail (iterate (* (- pi * pi)) 1))++    zs :: [a] -- [zeta(3) / (-pi^2), zeta(5) / pi^4, zeta(7) / (-pi^6)...]+    zs = zipWith (\w f -> negate (w / (1 + f))) ws fourth++    ys :: [a] -- [(1 - 1/4) * zeta(3) / (-pi^2), (1 - 1/4^2) * zeta(5) / pi^4...]+    ys = zipWith (*) zs fourth+    yss :: [[a]] -- [[], [ys !! 0], [ys !! 1, ys !! 0], [ys !! 2, ys !! 1, ys !! 0]...]+    yss = scanl (flip (:)) [] ys++    xs :: [a] -- first summand of RHS in (57) for m=[1..]+    xs = map (sum . zipWith (flip (/)) factorial2) yss++    ws :: [a] -- RHS in (57) for m=[1..]+    ws = zipWith (+) xs cs++    rs :: [a] -- [1, 1/2, 1/3, 1/4...]+    rs = map (\n -> recip (fromInteger n)) [1..]+    rss :: [[a]] -- [[1, 1/2, 1/3...], [1/2, 1/3, 1/4...], [1/3, 1/4...]]+    rss = iterate tail rs++    factorial2 :: [a] -- [2!, 4!, 6!..]+    factorial2 = map fromInteger $ tail $ skipOdds factorial++    fourth :: [a] -- [1 - 1/4, 1 - 1/4^2, 1 - 1/4^3...]+    fourth = tail $ map (1 -) $ iterate (/ 4) 1++    as :: [a] -- [zeta(0), zeta(2)/4, zeta(2*2)/4^2, zeta(2*3)/4^3...]+    as = zipWith (/) zetasEven' (iterate (* 4) 1)++    bs :: [a] -- map (+ log 2) [b(1), b(2), b(3)...],+              -- where b(m) = \sum_{n=0}^\infty (zeta(2n) / 4^n) / (n + m)+    bs = map ((+ log 2) . suminf eps . zipWith (*) as) rss++    cs :: [a] -- second summand of RHS in (57) for m = [1..]+    cs = zipWith (\b f -> b / f) bs factorial2++-- | Infinite sequence of approximate (up to given precision)+-- values of Riemann zeta-function at integer arguments, starting with @ζ(0)@.+-- Computations for odd arguments are performed in accordance to+-- <https://cr.yp.to/bib/2000/borwein.pdf Computational strategies for the Riemann zeta function>+-- by J. M. Borwein, D. M. Bradley, R. E. Crandall, formula (57).+--+-- >>> take 5 (zetas 1e-14) :: [Double]+-- > [-0.5,Infinity,1.6449340668482262,1.2020569031595942,1.0823232337111381]+--+-- Beware to force evaluation of @zetas !! 1@, if the type @a@ does not support infinite values+-- (for instance, 'Data.Number.Fixed.Fixed').+--+zetas :: (Floating a, Ord a) => a -> [a]+zetas eps = e : o : scanl1 f (intertwine es os)+  where+    e : es = zetasEven'+    o : os = zetasOdd eps++    -- Cap-and-floor to improve numerical stability:+    -- 0 < zeta(n + 1) - 1 < (zeta(n) - 1) / 2+    f x y = 1 `max` (y `min` (1 + (x - 1) / 2))
+ Math/NumberTheory/Zeta/Utils.hs view
@@ -0,0 +1,51 @@+-- |+-- Module:      Math.NumberTheory.Zeta.Utils+-- Copyright:   (c) 2018 Alexandre Rodrigues Baldé+-- Licence:     MIT+-- Maintainer:  Alexandre Rodrigues Baldé <alexandrer_b@outlook.com>+-- Stability:   Provisional+-- Portability: Non-portable (GHC extensions)+--+-- Shared utilities used by functions from @Math.NumberTheory.Zeta@.++module Math.NumberTheory.Zeta.Utils+  ( intertwine+  , skipEvens+  , skipOdds+  , suminf+  ) where++-- | Joins two lists element-by-element together into one, starting with the+-- first one provided as argument.+--+-- >>> take 10 $ intertwine [0, 2 ..] [1, 3 ..]+-- [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]+intertwine :: [a] -> [a] -> [a]+intertwine [] ys = ys +intertwine (x : xs) ys = x : intertwine ys xs ++-- | Skips every odd-indexed element from an infinite list.+-- Do NOT use with finite lists.+--+-- >>> take 10 (skipOdds [0, 1 ..])+-- [0, 2, 4, 6, 8, 10, 12, 14, 16, 18]+skipOdds :: [a] -> [a]+skipOdds (x : _ : xs) = x : skipOdds xs+skipOdds xs = xs++-- | Skips every even-indexed element from an infinite list.+-- Do NOT use with finite lists.+--+-- >>> take 10 (skipEvens [0, 1 ..])+-- [1, 3, 5, 7, 9, 11, 13, 15, 17, 19]+skipEvens :: [a] -> [a]+skipEvens = skipOdds . tail++-- | Sums every element of an infinite list up to a certain precision.+-- I.e. once an element falls below the given threshold it stops traversing+-- the list.+--+-- >>> suminf 1e-14 (iterate (/ 10) 1)+-- 1.1111111111111112+suminf :: (Floating a, Ord a) => a -> [a] -> a+suminf eps = sum . takeWhile ((>= eps / 111) . abs)
arithmoi.cabal view
@@ -1,200 +1,217 @@-name                : arithmoi-version             : 0.7.0.0-cabal-version       : >= 1.10-author              : Daniel Fischer-copyright           : (c) 2011 Daniel Fischer, 2016-2018 Andrew Lelechenko, Carter Schonwald-license             : MIT-license-file        : LICENSE-maintainer          : Carter Schonwald  carter at wellposed dot com,-                      Andrew Lelechenko andrew dot lelechenko at gmail dot com-build-type          : Simple-stability           : Provisional-homepage            : https://github.com/cartazio/arithmoi-bug-reports         : https://github.com/cartazio/arithmoi/issues--synopsis            : Efficient basic number-theoretic functions.-description         : A library of basic functionality needed for-                      number-theoretic calculations. The aim of this library-                      is to provide efficient implementations of the functions.--                      Primes and related things (totients, factorisation),-                      powers (integer roots and tests, modular exponentiation).--category            : Math, Algorithms, Number Theory--tested-with         : GHC==7.8.4, GHC==7.10.3, GHC==8.0.2, GHC==8.2.2--extra-source-files  : Changes--flag check-bounds-    description         : Replace unsafe array operations with safe ones-    default             : False-    manual              : True--library-    default-language: Haskell2010-    build-depends       : base >= 4.7 && < 5-                        , array >= 0.5 && < 0.6-                        , ghc-prim < 0.6-                        , integer-gmp < 1.1-                        , containers >= 0.5 && < 0.6-                        , random >= 1.0 && < 1.2-                        , mtl >= 2.0 && < 2.3-                        , exact-pi >= 0.4.1.1-                        , integer-logarithms >= 1.0-                        , vector >= 0.12-    if impl(ghc < 7.10)-      build-depends     : nats >= 1 && <1.2-    if impl(ghc < 8.0)-      build-depends     : semigroups >= 0.8--    exposed-modules     : Math.NumberTheory.ArithmeticFunctions-                          Math.NumberTheory.ArithmeticFunctions.Class-                          Math.NumberTheory.ArithmeticFunctions.Mertens-                          Math.NumberTheory.ArithmeticFunctions.Moebius-                          Math.NumberTheory.ArithmeticFunctions.SieveBlock-                          Math.NumberTheory.ArithmeticFunctions.Standard-                          Math.NumberTheory.Curves.Montgomery-                          Math.NumberTheory.Moduli-                          Math.NumberTheory.Moduli.Chinese-                          Math.NumberTheory.Moduli.Class-                          Math.NumberTheory.Moduli.Jacobi-                          Math.NumberTheory.Moduli.PrimitiveRoot-                          Math.NumberTheory.Moduli.Sqrt-                          Math.NumberTheory.MoebiusInversion-                          Math.NumberTheory.MoebiusInversion.Int-                          Math.NumberTheory.Recurrencies.Bilinear-                          Math.NumberTheory.Recurrencies.Linear-                          Math.NumberTheory.GaussianIntegers-                          Math.NumberTheory.GCD-                          Math.NumberTheory.GCD.LowLevel-                          Math.NumberTheory.Powers-                          Math.NumberTheory.Powers.Squares-                          Math.NumberTheory.Powers.Squares.Internal-                          Math.NumberTheory.Powers.Cubes-                          Math.NumberTheory.Powers.Fourth-                          Math.NumberTheory.Powers.General-                          Math.NumberTheory.Powers.Modular-                          Math.NumberTheory.Primes-                          Math.NumberTheory.Primes.Sieve-                          Math.NumberTheory.Primes.Factorisation-                          Math.NumberTheory.Primes.Factorisation.Certified-                          Math.NumberTheory.Primes.Counting-                          Math.NumberTheory.Primes.Testing-                          Math.NumberTheory.Primes.Testing.Certificates-                          Math.NumberTheory.Primes.Heap-                          Math.NumberTheory.UniqueFactorisation-                          Math.NumberTheory.Zeta-                          Math.NumberTheory.Prefactored-                          GHC.TypeNats.Compat-                          Math.NumberTheory.SmoothNumbers--    other-modules       : Math.NumberTheory.ArithmeticFunctions.SieveBlock.Unboxed-                          Math.NumberTheory.Utils-                          Math.NumberTheory.Utils.FromIntegral-                          Math.NumberTheory.Utils.Hyperbola-                          Math.NumberTheory.Unsafe-                          Math.NumberTheory.Primes.Counting.Impl-                          Math.NumberTheory.Primes.Counting.Approximate-                          Math.NumberTheory.Primes.Factorisation.Montgomery-                          Math.NumberTheory.Primes.Factorisation.TrialDivision-                          Math.NumberTheory.Primes.Sieve.Eratosthenes-                          Math.NumberTheory.Primes.Sieve.Indexing-                          Math.NumberTheory.Primes.Sieve.Misc-                          Math.NumberTheory.Primes.Testing.Probabilistic-                          Math.NumberTheory.Primes.Testing.Certified-                          Math.NumberTheory.Primes.Testing.Certificates.Internal-                          Math.NumberTheory.Primes.Types-    other-extensions    : BangPatterns--    ghc-options         : -O2 -Wall-    ghc-prof-options    : -O2 -auto-    if flag(check-bounds)-        cpp-options     : -DCheckBounds+name:          arithmoi+version:       0.8.0.0+cabal-version: >=1.10+build-type:    Simple+license:       MIT+license-file:  LICENSE+copyright:     (c) 2011 Daniel Fischer, 2016-2018 Andrew Lelechenko, Carter Schonwald+maintainer:    Carter Schonwald  carter at wellposed dot com,+               Andrew Lelechenko andrew dot lelechenko at gmail dot com+stability:     Provisional+homepage:      https://github.com/cartazio/arithmoi+bug-reports:   https://github.com/cartazio/arithmoi/issues+synopsis:      Efficient basic number-theoretic functions.+description:+  A library of basic functionality needed for+  number-theoretic calculations. The aim of this library+  is to provide efficient implementations of the functions.+  Primes and related things (totients, factorisation),+  powers (integer roots and tests, modular exponentiation).+category:      Math, Algorithms, Number Theory+author:        Daniel Fischer+tested-with:   GHC==7.10.3, GHC==8.0.2, GHC==8.2.2, GHC==8.4.3+extra-source-files:+  Changes  source-repository head-  type:     git+  type: git   location: https://github.com/cartazio/arithmoi +flag check-bounds+  description:+    Replace unsafe array operations with safe ones+  default: False+  manual: True -benchmark criterion-  build-depends:    base-                    , arithmoi-                    , gauge-                    , containers-                    , random-                    , integer-logarithms-                    , vector-  if impl(ghc < 7.10)-    build-depends     : nats >= 1 && <1.2-  if impl(ghc < 8.0)-    build-depends     : semigroups >= 0.8-  other-modules:    Math.NumberTheory.ArithmeticFunctionsBench-                  , Math.NumberTheory.GCDBench-                  , Math.NumberTheory.MertensBench-                  , Math.NumberTheory.PowersBench-                  , Math.NumberTheory.PrimesBench-                  , Math.NumberTheory.RecurrenciesBench-                  , Math.NumberTheory.SieveBlockBench-  hs-source-dirs:   benchmark-  main-is:          Bench.hs-  type:             exitcode-stdio-1.0+library+  build-depends:+    base >=4.7 && <5,+    array >=0.5 && <0.6,+    containers >=0.5 && <0.7,+    deepseq,+    exact-pi >=0.4.1.1,+    ghc-prim <0.6,+    integer-gmp <1.1,+    integer-logarithms >=1.0,+    random >=1.0 && <1.2,+    transformers >=0.4 && <0.6,+    vector >= 0.12+  if impl(ghc <8.0)+    build-depends:+      semigroups >=0.8+  exposed-modules:+    GHC.TypeNats.Compat+    Math.NumberTheory.ArithmeticFunctions+    Math.NumberTheory.ArithmeticFunctions.Mertens+    Math.NumberTheory.ArithmeticFunctions.Moebius+    Math.NumberTheory.ArithmeticFunctions.SieveBlock+    Math.NumberTheory.Curves.Montgomery+    Math.NumberTheory.Euclidean+    Math.NumberTheory.Euclidean.Coprimes+    Math.NumberTheory.GaussianIntegers+    Math.NumberTheory.GCD+    Math.NumberTheory.GCD.LowLevel+    Math.NumberTheory.Moduli+    Math.NumberTheory.Moduli.Chinese+    Math.NumberTheory.Moduli.Class+    Math.NumberTheory.Moduli.DiscreteLogarithm+    Math.NumberTheory.Moduli.Equations+    Math.NumberTheory.Moduli.Jacobi+    Math.NumberTheory.Moduli.PrimitiveRoot+    Math.NumberTheory.Moduli.Sqrt+    Math.NumberTheory.MoebiusInversion+    Math.NumberTheory.MoebiusInversion.Int+    Math.NumberTheory.Powers+    Math.NumberTheory.Powers.Cubes+    Math.NumberTheory.Powers.Fourth+    Math.NumberTheory.Powers.General+    Math.NumberTheory.Powers.Modular+    Math.NumberTheory.Powers.Squares+    Math.NumberTheory.Powers.Squares.Internal+    Math.NumberTheory.Prefactored+    Math.NumberTheory.Primes+    Math.NumberTheory.Primes.Counting+    Math.NumberTheory.Primes.Factorisation+    Math.NumberTheory.Primes.Factorisation.Certified+    Math.NumberTheory.Primes.Sieve+    Math.NumberTheory.Primes.Testing+    Math.NumberTheory.Primes.Testing.Certificates+    Math.NumberTheory.Quadratic.GaussianIntegers+    Math.NumberTheory.Quadratic.EisensteinIntegers+    Math.NumberTheory.Recurrencies+    Math.NumberTheory.Recurrencies.Bilinear+    Math.NumberTheory.Recurrencies.Linear+    Math.NumberTheory.SmoothNumbers+    Math.NumberTheory.UniqueFactorisation+    Math.NumberTheory.Zeta+    Math.NumberTheory.Zeta.Dirichlet+    Math.NumberTheory.Zeta.Riemann+  other-modules:+    Math.NumberTheory.ArithmeticFunctions.Class+    Math.NumberTheory.ArithmeticFunctions.SieveBlock.Unboxed+    Math.NumberTheory.ArithmeticFunctions.Standard+    Math.NumberTheory.Moduli.SqrtOld+    Math.NumberTheory.Primes.Counting.Approximate+    Math.NumberTheory.Primes.Counting.Impl+    Math.NumberTheory.Primes.Factorisation.Montgomery+    Math.NumberTheory.Primes.Factorisation.TrialDivision+    Math.NumberTheory.Primes.Sieve.Eratosthenes+    Math.NumberTheory.Primes.Sieve.Indexing+    Math.NumberTheory.Primes.Testing.Certificates.Internal+    Math.NumberTheory.Primes.Testing.Certified+    Math.NumberTheory.Primes.Testing.Probabilistic+    Math.NumberTheory.Primes.Types+    Math.NumberTheory.Recurrencies.Pentagonal+    Math.NumberTheory.Unsafe+    Math.NumberTheory.Utils+    Math.NumberTheory.Utils.FromIntegral+    Math.NumberTheory.Utils.Hyperbola+    Math.NumberTheory.Zeta.Utils   default-language: Haskell2010+  ghc-options: -O2 -Wall+  if flag(check-bounds)+    cpp-options: -DCheckBounds  test-suite spec-  type:                 exitcode-stdio-1.0-  hs-source-dirs:       test-suite-  ghc-options:          -Wall-  main-is:              Test.hs+  build-depends:+    base >=4.6 && <5,+    arithmoi,+    containers,+    exact-pi >=0.4.1.1,+    integer-gmp <1.1,+    QuickCheck >=2.10 && <2.13,+    smallcheck >=1.1.3 && <1.2,+    tasty >=0.10 && <1.2,+    tasty-hunit >=0.9 && <0.11,+    tasty-quickcheck >=0.9 && <0.11,+    tasty-smallcheck >=0.8 && <0.9,+    transformers >=0.5,+    vector+  if impl(ghc <8.0)+    build-depends:+      semigroups >=0.8+  other-modules:+    Math.NumberTheory.ArithmeticFunctionsTests+    Math.NumberTheory.ArithmeticFunctions.MertensTests+    Math.NumberTheory.ArithmeticFunctions.SieveBlockTests+    Math.NumberTheory.CurvesTests+    Math.NumberTheory.EisensteinIntegersTests+    Math.NumberTheory.GaussianIntegersTests+    Math.NumberTheory.GCDTests+    Math.NumberTheory.Moduli.ChineseTests+    Math.NumberTheory.Moduli.DiscreteLogarithmTests+    Math.NumberTheory.Moduli.ClassTests+    Math.NumberTheory.Moduli.EquationsTests+    Math.NumberTheory.Moduli.JacobiTests+    Math.NumberTheory.Moduli.PrimitiveRootTests+    Math.NumberTheory.Moduli.SqrtTests+    Math.NumberTheory.MoebiusInversion.IntTests+    Math.NumberTheory.MoebiusInversionTests+    Math.NumberTheory.Powers.CubesTests+    Math.NumberTheory.Powers.FourthTests+    Math.NumberTheory.Powers.GeneralTests+    Math.NumberTheory.Powers.ModularTests+    Math.NumberTheory.Powers.SquaresTests+    Math.NumberTheory.PrefactoredTests+    Math.NumberTheory.Primes.CountingTests+    Math.NumberTheory.Primes.FactorisationTests+    Math.NumberTheory.Primes.SieveTests+    Math.NumberTheory.Primes.TestingTests+    Math.NumberTheory.PrimesTests+    Math.NumberTheory.Recurrencies.PentagonalTests+    Math.NumberTheory.Recurrencies.BilinearTests+    Math.NumberTheory.Recurrencies.LinearTests+    Math.NumberTheory.SmoothNumbersTests+    Math.NumberTheory.TestUtils+    Math.NumberTheory.TestUtils.MyCompose+    Math.NumberTheory.TestUtils.Wrappers+    Math.NumberTheory.UniqueFactorisationTests+    Math.NumberTheory.Zeta.DirichletTests+    Math.NumberTheory.Zeta.RiemannTests+  type: exitcode-stdio-1.0+  main-is: Test.hs   default-language: Haskell2010-  build-depends:        arithmoi-                      , base >= 4.6 && < 5-                      , containers >= 0.5 && < 0.6-                      , tasty >= 0.10 && < 1.1-                      , tasty-smallcheck >= 0.8 && < 0.9-                      , tasty-quickcheck >= 0.9 && < 0.11-                      , tasty-hunit >= 0.9 && < 0.11-                      , QuickCheck >= 2.10 && < 2.12-                      , transformers >= 0.5-                      , integer-gmp < 1.1-                      , vector-  if impl(ghc < 7.10)-    build-depends     : smallcheck >= 1.1 && < 1.1.3,-                        nats >= 1 && <1.2-  else-    build-depends     : smallcheck >= 1.1.3 && < 1.2-  if impl(ghc < 8.0)-    build-depends     : semigroups >= 0.8+  hs-source-dirs: test-suite+  ghc-options: -Wall -  other-modules :   Math.NumberTheory.ArithmeticFunctionsTests-                  , Math.NumberTheory.ArithmeticFunctions.MertensTests-                  , Math.NumberTheory.ArithmeticFunctions.SieveBlockTests-                  , Math.NumberTheory.CurvesTests-                  , Math.NumberTheory.GaussianIntegersTests-                  , Math.NumberTheory.GCDTests-                  , Math.NumberTheory.GCD.LowLevelTests-                  , Math.NumberTheory.Recurrencies.LinearTests-                  , Math.NumberTheory.Recurrencies.BilinearTests-                  , Math.NumberTheory.Moduli.ChineseTests-                  , Math.NumberTheory.Moduli.ClassTests-                  , Math.NumberTheory.Moduli.JacobiTests-                  , Math.NumberTheory.Moduli.PrimitiveRootTests-                  , Math.NumberTheory.Moduli.SqrtTests-                  , Math.NumberTheory.Powers.CubesTests-                  , Math.NumberTheory.MoebiusInversionTests-                  , Math.NumberTheory.MoebiusInversion.IntTests-                  , Math.NumberTheory.Powers.FourthTests-                  , Math.NumberTheory.Powers.GeneralTests-                  , Math.NumberTheory.Powers.ModularTests-                  , Math.NumberTheory.Powers.SquaresTests-                  , Math.NumberTheory.PrefactoredTests-                  , Math.NumberTheory.PrimesTests-                  , Math.NumberTheory.Primes.CountingTests-                  , Math.NumberTheory.Primes.FactorisationTests-                  , Math.NumberTheory.Primes.SieveTests-                  , Math.NumberTheory.Primes.TestingTests-                  , Math.NumberTheory.TestUtils-                  , Math.NumberTheory.TestUtils.Wrappers-                  , Math.NumberTheory.TestUtils.MyCompose-                  , Math.NumberTheory.UniqueFactorisationTests-                  , Math.NumberTheory.ZetaTests+benchmark criterion+  build-depends:+    base,+    arithmoi,+    containers,+    deepseq,+    gauge,+    integer-logarithms,+    random,+    vector+  if impl(ghc <8.0)+    build-depends:+      semigroups >=0.8+  other-modules:+    Math.NumberTheory.ArithmeticFunctionsBench+    Math.NumberTheory.DiscreteLogarithmBench+    Math.NumberTheory.EisensteinIntegersBench+    Math.NumberTheory.GaussianIntegersBench+    Math.NumberTheory.GCDBench+    Math.NumberTheory.JacobiBench+    Math.NumberTheory.MertensBench+    Math.NumberTheory.PowersBench+    Math.NumberTheory.PrimesBench+    Math.NumberTheory.PrimitiveRootsBench+    Math.NumberTheory.RecurrenciesBench+    Math.NumberTheory.SieveBlockBench+    Math.NumberTheory.SmoothNumbersBench+  type: exitcode-stdio-1.0+  main-is: Bench.hs+  default-language: Haskell2010+  hs-source-dirs: benchmark
benchmark/Bench.hs view
@@ -3,19 +3,32 @@ import Gauge.Main  import Math.NumberTheory.ArithmeticFunctionsBench as ArithmeticFunctions+import Math.NumberTheory.DiscreteLogarithmBench as DiscreteLogarithm+import Math.NumberTheory.EisensteinIntegersBench as Eisenstein+import Math.NumberTheory.GaussianIntegersBench as Gaussian import Math.NumberTheory.GCDBench as GCD+import Math.NumberTheory.JacobiBench as Jacobi import Math.NumberTheory.MertensBench as Mertens import Math.NumberTheory.PowersBench as Powers import Math.NumberTheory.PrimesBench as Primes+import Math.NumberTheory.PrimitiveRootsBench as PrimitiveRoots import Math.NumberTheory.RecurrenciesBench as Recurrencies import Math.NumberTheory.SieveBlockBench as SieveBlock+import Math.NumberTheory.SmoothNumbersBench as SmoothNumbers +main :: IO () main = defaultMain   [ ArithmeticFunctions.benchSuite+  , DiscreteLogarithm.benchSuite+  , Eisenstein.benchSuite+  , Gaussian.benchSuite   , GCD.benchSuite+  , Jacobi.benchSuite   , Mertens.benchSuite   , Powers.benchSuite   , Primes.benchSuite+  , PrimitiveRoots.benchSuite   , Recurrencies.benchSuite   , SieveBlock.benchSuite+  , SmoothNumbers.benchSuite   ]
benchmark/Math/NumberTheory/ArithmeticFunctionsBench.hs view
@@ -1,3 +1,5 @@+{-# OPTIONS_GHC -fno-warn-type-defaults #-}+ module Math.NumberTheory.ArithmeticFunctionsBench   ( benchSuite   ) where@@ -7,20 +9,23 @@  import Math.NumberTheory.ArithmeticFunctions as A -compareFunctions :: String -> (Integer -> Integer) -> Benchmark-compareFunctions name new = bench name $ nf (map new) [1..100000]+compareFunctions :: String -> (Integer -> Integer) -> [Integer] -> Benchmark+compareFunctions name new range = bench name $ nf (map new) range  compareSetFunctions :: String -> (Integer -> Set Integer) -> Benchmark compareSetFunctions name new = bench name $ nf (map new) [1..100000]  benchSuite :: Benchmark benchSuite = bgroup "ArithmeticFunctions"-  [ compareSetFunctions "divisors" A.divisors-  , bench "divisors/int" $ nf (map A.divisorsSmall) [1 :: Int .. 100000]-  , compareFunctions "totient" A.totient-  , compareFunctions "carmichael" A.carmichael-  , compareFunctions "moebius" (A.runMoebius . A.moebius)-  , compareFunctions "tau" A.tau-  , compareFunctions "sigma 1" (A.sigma 1)-  , compareFunctions "sigma 2" (A.sigma 2)+  [ compareSetFunctions "divisors" A.divisors +  , bench "divisors/int" $ nf (map A.divisorsSmall)              [1 :: Int .. 100000]+  , compareFunctions "totient" A.totient                         [1..100000]+  , compareFunctions "carmichael" A.carmichael                   [1..100000]+  , compareFunctions "moebius" (A.runMoebius . A.moebius)        [1..100000]+  , compareFunctions "tau" A.tau                                 [1..100000]+  , compareFunctions "sigma 1" (A.sigma 1)                       [1..100000]+  , compareFunctions "sigma 2" (A.sigma 2)                       [1..100000]+  , compareFunctions "ramanujan range" ramanujan                 [1..2000]+  , compareFunctions "ramanujan large prime" ramanujan           [100003]+  , compareFunctions "ramanujan prime power" ramanujan           [2^3000]   ]
+ benchmark/Math/NumberTheory/DiscreteLogarithmBench.hs view
@@ -0,0 +1,66 @@+{-# LANGUAGE ExistentialQuantification #-}+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE ScopedTypeVariables #-}++{-# OPTIONS_GHC -fno-warn-type-defaults #-}++module Math.NumberTheory.DiscreteLogarithmBench+  ( benchSuite+  , rangeCases+  , discreteLogarithm'+  ) where++import Gauge.Main+import Data.Maybe+import GHC.TypeNats.Compat+import Data.Proxy+import Numeric.Natural++import Math.NumberTheory.Moduli.Class (isMultElement, KnownNat, MultMod, multElement, getVal,Mod)+import Math.NumberTheory.Moduli.DiscreteLogarithm (discreteLogarithm)+import Math.NumberTheory.Moduli.PrimitiveRoot (PrimitiveRoot, isPrimitiveRoot, unPrimitiveRoot, cyclicGroupFromModulo)++data Case = forall m. KnownNat m => Case (PrimitiveRoot m) (MultMod m) String++instance Show Case where+  show (Case a b s) = concat [show (getVal a'), "ⁿ == ", show b', " mod ", s]+    where a' = multElement $ unPrimitiveRoot a+          b' = getVal $ multElement b++makeCase :: (Integer, Integer, Natural, String) -> Maybe Case+makeCase (a,b,n,s) =+  case someNatVal n of+    SomeNat (_ :: Proxy m) ->+      Case <$> isPrimitiveRoot a' <*> isMultElement b' <*> pure s+        where a' = fromInteger a :: Mod m+              b' = fromInteger b++cases :: [Case]+cases = mapMaybe makeCase [ (5,  8,  10^9 + 7,  "10^9 + 7")+                          , (2,  7,    3^1000,    "3^1000")+                          , (2,  3, 10^11 + 3, "10^11 + 3")+                          , (3, 17,     5^700,     "5^700")+                          ]++rangeCases :: Natural -> Int -> [Case]+rangeCases start num = take num $ do+  n <- [start..]+  _cg <- maybeToList $ cyclicGroupFromModulo n+  case someNatVal n of+    SomeNat (_ :: Proxy m) -> do+      a <- take 1 $ mapMaybe isPrimitiveRoot [2 :: Mod m .. maxBound]+      b <- take 1 $ filter (/= unPrimitiveRoot a) $ mapMaybe isMultElement [2 .. maxBound]+      return $ Case a b (show n)++discreteLogarithm' :: Case -> Natural+discreteLogarithm' (Case a b _) = discreteLogarithm a b++benchSuite :: Benchmark+benchSuite = bgroup "Discrete logarithm"+  [ bgroup "individual case"+          [ bench (show c) $ nf discreteLogarithm' c | c <- cases]+  , bgroup "range"+          [ bench (show num ++ " cases near " ++ show n) $ nf (map discreteLogarithm') $ rangeCases n num+            | (n, num) <- [(10000, 100), (1000000, 100), (100000000, 100), (10000000000, 100)]+          ]+  ]
+ benchmark/Math/NumberTheory/EisensteinIntegersBench.hs view
@@ -0,0 +1,26 @@+{-# OPTIONS_GHC -fno-warn-type-defaults #-}+{-# OPTIONS_GHC -fno-warn-orphans       #-}++module Math.NumberTheory.EisensteinIntegersBench+  ( benchSuite+  ) where++import Control.DeepSeq+import Gauge.Main++import Math.NumberTheory.ArithmeticFunctions (tau)+import Math.NumberTheory.Quadratic.EisensteinIntegers++instance NFData EisensteinInteger++benchFindPrime :: Integer -> Benchmark+benchFindPrime n = bench (show n) $ nf findPrime n++benchTau :: Integer -> Benchmark+benchTau n = bench (show n) $ nf (\m -> sum [tau (x :+ y) | x <- [1..m], y <- [0..m]] :: Word) n++benchSuite :: Benchmark+benchSuite = bgroup "Eisenstein"+  [ bgroup "findPrime" $ map benchFindPrime [1000003, 10000141, 100000039, 1000000021, 10000000033, 100000000003, 1000000000039, 10000000000051]+  , bgroup "tau" $ map benchTau [10, 20, 40, 80]+  ]
benchmark/Math/NumberTheory/GCDBench.hs view
@@ -1,3 +1,6 @@+{-# OPTIONS_GHC -fno-warn-type-defaults #-}+{-# OPTIONS_GHC -fno-warn-deprecations  #-}+ module Math.NumberTheory.GCDBench   ( benchSuite   ) where@@ -6,16 +9,29 @@  import Math.NumberTheory.GCD as A import Prelude as P+import Numeric.Natural +averageGCD :: Integral a => (a -> a -> a) -> a -> a+averageGCD gcdF lim = sum [ gcdF x y | x <- [lim .. 2 * lim], y <- [lim .. x] ]++benchSuite :: Benchmark benchSuite = bgroup "GCD"   [ subSuite "large coprimes" 1073741823 100003   , subSuite "powers of 2" (2^12) (2^19)   , subSuite "power of 23" (23^3) (23^7)+  , bench "average prelude  Int"     $ nf (averageGCD P.gcd)       (2000 :: Int)+  , bench "average arithmoi Int"     $ nf (averageGCD A.binaryGCD) (2000 :: Int)+  , bench "average prelude  Word"    $ nf (averageGCD P.gcd)       (2000 :: Word)+  , bench "average arithmoi Word"    $ nf (averageGCD A.binaryGCD) (2000 :: Word)+  , bench "average prelude  Integer" $ nf (averageGCD P.gcd)       (2000 :: Integer)+  , bench "average arithmoi Integer" $ nf (averageGCD A.binaryGCD) (2000 :: Integer)+  , bench "average prelude  Natural" $ nf (averageGCD P.gcd)       (2000 :: Natural)+  , bench "average arithmoi Natural" $ nf (averageGCD A.binaryGCD) (2000 :: Natural)   ]   where subSuite :: String -> Int -> Int -> Benchmark         subSuite name m n = bgroup name           [ bench "Prelude.gcd" $ nf (P.gcd m) n           , bench "binaryGCD" $ nf (A.binaryGCD m) n-          , bench "Prelude.coprime" $ nf (\n -> 1 == P.gcd m n) n+          , bench "Prelude.coprime" $ nf (\t -> 1 == P.gcd m t) n           , bench "coprime" $ nf (A.coprime m) n           ]
+ benchmark/Math/NumberTheory/GaussianIntegersBench.hs view
@@ -0,0 +1,22 @@+{-# OPTIONS_GHC -fno-warn-type-defaults #-}++module Math.NumberTheory.GaussianIntegersBench+  ( benchSuite+  ) where++import Gauge.Main++import Math.NumberTheory.ArithmeticFunctions (tau)+import Math.NumberTheory.Quadratic.GaussianIntegers++benchFindPrime :: Integer -> Benchmark+benchFindPrime n = bench (show n) $ nf findPrime n++benchTau :: Integer -> Benchmark+benchTau n = bench (show n) $ nf (\m -> sum [tau (x :+ y) | x <- [1..m], y <- [0..m]] :: Word) n++benchSuite :: Benchmark+benchSuite = bgroup "Gaussian"+  [ bgroup "findPrime" $ map benchFindPrime [1000033, 10000121, 100000037, 1000000009, 10000000033, 100000000057, 1000000000061, 10000000000037]+  , bgroup "tau" $ map benchTau [10, 20, 40, 80]+  ]
+ benchmark/Math/NumberTheory/JacobiBench.hs view
@@ -0,0 +1,21 @@+{-# OPTIONS_GHC -fno-warn-type-defaults #-}++module Math.NumberTheory.JacobiBench+  ( benchSuite+  ) where++import Gauge.Main+import Numeric.Natural++import Math.NumberTheory.Moduli.Jacobi++doBench :: Integral a => (a -> a -> JacobiSymbol) -> a -> a+doBench func lim = sum [ x + y | y <- [3, 5 .. lim], x <- [0..y], func x y == One ]++benchSuite :: Benchmark+benchSuite = bgroup "Jacobi"+  [ bench "jacobi/Int"      $ nf (doBench jacobi  :: Int -> Int)         2000+  , bench "jacobi/Word"     $ nf (doBench jacobi  :: Word -> Word)       2000+  , bench "jacobi/Integer"  $ nf (doBench jacobi  :: Integer -> Integer) 2000+  , bench "jacobi/Natural"  $ nf (doBench jacobi  :: Natural -> Natural) 2000+  ]
benchmark/Math/NumberTheory/MertensBench.hs view
@@ -8,9 +8,6 @@   ) where  import Gauge.Main-#if __GLASGOW_HASKELL__ < 709-import Data.Word-#endif  import Math.NumberTheory.ArithmeticFunctions.Mertens 
+ benchmark/Math/NumberTheory/PrimitiveRootsBench.hs view
@@ -0,0 +1,40 @@+{-# OPTIONS_GHC -fno-warn-type-defaults #-}++module Math.NumberTheory.PrimitiveRootsBench+  ( benchSuite+  ) where++import Gauge.Main+import Data.Maybe++import Math.NumberTheory.Moduli.PrimitiveRoot+import Math.NumberTheory.UniqueFactorisation++primRootWrap :: Integer -> Word -> Integer -> Bool+primRootWrap p k g = isPrimitiveRoot' (CGOddPrimePower p' k) g+  where p' = fromJust $ isPrime p++primRootWrap2 :: Integer -> Word -> Integer -> Bool+primRootWrap2 p k g = isPrimitiveRoot' (CGDoubleOddPrimePower p' k) g+  where p' = fromJust $ isPrime p++cyclicWrap :: Integer -> Maybe (CyclicGroup Integer)+cyclicWrap = cyclicGroupFromModulo++benchSuite :: Benchmark+benchSuite = bgroup "PrimRoot"+  [ bgroup "groupFromModulo"+    [ bench "3^20000"             $ nf cyclicWrap (3^20000)             -- prime to large power+    , bench "10000000000000061"   $ nf cyclicWrap (10^16 + 61)          -- large prime+    , bench "2*3^20000"           $ nf cyclicWrap (2*3^20000)           -- twice prime to large power+    , bench "10000000000000046"   $ nf cyclicWrap (10^16 + 46)          -- twice large prime+    , bench "224403121196654400"  $ nf cyclicWrap (224403121196654400)  -- highly composite+    ]+  , bgroup "check prim roots"+    [ bench "3^20000"             $ nf (primRootWrap  3              20000) 2 -- prime to large power+    , bench "10000000000000061"   $ nf (primRootWrap  (10^16 + 61)   1)     3 -- large prime+    , bench "10000000000000061^2" $ nf (primRootWrap  (10^16 + 61)   2)     3 -- large prime squared+    , bench "2*3^20000"           $ nf (primRootWrap2 3              20000) 5 -- twice prime to large power+    , bench "10000000000000046"   $ nf (primRootWrap2 (5*10^15 + 23) 1)     5 -- twice large prime+    ]+  ]
benchmark/Math/NumberTheory/RecurrenciesBench.hs view
@@ -6,7 +6,8 @@  import Gauge.Main -import Math.NumberTheory.Recurrencies.Bilinear+import Math.NumberTheory.Recurrencies (binomial, eulerian1, eulerian2,+                                       stirling1, stirling2, partition)  benchTriangle :: String -> (forall a. (Integral a) => [[a]]) -> Int -> Benchmark benchTriangle name triangle n = bgroup name@@ -19,11 +20,29 @@     benchAt i j = bench ("!! " ++ show i ++ " !! " ++ show j)                 $ nf (\(x, y) -> triangle !! x !! y :: Integer) (i, j) +benchPartition :: Int -> Benchmark+benchPartition n = bgroup "partition"+  [ benchAt n+  , benchAt (n * 10)+  , benchAt (n * 100)+  ]+  where+    benchAt m = bench ("!!" ++ show m) $  nf (\k -> partition !! k :: Integer) m+ benchSuite :: Benchmark-benchSuite = bgroup "Bilinear"-  [ benchTriangle "binomial"  binomial 1000-  , benchTriangle "stirling1" stirling1 100-  , benchTriangle "stirling2" stirling2 100-  , benchTriangle "eulerian1" eulerian1 100-  , benchTriangle "eulerian2" eulerian2 100+benchSuite = bgroup "Recurrencies"+  [+    bgroup "Bilinear"+    [ benchTriangle "binomial"  binomial 1000+    , benchTriangle "stirling1" stirling1 100+    , benchTriangle "stirling2" stirling2 100+    , benchTriangle "eulerian1" eulerian1 100+    , benchTriangle "eulerian2" eulerian2 100+    ]+    ,+    bgroup "Pentagonal"+    [ bgroup "Partition function"+      [ benchPartition 1000+      ]+    ]   ]
benchmark/Math/NumberTheory/SieveBlockBench.hs view
@@ -14,16 +14,12 @@ #endif import qualified Data.Vector as V import qualified Data.Vector.Unboxed as U-#if __GLASGOW_HASKELL__ < 709-import Data.Word-#endif  import Math.NumberTheory.ArithmeticFunctions.Moebius import Math.NumberTheory.ArithmeticFunctions.SieveBlock-import Math.NumberTheory.Primes.Factorisation (totientSieve, sieveTotient, carmichaelSieve, sieveCarmichael)  blockLen :: Word-blockLen = 10^6+blockLen = 1000000  totientHelper :: Word -> Word -> Word totientHelper p 1 = p - 1@@ -37,12 +33,6 @@   , sbcFunctionOnPrimePower = totientHelper   } -sumOldTotientSieve :: Word -> Word-sumOldTotientSieve len' = sum $ map (fromInteger . sieveTotient sieve) [1 .. len]-  where-    len = toInteger len'-    sieve = totientSieve len- carmichaelHelper :: Word -> Word -> Word carmichaelHelper 2 1 = 1 carmichaelHelper 2 2 = 2@@ -59,12 +49,6 @@   , sbcFunctionOnPrimePower = carmichaelHelper   } -sumOldCarmichaelSieve :: Word -> Word-sumOldCarmichaelSieve len' = sum $ map (fromInteger . sieveCarmichael sieve) [1 .. len]-  where-    len = toInteger len'-    sieve = carmichaelSieve len- moebiusConfig :: SieveBlockConfig Moebius moebiusConfig = SieveBlockConfig   { sbcEmpty                = MoebiusP@@ -78,13 +62,11 @@ benchSuite :: Benchmark benchSuite = bgroup "SieveBlock"   [ bgroup "totient"-    [ bench "old"     $ nf sumOldTotientSieve blockLen-    , bench "boxed"   $ nf (V.sum . sieveBlock        totientBlockConfig 1) blockLen+    [ bench "boxed"   $ nf (V.sum . sieveBlock        totientBlockConfig 1) blockLen     , bench "unboxed" $ nf (U.sum . sieveBlockUnboxed totientBlockConfig 1) blockLen     ]   , bgroup "carmichael"-    [ bench "old"     $ nf sumOldCarmichaelSieve blockLen-    , bench "boxed"   $ nf (V.sum . sieveBlock        carmichaelBlockConfig 1) blockLen+    [ bench "boxed"   $ nf (V.sum . sieveBlock        carmichaelBlockConfig 1) blockLen     , bench "unboxed" $ nf (U.sum . sieveBlockUnboxed carmichaelBlockConfig 1) blockLen     ]   , bgroup "moebius"
+ benchmark/Math/NumberTheory/SmoothNumbersBench.hs view
@@ -0,0 +1,21 @@+{-# OPTIONS_GHC -fno-warn-type-defaults #-}++module Math.NumberTheory.SmoothNumbersBench+  ( benchSuite+  ) where++import Data.List (genericTake)+import Data.Maybe+import Gauge.Main++import Math.NumberTheory.SmoothNumbers++doBench :: Integral a => a -> a+doBench lim = sum $ genericTake lim $ smoothOver $ fromJust $ fromSmoothUpperBound lim++benchSuite :: Benchmark+benchSuite = bgroup "SmoothNumbers"+  [ bench "100"      $ nf doBench    (100 :: Int)+  , bench "1000"     $ nf doBench   (1000 :: Int)+  , bench "10000"    $ nf doBench  (10000 :: Int)+  ]
test-suite/Math/NumberTheory/ArithmeticFunctions/MertensTests.hs view
@@ -24,9 +24,6 @@ #endif import qualified Data.Vector as V import qualified Data.Vector.Unboxed as U-#if __GLASGOW_HASKELL__ < 709-import Data.Word-#endif  import Math.NumberTheory.ArithmeticFunctions import Math.NumberTheory.ArithmeticFunctions.Mertens
test-suite/Math/NumberTheory/ArithmeticFunctions/SieveBlockTests.hs view
@@ -25,9 +25,6 @@ #endif import qualified Data.Vector as V import qualified Data.Vector.Unboxed as U-#if __GLASGOW_HASKELL__ < 709-import Data.Word-#endif  import Math.NumberTheory.ArithmeticFunctions import Math.NumberTheory.ArithmeticFunctions.SieveBlock
test-suite/Math/NumberTheory/ArithmeticFunctionsTests.hs view
@@ -20,18 +20,11 @@ import Test.Tasty import Test.Tasty.HUnit -#if MIN_VERSION_base(4,8,0)-#else-import Prelude hiding (sum, all, elem)-import Data.Foldable-#endif- import Data.List (sort) import qualified Data.Set as S import qualified Data.IntSet as IS  import Math.NumberTheory.ArithmeticFunctions-import Math.NumberTheory.Primes.Factorisation import Math.NumberTheory.TestUtils  import Numeric.Natural@@ -39,25 +32,28 @@ oeisAssertion :: (Eq a, Show a) => String -> ArithmeticFunction Natural a -> [a] -> Assertion oeisAssertion name f baseline = assertEqual name baseline (map (runFunction f) [1 .. fromIntegral (length baseline)]) +wolframAlphaAssertion :: (Eq a, Show a) => String -> ArithmeticFunction Integer a -> [Integer] -> [a] -> Assertion+wolframAlphaAssertion name f domain baseline = assertEqual name baseline (map (runFunction f) domain)+ -- | tau(n) equals to a number of divisors.-divisorsProperty1 :: Natural -> Bool-divisorsProperty1 n = S.size (runFunction divisorsA n) == runFunction tauA n+divisorsProperty1 :: NonZero Natural -> Bool+divisorsProperty1 (NonZero n) = S.size (runFunction divisorsA n) == runFunction tauA n  -- | sigma(n) equals to a number of divisors.-divisorsProperty2 :: Natural -> Bool-divisorsProperty2 n = sum (runFunction divisorsA n) == runFunction (sigmaA 1) n+divisorsProperty2 :: NonZero Natural -> Bool+divisorsProperty2 (NonZero n) = sum (runFunction divisorsA n) == runFunction (sigmaA 1) n  -- | All divisors of n truly divides n.-divisorsProperty3 :: Natural -> Bool-divisorsProperty3 n = all (\d -> n `mod` d == 0) (runFunction divisorsA n)+divisorsProperty3 :: NonZero Natural -> Bool+divisorsProperty3 (NonZero n) = all (\d -> n `mod` d == 0) (runFunction divisorsA n)  -- | 'divisorsA' matches 'divisorsSmallA'-divisorsProperty4 :: Int -> Bool-divisorsProperty4 n = S.toAscList (runFunction divisorsA n) == IS.toAscList (runFunction divisorsSmallA n)+divisorsProperty4 :: NonZero Int -> Bool+divisorsProperty4 (NonZero n) = S.toAscList (runFunction divisorsA n) == IS.toAscList (runFunction divisorsSmallA n)  -- | 'divisorsA' matches 'divisorsListA'-divisorsProperty5 :: Int -> Bool-divisorsProperty5 n = S.toAscList (runFunction divisorsA n) == sort (runFunction divisorsListA n)+divisorsProperty5 :: NonZero Int -> Bool+divisorsProperty5 (NonZero n) = S.toAscList (runFunction divisorsA n) == sort (runFunction divisorsListA n)  -- | tau matches baseline from OEIS. tauOeis :: Assertion@@ -70,12 +66,12 @@   ]  -- | sigma_0 coincides with tau by definition-sigmaProperty1 :: Natural -> Bool-sigmaProperty1 n = runFunction tauA n == runFunction (sigmaA 0) n+sigmaProperty1 :: NonZero Natural -> Bool+sigmaProperty1 (NonZero n) = runFunction tauA n == runFunction (sigmaA 0) n  -- | value of totient is bigger than argument-sigmaProperty2 :: Natural -> Bool-sigmaProperty2 n = n <= 1 || runFunction (sigmaA 1) n > n+sigmaProperty2 :: NonZero Natural -> Bool+sigmaProperty2 (NonZero n) = n <= 1 || runFunction (sigmaA 1) n > n  -- | sigma_1 matches baseline from OEIS. sigma1Oeis :: Assertion@@ -96,21 +92,12 @@   ]  -- | value of totient if even, except totient(1) and totient(2)-totientProperty1 :: Natural -> Bool-totientProperty1 n = n <= 2 || even (runFunction totientA n)+totientProperty1 :: NonZero Natural -> Bool+totientProperty1 (NonZero n) = n <= 2 || even (runFunction totientA n)  -- | value of totient is smaller than argument-totientProperty2 :: Natural -> Bool-totientProperty2 n = n <= 1 || runFunction totientA n < n--totientSieve100 :: TotientSieve-totientSieve100 = totientSieve 100---- | totient matches sieveTotient-totientProperty3 :: Natural -> Bool-totientProperty3 n = n < 1-  || fromIntegral (runFunction totientA n)-    == sieveTotient totientSieve100 (fromIntegral n)+totientProperty2 :: NonZero Natural -> Bool+totientProperty2 (NonZero n) = n <= 1 || runFunction totientA n < n  -- | totient matches baseline from OEIS. totientOeis :: Assertion@@ -122,12 +109,12 @@   ]  -- | jordan_0 is zero for argument > 1-jordanProperty1 :: Natural -> Bool-jordanProperty1 n = n <= 1 || runFunction (jordanA 0) n == 0+jordanProperty1 :: NonZero Natural -> Bool+jordanProperty1 (NonZero n) = n <= 1 || runFunction (jordanA 0) n == 0  -- | jordan_1 coincides with totient by definition-jordanProperty2 :: Natural -> Bool-jordanProperty2 n = runFunction totientA n == runFunction (jordanA 1) n+jordanProperty2 :: NonZero Natural -> Bool+jordanProperty2 (NonZero n) = runFunction totientA n == runFunction (jordanA 1) n  -- | jordan_2 matches baseline from OEIS. jordan2Oeis :: Assertion@@ -138,6 +125,72 @@   , 1728, 1584, 2208, 1536   ] +-- | congruences 1,2,3,4 from https://en.wikipedia.org/wiki/Ramanujan_tau_function+ramanujanCongruence1 :: NonZero Natural -> Bool+ramanujanCongruence1 (NonZero n)+  | k == 1 = (ramanujan n' - sigma 11 n') `mod` (2^11) == 0+  | k == 3 = (ramanujan n' - 1217 * sigma 11 n') `mod` (2^13) == 0+  | k == 5 = (ramanujan n' - 1537 * sigma 11 n') `mod` (2^12) == 0+  | k == 7 = (ramanujan n' - 705 * sigma 11 n') `mod` (2^14) == 0+  | otherwise = True+  where k = n `mod` 8+        n' = fromIntegral n :: Integer++-- | congruences 8,9 from https://en.wikipedia.org/wiki/Ramanujan_tau_function+ramanujanCongruence2 :: NonZero Natural -> Bool+ramanujanCongruence2 (NonZero n)+  | (n `mod` 7) `elem` [0,1,2,4] = m `mod` 7 == 0+  | otherwise                    = m `mod` 49 == 0+  where m = ramanujan n' - n' * sigma 9 n'+        n' = fromIntegral n :: Integer++-- | ramanujan matches baseline from wolframAlpha: https://www.wolframalpha.com/input/?i=RamanujanTau%5BRange%5B100%5D%5D+ramanujanRange :: Assertion+ramanujanRange = wolframAlphaAssertion "A000594" ramanujanA [1..100]+  [ 1, -24, 252, -1472, 4830, -6048, -16744, 84480, -113643, -115920+  , 534612, -370944, -577738, 401856, 1217160, 987136, -6905934, 2727432+  , 10661420, -7109760, -4219488, -12830688, 18643272, 21288960, -25499225+  , 13865712, -73279080, 24647168, 128406630, -29211840, -52843168+  , -196706304, 134722224, 165742416, -80873520, 167282496, -182213314+  , -255874080, -145589976, 408038400, 308120442, 101267712, -17125708+  , -786948864, -548895690, -447438528, 2687348496, 248758272, -1696965207+  , 611981400, -1740295368, 850430336, -1596055698, 1758697920, 2582175960+  , -1414533120, 2686677840, -3081759120, -5189203740, -1791659520, 6956478662+  , 1268236032, 1902838392, 2699296768, -2790474540, -3233333376, -15481826884+  , 10165534848, 4698104544, 1940964480, 9791485272, -9600560640, 1463791322+  , 4373119536, -6425804700, -15693610240, -8951543328, 3494159424, 38116845680+  , 4767866880, 1665188361, -7394890608, -29335099668, 6211086336, -33355661220+  , 411016992, 32358470760, 45164021760, -24992917110, 13173496560, 9673645072+  , -27442896384, -13316478336, -64496363904, 51494658600, -49569988608+  , 75013568546, 40727164968, -60754911516, 37534859200+  ]++-- | ramanujan matches baseline from wolframAlpha: https://www.wolframalpha.com/input/?i=RamanujanTau%5B2%5ERange%5B20%5D%5D+ramanujanPowers2 :: Assertion+ramanujanPowers2 = wolframAlphaAssertion "wolframAlpha2^n" ramanujanA [2^n | n <- [1..20]]+  [ -24, -1472, 84480, 987136, -196706304, 2699296768, 338071388160+  , -13641873096704, -364965248630784, 36697722069188608, -133296500464680960+  , -71957818786545926144, 1999978883828768833536, 99370119662955604738048+  , -6480839625992253084794880, -47969854045919004468445184+  , 14424036051134190424902598656, -247934604141178449046286630912+  , -23589995333334539213089642905600, 1073929957281162404760946449842176+  ]++-- | ramanujan matches baseline from wolframAlpha: https://www.wolframalpha.com/input/?i=RamanujanTau%5B3%5ERange%5B20%5D%5D+ramanujanPowers3 :: Assertion+ramanujanPowers3 = wolframAlphaAssertion "wolframAlpha3^n" ramanujanA [3^n | n <- [1..20]]+  [ 252, -113643, -73279080, 1665188361, 13400796651732, 3082017633650397+  , -1597242480784468560, -948475282905952954479, 43930942451226107469612+  , 179090148438649827109433637, 37348482744132405171657919560+  , -22313464873940134819697044764519, -12239164820907737153507340756954108+  , 868493827155123300221022518147812077, 2386991774972433985188062567645398013280+  , 447670851294004737003138291024309833342241+  , -310035377434952569449318870332553243856267428+  , -157432463407787104647123294163886831498857358283+  , 15248856227707192449163419793501327951694151780600+  , 31731400364681474724113131979212395183355010696469801+  ]+ -- | moebius does not require full factorisation moebiusLazy :: Assertion moebiusLazy = assertEqual "moebius" MoebiusZ (runFunction moebiusA (2^2 * (2^100000-1) :: Natural))@@ -152,12 +205,12 @@   ]  -- | liouville values are [-1, 1]-liouvilleProperty1 :: Natural -> Bool-liouvilleProperty1 n = runFunction liouvilleA n `elem` [-1, 1]+liouvilleProperty1 :: NonZero Natural -> Bool+liouvilleProperty1 (NonZero n) = runFunction liouvilleA n `elem` [-1, 1]  -- | moebius is zero or equal to liouville-liouvilleProperty2 :: Natural -> Bool-liouvilleProperty2 n = m == MoebiusZ || l == runMoebius m+liouvilleProperty2 :: NonZero Natural -> Bool+liouvilleProperty2 (NonZero n) = m == MoebiusZ || l == runMoebius m   where     l = runFunction liouvilleA n     m = runFunction moebiusA   n@@ -173,17 +226,8 @@   ]  -- | carmichaeil divides totient-carmichaelProperty1 :: Natural -> Bool-carmichaelProperty1 n = runFunction totientA n `mod` runFunction carmichaelA n == 0--carmichaelSieve100 :: CarmichaelSieve-carmichaelSieve100 = carmichaelSieve 100---- | carmichael matches sieveCarmichael-carmichaelProperty2 :: Natural -> Bool-carmichaelProperty2 n = n < 1-  || fromIntegral (runFunction carmichaelA n)-    == sieveCarmichael carmichaelSieve100 (fromIntegral n)+carmichaelProperty1 :: NonZero Natural -> Bool+carmichaelProperty1 (NonZero n) = runFunction totientA n `mod` runFunction carmichaelA n == 0  -- | carmichael matches baseline from OEIS. carmichaelOeis :: Assertion@@ -195,8 +239,8 @@   ]  -- | smallOmega is smaller than bigOmega-omegaProperty1 :: Natural -> Bool-omegaProperty1 n = runFunction smallOmegaA n <= runFunction bigOmegaA n+omegaProperty1 :: NonZero Natural -> Bool+omegaProperty1 (NonZero n) = runFunction smallOmegaA n <= runFunction bigOmegaA n  -- | smallOmega matches baseline from OEIS. smallOmegaOeis :: Assertion@@ -248,7 +292,6 @@   , testGroup "Totient"     [ testSmallAndQuick "totient is even"      totientProperty1     , testSmallAndQuick "totient n < n"        totientProperty2-    , testSmallAndQuick "matches sieveTotient" totientProperty3     , testCase          "OEIS"                 totientOeis     ]   , testGroup "Jordan"@@ -256,6 +299,13 @@     , testSmallAndQuick "jordan_1 = totient" jordanProperty2     , testCase          "OEIS jordan_2"      jordan2Oeis     ]+  , testGroup "Ramanujan"+    [ testSmallAndQuick "ramanujan mod 8 congruences" ramanujanCongruence1+    , testSmallAndQuick "ramanujan mod 7 congruences" ramanujanCongruence2+    , testCase          "baseline ramanujan range"    ramanujanRange+    , testCase          "baseline ramanujan powers2"  ramanujanPowers2+    , testCase          "baseline ramanujan powers3"  ramanujanPowers3+    ]   , testGroup "Moebius"     [ testCase          "OEIS"           moebiusOeis     , testCase          "Lazy"           moebiusLazy@@ -267,7 +317,6 @@     ]   , testGroup "Carmichael"     [ testSmallAndQuick "carmichael divides totient" carmichaelProperty1-    , testSmallAndQuick "matches sieveCarmichael"    carmichaelProperty2     , testCase          "OEIS"                       carmichaelOeis     ]   , testGroup "Omegas"
test-suite/Math/NumberTheory/CurvesTests.hs view
@@ -22,10 +22,6 @@ import Math.NumberTheory.Curves.Montgomery import Math.NumberTheory.TestUtils -#if __GLASGOW_HASKELL__ < 709-import Data.Word-#endif- (==>?) :: Maybe a -> (a -> Property) -> Property x ==>? f = case x of   Nothing -> discard
+ test-suite/Math/NumberTheory/EisensteinIntegersTests.hs view
@@ -0,0 +1,208 @@+{-# OPTIONS_GHC -fno-warn-type-defaults #-}++-- |+-- Module:      Math.NumberTheory.EisensteinIntegersTests+-- Copyright:   (c) 2018 Alexandre Rodrigues Baldé+-- Licence:     MIT+-- Maintainer:  Alexandre Rodrigues Baldé <alexandrer_b@outlook.+-- Stability:   Provisional+--+-- Tests for Math.NumberTheory.EisensteinIntegers+--++module Math.NumberTheory.EisensteinIntegersTests+  ( testSuite+  ) where++import qualified Math.NumberTheory.Euclidean    as ED+import qualified Math.NumberTheory.Quadratic.EisensteinIntegers as E+import Math.NumberTheory.Primes                       (primes)+import Test.Tasty                                     (TestTree, testGroup)+import Test.Tasty.HUnit                               (Assertion, assertEqual,+                                                      testCase)++import Math.NumberTheory.TestUtils                    (Positive (..),+                                                       testSmallAndQuick)++-- | Check that @signum@ and @abs@ satisfy @z == signum z * abs z@, where @z@ is+-- an @EisensteinInteger@.+signumAbsProperty :: E.EisensteinInteger -> Bool+signumAbsProperty z = z == signum z * abs z++-- | Check that @abs@ maps an @EisensteinInteger@ to its associate in first+-- sextant.+absProperty :: E.EisensteinInteger -> Bool+absProperty z = isOrigin || (inFirstSextant && isAssociate)+  where+    z'@(x' E.:+ y') = abs z+    isOrigin = z' == 0 && z == 0+    -- The First sextant includes the positive real axis, but not the origin+    -- or the line defined by the linear equation @y = (sqrt 3) * x@ in the+    -- Cartesian plane.+    inFirstSextant = x' > y' && y' >= 0+    isAssociate = z' `elem` map (\e -> z * (1 E.:+ 1) ^ e) [0 .. 5]++-- | Verify that @div@ and @mod@ are what `divMod` produces.+divModProperty1 :: E.EisensteinInteger -> E.EisensteinInteger -> Bool+divModProperty1 x y = y == 0 || (q == q' && r == r')+  where+    (q, r) = ED.divMod x y+    q'     = ED.div x y+    r'     = ED.mod x y++-- | Verify that @divModE` produces the right quotient and remainder.+divModProperty2 :: E.EisensteinInteger -> E.EisensteinInteger -> Bool+divModProperty2 x y = (y == 0) || (x `ED.div` y) * y + (x `ED.mod` y) == x++-- | Verify that @divModE@ produces a remainder smaller than the divisor with+-- regards to the Euclidean domain's function.+modProperty1 :: E.EisensteinInteger -> E.EisensteinInteger -> Bool+modProperty1 x y = (y == 0) || (E.norm $ x `ED.mod` y) < (E.norm y)++-- | Verify that @quot@ and @rem@ are what `quotRem` produces.+quotRemProperty1 :: E.EisensteinInteger -> E.EisensteinInteger -> Bool+quotRemProperty1 x y = (y == 0) || q == q' && r == r'+  where+    (q, r) = ED.quotRem x y+    q'     = ED.quot x y+    r'     = ED.rem x y++-- | Verify that @quotRemE@ produces the right quotient and remainder.+quotRemProperty2 :: E.EisensteinInteger -> E.EisensteinInteger -> Bool+quotRemProperty2 x y = (y == 0) || (x `ED.quot` y) * y + (x `ED.rem` y) == x++-- | Verify that @gcd z1 z2@ always divides @z1@ and @z2@.+gcdEProperty1 :: E.EisensteinInteger -> E.EisensteinInteger -> Bool+gcdEProperty1 z1 z2+  = z1 == 0 && z2 == 0+  || z1 `ED.rem` z == 0 && z2 `ED.rem` z == 0 && z == abs z+  where+    z = ED.gcd z1 z2++-- | Verify that a common divisor of @z1, z2@ is a always divisor of @gcd z1 z2@.+gcdEProperty2 :: E.EisensteinInteger -> E.EisensteinInteger -> E.EisensteinInteger -> Bool+gcdEProperty2 z z1 z2+  = z == 0+  || (ED.gcd z1' z2') `ED.rem` z == 0+  where+    z1' = z * z1+    z2' = z * z2++-- | A special case that tests rounding/truncating in GCD.+gcdESpecialCase1 :: Assertion+gcdESpecialCase1 = assertEqual "gcd" 1 $ ED.gcd (12 E.:+ 23) (23 E.:+ 34)++findPrimesProperty1 :: Positive Int -> Bool+findPrimesProperty1 (Positive index) =+    let -- Only retain primes that are of the form @6k + 1@, for some nonzero natural @k@.+        prop prime = prime `mod` 6 == 1+        p = (!! index) $ filter prop $ drop 3 primes+    in E.isPrime $ E.findPrime p++-- | Checks that the @norm@ of the Euclidean domain of Eisenstein integers+-- is multiplicative i.e.+-- @forall e1 e2 in Z[ω] . norm(e1 * e2) == norm(e1) * norm(e2)@.+euclideanDomainProperty1 :: E.EisensteinInteger -> E.EisensteinInteger -> Bool+euclideanDomainProperty1 e1 e2 = E.norm (e1 * e2) == E.norm e1 * E.norm e2++-- | Checks that the numbers produced by @primes@ are actually Eisenstein+-- primes.+primesProperty1 :: Positive Int -> Bool+primesProperty1 (Positive index) = all E.isPrime $ take index $ E.primes++-- | Checks that the infinite list of Eisenstein primes @primes@ is ordered+-- by the numbers' norm.+primesProperty2 :: Positive Int -> Bool+primesProperty2 (Positive index) =+    let isOrdered :: [E.EisensteinInteger] -> Bool+        isOrdered xs = all (\(x,y) -> E.norm x <= E.norm y) . zip xs $ tail xs+    in isOrdered $ take index E.primes++-- | Checks that the numbers produced by @primes@ are all in the first+-- sextant.+primesProperty3 :: Positive Int -> Bool+primesProperty3 (Positive index) =+    all (\e -> abs e == e) $ take index $ E.primes++-- | An Eisenstein integer is either zero or associated (i.e. equal up to+-- multiplication by a unit) to the product of its factors raised to their+-- respective exponents.+factoriseProperty1 :: E.EisensteinInteger -> Bool+factoriseProperty1 g = g == 0 || abs g == abs g'+  where+    factors = E.factorise g+    g' = product $ map (uncurry (^)) factors++-- | Check that there are no factors with exponent @0@ in the factorisation.+factoriseProperty2 :: E.EisensteinInteger -> Bool+factoriseProperty2 z = z == 0 || all ((> 0) . snd) (E.factorise z)++-- | Check that no factor produced by @factorise@ is a unit.+factoriseProperty3 :: E.EisensteinInteger -> Bool+factoriseProperty3 z = z == 0 || all ((> 1) . E.norm . fst) (E.factorise z)++-- | Check that every prime factor in the factorisation is primary, excluding+-- @1 - ω@, if it is a factor.+factoriseProperty4 :: E.EisensteinInteger -> Bool+factoriseProperty4 z =+    z == 0 ||+    (all (\e -> e `ED.mod` 3 == 2) $+     filter (\e -> not $ elem e $ E.associates $ 1 E.:+ (-1)) $+     map fst $ E.factorise z)++factoriseSpecialCase1 :: Assertion+factoriseSpecialCase1 = assertEqual "should be equal"+  [(2 E.:+ 1, 3), (2 E.:+ 3, 1)]+  (E.factorise (15 E.:+ 12))++testSuite :: TestTree+testSuite = testGroup "EisensteinIntegers" $+  [ testSmallAndQuick "forall z . z == signum z * abs z" signumAbsProperty+  , testSmallAndQuick "abs z always returns an @EisensteinInteger@ in the\+                      \ first sextant of the complex plane" absProperty+  , testGroup "Division"+    [ testSmallAndQuick "divE and modE work properly" divModProperty1+    , testSmallAndQuick "divModE works properly" divModProperty2+    , testSmallAndQuick "The remainder's norm is smaller than the divisor's"+                        modProperty1++    , testSmallAndQuick "quotE and remE work properly" quotRemProperty1+    , testSmallAndQuick "quotRemE works properly" quotRemProperty2+    ]++  , testGroup "g.c.d."+    [ testSmallAndQuick "The g.c.d. of two Eisenstein integers divides them"+                        gcdEProperty1+    , testSmallAndQuick "A common divisor of two Eisenstein integers always\+                        \ divides the g.c.d. of those two integers"+                        gcdEProperty2+    , testCase          "g.c.d. (12 :+ 23) (23 :+ 34)" gcdESpecialCase1+    ]+  , testSmallAndQuick "The Eisenstein norm function is multiplicative"+                    euclideanDomainProperty1+  , testGroup "Primality"+    [ testSmallAndQuick "Eisenstein primes found by the norm search used in\+                        \ findPrime are really prime"+                        findPrimesProperty1+    , testSmallAndQuick "Eisenstein primes generated by `primes` are actually\+                        \ primes"+                        primesProperty1+    , testSmallAndQuick "The infinite list of Eisenstein primes produced by\+                        \ `primes` is ordered. "+                        primesProperty2+    , testSmallAndQuick "All generated primes are in the first sextant"+                        primesProperty3+    ]++    , testGroup "Factorisation"+      [ testSmallAndQuick "factorise produces correct results"+                          factoriseProperty1+      , testSmallAndQuick "factorise produces no factors with exponent 0"+                          factoriseProperty2+      , testSmallAndQuick "factorise produces no unit factors"+                          factoriseProperty3+      , testSmallAndQuick "factorise only produces primary primes"+                          factoriseProperty4+      , testCase          "factorise 15:+12" factoriseSpecialCase1+      ]+  ]
− test-suite/Math/NumberTheory/GCD/LowLevelTests.hs
@@ -1,74 +0,0 @@--- |--- Module:      Math.NumberTheory.GCD.LowLevelTests--- Copyright:   (c) 2016 Andrew Lelechenko--- Licence:     MIT--- Maintainer:  Andrew Lelechenko <andrew.lelechenko@gmail.com>--- Stability:   Provisional------ Tests for Math.NumberTheory.GCD.LowLevel-----{-# LANGUAGE CPP       #-}-{-# LANGUAGE MagicHash #-}--{-# OPTIONS_GHC -fno-warn-type-defaults #-}--module Math.NumberTheory.GCD.LowLevelTests-  ( testSuite-  ) where--import Test.Tasty--#if MIN_VERSION_base(4,8,0)-#else-import Data.Word-#endif--import GHC.Exts--import Math.NumberTheory.GCD.LowLevel-import Math.NumberTheory.TestUtils---- | Check that 'gcdInt' matches 'gcd'.-gcdIntProperty :: Int -> Int -> Bool-gcdIntProperty a b = gcdInt a b == gcd a b---- | Check that 'gcdWord' matches 'gcd'.-gcdWordProperty :: Word -> Word -> Bool-gcdWordProperty a b = gcdWord a b == gcd a b---- | Check that 'gcdInt#' matches 'gcd'.-gcdIntProperty# :: Int -> Int -> Bool-gcdIntProperty# a@(I# a') b@(I# b') = I# (gcdInt# a' b') == gcd a b---- | Check that 'gcdWord#' matches 'gcd'.-gcdWordProperty# :: Word -> Word -> Bool-gcdWordProperty# a@(W# a') b@(W# b') = W# (gcdWord# a' b') == gcd a b---- | Check that numbers are coprime iff their gcd equals to 1.-coprimeIntProperty :: Int -> Int -> Bool-coprimeIntProperty a b = coprimeInt a b == (gcd a b == 1)---- | Check that numbers are coprime iff their gcd equals to 1.-coprimeWordProperty :: Word -> Word -> Bool-coprimeWordProperty a b = coprimeWord a b == (gcd a b == 1)---- | Check that numbers are coprime iff their gcd equals to 1.-coprimeIntProperty# :: Int -> Int -> Bool-coprimeIntProperty# a@(I# a') b@(I# b') = coprimeInt# a' b' == (gcd a b == 1)---- | Check that numbers are coprime iff their gcd equals to 1.-coprimeWordProperty# :: Word -> Word -> Bool-coprimeWordProperty# a@(W# a') b@(W# b') = coprimeWord# a' b' == (gcd a b == 1)--testSuite :: TestTree-testSuite = testGroup "LowLevel"-  [ testSmallAndQuick "gcdInt"       gcdIntProperty-  , testSmallAndQuick "gcdWord"      gcdWordProperty-  , testSmallAndQuick "gcdInt#"      gcdIntProperty#-  , testSmallAndQuick "gcdWord#"     gcdWordProperty#-  , testSmallAndQuick "coprimeInt"   coprimeIntProperty-  , testSmallAndQuick "coprimeWord"  coprimeWordProperty-  , testSmallAndQuick "coprimeInt#"  coprimeIntProperty#-  , testSmallAndQuick "coprimeWord#" coprimeWordProperty#-  ]
test-suite/Math/NumberTheory/GCDTests.hs view
@@ -11,7 +11,9 @@ {-# LANGUAGE CPP                 #-} {-# LANGUAGE ScopedTypeVariables #-} -{-# OPTIONS_GHC -fno-warn-type-defaults #-}+{-# OPTIONS_GHC -fno-warn-type-defaults  #-}+{-# OPTIONS_GHC -fno-warn-unused-imports #-}+{-# OPTIONS_GHC -fno-warn-deprecations   #-}  module Math.NumberTheory.GCDTests   ( testSuite@@ -22,13 +24,11 @@  import Control.Arrow import Data.Bits-import Data.List (tails)-#if MIN_VERSION_base(4,8,0)-#else-import Data.Word-#endif+import Data.Semigroup+import Data.List (tails, sort) import Numeric.Natural +import Math.NumberTheory.Euclidean.Coprimes import Math.NumberTheory.GCD import Math.NumberTheory.TestUtils @@ -52,13 +52,13 @@ coprimeProperty (AnySign a) (AnySign b) = coprime a b == (gcd a b == 1)  splitIntoCoprimesProperty1 :: [(Positive Natural, Power Word)] -> Bool-splitIntoCoprimesProperty1 fs' = factorback fs == factorback (splitIntoCoprimes fs)+splitIntoCoprimesProperty1 fs' = factorback fs == factorback (unCoprimes $ splitIntoCoprimes fs)   where     fs = map (getPositive *** getPower) fs'     factorback = product . map (uncurry (^))  splitIntoCoprimesProperty2 :: [(Positive Natural, Power Word)] -> Bool-splitIntoCoprimesProperty2 fs' = multiplicities fs <= multiplicities (splitIntoCoprimes fs)+splitIntoCoprimesProperty2 fs' = multiplicities fs <= multiplicities (unCoprimes $ splitIntoCoprimes fs)   where     fs = map (getPositive *** getPower) fs'     multiplicities = sum . map snd . filter ((/= 1) . fst)@@ -66,7 +66,7 @@ splitIntoCoprimesProperty3 :: [(Positive Natural, Power Word)] -> Bool splitIntoCoprimesProperty3 fs' = and [ coprime x y | (x : xs) <- tails fs, y <- xs ]   where-    fs = map fst $ splitIntoCoprimes $ map (getPositive *** getPower) fs'+    fs = map fst $ unCoprimes $ splitIntoCoprimes $ map (getPositive *** getPower) fs'  -- | Check that evaluation never freezes. splitIntoCoprimesProperty4 :: [(Integer, Word)] -> Bool@@ -86,6 +86,43 @@ splitIntoCoprimesSpecialCase2 =   assertBool "should not fail" $ splitIntoCoprimesProperty4 [(0, 1), (-2, 0)] +toListReturnsCorrectValues :: Assertion+toListReturnsCorrectValues = assertEqual+  "should be equal"+  (sort $ unCoprimes $ splitIntoCoprimes [(140, 1), (165, 1)])+  ([(5,2),(28,1),(33,1)] :: [(Integer, Word)])++unionReturnsCorrectValues :: Assertion+unionReturnsCorrectValues = assertEqual "should be equal" expected actual+  where+    a :: Coprimes Integer Word+    a = splitIntoCoprimes [(700, 1), (165, 1)] -- [(5,3),(28,1),(33,1)]+    b = splitIntoCoprimes [(360, 1), (210, 1)] -- [(2,4),(3,3),(5,2),(7,1)]+    expected = [(2,6),(3,4),(5,5),(7,2),(11,1)]+    actual = sort $ unCoprimes (a <> b)++insertReturnsCorrectValuesWhenCoprimeBase :: Assertion+insertReturnsCorrectValuesWhenCoprimeBase =+  let a = insert 5 2 (singleton 4 3)+      expected = [(4,3), (5,2)]+      actual = sort $ unCoprimes a :: [(Int, Int)]+  in assertEqual "should be equal" expected actual++insertReturnsCorrectValuesWhenNotCoprimeBase :: Assertion+insertReturnsCorrectValuesWhenNotCoprimeBase =+  let a = insert 2 4 (insert 7 1 (insert 5 2 (singleton 4 3)))+      actual = sort $ unCoprimes a :: [(Int, Int)]+      expected = [(2,10), (5,2), (7,1)]+  in assertEqual "should be equal" expected actual++unionProperty1 :: [(Positive Natural, Power Word)] -> [(Positive Natural, Power Word)] -> Bool+unionProperty1 xs ys+  =  sort (unCoprimes (splitIntoCoprimes (xs' <> ys')))+  == sort (unCoprimes (splitIntoCoprimes xs' <> splitIntoCoprimes ys'))+  where+    xs' = map (getPositive *** getPower) xs+    ys' = map (getPositive *** getPower) ys+ testSuite :: TestTree testSuite = testGroup "GCD"   [ testSameIntegralProperty "binaryGCD"   binaryGCDProperty@@ -99,5 +136,12 @@     , testCase          "does not freeze 1"                   splitIntoCoprimesSpecialCase1     , testCase          "does not freeze 2"                   splitIntoCoprimesSpecialCase2     , testSmallAndQuick "does not freeze random"              splitIntoCoprimesProperty4+    ]+  , testGroup "Coprimes"+    [  testCase         "test equality"                       toListReturnsCorrectValues+    ,  testCase         "test union"                          unionReturnsCorrectValues+    ,  testCase         "test insert with coprime base"       insertReturnsCorrectValuesWhenCoprimeBase+    ,  testCase         "test insert with non-coprime base"   insertReturnsCorrectValuesWhenNotCoprimeBase+    ,  testSmallAndQuick "property union"                     unionProperty1     ]   ]
test-suite/Math/NumberTheory/GaussianIntegersTests.hs view
@@ -15,10 +15,15 @@   ) where  import Control.Monad (zipWithM_)+import Data.List (groupBy, sort) import Test.Tasty import Test.Tasty.HUnit -import Math.NumberTheory.GaussianIntegers+import qualified Math.NumberTheory.Euclidean as ED+import Math.NumberTheory.Quadratic.GaussianIntegers+import Math.NumberTheory.Moduli.Sqrt+import Math.NumberTheory.Powers (integerSquareRoot)+import Math.NumberTheory.UniqueFactorisation (unPrime) import Math.NumberTheory.TestUtils  lazyCases :: [(GaussianInteger, [(GaussianInteger, Int)])]@@ -26,69 +31,140 @@   [ ( 14145130733     * 10000000000000000000000000000000000000121     * 100000000000000000000000000000000000000000000000447-    , [(21037 :+ 117058, 1), (117058 :+ 21037, 1)]+    , [(117058 :+ 21037, 1), (21037 :+ 117058, 1)]     )   ]  -- | Number is zero or is equal to the product of its factors.-factoriseProperty1 :: Integer -> Integer -> Bool-factoriseProperty1 x y-  =  x == 0 && y == 0-  || g == g'+factoriseProperty1 :: GaussianInteger -> Bool+factoriseProperty1 g+  =  g == 0+  || abs g == abs g'   where-    g = x :+ y     factors = factorise g-    g' = product $ map (uncurry (.^)) factors+    g' = product $ map (uncurry (^)) factors -factoriseProperty2 :: (GaussianInteger, [(GaussianInteger, Int)]) -> Assertion-factoriseProperty2 (n, fs) = zipWithM_ (assertEqual (show n)) fs (factorise n)+factoriseProperty2 :: GaussianInteger -> Bool+factoriseProperty2 z = z == 0 || all ((> 0) . snd) (factorise z) +factoriseProperty3 :: GaussianInteger -> Bool+factoriseProperty3 z = z == 0 || all ((> 1) . norm . fst) (factorise z)++factoriseSpecialCase1 :: Assertion+factoriseSpecialCase1 = assertEqual "should be equal"+  [(3, 2), (1 :+ 2, 1), (2 :+ 3, 1)]+  (factorise (63 :+ 36))++factoriseSpecialCase2 :: (GaussianInteger, [(GaussianInteger, Int)]) -> Assertion+factoriseSpecialCase2 (n, fs) = zipWithM_ (assertEqual (show n)) fs (factorise n)++findPrimeReference :: PrimeWrapper Integer -> GaussianInteger+findPrimeReference (PrimeWrapper p) =+    let c : _ = sqrtsModPrime (-1) p+        k  = integerSquareRoot (unPrime p)+        bs = [1 .. k]+        asbs = map (\b' -> ((b' * c) `mod` (unPrime p), b')) bs+        (a, b) = head [ (a', b') | (a', b') <- asbs, a' <= k]+    in a :+ b++findPrimeProperty1 :: PrimeWrapper Integer -> Bool+findPrimeProperty1 p'@(PrimeWrapper p)+  = unPrime p `mod` 4 /= (1 :: Integer)+  || p1 == p2+  || abs (p1 * p2) == fromInteger (unPrime p)+  where+    p1 = findPrimeReference p'+    p2 = findPrime (unPrime p)+ -- | Number is prime iff it is non-zero --   and has exactly one (non-unit) factor.-isPrimeProperty :: Integer -> Integer -> Bool-isPrimeProperty x y-  =  x == 0 && y == 0+isPrimeProperty :: GaussianInteger -> Bool+isPrimeProperty g+  =  g == 0   || isPrime g && n == 1   || not (isPrime g) && n /= 1   where-    g = x :+ y     factors = factorise g-    nonUnitFactors = filter (\(p, _) -> norm p /= 1) factors     -- Count factors taking into account multiplicity-    n = sum $ map snd nonUnitFactors+    n = sum $ map snd factors +primesSpecialCase1 :: Assertion+primesSpecialCase1 = assertEqual "primes"+  (f [1+ι,2+ι,1+2*ι,3,3+2*ι,2+3*ι,4+ι,1+4*ι,5+2*ι,2+5*ι,6+ι,1+6*ι,5+4*ι,4+5*ι,7,7+2*ι,2+7*ι,6+5*ι,5+6*ι,8+3*ι,3+8*ι,8+5*ι,5+8*ι,9+4*ι,4+9*ι,10+ι,1+10*ι,10+3*ι,3+10*ι,8+7*ι,7+8*ι,11,11+4*ι,4+11*ι,10+7*ι,7+10*ι,11+6*ι,6+11*ι,13+2*ι,2+13*ι,10+9*ι,9+10*ι,12+7*ι,7+12*ι,14+ι,1+14*ι,15+2*ι,2+15*ι,13+8*ι,8+13*ι,15+4*ι])+  (f $ take 51 primes)+  where+    f :: [GaussianInteger] -> [[GaussianInteger]]+    f = map sort . groupBy (\g1 g2 -> norm g1 == norm g2)+ -- | The list of primes should include only primes. primesGeneratesPrimesProperty :: NonNegative Int -> Bool primesGeneratesPrimesProperty (NonNegative i) = isPrime (primes !! i) +-- | Check that primes generates the primes in order.+orderingPrimes :: Assertion+orderingPrimes = assertBool "primes are ordered" (and $ zipWith (<=) xs (tail xs))+  where xs = map norm $ take 1000 primes++numberOfPrimes :: Assertion+numberOfPrimes = assertEqual "counting primes: OEIS A091100"+  [16,100,668,4928,38404,313752,2658344]+  [4 * (length $ takeWhile ((<= 10^n) . norm) primes) | n <- [1..7]]+ -- | signum and abs should satisfy: z == signum z * abs z-signumAbsProperty :: Integer -> Integer -> Bool-signumAbsProperty x y = z == signum z * abs z-  where-    z = x :+ y+signumAbsProperty :: GaussianInteger -> Bool+signumAbsProperty z = z == signum z * abs z  -- | abs maps a Gaussian integer to its associate in first quadrant.-absProperty :: Integer -> Integer -> Bool-absProperty x y = isOrigin || (inFirstQuadrant && isAssociate)+absProperty :: GaussianInteger -> Bool+absProperty z = isOrigin || (inFirstQuadrant && isAssociate)   where-    z = x :+ y     z'@(x' :+ y') = abs z     isOrigin = z' == 0 && z == 0     inFirstQuadrant = x' > 0 && y' >= 0     -- first quadrant includes the positive real axis, but not the origin or the positive imaginary axis-    isAssociate = z' `elem` map (\e -> z * (0 :+ 1) .^ e) [0 .. 3]+    isAssociate = z' `elem` map (\e -> z * (0 :+ 1) ^ e) [0 .. 3] +gcdGProperty1 :: GaussianInteger -> GaussianInteger -> Bool+gcdGProperty1 z1 z2+  = z1 == 0 && z2 == 0+  || z1 `ED.rem` z == 0 && z2 `ED.rem` z == 0 && z == abs z+  where+    z = ED.gcd z1 z2++gcdGProperty2 :: GaussianInteger -> GaussianInteger -> GaussianInteger -> Bool+gcdGProperty2 z z1 z2+  = z == 0+  || (ED.gcd z1' z2') `ED.rem` z == 0+  where+    z1' = z * z1+    z2' = z * z2+ -- | a special case that tests rounding/truncating in GCD. gcdGSpecialCase1 :: Assertion-gcdGSpecialCase1 = assertEqual "gcdG" 1 $ gcdG (12 :+ 23) (23 :+ 34)+gcdGSpecialCase1 = assertEqual "gcdG" 1 $ ED.gcd (12 :+ 23) (23 :+ 34)  testSuite :: TestTree testSuite = testGroup "GaussianIntegers" $-  [ testSmallAndQuick "factorise"         factoriseProperty1-  , testSmallAndQuick "isPrime"           isPrimeProperty-  , testSmallAndQuick "primes"            primesGeneratesPrimesProperty-  , testSmallAndQuick "signumAbsProperty" signumAbsProperty-  , testSmallAndQuick "absProperty"       absProperty-  , testCase          "gcdG (12 :+ 23) (23 :+ 34)" gcdGSpecialCase1+  [ testGroup "factorise" (+    [ testSmallAndQuick "factor back"       factoriseProperty1+    , testSmallAndQuick "powers are > 0"    factoriseProperty2+    , testSmallAndQuick "factors are > 1"   factoriseProperty3+    , testCase          "factorise 63:+36"  factoriseSpecialCase1+    ]+    +++    map (\x -> testCase ("laziness " ++ show (fst x)) (factoriseSpecialCase2 x))+      lazyCases)++  , testSmallAndQuick "findPrime'"               findPrimeProperty1+  , testSmallAndQuick "isPrime"                  isPrimeProperty+  , testCase          "primes matches reference" primesSpecialCase1+  , testSmallAndQuick "primes"                   primesGeneratesPrimesProperty+  , testCase          "primes are ordered"       orderingPrimes+  , testCase          "counting primes"          numberOfPrimes+  , testSmallAndQuick "signumAbsProperty"        signumAbsProperty+  , testSmallAndQuick "absProperty"              absProperty+  , testGroup "gcd"+    [ testSmallAndQuick "is divisor"            gcdGProperty1+    , testSmallAndQuick "is greatest"           gcdGProperty2+    , testCase          "(12 :+ 23) (23 :+ 34)" gcdGSpecialCase1+    ]   ]-  ++-  map (\x -> testCase ("laziness " ++ show (fst x)) (factoriseProperty2 x)) lazyCases
test-suite/Math/NumberTheory/Moduli/ClassTests.hs view
@@ -19,7 +19,6 @@  import Test.Tasty -import Data.Bits import Data.Maybe import Numeric.Natural @@ -40,7 +39,7 @@   Just (SomeMod inv) -> gcd k m == 1 && k * getVal inv `mod` m == 1  -- | Check that 'powerMod' is multiplicative by first argument.-powerModProperty2 :: (Integral a, Bits a) => NonNegative a -> AnySign Integer -> AnySign Integer -> Positive Integer -> Bool+powerModProperty2 :: (Integral a) => NonNegative a -> AnySign Integer -> AnySign Integer -> Positive Integer -> Bool powerModProperty2 (NonNegative e) (AnySign b1) (AnySign b2) (Positive m)   =  e < 0 && (isNothing (invertMod b1 m) || isNothing (invertMod b2 m))   || pm1 * pm2 == pm12@@ -50,7 +49,7 @@     pm12 = powerMod (b1 * b2) e m  -- | Check that 'powerMod' is additive by second argument.-powerModProperty3 :: (Integral a, Bits a) => NonNegative a -> NonNegative a -> AnySign Integer -> Positive Integer -> Bool+powerModProperty3 :: (Integral a) => NonNegative a -> NonNegative a -> AnySign Integer -> Positive Integer -> Bool powerModProperty3 (NonNegative e1) (NonNegative e2) (AnySign b) (Positive m)   =  (e1 < 0 || e2 < 0) && isNothing (invertMod b m)   || e2 >= 0 && e1 + e2 < e1 -- check overflow
+ test-suite/Math/NumberTheory/Moduli/DiscreteLogarithmTests.hs view
@@ -0,0 +1,54 @@+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TypeOperators #-}+{-# LANGUAGE DataKinds #-}+{-# OPTIONS_GHC -fno-warn-type-defaults #-}+module Math.NumberTheory.Moduli.DiscreteLogarithmTests+  ( testSuite+  ) where++import Data.Maybe+import Numeric.Natural+import Test.Tasty+import Data.Semigroup+import Data.Proxy+import GHC.TypeNats.Compat++import Math.NumberTheory.Moduli.Class+import Math.NumberTheory.Moduli.PrimitiveRoot+import Math.NumberTheory.Moduli.DiscreteLogarithm+import Math.NumberTheory.ArithmeticFunctions (totient)+import Math.NumberTheory.TestUtils++-- | Ensure 'discreteLogarithm' returns in the appropriate range.+discreteLogRange :: Positive Natural -> Integer -> Integer -> Bool+discreteLogRange (Positive m) a b =+  case someNatVal m of+    SomeNat (_ :: Proxy m) -> fromMaybe True $ do+      a' <- isPrimitiveRoot (fromInteger a :: Mod m)+      b' <- isMultElement (fromInteger b)+      return $ discreteLogarithm a' b' < totient m++-- | Check that 'discreteLogarithm' inverts exponentiation.+discreteLogarithmProperty :: Positive Natural -> Integer -> Integer -> Bool+discreteLogarithmProperty (Positive m) a b =+  case someNatVal m of+    SomeNat (_ :: Proxy m) -> fromMaybe True $ do+      a' <- isPrimitiveRoot (fromInteger a :: Mod m)+      b' <- isMultElement (fromInteger b)+      return $ discreteLogarithm a' b' `stimes` unPrimitiveRoot a' == b'++-- | Check that 'discreteLogarithm' inverts exponentiation in the other direction.+discreteLogarithmProperty' :: Positive Natural -> Integer -> Natural -> Bool+discreteLogarithmProperty' (Positive m) a k =+  case someNatVal m of+    SomeNat (_ :: Proxy m) -> fromMaybe True $ do+      a'' <- isPrimitiveRoot (fromInteger a :: Mod m)+      let a' = unPrimitiveRoot a''+      return $ discreteLogarithm a'' (k `stimes` a') == k `mod` totient m++testSuite :: TestTree+testSuite = testGroup "Discrete logarithm"+  [ testSmallAndQuick "output is correct range" discreteLogRange+  , testSmallAndQuick "a^(log_a b) == b"        discreteLogarithmProperty+  , testSmallAndQuick "log_a a^k == k"          discreteLogarithmProperty'+  ]
+ test-suite/Math/NumberTheory/Moduli/EquationsTests.hs view
@@ -0,0 +1,47 @@+-- |+-- Module:      Math.NumberTheory.Moduli.EquationsTests+-- Copyright:   (c) 2018 Andrew Lelechenko+-- Licence:     MIT+-- Maintainer:  Andrew Lelechenko <andrew.lelechenko@gmail.com>+-- Stability:   Provisional+-- Portability: Non-portable (GHC extensions)+--++{-# LANGUAGE ScopedTypeVariables #-}++module Math.NumberTheory.Moduli.EquationsTests+  ( testSuite+  ) where++import Test.Tasty++import Data.List+import Data.Proxy+import GHC.TypeNats.Compat+import Numeric.Natural++import Math.NumberTheory.Moduli.Class+import Math.NumberTheory.Moduli.Equations+import Math.NumberTheory.TestUtils++solveLinearProp :: KnownNat m => Mod m -> Mod m -> Bool+solveLinearProp a b = sort (solveLinear a b) ==+  filter (\x -> a * x + b == 0) [minBound .. maxBound]++solveLinearProperty1 :: Positive Natural -> Integer -> Integer -> Bool+solveLinearProperty1 (Positive m) a b = case someNatVal m of+  SomeNat (_ :: Proxy t) -> solveLinearProp (fromInteger a :: Mod t) (fromInteger b)++solveQuadraticProp :: KnownNat m => Mod m -> Mod m -> Mod m -> Bool+solveQuadraticProp a b c = sort (solveQuadratic a b c) ==+  filter (\x -> a * x * x + b * x + c == 0) [minBound .. maxBound]++solveQuadraticProperty1 :: Positive Natural -> Integer -> Integer -> Integer -> Bool+solveQuadraticProperty1 (Positive m) a b c = case someNatVal m of+  SomeNat (_ :: Proxy t) -> solveQuadraticProp (fromInteger a :: Mod t) (fromInteger b) (fromInteger c)++testSuite :: TestTree+testSuite = testGroup "Equations"+  [ testSmallAndQuick "solveLinear"    solveLinearProperty1+  , testSmallAndQuick "solveQuadratic" solveQuadraticProperty1+  ]
test-suite/Math/NumberTheory/Moduli/JacobiTests.hs view
@@ -23,6 +23,7 @@ #if __GLASGOW_HASKELL__ < 803 import Data.Semigroup #endif+import Numeric.Natural  import Math.NumberTheory.Moduli hiding (invertMod) import Math.NumberTheory.TestUtils@@ -40,29 +41,90 @@   Zero     -> a `gcd` n /= 1   One      -> a `gcd` n == 1 +doesProductOverflow :: Integral a => a -> a -> Bool+doesProductOverflow x y = abs (toInteger (x * y)) < abs (toInteger x * toInteger y)+ -- https://en.wikipedia.org/wiki/Jacobi_symbol#Properties, item 4 jacobiProperty4 :: (Integral a, Bits a) => AnySign a -> AnySign a -> (MyCompose Positive Odd) a -> Bool-jacobiProperty4 (AnySign a) (AnySign b) (MyCompose (Positive (Odd n))) = jacobi (a * b) n == jacobi a n <> jacobi b n+jacobiProperty4 (AnySign a) (AnySign b) (MyCompose (Positive (Odd n))) =+  doesProductOverflow a b ||+  jacobi (a * b) n == jacobi a n <> jacobi b n +jacobiProperty4_Int :: AnySign Int -> AnySign Int -> (MyCompose Positive Odd) Int -> Bool+jacobiProperty4_Int = jacobiProperty4++jacobiProperty4_Word :: AnySign Word -> AnySign Word -> (MyCompose Positive Odd) Word -> Bool+jacobiProperty4_Word = jacobiProperty4+ jacobiProperty4_Integer :: AnySign Integer -> AnySign Integer -> (MyCompose Positive Odd) Integer -> Bool jacobiProperty4_Integer = jacobiProperty4 +jacobiProperty4_Natural :: AnySign Natural -> AnySign Natural -> (MyCompose Positive Odd) Natural -> Bool+jacobiProperty4_Natural = jacobiProperty4+ -- https://en.wikipedia.org/wiki/Jacobi_symbol#Properties, item 5 jacobiProperty5 :: (Integral a, Bits a) => AnySign a -> (MyCompose Positive Odd) a -> (MyCompose Positive Odd) a -> Bool-jacobiProperty5 (AnySign a) (MyCompose (Positive (Odd m))) (MyCompose (Positive (Odd n))) = jacobi a (m * n) == jacobi a m <> jacobi a n+jacobiProperty5 (AnySign a) (MyCompose (Positive (Odd m))) (MyCompose (Positive (Odd n))) =+  doesProductOverflow m n ||+  jacobi a (m * n) == jacobi a m <> jacobi a n +jacobiProperty5_Int :: AnySign Int -> (MyCompose Positive Odd) Int -> (MyCompose Positive Odd) Int -> Bool+jacobiProperty5_Int = jacobiProperty5++jacobiProperty5_Word :: AnySign Word -> (MyCompose Positive Odd) Word -> (MyCompose Positive Odd) Word -> Bool+jacobiProperty5_Word = jacobiProperty5+ jacobiProperty5_Integer :: AnySign Integer -> (MyCompose Positive Odd) Integer -> (MyCompose Positive Odd) Integer -> Bool jacobiProperty5_Integer = jacobiProperty5 +jacobiProperty5_Natural :: AnySign Natural -> (MyCompose Positive Odd) Natural -> (MyCompose Positive Odd) Natural -> Bool+jacobiProperty5_Natural = jacobiProperty5+ -- https://en.wikipedia.org/wiki/Jacobi_symbol#Properties, item 6 jacobiProperty6 :: (Integral a, Bits a) => (MyCompose Positive Odd) a -> (MyCompose Positive Odd) a -> Bool jacobiProperty6 (MyCompose (Positive (Odd m))) (MyCompose (Positive (Odd n))) = gcd m n /= 1 || jacobi m n <> jacobi n m == (if m `mod` 4 == 1 || n `mod` 4 == 1 then One else MinusOne) +-- https://en.wikipedia.org/wiki/Jacobi_symbol#Properties, item 7+jacobiProperty7 :: (Integral a, Bits a) => (MyCompose Positive Odd) a -> Bool+jacobiProperty7 (MyCompose (Positive (Odd n))) =+  jacobi (-1) n == if n `mod` 4 == 1 then One else MinusOne++jacobiProperty7_Int :: (MyCompose Positive Odd) Int -> Bool+jacobiProperty7_Int = jacobiProperty7++jacobiProperty7_Integer :: (MyCompose Positive Odd) Integer -> Bool+jacobiProperty7_Integer = jacobiProperty7++-- https://en.wikipedia.org/wiki/Jacobi_symbol#Properties, item 8+jacobiProperty8 :: (Integral a, Bits a) => (MyCompose Positive Odd) a -> Bool+jacobiProperty8 (MyCompose (Positive (Odd n))) =+  even n ||+  jacobi 2 n == if n `mod` 8 == 1 || n `mod` 8 == 7 then One else MinusOne++jacobiProperty9 :: (Integral a, Bits a, Bounded a) => (MyCompose Positive Odd) a -> Bool+jacobiProperty9 (MyCompose (Positive (Odd n))) =+  jacobi m n == jacobi (toInteger m) (toInteger n)+  where+    m = minBound++jacobiProperty9_Int :: (MyCompose Positive Odd) Int -> Bool+jacobiProperty9_Int = jacobiProperty9+ testSuite :: TestTree testSuite = testGroup "Jacobi"   [ testSameIntegralProperty "same modulo n"                jacobiProperty2   , testSameIntegralProperty "consistent with gcd"          jacobiProperty3-  , testSmallAndQuick        "multiplicative 1"             jacobiProperty4_Integer-  , testSmallAndQuick        "multiplicative 2"             jacobiProperty5_Integer+  , testSmallAndQuick        "multiplicative 1 Int"         jacobiProperty4_Int+  , testSmallAndQuick        "multiplicative 1 Word"        jacobiProperty4_Word+  , testSmallAndQuick        "multiplicative 1 Integer"     jacobiProperty4_Integer+  , testSmallAndQuick        "multiplicative 1 Natural"     jacobiProperty4_Natural+  , testSmallAndQuick        "multiplicative 2 Int"         jacobiProperty5_Int+  , testSmallAndQuick        "multiplicative 2 Word"        jacobiProperty5_Word+  , testSmallAndQuick        "multiplicative 2 Integer"     jacobiProperty5_Integer+  , testSmallAndQuick        "multiplicative 2 Natural"     jacobiProperty5_Natural   , testSameIntegralProperty "law of quadratic reciprocity" jacobiProperty6+  , testSmallAndQuick        "-1 Int"                       jacobiProperty7_Int+  , testSmallAndQuick        "-1 Integer"                   jacobiProperty7_Integer+  , testIntegralProperty     "2"                            jacobiProperty8+  , testSmallAndQuick        "minBound Int"                 jacobiProperty9_Int   ]
test-suite/Math/NumberTheory/Moduli/PrimitiveRootTests.hs view
@@ -17,25 +17,27 @@   ( testSuite   ) where +import Prelude hiding (gcd) import Test.Tasty  import qualified Data.Set as S-import Data.List (genericTake)-import Data.Maybe+import Data.List (genericTake, genericLength)+import Data.Maybe (isJust, isNothing, mapMaybe)+import Control.Arrow (first) import Numeric.Natural--#if !(MIN_VERSION_base(4,8,0))-import Data.Word-#endif+import Data.Proxy+import GHC.TypeNats.Compat  import Math.NumberTheory.ArithmeticFunctions (totient)+import Math.NumberTheory.Euclidean+import Math.NumberTheory.Euclidean.Coprimes import Math.NumberTheory.Moduli.Class (Mod, SomeMod(..), modulo) import Math.NumberTheory.Moduli.PrimitiveRoot-import Math.NumberTheory.Prefactored (prefValue)+import Math.NumberTheory.Prefactored (fromFactors, prefFactors, prefValue, Prefactored) import Math.NumberTheory.TestUtils import Math.NumberTheory.UniqueFactorisation -cyclicGroupProperty1 :: (Integral a, UniqueFactorisation a, Show a) => AnySign a -> Bool+cyclicGroupProperty1 :: (Euclidean a, Integral a, UniqueFactorisation a) => AnySign a -> Bool cyclicGroupProperty1 (AnySign n) = case cyclicGroupFromModulo n of   Nothing -> True   Just cg -> prefValue (cyclicGroupToModulo cg) == n@@ -60,30 +62,32 @@     go acc (x : xs) = if x `S.member` acc then False else go (S.insert x acc) xs  isPrimitiveRoot'Property1-  :: (Eq a, Integral a, UniqueFactorisation a)+  :: (Euclidean a, Integral a, UniqueFactorisation a)   => AnySign a -> CyclicGroup a -> Bool isPrimitiveRoot'Property1 (AnySign n) cg-  = gcd n (prefValue (cyclicGroupToModulo cg)) == 1+  = gcd (toInteger n) (prefValue (castPrefactored (cyclicGroupToModulo cg))) == 1   || not (isPrimitiveRoot' cg n) +castPrefactored :: Integral a => Prefactored a -> Prefactored Integer+castPrefactored = fromFactors . splitIntoCoprimes . map (first toInteger) . unCoprimes . prefFactors+ isPrimitiveRootProperty1 :: AnySign Integer -> Positive Natural -> Bool isPrimitiveRootProperty1 (AnySign n) (Positive m)   = case n `modulo` m of     SomeMod n' -> gcd n (toInteger m) == 1-               || not (isPrimitiveRoot n')+               || isNothing (isPrimitiveRoot n')     InfMod{}   -> False  isPrimitiveRootProperty2 :: Positive Natural -> Bool isPrimitiveRootProperty2 (Positive m)   = isNothing (cyclicGroupFromModulo m)-  || case 0 `modulo` m of-    SomeMod (_ :: Mod t) -> any isPrimitiveRoot [(minBound :: Mod t) .. maxBound]-    InfMod{}             -> False+  || case someNatVal m of+    SomeNat (_ :: Proxy t) -> any (isJust . isPrimitiveRoot) [(minBound :: Mod t) .. maxBound]  isPrimitiveRootProperty3 :: AnySign Integer -> Positive Natural -> Bool isPrimitiveRootProperty3 (AnySign n) (Positive m)   = case n `modulo` m of-    SomeMod n' -> not (isPrimitiveRoot n')+    SomeMod n' -> isNothing (isPrimitiveRoot n')                || allUnique (genericTake (totient m - 1) (iterate (* n') 1))     InfMod{}   -> False @@ -91,9 +95,15 @@ isPrimitiveRootProperty4 (AnySign n) (Positive m)   = isJust (cyclicGroupFromModulo m)   || case n `modulo` m of-    SomeMod n' -> not (isPrimitiveRoot n')+    SomeMod n' -> isNothing (isPrimitiveRoot n')     InfMod{}   -> False +isPrimitiveRootProperty5 :: Positive Natural -> Bool+isPrimitiveRootProperty5 (Positive m)+  = isNothing (cyclicGroupFromModulo m)+  || case someNatVal m of+       SomeNat (_ :: Proxy t) -> genericLength (mapMaybe isPrimitiveRoot [(minBound :: Mod t) .. maxBound]) == totient (totient m)+ testSuite :: TestTree testSuite = testGroup "Primitive root"   [ testGroup "CyclicGroup"@@ -110,9 +120,10 @@       ]     ]   , testGroup "isPrimitiveRoot"-    [ testSmallAndQuick "primitive root is coprime with modulo" isPrimitiveRootProperty1-    , testSmallAndQuick "cyclic group has a primitive root"     isPrimitiveRootProperty2-    , testSmallAndQuick "primitive root generates cyclic group" isPrimitiveRootProperty3-    , testSmallAndQuick "no primitive root in non-cyclic group" isPrimitiveRootProperty4+    [ testSmallAndQuick "primitive root is coprime with modulo"            isPrimitiveRootProperty1+    , testSmallAndQuick "cyclic group has a primitive root"                isPrimitiveRootProperty2+    , testSmallAndQuick "primitive root generates cyclic group"            isPrimitiveRootProperty3+    , testSmallAndQuick "no primitive root in non-cyclic group"            isPrimitiveRootProperty4+    , testSmallAndQuick "cyclic group has right number of primitive roots" isPrimitiveRootProperty5     ]   ]
test-suite/Math/NumberTheory/Moduli/SqrtTests.hs view
@@ -20,107 +20,219 @@ import Test.Tasty import Test.Tasty.HUnit -import Data.List (nub)+import Control.Arrow+import Data.List (group, sort) import Data.Maybe (fromJust)+import Numeric.Natural  import Math.NumberTheory.Moduli hiding (invertMod)-import Math.NumberTheory.UniqueFactorisation (unPrime, isPrime)+import Math.NumberTheory.UniqueFactorisation (unPrime, isPrime, Prime) import Math.NumberTheory.TestUtils -unwrapP :: PrimeWrapper Integer -> Integer-unwrapP (PrimeWrapper p) = unPrime p+unwrapP :: PrimeWrapper Integer -> Prime Integer+unwrapP (PrimeWrapper p) = p -unwrapPP :: (PrimeWrapper Integer, Power Int) -> (Integer, Int)-unwrapPP (p, Power e) = (unwrapP p, e)+unwrapPP :: (PrimeWrapper Integer, Power Word) -> (Prime Integer, Word)+unwrapPP (p, Power e) = (unwrapP p, e `mod` 5) +nubOrd :: Ord a => [a] -> [a]+nubOrd = map head . group . sort+ -- | Check that 'sqrtMod' is defined iff a quadratic residue exists. --   Also check that the result is a solution of input modular equation.-sqrtModPProperty :: AnySign Integer -> PrimeWrapper Integer -> Bool-sqrtModPProperty (AnySign n) (unwrapP -> p) = case sqrtModP n p of-  Nothing -> jacobi n p == MinusOne-  Just rt -> (p == 2 || jacobi n p /= MinusOne) && rt ^ 2 `mod` p == n `mod` p+sqrtsModPrimeProperty1 :: AnySign Integer -> PrimeWrapper Integer -> Bool+sqrtsModPrimeProperty1 (AnySign n) (unwrapP -> p'@(unPrime -> p)) = case sqrtsModPrime n p' of+  []     -> jacobi n p == MinusOne+  rt : _ -> (p == 2 || jacobi n p /= MinusOne) && rt ^ 2 `mod` p == n `mod` p -sqrtModPListProperty :: AnySign Integer -> PrimeWrapper Integer -> Bool-sqrtModPListProperty (AnySign n) (unwrapP -> p) = all (\rt -> rt ^ 2 `mod` p == n `mod` p) (sqrtModPList n p)+sqrtsModPrimeProperty2 :: AnySign Integer -> PrimeWrapper Integer -> Bool+sqrtsModPrimeProperty2 (AnySign n) (unwrapP -> p'@(unPrime -> p)) = all (\rt -> rt ^ 2 `mod` p == n `mod` p) (sqrtsModPrime n p') -sqrtModP'Property :: Positive Integer -> PrimeWrapper Integer -> Bool-sqrtModP'Property (Positive n) (unwrapP -> p) = (p /= 2 && jacobi n p /= One) || rt ^ 2 `mod` p == n `mod` p+sqrtsModPrimeProperty3 :: AnySign Integer -> PrimeWrapper Integer -> Bool+sqrtsModPrimeProperty3 (AnySign n) (unwrapP -> p'@(unPrime -> p)) = nubOrd rts == sort rts   where-    rt = sqrtModP' n p+    rts = map (`mod` p) $ sqrtsModPrime n p' +sqrtsModPrimeProperty4 :: AnySign Integer -> PrimeWrapper Integer -> Bool+sqrtsModPrimeProperty4 (AnySign n) (unwrapP -> p'@(unPrime -> p)) = all (\rt -> rt >= 0 && rt < p) (sqrtsModPrime n p')+ tonelliShanksProperty1 :: Positive Integer -> PrimeWrapper Integer -> Bool-tonelliShanksProperty1 (Positive n) (unwrapP -> p) = p `mod` 4 /= 1 || jacobi n p /= One || rt ^ 2 `mod` p == n `mod` p+tonelliShanksProperty1 (Positive n) (unwrapP -> p'@(unPrime -> p)) = p `mod` 4 /= 1 || jacobi n p /= One || rt ^ 2 `mod` p == n `mod` p   where-    rt = tonelliShanks n p+    rt : _ = sqrtsModPrime n p'  tonelliShanksProperty2 :: PrimeWrapper Integer -> Bool-tonelliShanksProperty2 (unwrapP -> p) = p `mod` 4 /= 1 || rt ^ 2 `mod` p == n `mod` p+tonelliShanksProperty2 (unwrapP -> p'@(unPrime -> p)) = p `mod` 4 /= 1 || rt ^ 2 `mod` p == n `mod` p   where     n  = head $ filter (\s -> jacobi s p == One) [2..p-1]-    rt = tonelliShanks n p+    rt : _ = sqrtsModPrime n p' +tonelliShanksProperty3 :: PrimeWrapper Integer -> Bool+tonelliShanksProperty3 (unwrapP -> p'@(unPrime -> p))+  = p `mod` 4 /= 1+  || rt ^ 2 `mod` p == p - 1+  where+    rt : _ = sqrtsModPrime (-1) p'+ tonelliShanksSpecialCases :: Assertion tonelliShanksSpecialCases =   assertEqual "OEIS A002224" [6, 32, 219, 439, 1526, 2987, 22193, 11740, 13854, 91168, 326277, 232059, 3230839, 4379725, 11754394, 32020334, 151024619, 345641931, 373671108, 1857111865, 8110112775, 4184367042] rts   where+    ps :: [Integer]     ps = [17, 73, 241, 1009, 2689, 8089, 33049, 53881, 87481, 483289, 515761, 1083289, 3818929, 9257329, 22000801, 48473881, 175244281, 427733329, 898716289, 8114538721, 9176747449, 23616331489]-    rts = map (\p -> tonelliShanks 2 p) ps+    rts = map (head . sqrtsModPrime 2 . fromJust . isPrime) ps -sqrtModPPProperty :: AnySign Integer -> (PrimeWrapper Integer, Power Int) -> Bool-sqrtModPPProperty (AnySign n) (unwrapP -> p, Power e) = gcd n p > 1 || case sqrtModPP n (p, e) of-  Nothing -> True-  Just rt -> rt ^ 2 `mod` (p ^ e) == n `mod` (p ^ e)+sqrtsModPrimePowerProperty1 :: AnySign Integer -> (PrimeWrapper Integer, Power Word) -> Bool+sqrtsModPrimePowerProperty1 (AnySign n) (unwrapP -> p'@(unPrime -> p), Power e) = gcd n p > 1+  || all (\rt -> rt ^ 2 `mod` (p ^ e) == n `mod` (p ^ e)) (sqrtsModPrimePower n p' e) -sqrtModPPBase2Property :: AnySign Integer -> Power Int -> Bool-sqrtModPPBase2Property n e = sqrtModPPProperty n (PrimeWrapper $ fromJust $ isPrime (2 :: Integer), e)+sqrtsModPrimePowerProperty2 :: AnySign Integer -> Power Word -> Bool+sqrtsModPrimePowerProperty2 n e = sqrtsModPrimePowerProperty1 n (PrimeWrapper $ fromJust $ isPrime (2 :: Integer), e) -sqrtModPPSpecialCase1 :: Assertion-sqrtModPPSpecialCase1 =-  assertEqual "sqrtModPP 16 2 2 = 4" (Just 0) (sqrtModPP 16 (2, 2))+sqrtsModPrimePowerProperty3 :: AnySign Integer -> (PrimeWrapper Integer, Power Word) -> Bool+sqrtsModPrimePowerProperty3 (AnySign n) (unwrapP -> p'@(unPrime -> p), Power e') = nubOrd rts == sort rts+  where+    e = e' `mod` 5+    m = p ^ e+    rts = map (`mod` m) $ sqrtsModPrimePower n p' e -sqrtModPPSpecialCase2 :: Assertion-sqrtModPPSpecialCase2 =-  assertEqual "sqrtModPP 16 3 2 = 4" (Just 4) (sqrtModPP 16 (3, 2))+sqrtsModPrimePowerProperty4 :: AnySign Integer -> Power Word -> Bool+sqrtsModPrimePowerProperty4 n e = sqrtsModPrimePowerProperty3 n (PrimeWrapper $ fromJust $ isPrime (2 :: Integer), e) -sqrtModPPListProperty :: AnySign Integer -> (PrimeWrapper Integer, Power Int) -> Bool-sqrtModPPListProperty (AnySign n) (unwrapP -> p, Power e) = gcd n p > 1-  || all (\rt -> rt ^ 2 `mod` (p ^ e) == n `mod` (p ^ e)) (sqrtModPPList n (p, e))+sqrtsModPrimePowerProperty5 :: AnySign Integer -> (PrimeWrapper Integer, Power Word) -> Bool+sqrtsModPrimePowerProperty5 (AnySign n) (unwrapP -> p'@(unPrime -> p), Power e') = all (\rt -> rt >= 0 && rt < m) rts+  where+    e = e' `mod` 5+    m = p ^ e+    rts = sqrtsModPrimePower n p' e -sqrtModFProperty :: AnySign Integer -> [(PrimeWrapper Integer, Power Int)] -> Bool-sqrtModFProperty (AnySign n) (map unwrapPP -> pes) = case sqrtModF n pes of-  Nothing -> True-  Just rt -> all (\(p, e) -> rt ^ 2 `mod` (p ^ e) == n `mod` (p ^ e)) pes+sqrtsModPrimePowerProperty6 :: AnySign Integer -> Power Word -> Bool+sqrtsModPrimePowerProperty6 n e = sqrtsModPrimePowerProperty5 n (PrimeWrapper $ fromJust $ isPrime (2 :: Integer), e) -sqrtModFListProperty :: AnySign Integer -> [(PrimeWrapper Integer, Power Int)] -> Bool-sqrtModFListProperty (AnySign n) (map unwrapPP -> pes)-  = nub ps /= ps || all+sqrtsModPrimePowerSpecialCase1 :: Assertion+sqrtsModPrimePowerSpecialCase1 =+  assertEqual "should be equal" [0, 2] (sort (sqrtsModPrimePower 16 (fromJust (isPrime (2 :: Integer))) 2))++sqrtsModPrimePowerSpecialCase2 :: Assertion+sqrtsModPrimePowerSpecialCase2 =+  assertEqual "should be equal" [4, 5] (sort (sqrtsModPrimePower 16 (fromJust (isPrime (3 :: Integer))) 2))++sqrtsModPrimePowerSpecialCase3 :: Assertion+sqrtsModPrimePowerSpecialCase3 =+  assertEqual "should be equal" [0, 3, 6] (sort (sqrtsModPrimePower 0 (fromJust (isPrime (3 :: Integer))) 2))++sqrtsModPrimePowerSpecialCase4 :: Assertion+sqrtsModPrimePowerSpecialCase4 =+  assertEqual "should be equal" [0, 9, 18] (sort (sqrtsModPrimePower 0 (fromJust (isPrime (3 :: Integer))) 3))++sqrtsModPrimePowerSpecialCase5 :: Assertion+sqrtsModPrimePowerSpecialCase5 =+  assertEqual "should be equal" [0, 4, 8, 12] (sort (sqrtsModPrimePower 0 (fromJust (isPrime (2 :: Integer))) 4))++sqrtsModPrimePowerSpecialCase6 :: Assertion+sqrtsModPrimePowerSpecialCase6 =+  assertEqual "should be equal" [3, 6, 12, 15, 21, 24] (sort (sqrtsModPrimePower 9 (fromJust (isPrime (3 :: Integer))) 3))++sqrtsModPrimePowerSpecialCase7 :: Assertion+sqrtsModPrimePowerSpecialCase7 =+  assertEqual "should be equal" [2, 6] (sort (sqrtsModPrimePower 4 (fromJust (isPrime (2 :: Integer))) 3))++sqrtsModPrimePowerSpecialCase8 :: Assertion+sqrtsModPrimePowerSpecialCase8 =+  assertEqual "should be equal" [1, 3] (sort (sqrtsModPrimePower 1 (fromJust (isPrime (2 :: Integer))) 2))++sqrtsModPrimePowerSpecialCase9 :: Assertion+sqrtsModPrimePowerSpecialCase9 =+  assertEqual "should be equal" [] (sort (sqrtsModPrimePower (-1) (fromJust (isPrime (2 :: Integer))) 2))++sqrtsModPrimePowerSpecialCase10 :: Assertion+sqrtsModPrimePowerSpecialCase10 =+  assertEqual "should be equal" [2, 6, 10, 14] (sort (sqrtsModPrimePower 4 (fromJust (isPrime (2 :: Integer))) 4))++sqrtsModPrimePowerSpecialCase11 :: Assertion+sqrtsModPrimePowerSpecialCase11 =+  assertEqual "should be equal" [4,12,20,28,36,44,52,60] (sort (sqrtsModPrimePower 16 (fromJust (isPrime (2 :: Integer))) 6))++sqrtsModFactorisationProperty1 :: AnySign Integer -> [(PrimeWrapper Integer, Power Word)] -> Bool+sqrtsModFactorisationProperty1 (AnySign n) (take 10 . map unwrapPP -> pes'@(map (first unPrime) -> pes))+  = nubOrd ps /= sort ps || all     (\rt -> all (\(p, e) -> rt ^ 2 `mod` (p ^ e) == n `mod` (p ^ e)) pes)-    (sqrtModFList n pes)+    (take 1000 $ sqrtsModFactorisation n pes')   where     ps = map fst pes -sqrtModFListSpecialCase :: Assertion-sqrtModFListSpecialCase =-  assertEqual "sqrtModPPList 0 [(2,1), (3,1), (5,1)]" [0] (sqrtModFList 0 [(2,1), (3,1), (5,1)])+sqrtsModFactorisationProperty2 :: AnySign Integer -> [(PrimeWrapper Integer, Power Word)] -> Bool+sqrtsModFactorisationProperty2 (AnySign n) (take 10 . map unwrapPP -> pes'@(map (first unPrime) -> pes))+  = nubOrd ps /= sort ps || nubOrd rts == sort rts+  where+    ps = map fst pes+    m = product $ map (\(p, e) -> p ^ e) pes+    rts = map (`mod` m) $ take 1000 $ sqrtsModFactorisation n pes' +sqrtsModFactorisationProperty3 :: AnySign Integer -> [(PrimeWrapper Integer, Power Word)] -> Bool+sqrtsModFactorisationProperty3 (AnySign n) (take 10 . map unwrapPP -> pes'@(map (first unPrime) -> pes))+  = nubOrd ps /= sort ps || all (\rt -> rt >= 0 && rt < m) rts+  where+    ps = map fst pes+    m = product $ map (\(p, e) -> p ^ e) pes+    rts = take 1000 $ sqrtsModFactorisation n pes'++sqrtsModFactorisationSpecialCase1 :: Assertion+sqrtsModFactorisationSpecialCase1 =+  assertEqual "should be equal" [0]+    (sqrtsModFactorisation 0 $ map (first (fromJust . isPrime)) [(2 :: Integer, 1), (3, 1), (5, 1)])++sqrtsModFactorisationSpecialCase2 :: Assertion+sqrtsModFactorisationSpecialCase2 =+  assertEqual "should be equal" [0]+    (sqrtsModFactorisation 0 $ map (first (fromJust . isPrime)) [(3 :: Integer, 1), (5, 1)])++sqrtsModProperty1 :: AnySign Integer -> Positive Natural -> Bool+sqrtsModProperty1 (AnySign n) (Positive m) = case n `modulo` m of+  SomeMod x -> sort (sqrtsMod x) == filter (\rt -> rt * rt == x) [minBound .. maxBound]+  InfMod{} -> True+ testSuite :: TestTree testSuite = testGroup "Sqrt"-  [ testSmallAndQuick "sqrtModP"         sqrtModPProperty-  , testSmallAndQuick "sqrtModPList"     sqrtModPListProperty-  , testSmallAndQuick "sqrtModP'"        sqrtModP'Property+  [ testGroup "sqrtsModPrime"+    [ testSmallAndQuick "matches jacobi"   sqrtsModPrimeProperty1+    , testSmallAndQuick "is residue"       sqrtsModPrimeProperty2+    , testSmallAndQuick "distinct"         sqrtsModPrimeProperty3+    , testSmallAndQuick "bounded"          sqrtsModPrimeProperty4+    ]   , testGroup "tonelliShanks"     [ testSmallAndQuick "generic"          tonelliShanksProperty1     , testSmallAndQuick "smallest residue" tonelliShanksProperty2+    , testSmallAndQuick "-1"               tonelliShanksProperty3     , testCase          "OEIS A002224"     tonelliShanksSpecialCases     ]-  , testGroup "sqrtModPP"-    [ testSmallAndQuick "generic"        sqrtModPPProperty-    , testSmallAndQuick "_  2 _"         sqrtModPPBase2Property-    , testCase          "16 2 2"         sqrtModPPSpecialCase1-    , testCase          "16 3 2"         sqrtModPPSpecialCase2+  , testGroup "sqrtsModPrimePower"+    [ testSmallAndQuick "generic"        sqrtsModPrimePowerProperty1+    , testSmallAndQuick "_  2 _"         sqrtsModPrimePowerProperty2+    , testSmallAndQuick "distinct"       sqrtsModPrimePowerProperty3+    , testSmallAndQuick "_  2 _"         sqrtsModPrimePowerProperty4+    , testSmallAndQuick "bounded"        sqrtsModPrimePowerProperty5+    , testSmallAndQuick "_  2 _"         sqrtsModPrimePowerProperty6+    , testCase          "16 2 2"         sqrtsModPrimePowerSpecialCase1+    , testCase          "16 3 2"         sqrtsModPrimePowerSpecialCase2+    , testCase          "0  3 2"         sqrtsModPrimePowerSpecialCase3+    , testCase          "0  3 3"         sqrtsModPrimePowerSpecialCase4+    , testCase          "0  2 4"         sqrtsModPrimePowerSpecialCase5+    , testCase          "9  3 3"         sqrtsModPrimePowerSpecialCase6+    , testCase          "4  2 3"         sqrtsModPrimePowerSpecialCase7+    , testCase          "1  2 2"         sqrtsModPrimePowerSpecialCase8+    , testCase          "-1 2 2"         sqrtsModPrimePowerSpecialCase9+    , testCase          "4  2 4"         sqrtsModPrimePowerSpecialCase10+    , testCase          "16 2 6"         sqrtsModPrimePowerSpecialCase11     ]-  , testSmallAndQuick "sqrtModPPList"    sqrtModPPListProperty-  , testSmallAndQuick "sqrtModF"         sqrtModFProperty-  , testSmallAndQuick "sqrtModFList"     sqrtModFListProperty-  , testCase          "sqrtModFList 0 [(2,1), (3,1), (5,1)]" sqrtModFListSpecialCase+  , testGroup "sqrtsModFactorisation"+    [ testSmallAndQuick "generic"                 sqrtsModFactorisationProperty1+    , testSmallAndQuick "distinct"                sqrtsModFactorisationProperty2+    , testSmallAndQuick "bounded"                 sqrtsModFactorisationProperty3+    , testCase          "0 [(2,1), (3,1), (5,1)]" sqrtsModFactorisationSpecialCase1+    , testCase          "0 [(3,1), (5,1)]"        sqrtsModFactorisationSpecialCase2+    ]+  , testGroup "sqrtsMod"+    [ testSmallAndQuick "generic" sqrtsModProperty1+    ]   ]
test-suite/Math/NumberTheory/Powers/CubesTests.hs view
@@ -20,11 +20,6 @@ import Test.Tasty.HUnit  import Data.Maybe-#if MIN_VERSION_base(4,8,0)-#else-import Data.Word-#endif-  import Math.NumberTheory.Powers.Cubes import Math.NumberTheory.TestUtils
test-suite/Math/NumberTheory/Powers/FourthTests.hs view
@@ -20,10 +20,6 @@ import Test.Tasty.HUnit  import Data.Maybe-#if MIN_VERSION_base(4,8,0)-#else-import Data.Word-#endif  import Math.NumberTheory.Powers.Fourth import Math.NumberTheory.TestUtils
test-suite/Math/NumberTheory/Powers/ModularTests.hs view
@@ -17,9 +17,7 @@   ) where  import Test.Tasty-#if MIN_VERSION_base(4,8,0) import Test.Tasty.HUnit-#endif  import Numeric.Natural @@ -46,7 +44,6 @@ powModProperty3 (NonNegative e1) (NonNegative e2) (AnySign b) (Positive m)   = (powMod' b e1 m * powMod' b e2 m) `mod` m == powMod' b (e1 + e2) m -#if __GLASGOW_HASKELL__ > 709 -- | Specialized to trigger 'powModInt'. powModProperty_Int :: AnySign Int -> NonNegative Int -> Positive Int -> Bool powModProperty_Int (AnySign b) (NonNegative e) (Positive m) = powModInt b e m == fromInteger (powMod' (fromIntegral b) (fromIntegral e) (fromIntegral m))@@ -54,7 +51,6 @@ -- | Specialized to trigger 'powModWord'. powModProperty_Word :: AnySign Word -> NonNegative Word -> Positive Word -> Bool powModProperty_Word (AnySign b) (NonNegative e) (Positive m) = powModWord b e m == fromInteger (powMod' (fromIntegral b) (fromIntegral e) (fromIntegral m))-#endif  -- | Specialized to trigger 'powModInteger'. powModProperty_Integer :: AnySign Integer -> NonNegative Integer -> Positive Integer -> Bool@@ -64,7 +60,7 @@ powModProperty_Natural :: AnySign Natural -> NonNegative Natural -> Positive Natural -> Bool powModProperty_Natural (AnySign b) (NonNegative e) (Positive m) = powMod b e m == fromInteger (powMod' (fromIntegral b) (fromIntegral e) (fromIntegral m)) -#if WORD_SIZE_IN_BITS == 64 && __GLASGOW_HASKELL__ > 709+#if WORD_SIZE_IN_BITS == 64 -- | Large modulo m such that m^2 overflows. powModSpecialCase1_Int :: Assertion powModSpecialCase1_Int =@@ -83,14 +79,12 @@     , testSmallAndQuick "multiplicative by base" powModProperty2     , testSmallAndQuick "additive by exponent"   powModProperty3 -#if __GLASGOW_HASKELL__ > 709     , testSmallAndQuick "powModInt"              powModProperty_Int     , testSmallAndQuick "powModWord"             powModProperty_Word-#endif     , testSmallAndQuick "powModInteger"          powModProperty_Integer     , testSmallAndQuick "powModNatural"          powModProperty_Natural -#if WORD_SIZE_IN_BITS == 64 && __GLASGOW_HASKELL__ > 709+#if WORD_SIZE_IN_BITS == 64     , testCase          "large modulo :: Int"    powModSpecialCase1_Int     , testCase          "large modulo :: Word"   powModSpecialCase1_Word #endif
test-suite/Math/NumberTheory/Powers/SquaresTests.hs view
@@ -20,10 +20,6 @@ import Test.Tasty.HUnit  import Data.Maybe-#if MIN_VERSION_base(4,8,0)-#else-import Data.Word-#endif  import Math.NumberTheory.Powers.Squares import Math.NumberTheory.TestUtils
test-suite/Math/NumberTheory/PrefactoredTests.hs view
@@ -19,25 +19,21 @@ import Test.Tasty  import Control.Arrow (second)-import Data.Bits (Bits) import Data.List (tails)-#if MIN_VERSION_base(4,8,0)-#else-import Data.Word-#endif import Numeric.Natural -import Math.NumberTheory.GCD (coprime, splitIntoCoprimes)+import Math.NumberTheory.Euclidean (Euclidean, coprime)+import Math.NumberTheory.Euclidean.Coprimes import Math.NumberTheory.Prefactored import Math.NumberTheory.TestUtils -isValid :: (Eq a, Bits a, Integral a) => Prefactored a -> Bool+isValid :: Euclidean a => Prefactored a -> Bool isValid pref   = abs n == abs (product (map (uncurry (^)) fs))   && and [ coprime g h | ((g, _) : gs) <- tails fs, (h, _) <- gs ]   where     n  = prefValue   pref-    fs = prefFactors pref+    fs = unCoprimes $ prefFactors pref  fromValueProperty :: Integer -> Bool fromValueProperty n = isValid pref && prefValue pref == n
test-suite/Math/NumberTheory/Primes/FactorisationTests.hs view
@@ -45,6 +45,8 @@   , (16757651897802863152387219654541878162,[(2,1),(29,1),(78173,1),(401529283,1),(1995634649,1),(4612433663779,1)])   , (16757651897802863152387219654541878163,[(11,1),(31,1),(112160981904206269,1),(438144115295608147,1)])   , (16757651897802863152387219654541878166,[(2,1),(23,1),(277,1),(505353699591289,1),(2602436338718275457,1)])+  , ((10 ^ 80 - 1) `div` 9, [(11,1),(17,1),(41,1),(73,1),(101,1),(137,1),(271,1),(3541,1),(9091,1),(27961,1),+                             (1676321,1),(5070721,1),(5882353,1),(5964848081,1),(19721061166646717498359681,1)])   ]  lazyCases :: [(Integer, [(Integer, Int)])]@@ -60,7 +62,7 @@ factoriseProperty1 = assertEqual "0" [] (factorise 1)  factoriseProperty2 :: Positive Integer -> Bool-factoriseProperty2 (Positive n) = (-1, 1) : factorise n == factorise (negate n)+factoriseProperty2 (Positive n) = factorise n == factorise (negate n)  factoriseProperty3 :: Positive Integer -> Bool factoriseProperty3 (Positive n) = all (isPrime . fst) (factorise n)
test-suite/Math/NumberTheory/Primes/SieveTests.hs view
@@ -1,6 +1,6 @@ -- | -- Module:      Math.NumberTheory.Primes.SieveTests--- Copyright:   (c) 2016 Andrew Lelechenko+-- Copyright:   (c) 2016-2018 Andrew Lelechenko -- Licence:     MIT -- Maintainer:  Andrew Lelechenko <andrew.lelechenko@gmail.com> -- Stability:   Provisional@@ -8,7 +8,8 @@ -- Tests for Math.NumberTheory.Primes.Sieve -- -{-# LANGUAGE CPP #-}+{-# LANGUAGE CPP                 #-}+{-# LANGUAGE ScopedTypeVariables #-}  {-# OPTIONS_GHC -fno-warn-type-defaults #-} {-# OPTIONS_GHC -fno-warn-deprecations  #-}@@ -22,49 +23,97 @@ import Test.Tasty import Test.Tasty.HUnit +import Data.Int+import Data.Proxy (Proxy(..))+import Data.Word+import Numeric.Natural (Natural)+ import Math.NumberTheory.Primes.Sieve-import qualified Math.NumberTheory.Primes.Heap as H+import Math.NumberTheory.Primes.Testing import Math.NumberTheory.TestUtils --- | Check that both 'primes' produce the same.-primesProperty1 :: Assertion-primesProperty1 = do-  assertEqual "Sieve == Heap" (trim primes) (trim H.primes)-  where-    trim = take 100000+lim1 :: Num a => a+lim1 = 1000000 --- | Check that both 'sieveFrom' produce the same.-sieveFromProperty1 :: AnySign Integer -> Bool-sieveFromProperty1 (AnySign lowBound)-  = trim (sieveFrom lowBound) == trim (H.sieveFrom lowBound)-  where-    trim = take 1000+lim2 :: Num a => a+lim2 = 100000 +lim3 :: Num a => a+lim3 = 1000++-- | Check that 'primes' matches 'isPrime'.+primesProperty1 :: forall a. (Integral a, Show a) => Proxy a -> Assertion+primesProperty1 _ = assertEqual "primes matches isPrime"+  (takeWhile (<= lim1) primes :: [a])+  (filter (isPrime . toInteger) [1..lim1])++primesProperty2 :: forall a. (Integral a, Bounded a, Show a) => Proxy a -> Assertion+primesProperty2 _ = assertEqual "primes matches isPrime"+  (primes :: [a])+  (filter (isPrime . toInteger) [1..maxBound])+ -- | Check that 'primeList' from 'primeSieve' matches truncated 'primes'. primeSieveProperty1 :: AnySign Integer -> Bool-primeSieveProperty1 (AnySign highBound)-  = primeList (primeSieve highBound) == takeWhile (<= (highBound `max` 7)) primes+primeSieveProperty1 (AnySign highBound')+  =  primeList (primeSieve highBound)+  == takeWhile (<= (highBound `max` 7)) primes+  where+    highBound = highBound' `rem` lim1  -- | Check that 'primeList' from 'psieveList' matches 'primes'.-psieveListProperty1 :: Assertion-psieveListProperty1 = do-  assertEqual "primes == primeList . psieveList" (trim primes) (trim $ concatMap primeList psieveList)-  where-    trim = take 100000+psieveListProperty1 :: forall a. (Integral a, Show a) => Proxy a -> Assertion+psieveListProperty1 _ = assertEqual "primes == primeList . psieveList"+  (take lim2 primes :: [a])+  (take lim2 $ concatMap primeList psieveList) --- | Check that 'primeList' from 'psieveFrom' matches 'sieveFrom'.-psieveFromProperty1 :: AnySign Integer -> Bool-psieveFromProperty1 (AnySign lowBound)-  = trim (sieveFrom lowBound) == trim (filter (>= lowBound) (concatMap primeList $ psieveFrom lowBound))+psieveListProperty2 :: forall a. (Integral a, Show a) => Proxy a -> Assertion+psieveListProperty2 _ = assertEqual "primes == primeList . psieveList"+  (primes :: [a])+  (concat $ takeWhile (not . null) $ map primeList psieveList)++-- | Check that 'sieveFrom' matches 'primeList' of 'psieveFrom'.+sieveFromProperty1 :: AnySign Integer -> Bool+sieveFromProperty1 (AnySign lowBound')+  =  take lim3 (sieveFrom lowBound)+  == take lim3 (filter (>= lowBound) (concatMap primeList $ psieveFrom lowBound))   where-    trim = take 1000+    lowBound = lowBound' `rem` lim1 +-- | Check that 'sieveFrom' matches 'isPrime' near 0.+sieveFromProperty2 :: AnySign Integer -> Bool+sieveFromProperty2 (AnySign lowBound')+  =  take lim3 (sieveFrom lowBound)+  == take lim3 (filter (isPrime . toInteger) [lowBound `max` 0 ..])+  where+    lowBound = lowBound' `rem` lim1  testSuite :: TestTree testSuite = testGroup "Sieve"-  [ testCase          "primes"     primesProperty1-  , testSmallAndQuick "sieveFrom"  sieveFromProperty1+  [ testGroup "primes"+    [ testCase "Int"     (primesProperty1 (Proxy :: Proxy Int))+    , testCase "Word"    (primesProperty1 (Proxy :: Proxy Word))+    , testCase "Integer" (primesProperty1 (Proxy :: Proxy Integer))+    , testCase "Natural" (primesProperty1 (Proxy :: Proxy Natural))++    , testCase "Int8"    (primesProperty2 (Proxy :: Proxy Int8))+    , testCase "Int16"   (primesProperty2 (Proxy :: Proxy Int16))+    , testCase "Word8"   (primesProperty2 (Proxy :: Proxy Word8))+    , testCase "Word16"  (primesProperty2 (Proxy :: Proxy Word16))+    ]   , testSmallAndQuick "primeSieve" primeSieveProperty1-  , testCase          "psieveList" psieveListProperty1-  , testSmallAndQuick "psieveFrom" psieveFromProperty1+  , testGroup "psieveList"+    [ testCase "Int"     (psieveListProperty1 (Proxy :: Proxy Int))+    , testCase "Word"    (psieveListProperty1 (Proxy :: Proxy Word))+    , testCase "Integer" (psieveListProperty1 (Proxy :: Proxy Integer))+    , testCase "Natural" (psieveListProperty1 (Proxy :: Proxy Natural))++    , testCase "Int8"    (psieveListProperty2 (Proxy :: Proxy Int8))+    , testCase "Int16"   (psieveListProperty2 (Proxy :: Proxy Int16))+    , testCase "Word8"   (psieveListProperty2 (Proxy :: Proxy Word8))+    , testCase "Word16"  (psieveListProperty2 (Proxy :: Proxy Word16))+    ]+  , testGroup "sieveFrom"+    [ testSmallAndQuick "psieveFrom"     sieveFromProperty1+    , testSmallAndQuick "isPrime near 0" sieveFromProperty2+    ]   ]
test-suite/Math/NumberTheory/PrimesTests.hs view
@@ -16,7 +16,6 @@   ) where  import Test.Tasty-import Test.Tasty.HUnit  import Math.NumberTheory.Primes import Math.NumberTheory.TestUtils@@ -31,17 +30,7 @@ primesSumProperty (NonNegative n) = primesSumWonk n == primesSum n  -sieveFactorSpecialCase1 :: Assertion-sieveFactorSpecialCase1 = do-    assertEqual "sieveFactor 2048" [(29, 1), (73, 1)] $ sieveFactor (factorSieve 2048) (29*73)-    assertEqual "sieveFactor 15"   [(3, 1),  (5, 2)]  $ sieveFactor (factorSieve 15) (75)--sieveFactorProperty :: Integer -> Bool-sieveFactorProperty n = (n==0) || factorise n == sieveFactor (factorSieve 25) n- testSuite :: TestTree testSuite = testGroup "Primes"   [ testSmallAndQuick "primesSum"   primesSumProperty-  , testCase          "sieveFactor special"  sieveFactorSpecialCase1-  , testSmallAndQuick "sieveFactor property" sieveFactorProperty   ]
test-suite/Math/NumberTheory/Recurrencies/BilinearTests.hs view
@@ -19,7 +19,10 @@  import Data.Ratio -import Math.NumberTheory.Recurrencies.Bilinear+import Math.NumberTheory.Recurrencies.Bilinear (bernoulli, binomial, euler,+                                                eulerian1, eulerian2,+                                                eulerPolyAt1, lah, stirling1,+                                                stirling2) import Math.NumberTheory.TestUtils  binomialProperty1 :: NonNegative Int -> Bool@@ -149,6 +152,32 @@          | k <- [0 .. m - 1]          ] +-- | For every odd positive integer @n@, @E_n@ is @0@.+eulerProperty1 :: Positive Int -> Bool+eulerProperty1 (Positive n) = euler !! (2 * n - 1) == 0++-- | Every positive even index produces a negative result.+eulerProperty2 :: NonNegative Int -> Bool+eulerProperty2 (NonNegative n) = euler !! (2 + 4 * n) < 0++-- | The Euler number sequence is https://oeis.org/A122045+eulerSpecialCase1 :: Assertion+eulerSpecialCase1 = assertEqual "euler"+    (take 20 euler)+    [1, 0, -1, 0, 5, 0, -61, 0, 1385, 0, -50521, 0, 2702765, 0, -199360981, 0, 19391512145, 0, -2404879675441, 0]++-- | For any even positive integer @n@, @E_n(1)@ is @0@.+eulerPAt1Property1 :: Positive Int -> Bool+eulerPAt1Property1 (Positive n) = (eulerPolyAt1 !! (2 * n)) == 0++-- | The numerators in this sequence are from https://oeis.org/A198631 while the+-- denominators are from https://oeis.org/A006519.+eulerPAt1SpecialCase1 :: Assertion+eulerPAt1SpecialCase1 = assertEqual "eulerPolyAt1"+    (take 20 eulerPolyAt1)+    (zipWith (%) [1, 1, 0, -1, 0, 1, 0, -17, 0, 31, 0, -691, 0, 5461, 0, -929569, 0, 3202291, 0, -221930581]+                 [1, 2, 1, 4, 1, 2, 1, 8, 1, 2, 1, 4, 1, 2, 1, 16, 1, 2, 1, 4])+ testSuite :: TestTree testSuite = testGroup "Bilinear"   [ testGroup "binomial"@@ -192,5 +221,14 @@     , testCase "B_1"                           bernoulliSpecialCase2     , testSmallAndQuick "sign"                 bernoulliProperty1     , testSmallAndQuick "recursive definition" bernoulliProperty2+    ]+    , testGroup "Euler numbers"+    [ testCase "First 20 elements of E_n are correct"           eulerSpecialCase1+    , testSmallAndQuick "E_n with n odd is 0"                   eulerProperty1+    , testSmallAndQuick "E_n for n in [2,6,8,12..] is negative" eulerProperty2+    ]+  , testGroup "Euler Polynomial of order N evaluated at 1"+    [ testCase "First 20 elements of E_n(1) are correct"        eulerPAt1SpecialCase1+    , testSmallAndQuick "E_n(1) with n in [2,4,6..] is 0"       eulerPAt1Property1     ]   ]
+ test-suite/Math/NumberTheory/Recurrencies/PentagonalTests.hs view
@@ -0,0 +1,105 @@+-- |+-- Module:      Math.NumberTheory.Recurrencies.PentagonalTests+-- Copyright:   (c) 2018 Alexandre Rodrigues Baldé+-- Licence:     MIT+-- Maintainer:  Alexandre Rodrigues Baldé <alexandrer_b@outlook.com>+-- Stability:   Provisional+-- Portability: Non-portable (GHC extensions)+--+-- Tests for Math.NumberTheory.Recurrencies.Pentagonal+--++{-# LANGUAGE CPP                 #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE ViewPatterns        #-}++{-# OPTIONS_GHC -fno-warn-type-defaults #-}++module Math.NumberTheory.Recurrencies.PentagonalTests+  ( testSuite+  ) where++import Data.Proxy                     (Proxy (..))+import GHC.Natural                    (Natural)+import GHC.TypeNats.Compat            (SomeNat (..), someNatVal)++import Math.NumberTheory.Moduli       (Mod, getVal)+import Math.NumberTheory.Recurrencies (partition)+import Math.NumberTheory.TestUtils++import Test.Tasty+import Test.Tasty.HUnit++-- | Helper to avoid writing @partition !!@ too many times.+partition' :: Num a => Int -> a+partition' = (partition !!)++-- | Check that the @k@-th generalized pentagonal number is+-- @div (3 * k² - k) 2@, where @k ∈ {0, 1, −1, 2, −2, 3, −3, 4, ...}@.+-- Notice that @-1@ is the @2 * abs (-1) == 2@-nd index in the zero-based list,+-- while @2@ is the @2 * 2 - 1 == 3@-rd, and so on.+pentagonalNumbersProperty1 :: AnySign Int -> Bool+pentagonalNumbersProperty1 (AnySign n)+    | n == 0    = pents !! 0           == 0+    | n > 0     = pents !! (2 * n - 1) == pent n+    | otherwise = pents !! (2 * abs n) == pent n+  where+    pent m = div (3 * (m * m) - m) 2++-- | Check that the first 20 elements of @partition@ are correct per+-- https://oeis.org/A000041.+partitionSpecialCase20 :: Assertion+partitionSpecialCase20 = assertEqual "partition"+    (take 20 partition)+    [1, 1, 2, 3, 5, 7, 11, 15, 22, 30, 42, 56, 77, 101, 135, 176, 231, 297, 385, 490]++-- | Copied from @Math.NumberTheory.Recurrencies.Pentagonal@ to test the+-- reference implementation of @partition@.+pentagonalSigns :: Num a => [a] -> [a]+pentagonalSigns = zipWith (*) (cycle [1, 1, -1, -1])++-- | Copied from @Math.NumberTheory.Recurrencies.Pentagonal@ to test the+-- reference implementation of @partition@.+pents :: (Enum a, Num a) => [a]+pents = interleave (scanl (\acc n -> acc + 3 * n - 1) 0 [1..])+                   (scanl (\acc n -> acc + 3 * n - 2) 1 [2..])+  where+    interleave :: [a] -> [a] -> [a]+    interleave (n : ns) (m : ms) = n : m : interleave ns ms+    interleave _ _ = []++-- | Check that @p(n) = p(n-1) + p(n-2) - p(n-5) - p(n-7) + p(n-11) + ...@,+-- where @p(x) = 0@ for any negative integer and @p(0) = 1@.+partitionProperty1 :: Positive Int -> Bool+partitionProperty1 (Positive n) =+    partition' n == (sum .+                     pentagonalSigns .+                     map (\m -> partition' (n - m)) .+                     takeWhile (\m -> n - m >= 0) .+                     tail $ pents)++-- | Check that+-- @partition :: [Math.NumberTheory.Moduli.Mod n] == map (`mod` n) partition@.+partitionProperty2 :: NonNegative Integer -> Positive Natural -> Bool+partitionProperty2 (NonNegative m)+                   n@(someNatVal . getPositive -> (SomeNat (Proxy :: Proxy n))) =+    (take m' . map getVal $ (partition :: [Mod n])) ==+    map helper (take m' partition :: [Integer])+  where+    m' = fromIntegral m+    n' = fromIntegral n+    helper x = x `mod` n'++testSuite :: TestTree+testSuite = testGroup "Pentagonal"+  [ testGroup "partition"+    [ testSmallAndQuick "matches definition"  partitionProperty1+    , testSmallAndQuick "mapping residue modulus 'n' is the same as giving\+                        \'partition' type '[Mod n]'" partitionProperty2+    , testCase          "first 20 elements of partition are correct"+                        partitionSpecialCase20+    ]+  , testGroup "Generalized pentagonal numbers"+    [ testSmallAndQuick "matches definition" pentagonalNumbersProperty1+    ]+  ]
+ test-suite/Math/NumberTheory/SmoothNumbersTests.hs view
@@ -0,0 +1,68 @@+-- |+-- Module:      Math.NumberTheory.SmoothNumbersTests+-- Copyright:   (c) 2018 Andrew Lelechenko+-- Licence:     MIT+-- Maintainer:  Andrew Lelechenko <andrew.lelechenko@gmail.com>+-- Stability:   Provisional+--+-- Tests for Math.NumberTheory.SmoothNumbersTests+--++{-# OPTIONS_GHC -fno-warn-type-defaults #-}++module Math.NumberTheory.SmoothNumbersTests+  ( testSuite+  ) where++import Prelude hiding (mod)+import Test.Tasty++import Data.Coerce+import Data.List (genericDrop, sort)+import qualified Data.Set as S+import Numeric.Natural++import Math.NumberTheory.Euclidean+import Math.NumberTheory.SmoothNumbers+import Math.NumberTheory.TestUtils++fromSetListProperty :: (Euclidean a, Ord a) => [a] -> Bool+fromSetListProperty xs = fromSet (S.fromList xs) == fromList (sort xs)++fromSmoothUpperBoundProperty :: Integral a => Positive a -> Bool+fromSmoothUpperBoundProperty (Positive n') = case fromSmoothUpperBound n of+    Nothing -> n < 2+    Just sb -> head (genericDrop (n - 1) (smoothOver (coerce sb))) == n+  where+    n = WrappedIntegral n' `mod` 5000++smoothOverInRangeProperty :: Integral a => SmoothBasis a -> Positive a -> Positive a -> Bool+smoothOverInRangeProperty s (Positive lo') (Positive diff')+  = xs == ys+  where+    lo   = WrappedIntegral lo'   `mod` 2^18+    diff = WrappedIntegral diff' `mod` 2^18+    hi   = lo + diff+    xs   = smoothOverInRange   (coerce s) lo hi+    ys   = smoothOverInRangeBF (coerce s) lo hi++testSuite :: TestTree+testSuite = testGroup "SmoothNumbers"+  [ testGroup "fromSet == fromList"+    [ testSmallAndQuick "Int"     (fromSetListProperty :: [Int] -> Bool)+    , testSmallAndQuick "Word"    (fromSetListProperty :: [Word] -> Bool)+    , testSmallAndQuick "Integer" (fromSetListProperty :: [Integer] -> Bool)+    , testSmallAndQuick "Natural" (fromSetListProperty :: [Natural] -> Bool)+    ]+  , testIntegralProperty "fromSmoothUpperBound" fromSmoothUpperBoundProperty+  , testGroup "smoothOverInRange == smoothOverInRangeBF"+    [ testSmallAndQuick "Int"+      (smoothOverInRangeProperty :: SmoothBasis Int -> Positive Int -> Positive Int -> Bool)+    , testSmallAndQuick "Word"+      (smoothOverInRangeProperty :: SmoothBasis Word -> Positive Word -> Positive Word -> Bool)+    , testSmallAndQuick "Integer"+      (smoothOverInRangeProperty :: SmoothBasis Integer -> Positive Integer -> Positive Integer -> Bool)+    , testSmallAndQuick "Natural"+      (smoothOverInRangeProperty :: SmoothBasis Natural -> Positive Natural -> Positive Natural -> Bool)+    ]+  ]
test-suite/Math/NumberTheory/TestUtils.hs view
@@ -36,30 +36,33 @@   , module Math.NumberTheory.TestUtils.MyCompose   , module Test.SmallCheck.Series   , Large(..)+  , NonZero(..)   , testIntegralProperty   , testSameIntegralProperty   , testIntegral2Property   , testSmallAndQuick++  -- * Export for @Zeta@ tests+  , assertEqualUpToEps   ) where  import Test.SmallCheck.Series (cons2) import Test.Tasty+import Test.Tasty.HUnit       (Assertion, assertBool) import Test.Tasty.SmallCheck as SC-import Test.Tasty.QuickCheck as QC hiding (Positive, NonNegative, generate, getNonNegative)+import Test.Tasty.QuickCheck as QC hiding (Positive, getPositive, NonNegative, generate, getNonNegative)  import Test.SmallCheck.Series (Positive(..), NonNegative(..), Serial(..), Series, generate, (\/)) -#if !(MIN_VERSION_base(4,8,0))-import Control.Applicative-import Data.Word-#endif- import Data.Bits import GHC.Exts import Numeric.Natural -import Math.NumberTheory.GaussianIntegers (GaussianInteger(..))+import Math.NumberTheory.Euclidean+import qualified Math.NumberTheory.Quadratic.EisensteinIntegers as E (EisensteinInteger(..))+import Math.NumberTheory.Quadratic.GaussianIntegers (GaussianInteger(..)) import Math.NumberTheory.Moduli.PrimitiveRoot (CyclicGroup(..))+import qualified Math.NumberTheory.SmoothNumbers as SN import Math.NumberTheory.UniqueFactorisation (UniqueFactorisation, Prime, unPrime)  import Math.NumberTheory.TestUtils.MyCompose@@ -69,23 +72,16 @@   arbitrary = fromInteger <$> (arbitrary `suchThat` (>= 0))   shrink = map fromInteger . filter (>= 0) . shrink . toInteger -instance Arbitrary GaussianInteger where-  arbitrary = (:+) <$> arbitrary <*> arbitrary-  shrink (x :+ y) = (:+) <$> shrink x <*> shrink y+instance Arbitrary E.EisensteinInteger where+  arbitrary = (E.:+) <$> arbitrary <*> arbitrary+  shrink (x E.:+ y) = map (x E.:+) (shrink y) ++ map (E.:+ y) (shrink x) -#if !(MIN_VERSION_smallcheck(1,1,3))-instance Monad m => Serial m Word where-  series =-    generate (\d -> if d >= 0 then pure 0 else empty) <|> nats-    where-      nats = generate $ \d -> if d > 0 then [1 .. fromInteger (toInteger d)] else empty+instance Monad m => Serial m E.EisensteinInteger where+  series = cons2 (E.:+) -instance Monad m => Serial m Natural where-  series =-    generate (\d -> if d >= 0 then pure 0 else empty) <|> nats-    where-      nats = generate $ \d -> if d > 0 then [1 .. fromInteger (toInteger d)] else empty-#endif+instance Arbitrary GaussianInteger where+  arbitrary = (:+) <$> arbitrary <*> arbitrary+  shrink (x :+ y) = map (x :+) (shrink y) ++ map (:+ y) (shrink x)  instance Monad m => Serial m GaussianInteger where   series = cons2 (:+)@@ -122,7 +118,16 @@ isOddPrime (PrimeWrapper p) = if (unPrime p :: a) == 2 then Nothing else Just p  -------------------------------------------------------------------------------+-- SmoothNumbers +instance (Ord a, Euclidean a, Arbitrary a) => Arbitrary (SN.SmoothBasis a) where+  arbitrary = (fmap getPositive <$> arbitrary) `suchThatMap` SN.fromList++instance (Ord a, Euclidean a, Serial m a) => Serial m (SN.SmoothBasis a) where+  series = (fmap getPositive <$> series) `suchThatMapSerial` SN.fromList++-------------------------------------------------------------------------------+ -- https://www.cs.ox.ac.uk/projects/utgp/school/andres.pdf, p. 21 -- :k Compose = (k1 -> Constraint) -> (k2 -> k1) -> (k2 -> Constraint) class    (f (g x)) => (f `Compose` g) x@@ -149,7 +154,7 @@  testIntegralProperty   :: forall wrapper bool. (TestableIntegral wrapper, SC.Testable IO bool, QC.Testable bool)-  => String -> (forall a. (Integral a, Bits a, UniqueFactorisation a, Show a) => wrapper a -> bool) -> TestTree+  => String -> (forall a. (Euclidean a, Integral a, Bits a, UniqueFactorisation a, Show a) => wrapper a -> bool) -> TestTree testIntegralProperty name f = testGroup name   [ SC.testProperty "smallcheck Int"     (f :: wrapper Int     -> bool)   , SC.testProperty "smallcheck Word"    (f :: wrapper Word    -> bool)@@ -220,3 +225,10 @@   [ SC.testProperty "smallcheck" f   , QC.testProperty "quickcheck" f   ]+++-- | Used in @Math.NumberTheory.Zeta.DirichletTests@ and+-- @Math.NumberTheory.Zeta.RiemannTests@.+assertEqualUpToEps :: String -> Double -> Double -> Double -> Assertion+assertEqualUpToEps msg eps expected actual+  = assertBool msg (abs (expected - actual) < eps)
test-suite/Math/NumberTheory/TestUtils/Wrappers.hs view
@@ -29,11 +29,6 @@  import Control.Applicative import Data.Functor.Classes-#if MIN_VERSION_base(4,8,0)-#else-import Data.Foldable (Foldable)-import Data.Traversable (Traversable)-#endif  import Test.Tasty.QuickCheck as QC hiding (Positive, NonNegative, generate, getNonNegative, getPositive) import Test.SmallCheck.Series (Positive(..), NonNegative(..), Serial(..), Series)@@ -101,6 +96,12 @@  instance Show1 NonNegative where   liftShowsPrec shw _ p (NonNegative a) = shw p a++-------------------------------------------------------------------------------+-- NonZero from QuickCheck++instance (Monad m, Num a, Eq a, Serial m a) => Serial m (NonZero a) where+  series = NonZero <$> series `suchThatSerial` (/= 0)  ------------------------------------------------------------------------------- -- Huge
test-suite/Math/NumberTheory/UniqueFactorisationTests.hs view
@@ -19,12 +19,7 @@  import Test.Tasty -#if MIN_VERSION_base(4,8,0)-#else-import Data.Word-#endif--import Math.NumberTheory.GaussianIntegers hiding (factorise)+import Math.NumberTheory.Quadratic.GaussianIntegers hiding (factorise) import Math.NumberTheory.UniqueFactorisation import Math.NumberTheory.TestUtils 
+ test-suite/Math/NumberTheory/Zeta/DirichletTests.hs view
@@ -0,0 +1,115 @@+-- |+-- Module:      Math.NumberTheory.Zeta.DirichletTests+-- Copyright:   (c) 2018 Alexandre Rodrigues Baldé+-- Licence:     MIT+-- Maintainer:  Alexandre Rodrigues Baldé <alexandrer_b@outlook.com>+-- Stability:   Provisional+--+-- Tests for Math.NumberTheory.Zeta.Dirichlet+--++{-# OPTIONS_GHC -fno-warn-type-defaults #-}++module Math.NumberTheory.Zeta.DirichletTests+  ( testSuite+  ) where++import Data.ExactPi                (approximateValue)++import Test.Tasty+import Test.Tasty.HUnit            (Assertion, assertEqual, testCase)++import Math.NumberTheory.Zeta      (betas, betasOdd)+import Math.NumberTheory.TestUtils++epsilon :: Double+epsilon = 1e-14++betas' :: [Double]+betas' = betas epsilon++betasOddSpecialCase1 :: Assertion+betasOddSpecialCase1+  = assertEqualUpToEps "beta(1) = pi/4" epsilon+    (approximateValue $ betasOdd !! 0)+    (pi / 4)++betasOddSpecialCase2 :: Assertion+betasOddSpecialCase2+  = assertEqualUpToEps "beta(3) = pi^3/32" epsilon+    (approximateValue $ betasOdd !! 1)+    (pi^3 / 32)++betasOddSpecialCase3 :: Assertion+betasOddSpecialCase3+  = assertEqualUpToEps "beta(5) = 5*pi^5/1536" epsilon+    (approximateValue $ betasOdd !! 2)+    ((5 * pi^5) / 1536)++betasOddProperty1 :: Positive Int -> Bool+betasOddProperty1 (Positive m)+  =  betaM < 1+  || betaM < betaM1+  where+    betaM  = approximateValue (betasOdd !! m)+    betaM1 = approximateValue (betasOdd !! (m + 1))++betasOddProperty2 :: NonNegative Int -> Bool+betasOddProperty2 (NonNegative m)+  = abs (betaM - betaM') < epsilon+  where+    betaM  = approximateValue (betasOdd !! m)+    betaM' = betas' !! ((2 * m) + 1)++betasSpecialCase1 :: Assertion+betasSpecialCase1+  = assertEqual "beta(0) = 1/2"+    (betas' !! 0)+    (1 / 2)++betasSpecialCase2 :: Assertion+betasSpecialCase2+  = assertEqualUpToEps "beta(2) = 0.9159655" epsilon+    (betas' !! 2)+    (0.9159655941772190150546035149323841107)++betasSpecialCase3 :: Assertion+betasSpecialCase3+  = assertEqualUpToEps "beta(4) = 0.9889445" epsilon+    (betas' !! 4)+    (0.9889445517411053361084226332283778213)++betasProperty1 :: Positive Int -> Bool+betasProperty1 (Positive m)+  =  betaM <= betaM1+  && betaM1 <= 1+  where+    betaM  = betas' !! m+    betaM1 = betas' !! (m + 1)++betasProperty2 :: NonNegative Int -> NonNegative Int -> Bool+betasProperty2 (NonNegative e1) (NonNegative e2)+  = maximum (take 10 $ drop 2 $ zipWith ((abs .) . (-)) (betas eps1) (betas eps2)) <= eps1 + eps2+  where+    eps1, eps2 :: Double+    eps1 = (1.0 / 2) ^ e1+    eps2 = (1.0 / 2) ^ e2+++testSuite :: TestTree+testSuite = testGroup "Beta"+  [ testGroup "betasOdd"+    [ testCase "beta(1)"                                        betasOddSpecialCase1+    , testCase "beta(3)"                                        betasOddSpecialCase2+    , testCase "beta(5)"                                        betasOddSpecialCase3+    , testSmallAndQuick "beta(2n-1) < beta(2n+1)"               betasOddProperty1+    , testSmallAndQuick "betasOdd matches betas"                betasOddProperty2+    ]+  , testGroup "betas"+    [ testCase "beta(0)"                                        betasSpecialCase1+    , testCase "beta(2)"                                        betasSpecialCase2+    , testCase "beta(4)"                                        betasSpecialCase3+    , testSmallAndQuick "beta(n) < beta(n+1)"                   betasProperty1+    , testSmallAndQuick "precision"                             betasProperty2+    ]+  ]
+ test-suite/Math/NumberTheory/Zeta/RiemannTests.hs view
@@ -0,0 +1,118 @@+-- |+-- Module:      Math.NumberTheory.Zeta.RiemannTests+-- Copyright:   (c) 2016 Andrew Lelechenko+-- Licence:     MIT+-- Maintainer:  Andrew Lelechenko <andrew.lelechenko@gmail.com>+-- Stability:   Provisional+--+-- Tests for Math.NumberTheory.Zeta.Riemann+--++{-# OPTIONS_GHC -fno-warn-type-defaults #-}++module Math.NumberTheory.Zeta.RiemannTests+  ( testSuite+  ) where++import Data.ExactPi                (approximateValue)++import Test.Tasty+import Test.Tasty.HUnit            (Assertion, assertEqual, testCase)++import Math.NumberTheory.Zeta+import Math.NumberTheory.TestUtils++epsilon :: Double+epsilon = 1e-14++zetasEvenSpecialCase1 :: Assertion+zetasEvenSpecialCase1+  = assertEqual "zeta(0) = -1/2"+    (approximateValue $ zetasEven !! 0)+    (-1 / 2)++zetasEvenSpecialCase2 :: Assertion+zetasEvenSpecialCase2+  = assertEqualUpToEps "zeta(2) = pi^2/6" epsilon+    (approximateValue $ zetasEven !! 1)+    (pi * pi / 6)++zetasEvenSpecialCase3 :: Assertion+zetasEvenSpecialCase3+  = assertEqualUpToEps "zeta(4) = pi^4/90" epsilon+    (approximateValue $ zetasEven !! 2)+    (pi ^ 4 / 90)++zetasEvenProperty1 :: Positive Int -> Bool+zetasEvenProperty1 (Positive m)+  =  zetaM < 1+  || zetaM > zetaM1+  where+    zetaM  = approximateValue (zetasEven !! m)+    zetaM1 = approximateValue (zetasEven !! (m + 1))++zetasEvenProperty2 :: Positive Int -> Bool+zetasEvenProperty2 (Positive m)+  = abs (zetaM - zetaM') < epsilon+  where+    zetaM  = approximateValue (zetasEven !! m)+    zetaM' = zetas' !! (2 * m)++zetas' :: [Double]+zetas' = zetas epsilon++zetasSpecialCase1 :: Assertion+zetasSpecialCase1+  = assertEqual "zeta(1) = Infinity"+    (zetas' !! 1)+    (1 / 0)++zetasSpecialCase2 :: Assertion+zetasSpecialCase2+  = assertEqualUpToEps "zeta(3) = 1.2020569" epsilon+    (zetas' !! 3)+    1.2020569031595942853997381615114499908++zetasSpecialCase3 :: Assertion+zetasSpecialCase3+  = assertEqualUpToEps "zeta(5) = 1.0369277" epsilon+    (zetas' !! 5)+    1.0369277551433699263313654864570341681++zetasProperty1 :: Positive Int -> Bool+zetasProperty1 (Positive m)+  =  zetaM >= zetaM1+  && zetaM1 >= 1+  where+    zetaM  = zetas' !! m+    zetaM1 = zetas' !! (m + 1)++-- | Let z1 be an approximation of z with precision eps1,+-- and z2 be an approximation of the same value with precision eps2.+-- Then (independently of the true value of z)+-- abs (z1 - z2) < eps1 + eps2.+zetasProperty2 :: NonNegative Int -> NonNegative Int -> Bool+zetasProperty2 (NonNegative e1) (NonNegative e2)+  = maximum (take 25 $ drop 2 $ zipWith ((abs .) . (-)) (zetas eps1) (zetas eps2)) < eps1 + eps2+  where+    eps1, eps2 :: Double+    eps1 = 1.0 / 2 ^ e1+    eps2 = 1.0 / 2 ^ e2++testSuite :: TestTree+testSuite = testGroup "Zeta"+  [ testGroup "zetasEven"+    [ testCase "zeta(0)"                          zetasEvenSpecialCase1+    , testCase "zeta(2)"                          zetasEvenSpecialCase2+    , testCase "zeta(4)"                          zetasEvenSpecialCase3+    , testSmallAndQuick "zeta(2n) > zeta(2n+2)"   zetasEvenProperty1+    , testSmallAndQuick "zetasEven matches zetas" zetasEvenProperty2+    ]+  , testGroup "zetas"+    [ testCase "zeta(1)"                          zetasSpecialCase1+    , testCase "zeta(3)"                          zetasSpecialCase2+    , testCase "zeta(5)"                          zetasSpecialCase3+    , testSmallAndQuick "zeta(n) > zeta(n+1)"     zetasProperty1+    , testSmallAndQuick "precision"               zetasProperty2+    ]+  ]
− test-suite/Math/NumberTheory/ZetaTests.hs
@@ -1,116 +0,0 @@--- |--- Module:      Math.NumberTheory.ZetaTests--- Copyright:   (c) 2016 Andrew Lelechenko--- Licence:     MIT--- Maintainer:  Andrew Lelechenko <andrew.lelechenko@gmail.com>--- Stability:   Provisional------ Tests for Math.NumberTheory.Zeta-----{-# OPTIONS_GHC -fno-warn-type-defaults #-}--module Math.NumberTheory.ZetaTests-  ( testSuite-  ) where--import Test.Tasty-import Test.Tasty.HUnit--import Math.NumberTheory.Zeta-import Math.NumberTheory.TestUtils--assertEqualUpToEps :: String -> Double -> Double -> Double -> Assertion-assertEqualUpToEps msg eps expected actual-  = assertBool msg (abs (expected - actual) < eps)--epsilon :: Double-epsilon = 1e-14--zetasEvenSpecialCase1 :: Assertion-zetasEvenSpecialCase1-  = assertEqual "zeta(0) = -1/2"-    (approximateValue $ zetasEven !! 0)-    (-1 / 2)--zetasEvenSpecialCase2 :: Assertion-zetasEvenSpecialCase2-  = assertEqualUpToEps "zeta(2) = pi^2/6" epsilon-    (approximateValue $ zetasEven !! 1)-    (pi * pi / 6)--zetasEvenSpecialCase3 :: Assertion-zetasEvenSpecialCase3-  = assertEqualUpToEps "zeta(4) = pi^4/90" epsilon-    (approximateValue $ zetasEven !! 2)-    (pi ^ 4 / 90)--zetasEvenProperty1 :: Positive Int -> Bool-zetasEvenProperty1 (Positive m)-  =  zetaM < 1-  || zetaM > zetaM1-  where-    zetaM  = approximateValue (zetasEven !! m)-    zetaM1 = approximateValue (zetasEven !! (m + 1))--zetasEvenProperty2 :: Positive Int -> Bool-zetasEvenProperty2 (Positive m)-  = abs (zetaM - zetaM') < epsilon-  where-    zetaM  = approximateValue (zetasEven !! m)-    zetaM' = zetas' !! (2 * m)--zetas' :: [Double]-zetas' = zetas epsilon--zetasSpecialCase1 :: Assertion-zetasSpecialCase1-  = assertEqual "zeta(1) = Infinity"-    (zetas' !! 1)-    (1 / 0)--zetasSpecialCase2 :: Assertion-zetasSpecialCase2-  = assertEqualUpToEps "zeta(3) = 1.2020569" epsilon-    (zetas' !! 3)-    1.2020569031595942853997381615114499908--zetasSpecialCase3 :: Assertion-zetasSpecialCase3-  = assertEqualUpToEps "zeta(5) = 1.0369277" epsilon-    (zetas' !! 5)-    1.0369277551433699263313654864570341681--zetasProperty1 :: Positive Int -> Bool-zetasProperty1 (Positive m)-  =  zetaM >= zetaM1-  && zetaM1 >= 1-  where-    zetaM  = zetas' !! m-    zetaM1 = zetas' !! (m + 1)--zetasProperty2 :: NonNegative Int -> NonNegative Int -> Bool-zetasProperty2 (NonNegative e1) (NonNegative e2)-  = maximum (take 25 $ drop 2 $ zipWith ((abs .) . (-)) (zetas eps1) (zetas eps2)) < eps1 + eps2-  where-    eps1, eps2 :: Double-    eps1 = 1.0 / 2 ^ e1-    eps2 = 1.0 / 2 ^ e2--testSuite :: TestTree-testSuite = testGroup "Zeta"-  [ testGroup "zetasEven"-    [ testCase "zeta(0)"                          zetasEvenSpecialCase1-    , testCase "zeta(2)"                          zetasEvenSpecialCase2-    , testCase "zeta(4)"                          zetasEvenSpecialCase3-    , testSmallAndQuick "zeta(2n) > zeta(2n+2)"   zetasEvenProperty1-    , testSmallAndQuick "zetasEven matches zetas" zetasEvenProperty2-    ]-  , testGroup "zetas"-    [ testCase "zeta(1)"                          zetasSpecialCase1-    , testCase "zeta(3)"                          zetasSpecialCase2-    , testCase "zeta(5)"                          zetasSpecialCase3-    , testSmallAndQuick "zeta(n) > zeta(n+1)"     zetasProperty1-    , testSmallAndQuick "precision"               zetasProperty2-    ]-  ]
test-suite/Test.hs view
@@ -1,13 +1,15 @@ import Test.Tasty  import qualified Math.NumberTheory.GCDTests as GCD-import qualified Math.NumberTheory.GCD.LowLevelTests as GCDLowLevel +import qualified Math.NumberTheory.Recurrencies.PentagonalTests as RecurrenciesPentagonal import qualified Math.NumberTheory.Recurrencies.BilinearTests as RecurrenciesBilinear import qualified Math.NumberTheory.Recurrencies.LinearTests as RecurrenciesLinear  import qualified Math.NumberTheory.Moduli.ChineseTests as ModuliChinese import qualified Math.NumberTheory.Moduli.ClassTests as ModuliClass+import qualified Math.NumberTheory.Moduli.DiscreteLogarithmTests as ModuliDiscreteLogarithm+import qualified Math.NumberTheory.Moduli.EquationsTests as ModuliEquations import qualified Math.NumberTheory.Moduli.JacobiTests as ModuliJacobi import qualified Math.NumberTheory.Moduli.PrimitiveRootTests as ModuliPrimitiveRoot import qualified Math.NumberTheory.Moduli.SqrtTests as ModuliSqrt@@ -29,15 +31,20 @@ import qualified Math.NumberTheory.Primes.SieveTests as Sieve import qualified Math.NumberTheory.Primes.TestingTests as Testing +import qualified Math.NumberTheory.EisensteinIntegersTests as Eisenstein+ import qualified Math.NumberTheory.GaussianIntegersTests as Gaussian  import qualified Math.NumberTheory.ArithmeticFunctionsTests as ArithmeticFunctions import qualified Math.NumberTheory.ArithmeticFunctions.MertensTests as Mertens import qualified Math.NumberTheory.ArithmeticFunctions.SieveBlockTests as SieveBlock import qualified Math.NumberTheory.UniqueFactorisationTests as UniqueFactorisation-import qualified Math.NumberTheory.ZetaTests as Zeta import qualified Math.NumberTheory.CurvesTests as Curves+import qualified Math.NumberTheory.SmoothNumbersTests as SmoothNumbers +import qualified Math.NumberTheory.Zeta.RiemannTests as Riemann+import qualified Math.NumberTheory.Zeta.DirichletTests as Dirichlet+ main :: IO () main = defaultMain tests @@ -50,17 +57,17 @@     , Modular.testSuite     , Squares.testSuite     ]-  , testGroup "GCD"-    [ GCD.testSuite-    , GCDLowLevel.testSuite-    ]+  , GCD.testSuite   , testGroup "Recurrencies"-    [ RecurrenciesLinear.testSuite+    [ RecurrenciesPentagonal.testSuite+    , RecurrenciesLinear.testSuite     , RecurrenciesBilinear.testSuite     ]   , testGroup "Moduli"     [ ModuliChinese.testSuite     , ModuliClass.testSuite+    , ModuliDiscreteLogarithm.testSuite+    , ModuliEquations.testSuite     , ModuliJacobi.testSuite     , ModuliPrimitiveRoot.testSuite     , ModuliSqrt.testSuite@@ -69,9 +76,7 @@     [ MoebiusInversion.testSuite     , MoebiusInversionInt.testSuite     ]-  , testGroup "Prefactored"-    [ Prefactored.testSuite-    ]+  , Prefactored.testSuite   , testGroup "Primes"     [ Primes.testSuite     , Counting.testSuite@@ -79,21 +84,19 @@     , Sieve.testSuite     , Testing.testSuite     ]-  , testGroup "Gaussian"-    [ Gaussian.testSuite-    ]+  , Eisenstein.testSuite+  , Gaussian.testSuite   , testGroup "ArithmeticFunctions"     [ ArithmeticFunctions.testSuite     , Mertens.testSuite     , SieveBlock.testSuite     ]-  , testGroup "UniqueFactorisation"-    [ UniqueFactorisation.testSuite-    ]+  , UniqueFactorisation.testSuite+  , Curves.testSuite+  , SmoothNumbers.testSuite+   , testGroup "Zeta"-    [ Zeta.testSuite-    ]-  , testGroup "Curves"-    [ Curves.testSuite+    [ Riemann.testSuite+    , Dirichlet.testSuite     ]   ]