This module defines an interface to the SMT solver yices for solving comparison
requests for integer sets defined by the usual boolean operations on the usual
The yices input is generated by producing input text files in yices format,
There is also the yices-easy hackage entry which uses the C-API of yices.
This could be an alternative if speed and robustness will be a problem.
-- ----------------------------------------------------------------------
-- * SMT output generation for SMT based comparison
-- ----------------------------------------------------------------------
-- | This maps are assumed to have distinct values in [
1..Map.size varmap],
type VarTypes =
Map.Map String BoolRep
data VarEnv = VarEnv { varmap :: VarMap
-- | Type alias and subtype definitions for the domain of the extended params
smtTypeDef :: VarEnv -> String
concat [ "(define-type t", show a, " (subtype (x"
, show a, "::int) ", smtBoolExp br, "))" ]
concat [ "(define-type t", show a, " int)" ]
f k a s = s ++ g k a ++ "\n"
-- | Predicate definition
smtPredDef :: VarEnv -> String -> BoolRep -> String
smtPredDef m s b = concat [ "(define ", s, "::(->"
, concat $ smtVars m " t"
, concat $ smtGenericVars m
in concat [" x", j, "::t", j])
, ") ", smtBoolExp b, "))" ]
smtVarDef :: VarEnv -> String
$ smtGenericVars m (\ i -> let j = show i
in concat ["(define x", j, "::t", j, ")"])
smtVars :: VarEnv -> String -> [String]
smtVars m s = smtGenericVars m ((s++) . show)
smtGenericVars :: VarEnv -> (Int -> a) -> [a]
smtGenericVars m f = map f [1 ..
Map.size $ varmap m]
smtGenericStmt :: VarEnv -> String -> String -> String -> String
let vl = concat $ map (" "++) $ smtVars m "x"
in concat ["(assert+ (not (", s, " (", a, vl, ") (", b, vl, "))))"]
smtEQStmt :: VarEnv -> String -> String -> String
smtEQStmt m a b = smtGenericStmt m "=" a b
smtLEStmt :: VarEnv -> String -> String -> String
smtLEStmt m a b = smtGenericStmt m "=>" a b
smtDisjStmt :: VarEnv -> String -> String -> String
let vl = concat $ map (" "++) $ smtVars m "x"
in concat ["(assert+ (and (", a, vl, ") (", b, vl, ")))"]
smtAllScript :: VarEnv -> BoolRep -> BoolRep -> String
unlines [ smtScriptHead m r1 r2
, smtEQStmt m "A" "B", "(check) (retract 1)"
, smtLEStmt m "A" "B", "(check) (retract 2)"
, smtLEStmt m "B" "A", "(check) (retract 3)"
, smtDisjStmt m "A" "B", "(check)" ]
smtAllScripts :: VarEnv -> BoolRep -> BoolRep -> [String]
let h = smtScriptHead m r1 r2
in [ unlines [h, smtEQStmt m "A" "B", "(check)"]
, unlines [h, smtLEStmt m "A" "B", "(check)"]
, unlines [h, smtLEStmt m "B" "A", "(check)"]
, unlines [h, smtDisjStmt m "A" "B", "(check)"]
smtScriptHead :: VarEnv -> BoolRep -> BoolRep -> String
smtScriptHead = smtScriptHead'
smtScriptHeadOrig :: VarEnv -> BoolRep -> BoolRep -> String
smtScriptHeadOrig m r1 r2 =
smtGenericScript :: VarEnv -> (VarEnv -> String -> String -> String)
-> BoolRep -> BoolRep -> String
smtGenericScript m f r1 r2 = smtScriptHead m r1 r2 ++ "\n" ++ f m "A" "B"
smtEQScript :: VarEnv -> BoolRep -> BoolRep -> String
smtEQScript m r1 r2 = smtGenericScript m smtEQStmt r1 r2
smtLEScript :: VarEnv -> BoolRep -> BoolRep -> String
smtLEScript m r1 r2 = smtGenericScript m smtLEStmt r1 r2
smtDisjScript :: VarEnv -> BoolRep -> BoolRep -> String
smtDisjScript m r1 r2 = smtGenericScript m smtDisjStmt r1 r2
data SMTStatus = Sat | Unsat deriving (Show, Eq)
smtCheck :: VarEnv -> BoolRep -> BoolRep -> IO [SMTStatus]
smtCheck m r1 r2 = smtMultiResponse $ smtAllScript m r1 r2
smtCheck' :: VarEnv -> BoolRep -> BoolRep -> IO [SMTStatus]
smtCheck' m r1 r2 = mapM smtResponse $ smtAllScripts m r1 r2
-- | The result states of the smt solver are translated to the
-- adequate compare outcome. The boolean value is true if the corresponding
smtStatusCompareTable :: [SMTStatus] -> (EPCompare, Bool, Bool)
smtStatusCompareTable l =
[Unsat, Unsat, Unsat, x] -> let b = x == Unsat in (Comparable EQ, b, b)
[Sat, Unsat, Sat, x] -> let b = x == Unsat in (Comparable LT, b, b)
[Sat, Sat, Unsat, x] -> let b = x == Unsat in (Comparable GT, b, b)
[Sat, Sat, Sat, Unsat] -> (Incomparable Disjoint, False, False)
[Sat, Sat, Sat, Sat] -> (Incomparable Overlap, False, False)
x -> error $ "smtStatusCompareTable: malformed status " ++ show x
tripleFst :: (a, b, c) -> a
smtCompare :: VarEnv -> BoolRep -> BoolRep -> IO (EPCompare, Bool, Bool)
smtCompare m r1 r2 = liftM smtStatusCompareTable $ smtCheck m r1 r2
smtResponseToStatus :: String -> SMTStatus
| isInfixOf "Error" s = error $ "yices-error: " ++ s
| otherwise = error $ "unknown yices error"
smtMultiResponse :: String -> IO [SMTStatus]
smtMultiResponse inp = do
-- putStrLn $ "\n\n" ++ inp ++ "\n\n\n\n\n\n\n\n\n\n"
s <- readProcess "yices" [] inp
-- putStrLn "---------------- DONE ----------------\n\n"
return $ map smtResponseToStatus $ lines s
smtResponse :: String -> IO SMTStatus
s <- readProcess "yices" [] inp
-- putStrLn "------ yices output ------"
return $ smtResponseToStatus $
-- * Alternative Script Generation (without subtypes)
smtScriptHead' :: VarEnv -> BoolRep -> BoolRep -> String
unlines [ "(set-arith-only! true)"
-- | Predicate definition
smtPredDef' :: VarEnv -> String -> BoolRep -> String
smtPredDef' m s b = concat [ "(define ", s, "::(->"
, concat $ smtGenericVars m $ const " int"
, concat $ smtGenericVars m
in concat [" x", j, "::int"])
, ") ", smtBoolExp b, "))" ]
smtVarDef' :: VarEnv -> String
$ smtGenericVars m (\ i -> let j = show i
in concat ["(define x", j, "::int)"])
smtVarConstraint' :: VarEnv -> String
smtVarConstraint' m = h l where
h l' = concat ["(assert (and ", concat l' , "))"]
Just br -> " " ++ smtBoolExp br