CurryInfo: smtlib-solver-3.0.0 / Solver.SMTLIB.Session

classes:

              
documentation:
--- ----------------------------------------------------------------------------
--- This module provides operations for an interactive communication with
--- SMT solvers - which implement the SMT-LIB interface - via stdin and stdout.
--- Currently only the Z3 SMT solver is supported.
---
--- @author  Jan Tikovsky, Marcellus Siegburg
--- @version August 2021
--- ----------------------------------------------------------------------------
name:
Solver.SMTLIB.Session
operations:
Solver.SMTLIB.Internal.Interaction.liftIOA defSMTOpts evalSessions freshSMTVars setSMTOpts solveAllSMTVars solveSMT solveSMTVars
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
types:
Solver.SMTLIB.Internal.Interaction.SMTSess Solver.SMTLIB.Types.SMTError Solver.SMTLIB.Types.SMTOpts Solver.SMTLIB.Types.SMTSolver
unsafe:
safe