{-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TypeApplications #-} {-# LANGUAGE ViewPatterns #-} -------------------------------------------------------------------------------- -- | -- Module : ArrayFire.Util -- Copyright : David Johnson (c) 2019-2020 -- License : BSD 3 -- Maintainer : David Johnson -- Stability : Experimental -- Portability : GHC -- -- Various utilities for working with the ArrayFire C library -- -- @ -- import qualified ArrayFire as A -- import Control.Monad -- -- main :: IO () -- main = do -- let arr = A.constant [1,1,1,1] 10 -- idx <- A.saveArray "key" arr "file.array" False -- foundIndex <- A.readArrayKeyCheck "file.array" "key" -- when (idx == foundIndex) $ do -- array <- A.readArrayKey "file.array" "key" -- print array -- @ -- @ -- ArrayFire Array -- [ 1 1 1 1 ] -- 10 -- @ -------------------------------------------------------------------------------- module ArrayFire.Util where import Control.Exception import Data.Proxy import Foreign.C.String import Foreign.ForeignPtr import Foreign.Marshal hiding (void) import Foreign.Storable import System.IO.Unsafe import ArrayFire.Internal.Types import ArrayFire.Internal.Util import ArrayFire.Exception import ArrayFire.FFI -- | Retrieve version for ArrayFire API -- -- @ -- >>> 'print' '=<<' 'getVersion' -- @ -- @ -- (3.6.4) -- @ getVersion :: IO (Int,Int,Int) getVersion = alloca $ \x -> alloca $ \y -> alloca $ \z -> do throwAFError =<< af_get_version x y z (,,) <$> (fromIntegral <$> peek x) <*> (fromIntegral <$> peek y) <*> (fromIntegral <$> peek z) -- | Prints array to stdout -- -- @ -- >>> 'printArray' (constant \@'Double' [1] 1) -- @ -- @ -- ArrayFire Array -- [ 1 1 1 1 ] -- 1.0 -- @ printArray :: Array a -- ^ Input 'Array' -> IO () printArray (Array fptr) = mask_ . withForeignPtr fptr $ \ptr -> throwAFError =<< af_print_array ptr -- | Gets git revision of ArrayFire -- -- @ -- >>> 'putStrLn' '=<<' 'getRevision' -- @ -- @ -- 1b8030c5 -- @ getRevision :: IO String getRevision = peekCString =<< af_get_revision -- | Prints 'Array' with error codes -- -- @ -- >>> printArrayGen "test" (constant \@'Double' [1] 1) 2 -- @ -- @ -- ArrayFire Array -- [ 1 1 1 1 ] -- 1.00 -- @ printArrayGen :: String -- ^ is the expression or name of the array -> Array a -- ^ is the input array -> Int -- ^ precision for the display -> IO () printArrayGen s (Array fptr) (fromIntegral -> prec) = do mask_ . withForeignPtr fptr $ \ptr -> withCString s $ \cstr -> throwAFError =<< af_print_array_gen cstr ptr prec -- | Saves 'Array' to disk -- -- Save an array to a binary file. -- The 'saveArray' and readArray functions are designed to provide store and read access to arrays using files written to disk. -- -- -- @ -- >>> saveArray "my array" (constant \@'Double' [1] 1) "array.file" 'True' -- @ -- @ -- 0 -- @ saveArray :: String -- ^ An expression used as tag/key for the 'Array' during readArray -> Array a -- ^ Input 'Array' -> FilePath -- ^ Path that 'Array' will be saved -> Bool -- ^ Used to append to an existing file when 'True' and create or overwrite an existing file when 'False' -> IO Int -- ^ The index location of the 'Array' in the file saveArray key (Array fptr) filename (fromIntegral . fromEnum -> append) = do mask_ . withForeignPtr fptr $ \ptr -> alloca $ \ptrIdx -> do withCString key $ \keyCstr -> withCString filename $ \filenameCstr -> do throwAFError =<< af_save_array ptrIdx keyCstr ptr filenameCstr append fromIntegral <$> peek ptrIdx -- | Reads Array by index -- -- The 'saveArray' and readArray functions are designed to provide store and read access to arrays using files written to disk. -- -- -- @ -- >>> readArrayIndex "array.file" 0 -- @ -- @ -- ArrayFire Array -- [ 1 1 1 1 ] -- 10.0000 -- @ readArrayIndex :: FilePath -- ^ Path to 'Array' location -> Int -- ^ Index into 'Array' -> IO (Array a) readArrayIndex str (fromIntegral -> idx') = withCString str $ \cstr -> createArray' (\p -> af_read_array_index p cstr idx') -- | Reads 'Array' by key -- -- @ -- >>> readArrayKey "array.file" "my array" -- @ -- @ -- ArrayFire 'Array' -- [ 1 1 1 1 ] -- 10.0000 -- @ readArrayKey :: FilePath -- ^ Path to 'Array' -> String -- ^ Key of 'Array' on disk -> IO (Array a) -- ^ Returned 'Array' readArrayKey fn key = withCString fn $ \fcstr -> withCString key $ \kcstr -> createArray' (\p -> af_read_array_key p fcstr kcstr) -- | Reads Array, checks if a key exists in the specified file -- -- When reading by key, it may be a good idea to run this function first to check for the key and then call the readArray using the index. -- -- -- @ -- >>> readArrayCheck "array.file" "my array" -- @ -- @ -- 0 -- @ readArrayKeyCheck :: FilePath -- ^ Path to file -> String -- ^ Key -> IO Int -- ^ is the tag/name of the array to be read. The key needs to have an exact match. readArrayKeyCheck a b = withCString a $ \acstr -> withCString b $ \bcstr -> fromIntegral <$> afCall1 (\p -> af_read_array_key_check p acstr bcstr) -- | Convert ArrayFire 'Array' to 'String', used for 'Show' instance. -- -- @ -- >>> 'putStrLn' '$' 'arrayString' (constant \@'Double' 10 [1,1,1,1]) -- @ -- @ -- ArrayFire 'Array' -- [ 1 1 1 1 ] -- 10.0000 -- @ arrayString :: Array a -- ^ Input 'Array' -> String -- ^ 'String' representation of 'Array' arrayString a = arrayToString "ArrayFire Array" a 4 True -- | Convert ArrayFire Array to String -- -- @ -- >>> print (constant \@'Double' 10 [1,1,1,1]) 4 'False' -- @ -- @ -- ArrayFire 'Array' -- [ 1 1 1 1 ] -- 10.0000 -- @ arrayToString :: String -- ^ Name of 'Array' -> Array a -- ^ 'Array' input -> Int -- ^ Precision of 'Array' values. -> Bool -- ^ If 'True', performs takes the transpose before rendering to 'String' -> String -- ^ 'Array' rendered to 'String' arrayToString expr (Array fptr) (fromIntegral -> prec) (fromIntegral . fromEnum -> trans) = unsafePerformIO . mask_ . withForeignPtr fptr $ \aptr -> withCString expr $ \expCstr -> alloca $ \ocstr -> do throwAFError =<< af_array_to_string ocstr expCstr aptr prec trans peekCString =<< peek ocstr -- | Retrieve size of ArrayFire data type -- -- @ -- >>> 'getSizeOf' ('Proxy' \@ 'Double') -- @ -- @ -- 8 -- @ getSizeOf :: forall a . AFType a => Proxy a -- ^ Witness of Haskell type that mirrors ArrayFire type. -> Int -- ^ Size of ArrayFire type getSizeOf proxy = unsafePerformIO . mask_ . alloca $ \csize -> do throwAFError =<< af_get_size_of csize (afType proxy) fromIntegral <$> peek csize