sbv 3.2 → 3.3
raw patch · 13 files changed
+283/−47 lines, 13 files
Files
- CHANGES.md +12/−1
- Data/SBV.hs +45/−1
- Data/SBV/BitVectors/Data.hs +106/−6
- Data/SBV/BitVectors/Model.hs +15/−16
- Data/SBV/Bridge/Boolector.hs +9/−3
- Data/SBV/Bridge/CVC4.hs +9/−3
- Data/SBV/Bridge/MathSAT.hs +9/−3
- Data/SBV/Bridge/Yices.hs +9/−3
- Data/SBV/Bridge/Z3.hs +9/−3
- Data/SBV/Provers/Prover.hs +22/−1
- Data/SBV/SMT/SMT.hs +36/−5
- SBVUnitTest/SBVUnitTestBuildTime.hs +1/−1
- sbv.cabal +1/−1
CHANGES.md view
@@ -1,7 +1,18 @@ * Hackage: <http://hackage.haskell.org/package/sbv> * GitHub: <http://leventerkok.github.com/sbv/> -* Latest Hackage released version: 3.2+* Latest Hackage released version: 3.3++### Version 3.3, 2014-12-05++ * Implement 'safe' and 'safeWith', which statically determine all calls to 'sAssert'+ being safe to execute. This way, users can pepper their programs with liberal+ calls to 'sAssert' and check they are all safe in one go without further worry.++ * Robustify the interface to external solvers, by making sure we catch cases where+ the external solver might exist but not be runnable (library dependency missing,+ for example). It is impossible to be absolutely foolproof, but we now catch a+ few more cases and fail gracefully. ### Version 3.2, 2014-11-18
Data/SBV.hs view
@@ -196,6 +196,10 @@ -- ** Checking constraint vacuity , isVacuous, isVacuousWith + -- * Checking safety+ -- $safeIntro+ , safe, safeWith, SExecutable(..)+ -- * Proving properties using multiple solvers -- $multiIntro , proveWithAll, proveWithAny, satWithAll, satWithAny, allSatWithAll, allSatWithAny@@ -213,7 +217,7 @@ -- ** Inspecting proof results -- $resultTypes- , ThmResult(..), SatResult(..), AllSatResult(..), SMTResult(..)+ , ThmResult(..), SatResult(..), AllSatResult(..), SMTResult(..), SafeResult(..) -- ** Programmable model extraction -- $programmableExtraction@@ -487,6 +491,46 @@ Note that the function 'sbvAvailableSolvers' will return all the installed solvers, which can be used as the first argument to all these functions, if you simply want to try all available solvers on a machine.+-}++{- $safeIntro++The 'sAssert' and 'sAssertCont' functions allow users to introduce invariants through-out their code to make sure+certain properties hold at all times. This is another mechanism to provide further documentation/contract info+into SBV code. The functions 'safe' and 'safeWith' can then be used to statically discharge these proof assumptions.+If a violation is found, SBV will print a model showing which inputs lead to the invariant being violated.++Here's a simple example. Let's assume we have a function that does subtraction, and requires it's+first argument to be larger than the second:++>>> let sub x y = sAssert "sub: x >= y must hold!" (x .>= y) (x - y)++Clearly, this function is not safe, as there's nothing that ensures us to pass a larger second argument.+If we try to prove a theorem regarding sub, we'll get an exception:++>>> prove $ \x y -> sub x y .>= (0 :: SInt16)+*** Exception: Assertion failure: "sub: x >= y must hold!"+ s0 = -32768 :: SInt16+ s1 = -32767 :: SInt16++Of course, we can use, 'safe' to statically see if such a violation is possible before we attempt a proof:++>>> safe (sub :: SInt8 -> SInt8 -> SInt8)+Assertion failure: "sub: x >= y must hold!"+ s0 = -128 :: SInt8+ s1 = -127 :: SInt8++What happens if we make sure to arrange for this invariant? Consider this version:++>>> let safeSub x y = ite (x .>= y) (sub x y) (sub y x)++Clearly, 'safeSub' must be safe. And indeed, SBV can prove that:++>>> safe (safeSub :: SInt8 -> SInt8 -> SInt8)+No safety violations detected.++Note how we used 'sub' and 'safeSub' polymorphically. We only need to monomorphise our types when a proof+attempt is done, as we did in the 'safe' calls. -} {- $optimizeIntro
Data/SBV/BitVectors/Data.hs view
@@ -32,7 +32,7 @@ , sbvToSW, sbvToSymSW, forceSWArg , SBVExpr(..), newExpr , cache, Cached, uncache, uncacheAI, HasKind(..)- , Op(..), NamedSymVar, UnintKind(..), getTableIndex, SBVPgm(..), Symbolic, runSymbolic, runSymbolic', State, getPathCondition, extendPathCondition+ , Op(..), NamedSymVar, UnintKind(..), getTableIndex, SBVPgm(..), Symbolic, SExecutable(..), runSymbolic, runSymbolic', State, getPathCondition, extendPathCondition , inProofMode, SBVRunMode(..), Kind(..), Outputtable(..), Result(..) , Logic(..), SMTLibLogic(..) , getTraceInfo, getConstraints, addConstraint@@ -57,11 +57,11 @@ import Data.List (intercalate, sortBy) import Data.Maybe (isJust, fromJust) -import qualified Data.IntMap as IMap (IntMap, empty, size, toAscList, lookup, insert, insertWith)-import qualified Data.Map as Map (Map, empty, toList, size, insert, lookup)-import qualified Data.Set as Set (Set, empty, toList, insert)-import qualified Data.Foldable as F (toList)-import qualified Data.Sequence as S (Seq, empty, (|>))+import qualified Data.IntMap as IMap (IntMap, empty, size, toAscList, lookup, insert, insertWith)+import qualified Data.Map as Map (Map, empty, toList, size, insert, lookup)+import qualified Data.Set as Set (Set, empty, toList, insert)+import qualified Data.Foldable as F (toList)+import qualified Data.Sequence as S (Seq, empty, (|>)) import System.Exit (ExitCode(..)) import System.Mem.StableName@@ -1298,6 +1298,9 @@ instance NFData SMTModel where rnf (SMTModel assocs unints uarrs) = rnf assocs `seq` rnf unints `seq` rnf uarrs `seq` () +instance NFData SMTScript where+ rnf (SMTScript b m) = rnf b `seq` rnf m `seq` ()+ -- | SMT-Lib logics. If left unspecified SBV will pick the logic based on what it determines is needed. However, the -- user can override this choice using the 'useLogic' parameter to the configuration. This is especially handy if -- one is experimenting with custom logics that might be supported on new solvers.@@ -1431,3 +1434,100 @@ instance Show SMTSolver where show = show . name++-- | Symbolically executable program fragments. This class is mainly used for 'safe' calls, and is sufficently populated internally to cover most use+-- cases. Users can extend it as they wish to allow 'safe' checks for SBV programs that return/take types that are user-defined.+class SExecutable a where+ sName_ :: a -> Symbolic ()+ sName :: [String] -> a -> Symbolic ()++instance NFData a => SExecutable (Symbolic a) where+ sName_ a = a >>= \r -> rnf r `seq` return ()+ sName [] = sName_+ sName xs = error $ "SBV.SExecutable.sName: Extra unmapped name(s): " ++ intercalate ", " xs++instance NFData a => SExecutable (SBV a) where+ sName_ v = sName_ (output v)+ sName xs v = sName xs (output v)++-- Unit output+instance SExecutable () where+ sName_ () = sName_ (output ())+ sName xs () = sName xs (output ())++-- List output+instance (NFData a, SymWord a) => SExecutable [SBV a] where+ sName_ vs = sName_ (output vs)+ sName xs vs = sName xs (output vs)++-- 2 Tuple output+instance (NFData a, SymWord a, NFData b, SymWord b) => SExecutable (SBV a, SBV b) where+ sName_ (a, b) = sName_ (output a >> output b)+ sName _ = sName_++-- 3 Tuple output+instance (NFData a, SymWord a, NFData b, SymWord b, NFData c, SymWord c) => SExecutable (SBV a, SBV b, SBV c) where+ sName_ (a, b, c) = sName_ (output a >> output b >> output c)+ sName _ = sName_++-- 4 Tuple output+instance (NFData a, SymWord a, NFData b, SymWord b, NFData c, SymWord c, NFData d, SymWord d) => SExecutable (SBV a, SBV b, SBV c, SBV d) where+ sName_ (a, b, c, d) = sName_ (output a >> output b >> output c >> output c >> output d)+ sName _ = sName_++-- 5 Tuple output+instance (NFData a, SymWord a, NFData b, SymWord b, NFData c, SymWord c, NFData d, SymWord d, NFData e, SymWord e) => SExecutable (SBV a, SBV b, SBV c, SBV d, SBV e) where+ sName_ (a, b, c, d, e) = sName_ (output a >> output b >> output c >> output d >> output e)+ sName _ = sName_++-- 6 Tuple output+instance (NFData a, SymWord a, NFData b, SymWord b, NFData c, SymWord c, NFData d, SymWord d, NFData e, SymWord e, NFData f, SymWord f) => SExecutable (SBV a, SBV b, SBV c, SBV d, SBV e, SBV f) where+ sName_ (a, b, c, d, e, f) = sName_ (output a >> output b >> output c >> output d >> output e >> output f)+ sName _ = sName_++-- 7 Tuple output+instance (NFData a, SymWord a, NFData b, SymWord b, NFData c, SymWord c, NFData d, SymWord d, NFData e, SymWord e, NFData f, SymWord f, NFData g, SymWord g) => SExecutable (SBV a, SBV b, SBV c, SBV d, SBV e, SBV f, SBV g) where+ sName_ (a, b, c, d, e, f, g) = sName_ (output a >> output b >> output c >> output d >> output e >> output f >> output g)+ sName _ = sName_++-- Functions+instance (SymWord a, SExecutable p) => SExecutable (SBV a -> p) where+ sName_ k = forall_ >>= \a -> sName_ $ k a+ sName (s:ss) k = forall s >>= \a -> sName ss $ k a+ sName [] k = sName_ k++-- 2 Tuple input+instance (SymWord a, SymWord b, SExecutable p) => SExecutable ((SBV a, SBV b) -> p) where+ sName_ k = forall_ >>= \a -> sName_ $ \b -> k (a, b)+ sName (s:ss) k = forall s >>= \a -> sName ss $ \b -> k (a, b)+ sName [] k = sName_ k++-- 3 Tuple input+instance (SymWord a, SymWord b, SymWord c, SExecutable p) => SExecutable ((SBV a, SBV b, SBV c) -> p) where+ sName_ k = forall_ >>= \a -> sName_ $ \b c -> k (a, b, c)+ sName (s:ss) k = forall s >>= \a -> sName ss $ \b c -> k (a, b, c)+ sName [] k = sName_ k++-- 4 Tuple input+instance (SymWord a, SymWord b, SymWord c, SymWord d, SExecutable p) => SExecutable ((SBV a, SBV b, SBV c, SBV d) -> p) where+ sName_ k = forall_ >>= \a -> sName_ $ \b c d -> k (a, b, c, d)+ sName (s:ss) k = forall s >>= \a -> sName ss $ \b c d -> k (a, b, c, d)+ sName [] k = sName_ k++-- 5 Tuple input+instance (SymWord a, SymWord b, SymWord c, SymWord d, SymWord e, SExecutable p) => SExecutable ((SBV a, SBV b, SBV c, SBV d, SBV e) -> p) where+ sName_ k = forall_ >>= \a -> sName_ $ \b c d e -> k (a, b, c, d, e)+ sName (s:ss) k = forall s >>= \a -> sName ss $ \b c d e -> k (a, b, c, d, e)+ sName [] k = sName_ k++-- 6 Tuple input+instance (SymWord a, SymWord b, SymWord c, SymWord d, SymWord e, SymWord f, SExecutable p) => SExecutable ((SBV a, SBV b, SBV c, SBV d, SBV e, SBV f) -> p) where+ sName_ k = forall_ >>= \a -> sName_ $ \b c d e f -> k (a, b, c, d, e, f)+ sName (s:ss) k = forall s >>= \a -> sName ss $ \b c d e f -> k (a, b, c, d, e, f)+ sName [] k = sName_ k++-- 7 Tuple input+instance (SymWord a, SymWord b, SymWord c, SymWord d, SymWord e, SymWord f, SymWord g, SExecutable p) => SExecutable ((SBV a, SBV b, SBV c, SBV d, SBV e, SBV f, SBV g) -> p) where+ sName_ k = forall_ >>= \a -> sName_ $ \b c d e f g -> k (a, b, c, d, e, f, g)+ sName (s:ss) k = forall s >>= \a -> sName ss $ \b c d e f g -> k (a, b, c, d, e, f, g)+ sName [] k = sName_ k
Data/SBV/BitVectors/Model.hs view
@@ -43,6 +43,8 @@ import qualified Data.Map as M +import qualified Control.Exception as C+ import Test.QuickCheck (Testable(..), Arbitrary(..)) import qualified Test.QuickCheck as QC (whenFail) import qualified Test.QuickCheck.Monadic as QC (monadicIO, run)@@ -52,10 +54,8 @@ import Data.SBV.BitVectors.Data import Data.SBV.Utils.Boolean --- The following two imports are only needed because of the doctest expressions we have. Sigh..--- It might be a good idea to reorg some of the content to avoid this. import Data.SBV.Provers.Prover (isSBranchFeasibleInState, isConditionSatisfiable, isVacuous, prove, defaultSMTCfg)-import Data.SBV.SMT.SMT (SatResult(..), ThmResult, showModel, getModelDictionary)+import Data.SBV.SMT.SMT (SafeResult(..), SatResult(..), ThmResult, getModelDictionary) -- | Newer versions of GHC (Starting with 7.8 I think), distinguishes between FiniteBits and Bits classes. -- We should really use FiniteBitSize for SBV which would make things better. In the interim, just work@@ -1221,9 +1221,8 @@ -- Otherwise symbolic simulation will stop with a run-time error. sAssert :: Mergeable a => String -> SBool -> a -> a sAssert msg = sAssertCont msg defCont- where die m = error $ intercalate "\n" $ ("Assertion failure: " ++ show msg) : m- defCont _ Nothing = die ["*** Fails in all assignments to inputs"]- defCont cfg (Just md) = die [showModel cfg (SMTModel (M.toList md) [] [])]+ where defCont _ Nothing = C.throw (SafeAlwaysFails msg)+ defCont cfg (Just md) = C.throw (SafeFailsInModel msg cfg (SMTModel (M.toList md) [] [])) -- | Symbolic assert with a programmable continuation. Check that the given boolean condition is always true in the given path. -- Otherwise symbolic simulation will transfer the failing model to the given continuation. The@@ -1649,16 +1648,16 @@ kg = kindOf (undefined :: g) kh = kindOf (undefined :: h) result st | Just (_, v) <- mbCgData, inProofMode st = sbvToSW st (v arg0 arg1 arg2 arg3 arg4 arg5 arg6)- | True = 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]+ | True = 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] -- Uncurried functions of two arguments instance (SymWord c, SymWord b, HasKind a) => Uninterpreted ((SBV c, SBV b) -> SBV a) where
Data/SBV/Bridge/Boolector.hs view
@@ -21,8 +21,8 @@ module Data.SBV.Bridge.Boolector ( -- * Boolector specific interface sbvCurrentSolver- -- ** Proving and checking satisfiability- , prove, sat, allSat, isVacuous, isTheorem, isSatisfiable+ -- ** Proving, checking satisfiability, and safety+ , prove, sat, safe, allSat, isVacuous, isTheorem, isSatisfiable -- ** Optimization routines , optimize, minimize, maximize -- * Non-Boolector specific SBV interface@@ -30,7 +30,7 @@ , module Data.SBV ) where -import Data.SBV hiding (prove, sat, allSat, isVacuous, isTheorem, isSatisfiable, optimize, minimize, maximize, sbvCurrentSolver)+import Data.SBV hiding (prove, sat, safe, allSat, isVacuous, isTheorem, isSatisfiable, optimize, minimize, maximize, sbvCurrentSolver) -- | Current solver instance, pointing to cvc4. sbvCurrentSolver :: SMTConfig@@ -47,6 +47,12 @@ => a -- ^ Property to check -> IO SatResult -- ^ Response of the SMT Solver, containing the model if found sat = satWith sbvCurrentSolver++-- | Check safety, i.e., prove that all 'sAssert' conditions are statically true in all paths+safe :: SExecutable a+ => a -- ^ Program to check the safety of+ -> IO SafeResult -- ^ Response of the SMT solver, containing the unsafe model if found+safe = safeWith sbvCurrentSolver -- | Find all satisfying solutions, using the CVC4 SMT solver allSat :: Provable a
Data/SBV/Bridge/CVC4.hs view
@@ -21,8 +21,8 @@ module Data.SBV.Bridge.CVC4 ( -- * CVC4 specific interface sbvCurrentSolver- -- ** Proving and checking satisfiability- , prove, sat, allSat, isVacuous, isTheorem, isSatisfiable+ -- ** Proving, checking satisfiability, and safety+ , prove, sat, safe, allSat, isVacuous, isTheorem, isSatisfiable -- ** Optimization routines , optimize, minimize, maximize -- * Non-CVC4 specific SBV interface@@ -30,7 +30,7 @@ , module Data.SBV ) where -import Data.SBV hiding (prove, sat, allSat, isVacuous, isTheorem, isSatisfiable, optimize, minimize, maximize, sbvCurrentSolver)+import Data.SBV hiding (prove, sat, safe, allSat, isVacuous, isTheorem, isSatisfiable, optimize, minimize, maximize, sbvCurrentSolver) -- | Current solver instance, pointing to cvc4. sbvCurrentSolver :: SMTConfig@@ -47,6 +47,12 @@ => a -- ^ Property to check -> IO SatResult -- ^ Response of the SMT Solver, containing the model if found sat = satWith sbvCurrentSolver++-- | Check safety, i.e., prove that all 'sAssert' conditions are statically true in all paths+safe :: SExecutable a+ => a -- ^ Program to check the safety of+ -> IO SafeResult -- ^ Response of the SMT solver, containing the unsafe model if found+safe = safeWith sbvCurrentSolver -- | Find all satisfying solutions, using the CVC4 SMT solver allSat :: Provable a
Data/SBV/Bridge/MathSAT.hs view
@@ -21,8 +21,8 @@ module Data.SBV.Bridge.MathSAT ( -- * MathSAT specific interface sbvCurrentSolver- -- ** Proving and checking satisfiability- , prove, sat, allSat, isVacuous, isTheorem, isSatisfiable+ -- ** Proving, checking satisfiability, and safety+ , prove, sat, safe, allSat, isVacuous, isTheorem, isSatisfiable -- ** Optimization routines , optimize, minimize, maximize -- * Non-MathSAT specific SBV interface@@ -30,7 +30,7 @@ , module Data.SBV ) where -import Data.SBV hiding (prove, sat, allSat, isVacuous, isTheorem, isSatisfiable, optimize, minimize, maximize, sbvCurrentSolver)+import Data.SBV hiding (prove, sat, safe, allSat, isVacuous, isTheorem, isSatisfiable, optimize, minimize, maximize, sbvCurrentSolver) -- | Current solver instance, pointing to cvc4. sbvCurrentSolver :: SMTConfig@@ -47,6 +47,12 @@ => a -- ^ Property to check -> IO SatResult -- ^ Response of the SMT Solver, containing the model if found sat = satWith sbvCurrentSolver++-- | Check safety, i.e., prove that all 'sAssert' conditions are statically true in all paths+safe :: SExecutable a+ => a -- ^ Program to check the safety of+ -> IO SafeResult -- ^ Response of the SMT solver, containing the unsafe model if found+safe = safeWith sbvCurrentSolver -- | Find all satisfying solutions, using the CVC4 SMT solver allSat :: Provable a
Data/SBV/Bridge/Yices.hs view
@@ -21,8 +21,8 @@ module Data.SBV.Bridge.Yices ( -- * Yices specific interface sbvCurrentSolver- -- ** Proving and checking satisfiability- , prove, sat, allSat, isVacuous, isTheorem, isSatisfiable+ -- ** Proving, checking satisfiability, and safety+ , prove, sat, safe, allSat, isVacuous, isTheorem, isSatisfiable -- ** Optimization routines , optimize, minimize, maximize -- * Non-Yices specific SBV interface@@ -30,7 +30,7 @@ , module Data.SBV ) where -import Data.SBV hiding (prove, sat, allSat, isVacuous, isTheorem, isSatisfiable, optimize, minimize, maximize, sbvCurrentSolver)+import Data.SBV hiding (prove, sat, safe, allSat, isVacuous, isTheorem, isSatisfiable, optimize, minimize, maximize, sbvCurrentSolver) -- | Current solver instance, pointing to yices. sbvCurrentSolver :: SMTConfig@@ -47,6 +47,12 @@ => a -- ^ Property to check -> IO SatResult -- ^ Response of the SMT Solver, containing the model if found sat = satWith sbvCurrentSolver++-- | Check safety, i.e., prove that all 'sAssert' conditions are statically true in all paths+safe :: SExecutable a+ => a -- ^ Program to check the safety of+ -> IO SafeResult -- ^ Response of the SMT solver, containing the unsafe model if found+safe = safeWith sbvCurrentSolver -- | Find all satisfying solutions, using the Yices SMT solver allSat :: Provable a
Data/SBV/Bridge/Z3.hs view
@@ -21,8 +21,8 @@ module Data.SBV.Bridge.Z3 ( -- * Z3 specific interface sbvCurrentSolver- -- ** Proving and checking satisfiability- , prove, sat, allSat, isVacuous, isTheorem, isSatisfiable+ -- ** Proving, checking satisfiability, and safety+ , prove, sat, safe, allSat, isVacuous, isTheorem, isSatisfiable -- ** Optimization routines , optimize, minimize, maximize -- * Non-Z3 specific SBV interface@@ -30,7 +30,7 @@ , module Data.SBV ) where -import Data.SBV hiding (prove, sat, allSat, isVacuous, isTheorem, isSatisfiable, optimize, minimize, maximize, sbvCurrentSolver)+import Data.SBV hiding (prove, sat, safe, allSat, isVacuous, isTheorem, isSatisfiable, optimize, minimize, maximize, sbvCurrentSolver) -- | Current solver instance, pointing to z3. sbvCurrentSolver :: SMTConfig@@ -47,6 +47,12 @@ => a -- ^ Property to check -> IO SatResult -- ^ Response of the SMT Solver, containing the model if found sat = satWith sbvCurrentSolver++-- | Check safety, i.e., prove that all 'sAssert' conditions are statically true in all paths+safe :: SExecutable a+ => a -- ^ Program to check the safety of+ -> IO SafeResult -- ^ Response of the SMT solver, containing the unsafe model if found+safe = safeWith sbvCurrentSolver -- | Find all satisfying solutions, using the Z3 SMT solver allSat :: Provable a
Data/SBV/Provers/Prover.hs view
@@ -13,13 +13,15 @@ {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE OverlappingInstances #-} {-# LANGUAGE BangPatterns #-}+{-# LANGUAGE ScopedTypeVariables #-} module Data.SBV.Provers.Prover ( SMTSolver(..), SMTConfig(..), Predicate, Provable(..)- , ThmResult(..), SatResult(..), AllSatResult(..), SMTResult(..)+ , ThmResult(..), SatResult(..), AllSatResult(..), SMTResult(..), SafeResult(..) , isSatisfiable, isSatisfiableWith, isTheorem, isTheoremWith , prove, proveWith , sat, satWith+ , safe, safeWith , allSat, allSatWith , isVacuous, isVacuousWith , SatModel(..), Modelable(..), displayModels, extractModels@@ -40,6 +42,8 @@ import qualified Data.Set as Set (Set, toList) +import qualified Control.Exception as C+ import Data.SBV.BitVectors.Data import Data.SBV.SMT.SMT import Data.SBV.SMT.SMTLib@@ -233,6 +237,10 @@ sat :: Provable a => a -> IO SatResult sat = satWith defaultSMTCfg +-- | Check if a given definition is safe; i.e., if all 'sAssert' conditions can be proven to hold.+safe :: SExecutable a => a -> IO SafeResult+safe = safeWith defaultSMTCfg+ -- | Return all satisfying assignments for a predicate, equivalent to @'allSatWith' 'defaultSMTCfg'@. -- Satisfying assignments are constructed lazily, so they will be available as returned by the solver -- and on demand.@@ -326,6 +334,19 @@ satWith :: Provable a => SMTConfig -> a -> IO SatResult satWith config a = simulate cvt config True [] a >>= callSolver True "Checking Satisfiability.." SatResult config where cvt = if useSMTLib2 config then toSMTLib2 else toSMTLib1++-- | Check if a given definition is safe using the given solver configuration; i.e., if all 'sAssert' conditions can be proven to hold.+safeWith :: SExecutable a => SMTConfig -> a -> IO SafeResult+safeWith config a = C.catchJust choose checkSafe return+ where checkSafe = do let msg = when (verbose config) . putStrLn . ("** " ++)+ isTiming = timing config+ msg "Starting safety checking symbolic simulation.."+ res <- timeIf isTiming "problem construction" $ runSymbolic (False, Just config) $ sName_ a >>= output+ msg $ "Generated symbolic trace:\n" ++ show res+ return SafeNeverFails+ choose e@(SafeNeverFails{}) = Just e+ choose e@(SafeAlwaysFails{}) = Just e+ choose e@(SafeFailsInModel{}) = Just e -- | Determine if the constraints are vacuous using the given SMT-solver isVacuousWith :: Provable a => SMTConfig -> a -> IO Bool
Data/SBV/SMT/SMT.hs view
@@ -10,12 +10,14 @@ ----------------------------------------------------------------------------- {-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE DeriveDataTypeable #-} module Data.SBV.SMT.SMT where import qualified Control.Exception as C import Control.Concurrent (newEmptyMVar, takeMVar, putMVar, forkIO)+import Control.DeepSeq (NFData(..)) import Control.Monad (when, zipWithM) import Data.Char (isSpace) import Data.Int (Int8, Int16, Int32, Int64)@@ -27,6 +29,7 @@ import System.IO (hClose, hFlush, hPutStr, hGetContents, hGetLine) import qualified Data.Map as M+import Data.Typeable import Data.SBV.BitVectors.AlgReals import Data.SBV.BitVectors.Data@@ -84,6 +87,22 @@ Satisfiable{} -> True _ -> False +-- | The result of an 'sAssert' call+data SafeResult = SafeNeverFails+ | SafeAlwaysFails String+ | SafeFailsInModel String SMTConfig SMTModel+ deriving Typeable++-- | The show instance for SafeResult. Note that this is for display purposes only,+-- user programs are likely to pattern match on the output and proceed accordingly.+instance Show SafeResult where+ show SafeNeverFails = "No safety violations detected."+ show (SafeAlwaysFails s) = intercalate "\n" ["Assertion failure: " ++ show s, "*** Fails in all assignments to inputs"]+ show (SafeFailsInModel s cfg md) = intercalate "\n" ["Assertion failure: " ++ show s, showModel cfg md]++-- | If a 'prove' or 'sat' call comes accross an 'sAssert' call that fails, they will throw a 'SafeResult' as an exception.+instance C.Exception SafeResult+ -- | Instances of 'SatModel' can be automatically extracted from models returned by the -- solvers. The idea is that the sbv infrastructure provides a stream of 'CW''s (constant-words) -- coming from the solver, and the type @a@ is interpreted based on these constants. Many typical@@ -348,11 +367,15 @@ let nm = show (name (solver cfg)) mbExecPath <- findExecutable execName case mbExecPath of- Nothing -> return $ Left $ "Unable to locate executable for " ++ nm- ++ "\nExecutable specified: " ++ show execName- Just execPath -> do (ec, contents, allErrors) <- runSolver cfg execPath opts script- let errors = dropWhile isSpace (cleanErrs allErrors)- case (null errors, xformExitCode (solver cfg) ec) of+ Nothing -> return $ Left $ "Unable to locate executable for " ++ nm+ ++ "\nExecutable specified: " ++ show execName+ Just execPath ->+ do solverResult <- dispatchSolver cfg execPath opts script+ case solverResult of+ Left s -> return $ Left s+ Right (ec, contents, allErrors) ->+ let errors = dropWhile isSpace (cleanErrs allErrors)+ in case (null errors, xformExitCode (solver cfg) ec) of (True, ExitSuccess) -> return $ Right $ map clean (filter (not . null) (lines contents)) (_, ec') -> let errors' = if null errors then (if null (dropWhile isSpace contents)@@ -395,6 +418,14 @@ case contents of Left e -> return $ failure (lines e) Right xs -> return $ success (mergeSExpr xs)++-- | Wrap the solver call to protect against any exceptions+dispatchSolver :: SMTConfig -> FilePath -> [String] -> SMTScript -> IO (Either String (ExitCode, String, String))+dispatchSolver cfg execPath opts script = rnf script `seq` (Right `fmap` runSolver cfg execPath opts script) `C.catch` (\(e::C.SomeException) -> bad (show e))+ where bad s = return $ Left $ unlines [ "Failed to start the external solver: " ++ s+ , "Make sure you can start " ++ show execPath+ , "from the command line without issues."+ ] -- | A variant of 'readProcessWithExitCode'; except it knows about continuation strings -- and can speak SMT-Lib2 (just a little).
SBVUnitTest/SBVUnitTestBuildTime.hs view
@@ -2,4 +2,4 @@ module SBVUnitTestBuildTime (buildTime) where buildTime :: String-buildTime = "Tue Nov 18 18:03:52 PST 2014"+buildTime = "Fri Dec 5 00:41:13 PST 2014"
sbv.cabal view
@@ -1,5 +1,5 @@ Name: sbv-Version: 3.2+Version: 3.3 Category: Formal Methods, Theorem Provers, Bit vectors, Symbolic Computation, Math, SMT Synopsis: SMT Based Verification: Symbolic Haskell theorem prover using SMT solving. Description: Express properties about Haskell programs and automatically prove them using SMT