packages feed

Flint2-Examples-0.1.0.0: app/poly_roots/Main.hs

import System.TimeIt

import Foreign.Ptr (Ptr, nullPtr, plusPtr)
import Foreign.C.Types
import Foreign.C.String
import Foreign.Storable
import Foreign.Marshal.Array

import Options.Applicative
import Options.Applicative.Help.Pretty

import Control.Monad
import Data.IORef

import Data.Number.Flint

-- main = putStrLn "done"

main = timeItNamed "time"
     $ run =<< customExecParser (prefs showHelpOnEmpty) opts where
  opts = info (parameters <**> helper) (
         fullDesc
      <> progDesc "Isolates all the complex roots of a polynomial with \
                  \integer coefficients.."
      <> header "Roots of polynomials")

run params@(Parameters digitsRefine digitsPrint polys) = do
  let prec = case digitsRefine of
               Just digits -> round $ fromIntegral digits / logBase 10 2 + 2
               Nothing     -> 16
  print params
  if not (null polys) then do
    pols <- product <$> mapM getPolynomial polys
    forM_ (factor pols) $ \(poly, e) -> do
      putStrLn $ "polynomial expression " ++ show poly 
               ++ " with multiplicity " ++ show e 
      withFmpzPoly poly $ \p -> do
        n <- fmpz_poly_degree p
        putStrLn $ "polynomial degree: " ++ show n
        z <- _acb_vec_init n
        arb_fmpz_poly_complex_roots z p arb_fmpz_poly_roots_verbose prec
        case digitsPrint of
          Just digits -> do
            forM_ [0..fromIntegral n-1] $ \j -> do
              acb_printn (z.+.j) digits arb_str_no_radius
              putStr "\n"
          Nothing -> return ()
        _acb_vec_clear z n
      return ()
  else do
    putStrLn $ "no polynomial expression given."

(.+.) x y = x `advancePtr` (fromIntegral y)

getPolynomial :: Polynomial -> IO FmpzPoly
getPolynomial x =
  case x of
    A n -> easyA n
    T n -> chebyshevT n
    U n -> chebyshevT n
    P n -> legendreP' n
    C n -> cyclotomicC n
    S n -> swinnertonDyerS n
    B n -> bernoulliB' n

data Polynomial
  = A CULong
  | T CULong
  | U CULong
  | P CULong
  | C CULong
  | S CULong
  | B CULong
  | W CULong
  | E CULong
  | M CULong
  | Coeffs [Integer]
  deriving Show

-- Parser ----------------------------------------------------------------------

data Parameters = Parameters {
  digitsRefine :: Maybe CLong
, digitsPrint :: Maybe CLong
, poly :: [Polynomial]
} deriving Show

parameters :: Parser Parameters
parameters = Parameters
  <$> optional ( option auto (
      help "the roots are refined to a relative tolerance\
           \better than 10^(-d). By default, the roots are \
           \only computed to sufficient\
           \accuracy to isolate them. The refinement is not\
           \currently done efficiently"
   <> long "refine"
   <> short 'r'
   <> metavar "RELATIVE-TOLERANCE"))
  <*> optional ( option auto (
      help "computed roots are printed to d decimals. \
           \By default, the roots are not printed."
   <> short 'd'
   <> long "print"
   <> metavar "DIGITS") )
  <*> many polynomial

polynomial :: Parser Polynomial
polynomial = subparser cmds where
  cmds = mconcat $ zipWith mkCmd desc [a, t, u, p, phi, s, b, w, e, m, coeffs]
  mkCmd x y = command (takeWhile (/=' ') x) (info y (progDesc x))

desc =
  [ "a <n>      Easy polynomial 1 + 2x + ... + (n+1)x^n"
  , "t <n>      Chebyshev polynomial T_n"
  , "u <n>      Chebyshev polynomial U_n"
  , "p <n>      Legendre polynomial P_n"
  , "c <n>      Cyclotomic polynomial Phi_n"
  , "s <n>      Swinnerton-Dyer polynomial S_n"
  , "b <n>      Bernoulli polynomial B_n"
  , "w <n>      Wilkinson polynomial W_n"
  , "e <n>      Taylor series of exp(x) truncated to degree n"
  , "m <n> <m>  The Mignotte-like polynomial x^n + (100x+1)^m, n > m"
  , "coeffs <c0 c1 ... cn>        c0 + c1 x + ... + cn x^n"
  ]

a, t, u, p, phi, s, b, w, e, m, coeffs :: Parser Polynomial

a   = A   <$> argument auto (metavar "n")
t   = T   <$> argument auto (metavar "n")
u   = U   <$> argument auto (metavar "n")
p   = P   <$> argument auto (metavar "n")
phi = C   <$> argument auto (metavar "n")
s   = S   <$> argument auto (metavar "n")
b   = B   <$> argument auto (metavar "n")
w   = W   <$> argument auto (metavar "n")
e   = E   <$> argument auto (metavar "n")
m   = M   <$> argument auto (metavar "n")
coeffs = Coeffs <$> many (argument auto (metavar "coeffs"))

-- polynomials -----------------------------------------------------------------

-- Legendre polynomial (denominator removed)
legendreP' n = do
  (poly, _) <- withNewFmpzPoly $ \p -> do
    withNewFmpqPoly $ \h -> do
      fmpq_poly_legendre_p h n
      fmpq_poly_get_numerator p h
  return poly

chebyshevT n = do
  (poly, _) <- withNewFmpzPoly $ \p -> do
    fmpz_poly_chebyshev_t p n
  return poly

chebyshevU n = do
  (poly, _) <- withNewFmpzPoly $ \p -> do
    fmpz_poly_chebyshev_u p n
  return poly

cyclotomicC n = do
  (poly, _) <- withNewFmpzPoly $ \p -> do
    fmpz_poly_cyclotomic  p n
  return poly

swinnertonDyerS n = do
  (poly, _) <- withNewFmpzPoly $ \p -> do
    fmpz_poly_swinnerton_dyer p n
  return poly

-- Bernoulli polynomial (denominator removed)
bernoulliB' n = do
  (poly, _) <- withNewFmpzPoly $ \p -> do
    withNewFmpqPoly $ \h -> do
      arith_bernoulli_polynomial h n
      fmpq_poly_get_numerator p h
  return poly

easyA n = do
  let poly = fromList (map fromIntegral [1..n]) :: FmpzPoly
  return poly