Skip to content

Consider known predicates in Booster's simplifier API #3953

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

Merged
merged 7 commits into from
Jul 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 1 addition & 1 deletion booster/library/Booster/Definition/Ceil.hs
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ computeCeilRule ::
computeCeilRule mllvm def [email protected]{lhs, requires, rhs, attributes, computedAttributes}
| null computedAttributes.notPreservesDefinednessReasons = pure Nothing
| otherwise = do
(res, _) <- runEquationT def mllvm Nothing mempty $ do
(res, _) <- runEquationT def mllvm Nothing mempty mempty $ do
lhsCeils <- Set.fromList <$> computeCeil lhs
requiresCeils <- Set.fromList <$> concatMapM (computeCeil . coerce) (Set.toList requires)
let subtractLHSAndRequiresCeils = (Set.\\ (lhsCeils `Set.union` requiresCeils)) . Set.fromList
Expand Down
32 changes: 17 additions & 15 deletions booster/library/Booster/Pattern/ApplyEquations.hs
Original file line number Diff line number Diff line change
Expand Up @@ -182,13 +182,13 @@ data EquationMetadata = EquationMetadata
}
deriving stock (Eq, Show)

startState :: SimplifierCache -> EquationState
startState cache =
startState :: SimplifierCache -> Set Predicate -> EquationState
startState cache known =
EquationState
{ termStack = mempty
, recursionStack = []
, changed = False
, predicates = mempty
, predicates = known
, cache
}

Expand Down Expand Up @@ -282,14 +282,15 @@ runEquationT ::
Maybe LLVM.API ->
Maybe SMT.SMTContext ->
SimplifierCache ->
Set Predicate ->
EquationT io a ->
io (Either EquationFailure a, SimplifierCache)
runEquationT definition llvmApi smtSolver sCache (EquationT m) = do
runEquationT definition llvmApi smtSolver sCache known (EquationT m) = do
globalEquationOptions <- liftIO GlobalState.readGlobalEquationOptions
logger <- getLogger
prettyModifiers <- getPrettyModifiers
(res, endState) <-
flip runStateT (startState sCache) $
flip runStateT (startState sCache known) $
runExceptT $
runReaderT
m
Expand Down Expand Up @@ -394,10 +395,11 @@ evaluateTerm ::
KoreDefinition ->
Maybe LLVM.API ->
Maybe SMT.SMTContext ->
Set Predicate ->
Term ->
io (Either EquationFailure Term, SimplifierCache)
evaluateTerm direction def llvmApi smtSolver =
runEquationT def llvmApi smtSolver mempty
evaluateTerm direction def llvmApi smtSolver knownPredicates =
runEquationT def llvmApi smtSolver mempty knownPredicates
. evaluateTerm' direction

-- version for internal nested evaluation
Expand All @@ -419,16 +421,15 @@ evaluatePattern ::
SimplifierCache ->
Pattern ->
io (Either EquationFailure Pattern, SimplifierCache)
evaluatePattern def mLlvmLibrary smtSolver cache =
runEquationT def mLlvmLibrary smtSolver cache . evaluatePattern'
evaluatePattern def mLlvmLibrary smtSolver cache pat =
runEquationT def mLlvmLibrary smtSolver cache pat.constraints . evaluatePattern' $ pat

-- version for internal nested evaluation
evaluatePattern' ::
LoggerMIO io =>
Pattern ->
EquationT io Pattern
evaluatePattern' pat@Pattern{term, constraints, ceilConditions} = withPatternContext pat $ do
pushConstraints constraints
evaluatePattern' pat@Pattern{term, ceilConditions} = withPatternContext pat $ do
newTerm <- withTermContext term $ evaluateTerm' BottomUp term
-- after evaluating the term, evaluate all (existing and
-- newly-acquired) constraints, once
Comment on lines -430 to 435
Copy link
Member

Choose a reason for hiding this comment

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

Maybe we should still start empty and push the path condition as the first step.
The code here returns all stored predicates as constraints of the pattern (in line 424) which may or may not be correct depending on how the function was called. This is correct for the current use of the function but might not be correct in all future use cases.
Alternatively, how about we inline all of evaluatedPattern' into evaluatePattern (so no mistakes are possible).

Expand All @@ -455,7 +456,7 @@ evaluateConstraints ::
Set Predicate ->
io (Either EquationFailure (Set Predicate), SimplifierCache)
evaluateConstraints def mLlvmLibrary smtSolver cache =
runEquationT def mLlvmLibrary smtSolver cache . evaluateConstraints'
runEquationT def mLlvmLibrary smtSolver cache mempty . evaluateConstraints'

