Skip to content

Commit 569d316

Browse files
committed
More work on making proof and solver conventions more uniform.
Use the SATQuery type for the "offline" proof exporters, and a variety of other tweaks.
1 parent fb2c486 commit 569d316

File tree

7 files changed

+162
-130
lines changed

7 files changed

+162
-130
lines changed

src/SAWScript/Builtins.hs

+31-14
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ import Verifier.SAW.FiniteValue
6464
, FirstOrderValue(..), asFiniteType
6565
, toFirstOrderValue, scFirstOrderValue
6666
)
67+
import Verifier.SAW.SATQuery
6768
import Verifier.SAW.SCTypeCheck hiding (TypedTerm)
6869
import qualified Verifier.SAW.SCTypeCheck as TC (TypedTerm(..))
6970
import Verifier.SAW.SharedTerm
@@ -780,47 +781,60 @@ offline_w4_unint_yices :: [String] -> String -> ProofScript SV.SatResult
780781
offline_w4_unint_yices unints path =
781782
wrapW4ProveExporter Prover.proveExportWhat4_yices unints path ".smt2"
782783

783-
proveWithExporter ::
784+
proveWithSATExporter ::
785+
(SharedContext -> FilePath -> SATQuery -> TopLevel ()) ->
786+
Set VarIndex ->
787+
String ->
788+
String ->
789+
ProofScript SV.SatResult
790+
proveWithSATExporter exporter unintSet path ext =
791+
withFirstGoal $ tacticSolve $ \g ->
792+
do let file = path ++ "." ++ goalType g ++ show (goalNum g) ++ ext
793+
stats <- Prover.proveWithSATExporter exporter unintSet file (goalProp g)
794+
return (SV.Unsat stats, stats, Just (SolverEvidence stats (goalProp g)))
795+
796+
proveWithPropExporter ::
784797
(SharedContext -> FilePath -> Prop -> TopLevel ()) ->
785798
String ->
786799
String ->
787800
ProofScript SV.SatResult
788-
proveWithExporter exporter path ext =
801+
proveWithPropExporter exporter path ext =
789802
withFirstGoal $ tacticSolve $ \g ->
790803
do let file = path ++ "." ++ goalType g ++ show (goalNum g) ++ ext
791-
stats <- Prover.proveWithExporter exporter file (goalProp g)
804+
stats <- Prover.proveWithPropExporter exporter file (goalProp g)
792805
return (SV.Unsat stats, stats, Just (SolverEvidence stats (goalProp g)))
793806

807+
794808
offline_aig :: FilePath -> ProofScript SV.SatResult
795809
offline_aig path = do
796810
SV.AIGProxy proxy <- lift $ SV.getProxy
797-
proveWithExporter (Prover.adaptExporter (Prover.writeAIG proxy)) path ".aig"
811+
proveWithSATExporter (Prover.writeAIG_SAT proxy) mempty path ".aig"
798812

799813
offline_cnf :: FilePath -> ProofScript SV.SatResult
800814
offline_cnf path = do
801815
SV.AIGProxy proxy <- lift $ SV.getProxy
802-
proveWithExporter (Prover.adaptExporter (Prover.writeCNF proxy)) path ".cnf"
816+
proveWithSATExporter (Prover.writeCNF proxy) mempty path ".cnf"
803817

804818
offline_coq :: FilePath -> ProofScript SV.SatResult
805-
offline_coq path = proveWithExporter (const (Prover.writeCoqProp "goal" [] [])) path ".v"
819+
offline_coq path = proveWithPropExporter (const (Prover.writeCoqProp "goal" [] [])) path ".v"
806820

807821
offline_extcore :: FilePath -> ProofScript SV.SatResult
808-
offline_extcore path = proveWithExporter (const Prover.writeCoreProp) path ".extcore"
822+
offline_extcore path = proveWithPropExporter (const Prover.writeCoreProp) path ".extcore"
809823

810824
offline_smtlib2 :: FilePath -> ProofScript SV.SatResult
811-
offline_smtlib2 path = proveWithExporter Prover.writeSMTLib2 path ".smt2"
825+
offline_smtlib2 path = proveWithSATExporter Prover.writeSMTLib2 mempty path ".smt2"
812826

