Skip to content

Commit 506b072

Browse files
committed
make mrRefinesFun, generalizeCoIndHypArgs het., add het. interface
1 parent ffec443 commit 506b072

File tree

4 files changed

+400
-194
lines changed

4 files changed

+400
-194
lines changed

heapster-saw/examples/sha512_mr_solver.saw

+1-1
Original file line numberDiff line numberDiff line change
@@ -29,5 +29,5 @@ monadify_term {{ processBlock_spec }};
2929

3030
mr_solver_prove round_00_15 {{ round_00_15_spec }};
3131
mr_solver_prove round_16_80 {{ round_16_80_spec }};
32-
// mr_solver_assume processBlock {{ processBlock_spec }};
32+
mr_solver_prove processBlock {{ processBlock_spec }};
3333
// mr_solver_prove processBlocks {{ processBlocks_spec }};

src/SAWScript/Prover/MRSolver/Monad.hs

+112-2
Original file line numberDiff line numberDiff line change
@@ -59,13 +59,14 @@ import SAWScript.Prover.MRSolver.Term
5959
-- | The context in which a failure occurred
6060
data FailCtx
6161
= FailCtxRefines NormComp NormComp
62+
| FailCtxCoIndHyp CoIndHyp
6263
| FailCtxMNF Term
6364
deriving Show
6465

6566
-- | That's MR. Failure to you
6667
data MRFailure
6768
= TermsNotRel Bool Term Term
68-
| TypesNotEq Type Type
69+
| TypesNotRel Bool Type Type
6970
| CompsDoNotRefine NormComp NormComp
7071
| ReturnNotError Term
7172
| FunsNotEq FunName FunName
@@ -89,6 +90,9 @@ data MRFailure
8990
pattern TermsNotEq :: Term -> Term -> MRFailure
9091
pattern TermsNotEq t1 t2 = TermsNotRel False t1 t2
9192

93+
pattern TypesNotEq :: Type -> Type -> MRFailure
94+
pattern TypesNotEq t1 t2 = TypesNotRel False t1 t2
95+
9296
-- | Remove the context from a 'MRFailure', i.e. remove all applications of the
9397
-- 'MRFailureLocalVar' and 'MRFailureCtx' constructors
9498
mrFailureWithoutCtx :: MRFailure -> MRFailure
@@ -118,6 +122,9 @@ instance PrettyInCtx FailCtx where
118122
prettyInCtx (FailCtxRefines m1 m2) =
119123
group <$> nest 2 <$>
120124
ppWithPrefixSep "When proving refinement:" m1 "|=" m2
125+
prettyInCtx (FailCtxCoIndHyp hyp) =
126+
group <$> nest 2 <$>
127+
ppWithPrefix "When doing co-induction with hypothesis:" hyp
121128
prettyInCtx (FailCtxMNF t) =
122129
group <$> nest 2 <$> vsepM [return "When normalizing computation:",
123130
prettyInCtx t]
@@ -127,8 +134,10 @@ instance PrettyInCtx MRFailure where
127134
ppWithPrefixSep "Could not prove terms equal:" t1 "and" t2
128135
prettyInCtx (TermsNotRel True t1 t2) =
129136
ppWithPrefixSep "Could not prove terms heterogeneously related:" t1 "and" t2
130-
prettyInCtx (TypesNotEq tp1 tp2) =
137+
prettyInCtx (TypesNotRel False tp1 tp2) =
131138
ppWithPrefixSep "Types not equal:" tp1 "and" tp2
139+
prettyInCtx (TypesNotRel True tp1 tp2) =
140+
ppWithPrefixSep "Types not heterogeneously related:" tp1 "and" tp2
132141
prettyInCtx (CompsDoNotRefine m1 m2) =
133142
ppWithPrefixSep "Could not prove refinement: " m1 "|=" m2
134143
prettyInCtx (ReturnNotError t) =
@@ -236,6 +245,28 @@ coIndHypArg :: CoIndHyp -> Either Int Int -> Term
236245
coIndHypArg hyp (Left i) = (coIndHypLHS hyp) !! i
237246
coIndHypArg hyp (Right i) = (coIndHypRHS hyp) !! i
238247

