115 lines
4.3 KiB
Haskell
115 lines
4.3 KiB
Haskell
module GNFS.FactorBase
|
|
( Relation(..)
|
|
, FactorBase(..)
|
|
, buildFactorBase
|
|
, relationRow
|
|
) where
|
|
|
|
import Data.Bits (setBit)
|
|
import Data.List (foldl')
|
|
import qualified Data.Map.Strict as M
|
|
|
|
import GNFS.FiniteField (rootsModP)
|
|
import GNFS.PolySelect (NFSPoly(..))
|
|
import GNFS.Polynomial
|
|
import GNFS.Util (primesFrom, modInv)
|
|
import LinearAlgebra.GF2 (BitVec)
|
|
import ModularArithmeticUtils (legendre)
|
|
import Primes.ErathosteneSieve (erathosteneSieve)
|
|
|
|
-- | A relation: the pair (a, b) with a - b*m smooth over the rational base and
|
|
-- a - b*alpha smooth over the algebraic base, with the full exponent data.
|
|
data Relation = Relation
|
|
{ relA :: !Integer
|
|
, relB :: !Integer
|
|
, relRat :: [(Integer, Int)] -- prime -> exponent of |a - b m|
|
|
, relAlg :: [((Integer, Integer), Int)] -- (p, r) -> valuation of a - b alpha
|
|
} deriving Show
|
|
|
|
data FactorBase = FactorBase
|
|
{ fbPoly :: NFSPoly
|
|
, fbRat :: [Integer] -- rational base: primes up to the bound
|
|
, fbAlg :: [(Integer, Integer)] -- algebraic base: (p, r), f(r) = 0 mod p, simple root
|
|
, fbAlgPrimes :: [Integer] -- distinct primes occurring in fbAlg
|
|
, fbAlgLifts :: [(Integer, [(Integer, Integer)])]
|
|
-- per prime p: for each root r, the Hensel lifts
|
|
-- (p^k, r_k) for k = 1, 2, ... (lazy, infinite)
|
|
, fbReal :: [Double] -- real roots of f (sign columns)
|
|
, fbQC :: [(Integer, Integer)] -- quadratic-character primes (q, s)
|
|
, fbColRat :: M.Map Integer Int
|
|
, fbColAlg :: M.Map (Integer, Integer) Int
|
|
, fbNumCols :: Int
|
|
}
|
|
|
|
-- | Build the three factor bases (rational, algebraic, quadratic characters).
|
|
buildFactorBase :: NFSPoly -> Integer -> Integer -> Int -> FactorBase
|
|
buildFactorBase np ratBound algBound nQC = fb
|
|
where
|
|
f = npCoeffs np
|
|
f' = derivP f
|
|
rat = erathosteneSieve ratBound
|
|
-- primes whose roots are all simple; primes with a repeated root are dropped
|
|
algPrimeRoots =
|
|
[ (p, rs)
|
|
| p <- erathosteneSieve algBound
|
|
, let rs = rootsModP p f
|
|
, not (null rs)
|
|
, all (\r -> evalP f' r `mod` p /= 0) rs
|
|
]
|
|
alg = [ (p, r) | (p, rs) <- algPrimeRoots, r <- rs ]
|
|
qc = take nQC
|
|
[ (q, s)
|
|
| q <- primesFrom (max algBound ratBound + 1)
|
|
, let rs = rootsModP q f
|
|
, s <- rs
|
|
, evalP f' s `mod` q /= 0
|
|
]
|
|
reals = realRoots f
|
|
-- Hensel lifting of a simple root r of f mod p to roots mod p^k
|
|
lifts p r0 = go p r0
|
|
where
|
|
go q rk =
|
|
let q' = q * p
|
|
inv = case modInv (evalP f' rk) q' of
|
|
Just i -> i
|
|
Nothing -> error "Hensel lift: derivative not invertible"
|
|
rk' = (rk - evalP f rk * inv) `mod` q'
|
|
in (q, rk) : go q' rk'
|
|
nRat = length rat
|
|
nAlg = length alg
|
|
fb = FactorBase
|
|
{ fbPoly = np
|
|
, fbRat = rat
|
|
, fbAlg = alg
|
|
, fbAlgPrimes = map fst algPrimeRoots
|
|
, fbAlgLifts = [ (p, lifts p r) | (p, r) <- alg ]
|
|
, fbReal = reals
|
|
, fbQC = qc
|
|
, fbColRat = M.fromList (zip rat [0 ..])
|
|
, fbColAlg = M.fromList (zip alg [0 ..])
|
|
, fbNumCols = 1 + nRat + nAlg + length reals + length qc
|
|
}
|
|
|
|
-- | Parity vector of a relation. Column layout:
|
|
-- [0] sign of a - b m | rational primes | algebraic ideals | real-place signs | quadratic characters
|
|
relationRow :: FactorBase -> Relation -> BitVec
|
|
relationRow fb rel = foldl' setBit 0 cols
|
|
where
|
|
a = relA rel
|
|
b = relB rel
|
|
m = npM (fbPoly fb)
|
|
nRat = length (fbRat fb)
|
|
nAlg = length (fbAlg fb)
|
|
offAlg = 1 + nRat
|
|
offReal = offAlg + nAlg
|
|
offQC = offReal + length (fbReal fb)
|
|
signCol = [ 0 | a - b * m < 0 ]
|
|
ratCols = [ 1 + fbColRat fb M.! p | (p, e) <- relRat rel, odd e ]
|
|
algCols = [ offAlg + fbColAlg fb M.! pr | (pr, e) <- relAlg rel, odd e ]
|
|
realCols = [ offReal + j | (j, th) <- zip [0 ..] (fbReal fb)
|
|
, fromInteger a < fromInteger b * th ]
|
|
qcCols = [ offQC + j | (j, (q, s)) <- zip [0 ..] (fbQC fb)
|
|
, let v = (a - b * s) `mod` q
|
|
, legendre v q == q - 1 ]
|
|
cols = signCol ++ ratCols ++ algCols ++ realCols ++ qcCols
|