packages feed

syntactic-0.7: CEFP/Examples/SolutionsSec2.hs

module Main where

import qualified Prelude

import MuFeldspar.Prelude


import MuFeldspar.Core
--import MuFeldspar.Tuple
import MuFeldspar.Frontend
import MuFeldspar.Vector


import Imperative.Imperative
import Imperative.Compiler

import Data.Word
import Data.Bits (Bits)

type VecBool = Vector (Data Bool)

type VecInt = Vector (Data Int)



-- Exercise 1

composeN :: (Syntax st) => (st -> st) -> Data Length -> st -> st
composeN f l i0 = forLoop l i0 g
  where
    g _ st = f st

tri :: (Syntax a) => (a -> a)  -> Vector a -> Vector a
tri f (Indexed len ixf) = indexed len ixf'
  where
    ixf' i = composeN f i (ixf i)


tri1 :: (Syntax a) => (a -> a)  -> Vector a -> Vector a
tri1 f (Indexed len ixf) = indexed len ixf'
  where
    ixf' i = forLoop i (ixf i) (\_ -> f)


{--
*Main> eval $ tri (*2) (1...6)
[1,4,12,32,80,192]
*Main> eval $ tri1 (*2) (1...6)
[1,4,12,32,80,192]
--}


-- Exercise 2

swapOE1 :: (Syntax a) => Vector a -> Vector a
swapOE1 v = Indexed (length v) ixf
  where
    ixf i = (i `mod` 2 == 0) ? (index v (i+1), index v (i-1))

-- same as above
swapOE2 :: Vector a -> Vector a
swapOE2 = premap (\i -> (i `mod` 2 == 0) ?  (i+1,i-1))

swapOE3 :: Vector a -> Vector a
swapOE3 = premap (`xor` 1)

premap :: (Data Index -> Data Index) -> Vector a -> Vector a
premap f (Indexed l ixf) = Indexed l (ixf . f)



-- Exercise 3

pows2 :: Data Int -> Vector (Data Int)
pows2 k = Indexed k (2^)    



pow2 :: Data Index -> Data Index
pow2 k = 1 << k                   -- or  2^k    

pows21 :: Data Length -> Vector (Data Index)
pows21 k = Indexed k pow2   





-- Exercise 4

pad :: Data Length -> VecBool -> VecBool
pad l v = (replicate (l - length v) false) ++ v

xorBool :: Data Bool -> Data Bool -> Data Bool
xorBool a b = not (a == b)

crcAdd :: VecBool -> VecBool -> VecBool
crcAdd as bs = zipWith xorBool (pad m as) (pad m bs)
  where
    m = max (length as) (length bs)






-- Exercise 5

-- direct implementation using reverseBits
bitr :: Data Index -> Data Index -> Data Index
bitr n a =
    share (oneBitsN n) $ \mask -> (complement mask .&. a) .|. rev mask
  where
    rev mask = rotateL (reverseBits (mask .&. a)) n

bitRev :: Data Index -> Vector a -> Vector a
bitRev n = premap (bitr n)

oneBitsN :: Data Index -> Data Index
oneBitsN  = complement . zeroBitsN

zeroBitsN :: Data Index -> Data Index
zeroBitsN = shiftL allOnes

allOnes :: Data Index
allOnes = complement 0



bitrH :: Index -> Data Index -> Data Index
bitrH n  a =
    share (oneBitsN vn) $ \mask -> (complement mask .&. a) .|. rev mask
  where
    rev mask = rotateL (reverseBits (mask .&. a)) vn
    vn = value n





-- transliteration of solution from bithacks
bitr1 :: Data Index -> Data Index -> Data Index
bitr1 n i = snd (pipe stage (countUp n) (i, i >> n))
  where
    stage _ (i,r) = (i>>1, (i .&. 1) .|. (r<<1))

bitRev1 :: Data Index -> Vector a -> Vector a
bitRev1 n = premap (bitr1 n)

countUp :: Data Length -> Vector (Data Index)
countUp n = Indexed n id

pipe :: Syntax a => (Data Index -> a -> a) -> Vector (Data Index) -> a -> a
pipe = flip . fold . flip 



-- A version of composeN that depends on a *Haskell* value

composeNH :: Index -> (a -> a) -> a -> a
composeNH 0 f = id
composeNH n f = (composeNH (n-1) f) . f


-- Now use this to make bitr. Note the type.

bitr1H :: Index -> Data Index -> Data Index
bitr1H n i = snd (composeNH n stage (i, i >> vn))
  where
    stage (i,r) = (i>>1, (i .&. 1) .|. (r<<1))
    vn = value n


-- Now we must provide the n parameter at compile time
-- and the recursion gets unwound

