{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE DefaultSignatures #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE PatternGuards #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE Rank2Types #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE TypeSynonymInstances #-}
{-# OPTIONS_GHC -fno-warn-orphans #-}
module Data.SBV.Core.Model (
Mergeable(..), EqSymbolic(..), OrdSymbolic(..), SDivisible(..), Uninterpreted(..), Metric(..), assertWithPenalty, SIntegral, SFiniteBits(..)
, ite, iteLazy, sFromIntegral, sShiftLeft, sShiftRight, sRotateLeft, sRotateRight, sSignedShiftArithRight, (.^)
, oneIf, genVar, genVar_, forall, forall_, exists, exists_
, pbAtMost, pbAtLeast, pbExactly, pbLe, pbGe, pbEq, pbMutexed, pbStronglyMutexed
, sBool, sBools, sWord8, sWord8s, sWord16, sWord16s, sWord32
, sWord32s, sWord64, sWord64s, sInt8, sInt8s, sInt16, sInt16s, sInt32, sInt32s, sInt64
, sInt64s, sInteger, sIntegers, sReal, sReals, sFloat, sFloats, sDouble, sDoubles, sChar, sChars, sString, sStrings, sList, sLists
, slet
, sRealToSInteger, label, observe
, sAssert
, liftQRem, liftDMod, symbolicMergeWithKind
, genLiteral, genFromCW, genMkSymVar
, sbvQuickCheck
)
where
import Control.Applicative (ZipList(ZipList))
import Control.Monad (when, unless, mplus)
import GHC.Generics (U1(..), M1(..), (:*:)(..), K1(..))
import qualified GHC.Generics as G
import GHC.Stack
import Data.Array (Array, Ix, listArray, elems, bounds, rangeSize)
import Data.Bits (Bits(..))
import Data.Char (toLower, isDigit)
import Data.Int (Int8, Int16, Int32, Int64)
import Data.List (genericLength, genericIndex, genericTake, unzip4, unzip5, unzip6, unzip7, intercalate, isPrefixOf)
import Data.Maybe (fromMaybe)
import Data.String (IsString(..))
import Data.Word (Word8, Word16, Word32, Word64)
import Data.Dynamic (fromDynamic, toDyn)
import Test.QuickCheck (Testable(..), Arbitrary(..))
import qualified Test.QuickCheck.Test as QC (isSuccess)
import qualified Test.QuickCheck as QC (quickCheckResult, counterexample)
import qualified Test.QuickCheck.Monadic as QC (monadicIO, run, assert, pre, monitor)
import Data.SBV.Core.AlgReals
import Data.SBV.Core.Data
import Data.SBV.Core.Symbolic
import Data.SBV.Core.Operations
import Data.SBV.Provers.Prover (defaultSMTCfg, SafeResult(..))
import Data.SBV.SMT.SMT (showModel)
import Data.SBV.Utils.Boolean
import Data.SBV.Utils.Lib (isKString)
genVar :: Maybe Quantifier -> Kind -> String -> Symbolic (SBV a)
genVar q k = mkSymSBV q k . Just
genVar_ :: Maybe Quantifier -> Kind -> Symbolic (SBV a)
genVar_ q k = mkSymSBV q k Nothing
genLiteral :: Integral a => Kind -> a -> SBV b
genLiteral k = SBV . SVal k . Left . mkConstCW k
genFromCW :: Integral a => CW -> a
genFromCW (CW _ (CWInteger x)) = fromInteger x
genFromCW c = error $ "genFromCW: Unsupported non-integral value: " ++ show c
genMkSymVar :: Kind -> Maybe Quantifier -> Maybe String -> Symbolic (SBV a)
genMkSymVar k mbq Nothing = genVar_ mbq k
genMkSymVar k mbq (Just s) = genVar mbq k s
instance SymWord ()
instance HasKind ()
instance SymWord Bool where
mkSymWord = genMkSymVar KBool
literal x = SBV (svBool x)
fromCW = cwToBool
instance SymWord Word8 where
mkSymWord = genMkSymVar (KBounded False 8)
literal = genLiteral (KBounded False 8)
fromCW = genFromCW
instance SymWord Int8 where
mkSymWord = genMkSymVar (KBounded True 8)
literal = genLiteral (KBounded True 8)
fromCW = genFromCW
instance SymWord Word16 where
mkSymWord = genMkSymVar (KBounded False 16)
literal = genLiteral (KBounded False 16)
fromCW = genFromCW
instance SymWord Int16 where
mkSymWord = genMkSymVar (KBounded True 16)
literal = genLiteral (KBounded True 16)
fromCW = genFromCW
instance SymWord Word32 where
mkSymWord = genMkSymVar (KBounded False 32)
literal = genLiteral (KBounded False 32)
fromCW = genFromCW
instance SymWord Int32 where
mkSymWord = genMkSymVar (KBounded True 32)
literal = genLiteral (KBounded True 32)
fromCW = genFromCW
instance SymWord Word64 where
mkSymWord = genMkSymVar (KBounded False 64)
literal = genLiteral (KBounded False 64)
fromCW = genFromCW
instance SymWord Int64 where
mkSymWord = genMkSymVar (KBounded True 64)
literal = genLiteral (KBounded True 64)
fromCW = genFromCW
instance SymWord Integer where
mkSymWord = genMkSymVar KUnbounded
literal = SBV . SVal KUnbounded . Left . mkConstCW KUnbounded
fromCW = genFromCW
instance SymWord AlgReal where
mkSymWord = genMkSymVar KReal
literal = SBV . SVal KReal . Left . CW KReal . CWAlgReal
fromCW (CW _ (CWAlgReal a)) = a
fromCW c = error $ "SymWord.AlgReal: Unexpected non-real value: " ++ show c
isConcretely (SBV (SVal KReal (Left (CW KReal (CWAlgReal v))))) p
| isExactRational v = p v
isConcretely _ _ = False
instance SymWord Float where
mkSymWord = genMkSymVar KFloat
literal = SBV . SVal KFloat . Left . CW KFloat . CWFloat
fromCW (CW _ (CWFloat a)) = a
fromCW c = error $ "SymWord.Float: Unexpected non-float value: " ++ show c
isConcretely _ _ = False
instance SymWord Double where
mkSymWord = genMkSymVar KDouble
literal = SBV . SVal KDouble . Left . CW KDouble . CWDouble
fromCW (CW _ (CWDouble a)) = a
fromCW c = error $ "SymWord.Double: Unexpected non-double value: " ++ show c
isConcretely _ _ = False
instance SymWord Char where
mkSymWord = genMkSymVar KChar
literal c = SBV . SVal KChar . Left . CW KChar $ CWChar c
fromCW (CW _ (CWChar a)) = a
fromCW c = error $ "SymWord.String: Unexpected non-char value: " ++ show c
instance SymWord a => SymWord [a] where
mkSymWord
| isKString (undefined :: [a]) = genMkSymVar KString
| True = genMkSymVar (KList (kindOf (undefined :: a)))
literal as
| isKString (undefined :: [a]) = case fromDynamic (toDyn as) of
Just s -> SBV . SVal KString . Left . CW KString . CWString $ s
Nothing -> error "SString: Cannot construct literal string!"
| True = let k = KList (kindOf (undefined :: a))
toCWVal a = case literal a of
SBV (SVal _ (Left (CW _ cwval))) -> cwval
_ -> error "SymWord.Sequence: could not produce a concrete word for value"
in SBV $ SVal k $ Left $ CW k $ CWList $ map toCWVal as
fromCW (CW _ (CWString a)) = fromMaybe (error "SString: Cannot extract a literal string!")
(fromDynamic (toDyn a))
fromCW (CW _ (CWList a)) = fromCW . CW (kindOf (undefined :: a)) <$> a
fromCW c = error $ "SymWord.fromCW: Unexpected non-list value: " ++ show c
instance IsString SString where
fromString = literal
sBool :: String -> Symbolic SBool
sBool = symbolic
sBools :: [String] -> Symbolic [SBool]
sBools = symbolics
sWord8 :: String -> Symbolic SWord8
sWord8 = symbolic
sWord8s :: [String] -> Symbolic [SWord8]
sWord8s = symbolics
sWord16 :: String -> Symbolic SWord16
sWord16 = symbolic
sWord16s :: [String] -> Symbolic [SWord16]
sWord16s = symbolics
sWord32 :: String -> Symbolic SWord32
sWord32 = symbolic
sWord32s :: [String] -> Symbolic [SWord32]
sWord32s = symbolics
sWord64 :: String -> Symbolic SWord64
sWord64 = symbolic
sWord64s :: [String] -> Symbolic [SWord64]
sWord64s = symbolics
sInt8 :: String -> Symbolic SInt8
sInt8 = symbolic
sInt8s :: [String] -> Symbolic [SInt8]
sInt8s = symbolics
sInt16 :: String -> Symbolic SInt16
sInt16 = symbolic
sInt16s :: [String] -> Symbolic [SInt16]
sInt16s = symbolics
sInt32 :: String -> Symbolic SInt32
sInt32 = symbolic
sInt32s :: [String] -> Symbolic [SInt32]
sInt32s = symbolics
sInt64 :: String -> Symbolic SInt64
sInt64 = symbolic
sInt64s :: [String] -> Symbolic [SInt64]
sInt64s = symbolics
sInteger:: String -> Symbolic SInteger
sInteger = symbolic
sIntegers :: [String] -> Symbolic [SInteger]
sIntegers = symbolics
sReal:: String -> Symbolic SReal
sReal = symbolic
sReals :: [String] -> Symbolic [SReal]
sReals = symbolics
sFloat :: String -> Symbolic SFloat
sFloat = symbolic
sFloats :: [String] -> Symbolic [SFloat]
sFloats = symbolics
sDouble :: String -> Symbolic SDouble
sDouble = symbolic
sDoubles :: [String] -> Symbolic [SDouble]
sDoubles = symbolics
sChar :: String -> Symbolic SChar
sChar = symbolic
sString :: String -> Symbolic SString
sString = symbolic
sChars :: [String] -> Symbolic [SChar]
sChars = symbolics
sStrings :: [String] -> Symbolic [SString]
sStrings = symbolics
sList :: forall a. SymWord a => String -> Symbolic (SList a)
sList = symbolic
sLists :: forall a. SymWord a => [String] -> Symbolic [SList a]
sLists = symbolics
sRealToSInteger :: SReal -> SInteger
sRealToSInteger x
| Just i <- unliteral x, isExactRational i
= literal $ floor (toRational i)
| True
= SBV (SVal KUnbounded (Right (cache y)))
where y st = do xsw <- sbvToSW st x
newExpr st KUnbounded (SBVApp (KindCast KReal KUnbounded) [xsw])
label :: SymWord a => String -> SBV a -> SBV a
label m x
| Just _ <- unliteral x = x
| True = SBV $ SVal k $ Right $ cache r
where k = kindOf x
r st = do xsw <- sbvToSW st x
newExpr st k (SBVApp (Label m) [xsw])
observe :: SymWord a => String -> SBV a -> SBV a
observe m x
| null m
= error "SBV.observe: Bad empty name!"
| map toLower m `elem` smtLibReservedNames
= error $ "SBV.observe: The name chosen is reserved, please change it!: " ++ show m
| "s" `isPrefixOf` m && all isDigit (drop 1 m)
= error $ "SBV.observe: Names of the form sXXX are internal to SBV, please use a different name: " ++ show m
| True
= SBV $ SVal k $ Right $ cache r
where k = kindOf x
r st = do xsw <- sbvToSW st x
recordObservable st m xsw
return xsw
infix 4 .==, ./=
class EqSymbolic a where
(.==) :: a -> a -> SBool
(./=) :: a -> a -> SBool
distinct :: [a] -> SBool
allEqual :: [a] -> SBool
sElem :: a -> [a] -> SBool
{-# MINIMAL (.==) #-}
x ./= y = bnot (x .== y)
allEqual [] = true
allEqual (x:xs) = bAll (x .==) xs
distinct [] = true
distinct (x:xs) = bAll (x ./=) xs &&& distinct xs
sElem x xs = bAny (.== x) xs
infix 4 .<, .<=, .>, .>=
class (Mergeable a, EqSymbolic a) => OrdSymbolic a where
(.<) :: a -> a -> SBool
(.<=) :: a -> a -> SBool
(.>) :: a -> a -> SBool
(.>=) :: a -> a -> SBool
smin :: a -> a -> a
smax :: a -> a -> a
inRange :: a -> (a, a) -> SBool
{-# MINIMAL (.<) #-}
a .<= b = a .< b ||| a .== b
a .> b = b .< a
a .>= b = b .<= a
a `smin` b = ite (a .<= b) a b
a `smax` b = ite (a .<= b) b a
inRange x (y, z) = x .>= y &&& x .<= z
instance EqSymbolic (SBV a) where
SBV x .== SBV y = SBV (svEqual x y)
SBV x ./= SBV y = SBV (svNotEqual x y)
distinct [] = true
distinct [_] = true
distinct xs
| all isConc xs
= checkDiff xs
| True
= SBV (SVal KBool (Right (cache r)))
where r st = do xsw <- mapM (sbvToSW st) xs
newExpr st KBool (SBVApp NotEqual xsw)
checkDiff [] = true
checkDiff (a:as) = bAll (a ./=) as &&& checkDiff as
isConc (SBV (SVal _ (Left _))) = True
isConc _ = False
instance SymWord a => OrdSymbolic (SBV a) where
SBV x .< SBV y = SBV (svLessThan x y)
SBV x .<= SBV y = SBV (svLessEq x y)
SBV x .> SBV y = SBV (svGreaterThan x y)
SBV x .>= SBV y = SBV (svGreaterEq x y)
instance EqSymbolic Bool where
x .== y = if x == y then true else false
instance EqSymbolic a => EqSymbolic [a] where
[] .== [] = true
(x:xs) .== (y:ys) = x .== y &&& xs .== ys
_ .== _ = false
instance OrdSymbolic a => OrdSymbolic [a] where
[] .< [] = false
[] .< _ = true
_ .< [] = false
(x:xs) .< (y:ys) = x .< y ||| (x .== y &&& xs .< ys)
instance EqSymbolic a => EqSymbolic (Maybe a) where
Nothing .== Nothing = true
Just a .== Just b = a .== b
_ .== _ = false
instance (OrdSymbolic a) => OrdSymbolic (Maybe a) where
Nothing .< Nothing = false
Nothing .< _ = true
Just _ .< Nothing = false
Just a .< Just b = a .< b
instance (EqSymbolic a, EqSymbolic b) => EqSymbolic (Either a b) where
Left a .== Left b = a .== b
Right a .== Right b = a .== b
_ .== _ = false
instance (OrdSymbolic a, OrdSymbolic b) => OrdSymbolic (Either a b) where
Left a .< Left b = a .< b
Left _ .< Right _ = true
Right _ .< Left _ = false
Right a .< Right b = a .< b
instance (EqSymbolic a, EqSymbolic b) => EqSymbolic (a, b) where
(a0, b0) .== (a1, b1) = a0 .== a1 &&& b0 .== b1
instance (OrdSymbolic a, OrdSymbolic b) => OrdSymbolic (a, b) where
(a0, b0) .< (a1, b1) = a0 .< a1 ||| (a0 .== a1 &&& b0 .< b1)
instance (EqSymbolic a, EqSymbolic b, EqSymbolic c) => EqSymbolic (a, b, c) where
(a0, b0, c0) .== (a1, b1, c1) = (a0, b0) .== (a1, b1) &&& c0 .== c1
instance (OrdSymbolic a, OrdSymbolic b, OrdSymbolic c) => OrdSymbolic (a, b, c) where
(a0, b0, c0) .< (a1, b1, c1) = (a0, b0) .< (a1, b1) ||| ((a0, b0) .== (a1, b1) &&& c0 .< c1)
instance (EqSymbolic a, EqSymbolic b, EqSymbolic c, EqSymbolic d) => EqSymbolic (a, b, c, d) where
(a0, b0, c0, d0) .== (a1, b1, c1, d1) = (a0, b0, c0) .== (a1, b1, c1) &&& d0 .== d1
instance (OrdSymbolic a, OrdSymbolic b, OrdSymbolic c, OrdSymbolic d) => OrdSymbolic (a, b, c, d) where
(a0, b0, c0, d0) .< (a1, b1, c1, d1) = (a0, b0, c0) .< (a1, b1, c1) ||| ((a0, b0, c0) .== (a1, b1, c1) &&& d0 .< d1)
instance (EqSymbolic a, EqSymbolic b, EqSymbolic c, EqSymbolic d, EqSymbolic e) => EqSymbolic (a, b, c, d, e) where
(a0, b0, c0, d0, e0) .== (a1, b1, c1, d1, e1) = (a0, b0, c0, d0) .== (a1, b1, c1, d1) &&& e0 .== e1
instance (OrdSymbolic a, OrdSymbolic b, OrdSymbolic c, OrdSymbolic d, OrdSymbolic e) => OrdSymbolic (a, b, c, d, e) where
(a0, b0, c0, d0, e0) .< (a1, b1, c1, d1, e1) = (a0, b0, c0, d0) .< (a1, b1, c1, d1) ||| ((a0, b0, c0, d0) .== (a1, b1, c1, d1) &&& e0 .< e1)
instance (EqSymbolic a, EqSymbolic b, EqSymbolic c, EqSymbolic d, EqSymbolic e, EqSymbolic f) => EqSymbolic (a, b, c, d, e, f) where
(a0, b0, c0, d0, e0, f0) .== (a1, b1, c1, d1, e1, f1) = (a0, b0, c0, d0, e0) .== (a1, b1, c1, d1, e1) &&& f0 .== f1
instance (OrdSymbolic a, OrdSymbolic b, OrdSymbolic c, OrdSymbolic d, OrdSymbolic e, OrdSymbolic f) => OrdSymbolic (a, b, c, d, e, f) where
(a0, b0, c0, d0, e0, f0) .< (a1, b1, c1, d1, e1, f1) = (a0, b0, c0, d0, e0) .< (a1, b1, c1, d1, e1)
||| ((a0, b0, c0, d0, e0) .== (a1, b1, c1, d1, e1) &&& f0 .< f1)
instance (EqSymbolic a, EqSymbolic b, EqSymbolic c, EqSymbolic d, EqSymbolic e, EqSymbolic f, EqSymbolic g) => EqSymbolic (a, b, c, d, e, f, g) where
(a0, b0, c0, d0, e0, f0, g0) .== (a1, b1, c1, d1, e1, f1, g1) = (a0, b0, c0, d0, e0, f0) .== (a1, b1, c1, d1, e1, f1) &&& g0 .== g1
instance (OrdSymbolic a, OrdSymbolic b, OrdSymbolic c, OrdSymbolic d, OrdSymbolic e, OrdSymbolic f, OrdSymbolic g) => OrdSymbolic (a, b, c, d, e, f, g) where
(a0, b0, c0, d0, e0, f0, g0) .< (a1, b1, c1, d1, e1, f1, g1) = (a0, b0, c0, d0, e0, f0) .< (a1, b1, c1, d1, e1, f1)
||| ((a0, b0, c0, d0, e0, f0) .== (a1, b1, c1, d1, e1, f1) &&& g0 .< g1)
class (SymWord a, Num a, Bits a, Integral a) => SIntegral a
instance SIntegral Word8
instance SIntegral Word16
instance SIntegral Word32
instance SIntegral Word64
instance SIntegral Int8
instance SIntegral Int16
instance SIntegral Int32
instance SIntegral Int64
instance SIntegral Integer
class (SymWord a, Num a, Bits a) => SFiniteBits a where
sFiniteBitSize :: SBV a -> Int
lsb :: SBV a -> SBool
msb :: SBV a -> SBool
blastBE :: SBV a -> [SBool]
blastLE :: SBV a -> [SBool]
fromBitsBE :: [SBool] -> SBV a
fromBitsLE :: [SBool] -> SBV a
sTestBit :: SBV a -> Int -> SBool
sExtractBits :: SBV a -> [Int] -> [SBool]
sPopCount :: SBV a -> SWord8
setBitTo :: SBV a -> Int -> SBool -> SBV a
fullAdder :: SBV a -> SBV a -> (SBool, SBV a)
fullMultiplier :: SBV a -> SBV a -> (SBV a, SBV a)
sCountLeadingZeros :: SBV a -> SWord8
sCountTrailingZeros :: SBV a -> SWord8
lsb (SBV v) = SBV (svTestBit v 0)
msb x = sTestBit x (sFiniteBitSize x - 1)
blastBE = reverse . blastLE
blastLE x = map (sTestBit x) [0 .. intSizeOf x - 1]
fromBitsBE = fromBitsLE . reverse
fromBitsLE bs
| length bs /= w
= error $ "SBV.SFiniteBits.fromBitsLE/BE: Expected: " ++ show w ++ " bits, received: " ++ show (length bs)
| True
= result
where w = sFiniteBitSize result
result = go 0 0 bs
go !acc _ [] = acc
go !acc !i (x:xs) = go (ite x (setBit acc i) acc) (i+1) xs
sTestBit (SBV x) i = SBV (svTestBit x i)
sExtractBits x = map (sTestBit x)
sPopCount x
| isConcrete x = go 0 x
| True = sum [ite b 1 0 | b <- blastLE x]
where
go !c 0 = c
go !c w = go (c+1) (w .&. (w-1))
setBitTo x i b = ite b (setBit x i) (clearBit x i)
fullAdder a b
| isSigned a = error "fullAdder: only works on unsigned numbers"
| True = (a .> s ||| b .> s, s)
where s = a + b
fullMultiplier a b
| isSigned a = error "fullMultiplier: only works on unsigned numbers"
| True = (go (sFiniteBitSize a) 0 a, a*b)
where go 0 p _ = p
go n p x = let (c, p') = ite (lsb x) (fullAdder p b) (false, p)
(o, p'') = shiftIn c p'
(_, x') = shiftIn o x
in go (n-1) p'' x'
shiftIn k v = (lsb v, mask .|. (v `shiftR` 1))
where mask = ite k (bit (sFiniteBitSize v - 1)) 0
sCountLeadingZeros x = fromIntegral m - go m
where m = sFiniteBitSize x - 1
go :: Int -> SWord8
go i | i < 0 = i8
| True = ite (sTestBit x i) i8 (go (i-1))
where i8 = literal (fromIntegral i :: Word8)
sCountTrailingZeros x = go 0
where m = sFiniteBitSize x
go :: Int -> SWord8
go i | i >= m = i8
| True = ite (sTestBit x i) i8 (go (i+1))
where i8 = literal (fromIntegral i :: Word8)
instance SFiniteBits Word8 where sFiniteBitSize _ = 8
instance SFiniteBits Word16 where sFiniteBitSize _ = 16
instance SFiniteBits Word32 where sFiniteBitSize _ = 32
instance SFiniteBits Word64 where sFiniteBitSize _ = 64
instance SFiniteBits Int8 where sFiniteBitSize _ = 8
instance SFiniteBits Int16 where sFiniteBitSize _ = 16
instance SFiniteBits Int32 where sFiniteBitSize _ = 32
instance SFiniteBits Int64 where sFiniteBitSize _ = 64
oneIf :: (Num a, SymWord a) => SBool -> SBV a
oneIf t = ite t 1 0
liftPB :: String -> PBOp -> [SBool] -> SBool
liftPB w o xs
| Just e <- check o
= error $ "SBV." ++ w ++ ": " ++ e
| True
= result
where check (PB_AtMost k) = pos k
check (PB_AtLeast k) = pos k
check (PB_Exactly k) = pos k
check (PB_Le cs k) = pos k `mplus` match cs
check (PB_Ge cs k) = pos k `mplus` match cs
check (PB_Eq cs k) = pos k `mplus` match cs
pos k
| k < 0 = Just $ "comparison value must be positive, received: " ++ show k
| True = Nothing
match cs
| any (< 0) cs = Just $ "coefficients must be non-negative. Received: " ++ show cs
| lxs /= lcs = Just $ "coefficient length must match number of arguments. Received: " ++ show (lcs, lxs)
| True = Nothing
where lxs = length xs
lcs = length cs
result = SBV (SVal KBool (Right (cache r)))
r st = do xsw <- mapM (sbvToSW st) xs
registerKind st KUnbounded
newExpr st KBool (SBVApp (PseudoBoolean o) xsw)
pbAtMost :: [SBool] -> Int -> SBool
pbAtMost xs k
| k < 0 = error $ "SBV.pbAtMost: Non-negative value required, received: " ++ show k
| all isConcrete xs = literal $ sum (map (pbToInteger "pbAtMost" 1) xs) <= fromIntegral k
| True = liftPB "pbAtMost" (PB_AtMost k) xs
pbAtLeast :: [SBool] -> Int -> SBool
pbAtLeast xs k
| k < 0 = error $ "SBV.pbAtLeast: Non-negative value required, received: " ++ show k
| all isConcrete xs = literal $ sum (map (pbToInteger "pbAtLeast" 1) xs) >= fromIntegral k
| True = liftPB "pbAtLeast" (PB_AtLeast k) xs
pbExactly :: [SBool] -> Int -> SBool
pbExactly xs k
| k < 0 = error $ "SBV.pbExactly: Non-negative value required, received: " ++ show k
| all isConcrete xs = literal $ sum (map (pbToInteger "pbExactly" 1) xs) == fromIntegral k
| True = liftPB "pbExactly" (PB_Exactly k) xs
pbLe :: [(Int, SBool)] -> Int -> SBool
pbLe xs k
| k < 0 = error $ "SBV.pbLe: Non-negative value required, received: " ++ show k
| all isConcrete (map snd xs) = literal $ sum [pbToInteger "pbLe" c b | (c, b) <- xs] <= fromIntegral k
| True = liftPB "pbLe" (PB_Le (map fst xs) k) (map snd xs)
pbGe :: [(Int, SBool)] -> Int -> SBool
pbGe xs k
| k < 0 = error $ "SBV.pbGe: Non-negative value required, received: " ++ show k
| all isConcrete (map snd xs) = literal $ sum [pbToInteger "pbGe" c b | (c, b) <- xs] >= fromIntegral k
| True = liftPB "pbGe" (PB_Ge (map fst xs) k) (map snd xs)
pbEq :: [(Int, SBool)] -> Int -> SBool
pbEq xs k
| k < 0 = error $ "SBV.pbEq: Non-negative value required, received: " ++ show k
| all isConcrete (map snd xs) = literal $ sum [pbToInteger "pbEq" c b | (c, b) <- xs] == fromIntegral k
| True = liftPB "pbEq" (PB_Eq (map fst xs) k) (map snd xs)
pbMutexed :: [SBool] -> SBool
pbMutexed xs = pbAtMost xs 1
pbStronglyMutexed :: [SBool] -> SBool
pbStronglyMutexed xs = pbExactly xs 1
pbToInteger :: String -> Int -> SBool -> Integer
pbToInteger w c b
| c < 0 = error $ "SBV." ++ w ++ ": Non-negative coefficient required, received: " ++ show c
| Just v <- unliteral b = if v then fromIntegral c else 0
| True = error $ "SBV.pbToInteger: Received a symbolic boolean: " ++ show (c, b)
isConcreteZero :: SBV a -> Bool
isConcreteZero (SBV (SVal _ (Left (CW _ (CWInteger n))))) = n == 0
isConcreteZero (SBV (SVal KReal (Left (CW KReal (CWAlgReal v))))) = isExactRational v && v == 0
isConcreteZero _ = False
isConcreteOne :: SBV a -> Bool
isConcreteOne (SBV (SVal _ (Left (CW _ (CWInteger 1))))) = True
isConcreteOne (SBV (SVal KReal (Left (CW KReal (CWAlgReal v))))) = isExactRational v && v == 1
isConcreteOne _ = False
instance (Ord a, Num a, SymWord a) => Num (SBV a) where
fromInteger = literal . fromIntegral
SBV x + SBV y = SBV (svPlus x y)
SBV x * SBV y = SBV (svTimes x y)
SBV x - SBV y = SBV (svMinus x y)
abs (SBV x) = SBV (svAbs x)
signum a
| hasSign a = ite (a .> z) i
$ ite (a .< z) (negate i) a
| True = ite (a .> z) i a
where z = genLiteral (kindOf a) (0::Integer)
i = genLiteral (kindOf a) (1::Integer)
negate (SBV x) = SBV (svUNeg x)
(.^) :: (Mergeable b, Num b, SIntegral e) => b -> SBV e -> b
b .^ e
| isConcrete e, Just (x :: Integer) <- unliteral (sFromIntegral e)
= if x >= 0 then let go n v
| n == 0 = 1
| even n = go (n `div` 2) (v * v)
| True = v * go (n `div` 2) (v * v)
in go x b
else error $ "(.^): exponentiation: negative exponent: " ++ show x
| not (isBounded e) || isSigned e
= error $ "(.^): exponentiation only works with unsigned bounded symbolic exponents, kind: " ++ show (kindOf e)
| True
=
let SBV expt = e
expBit i = SBV (svTestBit expt i)
blasted = map expBit [0 .. intSizeOf e - 1]
in product $ zipWith (\use n -> ite use n 1)
blasted
(iterate (\x -> x*x) b)
instance (SymWord a, Fractional a) => Fractional (SBV a) where
fromRational = literal . fromRational
SBV x / sy@(SBV y) | div0 = ite (sy .== 0) 0 res
| True = res
where res = SBV (svDivide x y)
div0 = case kindOf sy of
KFloat -> False
KDouble -> False
KReal -> True
k@KBounded{} -> error $ "Unexpected Fractional case for: " ++ show k
k@KUnbounded -> error $ "Unexpected Fractional case for: " ++ show k
k@KBool -> error $ "Unexpected Fractional case for: " ++ show k
k@KString -> error $ "Unexpected Fractional case for: " ++ show k
k@KChar -> error $ "Unexpected Fractional case for: " ++ show k
k@KList{} -> error $ "Unexpected Fractional case for: " ++ show k
k@KUserSort{} -> error $ "Unexpected Fractional case for: " ++ show k
instance (SymWord a, Fractional a, Floating a) => Floating (SBV a) where
pi = literal pi
exp = lift1FNS "exp" exp
log = lift1FNS "log" log
sqrt = lift1F FP_Sqrt sqrt
sin = lift1FNS "sin" sin
cos = lift1FNS "cos" cos
tan = lift1FNS "tan" tan
asin = lift1FNS "asin" asin
acos = lift1FNS "acos" acos
atan = lift1FNS "atan" atan
sinh = lift1FNS "sinh" sinh
cosh = lift1FNS "cosh" cosh
tanh = lift1FNS "tanh" tanh
asinh = lift1FNS "asinh" asinh
acosh = lift1FNS "acosh" acosh
atanh = lift1FNS "atanh" atanh
(**) = lift2FNS "**" (**)
logBase = lift2FNS "logBase" logBase
lift1F :: SymWord a => FPOp -> (a -> a) -> SBV a -> SBV a
lift1F w op a
| Just v <- unliteral a
= literal $ op v
| True
= SBV $ SVal k $ Right $ cache r
where k = kindOf a
r st = do swa <- sbvToSW st a
swm <- sbvToSW st sRNE
newExpr st k (SBVApp (IEEEFP w) [swm, swa])
lift1FNS :: (SymWord a, Floating a) => String -> (a -> a) -> SBV a -> SBV a
lift1FNS nm f sv
| Just v <- unliteral sv = literal $ f v
| True = error $ "SBV." ++ nm ++ ": not supported for symbolic values of type " ++ show (kindOf sv)
lift2FNS :: (SymWord a, Floating a) => String -> (a -> a -> a) -> SBV a -> SBV a -> SBV a
lift2FNS nm f sv1 sv2
| Just v1 <- unliteral sv1
, Just v2 <- unliteral sv2 = literal $ f v1 v2
| True = error $ "SBV." ++ nm ++ ": not supported for symbolic values of type " ++ show (kindOf sv1)
instance (Num a, Bits a, SymWord a) => Bits (SBV a) where
SBV x .&. SBV y = SBV (svAnd x y)
SBV x .|. SBV y = SBV (svOr x y)
SBV x `xor` SBV y = SBV (svXOr x y)
complement (SBV x) = SBV (svNot x)
bitSize x = intSizeOf x
bitSizeMaybe x = Just $ intSizeOf x
isSigned x = hasSign x
bit i = 1 `shiftL` i
setBit x i = x .|. genLiteral (kindOf x) (bit i :: Integer)
clearBit x i = x .&. genLiteral (kindOf x) (complement (bit i) :: Integer)
complementBit x i = x `xor` genLiteral (kindOf x) (bit i :: Integer)
shiftL (SBV x) i = SBV (svShl x i)
shiftR (SBV x) i = SBV (svShr x i)
rotateL (SBV x) i = SBV (svRol x i)
rotateR (SBV x) i = SBV (svRor x i)
x `testBit` i
| SBV (SVal _ (Left (CW _ (CWInteger n)))) <- x
= testBit n i
| True
= error $ "SBV.testBit: Called on symbolic value: " ++ show x ++ ". Use sTestBit instead."
popCount x
| SBV (SVal _ (Left (CW (KBounded _ w) (CWInteger n)))) <- x
= popCount (n .&. (bit w - 1))
| True
= error $ "SBV.popCount: Called on symbolic value: " ++ show x ++ ". Use sPopCount instead."
sFromIntegral :: forall a b. (Integral a, HasKind a, Num a, SymWord a, HasKind b, Num b, SymWord b) => SBV a -> SBV b
sFromIntegral x
| isReal x
= error "SBV.sFromIntegral: Called on a real value"
| Just v <- unliteral x
= literal (fromIntegral v)
| True
= result
where result = SBV (SVal kTo (Right (cache y)))
kFrom = kindOf x
kTo = kindOf (undefined :: b)
y st = do xsw <- sbvToSW st x
newExpr st kTo (SBVApp (KindCast kFrom kTo) [xsw])
liftViaSVal :: (SVal -> SVal -> SVal) -> SBV a -> SBV b -> SBV c
liftViaSVal f (SBV a) (SBV b) = SBV $ f a b
sShiftLeft :: (SIntegral a, SIntegral b) => SBV a -> SBV b -> SBV a
sShiftLeft = liftViaSVal svShiftLeft
sShiftRight :: (SIntegral a, SIntegral b) => SBV a -> SBV b -> SBV a
sShiftRight = liftViaSVal svShiftRight
sSignedShiftArithRight:: (SFiniteBits a, SIntegral b) => SBV a -> SBV b -> SBV a
sSignedShiftArithRight x i
| isSigned i = error "sSignedShiftArithRight: shift amount should be unsigned"
| isSigned x = ssa x i
| True = ite (msb x)
(complement (ssa (complement x) i))
(ssa x i)
where ssa = liftViaSVal svShiftRight
sRotateLeft :: (SIntegral a, SIntegral b, SDivisible (SBV b)) => SBV a -> SBV b -> SBV a
sRotateLeft = liftViaSVal svRotateLeft
sRotateRight :: (SIntegral a, SIntegral b, SDivisible (SBV b)) => SBV a -> SBV b -> SBV a
sRotateRight = liftViaSVal svRotateRight
instance (Show a, Bounded a, Integral a, Num a, SymWord a) => Enum (SBV a) where
succ x
| v == (maxBound :: a) = error $ "Enum.succ{" ++ showType x ++ "}: tried to take `succ' of maxBound"
| True = fromIntegral $ v + 1
where v = enumCvt "succ" x
pred x
| v == (minBound :: a) = error $ "Enum.pred{" ++ showType x ++ "}: tried to take `pred' of minBound"
| True = fromIntegral $ v - 1
where v = enumCvt "pred" x
toEnum x
| xi < fromIntegral (minBound :: a) || xi > fromIntegral (maxBound :: a)
= error $ "Enum.toEnum{" ++ showType r ++ "}: " ++ show x ++ " is out-of-bounds " ++ show (minBound :: a, maxBound :: a)
| True
= r
where xi :: Integer
xi = fromIntegral x
r :: SBV a
r = fromIntegral x
fromEnum x
| r < fromIntegral (minBound :: Int) || r > fromIntegral (maxBound :: Int)
= error $ "Enum.fromEnum{" ++ showType x ++ "}: value " ++ show r ++ " is outside of Int's bounds " ++ show (minBound :: Int, maxBound :: Int)
| True
= fromIntegral r
where r :: Integer
r = enumCvt "fromEnum" x
enumFrom x = map fromIntegral [xi .. fromIntegral (maxBound :: a)]
where xi :: Integer
xi = enumCvt "enumFrom" x
enumFromThen x y
| yi >= xi = map fromIntegral [xi, yi .. fromIntegral (maxBound :: a)]
| True = map fromIntegral [xi, yi .. fromIntegral (minBound :: a)]
where xi, yi :: Integer
xi = enumCvt "enumFromThen.x" x
yi = enumCvt "enumFromThen.y" y
enumFromThenTo x y z = map fromIntegral [xi, yi .. zi]
where xi, yi, zi :: Integer
xi = enumCvt "enumFromThenTo.x" x
yi = enumCvt "enumFromThenTo.y" y
zi = enumCvt "enumFromThenTo.z" z
enumCvt :: (SymWord a, Integral a, Num b) => String -> SBV a -> b
enumCvt w x = case unliteral x of
Nothing -> error $ "Enum." ++ w ++ "{" ++ showType x ++ "}: Called on symbolic value " ++ show x
Just v -> fromIntegral v
class SDivisible a where
sQuotRem :: a -> a -> (a, a)
sDivMod :: a -> a -> (a, a)
sQuot :: a -> a -> a
sRem :: a -> a -> a
sDiv :: a -> a -> a
sMod :: a -> a -> a
x `sQuot` y = fst $ x `sQuotRem` y
x `sRem` y = snd $ x `sQuotRem` y
x `sDiv` y = fst $ x `sDivMod` y
x `sMod` y = snd $ x `sDivMod` y
instance SDivisible Word64 where
sQuotRem x 0 = (0, x)
sQuotRem x y = x `quotRem` y
sDivMod x 0 = (0, x)
sDivMod x y = x `divMod` y
instance SDivisible Int64 where
sQuotRem x 0 = (0, x)
sQuotRem x y = x `quotRem` y
sDivMod x 0 = (0, x)
sDivMod x y = x `divMod` y
instance SDivisible Word32 where
sQuotRem x 0 = (0, x)
sQuotRem x y = x `quotRem` y
sDivMod x 0 = (0, x)
sDivMod x y = x `divMod` y
instance SDivisible Int32 where
sQuotRem x 0 = (0, x)
sQuotRem x y = x `quotRem` y
sDivMod x 0 = (0, x)
sDivMod x y = x `divMod` y
instance SDivisible Word16 where
sQuotRem x 0 = (0, x)
sQuotRem x y = x `quotRem` y
sDivMod x 0 = (0, x)
sDivMod x y = x `divMod` y
instance SDivisible Int16 where
sQuotRem x 0 = (0, x)
sQuotRem x y = x `quotRem` y
sDivMod x 0 = (0, x)
sDivMod x y = x `divMod` y
instance SDivisible Word8 where
sQuotRem x 0 = (0, x)
sQuotRem x y = x `quotRem` y
sDivMod x 0 = (0, x)
sDivMod x y = x `divMod` y
instance SDivisible Int8 where
sQuotRem x 0 = (0, x)
sQuotRem x y = x `quotRem` y
sDivMod x 0 = (0, x)
sDivMod x y = x `divMod` y
instance SDivisible Integer where
sQuotRem x 0 = (0, x)
sQuotRem x y = x `quotRem` y
sDivMod x 0 = (0, x)
sDivMod x y = x `divMod` y
instance SDivisible CW where
sQuotRem a b
| CWInteger x <- cwVal a, CWInteger y <- cwVal b
= let (r1, r2) = sQuotRem x y in (normCW a{ cwVal = CWInteger r1 }, normCW b{ cwVal = CWInteger r2 })
sQuotRem a b = error $ "SBV.sQuotRem: impossible, unexpected args received: " ++ show (a, b)
sDivMod a b
| CWInteger x <- cwVal a, CWInteger y <- cwVal b
= let (r1, r2) = sDivMod x y in (normCW a { cwVal = CWInteger r1 }, normCW b { cwVal = CWInteger r2 })
sDivMod a b = error $ "SBV.sDivMod: impossible, unexpected args received: " ++ show (a, b)
instance SDivisible SWord64 where
sQuotRem = liftQRem
sDivMod = liftDMod
instance SDivisible SInt64 where
sQuotRem = liftQRem
sDivMod = liftDMod
instance SDivisible SWord32 where
sQuotRem = liftQRem
sDivMod = liftDMod
instance SDivisible SInt32 where
sQuotRem = liftQRem
sDivMod = liftDMod
instance SDivisible SWord16 where
sQuotRem = liftQRem
sDivMod = liftDMod
instance SDivisible SInt16 where
sQuotRem = liftQRem
sDivMod = liftDMod
instance SDivisible SWord8 where
sQuotRem = liftQRem
sDivMod = liftDMod
instance SDivisible SInt8 where
sQuotRem = liftQRem
sDivMod = liftDMod
liftQRem :: SymWord a => SBV a -> SBV a -> (SBV a, SBV a)
liftQRem x y
| isConcreteZero x
= (x, x)
| isConcreteOne y
= (x, z)
| True
= ite (y .== z) (z, x) (qr x y)
where qr (SBV (SVal sgnsz (Left a))) (SBV (SVal _ (Left b))) = let (q, r) = sQuotRem a b in (SBV (SVal sgnsz (Left q)), SBV (SVal sgnsz (Left r)))
qr a@(SBV (SVal sgnsz _)) b = (SBV (SVal sgnsz (Right (cache (mk Quot)))), SBV (SVal sgnsz (Right (cache (mk Rem)))))
where mk o st = do sw1 <- sbvToSW st a
sw2 <- sbvToSW st b
mkSymOp o st sgnsz sw1 sw2
z = genLiteral (kindOf x) (0::Integer)
liftDMod :: (SymWord a, Num a, SDivisible (SBV a)) => SBV a -> SBV a -> (SBV a, SBV a)
liftDMod x y
| isConcreteZero x
= (x, x)
| isConcreteOne y
= (x, z)
| True
= ite (y .== z) (z, x) $ ite (signum r .== negate (signum y)) (q-i, r+y) qr
where qr@(q, r) = x `sQuotRem` y
z = genLiteral (kindOf x) (0::Integer)
i = genLiteral (kindOf x) (1::Integer)
instance SDivisible SInteger where
sDivMod = liftDMod
sQuotRem x y
| not (isSymbolic x || isSymbolic y)
= liftQRem x y
| True
= ite (y .== 0) (0, x) (qE+i, rE-i*y)
where (qE, rE) = liftQRem x y
i = ite (x .>= 0 ||| rE .== 0) 0
$ ite (y .> 0) 1 (-1)
instance (SymWord a, Arbitrary a) => Arbitrary (SBV a) where
arbitrary = literal `fmap` arbitrary
class Mergeable a where
symbolicMerge :: Bool -> SBool -> a -> a -> a
select :: (SymWord b, Num b) => [a] -> a -> SBV b -> a
select xs err ind
| isReal ind = bad "real"
| isFloat ind = bad "float"
| isDouble ind = bad "double"
| hasSign ind = ite (ind .< 0) err (walk xs ind err)
| True = walk xs ind err
where bad w = error $ "SBV.select: unsupported " ++ w ++ " valued select/index expression"
walk [] _ acc = acc
walk (e:es) i acc = walk es (i-1) (ite (i .== 0) e acc)
default symbolicMerge :: (G.Generic a, GMergeable (G.Rep a)) => Bool -> SBool -> a -> a -> a
symbolicMerge = symbolicMergeDefault
ite :: Mergeable a => SBool -> a -> a -> a
ite t a b
| Just r <- unliteral t = if r then a else b
| True = symbolicMerge True t a b
iteLazy :: Mergeable a => SBool -> a -> a -> a
iteLazy t a b
| Just r <- unliteral t = if r then a else b
| True = symbolicMerge False t a b
sAssert :: Maybe CallStack -> String -> SBool -> SBV a -> SBV a
sAssert cs msg cond x
| Just mustHold <- unliteral cond
= if mustHold
then x
else error $ show $ SafeResult ((locInfo . getCallStack) `fmap` cs, msg, Satisfiable defaultSMTCfg (SMTModel [] []))
| True
= SBV $ SVal k $ Right $ cache r
where k = kindOf x
r st = do xsw <- sbvToSW st x
let pc = getPathCondition st
mustNeverHappen = pc &&& bnot cond
cnd <- sbvToSW st mustNeverHappen
addAssertion st cs msg cnd
return xsw
locInfo ps = intercalate ",\n " (map loc ps)
where loc (f, sl) = concat [srcLocFile sl, ":", show (srcLocStartLine sl), ":", show (srcLocStartCol sl), ":", f]
symbolicMergeWithKind :: Kind -> Bool -> SBool -> SBV a -> SBV a -> SBV a
symbolicMergeWithKind k force (SBV t) (SBV a) (SBV b) = SBV (svSymbolicMerge k force t a b)
instance SymWord a => Mergeable (SBV a) where
symbolicMerge force t x y
| force = symbolicMergeWithKind (kindOf x) True t x y
| True = symbolicMergeWithKind (kindOf (undefined :: a)) False t x y
select xs err ind
| SBV (SVal _ (Left c)) <- ind = case cwVal c of
CWInteger i -> if i < 0 || i >= genericLength xs
then err
else xs `genericIndex` i
_ -> error $ "SBV.select: unsupported " ++ show (kindOf ind) ++ " valued select/index expression"
select xsOrig err ind = xs `seq` SBV (SVal kElt (Right (cache r)))
where kInd = kindOf ind
kElt = kindOf err
xs = case kindOf ind of
KBounded False i -> genericTake ((2::Integer) ^ (fromIntegral i :: Integer)) xsOrig
KBounded True i -> genericTake ((2::Integer) ^ (fromIntegral (i-1) :: Integer)) xsOrig
KUnbounded -> xsOrig
_ -> error $ "SBV.select: unsupported " ++ show (kindOf ind) ++ " valued select/index expression"
r st = do sws <- mapM (sbvToSW st) xs
swe <- sbvToSW st err
if all (== swe) sws
then return swe
else do idx <- getTableIndex st kInd kElt sws
swi <- sbvToSW st ind
let len = length xs
newExpr st kElt (SBVApp (LkUp (idx, kInd, kElt, len) swi swe) [])
instance Mergeable () where
symbolicMerge _ _ _ _ = ()
select _ _ _ = ()
instance Mergeable a => Mergeable [a] where
symbolicMerge f t xs ys
| lxs == lys = zipWith (symbolicMerge f t) xs ys
| True = error $ "SBV.Mergeable.List: No least-upper-bound for lists of differing size " ++ show (lxs, lys)
where (lxs, lys) = (length xs, length ys)
instance Mergeable a => Mergeable (ZipList a) where
symbolicMerge force test (ZipList xs) (ZipList ys)
= ZipList (symbolicMerge force test xs ys)
instance Mergeable a => Mergeable (Maybe a) where
symbolicMerge _ _ Nothing Nothing = Nothing
symbolicMerge f t (Just a) (Just b) = Just $ symbolicMerge f t a b
symbolicMerge _ _ a b = error $ "SBV.Mergeable.Maybe: No least-upper-bound for " ++ show (k a, k b)
where k Nothing = "Nothing"
k _ = "Just"
instance (Mergeable a, Mergeable b) => Mergeable (Either a b) where
symbolicMerge f t (Left a) (Left b) = Left $ symbolicMerge f t a b
symbolicMerge f t (Right a) (Right b) = Right $ symbolicMerge f t a b
symbolicMerge _ _ a b = error $ "SBV.Mergeable.Either: No least-upper-bound for " ++ show (k a, k b)
where k (Left _) = "Left"
k (Right _) = "Right"
instance (Ix a, Mergeable b) => Mergeable (Array a b) where
symbolicMerge f t a b
| ba == bb = listArray ba (zipWith (symbolicMerge f t) (elems a) (elems b))
| True = error $ "SBV.Mergeable.Array: No least-upper-bound for rangeSizes" ++ show (k ba, k bb)
where [ba, bb] = map bounds [a, b]
k = rangeSize
instance Mergeable b => Mergeable (a -> b) where
symbolicMerge f t g h x = symbolicMerge f t (g x) (h x)
instance (Mergeable a, Mergeable b) => Mergeable (a, b) where
symbolicMerge f t (i0, i1) (j0, j1) = (i i0 j0, i i1 j1)
where i a b = symbolicMerge f t a b
select xs (err1, err2) ind = (select as err1 ind, select bs err2 ind)
where (as, bs) = unzip xs
instance (Mergeable a, Mergeable b, Mergeable c) => Mergeable (a, b, c) where
symbolicMerge f t (i0, i1, i2) (j0, j1, j2) = (i i0 j0, i i1 j1, i i2 j2)
where i a b = symbolicMerge f t a b
select xs (err1, err2, err3) ind = (select as err1 ind, select bs err2 ind, select cs err3 ind)
where (as, bs, cs) = unzip3 xs
instance (Mergeable a, Mergeable b, Mergeable c, Mergeable d) => Mergeable (a, b, c, d) where
symbolicMerge f t (i0, i1, i2, i3) (j0, j1, j2, j3) = (i i0 j0, i i1 j1, i i2 j2, i i3 j3)
where i a b = symbolicMerge f t a b
select xs (err1, err2, err3, err4) ind = (select as err1 ind, select bs err2 ind, select cs err3 ind, select ds err4 ind)
where (as, bs, cs, ds) = unzip4 xs
instance (Mergeable a, Mergeable b, Mergeable c, Mergeable d, Mergeable e) => Mergeable (a, b, c, d, e) where
symbolicMerge f t (i0, i1, i2, i3, i4) (j0, j1, j2, j3, j4) = (i i0 j0, i i1 j1, i i2 j2, i i3 j3, i i4 j4)
where i a b = symbolicMerge f t a b
select xs (err1, err2, err3, err4, err5) ind = (select as err1 ind, select bs err2 ind, select cs err3 ind, select ds err4 ind, select es err5 ind)
where (as, bs, cs, ds, es) = unzip5 xs
instance (Mergeable a, Mergeable b, Mergeable c, Mergeable d, Mergeable e, Mergeable f) => Mergeable (a, b, c, d, e, f) where
symbolicMerge f t (i0, i1, i2, i3, i4, i5) (j0, j1, j2, j3, j4, j5) = (i i0 j0, i i1 j1, i i2 j2, i i3 j3, i i4 j4, i i5 j5)
where i a b = symbolicMerge f t a b
select xs (err1, err2, err3, err4, err5, err6) ind = (select as err1 ind, select bs err2 ind, select cs err3 ind, select ds err4 ind, select es err5 ind, select fs err6 ind)
where (as, bs, cs, ds, es, fs) = unzip6 xs
instance (Mergeable a, Mergeable b, Mergeable c, Mergeable d, Mergeable e, Mergeable f, Mergeable g) => Mergeable (a, b, c, d, e, f, g) where
symbolicMerge f t (i0, i1, i2, i3, i4, i5, i6) (j0, j1, j2, j3, j4, j5, j6) = (i i0 j0, i i1 j1, i i2 j2, i i3 j3, i i4 j4, i i5 j5, i i6 j6)
where i a b = symbolicMerge f t a b
select xs (err1, err2, err3, err4, err5, err6, err7) ind = (select as err1 ind, select bs err2 ind, select cs err3 ind, select ds err4 ind, select es err5 ind, select fs err6 ind, select gs err7 ind)
where (as, bs, cs, ds, es, fs, gs) = unzip7 xs
symbolicMergeDefault :: (G.Generic a, GMergeable (G.Rep a)) => Bool -> SBool -> a -> a -> a
symbolicMergeDefault force t x y = G.to $ symbolicMerge' force t (G.from x) (G.from y)
class GMergeable f where
symbolicMerge' :: Bool -> SBool -> f a -> f a -> f a
instance GMergeable U1 where
symbolicMerge' _ _ _ _ = U1
instance (Mergeable c) => GMergeable (K1 i c) where
symbolicMerge' force t (K1 x) (K1 y) = K1 $ symbolicMerge force t x y
instance (GMergeable f) => GMergeable (M1 i c f) where
symbolicMerge' force t (M1 x) (M1 y) = M1 $ symbolicMerge' force t x y
instance (GMergeable f, GMergeable g) => GMergeable (f :*: g) where
symbolicMerge' force t (x1 :*: y1) (x2 :*: y2) = symbolicMerge' force t x1 x2 :*: symbolicMerge' force t y1 y2
instance (SymWord a, Bounded a) => Bounded (SBV a) where
minBound = literal minBound
maxBound = literal maxBound
instance EqSymbolic (SArray a b) where
SArray a .== SArray b = SBV (a `eqSArr` b)
instance SymWord b => Mergeable (SArray a b) where
symbolicMerge _ = mergeArrays
instance SymWord b => Mergeable (SFunArray a b) where
symbolicMerge _ = mergeArrays
class Uninterpreted a where
uninterpret :: String -> a
cgUninterpret :: String -> [String] -> a -> a
sbvUninterpret :: Maybe ([String], a) -> String -> a
{-# MINIMAL sbvUninterpret #-}
uninterpret = sbvUninterpret Nothing
cgUninterpret nm code v = sbvUninterpret (Just (code, v)) nm
instance HasKind a => Uninterpreted (SBV a) where
sbvUninterpret mbCgData nm
| Just (_, v) <- mbCgData = v
| True = SBV $ SVal ka $ Right $ cache result
where ka = kindOf (undefined :: a)
result st = do isSMT <- inSMTMode st
case (isSMT, mbCgData) of
(True, Just (_, v)) -> sbvToSW st v
_ -> do newUninterpreted st nm (SBVType [ka]) (fst `fmap` mbCgData)
newExpr st ka $ SBVApp (Uninterpreted nm) []
instance (SymWord b, HasKind a) => Uninterpreted (SBV b -> SBV a) where
sbvUninterpret mbCgData nm = f
where f arg0
| Just (_, v) <- mbCgData, isConcrete arg0
= v arg0
| True
= SBV $ SVal ka $ Right $ cache result
where ka = kindOf (undefined :: a)
kb = kindOf (undefined :: b)
result st = do isSMT <- inSMTMode st
case (isSMT, mbCgData) of
(True, Just (_, v)) -> sbvToSW st (v arg0)
_ -> do newUninterpreted st nm (SBVType [kb, ka]) (fst `fmap` mbCgData)
sw0 <- sbvToSW st arg0
mapM_ forceSWArg [sw0]
newExpr st ka $ SBVApp (Uninterpreted nm) [sw0]
instance (SymWord c, SymWord b, HasKind a) => Uninterpreted (SBV c -> SBV b -> SBV a) where
sbvUninterpret mbCgData nm = f
where f arg0 arg1
| Just (_, v) <- mbCgData, isConcrete arg0, isConcrete arg1
= v arg0 arg1
| True
= SBV $ SVal ka $ Right $ cache result
where ka = kindOf (undefined :: a)
kb = kindOf (undefined :: b)
kc = kindOf (undefined :: c)
result st = do isSMT <- inSMTMode st
case (isSMT, mbCgData) of
(True, Just (_, v)) -> sbvToSW st (v arg0 arg1)
_ -> do newUninterpreted st nm (SBVType [kc, kb, ka]) (fst `fmap` mbCgData)
sw0 <- sbvToSW st arg0
sw1 <- sbvToSW st arg1
mapM_ forceSWArg [sw0, sw1]
newExpr st ka $ SBVApp (Uninterpreted nm) [sw0, sw1]
instance (SymWord d, SymWord c, SymWord b, HasKind a) => Uninterpreted (SBV d -> SBV c -> SBV b -> SBV a) where
sbvUninterpret mbCgData nm = f
where f arg0 arg1 arg2
| Just (_, v) <- mbCgData, isConcrete arg0, isConcrete arg1, isConcrete arg2
= v arg0 arg1 arg2
| True
= SBV $ SVal ka $ Right $ cache result
where ka = kindOf (undefined :: a)
kb = kindOf (undefined :: b)
kc = kindOf (undefined :: c)
kd = kindOf (undefined :: d)
result st = do isSMT <- inSMTMode st
case (isSMT, mbCgData) of
(True, Just (_, v)) -> sbvToSW st (v arg0 arg1 arg2)
_ -> do newUninterpreted st nm (SBVType [kd, kc, kb, ka]) (fst `fmap` mbCgData)
sw0 <- sbvToSW st arg0
sw1 <- sbvToSW st arg1
sw2 <- sbvToSW st arg2
mapM_ forceSWArg [sw0, sw1, sw2]
newExpr st ka $ SBVApp (Uninterpreted nm) [sw0, sw1, sw2]
instance (SymWord e, SymWord d, SymWord c, SymWord b, HasKind a) => Uninterpreted (SBV e -> SBV d -> SBV c -> SBV b -> SBV a) where
sbvUninterpret mbCgData nm = f
where f arg0 arg1 arg2 arg3
| Just (_, v) <- mbCgData, isConcrete arg0, isConcrete arg1, isConcrete arg2, isConcrete arg3
= v arg0 arg1 arg2 arg3
| True
= SBV $ SVal ka $ Right $ cache result
where ka = kindOf (undefined :: a)
kb = kindOf (undefined :: b)
kc = kindOf (undefined :: c)
kd = kindOf (undefined :: d)
ke = kindOf (undefined :: e)
result st = do isSMT <- inSMTMode st
case (isSMT, mbCgData) of
(True, Just (_, v)) -> sbvToSW st (v arg0 arg1 arg2 arg3)
_ -> do newUninterpreted st nm (SBVType [ke, kd, kc, kb, ka]) (fst `fmap` mbCgData)
sw0 <- sbvToSW st arg0
sw1 <- sbvToSW st arg1
sw2 <- sbvToSW st arg2
sw3 <- sbvToSW st arg3
mapM_ forceSWArg [sw0, sw1, sw2, sw3]
newExpr st ka $ SBVApp (Uninterpreted nm) [sw0, sw1, sw2, sw3]
instance (SymWord f, SymWord e, SymWord d, SymWord c, SymWord b, HasKind a) => Uninterpreted (SBV f -> SBV e -> SBV d -> SBV c -> SBV b -> SBV a) where
sbvUninterpret mbCgData nm = f
where f arg0 arg1 arg2 arg3 arg4
| Just (_, v) <- mbCgData, isConcrete arg0, isConcrete arg1, isConcrete arg2, isConcrete arg3, isConcrete arg4
= v arg0 arg1 arg2 arg3 arg4
| True
= SBV $ SVal ka $ Right $ cache result
where ka = kindOf (undefined :: a)
kb = kindOf (undefined :: b)
kc = kindOf (undefined :: c)
kd = kindOf (undefined :: d)
ke = kindOf (undefined :: e)
kf = kindOf (undefined :: f)
result st = do isSMT <- inSMTMode st
case (isSMT, mbCgData) of
(True, Just (_, v)) -> sbvToSW st (v arg0 arg1 arg2 arg3 arg4)
_ -> do newUninterpreted st nm (SBVType [kf, ke, kd, kc, kb, ka]) (fst `fmap` mbCgData)
sw0 <- sbvToSW st arg0
sw1 <- sbvToSW st arg1
sw2 <- sbvToSW st arg2
sw3 <- sbvToSW st arg3
sw4 <- sbvToSW st arg4
mapM_ forceSWArg [sw0, sw1, sw2, sw3, sw4]
newExpr st ka $ SBVApp (Uninterpreted nm) [sw0, sw1, sw2, sw3, sw4]
instance (SymWord g, SymWord f, SymWord e, SymWord d, SymWord c, SymWord b, HasKind a) => Uninterpreted (SBV g -> SBV f -> SBV e -> SBV d -> SBV c -> SBV b -> SBV a) where
sbvUninterpret mbCgData nm = f
where f arg0 arg1 arg2 arg3 arg4 arg5
| Just (_, v) <- mbCgData, isConcrete arg0, isConcrete arg1, isConcrete arg2, isConcrete arg3, isConcrete arg4, isConcrete arg5
= v arg0 arg1 arg2 arg3 arg4 arg5
| True
= SBV $ SVal ka $ Right $ cache result
where ka = kindOf (undefined :: a)
kb = kindOf (undefined :: b)
kc = kindOf (undefined :: c)
kd = kindOf (undefined :: d)
ke = kindOf (undefined :: e)
kf = kindOf (undefined :: f)
kg = kindOf (undefined :: g)
result st = do isSMT <- inSMTMode st
case (isSMT, mbCgData) of
(True, Just (_, v)) -> sbvToSW st (v arg0 arg1 arg2 arg3 arg4 arg5)
_ -> do newUninterpreted st nm (SBVType [kg, kf, ke, kd, kc, kb, ka]) (fst `fmap` mbCgData)
sw0 <- sbvToSW st arg0
sw1 <- sbvToSW st arg1
sw2 <- sbvToSW st arg2
sw3 <- sbvToSW st arg3
sw4 <- sbvToSW st arg4
sw5 <- sbvToSW st arg5
mapM_ forceSWArg [sw0, sw1, sw2, sw3, sw4, sw5]
newExpr st ka $ SBVApp (Uninterpreted nm) [sw0, sw1, sw2, sw3, sw4, sw5]
instance (SymWord h, SymWord g, SymWord f, SymWord e, SymWord d, SymWord c, SymWord b, HasKind a)
=> Uninterpreted (SBV h -> SBV g -> SBV f -> SBV e -> SBV d -> SBV c -> SBV b -> SBV a) where
sbvUninterpret mbCgData nm = f
where f arg0 arg1 arg2 arg3 arg4 arg5 arg6
| Just (_, v) <- mbCgData, isConcrete arg0, isConcrete arg1, isConcrete arg2, isConcrete arg3, isConcrete arg4, isConcrete arg5, isConcrete arg6
= v arg0 arg1 arg2 arg3 arg4 arg5 arg6
| True
= SBV $ SVal ka $ Right $ cache result
where ka = kindOf (undefined :: a)
kb = kindOf (undefined :: b)
kc = kindOf (undefined :: c)
kd = kindOf (undefined :: d)
ke = kindOf (undefined :: e)
kf = kindOf (undefined :: f)
kg = kindOf (undefined :: g)
kh = kindOf (undefined :: h)
result st = do isSMT <- inSMTMode st
case (isSMT, mbCgData) of
(True, Just (_, v)) -> sbvToSW st (v arg0 arg1 arg2 arg3 arg4 arg5 arg6)
_ -> do newUninterpreted st nm (SBVType [kh, kg, kf, ke, kd, kc, kb, ka]) (fst `fmap` mbCgData)
sw0 <- sbvToSW st arg0
sw1 <- sbvToSW st arg1
sw2 <- sbvToSW st arg2
sw3 <- sbvToSW st arg3
sw4 <- sbvToSW st arg4
sw5 <- sbvToSW st arg5
sw6 <- sbvToSW st arg6
mapM_ forceSWArg [sw0, sw1, sw2, sw3, sw4, sw5, sw6]
newExpr st ka $ SBVApp (Uninterpreted nm) [sw0, sw1, sw2, sw3, sw4, sw5, sw6]
instance (SymWord c, SymWord b, HasKind a) => Uninterpreted ((SBV c, SBV b) -> SBV a) where
sbvUninterpret mbCgData nm = let f = sbvUninterpret (uc2 `fmap` mbCgData) nm in uncurry f
where uc2 (cs, fn) = (cs, curry fn)
instance (SymWord d, SymWord c, SymWord b, HasKind a) => Uninterpreted ((SBV d, SBV c, SBV b) -> SBV a) where
sbvUninterpret mbCgData nm = let f = sbvUninterpret (uc3 `fmap` mbCgData) nm in \(arg0, arg1, arg2) -> f arg0 arg1 arg2
where uc3 (cs, fn) = (cs, \a b c -> fn (a, b, c))
instance (SymWord e, SymWord d, SymWord c, SymWord b, HasKind a)
=> Uninterpreted ((SBV e, SBV d, SBV c, SBV b) -> SBV a) where
sbvUninterpret mbCgData nm = let f = sbvUninterpret (uc4 `fmap` mbCgData) nm in \(arg0, arg1, arg2, arg3) -> f arg0 arg1 arg2 arg3
where uc4 (cs, fn) = (cs, \a b c d -> fn (a, b, c, d))
instance (SymWord f, SymWord e, SymWord d, SymWord c, SymWord b, HasKind a)
=> Uninterpreted ((SBV f, SBV e, SBV d, SBV c, SBV b) -> SBV a) where
sbvUninterpret mbCgData nm = let f = sbvUninterpret (uc5 `fmap` mbCgData) nm in \(arg0, arg1, arg2, arg3, arg4) -> f arg0 arg1 arg2 arg3 arg4
where uc5 (cs, fn) = (cs, \a b c d e -> fn (a, b, c, d, e))
instance (SymWord g, SymWord f, SymWord e, SymWord d, SymWord c, SymWord b, HasKind a)
=> Uninterpreted ((SBV g, SBV f, SBV e, SBV d, SBV c, SBV b) -> SBV a) where
sbvUninterpret mbCgData nm = let f = sbvUninterpret (uc6 `fmap` mbCgData) nm in \(arg0, arg1, arg2, arg3, arg4, arg5) -> f arg0 arg1 arg2 arg3 arg4 arg5
where uc6 (cs, fn) = (cs, \a b c d e f -> fn (a, b, c, d, e, f))
instance (SymWord h, SymWord g, SymWord f, SymWord e, SymWord d, SymWord c, SymWord b, HasKind a)
=> Uninterpreted ((SBV h, SBV g, SBV f, SBV e, SBV d, SBV c, SBV b) -> SBV a) where
sbvUninterpret mbCgData nm = let f = sbvUninterpret (uc7 `fmap` mbCgData) nm in \(arg0, arg1, arg2, arg3, arg4, arg5, arg6) -> f arg0 arg1 arg2 arg3 arg4 arg5 arg6
where uc7 (cs, fn) = (cs, \a b c d e f g -> fn (a, b, c, d, e, f, g))
instance SolverContext Symbolic where
constrain (SBV c) = imposeConstraint False [] c
softConstrain (SBV c) = imposeConstraint True [] c
namedConstraint nm (SBV c) = imposeConstraint False [(":named", nm)] c
constrainWithAttribute atts (SBV c) = imposeConstraint False atts c
setOption o = addNewSMTOption o
assertWithPenalty :: String -> SBool -> Penalty -> Symbolic ()
assertWithPenalty nm o p = addSValOptGoal $ unSBV `fmap` AssertWithPenalty nm o p
class Metric a where
minimize :: String -> a -> Symbolic ()
maximize :: String -> a -> Symbolic ()
instance Metric SWord8 where minimize nm o = addSValOptGoal (unSBV `fmap` Minimize nm o); maximize nm o = addSValOptGoal (unSBV `fmap` Maximize nm o)
instance Metric SWord16 where minimize nm o = addSValOptGoal (unSBV `fmap` Minimize nm o); maximize nm o = addSValOptGoal (unSBV `fmap` Maximize nm o)
instance Metric SWord32 where minimize nm o = addSValOptGoal (unSBV `fmap` Minimize nm o); maximize nm o = addSValOptGoal (unSBV `fmap` Maximize nm o)
instance Metric SWord64 where minimize nm o = addSValOptGoal (unSBV `fmap` Minimize nm o); maximize nm o = addSValOptGoal (unSBV `fmap` Maximize nm o)
instance Metric SInt8 where minimize nm o = addSValOptGoal (unSBV `fmap` Minimize nm o); maximize nm o = addSValOptGoal (unSBV `fmap` Maximize nm o)
instance Metric SInt16 where minimize nm o = addSValOptGoal (unSBV `fmap` Minimize nm o); maximize nm o = addSValOptGoal (unSBV `fmap` Maximize nm o)
instance Metric SInt32 where minimize nm o = addSValOptGoal (unSBV `fmap` Minimize nm o); maximize nm o = addSValOptGoal (unSBV `fmap` Maximize nm o)
instance Metric SInt64 where minimize nm o = addSValOptGoal (unSBV `fmap` Minimize nm o); maximize nm o = addSValOptGoal (unSBV `fmap` Maximize nm o)
instance Metric SInteger where minimize nm o = addSValOptGoal (unSBV `fmap` Minimize nm o); maximize nm o = addSValOptGoal (unSBV `fmap` Maximize nm o)
instance Metric SReal where minimize nm o = addSValOptGoal (unSBV `fmap` Minimize nm o); maximize nm o = addSValOptGoal (unSBV `fmap` Maximize nm o)
instance Testable SBool where
property (SBV (SVal _ (Left b))) = property (cwToBool b)
property _ = error "Quick-check: Constant folding produced a symbolic value! Perhaps used a non-reducible expression? Please report!"
instance Testable (Symbolic SBool) where
property prop = QC.monadicIO $ do (cond, r, modelVals) <- QC.run test
QC.pre cond
unless (r || null modelVals) $ QC.monitor (QC.counterexample (complain modelVals))
QC.assert r
where test = do (r, Result{resTraces=tvals, resObservables=ovals, resConsts=cs, resConstraints=cstrs, resUIConsts=unints}) <- runSymbolic Concrete prop
let cval = fromMaybe (error "Cannot quick-check in the presence of uninterpeted constants!") . (`lookup` cs)
cond = and [cwToBool (cval v) | (False, _, v) <- cstrs]
getObservable (nm, v) = case v `lookup` cs of
Just cw -> (nm, cw)
Nothing -> error $ "Quick-check: Observable " ++ nm ++ " did not reduce to a constant!"
case map fst unints of
[] -> case unliteral r of
Nothing -> noQC [show r]
Just b -> return (cond, b, tvals ++ map getObservable ovals)
us -> noQC us
complain qcInfo = showModel defaultSMTCfg (SMTModel [] qcInfo)
noQC us = error $ "Cannot quick-check in the presence of uninterpreted constants: " ++ intercalate ", " us
sbvQuickCheck :: Symbolic SBool -> IO Bool
sbvQuickCheck prop = QC.isSuccess `fmap` QC.quickCheckResult prop
instance Testable (Symbolic SVal) where
property m = property $ do s <- m
when (kindOf s /= KBool) $ error "Cannot quickcheck non-boolean value"
return (SBV s :: SBool)
slet :: forall a b. (HasKind a, HasKind b) => SBV a -> (SBV a -> SBV b) -> SBV b
slet x f = SBV $ SVal k $ Right $ cache r
where k = kindOf (undefined :: b)
r st = do xsw <- sbvToSW st x
let xsbv = SBV $ SVal (kindOf x) (Right (cache (const (return xsw))))
res = f xsbv
sbvToSW st res
{-# ANN module ("HLint: ignore Reduce duplication" :: String) #-}
{-# ANN module ("HLint: ignore Eta reduce" :: String) #-}