packages feed

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

#include <flint/fmpzi.h>

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 _ = #{size fmpzi_t}
  {-# INLINE alignment #-}
  alignment _ = #{alignment fmpzi_t}
  peek = undefined
  poke = undefined

-- | Create `Fmpzi`.
newFmpzi = do
  x <- mallocForeignPtr
  withForeignPtr x fmpzi_init
  addForeignPtrFinalizer p_fmpzi_clear x
  return $ Fmpzi x

-- | Create `Fmpzi`.
newFmpzi_ a b = do
  x <- mallocForeignPtr
  withForeignPtr x $ \x -> do
    fmpzi_init x
    fmpzi_set_si_si x a b
  addForeignPtrFinalizer p_fmpzi_clear x
  return $ Fmpzi x

-- | Use `Fmpzi`
{-# INLINE withFmpzi #-}
withFmpzi (Fmpzi x) f = do
  withForeignPtr x $ \p -> f p >>= return . (Fmpzi x,)

-- | Use real part of `Fmpzi`
{-# INLINE withFmpziReal #-}
withFmpziReal (Fmpzi x) f = do
  withForeignPtr x $ \p -> (Fmpzi x,) <$> f (castPtr p)

-- | Use imaginary part of `Fmpzi`
{-# INLINE withFmpziImag #-}
withFmpziImag (Fmpzi x) f = do
  withForeignPtr x $ \p -> (Fmpzi x,) <$> f (castPtr p `advancePtr` 1)

-- | Use new `Fmpzi`
{-# INLINE withNewFmpzi #-}
withNewFmpzi f = do
  x <- newFmpzi
  withFmpzi x 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 z = do
  printCStr fmpzi_get_str z
  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 ()