{--

main (v0)
  x3 := v0
  x4 := 1 :: Int
  x2 := (shiftR x3 x4)
  x5 := 1 :: Int
  x1 := (shiftR x2 x5)
  x6 := 1 :: Int
  x0 := (x1 .&. x6)
  x11 := v0
  x12 := 1 :: Int
  x10 := (shiftR x11 x12)
  x13 := 1 :: Int
  x9 := (x10 .&. x13)
  x17 := v0
  x18 := 1 :: Int
  x16 := (x17 .&. x18)
  x21 := v0
  x22 := 3 :: Int
  x20 := (shiftR x21 x22)
  x23 := 1 :: Int
  x19 := (shiftL x20 x23)
  x15 := (x16 .|. x19)
  x24 := 1 :: Int
  x14 := (shiftL x15 x24)
  x8 := (x9 .|. x14)
  x25 := 1 :: Int
  x7 := (shiftL x8 x25)
  out := (x0 .|. x7)


Compare with  printMain $ bitr1
which gives the expected for loop

main (v0,v1)
  x1 := v0
  x2 := v1
  x4 := v1
  x5 := v0
  x3 := (shiftR x4 x5)
  v3 := (tup2 x2 x3)

  for v2 in 0 .. (x1-1) do
    x8 := v3
    x7 := (sel1 x8)
    x9 := 1 :: Int
    x6 := (shiftR x7 x9)
    x13 := v3
    x12 := (sel1 x13)
    x14 := 1 :: Int
    x11 := (x12 .&. x14)
    x17 := v3
    x16 := (sel2 x17)
    x18 := 1 :: Int
    x15 := (shiftL x16 x18)
    x10 := (x11 .|. x15)
    v3 := (tup2 x6 x10)
  x0 := v3
  out := (sel2 x0)

--}






specbr m n v = bL2Int (l ++ r')
  where
    iv = int2BLN m v
    (l,r) = splitAt (m-n) iv
    r' = reverse r

testBit :: (Type a, Bits a) => Data a -> Data Index -> Data Bool
testBit l i = not ((l .&. (1<<i)) == 0)


int2BL :: (Type a, Bits a)  =>  Data a -> VecBool
int2BL l = reverse $ indexed (bitSize l) (testBit l)


int2BLN :: Data Length -> Data Int -> VecBool
int2BLN n v = reverse $ indexed n (testBit v)


bL2Int :: VecBool -> Data Int
bL2Int bs = scalarProduct (reverse (map b2i bs)) (pows2 (length bs))

bL2Int' :: VecBool -> Data Int
bL2Int' = sum . tri (*2) . map b2i

scalarProduct :: (Type a, Num a) => Vector (Data a) -> Vector (Data a) -> Data a
scalarProduct as bs = sum (zipWith (*) as bs)





-- Exercise 6   (See slides)

-- 2^n input FFT. Applies to sub-parts of input vector
-- of length 2^(n+i). 
-- There is currently no check that the input vector is at least of length 2^n


countDown n = reverse (indexed n id)

fft :: Data Index ->  Vector (Data Complex) -> Vector (Data Complex)
fft n = bitRev n . lin stage (countDown n)
  where
    stage k = combx f g (bitZero k) (flipBit k) twid 
      where
        f a b _ = a + b
        g a b t = t * (a-b)
        twid i  = cis ((-(value pi)*(i2n (lsbsN k i)))/  i2n (pow2 k))



combx f g c p x (Indexed l ixf) =  Indexed l ixf'
      where
        ixf' i = (c i) ? (f ai pi xi, g pi ai xi)
          where
            ai = ixf i
            pi = ixf (p i)
            xi = x i




lin :: Syntax a => (b -> a -> a) -> Vector b -> a -> a
lin f (Indexed len ixf) a = forLoop len a (\i st -> f (ixf i) st)

lsbsN :: Data Index -> Data Index -> Data Index
lsbsN k i = i .&. oneBitsN k

bitZero :: Data Index -> Data Index -> Data Bool
bitZero k i = (i .&. (1<<k)) == 0

flipBit ::  Data Index -> Data Index -> Data Index
flipBit k = (`xor` (1<<k))




-- Exercise 7 bitonic sort

-- bitonic merge (see slides)

comb :: (Syntax a) =>
        (t -> t -> a) -> (t -> t -> a)
         -> (Data Index -> Data Bool) -> (Data Index -> Data Index)
         -> Vector t 
         -> Vector a
comb f g c p (Indexed l ixf) = Indexed l ixf'
  where
    ixf' i = (c i) ? (f a b, g a b)
      where
        a = ixf i
        b = ixf (p i)

apart :: (Syntax a) =>
         (t -> t -> a) -> (t -> t -> a)
         -> Data Index
         -> Vector t
         -> Vector a
apart f g k = comb f g (bitZero k) (flipBit k)






bMerge :: Data Index -> Vector (Data Int) -> Vector (Data Int)
bMerge n = lin (apart min max) (countDown n)
  

-- now we'd like to be able to reverse half of each 2^n length sub-vector

halfRev :: Data Index -> Vector (Data a) -> Vector (Data a)
halfRev n = premap (\i -> (bitZero n' i) ? (i ,i `xor` oneBitsN n'))
  where
    n' = n-1


merge :: Data Index -> Vector (Data Int) -> Vector (Data Int)
merge n = bMerge n . halfRev n 

bsort :: Data Index -> Vector (Data Int) -> Vector (Data Int)
bsort n = lin merge (1...n)