{-# LINE 1 "src/Data/Number/Flint/Fmpz/Poly/Mat/FFI.hsc" #-}
{-|
module      :  Data.Number.Flint.Fmpz.Poly.Mat.FFI
copyright   :  (c) 2022 Hartmut Monien
license     :  GNU GPL, version 2 or above (see LICENSE)
maintainer  :  hmonien@uni-bonn.de
-}
module Data.Number.Flint.Fmpz.Poly.Mat.FFI (
  -- * Matrices of polynomials over the integers
    FmpzPolyMat (..)
  , CFmpzPolyMat (..)
  , newFmpzPolyMat
  , withFmpzPolyMat
  , withNewFmpzPolyMat
  -- * Memory management
  , fmpz_poly_mat_init
  , fmpz_poly_mat_init_set
  , fmpz_poly_mat_clear
  -- * Basic properties
  , fmpz_poly_mat_nrows
  , fmpz_poly_mat_ncols
  -- * Basic assignment and manipulation
  , fmpz_poly_mat_entry
  , fmpz_poly_mat_set
  , fmpz_poly_mat_swap
  , fmpz_poly_mat_swap_entrywise
  -- * Input and output
  , fmpz_poly_mat_print
  -- * Random matrix generation
  , fmpz_poly_mat_randtest
  , fmpz_poly_mat_randtest_unsigned
  , fmpz_poly_mat_randtest_sparse
  -- * Special matrices
  , fmpz_poly_mat_zero
  , fmpz_poly_mat_one
  -- * Basic comparison and properties
  , fmpz_poly_mat_equal
  , fmpz_poly_mat_is_zero
  , fmpz_poly_mat_is_one
  , fmpz_poly_mat_is_empty
  , fmpz_poly_mat_is_square
  -- * Norms
  , fmpz_poly_mat_max_bits
  , fmpz_poly_mat_max_length
  -- * Transpose
  , fmpz_poly_mat_transpose
  -- * Evaluation
  , fmpz_poly_mat_evaluate_fmpz
  -- * Arithmetic
  , fmpz_poly_mat_scalar_mul_fmpz_poly
  , fmpz_poly_mat_scalar_mul_fmpz
  , fmpz_poly_mat_add
  , fmpz_poly_mat_sub
  , fmpz_poly_mat_neg
  , fmpz_poly_mat_mul
  , fmpz_poly_mat_mul_classical
  , fmpz_poly_mat_mul_KS
  , fmpz_poly_mat_mullow
  , fmpz_poly_mat_sqr
  , fmpz_poly_mat_sqr_classical
  , fmpz_poly_mat_sqr_KS
  , fmpz_poly_mat_sqrlow
  , fmpz_poly_mat_pow
  , fmpz_poly_mat_pow_trunc
  , fmpz_poly_mat_prod
  -- * Row reduction
  , fmpz_poly_mat_find_pivot_any
  , fmpz_poly_mat_find_pivot_partial
  , fmpz_poly_mat_fflu
  , fmpz_poly_mat_rref
  -- * Trace
  , fmpz_poly_mat_trace
  -- * Determinant and rank
  , fmpz_poly_mat_det
  , fmpz_poly_mat_det_fflu
  , fmpz_poly_mat_det_interpolate
  , fmpz_poly_mat_rank
  -- * Inverse
  , fmpz_poly_mat_inv
  -- * Nullspace
  , fmpz_poly_mat_nullspace
  -- * Solving
  , fmpz_poly_mat_solve
  , fmpz_poly_mat_solve_fflu
  , fmpz_poly_mat_solve_fflu_precomp
) where

-- Matrices of polynomials over the integers -----------------------------------

import System.IO.Unsafe

import Control.Monad

import Foreign.C.String
import Foreign.C.Types
import Foreign.ForeignPtr
import Foreign.Ptr ( Ptr, FunPtr, nullPtr, 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.Poly
import Data.Number.Flint.Fmpz.Mat
import Data.Number.Flint.Fmpq
import Data.Number.Flint.NMod.Types
import Data.Number.Flint.Support.D.Mat
import Data.Number.Flint.Support.Mpf.Mat








-- fmpz_poly_mat_t -------------------------------------------------------------

data FmpzPolyMat = FmpzPolyMat {-# UNPACK #-} !(ForeignPtr CFmpzPolyMat) 
data CFmpzPolyMat = CFmpzPolyMat (Ptr CFmpzPoly) CLong CLong (Ptr (Ptr CFmpzPoly)) 

instance Storable CFmpzPolyMat where
  {-# INLINE sizeOf #-}
  sizeOf :: CFmpzPolyMat -> Int
sizeOf CFmpzPolyMat
_ = (Int
32)
{-# LINE 125 "src/Data/Number/Flint/Fmpz/Poly/Mat/FFI.hsc" #-}
  {-# INLINE alignment #-}
  alignment :: CFmpzPolyMat -> Int
alignment CFmpzPolyMat
_ = Int
8
{-# LINE 127 "src/Data/Number/Flint/Fmpz/Poly/Mat/FFI.hsc" #-}
  peek ptr = CFmpzPolyMat
    <$> (\hsc_ptr -> peekByteOff hsc_ptr 0) ptr
{-# LINE 129 "src/Data/Number/Flint/Fmpz/Poly/Mat/FFI.hsc" #-}
    <*> (\hsc_ptr -> peekByteOff hsc_ptr 8) ptr
{-# LINE 130 "src/Data/Number/Flint/Fmpz/Poly/Mat/FFI.hsc" #-}
    <*> (\hsc_ptr -> peekByteOff hsc_ptr 16) ptr
{-# LINE 131 "src/Data/Number/Flint/Fmpz/Poly/Mat/FFI.hsc" #-}
    <*> (\hsc_ptr -> peekByteOff hsc_ptr 24) ptr
{-# LINE 132 "src/Data/Number/Flint/Fmpz/Poly/Mat/FFI.hsc" #-}
  poke = error "CFmpzPolyMat.poke: Not defined."
 
newFmpzPolyMat :: CLong -> CLong -> IO FmpzPolyMat
newFmpzPolyMat CLong
rows CLong
cols = do
  ForeignPtr CFmpzPolyMat
x <- IO (ForeignPtr CFmpzPolyMat)
forall a. Storable a => IO (ForeignPtr a)
mallocForeignPtr
  ForeignPtr CFmpzPolyMat -> (Ptr CFmpzPolyMat -> IO ()) -> IO ()
forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
withForeignPtr ForeignPtr CFmpzPolyMat
x ((Ptr CFmpzPolyMat -> IO ()) -> IO ())
-> (Ptr CFmpzPolyMat -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \Ptr CFmpzPolyMat
x -> Ptr CFmpzPolyMat -> CLong -> CLong -> IO ()
fmpz_poly_mat_init Ptr CFmpzPolyMat
x CLong
rows CLong
cols
  FinalizerPtr CFmpzPolyMat -> ForeignPtr CFmpzPolyMat -> IO ()
forall a. FinalizerPtr a -> ForeignPtr a -> IO ()
addForeignPtrFinalizer FinalizerPtr CFmpzPolyMat
p_fmpz_poly_mat_clear ForeignPtr CFmpzPolyMat
x
  FmpzPolyMat -> IO FmpzPolyMat
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (FmpzPolyMat -> IO FmpzPolyMat) -> FmpzPolyMat -> IO FmpzPolyMat
forall a b. (a -> b) -> a -> b
$ ForeignPtr CFmpzPolyMat -> FmpzPolyMat
FmpzPolyMat ForeignPtr CFmpzPolyMat
x

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

{-# INLINE withNewFmpzPolyMat #-}
withNewFmpzPolyMat :: CLong -> CLong -> (Ptr CFmpzPolyMat -> IO a) -> IO (FmpzPolyMat, a)
withNewFmpzPolyMat CLong
rows CLong
cols Ptr CFmpzPolyMat -> IO a
f = do
  FmpzPolyMat
x <- CLong -> CLong -> IO FmpzPolyMat
newFmpzPolyMat CLong
rows CLong
cols
  FmpzPolyMat -> (Ptr CFmpzPolyMat -> IO a) -> IO (FmpzPolyMat, a)
forall {a}.
FmpzPolyMat -> (Ptr CFmpzPolyMat -> IO a) -> IO (FmpzPolyMat, a)
withFmpzPolyMat FmpzPolyMat
x Ptr CFmpzPolyMat -> IO a
f
  
-- Memory management -----------------------------------------------------------

-- | /fmpz_poly_mat_init/ /mat/ /rows/ /cols/ 
--
-- Initialises a matrix with the given number of rows and columns for use.
foreign import ccall "fmpz_poly_mat.h fmpz_poly_mat_init"
  fmpz_poly_mat_init :: Ptr CFmpzPolyMat -> CLong -> CLong -> IO ()

-- | /fmpz_poly_mat_init_set/ /mat/ /src/ 
--
-- Initialises a matrix @mat@ of the same dimensions as @src@, and sets it
-- to a copy of @src@.
foreign import ccall "fmpz_poly_mat.h fmpz_poly_mat_init_set"
  fmpz_poly_mat_init_set :: Ptr CFmpzPolyMat -> Ptr CFmpzPolyMat -> IO ()

-- | /fmpz_poly_mat_clear/ /mat/ 
--
-- Frees all memory associated with the matrix. The matrix must be
-- reinitialised if it is to be used again.
foreign import ccall "fmpz_poly_mat.h fmpz_poly_mat_clear"
  fmpz_poly_mat_clear :: Ptr CFmpzPolyMat -> IO ()

foreign import ccall "fmpz_poly_mat.h &fmpz_poly_mat_clear"
  p_fmpz_poly_mat_clear :: FunPtr (Ptr CFmpzPolyMat -> IO ())

-- Basic properties ------------------------------------------------------------

-- | /fmpz_poly_mat_nrows/ /mat/ 
--
-- Returns the number of rows in @mat@.
foreign import ccall "fmpz_poly_mat.h fmpz_poly_mat_nrows"
  fmpz_poly_mat_nrows :: Ptr CFmpzPolyMat -> IO CLong

-- | /fmpz_poly_mat_ncols/ /mat/ 
--
-- Returns the number of columns in @mat@.
foreign import ccall "fmpz_poly_mat.h fmpz_poly_mat_ncols"
  fmpz_poly_mat_ncols :: Ptr CFmpzPolyMat -> IO CLong

-- Basic assignment and manipulation -------------------------------------------

-- | /fmpz_poly_mat_entry/ /mat/ /i/ /j/ 
--
-- Gives a reference to the entry at row @i@ and column @j@. The reference
-- can be passed as an input or output variable to any @fmpz_poly@ function
-- for direct manipulation of the matrix element. No bounds checking is
-- performed.
fmpz_poly_mat_entry :: Ptr CFmpzPolyMat -> CLong -> CLong -> IO (Ptr CFmpzPoly)
fmpz_poly_mat_entry :: Ptr CFmpzPolyMat -> CLong -> CLong -> IO (Ptr CFmpzPoly)
fmpz_poly_mat_entry Ptr CFmpzPolyMat
mat CLong
i CLong
j = do
  CFmpzPolyMat Ptr CFmpzPoly
entries CLong
r CLong
c Ptr (Ptr CFmpzPoly)
rows <- Ptr CFmpzPolyMat -> IO CFmpzPolyMat
forall a. Storable a => Ptr a -> IO a
peek Ptr CFmpzPolyMat
mat
  Ptr CFmpzPoly -> IO (Ptr CFmpzPoly)
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (Ptr CFmpzPoly -> IO (Ptr CFmpzPoly))
-> Ptr CFmpzPoly -> IO (Ptr CFmpzPoly)
forall a b. (a -> b) -> a -> b
$ Ptr CFmpzPoly
entries Ptr CFmpzPoly -> Int -> Ptr CFmpzPoly
forall a. Storable a => Ptr a -> Int -> Ptr a
`advancePtr` (CLong -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral (CLong
iCLong -> CLong -> CLong
forall a. Num a => a -> a -> a
*CLong
cCLong -> CLong -> CLong
forall a. Num a => a -> a -> a
+CLong
j))
  
-- | /fmpz_poly_mat_set/ /mat1/ /mat2/ 
--
-- Sets @mat1@ to a copy of @mat2@.
foreign import ccall "fmpz_poly_mat.h fmpz_poly_mat_set"
  fmpz_poly_mat_set :: Ptr CFmpzPolyMat -> Ptr CFmpzPolyMat -> IO ()

-- | /fmpz_poly_mat_swap/ /mat1/ /mat2/ 
--
-- Swaps @mat1@ and @mat2@ efficiently.
foreign import ccall "fmpz_poly_mat.h fmpz_poly_mat_swap"
  fmpz_poly_mat_swap :: Ptr CFmpzPolyMat -> Ptr CFmpzPolyMat -> IO ()

-- | /fmpz_poly_mat_swap_entrywise/ /mat1/ /mat2/ 
--
-- Swaps two matrices by swapping the individual entries rather than
-- swapping the contents of the structs.
foreign import ccall "fmpz_poly_mat.h fmpz_poly_mat_swap_entrywise"
  fmpz_poly_mat_swap_entrywise :: Ptr CFmpzPolyMat -> Ptr CFmpzPolyMat -> IO ()

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

foreign import ccall "fmpz_poly_mat.h fmpz_poly_mat_fprint"
  fmpz_poly_mat_fprint :: Ptr CFile -> Ptr CFmpzPolyMat -> CString -> IO ()

foreign import ccall "fmpz_poly_mat.h fmpz_poly_mat_get_str"
  fmpz_poly_mat_get_str :: Ptr CFmpzPolyMat -> CString -> IO CString
  
-- | /fmpz_poly_mat_print/ /mat/ /x/ 
--
-- Prints the matrix @mat@ to standard output, using the variable @x@.
fmpz_poly_mat_print :: Ptr CFmpzPolyMat -> CString -> IO ()
fmpz_poly_mat_print :: Ptr CFmpzPolyMat -> CString -> IO ()
fmpz_poly_mat_print Ptr CFmpzPolyMat
mat CString
x = do
  (Ptr CFmpzPolyMat -> IO CString) -> Ptr CFmpzPolyMat -> IO CInt
forall a. (Ptr a -> IO CString) -> Ptr a -> IO CInt
printCStr (\Ptr CFmpzPolyMat
mat -> Ptr CFmpzPolyMat -> CString -> IO CString
fmpz_poly_mat_get_str Ptr CFmpzPolyMat
mat CString
x) Ptr CFmpzPolyMat
mat
  () -> IO ()
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return ()

-- Random matrix generation ----------------------------------------------------

-- | /fmpz_poly_mat_randtest/ /mat/ /state/ /len/ /bits/ 
--
-- This is equivalent to applying @fmpz_poly_randtest@ to all entries in
-- the matrix.
foreign import ccall "fmpz_poly_mat.h fmpz_poly_mat_randtest"
  fmpz_poly_mat_randtest :: Ptr CFmpzPolyMat -> Ptr CFRandState -> CLong -> CFBitCnt -> IO ()

-- | /fmpz_poly_mat_randtest_unsigned/ /mat/ /state/ /len/ /bits/ 
--
-- This is equivalent to applying @fmpz_poly_randtest_unsigned@ to all
-- entries in the matrix.
foreign import ccall "fmpz_poly_mat.h fmpz_poly_mat_randtest_unsigned"
  fmpz_poly_mat_randtest_unsigned :: Ptr CFmpzPolyMat -> Ptr CFRandState -> CLong -> CFBitCnt -> IO ()

-- | /fmpz_poly_mat_randtest_sparse/ /A/ /state/ /len/ /bits/ /density/ 
--
-- Creates a random matrix with the amount of nonzero entries given
-- approximately by the @density@ variable, which should be a fraction
-- between 0 (most sparse) and 1 (most dense).
-- 
-- The nonzero entries will have random lengths between 1 and @len@.
foreign import ccall "fmpz_poly_mat.h fmpz_poly_mat_randtest_sparse"
  fmpz_poly_mat_randtest_sparse :: Ptr CFmpzPolyMat -> Ptr CFRandState -> CLong -> CFBitCnt -> CFloat -> IO ()

-- Special matrices ------------------------------------------------------------

-- | /fmpz_poly_mat_zero/ /mat/ 
--
-- Sets @mat@ to the zero matrix.
foreign import ccall "fmpz_poly_mat.h fmpz_poly_mat_zero"
  fmpz_poly_mat_zero :: Ptr CFmpzPolyMat -> IO ()

-- | /fmpz_poly_mat_one/ /mat/ 
--
-- Sets @mat@ to the unit or identity matrix of given shape, having the
-- element 1 on the main diagonal and zeros elsewhere. If @mat@ is
-- nonsquare, it is set to the truncation of a unit matrix.
foreign import ccall "fmpz_poly_mat.h fmpz_poly_mat_one"
  fmpz_poly_mat_one :: Ptr CFmpzPolyMat -> IO ()

-- Basic comparison and properties ---------------------------------------------

-- | /fmpz_poly_mat_equal/ /mat1/ /mat2/ 
--
-- Returns nonzero if @mat1@ and @mat2@ have the same shape and all their
-- entries agree, and returns zero otherwise.
foreign import ccall "fmpz_poly_mat.h fmpz_poly_mat_equal"
  fmpz_poly_mat_equal :: Ptr CFmpzPolyMat -> Ptr CFmpzPolyMat -> IO CInt

-- | /fmpz_poly_mat_is_zero/ /mat/ 
--
-- Returns nonzero if all entries in @mat@ are zero, and returns zero
-- otherwise.
foreign import ccall "fmpz_poly_mat.h fmpz_poly_mat_is_zero"
  fmpz_poly_mat_is_zero :: Ptr CFmpzPolyMat -> IO CInt

-- | /fmpz_poly_mat_is_one/ /mat/ 
--
-- Returns nonzero if all entries of @mat@ on the main diagonal are the
-- constant polynomial 1 and all remaining entries are zero, and returns
-- zero otherwise. The matrix need not be square.
foreign import ccall "fmpz_poly_mat.h fmpz_poly_mat_is_one"
  fmpz_poly_mat_is_one :: Ptr CFmpzPolyMat -> IO CInt

-- | /fmpz_poly_mat_is_empty/ /mat/ 
--
-- Returns a non-zero value if the number of rows or the number of columns
-- in @mat@ is zero, and otherwise returns zero.
foreign import ccall "fmpz_poly_mat.h fmpz_poly_mat_is_empty"
  fmpz_poly_mat_is_empty :: Ptr CFmpzPolyMat -> IO CInt

-- | /fmpz_poly_mat_is_square/ /mat/ 
--
-- Returns a non-zero value if the number of rows is equal to the number of
-- columns in @mat@, and otherwise returns zero.
foreign import ccall "fmpz_poly_mat.h fmpz_poly_mat_is_square"
  fmpz_poly_mat_is_square :: Ptr CFmpzPolyMat -> IO CInt

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

-- | /fmpz_poly_mat_max_bits/ /A/ 
--
-- Returns the maximum number of bits among the coefficients of the entries
-- in @A@, or the negative of that value if any coefficient is negative.
foreign import ccall "fmpz_poly_mat.h fmpz_poly_mat_max_bits"
  fmpz_poly_mat_max_bits :: Ptr CFmpzPolyMat -> IO CLong

-- | /fmpz_poly_mat_max_length/ /A/ 
--
-- Returns the maximum polynomial length among all the entries in @A@.
foreign import ccall "fmpz_poly_mat.h fmpz_poly_mat_max_length"
  fmpz_poly_mat_max_length :: Ptr CFmpzPolyMat -> IO CLong

-- Transpose -------------------------------------------------------------------

-- | /fmpz_poly_mat_transpose/ /B/ /A/ 
--
-- Sets \(B\) to \(A^t\).
foreign import ccall "fmpz_poly_mat.h fmpz_poly_mat_transpose"
  fmpz_poly_mat_transpose :: Ptr CFmpzPolyMat -> Ptr CFmpzPolyMat -> IO ()

-- Evaluation ------------------------------------------------------------------

-- | /fmpz_poly_mat_evaluate_fmpz/ /B/ /A/ /x/ 
--
-- Sets the @fmpz_mat_t@ @B@ to @A@ evaluated entrywise at the point @x@.
foreign import ccall "fmpz_poly_mat.h fmpz_poly_mat_evaluate_fmpz"
  fmpz_poly_mat_evaluate_fmpz :: Ptr CFmpzMat -> Ptr CFmpzPolyMat -> Ptr CFmpz -> IO ()

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

-- | /fmpz_poly_mat_scalar_mul_fmpz_poly/ /B/ /A/ /c/ 
--
-- Sets @B@ to @A@ multiplied entrywise by the polynomial @c@.
foreign import ccall "fmpz_poly_mat.h fmpz_poly_mat_scalar_mul_fmpz_poly"
  fmpz_poly_mat_scalar_mul_fmpz_poly :: Ptr CFmpzPolyMat -> Ptr CFmpzPolyMat -> Ptr CFmpzPoly -> IO ()

-- | /fmpz_poly_mat_scalar_mul_fmpz/ /B/ /A/ /c/ 
--
-- Sets @B@ to @A@ multiplied entrywise by the integer @c@.
foreign import ccall "fmpz_poly_mat.h fmpz_poly_mat_scalar_mul_fmpz"
  fmpz_poly_mat_scalar_mul_fmpz :: Ptr CFmpzPolyMat -> Ptr CFmpzPolyMat -> Ptr CFmpz -> IO ()

-- | /fmpz_poly_mat_add/ /C/ /A/ /B/ 
--
-- Sets @C@ to the sum of @A@ and @B@. All matrices must have the same
-- shape. Aliasing is allowed.
foreign import ccall "fmpz_poly_mat.h fmpz_poly_mat_add"
  fmpz_poly_mat_add :: Ptr CFmpzPolyMat -> Ptr CFmpzPolyMat -> Ptr CFmpzPolyMat -> IO ()

-- | /fmpz_poly_mat_sub/ /C/ /A/ /B/ 
--
-- Sets @C@ to the sum of @A@ and @B@. All matrices must have the same
-- shape. Aliasing is allowed.
foreign import ccall "fmpz_poly_mat.h fmpz_poly_mat_sub"
  fmpz_poly_mat_sub :: Ptr CFmpzPolyMat -> Ptr CFmpzPolyMat -> Ptr CFmpzPolyMat -> IO ()

-- | /fmpz_poly_mat_neg/ /B/ /A/ 
--
-- Sets @B@ to the negation of @A@. The matrices must have the same shape.
-- Aliasing is allowed.
foreign import ccall "fmpz_poly_mat.h fmpz_poly_mat_neg"
  fmpz_poly_mat_neg :: Ptr CFmpzPolyMat -> Ptr CFmpzPolyMat -> IO ()

-- | /fmpz_poly_mat_mul/ /C/ /A/ /B/ 
--
-- Sets @C@ to the matrix product of @A@ and @B@. The matrices must have
-- compatible dimensions for matrix multiplication. Aliasing is allowed.
-- This function automatically chooses between classical and KS
-- multiplication.
foreign import ccall "fmpz_poly_mat.h fmpz_poly_mat_mul"
  fmpz_poly_mat_mul :: Ptr CFmpzPolyMat -> Ptr CFmpzPolyMat -> Ptr CFmpzPolyMat -> IO ()

-- | /fmpz_poly_mat_mul_classical/ /C/ /A/ /B/ 
--
-- Sets @C@ to the matrix product of @A@ and @B@, computed using the
-- classical algorithm. The matrices must have compatible dimensions for
-- matrix multiplication. Aliasing is allowed.
foreign import ccall "fmpz_poly_mat.h fmpz_poly_mat_mul_classical"
  fmpz_poly_mat_mul_classical :: Ptr CFmpzPolyMat -> Ptr CFmpzPolyMat -> Ptr CFmpzPolyMat -> IO ()

-- | /fmpz_poly_mat_mul_KS/ /C/ /A/ /B/ 
--
-- Sets @C@ to the matrix product of @A@ and @B@, computed using Kronecker
-- segmentation. The matrices must have compatible dimensions for matrix
-- multiplication. Aliasing is allowed.
foreign import ccall "fmpz_poly_mat.h fmpz_poly_mat_mul_KS"
  fmpz_poly_mat_mul_KS :: Ptr CFmpzPolyMat -> Ptr CFmpzPolyMat -> Ptr CFmpzPolyMat -> IO ()

-- | /fmpz_poly_mat_mullow/ /C/ /A/ /B/ /len/ 
--
-- Sets @C@ to the matrix product of @A@ and @B@, truncating each entry in
-- the result to length @len@. Uses classical matrix multiplication. The
-- matrices must have compatible dimensions for matrix multiplication.
-- Aliasing is allowed.
foreign import ccall "fmpz_poly_mat.h fmpz_poly_mat_mullow"
  fmpz_poly_mat_mullow :: Ptr CFmpzPolyMat -> Ptr CFmpzPolyMat -> Ptr CFmpzPolyMat -> CLong -> IO ()

-- | /fmpz_poly_mat_sqr/ /B/ /A/ 
--
-- Sets @B@ to the square of @A@, which must be a square matrix. Aliasing
-- is allowed. This function automatically chooses between classical and KS
-- squaring.
foreign import ccall "fmpz_poly_mat.h fmpz_poly_mat_sqr"
  fmpz_poly_mat_sqr :: Ptr CFmpzPolyMat -> Ptr CFmpzPolyMat -> IO ()

-- | /fmpz_poly_mat_sqr_classical/ /B/ /A/ 
--
-- Sets @B@ to the square of @A@, which must be a square matrix. Aliasing
-- is allowed. This function uses direct formulas for very small matrices,
-- and otherwise classical matrix multiplication.
foreign import ccall "fmpz_poly_mat.h fmpz_poly_mat_sqr_classical"
  fmpz_poly_mat_sqr_classical :: Ptr CFmpzPolyMat -> Ptr CFmpzPolyMat -> IO ()

-- | /fmpz_poly_mat_sqr_KS/ /B/ /A/ 
--
-- Sets @B@ to the square of @A@, which must be a square matrix. Aliasing
-- is allowed. This function uses Kronecker segmentation.
foreign import ccall "fmpz_poly_mat.h fmpz_poly_mat_sqr_KS"
  fmpz_poly_mat_sqr_KS :: Ptr CFmpzPolyMat -> Ptr CFmpzPolyMat -> IO ()

-- | /fmpz_poly_mat_sqrlow/ /B/ /A/ /len/ 
--
-- Sets @B@ to the square of @A@, which must be a square matrix, truncating
-- all entries to length @len@. Aliasing is allowed. This function uses
-- direct formulas for very small matrices, and otherwise classical matrix
-- multiplication.
foreign import ccall "fmpz_poly_mat.h fmpz_poly_mat_sqrlow"
  fmpz_poly_mat_sqrlow :: Ptr CFmpzPolyMat -> Ptr CFmpzPolyMat -> CLong -> IO ()

-- | /fmpz_poly_mat_pow/ /B/ /A/ /exp/ 
--
-- Sets @B@ to @A@ raised to the power @exp@, where @A@ is a square matrix.
-- Uses exponentiation by squaring. Aliasing is allowed.
foreign import ccall "fmpz_poly_mat.h fmpz_poly_mat_pow"
  fmpz_poly_mat_pow :: Ptr CFmpzPolyMat -> Ptr CFmpzPolyMat -> CULong -> IO ()

-- | /fmpz_poly_mat_pow_trunc/ /B/ /A/ /exp/ /len/ 
--
-- Sets @B@ to @A@ raised to the power @exp@, truncating all entries to
-- length @len@, where @A@ is a square matrix. Uses exponentiation by
-- squaring. Aliasing is allowed.
foreign import ccall "fmpz_poly_mat.h fmpz_poly_mat_pow_trunc"
  fmpz_poly_mat_pow_trunc :: Ptr CFmpzPolyMat -> Ptr CFmpzPolyMat -> CULong -> CLong -> IO ()

-- | /fmpz_poly_mat_prod/ /res/ /factors/ /n/ 
--
-- Sets @res@ to the product of the @n@ matrices given in the vector
-- @factors@, all of which must be square and of the same size. Uses binary
-- splitting.
foreign import ccall "fmpz_poly_mat.h fmpz_poly_mat_prod"
  fmpz_poly_mat_prod :: Ptr CFmpzPolyMat -> Ptr (Ptr CFmpzPolyMat) -> CLong -> IO ()

-- Row reduction ---------------------------------------------------------------

-- | /fmpz_poly_mat_find_pivot_any/ /mat/ /start_row/ /end_row/ /c/ 
--
-- Attempts to find a pivot entry for row reduction. Returns a row index
-- \(r\) between @start_row@ (inclusive) and @stop_row@ (exclusive) such
-- that column \(c\) in @mat@ has a nonzero entry on row \(r\), or returns
-- -1 if no such entry exists.
-- 
-- This implementation simply chooses the first nonzero entry it
-- encounters. This is likely to be a nearly optimal choice if all entries
-- in the matrix have roughly the same size, but can lead to unnecessary
-- coefficient growth if the entries vary in size.
foreign import ccall "fmpz_poly_mat.h fmpz_poly_mat_find_pivot_any"
  fmpz_poly_mat_find_pivot_any :: Ptr CFmpzPolyMat -> CLong -> CLong -> CLong -> IO CLong

-- | /fmpz_poly_mat_find_pivot_partial/ /mat/ /start_row/ /end_row/ /c/ 
--
-- Attempts to find a pivot entry for row reduction. Returns a row index
-- \(r\) between @start_row@ (inclusive) and @stop_row@ (exclusive) such
-- that column \(c\) in @mat@ has a nonzero entry on row \(r\), or returns
-- -1 if no such entry exists.
-- 
-- This implementation searches all the rows in the column and chooses the
-- nonzero entry of smallest degree. If there are several entries with the
-- same minimal degree, it chooses the entry with the smallest coefficient
-- bit bound. This heuristic typically reduces coefficient growth when the
-- matrix entries vary in size.
foreign import ccall "fmpz_poly_mat.h fmpz_poly_mat_find_pivot_partial"
  fmpz_poly_mat_find_pivot_partial :: Ptr CFmpzPolyMat -> CLong -> CLong -> CLong -> IO CLong

-- | /fmpz_poly_mat_fflu/ /B/ /den/ /perm/ /A/ /rank_check/ 
--
-- Uses fraction-free Gaussian elimination to set (@B@, @den@) to a
-- fraction-free LU decomposition of @A@ and returns the rank of @A@.
-- Aliasing of @A@ and @B@ is allowed.
-- 
-- Pivot elements are chosen with @fmpz_poly_mat_find_pivot_partial@. If
-- @perm@ is non-@NULL@, the permutation of rows in the matrix will also be
-- applied to @perm@.
-- 
-- If @rank_check@ is set, the function aborts and returns 0 if the matrix
-- is detected not to have full rank without completing the elimination.
-- 
-- The denominator @den@ is set to \(\pm \operatorname{det}(A)\), where the
-- sign is decided by the parity of the permutation. Note that the
-- determinant is not generally the minimal denominator.
foreign import ccall "fmpz_poly_mat.h fmpz_poly_mat_fflu"
  fmpz_poly_mat_fflu :: Ptr CFmpzPolyMat -> Ptr CFmpzPoly -> Ptr CLong -> Ptr CFmpzPolyMat -> CInt -> IO CLong

-- | /fmpz_poly_mat_rref/ /B/ /den/ /A/ 
--
-- Sets (@B@, @den@) to the reduced row echelon form of @A@ and returns the
-- rank of @A@. Aliasing of @A@ and @B@ is allowed.
-- 
-- The denominator @den@ is set to \(\pm \operatorname{det}(A)\). Note that
-- the determinant is not generally the minimal denominator.
foreign import ccall "fmpz_poly_mat.h fmpz_poly_mat_rref"
  fmpz_poly_mat_rref :: Ptr CFmpzPolyMat -> Ptr CFmpzPoly -> Ptr CFmpzPolyMat -> IO CLong

-- Trace -----------------------------------------------------------------------

-- | /fmpz_poly_mat_trace/ /trace/ /mat/ 
--
-- Computes the trace of the matrix, i.e. the sum of the entries on the
-- main diagonal. The matrix is required to be square.
foreign import ccall "fmpz_poly_mat.h fmpz_poly_mat_trace"
  fmpz_poly_mat_trace :: Ptr CFmpzPoly -> Ptr CFmpzPolyMat -> IO ()

-- Determinant and rank --------------------------------------------------------

-- | /fmpz_poly_mat_det/ /det/ /A/ 
--
-- Sets @det@ to the determinant of the square matrix @A@. Uses a direct
-- formula, fraction-free LU decomposition, or interpolation, depending on
-- the size of the matrix.
foreign import ccall "fmpz_poly_mat.h fmpz_poly_mat_det"
  fmpz_poly_mat_det :: Ptr CFmpzPoly -> Ptr CFmpzPolyMat -> IO ()

-- | /fmpz_poly_mat_det_fflu/ /det/ /A/ 
--
-- Sets @det@ to the determinant of the square matrix @A@. The determinant
-- is computed by performing a fraction-free LU decomposition on a copy of
-- @A@.
foreign import ccall "fmpz_poly_mat.h fmpz_poly_mat_det_fflu"
  fmpz_poly_mat_det_fflu :: Ptr CFmpzPoly -> Ptr CFmpzPolyMat -> IO ()

-- | /fmpz_poly_mat_det_interpolate/ /det/ /A/ 
--
-- Sets @det@ to the determinant of the square matrix @A@. The determinant
-- is computed by determining a bound \(n\) for its length, evaluating the
-- matrix at \(n\) distinct points, computing the determinant of each
-- integer matrix, and forming the interpolating polynomial.
foreign import ccall "fmpz_poly_mat.h fmpz_poly_mat_det_interpolate"
  fmpz_poly_mat_det_interpolate :: Ptr CFmpzPoly -> Ptr CFmpzPolyMat -> IO ()

-- | /fmpz_poly_mat_rank/ /A/ 
--
-- Returns the rank of @A@. Performs fraction-free LU decomposition on a
-- copy of @A@.
foreign import ccall "fmpz_poly_mat.h fmpz_poly_mat_rank"
  fmpz_poly_mat_rank :: Ptr CFmpzPolyMat -> IO CLong

-- Inverse ---------------------------------------------------------------------

-- | /fmpz_poly_mat_inv/ /Ainv/ /den/ /A/ 
--
-- Sets (@Ainv@, @den@) to the inverse matrix of @A@. Returns 1 if @A@ is
-- nonsingular and 0 if @A@ is singular. Aliasing of @Ainv@ and @A@ is
-- allowed.
-- 
-- More precisely, @det@ will be set to the determinant of @A@ and @Ainv@
-- will be set to the adjugate matrix of @A@. Note that the determinant is
-- not necessarily the minimal denominator.
-- 
-- Uses fraction-free LU decomposition, followed by solving for the
-- identity matrix.
foreign import ccall "fmpz_poly_mat.h fmpz_poly_mat_inv"
  fmpz_poly_mat_inv :: Ptr CFmpzPolyMat -> Ptr CFmpzPoly -> Ptr CFmpzPolyMat -> IO CInt

-- Nullspace -------------------------------------------------------------------

-- | /fmpz_poly_mat_nullspace/ /res/ /mat/ 
--
-- Computes the right rational nullspace of the matrix @mat@ and returns
-- the nullity.
-- 
-- More precisely, assume that @mat@ has rank \(r\) and nullity \(n\). Then
-- this function sets the first \(n\) columns of @res@ to linearly
-- independent vectors spanning the nullspace of @mat@. As a result, we
-- always have rank(@res@) \(= n\), and @mat@ \(\times\) @res@ is the zero
-- matrix.
-- 
-- The computed basis vectors will not generally be in a reduced form. In
-- general, the polynomials in each column vector in the result will have a
-- nontrivial common GCD.
foreign import ccall "fmpz_poly_mat.h fmpz_poly_mat_nullspace"
  fmpz_poly_mat_nullspace :: Ptr CFmpzPolyMat -> Ptr CFmpzPolyMat -> IO CLong

-- Solving ---------------------------------------------------------------------

-- | /fmpz_poly_mat_solve/ /X/ /den/ /A/ /B/ 
--
-- Solves the equation \(AX = B\) for nonsingular \(A\). More precisely,
-- computes (@X@, @den@) such that \(AX = B \times \operatorname{den}\).
-- Returns 1 if \(A\) is nonsingular and 0 if \(A\) is singular. The
-- computed denominator will not generally be minimal.
-- 
-- Uses fraction-free LU decomposition followed by fraction-free forward
-- and back substitution.
foreign import ccall "fmpz_poly_mat.h fmpz_poly_mat_solve"
  fmpz_poly_mat_solve :: Ptr CFmpzPolyMat -> Ptr CFmpzPoly -> Ptr CFmpzPolyMat -> Ptr CFmpzPolyMat -> IO CInt

-- | /fmpz_poly_mat_solve_fflu/ /X/ /den/ /A/ /B/ 
--
-- Solves the equation \(AX = B\) for nonsingular \(A\). More precisely,
-- computes (@X@, @den@) such that \(AX = B \times \operatorname{den}\).
-- Returns 1 if \(A\) is nonsingular and 0 if \(A\) is singular. The
-- computed denominator will not generally be minimal.
-- 
-- Uses fraction-free LU decomposition followed by fraction-free forward
-- and back substitution.
foreign import ccall "fmpz_poly_mat.h fmpz_poly_mat_solve_fflu"
  fmpz_poly_mat_solve_fflu :: Ptr CFmpzPolyMat -> Ptr CFmpzPoly -> Ptr CFmpzPolyMat -> Ptr CFmpzPolyMat -> IO CInt

-- | /fmpz_poly_mat_solve_fflu_precomp/ /X/ /perm/ /FFLU/ /B/ 
--
-- Performs fraction-free forward and back substitution given a precomputed
-- fraction-free LU decomposition and corresponding permutation.
foreign import ccall "fmpz_poly_mat.h fmpz_poly_mat_solve_fflu_precomp"
  fmpz_poly_mat_solve_fflu_precomp :: Ptr CFmpzPolyMat -> Ptr CLong -> Ptr CFmpzPolyMat -> Ptr CFmpzPolyMat -> IO ()