{-# LANGUAGE NoImplicitPrelude #-} {- Some of these functions might be moved to NumericPrelude. Wikipedia: (primitive) roots of unity modulo n (primitive) roots must be units and all units are (primitive) roots maximum possible order for primitive roots - Carmichael all possible orders: divisor of Carmichael (proof? statement already in Carmichael-function-article) sum of primitive roots that vanishes order of primitive root is a divisor of each possible exponent proof with GCD and diophantine in exponent check for primitive root: fast exponentiation, primitivity: check exponents that are prime divisors how to find a primitive root: just try sum of powers of a primitive root is zero number of primitive roots of given order g(n,k) > 0 if k|lambda(n) g(n,k) = 0 else g(n,1) = 1 g(4,2) = 1 g(2^n,2) = 3 for n>=3 ((-1) is always a square root of 1) g(2^n,2^k) = 2^k for k>=2 && k=3 and n in OEIS:A033948 sum(g(n,k), k\in\N) = phi(n) There are only a few patterns that occur as rows of g, but a row of g (i.e. g(n)) does functionally depend on either lambda(n) nor phi(n) lambda(14) = 6 nozeros(g(14)) = [1,1,2,2] (f ~ [1,2,3,6]) lambda(21) = 6 nozeros(g(21)) = [1,3,2,6] (f ~ [1,4,3,12]) phi(13) = 12 nozeros(g(13)) = [1,1,2,2,2,4] (f ~ [1,2,3,4,6,12]) phi(21) = 12 nozeros(g(21)) = [1,3,2,6] (f ~ [1,4,3,12]) However length(nozeros(f(n))) = numberofdivisors(lambda(n)) numberofdivisors=A000005 number of roots of given order easier to compute k|m => f(n,k) | f(n,m) g(n,k) = f(n,k) - sum(f(n,d), d|k and k/d prime) + ... inclusion-exclusion-principle better to write the other round: f(n,k) = sum(g(n,d), d|k) - this is Dirichlet convolution RUNM says f(n,k) is multiplicative list it in multiplicative function f(n,1) = 1 for n>=2 f(n,lambda(n)) = phi(n) f(n,a·b) = f(n,a)·f(n,b) if a and b are coprime (conjecture) f(n,lcm(a,b)) = lcm(f(n,a),f(n,b)) (conjecture) If this conjecture is true, then we only need to know f(n,p^i). The following conjecture is wrong: for prime p it is f(n,p^i) = gcd(lambda(n),p^i) counterexamples f(8,2) = 4, lambda(8)=2 f(63,3) = 9, lambda(63)=6 f(275,5) = 25, lambda(275)=20 f(1247,7) = 49, lambda(1247)=84 It seems to be: for prime p it is f(n,p^i) = p^j for some j How to find a modulus where there is a primitive root of order o? just try numbers from the sequence o+1, 2*o+1, 3*o+1 Because of [[Dirichlet's theorem on arithmetic progressions]] you will somewhen find a prime p, and its Carmichael value is p-1, which is a multiple of o. In this ring even 'o' is a unit. How to find a modulus where there are primitive roots of orders o1,..,ok? Just search for a modulus with roots of order lcm(o1,...,ok). The smallest such modulus should also be the smallest one that has primitive roots of orders o1,..,ok? Proof: If a ring has primitive roots of orders o1,..,ok then all orders divide the carmichael value of that ring, thus lcm(o1,...,ok) divides the carmichael value of that ring, thus there is a primitive root of order lcm(o1,...,ok). -} module Synthesizer.Basic.NumberTheory where import qualified Synthesizer.State.Signal as SigS import qualified Data.Set as Set import qualified Data.Map as Map import qualified Algebra.Ring as Ring import qualified Algebra.Units as Units import qualified Algebra.PrincipalIdealDomain as PID import qualified Algebra.IntegralDomain as Integral import qualified Algebra.ZeroTestable as ZeroTestable import qualified Number.ResidueClass.Check as RC import Number.ResidueClass.Check ((/:), ) import qualified Number.FixedPoint as FP import Data.Bits (Bits, (.&.), (.|.), shiftR, ) import qualified Data.List.HT as ListHT import Data.List (unfoldr, mapAccumL, genericDrop, genericSplitAt, ) import Data.Tuple.HT (mapFst, mapSnd, mapPair, swap, ) import Data.Maybe.HT (toMaybe, ) import Test.QuickCheck (Arbitrary(arbitrary), ) import NumericPrelude.Numeric import NumericPrelude.Base {- | The first pair member in @powerOfTwoFactors n@ is the maximum factor of @n@, that is a power of two. -} powerOfTwoFactors :: (Bits a, Integral.C a) => a -> (a, a) powerOfTwoFactors n = let powerOfTwo = n .&. (-n) in (powerOfTwo, div n powerOfTwo) {- | List all factorizations of an odd number where the first factor is at most the second factor and the first factors are in descending order. -} fermatFactors :: Integer -> [(Integer,Integer)] fermatFactors n = let root = FP.sqrt 1 n in map (\(a,b) -> (b-a,b+a)) $ mergeAndFilter (zip (scanl (+) n [1,3..]) [0 .. div (n-1) 2]) (zip (scanl (+) (root*root) $ iterate (2+) (2*root+1)) [root..]) mergeAndFilter :: (Ord a) => [(a,b)] -> [(a,c)] -> [(b,c)] mergeAndFilter ((a0,b):a0s) ((a1,c):a1s) = case compare a0 a1 of LT -> mergeAndFilter a0s ((a1,c):a1s) GT -> mergeAndFilter ((a0,b):a0s) a1s EQ -> (b,c) : mergeAndFilter a0s a1s mergeAndFilter _ _ = [] {- | Argument must be a prime. Usage of Set for efficient filtering of candidates seems to be overkill, since the multiplicative generator seems to be small in most cases, i.e. 2 or 3. -} multiplicativeGenerator :: Integer -> Integer multiplicativeGenerator p = let search candidates = case Set.minView candidates of Nothing -> error $ show p ++ " is not an odd prime" Just (x,rest) -> case orbitSet $ orbit p x of new -> -- fromIntegral (Set.size new) == p-2 if new == Set.fromList [1..p-1] then x else search (Set.difference rest new) in search (Set.fromList [2..p-1]) newtype Order = Order {getOrder :: Integer} deriving (Show, Eq, Ord) instance Arbitrary Order where arbitrary = fmap (Order . (1+) . abs) arbitrary instance Enum Order where succ (Order n) = Order (n+1) pred (Order n) = Order (n-1) fromEnum (Order n) = fromEnum n toEnum n = Order (toEnum n) enumFrom (Order from) = map Order $ enumFrom from enumFromThen (Order from) (Order thn) = map Order $ enumFromThen from thn enumFromTo (Order from) (Order to) = map Order $ enumFromTo from to enumFromThenTo (Order from) (Order thn) (Order to) = map Order $ enumFromThenTo from thn to countOrder :: [a] -> Order countOrder = foldl (\o _ -> succ o) (Order 0) dividesOrder :: Order -> Order -> Bool dividesOrder (Order k) (Order n) = divides k n -- class Integral.C a => PrimitiveRoot a where class PID.C a => PrimitiveRoot a where primitiveRootCandidates :: a -> [a] maximumOrderOfPrimitiveRootsOfUnity :: a -> Order instance PrimitiveRoot Integer where primitiveRootCandidates modu = [1 .. modu-1] maximumOrderOfPrimitiveRootsOfUnity = maximumOrderOfPrimitiveRootsOfUnityInteger {- For 'ordersOfPrimitiveRootsOfUnityInteger' and the connection to Euler's totient function we have chosen to have > primitiveRootsOfUnity m 1 == [1]. -} primitiveRootsOfUnity :: (PrimitiveRoot a, Eq a) => a -> Order -> [a] primitiveRootsOfUnity = primitiveRootsOfUnityPower {- Verifying that a ring has no primitive root of the wanted order takes a long time if we do it by exhaustive search. In the case of a=Integer we could first check, whether the considered residue ring has a primitive root of wanted order using the Carmichael function. We could certainly count the number of primitive roots and stop searching if we reach that count. -} primitiveRootsOfUnityPower :: (PrimitiveRoot a, Eq a) => a -> Order -> [a] primitiveRootsOfUnityPower modu (Order order) = let greatDivisors = map (div order) $ uniquePrimeFactors order in filter (\n -> let pow y = RC.representative $ (n /: modu) ^ y in PID.coprime n modu && pow order == one && all (\y -> pow y /= one) greatDivisors) $ primitiveRootCandidates modu primitiveRootsOfUnityNaive :: (PrimitiveRoot a, Eq a) => a -> Order -> [a] primitiveRootsOfUnityNaive _ (Order 0) = [] primitiveRootsOfUnityNaive modu (Order expo) = filter (\n -> let (prefix,end:_) = genericSplitAt (expo-1) $ SigS.toList $ orbit modu n in all (1/=) prefix && end==1) $ primitiveRootCandidates modu orbitSet :: Ord a => SigS.T a -> Set.Set a orbitSet list = SigS.foldR (\new cont seen -> if Set.member new seen then seen else cont (Set.insert new seen)) id list Set.empty orbit :: (Integral.C a) => a -> a -> SigS.T a orbit p x = SigS.iterate (\y -> mod (x*y) p) x {- | Does not emit values in ascending order and may return duplicates (e.g. primitiveRootsOfUnityFullOrbit 70000 10). I hoped it would be faster than the other implementations since it eliminates non-roots in large blocks. However it seems that managing the root candidates in a Set reduces performance significantly. The idea: Start with a seed that is a unit. Compute its orbit until a one is reached. Since it is a unit, we always encounter a one. We do not need to check for non-unit seeds, since (gcd modu seed) will be a divisor of all seed powers. In the orbit all numbers are powers of each other. Now finding the roots is a matter of solving a Diophantine equation of the exponents. In one such step all powers in an orbit are classified as roots or non-roots and thus we can remove them all from the set of root candidates and continue with the remaining candidates. Duplicates can occur if a seed in a later iteration is found again as power of another seed. -} primitiveRootsOfUnityFullOrbit :: (PrimitiveRoot a, Ord a) => a -> Order -> [a] primitiveRootsOfUnityFullOrbit modu expo = let search candidates = flip fmap (Set.minView candidates) $ \(x,rest) -> mapSnd (Set.difference rest . Set.fromList) $ primitiveRootsOfOrbit modu expo x in concat $ unfoldr search $ Set.fromList $ -- needed for modules with many divisors filter (PID.coprime modu) $ primitiveRootCandidates modu primitiveRootsOfUnityFullOrbitTest :: (PrimitiveRoot a, Ord a) => a -> Order -> [(a,[a])] primitiveRootsOfUnityFullOrbitTest modu expo = let search candidates = flip fmap (Set.minView candidates) $ \(x,rest) -> mapPair ((,) x, Set.difference rest . Set.fromList) $ primitiveRootsOfOrbit modu expo x in unfoldr search $ Set.fromList $ filter (PID.coprime modu) $ primitiveRootCandidates modu primitiveRootsOfOrbit :: (PrimitiveRoot a, Ord a) => a -> Order -> a -> ([a], [a]) primitiveRootsOfOrbit modu (Order expo) x = let orb = (1:) $ takeWhile (1/=) $ iterate (\y -> mod (x*y) modu) x (Order orbitSize) = countOrder orb in (if expo==0 then [] else {- size = length orb Search for m and k with 0 div size expo = gcd size m s = gcd size m We have to consider for m only the multiples of s. Then divide both sides of the equation by s, yielding 1 = gcd expo m' -} case divMod orbitSize expo of (s,0) -> map snd $ filter (PID.coprime expo . fst) $ zip [0 .. expo-1] -- (ListHT.sieve s $ orb) (map head $ iterate (genericDrop s) orb) _ -> [], orb) hasPrimitiveRootOfUnityNaive :: (PrimitiveRoot a, Ord a) => a -> Order -> Bool hasPrimitiveRootOfUnityNaive modu expo = any (dividesOrder expo . snd) $ ordersOfPrimitiveRootsOfUnityTest modu {- This should be a maximum both with respect to magnitude and to divisibility. -} maximumOrderOfPrimitiveRootsOfUnityNaive :: (PrimitiveRoot a, Ord a) => a -> Order maximumOrderOfPrimitiveRootsOfUnityNaive = foldl max (Order 1) . map snd . ordersOfPrimitiveRootsOfUnityTest {- | Computes a list of seeds and according maximum orders of roots of unity. All divisors of those maximum orders are possible orders of roots of unity, too. -} ordersOfPrimitiveRootsOfUnityTest :: (PrimitiveRoot a, Ord a) => a -> [(a, Order)] ordersOfPrimitiveRootsOfUnityTest modu = let search candidates = flip fmap (Set.minView candidates) $ \(x,rest) -> mapPair ((,) x, Set.difference rest . Set.fromList) $ orderOfOrbit modu x in unfoldr search $ Set.fromList $ filter (PID.coprime modu) $ primitiveRootCandidates modu {- | modu and x must be coprime. If they are not, then none of the numbers in the orbit is a root of unity and the function enters an infinite loop. -} orderOfOrbit :: (PrimitiveRoot a, Ord a) => a -> a -> (Order, [a]) orderOfOrbit modu x = let cyc = takeWhile (one/=) $ SigS.toList $ orbit modu x in (succ $ countOrder cyc, cyc) {- This test speeds up 'hasPrimitiveRootOfUnityNaive' considerably by considering the prime factors of modu. If modu is a prime, then the ring has a multiplicative generator, i.e. a primitive root of unity of order modu-1. That is, all primitive roots of unity are of an order that divides modu-1. It seems that if modu is a power of a prime, then the according ring has also multiplicative generator. I think this is the reason for generalising the Rader transform to signals of prime power length. -} hasPrimitiveRootOfUnityInteger :: Integer -> Order -> Bool hasPrimitiveRootOfUnityInteger modu expo = dividesOrder expo $ maximumOrderOfPrimitiveRootsOfUnityInteger modu {- Carmichael theorem: If the integer residue rings with coprime moduli m0 and m1 have primitive roots of maximum order o0 and o1, respectively, then the integer ring with modulus m0*m1 has maximum order (lcm o0 o1). -} {- This is the Carmichael function. OEIS-A002322 -} maximumOrderOfPrimitiveRootsOfUnityInteger :: Integer -> Order maximumOrderOfPrimitiveRootsOfUnityInteger = Order . lcmMulti . map (\(e,p) -> if p == 2 && e > 2 then p^(e-2) else p^(e-1) * (p-1)) . map (mapFst fromIntegral) . primeFactors {- The sum of the sub-lists should equal the Euler totient function values (OEIS-A000010). -} ordersOfPrimitiveRootsOfUnityInteger :: [[Int]] ordersOfPrimitiveRootsOfUnityInteger = flip map [1..] $ \modu -> let maxOrder = maximumOrderOfPrimitiveRootsOfUnity (modu::Integer) in map (length . primitiveRootsOfUnityPower modu) $ -- filter (flip divides maxOrder) $ [Order 1 .. maxOrder] ordersOfRootsOfUnityInteger :: [[Int]] ordersOfRootsOfUnityInteger = flip map [1..] $ \modu -> map (length . rootsOfUnityPower (modu::Integer)) $ [Order 1 ..] {- mapM_ print $ map (\n -> (n, maximumOrderOfPrimitiveRootsOfUnityInteger (fromIntegral n), take 30 $ ordersOfRootsOfUnityInteger !! (n-1))) [2..30] mapM_ print $ map (\n -> (n, maximumOrderOfPrimitiveRootsOfUnityInteger (fromIntegral n), let row = ordersOfRootsOfUnityInteger !! (n-1) in map (row!!) $ map pred $ take 10 $ iterate (2*) 1)) [2..30] -} ordersOfRootsOfUnityIntegerCondensed :: [[Int]] ordersOfRootsOfUnityIntegerCondensed = flip map [1..] $ \modu -> let maxOrder = maximumOrderOfPrimitiveRootsOfUnity (modu::Integer) in map (length . rootsOfUnityPower modu) $ -- filter (flip divides maxOrder) $ [Order 1 .. maxOrder] rootsOfUnityPower :: (PrimitiveRoot a, Eq a) => a -> Order -> [a] rootsOfUnityPower modu (Order expo) = filter (\n -> PID.coprime n modu && RC.representative ((n /: modu) ^ expo) == one) $ primitiveRootCandidates modu {- Corollary from the Carmichael function properties: If in Z_n there is a primitive root r of unity of order o, then for every Z_{m \cdot n} there is also a primitive root of unity with the same order. Collary: If in Z_n1 you have a primitive root of order o1, and so on for Z_{n_k} and order ok, then Z_{lcm(n1,...,nk)} has primitive roots for every of the order o1,...,on. Conjecture: If Z_n has a total number of m primitive roots of unity of order o, then Z_{k*n} has at least m primitive roots of unity of order o. Conjecture: Precondition: In Z_n there is a primitive root of prime order o. Claims: a) There are natural numbers m and k with n = m*(k*o+1) or n = m*o. b) The smallest such n is of the form k*o+1 with k>1. Counterexample for a) and non-prime o: o=15, n=77 Counterexample for b) and non-prime o: o=20, n=25; o=27, n=81; o=54, n=81; o=55, n=121 Corollary from definition of Carmichael function: For n>1, Z_{2^{n+2}} has primitive root of unity of order 2^n. -} {- | Given an order find integer residue rings where roots of unity of this order exist. The way they are constructed also warrants, that 'order' is a unit (i.e. invertible) in those rings. The list is not exhaustive but computes suggestions quickly. The first found modulus seems to be smallest one that exist. However, the first modulus is not the smallest one among the ones that only have the wanted primitive root, but where 'order' is not necessarily a unit. E.g. > ringsWithPrimitiveRootOfUnityAndUnit 840 == 2521 : 3361 : ... but the smallest modulus is 1763. Most of the numbers are primes. For these the recursion property of the Carmichael function immediately yields that there are primitive roots of unity of order 'order'. -} ringsWithPrimitiveRootOfUnityAndUnit :: Order -> [Integer] ringsWithPrimitiveRootOfUnityAndUnit order@(Order k) = filter (flip hasPrimitiveRootOfUnityInteger order) $ iterate (k+) 1 ringsWithPrimitiveRootsOfUnityAndUnitsNaive :: [Order] -> [Integer] -> [Integer] ringsWithPrimitiveRootsOfUnityAndUnitsNaive rootOrders units = filter (\n -> all (hasPrimitiveRootOfUnityInteger n) rootOrders && all (PID.coprime n) units) [1..] {- It would be nice to have the Omega monad here in order to enumerate all rings. -} ringWithPrimitiveRootsOfUnityAndUnits :: [Order] -> [Integer] -> Integer ringWithPrimitiveRootsOfUnityAndUnits rootOrders units = let p = lcmMulti units in lcmMulti $ map (head . filter (PID.coprime p) . ringsWithPrimitiveRootOfUnityAndUnit) $ rootOrders {- Search for an appriopriate modulus using the recursive definition of the Carmichael function. We chose the prime factors of the Carmichael function argument such that we get at least the prime factors in the function value that we need. The modulus constructed this way is usually not the smallest possible and it also does not provide that 'n' is a unit in the residue ring. The simpler function 'ringsWithPrimitiveRootOfUnityAndUnit' will usually produce a smaller modulus. -} ringWithPrimitiveRootsOfUnity :: Order -> Integer ringWithPrimitiveRootsOfUnity (Order n) = case n of 0 -> 2 _ -> product $ map (uncurry ringPower) $ snd $ mapAccumL (\factors (e,p) -> if Map.findWithDefault 0 p factors >= e then (factors, (0,p)) else if p==2 then (factors, case e of 0 -> (0,2) 1 -> (1,3) 2 -> (1,5) _ -> (e+2, 2)) else (Map.unionWith max factors $ Map.fromList $ map swap $ primeFactors $ p-1, (e+1, p))) Map.empty $ reverse $ primeFactors $ lcmMulti $ n : map (subtract 1) (partialPrimes n) lcmMulti :: (PID.C a) => [a] -> a lcmMulti = foldl lcm one {- | List all numbers that only contain prime factors 2 and 3 in ascending order. OEIS:A003586 -} numbers3Smooth :: [Integer] numbers3Smooth = foldr (\(x0:x1:xs) ys -> x0 : x1 : ListHT.mergeBy (<=) xs ys) (error "numbers3Smooth: infinite list should not have an end") $ iterate (map (3*)) $ iterate (2*) 1 numbers3SmoothAlt :: [Integer] numbers3SmoothAlt = unfoldr (fmap (\(m,rest) -> (m, Set.union rest $ Set.fromAscList [2*m,3*m])) . Set.minView) $ Set.singleton 1 {- OEIS:A051037 -} numbers5Smooth :: [Integer] numbers5Smooth = foldr (\(x0:x1:x2:xs) ys -> x0 : x1 : x2 : ListHT.mergeBy (<=) xs ys) (error "numbers5Smooth: infinite list should not have an end") $ iterate (map (5*)) $ numbers3Smooth numbers5SmoothAlt :: [Integer] numbers5SmoothAlt = unfoldr (fmap (\(m,rest) -> (m, Set.union rest $ Set.fromAscList [2*m,3*m,5*m])) . Set.minView) $ Set.singleton 1 ceilingPowerOfTwo :: (Ring.C a, Bits a) => a -> a ceilingPowerOfTwo 0 = 1 ceilingPowerOfTwo n = (1+) $ fst $ head $ dropWhile (uncurry (/=)) $ ListHT.mapAdjacent (,) $ scanl (\m d -> shiftR m d .|. m) (n-1) $ iterate (2*) 1 divideByMaximumPower :: (Integral.C a, ZeroTestable.C a) => a -> a -> a divideByMaximumPower b n = last $ n : unfoldr (\m -> case divMod m b of (q,r) -> toMaybe (isZero r) (q,q)) n divideByMaximumPowerRecursive :: (Integral.C a, Eq a, ZeroTestable.C a) => a -> a -> a divideByMaximumPowerRecursive b = let recourse n = case divMod b n of (q,0) -> recourse q _ -> n in recourse getMaximumExponent :: (Integral.C a, ZeroTestable.C a) => a -> a -> (Int,a) getMaximumExponent b n = last $ (0,n) : unfoldr (\(e,m) -> let (q,r) = divMod m b eq = (e+1,q) in toMaybe (isZero r) (eq,eq)) (0,n) is3Smooth :: Integer -> Bool is3Smooth = (1==) . divideByMaximumPower 3 . divideByMaximumPower 2 is5Smooth :: Integer -> Bool is5Smooth = (1==) . divideByMaximumPower 5 . divideByMaximumPower 3 . divideByMaximumPower 2 {- | Compute the smallest composite of 2 and 3 that is as least as large as the input. This can be interpreted as solving an integer linear programming problem with min (\(a,b) -> a * log 2 + b * log 3) over the domain {(a,b) : a>=0, b>=0, a * log 2 + b * log 3 >= log n} -} {- Problem: We cannot just start with the ceilingPowerOfTwo and then multiply with 3/4 until we fall below n, since the 3/4 decreases too fast. 27/32 is closer to one, and higher powers of 3 and 2 in the ratio make the ratio even closer to one. -} ceiling3Smooth :: Integer -> Integer ceiling3Smooth n = head $ dropWhile ( Integer ceiling5Smooth n = head $ dropWhile ( Integer ceiling3SmoothNaive = head . dropWhile (not . is3Smooth) . iterate (1+) ceiling5SmoothNaive :: Integer -> Integer ceiling5SmoothNaive = head . dropWhile (not . is5Smooth) . iterate (1+) {- | Compute all primes that occur in the course of dividing a Fourier transform into sub-transforms. -} partialPrimes :: Integer -> [Integer] partialPrimes = let primeFactorSet = Set.fromAscList . uniquePrimeFactors in unfoldr (fmap (\(p,set) -> (p, Set.union (primeFactorSet (p-1)) set)) . Set.maxView) . primeFactorSet -- cf. htam:NumberTheory uniquePrimeFactors :: (Integral.C a, Bits a, ZeroTestable.C a, Ord a) => a -> [a] -- map snd . primeFactors uniquePrimeFactors n = let oddFactors = foldr (\p go m -> let (q,r) = divMod m p in if r==0 then p : go (divideByMaximumPower p q) else if q >= p then go m else if m==1 then [] else m : []) (error "uniquePrimeFactors: end of infinite list") (iterate (2+) 3) in case powerOfTwoFactors n of (1,m) -> oddFactors m (_,m) -> 2 : oddFactors m {- | Prime factors and their exponents in ascending order. -} primeFactors :: (PrimitiveRoot a, Ord a) => a -> [(Int, a)] primeFactors n = let oddFactors = foldr (\p go m -> let (q0,r) = divMod m p in if r==0 then case getMaximumExponent p q0 of (e,q1) -> (e+1,p) : go q1 else if q0 >= p then go m else if m==1 then [] else (1,m) : []) (const []) (filter (not . Units.isUnit) $ primitiveRootCandidates n) in case getMaximumExponent 2 n of (0,m) -> oddFactors m (e,m) -> (e,2) : oddFactors m {- cf. htam:NumberTheory Shall this be moved to NumericPrelude? It should be replaced by a more sophisticated prime test. -} isPrime :: Integer -> Bool isPrime n = case primeFactors n of [] -> False (e,m):_ -> e==1 && m==n {- | Find lengths of signals that require many interim Rader transforms and end with the given length. raderWorstCases 2 = OEIS-A061092 raderWorstCases 5 = tail OEIS-A059411 Smallest raderWorstCase numbers are 2,5,13,17,19,31,37,41,43,61,... This matches the definition of OEIS-A061303. -} raderWorstCases :: Integer -> [Integer] raderWorstCases = iterate (\n -> head $ dropWhile (not . isPrime) $ tail $ iterate (n+) 1) {- | This is usually faster than 'fastFourierRing' since it does not need to factor large numbers. However, the generated modulus is usually much greater. -} {- I see the following opportunities for optimization: 1. Speedup 'fastFourierRing' by faster primality test (Miller-Rabin) and faster prime factorization (Pollard-Rho-method). These are also needed for maximumOrderOfPrimitiveRootsOfUnityInteger that is used by Fourier.Element.primitiveRoot in order to compute a root with maximum order. 2. Reduce the moduli produced by 'fastFourierRingAlt' by merging some orders that are passed to ringWithPrimitiveRootsOfUnityAndUnits, such that an LCM of a group of orders can still be handled. This is a kind of knapsack problem. Maybe we could collect the factors in a way such that (lcm orderGroup + 1) is prime. 3. Avoid to compute factorizations of numbers where we already know the factors or where we do not need the factors at all. Use the factors returned by partialPrimes in order to compute a prime factorization of lcmMulti (map pred (partialPrimes n)). Call this (product ps). Now search for rings of moduli (1 + k * product ps), where there are (small) primitive roots of order (product ps). We only need to check whether there are small numbers such as 2, 3, 5, 6, 7 that have a (product ps)-th power that is 1, using fast exponentiation. If there is a power being 1 then check for primitivity by computing (k * product ps / p)-th powers for all prime factors p of (k * product ps). If there is no primitive root <= 7, there may still be a primitive root of wanted order, but it is then cheaper to seek for larger moduli. If we finally have a nice modulus it is still stupid to factorize (modulus-1) and search for a primitive root in each invocation of Fourier.Element.primitiveRoot. We could define a special datatype analogously to ResidueClass, that stores the primitive root and its order additional to the ResidueClass modulus. -} fastFourierRingAlt :: Int -> Integer fastFourierRingAlt n = case n of 0 -> 2 1 -> 2 _ -> let ni = fromIntegral n ps = filter (>1) (map (subtract 1) (partialPrimes ni)) in ringWithPrimitiveRootsOfUnityAndUnits (map Order $ ni : ps) ps {- | Determine an integer residue ring in which a Fast Fourier transform of size n can be performed. It must contain certain primitive roots. If we choose a non-primitive root, then some off-diagonal values in F^-1·F are non-zero. -} {- When we need roots of orders o1,...,ok and according inverse elements we can also ask for a ring, where there is a root of order lcm(o1,...,ok). The answer to both questions is the same set of rings. This can be proven using the statement, that the order of any primitive root divides the carmichael value of the modulus. Since ringWithPrimitiveRootsOfUnityAndUnits multiplies the moduli of rings for o1,...,ok, it will produce large moduli. -} fastFourierRing :: Int -> Integer fastFourierRing n = case n of 0 -> 2 1 -> 2 _ -> let ni = fromIntegral n in {- We cannot use ringsWithPrimitiveRootOfUnityAndUnit since for 359 we already get an Int overflow. For 719, 1439, 2879 we also get a very large value. -} head $ filter isPrime $ (\order -> iterate (order +) 1) $ lcmMulti $ ni : map (subtract 1) (partialPrimes ni)