-
Notifications
You must be signed in to change notification settings - Fork 205
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
WIP: Draft version constraint generation #5472
Changes from 1 commit
040ef56
0205507
3476a5e
4675fdd
afc3766
c329b37
f3e4d17
a7ef445
c99827d
28eb1bb
80bb27a
220d21d
2bad89e
733f929
5545943
b736d85
4bc25cb
310d7b0
4b08356
e04944f
18b0b97
2f3bf70
0911a90
6651d8d
a8e6c94
50c56c3
d880fa5
aef855a
6c86c22
1c21ff2
a33365c
64370c2
f3bee74
13eb8a4
16aa3e3
642c1b9
c791f31
ba1fad5
344eca8
1cdf6e4
cdbed09
c62c276
ed91ada
b803eb9
a3ee542
91c989c
337b0ca
49563b0
ae4a276
77ea060
2d7c840
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
…r filtering
- Loading branch information
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -8,12 +8,12 @@ module DA.Daml.LF.Verify.Solve | |
( constructConstr | ||
, solveConstr | ||
, ConstraintSet(..) | ||
, Result(..) | ||
) where | ||
|
||
import Data.Bifunctor | ||
import Data.Maybe (fromJust, maybeToList) | ||
import Data.List (lookup) | ||
import Data.Set (toList, fromList) | ||
import Data.List (lookup, union, intersect) | ||
import qualified Data.Text as T | ||
import qualified SimpleSMT as S | ||
|
||
|
@@ -96,6 +96,23 @@ instance ConstrExpr a => ConstrExpr (Cond a) where | |
toCExp (Conditional b x Nothing) = CWhen (toCExp b) (toCExp x) | ||
toCExp (Conditional b x (Just y)) = CIf (toCExp b) (toCExp x) (toCExp y) | ||
|
||
-- | Gather all free variables in a constraint expression. | ||
gatherFreeVars :: ConstraintExpr | ||
-- ^ The constraint expression to traverse. | ||
-> [ExprVarName] | ||
gatherFreeVars (CBool _) = [] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You could |
||
gatherFreeVars (CInt _) = [] | ||
gatherFreeVars (CReal _) = [] | ||
gatherFreeVars (CVar x) = [x] | ||
gatherFreeVars (CAdd e1 e2) = gatherFreeVars e1 `union` gatherFreeVars e2 | ||
gatherFreeVars (CSub e1 e2) = gatherFreeVars e1 `union` gatherFreeVars e2 | ||
gatherFreeVars (CEq e1 e2) = gatherFreeVars e1 `union` gatherFreeVars e2 | ||
gatherFreeVars (CAnd e1 e2) = gatherFreeVars e1 `union` gatherFreeVars e2 | ||
gatherFreeVars (CNot e) = gatherFreeVars e | ||
gatherFreeVars (CIf e1 e2 e3) = gatherFreeVars e1 `union` | ||
gatherFreeVars e2 `union` gatherFreeVars e3 | ||
gatherFreeVars (CWhen e1 e2) = gatherFreeVars e1 `union` gatherFreeVars e2 | ||
|
||
-- | Gather the variable names bound within a skolem variable. | ||
skol2var :: Skolem | ||
-- ^ The skolem variable to handle. | ||
|
@@ -161,10 +178,19 @@ filterCondUpd tem f (Conditional b x (Just y)) = | |
in ( map (CWhen cb) cxcre ++ map (CWhen (CNot cb)) cycre | ||
, map (CWhen cb) cxarc ++ map (CWhen (CNot cb)) cyarc ) | ||
|
||
-- | Filter the given set of skolems, to only include those that occur in the | ||
-- given constraint expressions. Remove duplicates in the process. | ||
filterVars :: [ExprVarName] | ||
-- ^ The list of skolems to filter. | ||
-> [ConstraintExpr] | ||
-- ^ The constraint expressions in which the skolems should occur. | ||
-> [ExprVarName] | ||
filterVars vars cexprs = | ||
let freevars = foldl (\fv e -> fv `union` gatherFreeVars e) [] cexprs | ||
Gertjan423 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
in freevars `intersect` vars | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Any reason why we use lists instead of |
||
|
||
-- | Constructs a constraint set from the generator environment, together with | ||
-- the template name, the choice and field to be verified. | ||
-- TODO: The choice and field don't actually need to be in the same template. | ||
-- Take two templates as arguments. | ||
constructConstr :: Env 'Solving | ||
-- ^ The generator environment to convert. | ||
-> TypeConName | ||
|
@@ -241,24 +267,42 @@ declareVars s xs = zip xs <$> mapM (\x -> S.declare s (var2str x) S.tReal) xs | |
var2str :: ExprVarName -> String | ||
var2str (ExprVarName x) = T.unpack x | ||
|
||
-- | Data type denoting the outcome of the solver. | ||
data Result | ||
= Success | ||
-- ^ The total field amount remains preserved. | ||
| Fail [(S.SExpr, S.Value)] | ||
-- ^ The total field amound does not remain the same. A counter example is | ||
-- provided. | ||
| Unknown | ||
-- ^ The result is inconclusive. | ||
|
||
instance Show Result where | ||
show Success = "Success!" | ||
show (Fail cs) = "Fail. Counter example:" ++ foldl (flip step) "" cs | ||
where | ||
step :: (S.SExpr, S.Value) -> String -> String | ||
step (var, val) str = ("\n" ++) $ S.ppSExpr var $ (" = " ++) $ S.ppSExpr (S.value val) str | ||
show Unknown = "Inconclusive." | ||
|
||
-- | Solve a give constraint set. Prints 'unsat' when the constraint set is | ||
-- valid. It asserts that the set of created and archived contracts are not | ||
-- equal. | ||
solveConstr :: FilePath | ||
-- ^ The path to the constraint solver. | ||
-> ConstraintSet | ||
-- ^ The constraint set to solve. | ||
-> IO () | ||
-> IO Result | ||
solveConstr spath ConstraintSet{..} = do | ||
log <- S.newLogger 1 | ||
sol <- S.newSolver spath ["-in"] (Just log) | ||
vars <- declareVars sol $ filterDups _cVars | ||
vars <- declareVars sol $ filterVars _cVars (_cCres ++ _cArcs) | ||
cre <- foldl S.add (S.real 0) <$> mapM (cexp2sexp vars) _cCres | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. How does this work? You are working with integers in some places. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think it works somewhat by accident because |
||
arc <- foldl S.add (S.real 0) <$> mapM (cexp2sexp vars) _cArcs | ||
S.assert sol (S.not (cre `S.eq` arc)) | ||
S.check sol >>= print | ||
where | ||
-- TODO: Filter vars beforehand | ||
-- TODO: Where does this "_" come from? | ||
filterDups :: [ExprVarName] -> [ExprVarName] | ||
filterDups = filter (\(ExprVarName x) -> x /= "_") . toList . fromList | ||
S.check sol >>= \case | ||
S.Sat -> do | ||
counter <- S.getExprs sol $ map snd vars | ||
return $ Fail counter | ||
S.Unsat -> return Success | ||
S.Unknown -> return Unknown |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note that this only works in our Bazel setup. We need to figure out what we do if we ship things to users. Not sure if we want to ship an SMT solver so a reasonable option might be to let users pass a path to the SMT solver they want to use.