Skip to content

Commit 025a2bd

Browse files
committed
Migrate Montgomery to Atkin sieve
1 parent c103028 commit 025a2bd

File tree

3 files changed

+35
-43
lines changed

3 files changed

+35
-43
lines changed

Math/NumberTheory/Primes/Factorisation/Montgomery.hs

Lines changed: 27 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -61,11 +61,9 @@ import Math.NumberTheory.Curves.Montgomery
6161
import Math.NumberTheory.Euclidean.Coprimes (splitIntoCoprimes, unCoprimes)
6262
import Math.NumberTheory.Roots.General (highestPower, largePFPower)
6363
import Math.NumberTheory.Roots.Squares (integerSquareRoot')
64-
import Math.NumberTheory.Primes.Sieve.Eratosthenes (PrimeSieve(..), psieveFrom)
65-
import Math.NumberTheory.Primes.Sieve.Indexing (toPrim)
64+
import Math.NumberTheory.Primes.Sieve.Atkin
6665
import Math.NumberTheory.Primes.Small
6766
import Math.NumberTheory.Primes.Testing.Probabilistic
68-
import Math.NumberTheory.Unsafe
6967
import Math.NumberTheory.Utils
7068

7169
-- | @'factorise' n@ produces the prime factorisation of @n@. @'factorise' 0@ is
@@ -160,36 +158,36 @@ curveFactorisation primeBound primeTest prng seed mbdigs n
160158
fact :: Integer -> Int -> State g [(Integer, Word)]
161159
fact 1 _ = return mempty
162160
fact m digs = do
163-
let (b1, b2, ct) = findParms digs
161+
let (b1, b1Sieve, b2, ct) = findParms digs
164162
-- All factors (both @pfs@ and @cfs@), are pairwise coprime. This is
165163
-- because 'repFact' returns either a single factor, or output of 'workFact'.
166164
-- In its turn, 'workFact' returns either a single factor,
167165
-- or concats 'repFact's over coprime integers. Induction completes the proof.
168-
Factors pfs cfs <- repFact m b1 b2 ct
166+
Factors pfs cfs <- repFact m b1 b1Sieve b2 ct
169167
case cfs of
170168
[] -> return pfs
171169
_ -> do
172170
nfs <- forM cfs $ \(k, j) ->
173171
map (second (* j)) <$> fact k (if null pfs then digs + 5 else digs)
174172
return $ mconcat (pfs : nfs)
175173

176-
repFact :: Integer -> Word -> Word -> Word -> State g Factors
177-
repFact 1 _ _ _ = return mempty
178-
repFact m b1 b2 count =
174+
repFact :: Integer -> Word -> PrimeSieve -> Word -> Word -> State g Factors
175+
repFact 1 _ _ _ _ = return mempty
176+
repFact m b1 b1Sieve b2 count =
179177
case perfPw m of
180-
(_, 1) -> workFact m b1 b2 count
178+
(_, 1) -> workFact m b1 b1Sieve b2 count
181179
(b, e)
182180
| ptest b -> return $ singlePrimeFactor b e
183-
| otherwise -> modifyPowers (* e) <$> workFact b b1 b2 count
181+
| otherwise -> modifyPowers (* e) <$> workFact b b1 b1Sieve b2 count
184182

185-
workFact :: Integer -> Word -> Word -> Word -> State g Factors
186-
workFact 1 _ _ _ = return mempty
187-
workFact m _ _ 0 = return $ singleCompositeFactor m 1
188-
workFact m b1 b2 count = do
183+
workFact :: Integer -> Word -> PrimeSieve -> Word -> Word -> State g Factors
184+
workFact 1 _ _ _ _ = return mempty
185+
workFact m _ _ _ 0 = return $ singleCompositeFactor m 1
186+
workFact m b1 b1Sieve b2 count = do
189187
s <- rndR m
190188
case someNatVal (fromInteger m) of
191-
SomeNat (_ :: Proxy t) -> case montgomeryFactorisation b1 b2 (fromInteger s :: Mod t) of
192-
Nothing -> workFact m b1 b2 (count - 1)
189+
SomeNat (_ :: Proxy t) -> case montgomeryFactorisation b1 b1Sieve b2 (fromInteger s :: Mod t) of
190+
Nothing -> workFact m b1 b1Sieve b2 (count - 1)
193191
Just d -> do
194192
let cs = unCoprimes $ splitIntoCoprimes [(d, 1), (m `quot` d, 1)]
195193
-- Since all @cs@ are coprime, we can factor each of
@@ -198,7 +196,7 @@ curveFactorisation primeBound primeTest prng seed mbdigs n
198196
fmap mconcat $ flip mapM cs $
199197
\(x, xm) -> if ptest x
200198
then pure $ singlePrimeFactor x xm
201-
else repFact x b1 b2 (count - 1)
199+
else repFact x b1 b1Sieve b2 (count - 1)
202200

203201
data Factors = Factors
204202
{ _primeFactors :: [(Integer, Word)]
@@ -240,8 +238,8 @@ modifyPowers f (Factors pfs cfs)
240238
-- It is assumed that @n@ has no small prime factors.
241239
--
242240
-- The result is maybe a nontrivial divisor of @n@.
243-
montgomeryFactorisation :: KnownNat n => Word -> Word -> Mod n -> Maybe Integer
244-
montgomeryFactorisation b1 b2 s = case newPoint (toInteger (unMod s)) n of
241+
montgomeryFactorisation :: KnownNat n => Word -> PrimeSieve -> Word -> Mod n -> Maybe Integer
242+
montgomeryFactorisation b1 b1Sieve b2 s = case newPoint (toInteger (unMod s)) n of
245243
Nothing -> Nothing
246244
Just (SomePoint p0) -> do
247245
-- Small step: for each prime p <= b1
@@ -257,9 +255,7 @@ montgomeryFactorisation b1 b2 s = case newPoint (toInteger (unMod s)) n of
257255
g -> Just g
258256
where
259257
n = toInteger (natVal s)
260-
smallPowers
261-
= map findPower
262-
$ takeWhile (<= b1) (2 : 3 : 5 : list primeStore)
258+
smallPowers = map (findPower . fromIntegral) (atkinPrimeList b1Sieve)
263259
findPower p = go p
264260
where
265261
go acc
@@ -282,7 +278,7 @@ bigStep q b1 b2 = rs
282278
us * (pointZ p * pointX pq - pointX p * pointZ pq) `rem` n
283279
) ts qks) 1 qs
284280

