packages feed

co-feldspar-0.1.0.1: src/Feldspar/Verify/SMT.hs

module Feldspar.Verify.SMT
  ( module Feldspar.Verify.SMT
  , module SimpleSMT
  )
  where

import Data.List

import Control.Monad.State.Strict
import Control.Applicative

import SimpleSMT(
    SExpr(..), Result(..), Value(..)
  , bool, int, real, fun, fam, ite
  , tBool, tInt, tReal, tArray, tBits
  , select, store, concat, extract
  , bvULt, bvULeq, bvSLt, bvSLeq, bvNeg, bvAdd, bvSub, bvMul, bvUDiv
  , bvURem, bvSDiv, bvSRem, bvAnd, bvOr, bvNot, bvXOr, bvShl, bvAShr, bvLShr
  , signExtend, zeroExtend, realDiv
  , add, sub, mul, neg, abs, lt, leq, gt, geq, implies)
--  , newLogger)
import qualified SimpleSMT as SMT

--------------------------------------------------------------------------------
-- * Simple SMT front-end.
--------------------------------------------------------------------------------

type SMT = StateT SMTState IO

data SMTState = SMTState {
    st_solver :: SMT.Solver
  , st_next   :: Integer }

runZ3 :: [String] -> SMT a -> IO a
runZ3 args m = do
  --logger <- fmap Just (SMT.newLogger 0)
  let logger = Nothing
  solver <- SMT.newSolver "z3" (["-smt2", "-in", "-t:10000"] ++ args) logger
  --solver <- SMT.newSolver "cvc4" (["--lang=smt", "--force-logic=ALL", "--incremental","-"] ++ args) logger
  evalStateT m (SMTState solver 0)

freshNum :: SMT Integer
freshNum = do
  st <- get
  put st { st_next = st_next st + 1 }
  return (st_next st)

withSolver :: (SMT.Solver -> SMT a) -> SMT a
withSolver k = do
  st <- get
  k (st_solver st)

stack :: SMT a -> SMT a
stack m = withSolver $ \solver ->
  lift (SMT.push solver) *> m <* lift (SMT.pop solver)

not :: SExpr -> SExpr
not p
  | p == bool True  = bool False
  | p == bool False = bool True
  | otherwise = SMT.not p

conj :: [SExpr] -> SExpr
conj xs | bool False `elem` xs = bool False
conj [] = bool True
conj [x] = x
conj xs = fun "and" xs

disj :: [SExpr] -> SExpr
disj xs | bool True `elem` xs = bool True
disj [] = bool False
disj [x] = x
disj xs = fun "or" xs

(.||.), (.&&.) :: SExpr -> SExpr -> SExpr
x .||. y = disj [x, y]
x .&&. y = conj [x, y]

eq :: SExpr -> SExpr -> SExpr
eq x y
  | x == y = bool True
  | otherwise = SMT.eq x y

setOption :: String -> String -> SMT ()
setOption opt val = withSolver $ \solver -> lift (SMT.setOption solver opt val)

getExpr :: SExpr -> SMT Value
getExpr exp = withSolver $ \solver -> lift (SMT.getExpr solver exp)

assert :: SExpr -> SMT ()
assert expr = withSolver $ \solver -> lift (SMT.assert solver expr)

simplify :: SExpr -> SMT SExpr
simplify expr = withSolver $ \solver -> lift (SMT.command solver (fun "simplify" [expr]))

assertSimp :: SExpr -> SMT ()
assertSimp expr = simplify expr >>= assert

check :: SMT Result
check = withSolver $ \solver -> lift (SMT.check solver)

declare :: String -> SExpr -> SMT SExpr
declare name ty = withSolver $ \solver -> lift (SMT.declare solver name ty)

declareFun :: String -> [SExpr] -> SExpr -> SMT SExpr
declareFun name args res = withSolver $ \solver -> lift (SMT.declareFun solver name args res)

declareSort :: String -> SMT ()
declareSort name = withSolver $ \solver -> lift (SMT.simpleCommand solver ["declare-sort", name])

--------------------------------------------------------------------------------
-- ** Show SMT expressions.
--------------------------------------------------------------------------------

showSExpr :: SExpr -> String
showSExpr exp = SMT.showsSExpr exp ""

showValue :: Value -> String
showValue (Bool x)   = show x
showValue (Int x)    = show x
showValue (Real x)   = show x
showValue (Bits _ x) = show x
showValue (Other x)  = showSExpr x

showArray :: Value -> SExpr -> SMT String
showArray n arr = do
    vals <- sequence [ getExpr (select arr i) | i <- take cutoff (indexes n) ]
    if length (take (cutoff+1) (indexes n)) <= cutoff
    then
      return ("{" ++ intercalate ", " (map showValue vals) ++ "}")
    else
      return ("{" ++ intercalate ", " (map showValue vals) ++ ", ...}")
  where
    cutoff :: Int
    cutoff = 20

    indexes :: Value -> [SExpr]
    indexes (Int n)    = map int [0..n-1]
    indexes (Bits w n) = map (bits w) [0..n-1]

bits :: Int -> Integer -> SExpr
bits w n = List [Atom "_", Atom ("bv" ++ show m), int (fromIntegral w)]
  where
    m = n `mod` (2^w)

--------------------------------------------------------------------------------