{-# LINE 1 "src/Data/Number/Flint/NMod/Poly/Factor/FFI.hsc" #-}
{-|
module      :  Data.Number.Flint.NMod.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.NMod.Poly.Factor.FFI (
  -- * Factorisation of univariate polynomials over integers mod n (word-size n)
  -- * Types
    NModPolyFactor (..)
  , CNModPolyFactor (..)
  , newNModPolyFactor
  , withNModPolyFactor
  , withNewNModPolyFactor
  -- * Memory management
  , nmod_poly_factor_init
  , nmod_poly_factor_clear
  , nmod_poly_factor_realloc
  , nmod_poly_factor_fit_length
  , nmod_poly_factor_set
  -- * Output
  , nmod_poly_factor_print
  , nmod_poly_factor_print_pretty
  , nmod_poly_factor_fprint
  , nmod_poly_factor_fprint_pretty
  , nmod_poly_factor_get_str
  , nmod_poly_factor_get_str_pretty
  -- * Basic manipulations
  , nmod_poly_factor_insert
  , nmod_poly_factor_concat
  , nmod_poly_factor_pow
  , nmod_poly_remove
  , nmod_poly_is_irreducible
  , nmod_poly_is_irreducible_ddf
  , nmod_poly_is_irreducible_rabin
  , _nmod_poly_is_squarefree
  , nmod_poly_is_squarefree
  -- * Factorizations
  , nmod_poly_factor_squarefree
  , nmod_poly_factor_equal_deg_prob
  , nmod_poly_factor_equal_deg
  , nmod_poly_factor_distinct_deg
  , nmod_poly_factor_distinct_deg_threaded
  , nmod_poly_factor_cantor_zassenhaus
  , nmod_poly_factor_berlekamp
  , nmod_poly_factor_kaltofen_shoup
  , nmod_poly_factor_with_berlekamp
  , nmod_poly_factor_with_cantor_zassenhaus
  , nmod_poly_factor_with_kaltofen_shoup
  , nmod_poly_factor
  , _nmod_poly_interval_poly_worker
) where

-- Factorisation of univariate polynomials over integers mod n (word-size n)

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

import Data.Number.Flint.Flint
import Data.Number.Flint.Fmpz
import Data.Number.Flint.NMod
import Data.Number.Flint.NMod.Types
import Data.Number.Flint.ThreadPool



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

-- | Create new `NModPolyFactor`
newNModPolyFactor :: IO NModPolyFactor
newNModPolyFactor = do
  ForeignPtr CNModPolyFactor
x <- IO (ForeignPtr CNModPolyFactor)
forall a. Storable a => IO (ForeignPtr a)
mallocForeignPtr
  ForeignPtr CNModPolyFactor
-> (Ptr CNModPolyFactor -> IO ()) -> IO ()
forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
withForeignPtr ForeignPtr CNModPolyFactor
x ((Ptr CNModPolyFactor -> IO ()) -> IO ())
-> (Ptr CNModPolyFactor -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \Ptr CNModPolyFactor
x -> Ptr CNModPolyFactor -> IO ()
nmod_poly_factor_init Ptr CNModPolyFactor
x
  FinalizerPtr CNModPolyFactor -> ForeignPtr CNModPolyFactor -> IO ()
forall a. FinalizerPtr a -> ForeignPtr a -> IO ()
addForeignPtrFinalizer FinalizerPtr CNModPolyFactor
p_nmod_poly_factor_clear ForeignPtr CNModPolyFactor
x
  NModPolyFactor -> IO NModPolyFactor
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (NModPolyFactor -> IO NModPolyFactor)
-> NModPolyFactor -> IO NModPolyFactor
forall a b. (a -> b) -> a -> b
$ ForeignPtr CNModPolyFactor -> NModPolyFactor
NModPolyFactor ForeignPtr CNModPolyFactor
x

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

-- | Use new `NModPolyFactor`
{-# INLINE withNewNModPolyFactor #-}
withNewNModPolyFactor :: (Ptr CNModPolyFactor -> IO a) -> IO (NModPolyFactor, a)
withNewNModPolyFactor Ptr CNModPolyFactor -> IO a
f = do
  NModPolyFactor
x <- IO NModPolyFactor
newNModPolyFactor
  NModPolyFactor
-> (Ptr CNModPolyFactor -> IO a) -> IO (NModPolyFactor, a)
forall {a}.
NModPolyFactor
-> (Ptr CNModPolyFactor -> IO a) -> IO (NModPolyFactor, a)
withNModPolyFactor NModPolyFactor
x ((Ptr CNModPolyFactor -> IO a) -> IO (NModPolyFactor, a))
-> (Ptr CNModPolyFactor -> IO a) -> IO (NModPolyFactor, a)
forall a b. (a -> b) -> a -> b
$ \Ptr CNModPolyFactor
x -> Ptr CNModPolyFactor -> IO a
f Ptr CNModPolyFactor
x

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

-- | /nmod_poly_factor_init/ /fac/ 
-- 
-- Initialises @fac@ for use. An @nmod_poly_factor_t@ represents a
-- polynomial in factorised form as a product of polynomials with
-- associated exponents.
foreign import ccall "nmod_poly_factor.h nmod_poly_factor_init"
  nmod_poly_factor_init :: Ptr CNModPolyFactor -> IO ()

-- | /nmod_poly_factor_clear/ /fac/ 
-- 
-- Frees all memory associated with @fac@.
foreign import ccall "nmod_poly_factor.h nmod_poly_factor_clear"
  nmod_poly_factor_clear :: Ptr CNModPolyFactor -> IO ()

foreign import ccall "nmod_poly_factor.h &nmod_poly_factor_clear"
  p_nmod_poly_factor_clear :: FunPtr (Ptr CNModPolyFactor -> IO ())

-- | /nmod_poly_factor_realloc/ /fac/ /alloc/ 
-- 
-- Reallocates the factor structure to provide space for precisely @alloc@
-- factors.
foreign import ccall "nmod_poly_factor.h nmod_poly_factor_realloc"
  nmod_poly_factor_realloc :: Ptr CNModPolyFactor -> CLong -> IO ()

-- | /nmod_poly_factor_fit_length/ /fac/ /len/ 
-- 
-- 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 "nmod_poly_factor.h nmod_poly_factor_fit_length"
  nmod_poly_factor_fit_length :: Ptr CNModPolyFactor -> CLong -> IO ()

-- | /nmod_poly_factor_set/ /res/ /fac/ 
-- 
-- Sets @res@ to the same factorisation as @fac@.
foreign import ccall "nmod_poly_factor.h nmod_poly_factor_set"
  nmod_poly_factor_set :: Ptr CNModPolyFactor -> Ptr CNModPolyFactor -> IO ()

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

-- | /nmod_poly_factor_get_str/ /fac/
-- 
-- Returns string representation of the entries of @fac@.
foreign import ccall "nmod_poly_factor.h nmod_poly_factor_get_str"
  nmod_poly_factor_get_str :: Ptr CNModPolyFactor -> IO CString

-- | /nmod_poly_factor_get_str_pretty/ /fac/ /x/
-- 
-- Returns string representation of the entries of @fac@ as polynomials.
foreign import ccall "nmod_poly_factor.h nmod_poly_factor_get_str_pretty"
  nmod_poly_factor_get_str_pretty :: Ptr CNModPolyFactor -> CString -> IO CString

-- | /nmod_poly_factor_fprint/ /fac/ 
-- 
-- Prints the entries of @fac@ to stream.
foreign import ccall "nmod_poly_factor.h nmod_poly_factor_fprint"
  nmod_poly_factor_fprint :: Ptr CFile -> Ptr CNModPolyFactor -> IO ()

-- | /nmod_poly_factor_fprint_pretty/ /fac/ /x/
-- 
-- Prints the entries of @fac@ to stream a polynomials.
foreign import ccall "nmod_poly_factor.h nmod_poly_factor_fprint_pretty"
  nmod_poly_factor_fprint_pretty :: Ptr CFile -> Ptr CNModPolyFactor -> CString -> IO ()

-- | /nmod_poly_factor_print/ /fac/ 
-- 
-- Prints the entries of @fac@ to standard output.
nmod_poly_factor_print :: Ptr CNModPolyFactor -> IO ()
nmod_poly_factor_print :: Ptr CNModPolyFactor -> IO ()
nmod_poly_factor_print Ptr CNModPolyFactor
fac = do
  (Ptr CNModPolyFactor -> IO CString)
-> Ptr CNModPolyFactor -> IO CInt
forall a. (Ptr a -> IO CString) -> Ptr a -> IO CInt
printCStr Ptr CNModPolyFactor -> IO CString
nmod_poly_factor_get_str Ptr CNModPolyFactor
fac
  () -> IO ()
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return ()

-- | /nmod_poly_factor_print_pretty/ /fac/ /x/
-- 
-- Prints the entries of @fac@ to standard output as polynomials.
nmod_poly_factor_print_pretty :: Ptr CNModPolyFactor -> CString -> IO ()
nmod_poly_factor_print_pretty :: Ptr CNModPolyFactor -> CString -> IO ()
nmod_poly_factor_print_pretty Ptr CNModPolyFactor
fac CString
x = do
  (Ptr CNModPolyFactor -> IO CString)
-> Ptr CNModPolyFactor -> IO CInt
forall a. (Ptr a -> IO CString) -> Ptr a -> IO CInt
printCStr (\Ptr CNModPolyFactor
fac -> Ptr CNModPolyFactor -> CString -> IO CString
nmod_poly_factor_get_str_pretty Ptr CNModPolyFactor
fac CString
x) Ptr CNModPolyFactor
fac
  () -> IO ()
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return ()
  
--------------------------------------------------------------------------------

-- | /nmod_poly_factor_insert/ /fac/ /poly/ /exp/ 
-- 
-- 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 "nmod_poly_factor.h nmod_poly_factor_insert"
  nmod_poly_factor_insert :: Ptr CNModPolyFactor -> Ptr CNModPoly -> CLong -> IO ()

-- | /nmod_poly_factor_concat/ /res/ /fac/ 
-- 
-- Concatenates two factorisations.
-- 
-- This is equivalent to calling @nmod_poly_factor_insert@ repeatedly with
-- the individual factors of @fac@.
-- 
-- Does not support aliasing between @res@ and @fac@.
foreign import ccall "nmod_poly_factor.h nmod_poly_factor_concat"
  nmod_poly_factor_concat :: Ptr CNModPolyFactor -> Ptr CNModPolyFactor -> IO ()

-- | /nmod_poly_factor_pow/ /fac/ /exp/ 
-- 
-- Raises @fac@ to the power @exp@.
foreign import ccall "nmod_poly_factor.h nmod_poly_factor_pow"
  nmod_poly_factor_pow :: Ptr CNModPolyFactor -> CLong -> IO ()

-- | /nmod_poly_remove/ /f/ /p/ 
-- 
-- Removes the highest possible power of @p@ from @f@ and returns the
-- exponent.
foreign import ccall "nmod_poly_factor.h nmod_poly_remove"
  nmod_poly_remove :: Ptr CNModPoly -> Ptr CNModPoly -> IO CULong

-- | /nmod_poly_is_irreducible/ /f/ 
-- 
-- Returns 1 if the polynomial @f@ is irreducible, otherwise returns 0.
foreign import ccall "nmod_poly_factor.h nmod_poly_is_irreducible"
  nmod_poly_is_irreducible :: Ptr CNModPoly -> IO CInt

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

-- | /nmod_poly_is_irreducible_rabin/ /f/ 
-- 
-- Returns 1 if the polynomial @f@ is irreducible, otherwise returns 0.
-- Uses Rabin irreducibility test.
foreign import ccall "nmod_poly_factor.h nmod_poly_is_irreducible_rabin"
  nmod_poly_is_irreducible_rabin :: Ptr CNModPoly -> IO CInt

-- | /_nmod_poly_is_squarefree/ /f/ /len/ /mod/ 
-- 
-- 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 "nmod_poly_factor.h _nmod_poly_is_squarefree"
  _nmod_poly_is_squarefree :: Ptr CMp -> CLong -> Ptr CNMod -> IO CInt

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

-- | /nmod_poly_factor_squarefree/ /res/ /f/ 
-- 
-- Sets @res@ to a square-free factorization of @f@.
foreign import ccall "nmod_poly_factor.h nmod_poly_factor_squarefree"
  nmod_poly_factor_squarefree :: Ptr CNModPolyFactor -> Ptr CNModPoly -> IO ()

-- | /nmod_poly_factor_equal_deg_prob/ /factor/ /state/ /pol/ /d/ 
-- 
-- 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 "nmod_poly_factor.h nmod_poly_factor_equal_deg_prob"
  nmod_poly_factor_equal_deg_prob :: Ptr CNModPoly -> Ptr CFRandState -> Ptr CNModPoly -> CLong -> IO CInt

-- | /nmod_poly_factor_equal_deg/ /factors/ /pol/ /d/ 
-- 
-- 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 "nmod_poly_factor.h nmod_poly_factor_equal_deg"
  nmod_poly_factor_equal_deg :: Ptr CNModPolyFactor -> Ptr CNModPoly -> CLong -> IO ()

-- | /nmod_poly_factor_distinct_deg/ /res/ /poly/ /degs/ 
-- 
-- 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 \(f[d]\) are stored in @res@, and the degree \(d\) of the
-- irreducible factors is stored in @degs@ in the same order as the
-- factors.
-- 
-- Requires that @degs@ has enough space for @(n\/2)+1 * sizeof(slong)@.
foreign import ccall "nmod_poly_factor.h nmod_poly_factor_distinct_deg"
  nmod_poly_factor_distinct_deg :: Ptr CNModPolyFactor -> Ptr CNModPoly -> Ptr (Ptr CLong) -> IO ()

-- | /nmod_poly_factor_distinct_deg_threaded/ /res/ /poly/ /degs/ 
-- 
-- Multithreaded version of @nmod_poly_factor_distinct_deg@.
foreign import ccall "nmod_poly_factor.h nmod_poly_factor_distinct_deg_threaded"
  nmod_poly_factor_distinct_deg_threaded :: Ptr CNModPolyFactor -> Ptr CNModPoly -> Ptr (Ptr CLong) -> IO ()

-- | /nmod_poly_factor_cantor_zassenhaus/ /res/ /f/ 
-- 
-- Factorises a non-constant polynomial @f@ into monic irreducible factors
-- using the Cantor-Zassenhaus algorithm.
foreign import ccall "nmod_poly_factor.h nmod_poly_factor_cantor_zassenhaus"
  nmod_poly_factor_cantor_zassenhaus :: Ptr CNModPolyFactor -> Ptr CNModPoly -> IO ()

-- | /nmod_poly_factor_berlekamp/ /res/ /f/ 
-- 
-- Factorises a non-constant, squarefree polynomial @f@ into monic
-- irreducible factors using the Berlekamp algorithm.
foreign import ccall "nmod_poly_factor.h nmod_poly_factor_berlekamp"
  nmod_poly_factor_berlekamp :: Ptr CNModPolyFactor -> Ptr CNModPoly -> IO ()

-- | /nmod_poly_factor_kaltofen_shoup/ /res/ /poly/ 
-- 
-- 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.
-- If @flint_get_num_threads@ is greater than one
-- @nmod_poly_factor_distinct_deg_threaded@ is used.
foreign import ccall "nmod_poly_factor.h nmod_poly_factor_kaltofen_shoup"
  nmod_poly_factor_kaltofen_shoup :: Ptr CNModPolyFactor -> Ptr CNModPoly -> IO ()

-- | /nmod_poly_factor_with_berlekamp/ /res/ /f/ 
-- 
-- Factorises a general polynomial @f@ into monic irreducible factors and
-- returns 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 on all the
-- individual square-free factors.
foreign import ccall "nmod_poly_factor.h nmod_poly_factor_with_berlekamp"
  nmod_poly_factor_with_berlekamp :: Ptr CNModPolyFactor -> Ptr CNModPoly -> IO CMpLimb

-- | /nmod_poly_factor_with_cantor_zassenhaus/ /res/ /f/ 
-- 
-- Factorises a general polynomial @f@ into monic irreducible factors and
-- returns 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 "nmod_poly_factor.h nmod_poly_factor_with_cantor_zassenhaus"
  nmod_poly_factor_with_cantor_zassenhaus :: Ptr CNModPolyFactor -> Ptr CNModPoly -> IO CMpLimb

-- | /nmod_poly_factor_with_kaltofen_shoup/ /res/ /f/ 
-- 
-- Factorises a general polynomial @f@ into monic irreducible factors and
-- returns 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 "nmod_poly_factor.h nmod_poly_factor_with_kaltofen_shoup"
  nmod_poly_factor_with_kaltofen_shoup :: Ptr CNModPolyFactor -> Ptr CNModPoly -> IO CMpLimb

-- | /nmod_poly_factor/ /res/ /f/ 
-- 
-- Factorises a general polynomial @f@ into monic irreducible factors and
-- returns 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 either Cantor-Zassenhaus or
-- Berlekamp on all the individual square-free factors. Currently
-- Cantor-Zassenhaus is used by default unless the modulus is 2, in which
-- case Berlekamp is used.
foreign import ccall "nmod_poly_factor.h nmod_poly_factor"
  nmod_poly_factor :: Ptr CNModPolyFactor -> Ptr CNModPoly -> IO CMpLimb

-- | /_nmod_poly_interval_poly_worker/ /arg_ptr/ 
-- 
-- Worker function to compute interval polynomials in distinct degree
-- factorisation. Input\/output is stored in
-- @nmod_poly_interval_poly_arg_t@.
foreign import ccall "nmod_poly_factor.h _nmod_poly_interval_poly_worker"
  _nmod_poly_interval_poly_worker :: Ptr () -> IO ()