{-# LANGUAGE CPP #-}
#include "fusion-phases.h"

-- | Sum-like parallel combinators for unlifted arrays
module Data.Array.Parallel.Unlifted.Parallel.Sums 
        ( andUP, orUP
        , allUP, anyUP
        , sumUP, productUP
        , maximumUP, maximumByUP
        , maximumIndexByUP)
where
import Data.Array.Parallel.Unlifted.Sequential.Vector as Seq
import Data.Array.Parallel.Unlifted.Distributed
import Data.Array.Parallel.Unlifted.Parallel.Combinators
import Data.Array.Parallel.Unlifted.Parallel.Basics (indexedUP)


-- | Compute the logical AND of all the elements in a array.
andUP :: Vector Bool -> Bool
andUP = foldUP (&&) True
{-# INLINE_UP andUP #-}


-- | Compute the logical OR of all the elements in a array.
orUP :: Vector Bool -> Bool
orUP = foldUP (||) False
{-# INLINE_UP orUP #-}


-- | Check whether all the elements in a array meet the given predicate.
allUP :: Unbox e => (e -> Bool) -> Vector e -> Bool
allUP p = andUP . mapUP p
{-# INLINE_UP allUP #-}


-- | Check whether any of the elements in a array meet the given predicate.
anyUP :: Unbox e => (e -> Bool) -> Vector e -> Bool
anyUP p =  orUP . mapUP p
{-# INLINE_UP anyUP #-}


-- | Compute the sum all the elements of a array.
sumUP :: (Unbox a, DT a, Num a) => Vector a -> a
sumUP = foldUP (+) 0
{-# INLINE_UP sumUP #-}


-- | Compute the product of all the elements of an array.
productUP :: (DT e, Num e, Unbox e) => Vector e -> e
productUP = foldUP (*) 1
{-# INLINE_UP productUP #-}


-- | Determine the maximum element in an array.
maximumUP :: (DT e, Ord e, Unbox e) => Vector e -> e
maximumUP = fold1UP max
{-# INLINE_UP maximumUP #-}


-- | Determine the maximum element in an array under the given ordering
maximumByUP :: (DT e, Unbox e) => (e -> e -> Ordering) -> Vector e -> e
maximumByUP 
  = fold1UP . maxBy
  where
    maxBy compare' x y 
        = case x `compare'` y of
           LT -> y
           _  -> x
{-# INLINE_UP maximumByUP #-}


-- | Determine the index of the maximum element in an array under the
--   given ordering
maximumIndexByUP 
        :: (DT e, Unbox e) => (e -> e -> Ordering) -> Vector e -> Int
maximumIndexByUP cmp 
  = fst . maximumByUP cmp' . indexedUP
  where
    cmp' (_,x) (_,y) = cmp x y
{-# INLINE_UP maximumIndexByUP #-}