{-# LANGUAGE RecordWildCards     #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE PolyKinds           #-}
{-# LANGUAGE DataKinds           #-}
{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE FlexibleInstances   #-}
{-# LANGUAGE TypeApplications    #-}
{-# LANGUAGE ViewPatterns        #-}
{-# LANGUAGE KindSignatures      #-}
--------------------------------------------------------------------------------
-- |
-- Module      : ArrayFire.Array
-- Copyright   : David Johnson (c) 2019-2020
-- License     : BSD 3
-- Maintainer  : David Johnson <djohnson.m@gmail.com>
-- Stability   : Experimental
-- Portability : GHC
--
-- Functions for constructing and querying metadata from 'Array'
--
-- @
-- module Main where
--
-- import ArrayFire
--
-- main :: 'IO' ()
-- main = 'print' (matrix \@'Double' (2,2) [ [1..], [1..] ])
-- @
--
-- @
-- ArrayFire Array
-- [2 2 1 1]
--     1.0000     1.0000
--     2.0000     2.0000
-- @
--------------------------------------------------------------------------------
module ArrayFire.Array where

import           Control.Exception
import           Control.Monad
import           Data.Proxy
import           Data.Vector.Storable       hiding (mapM_, take, concat, concatMap)
import qualified Data.Vector.Storable       as V
import           Foreign.ForeignPtr
import           Foreign.Marshal            hiding (void)
import           Foreign.Ptr
import           Foreign.Storable

import           System.IO.Unsafe

import           ArrayFire.Exception
import           ArrayFire.FFI
import           ArrayFire.Util
import           ArrayFire.Internal.Array
import           ArrayFire.Internal.Defines
import           ArrayFire.Internal.Types

-- | Smart constructor for creating a scalar 'Array'
--
-- >>> scalar @Double 2.0
-- ArrayFire Array
-- [1 1 1 1]
--    2.0000
scalar :: AFType a => a -> Array a
scalar :: forall a. AFType a => a -> Array a
scalar a
x = [Int] -> [a] -> Array a
forall array. AFType array => [Int] -> [array] -> Array array
mkArray [Int
1] [a
x]

-- | Smart constructor for creating a vector 'Array'
--
-- >>> vector @Double 10 [1..]
-- ArrayFire Array
-- [10 1 1 1]
--     1.0000
--     2.0000
--     3.0000
--     4.0000
--     5.0000
--     6.0000
--     7.0000
--     8.0000
--     9.0000
--    10.0000
vector :: AFType a => Int -> [a] -> Array a
vector :: forall a. AFType a => Int -> [a] -> Array a
vector Int
n = [Int] -> [a] -> Array a
forall array. AFType array => [Int] -> [array] -> Array array
mkArray [Int
n] ([a] -> Array a) -> ([a] -> [a]) -> [a] -> Array a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> [a] -> [a]
forall a. Int -> [a] -> [a]
take Int
n

-- | Smart constructor for creating a matrix 'Array'
--
-- >>> A.matrix @Double (3,2) [[1,2,3],[4,5,6]]
-- ArrayFire Array
-- [3 2 1 1]
--    1.0000     4.0000
--    2.0000     5.0000
--    3.0000     6.0000
--
matrix :: AFType a => (Int,Int) -> [[a]] -> Array a
matrix :: forall a. AFType a => (Int, Int) -> [[a]] -> Array a
matrix (Int
x,Int
y)
  = [Int] -> [a] -> Array a
forall array. AFType array => [Int] -> [array] -> Array array
mkArray [Int
x,Int
y]
  ([a] -> Array a) -> ([[a]] -> [a]) -> [[a]] -> Array a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [[a]] -> [a]
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat
  ([[a]] -> [a]) -> ([[a]] -> [[a]]) -> [[a]] -> [a]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> [[a]] -> [[a]]
forall a. Int -> [a] -> [a]
take Int
y
  ([[a]] -> [[a]]) -> ([[a]] -> [[a]]) -> [[a]] -> [[a]]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ([a] -> [a]) -> [[a]] -> [[a]]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (Int -> [a] -> [a]
forall a. Int -> [a] -> [a]
take Int
x)

-- | Smart constructor for creating a cubic 'Array'
--
-- >>> cube @Double (2,2,2) [[[2,2],[2,2]],[[2,2],[2,2]]]
--
-- @
-- ArrayFire Array
-- [2 2 2 1]
--    2.0000     2.0000
--    2.0000     2.0000
--
--    2.0000     2.0000
--    2.0000     2.0000
-- @
cube :: AFType a => (Int,Int,Int) -> [[[a]]] -> Array a
cube :: forall a. AFType a => (Int, Int, Int) -> [[[a]]] -> Array a
cube (Int
x,Int
y,Int
z)
  = [Int] -> [a] -> Array a
forall array. AFType array => [Int] -> [array] -> Array array
mkArray [Int
x,Int
y,Int
z]
  ([a] -> Array a) -> ([[[a]]] -> [a]) -> [[[a]]] -> Array a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [[a]] -> [a]
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat
  ([[a]] -> [a]) -> ([[[a]]] -> [[a]]) -> [[[a]]] -> [a]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ([[a]] -> [a]) -> [[[a]]] -> [[a]]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap [[a]] -> [a]
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat
  ([[[a]]] -> [[a]]) -> ([[[a]]] -> [[[a]]]) -> [[[a]]] -> [[a]]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> [[[a]]] -> [[[a]]]
forall a. Int -> [a] -> [a]
take Int
z
  ([[[a]]] -> [[[a]]]) -> ([[[a]]] -> [[[a]]]) -> [[[a]]] -> [[[a]]]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ([[a]] -> [[a]]) -> [[[a]]] -> [[[a]]]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (Int -> [[a]] -> [[a]]
forall a. Int -> [a] -> [a]
take Int
y)
  ([[[a]]] -> [[[a]]]) -> ([[[a]]] -> [[[a]]]) -> [[[a]]] -> [[[a]]]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (([[a]] -> [[a]]) -> [[[a]]] -> [[[a]]]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (([[a]] -> [[a]]) -> [[[a]]] -> [[[a]]])
-> (Int -> [[a]] -> [[a]]) -> Int -> [[[a]]] -> [[[a]]]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ([a] -> [a]) -> [[a]] -> [[a]]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (([a] -> [a]) -> [[a]] -> [[a]])
-> (Int -> [a] -> [a]) -> Int -> [[a]] -> [[a]]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> [a] -> [a]
forall a. Int -> [a] -> [a]
take) Int
x

-- | Smart constructor for creating a tensor 'Array'
--
-- >>> tensor @Double (2,2,2,2) [[[[2,2],[2,2]],[[2,2],[2,2]]], [[[2,2],[2,2]],[[2,2],[2,2]]]]
--
-- @
-- ArrayFire Array
-- [2 2 2 2]
--     2.0000     2.0000
--     2.0000     2.0000
--
--     2.0000     2.0000
--     2.0000     2.0000
--
--
--     2.0000     2.0000
--     2.0000     2.0000
--
--     2.0000     2.0000
--     2.0000     2.0000
-- @
tensor :: AFType a => (Int, Int,Int,Int) -> [[[[a]]]] -> Array a
tensor :: forall a. AFType a => (Int, Int, Int, Int) -> [[[[a]]]] -> Array a
tensor (Int
w,Int
x,Int
y,Int
z)
  = [Int] -> [a] -> Array a
forall array. AFType array => [Int] -> [array] -> Array array
mkArray [Int
w,Int
x,Int
y,Int
z]
  ([a] -> Array a) -> ([[[[a]]]] -> [a]) -> [[[[a]]]] -> Array a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [[a]] -> [a]
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat
  ([[a]] -> [a]) -> ([[[[a]]]] -> [[a]]) -> [[[[a]]]] -> [a]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ([[a]] -> [a]) -> [[[a]]] -> [[a]]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap [[a]] -> [a]
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat
  ([[[a]]] -> [[a]]) -> ([[[[a]]]] -> [[[a]]]) -> [[[[a]]]] -> [[a]]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (([[[a]]] -> [[a]]) -> [[[[a]]]] -> [[[a]]]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (([[[a]]] -> [[a]]) -> [[[[a]]]] -> [[[a]]])
-> (([[a]] -> [a]) -> [[[a]]] -> [[a]])
-> ([[a]] -> [a])
-> [[[[a]]]]
-> [[[a]]]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ([[a]] -> [a]) -> [[[a]]] -> [[a]]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap) [[a]] -> [a]
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat
  ([[[[a]]]] -> [[[a]]])
-> ([[[[a]]]] -> [[[[a]]]]) -> [[[[a]]]] -> [[[a]]]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> [[[[a]]]] -> [[[[a]]]]
forall a. Int -> [a] -> [a]
take Int
z
  ([[[[a]]]] -> [[[[a]]]])
-> ([[[[a]]]] -> [[[[a]]]]) -> [[[[a]]]] -> [[[[a]]]]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (([[[a]]] -> [[[a]]]) -> [[[[a]]]] -> [[[[a]]]]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (([[[a]]] -> [[[a]]]) -> [[[[a]]]] -> [[[[a]]]])
-> (Int -> [[[a]]] -> [[[a]]]) -> Int -> [[[[a]]]] -> [[[[a]]]]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> [[[a]]] -> [[[a]]]
forall a. Int -> [a] -> [a]
take) Int
y
  ([[[[a]]]] -> [[[[a]]]])
-> ([[[[a]]]] -> [[[[a]]]]) -> [[[[a]]]] -> [[[[a]]]]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (([[[a]]] -> [[[a]]]) -> [[[[a]]]] -> [[[[a]]]]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (([[[a]]] -> [[[a]]]) -> [[[[a]]]] -> [[[[a]]]])
-> (Int -> [[[a]]] -> [[[a]]]) -> Int -> [[[[a]]]] -> [[[[a]]]]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ([[a]] -> [[a]]) -> [[[a]]] -> [[[a]]]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (([[a]] -> [[a]]) -> [[[a]]] -> [[[a]]])
-> (Int -> [[a]] -> [[a]]) -> Int -> [[[a]]] -> [[[a]]]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> [[a]] -> [[a]]
forall a. Int -> [a] -> [a]
take) Int
x
  ([[[[a]]]] -> [[[[a]]]])
-> ([[[[a]]]] -> [[[[a]]]]) -> [[[[a]]]] -> [[[[a]]]]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (([[[a]]] -> [[[a]]]) -> [[[[a]]]] -> [[[[a]]]]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (([[[a]]] -> [[[a]]]) -> [[[[a]]]] -> [[[[a]]]])
-> (Int -> [[[a]]] -> [[[a]]]) -> Int -> [[[[a]]]] -> [[[[a]]]]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ([[a]] -> [[a]]) -> [[[a]]] -> [[[a]]]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (([[a]] -> [[a]]) -> [[[a]]] -> [[[a]]])
-> (Int -> [[a]] -> [[a]]) -> Int -> [[[a]]] -> [[[a]]]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ([a] -> [a]) -> [[a]] -> [[a]]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (([a] -> [a]) -> [[a]] -> [[a]])
-> (Int -> [a] -> [a]) -> Int -> [[a]] -> [[a]]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> [a] -> [a]
forall a. Int -> [a] -> [a]
take) Int
w

-- | Internal function for 'Array' construction
--
-- >>> mkArray @Double [10] [1.0 .. 10.0]
-- ArrayFire Array
-- [10 1 1 1]
--     1.0000
--     2.0000
--     3.0000
--     4.0000
--     5.0000
--     6.0000
--     7.0000
--     8.0000
--     9.0000
--    10.0000
mkArray
  :: forall array
   . AFType array
  => [Int]
  -- ^ Dimensions
  -> [array]
  -- ^ Array elements
  -> Array array
  -- ^ Returned array
{-# NOINLINE mkArray #-}
mkArray :: forall array. AFType array => [Int] -> [array] -> Array array
mkArray [Int]
dims [array]
xs =
  IO (Array array) -> Array array
forall a. IO a -> a
unsafePerformIO (IO (Array array) -> Array array)
-> IO (Array array) -> Array array
forall a b. (a -> b) -> a -> b
$ do
    Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when ([array] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
Prelude.length (Int -> [array] -> [array]
forall a. Int -> [a] -> [a]
take Int
size [array]
xs) Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
size) (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$ do
      let msg :: String
msg = String
"Invalid elements provided. "
           String -> String -> String
forall a. Semigroup a => a -> a -> a
<> String
"Expected "
           String -> String -> String
forall a. Semigroup a => a -> a -> a
<> Int -> String
forall a. Show a => a -> String
show Int
size
           String -> String -> String
forall a. Semigroup a => a -> a -> a
<> String
" elements received "
           String -> String -> String
forall a. Semigroup a => a -> a -> a
<> Int -> String
forall a. Show a => a -> String
show ([array] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
Prelude.length [array]
xs)
      AFException -> IO ()
forall e a. Exception e => e -> IO a
throwIO (AFExceptionType -> Int -> String -> AFException
AFException AFExceptionType
SizeError Int
203 String
msg)
    AFArray
dataPtr <- Ptr array -> AFArray
forall a b. Ptr a -> Ptr b
castPtr (Ptr array -> AFArray) -> IO (Ptr array) -> IO AFArray
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [array] -> IO (Ptr array)
forall a. Storable a => [a] -> IO (Ptr a)
newArray (Int -> [array] -> [array]
forall a. Int -> [a] -> [a]
Prelude.take Int
size [array]
xs)
    let ndims :: CUInt
ndims = Int -> CUInt
forall a b. (Integral a, Num b) => a -> b
fromIntegral ([Int] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
Prelude.length [Int]
dims)
    (Ptr AFArray -> IO (Array array)) -> IO (Array array)
forall a b. Storable a => (Ptr a -> IO b) -> IO b
alloca ((Ptr AFArray -> IO (Array array)) -> IO (Array array))
-> (Ptr AFArray -> IO (Array array)) -> IO (Array array)
forall a b. (a -> b) -> a -> b
$ \Ptr AFArray
arrayPtr -> do
      Ptr AFArray -> IO ()
zeroOutArray Ptr AFArray
arrayPtr
      Ptr DimT
dimsPtr <- [DimT] -> IO (Ptr DimT)
forall a. Storable a => [a] -> IO (Ptr a)
newArray (CLLong -> DimT
DimT (CLLong -> DimT) -> (Int -> CLLong) -> Int -> DimT
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> CLLong
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int -> DimT) -> [Int] -> [DimT]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [Int]
dims)
      AFErr -> IO ()
throwAFError (AFErr -> IO ()) -> IO AFErr -> IO ()
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< Ptr AFArray -> AFArray -> CUInt -> Ptr DimT -> AFDtype -> IO AFErr
af_create_array Ptr AFArray
arrayPtr AFArray
dataPtr CUInt
ndims Ptr DimT
dimsPtr AFDtype
dType
      AFArray -> IO ()
forall a. Ptr a -> IO ()
free AFArray
dataPtr IO () -> IO () -> IO ()
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> Ptr DimT -> IO ()
forall a. Ptr a -> IO ()
free Ptr DimT
dimsPtr
      AFArray
arr <- Ptr AFArray -> IO AFArray
forall a. Storable a => Ptr a -> IO a
peek Ptr AFArray
arrayPtr
      ForeignPtr () -> Array array
forall a. ForeignPtr () -> Array a
Array (ForeignPtr () -> Array array)
-> IO (ForeignPtr ()) -> IO (Array array)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> FinalizerPtr () -> AFArray -> IO (ForeignPtr ())
forall a. FinalizerPtr a -> Ptr a -> IO (ForeignPtr a)
newForeignPtr FinalizerPtr ()
af_release_array_finalizer AFArray
arr
    where
      size :: Int
size  = [Int] -> Int
forall (t :: * -> *) a. (Foldable t, Num a) => t a -> a
Prelude.product [Int]
dims
      dType :: AFDtype
dType = Proxy array -> AFDtype
forall a. AFType a => Proxy a -> AFDtype
afType (forall {t}. Proxy t
forall {k} (t :: k). Proxy t
Proxy @array)

-- af_err af_create_handle(af_array *arr, const unsigned ndims, const dim_t * const dims, const af_dtype type);

-- | Copies an 'Array' to a new 'Array'
--
-- >>> copyArray (scalar @Double 10)
-- ArrayFire Array
-- [1 1 1 1]
--   10.0000
copyArray
  :: AFType a
  => Array a
  -- ^ 'Array' to be copied
  -> Array a
    -- ^ Newly copied 'Array'
copyArray :: forall a. AFType a => Array a -> Array a
copyArray = (Array a -> (Ptr AFArray -> AFArray -> IO AFErr) -> Array a
forall a.
Array a -> (Ptr AFArray -> AFArray -> IO AFErr) -> Array a
`op1` Ptr AFArray -> AFArray -> IO AFErr
af_copy_array)
-- af_err af_write_array(af_array arr, const void *data, const size_t bytes, af_source src);
-- af_err af_get_data_ptr(void *data, const af_array arr);

-- | Retains an 'Array', increases reference count
--
-- >>> retainArray (scalar @Double 10)
-- ArrayFire Array
-- [1 1 1 1]
--   10.0000
retainArray
  :: AFType a
  => Array a
  -- ^ Input 'Array'
  -> Array a
retainArray :: forall a. AFType a => Array a -> Array a
retainArray =
  (Array a -> (Ptr AFArray -> AFArray -> IO AFErr) -> Array a
forall a.
Array a -> (Ptr AFArray -> AFArray -> IO AFErr) -> Array a
`op1` Ptr AFArray -> AFArray -> IO AFErr
af_retain_array)

-- | Retrieves 'Array' reference count
--
-- >>> initialArray = scalar @Double 10
-- >>> retainedArray = retain initialArray
-- >>> getDataRefCount retainedArray
-- 2
--
getDataRefCount
  :: AFType a
  => Array a
  -- ^ Input 'Array'
  -> Int
  -- ^ Reference count
getDataRefCount :: forall a. AFType a => Array a -> Int
getDataRefCount =
  CInt -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral (CInt -> Int) -> (Array a -> CInt) -> Array a -> Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Array a -> (Ptr CInt -> AFArray -> IO AFErr) -> CInt
forall a b.
Storable a =>
Array b -> (Ptr a -> AFArray -> IO AFErr) -> a
`infoFromArray` Ptr CInt -> AFArray -> IO AFErr
af_get_data_ref_count)

-- af_err af_eval(af_array in);
-- af_err af_eval_multiple(const int num, af_array *arrays);

-- | Should manual evaluation occur
--
-- >>> setManualEvalFlag True
-- ()
setManualEvalFlag
  :: Bool
  -- ^ Whether or not to perform manual evaluation
  -> IO ()
setManualEvalFlag :: Bool -> IO ()
setManualEvalFlag (Int -> CBool
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int -> CBool) -> (Bool -> Int) -> Bool -> CBool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Bool -> Int
forall a. Enum a => a -> Int
fromEnum -> CBool
b) =
  IO AFErr -> IO ()
afCall (CBool -> IO AFErr
af_set_manual_eval_flag CBool
b)

-- | Retrieve manual evaluation status
--
-- >>> setManualEvalFlag False
-- >>> getManualEvalFlag
-- False
--
getManualEvalFlag
  :: IO Bool
getManualEvalFlag :: IO Bool
getManualEvalFlag =
  Int -> Bool
forall a. Enum a => Int -> a
toEnum (Int -> Bool) -> (CBool -> Int) -> CBool -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. CBool -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral (CBool -> Bool) -> IO CBool -> IO Bool
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (Ptr CBool -> IO AFErr) -> IO CBool
forall a. Storable a => (Ptr a -> IO AFErr) -> IO a
afCall1 Ptr CBool -> IO AFErr
af_get_manual_eval_flag

-- | Retrieve element count
--
-- >>> getElements (vector @Double 10 [1..])
-- 10
--
getElements
  :: AFType a
  => Array a
  -- ^ Input 'Array'
  -> Int
  -- ^ Count of elements in 'Array'
getElements :: forall a. AFType a => Array a -> Int
getElements Array a
a =
  DimT -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Array a
a Array a -> (Ptr DimT -> AFArray -> IO AFErr) -> DimT
forall a b.
Storable a =>
Array b -> (Ptr a -> AFArray -> IO AFErr) -> a
`infoFromArray` Ptr DimT -> AFArray -> IO AFErr
af_get_elements)

-- | Retrieve type of 'Array'
--
-- >>> getType (vector @Double 10 [1..])
-- F64
--
getType
  :: AFType a
  => Array a
  -> AFDType
getType :: forall a. AFType a => Array a -> AFDType
getType Array a
a = AFDtype -> AFDType
fromAFType (Array a
a Array a -> (Ptr AFDtype -> AFArray -> IO AFErr) -> AFDtype
forall a b.
Storable a =>
Array b -> (Ptr a -> AFArray -> IO AFErr) -> a
`infoFromArray` Ptr AFDtype -> AFArray -> IO AFErr
af_get_type)

-- | Retrieves dimensions of 'Array'
--
-- >>> getDims (vector @Double 10 [1..])
-- (10,1,1,1)
--
getDims
  :: AFType a
  => Array a
  -> (Int,Int,Int,Int)
getDims :: forall a. AFType a => Array a -> (Int, Int, Int, Int)
getDims Array a
arr = do
  let (DimT
a,DimT
b,DimT
c,DimT
d) = Array a
arr Array a
-> (Ptr DimT
    -> Ptr DimT -> Ptr DimT -> Ptr DimT -> AFArray -> IO AFErr)
-> (DimT, DimT, DimT, DimT)
forall a b c d arr.
(Storable a, Storable b, Storable c, Storable d) =>
Array arr
-> (Ptr a -> Ptr b -> Ptr c -> Ptr d -> AFArray -> IO AFErr)
-> (a, b, c, d)
`infoFromArray4` Ptr DimT -> Ptr DimT -> Ptr DimT -> Ptr DimT -> AFArray -> IO AFErr
af_get_dims
  (DimT -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral DimT
a, DimT -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral DimT
b, DimT -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral DimT
c, DimT -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral DimT
d)

-- | Retrieves number of dimensions in 'Array'
--
-- >>> getNumDims (matrix @Double (2,2) [[1..],[1..]])
-- 2
--
getNumDims
  :: AFType a
  => Array a
  -> Int
getNumDims :: forall a. AFType a => Array a -> Int
getNumDims = CUInt -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral (CUInt -> Int) -> (Array a -> CUInt) -> Array a -> Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Array a -> (Ptr CUInt -> AFArray -> IO AFErr) -> CUInt
forall a b.
Storable a =>
Array b -> (Ptr a -> AFArray -> IO AFErr) -> a
`infoFromArray` Ptr CUInt -> AFArray -> IO AFErr
af_get_numdims)

-- | Checks if an 'Array' is empty
--
-- >>> isEmpty (matrix @Double (2,2) [[1..],[1..]])
-- False
--
isEmpty
  :: AFType a
  => Array a
  -> Bool
isEmpty :: forall a. AFType a => Array a -> Bool
isEmpty Array a
a = Int -> Bool
forall a. Enum a => Int -> a
toEnum (Int -> Bool) -> (CBool -> Int) -> CBool -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. CBool -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral (CBool -> Bool) -> CBool -> Bool
forall a b. (a -> b) -> a -> b
$ (Array a
a Array a -> (Ptr CBool -> AFArray -> IO AFErr) -> CBool
forall a b.
Storable a =>
Array b -> (Ptr a -> AFArray -> IO AFErr) -> a
`infoFromArray` Ptr CBool -> AFArray -> IO AFErr
af_is_empty)

-- | Checks if an 'Array' is a scalar (contains only one element)
--
-- >>> isScalar (matrix @Double (2,2) [[1..],[1..]])
-- False
-- >>> isScalar (1.0 :: Array Double)
-- True
--
isScalar
  :: AFType a
  => Array a
  -> Bool
isScalar :: forall a. AFType a => Array a -> Bool
isScalar Array a
a = Int -> Bool
forall a. Enum a => Int -> a
toEnum (Int -> Bool) -> (CBool -> Int) -> CBool -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. CBool -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral (CBool -> Bool) -> CBool -> Bool
forall a b. (a -> b) -> a -> b
$ (Array a
a Array a -> (Ptr CBool -> AFArray -> IO AFErr) -> CBool
forall a b.
Storable a =>
Array b -> (Ptr a -> AFArray -> IO AFErr) -> a
`infoFromArray` Ptr CBool -> AFArray -> IO AFErr
af_is_scalar)

-- | Checks if an 'Array' is row-oriented
--
-- >>> isRow (matrix @Double (2,2) [[1..],[1..]])
-- False
--
isRow
  :: AFType a
  => Array a
  -> Bool
isRow :: forall a. AFType a => Array a -> Bool
isRow Array a
a = Int -> Bool
forall a. Enum a => Int -> a
toEnum (Int -> Bool) -> (CBool -> Int) -> CBool -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. CBool -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral (CBool -> Bool) -> CBool -> Bool
forall a b. (a -> b) -> a -> b
$ (Array a
a Array a -> (Ptr CBool -> AFArray -> IO AFErr) -> CBool
forall a b.
Storable a =>
Array b -> (Ptr a -> AFArray -> IO AFErr) -> a
`infoFromArray` Ptr CBool -> AFArray -> IO AFErr
af_is_row)

-- | Checks if an 'Array' is a column-oriented
--
-- >>> isColumn (vector @Double 10 [1..])
-- True
--
isColumn
  :: AFType a
  => Array a
  -> Bool
isColumn :: forall a. AFType a => Array a -> Bool
isColumn Array a
a = Int -> Bool
forall a. Enum a => Int -> a
toEnum (Int -> Bool) -> (CBool -> Int) -> CBool -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. CBool -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral (CBool -> Bool) -> CBool -> Bool
forall a b. (a -> b) -> a -> b
$ (Array a
a Array a -> (Ptr CBool -> AFArray -> IO AFErr) -> CBool
forall a b.
Storable a =>
Array b -> (Ptr a -> AFArray -> IO AFErr) -> a
`infoFromArray` Ptr CBool -> AFArray -> IO AFErr
af_is_column)

-- | Checks if an 'Array' is a vector
--
-- >>> isVector (vector @Double 10 [1..])
-- True
-- >>> isVector (1.0 :: Array Double)
-- False
--
isVector
  :: AFType a
  => Array a
  -> Bool
isVector :: forall a. AFType a => Array a -> Bool
isVector Array a
a = Int -> Bool
forall a. Enum a => Int -> a
toEnum (Int -> Bool) -> (CBool -> Int) -> CBool -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. CBool -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral (CBool -> Bool) -> CBool -> Bool
forall a b. (a -> b) -> a -> b
$ (Array a
a Array a -> (Ptr CBool -> AFArray -> IO AFErr) -> CBool
forall a b.
Storable a =>
Array b -> (Ptr a -> AFArray -> IO AFErr) -> a
`infoFromArray` Ptr CBool -> AFArray -> IO AFErr
af_is_vector)

-- | Checks if an 'Array' is a Complex
--
-- >>> isComplex (scalar (1.0 :+ 1.0) :: Array (Complex Double))
-- True
--
isComplex
  :: AFType a
  => Array a
  -> Bool
isComplex :: forall a. AFType a => Array a -> Bool
isComplex Array a
a = Int -> Bool
forall a. Enum a => Int -> a
toEnum (Int -> Bool) -> (CBool -> Int) -> CBool -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. CBool -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral (CBool -> Bool) -> CBool -> Bool
forall a b. (a -> b) -> a -> b
$ (Array a
a Array a -> (Ptr CBool -> AFArray -> IO AFErr) -> CBool
forall a b.
Storable a =>
Array b -> (Ptr a -> AFArray -> IO AFErr) -> a
`infoFromArray` Ptr CBool -> AFArray -> IO AFErr
af_is_complex)

-- | Checks if an 'Array' is Real
--
-- >>> isReal (scalar 1.0 :: Array Double)
-- True
--
isReal
  :: AFType a
  => Array a
  -> Bool
isReal :: forall a. AFType a => Array a -> Bool
isReal Array a
a = Int -> Bool
forall a. Enum a => Int -> a
toEnum (Int -> Bool) -> (CBool -> Int) -> CBool -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. CBool -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral (CBool -> Bool) -> CBool -> Bool
forall a b. (a -> b) -> a -> b
$ (Array a
a Array a -> (Ptr CBool -> AFArray -> IO AFErr) -> CBool
forall a b.
Storable a =>
Array b -> (Ptr a -> AFArray -> IO AFErr) -> a
`infoFromArray` Ptr CBool -> AFArray -> IO AFErr
af_is_real)

-- | Checks if an 'Array' is 'Double'
--
-- >>> isDouble (scalar 1.0 :: Array Double)
-- True
--
isDouble
  :: AFType a
  => Array a
  -> Bool
isDouble :: forall a. AFType a => Array a -> Bool
isDouble Array a
a = Int -> Bool
forall a. Enum a => Int -> a
toEnum (Int -> Bool) -> (CBool -> Int) -> CBool -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. CBool -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral (CBool -> Bool) -> CBool -> Bool
forall a b. (a -> b) -> a -> b
$ (Array a
a Array a -> (Ptr CBool -> AFArray -> IO AFErr) -> CBool
forall a b.
Storable a =>
Array b -> (Ptr a -> AFArray -> IO AFErr) -> a
`infoFromArray` Ptr CBool -> AFArray -> IO AFErr
af_is_double)

-- | Checks if an 'Array' is 'Float'
--
-- >>> isSingle (scalar 1.0 :: Array Float)
-- True
--
isSingle
  :: AFType a
  => Array a
  -> Bool
isSingle :: forall a. AFType a => Array a -> Bool
isSingle Array a
a = Int -> Bool
forall a. Enum a => Int -> a
toEnum (Int -> Bool) -> (CBool -> Int) -> CBool -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. CBool -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral (CBool -> Bool) -> CBool -> Bool
forall a b. (a -> b) -> a -> b
$ (Array a
a Array a -> (Ptr CBool -> AFArray -> IO AFErr) -> CBool
forall a b.
Storable a =>
Array b -> (Ptr a -> AFArray -> IO AFErr) -> a
`infoFromArray` Ptr CBool -> AFArray -> IO AFErr
af_is_single)

-- | Checks if an 'Array' is 'Double', 'Float', Complex 'Double', or Complex 'Float'
--
-- >>> isRealFloating (scalar 1.0 :: Array Double)
-- True
--
isRealFloating
  :: AFType a
  => Array a
  -> Bool
isRealFloating :: forall a. AFType a => Array a -> Bool
isRealFloating Array a
a = Int -> Bool
forall a. Enum a => Int -> a
toEnum (Int -> Bool) -> (CBool -> Int) -> CBool -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. CBool -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral (CBool -> Bool) -> CBool -> Bool
forall a b. (a -> b) -> a -> b
$ (Array a
a Array a -> (Ptr CBool -> AFArray -> IO AFErr) -> CBool
forall a b.
Storable a =>
Array b -> (Ptr a -> AFArray -> IO AFErr) -> a
`infoFromArray` Ptr CBool -> AFArray -> IO AFErr
af_is_realfloating)

-- | Checks if an 'Array' is 'Double' or 'Float'
--
-- >>> isFloating (scalar 1.0 :: Array Double)
-- True
isFloating
  :: AFType a
  => Array a
  -> Bool
isFloating :: forall a. AFType a => Array a -> Bool
isFloating Array a
a = Int -> Bool
forall a. Enum a => Int -> a
toEnum (Int -> Bool) -> (CBool -> Int) -> CBool -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. CBool -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral (CBool -> Bool) -> CBool -> Bool
forall a b. (a -> b) -> a -> b
$ (Array a
a Array a -> (Ptr CBool -> AFArray -> IO AFErr) -> CBool
forall a b.
Storable a =>
Array b -> (Ptr a -> AFArray -> IO AFErr) -> a
`infoFromArray` Ptr CBool -> AFArray -> IO AFErr
af_is_floating)

-- | Checks if an 'Array' is of type Int16, Int32, or Int64
--
-- >>> isInteger (scalar 1 :: Array Int16)
-- True
isInteger
  :: AFType a
  => Array a
  -> Bool
isInteger :: forall a. AFType a => Array a -> Bool
isInteger Array a
a = Int -> Bool
forall a. Enum a => Int -> a
toEnum (Int -> Bool) -> (CBool -> Int) -> CBool -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. CBool -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral (CBool -> Bool) -> CBool -> Bool
forall a b. (a -> b) -> a -> b
$ (Array a
a Array a -> (Ptr CBool -> AFArray -> IO AFErr) -> CBool
forall a b.
Storable a =>
Array b -> (Ptr a -> AFArray -> IO AFErr) -> a
`infoFromArray` Ptr CBool -> AFArray -> IO AFErr
af_is_integer)

-- | Checks if an 'Array' is of type CBool
--
-- >>> isBool (scalar 1 :: Array CBool)
-- True
isBool
  :: AFType a
  => Array a
  -> Bool
isBool :: forall a. AFType a => Array a -> Bool
isBool Array a
a = Int -> Bool
forall a. Enum a => Int -> a
toEnum (Int -> Bool) -> (CBool -> Int) -> CBool -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. CBool -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral (CBool -> Bool) -> CBool -> Bool
forall a b. (a -> b) -> a -> b
$ (Array a
a Array a -> (Ptr CBool -> AFArray -> IO AFErr) -> CBool
forall a b.
Storable a =>
Array b -> (Ptr a -> AFArray -> IO AFErr) -> a
`infoFromArray` Ptr CBool -> AFArray -> IO AFErr
af_is_bool)

-- | Checks if an 'Array' is sparse
--
-- >>> isSparse (scalar 1 :: Array Double)
-- False
isSparse
  :: AFType a
  => Array a
  -> Bool
isSparse :: forall a. AFType a => Array a -> Bool
isSparse Array a
a = Int -> Bool
forall a. Enum a => Int -> a
toEnum (Int -> Bool) -> (CBool -> Int) -> CBool -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. CBool -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral (CBool -> Bool) -> CBool -> Bool
forall a b. (a -> b) -> a -> b
$ (Array a
a Array a -> (Ptr CBool -> AFArray -> IO AFErr) -> CBool
forall a b.
Storable a =>
Array b -> (Ptr a -> AFArray -> IO AFErr) -> a
`infoFromArray` Ptr CBool -> AFArray -> IO AFErr
af_is_sparse)

-- | Converts an 'Array' to a 'Storable' 'Vector'
--
-- >>> toVector (vector @Double 10 [1..])
-- [1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0,10.0]
toVector :: forall a . AFType a => Array a -> Vector a
toVector :: forall a. AFType a => Array a -> Vector a
toVector arr :: Array a
arr@(Array ForeignPtr ()
fptr) = do
  IO (Vector a) -> Vector a
forall a. IO a -> a
unsafePerformIO (IO (Vector a) -> Vector a)
-> ((AFArray -> IO (Vector a)) -> IO (Vector a))
-> (AFArray -> IO (Vector a))
-> Vector a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. IO (Vector a) -> IO (Vector a)
forall a. IO a -> IO a
mask_ (IO (Vector a) -> IO (Vector a))
-> ((AFArray -> IO (Vector a)) -> IO (Vector a))
-> (AFArray -> IO (Vector a))
-> IO (Vector a)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ForeignPtr () -> (AFArray -> IO (Vector a)) -> IO (Vector a)
forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
withForeignPtr ForeignPtr ()
fptr ((AFArray -> IO (Vector a)) -> Vector a)
-> (AFArray -> IO (Vector a)) -> Vector a
forall a b. (a -> b) -> a -> b
$ \AFArray
arrPtr -> do
    let len :: Int
len = Array a -> Int
forall a. AFType a => Array a -> Int
getElements Array a
arr
        size :: Int
size = Int
len Int -> Int -> Int
forall a. Num a => a -> a -> a
* Proxy a -> Int
forall a. AFType a => Proxy a -> Int
getSizeOf (forall {t}. Proxy t
forall {k} (t :: k). Proxy t
Proxy @a)
    Ptr a
ptr <- Int -> IO (Ptr a)
forall a. Int -> IO (Ptr a)
mallocBytes (Int
len Int -> Int -> Int
forall a. Num a => a -> a -> a
* Int
size)
    AFErr -> IO ()
throwAFError (AFErr -> IO ()) -> IO AFErr -> IO ()
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< AFArray -> AFArray -> IO AFErr
af_get_data_ptr (Ptr a -> AFArray
forall a b. Ptr a -> Ptr b
castPtr Ptr a
ptr) AFArray
arrPtr
    ForeignPtr a
newFptr <- FinalizerPtr a -> Ptr a -> IO (ForeignPtr a)
forall a. FinalizerPtr a -> Ptr a -> IO (ForeignPtr a)
newForeignPtr FinalizerPtr a
forall a. FinalizerPtr a
finalizerFree Ptr a
ptr
    Vector a -> IO (Vector a)
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Vector a -> IO (Vector a)) -> Vector a -> IO (Vector a)
forall a b. (a -> b) -> a -> b
$ ForeignPtr a -> Int -> Vector a
forall a. Storable a => ForeignPtr a -> Int -> Vector a
unsafeFromForeignPtr0 ForeignPtr a
newFptr Int
len

-- | Converts an 'Array' to [a]
--
-- >>> toList (vector @Double 10 [1..])
-- [1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0,10.0]
toList :: forall a . AFType a => Array a -> [a]
toList :: forall a. AFType a => Array a -> [a]
toList = Vector a -> [a]
forall a. Storable a => Vector a -> [a]
V.toList (Vector a -> [a]) -> (Array a -> Vector a) -> Array a -> [a]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Array a -> Vector a
forall a. AFType a => Array a -> Vector a
toVector

-- | Retrieves single scalar value from an 'Array'
--
-- >>> getScalar (scalar @Double 22.0) :: Double
-- 22.0
getScalar :: forall a b . (Storable a, AFType b) => Array b -> a
getScalar :: forall a b. (Storable a, AFType b) => Array b -> a
getScalar (Array ForeignPtr ()
fptr) =
  IO a -> a
forall a. IO a -> a
unsafePerformIO (IO a -> a)
-> ((AFArray -> IO a) -> IO a) -> (AFArray -> IO a) -> a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. IO a -> IO a
forall a. IO a -> IO a
mask_ (IO a -> IO a)
-> ((AFArray -> IO a) -> IO a) -> (AFArray -> IO a) -> IO a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ForeignPtr () -> (AFArray -> IO a) -> IO a
forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
withForeignPtr ForeignPtr ()
fptr ((AFArray -> IO a) -> a) -> (AFArray -> IO a) -> a
forall a b. (a -> b) -> a -> b
$ \AFArray
arrPtr -> do
    (Ptr a -> IO a) -> IO a
forall a b. Storable a => (Ptr a -> IO b) -> IO b
alloca ((Ptr a -> IO a) -> IO a) -> (Ptr a -> IO a) -> IO a
forall a b. (a -> b) -> a -> b
$ \Ptr a
ptr -> do
      AFErr -> IO ()
throwAFError (AFErr -> IO ()) -> IO AFErr -> IO ()
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< AFArray -> AFArray -> IO AFErr
af_get_scalar (Ptr a -> AFArray
forall a b. Ptr a -> Ptr b
castPtr Ptr a
ptr) AFArray
arrPtr
      Ptr a -> IO a
forall a. Storable a => Ptr a -> IO a
peek Ptr a
ptr