813827
w4_offline_smtlib2 :: FilePath -> ProofScript SV.SatResult
814-
w4_offline_smtlib2 path = proveWithExporter Prover.writeSMTLib2What4 path ".smt2"
828+
w4_offline_smtlib2 path = proveWithSATExporter Prover.writeSMTLib2What4 mempty path ".smt2"
815829

816830
offline_unint_smtlib2 :: [String] -> FilePath -> ProofScript SV.SatResult
817831
offline_unint_smtlib2 unints path =
818832
do unintSet <- lift $ resolveNames unints
819-
proveWithExporter (Prover.writeUnintSMTLib2 unintSet) path ".smt2"
833+
proveWithSATExporter Prover.writeSMTLib2 unintSet path ".smt2"
820834

821835
offline_verilog :: FilePath -> ProofScript SV.SatResult
822836
offline_verilog path =
823-
proveWithExporter (Prover.adaptExporter Prover.write_verilog) path ".v"
837+
proveWithSATExporter Prover.writeVerilogSAT mempty path ".v"
824838

825839
parseAigerCex :: String -> IO [Bool]
826840
parseAigerCex text =
@@ -892,7 +906,8 @@ provePrim :: ProofScript SV.SatResult
892906
provePrim script t = do
893907
io $ checkBooleanSchema (ttSchema t)
894908
sc <- getSharedContext
895-
goal <- io $ makeProofGoal sc Universal 0 "prove" "prove" (ttTerm t)
909+
prop <- io $ predicateToProp sc Universal (ttTerm t)
910+
let goal = ProofGoal 0 "prove" "prove" prop
896911
(r, pstate) <- runStateT script (startProof goal)
897912
io (finishProof sc pstate) >>= \case
898913
(_stats, Just _) -> return ()
@@ -904,7 +919,8 @@ provePrintPrim :: ProofScript SV.SatResult
904919
-> TypedTerm -> TopLevel Theorem
905920
provePrintPrim script t = do
906921
sc <- getSharedContext
907-
goal <- io $ makeProofGoal sc Universal 0 "prove" "prove" (ttTerm t)
922+
prop <- io $ predicateToProp sc Universal (ttTerm t)
923+
let goal = ProofGoal 0 "prove" "prove" prop
908924
(r, pstate) <- runStateT script (startProof goal)
909925
opts <- rwPPOpts <$> getTopLevelRW
910926
io (finishProof sc pstate) >>= \case
@@ -919,7 +935,8 @@ satPrim :: ProofScript SV.SatResult -> TypedTerm
919935
satPrim script t =
920936
do io $ checkBooleanSchema (ttSchema t)
921937
sc <- getSharedContext
922-
goal <- io $ makeProofGoal sc Existential 0 "sat" "sat" (ttTerm t)
938+
prop <- io $ predicateToProp sc Existential (ttTerm t)
939+
let goal = ProofGoal 0 "sat" "sat" prop
923940
evalStateT script (startProof goal)
924941

925942
satPrintPrim :: ProofScript SV.SatResult

src/SAWScript/Crucible/JVM/Builtins.hs

+1-1
Original file line numberDiff line numberDiff line change
@@ -268,7 +268,7 @@ verifyObligations cc mspec tactic assumes asserts =
268268
let nm = mspec ^. csMethodName
269269
stats <- forM (zip [(0::Int)..] asserts) $ \(n, (msg, assert)) -> do
270270
goal <- io $ scImplies sc assume assert
271-
goal' <- io $ predicateToProp sc Universal [] goal
271+
goal' <- io $ predicateToProp sc Universal goal
272272
let goalname = concat [nm, " (", takeWhile (/= '\n') msg, ")"]
273273
proofgoal = ProofGoal n "vc" goalname goal'
274274
r <- evalStateT tactic (startProof proofgoal)

src/SAWScript/Crucible/LLVM/Builtins.hs

