sourcecode:
|
module Solver.SMTLIB.Session
( module Solver.SMTLIB.Types
, SMTError (..), SMTOpts (..), SMTSess, SMTSolver (..)
, defSMTOpts, evalSessions, freshSMTVars, setSMTOpts, solveSMT, solveSMTVars
, solveAllSMTVars, liftIOA
) where
import Control.Monad.Extra (concatMapM)
import Data.List (nub)
import Data.Maybe (fromJust)
import Language.SMTLIB.Goodies (assert, (/=%))
import Language.SMTLIB.Types ( Command (Push, Pop), ModelRsp, Sort, Term
, ValuationPair
)
import Solver.SMTLIB.Internal.Interaction
import Solver.SMTLIB.Types
--- default options for SMT solving
defSMTOpts :: SMTOpts
defSMTOpts = SMTOpts
{ incremental = False
, quiet = True
, tracing = False
, globalCmds = []
}
--- Evaluate SMT sessions by applying given solver and options
evalSessions :: SMTSolver -> SMTOpts -> SMTSess a -> IO a
evalSessions = evalSessionsImpl
--- Set options for SMT solving
setSMTOpts :: SMTOpts -> SMTSess ()
setSMTOpts opts = evalSession $ do
resetSession
modify $ \s -> s { options = opts }
--- Get n fresh variables of given sort
freshSMTVars :: Int -> Sort -> SMTSess [Term]
freshSMTVars n s = evalSession $ declareVars n s
--- Solve the SMT problem specified by the given SMT-LIB commands and
--- try to find a binding for all variables used
solveSMT :: [Command] -> SMTSess (Either [SMTError] [ModelRsp])
solveSMT cmds = evalSession $ do
bufferGlobalDefs
info "Asserting definitions and constraints"
sendCmds cmds
info "Checking satisfiability of constraints"
isSat <- checkSat
case isSat of
Sat -> do
info "Satisfiable -> Getting model for SMT problem"
m <- getModel
optReset
return m
res -> do
info "No model found for given SMT problem"
optReset
return $ Left $ res2Msgs res
--- Solve the SMT problem specified by the given SMT-LIB commands and
--- try to find a binding for all given variables
solveSMTVars :: [Term] -> [Command]
-> SMTSess (Either [SMTError] [ValuationPair])
solveSMTVars vars cmds = evalSession $ do
bufferGlobalDefs
info "Asserting definitions and constraints"
sendCmds cmds
info "Checking satisfiability of constraints"
isSat <- checkSat
case isSat of
Sat -> do
info "Satisfiable -> Getting bindings of given variables for SMT problem"
vps <- getValues vars
optReset
return vps
res -> do
info "No variable bindings found for given SMT problem"
optReset
return $ Left $ res2Msgs res
--- Solve the SMT problem specified by the given SMT-LIB commands and
--- try to find all bindings for the given variable.
--- The given integer determines how many counter examples are returned at
--- maximum for each variable.
solveAllSMTVars :: [Term] -> [Command] -> Int
-> SMTSess (Either [SMTError] [[ValuationPair]])
solveAllSMTVars vars cmds i = evalSession $ do
bufferGlobalDefs
info "Asserting definitions and constraints"
sendCmds cmds
info "Checking satisfiability of constraints"
isSat <- checkSat
case isSat of
Sat -> do
info "Satisfiable -> Getting bindings of given variables for SMT problem"
vps <- getValues vars
case vps of
Right vps' -> do
vpss <- concatMapM (getCounterExamples vps' i) vars
optReset
return $ Right $ nub vpss
Left e -> optReset >> (return $ Left e)
Unsat -> do
info "No variable bindings found for given SMT problem"
optReset
return $ Right []
res -> do
info "An error occurred while solving given SMT problem"
optReset
return $ Left $ res2Msgs res
where
getCounterExamples :: [ValuationPair] -> Int -> Term
-> SMT [[ValuationPair]]
getCounterExamples vps i' var = do
bufferCmds [Push 1]
vpss <- assertCounterExamples (fromJust $ lookup var vps) [vps] var i'
bufferCmds [Pop 1]
return vpss
assertCounterExamples :: Term -> [[ValuationPair]] -> Term -> Int
-> SMT [[ValuationPair]]
assertCounterExamples v vpss var i' = do
sendCmds [assert [var /=% v]]
isSat <- checkSat
case isSat of
Sat -> do
vps <- getValues vars
case vps of
Right vps' | i' > 1 -> assertCounterExamples
(fromJust $ lookup var vps')
(vps':vpss) var (i' - 1)
_ -> return vpss
_ -> return vpss
|