g2-0.2.0.0: src/G2/Equiv/Uninterpreted.hs
{-# LANGUAGE FlexibleContexts, OverloadedStrings #-}
module G2.Equiv.Uninterpreted where
import G2.Language
import qualified G2.Language.ExprEnv as E
import Data.Foldable
import Data.Maybe
import qualified Data.Monoid as DM
import qualified Data.HashMap.Lazy as HM
import qualified Data.HashSet as HS
import Debug.Trace
import qualified Data.Text as T
-- | Find variables that don't have binding and adjust the epxression environment to treat them as symbolic
addFreeVarsAsSymbolic :: ExprEnv -> ExprEnv
addFreeVarsAsSymbolic eenv = let xs = freeVars eenv eenv
in foldl' (flip E.insertSymbolic) eenv xs
-- | changing the signature of addFreeTypes so that we have
-- we want to modify the rewrite-rules passed in checkrule
-- (AstContainer c Expr, Astcontainer c Type, AstContainer t Expr, Astcontainer t Type) => c -> State t -> NameGen -> (c, State t, NameGen)
-- | apply subvars to the rule
addFreeTypes :: (ASTContainer c Expr, ASTContainer c Type, ASTContainer t Expr, ASTContainer t Type) => c -> State t -> NameGen -> (c, State t, NameGen)
addFreeTypes c s@(State {type_env = tenv }) ng =
let
(tenv', ng') = freeTypesToTypeEnv (freeTypes tenv s) ng
tenv'' = HM.union tenv tenv'
free_dc = HS.toList $ freeDC tenv'' s
m = dataConMapping free_dc
s' = subVars m s
c' = subVars m c
n_te = addDataCons tenv'' free_dc
in (c', s' { type_env = n_te }, ng' )
-- trace ("show map " ++ show m) (s' { type_env = n_te }, ng')
allDC :: ASTContainer t Expr => t -> HS.HashSet DataCon
allDC = evalASTs allDC'
allDC' :: Expr -> HS.HashSet DataCon
allDC' e = case e of
Data dc -> HS.singleton dc
Case _ _ _ as ->
HS.fromList $ mapMaybe (\(Alt am _) -> case am of
DataAlt dc _ -> Just dc
_ -> Nothing) as
_ -> HS.empty
freeDC :: ASTContainer e Expr => TypeEnv -> e -> HS.HashSet DataCon
freeDC typeEnv e =
let al = allDC e
inTEnv = HS.map (\(DataCon n _) -> n)
. HS.fromList
. concatMap dataCon
. HM.elems $ typeEnv in
HS.filter (\(DataCon n _) -> not (HS.member n inTEnv)) al
allTypes :: ASTContainer t Type => t -> [(Name, Kind)]
allTypes = evalASTs allTypes'
allTypes' :: Type -> [(Name, Kind)]
allTypes' t = case t of
TyCon n k -> [(n,k)]
_ -> []
freeTypes :: ASTContainer t Type => TypeEnv -> t -> [(Name, Kind)]
freeTypes typeEnv t = HM.toList $ HM.difference (HM.fromList $ allTypes t) typeEnv
-- | we getting "free" typesnames and insert it into the TypeEnv with a "uninterprted " dataCons
-- Uninterpreted means there are potentially unlimited amount of datacons for a free type
freeTypesToTypeEnv :: [(Name,Kind)] -> NameGen -> (TypeEnv, NameGen)
freeTypesToTypeEnv nks ng =
let (adts, ng') = mapNG freeTypesToTypeEnv' nks ng
in (HM.fromList adts, ng')
freeTypesToTypeEnv' :: (Name, Kind) -> NameGen -> ( (Name, AlgDataTy), NameGen)
freeTypesToTypeEnv' (n,k) ng =
let (bids, ng') = freshIds (argumentTypes $ PresType k) ng
(dcs,ng'') = unknownDC ng' n k bids
n_adt = (n, DataTyCon {bound_ids = bids,
data_cons = [dcs]})
in (n_adt, ng'')
unknownDC :: NameGen -> Name -> Kind -> [Id] -> (DataCon, NameGen)
unknownDC ng n@(Name occn _ _ _) k is =
let tc = TyCon n k
tv = map TyVar is
ta = foldl' TyApp tc tv
ti = TyLitInt `TyFun` ta
tfa = foldl' (flip TyForAll) ti is
(dc_n, ng') = freshSeededString ("Unknown" DM.<> occn) ng
in (DataCon dc_n tfa, ng')
-- | add free Datacons into the TypeEnv at the appriorpate Type)
addDataCons :: TypeEnv -> [DataCon] -> TypeEnv
addDataCons = foldl' addDataCon
addDataCon :: TypeEnv -> DataCon -> TypeEnv
addDataCon te dc | (TyCon n _):_ <- unTyApp $ returnType dc =
let dtc = HM.lookup n te
adt = case dtc of
Just (DataTyCon ids' dcs) -> DataTyCon {bound_ids = ids', data_cons = dc : dcs}
Nothing -> error "addDataCons: cannot find corresponding Name in TypeEnv"
Just _ -> error "addDataCons: Not DataTyCon AlgDataTy found"
in HM.insert n adt te
addDataCon _ _ = error "addDataCon: Type of DataCon had incorrect form"
-- | addMapping will handle classification between the DataCon and Type
addMapping :: [DataCon] -> ExprEnv -> ExprEnv
addMapping dcs ee = foldl' addMapping' ee dcs
addMapping' :: ExprEnv -> DataCon -> ExprEnv
addMapping' ee dc@(DataCon name _) = E.insert name (Data dc) ee
-- | The translation between GHC and g2 didn't have a matching id for the same occurence name
-- so we are using brute force by matching the same occurence name
dataConMapping :: [DataCon] -> HM.HashMap (T.Text, Maybe T.Text) DataCon
dataConMapping dcs = HM.fromList $ map dataConMapping' dcs
dataConMapping' :: DataCon -> ((T.Text, Maybe T.Text ), DataCon)
dataConMapping' dc@(DataCon (Name t mt _ _ ) _ ) = ((t,mt), dc)
subVars :: ASTContainer t Expr => HM.HashMap (T.Text, Maybe T.Text) DataCon -> t -> t
subVars m = modifyASTs (subVars' m)
subVars' :: HM.HashMap (T.Text, Maybe T.Text) DataCon -> Expr -> Expr
subVars' m expr@(Var (Id (Name t mt _ _) _ )) = case HM.lookup (t,mt) m of
Just (DataCon n' k) -> Data (DataCon n' k)
Nothing -> expr
subVars' _ expr = expr