+2-2
Original file line numberDiff line numberDiff line change
@@ -598,7 +598,7 @@ verifyObligations cc mspec tactic assumes asserts =
598598
stats <-
599599
forM (zip [(0::Int)..] asserts) $ \(n, (msg, assert)) ->
600600
do goal <- io $ scImplies sc assume assert
601-
goal' <- io $ predicateToProp sc Universal [] goal
601+
goal' <- io $ predicateToProp sc Universal goal
602602
let goalname = concat [nm, " (", takeWhile (/= '\n') msg, ")"]
603603
proofgoal = ProofGoal n "vc" goalname goal'
604604
r <- evalStateT tactic (startProof proofgoal)
@@ -760,7 +760,7 @@ assumptionsContainContradiction cc tactic assumptions =
760760
assume <- scAndList sc (toListOf (folded . Crucible.labeledPred) assumptions)
761761
-- implies falsehood
762762
goal <- scImplies sc assume =<< toSC sym st (W4.falsePred sym)
763-
goal' <- predicateToProp sc Universal [] goal
763+
goal' <- predicateToProp sc Universal goal
764764
return $ ProofGoal 0 "vc" "vacuousness check" goal'
765765
evalStateT tactic (startProof pgl) >>= \case
766766
Unsat _stats -> return True

src/SAWScript/Proof.hs

+65-43
Original file line numberDiff line numberDiff line change
@@ -42,10 +42,8 @@ module SAWScript.Proof
4242
, Evidence(..)
4343
, checkEvidence
4444

45-
, ProofGoal(..)
46-
, withFirstGoal
47-
4845
, Tactic
46+
, withFirstGoal
4947
, tacticIntro
5048
, tacticCut
5149
, tacticAssume
@@ -57,16 +55,18 @@ module SAWScript.Proof
5755
, tacticSolve
5856

5957
, Quantification(..)
60-
, makeProofGoal
6158
, predicateToProp
6259
, propToPredicate
6360

6461
, ProofState
6562
, psTimeout
6663
, psGoals
6764
, setProofTimeout
65+
, ProofGoal(..)
6866
, startProof
6967
, finishProof
68+
69+
, predicateToSATQuery
7070
) where
7171

7272
import qualified Control.Monad.Fail as F
@@ -411,47 +411,32 @@ data ProofGoal =
411411
data Quantification = Existential | Universal
412412
deriving Eq
413413

