g2-0.2.0.0: src/G2/Liquid/Inference/QualifGen.hs
{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE OverloadedStrings #-}
module G2.Liquid.Inference.QualifGen () where -- qualifGen) where
-- import G2.Language.Naming
-- import G2.Liquid.Inference.Sygus
-- import G2.Liquid.Helpers
-- import Sygus.LexSygus
-- import Sygus.ParseSygus
-- import Sygus.Print
-- import Sygus.Syntax
-- import Language.Fixpoint.Types.Constraints
-- import qualified Language.Fixpoint.Types.Names as LH
-- import Language.Fixpoint.Types.PrettyPrint
-- import qualified Data.HashMap.Lazy as HM
-- import Data.List
-- import qualified Data.Map as M
-- import Data.Maybe
-- import qualified Data.Text as T
-- import Data.Tuple
-- -- | Mocking measures to generate Qualifs.
-- data QMeasure = QMeasure { m_name :: String
-- , m_in :: Sort
-- , m_out :: Sort
-- , triv_out :: Term }
-- -- Mocking datatypes
-- data QDataType = QDataType { dt_smt_name :: String
-- , dt_name :: String
-- , dt_cons :: [String] }
-- data QualifConfig = QualifConfig { max_vars :: Int
-- , max_size :: Int
-- , datatypes :: [QDataType]
-- , measures :: [QMeasure] }
-- qualifGen :: FilePath -> IO ()
-- qualifGen qualif_fp = undefined -- do
{- let qc = QualifConfig
{ max_vars = 3
, max_size = 5
, datatypes = [ QDataType { dt_smt_name = "List"
, dt_name = "ListQualif.List a"
, dt_cons = ["cons", "nil"] }
, QDataType { dt_smt_name = "List_List"
, dt_name = "ListQualif.List (ListQualif.List b)"
, dt_cons = ["cons_cons", "nil_nil"] }]
, measures =
[ QMeasure { m_name = "size_m__0"
, m_in = listSort
, m_out = intSort
, triv_out = trivOutGen (TermIdent (ISymb "cons"))
(TermLit $ LitNum 0)
(TermLit $ LitNum 2000)
}
, QMeasure { m_name = "sizeXs_m__0"
, m_in = IdentSort (ISymb "List_List")
, m_out = intSort
, triv_out = trivOutGen (TermIdent (ISymb "cons_cons"))
(TermLit $ LitNum 0)
(TermLit $ LitNum 4000)
}
]
}
cmds <- qualifCalls qc
let printable_quals = map (cmdToQualifs (datatypes qc) (measures qc)) cmds
writeFile qualif_fp (intercalate "\n" printable_quals)
trivOutGen :: Term -> Term -> Term -> Term
trivOutGen v t1 t2 =
TermCall (ISymb "ite")
[TermCall (ISymb "=") [TermIdent (ISymb "a"), v], t1, t2]
qualifCalls :: QualifConfig -> IO [Cmd]
qualifCalls (QualifConfig { max_vars = max_v
, max_size = max_s
, datatypes = dt
, measures = meas }) = do
let srtss = concatMap (flip combinations (possibleDTs dt)) [1..max_v]
r <- mapM (\srts -> do
let varN = map (\i -> "x" ++ show i) ([0..] :: [Int])
svs = map (uncurry SortedVar) $ zip varN srts
let call = qualifCalls' dt meas svs
putStrLn . T.unpack $ printSygus call
res <- runCVC4Stream max_s . T.unpack $ printSygus call
case res of
Left err -> error "qualifGen: Bad call to CVC4"
Right res' -> do
let p_res = parse . lexSygus $ res'
all_used_res = filter defineFunAllUsed p_res
return all_used_res
) srtss
return $ concat r
combinations :: Int -> [a] -> [[a]]
combinations 0 _ = [[]]
combinations !n xs = [x:ys | x <- xs, ys <- combinations (n - 1) xs]
possibleDTs :: [QDataType] -> [Sort]
possibleDTs dts =
let
srts = map (IdentSort . ISymb . dt_smt_name) dts
in
[intSort, boolSort] ++ srts
qualifCalls' :: [QDataType] -> [QMeasure] -> [SortedVar] -> [Cmd]
qualifCalls' q_dt q_meas sortVars =
let
dt_srts = filter (\s -> s /= intSort && s /= boolSort)
. nub . map (\(SortedVar _ s) -> s) $ sortVars
gram_names = zip (map (\i -> "G" ++ show i) [0..]) dt_srts
gram = qualifGrammar gram_names q_meas
gram' = filterGrammar gram
in
[ SmtCmd (SetLogic "ALL")]
++
map qDataTypeToDeclareDataType q_dt
++
map qMeasureToDefineFun q_meas
++
[SynthFun "qualif" sortVars boolSort (Just gram')]
++
[ CheckSynth ]
qualifGrammar :: [(String, Sort)] -> [QMeasure] -> GrammarDef
qualifGrammar dt_gram_names meas =
let
sw_gram_names = map swap dt_gram_names
brl = GroupedRuleList "B" boolSort
(boolRuleList ++ qualifGramMeasCalls boolSort sw_gram_names meas)
irl = GroupedRuleList "I" intSort
(intRuleList ++ qualifGramMeasCalls intSort sw_gram_names meas)
dt_rule_lists = map (\(gn, s) -> GroupedRuleList gn s [GVariable s]) dt_gram_names
in
GrammarDef
([ SortedVar "B" boolSort
, SortedVar "I" intSort ]
++ map (uncurry SortedVar) dt_gram_names)
([brl, irl] ++ dt_rule_lists)
qualifGramMeasCalls :: Sort -> [(Sort, String)] -> [QMeasure] -> [GTerm]
qualifGramMeasCalls srt sort_to_gram = mapMaybe (qualifGramMeasCall srt sort_to_gram)
qualifGramMeasCall :: Sort -> [(Sort, String)] -> QMeasure -> Maybe GTerm
qualifGramMeasCall srt sort_to_gram meas@(QMeasure { m_name = f, m_in = i, m_out = out })
| srt == out
, Just g <- lookup i sort_to_gram =
Just . GBfTerm $ BfIdentifierBfs (ISymb f) [BfIdentifier (ISymb g)]
| otherwise = Nothing
-- | Eliminates or replaces the constant commands to avoid infinite grammars.
-- Eliminates And, since we get that anyway with Qualifs approach
filterGrammar :: GrammarDef -> GrammarDef
filterGrammar (GrammarDef sv grl) = GrammarDef sv $ map filterGrammar' grl
filterGrammar' :: GroupedRuleList -> GroupedRuleList
filterGrammar' (GroupedRuleList symb srt gterms) =
GroupedRuleList symb srt . filter (not . isAnd) $ filter (not . isConstant) gterms
isConstant :: GTerm -> Bool
isConstant (GConstant _) = True
isConstant _ = False
isAnd :: GTerm -> Bool
isAnd (GBfTerm (BfIdentifierBfs (ISymb "and") _)) = True
isAnd _ = False
-- | Converts a QDataType to a declare-datatype
qDataTypeToDeclareDataType :: QDataType -> Cmd
qDataTypeToDeclareDataType q_dt =
SmtCmd . DeclareDatatype (dt_smt_name q_dt)
. DTDec . map (flip DTConsDec []) $ dt_cons q_dt
-- | Converts a QMeasure to a define-fun
qMeasureToDefineFun :: QMeasure -> Cmd
qMeasureToDefineFun q_meas =
let
ar = SortedVar "a" (m_in q_meas)
in
SmtCmd $ DefineFun (m_name q_meas) [ar] (m_out q_meas) (triv_out q_meas)
-- | Returns True if given an SMT define fun command that uses all it's arguments. False otherwise
defineFunAllUsed :: Cmd -> Bool
defineFunAllUsed (SmtCmd (DefineFun _ sv _ t)) = allVariablesUsed sv t
defineFunAllUsed _ = False
-- | Returns true if all the variable are used in the Term. False otherwise.
allVariablesUsed :: [SortedVar] -> Term -> Bool
allVariablesUsed svs t =
let
vs = map (\(SortedVar i _) -> ISymb i) svs
used = usedIdentifiers t
in
vs \\ used == []
usedIdentifiers :: Term -> [Identifier]
usedIdentifiers (TermIdent ind) = [ind]
usedIdentifiers (TermLit _) = []
usedIdentifiers (TermCall _ ts) = mconcat $ map usedIdentifiers ts
usedIdentifiers (TermExists _ t) = usedIdentifiers t
usedIdentifiers (TermForAll _ t) = usedIdentifiers t
usedIdentifiers (TermLet vb t) = concatMap usedInVarBindings vb ++ usedIdentifiers t
usedInVarBindings :: VarBinding -> [Identifier]
usedInVarBindings (VarBinding _ t) = usedIdentifiers t
cmdToQualifs :: [QDataType] -> [QMeasure] -> Cmd -> String
cmdToQualifs dts meas (SmtCmd (DefineFun _ sv _ t)) =
let
sv_str = map sortedVarSymbol sv
sv_to_symb = M.fromList . zip sv_str $ map LH.symbol sv_str
meas_names = map (nameOcc . strToName . m_name) meas
lh_expr = termToLHExpr (MeasureSymbols $ map LH.symbol meas_names) sv_to_symb t
lh_expr_str = map (\c -> if c == '\n' then ' ' else c) $ show (pprintTidy Full lh_expr)
in
"qualif Qualif(" ++ bindSortedVars dts sv ++ ") : (" ++ lh_expr_str ++ ")"
sortedVarSymbol :: SortedVar -> Symbol
sortedVarSymbol (SortedVar v _) = v
bindSortedVars :: [QDataType] -> [SortedVar] -> String
bindSortedVars dts = intercalate ", " . map (bindSortedVar dts)
bindSortedVar :: [QDataType] -> SortedVar -> String
bindSortedVar dts (SortedVar v srt) = v ++ ":" ++ sortString dts srt
sortString :: [QDataType] -> Sort -> String
sortString dts (IdentSort (ISymb s))
| Just dt <- find (\d -> s == dt_smt_name d) dts = dt_name dt
| otherwise = s
sortString _ _ = error "sortString: Unexpected sort"
-------------------------------
-- Various specific sorts
-------------------------------
listSort :: Sort
listSort = IdentSort (ISymb "List")
-}