{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE ScopedTypeVariables #-}
module Data.Massiv.Array.Ops.Fold
(
fold
, ifoldMono
, foldMono
, ifoldSemi
, foldSemi
, foldOuterSlice
, ifoldOuterSlice
, foldInnerSlice
, ifoldInnerSlice
, minimumM
, minimum'
, maximumM
, maximum'
, sum
, product
, and
, or
, all
, any
, ifoldlInner
, foldlInner
, ifoldrInner
, foldrInner
, foldInner
, ifoldlWithin
, foldlWithin
, ifoldrWithin
, foldrWithin
, foldWithin
, ifoldlWithin'
, foldlWithin'
, ifoldrWithin'
, foldrWithin'
, foldWithin'
, foldlS
, foldrS
, ifoldlS
, ifoldrS
, foldlM
, foldrM
, foldlM_
, foldrM_
, ifoldlM
, ifoldrM
, ifoldlM_
, ifoldrM_
, foldrFB
, lazyFoldlS
, lazyFoldrS
, foldlP
, foldrP
, ifoldlP
, ifoldrP
, ifoldlIO
, ifoldrIO
) where
import Data.Massiv.Array.Delayed.Pull
import Data.Massiv.Array.Ops.Construct
import Data.Massiv.Array.Ops.Fold.Internal
import Data.Massiv.Core
import Data.Massiv.Core.Common
import Prelude hiding (all, and, any, foldl, foldr, map, maximum, minimum, or, product, sum)
ifoldMono ::
(Source r ix e, Monoid m)
=> (ix -> e -> m)
-> Array r ix e
-> m
ifoldMono f = ifoldlInternal (\a ix e -> a `mappend` f ix e) mempty mappend mempty
{-# INLINE ifoldMono #-}
ifoldSemi ::
(Source r ix e, Semigroup m)
=> (ix -> e -> m)
-> m
-> Array r ix e
-> m
ifoldSemi f m = ifoldlInternal (\a ix e -> a <> f ix e) m (<>) m
{-# INLINE ifoldSemi #-}
foldSemi ::
(Source r ix e, Semigroup m)
=> (e -> m)
-> m
-> Array r ix e
-> m
foldSemi f m = foldlInternal (\a e -> a <> f e) m (<>) m
{-# INLINE foldSemi #-}
ifoldlWithin :: (Index (Lower ix), IsIndexDimension ix n, Source r ix e) =>
Dimension n -> (ix -> a -> e -> a) -> a -> Array r ix e -> Array D (Lower ix) a
ifoldlWithin dim = ifoldlWithin' (fromDimension dim)
{-# INLINE ifoldlWithin #-}
foldlWithin :: (Index (Lower ix), IsIndexDimension ix n, Source r ix e) =>
Dimension n -> (a -> e -> a) -> a -> Array r ix e -> Array D (Lower ix) a
foldlWithin dim f = ifoldlWithin dim (const f)
{-# INLINE foldlWithin #-}
ifoldrWithin :: (Index (Lower ix), IsIndexDimension ix n, Source r ix e) =>
Dimension n -> (ix -> e -> a -> a) -> a -> Array r ix e -> Array D (Lower ix) a
ifoldrWithin dim = ifoldrWithin' (fromDimension dim)
{-# INLINE ifoldrWithin #-}
foldrWithin :: (Index (Lower ix), IsIndexDimension ix n, Source r ix e) =>
Dimension n -> (e -> a -> a) -> a -> Array r ix e -> Array D (Lower ix) a
foldrWithin dim f = ifoldrWithin dim (const f)
{-# INLINE foldrWithin #-}
ifoldlWithin' :: (Index (Lower ix), Source r ix e) =>
Dim -> (ix -> a -> e -> a) -> a -> Array r ix e -> Array D (Lower ix) a
ifoldlWithin' dim f acc0 arr =
makeArray (getComp arr) (SafeSz szl) $ \ixl ->
iter
(insertDim' ixl dim 0)
(insertDim' ixl dim (k - 1))
(pureIndex 1)
(<=)
acc0
(\ix acc' -> f ix acc' (unsafeIndex arr ix))
where
SafeSz sz = size arr
(k, szl) = pullOutDim' sz dim
{-# INLINE ifoldlWithin' #-}
foldlWithin' :: (Index (Lower ix), Source r ix e) =>
Dim -> (a -> e -> a) -> a -> Array r ix e -> Array D (Lower ix) a
foldlWithin' dim f = ifoldlWithin' dim (const f)
{-# INLINE foldlWithin' #-}
ifoldrWithin' :: (Index (Lower ix), Source r ix e) =>
Dim -> (ix -> e -> a -> a) -> a -> Array r ix e -> Array D (Lower ix) a
ifoldrWithin' dim f acc0 arr =
makeArray (getComp arr) (SafeSz szl) $ \ixl ->
iter
(insertDim' ixl dim (k - 1))
(insertDim' ixl dim 0)
(pureIndex (-1))
(>=)
acc0
(\ix acc' -> f ix (unsafeIndex arr ix) acc')
where
SafeSz sz = size arr
(k, szl) = pullOutDim' sz dim
{-# INLINE ifoldrWithin' #-}
foldrWithin' :: (Index (Lower ix), Source r ix e) =>
Dim -> (e -> a -> a) -> a -> Array r ix e -> Array D (Lower ix) a
foldrWithin' dim f = ifoldrWithin' dim (const f)
{-# INLINE foldrWithin' #-}
ifoldlInner :: (Index (Lower ix), Source r ix e) =>
(ix -> a -> e -> a) -> a -> Array r ix e -> Array D (Lower ix) a
ifoldlInner = ifoldlWithin' 1
{-# INLINE ifoldlInner #-}
foldlInner :: (Index (Lower ix), Source r ix e) =>
(a -> e -> a) -> a -> Array r ix e -> Array D (Lower ix) a
foldlInner = foldlWithin' 1
{-# INLINE foldlInner #-}
ifoldrInner :: (Index (Lower ix), Source r ix e) =>
(ix -> e -> a -> a) -> a -> Array r ix e -> Array D (Lower ix) a
ifoldrInner = ifoldrWithin' 1
{-# INLINE ifoldrInner #-}
foldrInner :: (Index (Lower ix), Source r ix e) =>
(e -> a -> a) -> a -> Array r ix e -> Array D (Lower ix) a
foldrInner = foldrWithin' 1
{-# INLINE foldrInner #-}
foldInner :: (Monoid e, Index (Lower ix), Source r ix e) => Array r ix e -> Array D (Lower ix) e
foldInner = foldlInner mappend mempty
{-# INLINE foldInner #-}
foldWithin ::
(Source r ix a, Monoid a, Index (Lower ix), IsIndexDimension ix n)
=> Dimension n
-> Array r ix a
-> Array D (Lower ix) a
foldWithin dim = foldlWithin dim mappend mempty
{-# INLINE foldWithin #-}
foldWithin' ::
(Source r ix a, Monoid a, Index (Lower ix))
=> Dim
-> Array r ix a
-> Array D (Lower ix) a
foldWithin' dim = foldlWithin' dim mappend mempty
{-# INLINE foldWithin' #-}
foldOuterSlice :: (OuterSlice r ix e, Monoid m) => (Elt r ix e -> m) -> Array r ix e -> m
foldOuterSlice f = ifoldOuterSlice (const f)
{-# INLINE foldOuterSlice #-}
ifoldOuterSlice :: (OuterSlice r ix e, Monoid m) => (Ix1 -> Elt r ix e -> m) -> Array r ix e -> m
ifoldOuterSlice f arr = foldMono g $ range (getComp arr) 0 (headDim (unSz (size arr)))
where
g i = f i (unsafeOuterSlice arr i)
{-# INLINE g #-}
{-# INLINE ifoldOuterSlice #-}
foldInnerSlice :: (InnerSlice r ix e, Monoid m) => (Elt r ix e -> m) -> Array r ix e -> m
foldInnerSlice f = ifoldInnerSlice (const f)
{-# INLINE foldInnerSlice #-}
ifoldInnerSlice :: (InnerSlice r ix e, Monoid m) => (Ix1 -> Elt r ix e -> m) -> Array r ix e -> m
ifoldInnerSlice f arr = foldMono g $ range (getComp arr) 0 (unSz k)
where
szs@(_, !k) = unsnocSz (size arr)
g i = f i (unsafeInnerSlice arr szs i)
{-# INLINE g #-}
{-# INLINE ifoldInnerSlice #-}
maximumM :: (MonadThrow m, Source r ix e, Ord e) => Array r ix e -> m e
maximumM arr =
if isEmpty arr
then throwM (SizeEmptyException (size arr))
else let !e0 = unsafeIndex arr zeroIndex
in pure $ foldlInternal max e0 max e0 arr
{-# INLINE maximumM #-}
maximum' :: (Source r ix e, Ord e) => Array r ix e -> e
maximum' = either throw id . maximumM
{-# INLINE maximum' #-}
minimumM :: (MonadThrow m, Source r ix e, Ord e) => Array r ix e -> m e
minimumM arr =
if isEmpty arr
then throwM (SizeEmptyException (size arr))
else let !e0 = unsafeIndex arr zeroIndex
in pure $ foldlInternal min e0 min e0 arr
{-# INLINE minimumM #-}
minimum' :: (Source r ix e, Ord e) => Array r ix e -> e
minimum' = either throw id . minimumM
{-# INLINE minimum' #-}
sum :: (Source r ix e, Num e) => Array r ix e -> e
sum = foldlInternal (+) 0 (+) 0
{-# INLINE sum #-}
product :: (Source r ix e, Num e) => Array r ix e -> e
product = foldlInternal (*) 1 (*) 1
{-# INLINE product #-}
and :: Source r ix Bool => Array r ix Bool -> Bool
and = foldlInternal (&&) True (&&) True
{-# INLINE and #-}
or :: Source r ix Bool => Array r ix Bool -> Bool
or = foldlInternal (||) False (||) False
{-# INLINE or #-}
all :: Source r ix e => (e -> Bool) -> Array r ix e -> Bool
all f = foldlInternal (\acc e -> acc && f e) True (&&) True
{-# INLINE all #-}
any :: Source r ix e => (e -> Bool) -> Array r ix e -> Bool
any f = foldlInternal (\acc e -> acc || f e) False (||) False
{-# INLINE any #-}