414-
-- | Construct a 'ProofGoal' from a term of type @Bool@, or a function
415-
-- of any arity with a boolean result type. Any function arguments are
416-
-- treated as quantified variables. If the 'Quantification' argument
417-
-- is 'Existential', then the predicate is negated and turned into a
418-
-- universally-quantified goal.
419-
makeProofGoal ::
420-
SharedContext ->
421-
Quantification ->
422-
Int {- goal number -} ->
423-
String {- goal type -} ->
424-
String {- goal name -} ->
425-
Term {- goal predicate -} ->
426-
IO ProofGoal
427-
makeProofGoal sc quant gnum gtype gname t =
428-
do t' <- predicateToProp sc quant [] t
429-
return (ProofGoal gnum gtype gname t')
430-
431414
-- | Convert a term with a function type of any arity into a pi type.
432415
-- Negate the term if the result type is @Bool@ and the quantification
433416
-- is 'Existential'.
434-
predicateToProp :: SharedContext -> Quantification -> [Term] -> Term -> IO Prop
435-
predicateToProp sc quant env t =
436-
case asLambda t of
437-
Just (x, ty, body) ->
438-
do Prop body' <- predicateToProp sc quant (ty : env) body
439-
Prop <$> scPi sc x ty body'
440-
Nothing ->
441-
do (argTs, resT) <- asPiList <$> scTypeOf' sc env t
442-
let toPi [] t0 =
443-
case asBoolType resT of
444-
Nothing -> return t0 -- TODO: check quantification
445-
Just () ->
446-
case quant of
447-
Universal -> scEqTrue sc t0
448-
Existential -> scEqTrue sc =<< scNot sc t0
449-
toPi ((x, xT) : tys) t0 =
450-
do t1 <- incVars sc 0 1 t0
451-
t2 <- scApply sc t1 =<< scLocalVar sc 0
452-
t3 <- toPi tys t2
453-
scPi sc x xT t3
454-
Prop <$> toPi argTs t
417+
predicateToProp :: SharedContext -> Quantification -> Term -> IO Prop
418+
predicateToProp sc quant = loop []
419+
where
420+
loop env t =
421+
case asLambda t of
422+
Just (x, ty, body) ->
423+
do Prop body' <- loop (ty : env) body
424+
Prop <$> scPi sc x ty body'
425+
Nothing ->
426+
do (argTs, resT) <- asPiList <$> scTypeOf' sc env t
427+
let toPi [] t0 =
428+
case asBoolType resT of
429+
Nothing -> return t0 -- TODO: check quantification TODO2: should this just be an error?
430+
Just () ->
431+
case quant of
432+
Universal -> scEqTrue sc t0
433+
Existential -> scEqTrue sc =<< scNot sc t0
434+
toPi ((x, xT) : tys) t0 =
435+
do t1 <- incVars sc 0 1 t0
436+
t2 <- scApply sc t1 =<< scLocalVar sc 0
437+
t3 <- toPi tys t2
438+
scPi sc x xT t3
439+
Prop <$> toPi argTs t
455440

456441
-- | Turn a pi type with an @EqTrue@ result into a lambda term with a
457442
-- boolean result type. This function exists to interface the new
@@ -683,6 +668,42 @@ withFirstGoal f =
683668
evidenceCont (e:es2)
684669
return (x, ProofState (gs' <> gs) concl (stats <> stats') timeout evidenceCont')
685670

671+
predicateToSATQuery :: SharedContext -> Set VarIndex -> Term -> IO SATQuery
672+
predicateToSATQuery sc unintSet tm0 =
673+
do (initVars, abstractVars) <- filterFirstOrderVars mempty mempty (getAllExts tm0)
674+
(finalVars, tm') <- processTerm initVars tm0
675+
return SATQuery
676+
{ satVariables = finalVars
677+
, satUninterp = Set.union unintSet abstractVars
678+
, satAsserts = [tm']
679+
}
680+
where
681+
filterFirstOrderVars fovars absvars [] = pure (fovars, absvars)
682+
filterFirstOrderVars fovars absvars (e:es) =
683+
runMaybeT (asFirstOrderTypeMaybe sc (ecType e)) >>= \case
684+
Nothing -> filterFirstOrderVars fovars (Set.insert (ecVarIndex e) absvars) es
685+
Just fot -> filterFirstOrderVars (Map.insert e fot fovars) absvars es
686+
687+
processTerm vars tm =
688+
case asLambda tm of
689+
Just (lnm,tp,body) ->
690+
do fot <- asFirstOrderType sc tp
691+
ec <- scFreshEC sc (Text.unpack lnm) tp
692+
etm <- scExtCns sc ec
693+
body' <- instantiateVar sc 0 etm body
694+
processTerm (Map.insert ec fot vars) body'
695+
696+
-- TODO: check that the type is a boolean
697+
Nothing ->
698+
do ty <- scTypeOf sc tm
699+
ok <- scConvertible sc True ty =<< scBoolType sc
700+
unless ok $ fail $ unlines
701+
[ "predicateToSATQuery: expected boolean result but got:"
702+
, showTerm ty
703+
, showTerm tm0
704+
]
705+
return (vars, tm)
706+
686707
-- | Given a proposition, compute a SAT query which will prove the proposition
687708
-- iff the SAT query is unsatisfiable.
688709
propToSATQuery :: SharedContext -> Set VarIndex -> Prop -> IO SATQuery
@@ -710,7 +731,7 @@ propToSATQuery sc unintSet prop =
710731
, looseVars body == emptyBitSet ->
711732
do processTerm vars (x:xs) body
712733

713-
-- TODO? Allow first-order hypotheses...
734+
-- TODO? Allow universal hypotheses...
714735

715736
| otherwise ->
716737
do fot <- asFirstOrderType sc tp
@@ -749,6 +770,7 @@ goalApply sc rule goal = applyFirst (asPiLists (unProp rule))
749770
mkNewGoals mts args
750771
mkNewGoals _ _ = return []
751772
newgoalterms <- mkNewGoals inst' (reverse ruleArgs)
773+
-- TODO, change the "ty" field to list the hypotheses?
752774
let newgoals = reverse [ goal { goalProp = t } | t <- newgoalterms ]
753775
return (Just newgoals)
754776

0 commit comments

Comments
 (0)