{-# LINE 1 "src/Data/Number/Flint/Acb/Modular/FFI.hsc" #-}
{-|
module      :  Data.Number.Flint.Acb.Modular.FFI
copyright   :  (c) 2022 Hartmut Monien
license     :  GNU GPL, version 2 or above (see LICENSE)
maintainer  :  hmonien@uni-bonn.de
-}
module Data.Number.Flint.Acb.Modular.FFI (
  -- * Modular forms of complex variables
  -- * The modular group
    PSL2Z (..)
  , CPSL2Z (..)
  , newPSL2Z
  , newPSL2Z_
  , withPSL2Z
  , withNewPSL2Z
  , withNewPSL2Z_
  , psl2z_init
  , psl2z_clear
  , psl2z_swap
  , psl2z_set
  , psl2z_one
  , psl2z_is_one
  , psl2z_get_str
  , psl2z_print
  , psl2z_fprint
  , psl2z_equal
  , psl2z_mul
  , psl2z_inv
  , psl2z_is_correct
  , psl2z_randtest
  -- * Word problem
  --
  -- $WordProblem
  , PSL2ZWord (..)
  , CPSL2ZWord (..)
  , newPSL2ZWord
  , withPSL2ZWord
  , withNewPSL2ZWord
  , psl2z_word_init
  , psl2z_word_clear
  , psl2z_get_word
  , psl2z_set_word
  , _perm_set_word
  , psl2z_word_fprint
  , psl2z_word_print
  , psl2z_word_get_str
  , psl2z_word_fprint_pretty
  , psl2z_word_print_pretty
  , psl2z_word_get_str_pretty
  , psl2z_get_perm
  -- * Modular transformations
  , acb_modular_transform
  , acb_modular_fundamental_domain_approx_d
  , acb_modular_fundamental_domain_approx_arf
  , acb_modular_fundamental_domain_approx
  , acb_modular_is_in_fundamental_domain
  -- * Addition sequences
  , acb_modular_fill_addseq
  -- * Jacobi theta functions
  , acb_modular_theta_transform
  , acb_modular_addseq_theta
  , acb_modular_theta_sum
  , acb_modular_theta_const_sum_basecase
  , acb_modular_theta_const_sum_rs
  , acb_modular_theta_const_sum
  , acb_modular_theta_notransform
  , acb_modular_theta
  , acb_modular_theta_jet_notransform
  , acb_modular_theta_jet
  , _acb_modular_theta_series
  , acb_modular_theta_series
  -- * Dedekind eta function
  , acb_modular_addseq_eta
  , acb_modular_eta_sum
  , acb_modular_epsilon_arg
  , acb_modular_eta
  -- * Modular forms
  , acb_modular_j
  , acb_modular_lambda
  , acb_modular_delta
  , acb_modular_eisenstein
  -- * Elliptic integrals and functions
  , acb_modular_elliptic_k
  , acb_modular_elliptic_k_cpx
  , acb_modular_elliptic_e
  , acb_modular_elliptic_p
  , acb_modular_elliptic_p_zpx
  -- * Class polynomials
  , acb_modular_hilbert_class_poly
) where

-- Modular forms of complex variables ------------------------------------------

import Control.Monad

import Foreign.C.String
import Foreign.C.Types
import Foreign.ForeignPtr
import Foreign.Ptr ( Ptr, FunPtr, plusPtr, castPtr, nullPtr )
import Foreign.Storable
import Foreign.Marshal ( free, peekArray )
import Foreign.Marshal.Array ( advancePtr )

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

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



-- psl2z_t ---------------------------------------------------------------------

data PSL2Z = PSL2Z {-# UNPACK #-} !(ForeignPtr CPSL2Z) 
data CPSL2Z = CPSL2Z (Ptr CFmpz) (Ptr CFmpz) (Ptr CFmpz) (Ptr CFmpz) 

instance Storable CPSL2Z where
  {-# INLINE sizeOf #-}
  sizeOf :: CPSL2Z -> Int
sizeOf CPSL2Z
_ = (Int
32)
{-# LINE 123 "src/Data/Number/Flint/Acb/Modular/FFI.hsc" #-}
  {-# INLINE alignment #-}
  alignment :: CPSL2Z -> Int
alignment CPSL2Z
_ = Int
8
{-# LINE 125 "src/Data/Number/Flint/Acb/Modular/FFI.hsc" #-}
  peek ptr = CPSL2Z
    <$> (return $ castPtr ptr)
    <*> (return $ castPtr ptr `advancePtr` 1)
    <*> (return $ castPtr ptr `advancePtr` 2)
    <*> (return $ castPtr ptr `advancePtr` 3)
  poke :: Ptr CPSL2Z -> CPSL2Z -> IO ()
poke = [Char] -> Ptr CPSL2Z -> CPSL2Z -> IO ()
forall a. HasCallStack => [Char] -> a
error [Char]
"CPSL2Z.poke: undefined."
  
newPSL2Z :: IO PSL2Z
newPSL2Z = do
  ForeignPtr CPSL2Z
x <- IO (ForeignPtr CPSL2Z)
forall a. Storable a => IO (ForeignPtr a)
mallocForeignPtr
  ForeignPtr CPSL2Z -> (Ptr CPSL2Z -> IO ()) -> IO ()
forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
withForeignPtr ForeignPtr CPSL2Z
x Ptr CPSL2Z -> IO ()
psl2z_init
  FinalizerPtr CPSL2Z -> ForeignPtr CPSL2Z -> IO ()
forall a. FinalizerPtr a -> ForeignPtr a -> IO ()
addForeignPtrFinalizer FinalizerPtr CPSL2Z
p_psl2z_clear ForeignPtr CPSL2Z
x
  PSL2Z -> IO PSL2Z
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (PSL2Z -> IO PSL2Z) -> PSL2Z -> IO PSL2Z
forall a b. (a -> b) -> a -> b
$ ForeignPtr CPSL2Z -> PSL2Z
PSL2Z ForeignPtr CPSL2Z
x

newPSL2Z_ :: Fmpz -> Fmpz -> Fmpz -> Fmpz -> IO PSL2Z
newPSL2Z_ Fmpz
a Fmpz
b Fmpz
c Fmpz
d = do
  ForeignPtr CPSL2Z
x <- IO (ForeignPtr CPSL2Z)
forall a. Storable a => IO (ForeignPtr a)
mallocForeignPtr
  ForeignPtr CPSL2Z -> (Ptr CPSL2Z -> IO ()) -> IO ()
forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
withForeignPtr ForeignPtr CPSL2Z
x ((Ptr CPSL2Z -> IO ()) -> IO ()) -> (Ptr CPSL2Z -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \Ptr CPSL2Z
x -> do
    Ptr CPSL2Z -> IO ()
psl2z_init Ptr CPSL2Z
x
    Fmpz
-> (Ptr CFmpz -> IO (Fmpz, (Fmpz, (Fmpz, ()))))
-> IO (Fmpz, (Fmpz, (Fmpz, (Fmpz, ()))))
forall {a}. Fmpz -> (Ptr CFmpz -> IO a) -> IO (Fmpz, a)
withFmpz Fmpz
a ((Ptr CFmpz -> IO (Fmpz, (Fmpz, (Fmpz, ()))))
 -> IO (Fmpz, (Fmpz, (Fmpz, (Fmpz, ())))))
-> (Ptr CFmpz -> IO (Fmpz, (Fmpz, (Fmpz, ()))))
-> IO (Fmpz, (Fmpz, (Fmpz, (Fmpz, ()))))
forall a b. (a -> b) -> a -> b
$ \Ptr CFmpz
a' -> do
      Fmpz
-> (Ptr CFmpz -> IO (Fmpz, (Fmpz, ())))
-> IO (Fmpz, (Fmpz, (Fmpz, ())))
forall {a}. Fmpz -> (Ptr CFmpz -> IO a) -> IO (Fmpz, a)
withFmpz Fmpz
b ((Ptr CFmpz -> IO (Fmpz, (Fmpz, ())))
 -> IO (Fmpz, (Fmpz, (Fmpz, ()))))
-> (Ptr CFmpz -> IO (Fmpz, (Fmpz, ())))
-> IO (Fmpz, (Fmpz, (Fmpz, ())))
forall a b. (a -> b) -> a -> b
$ \Ptr CFmpz
b' -> do
        Fmpz -> (Ptr CFmpz -> IO (Fmpz, ())) -> IO (Fmpz, (Fmpz, ()))
forall {a}. Fmpz -> (Ptr CFmpz -> IO a) -> IO (Fmpz, a)
withFmpz Fmpz
c ((Ptr CFmpz -> IO (Fmpz, ())) -> IO (Fmpz, (Fmpz, ())))
-> (Ptr CFmpz -> IO (Fmpz, ())) -> IO (Fmpz, (Fmpz, ()))
forall a b. (a -> b) -> a -> b
$ \Ptr CFmpz
c' -> do
          Fmpz -> (Ptr CFmpz -> IO ()) -> IO (Fmpz, ())
forall {a}. Fmpz -> (Ptr CFmpz -> IO a) -> IO (Fmpz, a)
withFmpz Fmpz
d ((Ptr CFmpz -> IO ()) -> IO (Fmpz, ()))
-> (Ptr CFmpz -> IO ()) -> IO (Fmpz, ())
forall a b. (a -> b) -> a -> b
$ \Ptr CFmpz
d' -> do
            CPSL2Z Ptr CFmpz
a Ptr CFmpz
b Ptr CFmpz
c Ptr CFmpz
d <- Ptr CPSL2Z -> IO CPSL2Z
forall a. Storable a => Ptr a -> IO a
peek Ptr CPSL2Z
x
            Ptr CFmpz -> Ptr CFmpz -> IO ()
fmpz_set Ptr CFmpz
a Ptr CFmpz
a'
            Ptr CFmpz -> Ptr CFmpz -> IO ()
fmpz_set Ptr CFmpz
b Ptr CFmpz
b'
            Ptr CFmpz -> Ptr CFmpz -> IO ()
fmpz_set Ptr CFmpz
c Ptr CFmpz
c'
            Ptr CFmpz -> Ptr CFmpz -> IO ()
fmpz_set Ptr CFmpz
d Ptr CFmpz
d'
    Ptr CPSL2Z -> IO ()
psl2z_normal_form Ptr CPSL2Z
x
    CInt
flag <- Ptr CPSL2Z -> IO CInt
psl2z_is_correct Ptr CPSL2Z
x
    Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (CInt
flag CInt -> CInt -> Bool
forall a. Eq a => a -> a -> Bool
/= CInt
1) (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$ do [Char] -> IO ()
forall a. HasCallStack => [Char] -> a
error [Char]
"newPSL2Z_ a b c d with ad - bc not one."
  FinalizerPtr CPSL2Z -> ForeignPtr CPSL2Z -> IO ()
forall a. FinalizerPtr a -> ForeignPtr a -> IO ()
addForeignPtrFinalizer FinalizerPtr CPSL2Z
p_psl2z_clear ForeignPtr CPSL2Z
x
  PSL2Z -> IO PSL2Z
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (PSL2Z -> IO PSL2Z) -> PSL2Z -> IO PSL2Z
forall a b. (a -> b) -> a -> b
$ ForeignPtr CPSL2Z -> PSL2Z
PSL2Z ForeignPtr CPSL2Z
x

{-# INLINE withPSL2Z #-}
withPSL2Z :: PSL2Z -> (Ptr CPSL2Z -> IO a) -> IO (PSL2Z, a)
withPSL2Z (PSL2Z ForeignPtr CPSL2Z
x) Ptr CPSL2Z -> IO a
f = do
  ForeignPtr CPSL2Z -> (Ptr CPSL2Z -> IO (PSL2Z, a)) -> IO (PSL2Z, a)
forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
withForeignPtr ForeignPtr CPSL2Z
x ((Ptr CPSL2Z -> IO (PSL2Z, a)) -> IO (PSL2Z, a))
-> (Ptr CPSL2Z -> IO (PSL2Z, a)) -> IO (PSL2Z, a)
forall a b. (a -> b) -> a -> b
$ \Ptr CPSL2Z
px -> Ptr CPSL2Z -> IO a
f Ptr CPSL2Z
px IO a -> (a -> IO (PSL2Z, a)) -> IO (PSL2Z, a)
forall a b. IO a -> (a -> IO b) -> IO b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= (PSL2Z, a) -> IO (PSL2Z, a)
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return ((PSL2Z, a) -> IO (PSL2Z, a))
-> (a -> (PSL2Z, a)) -> a -> IO (PSL2Z, a)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (ForeignPtr CPSL2Z -> PSL2Z
PSL2Z ForeignPtr CPSL2Z
x,)

{-# INLINE withNewPSL2Z #-}
withNewPSL2Z :: (Ptr CPSL2Z -> IO a) -> IO (PSL2Z, a)
withNewPSL2Z Ptr CPSL2Z -> IO a
f = do
  PSL2Z
x <- IO PSL2Z
newPSL2Z
  PSL2Z -> (Ptr CPSL2Z -> IO a) -> IO (PSL2Z, a)
forall {a}. PSL2Z -> (Ptr CPSL2Z -> IO a) -> IO (PSL2Z, a)
withPSL2Z PSL2Z
x Ptr CPSL2Z -> IO a
f

{-# INLINE withNewPSL2Z_ #-}
withNewPSL2Z_ :: Fmpz
-> Fmpz -> Fmpz -> Fmpz -> (Ptr CPSL2Z -> IO a) -> IO (PSL2Z, a)
withNewPSL2Z_ Fmpz
a Fmpz
b Fmpz
c Fmpz
d Ptr CPSL2Z -> IO a
f = do
  PSL2Z
x <- Fmpz -> Fmpz -> Fmpz -> Fmpz -> IO PSL2Z
newPSL2Z_ Fmpz
a Fmpz
b Fmpz
c Fmpz
d
  PSL2Z -> (Ptr CPSL2Z -> IO a) -> IO (PSL2Z, a)
forall {a}. PSL2Z -> (Ptr CPSL2Z -> IO a) -> IO (PSL2Z, a)
withPSL2Z PSL2Z
x Ptr CPSL2Z -> IO a
f

-- The modular group -----------------------------------------------------------

-- | /psl2z_init/ /g/ 
-- 
-- Initializes /g/ and set it to the identity element.
foreign import ccall "acb_modular.h psl2z_init_"
  psl2z_init :: Ptr CPSL2Z -> IO ()
 
-- | /psl2z_clear/ /g/ 
-- 
-- Clears /g/.
foreign import ccall "acb_modular.h psl2z_clear_"
  psl2z_clear :: Ptr CPSL2Z -> IO ()

foreign import ccall "acb_modular.h &psl2z_clear_"
  p_psl2z_clear :: FunPtr (Ptr CPSL2Z -> IO ())

foreign import ccall "acb_modular.h psl2z_normal_form"
  psl2z_normal_form :: Ptr CPSL2Z -> IO ()

-- | /psl2z_swap/ /f/ /g/ 
-- 
-- Swaps /f/ and /g/ efficiently.
foreign import ccall "acb_modular.h psl2z_swap_"
  psl2z_swap :: Ptr CPSL2Z -> Ptr CPSL2Z -> IO ()

-- | /psl2z_set/ /f/ /g/ 
-- 
-- Sets /f/ to a copy of /g/.
foreign import ccall "acb_modular.h psl2z_set_"
  psl2z_set :: Ptr CPSL2Z -> Ptr CPSL2Z -> IO ()

-- | /psl2z_one/ /g/ 
-- 
-- Sets /g/ to the identity element.
foreign import ccall "acb_modular.h psl2z_one_"
  psl2z_one :: Ptr CPSL2Z -> IO ()

-- | /psl2z_is_one/ /g/ 
-- 
-- Returns nonzero iff /g/ is the identity element.
foreign import ccall "acb_modular.h psl2z_is_one_"
  psl2z_is_one :: Ptr CPSL2Z -> IO CInt

foreign import ccall "acb_modular.h"
  psl2z_get_str :: Ptr CPSL2Z -> IO CString
  
-- | /psl2z_print/ /g/ 
-- 
-- Prints /g/ to standard output.
psl2z_print :: Ptr CPSL2Z -> IO ()
psl2z_print :: Ptr CPSL2Z -> IO ()
psl2z_print Ptr CPSL2Z
x = do
  CString
cs <- Ptr CPSL2Z -> IO CString
psl2z_get_str Ptr CPSL2Z
x
  [Char]
s <- CString -> IO [Char]
peekCString CString
cs
  CString -> IO ()
forall a. Ptr a -> IO ()
free CString
cs
  [Char] -> IO ()
putStr [Char]
s
  
-- | /psl2z_fprint/ /file/ /g/ 
-- 
-- Prints /g/ to the stream /file/.
foreign import ccall "acb_modular.h psl2z_fprint"
  psl2z_fprint :: Ptr CFile -> Ptr CPSL2Z -> IO ()

-- | /psl2z_equal/ /f/ /g/ 
-- 
-- Returns nonzero iff /f/ and /g/ are equal.
foreign import ccall "acb_modular.h psl2z_equal_"
  psl2z_equal :: Ptr CPSL2Z -> Ptr CPSL2Z -> IO CInt

-- | /psl2z_mul/ /h/ /f/ /g/ 
-- 
-- Sets /h/ to the product of /f/ and /g/, namely the matrix product with
-- the signs canonicalized.
foreign import ccall "acb_modular.h psl2z_mul"
  psl2z_mul :: Ptr CPSL2Z -> Ptr CPSL2Z -> Ptr CPSL2Z -> IO ()

-- | /psl2z_inv/ /h/ /g/ 
-- 
-- Sets /h/ to the inverse of /g/.
foreign import ccall "acb_modular.h psl2z_inv"
  psl2z_inv :: Ptr CPSL2Z -> Ptr CPSL2Z -> IO ()

-- | /psl2z_is_correct/ /g/ 
-- 
-- Returns nonzero iff /g/ contains correct data, i.e. satisfying
-- \(ad-bc = 1\), \(c \ge 0\), and \(d > 0\) if \(c = 0\).
foreign import ccall "acb_modular.h psl2z_is_correct"
  psl2z_is_correct :: Ptr CPSL2Z -> IO CInt

-- | /psl2z_randtest/ /g/ /state/ /bits/ 
-- 
-- Sets /g/ to a random element of \(\text{PSL}(2, \mathbb{Z})\) with
-- entries of bit length at most /bits/ (or 1, if /bits/ is not positive).
-- We first generate /a/ and /d/, compute their Bezout coefficients, divide
-- by the GCD, and then correct the signs.
foreign import ccall "acb_modular.h psl2z_randtest"
  psl2z_randtest :: Ptr CPSL2Z -> Ptr CFRandState -> CLong -> IO ()

-- Word problem ----------------------------------------------------------------

-- $WordProblem
--
-- Any element \(\gamma\) of \(\rm{PSL}_2(\mathbb{Z})\) can be
-- expressed in a word in the generatars of the modular group \(S\)
-- and \(T\). This decomposition is not unique. E.g.
-- the element \[\gamma = \begin{pmatrix} 36 & 7 \\ 5 & 1 \end{pmatrix}\]
-- corresponds to the word \([(T,7),(S,3),(T,-5),(S,3)]\) meaning
-- that \(\gamma\) can be written as
-- \[\gamma = T^7 S^3 T^{-5} S^3.\]



data PSL2ZWord = PSL2ZWord {-#UNPACK#-} !(ForeignPtr CPSL2ZWord)
data CPSL2ZWord = CPSL2ZWord (Ptr CFmpz) CLong

instance Storable CPSL2ZWord where
  {-# INLINE sizeOf #-}
  sizeOf :: CPSL2ZWord -> Int
sizeOf CPSL2ZWord
_ = (Int
16)
{-# LINE 289 "src/Data/Number/Flint/Acb/Modular/FFI.hsc" #-}
  {-# INLINE alignment #-}
  alignment :: CPSL2ZWord -> Int
alignment CPSL2ZWord
_ = Int
8
{-# LINE 291 "src/Data/Number/Flint/Acb/Modular/FFI.hsc" #-}
  peek ptr = CPSL2ZWord
    <$> (\hsc_ptr -> peekByteOff hsc_ptr 0) ptr
{-# LINE 293 "src/Data/Number/Flint/Acb/Modular/FFI.hsc" #-}
    <*> (\hsc_ptr -> peekByteOff hsc_ptr 8) ptr
{-# LINE 294 "src/Data/Number/Flint/Acb/Modular/FFI.hsc" #-}
  poke = error "CPSL2ZWord.poke: undefined."
  
newPSL2ZWord :: IO PSL2ZWord
newPSL2ZWord = do
  ForeignPtr CPSL2ZWord
x <- IO (ForeignPtr CPSL2ZWord)
forall a. Storable a => IO (ForeignPtr a)
mallocForeignPtr
  ForeignPtr CPSL2ZWord -> (Ptr CPSL2ZWord -> IO ()) -> IO ()
forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
withForeignPtr ForeignPtr CPSL2ZWord
x Ptr CPSL2ZWord -> IO ()
psl2z_word_init
  FinalizerPtr CPSL2ZWord -> ForeignPtr CPSL2ZWord -> IO ()
forall a. FinalizerPtr a -> ForeignPtr a -> IO ()
addForeignPtrFinalizer FinalizerPtr CPSL2ZWord
p_psl2z_word_clear ForeignPtr CPSL2ZWord
x
  PSL2ZWord -> IO PSL2ZWord
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (PSL2ZWord -> IO PSL2ZWord) -> PSL2ZWord -> IO PSL2ZWord
forall a b. (a -> b) -> a -> b
$ ForeignPtr CPSL2ZWord -> PSL2ZWord
PSL2ZWord ForeignPtr CPSL2ZWord
x

{-# INLINE withPSL2ZWord #-}
withPSL2ZWord :: PSL2ZWord -> (Ptr CPSL2ZWord -> IO a) -> IO (PSL2ZWord, a)
withPSL2ZWord (PSL2ZWord ForeignPtr CPSL2ZWord
x) Ptr CPSL2ZWord -> IO a
f = do
  ForeignPtr CPSL2ZWord
-> (Ptr CPSL2ZWord -> IO (PSL2ZWord, a)) -> IO (PSL2ZWord, a)
forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
withForeignPtr ForeignPtr CPSL2ZWord
x ((Ptr CPSL2ZWord -> IO (PSL2ZWord, a)) -> IO (PSL2ZWord, a))
-> (Ptr CPSL2ZWord -> IO (PSL2ZWord, a)) -> IO (PSL2ZWord, a)
forall a b. (a -> b) -> a -> b
$ \Ptr CPSL2ZWord
px -> Ptr CPSL2ZWord -> IO a
f Ptr CPSL2ZWord
px IO a -> (a -> IO (PSL2ZWord, a)) -> IO (PSL2ZWord, a)
forall a b. IO a -> (a -> IO b) -> IO b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= (PSL2ZWord, a) -> IO (PSL2ZWord, a)
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return ((PSL2ZWord, a) -> IO (PSL2ZWord, a))
-> (a -> (PSL2ZWord, a)) -> a -> IO (PSL2ZWord, a)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (ForeignPtr CPSL2ZWord -> PSL2ZWord
PSL2ZWord ForeignPtr CPSL2ZWord
x,)

{-# INLINE withNewPSL2ZWord #-}
withNewPSL2ZWord :: (Ptr CPSL2ZWord -> IO a) -> IO (PSL2ZWord, a)
withNewPSL2ZWord Ptr CPSL2ZWord -> IO a
f = do
  PSL2ZWord
x <- IO PSL2ZWord
newPSL2ZWord
  PSL2ZWord -> (Ptr CPSL2ZWord -> IO a) -> IO (PSL2ZWord, a)
forall {a}.
PSL2ZWord -> (Ptr CPSL2ZWord -> IO a) -> IO (PSL2ZWord, a)
withPSL2ZWord PSL2ZWord
x Ptr CPSL2ZWord -> IO a
f

--- | /psl2z_init/ /word/
--
-- Initializes /word/ for the word problem with the empty word.
foreign import ccall "psl2z.h psl2z_word_init"
  psl2z_word_init :: Ptr CPSL2ZWord -> IO ()

--- | /psl2z_clear/ /word/
--
-- Clears /word/.
foreign import ccall "psl2z.h psl2z_word_clear"
  psl2z_word_clear :: Ptr CPSL2ZWord -> IO ()

foreign import ccall "psl2z.h &psl2z_word_clear"
  p_psl2z_word_clear :: FunPtr (Ptr CPSL2ZWord -> IO ())

-- | /psl2z_get_word/ /word/ /x/
--
-- Decomposes \x\ into a word in /S/ and /T/.
foreign import ccall "psl2z.h psl2z_get_word"
  psl2z_get_word :: Ptr CPSL2ZWord -> Ptr CPSL2Z -> IO ()

-- | /psl2z__word/ /word/ /x/
--
-- Compose \x\ from a word in /S/ and /T/.
foreign import ccall "psl2z.h psl2z_set_word"
  psl2z_set_word :: Ptr CPSL2Z -> Ptr CPSL2ZWord -> IO ()

-- | /perm_set_word/ /x/ /s/ /t/ /n/ /word/
--
-- Calculate homomorphism for word from permutations `s` and `t`.
foreign import ccall "psl2z.h _perm_set_word"
  _perm_set_word :: Ptr CLong -> Ptr CLong -> Ptr CLong -> CLong
                 -> Ptr CPSL2ZWord -> IO ()

-- Word input output -----------------------------------------------------------

-- | /psl2z_word_fprint/ /word/
--
-- Outputs /word/ to a file as vector. 
foreign import ccall "psl2z.h psl2z_word_fprint"
  psl2z_word_fprint :: Ptr CFile -> Ptr CPSL2ZWord -> IO ()

-- | /psl2z_word_print/ /word/
--
-- Outputs /word/ to `stdout` as vector. 
psl2z_word_print :: Ptr CPSL2ZWord -> IO ()
psl2z_word_print :: Ptr CPSL2ZWord -> IO ()
psl2z_word_print Ptr CPSL2ZWord
word = do
  (Ptr CPSL2ZWord -> IO CString) -> Ptr CPSL2ZWord -> IO CInt
forall a. (Ptr a -> IO CString) -> Ptr a -> IO CInt
printCStr Ptr CPSL2ZWord -> IO CString
psl2z_word_get_str Ptr CPSL2ZWord
word
  () -> IO ()
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return ()

-- | /psl2z_word_get_str/ /word/
--
-- Returns as string representation of /word/ as vector. 
foreign import ccall "psl2z.h psl2z_word_get_str"
  psl2z_word_get_str :: Ptr CPSL2ZWord -> IO CString

-- | /psl2z_word_fprint_pretty/ /word/
--
-- Outputs /word/ to a file in tuples of generators with the
-- corresponding power.
foreign import ccall "psl2z.h psl2z_word_fprint_pretty"
  psl2z_word_fprint_pretty :: Ptr CFile -> Ptr CPSL2ZWord -> IO ()

-- | /psl2z_word_print_pretty/ /word/
--
-- Outputs /word/ to stdout in tuples of generators with the
-- corresponding power.
psl2z_word_print_pretty :: Ptr CPSL2ZWord -> IO ()
psl2z_word_print_pretty :: Ptr CPSL2ZWord -> IO ()
psl2z_word_print_pretty Ptr CPSL2ZWord
word = do
  (Ptr CPSL2ZWord -> IO CString) -> Ptr CPSL2ZWord -> IO CInt
forall a. (Ptr a -> IO CString) -> Ptr a -> IO CInt
printCStr Ptr CPSL2ZWord -> IO CString
psl2z_word_get_str_pretty Ptr CPSL2ZWord
word
  () -> IO ()
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return ()

-- | /psl2z_word_get_str_pretty/ /word/
--
-- Returns a string representation of /word/ in tuples of generators with the
-- corresponding power.
foreign import ccall "psl2z.h psl2z_word_get_str_pretty"
  psl2z_word_get_str_pretty :: Ptr CPSL2ZWord -> IO CString

-- | /psl2z_get_perm/ /p/ /s/ /t/ /n/ /x/
--
-- Returns the permutation \(p\) corresponding to \(x\) by the 
-- homomorphism \(\phi:{\textrm PSL}_2\left({\mathbb Z}\right)\rightarrow S_n\)
-- defined by the permutations \(s\) and \(t\):
--
-- \[
--    \begin{align}
--      \begin{pmatrix} 0 &-1 \\ 1 & 0 \end{pmatrix} &\mapsto s \\
--      \begin{pmatrix} 1 & 1 \\ 0 & 1 \end{pmatrix} &\mapsto t. \\
--    \end{align}
-- \]
foreign import ccall "psl2z.h psl2z_get_perm"
  psl2z_get_perm :: Ptr CLong -> Ptr CLong -> Ptr CLong -> CLong
                 -> Ptr CPSL2Z -> IO ()
                 
-- Modular transformations -----------------------------------------------------

-- | /acb_modular_transform/ /w/ /g/ /z/ /prec/ 
-- 
-- Applies the modular transformation /g/ to the complex number /z/,
-- evaluating
-- 
-- \[`\]
-- \[w = g z = \frac{az+b}{cz+d}.\]
foreign import ccall "acb_modular.h acb_modular_transform"
  acb_modular_transform :: Ptr CAcb -> Ptr CPSL2Z -> Ptr CAcb -> CLong -> IO ()

foreign import ccall "acb_modular.h acb_modular_fundamental_domain_approx_d"
  acb_modular_fundamental_domain_approx_d :: Ptr CPSL2Z -> CDouble -> CDouble -> CDouble -> IO ()

-- | /acb_modular_fundamental_domain_approx_arf/ /g/ /x/ /y/ /one_minus_eps/ /prec/ 
-- 
-- Attempts to determine a modular transformation /g/ that maps the complex
-- number \(x+yi\) to the fundamental domain or just slightly outside the
-- fundamental domain, where the target tolerance (not a strict bound) is
-- specified by /one_minus_eps/.
-- 
-- The inputs are assumed to be finite numbers, with /y/ positive.
-- 
-- Uses floating-point iteration, repeatedly applying either the
-- transformation \(z \gets z + b\) or \(z \gets -1/z\). The iteration is
-- terminated if \(|x| \le 1/2\) and \(x^2 + y^2 \ge 1 - \varepsilon\)
-- where \(1 - \varepsilon\) is passed as /one_minus_eps/. It is also
-- terminated if too many steps have been taken without convergence, or if
-- the numbers end up too large or too small for the working precision.
-- 
-- The algorithm can fail to produce a satisfactory transformation. The
-- output /g/ is always set to /some/ correct modular transformation, but
-- it is up to the user to verify a posteriori that /g/ maps \(x+yi\) close
-- enough to the fundamental domain.
foreign import ccall "acb_modular.h acb_modular_fundamental_domain_approx_arf"
  acb_modular_fundamental_domain_approx_arf :: Ptr CPSL2Z -> Ptr CArf -> Ptr CArf -> Ptr CArf -> CLong -> IO ()

-- | /acb_modular_fundamental_domain_approx/ /w/ /g/ /z/ /one_minus_eps/ /prec/ 
-- 
-- Attempts to determine a modular transformation /g/ that maps the complex
-- number \(z\) to the fundamental domain or just slightly outside the
-- fundamental domain, where the target tolerance (not a strict bound) is
-- specified by /one_minus_eps/. It also computes the transformed value
-- \(w = gz\).
-- 
-- This function first tries to use
-- @acb_modular_fundamental_domain_approx_d@ and checks if the result is
-- acceptable. If this fails, it calls
-- @acb_modular_fundamental_domain_approx_arf@ with higher precision.
-- Finally, \(w = gz\) is evaluated by a single application of /g/.
-- 
-- The algorithm can fail to produce a satisfactory transformation. The
-- output /g/ is always set to /some/ correct modular transformation, but
-- it is up to the user to verify a posteriori that \(w\) is close enough
-- to the fundamental domain.
foreign import ccall "acb_modular.h acb_modular_fundamental_domain_approx"
  acb_modular_fundamental_domain_approx :: Ptr CAcb -> Ptr CPSL2Z -> Ptr CAcb -> Ptr CArf -> CLong -> IO ()

-- | /acb_modular_is_in_fundamental_domain/ /z/ /tol/ /prec/ 
-- 
-- Returns nonzero if it is certainly true that \(|z| \ge 1 - \varepsilon\)
-- and \(|\operatorname{Re}(z)| \le 1/2 + \varepsilon\) where
-- \(\varepsilon\) is specified by /tol/. Returns zero if this is false or
-- cannot be determined.
foreign import ccall "acb_modular.h acb_modular_is_in_fundamental_domain"
  acb_modular_is_in_fundamental_domain :: Ptr CAcb -> Ptr CArf -> CLong -> IO CInt

-- Addition sequences ----------------------------------------------------------

-- | /acb_modular_fill_addseq/ /tab/ /len/ 
-- 
-- Builds a near-optimal addition sequence for a sequence of integers which
-- is assumed to be reasonably dense.
-- 
-- As input, the caller should set each entry in /tab/ to \(-1\) if that
-- index is to be part of the addition sequence, and to 0 otherwise. On
-- output, entry /i/ in /tab/ will either be zero (if the number is not
-- part of the sequence), or a value /j/ such that both /j/ and \(i - j\)
-- are also marked. The first two entries in /tab/ are ignored (the number
-- 1 is always assumed to be part of the sequence).
foreign import ccall "acb_modular.h acb_modular_fill_addseq"
  acb_modular_fill_addseq :: Ptr CLong -> CLong -> IO ()

-- Jacobi theta functions ------------------------------------------------------

-- Unfortunately, there are many inconsistent notational variations for
-- Jacobi theta functions in the literature. Unless otherwise noted, we use
-- the functions
--
-- \[`\]
-- \[\theta_1(z,\tau) = -i \sum_{n=-\infty}^{\infty} (-1)^n \exp(\pi i [(n + 1/2)^2 \tau + (2n + 1) z])
--                  = 2 q_{1/4} \sum_{n=0}^{\infty} (-1)^n q^{n(n+1)} \sin((2n+1) \pi z)\]
--
-- \[`\]
-- \[\theta_2(z,\tau) = \sum_{n=-\infty}^{\infty} \exp(\pi i [(n + 1/2)^2 \tau + (2n + 1) z])
--                  = 2 q_{1/4} \sum_{n=0}^{\infty} q^{n(n+1)} \cos((2n+1) \pi z)\]
--
-- \[`\]
-- \[\theta_3(z,\tau) = \sum_{n=-\infty}^{\infty} \exp(\pi i [n^2 \tau + 2n z])
--                  = 1 + 2 \sum_{n=1}^{\infty} q^{n^2} \cos(2n \pi z)\]
--
-- \[`\]
-- \[\theta_4(z,\tau) = \sum_{n=-\infty}^{\infty} (-1)^n \exp(\pi i [n^2 \tau + 2n z])
--                  = 1 + 2 \sum_{n=1}^{\infty} (-1)^n q^{n^2} \cos(2n \pi z)\]
--
-- where \(q = \exp(\pi i \tau)\) and \(q_{1/4} = \exp(\pi i \tau / 4)\).
-- Note that many authors write \(q_{1/4}\) as \(q^{1/4}\), but the
-- principal fourth root \((q)^{1/4} = \exp(\frac{1}{4} \log q)\) differs
-- from \(q_{1/4}\) in general and some formulas are only correct if one
-- reads \"q^{1\/4} = exp(pi i tau \/ 4)\". To avoid confusion, we only
-- write \(q^k\) when \(k\) is an integer.
--
-- | /acb_modular_theta_transform/ /R/ /S/ /C/ /g/ 
-- 
-- We wish to write a theta function with quasiperiod \(\tau\) in terms of
-- a theta function with quasiperiod \(\tau' = g \tau\), given some
-- \(g = (a, b; c, d) \in \text{PSL}(2, \mathbb{Z})\). For
-- \(i = 0, 1, 2, 3\), this function computes integers \(R_i\) and \(S_i\)
-- (/R/ and /S/ should be arrays of length 4) and \(C \in \{0, 1\}\) such
-- that
-- 
-- \[`\]
-- \[\theta_{1+i}(z,\tau) = \exp(\pi i R_i / 4) \cdot A \cdot B \cdot \theta_{1+S_i}(z',\tau')\]
-- 
-- where \(z' = z, A = B = 1\) if \(C = 0\), and
-- 
-- \[`\]
-- \[z' = \frac{-z}{c \tau + d}, \quad
-- A = \sqrt{\frac{i}{c \tau + d}}, \quad
-- B = \exp\left(-\pi i c \frac{z^2}{c \tau + d}\right)\]
-- 
-- if \(C = 1\). Note that \(A\) is well-defined with the principal branch
-- of the square root since \(A^2 = i/(c \tau + d)\) lies in the right
-- half-plane.
-- 
-- Firstly, if \(c = 0\), we have
-- \(\theta_i(z, \tau) = \exp(-\pi i b / 4) \theta_i(z, \tau+b)\) for
-- \(i = 1, 2\), whereas \(\theta_3\) and \(\theta_4\) remain unchanged
-- when \(b\) is even and swap places with each other when \(b\) is odd. In
-- this case we set \(C = 0\).
-- 
-- For an arbitrary \(g\) with \(c > 0\), we set \(C = 1\). The general
-- transformations are given by Rademacher < [Rad1973]>. We need the
-- function \(\theta_{m,n}(z,\tau)\) defined for \(m, n \in \mathbb{Z}\) by
-- (beware of the typos in < [Rad1973]>)
-- 
-- \[`\]
-- \[\theta_{0,0}(z,\tau) = \theta_3(z,\tau), \quad
-- \theta_{0,1}(z,\tau) = \theta_4(z,\tau)\]
-- 
-- \[`\]
-- \[\theta_{1,0}(z,\tau) = \theta_2(z,\tau), \quad
-- \theta_{1,1}(z,\tau) = i \theta_1(z,\tau)\]
-- 
-- \[`\]
-- \[\theta_{m+2,n}(z,\tau) = (-1)^n \theta_{m,n}(z,\tau)\]
-- 
-- \[`\]
-- \[\theta_{m,n+2}(z,\tau) = \theta_{m,n}(z,\tau).\]
-- 
-- Then we may write
-- 
-- \[
-- \begin{eqnarray*}
--   \theta_1(z,\tau) &=& \varepsilon_1 A B \theta_1(z', \tau')\\
--   \theta_2(z,\tau) &=& \varepsilon_2 A B \theta_{1-c,1+a}(z', \tau')\\
--   \theta_3(z,\tau) &=& \varepsilon_3 A B \theta_{1+d-c,1-b+a}(z', \tau')\\
--   \theta_4(z,\tau) &=& \varepsilon_4 A B \theta_{1+d,1-b}(z', \tau')
-- \end{eqnarray*}
-- \]
-- 
-- where \(\varepsilon_i\) is an 8th root of unity. Specifically, if we
-- denote the 24th root of unity in the transformation formula of the
-- Dedekind eta function by
-- \(\varepsilon(a,b,c,d) = \exp(\pi i R(a,b,c,d) / 12)\) (see
-- @acb_modular_epsilon_arg@), then:
-- 
-- \[
-- \begin{eqnarray*}
--   \varepsilon_1(a,b,c,d) &=& \exp(\pi i [R(-d,b,c,-a) + 1]/4)\\
--   \varepsilon_2(a,b,c,d) &=& \exp(\pi i [-R(a,b,c,d) + (5+(2-c)a)]/4)\\
--   \varepsilon_3(a,b,c,d) &=& \exp(\pi i [-R(a,b,c,d) + (4+(c-d-2)(b-a))]/4)\\
--   \varepsilon_4(a,b,c,d) &=& \exp(\pi i [-R(a,b,c,d) + (3-(2+d)b)]/4)\\
-- \end{eqnarray*}
-- \]
--
-- These formulas are easily derived from the formulas in < [Rad1973]>
-- (Rademacher has the transformed\/untransformed variables exchanged, and
-- his \"(\varepsilon\)\" differs from ours by a constant offset in the phase).
foreign import ccall "acb_modular.h acb_modular_theta_transform"
  acb_modular_theta_transform :: Ptr CInt -> Ptr CInt -> Ptr CInt -> Ptr CPSL2Z -> IO ()

-- | /acb_modular_addseq_theta/ /exponents/ /aindex/ /bindex/ /num/ 
-- 
-- Constructs an addition sequence for the first /num/ squares and
-- triangular numbers interleaved (excluding zero), i.e. 1, 2, 4, 6, 9, 12,
-- 16, 20, 25, 30 etc.
foreign import ccall "acb_modular.h acb_modular_addseq_theta"
  acb_modular_addseq_theta :: Ptr CLong -> Ptr CLong -> Ptr CLong -> CLong -> IO ()

-- | /acb_modular_theta_sum/ /theta1/ /theta2/ /theta3/ /theta4/ /w/ /w_is_unit/ /q/ /len/ /prec/ 
-- 
-- Simultaneously computes the first /len/ coefficients of each of the
-- formal power series
-- 
-- \[`\]
-- \[\theta_1(z+x,\tau) / q_{1/4} \in \mathbb{C}[[x]]\]
-- \[\theta_2(z+x,\tau) / q_{1/4} \in \mathbb{C}[[x]]\]
-- \[\theta_3(z+x,\tau) \in \mathbb{C}[[x]]\]
-- \[\theta_4(z+x,\tau) \in \mathbb{C}[[x]]\]
-- 
-- given \(w = \exp(\pi i z)\) and \(q = \exp(\pi i \tau)\), by summing a
-- finite truncation of the respective theta function series. In
-- particular, with /len/ equal to 1, computes the respective value of the
-- theta function at the point /z/. We require /len/ to be positive. If
-- /w_is_unit/ is nonzero, /w/ is assumed to lie on the unit circle, i.e.
-- /z/ is assumed to be real.
-- 
-- Note that the factor \(q_{1/4}\) is removed from \(\theta_1\) and
-- \(\theta_2\). To get the true theta function values, the user has to
-- multiply this factor back. This convention avoids unnecessary
-- computations, since the user can compute
-- \(q_{1/4} = \exp(\pi i \tau / 4)\) followed by \(q = (q_{1/4})^4\), and
-- in many cases when computing products or quotients of theta functions,
-- the factor \(q_{1/4}\) can be eliminated entirely.
-- 
-- This function is intended for \(|q| \ll 1\). It can be called with any
-- \(q\), but will return useless intervals if convergence is not rapid.
-- For general evaluation of theta functions, the user should only call
-- this function after applying a suitable modular transformation.
-- 
-- We consider the sums together, alternatingly updating
-- \((\theta_1, \theta_2)\) or \((\theta_3, \theta_4)\). For
-- \(k = 0, 1, 2, \ldots\), the powers of \(q\) are
-- \(\lfloor (k+2)^2 / 4 \rfloor = 1, 2, 4, 6, 9\) etc. and the powers of
-- \(w\) are \(\pm (k+2) = \pm 2, \pm 3, \pm 4, \ldots\) etc. The scheme is
-- illustrated by the following table:
-- 
-- \[`\]
-- \[\begin{aligned}
-- \begin{array}{llll}
--        & \theta_1, \theta_2 & q^0 & (w^1 \pm w^{-1}) \\
-- k = 0  & \theta_3, \theta_4 & q^1 & (w^2 \pm w^{-2}) \\
-- k = 1  & \theta_1, \theta_2 & q^2 & (w^3 \pm w^{-3}) \\
-- k = 2  & \theta_3, \theta_4 & q^4 & (w^4 \pm w^{-4}) \\
-- k = 3  & \theta_1, \theta_2 & q^6 & (w^5 \pm w^{-5}) \\
-- k = 4  & \theta_3, \theta_4 & q^9 & (w^6 \pm w^{-6}) \\
-- k = 5  & \theta_1, \theta_2 & q^{12} & (w^7 \pm w^{-7}) \\
-- \end{array}
-- \end{aligned}\]
-- 
-- For some integer \(N \ge 1\), the summation is stopped just before term
-- \(k = N\). Let \(Q = |q|\), \(W = \max(|w|,|w^{-1}|)\),
-- \(E = \lfloor (N+2)^2 / 4 \rfloor\) and
-- \(F = \lfloor (N+1)/2 \rfloor + 1\). The error of the zeroth derivative
-- can be bounded as
-- 
-- \[`\]
-- \[2 Q^E W^{N+2} \left[ 1 + Q^F W + Q^{2F} W^2 + \ldots \right]
-- = \frac{2 Q^E W^{N+2}}{1 - Q^F W}\]
-- 
-- provided that the denominator is positive (otherwise we set the error
-- bound to infinity). When /len/ is greater than 1, consider the
-- derivative of order /r/. The term of index /k/ and order /r/ picks up a
-- factor of magnitude \((k+2)^r\) from differentiation of \(w^{k+2}\) (it
-- also picks up a factor \(\pi^r\), but we omit this until we rescale the
-- coefficients at the end of the computation). Thus we have the error
-- bound
-- 
-- \[`\]
-- \[2 Q^E W^{N+2} (N+2)^r \left[ 1 + Q^F W \frac{(N+3)^r}{(N+2)^r} + Q^{2F} W^2 \frac{(N+4)^r}{(N+2)^r} + \ldots \right]\]
-- 
-- which by the inequality \((1 + m/(N+2))^r \le \exp(mr/(N+2))\) can be
-- bounded as
-- 
-- \[`\]
-- \[\frac{2 Q^E W^{N+2} (N+2)^r}{1 - Q^F W \exp(r/(N+2))},\]
-- 
-- again valid when the denominator is positive.
-- 
-- To actually evaluate the series, we write the even cosine terms as
-- \(w^{2n} + w^{-2n}\), the odd cosine terms as
-- \(w (w^{2n} + w^{-2n-2})\), and the sine terms as
-- \(w (w^{2n} - w^{-2n-2})\). This way we only need even powers of \(w\)
-- and \(w^{-1}\). The implementation is not yet optimized for real \(z\),
-- in which case further work can be saved.
-- 
-- This function does not permit aliasing between input and output
-- arguments.
foreign import ccall "acb_modular.h acb_modular_theta_sum"
  acb_modular_theta_sum :: Ptr CAcb -> Ptr CAcb -> Ptr CAcb -> Ptr CAcb -> Ptr CAcb -> CInt -> Ptr CAcb -> CLong -> CLong -> IO ()

foreign import ccall "acb_modular.h acb_modular_theta_const_sum_basecase"
  acb_modular_theta_const_sum_basecase :: Ptr CAcb -> Ptr CAcb -> Ptr CAcb -> Ptr CAcb -> CLong -> CLong -> IO ()

-- | /acb_modular_theta_const_sum_rs/ /theta2/ /theta3/ /theta4/ /q/ /N/ /prec/ 
-- 
-- Computes the truncated theta constant sums
-- \(\theta_2 = \sum_{k(k+1) < N} q^{k(k+1)}\),
-- \(\theta_3 = \sum_{k^2 < N} q^{k^2}\),
-- \(\theta_4 = \sum_{k^2 < N} (-1)^k q^{k^2}\). The /basecase/ version
-- uses a short addition sequence. The /rs/ version uses rectangular
-- splitting. The algorithms are described in < [EHJ2016]>.
foreign import ccall "acb_modular.h acb_modular_theta_const_sum_rs"
  acb_modular_theta_const_sum_rs :: Ptr CAcb -> Ptr CAcb -> Ptr CAcb -> Ptr CAcb -> CLong -> CLong -> IO ()

-- | /acb_modular_theta_const_sum/ /theta2/ /theta3/ /theta4/ /q/ /prec/ 
-- 
-- Computes the respective theta constants by direct summation (without
-- applying modular transformations). This function selects an appropriate
-- /N/, calls either @acb_modular_theta_const_sum_basecase@ or
-- @acb_modular_theta_const_sum_rs@ or depending on /N/, and adds a bound
-- for the truncation error.
foreign import ccall "acb_modular.h acb_modular_theta_const_sum"
  acb_modular_theta_const_sum :: Ptr CAcb -> Ptr CAcb -> Ptr CAcb -> Ptr CAcb -> CLong -> IO ()

-- | /acb_modular_theta_notransform/ /theta1/ /theta2/ /theta3/ /theta4/ /z/ /tau/ /prec/ 
-- 
-- Evaluates the Jacobi theta functions \(\theta_i(z,\tau)\),
-- \(i = 1, 2, 3, 4\) simultaneously. This function does not move \(\tau\)
-- to the fundamental domain. This is generally worse than
-- @acb_modular_theta@, but can be slightly better for moderate input.
foreign import ccall "acb_modular.h acb_modular_theta_notransform"
  acb_modular_theta_notransform :: Ptr CAcb -> Ptr CAcb -> Ptr CAcb -> Ptr CAcb -> Ptr CAcb -> Ptr CAcb -> CLong -> IO ()

-- | /acb_modular_theta/ /theta1/ /theta2/ /theta3/ /theta4/ /z/ /tau/ /prec/ 
-- 
-- Evaluates the Jacobi theta functions \(\theta_i(z,\tau)\),
-- \(i = 1, 2, 3, 4\) simultaneously. This function moves \(\tau\) to the
-- fundamental domain and then also reduces \(z\) modulo \(\tau\) before
-- calling @acb_modular_theta_sum@.
foreign import ccall "acb_modular.h acb_modular_theta"
  acb_modular_theta :: Ptr CAcb -> Ptr CAcb -> Ptr CAcb -> Ptr CAcb -> Ptr CAcb -> Ptr CAcb -> CLong -> IO ()

foreign import ccall "acb_modular.h acb_modular_theta_jet_notransform"
  acb_modular_theta_jet_notransform :: Ptr CAcb -> Ptr CAcb -> Ptr CAcb -> Ptr CAcb -> Ptr CAcb -> Ptr CAcb -> CLong -> CLong -> IO ()

-- | /acb_modular_theta_jet/ /theta1/ /theta2/ /theta3/ /theta4/ /z/ /tau/ /len/ /prec/ 
-- 
-- Evaluates the Jacobi theta functions along with their derivatives with
-- respect to /z/, writing the first /len/ coefficients in the power series
-- \(\theta_i(z+x,\tau) \in \mathbb{C}[[x]]\) to each respective output
-- variable. The /notransform/ version does not move \(\tau\) to the
-- fundamental domain or reduce \(z\) during the computation.
foreign import ccall "acb_modular.h acb_modular_theta_jet"
  acb_modular_theta_jet :: Ptr CAcb -> Ptr CAcb -> Ptr CAcb -> Ptr CAcb -> Ptr CAcb -> Ptr CAcb -> CLong -> CLong -> IO ()

foreign import ccall "acb_modular.h _acb_modular_theta_series"
  _acb_modular_theta_series :: Ptr CAcb -> Ptr CAcb -> Ptr CAcb -> Ptr CAcb -> Ptr CAcb -> CLong -> Ptr CAcb -> CLong -> CLong -> IO ()

-- | /acb_modular_theta_series/ /theta1/ /theta2/ /theta3/ /theta4/ /z/ /tau/ /len/ /prec/ 
-- 
-- Evaluates the respective Jacobi theta functions of the power series /z/,
-- truncated to length /len/. Either of the output variables can be /NULL/.
foreign import ccall "acb_modular.h acb_modular_theta_series"
  acb_modular_theta_series :: Ptr CAcbPoly -> Ptr CAcbPoly -> Ptr CAcbPoly -> Ptr CAcbPoly -> Ptr CAcbPoly -> Ptr CAcb -> CLong -> CLong -> IO ()

-- Dedekind eta function -------------------------------------------------------

-- | /acb_modular_addseq_eta/ /exponents/ /aindex/ /bindex/ /num/ 
-- 
-- Constructs an addition sequence for the first /num/ generalized
-- pentagonal numbers (excluding zero), i.e. 1, 2, 5, 7, 12, 15, 22, 26,
-- 35, 40 etc.
foreign import ccall "acb_modular.h acb_modular_addseq_eta"
  acb_modular_addseq_eta :: Ptr CLong -> Ptr CLong -> Ptr CLong -> CLong -> IO ()

-- | /acb_modular_eta_sum/ /eta/ /q/ /prec/ 
-- 
-- Evaluates the Dedekind eta function without the leading 24th root, i.e.
-- 
-- \[` \exp(-\pi i \tau/12) \eta(\tau) = \sum_{n=-\infty}^{\infty} (-1)^n q^{(3n^2-n)/2}\]
-- 
-- given \(q = \exp(2 \pi i \tau)\), by summing the defining series.
-- 
-- This function is intended for \(|q| \ll 1\). It can be called with any
-- \(q\), but will return useless intervals if convergence is not rapid.
-- For general evaluation of the eta function, the user should only call
-- this function after applying a suitable modular transformation.
-- 
-- The series is evaluated using either a short addition sequence or
-- rectangular splitting, depending on the number of terms. The algorithms
-- are described in < [EHJ2016]>.
foreign import ccall "acb_modular.h acb_modular_eta_sum"
  acb_modular_eta_sum :: Ptr CAcb -> Ptr CAcb -> CLong -> IO ()

-- | /acb_modular_epsilon_arg/ /g/ 
-- 
-- Given \(g = (a, b; c, d)\), computes an integer \(R\) such that
-- \(\varepsilon(a,b,c,d) = \exp(\pi i R / 12)\) is the 24th root of unity
-- in the transformation formula for the Dedekind eta function,
-- 
-- \[`\]
-- \[\eta\left(\frac{a\tau+b}{c\tau+d}\right) = \varepsilon (a,b,c,d)
--     \sqrt{c\tau+d} \eta(\tau).\]
foreign import ccall "acb_modular.h acb_modular_epsilon_arg"
  acb_modular_epsilon_arg :: Ptr CPSL2Z -> IO CInt

-- | /acb_modular_eta/ /r/ /tau/ /prec/ 
-- 
-- Computes the Dedekind eta function \(\eta(\tau)\) given \(\tau\) in the
-- upper half-plane. This function applies the functional equation to move
-- \(\tau\) to the fundamental domain before calling @acb_modular_eta_sum@.
foreign import ccall "acb_modular.h acb_modular_eta"
  acb_modular_eta :: Ptr CAcb -> Ptr CAcb -> CLong -> IO ()

-- Modular forms ---------------------------------------------------------------

-- | /acb_modular_j/ /r/ /tau/ /prec/ 
-- 
-- Computes Klein\'s j-invariant \(j(\tau)\) given \(\tau\) in the upper
-- half-plane. The function is normalized so that \(j(i) = 1728\). We first
-- move \(\tau\) to the fundamental domain, which does not change the value
-- of the function. Then we use the formula
-- \(j(\tau) = 32 (\theta_2^8+\theta_3^8+\theta_4^8)^3 / (\theta_2 \theta_3 \theta_4)^8\)
-- where \(\theta_i = \theta_i(0,\tau)\).
foreign import ccall "acb_modular.h acb_modular_j"
  acb_modular_j :: Ptr CAcb -> Ptr CAcb -> CLong -> IO ()

-- | /acb_modular_lambda/ /r/ /tau/ /prec/ 
-- 
-- Computes the lambda function
-- \(\lambda(\tau) = \theta_2^4(0,\tau) / \theta_3^4(0,\tau)\), which is
-- invariant under modular transformations \((a, b; c, d)\) where \(a, d\)
-- are odd and \(b, c\) are even.
foreign import ccall "acb_modular.h acb_modular_lambda"
  acb_modular_lambda :: Ptr CAcb -> Ptr CAcb -> CLong -> IO ()

-- | /acb_modular_delta/ /r/ /tau/ /prec/ 
-- 
-- Computes the modular discriminant \(\Delta(\tau) = \eta(\tau)^{24}\),
-- which transforms as
-- 
-- \[`\]
-- \[\Delta\left(\frac{a\tau+b}{c\tau+d}\right) = (c\tau+d)^{12} \Delta(\tau).\]
-- 
-- The modular discriminant is sometimes defined with an extra factor
-- \((2\pi)^{12}\), which we omit in this implementation.
foreign import ccall "acb_modular.h acb_modular_delta"
  acb_modular_delta :: Ptr CAcb -> Ptr CAcb -> CLong -> IO ()

-- | /acb_modular_eisenstein/ /r/ /tau/ /len/ /prec/ 
-- 
-- Computes simultaneously the first /len/ entries in the sequence of
-- Eisenstein series \(G_4(\tau), G_6(\tau), G_8(\tau), \ldots\), defined
-- by
-- 
-- \[`\]
-- \[G_{2k}(\tau) = \sum_{m^2 + n^2 \ne 0} \frac{1}{(m+n\tau )^{2k}}\]
-- 
-- and satisfying
-- 
-- \[`\]
-- \[G_{2k} \left(\frac{a\tau+b}{c\tau+d}\right) = (c\tau+d)^{2k} G_{2k}(\tau).\]
-- 
-- We first evaluate \(G_4(\tau)\) and \(G_6(\tau)\) on the fundamental
-- domain using theta functions, and then compute the Eisenstein series of
-- higher index using a recurrence relation.
foreign import ccall "acb_modular.h acb_modular_eisenstein"
  acb_modular_eisenstein :: Ptr CAcb -> Ptr CAcb -> CLong -> CLong -> IO ()

-- Elliptic integrals and functions --------------------------------------------

-- See the @acb_elliptic.h \<acb-elliptic>@ module for elliptic integrals
-- and functions. The following wrappers are available for backwards
-- compatibility.
--
foreign import ccall "acb_modular.h acb_modular_elliptic_k"
  acb_modular_elliptic_k :: Ptr CAcb -> Ptr CAcb -> CLong -> IO ()

foreign import ccall "acb_modular.h acb_modular_elliptic_k_cpx"
  acb_modular_elliptic_k_cpx :: Ptr CAcb -> Ptr CAcb -> CLong -> CLong -> IO ()

foreign import ccall "acb_modular.h acb_modular_elliptic_e"
  acb_modular_elliptic_e :: Ptr CAcb -> Ptr CAcb -> CLong -> IO ()

foreign import ccall "acb_modular.h acb_modular_elliptic_p"
  acb_modular_elliptic_p :: Ptr CAcb -> Ptr CAcb -> Ptr CAcb -> CLong -> IO ()

foreign import ccall "acb_modular.h acb_modular_elliptic_p_zpx"
  acb_modular_elliptic_p_zpx :: Ptr CAcb -> Ptr CAcb -> Ptr CAcb -> CLong -> CLong -> IO ()

-- Class polynomials -----------------------------------------------------------

-- | /acb_modular_hilbert_class_poly/ /res/ /D/ 
-- 
-- Sets /res/ to the Hilbert class polynomial of discriminant /D/, defined
-- as
-- 
-- \[`\]
-- \[H_D(x) = \prod_{(a,b,c)} \left(x - j\left(\frac{-b+\sqrt{D}}{2a}\right)\right)\]
-- 
-- where \((a,b,c)\) ranges over the primitive reduced positive definite
-- binary quadratic forms of discriminant \(b^2 - 4ac = D\).
-- 
-- The Hilbert class polynomial is only defined if \(D < 0\) and /D/ is
-- congruent to 0 or 1 mod 4. If some other value of /D/ is passed as
-- input, /res/ is set to the zero polynomial.
foreign import ccall "acb_modular.h acb_modular_hilbert_class_poly"
  acb_modular_hilbert_class_poly :: Ptr CFmpzPoly -> CLong -> IO ()