g2-0.2.0.0: src/G2/Liquid/Inference/Sygus/FCConverter.hs
{-# LANGUAGE OverloadedStrings #-}
module G2.Liquid.Inference.Sygus.FCConverter ( NMExprEnv
, convertConstraints) where
import G2.Language as G2
import G2.Liquid.Types
import G2.Liquid.Inference.Config
import G2.Liquid.Inference.FuncConstraint
import G2.Liquid.Inference.G2Calls
import G2.Liquid.Inference.PolyRef
import G2.Liquid.Inference.Sygus.SpecInfo
import qualified Data.HashMap.Lazy as HM
import qualified Data.List as L
import qualified Data.Map as M
import Data.Maybe
import Data.Tuple.Extra
type ConvertExpr a = G2.Expr -> a
type AndF a = [a] -> a
type OrF a = [a] -> a
type NotF a = a -> a
type ImpliesF a = a -> a -> a
type Func a = String -> [a] -> a
type KnownFunc a = String -> Integer -> Bool -> a
type ToBeFunc a = String -> Integer -> Bool -> a
------------------------------------
-- Building Formulas
------------------------------------
mkPreCall :: (InfConfigM m, ProgresserM m) =>
ConvertExpr form
-> AndF form
-> Func form
-> KnownFunc form
-> ToBeFunc form
-> NMExprEnv
-> TypeEnv
-> Measures
-> MeasureExs
-> Evals (Integer, Bool)
-> M.Map Name SpecInfo
-> FuncCall
-> [HigherOrderFuncCall]
-> m form
mkPreCall convExpr andF funcF knownF toBeF eenv tenv meas meas_ex evals m_si fc@(FuncCall { funcName = n }) hcalls
| Just si <- M.lookup n m_si
, Just (ev_i, ev_b) <- lookupEvals fc (pre_evals evals)
, Just func_e <- HM.lookup (nameOcc n, nameModule n) eenv = do
sy_body <- mkPreSynthBody convExpr funcF eenv tenv meas meas_ex (s_syn_pre si) (argumentTypes func_e) fc hcalls
let fixed_body = knownF (s_known_pre_name si) ev_i ev_b
to_be_body = toBeF (s_to_be_pre_name si) ev_i ev_b
case s_status si of
Synth -> return . andF $ fixed_body:sy_body
ToBeSynthed -> return $ andF [fixed_body, to_be_body]
Known -> return $ fixed_body
| otherwise = error "mkPreCall: specification not found"
mkPreSynthBody :: (InfConfigM m, ProgresserM m) =>
ConvertExpr form
-> Func form
-> NMExprEnv
-> TypeEnv
-> Measures
-> MeasureExs
-> [PolyBound SynthSpec]
-> [Type]
-> FuncCall
-> [HigherOrderFuncCall]
-> m [form]
mkPreSynthBody convExpr funcF eenv tenv meas meas_ex pre_spec func_ts (FuncCall { funcName = n, arguments = ars }) hcalls = do
let v_ars = filter (validArgForSMT . thd3)
. filter (\(_, t, _) -> not (isTyVar t))
. assignNums 1
$ zip func_ts ars
sy_body_p <- mapM (\(si_pb, ts_es) ->
let
t_ars = map (\(_, t, e) -> (t, e)) $ init ts_es
(i, l_rt, l_re) = last ts_es
re_pb = extractExprPolyBoundWithRoot l_re
rt_pb = extractTypePolyBound l_rt
in
case (i, l_rt) of
(Just i', TyFun _ _) -> do -- error $ "HERE\npre_spec = " ++ show pre_spec ++ "\nts_es = " ++ show ts_es
let arg_tys = argumentTypes $ PresType l_rt
return_ty = returnType $ PresType l_rt
hcalls' = filter (\hfc -> nameOcc (funcName hfc) == nameOcc n && nameUnique (funcName hfc) == i') hcalls
clls <- mapM (mkHigherOrderCall convExpr funcF eenv tenv meas meas_ex (removeHead si_pb) arg_tys return_ty) hcalls'
return $ concat clls
_ -> formCalls convExpr funcF tenv meas meas_ex n t_ars si_pb re_pb rt_pb
) . zip pre_spec . filter (not . null) $ L.inits v_ars
return $ concat sy_body_p
where
assignNums _ [] = []
assignNums i ((t@(TyFun _ _), e):ts) = (Just i, t, e):assignNums (i + 1) ts
assignNums i ((t, e):ts) = (Nothing, t, e):assignNums i ts
mkPostCall :: (InfConfigM m, ProgresserM m) =>
ConvertExpr form
-> AndF form
-> Func form
-> KnownFunc form
-> ToBeFunc form
-> NMExprEnv
-> TypeEnv
-> Measures
-> MeasureExs
-> Evals (Integer, Bool)
-> M.Map Name SpecInfo
-> FuncCall
-> m form
mkPostCall convExpr andF funcF knownF toBeF eenv tenv meas meas_ex evals m_si fc@(FuncCall { funcName = n })
| Just si <- M.lookup n m_si
, Just (ev_i, ev_b) <- lookupEvals fc (post_evals evals)
, Just func_e <- HM.lookup (nameOcc n, nameModule n) eenv = do
let fixed_body = knownF (s_known_post_name si) ev_i ev_b
to_be_body = toBeF (s_to_be_post_name si) ev_i ev_b
sy_body <- mkPostSynthBody convExpr funcF tenv meas meas_ex (s_syn_post si) (argumentTypes func_e) (returnType func_e) fc
case s_status si of
Synth -> return . andF $ fixed_body:sy_body
ToBeSynthed -> return $ andF [fixed_body, to_be_body]
Known -> return $ fixed_body
| otherwise = error "mkPostCall: specification not found"
mkPostSynthBody :: (InfConfigM m, ProgresserM m) =>
ConvertExpr form
-> Func form
-> TypeEnv
-> Measures
-> MeasureExs
-> PolyBound SynthSpec
-> [Type]
-> Type
-> FuncCall
-> m [form]
mkPostSynthBody convExpr funcF tenv meas meas_ex post_spec func_ts ret_ty (FuncCall { funcName = n, arguments = ars, returns = ret }) = do
let v_ars = filter (\(t, _) -> not (isTyVar t))
. filter (validArgForSMT . snd)
$ zip func_ts ars
smt_ret = extractExprPolyBoundWithRoot ret
smt_ret_ty = extractTypePolyBound ret_ty
formCalls convExpr funcF tenv meas meas_ex n v_ars post_spec smt_ret smt_ret_ty
mkHigherOrderCall :: (InfConfigM m, ProgresserM m) =>
ConvertExpr form
-> Func form
-> NMExprEnv
-> TypeEnv
-> Measures
-> MeasureExs
-> [PolyBound SynthSpec]
-> [Type] -- ^ Argument types
-> Type -- ^ Return Type
-> FuncCall
-> m [form]
mkHigherOrderCall convExpr funcF eenv tenv meas meas_ex pb_synth@(_:_) ar_ts ret_t fc = do
pre <- mkPreSynthBody convExpr funcF eenv tenv meas meas_ex (init pb_synth) ar_ts fc []
post <- mkPostSynthBody convExpr funcF tenv meas meas_ex (last pb_synth) ar_ts ret_t fc
return $ pre ++ post
mkHigherOrderCall _ _ _ _ _ _ _ _ _ _ = return []
formCalls :: (InfConfigM m, ProgresserM m) => ConvertExpr form -> Func form -> TypeEnv -> Measures -> MeasureExs -> Name -> [(Type, Expr)] -> PolyBound SynthSpec -> PolyBound [Expr] -> PolyBound Type -> m [form]
formCalls convExpr funcF tenv meas meas_ex n v_ars si_pb re_pb rt_pb = do
MaxSize mx_meas <- maxSynthFormSizeM
inf_con <- infConfigM
let smt_ars = concatMap (uncurry (adjustArgsWithCare inf_con n convExpr (fromInteger mx_meas) tenv meas meas_ex)) v_ars
si_re_rt_pb = case filterPBByType snd $ zipPB re_pb rt_pb of
Just re_rt_pb -> zipWithPB (\x (y, z) -> (x, y, z)) si_pb re_rt_pb
Nothing -> zipWithPB (\x (y, z) -> (x, y, z)) si_pb $ PolyBound ([], headValue rt_pb) [] -- error $ "formCalls: impossible, the polybound should have already been filtered" ++ "\nsi_pb = " ++ show si_pb ++ "\nre_pb = " ++ show re_pb ++ "\nrt_pb = " ++ show rt_pb
return $ concatMap (\(psi, re, rt) ->
let
f_smt_ars = if null (sy_args psi) then [] else smt_ars
smt_r = map (adjustArgs convExpr (fromInteger mx_meas) tenv meas meas_ex rt) re
in
map (\r -> funcF (sy_name psi) $ take (length (sy_args psi)) f_smt_ars ++ take (length (sy_rets psi)) r) smt_r
) $ extractValues si_re_rt_pb
convertConstraints :: (InfConfigM m, ProgresserM m) =>
ConvertExpr form
-> AndF form
-> OrF form
-> NotF form
-> ImpliesF form
-> Func form
-> KnownFunc form
-> ToBeFunc form
-> NMExprEnv
-> TypeEnv
-> Measures
-> MeasureExs
-> Evals (Integer, Bool)
-> M.Map Name SpecInfo
-> FuncConstraints
-> m [form]
convertConstraints convExpr andF orF notF impF funcF knownF toBeF eenv tenv meas meas_ex evals si fc = do
let fc' = toListFC fc
mapM (convertConstraint
convExpr
andF
orF
notF
impF
funcF
knownF
toBeF
eenv tenv meas meas_ex evals si) fc'
convertConstraint :: (InfConfigM m, ProgresserM m) =>
ConvertExpr form
-> AndF form
-> OrF form
-> NotF form
-> ImpliesF form
-> Func form
-> KnownFunc form
-> ToBeFunc form
-> NMExprEnv
-> TypeEnv
-> Measures
-> MeasureExs
-> Evals (Integer, Bool)
-> M.Map Name SpecInfo
-> FuncConstraint
-> m form
convertConstraint convExpr andF _ _ impF funcF knownF toBeF eenv tenv meas meas_ex evals si (Call All fc hcalls) = do
pre <- mkPreCall convExpr andF funcF knownF toBeF eenv tenv meas meas_ex evals si fc hcalls
post <- mkPostCall convExpr andF funcF knownF toBeF eenv tenv meas meas_ex evals si fc
return $ pre `impF` post
convertConstraint convExpr andF _ _ _ funcF knownF toBeF eenv tenv meas meas_ex evals si (Call Pre fc hcalls) =
mkPreCall convExpr andF funcF knownF toBeF eenv tenv meas meas_ex evals si fc hcalls
convertConstraint convExpr andF _ _ _ funcF knownF toBeF eenv tenv meas meas_ex evals si (Call Post fc _) =
mkPostCall convExpr andF funcF knownF toBeF eenv tenv meas meas_ex evals si fc
convertConstraint convExpr andF orF notF impF funcF knownF toBeF eenv tenv meas meas_ex evals si (AndFC fs) =
return . andF =<< mapM (convertConstraint convExpr andF orF notF impF funcF knownF toBeF eenv tenv meas meas_ex evals si) fs
convertConstraint convExpr andF orF notF impF funcF knownF toBeF eenv tenv meas meas_ex evals si (OrFC fs) =
return . orF =<< mapM (convertConstraint convExpr andF orF notF impF funcF knownF toBeF eenv tenv meas meas_ex evals si) fs
convertConstraint convExpr andF orF notF impF funcF knownF toBeF eenv tenv meas meas_ex evals si (ImpliesFC fc1 fc2) = do
lhs <- convertConstraint convExpr andF orF notF impF funcF knownF toBeF eenv tenv meas meas_ex evals si fc1
rhs <- convertConstraint convExpr andF orF notF impF funcF knownF toBeF eenv tenv meas meas_ex evals si fc2
return $ lhs `impF` rhs
convertConstraint convExpr andF orF notF impF funcF knownF toBeF eenv tenv meas meas_ex evals si (NotFC fc) =
return . notF =<< convertConstraint convExpr andF orF notF impF funcF knownF toBeF eenv tenv meas meas_ex evals si fc
adjustArgs :: ConvertExpr form -> Int -> TypeEnv -> Measures -> MeasureExs -> Type -> G2.Expr -> [form]
adjustArgs convExpr mx_meas tenv meas meas_ex t =
map convExpr
. map adjustLits
. substMeasures mx_meas tenv meas meas_ex t
substMeasures :: Int -> TypeEnv -> Measures -> MeasureExs -> Type -> G2.Expr -> [G2.Expr]
substMeasures mx_meas tenv meas meas_ex t e =
case typeToSort t of
Just _ -> [e]
Nothing ->
case HM.lookup e meas_ex of
Just es ->
let
-- Get a list of all measure/output pairs with usable types
es' = filter (isJust . typeToSort . returnType . snd) $ HM.toList es
-- Make sure that es's type is specific enough to be used with the measure
app_meas = applicableMeasures mx_meas tenv meas t
es'' = filter (\(ns, _) -> ns `HM.member` app_meas) es'
in
-- Sort to make sure we get the same order consistently
map snd $ L.sortBy (\(n1, _) (n2, _) -> compare n1 n2) es''
Nothing -> []
adjustArgsWithCare :: InferenceConfig -> Name -> ConvertExpr form -> Int -> TypeEnv -> Measures -> MeasureExs -> Type -> G2.Expr -> [form]
adjustArgsWithCare inf_con n convExpr mx_meas tenv meas meas_ex t
| use_invs inf_con
, specialFunction n =
map convExpr
. map adjustLits
. (\e -> case typeToSort t of Just _ -> [e]; Nothing -> [])
| otherwise = adjustArgs convExpr mx_meas tenv meas meas_ex t
adjustLits :: G2.Expr -> G2.Expr
adjustLits (App _ l@(Lit _)) = l
adjustLits e = e
validArgForSMT :: G2.Expr -> Bool
validArgForSMT e = not (isLHDict e) && not (isType e)
where
isType (Type _) = True
isType _ = False
isLHDict e_
| (TyCon (Name n _ _ _) _):_ <- unTyApp (typeOf e_) = n == "lh"
| otherwise = False