{-# LANGUAGE TypeApplications    #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE ViewPatterns        #-}
--------------------------------------------------------------------------------
-- |
-- Module      : ArrayFire.Algorithm
-- Copyright   : David Johnson (c) 2019-2020
-- License     : BSD 3
-- Maintainer  : David Johnson <djohnson.m@gmail.com>
-- Stability   : Experimental
-- Portability : GHC
--
-- Functions for aggregation, manipulation of 'Array'
--
-- @
-- module Main where
--
-- import qualified ArrayFire as A
--
-- main :: IO ()
-- main = print $ A.sum (A.vector @Double 10 [1..]) 0
-- -- ArrayFire Array
-- -- [1 1 1 1]
-- --   55.0000
-- @
--------------------------------------------------------------------------------
module ArrayFire.Algorithm where

import ArrayFire.FFI
import ArrayFire.Internal.Algorithm
import ArrayFire.Internal.Types

-- | Sum all of the elements in 'Array' along the specified dimension
--
-- >>> A.sum (A.vector @Double 10 [1..]) 0
-- ArrayFire Array
-- [1 1 1 1]
--    55.0000
--
-- >>> A.sum (A.matrix @Double (10,10) $ replicate 10 [1..]) 1
-- ArrayFire Array
-- [10 1 1 1]
--    10.0000
--    20.0000
--    30.0000
--    40.0000
--    50.0000
--    60.0000
--    70.0000
--    80.0000
--    90.0000
--   100.0000
--
sum
  :: AFType a
  => Array a
  -- ^ Array to sum
  -> Int
  -- ^ 0-based Dimension along which to perform sum
  -> Array a
  -- ^ Will return the sum of all values in the input array along the specified dimension
sum :: forall a. AFType a => Array a -> Int -> Array a
sum Array a
x (Int -> CInt
forall a b. (Integral a, Num b) => a -> b
fromIntegral -> CInt
n) = (Array a
x Array a -> (Ptr AFArray -> AFArray -> IO AFErr) -> Array a
forall a.
Array a -> (Ptr AFArray -> AFArray -> IO AFErr) -> Array a
`op1` (\Ptr AFArray
p AFArray
a -> Ptr AFArray -> AFArray -> CInt -> IO AFErr
af_sum Ptr AFArray
p AFArray
a CInt
n))

-- | Sum all of the elements in 'Array' along the specified dimension, using a default value for NaN
--
-- >>> A.sumNaN (A.vector @Double 10 [1..]) 0 0.0
-- ArrayFire Array
-- [1 1 1 1]
--   55.0000
sumNaN
  :: (Fractional a, AFType a)
  => Array a
  -- ^ Array to sum
  -> Int
  -- ^ Dimension along which to perform sum
  -> Double
  -- ^ Default value to use in the case of NaN
  -> Array a
  -- ^ Will return the sum of all values in the input array along the specified dimension, substituted with the default value
sumNaN :: forall a.
(Fractional a, AFType a) =>
Array a -> Int -> Double -> Array a
sumNaN Array a
n (Int -> CInt
forall a b. (Integral a, Num b) => a -> b
fromIntegral -> CInt
i) Double
d = (Array a
n Array a -> (Ptr AFArray -> AFArray -> IO AFErr) -> Array a
forall a.
Array a -> (Ptr AFArray -> AFArray -> IO AFErr) -> Array a
`op1` (\Ptr AFArray
p AFArray
a -> Ptr AFArray -> AFArray -> CInt -> Double -> IO AFErr
af_sum_nan Ptr AFArray
p AFArray
a CInt
i Double
d))

-- | Product all of the elements in 'Array' along the specified dimension
--
-- >>> A.product (A.vector @Double 10 [1..]) 0
-- ArrayFire Array
-- [1 1 1 1]
-- 3628800.0000
product
  :: AFType a
  => Array a
  -- ^ Array to product
  -> Int
  -- ^ Dimension along which to perform product
  -> Array a
  -- ^ Will return the product of all values in the input array along the specified dimension
product :: forall a. AFType a => Array a -> Int -> Array a
product Array a
x (Int -> CInt
forall a b. (Integral a, Num b) => a -> b
fromIntegral -> CInt
n) = (Array a
x Array a -> (Ptr AFArray -> AFArray -> IO AFErr) -> Array a
forall a.
Array a -> (Ptr AFArray -> AFArray -> IO AFErr) -> Array a
`op1` (\Ptr AFArray
p AFArray
a -> Ptr AFArray -> AFArray -> CInt -> IO AFErr
af_product Ptr AFArray
p AFArray
a CInt
n))

-- | Product all of the elements in 'Array' along the specified dimension, using a default value for NaN
--
-- >>> A.productNaN (A.vector @Double 10 [1..]) 0 0.0
-- ArrayFire Array
-- [1 1 1 1]
-- 3628800.0000
productNaN
  :: (AFType a, Fractional a)
  => Array a
  -- ^ Array to product
  -> Int
  -- ^ Dimension along which to perform product
  -> Double
  -- ^ Default value to use in the case of NaN
  -> Array a
  -- ^ Will return the product of all values in the input array along the specified dimension, substituted with the default value
productNaN :: forall a.
(AFType a, Fractional a) =>
Array a -> Int -> Double -> Array a
productNaN Array a
n (Int -> CInt
forall a b. (Integral a, Num b) => a -> b
fromIntegral -> CInt
i) Double
d = Array a
n Array a -> (Ptr AFArray -> AFArray -> IO AFErr) -> Array a
forall a.
Array a -> (Ptr AFArray -> AFArray -> IO AFErr) -> Array a
`op1` (\Ptr AFArray
p AFArray
a -> Ptr AFArray -> AFArray -> CInt -> Double -> IO AFErr
af_product_nan Ptr AFArray
p AFArray
a CInt
i Double
d)

-- | Take the minimum of an 'Array' along a specific dimension
--
-- >>> A.min (A.vector @Double 10 [1..]) 0
-- ArrayFire Array
-- [1 1 1 1]
--    1.0000
min
  :: AFType a
  => Array a
  -- ^ Array input
  -> Int
  -- ^ Dimension along which to retrieve the min element
  -> Array a
  -- ^ Will contain the minimum of all values in the input array along dim
min :: forall a. AFType a => Array a -> Int -> Array a
min Array a
x (Int -> CInt
forall a b. (Integral a, Num b) => a -> b
fromIntegral -> CInt
n) = Array a
x Array a -> (Ptr AFArray -> AFArray -> IO AFErr) -> Array a
forall a.
Array a -> (Ptr AFArray -> AFArray -> IO AFErr) -> Array a
`op1` (\Ptr AFArray
p AFArray
a -> Ptr AFArray -> AFArray -> CInt -> IO AFErr
af_min Ptr AFArray
p AFArray
a CInt
n)

-- | Take the maximum of an 'Array' along a specific dimension
--
-- >>> A.max (A.vector @Double 10 [1..]) 0
-- ArrayFire Array
-- [1 1 1 1]
--   10.0000
max
  :: AFType a
  => Array a
  -- ^ Array input
  -> Int
  -- ^ Dimension along which to retrieve the max element
  -> Array a
  -- ^ Will contain the maximum of all values in the input array along dim
max :: forall a. AFType a => Array a -> Int -> Array a
max Array a
x (Int -> CInt
forall a b. (Integral a, Num b) => a -> b
fromIntegral -> CInt
n) = Array a
x Array a -> (Ptr AFArray -> AFArray -> IO AFErr) -> Array a
forall a.
Array a -> (Ptr AFArray -> AFArray -> IO AFErr) -> Array a
`op1` (\Ptr AFArray
p AFArray
a -> Ptr AFArray -> AFArray -> CInt -> IO AFErr
af_max Ptr AFArray
p AFArray
a CInt
n)

-- | Find if all elements in an 'Array' are 'True' along a dimension
--
-- >>> A.allTrue (A.vector @CBool 10 (repeat 0)) 0
-- ArrayFire Array
-- [1 1 1 1]
--         0
allTrue
  :: forall a. AFType a
  => Array a
  -- ^ Array input
  -> Int
  -- ^ Dimension along which to see if all elements are True
  -> Array a
  -- ^ Will contain the maximum of all values in the input array along dim
allTrue :: forall a. AFType a => Array a -> Int -> Array a
allTrue Array a
x (Int -> CInt
forall a b. (Integral a, Num b) => a -> b
fromIntegral -> CInt
n) =
  Array a
x Array a -> (Ptr AFArray -> AFArray -> IO AFErr) -> Array a
forall a.
Array a -> (Ptr AFArray -> AFArray -> IO AFErr) -> Array a
`op1` (\Ptr AFArray
p AFArray
a -> Ptr AFArray -> AFArray -> CInt -> IO AFErr
af_all_true Ptr AFArray
p AFArray
a CInt
n)

-- | Find if any elements in an 'Array' are 'True' along a dimension
--
-- >>> A.anyTrue (A.vector @CBool 10 (repeat 0)) 0
-- ArrayFire Array
-- [1 1 1 1]
--         0
anyTrue
  :: forall a . AFType a
  => Array a
  -- ^ Array input
  -> Int
  -- ^ Dimension along which to see if all elements are True
  -> Array a
  -- ^ Returns if all elements are true
anyTrue :: forall a. AFType a => Array a -> Int -> Array a
anyTrue Array a
x (Int -> CInt
forall a b. (Integral a, Num b) => a -> b
fromIntegral -> CInt
n) =
  (Array a
x Array a -> (Ptr AFArray -> AFArray -> IO AFErr) -> Array a
forall a.
Array a -> (Ptr AFArray -> AFArray -> IO AFErr) -> Array a
`op1` (\Ptr AFArray
p AFArray
a -> Ptr AFArray -> AFArray -> CInt -> IO AFErr
af_any_true Ptr AFArray
p AFArray
a CInt
n))

-- | Count elements in an 'Array' along a dimension
--
-- >>> A.count (A.vector @Double 10 [1..]) 0
-- ArrayFire Array
-- [1 1 1 1]
--        10
count
  :: forall a . AFType a
  => Array a
  -- ^ Array input
  -> Int
  -- ^ Dimension along which to count
  -> Array Int
  -- ^ Count of all elements along dimension
count :: forall a. AFType a => Array a -> Int -> Array Int
count Array a
x (Int -> CInt
forall a b. (Integral a, Num b) => a -> b
fromIntegral -> CInt
n) = Array a
x Array a -> (Ptr AFArray -> AFArray -> IO AFErr) -> Array Int
forall a b.
Array a -> (Ptr AFArray -> AFArray -> IO AFErr) -> Array b
`op1d` (\Ptr AFArray
p AFArray
a -> Ptr AFArray -> AFArray -> CInt -> IO AFErr
af_count Ptr AFArray
p AFArray
a CInt
n)

-- | Sum all elements in an 'Array' along all dimensions
--
-- >>> A.sumAll (A.vector @Double 10 [1..])
-- (55.0,0.0)
sumAll
  :: AFType a
  => Array a
  -- ^ Input array
  -> (Double, Double)
  -- ^ imaginary and real part
sumAll :: forall a. AFType a => Array a -> (Double, Double)
sumAll = (Array a
-> (Ptr Double -> Ptr Double -> AFArray -> IO AFErr)
-> (Double, Double)
forall a b arr.
(Storable a, Storable b) =>
Array arr -> (Ptr a -> Ptr b -> AFArray -> IO AFErr) -> (a, b)
`infoFromArray2` Ptr Double -> Ptr Double -> AFArray -> IO AFErr
af_sum_all)

-- | Sum all elements in an 'Array' along all dimensions, using a default value for NaN
--
-- >>> A.sumNaNAll (A.vector @Double 10 [1..]) 0.0
-- (55.0,0.0)
sumNaNAll
  :: (AFType a, Fractional a)
  => Array a
  -- ^ Input array
  -> Double
  -- ^ NaN substitute
  -> (Double, Double)
  -- ^ imaginary and real part
sumNaNAll :: forall a.
(AFType a, Fractional a) =>
Array a -> Double -> (Double, Double)
sumNaNAll Array a
a Double
d = Array a
-> (Ptr Double -> Ptr Double -> AFArray -> IO AFErr)
-> (Double, Double)
forall a b arr.
(Storable a, Storable b) =>
Array arr -> (Ptr a -> Ptr b -> AFArray -> IO AFErr) -> (a, b)
infoFromArray2 Array a
a (\Ptr Double
p Ptr Double
g AFArray
x -> Ptr Double -> Ptr Double -> AFArray -> Double -> IO AFErr
af_sum_nan_all Ptr Double
p Ptr Double
g AFArray
x Double
d)

-- | Product all elements in an 'Array' along all dimensions, using a default value for NaN
--
-- >>> A.productAll (A.vector @Double 10 [1..])
-- (3628800.0,0.0)
productAll
  :: AFType a
  => Array a
  -- ^ Input array
  -> (Double, Double)
  -- ^ imaginary and real part
productAll :: forall a. AFType a => Array a -> (Double, Double)
productAll = (Array a
-> (Ptr Double -> Ptr Double -> AFArray -> IO AFErr)
-> (Double, Double)
forall a b arr.
(Storable a, Storable b) =>
Array arr -> (Ptr a -> Ptr b -> AFArray -> IO AFErr) -> (a, b)
`infoFromArray2` Ptr Double -> Ptr Double -> AFArray -> IO AFErr
af_product_all)

-- | Product all elements in an 'Array' along all dimensions, using a default value for NaN
--
-- >>> A.productNaNAll (A.vector @Double 10 [1..]) 1.0
-- (3628800.0,0.0)
productNaNAll
  :: (AFType a, Fractional a)
  => Array a
  -- ^ Input array
  -> Double
  -- ^ NaN substitute
  -> (Double, Double)
  -- ^ imaginary and real part
productNaNAll :: forall a.
(AFType a, Fractional a) =>
Array a -> Double -> (Double, Double)
productNaNAll Array a
a Double
d = Array a
-> (Ptr Double -> Ptr Double -> AFArray -> IO AFErr)
-> (Double, Double)
forall a b arr.
(Storable a, Storable b) =>
Array arr -> (Ptr a -> Ptr b -> AFArray -> IO AFErr) -> (a, b)
infoFromArray2 Array a
a (\Ptr Double
p Ptr Double
x AFArray
y -> Ptr Double -> Ptr Double -> AFArray -> Double -> IO AFErr
af_product_nan_all Ptr Double
p Ptr Double
x AFArray
y Double
d)

-- | Take the minimum across all elements along all dimensions in 'Array'
--
-- >>> A.minAll (A.vector @Double 10 [1..])
-- (1.0,0.0)
minAll
  :: AFType a
  => Array a
  -- ^ Input array
  -> (Double, Double)
  -- ^ imaginary and real part
minAll :: forall a. AFType a => Array a -> (Double, Double)
minAll = (Array a
-> (Ptr Double -> Ptr Double -> AFArray -> IO AFErr)
-> (Double, Double)
forall a b arr.
(Storable a, Storable b) =>
Array arr -> (Ptr a -> Ptr b -> AFArray -> IO AFErr) -> (a, b)
`infoFromArray2` Ptr Double -> Ptr Double -> AFArray -> IO AFErr
af_min_all)

-- | Take the maximum across all elements along all dimensions in 'Array'
--
-- >>> A.maxAll (A.vector @Double 10 [1..])
-- (10.0,0.0)
maxAll
  :: AFType a
  => Array a
  -- ^ Input array
  -> (Double, Double)
  -- ^ imaginary and real part
maxAll :: forall a. AFType a => Array a -> (Double, Double)
maxAll = (Array a
-> (Ptr Double -> Ptr Double -> AFArray -> IO AFErr)
-> (Double, Double)
forall a b arr.
(Storable a, Storable b) =>
Array arr -> (Ptr a -> Ptr b -> AFArray -> IO AFErr) -> (a, b)
`infoFromArray2` Ptr Double -> Ptr Double -> AFArray -> IO AFErr
af_max_all)

-- | Decide if all elements along all dimensions in 'Array' are True
--
-- >>> A.allTrueAll (A.vector @CBool 10 (repeat 1))
-- (1.0, 0.0)
allTrueAll
  :: AFType a
  => Array a
  -- ^ Input array
  -> (Double, Double)
  -- ^ imaginary and real part
allTrueAll :: forall a. AFType a => Array a -> (Double, Double)
allTrueAll = (Array a
-> (Ptr Double -> Ptr Double -> AFArray -> IO AFErr)
-> (Double, Double)
forall a b arr.
(Storable a, Storable b) =>
Array arr -> (Ptr a -> Ptr b -> AFArray -> IO AFErr) -> (a, b)
`infoFromArray2` Ptr Double -> Ptr Double -> AFArray -> IO AFErr
af_all_true_all)

-- | Decide if any elements along all dimensions in 'Array' are True
--
-- >>> A.anyTrueAll $ A.vector @CBool 10 (repeat 0)
-- (0.0,0.0)
anyTrueAll
  :: AFType a
  => Array a
  -- ^ Input array
  -> (Double, Double)
  -- ^ imaginary and real part
anyTrueAll :: forall a. AFType a => Array a -> (Double, Double)
anyTrueAll = (Array a
-> (Ptr Double -> Ptr Double -> AFArray -> IO AFErr)
-> (Double, Double)
forall a b arr.
(Storable a, Storable b) =>
Array arr -> (Ptr a -> Ptr b -> AFArray -> IO AFErr) -> (a, b)
`infoFromArray2` Ptr Double -> Ptr Double -> AFArray -> IO AFErr
af_any_true_all)

-- | Count all elements along all dimensions in 'Array'
--
-- >>> A.countAll (A.matrix @Double (100,100) (replicate 100 [1..]))
-- (10000.0,0.0)
countAll
  :: AFType a
  => Array a
  -- ^ Input array
  -> (Double, Double)
  -- ^ imaginary and real part
countAll :: forall a. AFType a => Array a -> (Double, Double)
countAll = (Array a
-> (Ptr Double -> Ptr Double -> AFArray -> IO AFErr)
-> (Double, Double)
forall a b arr.
(Storable a, Storable b) =>
Array arr -> (Ptr a -> Ptr b -> AFArray -> IO AFErr) -> (a, b)
`infoFromArray2` Ptr Double -> Ptr Double -> AFArray -> IO AFErr
af_count_all)

-- | Find the minimum element along a specified dimension in 'Array'
--
-- >>> A.imin (A.vector @Double 10 [1..]) 0
-- (ArrayFire Array
-- [1 1 1 1]
--    1.0000
-- ,ArrayFire Array
-- [1 1 1 1]
--         0
-- )
imin
  :: AFType a
  => Array a
  -- ^ Input array
  -> Int
  -- ^ The dimension along which the minimum value is extracted
  -> (Array a, Array a)
  -- ^ will contain the minimum of all values along dim, will also contain the location of minimum of all values in in along dim
imin :: forall a. AFType a => Array a -> Int -> (Array a, Array a)
imin Array a
a (Int -> CInt
forall a b. (Integral a, Num b) => a -> b
fromIntegral -> CInt
n) = Array a
-> (Ptr AFArray -> Ptr AFArray -> AFArray -> IO AFErr)
-> (Array a, Array a)
forall a.
Array a
-> (Ptr AFArray -> Ptr AFArray -> AFArray -> IO AFErr)
-> (Array a, Array a)
op2p Array a
a (\Ptr AFArray
x Ptr AFArray
y AFArray
z -> Ptr AFArray -> Ptr AFArray -> AFArray -> CInt -> IO AFErr
af_imin Ptr AFArray
x Ptr AFArray
y AFArray
z CInt
n)

-- | Find the maximum element along a specified dimension in 'Array'
--
-- >>> A.imax (A.vector @Double 10 [1..]) 0
-- (ArrayFire Array
-- [1 1 1 1]
--   10.0000
-- ,ArrayFire Array
-- [1 1 1 1]
--         9
-- )
imax
  :: AFType a
  => Array a
  -- ^ Input array
  -> Int
  -- ^ The dimension along which the minimum value is extracted
  -> (Array a, Array a)
  -- ^ will contain the maximum of all values in in along dim, will also contain the location of maximum of all values in in along dim
imax :: forall a. AFType a => Array a -> Int -> (Array a, Array a)
imax Array a
a (Int -> CInt
forall a b. (Integral a, Num b) => a -> b
fromIntegral -> CInt
n) = Array a
-> (Ptr AFArray -> Ptr AFArray -> AFArray -> IO AFErr)
-> (Array a, Array a)
forall a.
Array a
-> (Ptr AFArray -> Ptr AFArray -> AFArray -> IO AFErr)
-> (Array a, Array a)
op2p Array a
a (\Ptr AFArray
x Ptr AFArray
y AFArray
z -> Ptr AFArray -> Ptr AFArray -> AFArray -> CInt -> IO AFErr
af_imax Ptr AFArray
x Ptr AFArray
y AFArray
z CInt
n)

-- | Find the minimum element along all dimensions in 'Array'
--
-- >>> A.iminAll (A.vector @Double 10 [1..])
-- (1.0,0.0,0)
iminAll
  :: AFType a
  => Array a
  -- ^ Input array
  -> (Double, Double, Int)
  -- ^ will contain the real part of minimum value of all elements in input in, also will contain the imaginary part of minimum value of all elements in input in, will contain the location of minimum of all values in
iminAll :: forall a. AFType a => Array a -> (Double, Double, Int)
iminAll Array a
a = do
  let (Double
x,Double
y,CUInt -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral -> Int
z) = Array a
a Array a
-> (Ptr Double -> Ptr Double -> Ptr CUInt -> AFArray -> IO AFErr)
-> (Double, Double, CUInt)
forall a b c arr.
(Storable a, Storable b, Storable c) =>
Array arr
-> (Ptr a -> Ptr b -> Ptr c -> AFArray -> IO AFErr) -> (a, b, c)
`infoFromArray3` Ptr Double -> Ptr Double -> Ptr CUInt -> AFArray -> IO AFErr
af_imin_all
  (Double
x,Double
y,Int
z)

-- | Find the maximum element along all dimensions in 'Array'
--
-- >>> A.imaxAll (A.vector @Double 10 [1..])
-- (10.0,0.0,9)
imaxAll
  :: AFType a
  => Array a
  -- ^ Input array
  -> (Double, Double, Int)
  -- ^ will contain the real part of maximum value of all elements in input in, also will contain the imaginary part of maximum value of all elements in input in, will contain the location of maximum of all values in
imaxAll :: forall a. AFType a => Array a -> (Double, Double, Int)
imaxAll Array a
a = do
  let (Double
x,Double
y,CUInt -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral -> Int
z) = Array a
a Array a
-> (Ptr Double -> Ptr Double -> Ptr CUInt -> AFArray -> IO AFErr)
-> (Double, Double, CUInt)
forall a b c arr.
(Storable a, Storable b, Storable c) =>
Array arr
-> (Ptr a -> Ptr b -> Ptr c -> AFArray -> IO AFErr) -> (a, b, c)
`infoFromArray3` Ptr Double -> Ptr Double -> Ptr CUInt -> AFArray -> IO AFErr
af_imax_all
  (Double
x,Double
y,Int
z)

-- | Calculate sum of 'Array' across specified dimension
--
-- >>> A.accum (A.vector @Double 10 [1..]) 0
-- ArrayFire Array
-- [10 1 1 1]
--     1.0000
--     3.0000
--     6.0000
--    10.0000
--    15.0000
--    21.0000
--    28.0000
--    36.0000
--    45.0000
--    55.0000
accum
  :: AFType a
  => Array a
  -- ^ Input array
  -> Int
  -- ^ Dimension along which to calculate the sum
  -> Array a
  -- ^ Contains inclusive sum
accum :: forall a. AFType a => Array a -> Int -> Array a
accum Array a
a (Int -> CInt
forall a b. (Integral a, Num b) => a -> b
fromIntegral -> CInt
n) = Array a
a Array a -> (Ptr AFArray -> AFArray -> IO AFErr) -> Array a
forall a.
Array a -> (Ptr AFArray -> AFArray -> IO AFErr) -> Array a
`op1` (\Ptr AFArray
x AFArray
y -> Ptr AFArray -> AFArray -> CInt -> IO AFErr
af_accum Ptr AFArray
x AFArray
y CInt
n)

-- | Scan elements of an 'Array' across a dimension, using a 'BinaryOp', specifying inclusivity.
--
-- >>> A.scan (A.vector @Double 10 [1..]) 0 Add True
-- ArrayFire Array
-- [10 1 1 1]
--     1.0000
--     3.0000
--     6.0000
--    10.0000
--    15.0000
--    21.0000
--    28.0000
--    36.0000
--    45.0000
--    55.0000
scan
  :: AFType a
  => Array a
  -- ^ The input array
  -> Int
  -- ^ The dimension along which the scan is performed
  -> BinaryOp
  -- ^ Binary operation to be used
  -> Bool
  -- ^ Should the scan be inclusive or not
  -> Array a
  -- ^ The scan of the input
scan :: forall a. AFType a => Array a -> Int -> BinaryOp -> Bool -> Array a
scan Array a
a (Int -> CInt
forall a b. (Integral a, Num b) => a -> b
fromIntegral -> CInt
d) BinaryOp
op (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
inclusive) =
  Array a
a Array a -> (Ptr AFArray -> AFArray -> IO AFErr) -> Array a
forall a.
Array a -> (Ptr AFArray -> AFArray -> IO AFErr) -> Array a
`op1` (\Ptr AFArray
x AFArray
y -> Ptr AFArray -> AFArray -> CInt -> AFBinaryOp -> CBool -> IO AFErr
af_scan Ptr AFArray
x AFArray
y CInt
d (BinaryOp -> AFBinaryOp
toBinaryOp BinaryOp
op) CBool
inclusive)

-- | Scan elements of an 'Array' across a dimension, by key, using a 'BinaryOp', specifying inclusivity.
--
-- >>> A.scanByKey (A.vector @Int 7 [2..]) (A.vector @Int 10 [1..]) 1 Add True
-- ArrayFire Array
-- [10 1 1 1]
--          1
--          2
--          3
--          4
--          5
--          6
--          7
--          8
--          9
--         10
scanByKey
  :: (AFType a, AFType k)
  => Array k
  -- ^ The key array
  -> Array a
  -- ^ The input array
  -> Int
  -- ^ Dimension along which scan is performed
  -> BinaryOp
  -- ^ Type of binary operation used
  -> Bool
  -- ^ Is the scan incluside or not
  -> Array a
scanByKey :: forall a k.
(AFType a, AFType k) =>
Array k -> Array a -> Int -> BinaryOp -> Bool -> Array a
scanByKey Array k
a Array a
b (Int -> CInt
forall a b. (Integral a, Num b) => a -> b
fromIntegral -> CInt
d) BinaryOp
op (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
inclusive) =
  Array k
-> Array a
-> (Ptr AFArray -> AFArray -> AFArray -> IO AFErr)
-> Array a
forall b a.
Array b
-> Array a
-> (Ptr AFArray -> AFArray -> AFArray -> IO AFErr)
-> Array a
op2 Array k
a Array a
b (\Ptr AFArray
x AFArray
y AFArray
z -> Ptr AFArray
-> AFArray -> AFArray -> CInt -> AFBinaryOp -> CBool -> IO AFErr
af_scan_by_key Ptr AFArray
x AFArray
y AFArray
z CInt
d (BinaryOp -> AFBinaryOp
toBinaryOp BinaryOp
op) CBool
inclusive)

-- | Find indices where input Array is non zero
--
-- >>> A.where' (A.vector @Double 10 (repeat 0))
-- ArrayFire Array
-- [0 1 1 1]
-- <empty>
where'
  :: AFType a
  => Array a
  -- ^ Is the input array.
  -> Array a
  -- ^ will contain indices where input array is non-zero
where' :: forall a. AFType a => Array a -> Array a
where' = (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_where)

-- | First order numerical difference along specified dimension.
--
-- >>> A.diff1 (A.vector @Double 4 [10,35,65,95]) 0
-- ArrayFire Array
-- [3 1 1 1]
--    25.0000
--    30.0000
--    30.0000
diff1
  :: AFType a
  => Array a
  -- ^ Input array
  -> Int
  -- ^ Dimension along which numerical difference is performed
  -> Array a
  -- ^ Will contain first order numerical difference
diff1 :: forall a. AFType a => Array a -> Int -> Array a
diff1 Array a
a (Int -> CInt
forall a b. (Integral a, Num b) => a -> b
fromIntegral -> CInt
n) = Array a
a Array a -> (Ptr AFArray -> AFArray -> IO AFErr) -> Array a
forall a.
Array a -> (Ptr AFArray -> AFArray -> IO AFErr) -> Array a
`op1` (\Ptr AFArray
p AFArray
x -> Ptr AFArray -> AFArray -> CInt -> IO AFErr
af_diff1 Ptr AFArray
p AFArray
x CInt
n)

-- | Second order numerical difference along specified dimension.
--
-- >>> A.diff2 (A.vector @Double 5 [1.0,20,55,89,44]) 0
-- ArrayFire Array
-- [3 1 1 1]
--    16.0000
--    -1.0000
--   -79.0000
diff2
  :: AFType a
  => Array a
  -- ^ Input array
  -> Int
  -- ^ Dimension along which numerical difference is performed
  -> Array a
  -- ^ Will contain second order numerical difference
diff2 :: forall a. AFType a => Array a -> Int -> Array a
diff2 Array a
a (Int -> CInt
forall a b. (Integral a, Num b) => a -> b
fromIntegral -> CInt
n) = Array a
a Array a -> (Ptr AFArray -> AFArray -> IO AFErr) -> Array a
forall a.
Array a -> (Ptr AFArray -> AFArray -> IO AFErr) -> Array a
`op1` (\Ptr AFArray
p AFArray
x -> Ptr AFArray -> AFArray -> CInt -> IO AFErr
af_diff2 Ptr AFArray
p AFArray
x CInt
n)

-- | Sort an Array along a specified dimension, specifying ordering of results (ascending / descending)
--
-- >>> A.sort (A.vector @Double 4 [ 2,4,3,1 ]) 0 True
-- ArrayFire Array
-- [4 1 1 1]
--     1.0000
--     2.0000
--     3.0000
--     4.0000
--
-- >>> A.sort (A.vector @Double 4 [ 2,4,3,1 ]) 0 False
-- ArrayFire Array
-- [4 1 1 1]
--     4.0000
--     3.0000
--     2.0000
--     1.0000
sort
  :: AFType a
  => Array a
  -- ^ Input array
  -> Int
  -- ^ Dimension along `sort` is performed
  -> Bool
  -- ^ Return results in ascending order
  -> Array a
  -- ^ Will contain sorted input
sort :: forall a. AFType a => Array a -> Int -> Bool -> Array a
sort Array a
a (Int -> CUInt
forall a b. (Integral a, Num b) => a -> b
fromIntegral -> CUInt
n) (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) =
  Array a
a Array a -> (Ptr AFArray -> AFArray -> IO AFErr) -> Array a
forall a.
Array a -> (Ptr AFArray -> AFArray -> IO AFErr) -> Array a
`op1` (\Ptr AFArray
p AFArray
x -> Ptr AFArray -> AFArray -> CUInt -> CBool -> IO AFErr
af_sort Ptr AFArray
p AFArray
x CUInt
n CBool
b)

-- | Sort an 'Array' along a specified dimension, specifying ordering of results (ascending / descending), returns indices of sorted results
--
-- >>> A.sortIndex (A.vector @Double 4 [3,2,1,4]) 0 True
-- (ArrayFire Array
-- [4 1 1 1]
--     1.0000
--     2.0000
--     3.0000
--     4.0000
-- ,ArrayFire Array
-- [4 1 1 1]
--          2
--          1
--          0
--          3
-- )
sortIndex
  :: AFType a
  => Array a
  -- ^ Input array
  -> Int
  -- ^ Dimension along `sortIndex` is performed
  -> Bool
  -- ^ Return results in ascending order
  -> (Array a, Array a)
  -- ^ Contains the sorted, contains indices for original input
sortIndex :: forall a. AFType a => Array a -> Int -> Bool -> (Array a, Array a)
sortIndex Array a
a (Int -> CUInt
forall a b. (Integral a, Num b) => a -> b
fromIntegral -> CUInt
n) (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) =
  Array a
a Array a
-> (Ptr AFArray -> Ptr AFArray -> AFArray -> IO AFErr)
-> (Array a, Array a)
forall a.
Array a
-> (Ptr AFArray -> Ptr AFArray -> AFArray -> IO AFErr)
-> (Array a, Array a)
`op2p` (\Ptr AFArray
p1 Ptr AFArray
p2 AFArray
p3 -> Ptr AFArray -> Ptr AFArray -> AFArray -> CUInt -> CBool -> IO AFErr
af_sort_index Ptr AFArray
p1 Ptr AFArray
p2 AFArray
p3 CUInt
n CBool
b)

-- | Sort an 'Array' along a specified dimension by keys, specifying ordering of results (ascending / descending)
--
-- >>> A.sortByKey (A.vector @Double 4 [2,1,4,3]) (A.vector @Double 4 [10,9,8,7]) 0 True
-- (ArrayFire Array
-- [4 1 1 1]
--     1.0000
--     2.0000
--     3.0000
--     4.0000
-- ,ArrayFire Array
-- [4 1 1 1]
--     9.0000
--    10.0000
--     7.0000
--     8.0000
-- )
sortByKey
  :: AFType a
  => Array a
  -- ^ Keys input array
  -> Array a
  -- ^ Values input array
  -> Int
  -- ^ Dimension along which to perform the operation
  -> Bool
  -- ^ Return results in ascending order
  -> (Array a, Array a)
sortByKey :: forall a.
AFType a =>
Array a -> Array a -> Int -> Bool -> (Array a, Array a)
sortByKey Array a
a1 Array a
a2 (Int -> CUInt
forall a b. (Integral a, Num b) => a -> b
fromIntegral -> CUInt
n) (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) =
  Array a
-> Array a
-> (Ptr AFArray -> Ptr AFArray -> AFArray -> AFArray -> IO AFErr)
-> (Array a, Array a)
forall a.
Array a
-> Array a
-> (Ptr AFArray -> Ptr AFArray -> AFArray -> AFArray -> IO AFErr)
-> (Array a, Array a)
op2p2 Array a
a1 Array a
a2 (\Ptr AFArray
w Ptr AFArray
x AFArray
y AFArray
z -> Ptr AFArray
-> Ptr AFArray -> AFArray -> AFArray -> CUInt -> CBool -> IO AFErr
af_sort_by_key Ptr AFArray
w Ptr AFArray
x AFArray
y AFArray
z CUInt
n CBool
b)

-- | Finds the unique values in an 'Array', specifying if sorting should occur.
--
-- >>> A.setUnique (A.vector @Double 2 [1.0,1.0]) True
-- ArrayFire Array
-- [1 1 1 1]
--    1.0000
setUnique
  :: AFType a
  => Array a
  -- ^ input array
  -> Bool
  -- ^ if true, skips the sorting steps internally
  -> Array a
  -- ^ Will contain the unique values from in
setUnique :: forall a. AFType a => Array a -> Bool -> Array a
setUnique Array a
a (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) =
  Array a -> (Ptr AFArray -> AFArray -> IO AFErr) -> Array a
forall a.
Array a -> (Ptr AFArray -> AFArray -> IO AFErr) -> Array a
op1 Array a
a (\Ptr AFArray
x AFArray
y -> Ptr AFArray -> AFArray -> CBool -> IO AFErr
af_set_unique Ptr AFArray
x AFArray
y CBool
b)

-- | Takes the union of two 'Array's, specifying if `setUnique` should be called first.
--
-- >>> A.setUnion (A.vector @Double 3 [3,4,5]) (A.vector @Double 3 [1,2,3]) True
-- ArrayFire Array
-- [5 1 1 1]
--     1.0000
--     2.0000
--     3.0000
--     4.0000
--     5.0000
setUnion
  :: AFType a
  => Array a
  -- ^ First input array
  -> Array a
  -- ^ Second input array
  -> Bool
  -- ^ If true, skips calling unique internally
  -> Array a
setUnion :: forall a. AFType a => Array a -> Array a -> Bool -> Array a
setUnion Array a
a1 Array a
a2 (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) =
  Array a
-> Array a
-> (Ptr AFArray -> AFArray -> AFArray -> IO AFErr)
-> Array a
forall b a.
Array b
-> Array a
-> (Ptr AFArray -> AFArray -> AFArray -> IO AFErr)
-> Array a
op2 Array a
a1 Array a
a2 (\Ptr AFArray
x AFArray
y AFArray
z -> Ptr AFArray -> AFArray -> AFArray -> CBool -> IO AFErr
af_set_union Ptr AFArray
x AFArray
y AFArray
z CBool
b)

-- | Takes the intersection of two 'Array's, specifying if `setUnique` should be called first.
--
-- >>> A.setIntersect (A.vector @Double 3 [3,4,5]) (A.vector @Double 3 [1,2,3]) True
-- ArrayFire Array
-- [1 1 1 1]
--     3.0000
setIntersect
  :: AFType a
  => Array a
  -- ^ First input array
  -> Array a
  -- ^ Second input array
  -> Bool
  -- ^ If true, skips calling unique internally
  -> Array a
  -- ^ Intersection of first and second array
setIntersect :: forall a. AFType a => Array a -> Array a -> Bool -> Array a
setIntersect Array a
a1 Array a
a2 (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) =
  Array a
-> Array a
-> (Ptr AFArray -> AFArray -> AFArray -> IO AFErr)
-> Array a
forall b a.
Array b
-> Array a
-> (Ptr AFArray -> AFArray -> AFArray -> IO AFErr)
-> Array a
op2 Array a
a1 Array a
a2 (\Ptr AFArray
x AFArray
y AFArray
z -> Ptr AFArray -> AFArray -> AFArray -> CBool -> IO AFErr
af_set_intersect Ptr AFArray
x AFArray
y AFArray
z CBool
b)