Skip to content
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

Merged
merged 51 commits into from
May 20, 2020
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
51 commits
Select commit Hold shift + click to select a range
040ef56
Draft version constraint generation
Gertjan423 Apr 7, 2020
0205507
Some code cleanup
Gertjan423 Apr 8, 2020
3476a5e
Substitution functions
Gertjan423 Apr 9, 2020
4675fdd
Template generation
Gertjan423 Apr 9, 2020
afc3766
Reformatted
Gertjan423 Apr 9, 2020
c329b37
Attempt to fix failing check
Gertjan423 Apr 9, 2020
f3e4d17
Rework generation for value definitions into 2 phase approach
Gertjan423 Apr 15, 2020
a7ef445
Various small changes
Gertjan423 Apr 16, 2020
c99827d
Rework delta to env state
Gertjan423 Apr 16, 2020
28eb1bb
Incorporate data type definitions
Gertjan423 Apr 17, 2020
80bb27a
Various constraint generation bug fixes and improvements
Gertjan423 Apr 21, 2020
220d21d
First part of constraint solving
Gertjan423 Apr 21, 2020
2bad89e
Minor bugfixes
Gertjan423 Apr 22, 2020
733f929
Added simple-smt to bazel
Gertjan423 Apr 22, 2020
5545943
Depend on z3
cocreature Apr 22, 2020
b736d85
Working pipeline
Gertjan423 Apr 23, 2020
4bc25cb
Fix overwriting value definitions, and delayed choice bindings
Gertjan423 Apr 23, 2020
310d7b0
Keep track of contract id's after fetching
Gertjan423 Apr 24, 2020
4b08356
Renaming of choice parameters
Gertjan423 Apr 24, 2020
e04944f
Cleanup
Gertjan423 Apr 24, 2020
18b0b97
Reals instead of ints
Gertjan423 Apr 27, 2020
2f3bf70
Various TODOs
Gertjan423 Apr 27, 2020
0911a90
Added function documentation
Gertjan423 Apr 27, 2020
6651d8d
Small bugfix
Gertjan423 Apr 29, 2020
a8e6c94
Conditionals and forward references
Gertjan423 Apr 29, 2020
50c56c3
Small missing arithmetic
Gertjan423 May 6, 2020
d880fa5
More small missing arithmetic
Gertjan423 May 6, 2020
aef855a
Fix daml 1.0.1 bug
Gertjan423 May 6, 2020
6c86c22
Read arguments and support fields in different templates
Gertjan423 May 7, 2020
1c21ff2
Proper verify output for testing, generate counter example, proper va…
Gertjan423 May 7, 2020
a33365c
Working testing framework, with some basic test cases
Gertjan423 May 8, 2020
64370c2
Testing: build daml instead of storing dar files
Gertjan423 May 12, 2020
f3bee74
Proper handling of update types; constraint synonyms
Gertjan423 May 11, 2020
13eb8a4
Additional equality constraints after create update
Gertjan423 May 14, 2020
16aa3e3
Make assertion print conditional
Gertjan423 May 14, 2020
642c1b9
Various improvements from PR feedback
Gertjan423 May 14, 2020
c791f31
Apply suggestions from code review
Gertjan423 May 14, 2020
ba1fad5
Small fix: Add missing import
Gertjan423 May 14, 2020
344eca8
Small fix: convert numerics
Gertjan423 May 15, 2020
1cdf6e4
Replace PRSelf with correct package reference
Gertjan423 May 15, 2020
cdbed09
Style fixes
Gertjan423 May 15, 2020
c62c276
Rework conditionals to remove When
Gertjan423 May 19, 2020
ed91ada
Cleanup test daml files
Gertjan423 May 19, 2020
b803eb9
Merge branch 'master' into daml-lf-verification
Gertjan423 May 19, 2020
a3ee542
Small style fixes
Gertjan423 May 19, 2020
91c989c
Bugfix after merge
Gertjan423 May 19, 2020
337b0ca
Attempt to fix bazel windows error
Gertjan423 May 19, 2020
49563b0
Attempt #2 to fix bazel windows error
Gertjan423 May 19, 2020
ae4a276
Attempt #3 to fix bazel windows error
Gertjan423 May 19, 2020
77ea060
Attempt #4 to fix bazel windows error
Gertjan423 May 19, 2020
2d7c840
Attempt #5 to fix bazel windows error
Gertjan423 May 19, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Proper verify output for testing, generate counter example, proper va…
…r filtering
  • Loading branch information
Gertjan423 committed May 7, 2020
commit 1c21ff2782fbfda6e5952ff3bdfca59a6e0c3ffe
32 changes: 29 additions & 3 deletions compiler/daml-lf-verify/src/DA/Daml/LF/Verify.hs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@
{-# LANGUAGE DataKinds #-}

-- | Static verification of DAML packages.
module DA.Daml.LF.Verify ( main ) where
module DA.Daml.LF.Verify
( main
, verify
) where

import Data.Text
import Options.Applicative
Expand All @@ -25,15 +28,38 @@ main = do
fieldName = FieldName (pack optFieldName)
solver <- locateRunfiles "z3_nix/bin/z3"
Copy link
Contributor

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.

pkgs <- readPackages [optInputDar]
verify pkgs solver choiceTmpl choiceName fieldTmpl fieldName >>= print

-- | Execute the full verification pipeline.
verify :: [(PackageId, (Package, Maybe PackageName))]
-- ^ The packages to load.
-> FilePath
-- ^ The solver to use.
-> TypeConName
-- ^ The template in which the given choice is defined.
-> ChoiceName
-- ^ The choice to be verified.
-> TypeConName
-- ^ The template in which the given field is defined.
-> FieldName
-- ^ The field to be verified.
-> IO Result
verify pkgs solver choiceTmpl choiceName fieldTmpl fieldName = do
putStrLn "Start value gathering"
case runEnv (genPackages pkgs) (emptyEnv :: Env 'ValueGathering) of
Gertjan423 marked this conversation as resolved.
Show resolved Hide resolved
Left err-> putStrLn "Value phase finished with error: " >> print err
Left err-> do
putStrLn "Value phase finished with error: "
print err
return Unknown
Right env1 -> do
putStrLn "Start value solving"
let env2 = solveValueReferences env1
putStrLn "Start choice gathering"
case runEnv (genPackages pkgs) env2 of
Left err -> putStrLn "Choice phase finished with error: " >> print err
Left err -> do
putStrLn "Choice phase finished with error: "
print err
return Unknown
Right env3 -> do
putStrLn "Start choice solving"
let env4 = solveChoiceReferences env3
Expand Down
68 changes: 56 additions & 12 deletions compiler/daml-lf-verify/src/DA/Daml/LF/Verify/Solve.hs
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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 _) = []
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You could uniplate this if you want. Makes it a bit easier to see what’s going on and it’s more robust to changes to the ADT.

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.
Expand Down Expand Up @@ -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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any reason why we use lists instead of Set?


-- | 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
Expand Down Expand Up @@ -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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How does this work? You are working with integers in some places.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it works somewhat by accident because 0 is both a real and an integer literal. We should check the type.

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