-- |-- Module: Math.NumberTheory.ArithmeticFunctions.SieveBlock-- Copyright: (c) 2017 Andrew Lelechenko-- Licence: MIT-- Maintainer: Andrew Lelechenko <andrew.lelechenko@gmail.com>---- Bulk evaluation of arithmetic functions over continuous intervals-- without factorisation.--{-# LANGUAGE BangPatterns #-}{-# LANGUAGE MagicHash #-}{-# LANGUAGE ScopedTypeVariables #-}moduleMath.NumberTheory.ArithmeticFunctions.SieveBlock(runFunctionOverBlock ,SieveBlockConfig (..),multiplicativeSieveBlockConfig ,additiveSieveBlockConfig ,sieveBlock ,sieveBlockUnboxed ,sieveBlockMoebius )whereimportControl.Monad(forM_,when)importControl.Monad.ST(runST)importData.BitsimportData.CoerceimportqualifiedData.Vector.GenericasGimportqualifiedData.Vector.Generic.MutableasMGimportqualifiedData.VectorasVimportqualifiedData.Vector.UnboxedasUimportqualifiedData.Vector.Unboxed.MutableasMUimportGHC.ExtsimportMath.NumberTheory.ArithmeticFunctions.Class importMath.NumberTheory.ArithmeticFunctions.Moebius (Moebius ,sieveBlockMoebius )importMath.NumberTheory.Logarithms(wordLog2,integerLogBase')importMath.NumberTheory.Primes importMath.NumberTheory.Primes.Types importMath.NumberTheory.Roots(integerSquareRoot)importMath.NumberTheory.Utils.FromIntegral (wordToInt ,intToWord )-- | A record, which specifies a function to evaluate over a block.---- For example, here is a configuration for the totient function:---- > SieveBlockConfig-- > { sbcEmpty = 1-- > , sbcFunctionOnPrimePower = \p a -> (unPrime p - 1) * unPrime p ^ (a - 1)-- > , sbcAppend = (*)-- > }dataSieveBlockConfig a =SieveBlockConfig {forall a. SieveBlockConfig a -> a
sbcEmpty ::a -- ^ value of a function on 1,forall a. SieveBlockConfig a -> Prime Word -> Word -> a
sbcFunctionOnPrimePower ::Prime Word->Word->a -- ^ how to evaluate a function on prime powers,forall a. SieveBlockConfig a -> a -> a -> a
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 ::Numa =>(Prime Word->Word->a )->SieveBlockConfig a multiplicativeSieveBlockConfig :: forall a. Num a => (Prime Word -> Word -> a) -> SieveBlockConfig a
multiplicativeSieveBlockConfig Prime Word -> Word -> a
f =SieveBlockConfig {sbcEmpty :: a
sbcEmpty =a
1,sbcFunctionOnPrimePower :: Prime Word -> Word -> a
sbcFunctionOnPrimePower =Prime Word -> Word -> a
f ,sbcAppend :: a -> a -> a
sbcAppend =a -> a -> a
forall a. Num a => a -> a -> a
(*)}-- | Create a config for an additive function from its definition on prime powers.additiveSieveBlockConfig ::Numa =>(Prime Word->Word->a )->SieveBlockConfig a additiveSieveBlockConfig :: forall a. Num a => (Prime Word -> Word -> a) -> SieveBlockConfig a
additiveSieveBlockConfig Prime Word -> Word -> a
f =SieveBlockConfig {sbcEmpty :: a
sbcEmpty =a
0,sbcFunctionOnPrimePower :: Prime Word -> Word -> a
sbcFunctionOnPrimePower =Prime Word -> Word -> a
f ,sbcAppend :: a -> a -> a
sbcAppend =a -> a -> a
forall a. Num a => a -> a -> a
(+)}-- | 'runFunctionOverBlock' @f@ @x@ @l@ evaluates an arithmetic function-- for integers between @x@ and @x+l-1@ and returns a vector of length @l@.-- It completely avoids factorisation, so it is asymptotically faster than-- pointwise evaluation of @f@.---- Value of @f@ at 0, if zero falls into block, is undefined.---- Beware that for underlying non-commutative monoids the results may potentially-- differ from pointwise application via 'runFunction'.---- 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 ::ArithmeticFunction Worda ->Word->Word->V.Vectora runFunctionOverBlock :: forall a. ArithmeticFunction Word a -> Word -> Word -> Vector a
runFunctionOverBlock (ArithmeticFunction Prime Word -> Word -> m
f m -> a
g )=((m -> a) -> Vector m -> Vector a
forall (v :: * -> *) a b.
(Vector v a, Vector v b) =>
(a -> b) -> v a -> v b
G.mapm -> a
g (Vector m -> Vector a) -> (Word -> Vector m) -> Word -> Vector a
forall b c a. (b -> c) -> (a -> b) -> a -> c
.)((Word -> Vector m) -> Word -> Vector a)
-> (Word -> Word -> Vector m) -> Word -> Word -> Vector a
forall b c a. (b -> c) -> (a -> b) -> a -> c
.SieveBlockConfig m -> Word -> Word -> Vector m
forall (v :: * -> *) a.
Vector v a =>
SieveBlockConfig a -> Word -> Word -> v a
sieveBlock SieveBlockConfig {sbcEmpty :: m
sbcEmpty =m
forall a. Monoid a => a
mempty,sbcAppend :: m -> m -> m
sbcAppend =m -> m -> m
forall a. Semigroup a => a -> a -> a
(<>),sbcFunctionOnPrimePower :: Prime Word -> Word -> m
sbcFunctionOnPrimePower =(Prime Word -> Word -> m) -> Prime Word -> Word -> m
forall a b. Coercible a b => a -> b
coercePrime Word -> Word -> m
f }-- | Evaluate a function over a block in accordance to provided configuration.-- Value of @f@ at 0, if zero falls into block, is undefined.---- 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, following code lists smallest prime factors:---- >>> sieveBlock (SieveBlockConfig maxBound (\p _ -> unPrime p) min) 2 10 :: Data.Vector.Vector Word-- [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 -> [(unPrime p, k)]) (++)) 2 10 :: Data.Vector.Vector [(Word, Word)]-- [[(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 ::forallv a .G.Vectorv a =>SieveBlockConfig a ->Word->Word->v a sieveBlock :: forall (v :: * -> *) a.
Vector v a =>
SieveBlockConfig a -> Word -> Word -> v a
sieveBlock SieveBlockConfig a
_Word
_Word
0=v a
forall (v :: * -> *) a. Vector v a => v a
G.emptysieveBlock (SieveBlockConfig a
empty Prime Word -> Word -> a
f a -> a -> a
append )!Word
lowIndex' Word
len' =(forall s. ST s (v a)) -> v a
forall a. (forall s. ST s a) -> a
runST((forall s. ST s (v a)) -> v a) -> (forall s. ST s (v a)) -> v a
forall a b. (a -> b) -> a -> b
$doletlowIndex ::IntlowIndex :: Int
lowIndex =Word -> Int
wordToInt Word
lowIndex' len ::Intlen :: Int
len =Word -> Int
wordToInt Word
len' highIndex ::InthighIndex :: Int
highIndex =Int
lowIndex Int -> Int -> Int
forall a. Num a => a -> a -> a
+Int
len Int -> Int -> Int
forall a. Num a => a -> a -> a
-Int
1highIndex' ::WordhighIndex' :: Word
highIndex' =Int -> Word
intToWord Int
highIndex ps ::[Int]ps :: [Int]
ps =ifInt
highIndex Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<Int
4then[]else(Prime Int -> Int) -> [Prime Int] -> [Int]
forall a b. (a -> b) -> [a] -> [b]
mapPrime Int -> Int
forall a. Prime a -> a
unPrime [Int -> Prime Int
forall a.
(Bits a, Integral a, UniqueFactorisation a) =>
a -> Prime a
nextPrime Int
2..Int -> Prime Int
forall a.
(Bits a, Integral a, UniqueFactorisation a) =>
a -> Prime a
precPrime (Int -> Int
forall a. Integral a => a -> a
integerSquareRootInt
highIndex )]MVector s Word
as <-Int -> Word -> ST s (MVector (PrimState (ST s)) Word)
forall (m :: * -> *) a.
(PrimMonad m, Unbox a) =>
Int -> a -> m (MVector (PrimState m) a)
MU.replicateInt
len Word
1Mutable v s a
bs <-Int -> a -> ST s (Mutable v (PrimState (ST s)) a)
forall (m :: * -> *) (v :: * -> * -> *) a.
(PrimMonad m, MVector v a) =>
Int -> a -> m (v (PrimState m) a)
MG.replicateInt
len a
empty letdoPrime :: Int -> m ()
doPrime Int
2=doletfs :: Vector a
fs =Int -> (Int -> a) -> Vector a
forall a. Int -> (Int -> a) -> Vector a
V.generate(Word -> Int
wordLog2Word
highIndex' )(\Int
k ->Prime Word -> Word -> a
f (Word -> Prime Word
forall a. a -> Prime a
Prime Word
2)(Int -> Word
intToWord Int
k Word -> Word -> Word
forall a. Num a => a -> a -> a
+Word
1))npLow :: Word
npLow =(Word
lowIndex' Word -> Word -> Word
forall a. Num a => a -> a -> a
+Word
1)Word -> Int -> Word
forall a. Bits a => a -> Int -> a
`shiftR`Int
1npHigh :: Word
npHigh =Word
highIndex' Word -> Int -> Word
forall a. Bits a => a -> Int -> a
`shiftR`Int
1[Word] -> (Word -> m ()) -> m ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
t a -> (a -> m b) -> m ()
forM_[Word
npLow ..Word
npHigh ]((Word -> m ()) -> m ()) -> (Word -> m ()) -> m ()
forall a b. (a -> b) -> a -> b
$\np :: Word
np @(W#Word#
np# )->doletix :: Int
ix =Word -> Int
wordToInt (Word
np Word -> Int -> Word
forall a. Bits a => a -> Int -> a
`shiftL`Int
1)Int -> Int -> Int
forall a. Num a => a -> a -> a
-Int
lowIndex ::Inttz :: Int
tz =Int# -> Int
I#(Word# -> Int#
word2Int#(Word# -> Word#
ctz#Word#
np# ))MVector (PrimState m) Word -> (Word -> Word) -> Int -> m ()
forall (m :: * -> *) a.
(PrimMonad m, Unbox a) =>
MVector (PrimState m) a -> (a -> a) -> Int -> m ()
MU.unsafeModifyMVector s Word
MVector (PrimState m) Word
as (\Word
x ->Word
x Word -> Int -> Word
forall a. Bits a => a -> Int -> a
`shiftL`(Int
tz Int -> Int -> Int
forall a. Num a => a -> a -> a
+Int
1))Int
ix Mutable v (PrimState m) a -> (a -> a) -> Int -> m ()
forall (m :: * -> *) (v :: * -> * -> *) a.
(PrimMonad m, MVector v a) =>
v (PrimState m) a -> (a -> a) -> Int -> m ()
MG.unsafeModifyMutable v s a
Mutable v (PrimState m) a
bs (\a
y ->a
y a -> a -> a
`append` Vector a -> Int -> a
forall a. Vector a -> Int -> a
V.unsafeIndexVector a
fs Int
tz )Int
ix doPrime Int
p =doletp' :: Word
p' =Int -> Word
intToWord Int
p f0 :: a
f0 =Prime Word -> Word -> a
f (Word -> Prime Word
forall a. a -> Prime a
Prime Word
p' )Word
1logp :: Int
logp =Integer -> Integer -> Int
integerLogBase'(Int -> Integer
forall a. Integral a => a -> Integer
toIntegerInt
p )(Int -> Integer
forall a. Integral a => a -> Integer
toIntegerInt
highIndex )Int -> Int -> Int
forall a. Num a => a -> a -> a
-Int
1fs :: Vector a
fs =Int -> (Int -> a) -> Vector a
forall a. Int -> (Int -> a) -> Vector a
V.generateInt
logp (\Int
k ->Prime Word -> Word -> a
f (Word -> Prime Word
forall a. a -> Prime a
Prime Word
p' )(Int -> Word
intToWord Int
k Word -> Word -> Word
forall a. Num a => a -> a -> a
+Word
2))npLow :: Int
npLow =(Int
lowIndex Int -> Int -> Int
forall a. Num a => a -> a -> a
+Int
p Int -> Int -> Int
forall a. Num a => a -> a -> a
-Int
1)Int -> Int -> Int
forall a. Integral a => a -> a -> a
`quot`Int
p npHigh :: Int
npHigh =Int
highIndex Int -> Int -> Int
forall a. Integral a => a -> a -> a
`quot`Int
p [Int] -> (Int -> m ()) -> m ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
t a -> (a -> m b) -> m ()
forM_[Int
npLow ..Int
npHigh ]((Int -> m ()) -> m ()) -> (Int -> m ()) -> m ()
forall a b. (a -> b) -> a -> b
$\Int
np ->dolet!(I#Int#
ix# )=Int
np Int -> Int -> Int
forall a. Num a => a -> a -> a
*Int
p Int -> Int -> Int
forall a. Num a => a -> a -> a
-Int
lowIndex (Int
q ,Int
r )=Int
np Int -> Int -> (Int, Int)
forall a. Integral a => a -> a -> (a, a)
`quotRem`Int
p ifInt
r Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
/=Int
0thendoMVector (PrimState m) Word -> (Word -> Word) -> Int -> m ()
forall (m :: * -> *) a.
(PrimMonad m, Unbox a) =>
MVector (PrimState m) a -> (a -> a) -> Int -> m ()
MU.unsafeModifyMVector s Word
MVector (PrimState m) Word
as (Word -> Word -> Word
forall a. Num a => a -> a -> a
*Word
p' )(Int# -> Int
I#Int#
ix# )Mutable v (PrimState m) a -> (a -> a) -> Int -> m ()
forall (m :: * -> *) (v :: * -> * -> *) a.
(PrimMonad m, MVector v a) =>
v (PrimState m) a -> (a -> a) -> Int -> m ()
MG.unsafeModifyMutable v s a
Mutable v (PrimState m) a
bs (a -> a -> a
`append` a
f0 )(Int# -> Int
I#Int#
ix# )elsedoletpow :: Word
pow =Int -> Int -> Word
highestPowerDividing Int
p Int
q MVector (PrimState m) Word -> (Word -> Word) -> Int -> m ()
forall (m :: * -> *) a.
(PrimMonad m, Unbox a) =>
MVector (PrimState m) a -> (a -> a) -> Int -> m ()
MU.unsafeModifyMVector s Word
MVector (PrimState m) Word
as (\Word
x ->Word
x Word -> Word -> Word
forall a. Num a => a -> a -> a
*Word
p' Word -> Word -> Word
forall a b. (Num a, Integral b) => a -> b -> a
^(Word
pow Word -> Word -> Word
forall a. Num a => a -> a -> a
+Word
2))(Int# -> Int
I#Int#
ix# )Mutable v (PrimState m) a -> (a -> a) -> Int -> m ()
forall (m :: * -> *) (v :: * -> * -> *) a.
(PrimMonad m, MVector v a) =>
v (PrimState m) a -> (a -> a) -> Int -> m ()
MG.unsafeModifyMutable v s a
Mutable v (PrimState m) a
bs (\a
y ->a
y a -> a -> a
`append` Vector a -> Int -> a
forall a. Vector a -> Int -> a
V.unsafeIndexVector a
fs (Word -> Int
wordToInt Word
pow ))(Int# -> Int
I#Int#
ix# )[Int] -> (Int -> ST s ()) -> ST s ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
t a -> (a -> m b) -> m ()
forM_[Int]
ps Int -> ST s ()
forall {m :: * -> *}. (PrimState m ~ s, PrimMonad m) => Int -> m ()
doPrime [Int] -> (Int -> ST s ()) -> ST s ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
t a -> (a -> m b) -> m ()
forM_[Int
0..Int
len Int -> Int -> Int
forall a. Num a => a -> a -> a
-Int
1]((Int -> ST s ()) -> ST s ()) -> (Int -> ST s ()) -> ST s ()
forall a b. (a -> b) -> a -> b
$\Int
k ->doWord
a <-MVector (PrimState (ST s)) Word -> Int -> ST s Word
forall (m :: * -> *) a.
(PrimMonad m, Unbox a) =>
MVector (PrimState m) a -> Int -> m a
MU.unsafeReadMVector s Word
MVector (PrimState (ST s)) Word
as Int
k leta' :: Word
a' =Int -> Word
intToWord (Int
k Int -> Int -> Int
forall a. Num a => a -> a -> a
+Int
lowIndex )Bool -> ST s () -> ST s ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when(Word
a Word -> Word -> Bool
forall a. Eq a => a -> a -> Bool
/=Word
a' )(ST s () -> ST s ()) -> ST s () -> ST s ()
forall a b. (a -> b) -> a -> b
$Mutable v (PrimState (ST s)) a -> (a -> a) -> Int -> ST s ()
forall (m :: * -> *) (v :: * -> * -> *) a.
(PrimMonad m, MVector v a) =>
v (PrimState m) a -> (a -> a) -> Int -> m ()
MG.unsafeModifyMutable v s a
Mutable v (PrimState (ST s)) a
bs (\a
b ->a
b a -> a -> a
`append` Prime Word -> Word -> a
f (Word -> Prime Word
forall a. a -> Prime a
Prime (Word -> Prime Word) -> Word -> Prime Word
forall a b. (a -> b) -> a -> b
$Word
a' Word -> Word -> Word
forall a. Integral a => a -> a -> a
`quot`Word
a )Word
1)Int
k Mutable v (PrimState (ST s)) a -> ST s (v a)
forall (m :: * -> *) (v :: * -> *) a.
(PrimMonad m, Vector v a) =>
Mutable v (PrimState m) a -> m (v a)
G.unsafeFreezeMutable v s a
Mutable v (PrimState (ST s)) a
bs -- This is a variant of 'Math.NumberTheory.Utils.splitOff',-- specialized for better performance.highestPowerDividing ::Int->Int->WordhighestPowerDividing :: Int -> Int -> Word
highestPowerDividing !Int
_Int
0=Word
0highestPowerDividing Int
p Int
n =Word -> Int -> Word
forall {t}. Num t => t -> Int -> t
go Word
0Int
n wherego :: t -> Int -> t
go !t
k Int
m =caseInt
m Int -> Int -> (Int, Int)
forall a. Integral a => a -> a -> (a, a)
`quotRem`Int
p of(Int
q ,Int
0)->t -> Int -> t
go (t
k t -> t -> t
forall a. Num a => a -> a -> a
+t
1)Int
q (Int, Int)
_->t
k -- | This is 'sieveBlock' specialized to unboxed vectors.---- >>> sieveBlockUnboxed (SieveBlockConfig 1 (\_ a -> a + 1) (*)) 1 10-- [1,2,2,3,2,4,2,4,3,4]sieveBlockUnboxed ::U.Unboxa =>SieveBlockConfig a ->Word->Word->U.Vectora sieveBlockUnboxed :: forall a. Unbox a => SieveBlockConfig a -> Word -> Word -> Vector a
sieveBlockUnboxed =SieveBlockConfig a -> Word -> Word -> Vector a
forall (v :: * -> *) a.
Vector v a =>
SieveBlockConfig a -> Word -> Word -> v a
sieveBlock {-# SPECIALIZEsieveBlockUnboxed ::SieveBlockConfig Int->Word->Word->U.VectorInt#-}{-# SPECIALIZEsieveBlockUnboxed ::SieveBlockConfig Word->Word->Word->U.VectorWord#-}{-# SPECIALIZEsieveBlockUnboxed ::SieveBlockConfig Bool->Word->Word->U.VectorBool#-}{-# SPECIALIZEsieveBlockUnboxed ::SieveBlockConfig Moebius ->Word->Word->U.VectorMoebius #-}

AltStyle によって変換されたページ (->オリジナル) /