248+
-- | Set the @i@th argument on either the left- or right-hand side of a
249+
-- coinductive hypothesis to the given value
250+
coIndHypSetArg :: CoIndHyp -> Either Int Int -> Term -> CoIndHyp
251+
coIndHypSetArg hyp@(CoIndHyp {..}) (Left i) x =
252+
hyp { coIndHypLHS = take i coIndHypLHS ++ x : drop (i+1) coIndHypLHS }
253+
coIndHypSetArg hyp@(CoIndHyp {..}) (Right i) x =
254+
hyp { coIndHypRHS = take i coIndHypRHS ++ x : drop (i+1) coIndHypRHS }
255+
256+
-- | Set all of the arguments in the given list to the given value in a
257+
-- coinductive hypothesis, using 'coIndHypSetArg'
258+
coIndHypSetArgs :: CoIndHyp -> [Either Int Int] -> Term -> CoIndHyp
259+
coIndHypSetArgs hyp specs x =
260+
foldl' (\hyp' spec -> coIndHypSetArg hyp' spec x) hyp specs
261+
262+
-- | Add a variable to the context of a coinductive hypothesis, returning the
263+
-- updated coinductive hypothesis and a 'Term' which is the new variable
264+
coIndHypWithVar :: CoIndHyp -> LocalName -> Type -> MRM (CoIndHyp, Term)
265+
coIndHypWithVar (CoIndHyp ctx f1 f2 args1 args2 invar1 invar2) nm (Type tp) =
266+
do var <- liftSC1 scLocalVar 0
267+
(args1', args2') <- liftTermLike 0 1 (args1, args2)
268+
return (CoIndHyp (ctx ++ [(nm,tp)]) f1 f2 args1' args2' invar1 invar2, var)
269+
239270
-- | A map from pairs of function names to co-inductive hypotheses over those
240271
-- names
241272
type CoIndHyps = Map (FunName, FunName) CoIndHyp
@@ -440,6 +471,59 @@ liftSC5 :: (SharedContext -> a -> b -> c -> d -> e -> IO f) ->
440471
liftSC5 f a b c d e = mrSC >>= \sc -> liftIO (f sc a b c d e)
441472

442473

