{-# LINE 1 "src/Data/Number/Flint/Bernoulli/FFI.hsc" #-}
{-|
module      :  Data.Number.Flint.Bernoulli.FFI
copyright   :  (c) 2022 Hartmut Monien
license     :  GNU GPL, version 2 or above (see LICENSE)
maintainer  :  hmonien@uni-bonn.de
-}
module Data.Number.Flint.Bernoulli.FFI (
  -- * Support for Bernoulli numbers
  -- * Generation of Bernoulli numbers
    BernoulliRev (..)
  , CBernoulliRev (..)
  , newBernoulliRev
  , withBernoulliRev
  , withNewBernoulliRev
  , bernoulli_rev_init
  , bernoulli_rev_next
  , bernoulli_rev_clear
  , bernoulli_fmpq_vec_no_cache
  -- * Caching
  , bernoulli_cache_compute
  -- * Bounding
  , bernoulli_bound_2exp_si
  -- * Isolated Bernoulli numbers
  , bernoulli_mod_p_harvey
  , _bernoulli_fmpq_ui_zeta
  , _bernoulli_fmpq_ui_multi_mod
  , _bernoulli_fmpq_ui
  , bernoulli_fmpq_ui
) where

-- Support for Bernoulli numbers -----------------------------------------------

import Foreign.Ptr
import Foreign.ForeignPtr
import Foreign.C.Types
import Foreign.Storable

import Data.Number.Flint.Flint
import Data.Number.Flint.Fmpz
import Data.Number.Flint.Fmpq

import Data.Number.Flint.Arb.Types
import Data.Number.Flint.Acb.Types



-- bernoulli_rev_t -------------------------------------------------------------

data BernoulliRev = BernoulliRev {-# UNPACK #-} !(ForeignPtr CBernoulliRev)
type CBernoulliRev = CFlint BernoulliRev

instance Storable CBernoulliRev where
  sizeOf :: CBernoulliRev -> Int
sizeOf    CBernoulliRev
_ = (Int
144)
{-# LINE 54 "src/Data/Number/Flint/Bernoulli/FFI.hsc" #-}
  alignment _ = 8
{-# LINE 55 "src/Data/Number/Flint/Bernoulli/FFI.hsc" #-}
  peek = error "CBernoulliRev.peek: not implemented."
  poke :: Ptr CBernoulliRev -> CBernoulliRev -> IO ()
poke = [Char] -> Ptr CBernoulliRev -> CBernoulliRev -> IO ()
forall a. HasCallStack => [Char] -> a
error [Char]
"CBernoulliRev.poke: not implemented."
  
newBernoulliRev :: CULong -> IO BernoulliRev
newBernoulliRev CULong
n = do
  ForeignPtr CBernoulliRev
x <- IO (ForeignPtr CBernoulliRev)
forall a. Storable a => IO (ForeignPtr a)
mallocForeignPtr
  ForeignPtr CBernoulliRev -> (Ptr CBernoulliRev -> IO ()) -> IO ()
forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
withForeignPtr ForeignPtr CBernoulliRev
x ((Ptr CBernoulliRev -> IO ()) -> IO ())
-> (Ptr CBernoulliRev -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \Ptr CBernoulliRev
x -> do
    Ptr CBernoulliRev -> CULong -> IO ()
bernoulli_rev_init Ptr CBernoulliRev
x CULong
n
  FinalizerPtr CBernoulliRev -> ForeignPtr CBernoulliRev -> IO ()
forall a. FinalizerPtr a -> ForeignPtr a -> IO ()
addForeignPtrFinalizer FinalizerPtr CBernoulliRev
p_bernoulli_rev_clear ForeignPtr CBernoulliRev
x
  BernoulliRev -> IO BernoulliRev
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (BernoulliRev -> IO BernoulliRev)
-> BernoulliRev -> IO BernoulliRev
forall a b. (a -> b) -> a -> b
$ ForeignPtr CBernoulliRev -> BernoulliRev
BernoulliRev ForeignPtr CBernoulliRev
x

withBernoulliRev :: BernoulliRev -> (Ptr CBernoulliRev -> IO a) -> IO (BernoulliRev, a)
withBernoulliRev (BernoulliRev ForeignPtr CBernoulliRev
x) Ptr CBernoulliRev -> IO a
f = do
  ForeignPtr CBernoulliRev
-> (Ptr CBernoulliRev -> IO (BernoulliRev, a))
-> IO (BernoulliRev, a)
forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
withForeignPtr ForeignPtr CBernoulliRev
x ((Ptr CBernoulliRev -> IO (BernoulliRev, a))
 -> IO (BernoulliRev, a))
-> (Ptr CBernoulliRev -> IO (BernoulliRev, a))
-> IO (BernoulliRev, a)
forall a b. (a -> b) -> a -> b
$ \Ptr CBernoulliRev
xp -> (ForeignPtr CBernoulliRev -> BernoulliRev
BernoulliRev ForeignPtr CBernoulliRev
x,) (a -> (BernoulliRev, a)) -> IO a -> IO (BernoulliRev, a)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Ptr CBernoulliRev -> IO a
f Ptr CBernoulliRev
xp

withNewBernoulliRev :: CULong -> (Ptr CBernoulliRev -> IO a) -> IO (BernoulliRev, a)
withNewBernoulliRev CULong
n Ptr CBernoulliRev -> IO a
f = do
  BernoulliRev
x <- CULong -> IO BernoulliRev
newBernoulliRev CULong
n
  BernoulliRev -> (Ptr CBernoulliRev -> IO a) -> IO (BernoulliRev, a)
forall {a}.
BernoulliRev -> (Ptr CBernoulliRev -> IO a) -> IO (BernoulliRev, a)
withBernoulliRev BernoulliRev
x Ptr CBernoulliRev -> IO a
f
  
-- Generation of Bernoulli numbers ---------------------------------------------

-- | /bernoulli_rev_init/ /iter/ /n/ 
-- 
-- Initializes the iterator /iter/. The first Bernoulli number to be
-- generated by calling @bernoulli_rev_next@ is \(B_n\). It is assumed that
-- \(n\) is even.
foreign import ccall "bernoulli.h bernoulli_rev_init"
  bernoulli_rev_init :: Ptr CBernoulliRev -> CULong -> IO ()

-- | /bernoulli_rev_next/ /numer/ /denom/ /iter/ 
-- 
-- Sets /numer/ and /denom/ to the exact, reduced numerator and denominator
-- of the Bernoulli number \(B_k\) and advances the state of /iter/ so that
-- the next invocation generates \(B_{k-2}\).
foreign import ccall "bernoulli.h bernoulli_rev_next"
  bernoulli_rev_next :: Ptr CFmpz -> Ptr CFmpz -> Ptr CBernoulliRev -> IO ()

-- | /bernoulli_rev_clear/ /iter/ 
-- 
-- Frees all memory allocated internally by /iter/.
foreign import ccall "bernoulli.h bernoulli_rev_clear"
  bernoulli_rev_clear :: Ptr CBernoulliRev -> IO ()

foreign import ccall "bernoulli.h &bernoulli_rev_clear"
  p_bernoulli_rev_clear :: FunPtr (Ptr CBernoulliRev -> IO ())

-- | /bernoulli_fmpq_vec_no_cache/ /res/ /a/ /num/ 
-- 
-- Writes /num/ consecutive Bernoulli numbers to /res/ starting with
-- \(B_a\). This function is not currently optimized for a small count
-- /num/. The entries are not read from or written to the Bernoulli number
-- cache; if retrieving a vector of Bernoulli numbers is needed more than
-- once, use @bernoulli_cache_compute@ followed by @bernoulli_fmpq_ui@
-- instead.
-- 
-- This function is a wrapper for the /rev/ iterators. It can use multiple
-- threads internally.
foreign import ccall "bernoulli.h bernoulli_fmpq_vec_no_cache"
  bernoulli_fmpq_vec_no_cache :: Ptr CFmpq -> CULong -> CLong -> IO ()

-- Caching ---------------------------------------------------------------------

-- | /bernoulli_cache_compute/ /n/ 
-- 
-- Makes sure that the Bernoulli numbers up to at least \(B_{n-1}\) are
-- cached. Calling @flint_cleanup()@ frees the cache.
-- 
-- The cache is extended by calling @bernoulli_fmpq_vec_no_cache@
-- internally.
foreign import ccall "bernoulli.h bernoulli_cache_compute"
  bernoulli_cache_compute :: CLong -> IO ()

-- Bounding --------------------------------------------------------------------

-- | /bernoulli_bound_2exp_si/ /n/ 
-- 
-- Returns an integer \(b\) such that \(|B_n| \le 2^b\). Uses a lookup
-- table for small \(n\), and for larger \(n\) uses the inequality
-- \(|B_n| < 4 n! / (2 \pi)^n < 4 (n+1)^{n+1} e^{-n} / (2 \pi)^n\). Uses
-- integer arithmetic throughout, with the bound for the logarithm being
-- looked up from a table. If \(|B_n| = 0\), returns /LONG_MIN/. Otherwise,
-- the returned exponent \(b\) is never more than one percent larger than
-- the true magnitude.
-- 
-- This function is intended for use when \(n\) small enough that one might
-- comfortably compute \(B_n\) exactly. It aborts if \(n\) is so large that
-- internal overflow occurs.
foreign import ccall "bernoulli.h bernoulli_bound_2exp_si"
  bernoulli_bound_2exp_si :: CULong -> IO CLong

-- Isolated Bernoulli numbers --------------------------------------------------

-- | /bernoulli_mod_p_harvey/ /n/ /p/ 
-- 
-- Returns the \(B_n\) modulo the prime number /p/, computed using
-- Harvey\'s algorithm < [Har2010]>. The running time is linear in /p/. If
-- /p/ divides the numerator of \(B_n\), /UWORD_MAX/ is returned as an
-- error code.
foreign import ccall "bernoulli.h bernoulli_mod_p_harvey"
  bernoulli_mod_p_harvey :: CULong -> CULong -> IO CULong

-- | /_bernoulli_fmpq_ui_zeta/ /num/ /den/ /n/ 
-- 
-- Sets /num/ and /den/ to the reduced numerator and denominator of the
-- Bernoulli number \(B_n\).
-- 
-- The /zeta/ version computes the denominator \(d\) using the von
-- Staudt-Clausen theorem, numerically approximates \(B_n\) using
-- @arb_bernoulli_ui_zeta@, and then rounds \(d B_n\) to the correct
-- numerator.
-- 
-- The /multi_mod/ version reconstructs \(B_n\) by computing the high bits
-- via the Riemann zeta function and the low bits via Harvey\'s
-- multimodular algorithm. The tuning parameter /alpha/ should be a
-- fraction between 0 and 1 controlling the number of bits to compute by
-- the multimodular algorithm. If set to a negative number, a default value
-- will be used.
foreign import ccall "bernoulli.h _bernoulli_fmpq_ui_zeta"
  _bernoulli_fmpq_ui_zeta :: Ptr CFmpz -> Ptr CFmpz -> CULong -> IO ()

foreign import ccall "bernoulli.h  _bernoulli_fmpq_ui_multi_mod"
   _bernoulli_fmpq_ui_multi_mod :: Ptr CFmpz -> Ptr CFmpz -> CULong
                                -> CDouble -> IO () 
-- | /_bernoulli_fmpq_ui/ /num/ /den/ /n/ 
-- 
-- Computes the Bernoulli number \(B_n\) as an exact fraction, for an
-- isolated integer \(n\). This function reads \(B_n\) from the global
-- cache if the number is already cached, but does not automatically extend
-- the cache by itself.
foreign import ccall "bernoulli.h _bernoulli_fmpq_ui"
  _bernoulli_fmpq_ui :: Ptr CFmpz -> Ptr CFmpz -> CULong -> IO ()

foreign import ccall "bernoulli.h bernoulli_fmpq_ui"
  bernoulli_fmpq_ui :: Ptr CFmpq -> CULong -> IO ()