evaluateConstraints' ::
LoggerMIO io =>
Expand Down Expand Up @@ -948,10 +949,11 @@ simplifyConstraint ::
Maybe LLVM.API ->
Maybe SMT.SMTContext ->
SimplifierCache ->
Set Predicate ->
Predicate ->
io (Either EquationFailure Predicate, SimplifierCache)
simplifyConstraint def mbApi mbSMT cache (Predicate p) = do
runEquationT def mbApi mbSMT cache $ (coerce <$>) . simplifyConstraint' True $ p
simplifyConstraint def mbApi mbSMT cache knownPredicates (Predicate p) = do
runEquationT def mbApi mbSMT cache knownPredicates $ (coerce <$>) . simplifyConstraint' True $ p

simplifyConstraints ::
LoggerMIO io =>
Expand All @@ -962,7 +964,7 @@ simplifyConstraints ::
[Predicate] ->
io (Either EquationFailure [Predicate], SimplifierCache)
simplifyConstraints def mbApi mbSMT cache ps =
runEquationT def mbApi mbSMT cache $
runEquationT def mbApi mbSMT cache mempty $
concatMap splitAndBools
<$> mapM ((coerce <$>) . simplifyConstraint' True . coerce) ps

Expand Down
10 changes: 5 additions & 5 deletions booster/library/Booster/Pattern/Rewrite.hs
Original file line number Diff line number Diff line change
Expand Up @@ -353,7 +353,7 @@ applyRule pat@Pattern{ceilConditions} rule =
<+> (hsep . punctuate comma . map (pretty' @mods) $ knownTrue)

unclearRequires <-
catMaybes <$> mapM (checkConstraint id notAppliedIfBottom) toCheck
catMaybes <$> mapM (checkConstraint id notAppliedIfBottom prior) toCheck

-- check unclear requires-clauses in the context of known constraints (prior)
mbSolver <- lift $ RewriteT $ (.smtSolver) <$> ask
Expand Down Expand Up @@ -403,7 +403,7 @@ applyRule pat@Pattern{ceilConditions} rule =
Set.toList rule.ensures
trivialIfBottom = RewriteRuleAppT $ pure Trivial
newConstraints <-
catMaybes <$> mapM (checkConstraint id trivialIfBottom) ruleEnsures
catMaybes <$> mapM (checkConstraint id trivialIfBottom prior) ruleEnsures

-- check all new constraints together with the known side constraints
whenJust mbSolver $ \solver ->
Expand Down Expand Up @@ -450,17 +450,17 @@ applyRule pat@Pattern{ceilConditions} rule =
checkConstraint ::
(Predicate -> a) ->
RewriteRuleAppT (RewriteT io) (Maybe a) ->
Set.Set Predicate ->
Predicate ->
RewriteRuleAppT (RewriteT io) (Maybe a)
checkConstraint onUnclear onBottom p = do
checkConstraint onUnclear onBottom knownPredicates p = do
RewriteConfig{definition, llvmApi, smtSolver} <- lift $ RewriteT ask
oldCache <- lift . RewriteT . lift $ get
(simplified, cache) <-
withContext CtxConstraint $
simplifyConstraint definition llvmApi smtSolver oldCache p
simplifyConstraint definition llvmApi smtSolver oldCache knownPredicates p
Copy link
Member

Choose a reason for hiding this comment

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

As mentioned, one could just use pat.constraints here...

Suggested change
simplifyConstraint definition llvmApi smtSolver oldCache knownPredicates p
simplifyConstraint definition llvmApi smtSolver oldCache pat.constraints p

-- update cache
lift . RewriteT . lift . modify $ const cache
-- TODO should we keep the traces? Or only on success?
Copy link
Member

Choose a reason for hiding this comment

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

🚮

case simplified of
Right (Predicate FalseBool) -> onBottom
Right (Predicate TrueBool) -> pure Nothing
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
module USE-PATH-CONDITION-IN-EQUATIONS
imports INT
imports BOOL

syntax State ::= test1Init()
| test1State1()
| test1State2()

| test2Init()
| test2State1()
| test2State2()

syntax Int ::= test1F ( Int ) [function, total, no-evaluators]
| test2F ( Int ) [function, total, no-evaluators]

configuration <k> $PGM:State ~> .K </k>
<int> 0:Int </int>

////////////////////////////////////////////////////////////////////////////////
// Here the simplification's side condition is syntactically present //
// in the path condition and is not checked. //
// Result: Stuck at depth 2 in state test1State2() //
// after applying rules test1-init,test1-1-2 //
////////////////////////////////////////////////////////////////////////////////
rule [test1-init]: <k> test1Init() => test1State1() ... </k>
<int> _ => ?X </int>
ensures ?X ==Int 42

rule [test1-1-2]: <k> test1State1() => test1State2() ... </k>
<int> X </int>
requires test1F(X) >Int 0

rule [test1F-simplify]: test1F(X:Int) => X requires X ==Int 42 [simplification]

////////////////////////////////////////////////////////////////////////////////
// Here the simplification's side condition is implied by the path condition, //
// but we need an SMT solver to establish that. //
// Result: Aborted at depth 1 due to indeterminate condition of rule test2-1-2 //
////////////////////////////////////////////////////////////////////////////////
rule [test2-init]: <k> test2Init() => test2State1() ... </k>
<int> _ => ?X </int>
ensures ?X ==Int 42

rule [test2-1-2]: <k> test2State1() => test2State2() ... </k>
<int> X </int>
requires test2F(X) >Int 0

rule [test2F-simplify]: test2F(X:Int) => X requires X >Int 0 [simplification]

// to produce input state:
// krun --output kore --depth 1 -cPGM='test1Init()' | kore-parser test-kompiled/definition.kore --module TEST --pattern /dev/stdin --print-pattern-json > state-test1Init.json
// then edit state-test1Init.json to substitute test1State1() for test1Init()

endmodule
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
echo "kompiling use-path-condition-in-equations.k"
kompile --backend haskell use-path-condition-in-equations.k
cp use-path-condition-in-equations-kompiled/definition.kore use-path-condition-in-equations.kore
rm -r use-path-condition-in-equations-kompiled
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Test the use of the known path condition when applying simplifications

See `../resourses/use-path-condition-in-equations.k`.
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"reason": "stuck",
"depth": 2,
"state": {
"term": {
"format": "KORE",
"version": 1,
"term": {
"tag": "App",
"name": "Lbl'-LT-'generatedTop'-GT-'",
"sorts": [],
"args": [
{
"tag": "App",
"name": "Lbl'-LT-'k'-GT-'",
"sorts": [],
"args": [
{
"tag": "App",
"name": "kseq",
"sorts": [],
"args": [
{
"tag": "App",
"name": "inj",
"sorts": [
{
"tag": "SortApp",
"name": "SortState",
"args": []
},
{
"tag": "SortApp",
"name": "SortKItem",
"args": []
}
],
"args": [
{
"tag": "App",
"name": "Lbltest1State2'LParRParUnds'USE-PATH-CONDITION-IN-EQUATIONS'Unds'State",
"sorts": [],
"args": []
}
]
},
{
"tag": "App",
"name": "dotk",
"sorts": [],
"args": []
}
]
}
]
},
{
"tag": "App",
"name": "Lbl'-LT-'int'-GT-'",
"sorts": [],
"args": [
{
"tag": "EVar",
"name": "Var'Ques'X",
"sort": {
"tag": "SortApp",
"name": "SortInt",
"args": []
}
}
]
},
{
"tag": "App",
"name": "Lbl'-LT-'generatedCounter'-GT-'",
"sorts": [],
"args": [
{
"tag": "DV",
"sort": {
"tag": "SortApp",
"name": "SortInt",
"args": []
},
"value": "0"
}
]
}
]
}
},
"predicate": {
"format": "KORE",
"version": 1,
"term": {
"tag": "Equals",
"argSort": {
"tag": "SortApp",
"name": "SortBool",
"args": []
},
"sort": {
"tag": "SortApp",
"name": "SortGeneratedTopCell",
"args": []
},
"first": {
"tag": "DV",
"sort": {
"tag": "SortApp",
"name": "SortBool",
"args": []
},
"value": "true"
},
"second": {
"tag": "App",
"name": "Lbl'UndsEqlsEqls'Int'Unds'",
"sorts": [],
"args": [
{
"tag": "EVar",
"name": "Var'Ques'X",
"sort": {
"tag": "SortApp",
"name": "SortInt",
"args": []
}
},
{
"tag": "DV",
"sort": {
"tag": "SortApp",
"name": "SortInt",
"args": []
},
"value": "42"
}
]
}
}
}
}
}
}
Loading
Loading