packages feed

dph-prim-interface-0.5.1.1: interface/DPH_Interface.h

import Data.Array.Parallel.Base ( Tag, tagToInt, fromBool )
import qualified GHC.Base
import Prelude ((.), ($), Num(..), Eq(..), seq)
import qualified Prelude

instance Elt Int
instance Elt Word8
instance Elt Bool
instance Elt Float
instance Elt Double
instance (Elt a, Elt b) => Elt (a, b)

infixl 9 !:
infixr 5 +:+

-- Basics ---------------------------------------------------------------------
-- | O(1). Take the number of elements in an array.
length :: Elt a => Array a -> Int
{-# INLINE_BACKEND length #-}


-- Constructors ---------------------------------------------------------------
-- | An array with no elements.
empty :: Elt a => Array a
{-# INLINE_BACKEND empty #-}


-- | O(n). Append two arrays.
(+:+) :: Elt a => Array a -> Array a -> Array a
{-# INLINE_BACKEND (+:+) #-}


-- | Generate a new array given its length and a function to compute each element.
generate :: Elt a => Int -> (Int -> a) -> Array a
{-# INLINE_BACKEND generate #-}
generate n f = map f (enumFromTo 0 (n-1))

generate_cheap :: Elt a => Int -> (Int -> a) -> Array a
{-# INLINE_BACKEND generate_cheap #-}
generate_cheap n f = map f (enumFromTo 0 (n-1))

-- | O(n). Produce a new array by replicating a single element the given number of times.
replicate :: Elt a => Int -> a -> Array a
{-# INLINE CONLIKE PHASE_BACKEND replicate #-}

{-# RULES

"seq/replicate" forall n x y.
  seq (replicate n x) y = n `seq` x `seq` y

 #-}


-- | Produce an array by copying a portion of another array.
repeat  :: Elt a 
        => Int          -- ^ number of times to repeat the source
        -> Int          -- ^ length of source (can be less than the provided array)
        -> Array a      -- ^ array elements to repeat
        -> Array a
{-# INLINE_BACKEND repeat #-}


-- | Tag each element of an array with its index.
--
--   Example: @indexed [:42, 93, 13:] = [:(0, 42), (1, 93), (2, 13):]@ 
indexed :: Elt a => Array a -> Array (Int, a)
{-# INLINE_BACKEND indexed #-}


-- | Generate a range of @Int@s.
enumFromTo :: Int -> Int -> Array Int
{-# INLINE_BACKEND enumFromTo #-}

enumFromThenTo :: Int -> Int -> Int -> Array Int
{-# INLINE_BACKEND enumFromThenTo #-}

enumFromStepLen :: Int -> Int -> Int -> Array Int
{-# INLINE_BACKEND enumFromStepLen #-}

enumFromStepLenEach :: Int -> Array Int -> Array Int -> Array Int -> Array Int
{-# INLINE_BACKEND enumFromStepLenEach #-}


{-# RULES

"repeat/enumFromStepLen[Int]" forall i j k n len.
  repeat n len (enumFromStepLen i j k)
    = generate_cheap len (\m -> i + ((m `Prelude.rem` k) * j))

  #-}


-- Projections ----------------------------------------------------------------
-- | O(1). Retrieve a numbered element from an array.
(!:) :: Elt a => Array a -> Int -> a
{-# INLINE_BACKEND (!:) #-}


-- | O(n). Extract a subrange of elements from an array.
--   Example: @extract [:23, 42, 93, 50, 27:] 1 3  = [:42, 93, 50:]@
extract :: Elt a
        => Array a      -- ^ source array
        -> Int          -- ^ starting index in source array
        -> Int          -- ^ length of result array
        -> Array a
{-# INLINE_BACKEND extract #-}


-- | O(n). Drop some elements from the front of an array, 
--         returning the latter portion.
drop :: Elt a => Int -> Array a -> Array a
{-# INLINE_BACKEND drop #-}


-- Permutation ----------------------------------------------------------------
-- | O(n). Forwards permutation of array elements.
permute :: Elt a 
        => Array a      -- ^ source array
        -> Array Int    -- ^ indices in the destination to copy elements to
        -> Array a
{-# INLINE_BACKEND permute #-}


-- | O(n). Backwards permutation of array elements.
--
--   Example @bpermute [:50, 60, 20, 30:] 3 [:0, 3, 2:]  = [:50, 30, 20:]@
bpermute 
        :: Elt a 
        => Array a      -- ^ source array
        -> Array Int    -- ^ indices in the source to copy elements from.
        -> Array a
{-# INLINE_BACKEND bpermute #-}


-- | Combination of map and bpermute.
--
--   The advantage of using this combined version is that we dont need
--   to apply the parameter function to source elements that dont appear
--   in the result.
mbpermute :: (Elt a, Elt b) => (a->b) -> Array a -> Array Int -> Array b
{-# INLINE_BACKEND mbpermute #-}


-- | Default backwards permutation.
--
--   * The values of the index-value pairs are written into the position in the
--     result array that is indicated by the corresponding index.
--
--   * All positions not covered by the index-value pairs will have the value
--     determined by the initialiser function for that index position.
--
bpermuteDft:: Elt e => Int -> (Int -> e) -> Array (Int, e) -> Array e
{-# INLINE_BACKEND bpermuteDft #-}

{-# RULES
        
"bpermute/repeat" forall n len xs is.
  bpermute (repeat n len xs) is
    = len `Prelude.seq` bpermute xs (map (dph_mod_index len) is)

"bpermute/bpermute" forall xs is js.
  bpermute (bpermute xs is) js = bpermute xs (bpermute is js)

  #-}


-- Update ---------------------------------------------------------------------
-- | O(n). Copy the source array in the destination, using new values for the given indices.
update :: Elt a => Array a -> Array (Int, a) -> Array a
{-# INLINE_BACKEND update #-}


-- Packing and Combining -----------------------------------------------------
-- | Extract the elements from an array that match the given predicate.
filter :: Elt a => (a -> Bool) -> Array a -> Array a
{-# INLINE_BACKEND filter #-}


-- | Extract elements of an array where the associated flag is true.
pack :: Elt a => Array a -> Array Bool -> Array a
{-# INLINE_BACKEND pack #-}


-- | Combine two arrays, using a tag array to tell us where to get each element from.
--
--   Example: @combine [T,F,F,T,T,F] [1,2,3] [4,5,6] = [1,4,5,2,3,6]@
combine :: Elt a => Array Bool -> Array a -> Array a -> Array a
{-# INLINE_BACKEND combine #-}


-- | Like `combine`, but use a precomputed selector to speed up the process.
-- 
--   See dph-prim-seq:"Data.Array.Parallel.Unlifted.Sequential.Segmented.USel"
--   for a description of how this works.
--   
combine2 :: Elt a => Array Tag -> SelRep2 -> Array a -> Array a -> Array a
{-# INLINE_BACKEND combine2 #-}


-- | Interleave the elements of two arrays.
-- 
--   Example: @interleave [1,2,3] [4,5,6] = [1,4,2,5,3,6]@
interleave :: Elt a => Array a -> Array a -> Array a
{-# INLINE_BACKEND interleave #-}


-- Zipping and Unzipping ------------------------------------------------------
-- | O(1). Takes two arrays and returns an array of corresponding pairs.
--         If one array is short, excess elements of the longer array are discarded.
zip :: (Elt a, Elt b) => Array a -> Array b -> Array (a, b)
{-# INLINE CONLIKE PHASE_BACKEND zip #-}


-- | O(1). Transform an array into an array of the first components,
--         and an array of the second components.
unzip :: (Elt a, Elt b) => Array (a, b) -> (Array a, Array b)
{-# INLINE_BACKEND unzip #-}


-- | O(1). Take the first elements of an array of pairs.
fsts  :: (Elt a, Elt b) => Array (a, b) -> Array a
{-# INLINE_BACKEND fsts #-}


-- | O(1). Take the second elements of an array of pairs.
snds :: (Elt a, Elt b) => Array (a, b) -> Array b
{-# INLINE_BACKEND snds #-}


-- Maps and zipWith -----------------------------------------------------------
-- | Apply a worker function to each element of an array, yielding a new array.
map     :: (Elt a, Elt b)
        => (a -> b) -> Array a -> Array b
{-# INLINE_BACKEND map #-}


-- | zipWith generalises zip by zipping with the function given as the first
--         argument, instead of a tupling function.
zipWith :: (Elt a, Elt b, Elt c)
        => (a -> b -> c) -> Array a -> Array b -> Array c
{-# INLINE_BACKEND zipWith #-}


zipWith3 :: (Elt a, Elt b, Elt c, Elt d)
          => (a -> b -> c -> d) -> Array a -> Array b -> Array c -> Array d
{-# INLINE zipWith3 #-}
zipWith3 f xs ys zs
        = zipWith (\(x, y) z -> f x y z)
                  (zip xs ys)
                  zs

zipWith4 :: (Elt a, Elt b, Elt c, Elt d, Elt e)
         => (a -> b -> c -> d -> e)
         -> Array a -> Array b -> Array c -> Array d -> Array e
{-# INLINE zipWith4 #-}
zipWith4 f as bs cs ds
         = zipWith (\(a, b) (c, d) -> f a b c d)
                   (zip as bs)
                   (zip cs ds)


-- Generally useful rules -------------
{-# RULES
        
"zipWith/replicate" forall f m n x y.
  zipWith f (replicate m x) (replicate n y) = replicate m (f x y)

"zipWith/plusInt0_1" forall n xs.
  zipWith GHC.Base.plusInt (replicate n (GHC.Base.I# 0#)) xs = xs

"zipWith/plusInt0_2" forall n xs.
  zipWith GHC.Base.plusInt xs (replicate n (GHC.Base.I# 0#)) = xs

"zipWith(plusInt)/enumFromStepLen" forall i1 k1 n1 i2 k2 n2.
  zipWith GHC.Base.plusInt (enumFromStepLen i1 k1 n1)
                           (enumFromStepLen i2 k2 n2)
    = enumFromStepLen (i1+i2) (k1+k2) n1
  #-}


-- FIXME: These are the SMVM rules. They are intentionally quite specific and
-- we want to get rid of the ASAP.

{-# RULES

"map/zipWith (+)/enumFromStepLen" forall m n is.
  map (dph_mod_index m) (zipWith GHC.Base.plusInt (enumFromStepLen 0 m n) is)
    = map (dph_mod_index m) is

"map dph_mod_index/enumFromStepLenEach" forall k l is n1 n2.
  map (dph_mod_index k)
      (enumFromStepLenEach l is (replicate n1 (GHC.Base.I# 1#)) (replicate n2 k))
    = enumFromStepLenEach l (map (dph_mod_index k) is)
                            (replicate n1 (GHC.Base.I# 1#))
                            (replicate n2 k)

"map dph_mod_index/replicate_s" forall k segd xs.
  map (dph_mod_index k) (replicate_s segd xs)
    = replicate_s segd (map (dph_mod_index k) xs)

"map dph_mod_index/enumFromStepLen" forall k# i n.
  map (dph_mod_index (GHC.Base.I# k#)) (enumFromStepLen i (GHC.Base.I# k#) n)
    = replicate n i

"enumFromStepLenEach/replicate x 3" forall k m n1 n2 n3.
  enumFromStepLenEach m (replicate n1 (GHC.Base.I# 0#))
                        (replicate n2 (GHC.Base.I# 1#))
                        (replicate n3 k)
    = generate_cheap m (dph_mod_index k)

"bpermute/generate_cheap" forall n f xs.
  bpermute (generate_cheap n f) xs
    = map f xs
 #-}
              
 
-- The following rules fuse arithmetic operations that shouldnt have been
--  vectorised in the first place. For example, with  z = x * y + a, the vectoriser
--  will lift * and + to vector operations. The result of the  the multiply will be
--  written to a vector, and then read back to do the addition.
--
--  Adding the zipWith rules ensures that the multiply and addition are performed
--  in one go. On the other hand, they can break fusion in the backend library.
--
-- NOTE: These rules are only temporary, they should go away when we have 
--       vectorisation avoidance for scalar operations.

{- RULES  **************** DISABLED

"zipWith/zipWith/zipWith" forall f g h as bs cs ds.
  zipWith f (zipWith g as bs) (zipWith h cs ds)
   = zipWith4 (\a b c d -> f (g a b) (h c d)) as bs cs ds

"zipWith/zipWith_left"  forall f g as bs cs.
  zipWith f (zipWith g as bs) cs
   = zipWith3 (\a b c ->   f (g a b) c) as bs cs

"zipWith/zipWith_right" forall f g as bs cs.
  zipWith f as (zipWith g bs cs)
   = zipWith3 (\a b c ->   f a (g b c)) as bs cs

  -}


-- More rules to recover from the lack of vectorisation avoidance.
-- The regular form of the rules shows why we really dont want to do it this way.

{- RULES  ****************** DISABLED

"map/zipWith" forall f g xs ys.
  map f (zipWith g xs ys)
   = zipWith (\x y -> f (g x y)) xs ys

"zipWith3/map_1" forall f g xs ys zs.
  zipWith3 f (map g xs) ys zs
   = zipWith3 (\x y z -> f (g x) y z) xs ys zs

"zipWith3/map_2" forall f g xs ys zs.
  zipWith3 f xs (map g ys) zs
   = zipWith3 (\x y z -> f x (g y) z) xs ys zs

"zipWith3/map_3" forall f g xs ys zs.
  zipWith3 f xs ys (map g zs)
   = zipWith3 (\x y z -> f x y (g z)) xs ys zs

  -}


-- Folds ----------------------------------------------------------------------

-- | Left fold over an array.
fold :: Elt a => (a -> a -> a) -> a -> Array a -> a
{-# INLINE_BACKEND fold #-}

-- | Left fold over an array, using the first element to initialise the state.
fold1 :: Elt a => (a -> a -> a) -> Array a -> a
{-# INLINE_BACKEND fold1 #-}


-- | Compute the conjunction of all elements in a boolean array.
and :: Array Bool -> Bool
{-# INLINE_BACKEND and #-}

-- | Compute the sum of an array of numbers.
sum :: (Num a, Elt a) => Array a -> a
{-# INLINE_BACKEND sum #-}

-- | Similar to `foldl` but return an array of the intermediate states, including
--   the final state that is computed by `foldl`.
scan :: Elt a => (a -> a -> a) -> a -> Array a -> Array a
{-# INLINE_BACKEND scan #-}


{-# RULES

"seq/sum" forall xs e.
  seq (sum xs) e = seq xs e

"seq/scan<Int> (+)" forall i xs e.
  seq (scan GHC.Base.plusInt i xs) e = i `seq` xs `seq` e

"scan/replicate" forall z n x.
  scan GHC.Base.plusInt z (replicate n x)
    = enumFromStepLen z x n

  #-}


-- Segmented Constructors -----------------------------------------------------
append_s 
        :: Elt a
        => Segd         -- ^ segment descriptor of result aarray
        -> Segd         -- ^ segment descriptor of first array
        -> Array a      -- ^ data of first array
        -> Segd         -- ^ segment descriptor of second array
        -> Array a      -- ^ data of first array
        -> Array a
{-# INLINE_BACKEND append_s #-}


replicate_s :: Elt a => Segd -> Array a -> Array a
{-# INLINE CONLIKE PHASE_BACKEND replicate_s #-}


replicate_rs :: Elt a => Int -> Array a -> Array a
{-# INLINE CONLIKE PHASE_BACKEND replicate_rs #-}


{-# RULES

"append_s->interleave" forall n k idxs1 idxs2 idxs3 m1 m2 m3 xs ys.
  append_s (mkSegd (replicate n k) idxs1 m1)
           (mkSegd (replicate n (GHC.Base.I# 1#)) idxs2 m2) xs
           (mkSegd (replicate n (GHC.Base.I# 1#)) idxs3 m3) ys
    = interleave xs ys

  #-}

{-# RULES

"replicate_s/replicate" forall segd k x.
  replicate_s segd (replicate k x) = replicate (elementsSegd segd) x

"replicate_s->replicate_rs" forall n m idxs nm xs.
  replicate_s (mkSegd (replicate n m) idxs nm) xs
    = replicate_rs m xs

"replicate_rs/replicate" forall m n x.
  replicate_rs m (replicate n x) = replicate (m*n) x

"sum/replicate_rs" forall n xs.
  sum (replicate_rs n xs) = sum xs * n

"count/replicate_s" forall segd xs tag.
  count (replicate_s segd xs) tag
    = sum (packByTag (lengthsSegd segd) xs tag)

 #-}


-- Segmented Folds ------------------------------------------------------------
fold_s :: Elt a => (a -> a -> a) -> a -> Segd -> Array a -> Array a
{-# INLINE_BACKEND fold_s #-}

fold1_s :: Elt a => (a -> a -> a) -> Segd -> Array a -> Array a
{-# INLINE_BACKEND fold1_s #-}

fold_r :: Elt a => (a -> a -> a) -> a -> Int -> Array a -> Array a
{-# INLINE_BACKEND fold_r #-}

sum_s :: (Num a, Elt a) => Segd -> Array a -> Array a
{-# INLINE sum_s #-}
sum_s = fold_s (Prelude.+) 0

sum_r :: (Num a, Elt a) => Int ->Array a -> Array a
{-# INLINE_BACKEND sum_r #-}

{-# RULES

"fold_s/replicate1" forall f z n idxs n' xs.
  fold_s f z (mkSegd (replicate n (GHC.Base.I# 1#)) idxs n') xs = xs

"fold_s/replicate" forall f z m n idxs mn xs.
  fold_s f z (mkSegd (replicate m n) idxs mn) xs
    = fold_r f z n xs

  #-}


-- Operations on Segment Descriptors ------------------------------------------
indices_s :: Segd -> Array Int
{-# INLINE_BACKEND indices_s #-}

lengthSegd :: Segd -> Int
{-# INLINE_BACKEND lengthSegd #-}

lengthsSegd :: Segd -> Array Int
{-# INLINE_BACKEND lengthsSegd #-}

indicesSegd :: Segd -> Array Int
{-# INLINE_BACKEND indicesSegd #-}

elementsSegd :: Segd -> Int
{-# INLINE_BACKEND elementsSegd #-}

lengthsToSegd :: Array Int -> Segd
{-# INLINE lengthsToSegd #-}
lengthsToSegd ns = mkSegd ns (scan (+) 0 ns) (sum ns)

mkSegd :: Array Int -> Array Int -> Int -> Segd
{-# INLINE CONLIKE PHASE_BACKEND mkSegd #-}

plusSegd :: Segd -> Segd -> Segd
{-# INLINE plusSegd #-}
plusSegd segd1 segd2
  = mkSegd (zipWith (+) (lengthsSegd segd1) (lengthsSegd segd2))
           (zipWith (+) (indicesSegd segd1) (indicesSegd segd2))
           (elementsSegd segd1 `dph_plus` elementsSegd segd2)


{-# RULES

"lengthsSegd/mkSegd" forall lens idxs n.
  lengthsSegd (mkSegd lens idxs n) = lens

"indicesSegd/mkSegd" forall lens idxs n.
  indicesSegd (mkSegd lens idxs n) = idxs

"elementsSegd/mkSegd" forall lens idxs n.
  elementsSegd (mkSegd lens idxs n) = n

"seq/elementsSegd" forall segd e.
  seq (elementsSegd segd) e = seq segd e

"seq/mkSegd" forall lens idxs n e.
  seq (mkSegd lens idxs n) e = lens `seq` idxs `seq` n `seq` e

 #-}


-- Operations on Selectors ----------------------------------------------------

-- | O(1). Construct a selector. Selectors are used to speed up the `combine2` operation.
--
--   See dph-prim-seq:"Data.Array.Parallel.Unlifted.Sequential.Segmented.USel"
--   for a description of how this works.
mkSel2  :: Array Tag            -- ^ tags array
        -> Array Int            -- ^ indices array
        -> Int                  -- ^ number of elements taken from first source array
        -> Int                  -- ^ number of elements taken from second source array
        -> SelRep2      
        -> Sel2
{-# INLINE CONLIKE PHASE_BACKEND mkSel2 #-}


-- | O(1). Get the tags array of a selector.
tagsSel2 :: Sel2 -> Array Tag
{-# INLINE_BACKEND tagsSel2 #-}


-- | O(1). Get the indices array of a selector.
indicesSel2 :: Sel2 -> Array Int
{-# INLINE_BACKEND indicesSel2 #-}


-- | O(1). Get the number of elements that will be taken from the first array.
elementsSel2_0 :: Sel2 -> Int
{-# INLINE_BACKEND elementsSel2_0 #-}


-- | O(1). Get the number of elements that will be taken from the second array.
elementsSel2_1 :: Sel2 -> Int
{-# INLINE_BACKEND elementsSel2_1 #-}

repSel2 :: Sel2 -> SelRep2
{-# INLINE_BACKEND repSel2 #-}

mkSelRep2 :: Array Tag -> SelRep2
{-# INLINE CONLIKE PHASE_BACKEND mkSelRep2 #-}

indicesSelRep2 :: Array Tag -> SelRep2 -> Array Int
{-# INLINE_BACKEND indicesSelRep2 #-}

elementsSelRep2_0 :: Array Tag -> SelRep2 -> Int
{-# INLINE_BACKEND elementsSelRep2_0 #-}

elementsSelRep2_1 :: Array Tag -> SelRep2 -> Int
{-# INLINE_BACKEND elementsSelRep2_1 #-}


-- | O(n), Compute a selector from a tags array.
tagsToSel2 :: Array Tag -> Sel2
{-# INLINE tagsToSel2 #-}
tagsToSel2 tags = let rep = mkSelRep2 tags
                  in
                  mkSel2 tags (indicesSelRep2    tags rep)
                              (elementsSelRep2_0 tags rep)
                              (elementsSelRep2_1 tags rep)
                              rep

{-# RULES

"tagsSel2/mkSel2"
  forall ts is n0 n1 r. tagsSel2 (mkSel2 ts is n0 n1 r) = ts
"indicesSel2/mkSel2"
  forall ts is n0 n1 r. indicesSel2 (mkSel2 ts is n0 n1 r) = is
"elementsSel2_0/mkSel2"
  forall ts is n0 n1 r. elementsSel2_0 (mkSel2 ts is n0 n1 r) = n0
"elementsSel2_1/mkSel2"
  forall ts is n0 n1 r. elementsSel2_1 (mkSel2 ts is n0 n1 r) = n1
"repSel2/mkSel2"
  forall ts is n0 n1 r. repSel2 (mkSel2 ts is n0 n1 r) = r

  #-}


-- Packing and Picking --------------------------------------------------------

-- | Select the elements of an array that have a corresponding tag.
--   
-- @
-- packByTag [12, 24, 42, 93] [1, 0, 0, 1] 0
--  = [24, 42]
-- @
--
packByTag 
        :: Elt a
        => Array a      -- ^ data values
        -> Array Tag    -- ^ tag values
        -> Tag          -- ^ the tag of values to select
        -> Array a      -- ^ data values that had that tag

{-# INLINE_BACKEND packByTag #-}
packByTag xs tags !tag
        = fsts (filter (\p -> Prelude.snd p == tag) (zip xs tags))


pick :: (Elt a, Eq a) => Array a -> a -> Array Bool
{-# INLINE pick #-}
pick xs !x = map (x==) xs

{-# RULES

"tagZeroes" UNTIL_PHASE_BACKEND forall xs n.
  map fromBool (zipWith GHC.Base.eqInt xs (replicate n (GHC.Base.I# 0#)))
    = tagZeroes xs

"replicate_s/tagZeroes" forall lens idxs n.
  replicate_s (mkSegd lens idxs n) (tagZeroes lens)
    = replicate n 0

"packByTag/replicate" forall xs n t u.
  packByTag xs (replicate n t) u = if t == u then xs else empty

 #-}

{-# RULES

"packByTag/bpermute" forall xs is tags n.
  packByTag (bpermute xs is) tags n
    = bpermute xs (packByTag is tags n)

  #-}




-- Counting -------------------------------------------------------------------
-- | Count the number of elements in array that are equal to the given value.
count :: (Elt a, Eq a) => Array a -> a -> Int
{-# INLINE_BACKEND count #-}
count xs !x = sum (map (tagToInt . fromBool . (==) x) xs)


-- | Count the number of elements in segments that are equal to the given value.
count_s :: (Elt a, Eq a) => Segd -> Array a -> a -> Array Int
{-# INLINE_BACKEND count_s #-}
count_s segd xs !x = sum_s segd (map (tagToInt . fromBool . (==) x) xs)


{-# RULES

"count/seq" forall xs x y. seq (count xs x) y = seq xs (seq x y)

  #-}


-- Random Arrays --------------------------------------------------------------
randoms :: (Elt a, System.Random.Random a, System.Random.RandomGen g)
        => Int -> g -> Array a
{-# INLINE_BACKEND randoms #-}

randomRs :: (Elt a, System.Random.Random a, System.Random.RandomGen g)
          => Int -> (a,a) -> g -> Array a
{-# INLINE_BACKEND randomRs #-}


-- Array IO -------------------------------------------------------------------
instance IOElt Int
instance IOElt Double
instance (IOElt a, IOElt b) => IOElt (a, b)


-- | Write an array to a file.
hPut :: IOElt a => Handle -> Array a -> IO ()
{-# INLINE_BACKEND hPut #-}


-- | Read an array from a file.
hGet :: IOElt a => Handle -> IO (Array a)
{-# INLINE_BACKEND hGet #-}


-- | Convert an array to a list of elements.
toList :: Elt a => Array a -> [a]
{-# INLINE_BACKEND toList #-}


-- | Convert a list of elements to an array.
fromList :: Elt a => [a] -> Array a
{-# INLINE_BACKEND fromList #-}


-- Aliases for primitive operations -------------------------------------------
dph_mod_index :: Int -> Int -> Int
{-# INLINE_BACKEND dph_mod_index #-}
dph_mod_index by idx = idx `GHC.Base.remInt` by

dph_plus :: Int -> Int -> Int
{-# INLINE_BACKEND dph_plus #-}
dph_plus x y = x Prelude.+ y

{-# RULES

"dph_plus" forall m n.
  dph_plus (GHC.Base.I# m) (GHC.Base.I# n) = GHC.Base.I# m Prelude.+ GHC.Base.I# n

  #-}

dph_mult :: Int -> Int -> Int
{-# INLINE_BACKEND dph_mult #-}
dph_mult x y = x Prelude.* y


tagZeroes :: Array Int -> Array Tag
{-# INLINE CONLIKE PHASE_BACKEND tagZeroes #-}
tagZeroes xs = map (\x -> fromBool (x==0)) xs


-------------------------------------------------------------------------------
-- Currently disabled rules
-------------------------------------------------------------------------------

{- RULES

"packByTag/combine2ByTag" forall tags1 xs ys tags2 n.
  packByTag (combine2ByTag tags1 xs ys) tags2 n
    = combine2ByTag (packByTag tags1 tags2 n)
                    (packByTag xs (packByTag tags2 tags1 0) n)
                    (packByTag ys (packByTag tags2 tags1 1) n)

  -}