fregel-1.2.0: compiler/GenSMT.hs
{-# Language TypeSynonymInstances,FlexibleInstances,MultiParamTypeClasses,FunctionalDependencies,RankNTypes,FlexibleContexts,KindSignatures,ScopedTypeVariables #-}
{-# OPTIONS_GHC -i.. #-}
-- module GenSMT (genCommElimSpec, genInactivateSpec, PregelStepfn) where
module GenSMT
(genCommElimSpec, genInactivateSpec, collectVCStepfns, collectVCFixStepfns,
PregelStepfn, SMTOptimizable, stepfnName, applicableElimComm, applicableV2H)
where
import Spec
import ASTTrans
import ASTData
import TypeChecker
import Data.Char
import Data.List
import Debug.Trace
import System.IO.Unsafe
import DependencySimple (computeDependency, depAnnotate)
type Ty a = (DTypeTerm, a)
ppp v = unsafePerformIO $ do { putStrLn (show v); return v;}
sameConstructor :: DConstructor (Ty a) -> DConstructor (Ty b) -> Bool
sameConstructor (DConstructor con1 _) (DConstructor con2 _) = con1 == con2
vE, tRP, tBool :: String
vE = "|e|" -- name of edge
tRP = "_RP"
tBool = "Bool"
prelude :: String
prelude = unlines $
["(declare-datatypes () ((_RP _pinf _ninf _nan (_rv (_val Real)))))",
"(define-fun _isReal ((x _RP)) Bool",
" (not (or (= x _pinf) (or (= x _ninf) (= x _nan)))))",
"(define-fun _eq ((x _RP) (y _RP)) Bool",
" (and (_isReal x) (and (_isReal y) (= (_val x) (_val y)))))",
"(define-fun _neq ((x _RP) (y _RP)) Bool",
" (not (_eq x y)))",
"(define-fun _gt ((x _RP) (y _RP)) Bool",
" (or (= x _pinf) (or (= _ninf y)",
" (and (_isReal x) (and (_isReal y) (> (_val x) (_val y)))))))",
"(define-fun _lt ((x _RP) (y _RP)) Bool",
" (or (= x _ninf) (or (= y _pinf)",
" (and (_isReal x) (and (_isReal y) (< (_val x) (_val y)))))))",
"(define-fun _add ((x _RP) (y _RP)) _RP",
" (ite (and (_isReal x) (_isReal y)) (_rv (+ (_val x) (_val y))) _nan))",
"(define-fun _mult ((x _RP) (y _RP)) _RP",
" (ite (and (_isReal x) (_isReal y)) (_rv (* (_val x) (_val y))) _nan))",
"(define-fun _div ((x _RP) (y _RP)) _RP",
" (ite (and (_isReal x) (_isReal y)) (_rv (/ (_val x) (_val y))) _nan))",
"(define-fun _neg ((x _RP)) _RP",
" (ite (= x _pinf) _ninf (ite (= x _ninf) _pinf",
" (ite (= x _nan) _nan (_rv (- (_val x)))))))",
"(define-fun _min ((x _RP) (y _RP)) _RP (ite (_lt x y) x y))",
"(define-fun _max ((x _RP) (y _RP)) _RP (ite (_gt x y) x y))\n"]
genAuxDecls :: (Show a) =>
DRecordSpec (Ty a) -> [DGroundDef (Ty a)] -> [String]
genAuxDecls rs gdefs = [genDataDecls rs] ++ concatMap genAuxFunc gdefs
genDataDecls :: DRecordSpec (Ty a) -> String
genDataDecls (DRecordSpec (DConstructor dname _) fields _) =
genZ3DeclareDatatypes
("((" ++ dname ++ " (" ++ toHL dname ++ " " ++
unwords (map genF fields) ++ ")))")
True
where genF (DField fname _, ty) = "(" ++ fname ++ " " ++ genTy ty ++ ")"
toHL :: String -> String
toHL (c:s) = toLower c : s
genTy :: DType a -> String
genTy (DTInt _ ) = tRP
genTy (DTBool _ ) = tBool
genTy (DTDouble _ ) = tRP
genTy _ = undefined -- others may not be supported.
genAuxFunc :: (Show a) => DGroundDef (Ty a) -> [String]
genAuxFunc (DGDefVI (DDefVertInit (DFun fn _) _ expr _) _) = []
genAuxFunc (DGDefSmpl sd _) = [genSmplDef [] sd]
genAuxFunc (DGDefVC (DDefVertComp (DFun fn _) ldefs expr _) _) = []
genAuxFunc _ = []
getVC :: DProgramSpec (Ty a) -> [(String, [DSmplDef (Ty a)], DExpr (Ty a))]
getVC pr@(DProgramSpec rs (DProg _ defs _ _) _) = rs
where genVCdefs :: DGroundDef a -> [(String, [DSmplDef a], DExpr a)]
genVCdefs (DGDefVC (DDefVertComp (DFun fn _) ldefs expr _) _) =
if isDPregelFixStepArg fn dps then [(fn, ldefs, expr)] else []
genVCdefs _ = []
dps = collectDPregel pr
rs = concatMap genVCdefs defs
type PregelStepfn a =
(String, [DSmplDef a], DExpr a, DTermination a, DRecordSpec a)
type SMTOptimizable = (String, Bool, Bool)
-- (name of a step function,
-- applicable eliminate-commucation optimzation,
-- applicable vote-to-halt optimzation)
stepfnName :: SMTOptimizable -> String
stepfnName (name, _, _) = name
applicableElimComm :: SMTOptimizable -> Bool
applicableElimComm (_, b, _) = b
applicableV2H :: SMTOptimizable -> Bool
applicableV2H (_, _, b) = b
-- If pr is a DProgramSpec after typechecking, a is (ASTData.DTypeInfo, a').
-- collectVCStepfns :: (Show a) => DProgramSpec a -> [PregelStepfn a]
collectVCStepfns :: (Show a) => DProgramSpec (Ty a) -> [PregelStepfn (Ty a)]
collectVCStepfns pr@(DProgramSpec rs (DProg _ defs _ _) _) =
-- ppp "collectDPregel = " `seq` ppp dps `seq`
concatMap genVCStep defs
where dps = collectDPregel pr
-- genVCStep :: DGroundDef a -> [PregelStepfn a]
genVCStep (DGDefVC (DDefVertComp (DFun fn _) ldefs expr _) _) =
case dPregelStepArg fn dps of
Just term -> [(fn, ldefs, expr, term, getRecSpec rs ldefs expr)]
Nothing -> []
genVCStep _ = []
-- getRecSpec :: [DRecordSpec t] -> [DSmplDef t] -> DExpr t -> DRecordSpec t
getRecSpec rs ldefs expr =
if null cs then undefined
else if null (tail cs) then findRS (head cs) rs
else ppp "DConstructor is not uniq" `seq` findRS (head cs) rs
where cs = uniqList (getDConstrs ldefs expr)
-- uniqList :: Eq t => [t] -> [t]
uniqList [] = []
uniqList (x:xs) =
(if or (map (sameConstructor x) xs) then [] else [x])
++ uniqList xs
-- findRS :: DConstructor a -> [DRecordSpec a] -> DRecordSpec a
findRS con [] = undefined
findRS con (r@(DRecordSpec c mems _):rs)
| sameConstructor con c = r
| otherwise = findRS con rs
-- getDConstrs :: [DSmplDef t] -> DExpr t -> [DConstructor t]
getDConstrs ldefs expr = cs
where cs = concatMap col ldefs ++ collectDConstr expr
col (DDefVar _ _ e _) = collectDConstr e
col _ = []
collectVCFixStepfns :: (Show a) => DProgramSpec (Ty a) -> [PregelStepfn (Ty a)]
collectVCFixStepfns pr = filter isTermFix (collectVCStepfns pr)
where isTermFix (_, _, _, DTermF _, _) = True
isTermFix _ = False
genVC :: (Show a) =>
String -> (String, [DSmplDef (Ty a)], DExpr (Ty a)) ->
(String, [(DAgg (Ty a), DExpr (Ty a), DGen (Ty a), [DExpr (Ty a)])],
[String], String, [String])
genVC dn (fn, ldefs, expr) =
let mds = messageAggrs dn ldefs expr
mdts = map getType mds
vars = map (\n -> genZ3var ("m" ++ show n)) [1 .. length mds]
vc = genZ3DefineFun
fn
(genParenedStr
(genZ3VarTy vx dn : zipWith genZ3VarTy vars mdts))
dn
(snd (genLetsExpr vars ldefs expr))
True
vx = genZ3var "vx"
getType (DAggMin _, _, _, _) = tRP
getType (DAggMax _, _, _, _) = tRP
getType (DAggSum _, _, _, _) = tRP
getType (DAggProd _, _, _, _) = tRP
getType (DAggAnd _, _, _, _) = tBool
getType (DAggOr _, _, _, _) = tBool
getType (_, _, _, _) = "None"
{-
vars = map (\n -> "|m" ++ show n ++"|") [1 .. length mds]
vc = "(define-fun |" ++ fn ++ "| ((|vx| " ++ dn ++ ") " ++
(unwords $ map (\vn -> "(" ++ vn ++ " _RP)") vars) ++ ") " ++
dn ++ "\n " ++ snd (genLetsExpr vars ldefs expr) ++ ")\n"
-}
in (fn, mds, mdts, vc, vars)
-- genSmplDef has to use the typing information to produce the
-- correct type. This is TEKITOU.
genSmplDef :: (Show a) => [String] -> DSmplDef (Ty a) -> String
genSmplDef env (DDefFun (DFun fn _) vars defs expr _) =
genZ3DefineFun
fn
(genParenedStr (map genArg vars))
tRP
(snd (genLetsExpr env defs expr))
True
where genArg (DVar vn _) = genParenedStr [genZ3var vn, tRP]
-- where genArg (DVar vn _) = genParenedStr [vn, tRP]
genSmplDef env (DDefVar (DVar vn _) defs expr _) =
genZ3DeclareConst vn' tRP True ++
genZ3AssertEq vn' (snd (genLetsExpr env defs expr)) True
where vn' = genZ3var vn
{-
genSmplDef env (DDefVar (DVar vn _) defs expr _) =
genZ3DeclareConst vn tRP True ++
genZ3AssertEq vn (snd (genLetsExpr env defs expr)) True
-}
type Env = [String]
mapE :: (Show a) =>
(Env -> m a -> (Env, String)) -> Env -> [m a] -> (Env, [String])
mapE f env [] = (env,[])
mapE f env (a:x) = let (env',a') = f env a
(env'', x') = mapE f env' x
in (env'', a':x')
genLetsExpr :: (Show a) =>
Env -> [DSmplDef (Ty a)] -> DExpr (Ty a) -> (Env, String)
genLetsExpr env [] expr = genExpr env expr
genLetsExpr env defs expr =
let ds = zip defs (map collectDependDSmplDef defs)
defs' = map fst (sortBy compareDefs ds)
in -- ppp defs `seq` ppp ds `seq` ppp defs' `seq`
genLetsExpr' env defs' expr
genLetsExpr' :: (Show a) =>
Env -> [DSmplDef (Ty a)] -> DExpr (Ty a) -> (Env, String)
genLetsExpr' env [] expr = genExpr env expr
genLetsExpr' env (d:ds) expr =
let (env', dr) = genLet env d
(env'', er) = genLetsExpr' env' ds expr
in (env'', genSexpr "let" [genParenedStr [dr], er] False)
{-
genLetsExpr env defs expr =
let (env', dr) = mapE genLet env defs
(env'', er) = genExpr env' expr
ds = zip defs (map collectDependDSmplDef defs)
defs' = map fst (sortBy compareDefs ds)
in ppp defs `seq` ppp ds `seq` ppp defs' `seq`
(env'', genSexpr "let" [genParenedStr dr, er] False)
-}
compareDefs :: (DSmplDef (Ty a), [String]) -> (DSmplDef (Ty a), [String]) ->
Ordering
compareDefs (sdef1, dep1) (sdef2, dep2) =
let (n1:_) = getNames sdef1
(n2:_) = getNames sdef2
in if n2 `elem` dep1 then GT
else if n1 `elem` dep2 then LT
else EQ
genLet :: (Show a) => Env -> DSmplDef (Ty a) -> (Env, String)
genLet env (DDefVar (DVar vn _) defs expr _) =
let (env', dr) = genLetsExpr env defs expr
in (env', genSexpr (genZ3var vn) [dr] False)
-- in (env', genSexpr vn [dr] False)
genExpr :: (Show a) => Env -> DExpr (Ty a) -> (Env, String)
genExpr env (DIf e1 e2 e3 _) =
let (env', es) = mapE genExpr env [e1,e2,e3]
in (env', genSexpr "ite" es False)
genExpr env (DFunAp f@(DBinOp "!=" (tne,_)) exprs _) =
let at1 = argTypeName1 tne
(env', es) = mapE genExpr env exprs
in (env', genSexpr (genEqOp "!=" at1) es False)
genExpr env (DFunAp f exprs _)
= let (env', es) = mapE genExpr env exprs
in (env', genSexpr (genFunOp f) es False)
genExpr env (DConsAp (DConstructor cn _) exprs _)
= let (env', es) = mapE genExpr env exprs
in (env', genSexpr (toHL cn) es False)
genExpr env (DFieldAcc _ fns _)
= let es = foldr (\(DField fn _) r -> genSexpr fn [r] False) "|vx|" fns
in (env, es)
-- it is assumed that Curr is not used
genExpr env (DFieldAccE (DEdge _) [] _) = (env, vE)
genExpr (m : env) (DAggr agop e1 ge e2 _) = (env, m)
-- genExpr env (DVExp (DVar vn _) _) = (env, vn)
genExpr env (DVExp (DVar vn _) _) = (env, genZ3var vn)
genExpr env (DCExp c _) = (env, genConst c)
genExpr _ d = traceShow d undefined
genConst :: (Show a) => DConst (Ty a) -> String
genConst (DCInt i _) = "(_rv " ++ show i ++ ")"
genConst (DCBool True _) = "true"
genConst (DCBool False _) = "false"
genConst (DCDouble d _) = show d
genFunOp :: (Show a) => DFun (Ty a) -> String
genFunOp (DFun fn t) = genOF fn (argTypeName1 . fst $ t)
genFunOp (DBinOp opn t) = genOF opn (argTypeName1 . fst $ t)
genOF :: String -> String -> String
genOF "==" "Bool" = "="
genOF "==" _ = "_eq"
genOF "+" _ = "_add"
genOF "*" _ = "_mult"
genOF "/" _ = "_div"
genOF "neg"_ = "_neg"
genOF "min"_ = "_min"
genOF "max"_ = "_max"
genOF "||" _ = "or"
genOF "&&" _ = "and"
genOF ">" _ = "_gt"
genOF "<" _ = "_lt"
genOF a _ = a
genEqOp :: String -> String -> String
genEqOp "!=" "Int" = "_neq"
genEqOp "!=" "Float" = "_neq"
genEqOp "!=" "Bool" = "xor"
-- extracts aggregators concering message
messageAggrs :: (Show a) =>
String -> [DSmplDef (Ty a)] -> DExpr (Ty a) ->
[(DAgg (Ty a), DExpr (Ty a), DGen (Ty a), [DExpr (Ty a)])]
messageAggrs dn ldefs expr = msag expr ++ concatMap msagLet ldefs
where msag (DIf e1 e2 e3 _) = concatMap msag [e1, e2, e3]
msag (DFunAp _ exprs _) = concatMap msag exprs
msag (DConsAp (DConstructor cn _) exprs _) = concatMap msag exprs
msag (DAggr agop e1 ge e2 _) = [(agop, e1, ge, e2)]
msag a = []
msagLet (DDefVar (DVar vn _) defs expr _)
= msag expr ++ concatMap msagLet defs
genAggr :: DAgg (Ty a) -> String
genAggr (DAggMin _) = "_min"
genAggr (DAggMax _) = "_max"
genAggr (DAggSum _) = "_add"
genAggr (DAggProd _) = "_mult"
genAggr (DAggAnd _) = "and"
genAggr (DAggOr _) = "or"
genCommElimSpec :: (Show a) =>
[DGroundDef (Ty a)] -> PregelStepfn (Ty a) -> String
genCommElimSpec gdefs ps@(fname, ldefs, expr, term, recspec) =
prelude ++ unlines (genAuxDecls recspec gdefs) ++ mdfs ++
vc ++ vdefs ++ cnd ++ genZ3CheckSat True
where DRecordSpec (DConstructor dn _) dflds _ = recspec
mdfs = unlines $ zipWith3 (genAop dn) mds mdts [1..]
(fn, mds, mdts, vc, vars) = genVC dn (fname, ldefs, expr)
vars2 = map (\(a:vn) -> a : '2' : vn) vars
dcfld v t = genDC v t ++ genFldcon v dflds ++ "\n"
vdefs = dcfld v1 dn ++ dcfld v2 dn ++
genDC e tRP ++ genDC w dn ++ "\n" ++
unwords (zipWith genDC vars mdts) ++ "\n" ++
unwords (zipWith genDC vars2 mdts) ++ "\n"
aopApp (v,n) =
genSexpr (genZ3var ("aop" ++ show n)) [v, w, e] False
vcApp v f vs = genSexpr (genZ3var f) (v:vs) False
cnd = genZ3AssertEq v2 (vcApp v1 fn (map aopApp (zip vars [1..]))) True
++
genZ3AssertNotEq
(vcApp v2 fn vars2)
(vcApp v2 fn (map aopApp (zip vars2 [1..])))
True
v1 = genZ3var "v1"
v2 = genZ3var "v2"
e = genZ3var "e"
w = genZ3var "w"
{-
genInactivateSpec pr@(DProgramSpec rs p _) =
let (DRecordSpec (DConstructor dn _) dflds _) : _ = rs
[(fn, mds, vc, vars)] = map (genVC dn) $ getVC pr
vcApp v f vs = "(|" ++ f ++ "| " ++ v ++ " " ++ unwords vs ++")"
fldcon v = concat ["(assert (_isReal (" ++ fn ++ " " ++ v ++ ")))" |
(DField fn _, DTInt _) <- dflds]
dc t v = let ass = if t == tRP
then "(assert (_isReal " ++ v ++ ")) "
else ""
in "(declare-const " ++ v ++ " " ++ t ++ ") " ++ ass
units = map (\(aop,_,_,_) -> toUnit aop) mds
allOf = foldr (\a r -> "(and " ++ a ++ " " ++ r ++")") "true"
genFilter (_,_,_,es) = map (snd . genExpr []) es
cnd1 = "(assert " ++ allOf (concatMap genFilter mds) ++ ")\n"
cnd2 = "(assert (not (= |vx| " ++ vcApp "|vx|" fn units ++ ")))\n"
in prelude ++ unlines (genAuxDecls pr) ++ vc ++
dc dn "|vx|" ++ fldcon "|vx|" ++ "\n" ++
cnd1 ++ cnd2 ++ "(check-sat)\n"
-}
genInactivateSpec :: (Show a) =>
[DGroundDef (Ty a)] -> PregelStepfn (Ty a) -> String
genInactivateSpec gdefs (fname, ldefs, expr, term, recspec) =
prelude ++ unlines (genAuxDecls recspec gdefs) ++ vc ++ dcfld vx dn ++
"\n" ++ vdefs ++ cnd1 ++ cnd2 ++ genZ3CheckSat True
where DRecordSpec (DConstructor dn _) dflds _ = recspec
(fn, mds, mdts, vc, vars) = genVC dn (fname, ldefs, expr)
dcfld v t = genDC v t ++ genFldcon v dflds ++ "\n"
vdefs = genDC e tRP ++ "\n"
vcApp v f vs = genSexpr (genZ3var f) (v:vs) False
units = map (\(aop,_,_,_) -> toUnit aop) mds
allOf = foldr (\a r -> genSexpr "and" [a,r] False) "true"
genFilter (_,_,_,es) = map (snd . genExpr []) es
cnd1 = genSexpr "assert" [allOf (concatMap genFilter mds)] True
cnd2 = genZ3AssertNotEq vx (vcApp vx fn units) True
e = genZ3var "e"
vx = genZ3var "vx"
toUnit :: DAgg (Ty a) -> String
toUnit (DAggMin _) = "_pinf"
toUnit (DAggMax _) = "_ninf"
toUnit (DAggSum _) = "(_rv 0)"
toUnit (DAggProd _) = "(_rv 1)"
toUnit (DAggAnd _) = "true"
toUnit (DAggOr _) = "false"
genParenedStr :: [String] -> String
genParenedStr ss = "(" ++ unwords ss ++ ")"
genSexpr :: String -> [String] -> Bool -> String
genSexpr fn args nl = genParenedStr (fn : args) ++ if nl then "\n" else ""
genAop :: (Show a) =>
String -> (DAgg (Ty a), DExpr (Ty a), DGen (Ty a), [DExpr (Ty a)]) ->
String -> Int -> String
genAop dn p@(aop, e1, _ , _) t n =
genZ3DefineFun
("aop" ++ show n)
(genSexpr (genZ3VarTy mx t) [genZ3VarTy vx dn, genZ3VarTy vE tRP] False)
t -- Is this tekitou?
(genSexpr (genAggr aop) [snd (genExpr [] e1), mx] False)
True
where mx = genZ3var "mx"
vx = genZ3var "vx"
genFldcon :: (Show a) => String -> [(DField (Ty a), DType (Ty a))] -> String
genFldcon v dflds =
-- concat [genZ3AssertIsReal ("(" ++ fn ++ " " ++ v ++ ")") False
concat [genZ3AssertIsReal (genSexpr fn [v] False) False
| (DField fn _, DTInt _) <- dflds]
genDC :: String -> String -> String
genDC v t = let ass = if t == tRP
then genZ3AssertIsReal v False ++ " "
else ""
in genZ3DeclareConst v t False ++ " " ++ ass
genZ3DefineFun :: String -> String -> String -> String -> Bool -> String
genZ3DefineFun fname formals rty body nl =
genSexpr "define-fun" [genZ3var fname, formals, rty, body] nl
genZ3DeclareDatatypes :: String -> Bool -> String
genZ3DeclareDatatypes dt nl = genSexpr "declare-datatypes" ["()", dt] nl
genZ3DeclareConst :: String -> String -> Bool -> String
genZ3DeclareConst cname ty nl = genSexpr "declare-const" [cname, ty] nl
genZ3AssertEq :: String -> String -> Bool -> String
genZ3AssertEq op1 op2 nl =
genSexpr "assert" [genSexpr "=" [op1, op2] False] nl
genZ3AssertNotEq :: String -> String -> Bool -> String
genZ3AssertNotEq op1 op2 nl =
genSexpr "assert" [genSexpr "not" [genSexpr "=" [op1, op2] False] False] nl
genZ3AssertIsReal :: String -> Bool -> String
genZ3AssertIsReal op nl =
genSexpr "assert" [genSexpr "_isReal" [op] False] nl
genZ3VarTy :: String -> String -> String
genZ3VarTy v t = genParenedStr [v,t]
genZ3var :: String -> String
genZ3var v = "|" ++ v ++ "|"
genZ3CheckSat :: Bool -> String
genZ3CheckSat nl = "(check-sat)" ++ if nl then "\n" else ""
nthArgType :: Int -> DTypeTerm -> DTypeTerm
nthArgType n (DTypeTerm "->" [t1, t2]) | n == 1 = t1
| otherwise = nthArgType (n - 1) t2
nthArgType _ _ = undefined
argType1, argType2 :: DTypeTerm -> DTypeTerm
argType1 = nthArgType 1
argType2 = nthArgType 2
resultType :: DTypeTerm -> DTypeTerm
resultType (DTypeTerm "->" [_, t2]) = resultType t2
resultType t = t
dTypeName :: DTypeTerm -> String
dTypeName (DTypeTerm name _) = name
dTypeName (DTypeVar id) = id
argTypeName1, argTypeName2, resultTypeName :: DTypeTerm -> String
argTypeName1 = dTypeName . argType1
argTypeName2 = dTypeName . argType2
resultTypeName = dTypeName . resultType