packages feed

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