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