474+
----------------------------------------------------------------------
475+
-- * Relating Types Heterogeneously
476+
----------------------------------------------------------------------
477+
478+
-- | A datatype encapsulating all the way in which we consider two types to
479+
-- be heterogeneously related: either one is a @Num@ and the other is a @Nat@,
480+
-- one is a @BVVec@ and the other is a non-@BVVec@ vector (of the same length,
481+
-- this is checked in 'matchHet'), or both sides are pairs (whose components
482+
-- are respectively heterogeneously related, this recursion must be done where
483+
-- 'matchHet' is used, see 'typesHetRelated', for example)
484+
data HetRelated = HetBVNum Natural
485+
| HetNumBV Natural
486+
| HetBVVecVec (Term, Term, Term) (Term, Term)
487+
| HetVecBVVec (Term, Term) (Term, Term, Term)
488+
| HetPair (Term, Term) (Term, Term)
489+
490+
-- | Check to see if the given types match one of the cases of 'HetRelated'
491+
matchHet :: Term -> Term -> MRM (Maybe HetRelated)
492+
matchHet (asBitvectorType -> Just n)
493+
(asDataType -> Just (primName -> "Cryptol.Num", _)) =
494+
return $ Just $ HetBVNum n
495+
matchHet (asDataType -> Just (primName -> "Cryptol.Num", _))
496+
(asBitvectorType -> Just n) =
497+
return $ Just $ HetNumBV n
498+
matchHet (asBVVecType -> Just (n, len, a))
499+
(asNonBVVecVectorType -> Just (m, a')) =
500+
do m' <- mrBvToNat n len
501+
ms_are_eq <- mrConvertible m' m
502+
return $ if ms_are_eq then Just $ HetBVVecVec (n, len, a) (m, a')
503+
else Nothing
504+
matchHet (asNonBVVecVectorType -> Just (m, a'))
505+
(asBVVecType -> Just (n, len, a)) =
506+
do m' <- mrBvToNat n len
507+
ms_are_eq <- mrConvertible m' m
508+
return $ if ms_are_eq then Just $ HetVecBVVec (m, a') (n, len, a)
509+
else Nothing
510+
matchHet (asPairType -> Just (tpL1, tpR1))
511+
(asPairType -> Just (tpL2, tpR2)) =
512+
return $ Just $ HetPair (tpL1, tpR1) (tpL2, tpR2)
513+
matchHet _ _ = return $ Nothing
514+
515+
-- | Return true iff the given types are heterogeneously related
516+
typesHetRelated :: Term -> Term -> MRM Bool
517+
typesHetRelated tp1 tp2 = matchHet tp1 tp2 >>= \case
518+
Just (HetBVNum _) -> return True
519+
Just (HetNumBV _) -> return True
520+
Just (HetBVVecVec (_, _, a) (_, a')) -> typesHetRelated a a'
521+
Just (HetVecBVVec (_, a') (_, _, a)) -> typesHetRelated a' a
522+
Just (HetPair (tpL1, tpR1) (tpL2, tpR2)) ->
523+
(&&) <$> typesHetRelated tpL1 tpL2 <*> typesHetRelated tpR1 tpR2
524+
Nothing -> mrConvertible tp1 tp2
525+
526+
443527
----------------------------------------------------------------------
444528
-- * Functions for Building Terms
445529
----------------------------------------------------------------------
@@ -504,6 +588,10 @@ funNameType (GlobalName gd projs) =
504588
mrApplyAll :: Term -> [Term] -> MRM Term
505589
mrApplyAll f args = liftSC2 scApplyAllBeta f args
506590

591+
-- | Apply a 'Term' to a single argument and beta-reduce in Mr. Monad
592+
mrApply :: Term -> Term -> MRM Term
593+
mrApply f arg = mrApplyAll f [arg]
594+
507595
-- | Like 'scBvNat', but if given a bitvector literal it is converted to a
508596
-- natural number literal
509597
mrBvToNat :: Term -> Term -> MRM Term
@@ -566,6 +654,18 @@ uniquifyNames (nm:nms) nms_other =
566654
let nm' = uniquifyName nm nms_other in
567655
nm' : uniquifyNames nms (nm' : nms_other)
568656

657+
-- | Build a lambda term with the lifting (in the sense of 'incVars') of an
658+
-- MR Solver term
659+
mrLambdaLift :: TermLike tm => [(LocalName,Term)] -> tm ->
660+
([Term] -> tm -> MRM Term) -> MRM Term
661+
mrLambdaLift [] t f = f [] t
662+
mrLambdaLift ctx t f =
663+
do nms <- uniquifyNames (map fst ctx) <$> map fst <$> mrUVars
664+
let ctx' = zipWith (\nm (_,tp) -> (nm,tp)) nms ctx
665+
vars <- reverse <$> mapM (liftSC1 scLocalVar) [0 .. length ctx - 1]
666+
t' <- liftTermLike 0 (length ctx) t
667+
f vars t' >>= liftSC2 scLambdaList ctx'
668+
569669
-- | Run a MR Solver computation in a context extended with a universal
570670
-- variable, which is passed as a 'Term' to the sub-computation. Note that any
571671
-- assumptions made in the sub-computation will be lost when it completes.
@@ -728,6 +828,11 @@ mrCallsFun f = memoFixTermFun $ \recurse t -> case t of
728828
(unwrapTermF -> tf) ->
729829
foldM (\b t' -> if b then return b else recurse t') False tf
730830

831+
832+
----------------------------------------------------------------------
833+
-- * Monadic Operations on Mr. Solver State
834+
----------------------------------------------------------------------
835+
731836
-- | Make a fresh 'MRVar' of a given type, which must be closed, i.e., have no
732837
-- free uvars
733838
mrFreshVar :: LocalName -> Term -> MRM MRVar
@@ -1002,6 +1107,11 @@ mrFunAssumpRHSAsNormComp (OpaqueFunAssump f args) =
10021107
FunBind f args <$> CompFunReturn <$> Type <$> mrFunOutType f args
10031108
mrFunAssumpRHSAsNormComp (RewriteFunAssump rhs) = return rhs
10041109

1110+
1111+
----------------------------------------------------------------------
1112+
-- * Functions for Debug Output
1113+
----------------------------------------------------------------------
1114+
10051115
-- | Print a 'String' if the debug level is at least the supplied 'Int'
10061116
debugPrint :: Int -> String -> MRM ()
10071117
debugPrint i str =

src/SAWScript/Prover/MRSolver/SMT.hs

+58-50
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
{-# LANGUAGE OverloadedStrings #-}
33
{-# LANGUAGE ViewPatterns #-}
44
{-# LANGUAGE ImplicitParams #-}
5+
{-# LANGUAGE TupleSections #-}
56

67
{- |
78
Module : SAWScript.Prover.MRSolver.SMT
@@ -499,17 +500,6 @@ mrProveRelH' _ _ (asBoolType -> Just _) (asBoolType -> Just _) t1 t2 =
499500
mrProveRelH' _ _ (asIntegerType -> Just _) (asIntegerType -> Just _) t1 t2 =
500501
mrProveEqSimple (liftSC2 scIntEq) t1 t2
501502

502-
-- For pair types, prove both the left and right projections are related
503-
mrProveRelH' _ het (asPairType -> Just (tpL1, tpR1))
504-
(asPairType -> Just (tpL2, tpR2)) t1 t2 =
505-
do t1L <- liftSC1 scPairLeft t1
506-
t2L <- liftSC1 scPairLeft t2
507-
t1R <- liftSC1 scPairRight t1
508-
t2R <- liftSC1 scPairRight t2
509-
condL <- mrProveRelH het tpL1 tpL2 t1L t2L
510-
condR <- mrProveRelH het tpR1 tpR2 t1R t2R
511-
andTermInCtx condL condR
512-
513503
-- For BVVec types, prove all projections are related by quantifying over an
514504
-- index variable and proving the projections at that index are related
515505
mrProveRelH' _ het tp1@(asBVVecType -> Just (n1, len1, tpA1))
@@ -559,42 +549,60 @@ mrProveRelH' _ het tp1@(asNonBVVecVectorType -> Just (m1, tpA1))
559549
t2' <- mrGenBVVecFromVec m2 tpA2 t2 "mrProveRelH (BVVec/BVVec)" n len
560550
mrProveRelH het tp1' tp2' t1' t2'
561551

562-
-- If our relation is heterogeneous and we have a BVVec on one side and a
563-
-- non-BVVec vector on the other, wrap the non-BVVec vector term in
564-
-- genBVVecFromVec and recurse
565-
mrProveRelH' _ True tp1@(asBVVecType -> Just (n, len, _))
566-
tp2@(asNonBVVecVectorType -> Just (m, tpA2)) t1 t2 =
567-
do m' <- mrBvToNat n len
568-
ms_are_eq <- mrConvertible m' m
569-
if ms_are_eq then return () else
570-
throwMRFailure (TypesNotEq (Type tp1) (Type tp2))
571-
len' <- liftSC2 scGlobalApply "Prelude.bvToNat" [n, len]
572-
tp2' <- liftSC2 scVecType len' tpA2
573-
err_str_tm <- liftSC1 scString "FIXME: mrProveRelH error"
574-
err_tm <- liftSC2 scGlobalApply "Prelude.error" [tpA2, err_str_tm]
575-
t2' <- liftSC2 scGlobalApply "Prelude.genBVVecFromVec"
576-
[m, tpA2, t2, err_tm, n, len]
577-
-- mrDebugPPPrefixSep 2 "mrProveRelH on BVVec/Vec: " t1 "and" t2'
578-
mrProveRelH True tp1 tp2' t1 t2'
579-
mrProveRelH' _ True tp1@(asNonBVVecVectorType -> Just (m, tpA1))
580-
tp2@(asBVVecType -> Just (n, len, _)) t1 t2 =
581-
do m' <- mrBvToNat n len
582-
ms_are_eq <- mrConvertible m' m
583-
if ms_are_eq then return () else
584-
throwMRFailure (TypesNotEq (Type tp1) (Type tp2))
585-
len' <- liftSC2 scGlobalApply "Prelude.bvToNat" [n, len]
586-
tp1' <- liftSC2 scVecType len' tpA1
587-
err_str_tm <- liftSC1 scString "FIXME: mrProveRelH error"
588-
err_tm <- liftSC2 scGlobalApply "Prelude.error" [tpA1, err_str_tm]
589-
t1' <- liftSC2 scGlobalApply "Prelude.genBVVecFromVec"
590-
[m, tpA1, t1, err_tm, n, len]
591-
-- mrDebugPPPrefixSep 2 "mrProveRelH on Vec/BVVec: " t1' "and" t2
592-
mrProveRelH True tp1' tp2 t1' t2
593-
594-
-- As a fallback, for types we can't handle, just check convertibility
595-
mrProveRelH' _ _ tp1 tp2 t1 t2 =
596-
do success <- mrConvertible t1 t2
597-
if success then return () else
598-
mrDebugPPPrefixSep 2 "mrProveRelH could not match types: " tp1 "and" tp2 >>
599-
mrDebugPPPrefixSep 2 "and could not prove convertible: " t1 "and" t2
600-
TermInCtx [] <$> liftSC1 scBool success
552+
mrProveRelH' _ het tp1 tp2 t1 t2 = (het,) <$> matchHet tp1 tp2 >>= \case
553+
554+
-- If our relation is heterogeneous and we have a bitvector on one side and
555+
-- a Num on the other, ensure that the Num term is TCNum of some Nat, wrap
556+
-- the Nat with bvNat, and recurse
557+
(True, Just (HetBVNum n))
558+
| Just (primName -> "Cryptol.TCNum", [t2']) <- asCtor t2 ->
559+
do n_tm <- liftSC1 scNat n
560+
t2'' <- liftSC2 scGlobalApply "Prelude.bvNat" [n_tm, t2']
561+
mrProveRelH True tp1 tp1 t1 t2''
562+
| otherwise -> throwMRFailure (TermsNotEq t1 t2)
563+
(True, Just (HetNumBV n))
564+
| Just (primName -> "Cryptol.TCNum", [t1']) <- asCtor t1 ->
565+
do n_tm <- liftSC1 scNat n
566+
t1'' <- liftSC2 scGlobalApply "Prelude.bvNat" [n_tm, t1']
567+
mrProveRelH True tp1 tp1 t1'' t2
568+
| otherwise -> throwMRFailure (TermsNotEq t1 t2)
569+
570+
-- If our relation is heterogeneous and we have a BVVec on one side and a
571+
-- non-BVVec vector on the other, wrap the non-BVVec vector term in
572+
-- genBVVecFromVec and recurse
573+
(True, Just (HetBVVecVec (n, len, _) (m, tpA2))) ->
574+
do len' <- liftSC2 scGlobalApply "Prelude.bvToNat" [n, len]
575+
tp2' <- liftSC2 scVecType len' tpA2
576+
t2' <- mrGenBVVecFromVec m tpA2 t2 "mrProveRelH (BVVec/Vec)" n len
577+
-- mrDebugPPPrefixSep 2 "mrProveRelH on BVVec/Vec: " t1 "an`d" t2'
578+
mrProveRelH True tp1 tp2' t1 t2'
579+
(True, Just (HetVecBVVec (m, tpA1) (n, len, _))) ->
580+
do len' <- liftSC2 scGlobalApply "Prelude.bvToNat" [n, len]
581+
tp1' <- liftSC2 scVecType len' tpA1
582+
t1' <- mrGenBVVecFromVec m tpA1 t1 "mrProveRelH (Vec/BVVec)" n len
583+
-- mrDebugPPPrefixSep 2 "mrProveRelH on Vec/BVVec: " t1' "and" t2
584+
mrProveRelH True tp1' tp2 t1' t2
585+
586+
-- For pair types, prove both the left and right projections are related
587+
(_, Just (HetPair (tpL1, tpR1) (tpL2, tpR2))) ->
588+
do t1L <- liftSC1 scPairLeft t1
589+
t2L <- liftSC1 scPairLeft t2
590+
t1R <- liftSC1 scPairRight t1
591+
t2R <- liftSC1 scPairRight t2
592+
condL <- mrProveRelH het tpL1 tpL2 t1L t2L
593+
condR <- mrProveRelH het tpR1 tpR2 t1R t2R
594+
liftTermInCtx2 scAnd condL condR
595+
596+
-- As a fallback, for types we can't handle, just check convertibility (we do
597+
-- this in two cases to make sure we catch any missed 'HetRelated' patterns)
598+
(True, Nothing) ->
599+
do success <- mrConvertible t1 t2
600+
if success then return () else
601+
mrDebugPPPrefixSep 2 "mrProveRel could not match types: " tp1 "and" tp2 >>
602+
mrDebugPPPrefixSep 2 "and could not prove convertible: " t1 "and" t2
603+
TermInCtx [] <$> liftSC1 scBool success
604+
(False, _)->
605+
do success <- mrConvertible t1 t2
606+
if success then return () else
607+
mrDebugPPPrefixSep 2 "mrProveEq could not prove convertible: " t1 "and" t2
608+
TermInCtx [] <$> liftSC1 scBool success

0 commit comments

Comments
 (0)