packages feed

camfort-0.804: tests/Camfort/Specification/Stencils/ModelSpec.hs

{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE ImplicitParams #-}

module Camfort.Specification.Stencils.ModelSpec (spec) where

import Camfort.Helpers.Vec
import Camfort.Specification.Stencils
import Camfort.Specification.Stencils.Synthesis
import Camfort.Specification.Stencils.Model
import Camfort.Specification.Stencils.Syntax hiding (Spec)
import qualified Camfort.Specification.Stencils.Syntax as Syn

import Camfort.Analysis.Annotations
import qualified Language.Fortran.AST as F
import Language.Fortran.Util.Position

import Data.Bits
import Data.List
import Data.Map hiding (map)

import Test.Hspec
import Test.QuickCheck
import Test.Hspec.QuickCheck

spec :: Spec
spec = do
  describe "Stencils - Model" $ do
    describe "Test soundness of model 1" $ modelHasLeftInverse
    describe "Test soundness of model 2" $ modelHasApproxLeftInverse variations2
    describe "Test soundness of model 3" $ modelHasApproxLeftInverse variations3

  describe "Consistency of model with paper" $ do
    describe "Quickcheck" $ it "" $ property $ propPairwisePerm

    describe "Manual for absolute rep" $ do
      it "Check absolute rep (0)" $
                   (sort $ pp           [1,2,absoluteRep] [5,1,7])
        `shouldBe` (sort $ pairwisePerm [1,2,absoluteRep] [5,1,7])

      it "Check absolute rep (1)" $
                   (sort $ pp           [1,absoluteRep] [5,1])
        `shouldBe` (sort $ pairwisePerm [1,absoluteRep] [5,1])

      it "Check absolute rep (2)" $
                   (sort $ pp           [absoluteRep,2,absoluteRep] [absoluteRep,1,7])
        `shouldBe` (sort $ pairwisePerm [absoluteRep,2,absoluteRep] [absoluteRep,1,7])


propPairwisePerm :: [Int] -> [Int] -> Bool
propPairwisePerm x y = if (length x == length y && length x < 16)
                         then (sort . nub $ pp x y)
                           == (sort . nub $ pairwisePerm x y)
                         else True

pp :: [Int] -> [Int] -> [[Int]]
pp x y =
 let n = length x
 in map (\i ->
     map (\j ->
          ((x !! j) `times` (not (testBit i j))
   `plus` ((y !! j) `times` testBit i j))
          ) [0..(n-1)]
       ) [0 :: Int .. ((2^n)-1)]
    where times x True = x
          times x False = 0
          plus x y = x + y


variations :: [([[Int]], Syn.Result Spatial)]
variations =
  [ ([ [1], [0] ],
    Exact $ Spatial NonLinear (Sum [Product [Forward 1 1 True]]))

  , ([ [absoluteRep,1], [absoluteRep,0] ],
    Exact $ Spatial NonLinear (Sum [Product [Forward 1 2 True]]))

  , ([ [1,1], [0,1], [1,0], [0,0] ],
    Exact $ Spatial NonLinear (Sum [Product [Forward 1 1 True, Forward 1 2 True]]))

  , ([ [-1, 1], [0, 1] ],
    Exact $ Spatial NonLinear (Sum [Product [Backward 1 1 True, Forward 1 2 False]]))

  , ([ [-1], [0] ],
    Exact $ Spatial NonLinear (Sum [Product [Backward 1 1 True]]))

  , ([ [absoluteRep,-1], [absoluteRep,0] ],
    Exact $ Spatial NonLinear (Sum [Product [Backward 1 2 True]]))

  , ([ [-1,-1], [0,-1], [-1,0], [0,0] ],
    Exact $ Spatial NonLinear (Sum [Product [Backward 1 1 True, Backward 1 2 True]]))

  , ( [ [0,-1], [1,-1], [0,0], [1,0], [1,1], [0,1], [2,-1], [2,0], [2,1] ],
    Exact $ Spatial NonLinear
              (Sum [Product [ Forward 2 1 True, Centered 1 2 True ] ] ))

  , ( [ [-1,0], [-1,1], [0,0], [0,1], [1,1], [1,0], [-1,2], [0,2], [1,2] ],
    Exact $ Spatial NonLinear
              (Sum [Product [ Forward 2 2 True, Centered 1 1 True ] ] ))
 ]

variations2 :: [(Syn.Result [[Int]], Int, Syn.Result Spatial)]
variations2 =
  [
  -- Stencil which has some absolute component (not represented in the spec)
    (Exact [ [0, absoluteRep], [1, absoluteRep] ], 2,
    Exact $ Spatial NonLinear (Sum [Product [Forward 1 1 True]]))

 -- Spec on bounds
 ,  (Bound Nothing (Just $ [ [0, absoluteRep], [1, absoluteRep],
                             [2, absoluteRep] ]), 2,
     Bound Nothing
           (Just $ Spatial NonLinear (Sum [Product [Forward 2 1 True]])))
 ]

variations3 :: [(Syn.Result [[Int]], Int, Syn.Result Spatial)]
variations3 =
  [
 -- Spec on bounds
    (Bound Nothing (Just $ [ [0, absoluteRep, 0], [1, absoluteRep, 0],
                             [2, absoluteRep, 0],
                             [0, absoluteRep, 1], [1, absoluteRep, 1],
                             [2, absoluteRep, 1]]), 3,
     Bound Nothing
           (Just $ Spatial NonLinear (Sum [Product [Forward 1 3 True, Forward 2 1 True]])))
  ]

modelHasLeftInverse = mapM_ check (zip variations [0..])
  where check ((ixs, spec), n) = it ("("++show n++")") $ sort mdl `shouldBe` sort ixs
          where mdl = map fst . toList . fromExact . model $ spec

modelHasApproxLeftInverse vars = mapM_ check (zip vars [(0 :: Int)..])
  where check ((ixs, dims, spec), n) =
          it ("("++show n++")") $ mdl' `shouldBe` (fmap sort ixs)
            where mdl = let ?globalDimensionality = dims in mkModel spec
                  mdl' = fmap (sort . map fst . toList) mdl