packages feed

z3-0.2.0: Z3/Lang/Monad.hs

{-# LANGUAGE ExistentialQuantification  #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE MultiParamTypeClasses      #-}
{-# LANGUAGE NamedFieldPuns             #-}
{-# LANGUAGE ScopedTypeVariables        #-}

-- |
-- Module    : Z3.Lang.Monad
-- Copyright : (c) Iago Abal, 2012
--             (c) David Castro, 2012
-- License   : BSD3
-- Maintainer: Iago Abal <iago.abal@gmail.com>,
--             David Castro <david.castro.dcp@gmail.com>
-- Stability : experimental

module Z3.Lang.Monad (
    -- * Z3 Monad
      Z3
    , Z3State(..)
    , evalZ3
    , Args(..)
    , stdArgs
    , evalZ3With
    , fresh
    , deBruijnIx
    , newQLayout

    -- ** Lifted Z3.Base functions
    , liftZ3
    , assertCnstr
    , check
    , eval
    , getBool
    , getInt
    , getReal
    , getModel
    , getValue
    , mkSort
    , mkStringSymbol
    , mkLiteral
    , mkNot
    , mkBoolBin
    , mkBoolMulti
    , mkPattern
    , mkBound
    , mkForall
    , mkEq
    , mkCmp
    , mkFuncDecl
    , mkApp1
    , mkApp2
    , mkApp3
    , mkApp4
    , mkApp5
    , mkConst
    , mkUnaryMinus
    , mkCRingArith
    , mkIntArith
    , mkRealArith
    , mkIte

    -- * Satisfiability result
    , Base.Result(..)

    ) where

import Z3.Lang.Exprs

import qualified Z3.Base as Base

import Control.Applicative ( Applicative )
import Control.Monad.State

---------------------------------------------------------------------
-- The Z3 Monad

-- | Z3 monad.
--
newtype Z3 a = Z3 (StateT Z3State IO a)
    deriving (Functor, Applicative, Monad)

instance MonadState Z3State Z3 where
    get = Z3 $ StateT $ \s -> return (s,s)
    put st = Z3 $ StateT $ \_ -> return ((), st)

-- | Internal state of Z3 monad.
--
data Z3State
    = Z3State { uniqVal :: !Uniq
              , context :: Base.Context
              , qLayout :: !Layout
              }

-- | Eval a Z3 script.
--
evalZ3 :: Z3 a -> IO a
evalZ3 = evalZ3With stdArgs

-- | Eval a Z3 script.
--
evalZ3With :: Args -> Z3 a -> IO a
evalZ3With args (Z3 s) = do
    cfg  <- Base.mkConfig
    Base.set_MODEL cfg True
    Base.set_MODEL_PARTIAL cfg False
    Base.setParamValue cfg "WARNING" "false"
    iniConfig cfg args
    ctx  <- Base.mkContext cfg
    evalStateT s Z3State { uniqVal = 0
                         , context = ctx
                         , qLayout = 0
                         }

-- | Fresh symbol name.
--
fresh :: Z3 (Uniq, String)
fresh = do
    st <- get
    let i = uniqVal st
    put st { uniqVal = i + 1 }
    return (uniqVal st, 'v':show i)

-------------------------------------------------
-- Arguments

data Args
  = Args {
      softTimeout :: Maybe Int
        -- ^ soft timeout (in milliseconds)
    }

stdArgs :: Args
stdArgs
  = Args {
      softTimeout = Nothing
    }

iniConfig :: Base.Config -> Args -> IO ()
iniConfig cfg args = do
  Base.setParamValue cfg "SOFT_TIMEOUT" soft_timeout_val
  where soft_timeout_val = show $ maybe 0 id $ softTimeout args

-------------------------------------------------
-- HOAX-deBruijn conversion

getQLayout :: Z3 Layout
getQLayout = gets qLayout

deBruijnIx :: Layout -> Z3 Int
deBruijnIx k = do lyt <- getQLayout; return $ lyt-k-1

newQLayout :: (Expr a -> Z3 b) -> Z3 b
newQLayout f = do
  lyt <- getQLayout
  incQLayout
  x <- f (Tag lyt)
  decQLayout
  return x
  where incQLayout = modify (\st@Z3State{qLayout} -> st{ qLayout = qLayout+1 })
        decQLayout = modify (\st@Z3State{qLayout} -> st{ qLayout = qLayout-1 })

---------------------------------------------------------------------
-- Lifted Base functions

liftZ3 :: IO a -> Z3 a
liftZ3 = Z3 . lift

liftZ3Op :: (Base.Context -> IO b) -> Z3 b
liftZ3Op f = liftZ3 . f =<< gets context

liftZ3Op2 :: (Base.Context -> a -> IO b) -> a -> Z3 b
liftZ3Op2 f a = gets context >>= \ctx -> liftZ3 (f ctx a)

liftZ3Op3 :: (Base.Context -> a -> b -> IO c) -> a -> b -> Z3 c
liftZ3Op3 f a b = gets context >>= \ctx -> liftZ3 (f ctx a b)

liftZ3Op4 :: (Base.Context -> a -> b -> c -> IO d) -> a -> b -> c -> Z3 d
liftZ3Op4 f a b c = gets context >>= \ctx -> liftZ3 (f ctx a b c)

liftZ3Op5 :: (Base.Context -> a -> b -> c -> d -> IO e) -> a -> b -> c -> d -> Z3 e
liftZ3Op5 f a b c d = gets context >>= \ctx -> liftZ3 (f ctx a b c d)

assertCnstr :: Base.AST Bool -> Z3 ()
assertCnstr = liftZ3Op2 Base.assertCnstr

-- | Check satisfiability.
check :: Z3 (Base.Result ())
check = liftZ3Op Base.check

eval :: Base.Model -> Base.AST a -> Z3 (Maybe (Base.AST a))
eval = liftZ3Op3 Base.eval

getBool :: Base.AST Bool -> Z3 (Maybe Bool)
getBool = liftZ3Op2 Base.getBool

getInt :: Base.AST Integer -> Z3 Integer
getInt = liftZ3Op2 Base.getInt

getReal :: Base.AST Rational -> Z3 Rational
getReal = liftZ3Op2 Base.getReal

getModel :: Z3 (Base.Result Base.Model)
getModel = liftZ3Op Base.getModel

getValue :: Base.Z3Type a => Base.AST a -> Z3 a
getValue = liftZ3Op2 Base.getValue

mkSort :: Base.Z3Type a => Z3 (Base.Sort a)
mkSort = liftZ3Op Base.mkSort

mkStringSymbol :: String -> Z3 Base.Symbol
mkStringSymbol = liftZ3Op2 Base.mkStringSymbol

mkLiteral :: forall a. Base.Z3Type a => a -> Z3 (Base.AST a)
mkLiteral = liftZ3Op2 Base.mkValue

mkNot :: Base.AST Bool -> Z3 (Base.AST Bool)
mkNot = liftZ3Op2 Base.mkNot

mkBoolBin :: BoolBinOp -> Base.AST Bool -> Base.AST Bool -> Z3 (Base.AST Bool)
mkBoolBin Xor     = liftZ3Op3 Base.mkXor
mkBoolBin Implies = liftZ3Op3 Base.mkImplies
mkBoolBin Iff     = liftZ3Op3 Base.mkIff

mkBoolMulti :: BoolMultiOp -> [Base.AST Bool] -> Z3 (Base.AST Bool)
mkBoolMulti And = liftZ3Op2 Base.mkAnd
mkBoolMulti Or  = liftZ3Op2 Base.mkOr

mkPattern :: Base.Z3Type a => [Base.AST a] -> Z3 Base.Pattern
mkPattern = liftZ3Op2 Base.mkPattern

mkBound :: Base.Z3Type a => Int -> Base.Sort a -> Z3 (Base.AST a)
mkBound = liftZ3Op3 Base.mkBound

mkForall :: Base.Z3Type a => [Base.Pattern] -> Base.Symbol -> Base.Sort a -> Base.AST Bool -> Z3 (Base.AST Bool)
mkForall = liftZ3Op5 Base.mkForall

mkEq :: Base.Z3Type a => CmpOpE
                           -> Base.AST a -> Base.AST a
                           -> Z3 (Base.AST Bool)
mkEq Eq  = liftZ3Op3 Base.mkEq
mkEq Neq = liftZ3Op3 mkNeq
  where mkNeq ctx b1 = Base.mkNot ctx <=< Base.mkEq ctx b1

mkCmp :: Base.Z3Num a => CmpOpI
                          -> Base.AST a -> Base.AST a
                          -> Z3 (Base.AST Bool)
mkCmp Le = liftZ3Op3 Base.mkLe
mkCmp Lt = liftZ3Op3 Base.mkLt
mkCmp Ge = liftZ3Op3 Base.mkGe
mkCmp Gt = liftZ3Op3 Base.mkGt

mkFuncDecl :: Base.Z3Fun a => Base.Symbol
                                -> Z3 (Base.FuncDecl a)
mkFuncDecl = liftZ3Op2 Base.mkFuncDecl

mkApp1 :: (Base.Z3Type a, Base.Z3Type b)
            => Base.FuncDecl (a -> b)
                -> Base.AST a
                -> Z3 (Base.AST b)
mkApp1 = liftZ3Op3 Base.mkApp1

mkApp2 :: (Base.Z3Type a, Base.Z3Type b, Base.Z3Type c)
            => Base.FuncDecl (a -> b -> c)
                -> Base.AST a -> Base.AST b
                -> Z3 (Base.AST c)
mkApp2 = liftZ3Op4 Base.mkApp2

mkApp3 :: (Base.Z3Type a, Base.Z3Type b, Base.Z3Type c , Base.Z3Type d)
            => Base.FuncDecl (a -> b -> c -> d)
                -> Base.AST a -> Base.AST b -> Base.AST c
                -> Z3 (Base.AST d)
mkApp3 fd a b c
  = gets context >>= \ctx -> liftZ3 $ Base.mkApp3 ctx fd a b c

mkApp4 :: (Base.Z3Type a, Base.Z3Type b, Base.Z3Type c , Base.Z3Type d, Base.Z3Type e)
            => Base.FuncDecl (a -> b -> c -> d -> e)
                -> Base.AST a -> Base.AST b -> Base.AST c -> Base.AST d
                -> Z3 (Base.AST e)
mkApp4 fd a b c d
  = gets context >>= \ctx -> liftZ3 $ Base.mkApp4 ctx fd a b c d

mkApp5 :: (Base.Z3Type a, Base.Z3Type b, Base.Z3Type c , Base.Z3Type d, Base.Z3Type e, Base.Z3Type f)
            => Base.FuncDecl (a -> b -> c -> d -> e -> f)
                -> Base.AST a -> Base.AST b -> Base.AST c -> Base.AST d -> Base.AST e
                -> Z3 (Base.AST f)
mkApp5 fd a b c d e
  = gets context >>= \ctx -> liftZ3 $ Base.mkApp5 ctx fd a b c d e

mkConst :: Base.Z3Type a => Base.Symbol -> Base.Sort a -> Z3 (Base.AST a)
mkConst = liftZ3Op3 Base.mkConst

mkUnaryMinus :: Base.Z3Num a => Base.AST a -> Z3 (Base.AST a)
mkUnaryMinus = liftZ3Op2 Base.mkUnaryMinus

mkCRingArith :: Base.Z3Num a => CRingOp -> [Base.AST a] -> Z3 (Base.AST a)
mkCRingArith Add = liftZ3Op2 Base.mkAdd
mkCRingArith Mul = liftZ3Op2 Base.mkMul
mkCRingArith Sub = liftZ3Op2 Base.mkSub

mkIntArith :: IntOp
               -> Base.AST Integer -> Base.AST Integer
               -> Z3 (Base.AST Integer)
mkIntArith Quot = liftZ3Op3 Base.mkDiv
mkIntArith Mod  = liftZ3Op3 Base.mkMod
mkIntArith Rem  = liftZ3Op3 Base.mkRem

mkRealArith :: RealOp
                -> Base.AST Rational -> Base.AST Rational
                -> Z3 (Base.AST Rational)
mkRealArith Div = liftZ3Op3 Base.mkDiv

mkIte :: Base.AST Bool -> Base.AST a -> Base.AST a -> Z3 (Base.AST a)
mkIte = liftZ3Op4 Base.mkIte