285-
wheel :: Word
281+
wheel :: Num a => a
286282
wheel = 210
287283

288284
wheelCoprimes :: [Word]
@@ -307,15 +303,6 @@ enumAndMultiplyFromThenTo p from thn to = zip [from, thn .. to] progression
307303

308304
progression = pFrom : pThen : zipWith (\x0 x1 -> add x0 pStep x1) progression (tail progression)
309305

310-
-- primes, compactly stored as a bit sieve
311-
primeStore :: [PrimeSieve]
312-
primeStore = psieveFrom 7
313-
314-
-- generate list of primes from arrays
315-
list :: [PrimeSieve] -> [Word]
316-
list sieves = concat [[off + toPrim i | i <- [0 .. li], unsafeAt bs i]
317-
| PS vO bs <- sieves, let { (_,li) = bounds bs; off = fromInteger vO; }]
318-
319306
-- | @'smallFactors' n@ finds all prime divisors of @n > 1@ up to 2^16 by trial division and returns the
320307
-- list of these together with their multiplicities, and a possible remaining factor which may be composite.
321308
smallFactors :: Integer -> ([(Integer, Word)], Maybe Integer)
@@ -339,8 +326,10 @@ smallFactors n = case shiftToOddCount n of
339326
-- ("tier") return parameters B1, B2 and the number of curves to try
340327
-- before next "tier".
341328
-- Roughly based on http://www.mersennewiki.org/index.php/Elliptic_Curve_Method#Choosing_the_best_parameters_for_ECM
342-
testParms :: IntMap (Word, Word, Word)
343-
testParms = IM.fromList
329+
testParms :: IntMap (Word, PrimeSieve, Word, Word)
330+
testParms
331+
= IM.fromList
332+
$ map (\(k, (b1, b2, ct)) -> (k, (b1, atkinSieve 0 (fromIntegral b1), b2, ct)))
344333
[ (12, ( 400, 40000, 10))
345334
, (15, ( 2000, 200000, 25))
346335
, (20, ( 11000, 1100000, 90))
@@ -356,5 +345,7 @@ testParms = IM.fromList
356345
, (70, (2900000000, 290000000000, 340000))
357346
]
358347

359-
findParms :: Int -> (Word, Word, Word)
360-
findParms digs = maybe (wheel, 1000, 7) snd (IM.lookupLT digs testParms)
348+
findParms :: Int -> (Word, PrimeSieve, Word, Word)
349+
findParms digs
350+
= maybe (wheel, atkinSieve 0 wheel, 1000, 7) snd
351+
$ IM.lookupLT digs testParms

Math/NumberTheory/Primes/Sieve/Atkin.hs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ module Math.NumberTheory.Primes.Sieve.Atkin
1313
( atkinPrimeList
1414
, atkinSieve
1515
, atkinFromTo
16+
, PrimeSieve
1617
) where
1718

1819
import Control.Monad

Math/NumberTheory/Primes/Testing/Certified.hs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -227,20 +227,20 @@ findDecomposition n = go 1 n [] prms
227227
-- starting with curve s. Actually, this may loop infinitely, but the
228228
-- loop should not be entered before the heat death of the universe.
229229
findFactor :: Integer -> Int -> Integer -> Integer
230-
findFactor n digits s = case findLoop n lo hi count s of
230+
findFactor n digits s = case findLoop n lo loSieve hi count s of
231231
Left t -> findFactor n (digits+5) t
232232
Right f -> f
233233
where
234-
(lo,hi,count) = findParms digits
234+
(lo, loSieve, hi, count) = findParms digits
235235

236236
-- | Find a factor or say with which curve to continue.
237-
findLoop :: Integer -> Word -> Word -> Word -> Integer -> Either Integer Integer
238-
findLoop _ _ _ 0 s = Left s
239-
findLoop n lo hi ct s
237+
findLoop :: Integer -> Word -> PrimeSieve -> Word -> Word -> Integer -> Either Integer Integer
238+
findLoop _ _ _ _ 0 s = Left s
239+
findLoop n lo loSieve hi ct s
240240
| n <= s+2 = Left 6
241241
| otherwise = case someNatVal (fromInteger n) of
242-
SomeNat (_ :: Proxy t) -> case montgomeryFactorisation lo hi (fromInteger s :: Mod t) of
243-
Nothing -> findLoop n lo hi (ct-1) (s+1)
242+
SomeNat (_ :: Proxy t) -> case montgomeryFactorisation lo loSieve hi (fromInteger s :: Mod t) of
243+
Nothing -> findLoop n lo loSieve hi (ct-1) (s+1)
244244
Just fct
245245
| bailliePSW fct -> Right fct
246246
| otherwise -> Right (findFactor fct 8 (s+1))

0 commit comments

Comments
 (0)