{-# LANGUAGE BangPatterns #-}
module Data.SBV.Core.Operations
(
svTrue, svFalse, svBool
, svInteger, svFloat, svDouble, svReal, svEnumFromThenTo, svString, svChar
, svAsBool, svAsInteger, svNumerator, svDenominator
, svPlus, svTimes, svMinus, svUNeg, svAbs
, svDivide, svQuot, svRem, svQuotRem
, svEqual, svNotEqual
, svLessThan, svGreaterThan, svLessEq, svGreaterEq
, svAnd, svOr, svXOr, svNot
, svShl, svShr, svRol, svRor
, svExtract, svJoin
, svUninterpreted
, svIte, svLazyIte, svSymbolicMerge
, svSelect
, svSign, svUnsign, svSetBit, svWordFromBE, svWordFromLE
, svExp, svFromIntegral
, svToWord1, svFromWord1, svTestBit
, svShiftLeft, svShiftRight
, svRotateLeft, svRotateRight
, svBlastLE, svBlastBE
, svAddConstant, svIncrement, svDecrement
)
where
import Data.Bits (Bits(..))
import Data.List (genericIndex, genericLength, genericTake)
import Data.SBV.Core.AlgReals
import Data.SBV.Core.Kind
import Data.SBV.Core.Concrete
import Data.SBV.Core.Symbolic
import Data.Ratio
svTrue :: SVal
svTrue = SVal KBool (Left trueCW)
svFalse :: SVal
svFalse = SVal KBool (Left falseCW)
svBool :: Bool -> SVal
svBool b = if b then svTrue else svFalse
svInteger :: Kind -> Integer -> SVal
svInteger k n = SVal k (Left $! mkConstCW k n)
svFloat :: Float -> SVal
svFloat f = SVal KFloat (Left $! CW KFloat (CWFloat f))
svDouble :: Double -> SVal
svDouble d = SVal KDouble (Left $! CW KDouble (CWDouble d))
svString :: String -> SVal
svString s = SVal KString (Left $! CW KString (CWString s))
svChar :: Char -> SVal
svChar c = SVal KChar (Left $! CW KChar (CWChar c))
svReal :: Rational -> SVal
svReal d = SVal KReal (Left $! CW KReal (CWAlgReal (fromRational d)))
svAsBool :: SVal -> Maybe Bool
svAsBool (SVal _ (Left cw)) = Just (cwToBool cw)
svAsBool _ = Nothing
svAsInteger :: SVal -> Maybe Integer
svAsInteger (SVal _ (Left (CW _ (CWInteger n)))) = Just n
svAsInteger _ = Nothing
svNumerator :: SVal -> Maybe Integer
svNumerator (SVal KReal (Left (CW KReal (CWAlgReal (AlgRational True r))))) = Just $ numerator r
svNumerator _ = Nothing
svDenominator :: SVal -> Maybe Integer
svDenominator (SVal KReal (Left (CW KReal (CWAlgReal (AlgRational True r))))) = Just $ denominator r
svDenominator _ = Nothing
svEnumFromThenTo :: SVal -> Maybe SVal -> SVal -> Maybe [SVal]
svEnumFromThenTo bf mbs bt
| Just bs <- mbs, Just f <- svAsInteger bf, Just s <- svAsInteger bs, Just t <- svAsInteger bt, s /= f = Just $ map (svInteger (kindOf bf)) [f, s .. t]
| Nothing <- mbs, Just f <- svAsInteger bf, Just t <- svAsInteger bt = Just $ map (svInteger (kindOf bf)) [f .. t]
| True = Nothing
svPlus :: SVal -> SVal -> SVal
svPlus x y
| isConcreteZero x = y
| isConcreteZero y = x
| True = liftSym2 (mkSymOp Plus) rationalCheck (+) (+) (+) (+) x y
svTimes :: SVal -> SVal -> SVal
svTimes x y
| isConcreteZero x = x
| isConcreteZero y = y
| isConcreteOne x = y
| isConcreteOne y = x
| True = liftSym2 (mkSymOp Times) rationalCheck (*) (*) (*) (*) x y
svMinus :: SVal -> SVal -> SVal
svMinus x y
| isConcreteZero y = x
| True = liftSym2 (mkSymOp Minus) rationalCheck (-) (-) (-) (-) x y
svUNeg :: SVal -> SVal
svUNeg = liftSym1 (mkSymOp1 UNeg) negate negate negate negate
svAbs :: SVal -> SVal
svAbs = liftSym1 (mkSymOp1 Abs) abs abs abs abs
svDivide :: SVal -> SVal -> SVal
svDivide = liftSym2 (mkSymOp Quot) rationalCheck (/) idiv (/) (/)
where idiv x 0 = x
idiv x y = x `div` y
svExp :: SVal -> SVal -> SVal
svExp b e
| Just x <- svAsInteger e
= if x >= 0 then let go n v
| n == 0 = one
| even n = go (n `div` 2) (svTimes v v)
| True = svTimes v $ go (n `div` 2) (svTimes v v)
in go x b
else error $ "svExp: exponentiation: negative exponent: " ++ show x
| not (isBounded e) || hasSign e
= error $ "svExp: exponentiation only works with unsigned bounded symbolic exponents, kind: " ++ show (kindOf e)
| True
= prod $ zipWith (\use n -> svIte use n one)
(svBlastLE e)
(iterate (\x -> svTimes x x) b)
where prod = foldr svTimes one
one = svInteger (kindOf b) 1
svBlastLE :: SVal -> [SVal]
svBlastLE x = map (svTestBit x) [0 .. intSizeOf x - 1]
svSetBit :: SVal -> Int -> SVal
svSetBit x i = x `svOr` svInteger (kindOf x) (bit i :: Integer)
svBlastBE :: SVal -> [SVal]
svBlastBE = reverse . svBlastLE
svWordFromLE :: [SVal] -> SVal
svWordFromLE bs = go zero 0 bs
where zero = svInteger (KBounded False (length bs)) 0
go !acc _ [] = acc
go !acc !i (x:xs) = go (svIte x (svSetBit acc i) acc) (i+1) xs
svWordFromBE :: [SVal] -> SVal
svWordFromBE = svWordFromLE . reverse
svAddConstant :: Integral a => SVal -> a -> SVal
svAddConstant x i = x `svPlus` svInteger (kindOf x) (fromIntegral i)
svIncrement :: SVal -> SVal
svIncrement x = svAddConstant x (1::Integer)
svDecrement :: SVal -> SVal
svDecrement x = svAddConstant x (-1 :: Integer)
svQuot :: SVal -> SVal -> SVal
svQuot x y
| isConcreteZero x = x
| isConcreteZero y = svInteger (kindOf x) 0
| isConcreteOne y = x
| True = liftSym2 (mkSymOp Quot) nonzeroCheck
(noReal "quot") quot' (noFloat "quot") (noDouble "quot") x y
where
quot' a b | kindOf x == KUnbounded = div a (abs b) * signum b
| otherwise = quot a b
svRem :: SVal -> SVal -> SVal
svRem x y
| isConcreteZero x = x
| isConcreteZero y = x
| isConcreteOne y = svInteger (kindOf x) 0
| True = liftSym2 (mkSymOp Rem) nonzeroCheck
(noReal "rem") rem' (noFloat "rem") (noDouble "rem") x y
where
rem' a b | kindOf x == KUnbounded = mod a (abs b)
| otherwise = rem a b
svQuotRem :: SVal -> SVal -> (SVal, SVal)
svQuotRem x y = (x `svQuot` y, x `svRem` y)
eqOptBool :: Op -> SW -> SW -> SW -> Maybe SW
eqOptBool op w x y
| k == KBool && op == Equal && x == trueSW = Just y
| k == KBool && op == Equal && y == trueSW = Just x
| k == KBool && op == NotEqual && x == falseSW = Just y
| k == KBool && op == NotEqual && y == falseSW = Just x
| True = eqOpt w x y
where k = swKind x
svEqual :: SVal -> SVal -> SVal
svEqual = liftSym2B (mkSymOpSC (eqOptBool Equal trueSW) Equal) rationalCheck (==) (==) (==) (==) (==) (==) (==)
svNotEqual :: SVal -> SVal -> SVal
svNotEqual = liftSym2B (mkSymOpSC (eqOptBool NotEqual falseSW) NotEqual) rationalCheck (/=) (/=) (/=) (/=) (/=) (/=) (/=)
svLessThan :: SVal -> SVal -> SVal
svLessThan x y
| isConcreteMax x = svFalse
| isConcreteMin y = svFalse
| True = liftSym2B (mkSymOpSC (eqOpt falseSW) LessThan) rationalCheck (<) (<) (<) (<) (<) (<) (uiLift "<" (<)) x y
svGreaterThan :: SVal -> SVal -> SVal
svGreaterThan x y
| isConcreteMin x = svFalse
| isConcreteMax y = svFalse
| True = liftSym2B (mkSymOpSC (eqOpt falseSW) GreaterThan) rationalCheck (>) (>) (>) (>) (>) (>) (uiLift ">" (>)) x y
svLessEq :: SVal -> SVal -> SVal
svLessEq x y
| isConcreteMin x = svTrue
| isConcreteMax y = svTrue
| True = liftSym2B (mkSymOpSC (eqOpt trueSW) LessEq) rationalCheck (<=) (<=) (<=) (<=) (<=) (<=) (uiLift "<=" (<=)) x y
svGreaterEq :: SVal -> SVal -> SVal
svGreaterEq x y
| isConcreteMax x = svTrue
| isConcreteMin y = svTrue
| True = liftSym2B (mkSymOpSC (eqOpt trueSW) GreaterEq) rationalCheck (>=) (>=) (>=) (>=) (>=) (>=) (uiLift ">=" (>=)) x y
svAnd :: SVal -> SVal -> SVal
svAnd x y
| isConcreteZero x = x
| isConcreteOnes x = y
| isConcreteZero y = y
| isConcreteOnes y = x
| True = liftSym2 (mkSymOpSC opt And) (const (const True)) (noReal ".&.") (.&.) (noFloat ".&.") (noDouble ".&.") x y
where opt a b
| a == falseSW || b == falseSW = Just falseSW
| a == trueSW = Just b
| b == trueSW = Just a
| True = Nothing
svOr :: SVal -> SVal -> SVal
svOr x y
| isConcreteZero x = y
| isConcreteOnes x = x
| isConcreteZero y = x
| isConcreteOnes y = y
| True = liftSym2 (mkSymOpSC opt Or) (const (const True))
(noReal ".|.") (.|.) (noFloat ".|.") (noDouble ".|.") x y
where opt a b
| a == trueSW || b == trueSW = Just trueSW
| a == falseSW = Just b
| b == falseSW = Just a
| True = Nothing
svXOr :: SVal -> SVal -> SVal
svXOr x y
| isConcreteZero x = y
| isConcreteOnes x = svNot y
| isConcreteZero y = x
| isConcreteOnes y = svNot x
| True = liftSym2 (mkSymOpSC opt XOr) (const (const True))
(noReal "xor") xor (noFloat "xor") (noDouble "xor") x y
where opt a b
| a == b && swKind a == KBool = Just falseSW
| a == falseSW = Just b
| b == falseSW = Just a
| True = Nothing
svNot :: SVal -> SVal
svNot = liftSym1 (mkSymOp1SC opt Not)
(noRealUnary "complement") complement
(noFloatUnary "complement") (noDoubleUnary "complement")
where opt a
| a == falseSW = Just trueSW
| a == trueSW = Just falseSW
| True = Nothing
svShl :: SVal -> Int -> SVal
svShl x i
| i <= 0
= x
| isBounded x, i >= intSizeOf x
= svInteger k 0
| True
= x `svShiftLeft` svInteger k (fromIntegral i)
where k = kindOf x
svShr :: SVal -> Int -> SVal
svShr x i
| i <= 0
= x
| isBounded x, i >= intSizeOf x
= if not (hasSign x)
then z
else svIte (x `svLessThan` z) neg1 z
| True
= x `svShiftRight` svInteger k (fromIntegral i)
where k = kindOf x
z = svInteger k 0
neg1 = svInteger k (-1)
svRol :: SVal -> Int -> SVal
svRol x i
| i <= 0
= x
| True
= case kindOf x of
KBounded _ sz -> liftSym1 (mkSymOp1 (Rol (i `mod` sz)))
(noRealUnary "rotateL") (rot True sz i)
(noFloatUnary "rotateL") (noDoubleUnary "rotateL") x
_ -> svShl x i
svRor :: SVal -> Int -> SVal
svRor x i
| i <= 0
= x
| True
= case kindOf x of
KBounded _ sz -> liftSym1 (mkSymOp1 (Ror (i `mod` sz)))
(noRealUnary "rotateR") (rot False sz i)
(noFloatUnary "rotateR") (noDoubleUnary "rotateR") x
_ -> svShr x i
rot :: Bool -> Int -> Int -> Integer -> Integer
rot toLeft sz amt x
| sz < 2 = x
| True = norm x y' `shiftL` y .|. norm (x `shiftR` y') y
where (y, y') | toLeft = (amt `mod` sz, sz - y)
| True = (sz - y', amt `mod` sz)
norm v s = v .&. ((1 `shiftL` s) - 1)
svExtract :: Int -> Int -> SVal -> SVal
svExtract i j x@(SVal (KBounded s _) _)
| i < j
= SVal k (Left $! CW k (CWInteger 0))
| SVal _ (Left (CW _ (CWInteger v))) <- x
= SVal k (Left $! normCW (CW k (CWInteger (v `shiftR` j))))
| True
= SVal k (Right (cache y))
where k = KBounded s (i - j + 1)
y st = do sw <- svToSW st x
newExpr st k (SBVApp (Extract i j) [sw])
svExtract _ _ _ = error "extract: non-bitvector type"
svJoin :: SVal -> SVal -> SVal
svJoin x@(SVal (KBounded s i) a) y@(SVal (KBounded _ j) b)
| i == 0 = y
| j == 0 = x
| Left (CW _ (CWInteger m)) <- a, Left (CW _ (CWInteger n)) <- b
= SVal k (Left $! CW k (CWInteger (m `shiftL` j .|. n)))
| True
= SVal k (Right (cache z))
where
k = KBounded s (i + j)
z st = do xsw <- svToSW st x
ysw <- svToSW st y
newExpr st k (SBVApp Join [xsw, ysw])
svJoin _ _ = error "svJoin: non-bitvector type"
svUninterpreted :: Kind -> String -> Maybe [String] -> [SVal] -> SVal
svUninterpreted k nm code args = SVal k $ Right $ cache result
where result st = do let ty = SBVType (map kindOf args ++ [k])
newUninterpreted st nm ty code
sws <- mapM (svToSW st) args
mapM_ forceSWArg sws
newExpr st k $ SBVApp (Uninterpreted nm) sws
svIte :: SVal -> SVal -> SVal -> SVal
svIte t a b = svSymbolicMerge (kindOf a) True t a b
svLazyIte :: Kind -> SVal -> SVal -> SVal -> SVal
svLazyIte k t a b = svSymbolicMerge k False t a b
svSymbolicMerge :: Kind -> Bool -> SVal -> SVal -> SVal -> SVal
svSymbolicMerge k force t a b
| Just r <- svAsBool t
= if r then a else b
| force, rationalSBVCheck a b, areConcretelyEqual a b
= a
| True
= SVal k $ Right $ cache c
where c st = do swt <- svToSW st t
case () of
() | swt == trueSW -> svToSW st a
() | swt == falseSW -> svToSW st b
() -> do
let sta = st `extendSValPathCondition` svAnd t
let stb = st `extendSValPathCondition` svAnd (svNot t)
swa <- svToSW sta a
swb <- svToSW stb b
case () of
() | swa == swb -> return swa
() | swa == trueSW && swb == falseSW -> return swt
() | swa == falseSW && swb == trueSW -> newExpr st k (SBVApp Not [swt])
() -> newExpr st k (SBVApp Ite [swt, swa, swb])
svSelect :: [SVal] -> SVal -> SVal -> SVal
svSelect xs err ind
| 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"
svSelect xsOrig err ind = xs `seq` SVal kElt (Right (cache r))
where
kInd = kindOf ind
kElt = kindOf err
xs = case kInd of
KBounded False i -> genericTake ((2::Integer) ^ i) xsOrig
KBounded True i -> genericTake ((2::Integer) ^ (i-1)) xsOrig
KUnbounded -> xsOrig
_ -> error $ "SBV.select: unsupported " ++ show kInd ++ " valued select/index expression"
r st = do sws <- mapM (svToSW st) xs
swe <- svToSW st err
if all (== swe) sws
then return swe
else do idx <- getTableIndex st kInd kElt sws
swi <- svToSW st ind
let len = length xs
newExpr st kElt (SBVApp (LkUp (idx, kInd, kElt, len) swi swe) [])
svChangeSign :: Bool -> SVal -> SVal
svChangeSign s x
| Just n <- svAsInteger x = svInteger k n
| True = SVal k (Right (cache y))
where
k = KBounded s (intSizeOf x)
y st = do xsw <- svToSW st x
newExpr st k (SBVApp (Extract (intSizeOf x - 1) 0) [xsw])
svSign :: SVal -> SVal
svSign = svChangeSign True
svUnsign :: SVal -> SVal
svUnsign = svChangeSign False
svFromIntegral :: Kind -> SVal -> SVal
svFromIntegral kTo x
| Just v <- svAsInteger x
= svInteger kTo v
| True
= result
where result = SVal kTo (Right (cache y))
kFrom = kindOf x
y st = do xsw <- svToSW st x
newExpr st kTo (SBVApp (KindCast kFrom kTo) [xsw])
svToWord1 :: SVal -> SVal
svToWord1 b = svSymbolicMerge k True b (svInteger k 1) (svInteger k 0)
where k = KBounded False 1
svFromWord1 :: SVal -> SVal
svFromWord1 x = svNotEqual x (svInteger k 0)
where k = kindOf x
svTestBit :: SVal -> Int -> SVal
svTestBit x i
| i < intSizeOf x = svFromWord1 (svExtract i i x)
| True = svFalse
svShiftLeft :: SVal -> SVal -> SVal
svShiftLeft = svShift True
svShiftRight :: SVal -> SVal -> SVal
svShiftRight = svShift False
svShift :: Bool -> SVal -> SVal -> SVal
svShift toLeft x i
| Just r <- constFoldValue
= r
| cannotOverShift
= svIte (i `svLessThan` svInteger ki 0)
x
regularShiftValue
| True
= svIte (i `svLessThan` svInteger ki 0)
x
$ svIte (i `svGreaterEq` svInteger ki (fromIntegral (intSizeOf x)))
overShiftValue
regularShiftValue
where nm | toLeft = "shiftLeft"
| True = "shiftRight"
kx = kindOf x
ki = kindOf i
constFoldValue
| Just iv <- getConst i, iv == 0
= Just x
| Just xv <- getConst x, xv == 0
= Just x
| Just xv <- getConst x, Just iv <- getConst i
= Just $ SVal kx . Left $! normCW $ CW kx (CWInteger (xv `opC` shiftAmount iv))
| isInteger x || isInteger i
= bailOut $ "Not yet implemented unbounded/non-constants shifts for " ++ show (kx, ki) ++ ", please file a request!"
| not (isBounded x && isBounded i)
= bailOut $ "Unexpected kinds: " ++ show (kx, ki)
| True
= Nothing
where bailOut m = error $ "SBV." ++ nm ++ ": " ++ m
getConst (SVal _ (Left (CW _ (CWInteger val)))) = Just val
getConst _ = Nothing
opC | toLeft = shiftL
| True = shiftR
shiftAmount :: Integer -> Int
shiftAmount iv
| iv <= 0 = 0
| isInteger i, iv > fromIntegral (maxBound :: Int) = bailOut $ "Unsupported constant unbounded shift with amount: " ++ show iv
| isInteger x = fromIntegral iv
| iv >= fromIntegral ub = ub
| not (isBounded x && isBounded i) = bailOut $ "Unsupported kinds: " ++ show (kx, ki)
| True = fromIntegral iv
where ub = intSizeOf x
cannotOverShift = maxRepresentable <= fromIntegral (intSizeOf x)
where maxRepresentable :: Integer
maxRepresentable
| hasSign i = bit (intSizeOf i - 1) - 1
| True = bit (intSizeOf i ) - 1
overShiftValue | toLeft = zx
| hasSign x = svIte (x `svLessThan` zx) neg1 zx
| True = zx
where zx = svInteger kx 0
neg1 = svInteger kx (-1)
regularShiftValue = SVal kx $ Right $ cache result
where result st = do sw1 <- svToSW st x
sw2 <- svToSW st i
let op | toLeft = Shl
| True = Shr
adjustedShift <- if kx == ki
then return sw2
else newExpr st kx (SBVApp (KindCast ki kx) [sw2])
newExpr st kx (SBVApp op [sw1, adjustedShift])
svRotateLeft :: SVal -> SVal -> SVal
svRotateLeft x i
| not (isBounded x)
= svShiftLeft x i
| isBounded i && bit si <= toInteger sx
= svIte (svLessThan i zi)
(svSelect [x `svRor` k | k <- [0 .. bit si - 1]] z (svUNeg i))
(svSelect [x `svRol` k | k <- [0 .. bit si - 1]] z i)
| True
= svIte (svLessThan i zi)
(svSelect [x `svRor` k | k <- [0 .. sx - 1]] z (svUNeg i `svRem` n))
(svSelect [x `svRol` k | k <- [0 .. sx - 1]] z ( i `svRem` n))
where sx = intSizeOf x
si = intSizeOf i
z = svInteger (kindOf x) 0
zi = svInteger (kindOf i) 0
n = svInteger (kindOf i) (toInteger sx)
svRotateRight :: SVal -> SVal -> SVal
svRotateRight x i
| not (isBounded x)
= svShiftRight x i
| isBounded i && bit si <= toInteger sx
= svIte (svLessThan i zi)
(svSelect [x `svRol` k | k <- [0 .. bit si - 1]] z (svUNeg i))
(svSelect [x `svRor` k | k <- [0 .. bit si - 1]] z i)
| True
= svIte (svLessThan i zi)
(svSelect [x `svRol` k | k <- [0 .. sx - 1]] z (svUNeg i `svRem` n))
(svSelect [x `svRor` k | k <- [0 .. sx - 1]] z ( i `svRem` n))
where sx = intSizeOf x
si = intSizeOf i
z = svInteger (kindOf x) 0
zi = svInteger (kindOf i) 0
n = svInteger (kindOf i) (toInteger sx)
noUnint :: (Maybe Int, String) -> a
noUnint x = error $ "Unexpected operation called on uninterpreted/enumerated value: " ++ show x
noUnint2 :: (Maybe Int, String) -> (Maybe Int, String) -> a
noUnint2 x y = error $ "Unexpected binary operation called on uninterpreted/enumerated values: " ++ show (x, y)
noCharLift :: Char -> a
noCharLift x = error $ "Unexpected operation called on char: " ++ show x
noStringLift :: String -> a
noStringLift x = error $ "Unexpected operation called on string: " ++ show x
noCharLift2 :: Char -> Char -> a
noCharLift2 x y = error $ "Unexpected binary operation called on chars: " ++ show (x, y)
noStringLift2 :: String -> String -> a
noStringLift2 x y = error $ "Unexpected binary operation called on strings: " ++ show (x, y)
liftSym1 :: (State -> Kind -> SW -> IO SW) -> (AlgReal -> AlgReal) -> (Integer -> Integer) -> (Float -> Float) -> (Double -> Double) -> SVal -> SVal
liftSym1 _ opCR opCI opCF opCD (SVal k (Left a)) = SVal k . Left $! mapCW opCR opCI opCF opCD noCharLift noStringLift noUnint a
liftSym1 opS _ _ _ _ a@(SVal k _) = SVal k $ Right $ cache c
where c st = do swa <- svToSW st a
opS st k swa
liftSW2 :: (State -> Kind -> SW -> SW -> IO SW) -> Kind -> SVal -> SVal -> Cached SW
liftSW2 opS k a b = cache c
where c st = do sw1 <- svToSW st a
sw2 <- svToSW st b
opS st k sw1 sw2
liftSym2 :: (State -> Kind -> SW -> SW -> IO SW) -> (CW -> CW -> Bool) -> (AlgReal -> AlgReal -> AlgReal) -> (Integer -> Integer -> Integer) -> (Float -> Float -> Float) -> (Double -> Double -> Double) -> SVal -> SVal -> SVal
liftSym2 _ okCW opCR opCI opCF opCD (SVal k (Left a)) (SVal _ (Left b)) | okCW a b = SVal k . Left $! mapCW2 opCR opCI opCF opCD noCharLift2 noStringLift2 noUnint2 a b
liftSym2 opS _ _ _ _ _ a@(SVal k _) b = SVal k $ Right $ liftSW2 opS k a b
liftSym2B :: (State -> Kind -> SW -> SW -> IO SW) -> (CW -> CW -> Bool) -> (AlgReal -> AlgReal -> Bool) -> (Integer -> Integer -> Bool) -> (Float -> Float -> Bool) -> (Double -> Double -> Bool) -> (Char -> Char -> Bool) -> (String -> String -> Bool) -> ((Maybe Int, String) -> (Maybe Int, String) -> Bool) -> SVal -> SVal -> SVal
liftSym2B _ okCW opCR opCI opCF opCD opCC opCS opUI (SVal _ (Left a)) (SVal _ (Left b)) | okCW a b = svBool (liftCW2 opCR opCI opCF opCD opCC opCS opUI a b)
liftSym2B opS _ _ _ _ _ _ _ _ a b = SVal KBool $ Right $ liftSW2 opS KBool a b
mkSymOpSC :: (SW -> SW -> Maybe SW) -> Op -> State -> Kind -> SW -> SW -> IO SW
mkSymOpSC shortCut op st k a b = maybe (newExpr st k (SBVApp op [a, b])) return (shortCut a b)
mkSymOp :: Op -> State -> Kind -> SW -> SW -> IO SW
mkSymOp = mkSymOpSC (const (const Nothing))
mkSymOp1SC :: (SW -> Maybe SW) -> Op -> State -> Kind -> SW -> IO SW
mkSymOp1SC shortCut op st k a = maybe (newExpr st k (SBVApp op [a])) return (shortCut a)
mkSymOp1 :: Op -> State -> Kind -> SW -> IO SW
mkSymOp1 = mkSymOp1SC (const Nothing)
eqOpt :: SW -> SW -> SW -> Maybe SW
eqOpt w x y = case swKind x of
KFloat -> Nothing
KDouble -> Nothing
_ -> if x == y then Just w else Nothing
uiLift :: String -> (Int -> Int -> Bool) -> (Maybe Int, String) -> (Maybe Int, String) -> Bool
uiLift _ cmp (Just i, _) (Just j, _) = i `cmp` j
uiLift w _ a b = error $ "Data.SBV.Core.Operations: Impossible happened while trying to lift " ++ w ++ " over " ++ show (a, b)
isConcreteZero :: SVal -> Bool
isConcreteZero (SVal _ (Left (CW _ (CWInteger n)))) = n == 0
isConcreteZero (SVal KReal (Left (CW KReal (CWAlgReal v)))) = isExactRational v && v == 0
isConcreteZero _ = False
isConcreteOne :: SVal -> Bool
isConcreteOne (SVal _ (Left (CW _ (CWInteger 1)))) = True
isConcreteOne (SVal KReal (Left (CW KReal (CWAlgReal v)))) = isExactRational v && v == 1
isConcreteOne _ = False
isConcreteOnes :: SVal -> Bool
isConcreteOnes (SVal _ (Left (CW (KBounded b w) (CWInteger n)))) = n == if b then -1 else bit w - 1
isConcreteOnes (SVal _ (Left (CW KUnbounded (CWInteger n)))) = n == -1
isConcreteOnes (SVal _ (Left (CW KBool (CWInteger n)))) = n == 1
isConcreteOnes _ = False
isConcreteMax :: SVal -> Bool
isConcreteMax (SVal _ (Left (CW (KBounded False w) (CWInteger n)))) = n == bit w - 1
isConcreteMax (SVal _ (Left (CW (KBounded True w) (CWInteger n)))) = n == bit (w - 1) - 1
isConcreteMax (SVal _ (Left (CW KBool (CWInteger n)))) = n == 1
isConcreteMax _ = False
isConcreteMin :: SVal -> Bool
isConcreteMin (SVal _ (Left (CW (KBounded False _) (CWInteger n)))) = n == 0
isConcreteMin (SVal _ (Left (CW (KBounded True w) (CWInteger n)))) = n == - bit (w - 1)
isConcreteMin (SVal _ (Left (CW KBool (CWInteger n)))) = n == 0
isConcreteMin _ = False
areConcretelyEqual :: SVal -> SVal -> Bool
areConcretelyEqual (SVal _ (Left a)) (SVal _ (Left b)) = a == b
areConcretelyEqual _ _ = False
rationalCheck :: CW -> CW -> Bool
rationalCheck a b = case (cwVal a, cwVal b) of
(CWAlgReal x, CWAlgReal y) -> isExactRational x && isExactRational y
_ -> True
nonzeroCheck :: CW -> CW -> Bool
nonzeroCheck _ b = cwVal b /= CWInteger 0
rationalSBVCheck :: SVal -> SVal -> Bool
rationalSBVCheck (SVal KReal (Left a)) (SVal KReal (Left b)) = rationalCheck a b
rationalSBVCheck _ _ = True
noReal :: String -> AlgReal -> AlgReal -> AlgReal
noReal o a b = error $ "SBV.AlgReal." ++ o ++ ": Unexpected arguments: " ++ show (a, b)
noFloat :: String -> Float -> Float -> Float
noFloat o a b = error $ "SBV.Float." ++ o ++ ": Unexpected arguments: " ++ show (a, b)
noDouble :: String -> Double -> Double -> Double
noDouble o a b = error $ "SBV.Double." ++ o ++ ": Unexpected arguments: " ++ show (a, b)
noRealUnary :: String -> AlgReal -> AlgReal
noRealUnary o a = error $ "SBV.AlgReal." ++ o ++ ": Unexpected argument: " ++ show a
noFloatUnary :: String -> Float -> Float
noFloatUnary o a = error $ "SBV.Float." ++ o ++ ": Unexpected argument: " ++ show a
noDoubleUnary :: String -> Double -> Double
noDoubleUnary o a = error $ "SBV.Double." ++ o ++ ": Unexpected argument: " ++ show a
{-# ANN svIte ("HLint: ignore Eta reduce" :: String) #-}
{-# ANN svLazyIte ("HLint: ignore Eta reduce" :: String) #-}
{-# ANN module ("HLint: ignore Reduce duplication" :: String) #-}