packages feed

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

import System.IO.Unsafe
import Options.Applicative
import Control.Monad
import Control.Monad.State
import Foreign.C.Types
import Foreign.Marshal.Array 

import Data.Number.Flint

main = run =<< execParser opts where
  desc = "Reports the imaginary parts of consecutive nontrivial zeros \
         \of the Riemann zeta function starting with the nth zero."
  opts = info (options <**> helper) (
         fullDesc
      <> progDesc desc
      <> header desc)

run opts@(Options n_start count accuracy platt verbosity num_threads) = do
  when (verbosity > 0) $ do print opts
  if platt && n_start < 10000 then do
    putStrLn "This implementation of the platt algorithm \
             \is not valid\n below the 10000th zero.\n"
  else do
    flint_set_num_threads num_threads
    let (prec, digs) = case accuracy of
          Just (Precision p) -> (p, d2p p)
          Just (Digits d)    -> (p2d d, d)
          Nothing  -> (pDefault, p2d pDefault)
          where pDefault = 64 + ceiling (logBase 2 (fromIntegral n_start))
        d2p p = round (fromIntegral p * log 2 + 1)
        p2d d = round (fromIntegral d / log 2 + 3)
        requested = fromIntegral $ min count 30000 
        usePlatt = platt || (requested > 100 && n_start > 10^11)
        workingPrecision = if platt then 2*prec else prec
        digits = p2d workingPrecision
    p <- _arb_vec_init requested
    let n = fromInteger n_start :: Fmpz
    -- _ <- runStateT (calculate p platt requested prec digits) (n, 0, 0, 0)
    -- return ()
    withFmpz n $ \n -> do
       if not platt then do
         acb_dirichlet_hardy_z_zeros p n requested prec
         print_zeros p n_start requested digits
       else do 
         found <- acb_dirichlet_platt_local_hardy_z_zeros p n requested prec
         if ( found > 0 ) then do
           print_zeros p n_start found digits
         else do
           putStrLn "Failed to find some zero.\nIncrease precision.\n"
    _arb_vec_clear p $ fromIntegral requested

-- calculate :: Ptr CArb -> Bool -> Integer -> CLong -> CLong
--           -> StateT (Fmpz, Integer, Integer, Integer) IO ()
-- calculate p platt requested prec digits = do
--   (n, iter, count, num_old) <- get
--   let num = if count + num_old > requested then requested-count-1 else 2*num_old
--   withFmpz n $ \n -> do 
--     if not platt then do
--       acb_dirichlet_hardy_z_zeros p n num prec
--       print_zeros p n_start num digits
--       fmpz_add_ui n n (fromIntegral num)
--       put (n, succ iter, count + num, num)
--     else do
--       found <- acb_dirichlet_platt_local_hardy_z_zeros p n num prec
--       print_zeros p n_start found digits
--       if ( found > 0 ) then do
--         print_zeros p n_start found digits
--       else do
--         error "Failed to find some zero.\nIncrease precision.\n"
--       fmpz_add_ui n n (fromIntegral found)
--       put (n, succ iter, count + found, num)
--   when (count < requested) $ do calculate p platt requested prec digits

 
data Options = Options {
  n_start :: Integer
, count :: Integer
, accuracy :: Maybe Accuracy
, platt :: Bool
, verbosity :: Int
, num_threads :: CInt
} deriving Show

data Accuracy = Precision CLong | Digits CLong deriving Show

-- option parser ---------------------------------------------------------------

options :: Parser Options
options = Options
  <$> option pos (
      help "integer n > 0. start from nth zero."
   <> short 'n'
   <> value 1
   <> metavar "n")
  <*> option pos (
      help "number of zeros to calculate (<30000)."
   <> long "count"
   <> short 'c'
   <> value 30000
   <> metavar "count")
  <*> optional optionAccuracy
  <*> switch (
      help "use platt algorithm."
   <> showDefault
   <> long "platt")
  <*> option pos (
      help "verbosity."
   <> long "verbosity"
   <> short 'v'
   <> value 0
   <> metavar "verbosity")
  <*> option pos (
      help "number of threads."
   <> long "threads"
   <> short 't'
   <> value 1
   <> metavar "threads")

optionAccuracy = optionPrecision <|> optionDigits

optionPrecision :: Parser Accuracy
optionPrecision =  Precision <$> option pos (
      help "precision."
   <> long "prec"
   <> short 'p'
   <> metavar "precision")

optionDigits :: Parser Accuracy
optionDigits = Digits <$> option pos (
      help "number of digits."
   <> long "digits"
   <> short 'd'
   <> metavar "digits")
   
pos :: (Read a, Integral a) => ReadM a
pos = eitherReader $ \s -> do
  let result = read s
  if result >= 0 then 
    Right result
  else
    Left "expected positive number"

--------------------------------------------------------------------------------

print_zeros p n_start len digits = do
  forM_ [0 .. fromIntegral len - 1] $ \j -> do
    putStr $ show (fromIntegral n_start + j) ++ "\t"
    arb_printn (p `advancePtr` j) digits arb_str_no_radius
    putStr "\n"
-- print_zeros p n len digits = do
--   withNewFmpz $ \k -> do
--     fmpz_set k n
--     forM_ [0 .. len-1] $ \i -> do
--       fmpz_print k
--       putStr "\t"
--       arb_printn (p `advancePtr` i) digits arb_str_no_radius
--       putStr "\n"
--       fmpz_add_ui k k 1