packages feed

blas-0.7: tests/STVector.hs

{-# LANGUAGE Rank2Types, ScopedTypeVariables #-}
module STVector ( tests_STVector ) where


import Data.Elem.BLAS
import Data.Vector.Dense
import Data.Vector.Dense.ST

import qualified Test.Vector.Dense as Test

import Driver



---------------------------- Creating Vectors --------------------------------

newVector_S n ies = 
    (snd . unzip) $ sortAssocs $ 
        unionBy ((==) `on` fst) 
                (nubAssocs ies)
                (zip [0..(n-1)] (repeat 0))
  where
    nubAssocs = reverse . nubBy ((==) `on` fst) . reverse      
    sortAssocs = sortBy (comparing fst)

prop_NewVector (Assocs n ies) =
    newVector n ies `equivalent` newVector_S n ies

newListVector_S n es = take n $ es ++ repeat 0
prop_NewListVector (Nat n) es =
    newListVector n es `equivalent` newListVector_S n es


---------------------- Reading and Writing Elements --------------------------

getSize_S x = ( length x, x )
prop_GetSize = getSize `implements` getSize_S

readElem_S x i = ( x !! i, x )
prop_ReadElem (Index i n) =
    implementsFor n (`readElem` i) (`readElem_S` i)

canModifyElem_S x i = ( True, x )
prop_CanModifyElem i = (`canModifyElem` i) `implements` (`canModifyElem_S` i)

writeElem_S x i e = ( (), take i x ++ [e] ++ drop (i+1) x )
prop_WriteElem (Index i n) e =
    implementsFor n (\x -> writeElem x i e) (\x -> writeElem_S x i e)

modifyElem_S x i f = writeElem_S x i $ f (x!!i)
prop_ModifyElem (Index i n) f =
    implementsFor n (\x -> modifyElem x i f) (\x -> modifyElem_S x i f)

getIndices_S x = ( [0..(length x - 1)], x )
prop_GetIndicesLazy = getIndices `implements` getIndices_S
prop_GetIndicesStrict = getIndices' `implements` getIndices_S

getElemsLazyModifyWith_S f x = ( y, y ) where y = map f x
prop_GetElemsLazyModifyWith f = 
    (\x -> do { es <- getElems x ; modifyWith f x ; return es })
    `implements` 
    getElemsLazyModifyWith_S f

getElemsStrictModifyWith_S f x = ( x, y ) where y = map f x
prop_GetElemsStrictModifyWith f =
    (\x -> do { es <- getElems' x ; modifyWith f x ; return es })
    `implements` 
    getElemsStrictModifyWith_S f

getAssocsLazyModifyWith_S f x = ( zip [0..] y, y ) where y = map f x
prop_GetAssocsLazyModifyWith f =
    (\x -> do { ies <- getAssocs x ; modifyWith f x ; return ies })
    `implements` 
    getAssocsLazyModifyWith_S f

getAssocsStrictModifyWith_S f x = ( zip [0..] x, y ) where y = map f x
prop_GetAssocsStrictModifyWith f =
    (\x -> do { ies <- getAssocs' x ; modifyWith f x ; return ies })
    `implements` 
    getAssocsStrictModifyWith_S f


----------------------------- Special Vectors --------------------------------

newZeroVector_S n = replicate n 0
prop_NewZeroVector (Nat n) = 
    newZeroVector n `equivalent` newZeroVector_S n

setZero_S x = ( (), newZeroVector_S (length x) )
prop_SetZero = setZero `implements` setZero_S

newConstantVector_S n e = replicate n e
prop_NewConstantVector (Nat n) e = 
    newConstantVector n e `equivalent` newConstantVector_S n e

setConstant_S e x = ( (), newConstantVector_S (length x) e )
prop_SetConstant e = setConstant e `implements` setConstant_S e

newBasisVector_S n i = replicate i 0 ++ [1] ++ replicate (n-i-1) 0
prop_NewBasisVector (Index i n) = 
    newBasisVector n i `equivalent` newBasisVector_S n i

setBasisVector_S i x = ( (), newBasisVector_S (length x) i )
prop_SetBasisVector (Index i n) = 
    implementsFor n (setBasisVector i) (setBasisVector_S i)


----------------------------- Copying Vectors --------------------------------

newCopyVector_S x = ( x, x )
prop_NewCopyVector = 
    (\x -> newCopyVector x >>= abstract) `implements` newCopyVector_S

copyVector_S x y = ( (), y, y )
prop_CopyVector = copyVector `implements2` copyVector_S

swapVector_S x y = ( (), y, x )
prop_SwapVector = swapVector `implements2` swapVector_S


-------------------------- Unsary Vector Operations --------------------------

doConj_S x = ( (), map conjugate x )
prop_DoConj = doConj `implements` doConj_S

scaleBy_S k x = ( (), map (k*) x )
prop_ScaleBy k = scaleBy k `implements` scaleBy_S k

shiftBy_S k x = ( (), map (k+) x )
prop_ShiftBy k = shiftBy k `implements` shiftBy_S k

modifyWith_S f x = ( (), map f x )
prop_ModifyWith f = modifyWith f `implements` modifyWith_S f

getConjVector_S x = ( map conjugate x, x )
prop_GetConjVector = 
    (\x -> getConjVector x >>= abstract) `implements` getConjVector_S

getScaledVector_S k x = ( map (k*) x, x )
prop_GetScaledVector k = 
    (\x -> getScaledVector k x >>= abstract) `implements` (getScaledVector_S k)

getShiftedVector_S k x = ( map (k+) x, x )
prop_GetShiftedVector k = 
    (\x -> getShiftedVector k x >>= abstract) `implements` (getShiftedVector_S k)


------------------------- Binary Vector Operations ---------------------------

addVector_S x y = ( (), zipWith (+) x y, y )
prop_AddVector = addVector `implements2` addVector_S

subVector_S x y = ( (), zipWith (-) x y, y )
prop_SubVector = subVector `implements2` subVector_S

axpyVector_S alpha x y = ( (), x, zipWith (\xi yi -> alpha * xi + yi) x y )
prop_AxpyVector alpha = axpyVector alpha `implements2` axpyVector_S alpha

mulVector_S x y = ( (), zipWith (*) x y, y )
prop_MulVector = mulVector `implements2` mulVector_S

divVector_S x y = ( (), zipWith (/) x y, y )
prop_DivVector = divVector `implements2` divVector_S

getAddVector_S x y = ( zipWith (+) x y, x, y )
prop_GetAddVector =
    (\x y -> getAddVector x y >>= abstract) `implements2` getAddVector_S

getSubVector_S x y = ( zipWith (-) x y, x, y )
prop_GetSubVector =
    (\x y -> getSubVector x y >>= abstract) `implements2` getSubVector_S

getMulVector_S x y = ( zipWith (*) x y, x, y )
prop_GetMulVector =
    (\x y -> getMulVector x y >>= abstract) `implements2` getMulVector_S

getDivVector_S x y = ( zipWith (/) x y, x, y )
prop_GetDivVector =
    (\x y -> getDivVector x y >>= abstract) `implements2` getDivVector_S


-------------------------- Vector Properties ---------------------------------

getSumAbs_S x = ( foldl' (+) 0 $ map norm1 x, x )
prop_GetSumAbs = getSumAbs `implements` getSumAbs_S

getNorm2_S x = ( sqrt $ foldl' (+) 0 $ map (**2) $ map norm x, x )
prop_GetNorm2 = getNorm2 `implements` getNorm2_S

getWhichMaxAbs_S x = ( (i,x!!i), x) 
    where i = fst $ maximumBy (comparing snd) $ reverse $ zip [0..] $ map norm1 x
prop_GetWhichMaxAbs = 
    implementsIf (return . (>0) . dim) getWhichMaxAbs getWhichMaxAbs_S

getDot_S x y = ( foldl' (+) 0 $ zipWith (*) (map conjugate x) y, x, y )
prop_GetDot = getDot `implements2` getDot_S


------------------------------------------------------------------------
-- 
-- The specification language
--
    
abstract :: (BLAS1 e) => STVector s n e -> ST s [e]
abstract = getElems'

commutes :: (AEq a, Show a, AEq e, BLAS1 e) =>
    STVector s n e -> (STVector s n e -> ST s a) ->
        ([e] -> (a,[e])) -> ST s Bool
commutes x a f = do
    old <- abstract x
    r <- a x
    new <- abstract x
    let s      = f old
        s'     = (r,new)
        passed = s ~== s'
        
    when (not passed) $
        trace (printf ("expected `%s' but got `%s'") (show s) (show s'))
              return ()
              
    return passed

commutes2 :: (AEq a, Show a, AEq e, BLAS1 e) =>
    STVector s n e -> STVector s n e -> 
    (STVector s n e ->  STVector s n e -> ST s a) ->
        ([e] -> [e] -> (a,[e],[e])) -> ST s Bool
commutes2 x y a f = do
    oldX <- abstract x
    oldY <- abstract y
    r <- a x y
    newX <- abstract x
    newY <- abstract y
    let s      = f oldX oldY
        s'     = (r,newX,newY)
        passed = s ~== s'
        
    when (not passed) $
        trace (printf ("expected `%s' but got `%s'") (show s) (show s'))
            return ()
            
    return passed

equivalent :: (forall s . ST s (STVector s n E)) -> [E] -> Bool
equivalent x s = runST $ do
    x' <- (x >>= abstract)
    when (not $ x' === s) $
        trace (printf ("expected `%s' but got `%s'") (show s) (show x'))
            return ()
    return (x' === s)
    
implements :: (AEq a, Show a) =>
    (forall s . STVector s n E -> ST s a) ->
    ([E] -> (a,[E])) -> 
        Property
a `implements` f =
    forAll arbitrary $ \(Nat n) ->
        implementsFor n a f

implements2 :: (AEq a, Show a) =>
    (forall s . STVector s n E -> STVector s n E -> ST s a) ->
    ([E] -> [E] -> (a,[E],[E])) -> 
        Property
a `implements2` f =
    forAll arbitrary $ \(Nat n) ->
        implementsFor2 n a f

implementsFor :: (AEq a, Show a) =>
    Int ->
    (forall s . STVector s n E -> ST s a) ->
    ([E] -> (a,[E])) -> 
        Property
implementsFor n a f =
    forAll (Test.vector n) $ \x ->
        runST $ do
            x' <- unsafeThawVector x
            commutes x' a f

implementsFor2 :: (AEq a, Show a) =>
    Int ->
    (forall s . STVector s n E -> STVector s n E -> ST s a) ->
    ([E] -> [E] -> (a,[E],[E])) -> 
        Property
implementsFor2 n a f =
    forAll (Test.vector n) $ \x ->
    forAll (Test.vector n) $ \y ->
        runST $ do
            x' <- unsafeThawVector x
            y' <- unsafeThawVector y
            commutes2 x' y' a f

implementsIf :: (AEq a, Show a) =>
    (forall s . STVector s n E -> ST s Bool) ->
    (forall s . STVector s n E -> ST s a) ->
    ([E] -> (a,[E])) -> 
        Property
implementsIf pre a f =
    forAll arbitrary $ \(Nat n) ->
    forAll (Test.vector n) $ \x ->
        runST ( do
            x' <- thawVector x
            pre x') ==>
        runST ( do
            x' <- unsafeThawVector x
            commutes x' a f )

implementsIf2 :: (AEq a, Show a) =>
    (forall s . STVector s n E -> STVector s n E -> ST s Bool) ->
    (forall s . STVector s n E -> STVector s n E -> ST s a) ->
    ([E] -> [E] -> (a,[E],[E])) -> 
        Property
implementsIf2 pre a f =
    forAll arbitrary $ \(Nat n) ->
    forAll (Test.vector n) $ \x ->
    forAll (Test.vector n) $ \y ->
        runST ( do
            x' <- thawVector x
            y' <- thawVector y
            pre x' y') ==>
        runST ( do
            x' <- unsafeThawVector x
            y' <- unsafeThawVector y
            commutes2 x' y' a f )

            
------------------------------------------------------------------------

tests_STVector =
    [ ("newVector", mytest prop_NewVector)
    , ("newListVector", mytest prop_NewListVector)
    
    , ("getSize", mytest prop_GetSize)
    , ("readElem", mytest prop_ReadElem)
    , ("canModifyElem", mytest prop_CanModifyElem)
    , ("writeElem", mytest prop_WriteElem)
    , ("modifyElem", mytest prop_ModifyElem)

    , ("getIndices", mytest prop_GetIndicesLazy)
    , ("getIndices'", mytest prop_GetIndicesStrict)
    , ("getElems", mytest prop_GetElemsLazyModifyWith)
    , ("getElems'", mytest prop_GetElemsStrictModifyWith)
    , ("getAssocs", mytest prop_GetAssocsLazyModifyWith)
    , ("getAssocs'", mytest prop_GetAssocsStrictModifyWith)

    , ("newZeroVector", mytest prop_NewZeroVector)
    , ("setZero", mytest prop_SetZero)
    , ("newConstantVector", mytest prop_NewConstantVector)
    , ("setConstant", mytest prop_SetConstant)
    , ("newBasisVector", mytest prop_NewBasisVector)
    , ("setBasisVector", mytest prop_SetBasisVector)
    
    , ("newCopyVector", mytest prop_NewCopyVector)
    , ("copyVector", mytest prop_CopyVector)
    , ("swapVector", mytest prop_SwapVector)

    , ("doConj", mytest prop_DoConj)
    , ("scaleBy", mytest prop_ScaleBy)
    , ("shiftBy", mytest prop_ShiftBy)
    , ("modifyWith", mytest prop_ModifyWith)
    
    , ("getConjVector", mytest prop_GetConjVector)
    , ("getScaledVector", mytest prop_GetScaledVector)
    , ("getShiftedVector", mytest prop_GetShiftedVector)

    , ("addVector", mytest prop_AddVector)
    , ("subVector", mytest prop_SubVector)
    , ("axpyVector", mytest prop_AxpyVector)
    , ("mulVector", mytest prop_MulVector)
    , ("divVector", mytest prop_DivVector)
    
    , ("getAddVector", mytest prop_GetAddVector)
    , ("getSubVector", mytest prop_GetSubVector)
    , ("getMulVector", mytest prop_GetMulVector)
    , ("getDivVector", mytest prop_GetDivVector)

    , ("getSumAbs", mytest prop_GetSumAbs)
    , ("getNorm2", mytest prop_GetNorm2)
    , ("getWhichMaxAbs", mytest prop_GetWhichMaxAbs)
    , ("getDot", mytest prop_GetDot)

    ]