packages feed

Flint2-0.1.0.0: 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
) 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

#include <flint/bernoulli.h>

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

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

instance Storable CBernoulliRev where
  sizeOf    _ = #{size      bernoulli_rev_t}
  alignment _ = #{alignment bernoulli_rev_t}
  peek = error "CBernoulliRev.peek: not implemented."
  poke = error "CBernoulliRev.poke: not implemented."
  
newBernoulliRev n = do
  x <- mallocForeignPtr
  withForeignPtr x $ \x -> do
    bernoulli_rev_init x n
  addForeignPtrFinalizer p_bernoulli_rev_clear x
  return $ BernoulliRev x

withBernoulliRev (BernoulliRev x) f = do
  withForeignPtr x $ \xp -> (BernoulliRev x,) <$> f xp

withNewBernoulliRev n f = do
  x <- newBernoulliRev n
  withBernoulliRev x 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 ()

-- | /_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 ()