{-# LINE 1 "src/Data/Number/Flint/Fq/Poly/Factor/FFI.hsc" #-}
{-|
module      :  Data.Number.Flint.Fq.Poly.Factor.FFI
copyright   :  (c) 2022 Hartmut Monien
license     :  GNU GPL, version 2 or above (see LICENSE)
maintainer  :  hmonien@uni-bonn.de
-}
module Data.Number.Flint.Fq.Poly.Factor.FFI (
  -- * Factorisation of univariate polynomials over finite fields
    FqPolyFactor (..)
  , CFqPolyFactor (..)
  , newFqPolyFactor
  , withFqPolyFactor
  , withNewFqPolyFactor
  -- * Memory Management
  , fq_poly_factor_init
  , fq_poly_factor_clear
  , fq_poly_factor_realloc
  , fq_poly_factor_fit_length
  -- * Basic Operations
  , fq_poly_factor_set
  , fq_poly_factor_print_pretty
  , fq_poly_factor_print
  , fq_poly_factor_insert
  , fq_poly_factor_concat
  , fq_poly_factor_pow
  , fq_poly_remove
  -- * Irreducibility Testing
  , fq_poly_is_irreducible
  , fq_poly_is_irreducible_ddf
  , fq_poly_is_irreducible_ben_or
  , _fq_poly_is_squarefree
  , fq_poly_is_squarefree
  -- * Factorisation
  , fq_poly_factor_equal_deg_prob
  , fq_poly_factor_equal_deg
  , fq_poly_factor_split_single
  , fq_poly_factor_distinct_deg
  , fq_poly_factor_squarefree
  , fq_poly_factor
  , fq_poly_factor_cantor_zassenhaus
  , fq_poly_factor_kaltofen_shoup
  , fq_poly_factor_berlekamp
  , fq_poly_factor_with_berlekamp
  , fq_poly_factor_with_cantor_zassenhaus
  , fq_poly_factor_with_kaltofen_shoup
  , fq_poly_iterated_frobenius_preinv
  -- * Root Finding
  , fq_poly_roots
) where 

-- Factorisation of univariate polynomials over finite fields ------------------

import Control.Monad

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

import Data.Number.Flint.Flint
import Data.Number.Flint.Fmpz
import Data.Number.Flint.Fmpz.Mod.Poly
import Data.Number.Flint.Fmpz.Mod.Mat
import Data.Number.Flint.Fmpq
import Data.Number.Flint.Fq
import Data.Number.Flint.Fq.Poly









-- fq_poly_factor_t ------------------------------------------------------------

data FqPolyFactor = FqPolyFactor {-# UNPACK #-} !(ForeignPtr CFqPolyFactor)
data CFqPolyFactor = CFqPolyFactor (Ptr CFqPoly) (Ptr CLong) CLong CLong

instance Storable CFqPolyFactor where
  {-# INLINE sizeOf #-}
  sizeOf :: CFqPolyFactor -> Int
sizeOf CFqPolyFactor
_ = (Int
32)
{-# LINE 88 "src/Data/Number/Flint/Fq/Poly/Factor/FFI.hsc" #-}
  {-# INLINE alignment #-}
  alignment :: CFqPolyFactor -> Int
alignment CFqPolyFactor
_ = Int
8
{-# LINE 90 "src/Data/Number/Flint/Fq/Poly/Factor/FFI.hsc" #-}
  peek ptr = do
    poly  <- (\hsc_ptr -> peekByteOff hsc_ptr 0) ptr
{-# LINE 92 "src/Data/Number/Flint/Fq/Poly/Factor/FFI.hsc" #-}
    exp   <- (\hsc_ptr -> peekByteOff hsc_ptr 8) ptr
{-# LINE 93 "src/Data/Number/Flint/Fq/Poly/Factor/FFI.hsc" #-}
    num   <- (\hsc_ptr -> peekByteOff hsc_ptr 16) ptr
{-# LINE 94 "src/Data/Number/Flint/Fq/Poly/Factor/FFI.hsc" #-}
    alloc <- (\hsc_ptr -> peekByteOff hsc_ptr 24) ptr
{-# LINE 95 "src/Data/Number/Flint/Fq/Poly/Factor/FFI.hsc" #-}
    return $ CFqPolyFactor poly exp num alloc
  poke :: Ptr CFqPolyFactor -> CFqPolyFactor -> IO ()
poke = Ptr CFqPolyFactor -> CFqPolyFactor -> IO ()
forall a. HasCallStack => a
undefined

newFqPolyFactor :: FqCtx -> IO FqPolyFactor
newFqPolyFactor ctx :: FqCtx
ctx@(FqCtx ForeignPtr CFqCtx
fctx) = do
  ForeignPtr CFqPolyFactor
x <- IO (ForeignPtr CFqPolyFactor)
forall a. Storable a => IO (ForeignPtr a)
mallocForeignPtr
  ForeignPtr CFqPolyFactor -> (Ptr CFqPolyFactor -> IO ()) -> IO ()
forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
withForeignPtr ForeignPtr CFqPolyFactor
x ((Ptr CFqPolyFactor -> IO ()) -> IO ())
-> (Ptr CFqPolyFactor -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \Ptr CFqPolyFactor
x -> do
    FqCtx -> (Ptr CFqCtx -> IO ()) -> IO (FqCtx, ())
forall {a}. FqCtx -> (Ptr CFqCtx -> IO a) -> IO (FqCtx, a)
withFqCtx FqCtx
ctx ((Ptr CFqCtx -> IO ()) -> IO (FqCtx, ()))
-> (Ptr CFqCtx -> IO ()) -> IO (FqCtx, ())
forall a b. (a -> b) -> a -> b
$ \Ptr CFqCtx
ctx -> do
      Ptr CFqPolyFactor -> Ptr CFqCtx -> IO ()
fq_poly_factor_init Ptr CFqPolyFactor
x Ptr CFqCtx
ctx
    FinalizerEnvPtr CFqPolyFactor CFqCtx
-> Ptr CFqPolyFactor -> ForeignPtr CFqCtx -> IO ()
forall env a.
FinalizerEnvPtr env a -> Ptr env -> ForeignPtr a -> IO ()
addForeignPtrFinalizerEnv FinalizerEnvPtr CFqPolyFactor CFqCtx
p_fq_poly_factor_clear Ptr CFqPolyFactor
x ForeignPtr CFqCtx
fctx
  FqPolyFactor -> IO FqPolyFactor
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (FqPolyFactor -> IO FqPolyFactor)
-> FqPolyFactor -> IO FqPolyFactor
forall a b. (a -> b) -> a -> b
$ ForeignPtr CFqPolyFactor -> FqPolyFactor
FqPolyFactor ForeignPtr CFqPolyFactor
x

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

{-# INLINE withNewFqPolyFactor #-}
withNewFqPolyFactor :: FqCtx -> (Ptr CFqPolyFactor -> IO a) -> IO (FqPolyFactor, a)
withNewFqPolyFactor FqCtx
ctx Ptr CFqPolyFactor -> IO a
f = do
  FqPolyFactor
x <- FqCtx -> IO FqPolyFactor
newFqPolyFactor FqCtx
ctx
  FqPolyFactor -> (Ptr CFqPolyFactor -> IO a) -> IO (FqPolyFactor, a)
forall {a}.
FqPolyFactor -> (Ptr CFqPolyFactor -> IO a) -> IO (FqPolyFactor, a)
withFqPolyFactor FqPolyFactor
x Ptr CFqPolyFactor -> IO a
f
  
-- Memory Management -----------------------------------------------------------

-- | /fq_poly_factor_init/ /fac/ /ctx/ 
--
-- Initialises @fac@ for use. An @fq_poly_factor_t@ represents a polynomial
-- in factorised form as a product of polynomials with associated
-- exponents.
foreign import ccall "fq_poly_factor.h fq_poly_factor_init"
  fq_poly_factor_init :: Ptr CFqPolyFactor -> Ptr CFqCtx -> IO ()

-- | /fq_poly_factor_clear/ /fac/ /ctx/ 
--
-- Frees all memory associated with @fac@.
foreign import ccall "fq_poly_factor.h fq_poly_factor_clear"
  fq_poly_factor_clear :: Ptr CFqPolyFactor -> Ptr CFqCtx -> IO ()

foreign import ccall "fq_poly_factor.h &fq_poly_factor_clear"
  p_fq_poly_factor_clear :: FunPtr (Ptr CFqPolyFactor -> Ptr CFqCtx -> IO ())

-- | /fq_poly_factor_realloc/ /fac/ /alloc/ /ctx/ 
--
-- Reallocates the factor structure to provide space for precisely @alloc@
-- factors.
foreign import ccall "fq_poly_factor.h fq_poly_factor_realloc"
  fq_poly_factor_realloc :: Ptr CFqPolyFactor -> CLong -> Ptr CFqCtx -> IO ()

-- | /fq_poly_factor_fit_length/ /fac/ /len/ /ctx/ 
--
-- Ensures that the factor structure has space for at least @len@ factors.
-- This function takes care of the case of repeated calls by always at
-- least doubling the number of factors the structure can hold.
foreign import ccall "fq_poly_factor.h fq_poly_factor_fit_length"
  fq_poly_factor_fit_length :: Ptr CFqPolyFactor -> CLong -> Ptr CFqCtx -> IO ()

-- Basic Operations ------------------------------------------------------------

-- | /fq_poly_factor_set/ /res/ /fac/ /ctx/ 
--
-- Sets @res@ to the same factorisation as @fac@.
foreign import ccall "fq_poly_factor.h fq_poly_factor_set"
  fq_poly_factor_set :: Ptr CFqPolyFactor -> Ptr CFqPolyFactor -> Ptr CFqCtx -> IO ()

-- | /fq_poly_factor_print_pretty/ /fac/ /var/ /ctx/ 
-- 
-- Pretty-prints the entries of @fac@ to standard output.
fq_poly_factor_print_pretty :: Ptr CFqPolyFactor -> CString -> Ptr CFqCtx -> IO ()
fq_poly_factor_print_pretty Ptr CFqPolyFactor
fac CString
var Ptr CFqCtx
ctx = do
  CFqPolyFactor Ptr CFqPoly
poly Ptr CLong
exp CLong
num CLong
alloc <- Ptr CFqPolyFactor -> IO CFqPolyFactor
forall a. Storable a => Ptr a -> IO a
peek Ptr CFqPolyFactor
fac
  [Int] -> (Int -> IO ()) -> IO ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
t a -> (a -> m b) -> m ()
forM_ [Int
0..CLong -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral CLong
numInt -> Int -> Int
forall a. Num a => a -> a -> a
-Int
1] ((Int -> IO ()) -> IO ()) -> (Int -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \Int
j -> do
    Ptr CFqPoly -> CString -> Ptr CFqCtx -> IO CInt
fq_poly_print_pretty (Ptr CFqPoly
poly Ptr CFqPoly -> Int -> Ptr CFqPoly
forall a. Storable a => Ptr a -> Int -> Ptr a
`advancePtr` Int
j) CString
var Ptr CFqCtx
ctx
    CLong
m <- Ptr CLong -> IO CLong
forall a. Storable a => Ptr a -> IO a
peek (Ptr CLong
exp Ptr CLong -> Int -> Ptr CLong
forall a. Storable a => Ptr a -> Int -> Ptr a
`advancePtr` Int
j)
    String -> IO ()
putStrLn (String -> IO ()) -> String -> IO ()
forall a b. (a -> b) -> a -> b
$ String
" ^ " String -> String -> String
forall a. [a] -> [a] -> [a]
++ CLong -> String
forall a. Show a => a -> String
show CLong
m
    
-- | /fq_poly_factor_print/ /fac/ /ctx/ 
-- 
-- Prints the entries of @fac@ to standard output.
fq_poly_factor_print :: Ptr CFqPolyFactor -> Ptr CFqCtx -> IO ()
fq_poly_factor_print Ptr CFqPolyFactor
fac Ptr CFqCtx
ctx = do
  CFqPolyFactor Ptr CFqPoly
poly Ptr CLong
exp CLong
num CLong
alloc <- Ptr CFqPolyFactor -> IO CFqPolyFactor
forall a. Storable a => Ptr a -> IO a
peek Ptr CFqPolyFactor
fac
  [Int] -> (Int -> IO ()) -> IO ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
t a -> (a -> m b) -> m ()
forM_ [Int
0..CLong -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral CLong
numInt -> Int -> Int
forall a. Num a => a -> a -> a
-Int
1] ((Int -> IO ()) -> IO ()) -> (Int -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \Int
j -> do
    Ptr CFqPoly -> Ptr CFqCtx -> IO CInt
fq_poly_print (Ptr CFqPoly
poly Ptr CFqPoly -> Int -> Ptr CFqPoly
forall a. Storable a => Ptr a -> Int -> Ptr a
`advancePtr` Int
j) Ptr CFqCtx
ctx
    CLong
m <- Ptr CLong -> IO CLong
forall a. Storable a => Ptr a -> IO a
peek (Ptr CLong
exp Ptr CLong -> Int -> Ptr CLong
forall a. Storable a => Ptr a -> Int -> Ptr a
`advancePtr` Int
j)
    String -> IO ()
putStrLn (String -> IO ()) -> String -> IO ()
forall a b. (a -> b) -> a -> b
$ String
" ^ " String -> String -> String
forall a. [a] -> [a] -> [a]
++ CLong -> String
forall a. Show a => a -> String
show CLong
m

-- | /fq_poly_factor_insert/ /fac/ /poly/ /exp/ /ctx/ 
--
-- Inserts the factor @poly@ with multiplicity @exp@ into the factorisation
-- @fac@.
-- 
-- If @fac@ already contains @poly@, then @exp@ simply gets added to the
-- exponent of the existing entry.
foreign import ccall "fq_poly_factor.h fq_poly_factor_insert"
  fq_poly_factor_insert :: Ptr CFqPolyFactor -> Ptr CFqPoly -> CLong -> Ptr CFqCtx -> IO ()

-- | /fq_poly_factor_concat/ /res/ /fac/ /ctx/ 
--
-- Concatenates two factorisations.
-- 
-- This is equivalent to calling @fq_poly_factor_insert@ repeatedly with
-- the individual factors of @fac@.
-- 
-- Does not support aliasing between @res@ and @fac@.
foreign import ccall "fq_poly_factor.h fq_poly_factor_concat"
  fq_poly_factor_concat :: Ptr CFqPolyFactor -> Ptr CFqPolyFactor -> Ptr CFqCtx -> IO ()

-- | /fq_poly_factor_pow/ /fac/ /exp/ /ctx/ 
--
-- Raises @fac@ to the power @exp@.
foreign import ccall "fq_poly_factor.h fq_poly_factor_pow"
  fq_poly_factor_pow :: Ptr CFqPolyFactor -> CLong -> Ptr CFqCtx -> IO ()

-- | /fq_poly_remove/ /f/ /p/ /ctx/ 
--
-- Removes the highest possible power of @p@ from @f@ and returns the
-- exponent.
foreign import ccall "fq_poly_factor.h fq_poly_remove"
  fq_poly_remove :: Ptr CFqPoly -> Ptr CFqPoly -> Ptr CFqCtx -> IO CULong

-- Irreducibility Testing ------------------------------------------------------

-- | /fq_poly_is_irreducible/ /f/ /ctx/ 
--
-- Returns 1 if the polynomial @f@ is irreducible, otherwise returns 0.
foreign import ccall "fq_poly_factor.h fq_poly_is_irreducible"
  fq_poly_is_irreducible :: Ptr CFqPoly -> Ptr CFqCtx -> IO CInt

-- | /fq_poly_is_irreducible_ddf/ /f/ /ctx/ 
--
-- Returns 1 if the polynomial @f@ is irreducible, otherwise returns 0.
-- Uses fast distinct-degree factorisation.
foreign import ccall "fq_poly_factor.h fq_poly_is_irreducible_ddf"
  fq_poly_is_irreducible_ddf :: Ptr CFqPoly -> Ptr CFqCtx -> IO CInt

-- | /fq_poly_is_irreducible_ben_or/ /f/ /ctx/ 
--
-- Returns 1 if the polynomial @f@ is irreducible, otherwise returns 0.
-- Uses Ben-Or\'s irreducibility test.
foreign import ccall "fq_poly_factor.h fq_poly_is_irreducible_ben_or"
  fq_poly_is_irreducible_ben_or :: Ptr CFqPoly -> Ptr CFqCtx -> IO CInt

-- | /_fq_poly_is_squarefree/ /f/ /len/ /ctx/ 
--
-- Returns 1 if @(f, len)@ is squarefree, and 0 otherwise. As a special
-- case, the zero polynomial is not considered squarefree. There are no
-- restrictions on the length.
foreign import ccall "fq_poly_factor.h _fq_poly_is_squarefree"
  _fq_poly_is_squarefree :: Ptr (Ptr CFq) -> CLong -> Ptr CFqCtx -> IO CInt

-- | /fq_poly_is_squarefree/ /f/ /ctx/ 
--
-- Returns 1 if @f@ is squarefree, and 0 otherwise. As a special case, the
-- zero polynomial is not considered squarefree.
foreign import ccall "fq_poly_factor.h fq_poly_is_squarefree"
  fq_poly_is_squarefree :: Ptr CFqPoly -> Ptr CFqCtx -> IO CInt

-- Factorisation ---------------------------------------------------------------

-- | /fq_poly_factor_equal_deg_prob/ /factor/ /state/ /pol/ /d/ /ctx/ 
--
-- Probabilistic equal degree factorisation of @pol@ into irreducible
-- factors of degree @d@. If it passes, a factor is placed in factor and 1
-- is returned, otherwise 0 is returned and the value of factor is
-- undetermined.
-- 
-- Requires that @pol@ be monic, non-constant and squarefree.
foreign import ccall "fq_poly_factor.h fq_poly_factor_equal_deg_prob"
  fq_poly_factor_equal_deg_prob :: Ptr CFqPoly -> Ptr CFRandState -> Ptr CFqPoly -> CLong -> Ptr CFqCtx -> IO CInt

-- | /fq_poly_factor_equal_deg/ /factors/ /pol/ /d/ /ctx/ 
--
-- Assuming @pol@ is a product of irreducible factors all of degree @d@,
-- finds all those factors and places them in factors. Requires that @pol@
-- be monic, non-constant and squarefree.
foreign import ccall "fq_poly_factor.h fq_poly_factor_equal_deg"
  fq_poly_factor_equal_deg :: Ptr CFqPolyFactor -> Ptr CFqPoly -> CLong -> Ptr CFqCtx -> IO ()

-- | /fq_poly_factor_split_single/ /linfactor/ /input/ /ctx/ 
--
-- Assuming @input@ is a product of factors all of degree 1, finds a single
-- linear factor of @input@ and places it in @linfactor@. Requires that
-- @input@ be monic and non-constant.
foreign import ccall "fq_poly_factor.h fq_poly_factor_split_single"
  fq_poly_factor_split_single :: Ptr CFqPoly -> Ptr CFqPoly -> Ptr CFqCtx -> IO ()

-- | /fq_poly_factor_distinct_deg/ /res/ /poly/ /degs/ /ctx/ 
--
-- Factorises a monic non-constant squarefree polynomial @poly@ of degree
-- \(n\) into factors \(f[d]\) such that for \(1 \leq d \leq n\) \(f[d]\)
-- is the product of the monic irreducible factors of @poly@ of degree
-- \(d\). Factors are stored in @res@, associated powers of irreducible
-- polynomials are stored in @degs@ in the same order as factors.
-- 
-- Requires that @degs@ have enough space for irreducible polynomials\'
-- powers (maximum space required is @n * sizeof(slong)@).
foreign import ccall "fq_poly_factor.h fq_poly_factor_distinct_deg"
  fq_poly_factor_distinct_deg :: Ptr CFqPolyFactor -> Ptr CFqPoly -> Ptr (Ptr CLong) -> Ptr CFqCtx -> IO ()

-- | /fq_poly_factor_squarefree/ /res/ /f/ /ctx/ 
--
-- Sets @res@ to a squarefree factorization of @f@.
foreign import ccall "fq_poly_factor.h fq_poly_factor_squarefree"
  fq_poly_factor_squarefree :: Ptr CFqPolyFactor -> Ptr CFqPoly -> Ptr CFqCtx -> IO ()

-- | /fq_poly_factor/ /res/ /lead/ /f/ /ctx/ 
--
-- Factorises a non-constant polynomial @f@ into monic irreducible factors
-- choosing the best algorithm for given modulo and degree. The output
-- @lead@ is set to the leading coefficient of \(f\) upon return. Choice of
-- algorithm is based on heuristic measurements.
foreign import ccall "fq_poly_factor.h fq_poly_factor"
  fq_poly_factor :: Ptr CFqPolyFactor -> Ptr CFq -> Ptr CFqPoly -> Ptr CFqCtx -> IO ()

-- | /fq_poly_factor_cantor_zassenhaus/ /res/ /f/ /ctx/ 
--
-- Factorises a non-constant polynomial @f@ into monic irreducible factors
-- using the Cantor-Zassenhaus algorithm.
foreign import ccall "fq_poly_factor.h fq_poly_factor_cantor_zassenhaus"
  fq_poly_factor_cantor_zassenhaus :: Ptr CFqPolyFactor -> Ptr CFqPoly -> Ptr CFqCtx -> IO ()

-- | /fq_poly_factor_kaltofen_shoup/ /res/ /poly/ /ctx/ 
--
-- Factorises a non-constant polynomial @f@ into monic irreducible factors
-- using the fast version of Cantor-Zassenhaus algorithm proposed by
-- Kaltofen and Shoup (1998). More precisely this algorithm uses a “baby
-- step\/giant step” strategy for the distinct-degree factorization step.
foreign import ccall "fq_poly_factor.h fq_poly_factor_kaltofen_shoup"
  fq_poly_factor_kaltofen_shoup :: Ptr CFqPolyFactor -> Ptr CFqPoly -> Ptr CFqCtx -> IO ()

-- | /fq_poly_factor_berlekamp/ /factors/ /f/ /ctx/ 
--
-- Factorises a non-constant polynomial @f@ into monic irreducible factors
-- using the Berlekamp algorithm.
foreign import ccall "fq_poly_factor.h fq_poly_factor_berlekamp"
  fq_poly_factor_berlekamp :: Ptr CFqPolyFactor -> Ptr CFqPoly -> Ptr CFqCtx -> IO ()

-- | /fq_poly_factor_with_berlekamp/ /res/ /leading_coeff/ /f/ /ctx/ 
--
-- Factorises a general polynomial @f@ into monic irreducible factors and
-- sets @leading_coeff@ to the leading coefficient of @f@, or 0 if @f@ is
-- the zero polynomial.
-- 
-- This function first checks for small special cases, deflates @f@ if it
-- is of the form \(p(x^m)\) for some \(m > 1\), then performs a
-- square-free factorisation, and finally runs Berlekamp factorisation on
-- all the individual square-free factors.
foreign import ccall "fq_poly_factor.h fq_poly_factor_with_berlekamp"
  fq_poly_factor_with_berlekamp :: Ptr CFqPolyFactor -> Ptr CFq -> Ptr CFqPoly -> Ptr CFqCtx -> IO ()

-- | /fq_poly_factor_with_cantor_zassenhaus/ /res/ /leading_coeff/ /f/ /ctx/ 
--
-- Factorises a general polynomial @f@ into monic irreducible factors and
-- sets @leading_coeff@ to the leading coefficient of @f@, or 0 if @f@ is
-- the zero polynomial.
-- 
-- This function first checks for small special cases, deflates @f@ if it
-- is of the form \(p(x^m)\) for some \(m > 1\), then performs a
-- square-free factorisation, and finally runs Cantor-Zassenhaus on all the
-- individual square-free factors.
foreign import ccall "fq_poly_factor.h fq_poly_factor_with_cantor_zassenhaus"
  fq_poly_factor_with_cantor_zassenhaus :: Ptr CFqPolyFactor -> Ptr CFq -> Ptr CFqPoly -> Ptr CFqCtx -> IO ()

-- | /fq_poly_factor_with_kaltofen_shoup/ /res/ /leading_coeff/ /f/ /ctx/ 
--
-- Factorises a general polynomial @f@ into monic irreducible factors and
-- sets @leading_coeff@ to the leading coefficient of @f@, or 0 if @f@ is
-- the zero polynomial.
-- 
-- This function first checks for small special cases, deflates @f@ if it
-- is of the form \(p(x^m)\) for some \(m > 1\), then performs a
-- square-free factorisation, and finally runs Kaltofen-Shoup on all the
-- individual square-free factors.
foreign import ccall "fq_poly_factor.h fq_poly_factor_with_kaltofen_shoup"
  fq_poly_factor_with_kaltofen_shoup :: Ptr CFqPolyFactor -> Ptr CFq -> Ptr CFqPoly -> Ptr CFqCtx -> IO ()

-- | /fq_poly_iterated_frobenius_preinv/ /rop/ /n/ /v/ /vinv/ /ctx/ 
--
-- Sets @rop[i]@ to be \(x^{q^i}\bmod v\) for \(0 \le i < n\).
-- 
-- It is required that @vinv@ is the inverse of the reverse of @v@ mod
-- @x^lenv@.
foreign import ccall "fq_poly_factor.h fq_poly_iterated_frobenius_preinv"
  fq_poly_iterated_frobenius_preinv :: Ptr (Ptr CFqPoly) -> CLong -> Ptr CFqPoly -> Ptr CFqPoly -> Ptr CFqCtx -> IO ()

-- Root Finding ----------------------------------------------------------------

-- | /fq_poly_roots/ /r/ /f/ /with_multiplicity/ /ctx/ 
--
-- Fill \(r\) with factors of the form \(x - r_i\) where the \(r_i\) are
-- the distinct roots of a nonzero \(f\) in \(F_q\). If
-- \(with\_multiplicity\) is zero, the exponent \(e_i\) of the factor
-- \(x - r_i\) is \(1\). Otherwise, it is the largest \(e_i\) such that
-- \((x-r_i)^e_i\) divides \(f\). This function throws if \(f\) is zero,
-- but is otherwise always successful.
foreign import ccall "fq_poly_factor.h fq_poly_roots"
  fq_poly_roots :: Ptr CFqPolyFactor -> Ptr CFqPoly -> CInt -> Ptr CFqCtx -> IO ()