-----------------------------------------------------------------------------
-- |
-- Module      : Data.Array.Parallel.Unlifted.Parallel.Sums
-- Copyright   : (c) 2006         Roman Leshchinskiy
-- License     : see libraries/ndp/LICENSE
-- 
-- Maintainer  : Roman Leshchinskiy <rl@cse.unsw.edu.au>
-- Stability   : experimental
-- Portability : portable
--
-- Description ---------------------------------------------------------------
--
-- Sum-like parallel combinators for unlifted arrays
--

module Data.Array.Parallel.Unlifted.Parallel.Sums (
  andUP, orUP, sumUP
) where

import Data.Array.Parallel.Unlifted.Sequential
import Data.Array.Parallel.Unlifted.Distributed
import Data.Array.Parallel.Unlifted.Parallel.Combinators (
  foldUP, foldl1UP, fold1UP, mapUP)
import Data.Array.Parallel.Unlifted.Parallel.Basics ( 
  indexedUP)

import Data.Array.Parallel.Base (
  (:*:)(..), fstS)

andUP :: UArr Bool -> Bool
{-# INLINE andUP #-}
andUP = foldUP (&&) True


-- |
orUP :: UArr Bool -> Bool
{-# INLINE orUP #-}
orUP = foldUP (||) False

allUP :: UA e => (e -> Bool) -> UArr e -> Bool
{-# INLINE allUP #-}
allUP p = andUP . mapUP p

-- |
anyUP :: UA e => (e -> Bool) -> UArr e -> Bool
{-# INLINE anyUP #-}
anyUP p =  orUP . mapUP p


sumUP :: (UA a, DT a, Num a) => UArr a -> a
{-# INLINE sumUP #-}
sumUP = foldUP (+) 0

productUP :: (DT e, Num e, UA e) => UArr e -> e
{-# INLINE productUP #-}
productUP = foldUP (*) 1

-- |Determine the maximum element in an array
--
maximumUP :: (DT e, Ord e, UA e) => UArr e -> e
{-# INLINE maximumUP #-}
maximumUP = fold1UP max


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

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