arrayfire-0.9.0.0: src/ArrayFire/Statistics.hs
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE ViewPatterns #-}
{-# OPTIONS_GHC -fno-warn-unused-imports #-}
--------------------------------------------------------------------------------
-- |
-- Module : ArrayFire.Statistics
-- Copyright : David Johnson (c) 2019-2026
-- License : BSD3
-- Maintainer : David Johnson <code@dmj.io>
-- Stability : Experimental
-- Portability : GHC
--
-- Statistics API.
-- Example of finding the top k elements along with their indices from an 'Array'
--
-- @
-- >>> let (vals,indexes) = 'topk' ( 'vector' \@'Double' 10 [1..] ) 3 'TopKDefault'
-- >>> vals
--
-- ArrayFire Array
-- [3 1 1 1]
-- 10.0000
-- 9.0000
-- 8.0000
--
-- >>> indexes
--
-- ArrayFire Array
-- [3 1 1 1]
-- 9
-- 8
-- 7
-- @
--------------------------------------------------------------------------------
module ArrayFire.Statistics where
import Data.Word (Word32)
import Foreign.Ptr (nullPtr)
import ArrayFire.Array
import ArrayFire.FFI
import ArrayFire.Internal.Statistics
import ArrayFire.Internal.Types
-- | Calculates 'mean' of 'Array' along user-specified dimension.
--
-- >>> mean (vector @Double 10 [1..]) 0
-- ArrayFire Array
-- [1 1 1 1]
-- 5.5000
mean
:: (AFType a, Fractional a)
=> Array a
-- ^ Input 'Array'
-> Int
-- ^ The dimension along which the mean is extracted
-> Array a
-- ^ Will contain the mean of the input 'Array' along dimension dim
mean a n =
a `op1` (\x y ->
af_mean x y (fromIntegral n))
-- | Calculates 'meanWeighted' of 'Array' along user-specified dimension.
--
-- >>> meanWeighted (vector @Double 10 [1..10]) (vector @Double 10 [1..10]) 0
-- ArrayFire Array
-- [1 1 1 1]
-- 7.0000
meanWeighted
:: (AFType a, Fractional a)
=> Array a
-- ^ Input 'Array'
-> Array a
-- ^ Weights 'Array'
-> Int
-- ^ The dimension along which the mean is extracted
-> Array a
-- ^ Will contain the mean of the input 'Array' along dimension dim
meanWeighted x y (fromIntegral -> n) =
op2 x y $ \a b c ->
af_mean_weighted a b c n
-- | Calculates /variance/ of 'Array' along user-specified dimension.
--
-- >>> var (vector @Double 8 [1..8]) Population 0
-- ArrayFire Array
-- [1 1 1 1]
-- 5.2500
var
:: (AFType a, Fractional a)
=> Array a
-- ^ Input 'Array'
-> VarianceType
-- ^ boolean denoting Population variance (false) or Sample Variance (true)
-> Int
-- ^ The dimension along which the variance is extracted
-> Array a
-- ^ will contain the variance of the input array along dimension dim
var arr (fromIntegral . fromEnum -> b) d =
arr `op1` (\p x ->
af_var p x b (fromIntegral d))
-- | Data type used to express variance type in the 'var' function
data VarianceType = Population | Sample
deriving (Show, Eq, Enum)
-- | Calculates 'varWeighted' of 'Array' along user-specified dimension.
--
-- >>> varWeighted (vector @Double 10 [1..]) (vector @Double 10 [1..]) 0
-- ArrayFire Array
-- [1 1 1 1]
-- 1.9091
varWeighted
:: (AFType a, Fractional a)
=> Array a
-- ^ Input 'Array'
-> Array a
-- ^ Weights 'Array' used to scale input in before getting variance
-> Int
-- ^ The dimension along which the variance is extracted
-> Array a
-- ^ Contains the variance of the input array along dimension dim
varWeighted x y (fromIntegral -> n) =
op2 x y $ \a b c ->
af_var_weighted a b c n
-- | Calculates 'stdev' of 'Array' along user-specified dimension.
--
-- >>> stdev (vector @Double 10 (cycle [1,-1])) 0
-- ArrayFire Array
-- [1 1 1 1]
-- 1.0000
stdev
:: (AFType a, Fractional a)
=> Array a
-- ^ Input 'Array'
-> Int
-- ^ The dimension along which the standard deviation is extracted
-> Array a
-- ^ Contains the standard deviation of the input array along dimension dim
stdev a n =
a `op1` (\x y ->
af_stdev x y (fromIntegral n))
-- | Calculates /covariance/ of two 'Array's with a bias specifier.
--
-- >>> cov (vector @Double 10 (repeat 1)) (vector @Double 10 (repeat 1)) False
-- ArrayFire Array
-- [1 1 1 1]
-- 0.0000
cov
:: (AFType a, Fractional a)
=> Array a
-- ^ First input 'Array'
-> Array a
-- ^ Second input 'Array'
-> Bool
-- ^ A boolean specifying if biased estimate should be taken (default: 'False')
-> Array a
-- ^ Contains will the covariance of the input 'Array's
cov x y (fromIntegral . fromEnum -> n) =
op2 x y $ \a b c ->
af_cov a b c n
-- | Calculates 'median' of 'Array' along user-specified dimension.
--
-- >>> median (vector @Double 10 [1..]) 0
-- ArrayFire Array
-- [1 1 1 1]
-- 5.5000
median
:: (AFType a, Fractional a)
=> Array a
-- ^ Input 'Array'
-> Int
-- ^ Dimension along which to calculate 'median'
-> Array a
-- ^ Array containing 'median'
median a n =
a `op1` (\x y ->
af_median x y (fromIntegral n))
-- | Calculates 'mean' of all elements in an 'Array'
--
-- >>> meanAll $ matrix @Double (2,2) [[1,2],[4,5]]
-- 3.0
meanAll
:: forall a . AFResult a
=> Array a
-- ^ Input 'Array'
-> Scalar a
-- ^ Mean of all elements
meanAll arr = toAFResult @a (arr `infoFromArray2` af_mean_all)
-- | Calculates weighted mean of all elements in an 'Array'
--
-- >>> meanAllWeighted (matrix @Double (2,2) [[1,2],[3,4]]) (matrix @Double (2,2) [[1,2],[3,4]])
-- 2.8181818181818183
meanAllWeighted
:: forall a . AFResult a
=> Array a
-- ^ Input 'Array'
-> Array a
-- ^ 'Array' of weights
-> Scalar a
-- ^ Weighted mean
meanAllWeighted a b =
toAFResult @a (infoFromArray22 a b af_mean_all_weighted)
-- | Calculates variance of all elements in an 'Array'
--
-- >>> varAll (vector @Double 10 (repeat 10)) Population
-- 0.0
varAll
:: forall a . AFResult a
=> Array a
-- ^ Input 'Array'
-> VarianceType
-- ^ 'Population' variance (÷N) or 'Sample' variance (÷N-1)
-> Scalar a
-- ^ Variance of all elements
varAll a (fromIntegral . fromEnum -> b) =
toAFResult @a (infoFromArray2 a $ \x y z ->
af_var_all x y z b)
-- | Calculates weighted variance of all elements in an 'Array'
--
-- >>> varAllWeighted ( vector @Double 10 [1..] ) ( vector @Double 10 [1..] )
-- 6.011479591836735
varAllWeighted
:: forall a . AFResult a
=> Array a
-- ^ Input 'Array'
-> Array a
-- ^ 'Array' of weights
-> Scalar a
-- ^ Weighted variance of all elements
varAllWeighted a b =
toAFResult @a (infoFromArray22 a b af_var_all_weighted)
-- | Calculates standard deviation of all elements in an 'Array'
--
-- >>> stdevAll (vector @Double 10 (repeat 10))
-- 0.0
stdevAll
:: forall a . AFResult a
=> Array a
-- ^ Input 'Array'
-> Scalar a
-- ^ Standard deviation of all elements
stdevAll arr = toAFResult @a (arr `infoFromArray2` af_stdev_all)
-- | Calculates median of all elements in an 'Array'
--
-- >>> medianAll (vector @Double 10 (repeat 10))
-- 10.0
medianAll
:: forall a . AFResult a
=> Array a
-- ^ Input 'Array'
-> Scalar a
-- ^ Median of all elements
medianAll arr = toAFResult @a (arr `infoFromArray2` af_median_all)
-- | This algorithm returns Pearson product-moment correlation coefficient.
-- <https://en.wikipedia.org/wiki/Pearson_correlation_coefficient>
--
-- >>> corrCoef ( vector @Int 10 [1..] ) ( vector @Int 10 [10,9..] )
-- -1.0
corrCoef
:: forall a . AFResult a
=> Array a
-- ^ First input 'Array'
-> Array a
-- ^ Second input 'Array'
-> Scalar a
-- ^ Correlation coefficient
corrCoef a b =
toAFResult @a (infoFromArray22 a b af_corrcoef)
-- | This function returns the top k values along a given dimension of the input array.
--
-- @
-- >>> let (vals,indexes) = 'topk' ( 'vector' \@'Double' 10 [1..] ) 3 'TopKDefault'
-- >>> indexes
--
-- ArrayFire Array
-- [3 1 1 1]
-- 9
-- 8
-- 7
--
-- >>> vals
-- ArrayFire Array
-- [3 1 1 1]
-- 10.0000
-- 9.0000
-- 8.0000
-- @
--
-- The indices along with their values are returned. If the input is a multi-dimensional array, the indices will be the index of the value in that dimension. Order of duplicate values are not preserved. This function is optimized for small values of k.
-- This function performs the operation across all dimensions of the input array.
-- This function is optimized for small values of k.
-- The order of the returned keys may not be in the same order as the appear in the input array
--
topk
:: AFType a
=> Array a
-- ^ First input 'Array', with at least /k/ elements along /dim/
-> Int
-- ^ The number of elements to be retrieved along the dim dimension
-> TopK
-- ^ If descending, the highest values are returned. Otherwise, the lowest values are returned
-> (Array a, Array Word32)
-- ^ Returns The values of the top k elements along the dim dimension
-- along with the indices of the top k elements along the dim dimension
topk a (fromIntegral -> x) (fromTopK -> f)
= a `op2p` (\b c d -> af_topk b c d x 0 f)
-- | Simultaneously compute the mean and variance of an 'Array' along a dimension.
--
-- More efficient than calling 'mean' and 'var' separately.
--
-- >>> let (m, v) = meanVar (vector @Double 4 [1,2,3,4]) VariancePopulation 0
-- >>> m
-- ArrayFire Array
-- [1 1 1 1]
-- 2.5000
-- >>> v
-- ArrayFire Array
-- [1 1 1 1]
-- 1.2500
meanVar
:: (AFType a, Fractional a)
=> Array a
-- ^ Input 'Array'
-> VarBias
-- ^ Variance bias correction: 'VariancePopulation' (÷N) or 'VarianceSample' (÷N-1)
-> Int
-- ^ Dimension along which to compute
-> (Array a, Array a)
-- ^ (mean, variance)
meanVar arr bias (fromIntegral -> dim) =
arr `op2p` (\pMean pVar aPtr ->
af_meanvar pMean pVar aPtr nullPtr (fromVarBias bias) dim)
-- | Simultaneously compute the weighted mean and variance of an 'Array' along a dimension.
--
-- >>> let (m, v) = meanVarWeighted (vector @Double 4 [1,2,3,4]) (vector @Double 4 [1,1,1,1]) VariancePopulation 0
-- >>> m
-- ArrayFire Array
-- [1 1 1 1]
-- 2.5000
meanVarWeighted
:: (AFType a, Fractional a)
=> Array a
-- ^ Input 'Array'
-> Array a
-- ^ Weights 'Array'
-> VarBias
-- ^ Variance bias correction
-> Int
-- ^ Dimension along which to compute
-> (Array a, Array a)
-- ^ (mean, variance)
meanVarWeighted arr weights bias (fromIntegral -> dim) =
op2p2 arr weights $ \pMean pVar aPtr wPtr ->
af_meanvar pMean pVar aPtr wPtr (fromVarBias bias) dim