{-# LINE 1 "src/Data/Number/Flint/NF/Fmpzi/FFI.hsc" #-}
{-|
module      :  Data.Number.Flint.NF.Fmpzi.FFI
copyright   :  (c) 2022 Hartmut Monien
license     :  GNU GPL, version 2 or above (see LICENSE)
maintainer  :  hmonien@uni-bonn.de
-}
module Data.Number.Flint.NF.Fmpzi.FFI (
  -- * Gaussian integers
    Fmpzi (..)
  , CFmpzi (..)
  , newFmpzi
  , newFmpzi_
  , withFmpzi
  , withNewFmpzi
  , withFmpziReal
  , withFmpziImag
  -- * Types
  -- * Basic manipulation
  , fmpzi_init
  , fmpzi_clear
  , fmpzi_swap
  , fmpzi_zero
  , fmpzi_one
  , fmpzi_set
  , fmpzi_set_si_si
  -- * Input and output
  , fmpzi_get_str
  , fmpzi_fprint
  , fmpzi_print
  -- * Random number generation
  , fmpzi_randtest
  -- * Properties
  , fmpzi_equal
  , fmpzi_is_zero
  , fmpzi_is_one
  -- * Units
  , fmpzi_is_unit
  , fmpzi_canonical_unit_i_pow
  , fmpzi_canonicalise_unit
  -- * Norms
  , fmpzi_bits
  , fmpzi_norm
  -- * Arithmetic
  , fmpzi_conj
  , fmpzi_neg
  , fmpzi_add
  , fmpzi_sub
  , fmpzi_sqr
  , fmpzi_mul
  , fmpzi_pow_ui
  -- * Division
  , fmpzi_divexact
  , fmpzi_divrem
  , fmpzi_divrem_approx
  , fmpzi_remove_one_plus_i
  -- * GCD
  , fmpzi_gcd_euclidean
) where 

-- Gaussian integers -----------------------------------------------------------

import Control.Monad

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



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

-- Types -----------------------------------------------------------------------

data Fmpzi = Fmpzi {-# UNPACK #-} !(ForeignPtr CFmpzi)
data CFmpzi = CFmpzi CFmpz CFmpz

instance Storable CFmpzi where
  {-# INLINE sizeOf #-}
  sizeOf :: CFmpzi -> Int
sizeOf CFmpzi
_ = (Int
16)
{-# LINE 86 "src/Data/Number/Flint/NF/Fmpzi/FFI.hsc" #-}
  {-# INLINE alignment #-}
  alignment :: CFmpzi -> Int
alignment CFmpzi
_ = Int
8
{-# LINE 88 "src/Data/Number/Flint/NF/Fmpzi/FFI.hsc" #-}
  peek = undefined
  poke :: Ptr CFmpzi -> CFmpzi -> IO ()
poke = Ptr CFmpzi -> CFmpzi -> IO ()
forall a. HasCallStack => a
undefined

-- | Create `Fmpzi`.
newFmpzi :: IO Fmpzi
newFmpzi = do
  ForeignPtr CFmpzi
x <- IO (ForeignPtr CFmpzi)
forall a. Storable a => IO (ForeignPtr a)
mallocForeignPtr
  ForeignPtr CFmpzi -> (Ptr CFmpzi -> IO ()) -> IO ()
forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
withForeignPtr ForeignPtr CFmpzi
x Ptr CFmpzi -> IO ()
fmpzi_init
  FinalizerPtr CFmpzi -> ForeignPtr CFmpzi -> IO ()
forall a. FinalizerPtr a -> ForeignPtr a -> IO ()
addForeignPtrFinalizer FinalizerPtr CFmpzi
p_fmpzi_clear ForeignPtr CFmpzi
x
  Fmpzi -> IO Fmpzi
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (Fmpzi -> IO Fmpzi) -> Fmpzi -> IO Fmpzi
forall a b. (a -> b) -> a -> b
$ ForeignPtr CFmpzi -> Fmpzi
Fmpzi ForeignPtr CFmpzi
x

-- | Create `Fmpzi`.
newFmpzi_ :: CLong -> CLong -> IO Fmpzi
newFmpzi_ CLong
a CLong
b = do
  ForeignPtr CFmpzi
x <- IO (ForeignPtr CFmpzi)
forall a. Storable a => IO (ForeignPtr a)
mallocForeignPtr
  ForeignPtr CFmpzi -> (Ptr CFmpzi -> IO ()) -> IO ()
forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
withForeignPtr ForeignPtr CFmpzi
x ((Ptr CFmpzi -> IO ()) -> IO ()) -> (Ptr CFmpzi -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \Ptr CFmpzi
x -> do
    Ptr CFmpzi -> IO ()
fmpzi_init Ptr CFmpzi
x
    Ptr CFmpzi -> CLong -> CLong -> IO ()
fmpzi_set_si_si Ptr CFmpzi
x CLong
a CLong
b
  FinalizerPtr CFmpzi -> ForeignPtr CFmpzi -> IO ()
forall a. FinalizerPtr a -> ForeignPtr a -> IO ()
addForeignPtrFinalizer FinalizerPtr CFmpzi
p_fmpzi_clear ForeignPtr CFmpzi
x
  Fmpzi -> IO Fmpzi
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (Fmpzi -> IO Fmpzi) -> Fmpzi -> IO Fmpzi
forall a b. (a -> b) -> a -> b
$ ForeignPtr CFmpzi -> Fmpzi
Fmpzi ForeignPtr CFmpzi
x

-- | Use `Fmpzi`
{-# INLINE withFmpzi #-}
withFmpzi :: Fmpzi -> (Ptr CFmpzi -> IO a) -> IO (Fmpzi, a)
withFmpzi (Fmpzi ForeignPtr CFmpzi
x) Ptr CFmpzi -> IO a
f = do
  ForeignPtr CFmpzi -> (Ptr CFmpzi -> IO (Fmpzi, a)) -> IO (Fmpzi, a)
forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
withForeignPtr ForeignPtr CFmpzi
x ((Ptr CFmpzi -> IO (Fmpzi, a)) -> IO (Fmpzi, a))
-> (Ptr CFmpzi -> IO (Fmpzi, a)) -> IO (Fmpzi, a)
forall a b. (a -> b) -> a -> b
$ \Ptr CFmpzi
p -> Ptr CFmpzi -> IO a
f Ptr CFmpzi
p IO a -> (a -> IO (Fmpzi, a)) -> IO (Fmpzi, a)
forall a b. IO a -> (a -> IO b) -> IO b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= (Fmpzi, a) -> IO (Fmpzi, a)
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return ((Fmpzi, a) -> IO (Fmpzi, a))
-> (a -> (Fmpzi, a)) -> a -> IO (Fmpzi, a)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (ForeignPtr CFmpzi -> Fmpzi
Fmpzi ForeignPtr CFmpzi
x,)

-- | Use real part of `Fmpzi`
{-# INLINE withFmpziReal #-}
withFmpziReal :: Fmpzi -> (Ptr b -> IO a) -> IO (Fmpzi, a)
withFmpziReal (Fmpzi ForeignPtr CFmpzi
x) Ptr b -> IO a
f = do
  ForeignPtr CFmpzi -> (Ptr CFmpzi -> IO (Fmpzi, a)) -> IO (Fmpzi, a)
forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
withForeignPtr ForeignPtr CFmpzi
x ((Ptr CFmpzi -> IO (Fmpzi, a)) -> IO (Fmpzi, a))
-> (Ptr CFmpzi -> IO (Fmpzi, a)) -> IO (Fmpzi, a)
forall a b. (a -> b) -> a -> b
$ \Ptr CFmpzi
p -> (ForeignPtr CFmpzi -> Fmpzi
Fmpzi ForeignPtr CFmpzi
x,) (a -> (Fmpzi, a)) -> IO a -> IO (Fmpzi, a)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Ptr b -> IO a
f (Ptr CFmpzi -> Ptr b
forall a b. Ptr a -> Ptr b
castPtr Ptr CFmpzi
p)

-- | Use imaginary part of `Fmpzi`
{-# INLINE withFmpziImag #-}
withFmpziImag :: Fmpzi -> (Ptr a -> IO a) -> IO (Fmpzi, a)
withFmpziImag (Fmpzi ForeignPtr CFmpzi
x) Ptr a -> IO a
f = do
  ForeignPtr CFmpzi -> (Ptr CFmpzi -> IO (Fmpzi, a)) -> IO (Fmpzi, a)
forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
withForeignPtr ForeignPtr CFmpzi
x ((Ptr CFmpzi -> IO (Fmpzi, a)) -> IO (Fmpzi, a))
-> (Ptr CFmpzi -> IO (Fmpzi, a)) -> IO (Fmpzi, a)
forall a b. (a -> b) -> a -> b
$ \Ptr CFmpzi
p -> (ForeignPtr CFmpzi -> Fmpzi
Fmpzi ForeignPtr CFmpzi
x,) (a -> (Fmpzi, a)) -> IO a -> IO (Fmpzi, a)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Ptr a -> IO a
f (Ptr CFmpzi -> Ptr a
forall a b. Ptr a -> Ptr b
castPtr Ptr CFmpzi
p Ptr a -> Int -> Ptr a
forall a. Storable a => Ptr a -> Int -> Ptr a
`advancePtr` Int
1)

-- | Use new `Fmpzi`
{-# INLINE withNewFmpzi #-}
withNewFmpzi :: (Ptr CFmpzi -> IO a) -> IO (Fmpzi, a)
withNewFmpzi Ptr CFmpzi -> IO a
f = do
  Fmpzi
x <- IO Fmpzi
newFmpzi
  Fmpzi -> (Ptr CFmpzi -> IO a) -> IO (Fmpzi, a)
forall {a}. Fmpzi -> (Ptr CFmpzi -> IO a) -> IO (Fmpzi, a)
withFmpzi Fmpzi
x Ptr CFmpzi -> IO a
f 

-- Memory management -----------------------------------------------------------

foreign import ccall "fmpzi.h fmpzi_init"
  fmpzi_init :: Ptr CFmpzi -> IO ()

foreign import ccall "fmpzi.h fmpzi_clear"
  fmpzi_clear :: Ptr CFmpzi -> IO ()

foreign import ccall "fmpzi.h &fmpzi_clear"
  p_fmpzi_clear :: FunPtr (Ptr CFmpzi -> IO ())

-- Basic manipulation ----------------------------------------------------------

foreign import ccall "fmpzi.h fmpzi_swap"
  fmpzi_swap :: Ptr CFmpzi -> Ptr CFmpzi -> IO ()

foreign import ccall "fmpzi.h fmpzi_zero"
  fmpzi_zero :: Ptr CFmpzi -> IO ()

foreign import ccall "fmpzi.h fmpzi_one"
  fmpzi_one :: Ptr CFmpzi -> IO ()

foreign import ccall "fmpzi.h fmpzi_set"
  fmpzi_set :: Ptr CFmpzi -> Ptr CFmpzi -> IO ()

foreign import ccall "fmpzi.h fmpzi_set_si_si"
  fmpzi_set_si_si :: Ptr CFmpzi -> CLong -> CLong -> IO ()

-- Input and output ------------------------------------------------------------

foreign import ccall "fmpzi.h fmpzi_get_str"
  fmpzi_get_str :: Ptr CFmpzi -> IO CString

foreign import ccall "fmpzi.h fmpzi_fprint"
  fmpzi_fprint :: Ptr CFile -> Ptr CFmpzi -> IO ()
  
fmpzi_print :: Ptr CFmpzi -> IO ()
fmpzi_print :: Ptr CFmpzi -> IO ()
fmpzi_print Ptr CFmpzi
z = do
  (Ptr CFmpzi -> IO CString) -> Ptr CFmpzi -> IO CInt
forall a. (Ptr a -> IO CString) -> Ptr a -> IO CInt
printCStr Ptr CFmpzi -> IO CString
fmpzi_get_str Ptr CFmpzi
z
  () -> IO ()
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return ()

-- Random number generation ----------------------------------------------------

foreign import ccall "fmpzi.h fmpzi_randtest"
  fmpzi_randtest :: Ptr CFmpzi -> Ptr CFRandState -> CMpBitCnt -> IO ()

-- Properties ------------------------------------------------------------------

foreign import ccall "fmpzi.h fmpzi_equal"
  fmpzi_equal :: Ptr CFmpzi -> Ptr CFmpzi -> IO CInt

foreign import ccall "fmpzi.h fmpzi_is_zero"
  fmpzi_is_zero :: Ptr CFmpzi -> IO CInt

foreign import ccall "fmpzi.h fmpzi_is_one"
  fmpzi_is_one :: Ptr CFmpzi -> IO CInt

-- Units -----------------------------------------------------------------------

foreign import ccall "fmpzi.h fmpzi_is_unit"
  fmpzi_is_unit :: Ptr CFmpzi -> IO CInt

foreign import ccall "fmpzi.h fmpzi_canonical_unit_i_pow"
  fmpzi_canonical_unit_i_pow :: Ptr CFmpzi -> IO CLong

foreign import ccall "fmpzi.h fmpzi_canonicalise_unit"
  fmpzi_canonicalise_unit :: Ptr CFmpzi -> Ptr CFmpzi -> IO ()

-- Norms -----------------------------------------------------------------------

foreign import ccall "fmpzi.h fmpzi_bits"
  fmpzi_bits :: Ptr CFmpzi -> IO CLong

foreign import ccall "fmpzi.h fmpzi_norm"
  fmpzi_norm :: Ptr CFmpz -> Ptr CFmpzi -> IO ()

-- Arithmetic ------------------------------------------------------------------

foreign import ccall "fmpzi.h fmpzi_conj"
  fmpzi_conj :: Ptr CFmpzi -> Ptr CFmpzi -> IO ()

foreign import ccall "fmpzi.h fmpzi_neg"
  fmpzi_neg :: Ptr CFmpzi -> Ptr CFmpzi -> IO ()

foreign import ccall "fmpzi.h fmpzi_add"
  fmpzi_add :: Ptr CFmpzi -> Ptr CFmpzi -> Ptr CFmpzi -> IO ()

foreign import ccall "fmpzi.h fmpzi_sub"
  fmpzi_sub :: Ptr CFmpzi -> Ptr CFmpzi -> Ptr CFmpzi -> IO ()

foreign import ccall "fmpzi.h fmpzi_sqr"
  fmpzi_sqr :: Ptr CFmpzi -> Ptr CFmpzi -> IO ()

foreign import ccall "fmpzi.h fmpzi_mul"
  fmpzi_mul :: Ptr CFmpzi -> Ptr CFmpzi -> Ptr CFmpzi -> IO ()

foreign import ccall "fmpzi.h fmpzi_pow_ui"
  fmpzi_pow_ui :: Ptr CFmpzi -> Ptr CFmpzi -> CULong -> IO ()

-- Division --------------------------------------------------------------------

-- | /fmpzi_divexact/ /q/ /x/ /y/ 
-- 
-- Sets /q/ to the quotient of /x/ and /y/, assuming that the division is
-- exact.
foreign import ccall "fmpzi.h fmpzi_divexact"
  fmpzi_divexact :: Ptr CFmpzi -> Ptr CFmpzi -> Ptr CFmpzi -> IO ()

-- | /fmpzi_divrem/ /q/ /r/ /x/ /y/ 
-- 
-- Computes a quotient and remainder satisfying \(x = q y + r\) with
-- \(N(r) \le N(y)/2\), with a canonical choice of remainder when breaking
-- ties.
foreign import ccall "fmpzi.h fmpzi_divrem"
  fmpzi_divrem :: Ptr CFmpzi -> Ptr CFmpzi -> Ptr CFmpzi -> Ptr CFmpzi -> IO ()

-- | /fmpzi_divrem_approx/ /q/ /r/ /x/ /y/ 
-- 
-- Computes a quotient and remainder satisfying \(x = q y + r\) with
-- \(N(r) < N(y)\), with an implementation-defined, non-canonical choice of
-- remainder.
foreign import ccall "fmpzi.h fmpzi_divrem_approx"
  fmpzi_divrem_approx :: Ptr CFmpzi -> Ptr CFmpzi -> Ptr CFmpzi -> Ptr CFmpzi -> IO ()

-- | /fmpzi_remove_one_plus_i/ /res/ /x/ 
-- 
-- Divide /x/ exactly by the largest possible power \((1+i)^k\) and return
-- the exponent /k/.
foreign import ccall "fmpzi.h fmpzi_remove_one_plus_i"
  fmpzi_remove_one_plus_i :: Ptr CFmpzi -> Ptr CFmpzi -> IO CLong

-- GCD -------------------------------------------------------------------------

-- | /fmpzi_gcd_euclidean/ /res/ /x/ /y/ 
-- 
-- Computes the GCD of /x/ and /y/. The result is in canonical unit form.
-- 
-- The /euclidean/ version is a straightforward implementation of Euclid\'s
-- algorithm. The /euclidean_improved/ version is optimized by performing
-- approximate divisions. The /binary/ version uses a (1+i)-ary analog of
-- the binary GCD algorithm for integers < [Wei2000]>. The /shortest/
-- version finds the GCD as the shortest vector in a lattice. The default
-- version chooses an algorithm automatically.
foreign import ccall "fmpzi.h fmpzi_gcd_euclidean"
  fmpzi_gcd_euclidean :: Ptr CFmpzi -> Ptr CFmpzi -> Ptr CFmpzi -> IO ()