Flint2-0.1.0.0: src/Data/Number/Flint/Groups/Bool/Mat/FFI.hsc
{-|
module : Data.Number.Flint.Groups.Bool.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.Groups.Bool.Mat.FFI (
-- * Matrices over booleans
BoolMat (..)
, CBoolMat (..)
, newBoolMat
, withBoolMat
, withNewBoolMat
-- * Entries
, bool_mat_get_entry
, bool_mat_set_entry
-- * Memory management
, bool_mat_init
, bool_mat_clear
, bool_mat_is_empty
, bool_mat_is_square
-- * Conversions
, bool_mat_entry
, bool_mat_set
-- * Input and output
, bool_mat_get_str
, bool_mat_print
, bool_mat_fprint
-- * Value comparisons
, bool_mat_equal
, bool_mat_any
, bool_mat_all
, bool_mat_is_diagonal
, bool_mat_is_lower_triangular
, bool_mat_is_transitive
, bool_mat_is_nilpotent
-- * Random generation
, bool_mat_randtest
, bool_mat_randtest_diagonal
, bool_mat_randtest_nilpotent
-- * Special matrices
, bool_mat_zero
, bool_mat_one
, bool_mat_directed_path
, bool_mat_directed_cycle
-- * Transpose
, bool_mat_transpose
-- * Arithmetic
, bool_mat_complement
, bool_mat_add
, bool_mat_mul
, bool_mat_mul_entrywise
, bool_mat_sqr
, bool_mat_pow_ui
-- * Special functions
, bool_mat_trace
, bool_mat_nilpotency_degree
, bool_mat_transitive_closure
, bool_mat_get_strongly_connected_components
, bool_mat_all_pairs_longest_walk
) where
-- Matrices over booleans ------------------------------------------------------
-- A @bool_mat_t@ represents a dense matrix over the boolean semiring
-- \(\langle \left\{0, 1\right\}, \vee, \wedge \rangle\), implemented as an
-- array of entries of type @int@.
--
-- The dimension (number of rows and columns) of a matrix is fixed at
-- initialization, and the user must ensure that inputs and outputs to an
-- operation have compatible dimensions. The number of rows or columns in a
-- matrix can be zero.
--
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.Marshal.Array ( advancePtr )
import Foreign.Storable
import Foreign.Marshal ( free )
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
#include <flint/flint.h>
#include <flint/bool_mat.h>
--------------------------------------------------------------------------------
data BoolMat = BoolMat {-# UNPACK #-} !(ForeignPtr CBoolMat)
data CBoolMat = CBoolMat (Ptr CInt) CLong CLong (Ptr (Ptr CInt))
instance Storable CBoolMat where
{-# INLINE sizeOf #-}
sizeOf _ = #{size bool_mat_t}
{-# INLINE alignment #-}
alignment _ = #{alignment bool_mat_t}
peek ptr = CBoolMat
<$> #{peek bool_mat_struct, entries} ptr
<*> #{peek bool_mat_struct, r } ptr
<*> #{peek bool_mat_struct, c } ptr
<*> #{peek bool_mat_struct, rows } ptr
poke = error "CBoolMat.poke: Not defined."
newBoolMat rows cols = do
x <- mallocForeignPtr
withForeignPtr x $ \x -> bool_mat_init x rows cols
addForeignPtrFinalizer p_bool_mat_clear x
return $ BoolMat x
{-# INLINE withBoolMat #-}
withBoolMat (BoolMat x) f = do
withForeignPtr x $ \px -> f px >>= return . (BoolMat x,)
{-# INLINE withNewBoolMat #-}
withNewBoolMat rows cols f = do
x <- newBoolMat rows cols
withBoolMat x f
--------------------------------------------------------------------------------
-- | /bool_mat_get_entry/ /mat/ /i/ /j/
--
-- Returns the entry of matrix /mat/ at row /i/ and column /j/.
-- foreign import ccall "bool_mat.h bool_mat_get_entry"
bool_mat_get_entry :: Ptr CBoolMat -> CLong -> CLong -> IO CInt
bool_mat_get_entry mat i j = do
CBoolMat p r c _ <- peek mat
result <- peek (p `advancePtr` (fromIntegral (i*c + j)))
return result
-- | /bool_mat_set_entry/ /mat/ /i/ /j/ /x/
--
-- Sets the entry of matrix /mat/ at row /i/ and column /j/ to /x/.
bool_mat_set_entry :: Ptr CBoolMat -> CLong -> CLong -> CInt -> IO ()
bool_mat_set_entry mat i j x = do
CBoolMat p r c _ <- peek mat
poke (p `advancePtr` (fromIntegral (i*c + j))) x
-- Memory management -----------------------------------------------------------
-- | /bool_mat_init/ /mat/ /r/ /c/
--
-- Initializes the matrix, setting it to the zero matrix with /r/ rows and
-- /c/ columns.
foreign import ccall "bool_mat.h bool_mat_init"
bool_mat_init :: Ptr CBoolMat -> CLong -> CLong -> IO ()
-- | /bool_mat_clear/ /mat/
--
-- Clears the matrix, deallocating all entries.
foreign import ccall "bool_mat.h bool_mat_clear"
bool_mat_clear :: Ptr CBoolMat -> IO ()
foreign import ccall "bool_mat.h &bool_mat_clear"
p_bool_mat_clear :: FunPtr (Ptr CBoolMat -> IO ())
-- | /bool_mat_is_empty/ /mat/
--
-- Returns nonzero iff the number of rows or the number of columns in /mat/
-- is zero. Note that this does not depend on the entry values of /mat/.
bool_mat_is_empty :: Ptr CBoolMat -> IO CInt
bool_mat_is_empty mat = do
CBoolMat _ r c _ <- peek mat
return $ if r == 0 || c == 0 then 1 else 0
-- | /bool_mat_is_square/ /mat/
--
-- Returns nonzero iff the number of rows is equal to the number of columns
-- in /mat/.
bool_mat_is_square :: Ptr CBoolMat -> IO CInt
bool_mat_is_square mat = do
CBoolMat _ r c _ <- peek mat
return $ if r == c then 1 else 0
-- Conversions -----------------------------------------------------------------
bool_mat_entry mat i j = do
CBoolMat entries r c rows <- peek mat
return $ entries `advancePtr` (fromIntegral (i*c + j))
-- | /bool_mat_set/ /dest/ /src/
--
-- Sets /dest/ to /src/. The operands must have identical dimensions.
foreign import ccall "bool_mat.h bool_mat_set"
bool_mat_set :: Ptr CBoolMat -> Ptr CBoolMat -> IO ()
-- Input and output ------------------------------------------------------------
foreign import ccall "bool_mat.h bool_mat_get_str"
bool_mat_get_str :: Ptr CBoolMat -> IO CString
-- | /bool_mat_print/ /mat/
--
-- Prints each entry in the matrix.
bool_mat_print :: Ptr CBoolMat -> IO ()
bool_mat_print mat = do
printCStr bool_mat_get_str mat
return ()
-- | /bool_mat_fprint/ /file/ /mat/
--
-- Prints each entry in the matrix to the stream /file/.
foreign import ccall "bool_mat.h bool_mat_fprint"
bool_mat_fprint :: Ptr CFile -> Ptr CBoolMat -> IO ()
-- Value comparisons -----------------------------------------------------------
-- | /bool_mat_equal/ /mat1/ /mat2/
--
-- Returns nonzero iff the matrices have the same dimensions and identical
-- entries.
foreign import ccall "bool_mat.h bool_mat_equal"
bool_mat_equal :: Ptr CBoolMat -> Ptr CBoolMat -> IO CInt
-- | /bool_mat_any/ /mat/
--
-- Returns nonzero iff /mat/ has a nonzero entry.
foreign import ccall "bool_mat.h bool_mat_any"
bool_mat_any :: Ptr CBoolMat -> IO CInt
-- | /bool_mat_all/ /mat/
--
-- Returns nonzero iff all entries of /mat/ are nonzero.
foreign import ccall "bool_mat.h bool_mat_all"
bool_mat_all :: Ptr CBoolMat -> IO CInt
-- | /bool_mat_is_diagonal/ /A/
--
-- Returns nonzero iff \(i \ne j \implies \bar{A_{ij}}\).
foreign import ccall "bool_mat.h bool_mat_is_diagonal"
bool_mat_is_diagonal :: Ptr CBoolMat -> IO CInt
-- | /bool_mat_is_lower_triangular/ /A/
--
-- Returns nonzero iff \(i < j \implies \bar{A_{ij}}\).
foreign import ccall "bool_mat.h bool_mat_is_lower_triangular"
bool_mat_is_lower_triangular :: Ptr CBoolMat -> IO CInt
-- | /bool_mat_is_transitive/ /mat/
--
-- Returns nonzero iff \(A_{ij} \wedge A_{jk} \implies A_{ik}\).
foreign import ccall "bool_mat.h bool_mat_is_transitive"
bool_mat_is_transitive :: Ptr CBoolMat -> IO CInt
-- | /bool_mat_is_nilpotent/ /A/
--
-- Returns nonzero iff some positive matrix power of \(A\) is zero.
foreign import ccall "bool_mat.h bool_mat_is_nilpotent"
bool_mat_is_nilpotent :: Ptr CBoolMat -> IO CInt
-- Random generation -----------------------------------------------------------
-- | /bool_mat_randtest/ /mat/ /state/
--
-- Sets /mat/ to a random matrix.
foreign import ccall "bool_mat.h bool_mat_randtest"
bool_mat_randtest :: Ptr CBoolMat -> Ptr CFRandState -> IO ()
-- | /bool_mat_randtest_diagonal/ /mat/ /state/
--
-- Sets /mat/ to a random diagonal matrix.
foreign import ccall "bool_mat.h bool_mat_randtest_diagonal"
bool_mat_randtest_diagonal :: Ptr CBoolMat -> Ptr CFRandState -> IO ()
-- | /bool_mat_randtest_nilpotent/ /mat/ /state/
--
-- Sets /mat/ to a random nilpotent matrix.
foreign import ccall "bool_mat.h bool_mat_randtest_nilpotent"
bool_mat_randtest_nilpotent :: Ptr CBoolMat -> Ptr CFRandState -> IO ()
-- Special matrices ------------------------------------------------------------
-- | /bool_mat_zero/ /mat/
--
-- Sets all entries in mat to zero.
foreign import ccall "bool_mat.h bool_mat_zero"
bool_mat_zero :: Ptr CBoolMat -> IO ()
-- | /bool_mat_one/ /mat/
--
-- Sets the entries on the main diagonal to ones, and all other entries to
-- zero.
foreign import ccall "bool_mat.h bool_mat_one"
bool_mat_one :: Ptr CBoolMat -> IO ()
-- | /bool_mat_directed_path/ /A/
--
-- Sets \(A_{ij}\) to \(j = i + 1\). Requires that \(A\) is a square
-- matrix.
foreign import ccall "bool_mat.h bool_mat_directed_path"
bool_mat_directed_path :: Ptr CBoolMat -> IO ()
-- | /bool_mat_directed_cycle/ /A/
--
-- Sets \(A_{ij}\) to \(j = (i + 1) \mod n\) where \(n\) is the order of
-- the square matrix \(A\).
foreign import ccall "bool_mat.h bool_mat_directed_cycle"
bool_mat_directed_cycle :: Ptr CBoolMat -> IO ()
-- Transpose -------------------------------------------------------------------
-- | /bool_mat_transpose/ /dest/ /src/
--
-- Sets /dest/ to the transpose of /src/. The operands must have compatible
-- dimensions. Aliasing is allowed.
foreign import ccall "bool_mat.h bool_mat_transpose"
bool_mat_transpose :: Ptr CBoolMat -> Ptr CBoolMat -> IO ()
-- Arithmetic ------------------------------------------------------------------
-- | /bool_mat_complement/ /B/ /A/
--
-- Sets /B/ to the logical complement of /A/. That is \(B_{ij}\) is set to
-- \(\bar{A_{ij}}\). The operands must have the same dimensions.
foreign import ccall "bool_mat.h bool_mat_complement"
bool_mat_complement :: Ptr CBoolMat -> Ptr CBoolMat -> IO ()
-- | /bool_mat_add/ /res/ /mat1/ /mat2/
--
-- Sets /res/ to the sum of /mat1/ and /mat2/. The operands must have the
-- same dimensions.
foreign import ccall "bool_mat.h bool_mat_add"
bool_mat_add :: Ptr CBoolMat -> Ptr CBoolMat -> Ptr CBoolMat -> IO ()
-- | /bool_mat_mul/ /res/ /mat1/ /mat2/
--
-- Sets /res/ to the matrix product of /mat1/ and /mat2/. The operands must
-- have compatible dimensions for matrix multiplication.
foreign import ccall "bool_mat.h bool_mat_mul"
bool_mat_mul :: Ptr CBoolMat -> Ptr CBoolMat -> Ptr CBoolMat -> IO ()
-- | /bool_mat_mul_entrywise/ /res/ /mat1/ /mat2/
--
-- Sets /res/ to the entrywise product of /mat1/ and /mat2/. The operands
-- must have the same dimensions.
foreign import ccall "bool_mat.h bool_mat_mul_entrywise"
bool_mat_mul_entrywise :: Ptr CBoolMat -> Ptr CBoolMat -> Ptr CBoolMat -> IO ()
-- | /bool_mat_sqr/ /B/ /A/
--
-- Sets /B/ to the matrix square of /A/. The operands must both be square
-- with the same dimensions.
bool_mat_sqr :: Ptr CBoolMat -> Ptr CBoolMat -> IO ()
bool_mat_sqr b a = bool_mat_mul b a a
-- | /bool_mat_pow_ui/ /B/ /A/ /exp/
--
-- Sets /B/ to /A/ raised to the power /exp/. Requires that /A/ is a square
-- matrix.
foreign import ccall "bool_mat.h bool_mat_pow_ui"
bool_mat_pow_ui :: Ptr CBoolMat -> Ptr CBoolMat -> CULong -> IO ()
-- Special functions -----------------------------------------------------------
-- | /bool_mat_trace/ /mat/
--
-- Returns the trace of the matrix, i.e. the sum of entries on the main
-- diagonal of /mat/. The matrix is required to be square. The sum is in
-- the boolean semiring, so this function returns nonzero iff any entry on
-- the diagonal of /mat/ is nonzero.
foreign import ccall "bool_mat.h bool_mat_trace"
bool_mat_trace :: Ptr CBoolMat -> IO CInt
-- | /bool_mat_nilpotency_degree/ /A/
--
-- Returns the nilpotency degree of the \(n \times n\) matrix /A/. It
-- returns the smallest positive \(k\) such that \(A^k = 0\). If no such
-- \(k\) exists then the function returns \(-1\) if \(n\) is positive, and
-- otherwise it returns \(0\).
foreign import ccall "bool_mat.h bool_mat_nilpotency_degree"
bool_mat_nilpotency_degree :: Ptr CBoolMat -> IO CLong
-- | /bool_mat_transitive_closure/ /B/ /A/
--
-- Sets /B/ to the transitive closure \(\sum_{k=1}^\infty A^k\). The matrix
-- /A/ is required to be square.
foreign import ccall "bool_mat.h bool_mat_transitive_closure"
bool_mat_transitive_closure :: Ptr CBoolMat -> Ptr CBoolMat -> IO ()
-- | /bool_mat_get_strongly_connected_components/ /p/ /A/
--
-- Partitions the \(n\) row and column indices of the \(n \times n\) matrix
-- /A/ according to the strongly connected components (SCC) of the graph
-- for which /A/ is the adjacency matrix. If the graph has \(k\) SCCs then
-- the function returns \(k\), and for each vertex \(i \in [0, n-1]\),
-- \(p_i\) is set to the index of the SCC to which the vertex belongs. The
-- SCCs themselves can be considered as nodes in a directed acyclic graph
-- (DAG), and the SCCs are indexed in postorder with respect to that DAG.
foreign import ccall "bool_mat.h bool_mat_get_strongly_connected_components"
bool_mat_get_strongly_connected_components :: Ptr CLong -> Ptr CBoolMat -> IO CLong
-- | /bool_mat_all_pairs_longest_walk/ /B/ /A/
--
-- Sets \(B_{ij}\) to the length of the longest walk with endpoint vertices
-- \(i\) and \(j\) in the graph whose adjacency matrix is /A/. The matrix
-- /A/ must be square. Empty walks with zero length which begin and end at
-- the same vertex are allowed. If \(j\) is not reachable from \(i\) then
-- no walk from \(i\) to \(j\) exists and \(B_{ij}\) is set to the special
-- value \(-1\). If arbitrarily long walks from \(i\) to \(j\) exist then
-- \(B_{ij}\) is set to the special value \(-2\).
--
-- The function returns \(-2\) if any entry of \(B_{ij}\) is \(-2\), and
-- otherwise it returns the maximum entry in \(B\), except if \(A\) is
-- empty in which case \(-1\) is returned. Note that the returned value is
-- one less than that of @nilpotency_degree@.
--
-- This function can help quantify entrywise errors in a truncated
-- evaluation of a matrix power series. If /A/ is an indicator matrix with
-- the same sparsity pattern as a matrix \(M\) over the real or complex
-- numbers, and if \(B_{ij}\) does not take the special value \(-2\), then
-- the tail \(\left[ \sum_{k=N}^\infty a_k M^k \right]_{ij}\) vanishes when
-- \(N > B_{ij}\).
foreign import ccall "bool_mat.h bool_mat_all_pairs_longest_walk"
bool_mat_all_pairs_longest_walk :: Ptr CFmpzMat -> Ptr CBoolMat -> IO CLong