what4-1.0: doc/QuickStart.hs
{-# LANGUAGE GADTs #-}
module Main where
import Data.Foldable (forM_)
import System.IO (FilePath)
import Data.Parameterized.Nonce (newIONonceGenerator)
import Data.Parameterized.Some (Some(..))
import What4.Config (extendConfig)
import What4.Expr
( ExprBuilder, FloatModeRepr(..), newExprBuilder
, BoolExpr, GroundValue, groundEval )
import What4.Interface
( BaseTypeRepr(..), getConfiguration
, freshConstant, safeSymbol
, notPred, orPred, andPred )
import What4.Solver
(defaultLogData, z3Options, withZ3, SatResult(..))
import What4.Protocol.SMTLib2
(assume, sessionWriter, runCheckSat)
data BuilderState st = EmptyState
z3executable :: FilePath
z3executable = "z3"
main :: IO ()
main = do
Some ng <- newIONonceGenerator
sym <- newExprBuilder FloatIEEERepr EmptyState ng
-- This line is necessary for working with z3.
extendConfig z3Options (getConfiguration sym)
-- Let's determine if the following formula is satisfiable:
-- f(p, q, r) = (p | !q) & (q | r) & (!p | !r) & (!p | !q | r)
-- First, declare fresh constants for each of the three variables p, q, r.
p <- freshConstant sym (safeSymbol "p") BaseBoolRepr
q <- freshConstant sym (safeSymbol "q") BaseBoolRepr
r <- freshConstant sym (safeSymbol "r") BaseBoolRepr
-- Next, create terms for the negation of p, q, and r.
not_p <- notPred sym p
not_q <- notPred sym q
not_r <- notPred sym r
-- Next, build up each clause of f individually.
clause1 <- orPred sym p not_q
clause2 <- orPred sym q r
clause3 <- orPred sym not_p not_r
clause4 <- orPred sym not_p =<< orPred sym not_q r
-- Finally, create f out of the conjunction of all four clauses.
f <- andPred sym clause1 =<<
andPred sym clause2 =<<
andPred sym clause3 clause4
-- Determine if f is satisfiable, and print the instance if one is found.
checkModel sym f [ ("p", p)
, ("q", q)
, ("r", r)
]
-- Now, let's add one more clause to f.
clause5 <- orPred sym p =<< orPred sym q not_r
g <- andPred sym f clause5
-- Determine if g is satisfiable.
checkModel sym g [ ("p", p)
, ("q", q)
, ("r", r)
]
-- | Determine whether a predicate is satisfiable, and print out the values of a
-- set of expressions if a satisfying instance is found.
checkModel ::
ExprBuilder t st fs ->
BoolExpr t ->
[(String, BoolExpr t)] ->
IO ()
checkModel sym f es = do
-- We will use z3 to determine if f is satisfiable.
withZ3 sym z3executable defaultLogData $ \session -> do
-- Assume f is true.
assume (sessionWriter session) f
runCheckSat session $ \result ->
case result of
Sat (ge, _) -> do
putStrLn "Satisfiable, with model:"
forM_ es $ \(nm, e) -> do
v <- groundEval ge e
putStrLn $ " " ++ nm ++ " := " ++ show v
Unsat _ -> putStrLn "Unsatisfiable."
Unknown -> putStrLn "Solver failed to find a solution."