fregel-1.2.0: compiler/AggregatorExtraction.hs
{-# Language TypeSynonymInstances,FlexibleInstances,MultiParamTypeClasses,FunctionalDependencies,RankNTypes,FlexibleContexts,KindSignatures,ScopedTypeVariables #-}
{-
Transformation to extract aggregations from complex expressions (and recollect dependency info.?) (5th step).
Assumption:
- no function definition (other than vertex-computation and vertex-initialization)
- unique names
- let-bindings in the order consistent with their dependency
- no nested aggregation
-}
module AggregatorExtraction where
import Spec
import ASTData
import Control.Monad.State
import Data.Maybe
import Data.List
import Numeric (showHex)
import Debug.Trace
-- uniq id, aggregations, in-aggr?, move aggregator flags
type DEnvAE = (DUnique, [DSmplDef DASTData], Bool, [Bool])
class AggExtractable a where
aggExtract :: a -> State DEnvAE a -- returns a transformed expression
aggExtract x = return x -- default
getNewName :: String -> State (DEnvAE) DVarName
getNewName s =
do (i, as, af, mfs) <- get
let (n, i') = genNewName i s
put (i', as, af, mfs)
return n
-- entry point
aggExtraction :: forall (t :: * -> *) a . AggExtractable (t DASTData) => (t DASTData) -> DUnique -> (t DASTData, DUnique)
aggExtraction p uid = let (p', (uid', _, _, _)) = runState (aggExtract p) (uid, [], False, [True])
in (p', uid')
aggExtractionE :: (DExpr DASTData) -> DUnique -> (DExpr DASTData, [DSmplDef DASTData], DUnique)
aggExtractionE e uid = let (e', (uid', defs, _, _)) = runState (aggExtract e) (uid, [], False, [True])
in (e', defs, uid')
-- stores the given definition of a varible binding an aggregation to the env.
addAggDef :: DSmplDef DASTData -> State (DEnvAE) ()
addAggDef agg =
do (d, aggs, b, m) <- get
put (d, agg:aggs, b, m)
popAggDefs :: State DEnvAE ([DSmplDef DASTData])
popAggDefs =
do (d, aggs, f, m) <- get
put (d, [], f, m)
return aggs
unsetInAgg :: State DEnvAE ()
unsetInAgg =
do (d, aggs, _, m) <- get
put (d, aggs, False, m)
setInAgg :: State DEnvAE ()
setInAgg =
do (d, aggs, f, m) <- get
if f then error "nested aggregation is not allowed." else put (d, aggs, True, m)
needsAggMove :: State DEnvAE Bool
needsAggMove =
do x <- get
let (d, aggs, f, m:ms) = x
return m
setNeedsAggMove :: State DEnvAE ()
setNeedsAggMove =
do (d, aggs, f, ms)<- get
put(d, aggs, f, True:ms)
unsetNeedsAggMove :: State DEnvAE ()
unsetNeedsAggMove =
do (d, aggs, f, ms) <- get
put (d, aggs, f, False:ms)
restoreNeedsAggMove :: State DEnvAE ()
restoreNeedsAggMove =
do x <- get
let (d, aggs, f, _:ms) = x
put(d, aggs, f, ms)
instance AggExtractable (DProgramSpec DASTData) where
aggExtract (DProgramSpec rs p a) =
do p' <- aggExtract p
return (DProgramSpec rs p' a)
instance AggExtractable (DConst DASTData)
liftToGD def = DGDefSmpl def (getData def)
getDep :: forall (t :: * -> *) . (DAdditionalData (t DASTData) DASTData) => (t DASTData) -> [String]
getDep = (depOf . getData)
setDep :: forall (t :: * -> *) . (DAdditionalData (t DASTData) DASTData) => [String] -> (t DASTData) -> (t DASTData)
setDep deps x = setData ((getData x) { depOf = deps}) x
removeDep names deps = foldr delete deps names
instance AggExtractable (DProg DASTData) where
aggExtract (DProg f defs e a) =
do defaggs' <- mapM (\def -> do def' <- aggExtract def; aggs <- popAggDefs; return (def', map liftToGD aggs)) defs
let defs' = concatMap (\(def', aggs) -> aggs++[def']) defaggs'
e' <- aggExtract e
aggs <- popAggDefs
let defs'' = (defs' ++ map liftToGD aggs)
deps = removeDep (concatMap getNames defs''++["g"]) $ normalizeDepsX $ map getDep defs'' ++ [depOf (getData e')]
f' = setDep deps f
a' = a { depOf = deps}
return (DProg f' defs'' e' a')
instance AggExtractable (DGroundDef DASTData) where
aggExtract (DGDefVI d a) = do d' <- aggExtract d
return (DGDefVI d' (a {depOf = getDep d'}) )
aggExtract (DGDefVC d a) = do d' <- aggExtract d
return (DGDefVC d' (a {depOf = getDep d'}))
aggExtract (DGDefGV d a) = do d' <- aggExtract d
return (DGDefGV d' (a {depOf = getDep d'}))
aggExtract (DGDefGF d a) = do d' <- aggExtract d
return (DGDefGF d' (a {depOf = getDep d'}))
aggExtract (DGDefSmpl d a) = do d' <- aggExtract d
return (DGDefSmpl d' (a {depOf = getDep d'}))
aggExtractLet
:: forall (t :: * -> *) (v :: * -> *).
(DAdditionalData (v DASTData) DASTData,
DAdditionalData (t DASTData) DASTData,
AggExtractable (v DASTData)
)
=> [(t DASTData)] -> [(DSmplDef DASTData)] -> (v DASTData) -> DASTData -> [String] -> Bool -> State DEnvAE ([(t DASTData)], [(DSmplDef DASTData)], (v DASTData), DASTData)
aggExtractLet vs defs e a names extract =
do defaggs' <- mapM (\def -> do def' <- aggExtract def; aggs <- if extract then popAggDefs else return []; return (def', aggs)) defs
let defs' = concatMap (\(def', aggs) -> aggs++[def']) defaggs'
e' <- aggExtract e
aggs <- if extract then popAggDefs else return []
let defs'' = (defs' ++ aggs)
deps = removeDep (concatMap getNames defs''++names) $ normalizeDepsX $ map getDep defs'' ++ [depOf (getData e')]
vs' = map (setDep deps) vs
a' = a { depOf = deps}
return (vs', defs'', e', a')
instance AggExtractable (DDefVertComp DASTData) where
aggExtract (DDefVertComp f defs e a) =
do x <- aggExtractLet [f] defs e a ["v", "prev", "curr"] True
let ([f'], defs', e', a') = x
return (DDefVertComp f' defs' e' a')
instance AggExtractable (DDefVertInit DASTData) where
aggExtract (DDefVertInit f defs e a) =
do x <- aggExtractLet [f] defs e a ["v"] True
let ([f'], defs', e', a') = x
return (DDefVertInit f' defs' e' a')
instance AggExtractable (DDefGraphVar DASTData) where
aggExtract (DDefGraphVar v e a) =
do e' <- aggExtract e
let v' = setDep (getDep e') v
return (DDefGraphVar v' e' (a {depOf = getDep v'}))
instance AggExtractable (DDefGraphFun DASTData) where
aggExtract (DDefGraphFun f v defs e a) =
do defs' <- mapM aggExtract defs
e' <- aggExtract e
let f' = setDep (getDep e') f
return (DDefGraphFun f' v defs' e' (a {depOf = getDep f'}))
instance AggExtractable (DSmplDef DASTData) where
aggExtract (DDefFun f vs [] e a) =
do x <- aggExtractLet [f] [] e a (concatMap getNames vs) False
let ([f'], _, e', a') = x
return (DDefFun f' vs [] e' a')
aggExtract (DDefVar v [] e a) =
do x <- aggExtractLet [v] [] e a [] False
let ([v'], _, e', a') = x
return (DDefVar v' [] e' a')
aggExtract (DDefTuple vs [] e a) =
do x <- aggExtractLet vs [] e a (concatMap getNames vs) False
let (vs', _, e', a') = x
return (DDefTuple vs' [] e' a')
instance AggExtractable (DTermination DASTData) where
aggExtract (DTermF a) = return (DTermF a)
aggExtract (DTermI e a) =
do unsetNeedsAggMove
e' <- aggExtract e
restoreNeedsAggMove
return (DTermI e' (a { depOf = getDep e'}))
aggExtract (DTermU e a) =
do unsetNeedsAggMove
e' <- aggExtract e
restoreNeedsAggMove
return (DTermU e' (a { depOf = removeDep ["g"] (getDep e')}))
getDeps4 t1 t2 t3 t4 = normalizeDepsX $ [getDep t1, getDep t2, getDep t3, getDep t4]
getDeps3 t1 t2 t3 = normalizeDepsX $ [getDep t1, getDep t2, getDep t3]
getDeps t1 t2 = normalizeDepsX $ [getDep t1, getDep t2]
getDepsX ts = normalizeDepsX $ map getDep ts
normalizeDeps = nub -- remove duplicated dependency entries
normalizeDepsX = foldr (\a r -> normalizeDeps (a++r)) []
instance AggExtractable (DGraphExpr DASTData) where
aggExtract (DPregel f0 ft x g a) =
do f0' <- aggExtract f0
ft' <- aggExtract ft
x' <- aggExtract x
g' <- aggExtract g
let ds = getDeps4 f0' ft' x' g'
return (DPregel f0' ft' x' g' (a {depOf = ds}))
aggExtract (DGMap f g a) =
do f' <- aggExtract f
g' <- aggExtract g
let ds = getDeps f' g'
return (DGMap f' g' (a {depOf = ds}))
aggExtract (DGZip g1 g2 a) =
do g1' <- aggExtract g1
g2' <- aggExtract g2
let ds = getDeps g1' g2'
return (DGZip g1' g2' (a {depOf = ds}))
aggExtract (DGIter f0 ft x g a) =
do f0' <- aggExtract f0
ft' <- aggExtract ft
x' <- aggExtract x
g' <- aggExtract g
let ds = getDeps4 f0' ft' x' g'
return (DGIter f0' ft' x' g' (a {depOf = ds}))
aggExtract (DGVar v a) =
do v' <- aggExtract v
return (DGVar v' (a {depOf = getDep v'}))
instance AggExtractable (DExpr DASTData) where
aggExtract (DIf p t e a) =
do p' <- aggExtract p
t' <- aggExtract t
e' <- aggExtract e
let ds = getDeps3 p' t' e'
return (DIf p' t' e' (a {depOf = ds}))
aggExtract (DTuple es a) =
do es' <- mapM aggExtract es
let ds = getDepsX es'
return (DTuple es' (a {depOf = ds}))
aggExtract (DFunAp f es a) =
do f' <- aggExtract f
es' <- mapM aggExtract es
let ds = normalizeDepsX (getDep f' : map getDep es')
return (DFunAp f' es' (a {depOf = ds}))
aggExtract (DConsAp c es a) =
do c' <- aggExtract c
es' <- mapM aggExtract es
let ds = normalizeDepsX (getDep c' : map getDep es')
return (DConsAp c' es' (a {depOf = ds}))
aggExtract (DFieldAcc t fs a) =
do t' <- aggExtract t
fs' <- mapM aggExtract fs
let ds = normalizeDepsX (getDep t' : map getDep fs')
return (DFieldAcc t' fs' (a {depOf = ds}))
aggExtract (DFieldAccE e fs a) =
do e' <- aggExtract e
fs' <- mapM aggExtract fs
let ds = normalizeDepsX (getDep e' : map getDep fs')
return (DFieldAccE e' fs' (a {depOf = ds}))
aggExtract (DAggr a' e g es a) =
do setInAgg
a'' <- aggExtract a'
g' <- aggExtract g
e' <- aggExtract e
es' <- mapM aggExtract es
let ds = removeDep (case g of (DGenG _) -> ["u"]; (DGenTermG _) -> ["u"]; _ -> ["u","e"]) $ normalizeDepsX (getDep g' : getDep a'' : map (getDep) (e':es'))
moveflag <- needsAggMove
if moveflag then(do -- assigning a new name to this aggregation expression
newName <- getNewName "agg"
let d = [newName]
v = DVar newName (a {depOf = d}) -- new variable biding the aggregation
def = DDefVar v [] (DAggr a'' e' g' es' (a {depOf = ds})) (a {depOf = ds})
-- store the definition in the env
addAggDef def
unsetInAgg
return (DVExp v (a {depOf = d}))) -- returns the varible as the expression
else do unsetInAgg
return (DAggr a'' e' g' es' (a {depOf = ds}))
aggExtract (DVExp v a) =
do v' <- aggExtract v
return (DVExp v' (a {depOf = getDep v'}))
aggExtract (DCExp c a) =
do c' <- aggExtract c
return (DCExp c' (a {depOf = getDep c'}))
instance AggExtractable (DAgg DASTData) where
aggExtract (DAggMin a) =
do return (DAggMin (a { depOf = ["minimum"] }))
aggExtract (DAggMax a) =
do return (DAggMax (a { depOf = ["maximum"] }))
aggExtract (DAggSum a) =
do return (DAggSum (a { depOf = ["sum"] }))
aggExtract (DAggProd a) =
do return (DAggProd (a { depOf = ["prod"] }))
aggExtract (DAggAnd a) =
do return (DAggAnd (a { depOf = ["and"] }))
aggExtract (DAggOr a) =
do return (DAggOr (a { depOf = ["or"] }))
aggExtract (DAggChoice x a) =
do x' <- aggExtract x
let ds = getDep x'
return (DAggChoice x' (a { depOf = "random":ds }))
aggExtract (DTupledAgg as a) =
do as' <- mapM aggExtract as
let ds = getDepsX as'
return (DTupledAgg as' (a { depOf = ds }))
instance AggExtractable (DGen DASTData) where
aggExtract (DGenI a) = return (DGenI (a {depOf = ["v"]}))
aggExtract (DGenO a) = return (DGenO (a {depOf = ["v"]}))
aggExtract (DGenG a) = return (DGenG (a {depOf = ["g"]}))
aggExtract (DGenTermG a) = return (DGenTermG (a {depOf = ["g"]}))
instance AggExtractable (DEdge DASTData) where
aggExtract (DEdge a) = return (DEdge (a {depOf = ["e"]}))
instance AggExtractable (DTableExpr DASTData) where
aggExtract (DPrev v a) = return (DPrev v (a {depOf = [getName v, "prev"]}))
aggExtract (DCurr v a) = return (DCurr v (a {depOf = [getName v, "curr"]}))
aggExtract (DVal v a) = return (DVal v (a {depOf = [getName v, "val"]}))
instance AggExtractable (DField DASTData) where
-- aggExtract (DFfst a) = return (DFfst (a {depOf = ["_fst"]}))
-- aggExtract (DFsnd a) = return (DFsnd (a {depOf = ["_snd"]}))
aggExtract (DField f a) = return (DField f (a {depOf = [f]}))
instance AggExtractable (DFun DASTData) where
aggExtract (DBinOp f a) = return (DBinOp f (a {depOf = [f]}))
aggExtract (DFun f a) = return (DFun f (a {depOf = [f]}))
instance AggExtractable (DVar DASTData) where
aggExtract (DVar v a) = return (DVar v (a {depOf = [v]}))
instance AggExtractable (DConstructor DASTData) where
aggExtract (DConstructor c a) = return (DConstructor c (a {depOf = [c]}))