module Camfort.Specification.Stencils.Syntax where
import Camfort.Helpers
import Prelude hiding (sum)
import Data.Data
import Data.Generics.Uniplate.Data
import Data.List hiding (sum)
import Data.Function
import Data.Maybe
import Debug.Trace
import Control.Applicative
type Variable = String
data Result a =
Exact a | Bound (Maybe a) (Maybe a)
deriving (Eq, Data, Typeable, Show)
fromExact :: Result a -> a
fromExact (Exact a) = a
fromExact _ = error "Exception: fromExact on a non-exact result"
upperBound :: a -> Result a
upperBound x = Bound Nothing (Just x)
lowerBound :: a -> Result a
lowerBound x = Bound (Just x) Nothing
instance Functor Result where
fmap f (Exact x) = Exact (f x)
fmap f (Bound x y) = Bound (fmap f x) (fmap f y)
absoluteRep = 100 :: Int
type RegionEnv = [(String, RegionSum)]
type SpecDecls = [([String], Specification)]
pprintSpecDecls :: SpecDecls -> String
pprintSpecDecls =
concatMap (\(names, spec) ->
show spec ++ " :: " ++ (intercalate "," names) ++ "\n")
lookupAggregate :: Eq a => [([a], b)] -> a -> [b]
lookupAggregate [] _ = []
lookupAggregate ((names, spec) : ss) name =
if name `elem` names
then spec : lookupAggregate ss name
else lookupAggregate ss name
data Specification =
Specification (Either (Result Spatial) Temporal)
deriving (Eq, Data, Typeable)
data Temporal = Dependency [String] Bool
deriving (Eq, Data, Typeable)
data Spatial =
Spatial { modLinearity :: Linearity,
region :: RegionSum }
deriving (Eq, Data, Typeable)
fromBool :: Bool -> Linearity
fromBool True = NonLinear
fromBool False = Linear
hasDuplicates :: Eq a => [a] -> ([a], Bool)
hasDuplicates xs = (nub xs, nub xs /= xs)
setLinearity :: Linearity -> Specification -> Specification
setLinearity l (Specification (Left (Exact s))) =
Specification (Left (Exact (s { modLinearity = l })))
setLinearity l (Specification (Left (Bound sl su))) =
Specification (Left (Bound (sl >>= \s -> return $ s { modLinearity = l })
(su >>= \s -> return $ s { modLinearity = l })))
setLinearity l s = s
emptySpec = Specification . Left $ (one :: Result Spatial)
emptySpatialSpec = one :: Spatial
isEmpty :: Specification -> Bool
isEmpty (Specification (Right (Dependency [] _))) = True
isEmpty (Specification (Left s)) = isUnit s
data Linearity = Linear | NonLinear deriving (Eq, Data, Typeable)
type Dimension = Int
type Depth = Int
type IsRefl = Bool
data Region where
Forward :: Depth -> Dimension -> IsRefl -> Region
Backward :: Depth -> Dimension -> IsRefl -> Region
Centered :: Depth -> Dimension -> IsRefl -> Region
deriving (Eq, Data, Typeable)
getDimension :: Region -> Dimension
getDimension (Forward _ dim _) = dim
getDimension (Backward _ dim _) = dim
getDimension (Centered _ dim _) = dim
instance Ord Region where
(Forward dep dim _) <= (Forward dep' dim' _)
| dep == dep' = dim <= dim'
| otherwise = dep <= dep'
(Backward dep dim _) <= (Backward dep' dim' _)
| dep == dep' = dim <= dim'
| otherwise = dep <= dep'
(Centered dep dim _) <= (Centered dep' dim' _)
| dep == dep' = dim <= dim'
| otherwise = dep <= dep'
(Forward _ _ _) <= _ = True
(Backward _ _ _) <= (Centered _ _ _) = True
_ <= _ = False
newtype RegionProd = Product {unProd :: [Region]}
deriving (Eq, Data, Typeable)
newtype RegionSum = Sum {unSum :: [RegionProd]}
deriving (Eq, Data, Typeable)
instance Ord RegionProd where
(Product xs) <= (Product xs') = xs <= xs'
specPlus :: Specification -> Specification -> Maybe Specification
specPlus (Specification (Left (Bound (Just l) Nothing)))
(Specification (Left (Bound Nothing (Just u)))) =
Just $ Specification (Left (Bound (Just l) (Just u)))
specPlus (Specification (Left (Bound Nothing (Just u))))
(Specification (Left (Bound (Just l) Nothing))) =
Just $ Specification (Left (Bound (Just l) (Just u)))
specPlus (Specification (Left (Bound (Just l1) Nothing)))
(Specification (Left (Bound (Just l2) Nothing))) =
Just $ Specification (Left (Bound (Just $ l1 `sum` l2) Nothing))
specPlus (Specification (Left (Bound Nothing (Just l1))))
(Specification (Left (Bound Nothing (Just l2)))) =
Just $ Specification (Left (Bound Nothing (Just $ l1 `sum` l2)))
specPlus (Specification (Left (Exact s1))) (Specification (Left (Exact s2))) =
Just $ Specification (Left (Exact $ s1 `sum` s2))
specPlus (Specification (Right (Dependency vs1 m1)))
(Specification (Right (Dependency vs2 m2))) | m1 == m2=
Just $ Specification (Right (Dependency (vs1 ++ vs2) m1))
specPlus _ _ = Nothing
regionPlus :: Region -> Region -> Maybe Region
regionPlus (Forward dep dim reflx) (Backward dep' dim' reflx')
| dep == dep' && dim == dim' = Just $ Centered dep dim (reflx || reflx')
regionPlus (Backward dep dim reflx) (Forward dep' dim' reflx')
| dep == dep' && dim == dim' = Just $ Centered dep dim (reflx || reflx')
regionPlus x y | x == y = Just x
regionPlus x y = Nothing
instance PartialMonoid RegionProd where
emptyM = Product []
appendM (Product []) s = Just s
appendM s (Product []) = Just s
appendM (Product [s]) (Product [s']) =
regionPlus s s' >>= (\sCombined -> return $ Product [sCombined])
appendM (Product ss) (Product ss')
| ss == ss' = Just $ Product ss
| otherwise =
case absorbReflexive ss ss' of
Just (ss0, ss1) ->
case distAndOverlaps ss0 ss1 of
Just ss'' -> return $ Product $ sort ss''
Nothing -> return $ Product $ sort (ss0 ++ ss1)
Nothing -> case distAndOverlaps ss ss' of
Just ss'' -> return $ Product $ sort ss''
Nothing -> Nothing
absorbReflexive :: [Region] -> [Region] -> Maybe ([Region], [Region])
absorbReflexive a b =
absorbReflexive' (sortBy cmpDims a) (sortBy cmpDims b)
<|> absorbReflexive' (sortBy cmpDims b) (sortBy cmpDims a)
where cmpDims = compare `on` getDimension
absorbReflexive' [] [] = Just ([], [])
absorbReflexive' (Forward d dim reflx : rs) [Centered 0 dim' _]
| dim == dim' = Just ((Forward d dim True):rs, [])
absorbReflexive' (Backward d dim reflx : rs) [Centered 0 dim' _]
| dim == dim' = Just ((Backward d dim True):rs, [])
absorbReflexive' (Centered d dim reflx : rs) [Centered 0 dim' _]
| dim == dim' && d /= 0 = Just ((Centered d dim True):rs, [])
absorbReflexive' _ _ = Nothing
distAndOverlaps :: [Region] -> [Region] -> Maybe [Region]
distAndOverlaps x y =
if length x <= 1 || length y <= 1
then Nothing
else
distAndOverlaps' x y <|> distAndOverlaps' y x
distAndOverlaps' [] xs = Just xs
distAndOverlaps' xs [] = Just xs
distAndOverlaps' (Forward d dim refl : rs) (Forward d' dim' refl' : rs')
| rs == rs' && dim == dim'
= Just (Forward (max d d') dim (refl || refl') : rs)
distAndOverlaps' (Backward d dim refl : rs) (Backward d' dim' refl' : rs')
| rs == rs' && dim == dim'
= Just (Backward (max d d') dim (refl || refl') : rs)
distAndOverlaps' (Centered d dim refl : rs) (Centered d' dim' refl' : rs')
| rs == rs' && dim == dim' && d /= 0 && d' /= 0
= Just (Centered (max d d') dim (refl || refl') : rs)
distAndOverlaps' (Forward d dim refl : rs) (Centered d' dim' refl' : rs')
| rs == rs' && dim == dim' && d <= d' && d' /= 0
= Just (Centered d' dim (refl || refl') : rs)
distAndOverlaps' (Backward d dim refl : rs) (Centered d' dim' refl' : rs')
| rs == rs' && dim == dim' && d <= d' && d' /= 0
= Just (Centered d' dim (refl || refl') : rs)
distAndOverlaps' (Forward d dim reflx : rs) (Backward d' dim' reflx' : rs')
| rs == rs' && d == d' && dim == dim'
= Just (Centered d dim (reflx || reflx') : rs)
distAndOverlaps' (Centered d dim reflx : rs) (Centered 0 dim' True : rs')
| rs == rs' && dim == dim' && d /= 0
= Just (Centered d dim True : rs)
distAndOverlaps' (Forward d dim reflx : rs) (Centered 0 dim' True : rs')
| rs == rs' && dim == dim'
= Just (Forward d dim True : rs)
distAndOverlaps' (Backward d dim reflx : rs) (Centered 0 dim' True : rs')
| rs == rs' && dim == dim'
= Just (Backward d dim True : rs)
distAndOverlaps' p1@(Backward d1 dim1 refl1 : Backward d2 dim2 refl2 : rs)
p2@(Backward d1' dim1' refl1' : Backward d2' dim2' refl2' : rs')
| rs == rs' && dim1 == dim1' && dim2 == dim2'
&& d1 == d1' && d2 == d2' && refl1 == not refl1' && refl2 == not refl2'
= Just $ [Backward d1 dim1 True, Backward d2 dim2 True] ++ rs
| rs == rs' && dim1 == dim2' && dim2 == dim1'
&& d1 == d2' && d2 == d1' && refl1 == not refl2' && refl2 == not refl1'
= Just $ [Backward d1 dim1 True, Backward d2 dim2 True] ++ rs
distAndOverlaps' p1@(Centered d1 dim1 refl1 : Centered d2 dim2 refl2 : rs)
p2@(Centered d1' dim1' refl1' : Centered d2' dim2' refl2' : rs')
| rs == rs' && dim1 == dim1' && dim2 == dim2' && (d1 * d2 * d1' * d2' /= 0)
&& d1 == d1' && d2 == d2' && refl1 == not refl1' && refl2 == not refl2'
= Just $ [Centered d1 dim1 True, Centered d2 dim2 True] ++ rs
| rs == rs' && dim1 == dim2' && dim2 == dim1'
&& d1 == d2' && d2 == d1' && refl1 == not refl2' && refl2 == not refl1'
= Just $ [Centered d1 dim1 True, Centered d2 dim2 True] ++ rs
distAndOverlaps' p1@(Forward d1 dim1 refl1 : Forward d2 dim2 refl2 : rs)
p2@(Forward d1' dim1' refl1' : Forward d2' dim2' refl2' : rs')
| rs == rs' && dim1 == dim1' && dim2 == dim2' && (d1 * d2 * d1' * d2' /= 0)
&& d1 == d1' && d2 == d2' && refl1 == not refl1' && refl2 == not refl2'
= Just $ [Forward d1 dim1 True, Forward d2 dim2 True] ++ rs
| rs == rs' && dim1 == dim2' && dim2 == dim1' && (d1 * d2 * d1' * d2' /= 0)
&& d1 == d2' && d2 == d1' && refl1 == not refl2' && refl2 == not refl1'
= Just $ [Forward d1 dim1 True, Forward d2 dim2 True] ++ rs
distAndOverlaps' (r:rs) (r':rs')
| r == r' = do rs'' <- distAndOverlaps rs rs'
return $ r : rs''
distAndOverlaps' _ _ = Nothing
class RegionRig t where
sum :: t -> t -> t
prod :: t -> t -> t
one :: t
zero :: t
isUnit :: t -> Bool
instance RegionRig a => RegionRig (Maybe a) where
sum (Just x) (Just y) = Just $ sum x y
sum x Nothing = x
sum Nothing x = x
prod (Just x) (Just y) = Just $ prod x y
prod x Nothing = x
prod Nothing x = x
one = Just one
zero = Just zero
isUnit Nothing = True
isUnit (Just x) = isUnit x
instance RegionRig Linearity where
sum Linear Linear = Linear
sum _ _ = NonLinear
prod = sum
one = Linear
zero = Linear
isUnit Linear = True
isUnit _ = False
instance RegionRig Spatial where
sum (Spatial lin s) (Spatial lin' s') =
Spatial (sum lin lin') (sum s s')
prod (Spatial lin s) (Spatial lin' s') =
Spatial (prod lin lin') (prod s s')
one = Spatial one one
zero = Spatial zero zero
isUnit (Spatial _ ss) = isUnit ss
instance RegionRig (Result Spatial) where
sum (Exact s) (Exact s') = Exact (sum s s')
sum (Exact s) (Bound l u) = Bound (sum (Just s) l) (sum (Just s) u)
sum (Bound l u) (Bound l' u') = Bound (sum l l') (sum u u')
sum s s' = sum s' s
prod (Exact s) (Exact s') = Exact (prod s s')
prod (Exact s) (Bound l u) = Bound (prod (Just s) l) (prod (Just s) u)
prod (Bound l u) (Bound l' u') = Bound (prod l l') (prod u u')
prod s s' = prod s' s
one = Exact one
zero = Exact zero
isUnit (Exact s) = isUnit s
isUnit (Bound x y) = isUnit x && isUnit y
instance RegionRig RegionSum where
prod (Sum ss) (Sum ss') =
Sum $ nub $
do (Product spec) <- ss
(Product spec') <- ss'
return $ Product $ nub $ sort $ spec ++ spec'
sum (Sum ss) (Sum ss') = Sum $ normalise $ ss ++ ss'
zero = Sum []
one = Sum [Product []]
isUnit s@(Sum ss) = s == zero || s == one || all ((==) (Product [])) ss
showL :: Show a => [a] -> String
showL = intercalate "," . map show
showProdSpecs, showSumSpecs :: Show a => [a] -> String
showProdSpecs = intercalate "*" . map show
showSumSpecs = intercalate "+" . map show
instance Show Specification where
show (Specification (Left sp)) = "stencil " ++ show sp
show (Specification (Right sp)) = "stencil " ++ show sp
instance Show (Result Spatial) where
show (Exact s) = show s
show (Bound Nothing Nothing) = "empty"
show (Bound Nothing (Just s)) = "atMost, " ++ show s
show (Bound (Just s) Nothing) = "atLeast, " ++ show s
show (Bound (Just sL) (Just sU)) =
"atLeast, " ++ show sL ++ "; atMost, " ++ show sU
instance Show Spatial where
show (Spatial modLin region) =
intercalate ", " . catMaybes $ [lin, sregion]
where
sregion = case show region of
"empty" -> Nothing
xs -> Just xs
lin = case modLin of
NonLinear -> Nothing
Linear -> Just "readOnce"
instance Show Temporal where
show (Dependency vars mutual) =
"dependency (" ++ showL vars ++ ")" ++ if mutual then ", mutual" else ""
instance Show RegionSum where
show (Sum []) = "empty"
show (Sum [Product []]) = "empty"
show (Sum specs) =
intercalate " + " ppspecs
where ppspecs = filter ((/=) "") $ map show specs
instance Show RegionProd where
show (Product []) = ""
show (Product ss) =
intercalate "*" . (map (\s -> "(" ++ show s ++ ")")) $ ss
instance Show Region where
show (Forward dep dim reflx) = showRegion "forward" dep dim reflx
show (Backward dep dim reflx) = showRegion "backward" dep dim reflx
show (Centered dep dim reflx)
| dep == 0 = "reflexive(dim=" ++ show dim ++ ")"
| otherwise = showRegion "centered" dep dim reflx
showRegion typ depS dimS reflx = typ ++ "(depth=" ++ show depS
++ ", dim=" ++ show dimS
++ (if reflx then "" else ", irreflexive")
++ ")"
groupKeyBy :: Eq b => [(a, b)] -> [([a], b)]
groupKeyBy = groupKeyBy' . map (\ (k, v) -> ([k], v))
where
groupKeyBy' [] = []
groupKeyBy' [(ks, v)] = [(ks, v)]
groupKeyBy' ((ks1, v1):((ks2, v2):xs))
| v1 == v2 = groupKeyBy' ((ks1 ++ ks2, v1) : xs)
| otherwise = (ks1, v1) : groupKeyBy' ((ks2, v2) : xs)