Files
haskell-math/app/FactorizationUI.hs
T
2026-10-17 13:35:55 +02:00

138 lines
4.8 KiB
Haskell

module FactorizationUI (run) where
import System.Exit (exitSuccess)
import Utils (askChoice, askNumber)
import PrimeFactors (primeFactors, formatFactors)
import Factorization
( fermatFactorization, pollardPminus1, dixon, dixonDefaultParams
, gnfsWith, GNFSParams(..), defaultParams
)
run :: IO ()
run = do
putStrLn "Factorization"
putStrLn "1) Fermat factorization"
putStrLn "2) Pollard p-1"
putStrLn "3) Dixon"
putStrLn "4) General Number Field Sieve (GNFS)"
putStrLn "5) Prime factors (GNFS)"
choice <- askChoice 5
case choice of
1 -> fermatUI
2 -> pollardUI
3 -> dixonUI
4 -> gnfsUI
5 -> primeFactorsUI
_ -> error "Impossible"
fermatUI :: IO ()
fermatUI = do
n <- askNumber "Enter an integer n > 1:"
let (p, q) = fermatFactorization n
putStrLn ("n = " ++ show n)
putStrLn ("p = " ++ show p)
putStrLn ("q = " ++ show q)
pollardUI :: IO ()
pollardUI = do
n <- askNumber "Enter an integer n > 1:"
b <- askNumber "Enter the bound B:"
case pollardPminus1 n b of
Just factor -> do
putStrLn ("Found factor: " ++ show factor)
putStrLn ("Other factor: " ++ show (n `div` factor))
Nothing ->
putStrLn "Failed to find a factor (try a different B or method)."
dixonUI :: IO ()
dixonUI = do
putStrLn "Dixon"
putStrLn "Factors a composite n (not a prime, a perfect square or a prime power)."
putStrLn "Practical for n up to roughly 22 digits; 24 digits already takes a minute or two."
n <- askNumber "Enter an integer n > 1:"
putStrLn "Parameters:"
putStrLn "1) Automatic (recommended)"
putStrLn "2) Custom"
mode <- askChoice 2
let (autoB, autoX) = dixonDefaultParams n
(b, x) <- case mode of
1 -> return (autoB, autoX)
_ -> do
putStrLn ("Automatic values for this n: bound B = " ++ show autoB
++ ", max x = " ++ show autoX)
b' <- askNumber "Enter the bound B:"
x' <- askNumber "Enter the max integer x (the search starts at floor(sqrt n) + 1):"
return (b', x')
putStrLn "Running Dixon (this may take a while)..."
case dixon n b x of
Left err -> do
putStrLn ("Error: " ++ err)
if mode == 1
then putStrLn "Check that n is composite and not a perfect square or a prime power."
else return ()
Right (p, q) -> do
putStrLn ("n = " ++ show n)
putStrLn ("p = " ++ show p)
putStrLn ("q = " ++ show q)
gnfsUI :: IO ()
gnfsUI = do
putStrLn "General Number Field Sieve"
putStrLn "Factors a composite n (not a prime or a prime power) into two non-trivial factors."
putStrLn "Practical for n up to roughly 30 digits; the running time grows quickly beyond that."
n <- askNumber "Enter an integer n > 1:"
putStrLn "Parameters:"
putStrLn "1) Automatic (recommended)"
putStrLn "2) Custom"
mode <- askChoice 2
let auto = defaultParams n
params <- case mode of
1 -> return auto
_ -> do
putStrLn ("Automatic values for this n: degree = " ++ show (paramDegree auto)
++ ", bound B = " ++ show (paramRatBound auto)
++ ", sieve half-width = " ++ show (paramHalfWidth auto))
d <- askNumber "Enter the polynomial degree d (odd, 3 or 5):"
if d /= 3 && d /= 5
then do
putStrLn "The degree must be 3 or 5."
exitSuccess
else return ()
b <- askNumber "Enter the factor base bound B (used for both bases):"
w <- askNumber "Enter the sieve half-width (a ranges over [-w, w]):"
return auto { paramDegree = fromInteger d
, paramRatBound = b
, paramAlgBound = b
, paramHalfWidth = fromInteger w
}
putStrLn "Running GNFS (this may take a while)..."
case gnfsWith params n of
Left err ->
putStrLn ("Error: " ++ err)
Right (p, q) -> do
putStrLn ("n = " ++ show n)
putStrLn ("p = " ++ show p)
putStrLn ("q = " ++ show q)
primeFactorsUI :: IO ()
primeFactorsUI = do
putStrLn "Prime factors (GNFS)"
putStrLn "Decomposes n into its prime factors."
putStrLn "Large composites are split with the General Number Field Sieve, so numbers with more than about 30 digits may take very long."
n <- askNumber "Enter an integer n > 1:"
putStrLn "Running (this may take a while)..."
case primeFactors n of
Left err ->
putStrLn ("Error: " ++ err)
Right factors ->
putStrLn (show n ++ " = " ++ formatFactors factors)