packages feed

arithmoi 0.8.0.0 → 0.9.0.0

raw patch · 133 files changed

+4505/−3000 lines, 133 filesdep +hmatrix-gsldep +semiringsdep −semigroupsdep ~arraydep ~basedep ~containersnew-component:exe:sequence-modelPVP ok

version bump matches the API change (PVP)

Dependencies added: hmatrix-gsl, semirings

Dependencies removed: semigroups

Dependency ranges changed: array, base, containers, exact-pi

API changes (from Hackage documentation)

- Math.NumberTheory.GCD: binaryGCD :: (Integral a, Bits a) => a -> a -> a
- Math.NumberTheory.GCD: coprime :: (Integral a, Bits a) => a -> a -> Bool
- Math.NumberTheory.GCD: extendedGCD :: Integral a => a -> a -> (a, a, a)
- Math.NumberTheory.GCD.LowLevel: coprimeInt :: Int -> Int -> Bool
- Math.NumberTheory.GCD.LowLevel: coprimeInt# :: Int# -> Int# -> Bool
- Math.NumberTheory.GCD.LowLevel: coprimeWord :: Word -> Word -> Bool
- Math.NumberTheory.GCD.LowLevel: coprimeWord# :: Word# -> Word# -> Bool
- Math.NumberTheory.GCD.LowLevel: gcdInt :: Int -> Int -> Int
- Math.NumberTheory.GCD.LowLevel: gcdInt# :: Int# -> Int# -> Int#
- Math.NumberTheory.GCD.LowLevel: gcdWord :: Word -> Word -> Word
- Math.NumberTheory.GCD.LowLevel: gcdWord# :: Word# -> Word# -> Word#
- Math.NumberTheory.Moduli.Jacobi: jacobi' :: (Integral a, Bits a) => a -> a -> JacobiSymbol
- 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.Primes.Types.Prime a) => GHC.Classes.Eq (Math.NumberTheory.Moduli.PrimitiveRoot.CyclicGroup a)
- Math.NumberTheory.Moduli.PrimitiveRoot: instance GHC.Show.Show (Math.NumberTheory.Primes.Types.Prime a) => GHC.Show.Show (Math.NumberTheory.Moduli.PrimitiveRoot.CyclicGroup a)
- 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: divideByThree :: EisensteinInteger -> (Int, EisensteinInteger)
- Math.NumberTheory.Quadratic.EisensteinIntegers: factorise :: EisensteinInteger -> [(EisensteinInteger, Int)]
- Math.NumberTheory.Quadratic.EisensteinIntegers: isPrime :: EisensteinInteger -> Bool
- Math.NumberTheory.Quadratic.GaussianIntegers: (.^) :: (Integral a) => GaussianInteger -> a -> GaussianInteger
- Math.NumberTheory.Quadratic.GaussianIntegers: factorise :: GaussianInteger -> [(GaussianInteger, Int)]
- 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: isPrime :: GaussianInteger -> Bool
- Math.NumberTheory.Recurrencies.Bilinear: bernoulli :: Integral a => [Ratio a]
- Math.NumberTheory.Recurrencies.Bilinear: binomial :: Integral 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.Recurrencies.Bilinear: eulerian1 :: (Num a, Enum a) => [[a]]
- Math.NumberTheory.Recurrencies.Bilinear: eulerian2 :: (Num a, Enum a) => [[a]]
- Math.NumberTheory.Recurrencies.Bilinear: lah :: Integral a => [[a]]
- Math.NumberTheory.Recurrencies.Bilinear: stirling1 :: (Num a, Enum a) => [[a]]
- Math.NumberTheory.Recurrencies.Bilinear: stirling2 :: (Num a, Enum a) => [[a]]
- Math.NumberTheory.Recurrencies.Linear: factorial :: (Num a, Enum a) => [a]
- Math.NumberTheory.Recurrencies.Linear: fibonacci :: Num a => Int -> a
- Math.NumberTheory.Recurrencies.Linear: fibonacciPair :: Num a => Int -> (a, a)
- Math.NumberTheory.Recurrencies.Linear: generalLucas :: Num a => a -> a -> Int -> (a, a, a, a)
- Math.NumberTheory.Recurrencies.Linear: lucas :: Num a => Int -> a
- Math.NumberTheory.Recurrencies.Linear: lucasPair :: Num a => Int -> (a, a)
- Math.NumberTheory.UniqueFactorisation: class UniqueFactorisation a
- Math.NumberTheory.UniqueFactorisation: factorise :: UniqueFactorisation a => a -> [(Prime a, Word)]
- Math.NumberTheory.UniqueFactorisation: instance GHC.Classes.Eq Math.NumberTheory.UniqueFactorisation.EisensteinPrime
- Math.NumberTheory.UniqueFactorisation: instance GHC.Classes.Eq Math.NumberTheory.UniqueFactorisation.GaussianPrime
- Math.NumberTheory.UniqueFactorisation: instance GHC.Show.Show Math.NumberTheory.UniqueFactorisation.EisensteinPrime
- Math.NumberTheory.UniqueFactorisation: instance GHC.Show.Show Math.NumberTheory.UniqueFactorisation.GaussianPrime
- Math.NumberTheory.UniqueFactorisation: instance Math.NumberTheory.UniqueFactorisation.UniqueFactorisation GHC.Integer.Type.Integer
- Math.NumberTheory.UniqueFactorisation: instance Math.NumberTheory.UniqueFactorisation.UniqueFactorisation GHC.Natural.Natural
- Math.NumberTheory.UniqueFactorisation: instance Math.NumberTheory.UniqueFactorisation.UniqueFactorisation GHC.Types.Int
- Math.NumberTheory.UniqueFactorisation: instance Math.NumberTheory.UniqueFactorisation.UniqueFactorisation GHC.Types.Word
- 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.UniqueFactorisation: isPrime :: (UniqueFactorisation a, Eq a, Num a) => a -> Maybe (Prime a)
- Math.NumberTheory.UniqueFactorisation: unPrime :: UniqueFactorisation a => Prime a -> a
- Math.NumberTheory.Zeta: suminf :: (Floating a, Ord a) => a -> [a] -> a
+ Math.NumberTheory.ArithmeticFunctions: divisorCount :: (UniqueFactorisation n, Num a) => n -> a
+ Math.NumberTheory.ArithmeticFunctions: isNFree :: UniqueFactorisation n => Word -> n -> Bool
+ Math.NumberTheory.ArithmeticFunctions: isNFreeA :: Word -> ArithmeticFunction n Bool
+ Math.NumberTheory.ArithmeticFunctions: nFrees :: forall a. Integral a => Word -> [a]
+ Math.NumberTheory.ArithmeticFunctions: nFreesBlock :: forall a. Integral a => Word -> a -> Word -> [a]
+ Math.NumberTheory.ArithmeticFunctions: runFunctionOnFactors :: ArithmeticFunction n a -> [(Prime n, Word)] -> a
+ Math.NumberTheory.ArithmeticFunctions.Inverse: Infinity :: MinNatural
+ Math.NumberTheory.ArithmeticFunctions.Inverse: MaxNatural :: Natural -> MaxNatural
+ Math.NumberTheory.ArithmeticFunctions.Inverse: MaxWord :: Word -> MaxWord
+ Math.NumberTheory.ArithmeticFunctions.Inverse: MinNatural :: !Natural -> MinNatural
+ Math.NumberTheory.ArithmeticFunctions.Inverse: MinWord :: Word -> MinWord
+ Math.NumberTheory.ArithmeticFunctions.Inverse: [unMaxNatural] :: MaxNatural -> Natural
+ Math.NumberTheory.ArithmeticFunctions.Inverse: [unMaxWord] :: MaxWord -> Word
+ Math.NumberTheory.ArithmeticFunctions.Inverse: [unMinNatural] :: MinNatural -> !Natural
+ Math.NumberTheory.ArithmeticFunctions.Inverse: [unMinWord] :: MinWord -> Word
+ Math.NumberTheory.ArithmeticFunctions.Inverse: asSetOfPreimages :: (Euclidean a, Integral a) => (forall b. Semiring b => (a -> b) -> a -> b) -> a -> Set a
+ Math.NumberTheory.ArithmeticFunctions.Inverse: data MinNatural
+ Math.NumberTheory.ArithmeticFunctions.Inverse: instance Data.Semiring.Semiring Math.NumberTheory.ArithmeticFunctions.Inverse.MaxNatural
+ Math.NumberTheory.ArithmeticFunctions.Inverse: instance Data.Semiring.Semiring Math.NumberTheory.ArithmeticFunctions.Inverse.MaxWord
+ Math.NumberTheory.ArithmeticFunctions.Inverse: instance Data.Semiring.Semiring Math.NumberTheory.ArithmeticFunctions.Inverse.MinNatural
+ Math.NumberTheory.ArithmeticFunctions.Inverse: instance Data.Semiring.Semiring Math.NumberTheory.ArithmeticFunctions.Inverse.MinWord
+ Math.NumberTheory.ArithmeticFunctions.Inverse: instance GHC.Classes.Eq Math.NumberTheory.ArithmeticFunctions.Inverse.MaxNatural
+ Math.NumberTheory.ArithmeticFunctions.Inverse: instance GHC.Classes.Eq Math.NumberTheory.ArithmeticFunctions.Inverse.MaxWord
+ Math.NumberTheory.ArithmeticFunctions.Inverse: instance GHC.Classes.Eq Math.NumberTheory.ArithmeticFunctions.Inverse.MinNatural
+ Math.NumberTheory.ArithmeticFunctions.Inverse: instance GHC.Classes.Eq Math.NumberTheory.ArithmeticFunctions.Inverse.MinWord
+ Math.NumberTheory.ArithmeticFunctions.Inverse: instance GHC.Classes.Ord Math.NumberTheory.ArithmeticFunctions.Inverse.MaxNatural
+ Math.NumberTheory.ArithmeticFunctions.Inverse: instance GHC.Classes.Ord Math.NumberTheory.ArithmeticFunctions.Inverse.MaxWord
+ Math.NumberTheory.ArithmeticFunctions.Inverse: instance GHC.Classes.Ord Math.NumberTheory.ArithmeticFunctions.Inverse.MinNatural
+ Math.NumberTheory.ArithmeticFunctions.Inverse: instance GHC.Classes.Ord Math.NumberTheory.ArithmeticFunctions.Inverse.MinWord
+ Math.NumberTheory.ArithmeticFunctions.Inverse: instance GHC.Show.Show Math.NumberTheory.ArithmeticFunctions.Inverse.MaxNatural
+ Math.NumberTheory.ArithmeticFunctions.Inverse: instance GHC.Show.Show Math.NumberTheory.ArithmeticFunctions.Inverse.MaxWord
+ Math.NumberTheory.ArithmeticFunctions.Inverse: instance GHC.Show.Show Math.NumberTheory.ArithmeticFunctions.Inverse.MinNatural
+ Math.NumberTheory.ArithmeticFunctions.Inverse: instance GHC.Show.Show Math.NumberTheory.ArithmeticFunctions.Inverse.MinWord
+ Math.NumberTheory.ArithmeticFunctions.Inverse: instance GHC.Show.Show a => GHC.Show.Show (Math.NumberTheory.ArithmeticFunctions.Inverse.PrimePowers a)
+ Math.NumberTheory.ArithmeticFunctions.Inverse: inverseSigma :: (Semiring b, Euclidean a, UniqueFactorisation a, Integral a) => (a -> b) -> a -> b
+ Math.NumberTheory.ArithmeticFunctions.Inverse: inverseTotient :: (Semiring b, Euclidean a, UniqueFactorisation a, Ord a) => (a -> b) -> a -> b
+ Math.NumberTheory.ArithmeticFunctions.Inverse: newtype MaxNatural
+ Math.NumberTheory.ArithmeticFunctions.Inverse: newtype MaxWord
+ Math.NumberTheory.ArithmeticFunctions.Inverse: newtype MinWord
+ Math.NumberTheory.ArithmeticFunctions.NFreedom: nFrees :: forall a. Integral a => Word -> [a]
+ Math.NumberTheory.ArithmeticFunctions.NFreedom: nFreesBlock :: forall a. Integral a => Word -> a -> Word -> [a]
+ Math.NumberTheory.ArithmeticFunctions.NFreedom: sieveBlockNFree :: forall a. Integral a => Word -> a -> Word -> Vector Bool
+ Math.NumberTheory.Moduli.Chinese: chinese :: forall a. Euclidean a => (a, a) -> (a, a) -> Maybe a
+ Math.NumberTheory.Moduli.Chinese: chineseCoprime :: Euclidean a => (a, a) -> (a, a) -> Maybe a
+ Math.NumberTheory.Moduli.Chinese: chineseCoprimeSomeMod :: SomeMod -> SomeMod -> Maybe SomeMod
+ Math.NumberTheory.Moduli.Chinese: chineseSomeMod :: SomeMod -> SomeMod -> Maybe SomeMod
+ Math.NumberTheory.Moduli.PrimitiveRoot: instance Control.DeepSeq.NFData a => Control.DeepSeq.NFData (Math.NumberTheory.Moduli.PrimitiveRoot.CyclicGroup a)
+ Math.NumberTheory.Moduli.PrimitiveRoot: instance GHC.Classes.Eq a => GHC.Classes.Eq (Math.NumberTheory.Moduli.PrimitiveRoot.CyclicGroup a)
+ Math.NumberTheory.Moduli.PrimitiveRoot: instance GHC.Show.Show a => GHC.Show.Show (Math.NumberTheory.Moduli.PrimitiveRoot.CyclicGroup a)
+ Math.NumberTheory.Prefactored: instance (Math.NumberTheory.Euclidean.Euclidean a, Math.NumberTheory.Primes.UniqueFactorisation a) => Math.NumberTheory.Primes.UniqueFactorisation (Math.NumberTheory.Prefactored.Prefactored a)
+ Math.NumberTheory.Prefactored: instance Math.NumberTheory.Euclidean.Euclidean a => GHC.Num.Num (Math.NumberTheory.Prefactored.Prefactored a)
+ Math.NumberTheory.Primes: class Num a => UniqueFactorisation a
+ Math.NumberTheory.Primes: data Prime a
+ Math.NumberTheory.Primes: factorise :: UniqueFactorisation a => a -> [(Prime a, Word)]
+ Math.NumberTheory.Primes: instance GHC.Enum.Enum (Math.NumberTheory.Primes.Types.Prime GHC.Integer.Type.Integer)
+ Math.NumberTheory.Primes: instance GHC.Enum.Enum (Math.NumberTheory.Primes.Types.Prime GHC.Natural.Natural)
+ Math.NumberTheory.Primes: instance GHC.Enum.Enum (Math.NumberTheory.Primes.Types.Prime GHC.Types.Int)
+ Math.NumberTheory.Primes: instance GHC.Enum.Enum (Math.NumberTheory.Primes.Types.Prime GHC.Types.Word)
+ Math.NumberTheory.Primes: instance Math.NumberTheory.Primes.UniqueFactorisation GHC.Integer.Type.Integer
+ Math.NumberTheory.Primes: instance Math.NumberTheory.Primes.UniqueFactorisation GHC.Natural.Natural
+ Math.NumberTheory.Primes: instance Math.NumberTheory.Primes.UniqueFactorisation GHC.Types.Int
+ Math.NumberTheory.Primes: instance Math.NumberTheory.Primes.UniqueFactorisation GHC.Types.Word
+ Math.NumberTheory.Primes: isPrime :: UniqueFactorisation a => a -> Maybe (Prime a)
+ Math.NumberTheory.Primes: nextPrime :: (Bits a, Integral a, UniqueFactorisation a) => a -> Prime a
+ Math.NumberTheory.Primes: precPrime :: (Bits a, Integral a, UniqueFactorisation a) => a -> Prime a
+ Math.NumberTheory.Primes: primes :: Integral a => [Prime a]
+ Math.NumberTheory.Primes: unPrime :: Prime a -> a
+ Math.NumberTheory.Quadratic.EisensteinIntegers: infix 6 :+
+ Math.NumberTheory.Quadratic.EisensteinIntegers: instance Control.DeepSeq.NFData Math.NumberTheory.Quadratic.EisensteinIntegers.EisensteinInteger
+ Math.NumberTheory.Quadratic.EisensteinIntegers: instance Math.NumberTheory.Primes.UniqueFactorisation Math.NumberTheory.Quadratic.EisensteinIntegers.EisensteinInteger
+ Math.NumberTheory.Quadratic.GaussianIntegers: infix 6 :+
+ Math.NumberTheory.Quadratic.GaussianIntegers: instance Math.NumberTheory.Primes.UniqueFactorisation Math.NumberTheory.Quadratic.GaussianIntegers.GaussianInteger
+ Math.NumberTheory.Recurrences: partition :: Num a => [a]
+ Math.NumberTheory.Recurrences.Bilinear: bernoulli :: Integral a => [Ratio a]
+ Math.NumberTheory.Recurrences.Bilinear: binomial :: Integral a => [[a]]
+ Math.NumberTheory.Recurrences.Bilinear: euler :: forall a. Integral a => [a]
+ Math.NumberTheory.Recurrences.Bilinear: eulerPolyAt1 :: forall a. Integral a => [Ratio a]
+ Math.NumberTheory.Recurrences.Bilinear: eulerian1 :: (Num a, Enum a) => [[a]]
+ Math.NumberTheory.Recurrences.Bilinear: eulerian2 :: (Num a, Enum a) => [[a]]
+ Math.NumberTheory.Recurrences.Bilinear: faulhaberPoly :: Integral a => Int -> [Ratio a]
+ Math.NumberTheory.Recurrences.Bilinear: lah :: Integral a => [[a]]
+ Math.NumberTheory.Recurrences.Bilinear: stirling1 :: (Num a, Enum a) => [[a]]
+ Math.NumberTheory.Recurrences.Bilinear: stirling2 :: (Num a, Enum a) => [[a]]
+ Math.NumberTheory.Recurrences.Linear: factorial :: (Num a, Enum a) => [a]
+ Math.NumberTheory.Recurrences.Linear: fibonacci :: Num a => Int -> a
+ Math.NumberTheory.Recurrences.Linear: fibonacciPair :: Num a => Int -> (a, a)
+ Math.NumberTheory.Recurrences.Linear: generalLucas :: Num a => a -> a -> Int -> (a, a, a, a)
+ Math.NumberTheory.Recurrences.Linear: lucas :: Num a => Int -> a
+ Math.NumberTheory.Recurrences.Linear: lucasPair :: Num a => Int -> (a, a)
+ Math.NumberTheory.SmoothNumbers: isSmooth :: forall a. Euclidean a => SmoothBasis a -> a -> Bool
+ Math.NumberTheory.SmoothNumbers: smoothOver' :: forall a b. (Eq a, Num a, Ord b) => (a -> b) -> SmoothBasis a -> [a]
+ Math.NumberTheory.Zeta.Hurwitz: zetaHurwitz :: forall a. (Floating a, Ord a) => a -> a -> [a]
- Math.NumberTheory.ArithmeticFunctions: carmichaelA :: forall n. (UniqueFactorisation n, Integral n) => ArithmeticFunction n n
+ Math.NumberTheory.ArithmeticFunctions: carmichaelA :: (UniqueFactorisation n, Integral n) => ArithmeticFunction n n
- Math.NumberTheory.ArithmeticFunctions: divisors :: (UniqueFactorisation n, Num n, Ord n) => n -> Set n
+ Math.NumberTheory.ArithmeticFunctions: divisors :: (UniqueFactorisation n, Ord n) => n -> Set n
- Math.NumberTheory.ArithmeticFunctions: divisorsA :: forall n. (UniqueFactorisation n, Num n, Ord n) => ArithmeticFunction n (Set n)
+ Math.NumberTheory.ArithmeticFunctions: divisorsA :: (UniqueFactorisation n, Ord n) => ArithmeticFunction n (Set n)
- Math.NumberTheory.ArithmeticFunctions: divisorsList :: (UniqueFactorisation n, Num n) => n -> [n]
+ Math.NumberTheory.ArithmeticFunctions: divisorsList :: UniqueFactorisation n => n -> [n]
- Math.NumberTheory.ArithmeticFunctions: divisorsListA :: forall n. (UniqueFactorisation n, Num n) => ArithmeticFunction n [n]
+ Math.NumberTheory.ArithmeticFunctions: divisorsListA :: UniqueFactorisation n => ArithmeticFunction n [n]
- Math.NumberTheory.ArithmeticFunctions: divisorsSmall :: (UniqueFactorisation n, Prime n ~ Prime Int) => n -> IntSet
+ Math.NumberTheory.ArithmeticFunctions: divisorsSmall :: Int -> IntSet
- Math.NumberTheory.ArithmeticFunctions: divisorsSmallA :: forall n. (Prime n ~ Prime Int) => ArithmeticFunction n IntSet
+ Math.NumberTheory.ArithmeticFunctions: divisorsSmallA :: ArithmeticFunction Int IntSet
- Math.NumberTheory.ArithmeticFunctions: expMangoldt :: (UniqueFactorisation n, Num n) => n -> n
+ Math.NumberTheory.ArithmeticFunctions: expMangoldt :: UniqueFactorisation n => n -> n
- Math.NumberTheory.ArithmeticFunctions: expMangoldtA :: forall n. (UniqueFactorisation n, Num n) => ArithmeticFunction n n
+ Math.NumberTheory.ArithmeticFunctions: expMangoldtA :: UniqueFactorisation n => ArithmeticFunction n n
- Math.NumberTheory.ArithmeticFunctions: jordan :: (UniqueFactorisation n, Num n) => Word -> n -> n
+ Math.NumberTheory.ArithmeticFunctions: jordan :: UniqueFactorisation n => Word -> n -> n
- Math.NumberTheory.ArithmeticFunctions: jordanA :: forall n. (UniqueFactorisation n, Num n) => Word -> ArithmeticFunction n n
+ Math.NumberTheory.ArithmeticFunctions: jordanA :: UniqueFactorisation n => Word -> ArithmeticFunction n n
- Math.NumberTheory.ArithmeticFunctions: sigmaA :: forall n. (UniqueFactorisation n, Integral n) => Word -> ArithmeticFunction n n
+ Math.NumberTheory.ArithmeticFunctions: sigmaA :: (UniqueFactorisation n, Integral n) => Word -> ArithmeticFunction n n
- Math.NumberTheory.ArithmeticFunctions: totient :: (UniqueFactorisation n, Num n) => n -> n
+ Math.NumberTheory.ArithmeticFunctions: totient :: UniqueFactorisation n => n -> n
- Math.NumberTheory.ArithmeticFunctions: totientA :: forall n. (UniqueFactorisation n, Num n) => ArithmeticFunction n n
+ Math.NumberTheory.ArithmeticFunctions: totientA :: UniqueFactorisation n => ArithmeticFunction n n
- Math.NumberTheory.ArithmeticFunctions.SieveBlock: SieveBlockConfig :: a -> Word -> Word -> a -> a -> a -> a -> SieveBlockConfig a
+ Math.NumberTheory.ArithmeticFunctions.SieveBlock: SieveBlockConfig :: a -> (Prime Word -> Word -> a) -> (a -> a -> a) -> SieveBlockConfig a
- Math.NumberTheory.ArithmeticFunctions.SieveBlock: [sbcFunctionOnPrimePower] :: SieveBlockConfig a -> Word -> Word -> a
+ Math.NumberTheory.ArithmeticFunctions.SieveBlock: [sbcFunctionOnPrimePower] :: SieveBlockConfig a -> Prime Word -> Word -> a
- Math.NumberTheory.ArithmeticFunctions.SieveBlock: additiveSieveBlockConfig :: Num a => (Word -> Word -> a) -> SieveBlockConfig a
+ Math.NumberTheory.ArithmeticFunctions.SieveBlock: additiveSieveBlockConfig :: Num a => (Prime Word -> Word -> a) -> SieveBlockConfig a
- Math.NumberTheory.ArithmeticFunctions.SieveBlock: multiplicativeSieveBlockConfig :: Num a => (Word -> Word -> a) -> SieveBlockConfig a
+ Math.NumberTheory.ArithmeticFunctions.SieveBlock: multiplicativeSieveBlockConfig :: Num a => (Prime Word -> Word -> a) -> SieveBlockConfig a
- Math.NumberTheory.Moduli.PrimitiveRoot: CGDoubleOddPrimePower :: (Prime a) -> Word -> CyclicGroup a
+ Math.NumberTheory.Moduli.PrimitiveRoot: CGDoubleOddPrimePower :: Prime a -> Word -> CyclicGroup a
- Math.NumberTheory.Moduli.PrimitiveRoot: CGOddPrimePower :: (Prime a) -> Word -> CyclicGroup a
+ Math.NumberTheory.Moduli.PrimitiveRoot: CGOddPrimePower :: Prime a -> Word -> CyclicGroup a
- Math.NumberTheory.Moduli.PrimitiveRoot: cyclicGroupToModulo :: (Euclidean a, Ord a, UniqueFactorisation a) => CyclicGroup a -> Prefactored a
+ Math.NumberTheory.Moduli.PrimitiveRoot: cyclicGroupToModulo :: Euclidean a => CyclicGroup a -> Prefactored a
- Math.NumberTheory.Moduli.PrimitiveRoot: groupSize :: (Euclidean a, Ord a, UniqueFactorisation a) => CyclicGroup a -> Prefactored a
+ Math.NumberTheory.Moduli.PrimitiveRoot: groupSize :: (Euclidean a, UniqueFactorisation a) => CyclicGroup a -> Prefactored a
- Math.NumberTheory.Powers: highestPower :: Integral a => a -> (a, Int)
+ Math.NumberTheory.Powers: highestPower :: Integral a => a -> (a, Word)
- Math.NumberTheory.Powers.General: highestPower :: Integral a => a -> (a, Int)
+ Math.NumberTheory.Powers.General: highestPower :: Integral a => a -> (a, Word)
- Math.NumberTheory.Powers.General: largePFPower :: Integer -> Integer -> (Integer, Int)
+ Math.NumberTheory.Powers.General: largePFPower :: Integer -> Integer -> (Integer, Word)
- Math.NumberTheory.Primes.Counting: nthPrime :: Integer -> Integer
+ Math.NumberTheory.Primes.Counting: nthPrime :: Integer -> Prime Integer
- Math.NumberTheory.Primes.Factorisation: curveFactorisation :: forall g. Maybe Integer -> (Integer -> Bool) -> (Integer -> g -> (Integer, g)) -> g -> Maybe Int -> Integer -> [(Integer, Int)]
+ Math.NumberTheory.Primes.Factorisation: curveFactorisation :: forall g. Maybe Integer -> (Integer -> Bool) -> (Integer -> g -> (Integer, g)) -> g -> Maybe Int -> Integer -> [(Integer, Word)]
- Math.NumberTheory.Primes.Factorisation: defaultStdGenFactorisation :: StdGen -> Integer -> [(Integer, Int)]
+ Math.NumberTheory.Primes.Factorisation: defaultStdGenFactorisation :: StdGen -> Integer -> [(Integer, Word)]
- Math.NumberTheory.Primes.Factorisation: defaultStdGenFactorisation' :: StdGen -> Integer -> [(Integer, Int)]
+ Math.NumberTheory.Primes.Factorisation: defaultStdGenFactorisation' :: StdGen -> Integer -> [(Integer, Word)]
- Math.NumberTheory.Primes.Factorisation: factorise :: Integer -> [(Integer, Int)]
+ Math.NumberTheory.Primes.Factorisation: factorise :: Integer -> [(Integer, Word)]
- Math.NumberTheory.Primes.Factorisation: factorise' :: Integer -> [(Integer, Int)]
+ Math.NumberTheory.Primes.Factorisation: factorise' :: Integer -> [(Integer, Word)]
- Math.NumberTheory.Primes.Factorisation: smallFactors :: Integer -> Integer -> ([(Integer, Int)], Maybe Integer)
+ Math.NumberTheory.Primes.Factorisation: smallFactors :: Integer -> Integer -> ([(Integer, Word)], Maybe Integer)
- Math.NumberTheory.Primes.Factorisation: stdGenFactorisation :: Maybe Integer -> StdGen -> Maybe Int -> Integer -> [(Integer, Int)]
+ Math.NumberTheory.Primes.Factorisation: stdGenFactorisation :: Maybe Integer -> StdGen -> Maybe Int -> Integer -> [(Integer, Word)]
- Math.NumberTheory.Primes.Factorisation: stepFactorisation :: Integer -> [(Integer, Int)]
+ Math.NumberTheory.Primes.Factorisation: stepFactorisation :: Integer -> [(Integer, Word)]
- Math.NumberTheory.Primes.Factorisation: trialDivisionTo :: Integer -> Integer -> [(Integer, Int)]
+ Math.NumberTheory.Primes.Factorisation: trialDivisionTo :: Integer -> Integer -> [(Integer, Word)]
- Math.NumberTheory.Primes.Factorisation.Certified: certificateFactorisation :: Integer -> [((Integer, Int), PrimalityProof)]
+ Math.NumberTheory.Primes.Factorisation.Certified: certificateFactorisation :: Integer -> [((Integer, Word), PrimalityProof)]
- Math.NumberTheory.Primes.Factorisation.Certified: certifiedFactorisation :: Integer -> [(Integer, Int)]
+ Math.NumberTheory.Primes.Factorisation.Certified: certifiedFactorisation :: Integer -> [(Integer, Word)]
- Math.NumberTheory.Primes.Factorisation.Certified: provenFactorisation :: Integer -> Integer -> [((Integer, Int), PrimalityProof)]
+ Math.NumberTheory.Primes.Factorisation.Certified: provenFactorisation :: Integer -> Integer -> [((Integer, Word), PrimalityProof)]
- Math.NumberTheory.Primes.Sieve: primeList :: forall a. Integral a => PrimeSieve -> [a]
+ Math.NumberTheory.Primes.Sieve: primeList :: forall a. Integral a => PrimeSieve -> [Prime a]
- Math.NumberTheory.Primes.Sieve: primes :: (Ord a, Num a) => [a]
+ Math.NumberTheory.Primes.Sieve: primes :: Integral a => [Prime a]
- Math.NumberTheory.Primes.Sieve: sieveFrom :: Integer -> [Integer]
+ Math.NumberTheory.Primes.Sieve: sieveFrom :: Integer -> [Prime Integer]
- Math.NumberTheory.Primes.Testing.Certificates: Pock :: Integer -> Integer -> [(Integer, Int, Integer, PrimalityArgument)] -> PrimalityArgument
+ Math.NumberTheory.Primes.Testing.Certificates: Pock :: Integer -> Integer -> [(Integer, Word, Integer, PrimalityArgument)] -> PrimalityArgument
- Math.NumberTheory.Primes.Testing.Certificates: [factorList] :: PrimalityArgument -> [(Integer, Int, Integer, PrimalityArgument)]
+ Math.NumberTheory.Primes.Testing.Certificates: [factorList] :: PrimalityArgument -> [(Integer, Word, Integer, PrimalityArgument)]
- Math.NumberTheory.Quadratic.EisensteinIntegers: findPrime :: Integer -> EisensteinInteger
+ Math.NumberTheory.Quadratic.EisensteinIntegers: findPrime :: Prime Integer -> Prime EisensteinInteger
- Math.NumberTheory.Quadratic.EisensteinIntegers: primes :: [EisensteinInteger]
+ Math.NumberTheory.Quadratic.EisensteinIntegers: primes :: [Prime EisensteinInteger]
- Math.NumberTheory.Quadratic.GaussianIntegers: findPrime :: Integer -> GaussianInteger
+ Math.NumberTheory.Quadratic.GaussianIntegers: findPrime :: Prime Integer -> Prime GaussianInteger
- Math.NumberTheory.Quadratic.GaussianIntegers: primes :: [GaussianInteger]
+ Math.NumberTheory.Quadratic.GaussianIntegers: primes :: [Prime GaussianInteger]
- Math.NumberTheory.SmoothNumbers: smoothOverInRangeBF :: forall a. Integral a => SmoothBasis a -> a -> a -> [a]
+ Math.NumberTheory.SmoothNumbers: smoothOverInRangeBF :: forall a. (Enum a, Euclidean a) => SmoothBasis a -> a -> a -> [a]

Files

Changes view
@@ -1,3 +1,60 @@+0.9.0.0+    This release supports GHC 8.0, 8.2, 8.4 and 8.6.++    Breaking changes:++        Remove 'Prime' type family and introduce 'Prime' newtype. This newtype+        is now used extensively in public API:++        primes :: Integral a => [Prime a]+        primeList :: Integral a => PrimeSieve -> [Prime a]+        sieveFrom :: Integer -> [Prime Integer]+        nthPrime :: Integer -> Prime Integer++        'sbcFunctionOnPrimePower' now accepts 'Prime Word' instead of 'Word'.++        'Math.NumberTheory.Primes.{Factorisation,Testing,Counting,Sieve}'+        are no longer re-exported from 'Math.NumberTheory.Primes'.+        Merge 'Math.NumberTheory.UniqueFactorisation' into+        'Math.NumberTheory.Primes' (#135, #153).++        From now on 'Math.NumberTheory.Primes.Factorisation.factorise'+        and similar functions return [(Integer, Word)] instead of [(Integer, Int)].++        Remove deprecated 'Math.NumberTheory.GCD' and 'Math.NumberTheory.GCD.LowLevel'.++        Deprecate 'Math.NumberTheory.Recurrencies.*'.+        Use 'Math.NumberTheory.Recurrences.*' instead (#146).++    New features:++        New functions 'nextPrime' and 'precPrime'. Implement an instance of 'Enum' for primes (#153):++        > [nextPrime 101 .. precPrime 130]+        [Prime 101,Prime 103,Prime 107,Prime 109,Prime 113,Prime 127]++        Support Gaussian and Eisenstein integers in smooth numbers (#138).++        Add the Hurwitz zeta function on non-negative integer arguments (#126).++        Implement efficient tests of n-freeness: pointwise and in interval. See 'isNFree' and 'nFreesBlock' (#145).++        Generate preimages of the totient and the sum-of-divisors functions (#142):++        > inverseTotient 120 :: [Integer]+        [155,310,183,366,225,450,175,350,231,462,143,286,244,372,396,308,248]++        Generate coefficients of Faulhaber polynomials 'faulhaberPoly' (#70).++    Improvements:++        Better precision for exact values of Riemann zeta and Dirichlet beta+        functions (#123).++        Speed up certain cases of modular multiplication (#160).++        Extend Chinese theorem to non-coprime moduli (#71).+ 0.8.0.0     This release supports GHC 7.10, 8.0, 8.2, 8.4 and 8.6. 
GHC/TypeNats/Compat.hs view
@@ -14,15 +14,12 @@ #else  module GHC.TypeNats.Compat-  ( Nat-  , KnownNat-  , SomeNat(..)+  ( module GHC.TypeLits   , natVal   , someNatVal-  , sameNat   ) where -import GHC.TypeLits (Nat, KnownNat, SomeNat(..), sameNat)+import GHC.TypeLits hiding (natVal, someNatVal) import qualified GHC.TypeLits as TL import Numeric.Natural 
Math/NumberTheory/ArithmeticFunctions.hs view
@@ -3,8 +3,6 @@ -- Copyright:   (c) 2016 Andrew Lelechenko -- Licence:     MIT -- Maintainer:  Andrew Lelechenko <andrew.lelechenko@gmail.com>--- Stability:   Provisional--- Portability: Non-portable (GHC extensions) -- -- This module provides an interface for defining and manipulating -- arithmetic functions. It also defines several most widespreaded
Math/NumberTheory/ArithmeticFunctions/Class.hs view
@@ -3,8 +3,6 @@ -- Copyright:   (c) 2016 Andrew Lelechenko -- Licence:     MIT -- Maintainer:  Andrew Lelechenko <andrew.lelechenko@gmail.com>--- Stability:   Provisional--- Portability: Non-portable (GHC extensions) -- -- Generic type for arithmetic functions over arbitrary unique -- factorisation domains.@@ -18,6 +16,7 @@ module Math.NumberTheory.ArithmeticFunctions.Class   ( ArithmeticFunction(..)   , runFunction+  , runFunctionOnFactors   ) where  import Control.Applicative@@ -25,7 +24,7 @@ import Data.Semigroup #endif -import Math.NumberTheory.UniqueFactorisation+import Math.NumberTheory.Primes  -- | A typical arithmetic function operates on the canonical factorisation of -- a number into prime's powers and consists of two rules. The first one@@ -34,8 +33,8 @@ -- -- In the following definition the first argument is the function on prime's -- powers, the monoid instance determines a rule of combination (typically--- 'Product' or 'Sum'), and the second argument is convenient for unwrapping--- (typically, 'getProduct' or 'getSum').+-- 'Data.Semigroup.Product' or 'Data.Semigroup.Sum'), and the second argument is convenient for unwrapping+-- (typically, 'Data.Semigroup.getProduct' or 'Data.Semigroup.getSum'). data ArithmeticFunction n a where   ArithmeticFunction     :: Monoid m@@ -43,13 +42,16 @@     -> (m -> a)     -> ArithmeticFunction n a --- | Convert to function. The value on 0 is undefined.+-- | Convert to a function. The value on 0 is undefined. runFunction :: UniqueFactorisation n => ArithmeticFunction n a -> n -> a-runFunction (ArithmeticFunction f g)+runFunction f = runFunctionOnFactors f . factorise++-- | Convert to a function on prime factorisation.+runFunctionOnFactors :: ArithmeticFunction n a -> [(Prime n, Word)] -> a+runFunctionOnFactors (ArithmeticFunction f g)   = g   . mconcat   . map (uncurry f)-  . factorise  instance Functor (ArithmeticFunction n) where   fmap f (ArithmeticFunction g h) = ArithmeticFunction g (f . h)
+ Math/NumberTheory/ArithmeticFunctions/Inverse.hs view
@@ -0,0 +1,370 @@+-- |+-- Module:      Math.NumberTheory.ArithmeticFunctions.Inverse+-- Copyright:   (c) 2018 Andrew Lelechenko+-- Licence:     MIT+-- Maintainer:  Andrew Lelechenko <andrew.lelechenko@gmail.com>+--+-- Computing inverses of multiplicative functions.+-- The implementation is based on+-- <https://www.emis.de/journals/JIS/VOL19/Alekseyev/alek5.pdf Computing the Inverses, their Power Sums, and Extrema for Euler’s Totient and Other Multiplicative Functions>+-- by M. A. Alekseyev.++{-# LANGUAGE RankNTypes          #-}+{-# LANGUAGE ScopedTypeVariables #-}++module Math.NumberTheory.ArithmeticFunctions.Inverse+  ( inverseTotient+  , inverseSigma+  , -- * Wrappers+    MinWord(..)+  , MaxWord(..)+  , MinNatural(..)+  , MaxNatural(..)+  , -- * Utils+    asSetOfPreimages+  ) where++import Prelude hiding (rem, quot)+import Data.List+import Data.Map (Map)+import qualified Data.Map as M+import Data.Maybe+import Data.Ord (Down(..))+import Data.Semigroup+import Data.Semiring (Semiring(..))+import Data.Set (Set)+import qualified Data.Set as S+import Numeric.Natural++import Math.NumberTheory.ArithmeticFunctions+import Math.NumberTheory.Euclidean+import Math.NumberTheory.Logarithms+import Math.NumberTheory.Powers+import Math.NumberTheory.Primes+import Math.NumberTheory.Primes.Sieve (primes)+import Math.NumberTheory.Utils.DirichletSeries (DirichletSeries)+import qualified Math.NumberTheory.Utils.DirichletSeries as DS+import Math.NumberTheory.Utils.FromIntegral++data PrimePowers a = PrimePowers+  { _ppPrime  :: Prime a+  , _ppPowers :: [Word] -- sorted list+  }++instance Show a => Show (PrimePowers a) where+  show (PrimePowers p xs) = "PP " ++ show (unPrime p) ++ " " ++ show xs++-- | Convert a list of powers of a prime into an atomic Dirichlet series+-- (Section 4, Step 2).+atomicSeries+  :: Num a+  => (a -> b)               -- ^ How to inject a number into a semiring+  -> ArithmeticFunction a c -- ^ Arithmetic function, which we aim to inverse+  -> PrimePowers a          -- ^ List of powers of a prime+  -> DirichletSeries c b    -- ^ Atomic Dirichlet series+atomicSeries point (ArithmeticFunction f g) (PrimePowers p ks) =+  DS.fromDistinctAscList (map (\k -> (g (f p k), point (unPrime p ^ k))) ks)++-- | See section 5.1 of the paper.+invTotient+  :: forall a. (UniqueFactorisation a, Eq a)+  => [(Prime a, Word)]+  -- ^ Factorisation of a value of the totient function+  -> [PrimePowers a]+  -- ^ Possible prime factors of an argument of the totient function+invTotient fs = map (\p -> PrimePowers p (doPrime p)) ps+  where+    divs :: [a]+    divs = runFunctionOnFactors divisorsListA fs++    ps :: [Prime a]+    ps = mapMaybe (isPrime . (+ 1)) divs++    doPrime :: Prime a -> [Word]+    doPrime p = case lookup p fs of+      Nothing -> [1]+      Just k  -> [1 .. k+1]++-- | See section 5.2 of the paper.+invSigma+  :: forall a. (Euclidean a, Integral a, UniqueFactorisation a)+  => [(Prime a, Word)]+  -- ^ Factorisation of a value of the sum-of-divisors function+  -> [PrimePowers a]+  -- ^ Possible prime factors of an argument of the sum-of-divisors function+invSigma fs+  = map (\(x, ys) -> PrimePowers x (S.toList ys))+  $ M.assocs+  $ M.unionWith (<>) pksSmall pksLarge+  where+    numDivs :: a+    numDivs = runFunctionOnFactors tauA fs++    divs :: [a]+    divs = runFunctionOnFactors divisorsListA fs++    n :: a+    n = product $ map (\(p, k) -> unPrime p ^ k) fs++    -- There are two possible strategies to find possible prime factors+    -- of an argument of the sum-of-divisors function.+    -- 1. Take each prime p and each power e such that p^e <= n,+    -- compute sigma(p^e) and check whether it is a divisor of n.+    -- (corresponds to 'pksSmall' below)+    -- 2. Take each divisor d of n and each power e such that e <= log_2 d,+    -- compute p = floor(e-th root of (d - 1)) and check whether sigma(p^e) = d+    -- and p is actually prime (correposnds to 'pksLarge' below).+    --+    -- Asymptotically the second strategy is beneficial, but computing+    -- exact e-th roots of huge integers (especially when they exceed MAX_DOUBLE)+    -- is very costly. That is why we employ the first strategy for primes+    -- below limit 'lim' and the second one for larger ones. This allows us+    -- to loop over e <= log_lim d which is much smaller than log_2 d.+    --+    -- The value of 'lim' below was chosen heuristically;+    -- it may be tuned in future in accordance with new experimental data.+    lim :: a+    lim = numDivs `max` 2++    pksSmall :: Map (Prime a) (Set Word)+    pksSmall = M.fromDistinctAscList+      [ (p, pows)+      | p <- takeWhile ((< lim) . unPrime) primes+      , let pows = doPrime p+      , not (null pows)+      ]++    doPrime :: Prime a -> Set Word+    doPrime p' = let p = unPrime p' in S.fromDistinctAscList+      [ e+      | e <- [1 .. intToWord (integerLogBase (toInteger p) (toInteger n))]+      , n `rem` ((p ^ (e + 1) - 1) `quot` (p - 1)) == 0+      ]++    pksLarge :: Map (Prime a) (Set Word)+    pksLarge = M.unionsWith (<>)+      [ maybe mempty (flip M.singleton (S.singleton e)) (isPrime p)+      | d <- divs+      , e <- [1 .. intToWord (integerLogBase (toInteger lim) (toInteger d))]+      , let p = integerRoot e (d - 1)+      , p ^ (e + 1) - 1 == d * (p - 1)+      ]++-- | Instead of multiplying all atomic series and filtering out everything,+-- which is not divisible by @n@, we'd rather split all atomic series into+-- a couple of batches, each of which corresponds to a prime factor of @n@.+-- This allows us to crop resulting Dirichlet series (see 'filter' calls+-- in 'invertFunction' below) at the end of each batch, saving time and memory.+strategy+  :: forall a c. (Euclidean c, Ord c)+  => ArithmeticFunction a c+  -- ^ Arithmetic function, which we aim to inverse+  -> [(Prime c, Word)]+  -- ^ Factorisation of a value of the arithmetic function+  -> [PrimePowers a]+  -- ^ Possible prime factors of an argument of the arithmetic function+  -> [(Maybe (Prime c, Word), [PrimePowers a])]+  -- ^ Batches, corresponding to each element of the factorisation of a value+strategy (ArithmeticFunction f g) factors args = (Nothing, ret) : rets+  where+    (ret, rets)+      = mapAccumL go args+      $ sortOn (Down . fst) factors++    go+      :: [PrimePowers a]+      -> (Prime c, Word)+      -> ([PrimePowers a], (Maybe (Prime c, Word), [PrimePowers a]))+    go ts (p, k) = (rs, (Just (p, k), qs))+      where+        predicate (PrimePowers q ls) = any (\l -> g (f q l) `rem` unPrime p == 0) ls+        (qs, rs) = partition predicate ts++-- | Main workhorse.+invertFunction+  :: forall a b c.+     (Num a, Semiring b, Euclidean c, UniqueFactorisation c, Ord c)+  => (a -> b)+  -- ^ How to inject a number into a semiring+  -> ArithmeticFunction a c+  -- ^ Arithmetic function, which we aim to inverse+  -> ([(Prime c, Word)] -> [PrimePowers a])+  -- ^ How to find possible prime factors of the argument+  -> c+  -- ^ Value of the arithmetic function, which we aim to inverse+  -> b+  -- ^ Semiring element, representing preimages+invertFunction point f invF n+  = DS.lookup n+  $ foldl' (\ds b -> uncurry processBatch b ds) (DS.fromDistinctAscList []) batches+  where+    factors = factorise n+    batches = strategy f factors $ invF factors++    processBatch+      :: Maybe (Prime c, Word)+      -> [PrimePowers a]+      -> DirichletSeries c b+      -> DirichletSeries c b+    processBatch Nothing xs acc+      = foldl' (DS.timesAndCrop n) acc+      $ map (atomicSeries point f) xs++    -- This is equivalent to the next, general case, but is faster,+    -- since it avoids construction of many intermediate series.+    processBatch (Just (p, 1)) xs acc+      = DS.filter (\a -> a `rem` unPrime p == 0)+      $ foldl' (DS.timesAndCrop n) acc'+      $ map (atomicSeries point f) xs2+      where+        (xs1, xs2) = partition (\(PrimePowers _ ts) -> length ts == 1) xs+        vs = DS.unions $ map (atomicSeries point f) xs1+        (ys, zs) = DS.partition (\a -> a `rem` unPrime p == 0) acc+        acc' = ys `DS.union` DS.timesAndCrop n zs vs++    processBatch (Just pk) xs acc+      = (\(p, k) -> DS.filter (\a -> a `rem` (unPrime p ^ k) == 0)) pk+      $ foldl' (DS.timesAndCrop n) acc+      $ map (atomicSeries point f) xs++{-# SPECIALISE invertFunction :: Semiring b => (Int -> b) -> ArithmeticFunction Int Int -> ([(Prime Int, Word)] -> [PrimePowers Int]) -> Int -> b #-}+{-# SPECIALISE invertFunction :: Semiring b => (Word -> b) -> ArithmeticFunction Word Word -> ([(Prime Word, Word)] -> [PrimePowers Word]) -> Word -> b #-}+{-# SPECIALISE invertFunction :: Semiring b => (Integer -> b) -> ArithmeticFunction Integer Integer -> ([(Prime Integer, Word)] -> [PrimePowers Integer]) -> Integer -> b #-}+{-# SPECIALISE invertFunction :: Semiring b => (Natural -> b) -> ArithmeticFunction Natural Natural -> ([(Prime Natural, Word)] -> [PrimePowers Natural]) -> Natural -> b #-}++-- | The inverse for 'totient' function.+--+-- The return value is parameterized by a 'Semiring', which allows+-- various applications by providing different (multiplicative) embeddings.+-- E. g., list all preimages (see a helper 'asSetOfPreimages'):+--+-- >>> import qualified Data.Set as S+-- >>> import Data.Semigroup+-- >>> S.mapMonotonic getProduct (inverseTotient (S.singleton . Product) 120)+-- fromList [143,155,175,183,225,231,244,248,286,308,310,350,366,372,396,450,462]+--+-- Count preimages:+--+-- >>> inverseTotient (const 1) 120+-- 17+--+-- Sum preimages:+--+-- >>> inverseTotient id 120+-- 4904+--+-- Find minimal and maximal preimages:+--+-- >>> unMinWord (inverseTotient MinWord 120)+-- 143+-- >>> unMaxWord (inverseTotient MaxWord 120)+-- 462+inverseTotient+  :: (Semiring b, Euclidean a, UniqueFactorisation a, Ord a)+  => (a -> b)+  -> a+  -> b+inverseTotient point = invertFunction point totientA invTotient+{-# SPECIALISE inverseTotient :: Semiring b => (Int -> b) -> Int -> b #-}+{-# SPECIALISE inverseTotient :: Semiring b => (Word -> b) -> Word -> b #-}+{-# SPECIALISE inverseTotient :: Semiring b => (Integer -> b) -> Integer -> b #-}+{-# SPECIALISE inverseTotient :: Semiring b => (Natural -> b) -> Natural -> b #-}++-- | The inverse for 'sigma' 1 function.+--+-- The return value is parameterized by a 'Semiring', which allows+-- various applications by providing different (multiplicative) embeddings.+-- E. g., list all preimages (see a helper 'asSetOfPreimages'):+--+-- >>> import qualified Data.Set as S+-- >>> import Data.Semigroup+-- >>> S.mapMonotonic getProduct (inverseSigma (S.singleton . Product) 120)+-- fromList [54,56,87,95]+--+-- Count preimages:+--+-- >>> inverseSigma (const 1) 120+-- 4+--+-- Sum preimages:+--+-- >>> inverseSigma id 120+-- 292+--+-- Find minimal and maximal preimages:+--+-- >>> unMinWord (inverseSigma MinWord 120)+-- 54+-- >>> unMaxWord (inverseSigma MaxWord 120)+-- 95+inverseSigma+  :: (Semiring b, Euclidean a, UniqueFactorisation a, Integral a)+  => (a -> b)+  -> a+  -> b+inverseSigma point = invertFunction point (sigmaA 1) invSigma+{-# SPECIALISE inverseSigma :: Semiring b => (Int -> b) -> Int -> b #-}+{-# SPECIALISE inverseSigma :: Semiring b => (Word -> b) -> Word -> b #-}+{-# SPECIALISE inverseSigma :: Semiring b => (Integer -> b) -> Integer -> b #-}+{-# SPECIALISE inverseSigma :: Semiring b => (Natural -> b) -> Natural -> b #-}++--------------------------------------------------------------------------------+-- Wrappers++-- | Wrapper to use in conjunction with 'inverseTotient' and 'inverseSigma'.+-- Extracts the maximal preimage of function.+newtype MaxWord = MaxWord { unMaxWord :: Word }+  deriving (Eq, Ord, Show)++instance Semiring MaxWord where+  zero = MaxWord minBound+  one  = MaxWord 1+  plus  (MaxWord a) (MaxWord b) = MaxWord (a `max` b)+  times (MaxWord a) (MaxWord b) = MaxWord (a * b)++-- | Wrapper to use in conjunction with 'inverseTotient' and 'inverseSigma'.+-- Extracts the minimal preimage of function.+newtype MinWord = MinWord { unMinWord :: Word }+  deriving (Eq, Ord, Show)++instance Semiring MinWord where+  zero = MinWord maxBound+  one  = MinWord 1+  plus  (MinWord a) (MinWord b) = MinWord (a `min` b)+  times (MinWord a) (MinWord b) = MinWord (a * b)++-- | Wrapper to use in conjunction with 'inverseTotient' and 'inverseSigma'.+-- Extracts the maximal preimage of function.+newtype MaxNatural = MaxNatural { unMaxNatural :: Natural }+  deriving (Eq, Ord, Show)++instance Semiring MaxNatural where+  zero = MaxNatural 0+  one  = MaxNatural 1+  plus  (MaxNatural a) (MaxNatural b) = MaxNatural (a `max` b)+  times (MaxNatural a) (MaxNatural b) = MaxNatural (a * b)++-- | Wrapper to use in conjunction with 'inverseTotient' and 'inverseSigma'.+-- Extracts the minimal preimage of function.+data MinNatural+  = MinNatural { unMinNatural :: !Natural }+  | Infinity+  deriving (Eq, Ord, Show)++instance Semiring MinNatural where+  zero = Infinity+  one  = MinNatural 1++  plus a b = a `min` b++  times Infinity _ = Infinity+  times _ Infinity = Infinity+  times (MinNatural a) (MinNatural b) = MinNatural (a * b)++-- | Helper to extract a set of preimages for 'inverseTotient' or 'inverseSigma'.+asSetOfPreimages+  :: (Euclidean a, Integral a)+  => (forall b. Semiring b => (a -> b) -> a -> b)+  -> a+  -> S.Set a+asSetOfPreimages f = S.mapMonotonic getProduct . f (S.singleton . Product)
Math/NumberTheory/ArithmeticFunctions/Mertens.hs view
@@ -3,8 +3,6 @@ -- Copyright:   (c) 2018 Andrew Lelechenko -- Licence:     MIT -- Maintainer:  Andrew Lelechenko <andrew.lelechenko@gmail.com>--- Stability:   Provisional--- Portability: Non-portable (GHC extensions) -- -- Values of <https://en.wikipedia.org/wiki/Mertens_function Mertens function>. --
Math/NumberTheory/ArithmeticFunctions/Moebius.hs view
@@ -3,8 +3,6 @@ -- Copyright:   (c) 2018 Andrew Lelechenko -- Licence:     MIT -- Maintainer:  Andrew Lelechenko <andrew.lelechenko@gmail.com>--- Stability:   Provisional--- Portability: Non-portable (GHC extensions) -- -- Values of <https://en.wikipedia.org/wiki/Möbius_function Möbius function>. --@@ -38,15 +36,16 @@ import GHC.Integer.GMP.Internals import Unsafe.Coerce -import Math.NumberTheory.Primes (primes) import Math.NumberTheory.Powers.Squares (integerSquareRoot)+import Math.NumberTheory.Primes (unPrime)+import Math.NumberTheory.Primes.Sieve (primes) import Math.NumberTheory.Utils.FromIntegral (wordToInt)  import Math.NumberTheory.Logarithms  -- | Represents three possible values of <https://en.wikipedia.org/wiki/Möbius_function Möbius function>. data Moebius-  = MoebiusN -- ^ −1+  = MoebiusN -- ^ -1   | MoebiusZ -- ^  0   | MoebiusP -- ^  1   deriving (Eq, Ord, Show)@@ -127,7 +126,7 @@ -- 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]+-- [MoebiusP,MoebiusN,MoebiusN,MoebiusZ,MoebiusN,MoebiusP,MoebiusN,MoebiusZ,MoebiusZ,MoebiusP] sieveBlockMoebius   :: Word   -> Word@@ -162,7 +161,7 @@     -- Bit fiddling in 'mapper' is correct only     -- if all sufficiently small (<= 191) primes has been sieved out.     ps :: [Int]-    ps = takeWhile (<= (191 `max` integerSquareRoot highIndex)) $ map fromInteger primes+    ps = takeWhile (<= (191 `max` integerSquareRoot highIndex)) $ map unPrime primes      mapper :: Int -> Word8 -> Word8     mapper ix val
+ Math/NumberTheory/ArithmeticFunctions/NFreedom.hs view
@@ -0,0 +1,160 @@+-- |+-- Module:      Math.NumberTheory.ArithmeticFunctions.NFreedom+-- Copyright:   (c) 2018 Alexandre Rodrigues Baldé+-- Licence:     MIT+-- Maintainer:  Alexandre Rodrigues Baldé <alexandrer_b@outlook.com>+--+-- N-free number generation.+--++{-# LANGUAGE ScopedTypeVariables #-}++module Math.NumberTheory.ArithmeticFunctions.NFreedom+  ( nFrees+  , nFreesBlock+  , sieveBlockNFree+  ) where++import Control.Monad                         (forM_)+import Control.Monad.ST                      (runST)+import Data.List                             (scanl')+import qualified Data.Vector.Unboxed         as U+import qualified Data.Vector.Unboxed.Mutable as MU++import Math.NumberTheory.Powers.Squares      (integerSquareRoot)+import Math.NumberTheory.Primes              (unPrime)+import Math.NumberTheory.Primes.Sieve        (primes)+import Math.NumberTheory.Utils.FromIntegral  (wordToInt)++-- | Evaluate the `Math.NumberTheory.ArithmeticFunctions.isNFree` function over a block.+-- Value at @0@, if zero falls into block, is undefined.+--+-- This function should __**not**__ be used with a negative lower bound.+-- If it is, the result is undefined.+-- Furthermore, do not:+--+-- * use a block length greater than @maxBound :: Int@.+-- * use a power that is either of @0, 1@.+--+-- None of these preconditions are checked, and if any occurs, the result is+-- undefined, __if__ the function terminates.+--+-- >>> sieveBlockNFree 2 1 10+-- [True,True,True,False,True,True,True,False,False,True]+sieveBlockNFree+  :: forall a . Integral a+  => Word+  -- ^ Power whose @n@-freedom will be checked.+  -> a+  -- ^ Lower index of the block.+  -> Word+  -- ^ Length of the block.+  -> U.Vector Bool+  -- ^ Vector of flags, where @True@ at index @i@ means the @i@-th element of+  -- the block is @n@-free.+sieveBlockNFree _ _ 0 = U.empty+sieveBlockNFree n lowIndex len'+  = runST $ do+    as <- MU.replicate (wordToInt len') True+    forM_ ps $ \p -> do+      let pPow :: a+          pPow = p ^ n+          offset :: a+          offset = negate lowIndex `mod` pPow+          -- The second argument in @Data.Vector.Unboxed.Mutable.write@ is an+          -- @Int@, so to avoid segmentation faults or out-of-bounds errors,+          -- the enumeration's higher bound must always be less than+          -- @maxBound :: Int@.+          -- As mentioned above, this is not checked when using this function+          -- by itself, but is carefully managed when this function is called+          -- by @nFrees@, see the comments in it.+          indices :: [a]+          indices = [offset, offset + pPow .. len - 1]+      forM_ indices $ \ix -> do+          MU.write as (fromIntegral ix) False+    U.freeze as++  where+    len :: a+    len = fromIntegral len'++    highIndex :: a+    highIndex = lowIndex + len - 1++    ps :: [a]+    ps = takeWhile (<= integerSquareRoot highIndex) $ map unPrime primes++-- | For a given nonnegative integer power @n@, generate all @n@-free+-- numbers in ascending order, starting at @1@.+--+-- When @n@ is @0@ or @1@, the resulting list is @[1]@.+nFrees+    :: forall a. Integral a+    => Word+    -- ^ Power @n@ to be used to generate @n@-free numbers.+    -> [a]+    -- ^ Generated infinite list of @n@-free numbers.+nFrees 0 = [1]+nFrees 1 = [1]+nFrees n = concatMap (\(lo, len) -> nFreesBlock n lo len) $ zip bounds strides+  where+    -- The 56th element of @iterate (2 *) 256@ is @2^64 :: Word == 0@, so to+    -- avoid overflow only the first 55 elements of this list are used.+    -- After those, since @maxBound :: Int@ is the largest a vector can be,+    -- this value is just repeated. This means after a few dozen iterations,+    -- the sieve will stop increasing in size.+    strides :: [Word]+    strides = take 55 (iterate (2 *) 256) ++ repeat (fromIntegral (maxBound :: Int))++    -- Infinite list of lower bounds at which @sieveBlockNFree@ will be+    -- applied. This has type @Integral a => a@ instead of @Word@ because+    -- unlike the sizes of the sieve that eventually stop increasing (see+    -- above comment), the lower bound at which @sieveBlockNFree@ is called does not.+    bounds :: [a]+    bounds = scanl' (+) 1 $ map fromIntegral strides++-- | Generate @n@-free numbers in a block starting at a certain value.+-- The length of the list is determined by the value passed in as the third+-- argument. It will be lesser than or equal to this value.+--+-- This function should not be used with a negative lower bound. If it is,+-- the result is undefined.+--+-- The block length cannot exceed @maxBound :: Int@, this precondition is not+-- checked.+--+-- As with @nFrees@, passing @n = 0, 1@ results in an empty list.+nFreesBlock+    :: forall a . Integral a+    => Word+    -- ^ Power @n@ to be used to generate @n@-free numbers.+    -> a+    -- ^ Starting number in the block.+    -> Word+    -- ^ Maximum length of the block to be generated.+    -> [a]+    -- ^ Generated list of @n@-free numbers.+nFreesBlock 0 lo _ = help lo+nFreesBlock 1 lo _ = help lo+nFreesBlock n lowIndex len =+    let -- When indexing the array of flags @bs@, the index has to be an+        -- @Int@. As such, it's necessary to cast @strd@ twice.+        -- * Once, immediately below, to create the range of values whose+        -- @n@-freedom will be tested. Since @nFrees@ has return type+        -- @[a]@, this cannot be avoided as @strides@ has type @[Word]@.+        len' :: Int+        len' = wordToInt len+        -- * Twice, immediately below, to create the range of indices with+        -- which to query @bs@.+        len'' :: a+        len'' = fromIntegral len+        bs  = sieveBlockNFree n lowIndex len+    in map snd .+       filter ((bs U.!) . fst) .+       zip [0 .. len' - 1] $ [lowIndex .. lowIndex + len'']+{-# INLINE nFreesBlock #-}++help :: Integral a => a -> [a]+help 1 = [1]+help _ = []+{-# INLINE help #-}
Math/NumberTheory/ArithmeticFunctions/SieveBlock.hs view
@@ -3,8 +3,6 @@ -- Copyright:   (c) 2017 Andrew Lelechenko -- Licence:     MIT -- Maintainer:  Andrew Lelechenko <andrew.lelechenko@gmail.com>--- Stability:   Provisional--- Portability: Non-portable (GHC extensions) -- -- Bulk evaluation of arithmetic functions over continuous intervals -- without factorisation.@@ -37,7 +35,7 @@ import Math.NumberTheory.ArithmeticFunctions.Moebius (sieveBlockMoebius) import Math.NumberTheory.ArithmeticFunctions.SieveBlock.Unboxed import Math.NumberTheory.Logarithms (integerLogBase')-import Math.NumberTheory.Primes (primes)+import Math.NumberTheory.Primes.Sieve (primes) import Math.NumberTheory.Primes.Types import Math.NumberTheory.Powers.Squares (integerSquareRoot) import Math.NumberTheory.Utils (splitOff#)@@ -55,6 +53,7 @@ -- -- This is a thin wrapper over 'sieveBlock', read more details there. --+-- >>> import Math.NumberTheory.ArithmeticFunctions -- >>> runFunctionOverBlock carmichaelA 1 10 -- [1,1,2,2,4,2,6,2,6,4] runFunctionOverBlock@@ -79,12 +78,12 @@ -- -- For example, following code lists smallest prime factors: ----- >>> sieveBlock (SieveBlockConfig maxBound (\p _ -> p) min) 2 10+-- >>> sieveBlock (SieveBlockConfig maxBound (\p _ -> unPrime 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+-- >>> sieveBlock (SieveBlockConfig [] (\p k -> [(unPrime 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@@ -107,7 +106,7 @@         highIndex = lowIndex + len - 1          ps :: [Int]-        ps = takeWhile (<= integerSquareRoot highIndex) $ map fromInteger primes+        ps = takeWhile (<= integerSquareRoot highIndex) $ map unPrime primes      forM_ ps $ \p -> do @@ -116,7 +115,7 @@            fs = V.generate             (integerLogBase' (toInteger p) (toInteger highIndex))-            (\k -> f p' (intToWord k + 1))+            (\k -> f (Prime p') (intToWord k + 1))            offset :: Int           offset = negate lowIndex `mod` p@@ -125,10 +124,10 @@         W# a# <- MV.unsafeRead as ix         let !(# pow#, a'# #) = splitOff# p# (a# `quotWord#` p#)         MV.unsafeWrite as ix (W# a'#)-        MV.unsafeModify bs (\y -> y `append` V.unsafeIndex fs (I# pow#)) ix+        MV.unsafeModify bs (\y -> y `append` V.unsafeIndex fs (I# (word2Int# pow#))) ix      forM_ [0 .. len - 1] $ \k -> do       a <- MV.unsafeRead as k-      MV.unsafeModify bs (\b -> if a /= 1 then b `append` f a 1 else b) k+      MV.unsafeModify bs (\b -> if a /= 1 then b `append` f (Prime a) 1 else b) k      V.unsafeFreeze bs
Math/NumberTheory/ArithmeticFunctions/SieveBlock/Unboxed.hs view
@@ -3,8 +3,6 @@ -- Copyright:   (c) 2017 Andrew Lelechenko -- Licence:     MIT -- Maintainer:  Andrew Lelechenko <andrew.lelechenko@gmail.com>--- Stability:   Provisional--- Portability: Non-portable (GHC extensions) -- -- Bulk evaluation of arithmetic functions without factorisation -- of arguments.@@ -30,7 +28,8 @@  import Math.NumberTheory.ArithmeticFunctions.Moebius (Moebius) import Math.NumberTheory.Logarithms (integerLogBase')-import Math.NumberTheory.Primes (primes)+import Math.NumberTheory.Primes.Sieve (primes)+import Math.NumberTheory.Primes.Types (Prime(..)) import Math.NumberTheory.Powers.Squares (integerSquareRoot) import Math.NumberTheory.Utils (splitOff#) import Math.NumberTheory.Utils.FromIntegral (wordToInt, intToWord)@@ -41,20 +40,20 @@ -- -- > SieveBlockConfig -- >   { sbcEmpty                = 1--- >   , sbcFunctionOnPrimePower = (\p a -> (p - 1) * p ^ (a - 1)+-- >   , sbcFunctionOnPrimePower = \p a -> (unPrime p - 1) * unPrime p ^ (a - 1) -- >   , sbcAppend               = (*) -- >   } data SieveBlockConfig a = SieveBlockConfig   { sbcEmpty                :: a     -- ^ value of a function on 1-  , sbcFunctionOnPrimePower :: Word -> Word -> a+  , sbcFunctionOnPrimePower :: Prime Word -> Word -> a     -- ^ how to evaluate a function on prime powers   , sbcAppend               :: a -> a -> a     -- ^ how to combine values of a function on coprime arguments   }  -- | Create a config for a multiplicative function from its definition on prime powers.-multiplicativeSieveBlockConfig :: Num a => (Word -> Word -> a) -> SieveBlockConfig a+multiplicativeSieveBlockConfig :: Num a => (Prime Word -> Word -> a) -> SieveBlockConfig a multiplicativeSieveBlockConfig f = SieveBlockConfig   { sbcEmpty                = 1   , sbcFunctionOnPrimePower = f@@ -62,7 +61,7 @@   }  -- | Create a config for an additive function from its definition on prime powers.-additiveSieveBlockConfig :: Num a => (Word -> Word -> a) -> SieveBlockConfig a+additiveSieveBlockConfig :: Num a => (Prime Word -> Word -> a) -> SieveBlockConfig a additiveSieveBlockConfig f = SieveBlockConfig   { sbcEmpty                = 0   , sbcFunctionOnPrimePower = f@@ -74,7 +73,7 @@ -- -- Based on Algorithm M of <https://arxiv.org/pdf/1305.1639.pdf Parity of the number of primes in a given interval and algorithms of the sublinear summation> by A. V. Lelechenko. See Lemma 2 on p. 5 on its algorithmic complexity. For the majority of use-cases its time complexity is O(x^(1+ε)). ----- For example, here is an analogue of divisor function 'tau':+-- For example, here is an analogue of divisor function 'Math.NumberTheory.ArithmeticFunctions.tau': -- -- >>> sieveBlockUnboxed (SieveBlockConfig 1 (\_ a -> a + 1) (*)) 1 10 -- [1,2,2,3,2,4,2,4,3,4]@@ -100,7 +99,7 @@         highIndex = lowIndex + len - 1          ps :: [Int]-        ps = takeWhile (<= integerSquareRoot highIndex) $ map fromInteger primes+        ps = takeWhile (<= integerSquareRoot highIndex) $ map unPrime primes      forM_ ps $ \p -> do @@ -109,7 +108,7 @@            fs = V.generate             (integerLogBase' (toInteger p) (toInteger highIndex))-            (\k -> f p' (intToWord k + 1))+            (\k -> f (Prime p') (intToWord k + 1))            offset :: Int           offset = negate lowIndex `mod` p@@ -118,11 +117,11 @@         W# a# <- MV.unsafeRead as ix         let !(# pow#, a'# #) = splitOff# p# (a# `quotWord#` p#)         MV.unsafeWrite as ix (W# a'#)-        MV.unsafeModify bs (\y -> y `append` V.unsafeIndex fs (I# pow#)) ix+        MV.unsafeModify bs (\y -> y `append` V.unsafeIndex fs (I# (word2Int# pow#))) ix      forM_ [0 .. len - 1] $ \k -> do       a <- MV.unsafeRead as k-      MV.unsafeModify bs (\b -> if a /= 1 then b `append` f a 1 else b) k+      MV.unsafeModify bs (\b -> if a /= 1 then b `append` f (Prime a) 1 else b) k      V.unsafeFreeze bs 
Math/NumberTheory/ArithmeticFunctions/Standard.hs view
@@ -3,26 +3,19 @@ -- Copyright:   (c) 2016 Andrew Lelechenko -- Licence:     MIT -- Maintainer:  Andrew Lelechenko <andrew.lelechenko@gmail.com>--- Stability:   Provisional--- Portability: Non-portable (GHC extensions) -- -- Textbook arithmetic functions. -- -{-# LANGUAGE CPP                 #-} {-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE TypeFamilies        #-}-{-# LANGUAGE ViewPatterns        #-} -{-# OPTIONS_HADDOCK hide #-}- module Math.NumberTheory.ArithmeticFunctions.Standard   ( -- * Multiplicative functions     multiplicative   , divisors, divisorsA   , divisorsList, divisorsListA   , divisorsSmall, divisorsSmallA-  , tau, tauA+  , divisorCount, tau, tauA   , sigma, sigmaA   , totient, totientA   , jordan, jordanA@@ -36,6 +29,7 @@     -- * Misc   , carmichael, carmichaelA   , expMangoldt, expMangoldtA+  , isNFree, isNFreeA, nFrees, nFreesBlock   ) where  import Data.Coerce@@ -47,7 +41,8 @@  import Math.NumberTheory.ArithmeticFunctions.Class import Math.NumberTheory.ArithmeticFunctions.Moebius-import Math.NumberTheory.UniqueFactorisation+import Math.NumberTheory.ArithmeticFunctions.NFreedom (nFrees, nFreesBlock)+import Math.NumberTheory.Primes import Math.NumberTheory.Utils.FromIntegral  import Numeric.Natural@@ -56,14 +51,15 @@ multiplicative :: Num a => (Prime n -> Word -> a) -> ArithmeticFunction n a multiplicative f = ArithmeticFunction ((Product .) . f) getProduct -divisors :: (UniqueFactorisation n, Num n, Ord n) => n -> Set n+-- | See 'divisorsA'.+divisors :: (UniqueFactorisation n, Ord n) => n -> Set n divisors = runFunction divisorsA {-# SPECIALIZE divisors :: Natural -> Set Natural #-} {-# SPECIALIZE divisors :: Integer -> Set Integer #-}  -- | The set of all (positive) divisors of an argument.-divisorsA :: forall n. (UniqueFactorisation n, Num n, Ord n) => ArithmeticFunction n (Set n)-divisorsA = ArithmeticFunction (\((unPrime :: Prime n -> n) -> p) k -> SetProduct $ divisorsHelper p k) (S.insert 1 . getSetProduct)+divisorsA :: (UniqueFactorisation n, Ord n) => ArithmeticFunction n (Set n)+divisorsA = ArithmeticFunction (\p -> SetProduct . divisorsHelper (unPrime p)) (S.insert 1 . getSetProduct)  divisorsHelper :: Num n => n -> Word -> Set n divisorsHelper _ 0 = S.empty@@ -71,12 +67,13 @@ divisorsHelper p a = S.fromDistinctAscList $ p : p * p : map (p ^) [3 .. wordToInt a] {-# INLINE divisorsHelper #-} -divisorsList :: (UniqueFactorisation n, Num n) => n -> [n]+-- | See 'divisorsListA'.+divisorsList :: UniqueFactorisation n => n -> [n] divisorsList = runFunction divisorsListA  -- | The unsorted list of all (positive) divisors of an argument, produced in lazy fashion.-divisorsListA :: forall n. (UniqueFactorisation n, Num n) => ArithmeticFunction n [n]-divisorsListA = ArithmeticFunction (\((unPrime :: Prime n -> n) -> p) k -> ListProduct $ divisorsListHelper p k) ((1 :) . getListProduct)+divisorsListA :: UniqueFactorisation n => ArithmeticFunction n [n]+divisorsListA = ArithmeticFunction (\p -> ListProduct . divisorsListHelper (unPrime p)) ((1 :) . getListProduct)  divisorsListHelper :: Num n => n -> Word -> [n] divisorsListHelper _ 0 = []@@ -84,12 +81,13 @@ divisorsListHelper p a = p : p * p : map (p ^) [3 .. wordToInt a] {-# INLINE divisorsListHelper #-} -divisorsSmall :: (UniqueFactorisation n, Prime n ~ Prime Int) => n -> IntSet+-- | See 'divisorsSmallA'.+divisorsSmall :: Int -> IntSet divisorsSmall = runFunction divisorsSmallA  -- | Same as 'divisors', but with better performance on cost of type restriction.-divisorsSmallA :: forall n. (Prime n ~ Prime Int) => ArithmeticFunction n IntSet-divisorsSmallA = ArithmeticFunction (\p k -> IntSetProduct $ divisorsHelperSmall (unPrime p) k) (IS.insert 1 . getIntSetProduct)+divisorsSmallA :: ArithmeticFunction Int IntSet+divisorsSmallA = ArithmeticFunction (\p -> IntSetProduct . divisorsHelperSmall (unPrime p)) (IS.insert 1 . getIntSetProduct)  divisorsHelperSmall :: Int -> Word -> IntSet divisorsHelperSmall _ 0 = IS.empty@@ -97,6 +95,14 @@ divisorsHelperSmall p a = IS.fromDistinctAscList $ p : p * p : map (p ^) [3 .. wordToInt a] {-# INLINE divisorsHelperSmall #-} +-- | Synonym for 'tau'.+--+-- >>> map divisorCount [1..10]+-- [1,2,2,3,2,4,2,4,3,4]+divisorCount :: (UniqueFactorisation n, Num a) => n -> a+divisorCount = tau++-- | See 'tauA'. tau :: (UniqueFactorisation n, Num a) => n -> a tau = runFunction tauA @@ -106,6 +112,7 @@ tauA :: Num a => ArithmeticFunction n a tauA = multiplicative $ const (fromIntegral . succ) +-- | See 'sigmaA'. sigma :: (UniqueFactorisation n, Integral n) => Word -> n -> n sigma = runFunction . sigmaA @@ -113,10 +120,10 @@ -- -- > sigmaA = multiplicative (\p k -> sum $ map (p ^) [0..k]) -- > sigmaA 0 = tauA-sigmaA :: forall n. (UniqueFactorisation n, Integral n) => Word -> ArithmeticFunction n n+sigmaA :: (UniqueFactorisation n, Integral n) => Word -> ArithmeticFunction n n sigmaA 0 = tauA-sigmaA 1 = multiplicative $ \((unPrime :: Prime n -> n) -> p) -> sigmaHelper p-sigmaA a = multiplicative $ \((unPrime :: Prime n -> n) -> p) -> sigmaHelper (p ^ wordToInt a)+sigmaA 1 = multiplicative $ sigmaHelper . unPrime+sigmaA a = multiplicative $ sigmaHelper . (^ wordToInt a) . unPrime  sigmaHelper :: Integral n => n -> Word -> n sigmaHelper pa 1 = pa + 1@@ -124,25 +131,27 @@ sigmaHelper pa k = (pa ^ wordToInt (k + 1) - 1) `quot` (pa - 1) {-# INLINE sigmaHelper #-} -totient :: (UniqueFactorisation n, Num n) => n -> n+-- | See 'totientA'.+totient :: UniqueFactorisation n => n -> n totient = runFunction totientA  -- | Calculates the totient of a positive number @n@, i.e. --   the number of @k@ with @1 <= k <= n@ and @'gcd' n k == 1@, --   in other words, the order of the group of units in @&#8484;/(n)@.-totientA :: forall n. (UniqueFactorisation n, Num n) => ArithmeticFunction n n-totientA = multiplicative $ \((unPrime :: Prime n -> n) -> p) -> jordanHelper p+totientA :: UniqueFactorisation n => ArithmeticFunction n n+totientA = multiplicative $ jordanHelper . unPrime -jordan :: (UniqueFactorisation n, Num n) => Word -> n -> n+-- | See 'jordanA'.+jordan :: UniqueFactorisation n => Word -> n -> n jordan = runFunction . jordanA  -- | Calculates the k-th Jordan function of an argument. -- -- > jordanA 1 = totientA-jordanA :: forall n. (UniqueFactorisation n, Num n) => Word -> ArithmeticFunction n n+jordanA :: UniqueFactorisation n => Word -> ArithmeticFunction n n jordanA 0 = multiplicative $ \_ _ -> 0 jordanA 1 = totientA-jordanA a = multiplicative $ \((unPrime :: Prime n -> n) -> p) -> jordanHelper (p ^ wordToInt a)+jordanA a = multiplicative $ jordanHelper . (^ wordToInt a) . unPrime  jordanHelper :: Num n => n -> Word -> n jordanHelper pa 1 = pa - 1@@ -150,13 +159,14 @@ jordanHelper pa k = (pa - 1) * pa ^ wordToInt (k - 1) {-# INLINE jordanHelper #-} +-- | See 'ramanujanA'. 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+ramanujanA = multiplicative $ ramanujanHelper . unPrime  ramanujanHelper :: Integer -> Word -> Integer ramanujanHelper _ 0 = 1@@ -171,6 +181,7 @@         tpPowers = reverse $ take (length binomials) $ iterate (* tp^(2::Int)) (if even k then 1 else tp) {-# INLINE ramanujanHelper #-} +-- | See 'moebiusA'. moebius :: UniqueFactorisation n => n -> Moebius moebius = runFunction moebiusA @@ -182,6 +193,7 @@     f 0 = MoebiusP     f _ = MoebiusZ +-- | See 'liouvilleA'. liouville :: (UniqueFactorisation n, Num a) => n -> a liouville = runFunction liouvilleA @@ -189,16 +201,18 @@ liouvilleA :: Num a => ArithmeticFunction n a liouvilleA = ArithmeticFunction (const $ Xor . odd) runXor +-- | See 'carmichaelA'. carmichael :: (UniqueFactorisation n, Integral n) => n -> n carmichael = runFunction carmichaelA-{- The specializations reflects available specializations of lcm. -}-{-# SPECIALIZE carmichael :: Int -> Int #-}+{-# SPECIALIZE carmichael :: Int     -> Int #-}+{-# SPECIALIZE carmichael :: Word    -> Word #-} {-# SPECIALIZE carmichael :: Integer -> Integer #-}+{-# SPECIALIZE carmichael :: Natural -> Natural #-}  -- | Calculates the Carmichael function for a positive integer, that is, --   the (smallest) exponent of the group of units in @&#8484;/(n)@.-carmichaelA :: forall n. (UniqueFactorisation n, Integral n) => ArithmeticFunction n n-carmichaelA = ArithmeticFunction (\((unPrime :: Prime n -> n) -> p) k -> LCM $ f p k) getLCM+carmichaelA :: (UniqueFactorisation n, Integral n) => ArithmeticFunction n n+carmichaelA = ArithmeticFunction (\p -> LCM . f (unPrime p)) getLCM   where     f 2 1 = 1     f 2 2 = 2@@ -211,6 +225,7 @@ additive :: Num a => (Prime n -> Word -> a) -> ArithmeticFunction n a additive f = ArithmeticFunction ((Sum .) . f) getSum +-- | See 'smallOmegaA'. smallOmega :: (UniqueFactorisation n, Num a) => n -> a smallOmega = runFunction smallOmegaA @@ -220,6 +235,7 @@ smallOmegaA :: Num a => ArithmeticFunction n a smallOmegaA = additive (\_ _ -> 1) +-- | See 'bigOmegaA'. bigOmega :: UniqueFactorisation n => n -> Word bigOmega = runFunction bigOmegaA @@ -229,12 +245,13 @@ bigOmegaA :: ArithmeticFunction n Word bigOmegaA = additive $ const id -expMangoldt :: (UniqueFactorisation n, Num n) => n -> n+-- | See 'expMangoldtA'.+expMangoldt :: UniqueFactorisation n => n -> n expMangoldt = runFunction expMangoldtA  -- | The exponent of von Mangoldt function. Use @log expMangoldtA@ to recover von Mangoldt function itself.-expMangoldtA :: forall n. (UniqueFactorisation n, Num n) => ArithmeticFunction n n-expMangoldtA = ArithmeticFunction (\((unPrime :: Prime n -> n) -> p) _ -> MangoldtOne p) runMangoldt+expMangoldtA :: UniqueFactorisation n => ArithmeticFunction n n+expMangoldtA = ArithmeticFunction (const . MangoldtOne . unPrime) runMangoldt  data Mangoldt a   = MangoldtZero@@ -255,6 +272,16 @@ instance Monoid (Mangoldt a) where   mempty  = MangoldtZero   mappend = (<>)++-- | See 'isNFreeA'.+isNFree :: UniqueFactorisation n => Word -> n -> Bool+isNFree n = runFunction (isNFreeA n)++-- | Check if an integer is @n@-free. An integer @x@ is @n@-free if in its+-- factorisation into prime factors, no factor has an exponent larger than or+-- equal to @n@.+isNFreeA :: Word -> ArithmeticFunction n Bool+isNFreeA n = ArithmeticFunction (\_ pow -> All $ pow < n) getAll  newtype LCM a = LCM { getLCM :: a } 
Math/NumberTheory/Curves/Montgomery.hs view
@@ -3,8 +3,6 @@ -- Copyright:   (c) 2017 Andrew Lelechenko -- Licence:     MIT -- Maintainer:  Andrew Lelechenko <andrew.lelechenko@gmail.com>--- Stability:   Provisional--- Portability: Non-portable (GHC extensions) -- -- Arithmetic on Montgomery elliptic curve. --@@ -56,9 +54,11 @@   , pointZ :: !Integer -- ^ Extract z-coordinate.   } +-- | Extract (a + 2) \/ 4, where a is a coefficient in curve's equation. pointA24 :: forall a24 n. KnownNat a24 => Point a24 n -> Integer pointA24 _ = toInteger $ natVal (Proxy :: Proxy a24) +-- | Extract modulo of the curve. pointN :: forall a24 n. KnownNat n => Point a24 n -> Integer pointN _ = toInteger $ natVal (Proxy :: Proxy n) 
Math/NumberTheory/Euclidean.hs view
@@ -3,8 +3,6 @@ -- 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. --@@ -63,7 +61,7 @@   lcm 0 _ =  0   lcm x y =  abs ((x `quot` (gcd x y)) * y) -  -- | Test whether two numbers are coprime .+  -- | Test whether two numbers are coprime.   coprime :: a -> a -> Bool   coprime x y = gcd x y == 1 @@ -102,7 +100,7 @@ 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.+-- | Wrapper around 'Integral', which has an 'Euclidean' instance. newtype WrappedIntegral a = WrappedIntegral { unWrappedIntegral :: a }   deriving (Eq, Ord, Show, Num, Integral, Real, Enum) @@ -153,6 +151,7 @@   -- https://ghc.haskell.org/trac/ghc/ticket/15350   -- extendedGCD = gcdExtInteger +-- | Beware that 'extendedGCD' does not make any sense for 'Natural'. instance Euclidean Natural where   quotRem = P.quotRem   divMod  = P.divMod
− Math/NumberTheory/GCD.hs
@@ -1,261 +0,0 @@--- |--- Module:      Math.NumberTheory.GCD--- Copyright:   (c) 2011 Daniel Fischer--- Licence:     MIT--- Maintainer:  Daniel Fischer <daniel.is.fischer@googlemail.com>--- Stability:   Provisional--- Portability: Non-portable (GHC extensions)------ This module exports GCD and coprimality test using the binary gcd algorithm--- and GCD with the extended Euclidean algorithm.------ Efficiently counting the number of trailing zeros, the binary gcd algorithm--- can perform considerably faster than the Euclidean algorithm on average.--- For 'Int', GHC has a rewrite rule to use GMP's fast gcd, depending on--- hardware and\/or GMP version, that can be faster or slower than the binary--- algorithm (on my 32-bit box, binary is faster, on my 64-bit box, GMP).--- For 'Word' and the sized @IntN\/WordN@ types, there is no rewrite rule (yet)--- in GHC, and the binary algorithm performs consistently (so far as my tests go)--- much better (if this module's rewrite rules fire).------ 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           #-}--{-# OPTIONS_GHC -fno-warn-unused-imports #-}-{-# OPTIONS_GHC -fno-warn-deprecations   #-}--module Math.NumberTheory.GCD-    ( binaryGCD-    , extendedGCD-    , coprime-    ) where--import Data.Bits-import Data.Semigroup--import GHC.Word-import GHC.Int--import Math.NumberTheory.GCD.LowLevel-import Math.NumberTheory.Utils--#include "MachDeps.h"--{-# RULES-"binaryGCD/Int"     binaryGCD = gcdInt-"binaryGCD/Word"    binaryGCD = gcdWord-"binaryGCD/Int8"    binaryGCD = gi8-"binaryGCD/Int16"   binaryGCD = gi16-"binaryGCD/Int32"   binaryGCD = gi32-"binaryGCD/Word8"   binaryGCD = gw8-"binaryGCD/Word16"  binaryGCD = gw16-"binaryGCD/Word32"  binaryGCD = gw32-  #-}-#if WORD_SIZE_IN_BITS == 64-gi64 :: Int64 -> Int64 -> Int64-gi64 (I64# x#) (I64# y#) = I64# (gcdInt# x# y#)--gw64 :: Word64 -> Word64 -> Word64-gw64 (W64# x#) (W64# y#) = W64# (gcdWord# x# y#)--{-# RULES-"binaryGCD/Int64"   binaryGCD = gi64-"binaryGCD/Word64"  binaryGCD = gw64-  #-}-#endif-{-# INLINE [1] binaryGCD #-}--- | Calculate the greatest common divisor using the binary gcd algorithm.---   Depending on type and hardware, that can be considerably faster than---   @'Prelude.gcd'@ but it may also be significantly slower.------   There are specialised functions for @'Int'@ and @'Word'@ and rewrite rules---   for those and @IntN@ and @WordN@, @N <= WORD_SIZE_IN_BITS@, to use the---   specialised variants. These types are worth benchmarking, others probably not.------   It is very slow for 'Integer' (and probably every type except the abovementioned),---   I recommend not using it for those.------   Relies on twos complement or sign and magnitude representaion for signed types.-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 #-}-#endif-{-# SPECIALISE binaryGCDImpl :: Integer -> Integer -> Integer #-}-binaryGCDImpl :: (Integral a, Bits a) => a -> a -> a-binaryGCDImpl a 0 = abs a-binaryGCDImpl 0 b = abs b-binaryGCDImpl a b =-    case shiftToOddCount a' of-      (!za, !oa) ->-        case shiftToOddCount b' of-          (!zb, !ob) -> gcdOdd (abs oa) (abs ob) `shiftL` min za zb-    where-      a' = abs a-      b' = abs b--{-# SPECIALISE extendedGCD :: Int -> Int -> (Int, Int, Int),-                              Word -> Word -> (Word, Word, Word),-                              Integer -> Integer -> (Integer, Integer, Integer)-  #-}--- | 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 :: Integral a => a -> a -> (a, a, a)-extendedGCD a b = (d, u, v)-  where-    (d, x, y) = eGCD 0 1 1 0 (abs a) (abs b)-    u | a < 0     = negate x-      | otherwise = x-    v | b < 0     = negate y-      | otherwise = y-    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-{-# DEPRECATED extendedGCD "Use 'Math.NumberTheory.Euclidean.extendedGCD'" #-}--{-# RULES-"coprime/Int"       coprime = coprimeInt-"coprime/Word"      coprime = coprimeWord-"coprime/Int8"      coprime = ci8-"coprime/Int16"     coprime = ci16-"coprime/Int32"     coprime = ci32-"coprime/Word8"     coprime = cw8-"coprime/Word16"    coprime = cw16-"coprime/Word32"    coprime = cw32-  #-}-#if WORD_SIZE_IN_BITS == 64-ci64 :: Int64 -> Int64 -> Bool-ci64 (I64# x#) (I64# y#) = coprimeInt# x# y#--cw64 :: Word64 -> Word64 -> Bool-cw64 (W64# x#) (W64# y#) = coprimeWord# x# y#--{-# RULES-"coprime/Int64"     coprime = ci64-"coprime/Word64"    coprime = cw64-  #-}-#endif-{-# INLINE [1] coprime #-}--- | Test whether two numbers are coprime using an abbreviated binary gcd algorithm.---   A little bit faster than checking @binaryGCD a b == 1@ if one of the arguments---   is even, much faster if both are even.------   The remarks about performance at 'binaryGCD' apply here too, use this function---   only at the types with rewrite rules.------   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-#if WORD_SIZE_IN_BITS < 64-{-# SPECIALISE coprimeImpl :: Word64 -> Word64 -> Bool,-                              Int64 -> Int64 -> Bool #-}-#endif-{-# SPECIALISE coprimeImpl :: Integer -> Integer -> Bool #-}-coprimeImpl :: (Integral a, Bits a) => a -> a -> Bool-coprimeImpl a b =-  (a' == 1 || b' == 1)-  || (a' /= 0 && b' /= 0 && ((a .|. b) .&. 1) == 1-      && gcdOdd (abs (shiftToOdd a')) (abs (shiftToOdd b')) == 1)-    where-      a' = abs a-      b' = abs b---- Auxiliaries---- gcd of two odd numbers-{-# INLINE gcdOdd #-}-gcdOdd :: (Integral a, Bits a) => a -> a -> a-gcdOdd a b-  | a == 1 || b == 1    = 1-  | a < b               = oddGCD b a-  | a > b               = oddGCD a b-  | otherwise           = a--{-# SPECIALISE oddGCD :: Integer -> Integer -> Integer #-}-#if WORD_SIZE_IN_BITS < 64-{-# SPECIALISE oddGCD :: Int64 -> Int64 -> Int64,-                         Word64 -> Word64 -> Word64-  #-}-#endif-oddGCD :: (Integral a, Bits a) => a -> a -> a-oddGCD a b =-    case shiftToOdd (a-b) of-      1 -> 1-      c | c < b     -> oddGCD b c-        | c > b     -> oddGCD c b-        | otherwise -> c------------------------------------------------------------------------------------                Blech! Getting the rules to fire isn't easy.               ------------------------------------------------------------------------------------gi8 :: Int8 -> Int8 -> Int8-gi8 (I8# x#) (I8# y#) = I8# (gcdInt# x# y#)--gi16 :: Int16 -> Int16 -> Int16-gi16 (I16# x#) (I16# y#) = I16# (gcdInt# x# y#)--gi32 :: Int32 -> Int32 -> Int32-gi32 (I32# x#) (I32# y#) = I32# (gcdInt# x# y#)--gw8 :: Word8 -> Word8 -> Word8-gw8 (W8# x#) (W8# y#) = W8# (gcdWord# x# y#)--gw16 :: Word16 -> Word16 -> Word16-gw16 (W16# x#) (W16# y#) = W16# (gcdWord# x# y#)--gw32 :: Word32 -> Word32 -> Word32-gw32 (W32# x#) (W32# y#) = W32# (gcdWord# x# y#)--ci8 :: Int8 -> Int8 -> Bool-ci8 (I8# x#) (I8# y#) = coprimeInt# x# y#--ci16 :: Int16 -> Int16 -> Bool-ci16 (I16# x#) (I16# y#) = coprimeInt# x# y#--ci32 :: Int32 -> Int32 -> Bool-ci32 (I32# x#) (I32# y#) = coprimeInt# x# y#--cw8 :: Word8 -> Word8 -> Bool-cw8 (W8# x#) (W8# y#) = coprimeWord# x# y#--cw16 :: Word16 -> Word16 -> Bool-cw16 (W16# x#) (W16# y#) = coprimeWord# x# y#--cw32 :: Word32 -> Word32 -> Bool-cw32 (W32# x#) (W32# y#) = coprimeWord# x# y#
− Math/NumberTheory/GCD/LowLevel.hs
@@ -1,104 +0,0 @@--- |--- Module:      Math.NumberTheory.GCD.LowLevel--- Copyright:   (c) 2011 Daniel Fischer--- Licence:     MIT--- Maintainer:  Daniel Fischer <daniel.is.fischer@googlemail.com>--- Stability:   Provisional--- Portability: Non-portable (GHC extensions)------ Low level gcd and coprimality functions using the binary gcd algorithm.--- Normally, accessing these via the higher level interface of "Math.NumberTheory.GCD"--- should be sufficient.----{-# LANGUAGE MagicHash     #-}-{-# LANGUAGE UnboxedTuples #-}-module Math.NumberTheory.GCD.LowLevel-  ( -- * Specialised GCDs-    gcdInt-  , gcdWord-    -- ** GCDs for unboxed types-  , gcdInt#-  , gcdWord#-    -- * Specialised tests for coprimality-  , coprimeInt-  , coprimeWord-    -- ** Coprimality tests for unboxed types-  , coprimeInt#-  , coprimeWord#-  ) where--import GHC.Base--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#)---- | Test whether two 'Int's are coprime, using an abbreviated binary gcd algorithm.-coprimeInt :: Int -> Int -> Bool-coprimeInt (I# a#) (I# b#) = coprimeInt# a# b#---- | Greatest common divisor of two 'Word's, calculated with the binary gcd algorithm.-gcdWord :: Word -> Word -> Word-gcdWord (W# a#) (W# b#) = W# (gcdWord# a# b#)---- | Test whether two 'Word's are coprime, using an abbreviated binary gcd algorithm.-coprimeWord :: Word -> Word -> Bool-coprimeWord (W# a#) (W# b#) = coprimeWord# a# b#---- | Greatest common divisor of two 'Int#'s, calculated with the binary gcd algorithm.-gcdInt# :: Int# -> Int# -> Int#-gcdInt# a# b# = word2Int# (gcdWord# (int2Word# (absInt# a#)) (int2Word# (absInt# b#)))----- | Test whether two 'Int#'s are coprime.-coprimeInt# :: Int# -> Int# -> Bool-coprimeInt# a# b# = coprimeWord# (int2Word# (absInt# a#)) (int2Word# (absInt# b#))---- | Greatest common divisor of two 'Word#'s, calculated with the binary gcd algorithm.-gcdWord# :: Word# -> Word# -> Word#-gcdWord# a# 0## = a#-gcdWord# 0## b# = b#-gcdWord# a# b#  =-    case shiftToOddCount# a# of-      (# za#, oa# #) ->-        case shiftToOddCount# b# of-          (# zb#, ob# #) -> gcdWordOdd# oa# ob# `uncheckedShiftL#` (if isTrue# (za# <# zb#) then za# else zb#)---- | Test whether two 'Word#'s are coprime.-coprimeWord# :: Word# -> Word# -> Bool-coprimeWord# a# b# =-  (isTrue# (a# `eqWord#` 1##) || isTrue# (b# `eqWord#` 1##))-  || (isTrue# (((a# `or#` b#) `and#` 1##) `eqWord#` 1##) -- not both even-      && ((isTrue# (a# `neWord#` 0##) && isTrue# (b# `neWord#` 0##)) -- neither is zero-      && isTrue# (gcdWordOdd# (shiftToOdd# a#) (shiftToOdd# b#) `eqWord#` 1##)))---- Various auxiliary functions---- calculate the gcd of two odd numbers-{-# INLINE gcdWordOdd# #-}-gcdWordOdd# :: Word# -> Word# -> Word#-gcdWordOdd# a# b#-  | isTrue# (a# `eqWord#` 1##) || isTrue# (b# `eqWord#` 1##)    = 1##-  | isTrue# (a# `eqWord#` b#)                                   = a#-  | isTrue# (a# `ltWord#` b#)                                   = oddGCD# b# a#-  | otherwise                                                   = oddGCD# a# b#---- calculate the gcd of two odd numbers using the binary gcd algorithm--- Precondition: first argument strictly larger than second (which should be greater than 1)-oddGCD# :: Word# -> Word# -> Word#-oddGCD# a# b# =-    case shiftToOdd# (a# `minusWord#` b#) of-      1## -> 1##-      c#  | isTrue# (c# `ltWord#` b#)   -> oddGCD# b# c#-          | isTrue# (c# `gtWord#` b#)   -> oddGCD# c# b#-          | otherwise                   -> c#--absInt# :: Int# -> Int#-absInt# i#-  | isTrue# (i# <# 0#)  = negateInt# i#-  | otherwise           = i#
− Math/NumberTheory/GaussianIntegers.hs
@@ -1,18 +0,0 @@--- |--- 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.-----module Math.NumberTheory.GaussianIntegers-  {-# DEPRECATED "Use Math.NumberTheory.Quadratic.GaussianIntegers instead" #-}-  ( module Math.NumberTheory.Quadratic.GaussianIntegers-  ) where--import Math.NumberTheory.Quadratic.GaussianIntegers
Math/NumberTheory/Moduli.hs view
@@ -3,8 +3,6 @@ -- Copyright:   (c) 2011 Daniel Fischer -- Licence:     MIT -- Maintainer:  Daniel Fischer <daniel.is.fischer@googlemail.com>--- Stability:   Provisional--- Portability: Non-portable (GHC extensions) -- -- Miscellaneous functions related to modular arithmetic. --
Math/NumberTheory/Moduli/Chinese.hs view
@@ -1,26 +1,165 @@ -- | -- Module:      Math.NumberTheory.Moduli.Chinese--- Copyright:   (c) 2011 Daniel Fischer+-- Copyright:   (c) 2011 Daniel Fischer, 2018 Andrew Lelechenko -- Licence:     MIT -- Maintainer:  Andrew Lelechenko <andrew.lelechenko@gmail.com>--- Stability:   Provisional--- Portability: Non-portable (GHC extensions) -- -- Chinese remainder theorem -- -{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE BangPatterns        #-}+{-# LANGUAGE CPP                 #-}+{-# LANGUAGE RankNTypes          #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TupleSections       #-}+{-# LANGUAGE TypeApplications    #-}+{-# LANGUAGE TypeOperators       #-} +#if __GLASGOW_HASKELL__ > 805+{-# LANGUAGE NoStarIsType #-}+#endif+ module Math.NumberTheory.Moduli.Chinese-  ( chineseRemainder+  ( -- * Safe interface+    chinese+  , chineseCoprime+  , chineseSomeMod+  , chineseCoprimeSomeMod++  , -- * Unsafe interface+    chineseRemainder   , chineseRemainder2   ) where +import Prelude hiding (mod, quot, gcd, lcm)+ import Control.Monad (foldM)+import Data.Foldable+import Data.Ratio+import GHC.TypeNats.Compat+import Numeric.Natural -import Math.NumberTheory.Euclidean (extendedGCD)-import Math.NumberTheory.Utils (recipMod)+import Math.NumberTheory.Moduli.Class+import Math.NumberTheory.Euclidean+import Math.NumberTheory.Euclidean.Coprimes+import Math.NumberTheory.Utils (recipMod, splitOff) +-- | 'chineseCoprime' @(n1, m1)@ @(n2, m2)@ returns @n@ such that+-- @n \`mod\` m1 == n1@ and @n \`mod\` m2 == n2@.+-- Moduli @m1@ and @m2@ must be coprime, otherwise 'Nothing' is returned.+--+-- This function is slightly faster than 'chinese', but more restricted.+--+-- >>> chineseCoprime (1, 2) (2, 3)+-- Just 5+-- >>> chineseCoprime (3, 4) (5, 6)+-- Nothing -- moduli must be coprime+chineseCoprime :: Euclidean a => (a, a) -> (a, a) -> Maybe a+chineseCoprime (n1, m1) (n2, m2) = case d of+  1 -> Just $ ((1 - u * m1) * n1 + (1 - v * m2) * n2) `mod` (m1 * m2)+  _ -> Nothing+  where+    (d, u, v) = extendedGCD m1 m2++{-# SPECIALISE chineseCoprime :: (Int, Int) -> (Int, Int) -> Maybe Int #-}+{-# SPECIALISE chineseCoprime :: (Word, Word) -> (Word, Word) -> Maybe Word #-}+{-# SPECIALISE chineseCoprime :: (Integer, Integer) -> (Integer, Integer) -> Maybe Integer #-}+{-# SPECIALISE chineseCoprime :: (Natural, Natural) -> (Natural, Natural) -> Maybe Natural #-}++-- | 'chinese' @(n1, m1)@ @(n2, m2)@ returns @n@ such that+-- @n \`mod\` m1 == n1@ and @n \`mod\` m2 == n2@, if exists.+-- Moduli @m1@ and @m2@ are allowed to have common factors.+--+-- >>> chinese (1, 2) (2, 3)+-- Just 5+-- >>> chinese (3, 4) (5, 6)+-- Just 11+-- >>> chinese (3, 4) (2, 6)+-- Nothing+chinese :: forall a. Euclidean a => (a, a) -> (a, a) -> Maybe a+chinese (n1, m1) (n2, m2)+  | n1 `mod` g == n2 `mod` g+  = chineseCoprime (n1 `mod` m1', m1') (n2 `mod` m2', m2')+  | otherwise+  = Nothing+  where+    g :: a+    g = gcd m1 m2++    ms :: [(a, Word)]+    ms = unCoprimes $ splitIntoCoprimes [(m1, 1), (m2 `quot` g, 1)]++    m1', m2' :: a+    (m1', m2') = foldl' go (1, 1) $ map fst ms++    go :: (a, a) -> a -> (a, a)+    go (t1, t2) p+      | k1 <= k2+      = (t1, t2 * p ^ k2)+      | otherwise+      = (t1 * p ^ k1, t2)+      where+        (k1, _) = splitOff p m1+        (k2, _) = splitOff p m2++{-# SPECIALISE chinese :: (Int, Int) -> (Int, Int) -> Maybe Int #-}+{-# SPECIALISE chinese :: (Word, Word) -> (Word, Word) -> Maybe Word #-}+{-# SPECIALISE chinese :: (Integer, Integer) -> (Integer, Integer) -> Maybe Integer #-}+{-# SPECIALISE chinese :: (Natural, Natural) -> (Natural, Natural) -> Maybe Natural #-}++isCompatible :: KnownNat m => Mod m -> Rational -> Bool+isCompatible n r = case invertMod (fromInteger (denominator r)) of+  Nothing -> False+  Just r' -> r' * fromInteger (numerator r) == n++chineseWrap+  :: (Integer -> Integer -> Integer)+  -> ((Integer, Integer) -> (Integer, Integer) -> Maybe Integer)+  -> SomeMod+  -> SomeMod+  -> Maybe SomeMod+chineseWrap f g (SomeMod n1) (SomeMod n2)+  = fmap (`modulo` fromInteger (f m1 m2)) (g (getVal n1, m1) (getVal n2, m2))+  where+    m1 = getMod n1+    m2 = getMod n2+chineseWrap _ _ (SomeMod n) (InfMod r)+  | isCompatible n r = Just $ InfMod r+  | otherwise        = Nothing+chineseWrap _ _ (InfMod r) (SomeMod n)+  | isCompatible n r = Just $ InfMod r+  | otherwise        = Nothing+chineseWrap _ _ (InfMod r1) (InfMod r2)+  | r1 == r2  = Just $ InfMod r1+  | otherwise = Nothing++-- | Same as 'chineseCoprime', but operates on residues.+--+-- >>> :set -XDataKinds+-- >>> import Math.NumberTheory.Moduli.Class+-- >>> (1 `modulo` 2) `chineseCoprimeSomeMod` (2 `modulo` 3)+-- Just (5 `modulo` 6)+-- >>> (3 `modulo` 4) `chineseCoprimeSomeMod` (5 `modulo` 6)+-- Nothing+chineseCoprimeSomeMod :: SomeMod -> SomeMod -> Maybe SomeMod+chineseCoprimeSomeMod = chineseWrap (*) chineseCoprime++-- | Same as 'chinese', but operates on residues.+--+-- >>> :set -XDataKinds+-- >>> import Math.NumberTheory.Moduli.Class+-- >>> (1 `modulo` 2) `chineseSomeMod` (2 `modulo` 3)+-- Just (5 `modulo` 6)+-- >>> (3 `modulo` 4) `chineseSomeMod` (5 `modulo` 6)+-- Just (11 `modulo` 12)+-- >>> (3 `modulo` 4) `chineseSomeMod` (2 `modulo` 6)+-- Nothing+chineseSomeMod :: SomeMod -> SomeMod -> Maybe SomeMod+chineseSomeMod = chineseWrap lcm chinese++-------------------------------------------------------------------------------+-- Unsafe interface+ -- | Given a list @[(r_1,m_1), ..., (r_n,m_n)]@ of @(residue,modulus)@ --   pairs, @chineseRemainder@ calculates the solution to the simultaneous --   congruences@@ -32,7 +171,7 @@ --   if all moduli are positive and pairwise coprime. Otherwise --   the result is @Nothing@ regardless of whether --   a solution exists.-chineseRemainder :: [(Integer,Integer)] -> Maybe Integer+chineseRemainder :: [(Integer, Integer)] -> Maybe Integer chineseRemainder remainders = foldM addRem 0 remainders   where     !modulus = product (map snd remainders)@@ -48,7 +187,7 @@ -- > r ≡ r_k (mod m_k) -- --   if @m_1@ and @m_2@ are coprime.-chineseRemainder2 :: (Integer,Integer) -> (Integer,Integer) -> Integer-chineseRemainder2 (r1, md1) (r2,md2)-    = case extendedGCD md1 md2 of-        (_,u,v) -> ((1 - u*md1)*r1 + (1 - v*md2)*r2) `mod` (md1*md2)+chineseRemainder2 :: (Integer, Integer) -> (Integer, Integer) -> Integer+chineseRemainder2 (n1, m1) (n2, m2) = ((1 - u * m1) * n1 + (1 - v * m2) * n2) `mod` (m1 * m2)+  where+    (_, u, v) = extendedGCD m1 m2
Math/NumberTheory/Moduli/Class.hs view
@@ -3,20 +3,21 @@ -- Copyright:   (c) 2017 Andrew Lelechenko -- Licence:     MIT -- Maintainer:  Andrew Lelechenko <andrew.lelechenko@gmail.com>--- Stability:   Provisional--- Portability: Non-portable (GHC extensions) -- -- Safe modular arithmetic with modulo on type level. -- +{-# LANGUAGE BangPatterns               #-} {-# LANGUAGE DataKinds                  #-} {-# LANGUAGE GADTs                      #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE KindSignatures             #-} {-# LANGUAGE LambdaCase                 #-}+{-# LANGUAGE MagicHash                  #-} {-# LANGUAGE RankNTypes                 #-} {-# LANGUAGE ScopedTypeVariables        #-} {-# LANGUAGE StandaloneDeriving         #-}+{-# LANGUAGE UnboxedTuples              #-}  module Math.NumberTheory.Moduli.Class   ( -- * Known modulo@@ -46,11 +47,11 @@ import Data.Ratio import Data.Semigroup import Data.Type.Equality+import GHC.Exts import GHC.Integer.GMP.Internals+import GHC.Natural (Natural(..), powModNatural) import GHC.TypeNats.Compat -import GHC.Natural (Natural, powModNatural)- -- | Wrapper for residues modulo @m@. -- -- @Mod 3 :: Mod 10@ stands for the class of integers, congruent to 3 modulo 10 (…−17, −7, 3, 13, 23…).@@ -89,9 +90,25 @@   negate mx@(Mod x) =     Mod $ if x == 0 then 0 else getNatMod mx - x   {-# INLINE negate #-}-  mx@(Mod x) * Mod y =-    Mod $ x * y `rem` getNatMod mx -- `rem` is slightly faster than `mod`++  -- If modulo is small and fits into one machine word,+  -- there is no need to use long arithmetic at all+  -- and we can save some allocations.+  mx@(Mod (NatS# x#)) * (Mod (NatS# y#)) = case getNatMod mx of+    NatS# m# -> let !(# z1#, z2# #) = timesWord2# x# y# in+                let !(# _, r# #) = quotRemWord2# z1# z2# m# in+                Mod (NatS# r#)+    NatJ# b# -> let !(# z1#, z2# #) = timesWord2# x# y# in+                let r# = wordToBigNat2 z1# z2# `remBigNat` b# in+                Mod $ if isTrue# (sizeofBigNat# r# ==# 1#)+                  then NatS# (bigNatToWord r#)+                  else NatJ# r#++  mx@(Mod !x) * (Mod !y) =+    Mod $ x * y `rem` getNatMod mx+    -- `rem` is slightly faster than `mod`   {-# INLINE (*) #-}+   abs = id   {-# INLINE abs #-}   signum = const $ Mod 1@@ -152,11 +169,11 @@     y = recipModInteger (getVal mx) (getMod mx) {-# INLINABLE invertMod #-} --- | Drop-in replacement for '^', with much better performance.+-- | Drop-in replacement for 'Prelude.^', with much better performance. -- -- >>> :set -XDataKinds -- >>> powMod (3 :: Mod 10) 4--- > (1 `modulo` 10)+-- (1 `modulo` 10) powMod :: (KnownNat m, Integral a) => Mod m -> a -> Mod m powMod mx a   | a < 0     = error $ "^{Mod}: negative exponent"@@ -173,7 +190,10 @@ "powMod/2/Integer"     forall x. powMod x (2 :: Integer) = let u = x in u*u "powMod/3/Integer"     forall x. powMod x (3 :: Integer) = let u = x in u*u*u "powMod/2/Int"         forall x. powMod x (2 :: Int)     = let u = x in u*u-"powMod/3/Int"         forall x. powMod x (3 :: Int)     = let u = x in u*u*u #-}+"powMod/3/Int"         forall x. powMod x (3 :: Int)     = let u = x in u*u*u+"powMod/2/Word"        forall x. powMod x (2 :: Word)    = let u = x in u*u+"powMod/3/Word"        forall x. powMod x (3 :: Word)    = let u = x in u*u*u+#-}  -- | Infix synonym of 'powMod'. (^%) :: (KnownNat m, Integral a) => Mod m -> a -> Mod m@@ -188,8 +208,9 @@  -- | 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)+newtype MultMod m = MultMod {+  multElement :: Mod m -- ^ Unwrap a residue.+  } deriving (Eq, Ord, Show)  instance KnownNat m => Semigroup (MultMod m) where   MultMod a <> MultMod b = MultMod (a * b)@@ -225,7 +246,7 @@ -- -- >>> 2 `modulo` 10 + 4 `modulo` 15 -- (1 `modulo` 5)--- >>> 2 `modulo` 10 * 4 `modulo` 15+-- >>> (2 `modulo` 10) * (4 `modulo` 15) -- (3 `modulo` 5) -- >>> 2 `modulo` 10 + fromRational (3 % 7) -- (1 `modulo` 10)@@ -322,7 +343,7 @@ -- -- >>> invertSomeMod (3 `modulo` 10) -- Just (7 `modulo` 10) -- because 3 * 7 = 1 :: Mod 10--- >>> invertMod (4 `modulo` 10)+-- >>> invertSomeMod (4 `modulo` 10) -- Nothing -- >>> invertSomeMod (fromRational (2 % 5)) -- Just 5 % 2@@ -338,8 +359,8 @@   SomeMod -> Int     -> SomeMod,   SomeMod -> Word    -> SomeMod #-} --- | Drop-in replacement for '^', with much better performance.--- When -O is enabled, there is a rewrite rule, which specialises '^' to 'powSomeMod'.+-- | Drop-in replacement for 'Prelude.^', with much better performance.+-- When -O is enabled, there is a rewrite rule, which specialises 'Prelude.^' to 'powSomeMod'. -- -- >>> powSomeMod (3 `modulo` 10) 4 -- (1 `modulo` 10)
Math/NumberTheory/Moduli/DiscreteLogarithm.hs view
@@ -3,8 +3,6 @@ -- Copyright:    (c) 2018 Bhavik Mehta -- License:      MIT -- Maintainer:   Andrew Lelechenko <andrew.lelechenko@gmail.com>--- Stability:    Provisional--- Portability:  Non-portable --  {-# LANGUAGE BangPatterns        #-}@@ -27,7 +25,7 @@ import Math.NumberTheory.Moduli.Equations     (solveLinear) import Math.NumberTheory.Moduli.PrimitiveRoot (PrimitiveRoot(..), CyclicGroup(..)) import Math.NumberTheory.Powers.Squares       (integerSquareRoot)-import Math.NumberTheory.UniqueFactorisation  (unPrime)+import Math.NumberTheory.Primes  (unPrime)  -- | Computes the discrete logarithm. Currently uses a combination of the baby-step -- giant-step method and Pollard's rho algorithm, with Bach reduction.@@ -42,13 +40,17 @@   -> 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)*+    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       (toInteger . unPrime -> p) k+      -> discreteLogarithmPP p k (getVal a) (getVal b)+    CGDoubleOddPrimePower (toInteger . 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 #-}
Math/NumberTheory/Moduli/Equations.hs view
@@ -3,8 +3,6 @@ -- Copyright:   (c) 2018 Andrew Lelechenko -- Licence:     MIT -- Maintainer:  Andrew Lelechenko <andrew.lelechenko@gmail.com>--- Stability:   Provisional--- Portability: Non-portable (GHC extensions) -- -- Polynomial modular equations. --@@ -22,7 +20,7 @@ import Math.NumberTheory.Moduli.Chinese import Math.NumberTheory.Moduli.Class import Math.NumberTheory.Moduli.Sqrt-import Math.NumberTheory.UniqueFactorisation+import Math.NumberTheory.Primes import Math.NumberTheory.Utils (recipMod)  -------------------------------------------------------------------------------@@ -65,7 +63,7 @@   => Mod m   -- ^ a   -> Mod m   -- ^ b   -> Mod m   -- ^ c-  -> [Mod m] -- ^ list of c+  -> [Mod m] -- ^ list of x solveQuadratic a b c   = map fromInteger   $ fst
Math/NumberTheory/Moduli/Jacobi.hs view
@@ -3,8 +3,6 @@ -- 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) -- -- <https://en.wikipedia.org/wiki/Jacobi_symbol Jacobi symbol> -- is a generalization of the Legendre symbol, useful for primality@@ -20,7 +18,6 @@ module Math.NumberTheory.Moduli.Jacobi   ( JacobiSymbol(..)   , jacobi-  , jacobi'   ) where  import Data.Bits@@ -91,7 +88,6 @@                                 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 jacPS :: (Integral a, Bits a) => JacobiSymbol -> a -> a -> JacobiSymbol
Math/NumberTheory/Moduli/PrimitiveRoot.hs view
@@ -3,8 +3,6 @@ -- Copyright:   (c) 2017 Andrew Lelechenko -- Licence:     MIT -- Maintainer:  Andrew Lelechenko <andrew.lelechenko@gmail.com>--- Stability:   Provisional--- Portability: Non-portable (GHC extensions) -- -- Primitive roots and cyclic groups. --@@ -42,8 +40,7 @@ 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 Math.NumberTheory.Primes  import Control.DeepSeq import Control.Monad (guard)@@ -62,12 +59,9 @@   -- ^ 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 (Eq, Show, Generic) -deriving instance Eq   (Prime a) => Eq   (CyclicGroup a)-deriving instance Show (Prime a) => Show (CyclicGroup a)+instance NFData a => NFData (CyclicGroup a)  -- | Check whether a multiplicative group of residues, -- characterized by its modulo, is cyclic and, if yes, return its form.@@ -75,7 +69,7 @@ -- >>> cyclicGroupFromModulo 4 -- Just CG4 -- >>> cyclicGroupFromModulo (2 * 13 ^ 3)--- Just (CGDoubleOddPrimePower (PrimeNat 13) 3)+-- Just (CGDoubleOddPrimePower (Prime 13) 3) -- >>> cyclicGroupFromModulo (4 * 13) -- Nothing cyclicGroupFromModulo@@ -97,7 +91,7 @@   :: (Integral a, UniqueFactorisation a)   => a   -> Maybe (Prime a, Word)-isPrimePower n = (, intToWord k) <$> isPrime m+isPrimePower n = (, k) <$> isPrime m   where     (m, k) = highestPower n @@ -105,13 +99,13 @@ -- a cyclic multiplicative group of residues. -- -- >>> cyclicGroupToModulo CG4--- Prefactored {prefValue = 4, prefFactors = Coprimes {unCoprimes = fromList [(2,2)]}}+-- Prefactored {prefValue = 4, prefFactors = Coprimes {unCoprimes = [(2,2)]}} ----- >>> :set -XTypeFamilies--- >>> cyclicGroupToModulo (CGDoubleOddPrimePower (PrimeNat 13) 3)--- Prefactored {prefValue = 4394, prefFactors = Coprimes {unCoprimes = fromList [(2,1),(13,3)]}}+-- >>> import Data.Maybe+-- >>> cyclicGroupToModulo (CGDoubleOddPrimePower (fromJust (isPrime 13)) 3)+-- Prefactored {prefValue = 4394, prefFactors = Coprimes {unCoprimes = [(13,3),(2,1)]}} cyclicGroupToModulo-  :: (E.Euclidean a, Ord a, UniqueFactorisation a)+  :: E.Euclidean a   => CyclicGroup a   -> Prefactored a cyclicGroupToModulo = fromFactors . \case@@ -121,7 +115,8 @@   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.+-- | 'PrimitiveRoot' m is a type which is only inhabited+-- by <https://en.wikipedia.org/wiki/Primitive_root_modulo_n primitive roots> of m. data PrimitiveRoot m = PrimitiveRoot   { unPrimitiveRoot :: MultMod m -- ^ Extract primitive root value.   , getGroup        :: CyclicGroup Natural -- ^ Get cyclic group structure.@@ -163,14 +158,9 @@ -- -- >>> :set -XDataKinds -- >>> isPrimitiveRoot (1 :: Mod 13)--- False+-- Nothing -- >>> isPrimitiveRoot (2 :: Mod 13)--- True------ Here is how to list all primitive roots:------ >>> mapMaybe isPrimitiveRoot [minBound .. maxBound] :: [Mod 13]--- [(2 `modulo` 13), (6 `modulo` 13), (7 `modulo` 13), (11 `modulo` 13)]+-- Just (PrimitiveRoot {unPrimitiveRoot = MultMod {multElement = (2 `modulo` 13)}, getGroup = CGOddPrimePower (Prime 13) 1}) -- -- This function is a convenient wrapper around 'isPrimitiveRoot''. The latter -- provides better control and performance, if you need them.@@ -185,5 +175,5 @@   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 :: (E.Euclidean a, UniqueFactorisation a) => CyclicGroup a -> Prefactored a groupSize = totient . cyclicGroupToModulo
Math/NumberTheory/Moduli/Sqrt.hs view
@@ -3,8 +3,6 @@ -- Copyright:   (c) 2011 Daniel Fischer -- Licence:     MIT -- Maintainer:  Andrew Lelechenko <andrew.lelechenko@gmail.com>--- Stability:   Provisional--- Portability: Non-portable (GHC extensions) -- -- Modular square roots. --@@ -30,7 +28,6 @@   , Old.sqrtModFList   ) where -import Control.Arrow hiding (loop) import Control.Monad (liftM2) import Data.Bits @@ -38,9 +35,9 @@ 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.Primes (Prime, factorise) import Math.NumberTheory.Utils (shiftToOddCount, splitOff, recipMod) import Math.NumberTheory.Utils.FromIntegral @@ -50,13 +47,12 @@ -- -- >>> :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)]+-- [(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 --- | List all square roots modulo a number, which factorisation is passed as a second argument.+-- | List all square roots modulo a number, the factorisation of which is+-- passed as a second argument. -- -- >>> sqrtsModFactorisation 1 (factorise 60) -- [1,49,41,29,31,19,11,59]@@ -65,7 +61,7 @@ sqrtsModFactorisation n pps = map fst $ foldl1 (liftM2 comb) cs   where     ms :: [Integer]-    ms = map (\(PrimeNat p, pow) -> toInteger p ^ pow) pps+    ms = map (\(Prime p, pow) -> p ^ pow) pps      rs :: [[Integer]]     rs = map (\(p, pow) -> sqrtsModPrimePower n p pow) pps@@ -75,15 +71,17 @@      comb t1@(_, m1) t2@(_, m2) = (chineseRemainder2 t1 t2, m1 * m2) --- | List all square roots modulo power of a prime.+-- | List all square roots modulo the power of a prime. --+-- >>> import Data.Maybe+-- >>> import Math.NumberTheory.Primes -- >>> 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+sqrtsModPrimePower nn (Prime 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)@@ -95,7 +93,7 @@           then go rr os           else go rr os ++ go (primeExpo - rr) os       where-        k = intToWord kk `quot` 2+        k = 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]@@ -108,6 +106,8 @@  -- | List all square roots by prime modulo. --+-- >>> import Data.Maybe+-- >>> import Math.NumberTheory.Primes -- >>> sqrtsModPrime 1 (fromJust (isPrime 5)) -- [1,4] -- >>> sqrtsModPrime 0 (fromJust (isPrime 5))@@ -115,8 +115,8 @@ -- >>> 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+sqrtsModPrime n (Prime 2) = [n `mod` 2]+sqrtsModPrime n (Prime prime) = case jacobi n prime of   MinusOne -> []   Zero     -> [0]   One      -> let r = sqrtModP' (n `mod` prime) prime in [r, prime - r]@@ -135,7 +135,7 @@                     = sqrtOfMinusOne prime     | otherwise     = tonelliShanks square prime --- | p must be of form 4k + 1+-- | @p@ must be of form @4k + 1@ sqrtOfMinusOne :: Integer -> Integer sqrtOfMinusOne p   = head@@ -152,7 +152,7 @@ tonelliShanks :: Integer -> Integer -> Integer tonelliShanks square prime = loop rc t1 generator log2   where-    (log2,q) = shiftToOddCount (prime-1)+    (wordToInt -> log2,q) = shiftToOddCount (prime-1)     nonSquare = findNonSquare prime     generator = powMod nonSquare q prime     rc = powMod square ((q+1) `quot` 2) prime@@ -176,7 +176,7 @@  -- | 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+sqrtModPP' n prime expo = case sqrtsModPrime n (Prime prime) of                             []    -> Nothing                             r : _ -> fixup r   where@@ -184,12 +184,12 @@               in if diff' == 0                    then Just r                    else case splitOff prime diff' of-                          (e,q) | expo <= intToWord e -> Just r+                          (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 <= intToWord ex    = root'+        | expo <= ex    = root'         | otherwise     = hoist inv root' (nelim `mod` prime) (prime^ex)           where             root' = (root + (inv*(prime-elim))*pp) `mod` (prime*pp)@@ -198,13 +198,13 @@  -- dirty, dirty sqM2P :: Integer -> Word -> Maybe Integer-sqM2P n (wordToInt -> e)+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+    | otherwise = fmap ((`mod` mdl) . (`shiftL` wordToInt k2)) $ solve s e2       where-        mdl = 1 `shiftL` e+        mdl = 1 `shiftL` wordToInt e         n' = n `mod` mdl         (k, s) = shiftToOddCount n'         k2 = k `quot` 2@@ -220,7 +220,7 @@                     | pw >= e2  = Just x                     | otherwise = fixup x' pw'                       where-                        x' = x + (1 `shiftL` (pw-1))+                        x' = x + (1 `shiftL` (wordToInt pw - 1))                         d = x'*x' - r                         pw' = if d == 0 then e2 else fst (shiftToOddCount d) @@ -239,7 +239,7 @@     | 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+                        ++ map unPrime (sieveFrom (68 + n `rem` 4)) -- prevent sharing         search (p:ps) = case jacobi p n of           MinusOne -> p           _        -> search ps
Math/NumberTheory/Moduli/SqrtOld.hs view
@@ -3,14 +3,13 @@ -- 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          #-}+{-# LANGUAGE ViewPatterns #-}  module Math.NumberTheory.Moduli.SqrtOld   ( sqrtModP@@ -26,15 +25,14 @@ 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.Primes.Types (unPrime) import Math.NumberTheory.Utils (shiftToOddCount, splitOff)+import Math.NumberTheory.Utils.FromIntegral  {-# DEPRECATED sqrtModP, sqrtModP', sqrtModPList, tonelliShanks "Use 'Math.NumberTheory.Moduli.Sqrt.sqrtsModPrime' instead" #-} {-# DEPRECATED sqrtModPP, sqrtModPPList "Use 'Math.NumberTheory.Moduli.Sqrt.sqrtsModPrimePower' instead" #-}@@ -119,12 +117,12 @@               in if diff' == 0                    then Just r                    else case splitOff prime diff' of-                          (e,q) | expo <= e -> Just r+                          (wordToInt -> 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'+        | expo <= wordToInt ex    = root'         | otherwise     = hoist inv root' (nelim `mod` prime) (prime^ex)           where             root' = (root + (inv*(prime-elim))*pp) `mod` (prime*pp)@@ -141,7 +139,7 @@       where         mdl = 1 `shiftL` e         n' = n `mod` mdl-        (k,s) = shiftToOddCount n'+        (wordToInt -> k,s) = shiftToOddCount n'         k2 = k `quot` 2         e2 = e-k         solve _ 1 = Just 1@@ -149,7 +147,7 @@         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))+            | otherwise     = fixup r (wordToInt $ fst $ shiftToOddCount (r-1))               where                 fixup x pw                     | pw >= e2  = Just x@@ -157,7 +155,7 @@                       where                         x' = x + (1 `shiftL` (pw-1))                         d = x'*x' - r-                        pw' = if d == 0 then e2 else fst (shiftToOddCount d)+                        pw' = if d == 0 then e2 else wordToInt (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@@ -222,7 +220,7 @@     | 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+                        ++ map unPrime (sieveFrom (68 + n `rem` 4)) -- prevent sharing         search (p:ps) = case jacobi p n of           MinusOne -> p           _        -> search ps
Math/NumberTheory/MoebiusInversion.hs view
@@ -3,23 +3,23 @@ -- Copyright:   (c) 2012 Daniel Fischer -- Licence:     MIT -- Maintainer:  Daniel Fischer <daniel.is.fischer@googlemail.com>--- Stability:   Provisional--- Portability: Non-portable (GHC extensions) -- -- Generalised Möbius inversion----{-# LANGUAGE BangPatterns, FlexibleContexts #-}++{-# LANGUAGE BangPatterns        #-}+{-# LANGUAGE FlexibleContexts    #-}+{-# LANGUAGE ScopedTypeVariables #-}+ module Math.NumberTheory.MoebiusInversion     ( generalInversion     , totientSum     ) where -import Data.Array.ST import Control.Monad import Control.Monad.ST+import qualified Data.Vector.Mutable as MV  import Math.NumberTheory.Powers.Squares-import Math.NumberTheory.Unsafe  -- | @totientSum n@ is, for @n > 0@, the sum of @[totient k | k <- [1 .. n]]@, --   computed via generalised Möbius inversion.@@ -85,58 +85,67 @@     | otherwise = fastInvert fun n  fastInvert :: (Int -> Integer) -> Int -> Integer-fastInvert fun n = big `unsafeAt` 0-  where-    !k0 = integerSquareRoot (n `quot` 2)-    !mk0 = n `quot` (2*k0+1)-    kmax a m = (a `quot` m - 1) `quot` 2-    big = runSTArray $ do-        small <- newArray_ (0,mk0) :: ST s (STArray s Int Integer)-        unsafeWrite small 0 0-        unsafeWrite small 1 $! (fun 1)-        when (mk0 >= 2) $-            unsafeWrite small 2 $! (fun 2 - fun 1)-        let calcit switch change i-                | mk0 < i   = return (switch,change)-                | i == change = calcit (switch+1) (change + 4*switch+6) i-                | otherwise = do-                    let mloop !acc k !m-                            | k < switch    = kloop acc k-                            | otherwise     = do-                                val <- unsafeRead small m-                                let nxtk = kmax i (m+1)-                                mloop (acc - fromIntegral (k-nxtk)*val) nxtk (m+1)-                        kloop !acc k-                            | k == 0    = do-                                unsafeWrite small i $! acc-                                calcit switch change (i+1)-                            | otherwise = do-                                val <- unsafeRead small (i `quot` (2*k+1))-                                kloop (acc-val) (k-1)-                    mloop (fun i - fun (i `quot` 2)) ((i-1) `quot` 2) 1-        (sw, ch) <- calcit 1 8 3-        large <- newArray_ (0,k0-1)-        let calcbig switch change j-                | j == 0    = return large-                | (2*j-1)*change <= n   = calcbig (switch+1) (change + 4*switch+6) j-                | otherwise = do-                    let i = n `quot` (2*j-1)-                        mloop !acc k m-                            | k < switch    = kloop acc k-                            | otherwise     = do-                                val <- unsafeRead small m-                                let nxtk = kmax i (m+1)-                                mloop (acc - fromIntegral (k-nxtk)*val) nxtk (m+1)-                        kloop !acc k-                            | k == 0    = do-                                unsafeWrite large (j-1) $! acc-                                calcbig switch change (j-1)-                            | otherwise = do-                                let m = i `quot` (2*k+1)-                                val <- if m <= mk0-                                         then unsafeRead small m-                                         else unsafeRead large (k*(2*j-1)+j-1)-                                kloop (acc-val) (k-1)-                    mloop (fun i - fun (i `quot` 2)) ((i-1) `quot` 2) 1-        calcbig sw ch k0+fastInvert fun n = runST (fastInvertST fun n)++fastInvertST :: forall s. (Int -> Integer) -> Int -> ST s Integer+fastInvertST fun n = do+    let !k0 = integerSquareRoot (n `quot` 2)+        !mk0 = n `quot` (2*k0+1)+        kmax a m = (a `quot` m - 1) `quot` 2++    small <- MV.unsafeNew (mk0 + 1) :: ST s (MV.MVector s Integer)+    MV.unsafeWrite small 0 0+    MV.unsafeWrite small 1 $! (fun 1)+    when (mk0 >= 2) $+        MV.unsafeWrite small 2 $! (fun 2 - fun 1)++    let calcit :: Int -> Int -> Int -> ST s (Int, Int)+        calcit switch change i+            | mk0 < i   = return (switch,change)+            | i == change = calcit (switch+1) (change + 4*switch+6) i+            | otherwise = do+                let mloop !acc k !m+                        | k < switch    = kloop acc k+                        | otherwise     = do+                            val <- MV.unsafeRead small m+                            let nxtk = kmax i (m+1)+                            mloop (acc - fromIntegral (k-nxtk)*val) nxtk (m+1)+                    kloop !acc k+                        | k == 0    = do+                            MV.unsafeWrite small i $! acc+                            calcit switch change (i+1)+                        | otherwise = do+                            val <- MV.unsafeRead small (i `quot` (2*k+1))+                            kloop (acc-val) (k-1)+                mloop (fun i - fun (i `quot` 2)) ((i-1) `quot` 2) 1++    (sw, ch) <- calcit 1 8 3+    large <- MV.unsafeNew k0 :: ST s (MV.MVector s Integer)++    let calcbig :: Int -> Int -> Int -> ST s (MV.MVector s Integer)+        calcbig switch change j+            | j == 0    = return large+            | (2*j-1)*change <= n   = calcbig (switch+1) (change + 4*switch+6) j+            | otherwise = do+                let i = n `quot` (2*j-1)+                    mloop !acc k m+                        | k < switch    = kloop acc k+                        | otherwise     = do+                            val <- MV.unsafeRead small m+                            let nxtk = kmax i (m+1)+                            mloop (acc - fromIntegral (k-nxtk)*val) nxtk (m+1)+                    kloop !acc k+                        | k == 0    = do+                            MV.unsafeWrite large (j-1) $! acc+                            calcbig switch change (j-1)+                        | otherwise = do+                            let m = i `quot` (2*k+1)+                            val <- if m <= mk0+                                     then MV.unsafeRead small m+                                     else MV.unsafeRead large (k*(2*j-1)+j-1)+                            kloop (acc-val) (k-1)+                mloop (fun i - fun (i `quot` 2)) ((i-1) `quot` 2) 1++    mvec <- calcbig sw ch k0+    MV.unsafeRead mvec 0 
Math/NumberTheory/MoebiusInversion/Int.hs view
@@ -3,24 +3,23 @@ -- Copyright:   (c) 2012 Daniel Fischer -- Licence:     MIT -- Maintainer:  Daniel Fischer <daniel.is.fischer@googlemail.com>--- Stability:   Provisional--- Portability: Non-portable (GHC extensions) -- -- Generalised Möbius inversion for 'Int' valued functions.----{-# LANGUAGE BangPatterns, FlexibleContexts #-}-{-# OPTIONS_GHC -fspec-constr-count=8 #-}++{-# LANGUAGE BangPatterns        #-}+{-# LANGUAGE FlexibleContexts    #-}+{-# LANGUAGE ScopedTypeVariables #-}+ module Math.NumberTheory.MoebiusInversion.Int     ( generalInversion     , totientSum     ) where -import Data.Array.ST import Control.Monad import Control.Monad.ST+import qualified Data.Vector.Unboxed.Mutable as MV  import Math.NumberTheory.Powers.Squares-import Math.NumberTheory.Unsafe  -- | @totientSum n@ is, for @n > 0@, the sum of @[totient k | k <- [1 .. n]]@, --   computed via generalised Möbius inversion.@@ -86,57 +85,66 @@     | otherwise = fastInvert fun n  fastInvert :: (Int -> Int) -> Int -> Int-fastInvert fun n = big `unsafeAt` 0-  where-    !k0 = integerSquareRoot (n `quot` 2)-    !mk0 = n `quot` (2*k0+1)-    kmax a m = (a `quot` m - 1) `quot` 2-    big = runSTUArray $ do-        small <- newArray_ (0,mk0) :: ST s (STUArray s Int Int)-        unsafeWrite small 0 0-        unsafeWrite small 1 (fun 1)-        when (mk0 >= 2) $-            unsafeWrite small 2 (fun 2 - fun 1)-        let calcit switch change i-                | mk0 < i   = return (switch,change)-                | i == change = calcit (switch+1) (change + 4*switch+6) i-                | otherwise = do-                    let mloop !acc k !m-                            | k < switch    = kloop acc k-                            | otherwise     = do-                                val <- unsafeRead small m-                                let nxtk = kmax i (m+1)-                                mloop (acc - (k-nxtk)*val) nxtk (m+1)-                        kloop !acc k-                            | k == 0    = do-                                unsafeWrite small i acc-                                calcit switch change (i+1)-                            | otherwise = do-                                val <- unsafeRead small (i `quot` (2*k+1))-                                kloop (acc-val) (k-1)-                    mloop (fun i - fun (i `quot` 2)) ((i-1) `quot` 2) 1-        (sw, ch) <- calcit 1 8 3-        large <- newArray_ (0,k0-1)-        let calcbig switch change j-                | j == 0    = return large-                | (2*j-1)*change <= n   = calcbig (switch+1) (change + 4*switch+6) j-                | otherwise = do-                    let i = n `quot` (2*j-1)-                        mloop !acc k m-                            | k < switch    = kloop acc k-                            | otherwise     = do-                                val <- unsafeRead small m-                                let nxtk = kmax i (m+1)-                                mloop (acc - (k-nxtk)*val) nxtk (m+1)-                        kloop !acc k-                            | k == 0    = do-                                unsafeWrite large (j-1) acc-                                calcbig switch change (j-1)-                            | otherwise = do-                                let m = i `quot` (2*k+1)-                                val <- if m <= mk0-                                         then unsafeRead small m-                                         else unsafeRead large (k*(2*j-1)+j-1)-                                kloop (acc-val) (k-1)-                    mloop (fun i - fun (i `quot` 2)) ((i-1) `quot` 2) 1-        calcbig sw ch k0+fastInvert fun n = runST (fastInvertST fun n)++fastInvertST :: forall s. (Int -> Int) -> Int -> ST s Int+fastInvertST fun n = do+    let !k0 = integerSquareRoot (n `quot` 2)+        !mk0 = n `quot` (2*k0+1)+        kmax a m = (a `quot` m - 1) `quot` 2++    small <- MV.unsafeNew (mk0 + 1) :: ST s (MV.MVector s Int)+    MV.unsafeWrite small 0 0+    MV.unsafeWrite small 1 $! (fun 1)+    when (mk0 >= 2) $+        MV.unsafeWrite small 2 $! (fun 2 - fun 1)++    let calcit :: Int -> Int -> Int -> ST s (Int, Int)+        calcit switch change i+            | mk0 < i   = return (switch,change)+            | i == change = calcit (switch+1) (change + 4*switch+6) i+            | otherwise = do+                let mloop !acc k !m+                        | k < switch    = kloop acc k+                        | otherwise     = do+                            val <- MV.unsafeRead small m+                            let nxtk = kmax i (m+1)+                            mloop (acc - fromIntegral (k-nxtk)*val) nxtk (m+1)+                    kloop !acc k+                        | k == 0    = do+                            MV.unsafeWrite small i $! acc+                            calcit switch change (i+1)+                        | otherwise = do+                            val <- MV.unsafeRead small (i `quot` (2*k+1))+                            kloop (acc-val) (k-1)+                mloop (fun i - fun (i `quot` 2)) ((i-1) `quot` 2) 1++    (sw, ch) <- calcit 1 8 3+    large <- MV.unsafeNew k0 :: ST s (MV.MVector s Int)++    let calcbig :: Int -> Int -> Int -> ST s (MV.MVector s Int)+        calcbig switch change j+            | j == 0    = return large+            | (2*j-1)*change <= n   = calcbig (switch+1) (change + 4*switch+6) j+            | otherwise = do+                let i = n `quot` (2*j-1)+                    mloop !acc k m+                        | k < switch    = kloop acc k+                        | otherwise     = do+                            val <- MV.unsafeRead small m+                            let nxtk = kmax i (m+1)+                            mloop (acc - fromIntegral (k-nxtk)*val) nxtk (m+1)+                    kloop !acc k+                        | k == 0    = do+                            MV.unsafeWrite large (j-1) $! acc+                            calcbig switch change (j-1)+                        | otherwise = do+                            let m = i `quot` (2*k+1)+                            val <- if m <= mk0+                                     then MV.unsafeRead small m+                                     else MV.unsafeRead large (k*(2*j-1)+j-1)+                            kloop (acc-val) (k-1)+                mloop (fun i - fun (i `quot` 2)) ((i-1) `quot` 2) 1++    mvec <- calcbig sw ch k0+    MV.unsafeRead mvec 0
Math/NumberTheory/Powers.hs view
@@ -3,8 +3,6 @@ -- Copyright:   (c) 2011 Daniel Fischer -- Licence:     MIT -- Maintainer:  Daniel Fischer <daniel.is.fischer@googlemail.com>--- Stability:   Provisional--- Portability: Non-portable (GHC extensions) -- -- Calculating integer roots, modular powers and related things. -- This module reexports the most needed functions from the implementation
Math/NumberTheory/Powers/Cubes.hs view
@@ -3,8 +3,6 @@ -- Copyright:   (c) 2011 Daniel Fischer -- Licence:     MIT -- Maintainer:  Daniel Fischer <daniel.is.fischer@googlemail.com>--- Stability:   Provisional--- Portability: Non-portable (GHC extensions) -- -- Functions dealing with cubes. Moderately efficient calculation of integer -- cube roots and testing for cubeness.@@ -20,25 +18,26 @@  #include "MachDeps.h" -import Data.Array.Unboxed-import Data.Array.ST-+import Control.Monad.ST import Data.Bits+import qualified Data.Vector.Unboxed as V+import qualified Data.Vector.Unboxed.Mutable as MV  import GHC.Base import GHC.Integer import GHC.Integer.GMP.Internals import GHC.Integer.Logarithms (integerLog2#) -import Math.NumberTheory.Unsafe+import Numeric.Natural  -- | Calculate the integer cube root of an integer @n@, --   that is the largest integer @r@ such that @r^3 <= n@. --   Note that this is not symmetric about @0@, for example --   @integerCubeRoot (-2) = (-2)@ while @integerCubeRoot 2 = 1@. {-# SPECIALISE integerCubeRoot :: Int -> Int,+                                  Word -> Word,                                   Integer -> Integer,-                                  Word -> Word+                                  Natural -> Natural   #-} integerCubeRoot :: Integral a => a -> a integerCubeRoot 0 = 0@@ -68,7 +67,8 @@ --   @Just r@ if @n == r^3@. {-# SPECIALISE exactCubeRoot :: Int -> Maybe Int,                                 Word -> Maybe Word,-                                Integer -> Maybe Integer+                                Integer -> Maybe Integer,+                                Natural -> Maybe Natural   #-} exactCubeRoot :: Integral a => a -> Maybe a exactCubeRoot 0 = Just 0@@ -85,8 +85,9 @@  -- | Test whether an integer is a cube. {-# SPECIALISE isCube :: Int -> Bool,+                         Word -> Bool,                          Integer -> Bool,-                         Word -> Bool+                         Natural -> Bool   #-} isCube :: Integral a => a -> Bool isCube 0 = True@@ -104,8 +105,9 @@ --   this is much faster than @let r = cubeRoot n in r*r*r == n@. --   The condition @n >= 0@ is /not/ checked. {-# SPECIALISE isCube' :: Int -> Bool,+                          Word -> Bool,                           Integer -> Bool,-                          Word -> Bool+                          Natural -> Bool   #-} isCube' :: Integral a => a -> Bool isCube' !n = isPossibleCube n@@ -117,15 +119,16 @@ --   Only about 0.08% of all numbers pass this test. --   The precondition @n >= 0@ is /not/ checked. {-# SPECIALISE isPossibleCube :: Int -> Bool,+                                 Word -> Bool,                                  Integer -> Bool,-                                 Word -> Bool+                                 Natural -> Bool   #-} isPossibleCube :: Integral a => a -> Bool-isPossibleCube !n =-    unsafeAt cr512 (fromIntegral n .&. 511)-    && unsafeAt cubeRes837 (fromIntegral (n `rem` 837))-    && unsafeAt cubeRes637 (fromIntegral (n `rem` 637))-    && unsafeAt cubeRes703 (fromIntegral (n `rem` 703))+isPossibleCube !n+    =  V.unsafeIndex cr512 (fromIntegral n .&. 511)+    && V.unsafeIndex cubeRes837 (fromIntegral (n `rem` 837))+    && V.unsafeIndex cubeRes637 (fromIntegral (n `rem` 637))+    && V.unsafeIndex cubeRes703 (fromIntegral (n `rem` 703))  ---------------------------------------------------------------------- --                         Utility Functions                        --@@ -168,7 +171,6 @@ cubeRootIgr 0 = 0 cubeRootIgr n = newton3 n (approxCuRt n) -{-# SPECIALISE newton3 :: Int -> Int -> Int #-} {-# SPECIALISE newton3 :: Integer -> Integer -> Integer #-} newton3 :: Integral a => a -> a -> a newton3 n a = go (step a)@@ -210,40 +212,43 @@ appCuRt _ = error "integerCubeRoot': negative argument"  -- not very discriminating, but cheap, so it's an overall gain-cr512 :: UArray Int Bool-cr512 = runSTUArray $ do-    ar <- newArray (0,511) True+cr512 :: V.Vector Bool+cr512 = runST $ do+    ar <- MV.replicate 512 True     let note s i-            | i < 512   = unsafeWrite ar i False >> note s (i+s)+            | i < 512   = MV.unsafeWrite ar i False >> note s (i+s)             | otherwise = return ()     note 4 2     note 8 4     note 32 16     note 64 32     note 256 128-    unsafeWrite ar 256 False-    return ar+    MV.unsafeWrite ar 256 False+    V.unsafeFreeze ar  -- Remainders modulo @3^3 * 31@-cubeRes837 :: UArray Int Bool-cubeRes837 = runSTUArray $ do-    ar <- newArray (0,836) False-    let note 837 = return ar-        note k = unsafeWrite ar ((k*k*k) `rem` 837) True >> note (k+1)+cubeRes837 :: V.Vector Bool+cubeRes837 = runST $ do+    ar <- MV.replicate 837 False+    let note 837 = return ()+        note k = MV.unsafeWrite ar ((k*k*k) `rem` 837) True >> note (k+1)     note 0+    V.unsafeFreeze ar  -- Remainders modulo @7^2 * 13@-cubeRes637 :: UArray Int Bool-cubeRes637 = runSTUArray $ do-    ar <- newArray (0,636) False-    let note 637 = return ar-        note k = unsafeWrite ar ((k*k*k) `rem` 637) True >> note (k+1)+cubeRes637 :: V.Vector Bool+cubeRes637 = runST $ do+    ar <- MV.replicate 637 False+    let note 637 = return ()+        note k = MV.unsafeWrite ar ((k*k*k) `rem` 637) True >> note (k+1)     note 0+    V.unsafeFreeze ar  -- Remainders modulo @19 * 37@-cubeRes703 :: UArray Int Bool-cubeRes703 = runSTUArray $ do-    ar <- newArray (0,702) False-    let note 703 = return ar-        note k = unsafeWrite ar ((k*k*k) `rem` 703) True >> note (k+1)+cubeRes703 :: V.Vector Bool+cubeRes703 = runST $ do+    ar <- MV.replicate 703 False+    let note 703 = return ()+        note k = MV.unsafeWrite ar ((k*k*k) `rem` 703) True >> note (k+1)     note 0+    V.unsafeFreeze ar
Math/NumberTheory/Powers/Fourth.hs view
@@ -3,8 +3,6 @@ -- Copyright:   (c) 2011 Daniel Fischer -- Licence:     MIT -- Maintainer:  Daniel Fischer <daniel.is.fischer@googlemail.com>--- Stability:   Provisional--- Portability: Non-portable (GHC extensions) -- -- Functions dealing with fourth powers. Efficient calculation of integer fourth -- roots and efficient testing for being a square's square.@@ -20,24 +18,25 @@  #include "MachDeps.h" +import Control.Monad.ST+import Data.Bits+import qualified Data.Vector.Unboxed as V+import qualified Data.Vector.Unboxed.Mutable as MV+ import GHC.Base import GHC.Integer import GHC.Integer.GMP.Internals import GHC.Integer.Logarithms (integerLog2#) -import Data.Array.Unboxed-import Data.Array.ST--import Data.Bits--import Math.NumberTheory.Unsafe+import Numeric.Natural  -- | Calculate the integer fourth root of a nonnegative number, --   that is, the largest integer @r@ with @r^4 <= n@. --   Throws an error on negaitve input. {-# SPECIALISE integerFourthRoot :: Int -> Int,+                                    Word -> Word,                                     Integer -> Integer,-                                    Word -> Word+                                    Natural -> Natural   #-} integerFourthRoot :: Integral a => a -> a integerFourthRoot n@@ -60,8 +59,9 @@ -- | Returns @Nothing@ if @n@ is not a fourth power, --   @Just r@ if @n == r^4@ and @r >= 0@. {-# SPECIALISE exactFourthRoot :: Int -> Maybe Int,+                                  Word -> Maybe Word,                                   Integer -> Maybe Integer,-                                  Word -> Maybe Word+                                  Natural -> Maybe Natural   #-} exactFourthRoot :: Integral a => a -> Maybe a exactFourthRoot 0 = Just 0@@ -77,8 +77,9 @@ --   First nonnegativity is checked, then the unchecked --   test is called. {-# SPECIALISE isFourthPower :: Int -> Bool,+                                Word -> Bool,                                 Integer -> Bool,-                                Word -> Bool+                                Natural -> Bool   #-} isFourthPower :: Integral a => a -> Bool isFourthPower 0 = True@@ -89,8 +90,9 @@ --   'isPossibleFourthPower' test, its integer fourth root --   is calculated. {-# SPECIALISE isFourthPower' :: Int -> Bool,+                                 Word -> Bool,                                  Integer -> Bool,-                                 Word -> Bool+                                 Natural -> Bool   #-} isFourthPower' :: Integral a => a -> Bool isFourthPower' n = isPossibleFourthPower n && r2*r2 == n@@ -102,14 +104,15 @@ --   The condition is /not/ checked. --   This eliminates about 99.958% of numbers. {-# SPECIALISE isPossibleFourthPower :: Int -> Bool,+                                        Word -> Bool,                                         Integer -> Bool,-                                        Word -> Bool+                                        Natural -> Bool   #-} isPossibleFourthPower :: Integral a => a -> Bool-isPossibleFourthPower n =-        biSqRes256 `unsafeAt` (fromIntegral n .&. 255)-      && biSqRes425 `unsafeAt` (fromIntegral (n `rem` 425))-      && biSqRes377 `unsafeAt` (fromIntegral (n `rem` 377))+isPossibleFourthPower n+  =  V.unsafeIndex biSqRes256 (fromIntegral n .&. 255)+  && V.unsafeIndex biSqRes425 (fromIntegral (n `rem` 425))+  && V.unsafeIndex biSqRes377 (fromIntegral (n `rem` 377))  {-# SPECIALISE newton4 :: Integer -> Integer -> Integer #-} newton4 :: Integral a => a -> a -> a@@ -151,28 +154,31 @@ appBiSqrt _ = error "integerFourthRoot': negative argument"  -biSqRes256 :: UArray Int Bool-biSqRes256 = runSTUArray $ do-    ar <- newArray (0,255) False-    let note 257 = return ar-        note i = unsafeWrite ar i True >> note (i+16)-    unsafeWrite ar 0 True-    unsafeWrite ar 16 True+biSqRes256 :: V.Vector Bool+biSqRes256 = runST $ do+    ar <- MV.replicate 256 False+    let note 257 = return ()+        note i = MV.unsafeWrite ar i True >> note (i+16)+    MV.unsafeWrite ar 0 True+    MV.unsafeWrite ar 16 True     note 1+    V.unsafeFreeze ar -biSqRes425 :: UArray Int Bool-biSqRes425 = runSTUArray $ do-    ar <- newArray (0,424) False-    let note 154 = return ar-        note i = unsafeWrite ar ((i*i*i*i) `rem` 425) True >> note (i+1)+biSqRes425 :: V.Vector Bool+biSqRes425 = runST $ do+    ar <- MV.replicate 425 False+    let note 154 = return ()+        note i = MV.unsafeWrite ar ((i*i*i*i) `rem` 425) True >> note (i+1)     note 0+    V.unsafeFreeze ar -biSqRes377 :: UArray Int Bool-biSqRes377 = runSTUArray $ do-    ar <- newArray (0,376) False-    let note 144 = return ar-        note i = unsafeWrite ar ((i*i*i*i) `rem` 377) True >> note (i+1)+biSqRes377 :: V.Vector Bool+biSqRes377 = runST $ do+    ar <- MV.replicate 377 False+    let note 144 = return ()+        note i = MV.unsafeWrite ar ((i*i*i*i) `rem` 377) True >> note (i+1)     note 0+    V.unsafeFreeze ar  biSqrtInt :: Int -> Int biSqrtInt 0 = 0
Math/NumberTheory/Powers/General.hs view
@@ -3,8 +3,6 @@ -- Copyright:   (c) 2011 Daniel Fischer -- Licence:     MIT -- Maintainer:  Daniel Fischer <daniel.is.fischer@googlemail.com>--- Stability:   Provisional--- Portability: Non-portable (GHC extensions) -- -- Calculating integer roots and determining perfect powers. -- The algorithms are moderately efficient.@@ -31,6 +29,8 @@ import Data.List (foldl') import qualified Data.Set as Set +import Numeric.Natural+ import Math.NumberTheory.Logarithms (integerLogBase') import Math.NumberTheory.Utils  (shiftToOddCount                                 , splitOff@@ -38,6 +38,7 @@ import qualified Math.NumberTheory.Powers.Squares as P2 import qualified Math.NumberTheory.Powers.Cubes as P3 import qualified Math.NumberTheory.Powers.Fourth as P4+import Math.NumberTheory.Utils.FromIntegral (intToWord, wordToInt)  -- | Calculate an integer root, @'integerRoot' k n@ computes the (floor of) the @k@-th --   root of @n@, where @k@ must be positive.@@ -50,10 +51,13 @@ {-# SPECIALISE integerRoot :: Int -> Int -> Int,                               Int -> Word -> Word,                               Int -> Integer -> Integer,+                              Int -> Natural -> Natural,                               Word -> Int -> Int,                               Word -> Word -> Word,                               Word -> Integer -> Integer,-                              Integer -> Integer -> Integer+                              Word -> Natural -> Natural,+                              Integer -> Integer -> Integer,+                              Natural -> Natural -> Natural   #-} integerRoot :: (Integral a, Integral b) => b -> a -> a integerRoot 1 n         = n@@ -155,7 +159,7 @@ --   remaining factor is examined by trying the divisors of the @gcd@ --   of the prime exponents if some have been found, otherwise by trying --   prime exponents recursively.-highestPower :: Integral a => a -> (a, Int)+highestPower :: Integral a => a -> (a, Word) highestPower n'   | abs n <= 1  = (n', 3)   | n < 0       = case integerHighPower (negate n) of@@ -167,7 +171,7 @@       n :: Integer       n = toInteger n' -      sqr :: Int -> Integer -> Integer+      sqr :: Word -> Integer -> Integer       sqr 0 m = m       sqr k m = sqr (k-1) (m*m) @@ -180,18 +184,19 @@ --   and primality testing, it is not expected to be generally useful. --   The assumptions are not checked, if they are not satisfied, wrong --   results and wasted work may be the consequence.-largePFPower :: Integer -> Integer -> (Integer, Int)+largePFPower :: Integer -> Integer -> (Integer, Word) largePFPower bd n = rawPower ln n   where-    ln = integerLogBase' (bd+1) n+    ln = intToWord (integerLogBase' (bd+1) n)  ------------------------------------------------------------------------------------------ --                                  Auxiliary functions                                 -- ------------------------------------------------------------------------------------------  {-# SPECIALISE newtonK :: Int -> Int -> Int -> Int,+                          Word -> Word -> Word -> Word,                           Integer -> Integer -> Integer -> Integer,-                          Word -> Word -> Word -> Word+                          Natural -> Natural -> Natural -> Natural   #-} newtonK :: Integral a => a -> a -> a -> a newtonK k n a = go (step a)@@ -204,9 +209,10 @@         where           l = step m -{-# SPECIALISE approxKthRoot :: Int -> Integer -> Integer,-                                Int -> Int -> Int,-                                Int -> Word -> Word+{-# SPECIALISE approxKthRoot :: Int -> Int -> Int,+                                Int -> Word -> Word,+                                Int -> Integer -> Integer,+                                Int -> Natural -> Natural   #-} approxKthRoot :: Integral a => Int -> a -> a approxKthRoot k = fromInteger . appKthRoot k . fromIntegral@@ -230,7 +236,7 @@                           `shiftLInteger` (h# -# 401#)  -- assumption: argument is > 1-integerHighPower :: Integer -> (Integer, Int)+integerHighPower :: Integer -> (Integer, Word) integerHighPower n   | n < 4       = (n,1)   | otherwise   = case shiftToOddCount n of@@ -239,7 +245,7 @@                              where                                r = P2.integerSquareRoot m -findHighPower :: Int -> [(Integer,Int)] -> Integer -> Integer -> [Integer] -> (Integer, Int)+findHighPower :: Word -> [(Integer, Word)] -> Integer -> Integer -> [Integer] -> (Integer, Word) findHighPower 1 pws m _ _ = (foldl' (*) m [p^e | (p,e) <- pws], 1) findHighPower e pws 1 _ _ = (foldl' (*) 1 [p^(ex `quot` e) | (p,ex) <- pws], e) findHighPower e pws m s (p:ps)@@ -250,7 +256,7 @@       (k,r) -> findHighPower (gcd k e) ((p,k):pws) r (P2.integerSquareRoot r) ps findHighPower e pws m _ [] = finishPower e pws m -spBEx :: Int+spBEx :: Word spBEx = 14  spBound :: Integer@@ -266,20 +272,20 @@         go []     = True  -- n large, has no prime divisors < spBound-finishPower :: Int -> [(Integer, Int)] -> Integer -> (Integer, Int)+finishPower :: Word -> [(Integer, Word)] -> Integer -> (Integer, Word) finishPower e pws n-  | n < (1 `shiftL` (2*spBEx))  = (foldl' (*) n [p^ex | (p,ex) <- pws], 1)    -- n is prime+  | n < (1 `shiftL` wordToInt (2*spBEx))  = (foldl' (*) n [p^ex | (p,ex) <- pws], 1)    -- n is prime   | e == 0  = rawPower maxExp n   | otherwise = go divs     where-      maxExp = (I# (integerLog2# n)) `quot` spBEx+      maxExp = (W# (int2Word# (integerLog2# n))) `quot` spBEx       divs = divisorsTo maxExp e       go [] = (foldl' (*) n [p^ex | (p,ex) <- pws], 1)       go (d:ds) = case exactRoot d n of                     Just r -> (foldl' (*) r [p^(ex `quot` d) | (p,ex) <- pws], d)                     Nothing -> go ds -rawPower :: Int -> Integer -> (Integer, Int)+rawPower :: Word -> Integer -> (Integer, Word) rawPower mx n   | mx < 2      = (n,1)   | mx == 2     = case P2.exactSquareRoot n of@@ -293,7 +299,7 @@                                            (m,e) -> (m, 2*e)                                Nothing -> rawOddPower mx n -rawOddPower :: Int -> Integer -> (Integer, Int)+rawOddPower :: Word -> Integer -> (Integer, Word) rawOddPower mx n   | mx < 3       = (n,1) rawOddPower mx n = case P3.exactCubeRoot n of@@ -301,7 +307,7 @@                                  (m,e) -> (m, 3*e)                      Nothing -> badPower mx n -badPower :: Int -> Integer -> (Integer, Int)+badPower :: Word -> Integer -> (Integer, Word) badPower mx n   | mx < 5      = (n,1)   | otherwise   = go 1 mx n (takeWhile (<= mx) $ scanl (+) 5 $ cycle [2,4])@@ -313,25 +319,25 @@                         Nothing -> go e b m ks       go e _ m []   = (m,e) -divisorsTo :: Int -> Int -> [Int]+divisorsTo :: Word -> Word -> [Word] divisorsTo mx n = case shiftToOddCount n of                     (k,o) | k == 0 -> go (Set.singleton 1) n iops-                          | otherwise -> go (Set.fromDistinctAscList $ takeWhile (<= mx) $ take (k+1) (iterate (*2) 1)) o iops+                          | otherwise -> go (Set.fromDistinctAscList $ takeWhile (<= mx) $ take (wordToInt k + 1) (iterate (*2) 1)) o iops   where     mset k st = fst (Set.split (mx+1) (Set.mapMonotonic (*k) st))     -- unP p m = (k, m / p ^ k), where k is as large as possible such that p ^ k still divides m-    unP :: Int -> Int -> (Int,Int)+    unP :: Word -> Word -> (Word, Word)     unP p m = goP 0 m       where-        goP :: Int -> Int -> (Int,Int)+        goP :: Word -> Word -> (Word, Word)         goP !i j = case j `quotRem` p of                      (q,r) | r == 0 -> goP (i+1) q                            | otherwise -> (i,j)-    iops :: [Int]+    iops :: [Word]     iops = 3:5:prs-    prs :: [Int]+    prs :: [Word]     prs = 7:filter prm (scanl (+) 11 $ cycle [2,4,2,4,6,2,6,4])-    prm :: Int -> Bool+    prm :: Word -> Bool     prm k = td prs       where         td (p:ps) = (p*p > k) || (k `rem` p /= 0 && td ps)@@ -343,5 +349,5 @@         case unP p m of           (0,_) -> go st m ps           -- iterate f x = [x, f x, f (f x)...]-          (k,r) -> go (Set.unions (take (k + 1) (iterate (mset p) st))) r ps+          (k,r) -> go (Set.unions (take (wordToInt k + 1) (iterate (mset p) st))) r ps     go st m [] = go st m [m+1]
Math/NumberTheory/Powers/Modular.hs view
@@ -3,8 +3,6 @@ -- Copyright:   (c) 2017 Andrew Lelechenko -- Licence:     MIT -- Maintainer:  Andrew Lelechenko <andrew.lelechenko@gmail.com>--- Stability:   Provisional--- Portability: Non-portable (GHC extensions) -- -- Modular powers (a. k. a. modular exponentiation). --@@ -44,7 +42,7 @@ -- -- >>> powMod 3 101 (2^60-1 :: Integer) -- 1018105167100379328 -- correct--- >>> powMod 3 101 (2^60-1 :: Int64)+-- >>> powMod 3 101 (2^60-1 :: Int) -- 1115647832265427613 -- incorrect due to overflow -- >>> powModInt 3 101 (2^60-1 :: Int) -- 1018105167100379328 -- correct
Math/NumberTheory/Powers/Squares.hs view
@@ -3,8 +3,6 @@ -- Copyright:   (c) 2011 Daniel Fischer -- Licence:     MIT -- Maintainer:  Daniel Fischer <daniel.is.fischer@googlemail.com>--- Stability:   Provisional--- Portability: Non-portable (GHC extensions) -- -- Functions dealing with squares. Efficient calculation of integer square roots -- and efficient testing for squareness.@@ -25,12 +23,12 @@  #include "MachDeps.h" -import Data.Array.Unboxed-import Data.Array.ST-+import Control.Monad.ST import Data.Bits+import qualified Data.Vector.Unboxed as V+import qualified Data.Vector.Unboxed.Mutable as MV -import Math.NumberTheory.Unsafe+import Numeric.Natural  import Math.NumberTheory.Powers.Squares.Internal @@ -39,7 +37,8 @@ --   Throws an error on negative input. {-# SPECIALISE integerSquareRoot :: Int -> Int,                                     Word -> Word,-                                    Integer -> Integer+                                    Integer -> Integer,+                                    Natural -> Natural   #-} integerSquareRoot :: Integral a => a -> a integerSquareRoot n@@ -64,7 +63,8 @@ {-# SPECIALISE integerSquareRootRem ::         Int -> (Int, Int),         Word -> (Word, Word),-        Integer -> (Integer, Integer)+        Integer -> (Integer, Integer),+        Natural -> (Natural, Natural)   #-} integerSquareRootRem :: Integral a => a -> (a, a) integerSquareRootRem n@@ -92,7 +92,8 @@ --   Checks for negativity and 'isPossibleSquare'. {-# SPECIALISE exactSquareRoot :: Int -> Maybe Int,                                   Word -> Maybe Word,-                                  Integer -> Maybe Integer+                                  Integer -> Maybe Integer,+                                  Natural -> Maybe Natural   #-} exactSquareRoot :: Integral a => a -> Maybe a exactSquareRoot n@@ -106,7 +107,8 @@ --   is checked, if it is, the integer square root is calculated. {-# SPECIALISE isSquare :: Int -> Bool,                            Word -> Bool,-                           Integer -> Bool+                           Integer -> Bool,+                           Natural -> Bool   #-} isSquare :: Integral a => a -> Bool isSquare n = n >= 0 && isSquare' n@@ -119,7 +121,8 @@ --   arguments may cause any kind of havoc. {-# SPECIALISE isSquare' :: Int -> Bool,                             Word -> Bool,-                            Integer -> Bool+                            Integer -> Bool,+                            Natural -> Bool   #-} isSquare' :: Integral a => a -> Bool isSquare' n@@ -137,17 +140,18 @@ --   to eliminate altogether about 99.436% of all numbers. -- --   This is the test used by 'exactSquareRoot'. For large numbers,---   the slower but more discriminating test 'isPossibleSqure2' is+--   the slower but more discriminating test 'isPossibleSquare2' is --   faster. {-# SPECIALISE isPossibleSquare :: Int -> Bool,+                                   Word -> Bool,                                    Integer -> Bool,-                                   Word -> Bool+                                   Natural -> Bool   #-} isPossibleSquare :: Integral a => a -> Bool-isPossibleSquare n =-  unsafeAt sr256 ((fromIntegral n) .&. 255)-  && unsafeAt sr693 (fromIntegral (n `rem` 693))-  && unsafeAt sr325 (fromIntegral (n `rem` 325))+isPossibleSquare n+  =  V.unsafeIndex sr256 ((fromIntegral n) .&. 255)+  && V.unsafeIndex sr693 (fromIntegral (n `rem` 693))+  && V.unsafeIndex sr325 (fromIntegral (n `rem` 325))  -- | Test whether a non-negative number may be a square. --   Non-negativity is not checked, passing negative arguments may@@ -163,55 +167,57 @@ --   numbers, where calculating the square root becomes more expensive, --   it is much faster (if the vast majority of tested numbers aren't squares). {-# SPECIALISE isPossibleSquare2 :: Int -> Bool,+                                    Word -> Bool,                                     Integer -> Bool,-                                    Word -> Bool+                                    Natural -> Bool   #-} isPossibleSquare2 :: Integral a => a -> Bool-isPossibleSquare2 n =-  unsafeAt sr256 ((fromIntegral n) .&. 255)-  && unsafeAt sr819  (fromIntegral (n `rem` 819))-  && unsafeAt sr1025 (fromIntegral (n `rem` 1025))-  && unsafeAt sr2047 (fromIntegral (n `rem` 2047))-  && unsafeAt sr4097 (fromIntegral (n `rem` 4097))-  && unsafeAt sr341  (fromIntegral (n `rem` 341))+isPossibleSquare2 n+  =  V.unsafeIndex sr256  ((fromIntegral n) .&. 255)+  && V.unsafeIndex sr819  (fromIntegral (n `rem` 819))+  && V.unsafeIndex sr1025 (fromIntegral (n `rem` 1025))+  && V.unsafeIndex sr2047 (fromIntegral (n `rem` 2047))+  && V.unsafeIndex sr4097 (fromIntegral (n `rem` 4097))+  && V.unsafeIndex sr341  (fromIntegral (n `rem` 341))  ----------------------------------------------------------------------------- --  Auxiliary Stuff  -- Make an array indicating whether a remainder is a square remainder.-sqRemArray :: Int -> UArray Int Bool-sqRemArray md = runSTUArray $ do-  arr <- newArray (0,md-1) False+sqRemArray :: Int -> V.Vector Bool+sqRemArray md = runST $ do+  ar <- MV.replicate md False   let !stop = (md `quot` 2) + 1       fill k-        | k < stop  = unsafeWrite arr ((k*k) `rem` md) True >> fill (k+1)-        | otherwise = return arr-  unsafeWrite arr 0 True-  unsafeWrite arr 1 True+        | k < stop  = MV.unsafeWrite ar ((k*k) `rem` md) True >> fill (k+1)+        | otherwise = return ()+  MV.unsafeWrite ar 0 True+  MV.unsafeWrite ar 1 True   fill 2+  V.unsafeFreeze ar -sr256 :: UArray Int Bool+sr256 :: V.Vector Bool sr256 = sqRemArray 256 -sr819 :: UArray Int Bool+sr819 :: V.Vector Bool sr819 = sqRemArray 819 -sr4097 :: UArray Int Bool+sr4097 :: V.Vector Bool sr4097 = sqRemArray 4097 -sr341 :: UArray Int Bool+sr341 :: V.Vector Bool sr341 = sqRemArray 341 -sr1025 :: UArray Int Bool+sr1025 :: V.Vector Bool sr1025 = sqRemArray 1025 -sr2047 :: UArray Int Bool+sr2047 :: V.Vector Bool sr2047 = sqRemArray 2047 -sr693 :: UArray Int Bool+sr693 :: V.Vector Bool sr693 = sqRemArray 693 -sr325 :: UArray Int Bool+sr325 :: V.Vector Bool sr325 = sqRemArray 325  -- Specialisations for Int, Word, and Integer
Math/NumberTheory/Powers/Squares/Internal.hs view
@@ -3,8 +3,6 @@ -- Copyright:   (c) 2016 Andrew Lelechenko -- Licence:     MIT -- Maintainer:  Andrew Lelechenko <andrew.lelechenko@gmail.com>--- Stability:   Provisional--- Portability: Non-portable (GHC extensions) -- -- Internal functions dealing with square roots. End-users should not import this module. 
Math/NumberTheory/Prefactored.hs view
@@ -3,8 +3,6 @@ -- Copyright:   (c) 2017 Andrew Lelechenko -- Licence:     MIT -- Maintainer:  Andrew Lelechenko <andrew.lelechenko@gmail.com>--- Stability:   Provisional--- Portability: Non-portable (GHC extensions) -- -- Type for numbers, accompanied by their factorisation. --@@ -26,7 +24,8 @@  import Math.NumberTheory.Euclidean import Math.NumberTheory.Euclidean.Coprimes-import Math.NumberTheory.UniqueFactorisation+import Math.NumberTheory.Primes+import Math.NumberTheory.Primes.Types  -- | A container for a number and its pairwise coprime (but not neccessarily prime) -- factorisation.@@ -36,29 +35,23 @@ -- -- For instance, let @p@ and @q@ be big primes: ----- >>> let p, q :: Integer--- >>>     p = 1000000000000000000000000000057--- >>>     q = 2000000000000000000000000000071+-- >>> let p = 1000000000000000000000000000057 :: Integer+-- >>> let q = 2000000000000000000000000000071 :: Integer ----- It would be  difficult to compute prime factorisation of their product--- as is:--- 'factorise' would take ages. Things become different if we simply+-- It would be difficult to compute the totient function+-- of their product as is, because once we multiplied them+-- the information of factors is lost and+-- 'Math.NumberTheory.ArithmeticFunctions.totient' (@p@ * @q@)+-- 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------ 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)]+-- >>> let p = 1000000000000000000000000000057 :: Prefactored Integer+-- >>> let q = 2000000000000000000000000000071 :: Prefactored Integer ----- Moreover, we can instantly compute 'totient' and its iterations.--- It works fine, because output of 'totient' is also prefactored.+-- Now the 'Math.NumberTheory.ArithmeticFunctions.totient' function+-- can be computed instantly: --+-- >>> import Math.NumberTheory.ArithmeticFunctions -- >>> prefValue $ totient (p^2 * q^3) -- 8000000000000000000000000001752000000000000000000000000151322000000000000000000000006445392000000000000000000000135513014000000000000000000001126361040 -- >>> prefValue $ totient $ totient (p^2 * q^3)@@ -66,14 +59,11 @@ -- -- Let us look under the hood: --+-- >>> import Math.NumberTheory.ArithmeticFunctions -- >>> prefFactors $ totient (p^2 * q^3)--- Coprimes {unCoprimes = fromList [(2,4),(3,3),---   (41666666666666666666666666669,1),(111111111111111111111111111115,1),---   (1000000000000000000000000000057,1),(2000000000000000000000000000071,2)]}+-- Coprimes {unCoprimes = [(1000000000000000000000000000057,1),(41666666666666666666666666669,1),(2000000000000000000000000000071,2),(111111111111111111111111111115,1),(2,4),(3,3)]} -- >>> 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)]}+-- Coprimes {unCoprimes = [(39521,1),(6046667,1),(22222222222222222222222222223,1),(2000000000000000000000000000071,1),(361696272343,1),(85331809838489,1),(227098769,1),(199937,1),(5,3),(41666666666666666666666666669,1),(2,22),(3,8)]} -- -- Pairwise coprimality of factors is crucial, because it allows -- us to process them independently, possibly even@@ -93,7 +83,7 @@ -- | Create 'Prefactored' from a given number. -- -- >>> fromValue 123--- Prefactored {prefValue = 123, prefFactors = Coprimes {unCoprimes = fromList [(123,1)]}}+-- Prefactored {prefValue = 123, prefFactors = Coprimes {unCoprimes = [(123,1)]}} fromValue :: (Eq a, Num a) => a -> Prefactored a fromValue a = Prefactored a (singleton a 1) @@ -101,13 +91,13 @@ -- (but not neccesarily prime) factors with multiplicities. -- -- >>> fromFactors (splitIntoCoprimes [(140, 1), (165, 1)])--- Prefactored {prefValue = 23100, prefFactors = Coprimes {unCoprimes = fromList [(5,2),(28,1),(33,1)]}}+-- Prefactored {prefValue = 23100, prefFactors = Coprimes {unCoprimes = [(28,1),(33,1),(5,2)]}} -- >>> fromFactors (splitIntoCoprimes [(140, 2), (165, 3)])--- Prefactored {prefValue = 88045650000, prefFactors = Coprimes {unCoprimes = fromList [(5,5),(28,2),(33,3)]}}+-- Prefactored {prefValue = 88045650000, prefFactors = Coprimes {unCoprimes = [(28,2),(33,3),(5,5)]}} fromFactors :: Num a => Coprimes a Word -> Prefactored a fromFactors as = Prefactored (product (map (uncurry (^)) (unCoprimes as))) as -instance (Euclidean a, Ord a) => Num (Prefactored a) where+instance Euclidean a => Num (Prefactored a) where   Prefactored v1 _ + Prefactored v2 _     = fromValue (v1 + v2)   Prefactored v1 _ - Prefactored v2 _@@ -119,12 +109,9 @@   signum (Prefactored v _) = Prefactored (signum v) mempty   fromInteger n = fromValue (fromInteger n) -type instance Prime (Prefactored a) = Prime a--instance (Eq a, Num a, UniqueFactorisation a) => UniqueFactorisation (Prefactored a) where-  unPrime p = fromValue (unPrime p)+instance (Euclidean a, UniqueFactorisation a) => UniqueFactorisation (Prefactored a) where   factorise (Prefactored _ f)-    = concatMap (\(x, xm) -> map (second (* xm)) (factorise x)) (unCoprimes f)+    = concatMap (\(x, xm) -> map (\(p, k) -> (Prime $ fromValue $ unPrime p, k * xm)) (factorise x)) (unCoprimes f)   isPrime (Prefactored _ f) = case unCoprimes f of-    [(n, 1)] -> isPrime n+    [(n, 1)] -> Prime . fromValue . unPrime <$> isPrime n     _        -> Nothing
Math/NumberTheory/Primes.hs view
@@ -1,19 +1,259 @@ -- | -- Module:      Math.NumberTheory.Primes--- Copyright:   (c) 2011 Daniel Fischer+-- Copyright:   (c) 2016-2018 Andrew.Lelechenko -- Licence:     MIT--- Maintainer:  Daniel Fischer <daniel.is.fischer@googlemail.com>--- Stability:   Provisional--- Portability: Non-portable (GHC extensions)+-- Maintainer:  Andrew Lelechenko <andrew.lelechenko@gmail.com> --++{-# LANGUAGE CPP               #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE LambdaCase        #-}++{-# OPTIONS_GHC -fno-warn-orphans #-}+ module Math.NumberTheory.Primes-    ( module Math.NumberTheory.Primes.Sieve-    , module Math.NumberTheory.Primes.Counting-    , module Math.NumberTheory.Primes.Testing-    , module Math.NumberTheory.Primes.Factorisation+    ( Prime+    , unPrime+    , nextPrime+    , precPrime+    , UniqueFactorisation(..)+    , -- * Old interface+      primes     ) where -import Math.NumberTheory.Primes.Sieve-import Math.NumberTheory.Primes.Counting-import Math.NumberTheory.Primes.Testing-import Math.NumberTheory.Primes.Factorisation+import Control.Arrow+import Data.Bits+import Data.Coerce+import Data.Maybe++import Math.NumberTheory.Primes.Counting (nthPrime, primeCount)+import qualified Math.NumberTheory.Primes.Factorisation as F (factorise)+import qualified Math.NumberTheory.Primes.Testing.Probabilistic as T (isPrime)+import Math.NumberTheory.Primes.Sieve.Eratosthenes (primes, sieveRange, primeList, psieveFrom, primeSieve)+import Math.NumberTheory.Primes.Types+import Math.NumberTheory.Utils (toWheel30, fromWheel30)+import Math.NumberTheory.Utils.FromIntegral++import Numeric.Natural++-- | A class for unique factorisation domains.+class Num a => UniqueFactorisation a where+  -- | Factorise a number into a product of prime powers.+  -- Factorisation of 0 is an undefined behaviour. Otherwise+  -- following invariants hold:+  --+  -- > abs n == abs (product (map (\(p, k) -> unPrime p ^ k) (factorise n)))+  -- > all ((> 0) . snd) (factorise n)+  --+  -- >>> factorise (1 :: Integer)+  -- []+  -- >>> factorise (-1 :: Integer)+  -- []+  -- >>> factorise (6 :: Integer)+  -- [(Prime 2,1),(Prime 3,1)]+  -- >>> factorise (-108 :: Integer)+  -- [(Prime 2,2),(Prime 3,3)]+  --+  -- This function is a replacement+  -- for 'Math.NumberTheory.Primes.Factorisation.factorise'.+  -- If you were looking for the latter, please import+  -- "Math.NumberTheory.Primes.Factorisation" instead of this module.+  --+  -- __Warning:__ there are no guarantees of any particular+  -- order of prime factors, do not expect them to be ascending. E. g.,+  --+  -- >>> factorise 10251562501+  -- [(Prime 101701,1),(Prime 100801,1)]+  factorise :: a -> [(Prime a, Word)]+  -- | Check whether an argument is prime.+  -- If it is then return an associated prime.+  --+  -- >>> isPrime (3 :: Integer)+  -- Just (Prime 3)+  -- >>> isPrime (4 :: Integer)+  -- Nothing+  -- >>> isPrime (-5 :: Integer)+  -- Just (Prime 5)+  --+  -- This function is a replacement+  -- for 'Math.NumberTheory.Primes.Testing.isPrime'.+  -- If you were looking for the latter, please import+  -- "Math.NumberTheory.Primes.Testing" instead of this module.+  isPrime   :: a -> Maybe (Prime a)++instance UniqueFactorisation Int where+  factorise = map (Prime . integerToInt *** id) . F.factorise . intToInteger+  isPrime n = if T.isPrime (toInteger n) then Just (Prime $ abs n) else Nothing++instance UniqueFactorisation Word where+  factorise = map (coerce integerToWord *** id) . F.factorise . wordToInteger+  isPrime n = if T.isPrime (toInteger n) then Just (Prime n) else Nothing++instance UniqueFactorisation Integer where+  factorise = coerce . F.factorise+  isPrime n = if T.isPrime n then Just (Prime $ abs n) else Nothing++instance UniqueFactorisation Natural where+  factorise = map (coerce integerToNatural *** id) . F.factorise . naturalToInteger+  isPrime n = if T.isPrime (toInteger n) then Just (Prime n) else Nothing++-- | Smallest prime, greater or equal to argument.+--+-- > nextPrime (-100) ==    2+-- > nextPrime  1000  == 1009+-- > nextPrime  1009  == 1009+nextPrime :: (Bits a, Integral a, UniqueFactorisation a) => a -> Prime a+nextPrime n+  | n <= 2    = Prime 2+  | n <= 3    = Prime 3+  | n <= 5    = Prime 5+  | otherwise = head $ mapMaybe isPrime $+                  dropWhile (< n) $ map fromWheel30 [toWheel30 n ..]+                  -- dropWhile is important, because fromWheel30 (toWheel30 n) may appear to be < n.+                  -- E. g., fromWheel30 (toWheel30 94) == 97++-- | Largest prime, less or equal to argument. Undefined, when argument < 2.+--+-- > precPrime 100 == 97+-- > precPrime  97 == 97+precPrime :: (Bits a, Integral a, UniqueFactorisation a) => a -> Prime a+precPrime n+  | n < 2     = error $ "precPrime: tried to take `precPrime` of an argument less than 2"+  | n < 3     = Prime 2+  | n < 5     = Prime 3+  | n < 7     = Prime 5+  | otherwise = head $ mapMaybe isPrime $+                  dropWhile (> n) $ map fromWheel30 [toWheel30 n, toWheel30 n - 1 ..]+                  -- dropWhile is important, because fromWheel30 (toWheel30 n) may appear to be > n.+                  -- E. g., fromWheel30 (toWheel30 100) == 101++-------------------------------------------------------------------------------+-- Prime sequences++data Algorithm = IsPrime | Sieve++chooseAlgorithm :: Integral a => a -> a -> Algorithm+chooseAlgorithm from to+  | to <= fromIntegral sieveRange+  && to < from + truncate (sqrt (fromIntegral from) :: Double)+  = IsPrime+  | to > fromIntegral sieveRange+  && to < from + truncate (0.036 * sqrt (fromIntegral from) + 40000 :: Double)+  = IsPrime+  | otherwise+  = Sieve++succGeneric :: (Bits a, Integral a, UniqueFactorisation a) => Prime a -> Prime a+succGeneric = \case+  Prime 2 -> Prime 3+  Prime 3 -> Prime 5+  Prime 5 -> Prime 7+  Prime p -> head $ mapMaybe isPrime $ map fromWheel30 [toWheel30 p + 1 ..]++succGenericBounded+  :: (Bits a, Integral a, UniqueFactorisation a, Bounded a)+  => Prime a+  -> Prime a+succGenericBounded = \case+  Prime 2 -> Prime 3+  Prime 3 -> Prime 5+  Prime 5 -> Prime 7+  Prime p -> case mapMaybe isPrime $ map fromWheel30 [toWheel30 p + 1 .. toWheel30 maxBound] of+    []    -> error "Enum.succ{Prime}: tried to take `succ' near `maxBound'"+    q : _ -> q++predGeneric :: (Bits a, Integral a, UniqueFactorisation a) => Prime a -> Prime a+predGeneric = \case+  Prime 2 -> error "Enum.pred{Prime}: tried to take `pred' of 2"+  Prime 3 -> Prime 2+  Prime 5 -> Prime 3+  Prime 7 -> Prime 5+  Prime p -> head $ mapMaybe isPrime $ map fromWheel30 [toWheel30 p - 1, toWheel30 p - 2 ..]++-- 'dropWhile' is important, because 'psieveFrom' can actually contain primes less than p.+enumFromGeneric :: Integral a => Prime a -> [Prime a]+enumFromGeneric p@(Prime p')+  = coerce+  $ dropWhile (< p)+  $ concat+  $ takeWhile (not . null)+  $ map primeList+  $ psieveFrom+  $ toInteger p'++enumFromToGeneric :: (Bits a, Integral a, UniqueFactorisation a) => Prime a -> Prime a -> [Prime a]+enumFromToGeneric p@(Prime p') q@(Prime q') = takeWhile (<= q) $ dropWhile (< p) $+  case chooseAlgorithm p' q' of+    IsPrime -> Prime 2 : Prime 3 : Prime 5 : mapMaybe isPrime (map fromWheel30 [toWheel30 p' .. toWheel30 q'])+    Sieve   ->+      if q' < fromIntegral sieveRange+      then           primeList $ primeSieve $ toInteger q'+      else concatMap primeList $ psieveFrom $ toInteger p'++enumFromThenGeneric :: (Bits a, Integral a, UniqueFactorisation a) => Prime a -> Prime a -> [Prime a]+enumFromThenGeneric p@(Prime p') (Prime q') = case p' `compare` q' of+  LT -> filter (\(Prime r') -> (r' - p') `mod` delta == 0) $ enumFromGeneric p+    where+      delta = q' - p'+  EQ -> repeat p+  GT -> filter (\(Prime r') -> (p' - r') `mod` delta == 0) $ reverse $ enumFromToGeneric (Prime 2) p+    where+      delta = p' - q'++enumFromThenToGeneric :: (Bits a, Integral a, UniqueFactorisation a) => Prime a -> Prime a -> Prime a -> [Prime a]+enumFromThenToGeneric p@(Prime p') (Prime q') r@(Prime r') = case p' `compare` q' of+  LT -> filter (\(Prime t') -> (t' - p') `mod` delta == 0) $ enumFromToGeneric p r+    where+      delta = q' - p'+  EQ -> if p' <= r' then repeat p else []+  GT -> filter (\(Prime t') -> (p' - t') `mod` delta == 0) $ reverse $ enumFromToGeneric r p+    where+      delta = p' - q'++instance Enum (Prime Integer) where+  toEnum = nthPrime . intToInteger+  fromEnum = integerToInt . primeCount . unPrime+  succ = succGeneric+  pred = predGeneric+  enumFrom = enumFromGeneric+  enumFromTo = enumFromToGeneric+  enumFromThen = enumFromThenGeneric+  enumFromThenTo = enumFromThenToGeneric++instance Enum (Prime Natural) where+  toEnum = Prime . integerToNatural . unPrime . nthPrime . intToInteger+  fromEnum = integerToInt . primeCount . naturalToInteger . unPrime+  succ = succGeneric+  pred = predGeneric+  enumFrom = enumFromGeneric+  enumFromTo = enumFromToGeneric+  enumFromThen = enumFromThenGeneric+  enumFromThenTo = enumFromThenToGeneric++instance Enum (Prime Int) where+  toEnum n = if p > intToInteger maxBound+    then error $ "Enum.toEnum{Prime}: " ++ show n ++ "th prime = " ++ show p ++ " is out of bounds of Int"+    else Prime (integerToInt p)+    where+      Prime p = nthPrime (intToInteger n)+  fromEnum = integerToInt . primeCount . intToInteger . unPrime+  succ = succGenericBounded+  pred = predGeneric+  enumFrom = enumFromGeneric+  enumFromTo = enumFromToGeneric+  enumFromThen = enumFromThenGeneric+  enumFromThenTo = enumFromThenToGeneric++instance Enum (Prime Word) where+  toEnum n = if p > wordToInteger maxBound+    then error $ "Enum.toEnum{Prime}: " ++ show n ++ "th prime = " ++ show p ++ " is out of bounds of Word"+    else Prime (integerToWord p)+    where+      Prime p = nthPrime (intToInteger n)+  fromEnum = integerToInt . primeCount . wordToInteger . unPrime+  succ = succGenericBounded+  pred = predGeneric+  enumFrom = enumFromGeneric+  enumFromTo = enumFromToGeneric+  enumFromThen = enumFromThenGeneric+  enumFromThenTo = enumFromThenToGeneric
Math/NumberTheory/Primes/Counting.hs view
@@ -3,8 +3,6 @@ -- Copyright:   (c) 2011 Daniel Fischer -- Licence:     MIT -- Maintainer:  Daniel Fischer <daniel.is.fischer@googlemail.com>--- Stability:   Provisional--- Portability: non-portable -- -- Number of primes not exceeding @n@, @&#960;(n)@, and @n@-th prime; also fast, but -- reasonably accurate approximations to these.
Math/NumberTheory/Primes/Counting/Approximate.hs view
@@ -3,8 +3,6 @@ -- Copyright:   (c) 2011 Daniel Fischer -- Licence:     MIT -- Maintainer:  Daniel Fischer <daniel.is.fischer@googlemail.com>--- Stability:   Provisional--- Portability: portable -- -- Approximations to the number of primes below a limit and the -- n-th prime.
Math/NumberTheory/Primes/Counting/Impl.hs view
@@ -3,8 +3,6 @@ -- Copyright:   (c) 2011 Daniel Fischer -- Licence:     MIT -- Maintainer:  Daniel Fischer <daniel.is.fischer@googlemail.com>--- Stability:   Provisional--- Portability: non-portable -- -- Number of primes not exceeding @n@, @&#960;(n)@, and @n@-th prime. --@@ -27,6 +25,7 @@ import Math.NumberTheory.Primes.Sieve.Eratosthenes import Math.NumberTheory.Primes.Sieve.Indexing import Math.NumberTheory.Primes.Counting.Approximate+import Math.NumberTheory.Primes.Types import Math.NumberTheory.Powers.Squares import Math.NumberTheory.Powers.Cubes import Math.NumberTheory.Logarithms@@ -61,7 +60,7 @@ primeCount n     | n > primeCountMaxArg = error $ "primeCount: can't handle bound " ++ show n     | n < 2     = 0-    | n < 1000  = fromIntegral . length . takeWhile (<= n) . primeList . primeSieve $ max 242 n+    | n < 1000  = fromIntegral . length . takeWhile (<= n) . map unPrime . primeList . primeSieve $ max 242 n     | n < 30000 = runST $ do         ba <- sieveTo n         (s,e) <- getBounds ba@@ -86,13 +85,13 @@ -- --   Requires @/O/((n*log n)^0.5)@ space, the time complexity is roughly @/O/((n*log n)^0.7@. --   The argument must be strictly positive, and must not exceed 'nthPrimeMaxArg'.-nthPrime :: Integer -> Integer+nthPrime :: Integer -> Prime Integer nthPrime n     | n < 1         = error "Prime indexing starts at 1"     | n > nthPrimeMaxArg = error $ "nthPrime: can't handle index " ++ show n-    | n < 200000    = nthPrimeCt n-    | ct0 < n       = tooLow n p0 (n-ct0) approxGap-    | otherwise     = tooHigh n p0 (ct0-n) approxGap+    | n < 200000    = Prime $ nthPrimeCt n+    | ct0 < n       = Prime $ tooLow n p0 (n-ct0) approxGap+    | otherwise     = Prime $ tooHigh n p0 (ct0-n) approxGap       where         p0 = nthPrimeApprox n         approxGap = (7 * fromIntegral (integerLog2' p0)) `quot` 10
Math/NumberTheory/Primes/Factorisation.hs view
@@ -3,8 +3,6 @@ -- Copyright:   (c) 2011 Daniel Fischer -- Licence:     MIT -- Maintainer:  Daniel Fischer <daniel.is.fischer@googlemail.com>--- Stability:   Provisional--- Portability: Non-portable (GHC extensions) -- -- Various functions related to prime factorisation. -- Many of these functions use the prime factorisation of an 'Integer'.
Math/NumberTheory/Primes/Factorisation/Certified.hs view
@@ -3,8 +3,6 @@ -- Copyright:   (c) 2011 Daniel Fischer -- Licence:     MIT -- Maintainer:  Daniel Fischer <daniel.is.fischer@googlemail.com>--- Stability:   Provisional--- Portability: Non-portable (GHC extensions) -- -- Factorisation proving the primality of the found factors. --@@ -30,12 +28,12 @@  -- | @'certifiedFactorisation' n@ produces the prime factorisation --   of @n@, proving the primality of the factors, but doesn't report the proofs.-certifiedFactorisation :: Integer -> [(Integer,Int)]+certifiedFactorisation :: Integer -> [(Integer, Word)] certifiedFactorisation = map fst . certificateFactorisation  -- | @'certificateFactorisation' n@ produces a 'provenFactorisation' --   with a default bound of @100000@.-certificateFactorisation :: Integer -> [((Integer,Int),PrimalityProof)]+certificateFactorisation :: Integer -> [((Integer, Word),PrimalityProof)] certificateFactorisation n = provenFactorisation 100000 n  -- | @'provenFactorisation' bound n@ constructs a the prime factorisation of @n@@@ -47,7 +45,7 @@ --   Construction of primality proofs can take a /very/ long time, so this --   will usually be slow (but should be faster than using 'factorise' and --   proving the primality of the factors from scratch).-provenFactorisation :: Integer -> Integer -> [((Integer,Int),PrimalityProof)]+provenFactorisation :: Integer -> Integer -> [((Integer, Word),PrimalityProof)] provenFactorisation _ 1 = [] provenFactorisation bd n     | n < 2     = error "provenFactorisation: argument not positive"@@ -61,7 +59,7 @@                                                 (mkStdGen $ fromIntegral n `xor` 0xdeadbeef) Nothing k  -- | verify that we indeed have a correct primality proof-test :: [((Integer,Int),PrimalityProof)] -> [((Integer,Int),PrimalityProof)]+test :: [((Integer, Word),PrimalityProof)] -> [((Integer, Word),PrimalityProof)] test (t@((p,_),prf):more)     | p == cprime prf && checkPrimalityProof prf    = t : test more     | otherwise = error (invalid p prf)@@ -89,7 +87,7 @@                    -> g                             -- ^ Initial PRNG state                    -> Maybe Int                     -- ^ Estimated number of digits of the smallest prime factor                    -> Integer                       -- ^ The number to factorise-                   -> [((Integer,Int),PrimalityProof)]+                   -> [((Integer, Word),PrimalityProof)]                                                     -- ^ List of prime factors, exponents and primality proofs certiFactorisation primeBound primeTest prng seed mbdigs n     = case ptest n of@@ -147,7 +145,7 @@                             return  (mergeAll [dp,cp,gp], dc ++ cc ++ gc)  -- | merge two lists of factors, so that the result is strictly increasing (wrt the primes)-merge :: [((Integer,Int),PrimalityProof)] -> [((Integer,Int),PrimalityProof)] -> [((Integer,Int),PrimalityProof)]+merge :: [((Integer, Word), PrimalityProof)] -> [((Integer, Word), PrimalityProof)] -> [((Integer, Word), PrimalityProof)] merge xxs@(x@((p,e),c):xs) yys@(y@((q,d),_):ys)     = case compare p q of         LT -> x : merge xs yys@@ -157,7 +155,7 @@ merge xs _  = xs  -- | merge a list of lists of factors so that the result is strictly increasing (wrt the primes)-mergeAll :: [[((Integer,Int),PrimalityProof)]] -> [((Integer,Int),PrimalityProof)]+mergeAll :: [[((Integer, Word), PrimalityProof)]] -> [((Integer, Word), PrimalityProof)] mergeAll [] = [] mergeAll [xs] = xs mergeAll (xs:ys:zss) = merge (merge xs ys) (mergeAll zss)
Math/NumberTheory/Primes/Factorisation/Montgomery.hs view
@@ -3,8 +3,6 @@ -- Copyright:   (c) 2011 Daniel Fischer -- Licence:     MIT -- Maintainer:  Daniel Fischer <daniel.is.fischer@googlemail.com>--- Stability:   Provisional--- Portability: Non-portable (GHC extensions) -- -- Factorisation of 'Integer's by the elliptic curve algorithm after Montgomery. -- The algorithm is explained at@@ -72,13 +70,20 @@ import Math.NumberTheory.Primes.Sieve.Eratosthenes import Math.NumberTheory.Primes.Sieve.Indexing import Math.NumberTheory.Primes.Testing.Probabilistic+import Math.NumberTheory.Primes.Types (unPrime) import Math.NumberTheory.Unsafe import Math.NumberTheory.Utils  -- | @'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)]+--+-- __Warning:__ there are no guarantees of any particular+-- order of prime factors, do not expect them to be ascending. E. g.,+--+-- >>> factorise 10251562501+-- [(101701,1),(100801,1)]+factorise :: Integer -> [(Integer, Word)] factorise n     | abs n == 1 = []     | n < 0      = factorise (-n)@@ -86,14 +91,14 @@     | otherwise  = factorise' n  -- | Like 'factorise', but without input checking, hence @n > 1@ is required.-factorise' :: Integer -> [(Integer,Int)]+factorise' :: Integer -> [(Integer, Word)] factorise' n = defaultStdGenFactorisation' (mkStdGen $ fromInteger n `xor` 0xdeadbeef) n  -- | @'stepFactorisation'@ is like 'factorise'', except that it doesn't use a --   pseudo random generator but steps through the curves in order. --   This strategy turns out to be surprisingly fast, on average it doesn't --   seem to be slower than the 'StdGen' based variant.-stepFactorisation :: Integer -> [(Integer,Int)]+stepFactorisation :: Integer -> [(Integer, Word)] stepFactorisation n     = let (sfs,mb) = smallFactors 100000 n       in sfs ++ case mb of@@ -106,7 +111,7 @@ --   For negative numbers, a factor of @-1@ is included, the factorisation of @1@ --   is empty. Since @0@ has no prime factorisation, a zero argument causes --   an error.-defaultStdGenFactorisation :: StdGen -> Integer -> [(Integer,Int)]+defaultStdGenFactorisation :: StdGen -> Integer -> [(Integer, Word)] defaultStdGenFactorisation sg n     | n == 0    = error "0 has no prime factorisation"     | n < 0     = (-1,1) : defaultStdGenFactorisation sg (-n)@@ -115,7 +120,7 @@  -- | Like 'defaultStdGenFactorisation', but without input checking, so --   @n@ must be larger than @1@.-defaultStdGenFactorisation' :: StdGen -> Integer -> [(Integer,Int)]+defaultStdGenFactorisation' :: StdGen -> Integer -> [(Integer, Word)] defaultStdGenFactorisation' sg n     = let (sfs,mb) = smallFactors 100000 n       in sfs ++ case mb of@@ -130,11 +135,11 @@ --   The primality test is 'bailliePSW', the @prng@ function - naturally - --   'randomR'. This function also requires small prime factors to have been --   stripped before.-stdGenFactorisation :: Maybe Integer    -- ^ Lower bound for composite divisors-                    -> StdGen           -- ^ Standard PRNG-                    -> Maybe Int        -- ^ Estimated number of digits of smallest prime factor-                    -> Integer          -- ^ The number to factorise-                    -> [(Integer,Int)]  -- ^ List of prime factors and exponents+stdGenFactorisation :: Maybe Integer     -- ^ Lower bound for composite divisors+                    -> StdGen            -- ^ Standard PRNG+                    -> Maybe Int         -- ^ Estimated number of digits of smallest prime factor+                    -> Integer           -- ^ The number to factorise+                    -> [(Integer, Word)] -- ^ List of prime factors and exponents stdGenFactorisation primeBound sg digits n     = curveFactorisation primeBound bailliePSW (\m -> randomR (6,m-2)) sg digits n @@ -164,7 +169,7 @@   -> g                              -- ^ Initial PRNG state   -> Maybe Int                      -- ^ Estimated number of digits of the smallest prime factor   -> Integer                        -- ^ The number to factorise-  -> [(Integer, Int)]               -- ^ List of prime factors and exponents+  -> [(Integer, Word)]              -- ^ List of prime factors and exponents curveFactorisation primeBound primeTest prng seed mbdigs n     | n == 1    = []     | ptest n   = [(n, 1)]@@ -179,10 +184,10 @@         rndR :: Integer -> State g Integer         rndR k = state (prng k) -        perfPw :: Integer -> (Integer, Int)+        perfPw :: Integer -> (Integer, Word)         perfPw = maybe highestPower (largePFPower . integerSquareRoot') primeBound -        fact :: Integer -> Int -> State g [(Integer, Int)]+        fact :: Integer -> Int -> State g [(Integer, Word)]         fact 1 _ = return mempty         fact m digs = do           let (b1, b2, ct) = findParms digs@@ -227,14 +232,14 @@                               else repFact x b1 b2 (count - 1)  data Factors = Factors-  { _primeFactors     :: [(Integer, Int)]-  , _compositeFactors :: [(Integer, Int)]+  { _primeFactors     :: [(Integer, Word)]+  , _compositeFactors :: [(Integer, Word)]   } -singlePrimeFactor :: Integer -> Int -> Factors+singlePrimeFactor :: Integer -> Word -> Factors singlePrimeFactor a b = Factors [(a, b)] [] -singleCompositeFactor :: Integer -> Int -> Factors+singleCompositeFactor :: Integer -> Word -> Factors singleCompositeFactor a b = Factors [] [(a, b)]  instance Semigroup Factors where@@ -245,7 +250,7 @@   mempty = Factors [] []   mappend = (<>) -modifyPowers :: (Int -> Int) -> Factors -> Factors+modifyPowers :: (Word -> Word) -> Factors -> Factors modifyPowers f (Factors pfs cfs)   = Factors (map (second f) pfs) (map (second f) cfs) @@ -343,12 +348,12 @@  -- | @'smallFactors' bound n@ finds all prime divisors of @n > 1@ up to @bound@ by trial division and returns the --   list of these together with their multiplicities, and a possible remaining factor which may be composite.-smallFactors :: Integer -> Integer -> ([(Integer,Int)], Maybe Integer)+smallFactors :: Integer -> Integer -> ([(Integer, Word)], Maybe Integer) smallFactors bd n = case shiftToOddCount n of                       (0,m) -> go m prms                       (k,m) -> (2,k) <: if m == 1 then ([],Nothing) else go m prms   where-    prms = tail (primeStore >>= primeList)+    prms = map unPrime $ tail (primeStore >>= primeList)     x <: ~(l,b) = (x:l,b)     go m (p:ps)         | m < p*p   = ([(m,1)], Nothing)
Math/NumberTheory/Primes/Factorisation/TrialDivision.hs view
@@ -3,8 +3,6 @@ -- Copyright:   (c) 2011 Daniel Fischer -- Licence:     MIT -- Maintainer:  Daniel Fischer <daniel.is.fischer@googlemail.com>--- Stability:   Provisional--- Portability: Non-portable (GHC extensions) -- -- Factorisation and primality testing using trial division. --@@ -21,12 +19,13 @@  import Math.NumberTheory.Primes.Sieve.Eratosthenes import Math.NumberTheory.Powers.Squares+import Math.NumberTheory.Primes.Types import Math.NumberTheory.Utils  -- | Factorise an 'Integer' using a given list of numbers considered prime. --   If the list is not a list of primes containing all relevant primes, the --   result could be surprising.-trialDivisionWith :: [Integer] -> Integer -> [(Integer,Int)]+trialDivisionWith :: [Integer] -> Integer -> [(Integer, Word)] trialDivisionWith prs n     | n < 0     = trialDivisionWith prs (-n)     | n == 0    = error "trialDivision of 0"@@ -47,11 +46,11 @@ --   primes @<= bound@. If @n@ has prime divisors @> bound@, the last entry --   in the list is the product of all these. If @n <= bound^2@, this is a --   full factorisation, but very slow if @n@ has large prime divisors.-trialDivisionTo :: Integer -> Integer -> [(Integer,Int)]+trialDivisionTo :: Integer -> Integer -> [(Integer, Word)] trialDivisionTo bd     | bd < 100      = trialDivisionTo 100-    | bd < 10000000 = trialDivisionWith (primeList $ primeSieve bd)-    | otherwise     = trialDivisionWith (takeWhile (<= bd) $ (psieveList >>= primeList))+    | bd < 10000000 = trialDivisionWith (map unPrime $ primeList $ primeSieve bd)+    | otherwise     = trialDivisionWith (takeWhile (<= bd) $ map unPrime $ (psieveList >>= primeList))  -- | Check whether a number is coprime to all of the numbers in the list --   (assuming that list contains only numbers > 1 and is ascending).@@ -69,5 +68,5 @@ trialDivisionPrimeTo :: Integer -> Integer -> Bool trialDivisionPrimeTo bd     | bd < 100      = trialDivisionPrimeTo 100-    | bd < 10000000 = trialDivisionPrimeWith (primeList $ primeSieve bd)-    | otherwise     = trialDivisionPrimeWith (takeWhile (<= bd) $ (psieveList >>= primeList))+    | bd < 10000000 = trialDivisionPrimeWith (map unPrime $ primeList $ primeSieve bd)+    | otherwise     = trialDivisionPrimeWith (takeWhile (<= bd) $ map unPrime $ (psieveList >>= primeList))
Math/NumberTheory/Primes/Sieve.hs view
@@ -3,8 +3,6 @@ -- 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 sieve. -- Currently, an enhanced sieve of Eratosthenes is used, switching to an
Math/NumberTheory/Primes/Sieve/Eratosthenes.hs view
@@ -3,8 +3,6 @@ -- Copyright:   (c) 2011 Daniel Fischer -- Licence:     MIT -- Maintainer:  Daniel Fischer <daniel.is.fischer@googlemail.com>--- Stability:   Provisional--- Portability: Non-portable (GHC extensions) -- -- Sieve --@@ -38,6 +36,7 @@ import Control.Monad.ST import Data.Array.ST import Data.Array.Unboxed+import Data.Coerce import Data.Proxy import Control.Monad (when) import Data.Bits@@ -51,6 +50,7 @@ import Math.NumberTheory.Utils.FromIntegral import Math.NumberTheory.Primes.Counting.Approximate import Math.NumberTheory.Primes.Sieve.Indexing+import Math.NumberTheory.Primes.Types  #define IX_MASK     0xFFFFF #define IX_BITS     20@@ -112,12 +112,14 @@  -- | Generate a list of primes for consumption from a --   'PrimeSieve'.-primeList :: forall a. Integral a => PrimeSieve -> [a]+primeList :: forall a. Integral a => PrimeSieve -> [Prime 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+  | v == 0    = (coerce :: [a] -> [Prime a])+              $ takeWhileIncreasing $ 2 : 3 : 5 : primeListInternal ps+  | otherwise = (coerce :: [a] -> [Prime a])+              $ takeWhileIncreasing $ primeListInternal ps  primeListInternal :: Num a => PrimeSieve -> [a] primeListInternal (PS v0 bs)@@ -143,30 +145,32 @@ -- | Ascending list of primes. -- -- >>> take 10 primes--- [2, 3, 5, 7, 11, 13, 17, 19, 23, 29]+-- [Prime 2,Prime 3,Prime 5,Prime 7,Prime 11,Prime 13,Prime 17,Prime 19,Prime 23,Prime 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+-- >>> primes !! 1000000 :: Prime Int+-- Prime 15485867 -- (5.32 secs, 6,945,267,496 bytes)--- >>> primes !! 1000000 :: Int--- 15485867+-- >>> primes !! 1000000 :: Prime Int+-- Prime 15485867 -- (5.19 secs, 6,945,267,496 bytes) -- -- against ----- >>> let primes' = primes :: [Int]--- >>> primes' !! 1000000 :: Int--- 15485867+-- >>> let primes' = primes :: [Prime Int]+-- >>> primes' !! 1000000 :: Prime Int+-- Prime 15485867 -- (5.29 secs, 6,945,269,856 bytes)--- >>> primes' !! 1000000 :: Int--- 15485867+-- >>> primes' !! 1000000 :: Prime Int+-- Prime 15485867 -- (0.02 secs, 336,232 bytes)-primes :: (Ord a, Num a) => [a]-primes = takeWhileIncreasing $ 2 : 3 : 5 : concatMap primeListInternal psieveList+primes :: Integral a => [Prime a]+primes+  = (coerce :: [a] -> [Prime a])+  $ 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'@@@ -366,9 +370,9 @@           return (bitCountWord (w1 `shiftL` (RMASK - ei + si)))  -- | @'sieveFrom' n@ creates the list of primes not less than @n@.-sieveFrom :: Integer -> [Integer]+sieveFrom :: Integer -> [Prime Integer] sieveFrom n = case psieveFrom n of-                        ps -> dropWhile (< n) (ps >>= primeList)+                        ps -> dropWhile ((< n) . unPrime) (ps >>= primeList)  -- | @'psieveFrom' n@ creates the list of 'PrimeSieve's starting roughly --   at @n@. Due to the organisation of the sieve, the list may contain
Math/NumberTheory/Primes/Sieve/Indexing.hs view
@@ -3,8 +3,6 @@ -- Copyright:   (c) 2011 Daniel Fischer -- Licence:     MIT -- Maintainer:  Daniel Fischer <daniel.is.fischer@googlemail.com>--- Stability:   Provisional--- Portability: Non-portable (GHC extensions) -- -- Auxiliary stuff, conversion between number and index, -- remainders modulo 30 and related things.
Math/NumberTheory/Primes/Testing.hs view
@@ -3,8 +3,6 @@ -- Copyright:   (c) 2011 Daniel Fischer -- Licence:     MIT -- Maintainer:  Daniel Fischer <daniel.is.fischer@googlemail.com>--- Stability:   Provisional--- Portability: Non-portable (GHC extensions) -- -- Primality tests. 
Math/NumberTheory/Primes/Testing/Certificates.hs view
@@ -3,8 +3,6 @@ -- Copyright:   (c) 2011 Daniel Fischer -- Licence:     MIT -- Maintainer:  Daniel Fischer <daniel.is.fischer@googlemail.com>--- Stability:   Provisional--- Portability: Non-portable (GHC extensions) -- -- Certificates for primality or compositeness. module Math.NumberTheory.Primes.Testing.Certificates
Math/NumberTheory/Primes/Testing/Certificates/Internal.hs view
@@ -3,8 +3,6 @@ -- Copyright:   (c) 2011 Daniel Fischer -- Licence:     MIT -- Maintainer:  Daniel Fischer <daniel.is.fischer@googlemail.com>--- Stability:   Provisional--- Portability: Non-portable (GHC extensions) -- -- Certificates for primality or compositeness. {-# LANGUAGE CPP #-}@@ -40,6 +38,7 @@ import Math.NumberTheory.Primes.Factorisation.Montgomery import Math.NumberTheory.Primes.Testing.Probabilistic import Math.NumberTheory.Primes.Sieve.Eratosthenes+import Math.NumberTheory.Primes.Types (unPrime) import Math.NumberTheory.Powers.Squares  -- | A certificate of either compositeness or primality of an@@ -63,7 +62,7 @@       deriving Show  -- | An argument for compositeness of a number (which must be @> 1@).---   'CompositenessProof's translate directly to 'CompositenessArguments',+--   'CompositenessProof's translate directly to 'CompositenessArgument's, --   correct arguments can be transformed into proofs. This type allows the --   manipulation of proofs while maintaining their correctness. --   The only way to access components of a 'CompositenessProof' except@@ -81,7 +80,7 @@ data PrimalityProof     = Pocklington { cprime :: !Integer          -- ^ The number whose primality is proved.                   , factorisedPart, cofactor :: !Integer-                  , knownFactors :: ![(Integer,Int,Integer,PrimalityProof)]+                  , knownFactors :: ![(Integer, Word, Integer, PrimalityProof)]                   }     | TrialDivision { cprime :: !Integer        -- ^ The number whose primality is proved.                     , tdLimit :: !Integer }@@ -90,7 +89,7 @@       deriving Show  -- | An argument for primality of a number (which must be @> 1@).---   'PrimalityProof's translate directly to 'PrimalityArguments',+--   'PrimalityProof's translate directly to 'PrimalityArgument's, --   correct arguments can be transformed into proofs. This type allows the --   manipulation of proofs while maintaining their correctness. --   The only way to access components of a 'PrimalityProof' except@@ -98,13 +97,14 @@ data PrimalityArgument     = Pock { aprime :: Integer            , largeFactor, smallFactor :: Integer-           , factorList :: [(Integer,Int,Integer,PrimalityArgument)]+           , factorList :: [(Integer, Word, Integer, PrimalityArgument)]            }                                 -- ^ A suggested Pocklington certificate     | Division { aprime, alimit :: Integer } -- ^ Primality should be provable by trial division to @alimit@     | Obvious { aprime :: Integer }          -- ^ @aprime@ is said to be obviously prime, that holds for primes @< 30@     | Assumption { aprime :: Integer }       -- ^ Primality assumed       deriving (Show, Read, Eq, Ord) +-- | Eliminate 'Certificate'. argueCertificate :: Certificate -> Either CompositenessArgument PrimalityArgument argueCertificate (Composite proof) = Left (argueCompositeness proof) argueCertificate (Prime proof) = Right (arguePrimality proof)@@ -294,12 +294,12 @@  -- | Find a decomposition of p-1 for the pocklington certificate. --   Usually bloody slow if p-1 has two (or more) /large/ prime divisors.-findDecomposition :: Integer -> (Integer, [(Integer,Int,Bool)], Integer)+findDecomposition :: Integer -> (Integer, [(Integer, Word, Bool)], Integer) findDecomposition n = go 1 n [] prms   where     sr = integerSquareRoot' n     pbd = min 1000000 (sr+20)-    prms = primeList (primeSieve $ pbd)+    prms = map unPrime $ primeList (primeSieve $ pbd)     go a b afs (p:ps)         | a > b     = (a,afs,b)         | otherwise = case splitOff p b of
Math/NumberTheory/Primes/Testing/Certified.hs view
@@ -3,8 +3,6 @@ -- Copyright:   (c) 2011 Daniel Fischer -- Licence:     MIT -- Maintainer:  Daniel Fischer <daniel.is.fischer@googlemail.com>--- Stability:   Provisional--- Portability: Non-portable (GHC extensions) -- -- Deterministic primality testing. module Math.NumberTheory.Primes.Testing.Certified (isCertifiedPrime) where
Math/NumberTheory/Primes/Testing/Probabilistic.hs view
@@ -3,8 +3,6 @@ -- Copyright:   (c) 2011 Daniel Fischer, 2017 Andrew Lelechenko -- Licence:     MIT -- Maintainer:  Daniel Fischer <daniel.is.fischer@googlemail.com>--- Stability:   Provisional--- Portability: Non-portable (GHC extensions) -- -- Probabilistic primality tests, Miller-Rabin and Baillie-PSW. {-# LANGUAGE CPP, MagicHash, BangPatterns #-}
Math/NumberTheory/Primes/Types.hs view
@@ -3,8 +3,6 @@ -- Copyright:   (c) 2017 Andrew Lelechenko -- Licence:     MIT -- Maintainer:  Andrew Lelechenko <andrew.lelechenko@gmail.com>--- Stability:   Provisional--- Portability: Non-portable (GHC extensions) -- -- This is an internal module, defining types for primes. -- Should not be exposed to users.@@ -15,41 +13,62 @@ {-# LANGUAGE DeriveGeneric #-}  module Math.NumberTheory.Primes.Types-  ( Prime-  , Prm(..)-  , PrimeNat(..)+  ( Prime(..)   ) where -import Numeric.Natural import GHC.Generics import Control.DeepSeq -newtype Prm = Prm { unPrm :: Word }-  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 }+-- | Wrapper for prime elements of @a@. It is supposed to be constructed+-- by 'Math.NumberTheory.Primes.nextPrime' / 'Math.NumberTheory.Primes.precPrime'.+-- and eliminated by 'unPrime'.+--+-- One can leverage 'Enum' instance to generate lists of primes.+-- Here are some examples.+--+-- *  Generate primes from the given interval:+--+--    >>> [nextPrime 101 .. precPrime 130]+--    [Prime 101,Prime 103,Prime 107,Prime 109,Prime 113,Prime 127]+--+-- *  Generate an infinite list of primes:+--+--    >>> [nextPrime 101 ..]+--    [Prime 101,Prime 103,Prime 107,Prime 109,Prime 113,Prime 127...+--+-- *  Generate primes from the given interval of form p = 6k+5:+--+--    >>> [nextPrime 101, nextPrime 107 .. precPrime 150]+--    [Prime 101,Prime 107,Prime 113,Prime 131,Prime 137,Prime 149]+--+-- *  Get next prime:+--+--    >>> succ (nextPrime 101)+--    Prime 103+--+-- *  Get previous prime:+--+--    >>> prec (nextPrime 101)+--    Prime 97+--+-- *  Count primes less than a given number (cf. 'Math.NumberTheory.Primes.Counting.approxPrimeCount'):+--+--    >>> fromEnum (precPrime 100)+--    25+--+-- *  Get 25-th prime number (cf. 'Math.NumberTheory.Primes.Counting.nthPrimeApprox'):+--+--    >>> toEnum 25 :: Prime Int+--    Prime 97+--+newtype Prime a = Prime+  { unPrime :: a -- ^ Unwrap prime element.+  }   deriving (Eq, Ord, Generic) -instance NFData PrimeNat+instance NFData a => NFData (Prime a) -instance Show PrimeNat where-  showsPrec d (PrimeNat p) r = (if d > 10 then "(" ++ s ++ ")" else s) ++ r+instance Show a => Show (Prime a) where+  showsPrec d (Prime p) r = (if d > 10 then "(" ++ s ++ ")" else s) ++ r     where-      s = "PrimeNat " ++ show p---- | Type of primes of a given unique factorisation domain.------ @abs (unPrime n) == unPrime n@ must hold for all @n@ of type @Prime t@-type family Prime (f :: *) :: *--type instance Prime Int     = Prm-type instance Prime Word    = Prm-type instance Prime Integer = PrimeNat-type instance Prime Natural = PrimeNat+      s = "Prime " ++ show p
Math/NumberTheory/Quadratic/EisensteinIntegers.hs view
@@ -3,8 +3,6 @@ -- 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.@@ -13,6 +11,7 @@ {-# LANGUAGE BangPatterns   #-} {-# LANGUAGE DeriveGeneric  #-} {-# LANGUAGE RankNTypes     #-}+{-# LANGUAGE TypeFamilies   #-}  module Math.NumberTheory.Quadratic.EisensteinIntegers   ( EisensteinInteger(..)@@ -22,15 +21,13 @@   , associates   , ids -  , divideByThree-   -- * Primality functions-  , factorise   , findPrime-  , isPrime   , primes   ) where +import Control.DeepSeq+import Data.Coerce import Data.List                                       (mapAccumL, partition) import Data.Maybe                                      (fromMaybe) import Data.Ord                                        (comparing)@@ -38,23 +35,25 @@  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.Primes.Types+import qualified Math.NumberTheory.Primes  as U import Math.NumberTheory.Utils                          (mergeBy)-import Math.NumberTheory.Utils.FromIntegral             (integerToNatural)+import Math.NumberTheory.Utils.FromIntegral  infix 6 :+ --- | An Eisenstein integer is a + bω, where a and b are both integers.+-- | An Eisenstein integer is @a + bω@, where @a@ and @b@ are both integers. data EisensteinInteger = (:+) { real :: !Integer, imag :: !Integer }     deriving (Eq, Ord, Generic) +instance NFData EisensteinInteger+ -- | The imaginary unit for Eisenstein integers, where -- -- > ω == (-1/2) + ((sqrt 3)/2)ι == exp(2*pi*ι/3)--- and ι is the usual imaginary unit with ι² == -1.+-- and @ι@ is the usual imaginary unit with @ι² == -1@. ω :: EisensteinInteger ω = 0 :+ 1 @@ -97,13 +96,6 @@ 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@@ -149,12 +141,12 @@  -- | Remove @1 - ω@ factors from an @EisensteinInteger@, and calculate that -- prime's multiplicity in the number's factorisation.-divideByThree :: EisensteinInteger -> (Int, EisensteinInteger)+divideByThree :: EisensteinInteger -> (Word, EisensteinInteger) divideByThree = go 0   where-    go :: Int -> EisensteinInteger -> (Int, EisensteinInteger)+    go :: Word -> EisensteinInteger -> (Word, EisensteinInteger)     go !n z@(a :+ b) | r1 == 0 && r2 == 0 = go (n + 1) (q1 :+ q2)-                      | otherwise          = (n, abs z)+                     | 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))@.@@ -167,138 +159,146 @@ -- -- 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@+--     * Each prime of the form @3n + 1@ is actually of the 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)@. ----- * 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+-- The goal is to solve @z^2 - z + 1 ≡ 0 (mod 6k + 1)@. One has:+--+--     1. @z^2 - z + 1 ≡ 0 (mod 6k + 1)@+--     2. @z^2 - z ≡ -1 (mod 6k + 1)@+--     3. @z^2 - z + 9k^2 ≡ 9k^2 - 1 (mod 6k + 1)@+--     4. @(z + 3k)^2 ≡ 9k^2 - 1 (mod 6k + 1)@+--     5. @z + 3k = sqrtsModPrime(9k^2 - 1) (mod 6k + 1)@+--     6. @z = (sqrtsModPrime(9k^2 - 1) (mod 6k + 1)) - 3k@+--+-- For example, let @p = 7@, then @k = 1@.+-- Square root of @9*1^2-1 ≡ 1 (mod 7)@, and @z = 1 - 3*1 = -2 ≡ 5 (mod 7)@.+--+-- Truly, @norm (5 :+ 1) = 25 - 5 + 1 = 21 ≡ 0 (mod 7)@.+findPrime :: Prime Integer -> U.Prime EisensteinInteger+findPrime p = case sqrtsModPrime (9*k*k - 1) p of     []    -> error "findPrime: argument must be prime p = 6k + 1"-    z : _ -> ED.gcd (p :+ 0) ((z - 3 * k) :+ 1)+    z : _ -> Prime $ ED.gcd (unPrime p :+ 0) ((z - 3 * k) :+ 1)     where         k :: Integer-        k = p `div` 6+        k = unPrime p `div` 6 --- | An infinite list of Eisenstein primes. Uses primes in Z to exhaustively--- generate all Eisenstein primes in order of ascending magnitude.+-- | An infinite list of Eisenstein primes. Uses primes in @Z@ to exhaustively+-- generate all Eisenstein primes in order of ascending norm.+-- -- * 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)]]+-- applying 'associates' to each prime in this list.+primes :: [Prime EisensteinInteger]+primes = coerce $ (2 :+ 1) : mergeBy (comparing norm) l r+  where+    leftPrimes, rightPrimes :: [Prime Integer]+    (leftPrimes, rightPrimes) = partition (\p -> unPrime p `mod` 3 == 2) Sieve.primes+    rightPrimes' = filter (\prime -> unPrime prime `mod` 3 == 1) $ tail rightPrimes+    l = [unPrime p :+ 0 | p <- leftPrimes]+    r = [g | p <- rightPrimes', let x :+ y = unPrime (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@.+-- | [Implementation notes for factorise function] ----- * 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@.+-- Compute the prime factorisation of a Eisenstein integer. ----- * 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@.+--     1. 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@.+--     2. 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@.+--     3. 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 Eisenstein primes. ----- * 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 the equation from Theorem 8.4: ----- * 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]]@+-- 1. @norm μ = norm ( (-1)^a * ω^b * (1 - ω)^c * product [ π_i^a_i | i <- [1..N]] ) ==@+-- 2. @norm μ = norm ((-1)^a) * norm (ω^b) * norm ((1 - ω)^c) * norm (product [ π_i^a_i | i <- [1..N]]) ==@+-- 3. @norm μ = (norm (-1))^a * (norm ω)^b * (norm (1 - ω))^c * product [ norm (π_i^a_i) | i <- [1..N]] ==@+-- 4. @norm μ = (norm (-1))^a * (norm ω)^b * (norm (1 - ω))^c * product [ (norm π_i)^a_i) | i <- [1..N]] ==@+-- 5. @norm μ = 1^a * 1^b * 3^c * product [ (norm π_i)^a_i) | i <- [1..N]] ==@+-- 6. @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 remainder of the Eisenstein integer factorisation problem is about+-- finding appropriate Eisenstein primes @[e_i | i <- [1..M]]@ such that+-- @map norm [e_i | i <- [1..M]] == map norm [π_i | i <- [1..N]]@+-- where @ 1 < N <= M@ are integers and @==@ is equality on sets+-- (i.e.duplicates do not matter). ----- * 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)]+-- NB: The reason @M >= N@ is because the prime factors of an Eisenstein integer+-- may include a prime factor and its conjugate (both have the same norm),+-- meaning the number may have more Eisenstein prime factors than its norm has+-- integer prime factors.+factorise :: EisensteinInteger -> [(Prime EisensteinInteger, Word)] factorise g = concat $               snd $-              mapAccumL go (abs g) (Factorisation.factorise $ norm g)+              mapAccumL go (abs g) (U.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."+    go :: EisensteinInteger -> (Prime Integer, Word) -> (EisensteinInteger, [(Prime EisensteinInteger, Word)])+    go z (Prime 3, e)+      | e == n    = (q, [(Prime (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')])+    go z (p, e)+      | unPrime p `mod` 3 == 2+      = let e' = e `quot` 2 in (z `quotI` (unPrime p ^ e'), [(Prime (unPrime 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')])+      -- 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 = findPrime p+        x :+ y = unPrime gp         -- @gp'@ is @gp@'s conjugate.-        gp'              = primary $ abs $ x :+ (x - y)-        (k, k', z') = divideByPrime gp gp' p e z+        gp' = Prime (x :+ (x - y))+        (k, k', z') = divideByPrime gp gp' (unPrime 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+    :: Prime EisensteinInteger -- ^ Eisenstein prime @p@+    -> Prime EisensteinInteger -- ^ Conjugate of @p@+    -> Integer                 -- ^ Precomputed norm of @p@, of form @4k + 1@+    -> Word                    -- ^ Expected number of factors (either @p@ or @conjugate p@)+                               --   in Eisenstein integer @z@+    -> EisensteinInteger       -- ^ Eisenstein integer @z@+    -> ( Word                  -- Multiplicity of factor @p@ in @z@+       , Word                  -- 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 :: Word -> Word -> EisensteinInteger -> (Word, Word, 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'+                z'' = head $ drop (wordToInt d2)+                    $ iterate (\g -> fromMaybe err $ (g * unPrime p) `quotEvenI` np) z' -        go1 :: Int -> Int -> EisensteinInteger -> (Int, EisensteinInteger)+        go1 :: Word -> Word -> EisensteinInteger -> (Word, EisensteinInteger)         go1 0 d z = (d, z)         go1 c d z-            | Just z' <- (z * p') `quotEvenI` np+            | Just z' <- (z * unPrime p') `quotEvenI` np             = go1 (c - 1) (d + 1) z'             | otherwise             = (d, z)@@ -313,3 +313,14 @@   where     (xq, xr) = x `quotRem` n     (yq, yr) = y `quotRem` n++-------------------------------------------------------------------------------++-- | See the source code and Haddock comments for the @factorise@ and @isPrime@+-- functions in this module (they are not exported) for implementation+-- details.+instance U.UniqueFactorisation EisensteinInteger where+  factorise 0 = []+  factorise e = coerce $ factorise e++  isPrime e = if isPrime e then Just (Prime e) else Nothing
Math/NumberTheory/Quadratic/GaussianIntegers.hs view
@@ -3,32 +3,26 @@ -- 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 BangPatterns  #-} {-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE TypeFamilies  #-}  module Math.NumberTheory.Quadratic.GaussianIntegers (     GaussianInteger(..),     ι,     conjugate,     norm,-    (.^),-    isPrime,     primes,-    gcdG,-    gcdG',     findPrime,-    findPrime',-    factorise, ) where  import Control.DeepSeq (NFData)+import Data.Coerce import Data.List (mapAccumL, partition) import Data.Maybe (fromMaybe) import Data.Ord (comparing)@@ -38,15 +32,14 @@ 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 Math.NumberTheory.Primes.Types import qualified Math.NumberTheory.Primes.Sieve as Sieve import qualified Math.NumberTheory.Primes.Testing as Testing+import qualified Math.NumberTheory.Primes  as U import Math.NumberTheory.Utils              (mergeBy)-import Math.NumberTheory.Utils.FromIntegral (integerToNatural)+import Math.NumberTheory.Utils.FromIntegral  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)@@ -119,77 +112,47 @@ -- |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]]+primes :: [U.Prime GaussianInteger]+primes = coerce $ (1 :+ 1) : mergeBy (comparing norm) l r+  where+    leftPrimes, rightPrimes :: [Prime Integer]+    (leftPrimes, rightPrimes) = partition (\p -> unPrime p `mod` 4 == 3) (tail Sieve.primes)+    l = [unPrime p :+ 0 | p <- leftPrimes]+    r = [g | p <- rightPrimes, let Prime (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+findPrime :: Prime Integer -> U.Prime GaussianInteger+findPrime p = case sqrtsModPrime (-1) p of     []    -> error "findPrime: an argument must be prime p = 4k + 1"-    z : _ -> go p z -- Effectively we calculate gcdG' (p :+ 0) (z :+ 1)+    z : _ -> Prime $ go (unPrime p) z -- Effectively we calculate gcdG' (p :+ 0) (z :+ 1)     where         sqrtp :: Integer-        sqrtp = integerSquareRoot p+        sqrtp = integerSquareRoot (unPrime 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).+-- | 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)+factorise :: GaussianInteger -> [(Prime GaussianInteger, Word)]+factorise g = concat $ snd $ mapAccumL go g (U.factorise $ norm g)     where-        go :: GaussianInteger -> (Integer, Int) -> (GaussianInteger, [(GaussianInteger, Int)])-        go z (2, e) = (divideByTwo z, [(1 :+ 1, e)])+        go :: GaussianInteger -> (Prime Integer, Word) -> (GaussianInteger, [(Prime GaussianInteger, Word)])+        go z (Prime 2, e) = (divideByTwo z, [(Prime (1 :+ 1), e)])         go z (p, e)-            | p `mod` 4 == 3-            = let e' = e `quot` 2 in (z `quotI` (p ^ e'), [(p :+ 0, e')])+            | unPrime p `mod` 4 == 3+            = let e' = e `quot` 2 in (z `quotI` (unPrime p ^ e'), [(Prime (unPrime 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)+                    (k, k', z') = divideByPrime gp (unPrime p) e z+                    gp' = Prime (abs (conjugate (unPrime gp)))  -- | Remove all (1:+1) factors from the argument, -- avoiding complex division.@@ -205,18 +168,18 @@ -- | 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+    :: Prime GaussianInteger -- ^ Gaussian prime p+    -> Integer               -- ^ Precomputed norm of p, of form 4k + 1+    -> Word                  -- ^ Expected number of factors (either p or conj p)+                             --   in Gaussian integer z+    -> GaussianInteger       -- ^ Gaussian integer z+    -> ( Word                -- Multiplicity of factor p in z+       , Word                -- 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 :: Word -> Word -> GaussianInteger -> (Word, Word, GaussianInteger)         go 0 d z = (d, d, z)         go c d z             | c >= 2@@ -226,13 +189,13 @@             where                 (d1, z') = go1 c 0 z                 d2 = c - d1-                z'' = head $ drop d2-                    $ iterate (\g -> fromMaybe err $ (g * p) `quotEvenI` np) z'+                z'' = head $ drop (wordToInt d2)+                    $ iterate (\g -> fromMaybe err $ (g * unPrime p) `quotEvenI` np) z' -        go1 :: Int -> Int -> GaussianInteger -> (Int, GaussianInteger)+        go1 :: Word -> Word -> GaussianInteger -> (Word, GaussianInteger)         go1 0 d z = (d, z)         go1 c d z-            | Just z' <- (z * conjugate p) `quotEvenI` np+            | Just z' <- (z * conjugate (unPrime p)) `quotEvenI` np             = go1 (c - 1) (d + 1) z'             | otherwise             = (d, z)@@ -252,3 +215,11 @@     where         (xq, xr) = x `quotRem` n         (yq, yr) = y `quotRem` n++-------------------------------------------------------------------------------++instance U.UniqueFactorisation GaussianInteger where+  factorise 0 = []+  factorise g = coerce $ factorise g++  isPrime g = if isPrime g then Just (Prime g) else Nothing
+ Math/NumberTheory/Recurrences.hs view
@@ -0,0 +1,16 @@+-- |+-- Module:      Math.NumberTheory.Recurrences+-- Copyright:   (c) 2018 Alexandre Rodrigues Baldé+-- Licence:     MIT+-- Maintainer:  Alexandre Rodrigues Baldé <alexandrer_b@outlook.com>+--++module Math.NumberTheory.Recurrences+    ( module Math.NumberTheory.Recurrences.Linear+    , module Math.NumberTheory.Recurrences.Bilinear+    , module Math.NumberTheory.Recurrences.Pentagonal+    ) where++import Math.NumberTheory.Recurrences.Bilinear+import Math.NumberTheory.Recurrences.Linear+import Math.NumberTheory.Recurrences.Pentagonal (partition)
+ Math/NumberTheory/Recurrences/Bilinear.hs view
@@ -0,0 +1,270 @@+-- |+-- Module:      Math.NumberTheory.Recurrences.Bilinear+-- Copyright:   (c) 2016 Andrew Lelechenko+-- Licence:     MIT+-- Maintainer:  Andrew Lelechenko <andrew.lelechenko@gmail.com>+--+-- Bilinear recurrent sequences and Bernoulli numbers,+-- roughly covering Ch. 5-6 of /Concrete Mathematics/+-- by R. L. Graham, D. E. Knuth and O. Patashnik.+--+-- #memory# __Note on memory leaks and memoization.__+-- 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)+--+-- 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)++{-# LANGUAGE CPP                 #-}+{-# LANGUAGE ScopedTypeVariables #-}++module Math.NumberTheory.Recurrences.Bilinear+  ( binomial+  , stirling1+  , stirling2+  , lah+  , eulerian1+  , eulerian2+  , bernoulli+  , euler+  , eulerPolyAt1+  , faulhaberPoly+  ) where++import Data.List+import Data.Ratio+import Numeric.Natural++import Math.NumberTheory.Recurrences.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]]+--+-- 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@.+-- Use the symmetry of Pascal triangle @binomial !! n !! k == binomial !! n !! (n - k)@ to speed up computations.+--+-- One could also consider 'Math.Combinat.Numbers.binomial' to compute stand-alone values.+binomial :: Integral a => [[a]]+binomial = map f [0..]+  where+    f n = scanl (\x k -> x * (n - k + 1) `div` k) 1 [1..n]+{-# SPECIALIZE binomial :: [[Int]]     #-}+{-# SPECIALIZE binomial :: [[Word]]    #-}+{-# SPECIALIZE binomial :: [[Integer]] #-}+{-# SPECIALIZE binomial :: [[Natural]] #-}++-- | 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]]+--+-- 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@.+--+-- One could also consider 'Math.Combinat.Numbers.unsignedStirling1st' to compute stand-alone values.+stirling1 :: (Num a, Enum a) => [[a]]+stirling1 = scanl f [1] [0..]+  where+    f xs n = 0 : zipIndexedListWithTail (\_ x y -> x + n * y) 1 xs 0+{-# SPECIALIZE stirling1 :: [[Int]]     #-}+{-# SPECIALIZE stirling1 :: [[Word]]    #-}+{-# SPECIALIZE stirling1 :: [[Integer]] #-}+{-# SPECIALIZE stirling1 :: [[Natural]] #-}++-- | 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]]+--+-- 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@.+--+-- One could also consider 'Math.Combinat.Numbers.stirling2nd' to compute stand-alone values.+stirling2 :: (Num a, Enum a) => [[a]]+stirling2 = iterate f [1]+  where+    f xs = 0 : zipIndexedListWithTail (\k x y -> x + k * y) 1 xs 0+{-# SPECIALIZE stirling2 :: [[Int]]     #-}+{-# SPECIALIZE stirling2 :: [[Word]]    #-}+{-# SPECIALIZE stirling2 :: [[Integer]] #-}+{-# SPECIALIZE stirling2 :: [[Natural]] #-}++-- | 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]]+--+-- 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@.+lah :: Integral a => [[a]]+-- Implementation was derived from code by https://github.com/grandpascorpion+lah = zipWith f (tail factorial) [1..]+  where+    f nf n = scanl (\x k -> x * (n - k) `div` (k * (k + 1))) nf [1..n-1]+{-# SPECIALIZE lah :: [[Int]]     #-}+{-# SPECIALIZE lah :: [[Word]]    #-}+{-# SPECIALIZE lah :: [[Integer]] #-}+{-# SPECIALIZE lah :: [[Natural]] #-}++-- | 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]]+--+-- 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@.+--+eulerian1 :: (Num a, Enum a) => [[a]]+eulerian1 = scanl f [] [1..]+  where+    f xs n = 1 : zipIndexedListWithTail (\k x y -> (n - k) * x + (k + 1) * y) 1 xs 0+{-# SPECIALIZE eulerian1 :: [[Int]]     #-}+{-# SPECIALIZE eulerian1 :: [[Word]]    #-}+{-# SPECIALIZE eulerian1 :: [[Integer]] #-}+{-# SPECIALIZE eulerian1 :: [[Natural]] #-}++-- | 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]]+--+-- 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@.+--+eulerian2 :: (Num a, Enum a) => [[a]]+eulerian2 = scanl f [] [1..]+  where+    f xs n = 1 : zipIndexedListWithTail (\k x y -> (2 * n - k - 1) * x + (k + 1) * y) 1 xs 0+{-# SPECIALIZE eulerian2 :: [[Int]]     #-}+{-# SPECIALIZE eulerian2 :: [[Word]]    #-}+{-# SPECIALIZE eulerian2 :: [[Integer]] #-}+{-# SPECIALIZE eulerian2 :: [[Natural]] #-}++-- | Infinite zero-based sequence of <https://en.wikipedia.org/wiki/Bernoulli_number Bernoulli numbers>,+-- 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]+--+-- 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 = helperForB_E_EP id (map recip [1..])+{-# SPECIALIZE bernoulli :: [Ratio Int] #-}+{-# SPECIALIZE bernoulli :: [Rational] #-}++-- | <https://en.wikipedia.org/wiki/Faulhaber%27s_formula Faulhaber's formula>.+--+-- >>> sum (map (^ 10) [0..100])+-- 959924142434241924250+-- >>> sum $ zipWith (*) (faulhaberPoly 10) (iterate (* 100) 1)+-- 959924142434241924250 % 1+faulhaberPoly :: Integral a => Int -> [Ratio a]+-- Implementation by https://github.com/CarlEdman+faulhaberPoly p+  = zipWith (*) ((0:)+  $ reverse+  $ take (p+1) $ bernoulli)+  $ map (% (fromIntegral p+1))+  $ zipWith (*) (iterate negate (if odd p then 1 else -1))+  $ binomial !! (fromIntegral p+1)++-- | 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++-- zipIndexedListWithTail f n as a == zipWith3 f [n..] as (tail as ++ [a])+-- but inlines much better and avoids checks for distinct sizes of lists.+zipIndexedListWithTail :: Enum b => (b -> a -> a -> b) -> b -> [a] -> a -> [b]+zipIndexedListWithTail f n as a = case as of+  []       -> []+  (x : xs) -> go n x xs+  where+    go m y ys = case ys of+      []       -> 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/Recurrences/Linear.hs view
@@ -0,0 +1,136 @@+-- |+-- Module:      Math.NumberTheory.Recurrences.Linear+-- Copyright:   (c) 2011 Daniel Fischer+-- Licence:     MIT+-- Maintainer:  Daniel Fischer <daniel.is.fischer@googlemail.com>+--+-- Efficient calculation of linear recurrent sequences, including Fibonacci and Lucas sequences.++{-# LANGUAGE CPP #-}+module Math.NumberTheory.Recurrences.Linear+  ( factorial+  , fibonacci+  , fibonacciPair+  , lucas+  , lucasPair+  , generalLucas+  ) where++#include "MachDeps.h"++import Data.Bits+import Numeric.Natural++-- | Infinite zero-based table of factorials.+--+-- >>> take 5 factorial+-- [1,1,2,6,24]+--+-- The time-and-space behaviour of 'factorial' is similar to described in+-- "Math.NumberTheory.Recurrences.Bilinear#memory".+factorial :: (Num a, Enum a) => [a]+factorial = scanl (*) 1 [1..]+{-# SPECIALIZE factorial :: [Int]     #-}+{-# SPECIALIZE factorial :: [Word]    #-}+{-# SPECIALIZE factorial :: [Integer] #-}+{-# SPECIALIZE factorial :: [Natural] #-}++-- | @'fibonacci' k@ calculates the @k@-th Fibonacci number in+--   /O/(@log (abs k)@) steps. The index may be negative. This+--   is efficient for calculating single Fibonacci numbers (with+--   large index), but for computing many Fibonacci numbers in+--   close proximity, it is better to use the simple addition+--   formula starting from an appropriate pair of successive+--   Fibonacci numbers.+fibonacci :: Num a => Int -> a+fibonacci = fst . fibonacciPair+{-# SPECIALIZE fibonacci :: Int -> Int     #-}+{-# SPECIALIZE fibonacci :: Int -> Word    #-}+{-# SPECIALIZE fibonacci :: Int -> Integer #-}+{-# SPECIALIZE fibonacci :: Int -> Natural #-}++-- | @'fibonacciPair' k@ returns the pair @(F(k), F(k+1))@ of the @k@-th+--   Fibonacci number and its successor, thus it can be used to calculate+--   the Fibonacci numbers from some index on without needing to compute+--   the previous. The pair is efficiently calculated+--   in /O/(@log (abs k)@) steps. The index may be negative.+fibonacciPair :: Num a => Int -> (a, a)+fibonacciPair n+  | n < 0     = let (f,g) = fibonacciPair (-(n+1)) in if testBit n 0 then (g, -f) else (-g, f)+  | n == 0    = (0, 1)+  | otherwise = look (WORD_SIZE_IN_BITS - 2)+    where+      look k+        | testBit n k = go (k-1) 0 1+        | otherwise   = look (k-1)+      go k g f+        | k < 0       = (f, f+g)+        | testBit n k = go (k-1) (f*(f+shiftL1 g)) ((f+g)*shiftL1 f + g*g)+        | otherwise   = go (k-1) (f*f+g*g) (f*(f+shiftL1 g))+{-# SPECIALIZE fibonacciPair :: Int -> (Int, Int)         #-}+{-# SPECIALIZE fibonacciPair :: Int -> (Word, Word)       #-}+{-# SPECIALIZE fibonacciPair :: Int -> (Integer, Integer) #-}+{-# SPECIALIZE fibonacciPair :: Int -> (Natural, Natural) #-}++-- | @'lucas' k@ computes the @k@-th Lucas number. Very similar+--   to @'fibonacci'@.+lucas :: Num a => Int -> a+lucas = fst . lucasPair+{-# SPECIALIZE lucas :: Int -> Int     #-}+{-# SPECIALIZE lucas :: Int -> Word    #-}+{-# SPECIALIZE lucas :: Int -> Integer #-}+{-# SPECIALIZE lucas :: Int -> Natural #-}++-- | @'lucasPair' k@ computes the pair @(L(k), L(k+1))@ of the @k@-th+--   Lucas number and its successor. Very similar to @'fibonacciPair'@.+lucasPair :: Num a => Int -> (a, a)+lucasPair n+  | n < 0     = let (f,g) = lucasPair (-(n+1)) in if testBit n 0 then (-g, f) else (g, -f)+  | n == 0    = (2, 1)+  | otherwise = look (WORD_SIZE_IN_BITS - 2)+    where+      look k+        | testBit n k = go (k-1) 0 1+        | otherwise   = look (k-1)+      go k g f+        | k < 0       = (shiftL1 g + f,g+3*f)+        | otherwise   = go (k-1) g' f'+          where+            (f',g')+              | testBit n k = (shiftL1 (f*(f+g)) + g*g,f*(shiftL1 g + f))+              | otherwise   = (f*(shiftL1 g + f),f*f+g*g)+{-# SPECIALIZE lucasPair :: Int -> (Int, Int)         #-}+{-# SPECIALIZE lucasPair :: Int -> (Word, Word)       #-}+{-# SPECIALIZE lucasPair :: Int -> (Integer, Integer) #-}+{-# SPECIALIZE lucasPair :: Int -> (Natural, Natural) #-}++-- | @'generalLucas' p q k@ calculates the quadruple @(U(k), U(k+1), V(k), V(k+1))@+--   where @U(i)@ is the Lucas sequence of the first kind and @V(i)@ the Lucas+--   sequence of the second kind for the parameters @p@ and @q@, where @p^2-4q /= 0@.+--   Both sequences satisfy the recurrence relation @A(j+2) = p*A(j+1) - q*A(j)@,+--   the starting values are @U(0) = 0, U(1) = 1@ and @V(0) = 2, V(1) = p@.+--   The Fibonacci numbers form the Lucas sequence of the first kind for the+--   parameters @p = 1, q = -1@ and the Lucas numbers form the Lucas sequence of+--   the second kind for these parameters.+--   Here, the index must be non-negative, since the terms of the sequence for+--   negative indices are in general not integers.+generalLucas :: Num a => a -> a -> Int -> (a, a, a, a)+generalLucas p q k+  | k < 0       = error "generalLucas: negative index"+  | k == 0      = (0,1,2,p)+  | otherwise   = look (WORD_SIZE_IN_BITS - 2)+    where+      look i+        | testBit k i   = go (i-1) 1 p p q+        | otherwise     = look (i-1)+      go i un un1 vn qn+        | i < 0         = (un, un1, vn, p*un1 - shiftL1 (q*un))+        | testBit k i   = go (i-1) (un1*vn-qn) ((p*un1-q*un)*vn - p*qn) ((p*un1 - (2*q)*un)*vn - p*qn) (qn*qn*q)+        | otherwise     = go (i-1) (un*vn) (un1*vn-qn) (vn*vn - 2*qn) (qn*qn)+{-# SPECIALIZE generalLucas :: Int     -> Int     -> Int -> (Int, Int, Int, Int)                 #-}+{-# SPECIALIZE generalLucas :: Word    -> Word    -> Int -> (Word, Word, Word, Word)             #-}+{-# SPECIALIZE generalLucas :: Integer -> Integer -> Int -> (Integer, Integer, Integer, Integer) #-}+{-# SPECIALIZE generalLucas :: Natural -> Natural -> Int -> (Natural, Natural, Natural, Natural) #-}++shiftL1 :: Num a => a -> a+shiftL1 n = n + n
+ Math/NumberTheory/Recurrences/Pentagonal.hs view
@@ -0,0 +1,95 @@+-- |+-- Module:      Math.NumberTheory.Recurrences.Pentagonal+-- Copyright:   (c) 2018 Alexandre Rodrigues Baldé+-- Licence:     MIT+-- Maintainer:  Alexandre Rodrigues Baldé <alexandrer_b@outlook.com>+--+-- Values of <https://en.wikipedia.org/wiki/Partition_(number_theory)#Partition_function partition function>.+--++{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE RankNTypes   #-}++module Math.NumberTheory.Recurrences.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+-- >>> import Math.NumberTheory.Moduli.Class+-- >>> 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/Recurrencies.hs view
@@ -1,18 +1,17 @@ -- | -- Module:      Math.NumberTheory.Recurrencies+-- Description: Deprecated -- 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+module Math.NumberTheory.Recurrencies {-# DEPRECATED "Use `Math.NumberTheory.Recurrences` instead." #-}+    ( module Math.NumberTheory.Recurrences.Linear+    , module Math.NumberTheory.Recurrences.Bilinear+    , module Math.NumberTheory.Recurrences.Pentagonal     ) where -import Math.NumberTheory.Recurrencies.Bilinear-import Math.NumberTheory.Recurrencies.Linear-import Math.NumberTheory.Recurrencies.Pentagonal (partition)+import Math.NumberTheory.Recurrences.Bilinear+import Math.NumberTheory.Recurrences.Linear+import Math.NumberTheory.Recurrences.Pentagonal (partition)
Math/NumberTheory/Recurrencies/Bilinear.hs view
@@ -1,10 +1,9 @@ -- | -- Module:      Math.NumberTheory.Recurrencies.Bilinear+-- Description: Deprecated -- Copyright:   (c) 2016 Andrew Lelechenko -- Licence:     MIT -- Maintainer:  Andrew Lelechenko <andrew.lelechenko@gmail.com>--- Stability:   Provisional--- Portability: Non-portable (GHC extensions) -- -- Bilinear recurrent sequences and Bernoulli numbers, -- roughly covering Ch. 5-6 of /Concrete Mathematics/@@ -32,224 +31,8 @@ -- 1 -- (0.01 secs, 391,152 bytes) -{-# LANGUAGE CPP                 #-}-{-# LANGUAGE ScopedTypeVariables #-}--module Math.NumberTheory.Recurrencies.Bilinear-  ( binomial-  , stirling1-  , stirling2-  , lah-  , eulerian1-  , eulerian2-  , bernoulli-  , euler-  , eulerPolyAt1-  ) where--import Data.List-import Data.Ratio-import Numeric.Natural--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]]------ 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@.--- Use the symmetry of Pascal triangle @binomial !! n !! k == binomial !! n !! (n - k)@ to speed up computations.------ One could also consider 'Math.Combinat.Numbers.binomial' to compute stand-alone values.-binomial :: Integral a => [[a]]-binomial = map f [0..]-  where-    f n = scanl (\x k -> x * (n - k + 1) `div` k) 1 [1..n]-{-# SPECIALIZE binomial :: [[Int]]     #-}-{-# SPECIALIZE binomial :: [[Word]]    #-}-{-# SPECIALIZE binomial :: [[Integer]] #-}-{-# SPECIALIZE binomial :: [[Natural]] #-}---- | 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]]------ 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@.------ One could also consider 'Math.Combinat.Numbers.unsignedStirling1st' to compute stand-alone values.-stirling1 :: (Num a, Enum a) => [[a]]-stirling1 = scanl f [1] [0..]-  where-    f xs n = 0 : zipIndexedListWithTail (\_ x y -> x + n * y) 1 xs 0-{-# SPECIALIZE stirling1 :: [[Int]]     #-}-{-# SPECIALIZE stirling1 :: [[Word]]    #-}-{-# SPECIALIZE stirling1 :: [[Integer]] #-}-{-# SPECIALIZE stirling1 :: [[Natural]] #-}---- | 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]]------ 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@.------ One could also consider 'Math.Combinat.Numbers.stirling2nd' to compute stand-alone values.-stirling2 :: (Num a, Enum a) => [[a]]-stirling2 = iterate f [1]-  where-    f xs = 0 : zipIndexedListWithTail (\k x y -> x + k * y) 1 xs 0-{-# SPECIALIZE stirling2 :: [[Int]]     #-}-{-# SPECIALIZE stirling2 :: [[Word]]    #-}-{-# SPECIALIZE stirling2 :: [[Integer]] #-}-{-# SPECIALIZE stirling2 :: [[Natural]] #-}---- | 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]]------ 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@.-lah :: Integral a => [[a]]--- Implementation was derived from code by https://github.com/grandpascorpion-lah = zipWith f (tail factorial) [1..]-  where-    f nf n = scanl (\x k -> x * (n - k) `div` (k * (k + 1))) nf [1..n-1]-{-# SPECIALIZE lah :: [[Int]]     #-}-{-# SPECIALIZE lah :: [[Word]]    #-}-{-# SPECIALIZE lah :: [[Integer]] #-}-{-# SPECIALIZE lah :: [[Natural]] #-}---- | 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]]------ 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@.----eulerian1 :: (Num a, Enum a) => [[a]]-eulerian1 = scanl f [] [1..]-  where-    f xs n = 1 : zipIndexedListWithTail (\k x y -> (n - k) * x + (k + 1) * y) 1 xs 0-{-# SPECIALIZE eulerian1 :: [[Int]]     #-}-{-# SPECIALIZE eulerian1 :: [[Word]]    #-}-{-# SPECIALIZE eulerian1 :: [[Integer]] #-}-{-# SPECIALIZE eulerian1 :: [[Natural]] #-}---- | 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]]------ 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@.----eulerian2 :: (Num a, Enum a) => [[a]]-eulerian2 = scanl f [] [1..]-  where-    f xs n = 1 : zipIndexedListWithTail (\k x y -> (2 * n - k - 1) * x + (k + 1) * y) 1 xs 0-{-# SPECIALIZE eulerian2 :: [[Int]]     #-}-{-# SPECIALIZE eulerian2 :: [[Word]]    #-}-{-# SPECIALIZE eulerian2 :: [[Integer]] #-}-{-# SPECIALIZE eulerian2 :: [[Natural]] #-}---- | Infinite zero-based sequence of <https://en.wikipedia.org/wiki/Bernoulli_number Bernoulli numbers>,--- 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]------ 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 = 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---- zipIndexedListWithTail f n as a == zipWith3 f [n..] as (tail as ++ [a])--- but inlines much better and avoids checks for distinct sizes of lists.-zipIndexedListWithTail :: Enum b => (b -> a -> a -> b) -> b -> [a] -> a -> [b]-zipIndexedListWithTail f n as a = case as of-  []       -> []-  (x : xs) -> go n x xs-  where-    go m y ys = case ys of-      []       -> 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 #-}+module Math.NumberTheory.Recurrencies.Bilinear {-# DEPRECATED "Use `Math.NumberTheory.Recurrences.Bilinear` instead." #-}+    ( module Math.NumberTheory.Recurrences.Bilinear+    ) where --- | 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]     #-}+import Math.NumberTheory.Recurrences.Bilinear
Math/NumberTheory/Recurrencies/Linear.hs view
@@ -1,138 +1,14 @@ -- | -- Module:      Math.NumberTheory.Recurrencies.Linear+-- Description: Deprecated -- Copyright:   (c) 2011 Daniel Fischer -- Licence:     MIT -- Maintainer:  Daniel Fischer <daniel.is.fischer@googlemail.com>--- Stability:   Provisional--- Portability: Non-portable (GHC extensions) -- -- Efficient calculation of linear recurrent sequences, including Fibonacci and Lucas sequences. -{-# LANGUAGE CPP #-}-module Math.NumberTheory.Recurrencies.Linear-  ( factorial-  , fibonacci-  , fibonacciPair-  , lucas-  , lucasPair-  , generalLucas-  ) where--#include "MachDeps.h"--import Data.Bits-import Numeric.Natural---- | Infinite zero-based table of factorials.------ >>> 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".-factorial :: (Num a, Enum a) => [a]-factorial = scanl (*) 1 [1..]-{-# SPECIALIZE factorial :: [Int]     #-}-{-# SPECIALIZE factorial :: [Word]    #-}-{-# SPECIALIZE factorial :: [Integer] #-}-{-# SPECIALIZE factorial :: [Natural] #-}---- | @'fibonacci' k@ calculates the @k@-th Fibonacci number in---   /O/(@log (abs k)@) steps. The index may be negative. This---   is efficient for calculating single Fibonacci numbers (with---   large index), but for computing many Fibonacci numbers in---   close proximity, it is better to use the simple addition---   formula starting from an appropriate pair of successive---   Fibonacci numbers.-fibonacci :: Num a => Int -> a-fibonacci = fst . fibonacciPair-{-# SPECIALIZE fibonacci :: Int -> Int     #-}-{-# SPECIALIZE fibonacci :: Int -> Word    #-}-{-# SPECIALIZE fibonacci :: Int -> Integer #-}-{-# SPECIALIZE fibonacci :: Int -> Natural #-}---- | @'fibonacciPair' k@ returns the pair @(F(k), F(k+1))@ of the @k@-th---   Fibonacci number and its successor, thus it can be used to calculate---   the Fibonacci numbers from some index on without needing to compute---   the previous. The pair is efficiently calculated---   in /O/(@log (abs k)@) steps. The index may be negative.-fibonacciPair :: Num a => Int -> (a, a)-fibonacciPair n-  | n < 0     = let (f,g) = fibonacciPair (-(n+1)) in if testBit n 0 then (g, -f) else (-g, f)-  | n == 0    = (0, 1)-  | otherwise = look (WORD_SIZE_IN_BITS - 2)-    where-      look k-        | testBit n k = go (k-1) 0 1-        | otherwise   = look (k-1)-      go k g f-        | k < 0       = (f, f+g)-        | testBit n k = go (k-1) (f*(f+shiftL1 g)) ((f+g)*shiftL1 f + g*g)-        | otherwise   = go (k-1) (f*f+g*g) (f*(f+shiftL1 g))-{-# SPECIALIZE fibonacciPair :: Int -> (Int, Int)         #-}-{-# SPECIALIZE fibonacciPair :: Int -> (Word, Word)       #-}-{-# SPECIALIZE fibonacciPair :: Int -> (Integer, Integer) #-}-{-# SPECIALIZE fibonacciPair :: Int -> (Natural, Natural) #-}---- | @'lucas' k@ computes the @k@-th Lucas number. Very similar---   to @'fibonacci'@.-lucas :: Num a => Int -> a-lucas = fst . lucasPair-{-# SPECIALIZE lucas :: Int -> Int     #-}-{-# SPECIALIZE lucas :: Int -> Word    #-}-{-# SPECIALIZE lucas :: Int -> Integer #-}-{-# SPECIALIZE lucas :: Int -> Natural #-}---- | @'lucasPair' k@ computes the pair @(L(k), L(k+1))@ of the @k@-th---   Lucas number and its successor. Very similar to @'fibonacciPair'@.-lucasPair :: Num a => Int -> (a, a)-lucasPair n-  | n < 0     = let (f,g) = lucasPair (-(n+1)) in if testBit n 0 then (-g, f) else (g, -f)-  | n == 0    = (2, 1)-  | otherwise = look (WORD_SIZE_IN_BITS - 2)-    where-      look k-        | testBit n k = go (k-1) 0 1-        | otherwise   = look (k-1)-      go k g f-        | k < 0       = (shiftL1 g + f,g+3*f)-        | otherwise   = go (k-1) g' f'-          where-            (f',g')-              | testBit n k = (shiftL1 (f*(f+g)) + g*g,f*(shiftL1 g + f))-              | otherwise   = (f*(shiftL1 g + f),f*f+g*g)-{-# SPECIALIZE lucasPair :: Int -> (Int, Int)         #-}-{-# SPECIALIZE lucasPair :: Int -> (Word, Word)       #-}-{-# SPECIALIZE lucasPair :: Int -> (Integer, Integer) #-}-{-# SPECIALIZE lucasPair :: Int -> (Natural, Natural) #-}---- | @'generalLucas' p q k@ calculates the quadruple @(U(k), U(k+1), V(k), V(k+1))@---   where @U(i)@ is the Lucas sequence of the first kind and @V(i)@ the Lucas---   sequence of the second kind for the parameters @p@ and @q@, where @p^2-4q /= 0@.---   Both sequences satisfy the recurrence relation @A(j+2) = p*A(j+1) - q*A(j)@,---   the starting values are @U(0) = 0, U(1) = 1@ and @V(0) = 2, V(1) = p@.---   The Fibonacci numbers form the Lucas sequence of the first kind for the---   parameters @p = 1, q = -1@ and the Lucas numbers form the Lucas sequence of---   the second kind for these parameters.---   Here, the index must be non-negative, since the terms of the sequence for---   negative indices are in general not integers.-generalLucas :: Num a => a -> a -> Int -> (a, a, a, a)-generalLucas p q k-  | k < 0       = error "generalLucas: negative index"-  | k == 0      = (0,1,2,p)-  | otherwise   = look (WORD_SIZE_IN_BITS - 2)-    where-      look i-        | testBit k i   = go (i-1) 1 p p q-        | otherwise     = look (i-1)-      go i un un1 vn qn-        | i < 0         = (un, un1, vn, p*un1 - shiftL1 (q*un))-        | testBit k i   = go (i-1) (un1*vn-qn) ((p*un1-q*un)*vn - p*qn) ((p*un1 - (2*q)*un)*vn - p*qn) (qn*qn*q)-        | otherwise     = go (i-1) (un*vn) (un1*vn-qn) (vn*vn - 2*qn) (qn*qn)-{-# SPECIALIZE generalLucas :: Int     -> Int     -> Int -> (Int, Int, Int, Int)                 #-}-{-# SPECIALIZE generalLucas :: Word    -> Word    -> Int -> (Word, Word, Word, Word)             #-}-{-# SPECIALIZE generalLucas :: Integer -> Integer -> Int -> (Integer, Integer, Integer, Integer) #-}-{-# SPECIALIZE generalLucas :: Natural -> Natural -> Int -> (Natural, Natural, Natural, Natural) #-}+module Math.NumberTheory.Recurrencies.Linear {-# DEPRECATED "Use `Math.NumberTheory.Recurrences.Linear` instead." #-}+    ( module Math.NumberTheory.Recurrences.Linear+    ) where -shiftL1 :: Num a => a -> a-shiftL1 n = n + n+import Math.NumberTheory.Recurrences.Linear
− Math/NumberTheory/Recurrencies/Pentagonal.hs
@@ -1,96 +0,0 @@--- |--- 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
@@ -3,8 +3,6 @@ -- Copyright:   (c) 2018 Frederick Schneider -- Licence:     MIT -- Maintainer:  Frederick Schneider <frederick.schneider2011@gmail.com>--- Stability:   Provisional--- Portability: Non-portable (GHC extensions) -- -- A <https://en.wikipedia.org/wiki/Smooth_number smooth number> -- is an integer, which can be represented as a product of powers of elements@@ -22,44 +20,49 @@   , fromSmoothUpperBound     -- * Generate smooth numbers   , smoothOver+  , smoothOver'   , smoothOverInRange   , smoothOverInRangeBF++  -- * Verify if a number is smooth+  , isSmooth   ) where  import Prelude hiding (div, mod, gcd) import Data.Coerce import Data.List (nub) import qualified Data.Set as S-import Math.NumberTheory.Euclidean+import qualified Math.NumberTheory.Euclidean as E+import Math.NumberTheory.Primes (unPrime) import Math.NumberTheory.Primes.Sieve (primes)  -- | An abstract representation of a smooth basis.--- It consists of a set of coprime numbers ≥2.+-- It consists of a set of numbers ≥2. newtype SmoothBasis a = SmoothBasis { unSmoothBasis :: [a] } deriving (Eq, Show) --- | Build a 'SmoothBasis' from a set of coprime numbers ≥2.+-- | Build a 'SmoothBasis' from a set of numbers ≥2. -- -- >>> import qualified Data.Set as Set -- >>> fromSet (Set.fromList [2, 3])--- Just (SmoothBasis [2, 3])--- >>> fromSet (Set.fromList [2, 4]) -- should be coprime--- Nothing+-- Just (SmoothBasis {unSmoothBasis = [2,3]})+-- >>> fromSet (Set.fromList [2, 4])+-- Just (SmoothBasis {unSmoothBasis = [2,4]}) -- >>> fromSet (Set.fromList [1, 3]) -- should be >= 2 -- Nothing-fromSet :: Euclidean a => S.Set a -> Maybe (SmoothBasis a)+fromSet :: E.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.+-- | Build a 'SmoothBasis' from a list of numbers ≥2. -- -- >>> fromList [2, 3]--- Just (SmoothBasis [2, 3])+-- Just (SmoothBasis {unSmoothBasis = [2,3]}) -- >>> fromList [2, 2]--- Just (SmoothBasis [2])--- >>> fromList [2, 4] -- should be coprime--- Nothing+-- Just (SmoothBasis {unSmoothBasis = [2]})+-- >>> fromList [2, 4]+-- Just (SmoothBasis {unSmoothBasis = [2,4]}) -- >>> fromList [1, 3] -- should be >= 2 -- Nothing-fromList :: Euclidean a => [a] -> Maybe (SmoothBasis a)+fromList :: E.Euclidean a => [a] -> Maybe (SmoothBasis a) fromList l = if isValid l' then Just (SmoothBasis l') else Nothing   where     l' = nub l@@ -67,36 +70,53 @@ -- | Build a 'SmoothBasis' from a list of primes below given bound. -- -- >>> fromSmoothUpperBound 10--- Just (SmoothBasis [2, 3, 5, 7])+-- Just (SmoothBasis {unSmoothBasis = [2,3,5,7]}) -- >>> fromSmoothUpperBound 1 -- Nothing fromSmoothUpperBound :: Integral a => a -> Maybe (SmoothBasis a) fromSmoothUpperBound n = if (n < 2)                          then Nothing-                         else Just $ SmoothBasis $ takeWhile (<= n) primes+                         else Just $ SmoothBasis $ takeWhile (<= n) $ map unPrime primes +-- | Helper used by @smoothOver@ (@Integral@ constraint) and @smoothOver'@+-- (@Euclidean@ constraint) Since the typeclass constraint is just+-- @Num@, it receives a @norm@ comparison function for the generated smooth+-- numbers.+-- This function relies on the fact that for any element of a smooth basis @p@+-- and any @a@ it is true that @norm (a * p) > norm a@.+-- This condition is not checked.+smoothOver' :: forall a b . (Eq a, Num a, Ord b) => (a -> b) -> SmoothBasis a -> [a]+smoothOver' norm pl =+    foldr+    (\p l -> mergeListLists $ iterate (map $ abs . (p*)) l)+    [1]+    (nub $ unSmoothBasis pl)+  where+    {-# INLINE mergeListLists #-}+    mergeListLists :: [[a]] -> [a]+    mergeListLists = foldr go1 []+      where+        go1 :: [a] -> [a] -> [a]+        go1 []    b = b+        go1 (h:t) b = h:(go2 t b)++        go2 :: [a] -> [a] -> [a]+        go2 a [] = a+        go2 [] b = b+        go2 a@(ah:at) b@(bh:bt)+          | norm bh < norm ah   = bh : (go2 a bt)+          | ah == bh    = ah : (go2 at bt)+          | otherwise = ah : (go2 at b)+ -- | Generate an infinite ascending list of -- <https://en.wikipedia.org/wiki/Smooth_number smooth numbers> -- over a given smooth basis. -- -- >>> import Data.Maybe -- >>> take 10 (smoothOver (fromJust (fromList [2, 5])))--- [1, 2, 4, 5, 8, 10, 16, 20, 25, 32]+-- [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 :: Ord a => [a] -> [a] -> [a]-        go1 (h:t) b = h:(go2 t b)-        go1 _     b = b--        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+smoothOver = smoothOver' abs  -- | Generate an ascending list of -- <https://en.wikipedia.org/wiki/Smooth_number smooth numbers>@@ -108,13 +128,13 @@ -- -- >>> import Data.Maybe -- >>> smoothOverInRange (fromJust (fromList [2, 5])) 100 200--- [100, 125, 128, 160, 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))+  $ smoothOver (coerce s :: SmoothBasis (E.WrappedIntegral a))  -- | Generate an ascending list of -- <https://en.wikipedia.org/wiki/Smooth_number smooth numbers>@@ -128,25 +148,34 @@ -- -- >>> 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]+-- [100,125,128,160,200]+smoothOverInRangeBF+  :: forall a. (Enum a, E.Euclidean a)+  => SmoothBasis a+  -> a+  -> a+  -> [a] smoothOverInRangeBF prs lo hi   = coerce-  $ filter (mf prs')+  $ filter (isSmooth 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 :: Euclidean a => [a] -> Bool+isValid :: (Eq a, Num a) => [a] -> Bool isValid pl = length pl /= 0 && v' pl   where-    v' :: Euclidean a => [a] -> Bool+    v' :: (Eq a, Num a) => [a] -> Bool     v' []     = True-    v' (x:xs) = x /= 0 && abs x /= 1 && abs x == x && all (coprime x) xs && v' xs+    v' (x:xs) = x /= 0 && abs x /= 1 && abs x == x && v' xs++-- | @isSmooth@ checks if a given number is smooth under a certain @SmoothBasis@.+-- Does not check if the @SmoothBasis@ is valid.+isSmooth :: forall a . E.Euclidean a => SmoothBasis a -> a -> Bool+isSmooth prs x = mf (unSmoothBasis prs) x+  where+    mf :: [a] -> a -> Bool+    mf _         0 = False+    mf []        n = abs n == 1 -- mf means manually factor+    mf pl@(p:ps) n = if E.mod n p == 0+                     then mf pl (E.div n p)+                     else mf ps n
Math/NumberTheory/UniqueFactorisation.hs view
@@ -1,90 +1,13 @@ -- |--- Module:      Math.NumberTheory.UniqueFactorisation--- Copyright:   (c) 2016 Andrew Lelechenko+-- Module:      Math.NumberTheory.Recurrencies+-- Description: Deprecated+-- Copyright:   (c) 2019 Andrew Lelechenko -- Licence:     MIT -- Maintainer:  Andrew Lelechenko <andrew.lelechenko@gmail.com>--- Stability:   Provisional--- Portability: Non-portable (GHC extensions) ----- An abstract type class for unique factorisation domains.--- -{-# LANGUAGE CPP               #-}-{-# LANGUAGE TypeFamilies      #-}-{-# LANGUAGE DefaultSignatures #-}--module Math.NumberTheory.UniqueFactorisation-  ( Prime-  , UniqueFactorisation(..)-  ) where--import Control.Arrow-import Data.Coerce--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.Quadratic.EisensteinIntegers as E-import qualified Math.NumberTheory.Quadratic.GaussianIntegers as G-import Math.NumberTheory.Utils.FromIntegral--import Numeric.Natural--type instance Prime G.GaussianInteger = GaussianPrime---- | The following invariant must hold for @n /= 0@:------ > abs n == abs (product (map (\(p, k) -> unPrime p ^ k) (factorise n)))------ The result of 'factorise' should not contain zero powers and should not change after multiplication of the argument by domain's unit.-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--  {-# MINIMAL unPrime, factorise #-}--instance UniqueFactorisation Int where-  unPrime   = coerce wordToInt-  factorise = map (coerce integerToWord *** intToWord) . F.factorise . intToInteger--instance UniqueFactorisation Word where-  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 = 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 = 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 }-  deriving (Eq, Show)--instance UniqueFactorisation G.GaussianInteger where-  unPrime = coerce--  factorise 0 = []-  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+module Math.NumberTheory.UniqueFactorisation {-# DEPRECATED "Use `Math.NumberTheory.Primes` instead." #-}+    ( module Math.NumberTheory.Primes+    ) where -  factorise 0 = []-  factorise e = map (coerce *** intToWord) $ E.factorise e+import Math.NumberTheory.Primes
Math/NumberTheory/Unsafe.hs view
@@ -3,7 +3,6 @@ -- Copyright:   (c) 2016 Andrew Lelechenko -- Licence:     MIT -- Maintainer:  Andrew Lelechenko <andrew.lelechenko@gmail.com>--- Stability:   Provisional -- -- Layer to switch between safe and unsafe arrays. --
Math/NumberTheory/Utils.hs view
@@ -3,8 +3,6 @@ -- Copyright:   (c) 2011 Daniel Fischer -- Licence:     MIT -- Maintainer:  Daniel Fischer <daniel.is.fischer@googlemail.com>--- Stability:   Provisional--- Portability: Non-portable (GHC extensions) -- -- Some utilities, mostly for bit twiddling. --@@ -25,17 +23,23 @@     , mergeBy      , recipMod++    , toWheel30+    , fromWheel30     ) where  #include "MachDeps.h" +import Prelude hiding (mod, quotRem)+import qualified Prelude as P+ import GHC.Base -import GHC.Integer import GHC.Integer.GMP.Internals import GHC.Natural  import Data.Bits+import Math.NumberTheory.Euclidean  uncheckedShiftR :: Word -> Int -> Word uncheckedShiftR (W# w#) (I# i#) = W# (uncheckedShiftRL# w# i#)@@ -50,58 +54,56 @@ "shiftToOddCount/Natural"   shiftToOddCount = shiftOCNatural   #-} {-# INLINE [1] shiftToOddCount #-}-shiftToOddCount :: Integral a => a -> (Int, a)+shiftToOddCount :: Integral a => a -> (Word, a) shiftToOddCount n = case shiftOCInteger (fromIntegral n) of                       (z, o) -> (z, fromInteger o)  -- | Specialised version for @'Word'@. --   Precondition: argument strictly positive (not checked).-shiftOCWord :: Word -> (Int, Word)+shiftOCWord :: Word -> (Word, Word) shiftOCWord (W# w#) = case shiftToOddCount# w# of-                        (# z# , u# #) -> (I# z#, W# u#)+                        (# z# , u# #) -> (W# z#, W# u#)  -- | Specialised version for @'Int'@. --   Precondition: argument nonzero (not checked).-shiftOCInt :: Int -> (Int, Int)+shiftOCInt :: Int -> (Word, Int) shiftOCInt (I# i#) = case shiftToOddCount# (int2Word# i#) of-                        (# z#, u# #) -> (I# z#, I# (word2Int# u#))+                        (# z#, u# #) -> (W# z#, I# (word2Int# u#))  -- | Specialised version for @'Integer'@. --   Precondition: argument nonzero (not checked).-shiftOCInteger :: Integer -> (Int, Integer)+shiftOCInteger :: Integer -> (Word, Integer) shiftOCInteger n@(S# i#) =     case shiftToOddCount# (int2Word# i#) of-      (# z#, w# #)-        | isTrue# (z# ==# 0#) -> (0, n)-        | otherwise -> (I# z#, S# (word2Int# w#))+      (# 0##, _ #) -> (0, n)+      (# z#, w# #) -> (W# z#, wordToInteger w#) shiftOCInteger n@(Jp# bn#) = case bigNatZeroCount bn# of-                                 0#  -> (0, n)-                                 z#  -> (I# z#, n `shiftRInteger` z#)+                                 0## -> (0, n)+                                 z#  -> (W# z#, bigNatToInteger (bn# `shiftRBigNat` (word2Int# z#))) shiftOCInteger n@(Jn# bn#) = case bigNatZeroCount bn# of-                                 0#  -> (0, n)-                                 z#  -> (I# z#, n `shiftRInteger` z#)+                                 0## -> (0, n)+                                 z#  -> (W# z#, bigNatToNegInteger (bn# `shiftRBigNat` (word2Int# z#)))  -- | Specialised version for @'Natural'@. --   Precondition: argument nonzero (not checked).-shiftOCNatural :: Natural -> (Int, Natural)+shiftOCNatural :: Natural -> (Word, Natural) shiftOCNatural n@(NatS# i#) =     case shiftToOddCount# i# of-      (# z#, w# #)-        | isTrue# (z# ==# 0#) -> (0, n)-        | otherwise -> (I# z#, NatS# w#)+      (# 0##, _ #) -> (0, n)+      (# z#, w# #) -> (W# z#, NatS# w#) shiftOCNatural n@(NatJ# bn#) = case bigNatZeroCount bn# of-                                 0#  -> (0, n)-                                 z#  -> (I# z#, NatJ# (bn# `shiftRBigNat` z#))+                                 0## -> (0, n)+                                 z#  -> (W# z#, bigNatToNatural (bn# `shiftRBigNat` (word2Int# z#)))  -- | Count trailing zeros in a @'BigNat'@. --   Precondition: argument nonzero (not checked, Integer invariant).-bigNatZeroCount :: BigNat -> Int#-bigNatZeroCount bn# = count 0# 0#+bigNatZeroCount :: BigNat -> Word#+bigNatZeroCount bn# = count 0## 0#   where     count a# i# =           case indexBigNat# bn# i# of-            0## -> count (a# +# WORD_SIZE_IN_BITS#) (i# +# 1#)-            w#  -> a# +# word2Int# (ctz# w#)+            0## -> count (a# `plusWord#` WORD_SIZE_IN_BITS##) (i# +# 1#)+            w#  -> a# `plusWord#` ctz# w#  -- | Remove factors of @2@. If @n = 2^k*m@ with @m@ odd, the result is @m@. --   Precondition: argument not @0@ (not checked).@@ -127,13 +129,13 @@ -- | Specialised version for @'Int'@. --   Precondition: argument nonzero (not checked). shiftOInteger :: Integer -> Integer-shiftOInteger (S# i#) = S# (word2Int# (shiftToOdd# (int2Word# i#)))-shiftOInteger n@(Jn# bn#) = case bigNatZeroCount bn# of-                                 0#  -> n-                                 z#  -> n `shiftRInteger` z#+shiftOInteger (S# i#) = wordToInteger (shiftToOdd# (int2Word# i#)) shiftOInteger n@(Jp# bn#) = case bigNatZeroCount bn# of-                                 0#  -> n-                                 z#  -> n `shiftRInteger` z#+                                 0## -> n+                                 z#  -> bigNatToInteger (bn# `shiftRBigNat` (word2Int# z#))+shiftOInteger n@(Jn# bn#) = case bigNatZeroCount bn# of+                                 0## -> n+                                 z#  -> bigNatToNegInteger (bn# `shiftRBigNat` (word2Int# z#))  -- | Shift argument right until the result is odd. --   Precondition: argument not @0@, not checked.@@ -141,9 +143,9 @@ 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 word2Int# (ctz# w#) of-                        k# -> (# k#, uncheckedShiftRL# w# k# #)+shiftToOddCount# :: Word# -> (# Word#, Word# #)+shiftToOddCount# w# = case ctz# w# of+                        k# -> (# k#, uncheckedShiftRL# w# (word2Int# k#) #)  -- | Number of 1-bits in a @'Word#'@. bitCountWord# :: Word# -> Int#@@ -158,7 +160,7 @@ bitCountInt :: Int -> Int bitCountInt = popCount -splitOff :: Integral a => a -> a -> (Int, a)+splitOff :: Euclidean a => a -> a -> (Word, a) splitOff _ 0 = (0, 0) -- prevent infinite loop splitOff p n = go 0 n   where@@ -169,12 +171,12 @@  -- | It is difficult to convince GHC to unbox output of 'splitOff' and 'splitOff.go', -- so we fallback to a specialized unboxed version to minimize allocations.-splitOff# :: Word# -> Word# -> (# Int#, Word# #)-splitOff# _ 0## = (# 0#, 0## #)-splitOff# p n = go 0# n+splitOff# :: Word# -> Word# -> (# Word#, Word# #)+splitOff# _ 0## = (# 0##, 0## #)+splitOff# p n = go 0## n   where     go k m = case m `quotRemWord#` p of-      (# q, 0## #) -> go (k +# 1#) q+      (# q, 0## #) -> go (k `plusWord#` 1##) q       _            -> (# k, m #) {-# INLINABLE splitOff# #-} @@ -195,3 +197,21 @@ recipMod x m = case recipModInteger (x `mod` m) m of   0 -> Nothing   y -> Just y++bigNatToNatural :: BigNat -> Natural+bigNatToNatural bn+  | isTrue# (sizeofBigNat# bn ==# 1#) = NatS# (bigNatToWord bn)+  | otherwise = NatJ# bn++-------------------------------------------------------------------------------+-- Helpers for mapping to rough numbers and back.+-- Copypasted from Data.BitStream.WheelMapping++toWheel30 :: (Integral a, Bits a) => a -> a+toWheel30 i = q `shiftL` 3 + (r + r `shiftR` 4) `shiftR` 2+  where+    (q, r) = i `P.quotRem` 30++fromWheel30 :: (Num a, Bits a) => a -> a+fromWheel30 i = ((i `shiftL` 2 - i `shiftR` 2) .|. 1)+              + ((i `shiftL` 1 - i `shiftR` 1) .&. 2)
+ Math/NumberTheory/Utils/DirichletSeries.hs view
@@ -0,0 +1,86 @@+-- |+-- Module:      Math.NumberTheory.Utils.DirichletSeries+-- Copyright:   (c) 2018 Andrew Lelechenko+-- Licence:     MIT+-- Maintainer:  Andrew Lelechenko <andrew.lelechenko@gmail.com>+--+-- An abstract representation of a Dirichlet series over a semiring.+--++{-# LANGUAGE ScopedTypeVariables   #-}+{-# LANGUAGE TypeApplications      #-}+{-# LANGUAGE ViewPatterns          #-}++module Math.NumberTheory.Utils.DirichletSeries+  ( DirichletSeries+  , fromDistinctAscList+  , lookup+  , filter+  , partition+  , unions+  , union+  , size+  , timesAndCrop+  ) where++import Prelude hiding (filter, last, rem, quot, snd, lookup)+import Data.Coerce+import Data.Map (Map)+import qualified Data.Map.Strict as M+import Data.Semiring (Semiring(..))+import Numeric.Natural++import Math.NumberTheory.Euclidean++-- Sparse Dirichlet series are represented by an ascending list of pairs.+-- For instance, [(a, b), (c, d)] stands for 1 + b/a^s + d/c^s.+-- Note that the representation still may include a term (1, b), so+-- [(1, b), (c, d)] means (1 + b) + d/c^s.+newtype DirichletSeries a b = DirichletSeries { _unDirichletSeries :: Map a b }+  deriving (Show)++fromDistinctAscList :: forall a b. [(a, b)] -> DirichletSeries a b+fromDistinctAscList = coerce (M.fromDistinctAscList @a @b)++lookup :: (Ord a, Num a, Semiring b) => a -> DirichletSeries a b -> b+lookup 1 (DirichletSeries m) = M.findWithDefault zero 1 m `plus` one+lookup a (DirichletSeries m) = M.findWithDefault zero a m++filter :: forall a b. (a -> Bool) -> DirichletSeries a b -> DirichletSeries a b+filter predicate = coerce (M.filterWithKey @a @b (\k _ -> predicate k))++partition :: forall a b. (a -> Bool) -> DirichletSeries a b -> (DirichletSeries a b, DirichletSeries a b)+partition predicate = coerce (M.partitionWithKey @a @b (\k _ -> predicate k))++unions :: forall a b. (Ord a, Semiring b) => [DirichletSeries a b] -> DirichletSeries a b+unions = coerce (M.unionsWith plus :: [Map a b] -> Map a b)++union :: forall a b. (Ord a, Semiring b) => DirichletSeries a b -> DirichletSeries a b -> DirichletSeries a b+union = coerce (M.unionWith @a @b plus)++size :: forall a b. DirichletSeries a b -> Int+size = coerce (M.size @a @b)++-- | Let as = sum_i k_i/a_i^s and bs = sum_i l_i/b_i^s be Dirichlet series,+-- and all a_i and b_i are divisors of n. Return Dirichlet series cs,+-- which contains all terms as * bs = sum_i m_i/c_i^s such that c_i divides n.+timesAndCrop+  :: (Euclidean a, Ord a, Semiring b)+  => a+  -> DirichletSeries a b+  -> DirichletSeries a b+  -> DirichletSeries a b+timesAndCrop n (DirichletSeries as) (DirichletSeries bs)+  = DirichletSeries+  $ M.unionWith plus (M.unionWith plus as bs)+  $ M.fromListWith plus+  [ (a * b, fa `times` fb)+  | (b, fb) <- M.assocs bs+  , let nb = n `quot` b+  , (a, fa) <- takeWhile ((<= nb) . fst) (M.assocs as)+  , nb `rem` a == 0+  ]+{-# SPECIALISE timesAndCrop :: Semiring b => Int -> DirichletSeries Int b -> DirichletSeries Int b -> DirichletSeries Int b #-}+{-# SPECIALISE timesAndCrop :: Semiring b => Word -> DirichletSeries Word b -> DirichletSeries Word b -> DirichletSeries Word b #-}+{-# SPECIALISE timesAndCrop :: Semiring b => Integer -> DirichletSeries Integer b -> DirichletSeries Integer b -> DirichletSeries Integer b #-}+{-# SPECIALISE timesAndCrop :: Semiring b => Natural -> DirichletSeries Natural b -> DirichletSeries Natural b -> DirichletSeries Natural b #-}
Math/NumberTheory/Utils/FromIntegral.hs view
@@ -3,8 +3,6 @@ -- Copyright:   (c) 2017 Andrew Lelechenko -- Licence:     MIT -- Maintainer:  Andrew Lelechenko <andrew.lelechenko@gmail.com>--- Stability:   Provisional--- Portability: Non-portable (GHC extensions) -- -- Monomorphic `fromIntegral`. --@@ -19,6 +17,7 @@   , naturalToInteger   , integerToNatural   , integerToWord+  , integerToInt   ) where  import Numeric.Natural@@ -50,3 +49,7 @@ integerToWord :: Integer -> Word integerToWord = fromIntegral {-# INLINE integerToWord #-}++integerToInt :: Integer -> Int+integerToInt = fromIntegral+{-# INLINE integerToInt #-}
Math/NumberTheory/Utils/Hyperbola.hs view
@@ -3,8 +3,6 @@ -- Copyright:   (c) 2018 Andrew Lelechenko -- Licence:     MIT -- Maintainer:  Andrew Lelechenko <andrew.lelechenko@gmail.com>--- Stability:   Provisional--- Portability: Non-portable (GHC extensions) -- -- Highest points under hyperbola. --
Math/NumberTheory/Zeta.hs view
@@ -3,8 +3,6 @@ -- Copyright:   (c) 2018 Andrew Lelechenko -- Licence:     MIT -- Maintainer:  Andrew Lelechenko <andrew.lelechenko@gmail.com>--- Stability:   Provisional--- Portability: Non-portable (GHC extensions) -- -- Interface to work with Riemann zeta-function and Dirichlet beta-function. @@ -12,10 +10,12 @@  module Math.NumberTheory.Zeta   ( module Math.NumberTheory.Zeta.Dirichlet+  , module Math.NumberTheory.Zeta.Hurwitz   , module Math.NumberTheory.Zeta.Riemann   , module Math.NumberTheory.Zeta.Utils   ) where  import Math.NumberTheory.Zeta.Dirichlet+import Math.NumberTheory.Zeta.Hurwitz import Math.NumberTheory.Zeta.Riemann import Math.NumberTheory.Zeta.Utils
Math/NumberTheory/Zeta/Dirichlet.hs view
@@ -3,8 +3,6 @@ -- 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. @@ -16,25 +14,21 @@   , betasOdd   ) where -import Data.ExactPi                     (ExactPi (..), approximateValue)-import Data.List                        (zipWith4)-import Data.Ratio                       ((%))+import Data.ExactPi+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)+import Math.NumberTheory.Recurrences  (euler, factorial)+import Math.NumberTheory.Zeta.Hurwitz (zetaHurwitz)+import Math.NumberTheory.Zeta.Utils   (intertwine, skipOdds)  -- | 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---+-- >>> approximateValue (betasOdd !! 25) :: Double+-- 0.9999999999999987+-- >>> import Data.Number.Fixed+-- >>> approximateValue (betasOdd !! 25) :: Fixed Prec50+-- 0.99999999999999999999999960726927497384196726751694 betasOdd :: [ExactPi] betasOdd = zipWith Exact [1, 3 ..] $ zipWith4                                      (\sgn denom eul twos -> sgn * (eul % (twos * denom)))@@ -43,127 +37,34 @@                                      (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+betasEven eps = (1 / 2) : hurwitz   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+    hurwitz :: [a]+    hurwitz =+        zipWith3 (\quarter threeQuarters four ->+            (quarter - threeQuarters) / four)+        (tail . skipOdds $ zetaHurwitz eps 0.25)+        (tail . skipOdds $ zetaHurwitz eps 0.75)+        (iterate (16 *) 16)  -- | 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]+-- The algorithm previously 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), but is now based on the+-- 'Math.NumberTheory.Zeta.Hurwitz.zetaHurwitz' recurrence.+--+-- >>> take 5 (betas 1e-14) :: [Double]+-- [0.5,0.7853981633974483,0.9159655941772189,0.9689461462593694,0.9889445517411051] betas :: (Floating a, Ord a) => a -> [a] betas eps = e : o : scanl1 f (intertwine es os)   where     e : es = betasEven eps-    o : os = betasOdd'+    o : os = map (getRationalLimit (\a b -> abs (a - b) < eps) . rationalApproximations) betasOdd      -- Cap-and-floor to improve numerical stability:     -- 1 > beta(n + 1) - 1 > (beta(n) - 1) / 2
+ Math/NumberTheory/Zeta/Hurwitz.hs view
@@ -0,0 +1,125 @@+-- |+-- Module:      Math.NumberTheory.Zeta.Hurwitz+-- Copyright:   (c) 2018 Alexandre Rodrigues Baldé+-- Licence:     MIT+-- Maintainer:  Alexandre Rodrigues Baldé <alexandrer_b@outlook.com>+--+-- Hurwitz zeta function.++{-# LANGUAGE ScopedTypeVariables #-}++module Math.NumberTheory.Zeta.Hurwitz+  ( zetaHurwitz+  ) where++import Math.NumberTheory.Recurrences (bernoulli, factorial)+import Math.NumberTheory.Zeta.Utils  (skipEvens, skipOdds)++-- | Values of Hurwitz zeta function evaluated at @ζ(s, a)@ with+-- @forall t1 . (Floating t1, Ord t1) => a ∈ t1@, and @s ∈ [0, 1 ..]@.+--+-- The algorithm used was based on the Euler-Maclaurin formula and was derived+-- from <http://fredrikj.net/thesis/thesis.pdf Fast and Rigorous Computation of Special Functions to High Precision>+-- by F. Johansson, chapter 4.8, formula 4.8.5.+--+-- The error for each value in this recurrence is given in formula 4.8.9 as an+--  indefinite integral, and in formula 4.8.12 as a closed form formula.+--+-- It is the __user's responsibility__ to provide an appropriate precision for+-- the type chosen.+--+-- For instance, when using @Double@s, it does not make sense+-- to provide a number @ε >= 1e-53@ as the desired precision. For @Float@s,+-- providing an @ε >= 1e-24@ also does not make sense.+-- Example of how to call the function:+--+-- >>> zetaHurwitz 1e-15 0.25 !! 5+-- 1024.3489745265808+zetaHurwitz :: forall a . (Floating a, Ord a) => a -> a -> [a]+zetaHurwitz eps a = zipWith3 (\s i t -> s + i + t) ss is ts+  where+    -- When given @1e-14@ as the @eps@ argument, this'll be+    -- @div (33 * (length . takeWhile (>= 1) . iterate (/ 10) . recip) 1e-14) 10 == div (33 * 14) 10@+    -- @div (33 * 14) 10 == 46.+    -- meaning @N,M@ in formula 4.8.5 will be @46@.+    -- Multiplying by 33 and dividing by 10 is because asking for @14@ digits+    -- of decimal precision equals asking for @(log 10 / log 2) * 14 ~ 3.3 * 14 ~ 46@+    -- bits of precision.+    digitsOfPrecision :: Integer+    digitsOfPrecision =+       let magnitude = toInteger . length . takeWhile (>= 1) . iterate (/ 10) . recip $ eps+       in  div (magnitude * 33) 10++    -- @a + n@+    aPlusN :: a+    aPlusN = a + fromIntegral digitsOfPrecision++    -- @[(a + n)^s | s <- [0, 1, 2 ..]]@+    powsOfAPlusN :: [a]+    powsOfAPlusN = iterate (aPlusN *) 1++    -- [                   [      1      ] |                   ]+    -- | \sum_{k=0}^\(n-1) | ----------- | | s <- [0, 1, 2 ..] |+    -- [                   [ (a + k) ^ s ] |                   ]+    -- @S@ value in 4.8.5 formula.+    ss :: [a]+    ss = let numbers = map ((a +) . fromInteger) [0..digitsOfPrecision-1]+             denoms  = replicate (fromInteger digitsOfPrecision) 1 :+                       iterate (zipWith (*) numbers) numbers+         in map (sum . map recip) denoms++    -- [ (a + n) ^ (1 - s)            a + n         |                   ]+    -- | ----------------- = ---------------------- | s <- [0, 1, 2 ..] |+    -- [       s - 1          (a + n) ^ s * (s - 1) |                   ]+    -- @I@ value in 4.8.5 formula.+    is :: [a]+    is = let denoms = zipWith+                      (\powOfA int -> powOfA * fromInteger int)+                      powsOfAPlusN+                      [-1, 0..]+         in zipWith (/) (repeat aPlusN) denoms++    -- [      1      |             ]+    -- [ ----------- | s <- [0 ..] ]+    -- [ (a + n) ^ s |             ]+    constants2 :: [a]+    constants2 = map recip powsOfAPlusN++    -- [ [(s)_(2*k - 1) | k <- [1 ..]], s <- [0 ..]], i.e. odd indices of+    -- infinite rising factorial sequences, each sequence starting at a+    -- positive integer.+    pochhammers :: [[Integer]]+    pochhammers = let -- [ [(s)_k | k <- [1 ..]], s <- [1 ..]]+                      pochhs :: [[Integer]]+                      pochhs = iterate (\(x : xs) -> map (`div` x) xs) (tail factorial)+                  in -- When @s@ is @0@, the infinite sequence of rising+                     -- factorials starting at @s@ is @[0,0,0,0..]@.+                     repeat 0 : map skipOdds pochhs++    -- [            B_2k           |             ]+    -- | ------------------------- | k <- [1 ..] |+    -- [ (2k)! (a + n) ^ (2*k - 1) |             ]+    second :: [a]+    second =+        take (fromInteger digitsOfPrecision) $+        zipWith3+        (\bern evenFac denom -> fromRational bern / (denom * fromInteger evenFac))+        (tail $ skipOdds bernoulli)+        (tail $ skipOdds factorial)+        -- Recall that @powsOfAPlusN = [(a + n) ^ s | s <- [0 ..]]@, so this+        -- is @[(a + n) ^ (2 * s - 1) | s <- [1 ..]]@+        (skipEvens powsOfAPlusN)++    fracs :: [a]+    fracs = zipWith+            (\sec pochh -> sum $ zipWith (\s p -> s * fromInteger p) sec pochh)+            (repeat second)+            pochhammers++    -- Infinite list of @T@ values in 4.8.5 formula, for every @s@ in+    -- @[0, 1, 2 ..]@.+    ts :: [a]+    ts = zipWith+         (\constant2 frac -> constant2 * (0.5 + frac))+         constants2+         fracs
Math/NumberTheory/Zeta/Riemann.hs view
@@ -3,8 +3,6 @@ -- Copyright:   (c) 2016 Andrew Lelechenko -- Licence:     MIT -- Maintainer:  Andrew Lelechenko <andrew.lelechenko@gmail.com>--- Stability:   Provisional--- Portability: Non-portable (GHC extensions) -- -- Riemann zeta-function. @@ -16,11 +14,12 @@   , zetasOdd   ) where -import Data.ExactPi                     (ExactPi (..), approximateValue)-import Data.Ratio                       ((%))+import Data.ExactPi+import Data.Ratio                     ((%)) -import Math.NumberTheory.Recurrencies   (bernoulli, factorial)-import Math.NumberTheory.Zeta.Utils     (intertwine, skipOdds, suminf)+import Math.NumberTheory.Recurrences  (bernoulli)+import Math.NumberTheory.Zeta.Hurwitz (zetaHurwitz)+import Math.NumberTheory.Zeta.Utils   (intertwine, skipEvens, skipOdds)  -- | 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:@@ -39,66 +38,29 @@   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-+-- | Infinite sequence of approximate values of Riemann zeta-function+-- at odd arguments, starting with @ζ(1)@. 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+zetasOdd eps = (1 / 0) : tail (skipEvens $ zetaHurwitz eps 1)  -- | 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+--+-- Computations for odd arguments were formerly 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).+-- by J. M. Borwein, D. M. Bradley, R. E. Crandall, formula (57), but now use+-- the 'Math.NumberTheory.Zeta.Hurwitz.zetaHurwitz' recurrence. -- -- >>> take 5 (zetas 1e-14) :: [Double]--- > [-0.5,Infinity,1.6449340668482262,1.2020569031595942,1.0823232337111381]+-- [-0.5,Infinity,1.6449340668482264,1.2020569031595942,1.0823232337111381] ----- Beware to force evaluation of @zetas !! 1@, if the type @a@ does not support infinite values+-- 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'+    e : es = map (getRationalLimit (\a b -> abs (a - b) < eps) . rationalApproximations) zetasEven     o : os = zetasOdd eps      -- Cap-and-floor to improve numerical stability:
Math/NumberTheory/Zeta/Utils.hs view
@@ -3,8 +3,6 @@ -- 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@. @@ -12,23 +10,22 @@   ( 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]+-- [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 +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]+-- [0,2,4,6,8,10,12,14,16,18] skipOdds :: [a] -> [a] skipOdds (x : _ : xs) = x : skipOdds xs skipOdds xs = xs@@ -37,15 +34,6 @@ -- Do NOT use with finite lists. -- -- >>> take 10 (skipEvens [0, 1 ..])--- [1, 3, 5, 7, 9, 11, 13, 15, 17, 19]+-- [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)
+ app/SequenceModel.hs view
@@ -0,0 +1,83 @@+-- Model fitting to derive coefficients in+-- Math.NumberTheory.Primes.Sequence.chooseAlgorithm++module Main where++import Numeric.GSL.Fitting++-- | Benchmarks Sequence/filterIsPrime+-- ([start, length], ([time in microseconds], weight))+filterIsPrimeBenchData :: [([Double], ([Double], Double))]+filterIsPrimeBenchData =+  [ ([100000, 1000], ([777], 0.1))+  , ([100000, 10000], ([8523], 0.1))+  , ([1000000, 1000], ([813], 0.1))+  , ([1000000, 10000], ([8247], 0.1))+  , ([1000000, 100000], ([78600], 0.1))+  , ([10000000, 1000], ([765], 0.1))+  , ([10000000, 10000], ([7685], 0.1))+  , ([10000000, 100000], ([78900], 0.1))+  , ([10000000, 1000000], ([785000], 0.1))+  , ([100000000, 1000], ([792], 0.1))+  , ([100000000, 10000], ([8094], 0.1))+  , ([100000000, 100000], ([79280], 0.1))+  , ([100000000, 1000000], ([771600], 0.1))+  , ([100000000, 10000000], ([7670000], 0.1))+  ]++filterIsPrimeBenchModel :: [(Double, Double)]+filterIsPrimeBenchModel = sol+  where+    model [d] [from, len] = [len * d]+    modelDer [d] [from, len] = [[len]]+    (sol, _) = fitModelScaled 1E-10 1E-10 20 (model, modelDer) filterIsPrimeBenchData [1]++filterIsPrimeBenchApprox :: ([Double], ([Double], Double)) -> [Double]+filterIsPrimeBenchApprox ([from, len], ([exact], _)) = [from, len, exact, fromInteger (floor (appr / exact * 1000)) / 1000]+  where+    [(d, _)] = filterIsPrimeBenchModel+    appr = len * d++-- | Benchmarks Sequence/eratosthenes+-- ([start, length], ([time in microseconds], weight))+eratosthenesData :: [([Double], ([Double], Double))]+eratosthenesData =+  [ ([10000000000,1000000], ([21490], 0.1))+  , ([10000000000,10000000], ([103200], 0.1))+  , ([10000000000,100000000], ([956800], 0.1))+  , ([10000000000,1000000000], ([9473000], 0.1))+  , ([100000000000,10000000], ([107000], 0.1))+  , ([1000000000000,10000000], ([129900], 0.1))+  , ([10000000000000,10000000], ([202900], 0.1))+  , ([100000000000000,10000000], ([420400], 0.1))+  , ([1000000000000000,10000000], ([1048000], 0.1))+  , ([10000000000000000,10000000], ([2940000], 0.1))+  , ([100000000000000000,10000000], ([8763000], 0.1))+  ]++eratosthenesModel :: [(Double, Double)]+eratosthenesModel = sol+  where+    model [a, b, c] [from, len] = [a * len + b * sqrt from + c]+    modelDer [a, b, c] [from, len] = [[len, sqrt from, 1]]+    (sol, _) = fitModelScaled 1E-10 1E-10 20 (model, modelDer) eratosthenesData [1,0,0]++eratosthenesApprox :: ([Double], ([Double], Double)) -> [Double]+eratosthenesApprox ([from, len], ([exact], _)) = [from, len, exact, fromInteger (floor (appr / exact * 1000)) / 1000]+  where+    [(a, _), (b, _), (c, _)] = eratosthenesModel+    appr = a * len + b * sqrt from + c++coeffs :: (Double, Double)+coeffs = (b / (d - a), c / (d - a))+  where+    [(a, _), (b, _), (c, _)] = eratosthenesModel+    [(d, _)] = filterIsPrimeBenchModel++main :: IO ()+main = do+  print filterIsPrimeBenchModel+  mapM_ (print . filterIsPrimeBenchApprox) filterIsPrimeBenchData+  print eratosthenesModel+  mapM_ (print . eratosthenesApprox) eratosthenesData+  print coeffs
arithmoi.cabal view
@@ -1,5 +1,5 @@ name:          arithmoi-version:       0.8.0.0+version:       0.9.0.0 cabal-version: >=1.10 build-type:    Simple license:       MIT@@ -19,7 +19,7 @@   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+tested-with:   GHC ==8.0.2 GHC ==8.2.2 GHC ==8.4.4 GHC ==8.6.5 GHC ==8.8.1 extra-source-files:   Changes @@ -35,32 +35,29 @@  library   build-depends:-    base >=4.7 && <5,+    base >=4.9 && <5,     array >=0.5 && <0.6,     containers >=0.5 && <0.7,     deepseq,-    exact-pi >=0.4.1.1,+    exact-pi >=0.5,     ghc-prim <0.6,     integer-gmp <1.1,     integer-logarithms >=1.0,     random >=1.0 && <1.2,     transformers >=0.4 && <0.6,+    semirings >= 0.2,     vector >= 0.12-  if impl(ghc <8.0)-    build-depends:-      semigroups >=0.8   exposed-modules:     GHC.TypeNats.Compat     Math.NumberTheory.ArithmeticFunctions+    Math.NumberTheory.ArithmeticFunctions.Inverse     Math.NumberTheory.ArithmeticFunctions.Mertens+    Math.NumberTheory.ArithmeticFunctions.NFreedom     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@@ -88,13 +85,17 @@     Math.NumberTheory.Primes.Testing.Certificates     Math.NumberTheory.Quadratic.GaussianIntegers     Math.NumberTheory.Quadratic.EisensteinIntegers+    Math.NumberTheory.Recurrences     Math.NumberTheory.Recurrencies+    Math.NumberTheory.Recurrences.Bilinear     Math.NumberTheory.Recurrencies.Bilinear+    Math.NumberTheory.Recurrences.Linear     Math.NumberTheory.Recurrencies.Linear     Math.NumberTheory.SmoothNumbers     Math.NumberTheory.UniqueFactorisation     Math.NumberTheory.Zeta     Math.NumberTheory.Zeta.Dirichlet+    Math.NumberTheory.Zeta.Hurwitz     Math.NumberTheory.Zeta.Riemann   other-modules:     Math.NumberTheory.ArithmeticFunctions.Class@@ -111,9 +112,10 @@     Math.NumberTheory.Primes.Testing.Certified     Math.NumberTheory.Primes.Testing.Probabilistic     Math.NumberTheory.Primes.Types-    Math.NumberTheory.Recurrencies.Pentagonal+    Math.NumberTheory.Recurrences.Pentagonal     Math.NumberTheory.Unsafe     Math.NumberTheory.Utils+    Math.NumberTheory.Utils.DirichletSeries     Math.NumberTheory.Utils.FromIntegral     Math.NumberTheory.Utils.Hyperbola     Math.NumberTheory.Zeta.Utils@@ -124,30 +126,29 @@  test-suite spec   build-depends:-    base >=4.6 && <5,+    base >=4.9 && <5,     arithmoi,     containers,     exact-pi >=0.4.1.1,     integer-gmp <1.1,-    QuickCheck >=2.10 && <2.13,+    QuickCheck >=2.10,+    semirings >= 0.2,     smallcheck >=1.1.3 && <1.2,-    tasty >=0.10 && <1.2,+    tasty >=0.10,     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.InverseTests     Math.NumberTheory.ArithmeticFunctions.MertensTests     Math.NumberTheory.ArithmeticFunctions.SieveBlockTests     Math.NumberTheory.CurvesTests     Math.NumberTheory.EisensteinIntegersTests     Math.NumberTheory.GaussianIntegersTests-    Math.NumberTheory.GCDTests+    Math.NumberTheory.EuclideanTests     Math.NumberTheory.Moduli.ChineseTests     Math.NumberTheory.Moduli.DiscreteLogarithmTests     Math.NumberTheory.Moduli.ClassTests@@ -165,12 +166,13 @@     Math.NumberTheory.PrefactoredTests     Math.NumberTheory.Primes.CountingTests     Math.NumberTheory.Primes.FactorisationTests+    Math.NumberTheory.Primes.SequenceTests     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.Recurrences.PentagonalTests+    Math.NumberTheory.Recurrences.BilinearTests+    Math.NumberTheory.Recurrences.LinearTests     Math.NumberTheory.SmoothNumbersTests     Math.NumberTheory.TestUtils     Math.NumberTheory.TestUtils.MyCompose@@ -188,30 +190,42 @@   build-depends:     base,     arithmoi,+    array,     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.EuclideanBench     Math.NumberTheory.GaussianIntegersBench-    Math.NumberTheory.GCDBench+    Math.NumberTheory.InverseBench     Math.NumberTheory.JacobiBench     Math.NumberTheory.MertensBench     Math.NumberTheory.PowersBench     Math.NumberTheory.PrimesBench     Math.NumberTheory.PrimitiveRootsBench-    Math.NumberTheory.RecurrenciesBench+    Math.NumberTheory.RecurrencesBench+    Math.NumberTheory.SequenceBench     Math.NumberTheory.SieveBlockBench     Math.NumberTheory.SmoothNumbersBench+    Math.NumberTheory.ZetaBench   type: exitcode-stdio-1.0   main-is: Bench.hs   default-language: Haskell2010   hs-source-dirs: benchmark++executable sequence-model+  build-depends:+    base,+    arithmoi,+    containers,+    hmatrix-gsl+  buildable: False+  main-is: SequenceModel.hs+  hs-source-dirs: app+  default-language: Haskell2010
benchmark/Bench.hs view
@@ -5,30 +5,36 @@ import Math.NumberTheory.ArithmeticFunctionsBench as ArithmeticFunctions import Math.NumberTheory.DiscreteLogarithmBench as DiscreteLogarithm import Math.NumberTheory.EisensteinIntegersBench as Eisenstein+import Math.NumberTheory.EuclideanBench as Euclidean import Math.NumberTheory.GaussianIntegersBench as Gaussian-import Math.NumberTheory.GCDBench as GCD+import Math.NumberTheory.InverseBench as Inverse 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.RecurrencesBench as Recurrences+import Math.NumberTheory.SequenceBench as Sequence import Math.NumberTheory.SieveBlockBench as SieveBlock import Math.NumberTheory.SmoothNumbersBench as SmoothNumbers+import Math.NumberTheory.ZetaBench as Zeta  main :: IO () main = defaultMain   [ ArithmeticFunctions.benchSuite   , DiscreteLogarithm.benchSuite   , Eisenstein.benchSuite+  , Euclidean.benchSuite   , Gaussian.benchSuite-  , GCD.benchSuite+  , Inverse.benchSuite   , Jacobi.benchSuite   , Mertens.benchSuite   , Powers.benchSuite   , Primes.benchSuite   , PrimitiveRoots.benchSuite-  , Recurrencies.benchSuite+  , Recurrences.benchSuite+  , Sequence.benchSuite   , SieveBlock.benchSuite   , SmoothNumbers.benchSuite+  , Zeta.benchSuite   ]
benchmark/Math/NumberTheory/EisensteinIntegersBench.hs view
@@ -5,16 +5,15 @@   ( benchSuite   ) where -import Control.DeepSeq+import Data.Maybe import Gauge.Main  import Math.NumberTheory.ArithmeticFunctions (tau)+import Math.NumberTheory.Primes (isPrime) import Math.NumberTheory.Quadratic.EisensteinIntegers -instance NFData EisensteinInteger- benchFindPrime :: Integer -> Benchmark-benchFindPrime n = bench (show n) $ nf findPrime n+benchFindPrime n = bench (show n) $ nf findPrime (fromJust (isPrime n))  benchTau :: Integer -> Benchmark benchTau n = bench (show n) $ nf (\m -> sum [tau (x :+ y) | x <- [1..m], y <- [0..m]] :: Word) n
+ benchmark/Math/NumberTheory/EuclideanBench.hs view
@@ -0,0 +1,19 @@+{-# OPTIONS_GHC -fno-warn-type-defaults #-}++module Math.NumberTheory.EuclideanBench+  ( benchSuite+  ) where++import Gauge.Main++import Math.NumberTheory.Euclidean++doBench :: Integral a => (a -> a -> (a, a, a)) -> a -> a+doBench func lim = sum [ let (a, b, c) = func x y in a + b + c | y <- [3, 5 .. lim], x <- [0..y] ]++benchSuite :: Benchmark+benchSuite = bgroup "Euclidean"+  [ bench "extendedGCD/Int"      $ nf (doBench extendedGCD :: Int -> Int)         1000+  , bench "extendedGCD/Word"     $ nf (doBench extendedGCD :: Word -> Word)       1000+  , bench "extendedGCD/Integer"  $ nf (doBench extendedGCD :: Integer -> Integer) 1000+  ]
− benchmark/Math/NumberTheory/GCDBench.hs
@@ -1,37 +0,0 @@-{-# OPTIONS_GHC -fno-warn-type-defaults #-}-{-# OPTIONS_GHC -fno-warn-deprecations  #-}--module Math.NumberTheory.GCDBench-  ( benchSuite-  ) where--import Gauge.Main--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 (\t -> 1 == P.gcd m t) n-          , bench "coprime" $ nf (A.coprime m) n-          ]
benchmark/Math/NumberTheory/GaussianIntegersBench.hs view
@@ -4,13 +4,15 @@   ( benchSuite   ) where +import Data.Maybe import Gauge.Main  import Math.NumberTheory.ArithmeticFunctions (tau)+import Math.NumberTheory.Primes (isPrime) import Math.NumberTheory.Quadratic.GaussianIntegers  benchFindPrime :: Integer -> Benchmark-benchFindPrime n = bench (show n) $ nf findPrime n+benchFindPrime n = bench (show n) $ nf findPrime (fromJust (isPrime n))  benchTau :: Integer -> Benchmark benchTau n = bench (show n) $ nf (\m -> sum [tau (x :+ y) | x <- [1..m], y <- [0..m]] :: Word) n
+ benchmark/Math/NumberTheory/InverseBench.hs view
@@ -0,0 +1,58 @@+{-# LANGUAGE TypeApplications      #-}++{-# OPTIONS_GHC -fno-warn-type-defaults #-}++module Math.NumberTheory.InverseBench+  ( benchSuite+  ) where++import Gauge.Main+import Numeric.Natural++import Math.NumberTheory.ArithmeticFunctions.Inverse+import Math.NumberTheory.Euclidean+import Math.NumberTheory.Primes++fact :: (Enum a, Num a) => a+fact = product [1..13]++tens :: Num a => a+tens = 10 ^ 18++countInverseTotient :: (Ord a, Euclidean a, UniqueFactorisation a) => a -> Word+countInverseTotient = inverseTotient (const 1)++countInverseSigma :: (Integral a, Euclidean a, UniqueFactorisation a) => a -> Word+countInverseSigma = inverseSigma (const 1)++benchSuite :: Benchmark+benchSuite = bgroup "Inverse"+  [ bgroup "Totient"+    [ bgroup "factorial"+      [ bench "Int"     $ nf (countInverseTotient @Int)     fact+      , bench "Word"    $ nf (countInverseTotient @Word)    fact+      , bench "Integer" $ nf (countInverseTotient @Integer) fact+      , bench "Natural" $ nf (countInverseTotient @Natural) fact+      ]+    , bgroup "power of 10"+      [ bench "Int"     $ nf (countInverseTotient @Int)     tens+      , bench "Word"    $ nf (countInverseTotient @Word)    tens+      , bench "Integer" $ nf (countInverseTotient @Integer) tens+      , bench "Natural" $ nf (countInverseTotient @Natural) tens+      ]+    ]+  , bgroup "Sigma1"+    [ bgroup "factorial"+      [ bench "Int"     $ nf (countInverseSigma @Int)     fact+      , bench "Word"    $ nf (countInverseSigma @Word)    fact+      , bench "Integer" $ nf (countInverseSigma @Integer) fact+      , bench "Natural" $ nf (countInverseSigma @Natural) fact+      ]+    , bgroup "power of 10"+      [ bench "Int"     $ nf (countInverseSigma @Int)     tens+      , bench "Word"    $ nf (countInverseSigma @Word)    tens+      , bench "Integer" $ nf (countInverseSigma @Integer) tens+      , bench "Natural" $ nf (countInverseSigma @Natural) tens+      ]+    ]+  ]
benchmark/Math/NumberTheory/PrimesBench.hs view
@@ -8,7 +8,8 @@ import System.Random  import Math.NumberTheory.Logarithms (integerLog2)-import Math.NumberTheory.Primes+import Math.NumberTheory.Primes.Factorisation+import Math.NumberTheory.Primes.Testing  genInteger :: Int -> Int -> Integer genInteger salt bits
benchmark/Math/NumberTheory/PrimitiveRootsBench.hs view
@@ -8,7 +8,7 @@ import Data.Maybe  import Math.NumberTheory.Moduli.PrimitiveRoot-import Math.NumberTheory.UniqueFactorisation+import Math.NumberTheory.Primes  primRootWrap :: Integer -> Word -> Integer -> Bool primRootWrap p k g = isPrimitiveRoot' (CGOddPrimePower p' k) g
+ benchmark/Math/NumberTheory/RecurrencesBench.hs view
@@ -0,0 +1,48 @@+{-# LANGUAGE RankNTypes #-}++module Math.NumberTheory.RecurrencesBench+  ( benchSuite+  ) where++import Gauge.Main++import Math.NumberTheory.Recurrences (binomial, eulerian1, eulerian2,+                                      stirling1, stirling2, partition)++benchTriangle :: String -> (forall a. (Integral a) => [[a]]) -> Int -> Benchmark+benchTriangle name triangle n = bgroup name+  [ benchAt (10 * n)  (1 * n)+  , benchAt (10 * n)  (2 * n)+  , benchAt (10 * n)  (5 * n)+  , benchAt (10 * n)  (9 * n)+  ]+  where+    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 "Recurrences"+  [+    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/RecurrenciesBench.hs
@@ -1,48 +0,0 @@-{-# LANGUAGE RankNTypes #-}--module Math.NumberTheory.RecurrenciesBench-  ( benchSuite-  ) where--import Gauge.Main--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-  [ benchAt (10 * n)  (1 * n)-  , benchAt (10 * n)  (2 * n)-  , benchAt (10 * n)  (5 * n)-  , benchAt (10 * n)  (9 * n)-  ]-  where-    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 "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/SequenceBench.hs view
@@ -0,0 +1,71 @@+{-# OPTIONS_GHC -fno-warn-type-defaults #-}++module Math.NumberTheory.SequenceBench+  ( benchSuite+  ) where++import Gauge.Main++import Data.Array.IArray ((!))+import Data.Array.Unboxed+import Data.Bits++import Math.NumberTheory.Primes (Prime(..))+import Math.NumberTheory.Primes.Sieve as P+import Math.NumberTheory.Primes.Testing as P++filterIsPrime :: (Integer, Integer) -> Integer+filterIsPrime (p, q) = sum $ takeWhile (<= q) $ dropWhile (< p) $ filter isPrime (map toPrim [toIdx p .. toIdx q])++eratosthenes :: (Integer, Integer) -> Integer+eratosthenes (p, q) = sum $ takeWhile (<= q) $ dropWhile (< p) $ map unPrime $ if q < toInteger sieveRange+        then           primeList $ primeSieve q+        else concatMap primeList $ psieveFrom p++filterIsPrimeBench :: Benchmark+filterIsPrimeBench = bgroup "filterIsPrime" $+  map (\(x, y) -> bench (show (x, y)) $ nf filterIsPrime (x, x + y))+  [ (10 ^ x, 10 ^ y)+  | x <- [5..8]+  , y <- [3..x-1]+  ]++eratosthenesBench :: Benchmark+eratosthenesBench = bgroup "eratosthenes" $+  map (\(x, y) -> bench (show (x, y)) $ nf eratosthenes (x, x + y))+  [ (10 ^ x, 10 ^ y)+  | x <- [10..17]+  , y <- [6..x-1]+  , x == 10 || y == 7+  ]++benchSuite :: Benchmark+benchSuite = bgroup "Sequence"+    [ filterIsPrimeBench+    , eratosthenesBench+    ]++-------------------------------------------------------------------------------+-- Utils copypasted from internal modules++sieveRange :: Int+sieveRange = 30*128*1024++rho :: Int -> Int+rho i = residues ! i++residues :: UArray Int Int+residues = listArray (0,7) [7,11,13,17,19,23,29,31]++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)++toPrim :: Integral a => Int -> a+toPrim ix = 30*fromIntegral k + fromIntegral (rho i)+  where+    i = ix .&. 7+    k = ix `shiftR` 3
benchmark/Math/NumberTheory/SieveBlockBench.hs view
@@ -17,6 +17,7 @@  import Math.NumberTheory.ArithmeticFunctions.Moebius import Math.NumberTheory.ArithmeticFunctions.SieveBlock+import Math.NumberTheory.Primes  blockLen :: Word blockLen = 1000000@@ -30,7 +31,7 @@ totientBlockConfig = SieveBlockConfig   { sbcEmpty                = 1   , sbcAppend               = (*)-  , sbcFunctionOnPrimePower = totientHelper+  , sbcFunctionOnPrimePower = totientHelper . unPrime   }  carmichaelHelper :: Word -> Word -> Word@@ -46,7 +47,7 @@   { sbcEmpty                = 1   -- There is a specialized 'gcd' for Word, but not 'lcm'.   , sbcAppend               = (\x y -> (x `quot` (gcd x y)) * y)-  , sbcFunctionOnPrimePower = carmichaelHelper+  , sbcFunctionOnPrimePower = carmichaelHelper . unPrime   }  moebiusConfig :: SieveBlockConfig Moebius
benchmark/Math/NumberTheory/SmoothNumbersBench.hs view
@@ -8,9 +8,10 @@ import Data.Maybe import Gauge.Main +import Math.NumberTheory.Euclidean (Euclidean) import Math.NumberTheory.SmoothNumbers -doBench :: Integral a => a -> a+doBench :: (Euclidean a, Integral a) => a -> a doBench lim = sum $ genericTake lim $ smoothOver $ fromJust $ fromSmoothUpperBound lim  benchSuite :: Benchmark
+ benchmark/Math/NumberTheory/ZetaBench.hs view
@@ -0,0 +1,15 @@+{-# OPTIONS_GHC -fno-warn-type-defaults #-}++module Math.NumberTheory.ZetaBench+  ( benchSuite+  ) where++import Gauge.Main++import Math.NumberTheory.Zeta++benchSuite :: Benchmark+benchSuite = bgroup "Zeta"+  [ bench "riemann zeta"   $ nf (\eps -> sum $ take 20 $ zetas eps) (1e-15 :: Double)+  , bench "dirichlet beta" $ nf (\eps -> sum $ take 20 $ betas eps) (1e-15 :: Double)+  ]
+ test-suite/Math/NumberTheory/ArithmeticFunctions/InverseTests.hs view
@@ -0,0 +1,262 @@+-- |+-- Module:      Math.NumberTheory.ArithmeticFunctions.InverseTests+-- Copyright:   (c) 2018 Andrew Lelechenko+-- Licence:     MIT+-- Maintainer:  Andrew Lelechenko <andrew.lelechenko@gmail.com>+-- Stability:   Provisional+--+-- Tests for Math.NumberTheory.ArithmeticFunctions.Inverse+--++{-# LANGUAGE FlexibleContexts      #-}+{-# LANGUAGE ScopedTypeVariables   #-}++{-# OPTIONS_GHC -fno-warn-type-defaults #-}++module Math.NumberTheory.ArithmeticFunctions.InverseTests+  ( testSuite+  ) where++import Test.Tasty+import Test.Tasty.HUnit++import qualified Data.Set as S++import Math.NumberTheory.ArithmeticFunctions+import Math.NumberTheory.ArithmeticFunctions.Inverse+import Math.NumberTheory.Euclidean+import Math.NumberTheory.Primes+import Math.NumberTheory.Recurrences+import Math.NumberTheory.TestUtils++-------------------------------------------------------------------------------+-- Totient++totientProperty1 :: forall a. (Euclidean a, Integral a, UniqueFactorisation a) => Positive a -> Bool+totientProperty1 (Positive x) = x `S.member` asSetOfPreimages inverseTotient (totient x)++totientProperty2 :: (Euclidean a, Integral a, UniqueFactorisation a) => Positive a -> Bool+totientProperty2 (Positive x) = all (== x) (S.map totient (asSetOfPreimages inverseTotient x))++-- | http://oeis.org/A055506+totientCountFactorial :: [Word]+totientCountFactorial =+  [ 2+  , 3+  , 4+  , 10+  , 17+  , 49+  , 93+  , 359+  , 1138+  , 3802+  , 12124+  , 52844+  , 182752+  , 696647+  , 2852886+  , 16423633+  , 75301815+  , 367900714+  ]++totientSpecialCases1 :: [Assertion]+totientSpecialCases1 = zipWith mkAssert (tail factorial) totientCountFactorial+  where+    mkAssert n m = assertEqual "should be equal" m (totientCount n)++    totientCount :: Word -> Word+    totientCount = inverseTotient (const 1)++-- | http://oeis.org/A055487+totientMinFactorial :: [Word]+totientMinFactorial =+  [ 1+  , 3+  , 7+  , 35+  , 143+  , 779+  , 5183+  , 40723+  , 364087+  , 3632617+  , 39916801+  , 479045521+  , 6227180929+  , 87178882081+  , 1307676655073+  , 20922799053799+  , 355687465815361+  , 6402373865831809+  ]++totientSpecialCases2 :: [Assertion]+totientSpecialCases2 = zipWith mkAssert (tail factorial) totientMinFactorial+  where+    mkAssert n m = assertEqual "should be equal" m (totientMin n)++    totientMin :: Word -> Word+    totientMin = unMinWord . inverseTotient MinWord++-- | http://oeis.org/A165774+totientMaxFactorial :: [Word]+totientMaxFactorial =+  [ 2+  , 6+  , 18+  , 90+  , 462+  , 3150+  , 22050+  , 210210+  , 1891890+  , 19969950+  , 219669450+  , 2847714870+  , 37020293310+  , 520843112790+  , 7959363061650+  , 135309172048050+  , 2300255924816850+  , 41996101027370490+  ]++totientSpecialCases3 :: [Assertion]+totientSpecialCases3 = zipWith mkAssert (tail factorial) totientMaxFactorial+  where+    mkAssert n m = assertEqual "should be equal" m (totientMax n)++    totientMax :: Word -> Word+    totientMax = unMaxWord . inverseTotient MaxWord++-------------------------------------------------------------------------------+-- Sigma++sigmaProperty1 :: forall a. (Euclidean a, UniqueFactorisation a, Integral a) => Positive a -> Bool+sigmaProperty1 (Positive x) = x `S.member` asSetOfPreimages inverseSigma (sigma 1 x)++sigmaProperty2 :: (Euclidean a, UniqueFactorisation a, Integral a) => Positive a -> Bool+sigmaProperty2 (Positive x) = all (== x) (S.map (sigma 1) (asSetOfPreimages inverseSigma x))++-- | http://oeis.org/A055486+sigmaCountFactorial :: [Word]+sigmaCountFactorial =+  [ 1+  , 0+  , 1+  , 3+  , 4+  , 15+  , 33+  , 111+  , 382+  , 1195+  , 3366+  , 14077+  , 53265+  , 229603+  , 910254+  , 4524029+  , 18879944+  , 91336498+  ]++sigmaSpecialCases1 :: [Assertion]+sigmaSpecialCases1 = zipWith mkAssert (tail factorial) sigmaCountFactorial+  where+    mkAssert n m = assertEqual "should be equal" m (sigmaCount n)++    sigmaCount :: Word -> Word+    sigmaCount = inverseSigma (const 1)++-- | http://oeis.org/A055488+sigmaMinFactorial :: [Word]+sigmaMinFactorial =+  [ 5+  , 14+  , 54+  , 264+  , 1560+  , 10920+  , 97440+  , 876960+  , 10263240+  , 112895640+  , 1348827480+  , 18029171160+  , 264370186080+  , 3806158356000+  , 62703141621120+  , 1128159304272000+  ]++sigmaSpecialCases2 :: [Assertion]+sigmaSpecialCases2 = zipWith mkAssert (drop 3 factorial) sigmaMinFactorial+  where+    mkAssert n m = assertEqual "should be equal" m (sigmaMin n)++    sigmaMin :: Word -> Word+    sigmaMin = unMinWord . inverseSigma MinWord++-- | http://oeis.org/A055489+sigmaMaxFactorial :: [Word]+sigmaMaxFactorial =+  [ 5+  , 23+  , 95+  , 719+  , 5039+  , 39917+  , 361657+  , 3624941+  , 39904153+  , 479001599+  , 6226862869+  , 87178291199+  , 1307672080867+  , 20922780738961+  , 355687390376431+  , 6402373545694717+  ]++sigmaSpecialCases3 :: [Assertion]+sigmaSpecialCases3 = zipWith mkAssert (drop 3 factorial) sigmaMaxFactorial+  where+    mkAssert n m = assertEqual "should be equal" m (sigmaMax n)++    sigmaMax :: Word -> Word+    sigmaMax = unMaxWord . inverseSigma MaxWord++sigmaSpecialCase4 :: Assertion+sigmaSpecialCase4 = assertBool "200 should be in inverseSigma(sigma(200))" $+  sigmaProperty1 $ Positive (200 :: Word)++-------------------------------------------------------------------------------+-- TestTree++testSuite :: TestTree+testSuite = testGroup "Inverse"+  [ testGroup "Totient"+    [ testIntegralPropertyNoLarge "forward"  totientProperty1+    , testIntegralPropertyNoLarge "backward" totientProperty2+    , testGroup "count"+      (zipWith (\i a -> testCase ("factorial " ++ show i) a) [1..] totientSpecialCases1)+    , testGroup "min"+      (zipWith (\i a -> testCase ("factorial " ++ show i) a) [1..] totientSpecialCases2)+    , testGroup "max"+      (zipWith (\i a -> testCase ("factorial " ++ show i) a) [1..] totientSpecialCases3)+    ]+  , testGroup "Sigma1"+    [ testIntegralPropertyNoLarge "forward"  sigmaProperty1+    , testIntegralPropertyNoLarge "backward" sigmaProperty2+    , testCase "200" sigmaSpecialCase4+    , testGroup "count"+      (zipWith (\i a -> testCase ("factorial " ++ show i) a) [1..] sigmaSpecialCases1)+    , testGroup "min"+      (zipWith (\i a -> testCase ("factorial " ++ show i) a) [1..] sigmaSpecialCases2)+    , testGroup "max"+      (zipWith (\i a -> testCase ("factorial " ++ show i) a) [1..] sigmaSpecialCases3)+    ]+  ]
test-suite/Math/NumberTheory/ArithmeticFunctions/MertensTests.hs view
@@ -3,7 +3,6 @@ -- Copyright:   (c) 2018 Andrew Lelechenko -- Licence:     MIT -- Maintainer:  Andrew Lelechenko <andrew.lelechenko@gmail.com>--- Stability:   Provisional -- -- Tests for Math.NumberTheory.ArithmeticFunctions.Mertens --
test-suite/Math/NumberTheory/ArithmeticFunctions/SieveBlockTests.hs view
@@ -3,7 +3,6 @@ -- Copyright:   (c) 2016 Andrew Lelechenko -- Licence:     MIT -- Maintainer:  Andrew Lelechenko <andrew.lelechenko@gmail.com>--- Stability:   Provisional -- -- Tests for Math.NumberTheory.ArithmeticFunctions.SieveBlock --@@ -28,6 +27,7 @@  import Math.NumberTheory.ArithmeticFunctions import Math.NumberTheory.ArithmeticFunctions.SieveBlock+import Math.NumberTheory.Primes (unPrime)  pointwiseTest :: (Eq a, Show a) => ArithmeticFunction Word a -> Word -> Word -> IO () pointwiseTest f lowIndex len = assertEqual "pointwise"@@ -72,7 +72,7 @@ multiplicativeConfig f = SieveBlockConfig   { sbcEmpty                = 1   , sbcAppend               = (*)-  , sbcFunctionOnPrimePower = f+  , sbcFunctionOnPrimePower = f . unPrime   }  moebiusConfig :: SieveBlockConfig Moebius@@ -98,7 +98,7 @@     ]   , testGroup "unboxed"     [ testCase "id"      $ unboxedTest $ multiplicativeConfig (^)-    , testCase "tau"     $ unboxedTest $ multiplicativeConfig (const id)+    , testCase "tau"     $ unboxedTest $ multiplicativeConfig (\_ a -> succ a )     , testCase "moebius" $ unboxedTest moebiusConfig     , testCase "totient" $ unboxedTest $ multiplicativeConfig (\p a -> (p - 1) * p ^ (a - 1))     ]
test-suite/Math/NumberTheory/ArithmeticFunctionsTests.hs view
@@ -3,7 +3,6 @@ -- Copyright:   (c) 2016 Andrew Lelechenko -- Licence:     MIT -- Maintainer:  Andrew Lelechenko <andrew.lelechenko@gmail.com>--- Stability:   Provisional -- -- Tests for Math.NumberTheory.ArithmeticFunctions --@@ -25,7 +24,9 @@ import qualified Data.IntSet as IS  import Math.NumberTheory.ArithmeticFunctions+import Math.NumberTheory.Primes (UniqueFactorisation (factorise)) import Math.NumberTheory.TestUtils+import Math.NumberTheory.Zeta (zetas)  import Numeric.Natural @@ -271,6 +272,46 @@   , 73, 1, 1, 1, 1, 1, 79, 1, 3, 1, 83, 1, 1, 1, 1, 1, 89, 1, 1, 1, 1, 1, 1   ] +nFreedomProperty1 :: Word -> NonZero Natural -> Bool+nFreedomProperty1 n (NonZero m) =+    isNFree n m == (all ((< n) . snd) . factorise) m++nFreedomProperty2 :: Power Word -> NonNegative Int -> Bool+nFreedomProperty2 (Power n) (NonNegative m) =+    let n' | n == maxBound = n+           | otherwise     = n + 1+    in take m (filter (isNFree n') [1 ..]) == take m (nFrees n' :: [Integer])++nFreedomProperty3 :: Power Word -> Positive Int -> Bool+nFreedomProperty3 (Power n) (Positive m) =+    let n' | n == maxBound = n+           | otherwise     = n + 1+        zet = 1 / zetas 1e-14 !! (fromIntegral n') :: Double+        m' = 100 * m+        nfree = fromIntegral m' /+                fromIntegral (head (drop (m' - 1) $ nFrees n' :: [Integer]))+    in 1 / fromIntegral m >= abs (zet - nfree)++-- |+-- * Using a bounded integer type like @Int@ instead of @Integer@ here means+-- even a relatively low value of @n@, e.g. 20 may cause out-of-bounds memory+-- accesses in @nFreesBlock@.+-- * Using @Integer@ prevents this, so that is the numeric type used here.+nFreesBlockProperty1 :: Power Word -> Positive Integer -> Word -> Bool+nFreesBlockProperty1 (Power n) (Positive lo) w =+    let block = nFreesBlock n lo w+        len   = length block+        blk   = take len . dropWhile (< lo) . nFrees $ n+    in block == blk++nFreedomAssertion1 :: Assertion+nFreedomAssertion1 =+    assertEqual "1 is the sole 0-free number" (nFrees 0) ([1] :: [Int])++nFreedomAssertion2 :: Assertion+nFreedomAssertion2 =+    assertEqual "1 is the sole 1-free number" (nFrees 1) ([1] :: [Int])+ testSuite :: TestTree testSuite = testGroup "ArithmeticFunctions"   [ testGroup "Divisors"@@ -326,5 +367,13 @@     ]   , testGroup "Mangoldt"     [ testCase "OEIS" mangoldtOeis+    ]+  , testGroup "N-freedom"+    [ testSmallAndQuick "`isNFree` matches the definition" nFreedomProperty1+    , testSmallAndQuick "numbers produces by `nFrees`s are `n`-free" nFreedomProperty2+    , testSmallAndQuick "distribution of n-free numbers matches expected" nFreedomProperty3+    , testSmallAndQuick "nFreesBlock matches nFrees" nFreesBlockProperty1+    , testCase "`1` is the only 0-free number" nFreedomAssertion1+    , testCase "`1` is the only 1-free number" nFreedomAssertion2     ]   ]
test-suite/Math/NumberTheory/CurvesTests.hs view
@@ -3,7 +3,6 @@ -- Copyright:   (c) 2017 Andrew Lelechenko -- Licence:     MIT -- Maintainer:  Andrew Lelechenko <andrew.lelechenko@gmail.com>--- Stability:   Provisional -- -- Tests for Math.NumberTheory.Curves --
test-suite/Math/NumberTheory/EisensteinIntegersTests.hs view
@@ -5,7 +5,6 @@ -- Copyright:   (c) 2018 Alexandre Rodrigues Baldé -- Licence:     MIT -- Maintainer:  Alexandre Rodrigues Baldé <alexandrer_b@outlook.--- Stability:   Provisional -- -- Tests for Math.NumberTheory.EisensteinIntegers --@@ -14,13 +13,15 @@   ( testSuite   ) where -import qualified Math.NumberTheory.Euclidean    as ED-import qualified Math.NumberTheory.Quadratic.EisensteinIntegers as E-import Math.NumberTheory.Primes                       (primes)+import Data.Maybe (fromJust, isJust) import Test.Tasty                                     (TestTree, testGroup) import Test.Tasty.HUnit                               (Assertion, assertEqual,                                                       testCase) +import qualified Math.NumberTheory.Euclidean as ED+import qualified Math.NumberTheory.Quadratic.EisensteinIntegers as E+import Math.NumberTheory.Primes+import Math.NumberTheory.Primes.Sieve (primes) import Math.NumberTheory.TestUtils                    (Positive (..),                                                        testSmallAndQuick) @@ -95,9 +96,9 @@ 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+        prop prime = unPrime prime `mod` 6 == 1         p = (!! index) $ filter prop $ drop 3 primes-    in E.isPrime $ E.findPrime p+    in isJust (isPrime (unPrime (E.findPrime p) :: E.EisensteinInteger))  -- | Checks that the @norm@ of the Euclidean domain of Eisenstein integers -- is multiplicative i.e.@@ -108,21 +109,21 @@ -- | 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+primesProperty1 (Positive index) = all (isJust . isPrime . (unPrime :: Prime E.EisensteinInteger -> E.EisensteinInteger)) $ 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+    let isOrdered :: [Prime E.EisensteinInteger] -> Bool+        isOrdered xs = all (\(x, y) -> E.norm (unPrime x) <= E.norm (unPrime 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+    all (\e -> abs (unPrime e) == (unPrime e :: E.EisensteinInteger)) $ 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@@ -130,30 +131,23 @@ factoriseProperty1 :: E.EisensteinInteger -> Bool factoriseProperty1 g = g == 0 || abs g == abs g'   where-    factors = E.factorise g-    g' = product $ map (uncurry (^)) factors+    factors = factorise g+    g' = product $ map (\(p, k) -> unPrime p ^ k) 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)+factoriseProperty2 z = z == 0 || all ((> 0) . snd) (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)+factoriseProperty3 z = z == 0 || all ((> 1) . E.norm . unPrime . fst) (factorise z)  factoriseSpecialCase1 :: Assertion factoriseSpecialCase1 = assertEqual "should be equal"-  [(2 E.:+ 1, 3), (2 E.:+ 3, 1)]-  (E.factorise (15 E.:+ 12))+  [ (fromJust $ isPrime $ 2 E.:+ 1, 3)+  , (fromJust $ isPrime $ 3 E.:+ 1, 1)+  ]+  (factorise (15 E.:+ 12))  testSuite :: TestTree testSuite = testGroup "EisensteinIntegers" $@@ -201,8 +195,6 @@                           factoriseProperty2       , testSmallAndQuick "factorise produces no unit factors"                           factoriseProperty3-      , testSmallAndQuick "factorise only produces primary primes"-                          factoriseProperty4       , testCase          "factorise 15:+12" factoriseSpecialCase1       ]   ]
+ test-suite/Math/NumberTheory/EuclideanTests.hs view
@@ -0,0 +1,148 @@+-- |+-- Module:      Math.NumberTheory.EuclideanTests+-- Copyright:   (c) 2016 Andrew Lelechenko+-- Licence:     MIT+-- Maintainer:  Andrew Lelechenko <andrew.lelechenko@gmail.com>+--+-- Tests for Math.NumberTheory.Euclidean+--++{-# LANGUAGE CPP                 #-}+{-# LANGUAGE ScopedTypeVariables #-}++{-# OPTIONS_GHC -fno-warn-type-defaults  #-}+{-# OPTIONS_GHC -fno-warn-unused-imports #-}+{-# OPTIONS_GHC -fno-warn-deprecations   #-}++module Math.NumberTheory.EuclideanTests+  ( testSuite+  ) where++import Prelude hiding (gcd)+import Test.Tasty+import Test.Tasty.HUnit++import Control.Arrow+import Data.Bits+import Data.Maybe+import Data.Semigroup+import Data.List (tails, sort)+import Numeric.Natural++import Math.NumberTheory.Euclidean+import Math.NumberTheory.Euclidean.Coprimes+import Math.NumberTheory.TestUtils++-- | Check that 'extendedGCD' is consistent with documentation.+extendedGCDProperty :: forall a. (Bits a, Euclidean a, Ord a) => AnySign a -> AnySign a -> Bool+extendedGCDProperty (AnySign a) (AnySign b)+  | isNatural a = True -- extendedGCD does not make sense for Natural+  | otherwise =+  u * a + v * b == d+  && d == gcd a b+  -- (-1) >= 0 is true for unsigned types+  && (abs u < abs b || abs b <= 1 || (-1 :: a) >= 0)+  && (abs v < abs a || abs a <= 1 || (-1 :: a) >= 0)+  where+    (d, u, v) = extendedGCD a b++isNatural :: Bits a => a -> Bool+isNatural a = isNothing (bitSizeMaybe a) && not (isSigned a)++-- | Check that numbers are coprime iff their gcd equals to 1.+coprimeProperty :: (Euclidean a) => AnySign a -> AnySign a -> Bool+coprimeProperty (AnySign a) (AnySign b) = coprime a b == (gcd a b == 1)++splitIntoCoprimesProperty1 :: [(Positive Natural, Power Word)] -> Bool+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 (unCoprimes $ splitIntoCoprimes fs)+  where+    fs = map (getPositive *** getPower) fs'+    multiplicities = sum . map snd . filter ((/= 1) . fst)++splitIntoCoprimesProperty3 :: [(Positive Natural, Power Word)] -> Bool+splitIntoCoprimesProperty3 fs' = and [ coprime x y | (x : xs) <- tails fs, y <- xs ]+  where+    fs = map fst $ unCoprimes $ splitIntoCoprimes $ map (getPositive *** getPower) fs'++-- | Check that evaluation never freezes.+splitIntoCoprimesProperty4 :: [(Integer, Word)] -> Bool+splitIntoCoprimesProperty4 fs' = fs == fs+  where+    fs = splitIntoCoprimes fs'++-- | This is an undefined behaviour, but at least it should not+-- throw exceptions or loop forever.+splitIntoCoprimesSpecialCase1 :: Assertion+splitIntoCoprimesSpecialCase1 =+  assertBool "should not fail" $ splitIntoCoprimesProperty4 [(0, 0), (0, 0)]++-- | This is an undefined behaviour, but at least it should not+-- throw exceptions or loop forever.+splitIntoCoprimesSpecialCase2 :: Assertion+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 "Euclidean"+  [ testSameIntegralProperty "extendedGCD" extendedGCDProperty+  , testSameIntegralProperty "coprime"     coprimeProperty+  , testGroup "splitIntoCoprimes"+    [ testSmallAndQuick "preserves product of factors"        splitIntoCoprimesProperty1+    , testSmallAndQuick "number of factors is non-decreasing" splitIntoCoprimesProperty2+    , testSmallAndQuick "output factors are coprime"          splitIntoCoprimesProperty3++    , 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/GCDTests.hs
@@ -1,147 +0,0 @@--- |--- Module:      Math.NumberTheory.GCDTests--- Copyright:   (c) 2016 Andrew Lelechenko--- Licence:     MIT--- Maintainer:  Andrew Lelechenko <andrew.lelechenko@gmail.com>--- Stability:   Provisional------ Tests for Math.NumberTheory.GCD-----{-# LANGUAGE CPP                 #-}-{-# LANGUAGE ScopedTypeVariables #-}--{-# OPTIONS_GHC -fno-warn-type-defaults  #-}-{-# OPTIONS_GHC -fno-warn-unused-imports #-}-{-# OPTIONS_GHC -fno-warn-deprecations   #-}--module Math.NumberTheory.GCDTests-  ( testSuite-  ) where--import Test.Tasty-import Test.Tasty.HUnit--import Control.Arrow-import Data.Bits-import Data.Semigroup-import Data.List (tails, sort)-import Numeric.Natural--import Math.NumberTheory.Euclidean.Coprimes-import Math.NumberTheory.GCD-import Math.NumberTheory.TestUtils---- | Check that 'binaryGCD' matches 'gcd'.-binaryGCDProperty :: (Integral a, Bits a) => AnySign a -> AnySign a -> Bool-binaryGCDProperty (AnySign a) (AnySign b) = binaryGCD a b == gcd a b---- | Check that 'extendedGCD' is consistent with documentation.-extendedGCDProperty :: forall a. Integral a => AnySign a -> AnySign a -> Bool-extendedGCDProperty (AnySign a) (AnySign b) =-  u * a + v * b == d-  && d == gcd a b-  -- (-1) >= 0 is true for unsigned types-  && (abs u < abs b || abs b <= 1 || (-1 :: a) >= 0)-  && (abs v < abs a || abs a <= 1 || (-1 :: a) >= 0)-  where-    (d, u, v) = extendedGCD a b---- | Check that numbers are coprime iff their gcd equals to 1.-coprimeProperty :: (Integral a, Bits a) => AnySign a -> AnySign a -> Bool-coprimeProperty (AnySign a) (AnySign b) = coprime a b == (gcd a b == 1)--splitIntoCoprimesProperty1 :: [(Positive Natural, Power Word)] -> Bool-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 (unCoprimes $ splitIntoCoprimes fs)-  where-    fs = map (getPositive *** getPower) fs'-    multiplicities = sum . map snd . filter ((/= 1) . fst)--splitIntoCoprimesProperty3 :: [(Positive Natural, Power Word)] -> Bool-splitIntoCoprimesProperty3 fs' = and [ coprime x y | (x : xs) <- tails fs, y <- xs ]-  where-    fs = map fst $ unCoprimes $ splitIntoCoprimes $ map (getPositive *** getPower) fs'---- | Check that evaluation never freezes.-splitIntoCoprimesProperty4 :: [(Integer, Word)] -> Bool-splitIntoCoprimesProperty4 fs' = fs == fs-  where-    fs = splitIntoCoprimes fs'---- | This is an undefined behaviour, but at least it should not--- throw exceptions or loop forever.-splitIntoCoprimesSpecialCase1 :: Assertion-splitIntoCoprimesSpecialCase1 =-  assertBool "should not fail" $ splitIntoCoprimesProperty4 [(0, 0), (0, 0)]---- | This is an undefined behaviour, but at least it should not--- throw exceptions or loop forever.-splitIntoCoprimesSpecialCase2 :: Assertion-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-  , testSameIntegralProperty "extendedGCD" extendedGCDProperty-  , testSameIntegralProperty "coprime"     coprimeProperty-  , testGroup "splitIntoCoprimes"-    [ testSmallAndQuick "preserves product of factors"        splitIntoCoprimesProperty1-    , testSmallAndQuick "number of factors is non-decreasing" splitIntoCoprimesProperty2-    , testSmallAndQuick "output factors are coprime"          splitIntoCoprimesProperty3--    , 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
@@ -5,7 +5,6 @@ -- Copyright:   (c) 2016 Chris Fredrickson, Google Inc. -- Licence:     MIT -- Maintainer:  Chris Fredrickson <chris.p.fredrickson@gmail.com>--- Stability:   Provisional -- -- Tests for Math.NumberTheory.GaussianIntegers --@@ -16,6 +15,7 @@  import Control.Monad (zipWithM_) import Data.List (groupBy, sort)+import Data.Maybe (fromJust, mapMaybe) import Test.Tasty import Test.Tasty.HUnit @@ -23,15 +23,15 @@ import Math.NumberTheory.Quadratic.GaussianIntegers import Math.NumberTheory.Moduli.Sqrt import Math.NumberTheory.Powers (integerSquareRoot)-import Math.NumberTheory.UniqueFactorisation (unPrime)+import Math.NumberTheory.Primes (Prime, unPrime, UniqueFactorisation(..)) import Math.NumberTheory.TestUtils -lazyCases :: [(GaussianInteger, [(GaussianInteger, Int)])]+lazyCases :: [(GaussianInteger, [(Prime GaussianInteger, Word)])] lazyCases =   [ ( 14145130733     * 10000000000000000000000000000000000000121     * 100000000000000000000000000000000000000000000000447-    , [(117058 :+ 21037, 1), (21037 :+ 117058, 1)]+    , [(fromJust $ isPrime $ 117058 :+ 21037, 1), (fromJust $ isPrime $ 21037 :+ 117058, 1)]     )   ] @@ -42,24 +42,27 @@   || abs g == abs g'   where     factors = factorise g-    g' = product $ map (uncurry (^)) factors+    g' = product $ map (\(p, k) -> unPrime p ^ k) factors  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)+factoriseProperty3 z = z == 0 || all ((> 1) . norm . unPrime . fst) (factorise z)  factoriseSpecialCase1 :: Assertion factoriseSpecialCase1 = assertEqual "should be equal"-  [(3, 2), (1 :+ 2, 1), (2 :+ 3, 1)]+  [ (fromJust $ isPrime $ 3 :+ 0, 2)+  , (fromJust $ isPrime $ 1 :+ 2, 1)+  , (fromJust $ isPrime $ 2 :+ 3, 1)+  ]   (factorise (63 :+ 36)) -factoriseSpecialCase2 :: (GaussianInteger, [(GaussianInteger, Int)]) -> Assertion+factoriseSpecialCase2 :: (GaussianInteger, [(Prime GaussianInteger, Word)]) -> Assertion factoriseSpecialCase2 (n, fs) = zipWithM_ (assertEqual (show n)) fs (factorise n) -findPrimeReference :: PrimeWrapper Integer -> GaussianInteger-findPrimeReference (PrimeWrapper p) =+findPrimeReference :: Prime Integer -> GaussianInteger+findPrimeReference p =     let c : _ = sqrtsModPrime (-1) p         k  = integerSquareRoot (unPrime p)         bs = [1 .. k]@@ -67,22 +70,22 @@         (a, b) = head [ (a', b') | (a', b') <- asbs, a' <= k]     in a :+ b -findPrimeProperty1 :: PrimeWrapper Integer -> Bool-findPrimeProperty1 p'@(PrimeWrapper p)+findPrimeProperty1 :: Prime Integer -> Bool+findPrimeProperty1 p   = unPrime p `mod` 4 /= (1 :: Integer)   || p1 == p2   || abs (p1 * p2) == fromInteger (unPrime p)   where-    p1 = findPrimeReference p'-    p2 = findPrime (unPrime p)+    p1 = findPrimeReference p+    p2 = unPrime (findPrime p)  -- | Number is prime iff it is non-zero --   and has exactly one (non-unit) factor. isPrimeProperty :: GaussianInteger -> Bool-isPrimeProperty g-  =  g == 0-  || isPrime g && n == 1-  || not (isPrime g) && n /= 1+isPrimeProperty 0 = True+isPrimeProperty g = case isPrime g of+  Nothing -> n /= 1+  Just{}  -> n == 1   where     factors = factorise g     -- Count factors taking into account multiplicity@@ -90,25 +93,27 @@  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 $ mapMaybe isPrime [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)+    f :: [Prime GaussianInteger] -> [[Prime GaussianInteger]]+    f = map sort . groupBy (\g1 g2 -> norm (unPrime g1) == norm (unPrime g2))  -- | The list of primes should include only primes. primesGeneratesPrimesProperty :: NonNegative Int -> Bool-primesGeneratesPrimesProperty (NonNegative i) = isPrime (primes !! i)+primesGeneratesPrimesProperty (NonNegative i) = case isPrime (unPrime (primes !! i) :: GaussianInteger) of+  Nothing -> False+  Just{}  -> True  -- | 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+  where xs = map (norm . unPrime) $ 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]]+  [4 * (length $ takeWhile ((<= 10^n) . norm . unPrime) primes) | n <- [1..7]]  -- | signum and abs should satisfy: z == signum z * abs z signumAbsProperty :: GaussianInteger -> Bool
test-suite/Math/NumberTheory/Moduli/ChineseTests.hs view
@@ -3,7 +3,6 @@ -- Copyright:   (c) 2016 Andrew Lelechenko -- Licence:     MIT -- Maintainer:  Andrew Lelechenko <andrew.lelechenko@gmail.com>--- Stability:   Provisional -- -- Tests for Math.NumberTheory.Moduli.Chinese --@@ -41,8 +40,32 @@ chineseRemainder2Property r1 (Positive m1) r2 (Positive m2) = gcd m1 m2 /= 1   || Just (chineseRemainder2 (r1, m1) (r2, m2)) == chineseRemainder [(r1, m1), (r2, m2)] +chineseCoprimeProperty :: Integer -> Positive Integer -> Integer -> Positive Integer -> Bool+chineseCoprimeProperty n1 (Positive m1) n2 (Positive m2) = case gcd m1 m2 of+  1 -> case chineseCoprime (n1, m1) (n2, m2) of+    Nothing -> False+    Just n  -> n `mod` m1 == n1 `mod` m1 && n `mod` m2 == n2 `mod` m2+  _ -> case chineseCoprime (n1, m1) (n2, m2) of+    Nothing -> True+    Just{}  -> False++chineseProperty :: Integer -> Positive Integer -> Integer -> Positive Integer -> Bool+chineseProperty n1 (Positive m1) n2 (Positive m2) = if compatible+  then case chinese (n1, m1) (n2, m2) of+    Nothing -> False+    Just n  -> n `mod` m1 == n1 `mod` m1 && n `mod` m2 == n2 `mod` m2+  else case chineseCoprime (n1, m1) (n2, m2) of+    Nothing -> True+    Just{}  -> False+  where+    g = gcd m1 m2+    compatible = n1 `mod` g == n2 `mod` g++ testSuite :: TestTree testSuite = testGroup "Chinese"   [ testSmallAndQuick "chineseRemainder"  chineseRemainderProperty   , testSmallAndQuick "chineseRemainder2" chineseRemainder2Property+  , testSmallAndQuick "chineseCoprime"    chineseCoprimeProperty+  , testSmallAndQuick "chinese"           chineseProperty   ]
test-suite/Math/NumberTheory/Moduli/ClassTests.hs view
@@ -3,7 +3,6 @@ -- Copyright:   (c) 2016 Andrew Lelechenko -- Licence:     MIT -- Maintainer:  Andrew Lelechenko <andrew.lelechenko@gmail.com>--- Stability:   Provisional -- -- Tests for Math.NumberTheory.Moduli.Class --@@ -18,6 +17,7 @@   ) where  import Test.Tasty+import qualified Test.Tasty.QuickCheck as QC  import Data.Maybe import Numeric.Natural@@ -94,6 +94,27 @@     m3 = toInteger $ m1 `gcd` m2     x3 = (x1 * x2) `mod` m3 +sameSomeModMulProperty :: Integer -> Integer -> Positive Natural -> Bool+sameSomeModMulProperty x1 x2 (Positive m) = case (x1 `modulo` m) * (x2 `modulo` m) of+  SomeMod z -> getMod z == toInteger m && getVal z == x3+  InfMod{}  -> False+  where+    x3 = (x1 * x2) `mod` toInteger m++sameSomeModMulHugeProperty :: Integer -> Integer -> Positive (Huge Natural) -> Bool+sameSomeModMulHugeProperty x1 x2 (Positive (Huge m)) = case (x1 `modulo` m) * (x2 `modulo` m) of+  SomeMod z -> getMod z == toInteger m && getVal z == x3+  InfMod{}  -> False+  where+    x3 = (x1 * x2) `mod` toInteger m++sameSomeModMulHugeAllProperty :: Huge Integer -> Huge Integer -> Positive (Huge Natural) -> Bool+sameSomeModMulHugeAllProperty (Huge x1) (Huge x2) (Positive (Huge m)) = case (x1 `modulo` m) * (x2 `modulo` m) of+  SomeMod z -> getMod z == toInteger m && getVal z == x3+  InfMod{}  -> False+  where+    x3 = (x1 * x2) `mod` toInteger m+ someModNegProperty :: Integer -> Positive Natural -> Bool someModNegProperty x1 (Positive m1) = case negate (x1 `modulo` m1) of   SomeMod z -> getMod z == m3 && getVal z == x3@@ -150,6 +171,11 @@       [ testSmallAndQuick "multiplicative by base"  powerModProperty2_Integer       , testSmallAndQuick "additive by exponent"    powerModProperty3_Integer       ]+    ]+  , testGroup "Same SomeMod"+    [ testSmallAndQuick "mul" sameSomeModMulProperty+    , QC.testProperty "mul huge" sameSomeModMulHugeProperty+    , QC.testProperty "mul huge all" sameSomeModMulHugeAllProperty     ]   , testGroup "SomeMod"     [ testSmallAndQuick "add" someModAddProperty
test-suite/Math/NumberTheory/Moduli/EquationsTests.hs view
@@ -3,8 +3,6 @@ -- Copyright:   (c) 2018 Andrew Lelechenko -- Licence:     MIT -- Maintainer:  Andrew Lelechenko <andrew.lelechenko@gmail.com>--- Stability:   Provisional--- Portability: Non-portable (GHC extensions) --  {-# LANGUAGE ScopedTypeVariables #-}
test-suite/Math/NumberTheory/Moduli/JacobiTests.hs view
@@ -3,7 +3,6 @@ -- Copyright:   (c) 2016 Andrew Lelechenko -- Licence:     MIT -- Maintainer:  Andrew Lelechenko <andrew.lelechenko@gmail.com>--- Stability:   Provisional -- -- Tests for Math.NumberTheory.Moduli.Jacobi --@@ -23,7 +22,6 @@ #if __GLASGOW_HASKELL__ < 803 import Data.Semigroup #endif-import Numeric.Natural  import Math.NumberTheory.Moduli hiding (invertMod) import Math.NumberTheory.TestUtils@@ -50,36 +48,12 @@   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))) =   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)@@ -112,19 +86,13 @@  testSuite :: TestTree testSuite = testGroup "Jacobi"-  [ testSameIntegralProperty "same modulo n"                jacobiProperty2-  , testSameIntegralProperty "consistent with gcd"          jacobiProperty3-  , 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+  [ testSameIntegralProperty  "same modulo n"                jacobiProperty2+  , testSameIntegralProperty  "consistent with gcd"          jacobiProperty3+  , testSameIntegralProperty3 "multiplicative 1"             jacobiProperty4+  , testSameIntegralProperty3 "multiplicative 2"             jacobiProperty5+  , 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
@@ -3,7 +3,6 @@ -- Copyright:   (c) 2017 Andrew Lelechenko -- Licence:     MIT -- Maintainer:  Andrew Lelechenko <andrew.lelechenko@gmail.com>--- Stability:   Provisional -- -- Tests for Math.NumberTheory.Moduli.PrimitiveRoot --@@ -34,8 +33,8 @@ import Math.NumberTheory.Moduli.Class (Mod, SomeMod(..), modulo) import Math.NumberTheory.Moduli.PrimitiveRoot import Math.NumberTheory.Prefactored (fromFactors, prefFactors, prefValue, Prefactored)+import Math.NumberTheory.Primes import Math.NumberTheory.TestUtils-import Math.NumberTheory.UniqueFactorisation  cyclicGroupProperty1 :: (Euclidean a, Integral a, UniqueFactorisation a) => AnySign a -> Bool cyclicGroupProperty1 (AnySign n) = case cyclicGroupFromModulo n of
test-suite/Math/NumberTheory/Moduli/SqrtTests.hs view
@@ -3,7 +3,6 @@ -- Copyright:   (c) 2016 Andrew Lelechenko -- Licence:     MIT -- Maintainer:  Andrew Lelechenko <andrew.lelechenko@gmail.com>--- Stability:   Provisional -- -- Tests for Math.NumberTheory.Moduli.Sqrt --@@ -26,49 +25,46 @@ import Numeric.Natural  import Math.NumberTheory.Moduli hiding (invertMod)-import Math.NumberTheory.UniqueFactorisation (unPrime, isPrime, Prime)+import Math.NumberTheory.Primes (unPrime, isPrime, Prime) import Math.NumberTheory.TestUtils -unwrapP :: PrimeWrapper Integer -> Prime Integer-unwrapP (PrimeWrapper p) = p--unwrapPP :: (PrimeWrapper Integer, Power Word) -> (Prime Integer, Word)-unwrapPP (p, Power e) = (unwrapP p, e `mod` 5)+unwrapPP :: (Prime Integer, Power Word) -> (Prime Integer, Word)+unwrapPP (p, Power e) = (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.-sqrtsModPrimeProperty1 :: AnySign Integer -> PrimeWrapper Integer -> Bool-sqrtsModPrimeProperty1 (AnySign n) (unwrapP -> p'@(unPrime -> p)) = case sqrtsModPrime n p' of+sqrtsModPrimeProperty1 :: AnySign Integer -> Prime Integer -> Bool+sqrtsModPrimeProperty1 (AnySign n) 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 -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')+sqrtsModPrimeProperty2 :: AnySign Integer -> Prime Integer -> Bool+sqrtsModPrimeProperty2 (AnySign n) p'@(unPrime -> p) = all (\rt -> rt ^ 2 `mod` p == n `mod` p) (sqrtsModPrime n p') -sqrtsModPrimeProperty3 :: AnySign Integer -> PrimeWrapper Integer -> Bool-sqrtsModPrimeProperty3 (AnySign n) (unwrapP -> p'@(unPrime -> p)) = nubOrd rts == sort rts+sqrtsModPrimeProperty3 :: AnySign Integer -> Prime Integer -> Bool+sqrtsModPrimeProperty3 (AnySign n) p'@(unPrime -> p) = nubOrd rts == sort rts   where     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')+sqrtsModPrimeProperty4 :: AnySign Integer -> Prime Integer -> Bool+sqrtsModPrimeProperty4 (AnySign n) p'@(unPrime -> p) = all (\rt -> rt >= 0 && rt < p) (sqrtsModPrime n p') -tonelliShanksProperty1 :: Positive Integer -> PrimeWrapper Integer -> Bool-tonelliShanksProperty1 (Positive n) (unwrapP -> p'@(unPrime -> p)) = p `mod` 4 /= 1 || jacobi n p /= One || rt ^ 2 `mod` p == n `mod` p+tonelliShanksProperty1 :: Positive Integer -> Prime Integer -> Bool+tonelliShanksProperty1 (Positive n) p'@(unPrime -> p) = p `mod` 4 /= 1 || jacobi n p /= One || rt ^ 2 `mod` p == n `mod` p   where     rt : _ = sqrtsModPrime n p' -tonelliShanksProperty2 :: PrimeWrapper Integer -> Bool-tonelliShanksProperty2 (unwrapP -> p'@(unPrime -> p)) = p `mod` 4 /= 1 || rt ^ 2 `mod` p == n `mod` p+tonelliShanksProperty2 :: Prime Integer -> Bool+tonelliShanksProperty2 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 : _ = sqrtsModPrime n p' -tonelliShanksProperty3 :: PrimeWrapper Integer -> Bool-tonelliShanksProperty3 (unwrapP -> p'@(unPrime -> p))+tonelliShanksProperty3 :: Prime Integer -> Bool+tonelliShanksProperty3 p'@(unPrime -> p)   = p `mod` 4 /= 1   || rt ^ 2 `mod` p == p - 1   where@@ -82,32 +78,32 @@     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 (head . sqrtsModPrime 2 . fromJust . isPrime) ps -sqrtsModPrimePowerProperty1 :: AnySign Integer -> (PrimeWrapper Integer, Power Word) -> Bool-sqrtsModPrimePowerProperty1 (AnySign n) (unwrapP -> p'@(unPrime -> p), Power e) = gcd n p > 1+sqrtsModPrimePowerProperty1 :: AnySign Integer -> (Prime Integer, Power Word) -> Bool+sqrtsModPrimePowerProperty1 (AnySign n) (p'@(unPrime -> p), Power e) = gcd n p > 1   || all (\rt -> rt ^ 2 `mod` (p ^ e) == n `mod` (p ^ e)) (sqrtsModPrimePower n p' e)  sqrtsModPrimePowerProperty2 :: AnySign Integer -> Power Word -> Bool-sqrtsModPrimePowerProperty2 n e = sqrtsModPrimePowerProperty1 n (PrimeWrapper $ fromJust $ isPrime (2 :: Integer), e)+sqrtsModPrimePowerProperty2 n e = sqrtsModPrimePowerProperty1 n (fromJust $ isPrime (2 :: Integer), e) -sqrtsModPrimePowerProperty3 :: AnySign Integer -> (PrimeWrapper Integer, Power Word) -> Bool-sqrtsModPrimePowerProperty3 (AnySign n) (unwrapP -> p'@(unPrime -> p), Power e') = nubOrd rts == sort rts+sqrtsModPrimePowerProperty3 :: AnySign Integer -> (Prime Integer, Power Word) -> Bool+sqrtsModPrimePowerProperty3 (AnySign n) (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  sqrtsModPrimePowerProperty4 :: AnySign Integer -> Power Word -> Bool-sqrtsModPrimePowerProperty4 n e = sqrtsModPrimePowerProperty3 n (PrimeWrapper $ fromJust $ isPrime (2 :: Integer), e)+sqrtsModPrimePowerProperty4 n e = sqrtsModPrimePowerProperty3 n (fromJust $ isPrime (2 :: Integer), 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+sqrtsModPrimePowerProperty5 :: AnySign Integer -> (Prime Integer, Power Word) -> Bool+sqrtsModPrimePowerProperty5 (AnySign n) (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  sqrtsModPrimePowerProperty6 :: AnySign Integer -> Power Word -> Bool-sqrtsModPrimePowerProperty6 n e = sqrtsModPrimePowerProperty5 n (PrimeWrapper $ fromJust $ isPrime (2 :: Integer), e)+sqrtsModPrimePowerProperty6 n e = sqrtsModPrimePowerProperty5 n (fromJust $ isPrime (2 :: Integer), e)  sqrtsModPrimePowerSpecialCase1 :: Assertion sqrtsModPrimePowerSpecialCase1 =@@ -153,7 +149,7 @@ 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 Integer -> [(Prime 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)@@ -161,7 +157,7 @@   where     ps = map fst pes -sqrtsModFactorisationProperty2 :: AnySign Integer -> [(PrimeWrapper Integer, Power Word)] -> Bool+sqrtsModFactorisationProperty2 :: AnySign Integer -> [(Prime 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@@ -169,7 +165,7 @@     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 Integer -> [(Prime 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
test-suite/Math/NumberTheory/MoebiusInversion/IntTests.hs view
@@ -3,7 +3,6 @@ -- Copyright:   (c) 2016 Andrew Lelechenko -- Licence:     MIT -- Maintainer:  Andrew Lelechenko <andrew.lelechenko@gmail.com>--- Stability:   Provisional -- -- Tests for Math.NumberTheory.MoebiusInversion.Int --
test-suite/Math/NumberTheory/MoebiusInversionTests.hs view
@@ -3,7 +3,6 @@ -- Copyright:   (c) 2016 Andrew Lelechenko -- Licence:     MIT -- Maintainer:  Andrew Lelechenko <andrew.lelechenko@gmail.com>--- Stability:   Provisional -- -- Tests for Math.NumberTheory.MoebiusInversion --
test-suite/Math/NumberTheory/Powers/CubesTests.hs view
@@ -3,7 +3,6 @@ -- Copyright:   (c) 2016 Andrew Lelechenko -- Licence:     MIT -- Maintainer:  Andrew Lelechenko <andrew.lelechenko@gmail.com>--- Stability:   Provisional -- -- Tests for Math.NumberTheory.Powers.Cubes --@@ -37,9 +36,9 @@   where     m = integerCubeRoot n     cond-      | m == -1   = n == -1-      | m < 0     = (m + 1) ^ 2 <= n `div` (m + 1)-      | otherwise = (m + 1) ^ 2 >= n `div` (m + 1)+      | m < 0 && m == -1 = n == -1+      | m < 0            = (m + 1) ^ 2 <= n `div` (m + 1)+      | otherwise        = (m + 1) ^ 2 >= n `div` (m + 1)  -- | Specialized to trigger 'cubeRootInt''. integerCubeRootProperty_Int :: AnySign Int -> Bool@@ -55,14 +54,14 @@  -- | Check that 'integerCubeRoot' returns the largest integer @m@ with @m^3 <= n@, , where @n@ has form @k@^3-1. integerCubeRootProperty2 :: Integral a => AnySign a -> Bool-integerCubeRootProperty2 (AnySign k) = m ^ 3 <= n && (m + 1) ^ 3 /= n && cond+integerCubeRootProperty2 (AnySign k) = k == 0 || (m ^ 3 <= n && (m + 1) ^ 3 /= n && cond)   where     n = k ^ 3 - 1     m = integerCubeRoot n     cond-      | m == -1   = n == -1-      | m < 0     = (m + 1) ^ 2 <= n `div` (m + 1)-      | otherwise = (m + 1) ^ 2 >= n `div` (m + 1)+      | m < 0 && m == -1 = n == -1+      | m < 0            = (m + 1) ^ 2 <= n `div` (m + 1)+      | otherwise        = (m + 1) ^ 2 >= n `div` (m + 1)  -- | Specialized to trigger 'cubeRootInt''. integerCubeRootProperty2_Int :: AnySign Int -> Bool
test-suite/Math/NumberTheory/Powers/FourthTests.hs view
@@ -3,7 +3,6 @@ -- Copyright:   (c) 2016 Andrew Lelechenko -- Licence:     MIT -- Maintainer:  Andrew Lelechenko <andrew.lelechenko@gmail.com>--- Stability:   Provisional -- -- Tests for Math.NumberTheory.Powers.Fourth --@@ -50,18 +49,18 @@ integerFourthRootProperty_Integer = integerFourthRootProperty  -- | Check that 'integerFourthRoot' returns the largest integer @m@ with @m^4 <= n@, , where @n@ has form @k@^4-1.-integerFourthRootProperty2 :: Integral a => NonNegative a -> Bool-integerFourthRootProperty2 (NonNegative k) = n < 0 || m >= 0 && m ^ 4 <= n && (m + 1) ^ 4 /= n && (m + 1) ^ 3 >= n `div` (m + 1)+integerFourthRootProperty2 :: Integral a => Positive a -> Bool+integerFourthRootProperty2 (Positive k) = n < 0 || m >= 0 && m ^ 4 <= n && (m + 1) ^ 4 /= n && (m + 1) ^ 3 >= n `div` (m + 1)   where     n = k ^ 4 - 1     m = integerFourthRoot n  -- | Specialized to trigger 'biSqrtInt.-integerFourthRootProperty2_Int :: NonNegative Int -> Bool+integerFourthRootProperty2_Int :: Positive Int -> Bool integerFourthRootProperty2_Int = integerFourthRootProperty2  -- | Specialized to trigger 'biSqrtWord'.-integerFourthRootProperty2_Word :: NonNegative Word -> Bool+integerFourthRootProperty2_Word :: Positive Word -> Bool integerFourthRootProperty2_Word = integerFourthRootProperty2  #if WORD_SIZE_IN_BITS == 64
test-suite/Math/NumberTheory/Powers/GeneralTests.hs view
@@ -3,7 +3,6 @@ -- Copyright:   (c) 2016 Andrew Lelechenko -- Licence:     MIT -- Maintainer:  Andrew Lelechenko <andrew.lelechenko@gmail.com>--- Stability:   Provisional -- -- Tests for Math.NumberTheory.Powers.General --@@ -52,7 +51,7 @@  -- | Check that the first component of 'highestPower' is square-free. highestPowerProperty :: Integral a => AnySign a -> Bool-highestPowerProperty (AnySign n) = (n `elem` [-1, 0, 1] && k == 3) || (b ^ k == n && b' == b && k' == 1)+highestPowerProperty (AnySign n) = (n + 1 `elem` [0, 1, 2] && k == 3) || (b ^ k == n && b' == b && k' == 1)   where     (b, k) = highestPower n     (b', k') = highestPower b
test-suite/Math/NumberTheory/Powers/ModularTests.hs view
@@ -3,7 +3,6 @@ -- Copyright:   (c) 2017 Andrew Lelechenko -- Licence:     MIT -- Maintainer:  Andrew Lelechenko <andrew.lelechenko@gmail.com>--- Stability:   Provisional -- -- Tests for Math.NumberTheory.Powers.Modular --
test-suite/Math/NumberTheory/Powers/SquaresTests.hs view
@@ -3,7 +3,6 @@ -- Copyright:   (c) 2016 Andrew Lelechenko -- Licence:     MIT -- Maintainer:  Andrew Lelechenko <andrew.lelechenko@gmail.com>--- Stability:   Provisional -- -- Tests for Math.NumberTheory.Powers.Squares --@@ -50,23 +49,23 @@ integerSquareRootProperty_Integer = integerSquareRootProperty  -- | Check that 'integerSquareRoot' returns the largest integer @m@ with @m*m <= n@, where @n@ has form @k@^2-1.-integerSquareRootProperty2 :: Integral a => NonNegative a -> Bool-integerSquareRootProperty2 (NonNegative k) = n < 0+integerSquareRootProperty2 :: Integral a => Positive a -> Bool+integerSquareRootProperty2 (Positive k) = n < 0   || m >=0 && m * m <= n && (m + 1) ^ 2 /= n && m + 1 >= n `div` (m + 1)   where     n = k ^ 2 - 1     m = integerSquareRoot n  -- | Specialized to trigger 'isqrtInt''.-integerSquareRootProperty2_Int :: NonNegative Int -> Bool+integerSquareRootProperty2_Int :: Positive Int -> Bool integerSquareRootProperty2_Int = integerSquareRootProperty2  -- | Specialized to trigger 'isqrtWord'.-integerSquareRootProperty2_Word :: NonNegative Word -> Bool+integerSquareRootProperty2_Word :: Positive Word -> Bool integerSquareRootProperty2_Word = integerSquareRootProperty2  -- | Specialized to trigger 'isqrtInteger'.-integerSquareRootProperty2_Integer :: NonNegative Integer -> Bool+integerSquareRootProperty2_Integer :: Positive Integer -> Bool integerSquareRootProperty2_Integer = integerSquareRootProperty2  #if WORD_SIZE_IN_BITS == 64
test-suite/Math/NumberTheory/PrefactoredTests.hs view
@@ -3,7 +3,6 @@ -- Copyright:   (c) 2017 Andrew Lelechenko -- Licence:     MIT -- Maintainer:  Andrew Lelechenko <andrew.lelechenko@gmail.com>--- Stability:   Provisional -- -- Tests for Math.NumberTheory.Prefactored --
test-suite/Math/NumberTheory/Primes/CountingTests.hs view
@@ -3,7 +3,6 @@ -- Copyright:   (c) 2016 Andrew Lelechenko -- Licence:     MIT -- Maintainer:  Andrew Lelechenko <andrew.lelechenko@gmail.com>--- Stability:   Provisional -- -- Tests for Math.NumberTheory.Primes.Counting --@@ -17,6 +16,7 @@ import Test.Tasty import Test.Tasty.HUnit +import Math.NumberTheory.Primes (unPrime) import Math.NumberTheory.Primes.Counting import Math.NumberTheory.Primes.Testing import Math.NumberTheory.TestUtils@@ -73,13 +73,13 @@ primeCountSpecialCases :: [Assertion] primeCountSpecialCases = map a table   where-  a (n, m) = assertEqual "primeCount" m (primeCount n)+    a (n, m) = assertEqual "primeCount" m (primeCount n)   -- | Check that values of 'nthPrime' are positive. nthPrimeProperty1 :: Positive Integer -> Bool nthPrimeProperty1 (Positive n) = n > nthPrimeMaxArg-  || nthPrime n > 0+  || unPrime (nthPrime n) > 0  -- | Check that 'nthPrime' is monotonically increasing function. nthPrimeProperty2 :: Positive Integer -> Positive Integer -> Bool@@ -94,13 +94,13 @@  -- | Check that values of 'nthPrime' are prime. nthPrimeProperty3 :: Positive Integer -> Bool-nthPrimeProperty3 (Positive n) = isPrime $ nthPrime n+nthPrimeProperty3 (Positive n) = isPrime $ unPrime $ nthPrime n  -- | Check tabulated values. nthPrimeSpecialCases :: [Assertion] nthPrimeSpecialCases = map a table   where-  a (n, m) = assertBool "nthPrime" $ n > nthPrime m+  a (n, m) = assertBool "nthPrime" $ n > unPrime (nthPrime m)   -- | Check that values of 'approxPrimeCount' are non-negative.@@ -120,7 +120,7 @@ -- | Check that 'nthPrimeApprox' is consistent with 'nthPrimeApproxUnderestimateLimit'. nthPrimeApproxProperty2 :: Positive Integer -> Bool nthPrimeApproxProperty2 (Positive a) = a >= nthPrimeApproxUnderestimateLimit-  || toInteger (nthPrimeApprox a) <= nthPrime (toInteger a)+  || toInteger (nthPrimeApprox a) <= unPrime (nthPrime (toInteger a))   testSuite :: TestTree
test-suite/Math/NumberTheory/Primes/FactorisationTests.hs view
@@ -3,7 +3,6 @@ -- Copyright:   (c) 2017 Andrew Lelechenko -- Licence:     MIT -- Maintainer:  Andrew Lelechenko <andrew.lelechenko@gmail.com>--- Stability:   Provisional -- -- Tests for Math.NumberTheory.Primes.Factorisation --@@ -24,7 +23,7 @@ import Math.NumberTheory.Primes.Testing import Math.NumberTheory.TestUtils -specialCases :: [(Integer, [(Integer, Int)])]+specialCases :: [(Integer, [(Integer, Word)])] specialCases =   [ (4181339589500970917,[(15034813,1),(278110515209,1)])   , (4181339589500970918,[(2,1),(3,2),(7,1),(2595773,1),(12784336241,1)])@@ -49,7 +48,7 @@                              (1676321,1),(5070721,1),(5882353,1),(5964848081,1),(19721061166646717498359681,1)])   ] -lazyCases :: [(Integer, [(Integer, Int)])]+lazyCases :: [(Integer, [(Integer, Word)])] lazyCases =   [ ( 14145130711     * 10000000000000000000000000000000000000121@@ -75,10 +74,10 @@ factoriseProperty5 :: Positive Integer -> Bool factoriseProperty5 (Positive n) = product (map (uncurry (^)) (factorise n)) == n -factoriseProperty6 :: (Integer, [(Integer, Int)]) -> Assertion+factoriseProperty6 :: (Integer, [(Integer, Word)]) -> Assertion factoriseProperty6 (n, fs) = assertEqual (show n) (sort fs) (sort (factorise n)) -factoriseProperty7 :: (Integer, [(Integer, Int)]) -> Assertion+factoriseProperty7 :: (Integer, [(Integer, Word)]) -> Assertion factoriseProperty7 (n, fs) = zipWithM_ (assertEqual (show n)) fs (factorise n)  testSuite :: TestTree
+ test-suite/Math/NumberTheory/Primes/SequenceTests.hs view
@@ -0,0 +1,146 @@+{-# LANGUAGE FlexibleContexts    #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TypeApplications    #-}++module Math.NumberTheory.Primes.SequenceTests+  ( testSuite+  ) where++import Test.Tasty++import Data.Bits+import Data.Maybe+import Data.Proxy+import Numeric.Natural++import Math.NumberTheory.Primes+import Math.NumberTheory.Primes.Counting (nthPrime, primeCount)+import Math.NumberTheory.TestUtils++nextPrimeProperty+  :: (Bits a, Integral a, UniqueFactorisation a)+  => AnySign a+  -> Bool+nextPrimeProperty (AnySign n) = unPrime (nextPrime n) >= n++precPrimeProperty+  :: (Bits a, Integral a, UniqueFactorisation a)+  => Positive a+  -> Bool+precPrimeProperty (Positive n) = n <= 2 || unPrime (precPrime n) <= n++toEnumProperty+  :: forall a.+     (Enum (Prime a), Integral a)+  => Proxy a+  -> Int+  -> Bool+toEnumProperty _ n = n <= 0 || unPrime (toEnum n :: Prime a) == fromInteger (unPrime (nthPrime (toInteger n)))++fromEnumProperty+  :: (Enum (Prime a), Integral a)+  => Prime a+  -> Bool+fromEnumProperty p = fromEnum p == fromInteger (primeCount (toInteger (unPrime p)))++succProperty+  :: (Enum a, Enum (Prime a), Num a, UniqueFactorisation a)+  => Prime a+  -> Bool+succProperty p = all (isNothing . isPrime) [unPrime p + 1 .. unPrime (succ p) - 1]++predProperty+  :: (Enum a, Enum (Prime a), Ord a, Num a, UniqueFactorisation a)+  => Prime a+  -> Bool+predProperty p = unPrime p <= 2 || all (isNothing . isPrime) [unPrime (pred p) + 1 .. unPrime p - 1]++enumFromProperty+  :: (Ord a, Enum (Prime a))+  => Prime a+  -> Prime a+  -> Bool+enumFromProperty p q = [p..q] == takeWhile (<= q) [p..]++enumFromToProperty+  :: (Eq a, Enum a, Enum (Prime a), UniqueFactorisation a)+  => Prime a+  -> Prime a+  -> Bool+enumFromToProperty p q = [p..q] == mapMaybe isPrime [unPrime p .. unPrime q]++enumFromThenProperty+  :: (Show a, Ord a, Enum (Prime a))+  => Prime a+  -> Prime a+  -> Prime a+  -> Bool+enumFromThenProperty p q r = case p `compare` q of+  LT -> enumFromThenTo p q r == takeWhile (<= r) (enumFromThen p q)+  EQ -> True+  GT -> enumFromThenTo p q r == takeWhile (>= r) (enumFromThen p q)++enumFromThenToProperty+  :: (Ord a, Enum a, Enum (Prime a), UniqueFactorisation a, Show a)+  => Prime a+  -> Prime a+  -> Prime a+  -> Bool+enumFromThenToProperty p q r+  | p == q && q <= r = True+  | otherwise+  = [p, q .. r] == mapMaybe isPrime [unPrime p, unPrime q .. unPrime r]++testSuite :: TestTree+testSuite = testGroup "Sequence"+  [ testIntegralPropertyNoLarge "nextPrime" nextPrimeProperty+  , testIntegralPropertyNoLarge "precPrime" precPrimeProperty+  , testGroup "toEnum"+    [ testSmallAndQuick "Int" (toEnumProperty (Proxy @Int))+    , testSmallAndQuick "Word" (toEnumProperty (Proxy @Word))+    , testSmallAndQuick "Integer" (toEnumProperty (Proxy @Integer))+    , testSmallAndQuick "Natural" (toEnumProperty (Proxy @Natural))+    ]+  , testGroup "fromEnum"+    [ testSmallAndQuick "Int" (fromEnumProperty @Int)+    , testSmallAndQuick "Word" (fromEnumProperty @Word)+    , testSmallAndQuick "Integer" (fromEnumProperty @Integer)+    , testSmallAndQuick "Natural" (fromEnumProperty @Natural)+    ]+  , testGroup "succ"+    [ testSmallAndQuick "Int" (succProperty @Int)+    , testSmallAndQuick "Word" (succProperty @Word)+    , testSmallAndQuick "Integer" (succProperty @Integer)+    , testSmallAndQuick "Natural" (succProperty @Natural)+    ]+  , testGroup "pred"+    [ testSmallAndQuick "Int" (predProperty @Int)+    , testSmallAndQuick "Word" (predProperty @Word)+    , testSmallAndQuick "Integer" (predProperty @Integer)+    , testSmallAndQuick "Natural" (predProperty @Natural)+    ]+  , testGroup "enumFrom"+    [ testSmallAndQuick "Int" (enumFromProperty @Int)+    , testSmallAndQuick "Word" (enumFromProperty @Word)+    , testSmallAndQuick "Integer" (enumFromProperty @Integer)+    , testSmallAndQuick "Natural" (enumFromProperty @Natural)+    ]+  , testGroup "enumFromTo"+    [ testSmallAndQuick "Int" (enumFromToProperty @Int)+    , testSmallAndQuick "Word" (enumFromToProperty @Word)+    , testSmallAndQuick "Integer" (enumFromToProperty @Integer)+    , testSmallAndQuick "Natural" (enumFromToProperty @Natural)+    ]+  , testGroup "enumFromThen"+    [ testSmallAndQuick "Int" (enumFromThenProperty @Int)+    , testSmallAndQuick "Word" (enumFromThenProperty @Word)+    , testSmallAndQuick "Integer" (enumFromThenProperty @Integer)+    , testSmallAndQuick "Natural" (enumFromThenProperty @Natural)+    ]+  , testGroup "enumFromThenTo"+    [ testSmallAndQuick "Int" (enumFromThenToProperty @Int)+    , testSmallAndQuick "Word" (enumFromThenToProperty @Word)+    , testSmallAndQuick "Integer" (enumFromThenToProperty @Integer)+    , testSmallAndQuick "Natural" (enumFromThenToProperty @Natural)+    ]+  ]
test-suite/Math/NumberTheory/Primes/SieveTests.hs view
@@ -3,7 +3,6 @@ -- Copyright:   (c) 2016-2018 Andrew Lelechenko -- Licence:     MIT -- Maintainer:  Andrew Lelechenko <andrew.lelechenko@gmail.com>--- Stability:   Provisional -- -- Tests for Math.NumberTheory.Primes.Sieve --@@ -28,6 +27,7 @@ import Data.Word import Numeric.Natural (Natural) +import Math.NumberTheory.Primes (Prime, unPrime) import Math.NumberTheory.Primes.Sieve import Math.NumberTheory.Primes.Testing import Math.NumberTheory.TestUtils@@ -44,45 +44,45 @@ -- | Check that 'primes' matches 'isPrime'. primesProperty1 :: forall a. (Integral a, Show a) => Proxy a -> Assertion primesProperty1 _ = assertEqual "primes matches isPrime"-  (takeWhile (<= lim1) primes :: [a])+  (takeWhile (<= lim1) (map unPrime 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])+  (map unPrime 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+  == takeWhile ((<= (highBound `max` 7)) . unPrime) primes   where     highBound = highBound' `rem` lim1  -- | Check that 'primeList' from 'psieveList' matches 'primes'. psieveListProperty1 :: forall a. (Integral a, Show a) => Proxy a -> Assertion psieveListProperty1 _ = assertEqual "primes == primeList . psieveList"-  (take lim2 primes :: [a])+  (take lim2 primes :: [Prime a])   (take lim2 $ concatMap primeList psieveList)  psieveListProperty2 :: forall a. (Integral a, Show a) => Proxy a -> Assertion psieveListProperty2 _ = assertEqual "primes == primeList . psieveList"-  (primes :: [a])+  (primes :: [Prime 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))+  == take lim3 (filter ((>= lowBound) . unPrime) (concatMap primeList $ psieveFrom lowBound))   where     lowBound = lowBound' `rem` lim1  -- | Check that 'sieveFrom' matches 'isPrime' near 0. sieveFromProperty2 :: AnySign Integer -> Bool sieveFromProperty2 (AnySign lowBound')-  =  take lim3 (sieveFrom lowBound)+  =  take lim3 (map unPrime (sieveFrom lowBound))   == take lim3 (filter (isPrime . toInteger) [lowBound `max` 0 ..])   where     lowBound = lowBound' `rem` lim1
test-suite/Math/NumberTheory/Primes/TestingTests.hs view
@@ -3,7 +3,6 @@ -- Copyright:   (c) 2017 Andrew Lelechenko -- Licence:     MIT -- Maintainer:  Andrew Lelechenko <andrew.lelechenko@gmail.com>--- Stability:   Provisional -- -- Tests for Math.NumberTheory.Primes.Testing --
test-suite/Math/NumberTheory/PrimesTests.hs view
@@ -3,7 +3,6 @@ -- Copyright:   (c) 2016 Andrew Lelechenko -- Licence:     MIT -- Maintainer:  Andrew Lelechenko <andrew.lelechenko@gmail.com>--- Stability:   Provisional -- -- Tests for Math.NumberTheory.Primes --@@ -17,14 +16,15 @@  import Test.Tasty -import Math.NumberTheory.Primes+import Math.NumberTheory.Primes (unPrime)+import Math.NumberTheory.Primes.Sieve (primeSieve, primeList, primes) import Math.NumberTheory.TestUtils  primesSumWonk :: Int -> Int-primesSumWonk upto = sum . takeWhile (< upto) . map fromInteger . primeList $ primeSieve (toInteger upto)+primesSumWonk upto = sum . takeWhile (< upto) . map unPrime . primeList $ primeSieve (toInteger upto)  primesSum :: Int -> Int-primesSum upto = sum . takeWhile (< upto) . map fromInteger $ primes+primesSum upto = sum . takeWhile (< upto) . map unPrime $ primes  primesSumProperty :: NonNegative Int -> Bool primesSumProperty (NonNegative n) = primesSumWonk n == primesSum n
+ test-suite/Math/NumberTheory/Recurrences/BilinearTests.hs view
@@ -0,0 +1,233 @@+-- |+-- Module:      Math.NumberTheory.Recurrences.BilinearTests+-- Copyright:   (c) 2016 Andrew Lelechenko+-- Licence:     MIT+-- Maintainer:  Andrew Lelechenko <andrew.lelechenko@gmail.com>+--+-- Tests for Math.NumberTheory.Recurrences.Bilinear+--++{-# OPTIONS_GHC -fno-warn-type-defaults #-}++module Math.NumberTheory.Recurrences.BilinearTests+  ( testSuite+  ) where++import Test.Tasty+import Test.Tasty.HUnit++import Data.Ratio++import Math.NumberTheory.Recurrences.Bilinear (bernoulli, binomial, euler,+                                               eulerian1, eulerian2,+                                               eulerPolyAt1, lah, stirling1,+                                               stirling2)+import Math.NumberTheory.TestUtils++binomialProperty1 :: NonNegative Int -> Bool+binomialProperty1 (NonNegative i) = length (binomial !! i) == i + 1++binomialProperty2 :: NonNegative Int -> Bool+binomialProperty2 (NonNegative i) = binomial !! i !! 0 == 1++binomialProperty3 :: NonNegative Int -> Bool+binomialProperty3 (NonNegative i) = binomial !! i !! i == 1++binomialProperty4 :: Positive Int -> Positive Int -> Bool+binomialProperty4 (Positive i) (Positive j)+  =  j >= i+  || binomial !! i !! j+  == binomial !! (i - 1) !! (j - 1)+  +  binomial !! (i - 1) !! j++stirling1Property1 :: NonNegative Int -> Bool+stirling1Property1 (NonNegative i) = length (stirling1 !! i) == i + 1++stirling1Property2 :: NonNegative Int -> Bool+stirling1Property2 (NonNegative i)+  =  stirling1 !! i !! 0+  == if i == 0 then 1 else 0++stirling1Property3 :: NonNegative Int -> Bool+stirling1Property3 (NonNegative i) = stirling1 !! i !! i == 1++stirling1Property4 :: Positive Int -> Positive Int -> Bool+stirling1Property4 (Positive i) (Positive j)+  =  j >= i+  || stirling1 !! i !! j+  == stirling1 !! (i - 1) !! (j - 1)+  +  (toInteger i - 1) * stirling1 !! (i - 1) !! j++stirling2Property1 :: NonNegative Int -> Bool+stirling2Property1 (NonNegative i) = length (stirling2 !! i) == i + 1++stirling2Property2 :: NonNegative Int -> Bool+stirling2Property2 (NonNegative i)+  =  stirling2 !! i !! 0+  == if i == 0 then 1 else 0++stirling2Property3 :: NonNegative Int -> Bool+stirling2Property3 (NonNegative i) = stirling2 !! i !! i == 1++stirling2Property4 :: Positive Int -> Positive Int -> Bool+stirling2Property4 (Positive i) (Positive j)+  =  j >= i+  || stirling2 !! i !! j+  == stirling2 !! (i - 1) !! (j - 1)+  +  toInteger j * stirling2 !! (i - 1) !! j++lahProperty1 :: NonNegative Int -> Bool+lahProperty1 (NonNegative i) = length (lah !! i) == i + 1++lahProperty2 :: NonNegative Int -> Bool+lahProperty2 (NonNegative i)+  =  lah !! i !! 0+  == product [1 .. i+1]++lahProperty3 :: NonNegative Int -> Bool+lahProperty3 (NonNegative i) = lah !! i !! i == 1++lahProperty4 :: Positive Int -> Positive Int -> Bool+lahProperty4 (Positive i) (Positive j)+  =  j >= i+  || lah !! i !! j+  == sum [ stirling1 !! (i + 1) !! k * stirling2 !! k !! (j + 1) | k <- [j + 1 .. i + 1] ]++eulerian1Property1 :: NonNegative Int -> Bool+eulerian1Property1 (NonNegative i) = length (eulerian1 !! i) == i++eulerian1Property2 :: Positive Int -> Bool+eulerian1Property2 (Positive i) = eulerian1 !! i !! 0 == 1++eulerian1Property3 :: Positive Int -> Bool+eulerian1Property3 (Positive i) = eulerian1 !! i !! (i - 1) == 1++eulerian1Property4 :: Positive Int -> Positive Int -> Bool+eulerian1Property4 (Positive i) (Positive j)+  =  j >= i - 1+  || eulerian1 !! i !! j+  == (toInteger $ i - j) * eulerian1 !! (i - 1) !! (j - 1)+  +  (toInteger   j + 1) * eulerian1 !! (i - 1) !! j++eulerian2Property1 :: NonNegative Int -> Bool+eulerian2Property1 (NonNegative i) = length (eulerian2 !! i) == i++eulerian2Property2 :: Positive Int -> Bool+eulerian2Property2 (Positive i)+  =  eulerian2 !! i !! 0 == 1++eulerian2Property3 :: Positive Int -> Bool+eulerian2Property3 (Positive i)+  =  eulerian2 !! i !! (i - 1)+  == product [1 .. toInteger i]++eulerian2Property4 :: Positive Int -> Positive Int -> Bool+eulerian2Property4 (Positive i) (Positive j)+  =  j >= i - 1+  || eulerian2 !! i !! j+  == (toInteger $ 2 * i - j - 1) * eulerian2 !! (i - 1) !! (j - 1)+  +  (toInteger j + 1) * eulerian2 !! (i - 1) !! j++bernoulliSpecialCase1 :: Assertion+bernoulliSpecialCase1 = assertEqual "B_0 = 1" (bernoulli !! 0) 1++bernoulliSpecialCase2 :: Assertion+bernoulliSpecialCase2 = assertEqual "B_1 = -1/2" (bernoulli !! 1) (- 1 % 2)++bernoulliProperty1 :: NonNegative Int -> Bool+bernoulliProperty1 (NonNegative m)+  = case signum (bernoulli !! m) of+    1  -> m == 0 || m `mod` 4 == 2+    0  -> m /= 1 && odd m+    -1 -> m == 1 || (m /= 0 && m `mod` 4 == 0)+    _  -> False++bernoulliProperty2 :: NonNegative Int -> Bool+bernoulliProperty2 (NonNegative m)+  =  bernoulli !! m+  == (if m == 0 then 1 else 0)+  -  sum [ bernoulli !! k+         * (binomial !! m !! k % (toInteger $ m - k + 1))+         | 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"+    [ testSmallAndQuick "shape"      binomialProperty1+    , testSmallAndQuick "left side"  binomialProperty2+    , testSmallAndQuick "right side" binomialProperty3+    , testSmallAndQuick "recurrency" binomialProperty4+    ]+  , testGroup "stirling1"+    [ testSmallAndQuick "shape"      stirling1Property1+    , testSmallAndQuick "left side"  stirling1Property2+    , testSmallAndQuick "right side" stirling1Property3+    , testSmallAndQuick "recurrency" stirling1Property4+    ]+  , testGroup "stirling2"+    [ testSmallAndQuick "shape"      stirling2Property1+    , testSmallAndQuick "left side"  stirling2Property2+    , testSmallAndQuick "right side" stirling2Property3+    , testSmallAndQuick "recurrency" stirling2Property4+    ]+  , testGroup "lah"+    [ testSmallAndQuick "shape"         lahProperty1+    , testSmallAndQuick "left side"     lahProperty2+    , testSmallAndQuick "right side"    lahProperty3+    , testSmallAndQuick "zip stirlings" lahProperty4+    ]+  , testGroup "eulerian1"+    [ testSmallAndQuick "shape"      eulerian1Property1+    , testSmallAndQuick "left side"  eulerian1Property2+    , testSmallAndQuick "right side" eulerian1Property3+    , testSmallAndQuick "recurrency" eulerian1Property4+    ]+  , testGroup "eulerian2"+    [ testSmallAndQuick "shape"      eulerian2Property1+    , testSmallAndQuick "left side"  eulerian2Property2+    , testSmallAndQuick "right side" eulerian2Property3+    , testSmallAndQuick "recurrency" eulerian2Property4+    ]+  , testGroup "bernoulli"+    [ testCase "B_0"                           bernoulliSpecialCase1+    , 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/Recurrences/LinearTests.hs view
@@ -0,0 +1,103 @@+-- |+-- Module:      Math.NumberTheory.Recurrences.LinearTests+-- Copyright:   (c) 2016 Andrew Lelechenko+-- Licence:     MIT+-- Maintainer:  Andrew Lelechenko <andrew.lelechenko@gmail.com>+--+-- Tests for Math.NumberTheory.Recurrences.Linear+--++{-# LANGUAGE CPP       #-}++{-# OPTIONS_GHC -fno-warn-type-defaults #-}++module Math.NumberTheory.Recurrences.LinearTests+  ( testSuite+  ) where++import Test.Tasty+import Test.Tasty.HUnit++import Math.NumberTheory.Recurrences.Linear+import Math.NumberTheory.TestUtils++-- | Check that 'fibonacci' matches the definition of Fibonacci sequence.+fibonacciProperty1 :: AnySign Int -> Bool+fibonacciProperty1 (AnySign n) = fibonacci n + fibonacci (n + 1) == fibonacci (n +2)++-- | Check that 'fibonacci' for negative indices is correctly defined.+fibonacciProperty2 :: NonNegative Int -> Bool+fibonacciProperty2 (NonNegative n) = fibonacci n == (if even n then negate else id) (fibonacci (- n))++-- | Check that 'fibonacciPair' is a pair of consequent 'fibonacci'.+fibonacciPairProperty :: AnySign Int -> Bool+fibonacciPairProperty (AnySign n) = fibonacciPair n == (fibonacci n, fibonacci (n + 1))++-- | Check that 'fibonacci 0' is 0.+fibonacciSpecialCase0 :: Assertion+fibonacciSpecialCase0 = assertEqual "fibonacci" (fibonacci 0) 0++-- | Check that 'fibonacci 1' is 1.+fibonacciSpecialCase1 :: Assertion+fibonacciSpecialCase1 = assertEqual "fibonacci" (fibonacci 1) 1+++-- | Check that 'lucas' matches the definition of Lucas sequence.+lucasProperty1 :: AnySign Int -> Bool+lucasProperty1 (AnySign n) = lucas n + lucas (n + 1) == lucas (n +2)++-- | Check that 'lucas' for negative indices is correctly defined.+lucasProperty2 :: NonNegative Int -> Bool+lucasProperty2 (NonNegative n) = lucas n == (if odd n then negate else id) (lucas (- n))++-- | Check that 'lucasPair' is a pair of consequent 'lucas'.+lucasPairProperty :: AnySign Int -> Bool+lucasPairProperty (AnySign n) = lucasPair n == (lucas n, lucas (n + 1))++-- | Check that 'lucas 0' is 2.+lucasSpecialCase0 :: Assertion+lucasSpecialCase0 = assertEqual "lucas" (lucas 0) 2++-- | Check that 'lucas 1' is 1.+lucasSpecialCase1 :: Assertion+lucasSpecialCase1 = assertEqual "lucas" (lucas 1) 1++-- | Check that 'generalLucas' matches its definition.+generalLucasProperty1 :: AnySign Integer -> AnySign Integer -> NonNegative Int -> Bool+generalLucasProperty1 (AnySign p) (AnySign q) (NonNegative n) = un1 == un1' && vn1 == vn1' && un2 == p * un1 - q * un && vn2 == p * vn1 - q * vn+  where+    (un, un1, vn, vn1) = generalLucas p q n+    (un1', un2, vn1', vn2) = generalLucas p q (n + 1)++-- | Check that 'generalLucas' 1 (-1) is 'fibonacciPair' plus 'lucasPair'.+generalLucasProperty2 :: NonNegative Int -> Bool+generalLucasProperty2 (NonNegative n) = (un, un1) == fibonacciPair n && (vn, vn1) == lucasPair n+  where+    (un, un1, vn, vn1) = generalLucas 1 (-1) n++-- | Check that 'generalLucas' p _ 0 is (0, 1, 2, p).+generalLucasProperty3 :: AnySign Integer -> AnySign Integer -> Bool+generalLucasProperty3 (AnySign p) (AnySign q) = generalLucas p q 0 == (0, 1, 2, p)++testSuite :: TestTree+testSuite = testGroup "Linear"+  [ testGroup "fibonacci"+    [ testSmallAndQuick "matches definition"  fibonacciProperty1+    , testSmallAndQuick "negative indices"    fibonacciProperty2+    , testSmallAndQuick "pair"                fibonacciPairProperty+    , testCase          "fibonacci 0"         fibonacciSpecialCase0+    , testCase          "fibonacci 1"         fibonacciSpecialCase1+    ]+  , testGroup "lucas"+    [ testSmallAndQuick "matches definition"  lucasProperty1+    , testSmallAndQuick "negative indices"    lucasProperty2+    , testSmallAndQuick "pair"                lucasPairProperty+    , testCase          "lucas 0"             lucasSpecialCase0+    , testCase          "lucas 1"             lucasSpecialCase1+    ]+  , testGroup "generalLucas"+    [ testSmallAndQuick "matches definition"  generalLucasProperty1+    , testSmallAndQuick "generalLucas 1 (-1)" generalLucasProperty2+    , testSmallAndQuick "generalLucas _ _ 0"  generalLucasProperty3+    ]+  ]
+ test-suite/Math/NumberTheory/Recurrences/PentagonalTests.hs view
@@ -0,0 +1,103 @@+-- |+-- Module:      Math.NumberTheory.Recurrences.PentagonalTests+-- Copyright:   (c) 2018 Alexandre Rodrigues Baldé+-- Licence:     MIT+-- Maintainer:  Alexandre Rodrigues Baldé <alexandrer_b@outlook.com>+--+-- Tests for Math.NumberTheory.Recurrences.Pentagonal+--++{-# LANGUAGE CPP                 #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE ViewPatterns        #-}++{-# OPTIONS_GHC -fno-warn-type-defaults #-}++module Math.NumberTheory.Recurrences.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.Recurrences (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.Recurrences.Pentagonal@ to test the+-- reference implementation of @partition@.+pentagonalSigns :: Num a => [a] -> [a]+pentagonalSigns = zipWith (*) (cycle [1, 1, -1, -1])++-- | Copied from @Math.NumberTheory.Recurrences.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/Recurrencies/BilinearTests.hs
@@ -1,234 +0,0 @@--- |--- Module:      Math.NumberTheory.Recurrencies.BilinearTests--- Copyright:   (c) 2016 Andrew Lelechenko--- Licence:     MIT--- Maintainer:  Andrew Lelechenko <andrew.lelechenko@gmail.com>--- Stability:   Provisional------ Tests for Math.NumberTheory.Recurrencies.Bilinear-----{-# OPTIONS_GHC -fno-warn-type-defaults #-}--module Math.NumberTheory.Recurrencies.BilinearTests-  ( testSuite-  ) where--import Test.Tasty-import Test.Tasty.HUnit--import Data.Ratio--import Math.NumberTheory.Recurrencies.Bilinear (bernoulli, binomial, euler,-                                                eulerian1, eulerian2,-                                                eulerPolyAt1, lah, stirling1,-                                                stirling2)-import Math.NumberTheory.TestUtils--binomialProperty1 :: NonNegative Int -> Bool-binomialProperty1 (NonNegative i) = length (binomial !! i) == i + 1--binomialProperty2 :: NonNegative Int -> Bool-binomialProperty2 (NonNegative i) = binomial !! i !! 0 == 1--binomialProperty3 :: NonNegative Int -> Bool-binomialProperty3 (NonNegative i) = binomial !! i !! i == 1--binomialProperty4 :: Positive Int -> Positive Int -> Bool-binomialProperty4 (Positive i) (Positive j)-  =  j >= i-  || binomial !! i !! j-  == binomial !! (i - 1) !! (j - 1)-  +  binomial !! (i - 1) !! j--stirling1Property1 :: NonNegative Int -> Bool-stirling1Property1 (NonNegative i) = length (stirling1 !! i) == i + 1--stirling1Property2 :: NonNegative Int -> Bool-stirling1Property2 (NonNegative i)-  =  stirling1 !! i !! 0-  == if i == 0 then 1 else 0--stirling1Property3 :: NonNegative Int -> Bool-stirling1Property3 (NonNegative i) = stirling1 !! i !! i == 1--stirling1Property4 :: Positive Int -> Positive Int -> Bool-stirling1Property4 (Positive i) (Positive j)-  =  j >= i-  || stirling1 !! i !! j-  == stirling1 !! (i - 1) !! (j - 1)-  +  (toInteger i - 1) * stirling1 !! (i - 1) !! j--stirling2Property1 :: NonNegative Int -> Bool-stirling2Property1 (NonNegative i) = length (stirling2 !! i) == i + 1--stirling2Property2 :: NonNegative Int -> Bool-stirling2Property2 (NonNegative i)-  =  stirling2 !! i !! 0-  == if i == 0 then 1 else 0--stirling2Property3 :: NonNegative Int -> Bool-stirling2Property3 (NonNegative i) = stirling2 !! i !! i == 1--stirling2Property4 :: Positive Int -> Positive Int -> Bool-stirling2Property4 (Positive i) (Positive j)-  =  j >= i-  || stirling2 !! i !! j-  == stirling2 !! (i - 1) !! (j - 1)-  +  toInteger j * stirling2 !! (i - 1) !! j--lahProperty1 :: NonNegative Int -> Bool-lahProperty1 (NonNegative i) = length (lah !! i) == i + 1--lahProperty2 :: NonNegative Int -> Bool-lahProperty2 (NonNegative i)-  =  lah !! i !! 0-  == product [1 .. i+1]--lahProperty3 :: NonNegative Int -> Bool-lahProperty3 (NonNegative i) = lah !! i !! i == 1--lahProperty4 :: Positive Int -> Positive Int -> Bool-lahProperty4 (Positive i) (Positive j)-  =  j >= i-  || lah !! i !! j-  == sum [ stirling1 !! (i + 1) !! k * stirling2 !! k !! (j + 1) | k <- [j + 1 .. i + 1] ]--eulerian1Property1 :: NonNegative Int -> Bool-eulerian1Property1 (NonNegative i) = length (eulerian1 !! i) == i--eulerian1Property2 :: Positive Int -> Bool-eulerian1Property2 (Positive i) = eulerian1 !! i !! 0 == 1--eulerian1Property3 :: Positive Int -> Bool-eulerian1Property3 (Positive i) = eulerian1 !! i !! (i - 1) == 1--eulerian1Property4 :: Positive Int -> Positive Int -> Bool-eulerian1Property4 (Positive i) (Positive j)-  =  j >= i - 1-  || eulerian1 !! i !! j-  == (toInteger $ i - j) * eulerian1 !! (i - 1) !! (j - 1)-  +  (toInteger   j + 1) * eulerian1 !! (i - 1) !! j--eulerian2Property1 :: NonNegative Int -> Bool-eulerian2Property1 (NonNegative i) = length (eulerian2 !! i) == i--eulerian2Property2 :: Positive Int -> Bool-eulerian2Property2 (Positive i)-  =  eulerian2 !! i !! 0 == 1--eulerian2Property3 :: Positive Int -> Bool-eulerian2Property3 (Positive i)-  =  eulerian2 !! i !! (i - 1)-  == product [1 .. toInteger i]--eulerian2Property4 :: Positive Int -> Positive Int -> Bool-eulerian2Property4 (Positive i) (Positive j)-  =  j >= i - 1-  || eulerian2 !! i !! j-  == (toInteger $ 2 * i - j - 1) * eulerian2 !! (i - 1) !! (j - 1)-  +  (toInteger j + 1) * eulerian2 !! (i - 1) !! j--bernoulliSpecialCase1 :: Assertion-bernoulliSpecialCase1 = assertEqual "B_0 = 1" (bernoulli !! 0) 1--bernoulliSpecialCase2 :: Assertion-bernoulliSpecialCase2 = assertEqual "B_1 = -1/2" (bernoulli !! 1) (- 1 % 2)--bernoulliProperty1 :: NonNegative Int -> Bool-bernoulliProperty1 (NonNegative m)-  = case signum (bernoulli !! m) of-    1  -> m == 0 || m `mod` 4 == 2-    0  -> m /= 1 && odd m-    -1 -> m == 1 || (m /= 0 && m `mod` 4 == 0)-    _  -> False--bernoulliProperty2 :: NonNegative Int -> Bool-bernoulliProperty2 (NonNegative m)-  =  bernoulli !! m-  == (if m == 0 then 1 else 0)-  -  sum [ bernoulli !! k-         * (binomial !! m !! k % (toInteger $ m - k + 1))-         | 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"-    [ testSmallAndQuick "shape"      binomialProperty1-    , testSmallAndQuick "left side"  binomialProperty2-    , testSmallAndQuick "right side" binomialProperty3-    , testSmallAndQuick "recurrency" binomialProperty4-    ]-  , testGroup "stirling1"-    [ testSmallAndQuick "shape"      stirling1Property1-    , testSmallAndQuick "left side"  stirling1Property2-    , testSmallAndQuick "right side" stirling1Property3-    , testSmallAndQuick "recurrency" stirling1Property4-    ]-  , testGroup "stirling2"-    [ testSmallAndQuick "shape"      stirling2Property1-    , testSmallAndQuick "left side"  stirling2Property2-    , testSmallAndQuick "right side" stirling2Property3-    , testSmallAndQuick "recurrency" stirling2Property4-    ]-  , testGroup "lah"-    [ testSmallAndQuick "shape"         lahProperty1-    , testSmallAndQuick "left side"     lahProperty2-    , testSmallAndQuick "right side"    lahProperty3-    , testSmallAndQuick "zip stirlings" lahProperty4-    ]-  , testGroup "eulerian1"-    [ testSmallAndQuick "shape"      eulerian1Property1-    , testSmallAndQuick "left side"  eulerian1Property2-    , testSmallAndQuick "right side" eulerian1Property3-    , testSmallAndQuick "recurrency" eulerian1Property4-    ]-  , testGroup "eulerian2"-    [ testSmallAndQuick "shape"      eulerian2Property1-    , testSmallAndQuick "left side"  eulerian2Property2-    , testSmallAndQuick "right side" eulerian2Property3-    , testSmallAndQuick "recurrency" eulerian2Property4-    ]-  , testGroup "bernoulli"-    [ testCase "B_0"                           bernoulliSpecialCase1-    , 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/LinearTests.hs
@@ -1,104 +0,0 @@--- |--- Module:      Math.NumberTheory.Recurrencies.LinearTests--- Copyright:   (c) 2016 Andrew Lelechenko--- Licence:     MIT--- Maintainer:  Andrew Lelechenko <andrew.lelechenko@gmail.com>--- Stability:   Provisional------ Tests for Math.NumberTheory.Recurrencies.Linear-----{-# LANGUAGE CPP       #-}--{-# OPTIONS_GHC -fno-warn-type-defaults #-}--module Math.NumberTheory.Recurrencies.LinearTests-  ( testSuite-  ) where--import Test.Tasty-import Test.Tasty.HUnit--import Math.NumberTheory.Recurrencies.Linear-import Math.NumberTheory.TestUtils---- | Check that 'fibonacci' matches the definition of Fibonacci sequence.-fibonacciProperty1 :: AnySign Int -> Bool-fibonacciProperty1 (AnySign n) = fibonacci n + fibonacci (n + 1) == fibonacci (n +2)---- | Check that 'fibonacci' for negative indices is correctly defined.-fibonacciProperty2 :: NonNegative Int -> Bool-fibonacciProperty2 (NonNegative n) = fibonacci n == (if even n then negate else id) (fibonacci (- n))---- | Check that 'fibonacciPair' is a pair of consequent 'fibonacci'.-fibonacciPairProperty :: AnySign Int -> Bool-fibonacciPairProperty (AnySign n) = fibonacciPair n == (fibonacci n, fibonacci (n + 1))---- | Check that 'fibonacci 0' is 0.-fibonacciSpecialCase0 :: Assertion-fibonacciSpecialCase0 = assertEqual "fibonacci" (fibonacci 0) 0---- | Check that 'fibonacci 1' is 1.-fibonacciSpecialCase1 :: Assertion-fibonacciSpecialCase1 = assertEqual "fibonacci" (fibonacci 1) 1----- | Check that 'lucas' matches the definition of Lucas sequence.-lucasProperty1 :: AnySign Int -> Bool-lucasProperty1 (AnySign n) = lucas n + lucas (n + 1) == lucas (n +2)---- | Check that 'lucas' for negative indices is correctly defined.-lucasProperty2 :: NonNegative Int -> Bool-lucasProperty2 (NonNegative n) = lucas n == (if odd n then negate else id) (lucas (- n))---- | Check that 'lucasPair' is a pair of consequent 'lucas'.-lucasPairProperty :: AnySign Int -> Bool-lucasPairProperty (AnySign n) = lucasPair n == (lucas n, lucas (n + 1))---- | Check that 'lucas 0' is 2.-lucasSpecialCase0 :: Assertion-lucasSpecialCase0 = assertEqual "lucas" (lucas 0) 2---- | Check that 'lucas 1' is 1.-lucasSpecialCase1 :: Assertion-lucasSpecialCase1 = assertEqual "lucas" (lucas 1) 1---- | Check that 'generalLucas' matches its definition.-generalLucasProperty1 :: AnySign Integer -> AnySign Integer -> NonNegative Int -> Bool-generalLucasProperty1 (AnySign p) (AnySign q) (NonNegative n) = un1 == un1' && vn1 == vn1' && un2 == p * un1 - q * un && vn2 == p * vn1 - q * vn-  where-    (un, un1, vn, vn1) = generalLucas p q n-    (un1', un2, vn1', vn2) = generalLucas p q (n + 1)---- | Check that 'generalLucas' 1 (-1) is 'fibonacciPair' plus 'lucasPair'.-generalLucasProperty2 :: NonNegative Int -> Bool-generalLucasProperty2 (NonNegative n) = (un, un1) == fibonacciPair n && (vn, vn1) == lucasPair n-  where-    (un, un1, vn, vn1) = generalLucas 1 (-1) n---- | Check that 'generalLucas' p _ 0 is (0, 1, 2, p).-generalLucasProperty3 :: AnySign Integer -> AnySign Integer -> Bool-generalLucasProperty3 (AnySign p) (AnySign q) = generalLucas p q 0 == (0, 1, 2, p)--testSuite :: TestTree-testSuite = testGroup "Linear"-  [ testGroup "fibonacci"-    [ testSmallAndQuick "matches definition"  fibonacciProperty1-    , testSmallAndQuick "negative indices"    fibonacciProperty2-    , testSmallAndQuick "pair"                fibonacciPairProperty-    , testCase          "fibonacci 0"         fibonacciSpecialCase0-    , testCase          "fibonacci 1"         fibonacciSpecialCase1-    ]-  , testGroup "lucas"-    [ testSmallAndQuick "matches definition"  lucasProperty1-    , testSmallAndQuick "negative indices"    lucasProperty2-    , testSmallAndQuick "pair"                lucasPairProperty-    , testCase          "lucas 0"             lucasSpecialCase0-    , testCase          "lucas 1"             lucasSpecialCase1-    ]-  , testGroup "generalLucas"-    [ testSmallAndQuick "matches definition"  generalLucasProperty1-    , testSmallAndQuick "generalLucas 1 (-1)" generalLucasProperty2-    , testSmallAndQuick "generalLucas _ _ 0"  generalLucasProperty3-    ]-  ]
− test-suite/Math/NumberTheory/Recurrencies/PentagonalTests.hs
@@ -1,105 +0,0 @@--- |--- 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
@@ -3,7 +3,6 @@ -- Copyright:   (c) 2018 Andrew Lelechenko -- Licence:     MIT -- Maintainer:  Andrew Lelechenko <andrew.lelechenko@gmail.com>--- Stability:   Provisional -- -- Tests for Math.NumberTheory.SmoothNumbersTests --@@ -16,19 +15,38 @@  import Prelude hiding (mod) import Test.Tasty+import Test.Tasty.HUnit  import Data.Coerce-import Data.List (genericDrop, sort)+import Data.List (genericDrop, nub, sort)+import Data.Maybe (fromJust) import qualified Data.Set as S import Numeric.Natural -import Math.NumberTheory.Euclidean+import Math.NumberTheory.Euclidean (Euclidean (..), WrappedIntegral (..))+import Math.NumberTheory.Primes (Prime (..))+import qualified Math.NumberTheory.Quadratic.GaussianIntegers as G+import qualified Math.NumberTheory.Quadratic.EisensteinIntegers as E import Math.NumberTheory.SmoothNumbers import Math.NumberTheory.TestUtils  fromSetListProperty :: (Euclidean a, Ord a) => [a] -> Bool fromSetListProperty xs = fromSet (S.fromList xs) == fromList (sort xs) +isSmoothPropertyHelper :: Euclidean a => (a -> Integer) -> [a] -> Int -> Int -> Bool+isSmoothPropertyHelper norm primes' i1 i2 =+    let primes = take i1 primes'+        basis  = fromJust (fromList primes)+    in all (isSmooth basis) $ take i2 $ smoothOver' norm basis++isSmoothProperty1 :: Positive Int -> Positive Int -> Bool+isSmoothProperty1 (Positive i1) (Positive i2) =+    isSmoothPropertyHelper G.norm (map unPrime G.primes) i1 i2++isSmoothProperty2 :: Positive Int -> Positive Int -> Bool+isSmoothProperty2 (Positive i1) (Positive i2) =+    isSmoothPropertyHelper E.norm (map unPrime E.primes) i1 i2+ fromSmoothUpperBoundProperty :: Integral a => Positive a -> Bool fromSmoothUpperBoundProperty (Positive n') = case fromSmoothUpperBound n of     Nothing -> n < 2@@ -46,6 +64,19 @@     xs   = smoothOverInRange   (coerce s) lo hi     ys   = smoothOverInRangeBF (coerce s) lo hi +smoothNumbersAreUniqueProperty :: Integral a => SmoothBasis a -> Positive Int -> Bool+smoothNumbersAreUniqueProperty s (Positive len)+  = nub l == l+  where+    l = take len $ smoothOver s++isSmoothSpecialCase1 :: Assertion+isSmoothSpecialCase1 = assertBool "should be distinct" $ nub l == l+  where+    b = fromJust $ fromList [1+3*G.ι,6+8*G.ι]+    l = take 10 $ map abs $ smoothOver' G.norm b++ testSuite :: TestTree testSuite = testGroup "SmoothNumbers"   [ testGroup "fromSet == fromList"@@ -64,5 +95,19 @@       (smoothOverInRangeProperty :: SmoothBasis Integer -> Positive Integer -> Positive Integer -> Bool)     , testSmallAndQuick "Natural"       (smoothOverInRangeProperty :: SmoothBasis Natural -> Positive Natural -> Positive Natural -> Bool)+    ]+  , testGroup "smoothOver generates a list without duplicates"+    [ testSmallAndQuick "Integer"+      (smoothNumbersAreUniqueProperty :: SmoothBasis Integer -> Positive Int -> Bool)+    , testSmallAndQuick "Natural"+      (smoothNumbersAreUniqueProperty :: SmoothBasis Natural -> Positive Int -> Bool)+    ]+  , testGroup "Quadratic rings (Gaussian/Eisenstein)"+    [ testGroup "Check that a list of smooth numbers generated by `smoothOver` \+                \ only contains valid smooth numbers for the generated basis."+      [ testSmallAndQuick "Gaussian" isSmoothProperty1+      , testSmallAndQuick "Eisenstein" isSmoothProperty2+      ]+    , testCase "all distinct for base [1+3*i,6+8*i]" isSmoothSpecialCase1     ]   ]
test-suite/Math/NumberTheory/TestUtils.hs view
@@ -3,8 +3,6 @@ -- Copyright:   (c) 2016 Andrew Lelechenko -- Licence:     MIT -- Maintainer:  Andrew Lelechenko <andrew.lelechenko@gmail.com>--- Stability:   Provisional--- Portability: Non-portable (GHC extensions) -- -- Utils to test Math.NumberTheory --@@ -21,12 +19,9 @@ {-# LANGUAGE TypeFamilies               #-} {-# LANGUAGE TypeOperators              #-} {-# LANGUAGE UndecidableInstances       #-}--#if __GLASGOW_HASKELL__ >= 800 {-# LANGUAGE UndecidableSuperClasses    #-}  {-# OPTIONS_GHC -fconstraint-solver-iterations=0 #-}-#endif  {-# OPTIONS_GHC -fno-warn-orphans #-} {-# OPTIONS_GHC -fno-warn-type-defaults #-}@@ -38,7 +33,9 @@   , Large(..)   , NonZero(..)   , testIntegralProperty+  , testIntegralPropertyNoLarge   , testSameIntegralProperty+  , testSameIntegralProperty3   , testIntegral2Property   , testSmallAndQuick @@ -55,6 +52,7 @@ import Test.SmallCheck.Series (Positive(..), NonNegative(..), Serial(..), Series, generate, (\/))  import Data.Bits+import Data.Semiring (Semiring) import GHC.Exts import Numeric.Natural @@ -62,8 +60,8 @@ import qualified Math.NumberTheory.Quadratic.EisensteinIntegers as E (EisensteinInteger(..)) import Math.NumberTheory.Quadratic.GaussianIntegers (GaussianInteger(..)) import Math.NumberTheory.Moduli.PrimitiveRoot (CyclicGroup(..))+import Math.NumberTheory.Primes (UniqueFactorisation, Prime, unPrime) import qualified Math.NumberTheory.SmoothNumbers as SN-import Math.NumberTheory.UniqueFactorisation (UniqueFactorisation, Prime, unPrime)  import Math.NumberTheory.TestUtils.MyCompose import Math.NumberTheory.TestUtils.Wrappers@@ -94,10 +92,10 @@     [ (1, pure CG2)     , (1, pure CG4)     , (9, CGOddPrimePower-      <$> (arbitrary :: Gen (PrimeWrapper a)) `suchThatMap` isOddPrime+      <$> (arbitrary :: Gen (Prime a)) `suchThatMap` isOddPrime       <*> (getPower <$> arbitrary))     , (9, CGDoubleOddPrimePower-      <$> (arbitrary :: Gen (PrimeWrapper a)) `suchThatMap` isOddPrime+      <$> (arbitrary :: Gen (Prime a)) `suchThatMap` isOddPrime       <*> (getPower <$> arbitrary))     ] @@ -105,17 +103,17 @@   series = pure CG2         \/ pure CG4         \/ (CGOddPrimePower-           <$> (series :: Series m (PrimeWrapper a)) `suchThatMapSerial` isOddPrime+           <$> (series :: Series m (Prime a)) `suchThatMapSerial` isOddPrime            <*> (getPower <$> series))         \/ (CGDoubleOddPrimePower-           <$> (series :: Series m (PrimeWrapper a)) `suchThatMapSerial` isOddPrime+           <$> (series :: Series m (Prime a)) `suchThatMapSerial` isOddPrime            <*> (getPower <$> series))  isOddPrime   :: forall a. (Eq a, Num a, UniqueFactorisation a)-  => PrimeWrapper a+  => Prime a   -> Maybe (Prime a)-isOddPrime (PrimeWrapper p) = if (unPrime p :: a) == 2 then Nothing else Just p+isOddPrime p = if (unPrime p :: a) == 2 then Nothing else Just p  ------------------------------------------------------------------------------- -- SmoothNumbers@@ -144,44 +142,82 @@     Matrix (a ': as) w bs = (ConcatMap (a `Compose` w) bs, Matrix as w bs)  type TestableIntegral wrapper =-  ( Matrix '[Arbitrary, Show, Serial IO] wrapper '[Int, Word, Integer]-  , Matrix '[Arbitrary, Show] wrapper '[Large Int, Large Word, Huge Integer]+  ( Matrix '[Arbitrary, Show, Serial IO] wrapper '[Int, Word, Integer, Natural]+  , Matrix '[Arbitrary, Show] wrapper '[Large Int, Large Word, Huge Integer, Huge Natural]   , Matrix '[Bounded, Integral] wrapper '[Int, Word]   , Num (wrapper Integer)+  , Num (wrapper Natural)   , Functor wrapper   ) - testIntegralProperty   :: forall wrapper bool. (TestableIntegral wrapper, SC.Testable IO bool, QC.Testable bool)-  => String -> (forall a. (Euclidean a, Integral a, Bits a, UniqueFactorisation a, Show a) => wrapper a -> bool) -> TestTree+  => String -> (forall a. (Euclidean a, Semiring 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)   , SC.testProperty "smallcheck Integer" (f :: wrapper Integer -> bool)+  , SC.testProperty "smallcheck Natural" (f :: wrapper Natural -> bool)   , QC.testProperty "quickcheck Int"     (f :: wrapper Int     -> bool)   , QC.testProperty "quickcheck Word"    (f :: wrapper Word    -> bool)   , QC.testProperty "quickcheck Integer" (f :: wrapper Integer -> bool)+  , QC.testProperty "quickcheck Natural" (f :: wrapper Natural -> bool)   , QC.testProperty "quickcheck Large Int"     ((f :: wrapper Int     -> bool) . getLarge)   , QC.testProperty "quickcheck Large Word"    ((f :: wrapper Word    -> bool) . getLarge)   , QC.testProperty "quickcheck Huge  Integer" ((f :: wrapper Integer -> bool) . getHuge)+  , QC.testProperty "quickcheck Huge  Natural" ((f :: wrapper Natural -> bool) . getHuge)   ] +testIntegralPropertyNoLarge+  :: forall wrapper bool. (TestableIntegral wrapper, SC.Testable IO bool, QC.Testable bool)+  => String -> (forall a. (Euclidean a, Semiring a, Integral a, Bits a, UniqueFactorisation a, Show a) => wrapper a -> bool) -> TestTree+testIntegralPropertyNoLarge name f = testGroup name+  [ SC.testProperty "smallcheck Int"     (f :: wrapper Int     -> bool)+  , SC.testProperty "smallcheck Word"    (f :: wrapper Word    -> bool)+  , SC.testProperty "smallcheck Integer" (f :: wrapper Integer -> bool)+  , SC.testProperty "smallcheck Natural" (f :: wrapper Natural -> bool)+  , QC.testProperty "quickcheck Int"     (f :: wrapper Int     -> bool)+  , QC.testProperty "quickcheck Word"    (f :: wrapper Word    -> bool)+  , QC.testProperty "quickcheck Integer" (f :: wrapper Integer -> bool)+  , QC.testProperty "quickcheck Natural" (f :: wrapper Natural -> bool)+  ]+ testSameIntegralProperty   :: forall wrapper1 wrapper2 bool. (TestableIntegral wrapper1, TestableIntegral wrapper2, SC.Testable IO bool, QC.Testable bool)-  => String -> (forall a. (Integral a, Bits a, UniqueFactorisation a, Show a) => wrapper1 a -> wrapper2 a -> bool) -> TestTree+  => String -> (forall a. (Euclidean a, Integral a, Bits a, UniqueFactorisation a, Show a) => wrapper1 a -> wrapper2 a -> bool) -> TestTree testSameIntegralProperty name f = testGroup name   [ SC.testProperty "smallcheck Int"     (f :: wrapper1 Int     -> wrapper2 Int     -> bool)   , SC.testProperty "smallcheck Word"    (f :: wrapper1 Word    -> wrapper2 Word    -> bool)   , SC.testProperty "smallcheck Integer" (f :: wrapper1 Integer -> wrapper2 Integer -> bool)+  , SC.testProperty "smallcheck Natural" (f :: wrapper1 Natural -> wrapper2 Natural -> bool)   , QC.testProperty "quickcheck Int"     (f :: wrapper1 Int     -> wrapper2 Int     -> bool)   , QC.testProperty "quickcheck Word"    (f :: wrapper1 Word    -> wrapper2 Word    -> bool)   , QC.testProperty "quickcheck Integer" (f :: wrapper1 Integer -> wrapper2 Integer -> bool)+  , QC.testProperty "quickcheck Natural" (f :: wrapper1 Natural -> wrapper2 Natural -> bool)   , QC.testProperty "quickcheck Large Int"     (\a b -> (f :: wrapper1 Int     -> wrapper2 Int     -> bool) (getLarge <$> a) (getLarge <$> b))   , QC.testProperty "quickcheck Large Word"    (\a b -> (f :: wrapper1 Word    -> wrapper2 Word    -> bool) (getLarge <$> a) (getLarge <$> b))   , QC.testProperty "quickcheck Huge  Integer" (\a b -> (f :: wrapper1 Integer -> wrapper2 Integer -> bool) (getHuge  <$> a) (getHuge  <$> b))+  , QC.testProperty "quickcheck Huge  Natural" (\a b -> (f :: wrapper1 Natural -> wrapper2 Natural -> bool) (getHuge  <$> a) (getHuge  <$> b))   ] +testSameIntegralProperty3+  :: forall wrapper1 wrapper2 wrapper3 bool. (TestableIntegral wrapper1, TestableIntegral wrapper2, TestableIntegral wrapper3, SC.Testable IO bool, QC.Testable bool)+  => String -> (forall a. (Euclidean a, Integral a, Bits a, UniqueFactorisation a, Show a) => wrapper1 a -> wrapper2 a -> wrapper3 a -> bool) -> TestTree+testSameIntegralProperty3 name f = testGroup name+  [ SC.testProperty "smallcheck Int"     (f :: wrapper1 Int     -> wrapper2 Int     -> wrapper3 Int     -> bool)+  , SC.testProperty "smallcheck Word"    (f :: wrapper1 Word    -> wrapper2 Word    -> wrapper3 Word    -> bool)+  , SC.testProperty "smallcheck Integer" (f :: wrapper1 Integer -> wrapper2 Integer -> wrapper3 Integer -> bool)+  , SC.testProperty "smallcheck Natural" (f :: wrapper1 Natural -> wrapper2 Natural -> wrapper3 Natural -> bool)+  , QC.testProperty "quickcheck Int"     (f :: wrapper1 Int     -> wrapper2 Int     -> wrapper3 Int     -> bool)+  , QC.testProperty "quickcheck Word"    (f :: wrapper1 Word    -> wrapper2 Word    -> wrapper3 Word    -> bool)+  , QC.testProperty "quickcheck Integer" (f :: wrapper1 Integer -> wrapper2 Integer -> wrapper3 Integer -> bool)+  , QC.testProperty "quickcheck Natural" (f :: wrapper1 Natural -> wrapper2 Natural -> wrapper3 Natural -> bool)+  , QC.testProperty "quickcheck Large Int"     (\a b c -> (f :: wrapper1 Int     -> wrapper2 Int     -> wrapper3 Int     -> bool) (getLarge <$> a) (getLarge <$> b) (getLarge <$> c))+  , QC.testProperty "quickcheck Large Word"    (\a b c -> (f :: wrapper1 Word    -> wrapper2 Word    -> wrapper3 Word    -> bool) (getLarge <$> a) (getLarge <$> b) (getLarge <$> c))+  , QC.testProperty "quickcheck Huge  Integer" (\a b c -> (f :: wrapper1 Integer -> wrapper2 Integer -> wrapper3 Integer -> bool) (getHuge  <$> a) (getHuge  <$> b) (getHuge  <$> c))+  , QC.testProperty "quickcheck Huge  Natural" (\a b c -> (f :: wrapper1 Natural -> wrapper2 Natural -> wrapper3 Natural -> bool) (getHuge  <$> a) (getHuge  <$> b) (getHuge  <$> c))+  ]+ testIntegral2Property   :: forall wrapper1 wrapper2 bool. (TestableIntegral wrapper1, TestableIntegral wrapper2, SC.Testable IO bool, QC.Testable bool)   => String -> (forall a1 a2. (Integral a1, Integral a2, Bits a1, Bits a2, UniqueFactorisation a1, UniqueFactorisation a2, Show a1, Show a2) => wrapper1 a1 -> wrapper2 a2 -> bool) -> TestTree@@ -189,32 +225,53 @@   [ SC.testProperty "smallcheck Int Int"         (f :: wrapper1 Int     -> wrapper2 Int     -> bool)   , SC.testProperty "smallcheck Int Word"        (f :: wrapper1 Int     -> wrapper2 Word    -> bool)   , SC.testProperty "smallcheck Int Integer"     (f :: wrapper1 Int     -> wrapper2 Integer -> bool)+  , SC.testProperty "smallcheck Int Natural"     (f :: wrapper1 Int     -> wrapper2 Natural -> bool)   , SC.testProperty "smallcheck Word Int"        (f :: wrapper1 Word    -> wrapper2 Int     -> bool)   , SC.testProperty "smallcheck Word Word"       (f :: wrapper1 Word    -> wrapper2 Word    -> bool)   , SC.testProperty "smallcheck Word Integer"    (f :: wrapper1 Word    -> wrapper2 Integer -> bool)+  , SC.testProperty "smallcheck Word Natural"    (f :: wrapper1 Word    -> wrapper2 Natural -> bool)   , SC.testProperty "smallcheck Integer Int"     (f :: wrapper1 Integer -> wrapper2 Int     -> bool)   , SC.testProperty "smallcheck Integer Word"    (f :: wrapper1 Integer -> wrapper2 Word    -> bool)   , SC.testProperty "smallcheck Integer Integer" (f :: wrapper1 Integer -> wrapper2 Integer -> bool)+  , SC.testProperty "smallcheck Integer Natural" (f :: wrapper1 Integer -> wrapper2 Natural -> bool)+  , SC.testProperty "smallcheck Natural Int"     (f :: wrapper1 Natural -> wrapper2 Int     -> bool)+  , SC.testProperty "smallcheck Natural Word"    (f :: wrapper1 Natural -> wrapper2 Word    -> bool)+  , SC.testProperty "smallcheck Natural Integer" (f :: wrapper1 Natural -> wrapper2 Integer -> bool)+  , SC.testProperty "smallcheck Natural Natural" (f :: wrapper1 Natural -> wrapper2 Natural -> bool)    , QC.testProperty "quickcheck Int Int"         (f :: wrapper1 Int     -> wrapper2 Int     -> bool)   , QC.testProperty "quickcheck Int Word"        (f :: wrapper1 Int     -> wrapper2 Word    -> bool)   , QC.testProperty "quickcheck Int Integer"     (f :: wrapper1 Int     -> wrapper2 Integer -> bool)+  , QC.testProperty "quickcheck Int Natural"     (f :: wrapper1 Int     -> wrapper2 Natural -> bool)   , QC.testProperty "quickcheck Word Int"        (f :: wrapper1 Word    -> wrapper2 Int     -> bool)   , QC.testProperty "quickcheck Word Word"       (f :: wrapper1 Word    -> wrapper2 Word    -> bool)   , QC.testProperty "quickcheck Word Integer"    (f :: wrapper1 Word    -> wrapper2 Integer -> bool)+  , QC.testProperty "quickcheck Word Natural"    (f :: wrapper1 Word    -> wrapper2 Natural -> bool)   , QC.testProperty "quickcheck Integer Int"     (f :: wrapper1 Integer -> wrapper2 Int     -> bool)   , QC.testProperty "quickcheck Integer Word"    (f :: wrapper1 Integer -> wrapper2 Word    -> bool)   , QC.testProperty "quickcheck Integer Integer" (f :: wrapper1 Integer -> wrapper2 Integer -> bool)+  , QC.testProperty "quickcheck Integer Natural" (f :: wrapper1 Integer -> wrapper2 Natural -> bool)+  , QC.testProperty "quickcheck Natural Int"     (f :: wrapper1 Natural -> wrapper2 Int     -> bool)+  , QC.testProperty "quickcheck Natural Word"    (f :: wrapper1 Natural -> wrapper2 Word    -> bool)+  , QC.testProperty "quickcheck Natural Integer" (f :: wrapper1 Natural -> wrapper2 Integer -> bool)+  , QC.testProperty "quickcheck Natural Natural" (f :: wrapper1 Natural -> wrapper2 Natural -> bool)    , QC.testProperty "quickcheck Large Int Int"         ((f :: wrapper1 Int     -> wrapper2 Int     -> bool) . fmap getLarge)   , QC.testProperty "quickcheck Large Int Word"        ((f :: wrapper1 Int     -> wrapper2 Word    -> bool) . fmap getLarge)   , QC.testProperty "quickcheck Large Int Integer"     ((f :: wrapper1 Int     -> wrapper2 Integer -> bool) . fmap getLarge)+  , QC.testProperty "quickcheck Large Int Natural"     ((f :: wrapper1 Int     -> wrapper2 Natural -> bool) . fmap getLarge)   , QC.testProperty "quickcheck Large Word Int"        ((f :: wrapper1 Word    -> wrapper2 Int     -> bool) . fmap getLarge)   , QC.testProperty "quickcheck Large Word Word"       ((f :: wrapper1 Word    -> wrapper2 Word    -> bool) . fmap getLarge)   , QC.testProperty "quickcheck Large Word Integer"    ((f :: wrapper1 Word    -> wrapper2 Integer -> bool) . fmap getLarge)+  , QC.testProperty "quickcheck Large Word Natural"    ((f :: wrapper1 Word    -> wrapper2 Natural -> bool) . fmap getLarge)   , QC.testProperty "quickcheck Huge  Integer Int"     ((f :: wrapper1 Integer -> wrapper2 Int     -> bool) . fmap getHuge)   , QC.testProperty "quickcheck Huge  Integer Word"    ((f :: wrapper1 Integer -> wrapper2 Word    -> bool) . fmap getHuge)   , QC.testProperty "quickcheck Huge  Integer Integer" ((f :: wrapper1 Integer -> wrapper2 Integer -> bool) . fmap getHuge)+  , QC.testProperty "quickcheck Huge  Integer Natural" ((f :: wrapper1 Integer -> wrapper2 Natural -> bool) . fmap getHuge)+  , QC.testProperty "quickcheck Huge  Natural Int"     ((f :: wrapper1 Natural -> wrapper2 Int     -> bool) . fmap getHuge)+  , QC.testProperty "quickcheck Huge  Natural Word"    ((f :: wrapper1 Natural -> wrapper2 Word    -> bool) . fmap getHuge)+  , QC.testProperty "quickcheck Huge  Natural Integer" ((f :: wrapper1 Natural -> wrapper2 Integer -> bool) . fmap getHuge)+  , QC.testProperty "quickcheck Huge  Natural Natural" ((f :: wrapper1 Natural -> wrapper2 Natural -> bool) . fmap getHuge)   ]  testSmallAndQuick
test-suite/Math/NumberTheory/TestUtils/MyCompose.hs view
@@ -3,8 +3,6 @@ -- Copyright:   (c) 2016-2017 Andrew Lelechenko -- Licence:     MIT -- Maintainer:  Andrew Lelechenko <andrew.lelechenko@gmail.com>--- Stability:   Provisional--- Portability: Non-portable (GHC extensions) -- -- Utils to test Math.NumberTheory --
test-suite/Math/NumberTheory/TestUtils/Wrappers.hs view
@@ -3,8 +3,6 @@ -- Copyright:   (c) 2016 Andrew Lelechenko -- Licence:     MIT -- Maintainer:  Andrew Lelechenko <andrew.lelechenko@gmail.com>--- Stability:   Provisional--- Portability: Non-portable (GHC extensions) -- -- Utils to test Math.NumberTheory --@@ -28,18 +26,20 @@ module Math.NumberTheory.TestUtils.Wrappers where  import Control.Applicative+import Data.Coerce import Data.Functor.Classes  import Test.Tasty.QuickCheck as QC hiding (Positive, NonNegative, generate, getNonNegative, getPositive) import Test.SmallCheck.Series (Positive(..), NonNegative(..), Serial(..), Series) -import Math.NumberTheory.UniqueFactorisation+import Math.NumberTheory.Euclidean (Euclidean)+import Math.NumberTheory.Primes (Prime, UniqueFactorisation(..))  ------------------------------------------------------------------------------- -- AnySign  newtype AnySign a = AnySign { getAnySign :: a }-  deriving (Eq, Ord, Read, Show, Num, Enum, Bounded, Integral, Real, Functor, Foldable, Traversable, Arbitrary)+  deriving (Eq, Ord, Read, Show, Num, Enum, Bounded, Integral, Real, Functor, Foldable, Traversable, Arbitrary, Euclidean)  instance (Monad m, Serial m a) => Serial m (AnySign a) where   series = AnySign <$> series@@ -57,6 +57,7 @@ -- Positive from smallcheck  deriving instance Functor Positive+deriving instance Euclidean a => Euclidean (Positive a)  instance (Num a, Ord a, Arbitrary a) => Arbitrary (Positive a) where   arbitrary = Positive <$> (arbitrary `suchThat` (> 0))@@ -79,6 +80,7 @@ -- NonNegative from smallcheck  deriving instance Functor NonNegative+deriving instance Euclidean a => Euclidean (NonNegative a)  instance (Num a, Ord a, Arbitrary a) => Arbitrary (NonNegative a) where   arbitrary = NonNegative <$> (arbitrary `suchThat` (>= 0))@@ -103,6 +105,10 @@ instance (Monad m, Num a, Eq a, Serial m a) => Serial m (NonZero a) where   series = NonZero <$> series `suchThatSerial` (/= 0) +instance (Eq a, Num a, Enum a, Bounded a) => Bounded (NonZero a) where+  minBound = if minBound == (0 :: a) then NonZero (succ minBound) else NonZero minBound+  maxBound = if maxBound == (0 :: a) then NonZero (pred maxBound) else NonZero maxBound+ ------------------------------------------------------------------------------- -- Huge @@ -128,13 +134,13 @@ -- Power  newtype Power a = Power { getPower :: a }-  deriving (Eq, Ord, Read, Show, Num, Enum, Bounded, Integral, Real, Functor, Foldable, Traversable)+  deriving (Eq, Ord, Read, Show, Num, Enum, Bounded, Integral, Real, Functor, Foldable, Traversable, Euclidean)  instance (Monad m, Num a, Ord a, Serial m a) => Serial m (Power a) where   series = Power <$> series `suchThatSerial` (> 0)  instance (Num a, Ord a, Integral a, Arbitrary a) => Arbitrary (Power a) where-  arbitrary = Power <$> (getSmall <$> arbitrary) `suchThat` (> 0)+  arbitrary = Power <$> arbitrarySizedNatural `suchThat` (> 0)   shrink (Power x) = Power <$> filter (> 0) (shrink x)  instance Eq1 Power where@@ -171,34 +177,22 @@ ------------------------------------------------------------------------------- -- Prime -newtype PrimeWrapper a = PrimeWrapper { getPrime :: Prime a }--deriving instance Eq   (Prime a) => Eq   (PrimeWrapper a)-deriving instance Ord  (Prime a) => Ord  (PrimeWrapper a)-deriving instance Show (Prime a) => Show (PrimeWrapper a)--instance (Arbitrary a, UniqueFactorisation a) => Arbitrary (PrimeWrapper a) where-  arbitrary = PrimeWrapper <$> (arbitrary :: Gen a) `suchThatMap` isPrime+instance (Arbitrary a, UniqueFactorisation a) => Arbitrary (Prime a) where+  arbitrary = (arbitrary :: Gen a) `suchThatMap` isPrime -instance (Monad m, Serial m a, UniqueFactorisation a) => Serial m (PrimeWrapper a) where-  series = PrimeWrapper <$> (series :: Series m a) `suchThatMapSerial` isPrime+instance (Monad m, Serial m a, UniqueFactorisation a) => Serial m (Prime a) where+  series = (series :: Series m a) `suchThatMapSerial` isPrime  ------------------------------------------------------------------------------- -- UniqueFactorisation -type instance Prime (Large a) = Prime a- instance UniqueFactorisation a => UniqueFactorisation (Large a) where-  unPrime p = Large (unPrime p)-  factorise (Large x) = factorise x-  isPrime (Large x) = isPrime x--type instance Prime (Huge a) = Prime a+  factorise (Large x) = coerce $ factorise x+  isPrime (Large x) = coerce $ isPrime x  instance UniqueFactorisation a => UniqueFactorisation (Huge a) where-  unPrime p = Huge (unPrime p)-  factorise (Huge x) = factorise x-  isPrime (Huge x) = isPrime x+  factorise (Huge x) = coerce $ factorise x+  isPrime (Huge x) = coerce $ isPrime x  ------------------------------------------------------------------------------- -- Utils
test-suite/Math/NumberTheory/UniqueFactorisationTests.hs view
@@ -3,7 +3,6 @@ -- Copyright:   (c) 2016 Andrew Lelechenko -- Licence:     MIT -- Maintainer:  Andrew Lelechenko <andrew.lelechenko@gmail.com>--- Stability:   Provisional -- -- Tests for Math.NumberTheory.ArithmeticFunctions --@@ -19,8 +18,9 @@  import Test.Tasty -import Math.NumberTheory.Quadratic.GaussianIntegers hiding (factorise)-import Math.NumberTheory.UniqueFactorisation+import Math.NumberTheory.Quadratic.EisensteinIntegers+import Math.NumberTheory.Quadratic.GaussianIntegers+import Math.NumberTheory.Primes import Math.NumberTheory.TestUtils  import Numeric.Natural@@ -43,5 +43,6 @@   , testSmallAndQuick "Integer" (testRules :: Integer -> Bool)   , testSmallAndQuick "Natural" (testRules :: Natural -> Bool) -  , testSmallAndQuick "GaussianInteger" (testRules :: GaussianInteger -> Bool)+  , testSmallAndQuick "GaussianInteger"   (testRules :: GaussianInteger   -> Bool)+  , testSmallAndQuick "EisensteinInteger" (testRules :: EisensteinInteger -> Bool)   ]
test-suite/Math/NumberTheory/Zeta/DirichletTests.hs view
@@ -3,7 +3,6 @@ -- Copyright:   (c) 2018 Alexandre Rodrigues Baldé -- Licence:     MIT -- Maintainer:  Alexandre Rodrigues Baldé <alexandrer_b@outlook.com>--- Stability:   Provisional -- -- Tests for Math.NumberTheory.Zeta.Dirichlet --@@ -89,11 +88,11 @@  betasProperty2 :: NonNegative Int -> NonNegative Int -> Bool betasProperty2 (NonNegative e1) (NonNegative e2)-  = maximum (take 10 $ drop 2 $ zipWith ((abs .) . (-)) (betas eps1) (betas eps2)) <= eps1 + eps2+  = maximum (take 35 $ drop 2 $ zipWith ((abs .) . (-)) (betas eps1) (betas eps2)) <= eps1 + eps2   where     eps1, eps2 :: Double-    eps1 = (1.0 / 2) ^ e1-    eps2 = (1.0 / 2) ^ e2+    eps1 = max ((1.0 / 2) ^ e1) ((1.0 / 2) ^ 53)+    eps2 = max ((1.0 / 2) ^ e2) ((1.0 / 2) ^ 53)   testSuite :: TestTree
test-suite/Math/NumberTheory/Zeta/RiemannTests.hs view
@@ -3,7 +3,6 @@ -- Copyright:   (c) 2016 Andrew Lelechenko -- Licence:     MIT -- Maintainer:  Andrew Lelechenko <andrew.lelechenko@gmail.com>--- Stability:   Provisional -- -- Tests for Math.NumberTheory.Zeta.Riemann --@@ -93,11 +92,11 @@ -- 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+  = maximum (take 35 $ drop 2 $ zipWith ((abs .) . (-)) (zetas eps1) (zetas eps2)) < eps1 + eps2   where     eps1, eps2 :: Double-    eps1 = 1.0 / 2 ^ e1-    eps2 = 1.0 / 2 ^ e2+    eps1 = max ((1.0 / 2) ^ e1) ((1.0 / 2) ^ 53)+    eps2 = max ((1.0 / 2) ^ e2) ((1.0 / 2) ^ 53)  testSuite :: TestTree testSuite = testGroup "Zeta"
test-suite/Test.hs view
@@ -1,10 +1,10 @@ import Test.Tasty -import qualified Math.NumberTheory.GCDTests as GCD+import qualified Math.NumberTheory.EuclideanTests as Euclidean -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.Recurrences.PentagonalTests as RecurrencesPentagonal+import qualified Math.NumberTheory.Recurrences.BilinearTests as RecurrencesBilinear+import qualified Math.NumberTheory.Recurrences.LinearTests as RecurrencesLinear  import qualified Math.NumberTheory.Moduli.ChineseTests as ModuliChinese import qualified Math.NumberTheory.Moduli.ClassTests as ModuliClass@@ -28,6 +28,7 @@ import qualified Math.NumberTheory.PrimesTests as Primes import qualified Math.NumberTheory.Primes.CountingTests as Counting import qualified Math.NumberTheory.Primes.FactorisationTests as Factorisation+import qualified Math.NumberTheory.Primes.SequenceTests as Sequence import qualified Math.NumberTheory.Primes.SieveTests as Sieve import qualified Math.NumberTheory.Primes.TestingTests as Testing @@ -36,6 +37,7 @@ import qualified Math.NumberTheory.GaussianIntegersTests as Gaussian  import qualified Math.NumberTheory.ArithmeticFunctionsTests as ArithmeticFunctions+import qualified Math.NumberTheory.ArithmeticFunctions.InverseTests as Inverse import qualified Math.NumberTheory.ArithmeticFunctions.MertensTests as Mertens import qualified Math.NumberTheory.ArithmeticFunctions.SieveBlockTests as SieveBlock import qualified Math.NumberTheory.UniqueFactorisationTests as UniqueFactorisation@@ -57,11 +59,11 @@     , Modular.testSuite     , Squares.testSuite     ]-  , GCD.testSuite-  , testGroup "Recurrencies"-    [ RecurrenciesPentagonal.testSuite-    , RecurrenciesLinear.testSuite-    , RecurrenciesBilinear.testSuite+  , Euclidean.testSuite+  , testGroup "Recurrences"+    [ RecurrencesPentagonal.testSuite+    , RecurrencesLinear.testSuite+    , RecurrencesBilinear.testSuite     ]   , testGroup "Moduli"     [ ModuliChinese.testSuite@@ -81,6 +83,7 @@     [ Primes.testSuite     , Counting.testSuite     , Factorisation.testSuite+    , Sequence.testSuite     , Sieve.testSuite     , Testing.testSuite     ]@@ -88,6 +91,7 @@   , Gaussian.testSuite   , testGroup "ArithmeticFunctions"     [ ArithmeticFunctions.testSuite+    , Inverse.testSuite     , Mertens.testSuite     , SieveBlock.testSuite     ]