Skip to content

Commit 328cd2c

Browse files
authored
3956 branching on complete conditions in Booster (#4058)
Part of #3956 Partially subsumes #3960 This PR makes the rewrite rule application algorithm of Booster more powerful by allowing branching on *complete conditions*. The rewriting algorithm is modified: - when checking the `requires` clause of a rule, we compute the remainder condition `RULE_REM` of that attempted, which is the semantically-checked subset of the required conjuncts `P` which *unclear* after checking its entailment form the pattern's constrains `PC`, meaning that (PC /\ P, PC /\ not P) is (SAT, SAT) or any of the two queries were UNKNOWN - if that remainder is not empty, we return it's *negation* together with the result - when we are finished attempting a *priority group* of rules, we collect the negated remainder conditions `not RULE_REM_i` and conjunct them. This the groups remainder condition `GROUP_REM == not RULE_REM_1 /\ not RULE_REM_2 /\ ... /\ not RULE_REM_n` - At that point, we need to check `GROUP_REM` for satisfiablity. - **If the `GROUP_REM` condition is UNSAT, it means that this group of rules is *complete***, meaning that no other rule can possibly apply, and we do not need to even attempt applying rules of lower priority. This behaviour is the **primary contribution of this PR**. - Otherwise, if it is SAT or solver said UNKNOWN, it means that this group of rules is not complete, i.e. it does not cover the whole space of logical possibility, and we need to construct a remainder configuration, and continue attempting to apply other rules to it. If no rules remain, it means that we are stuck and the semantics is incomplete. This PR does not implement the process of descending into the remainder branch. **Booster with this PR will abort on a SAT remainder**. This behaviour is active by default in `booster-dev` and can be enabled in `kore-rpc-booster` with the flag `--fallback-on Aborted,Stuck` (the default is `Aborted,Stuck,Branching`). Note that with the default reasons, the behaviour of `kore-rpc-booster` is functionally the same, but operationally slightly different: In `Proxy.hs`, Booster may not return `Branching`, and the fallback logic will confirm that Kore returns `Branching` as well, flagging any differences in the `[proxy]` logs (see [Proxy.hs#L391](https://github.com/runtimeverification/haskell-backend/blob/3956-booster-rewrite-rule-remainders/booster/tools/booster/Proxy.hs#L391)). TODO: we need a better flag to enabled branching in Booster, as giving a `--fallback-on Aborted,Stuck` is really non-intuitive. Note: a naive algorithm to compute the remainder conditions would be: after applying a group of rules, take their substituted requires clauses, disjunct and negate. However, this yields a non-minimal predicate that was not simplified and syntactically filtered, potentially making it harder for the SMT solver to solve. The algorithm described above and implemented in this PR re-uses the indeterminate results obtained while applying individual rules and simplifying/checking their individual requires clauses. This logic has been originally proposed by Sam in #3960. See [remainder-predicates.k](https://github.com/runtimeverification/haskell-backend/blob/3956-booster-rewrite-rule-remainders/booster/test/rpc-integration/resources/remainder-predicates.k) and [test-remainder-predicates](https://github.com/runtimeverification/haskell-backend/blob/3956-booster-rewrite-rule-remainders/booster/test/rpc-integration/test-remainder-predicates) for a series of integrations tests that cover the behaviour of `booster-dev` and `kore-rpc-booster`.
1 parent b2ef73c commit 328cd2c

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

51 files changed

+123761
-214
lines changed

booster/library/Booster/JsonRpc.hs

+53-29
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ import Control.Monad
2222
import Control.Monad.IO.Class
2323
import Control.Monad.Trans.Except (catchE, except, runExcept, runExceptT, throwE, withExceptT)
2424
import Crypto.Hash (SHA256 (..), hashWith)
25-
import Data.Bifunctor (second)
25+
import Data.Bifunctor (first, second)
2626
import Data.Foldable
2727
import Data.List (singleton)
2828
import Data.Map.Strict (Map)
@@ -38,7 +38,7 @@ import GHC.Records
3838
import Numeric.Natural
3939

4040
import Booster.CLOptions (RewriteOptions (..))
41-
import Booster.Definition.Attributes.Base (UniqueId, getUniqueId, uniqueId)
41+
import Booster.Definition.Attributes.Base (getUniqueId, uniqueId)
4242
import Booster.Definition.Base (KoreDefinition (..))
4343
import Booster.Definition.Base qualified as Definition (RewriteRule (..))
4444
import Booster.LLVM as LLVM (API)
@@ -49,6 +49,7 @@ import Booster.Pattern.Base qualified as Pattern
4949
import Booster.Pattern.Implies (runImplies)
5050
import Booster.Pattern.Pretty
5151
import Booster.Pattern.Rewrite (
52+
AppliedRuleMetadata (..),
5253
RewriteConfig (..),
5354
RewriteFailed (..),
5455
RewriteResult (..),
@@ -57,7 +58,9 @@ import Booster.Pattern.Rewrite (
5758
)
5859
import Booster.Pattern.Substitution qualified as Substitution
5960
import Booster.Pattern.Util (
61+
externaliseRuleMarker,
6062
freeVariables,
63+
modifyVarName,
6164
sortOfPattern,
6265
sortOfTerm,
6366
)
@@ -479,11 +482,13 @@ execResponse req (d, traces, rr) unsupported = case rr of
479482
{ reason = RpcTypes.Branching
480483
, depth
481484
, logs
482-
, state = toExecState p unsupported Nothing
485+
, state = toExecState p Nothing unsupported
483486
, nextStates =
484-
Just $
485-
map (\(_, muid, p') -> toExecState p' unsupported (Just muid)) $
486-
toList nexts
487+
Just
488+
$ map
489+
( \(rewritten, ruleMetadata) -> toExecState rewritten (Just ruleMetadata) unsupported
490+
)
491+
$ toList nexts
487492
, rule = Nothing
488493
, unknownPredicate = Nothing
489494
}
@@ -494,7 +499,7 @@ execResponse req (d, traces, rr) unsupported = case rr of
494499
{ reason = RpcTypes.Stuck
495500
, depth
496501
, logs
497-
, state = toExecState p unsupported Nothing
502+
, state = toExecState p Nothing unsupported
498503
, nextStates = Nothing
499504
, rule = Nothing
500505
, unknownPredicate = Nothing
@@ -506,7 +511,7 @@ execResponse req (d, traces, rr) unsupported = case rr of
506511
{ reason = RpcTypes.Vacuous
507512
, depth
508513
, logs
509-
, state = toExecState p unsupported Nothing
514+
, state = toExecState p Nothing unsupported
510515
, nextStates = Nothing
511516
, rule = Nothing
512517
, unknownPredicate = Nothing
@@ -518,8 +523,8 @@ execResponse req (d, traces, rr) unsupported = case rr of
518523
{ reason = RpcTypes.CutPointRule
519524
, depth
520525
, logs
521-
, state = toExecState p unsupported Nothing
522-
, nextStates = Just [toExecState next unsupported Nothing]
526+
, state = toExecState p Nothing unsupported
527+
, nextStates = Just [toExecState next Nothing unsupported]
523528
, rule = Just lbl
524529
, unknownPredicate = Nothing
525530
}
@@ -530,7 +535,7 @@ execResponse req (d, traces, rr) unsupported = case rr of
530535
{ reason = RpcTypes.TerminalRule
531536
, depth
532537
, logs
533-
, state = toExecState p unsupported Nothing
538+
, state = toExecState p Nothing unsupported
534539
, nextStates = Nothing
535540
, rule = Just lbl
536541
, unknownPredicate = Nothing
@@ -542,7 +547,7 @@ execResponse req (d, traces, rr) unsupported = case rr of
542547
{ reason = RpcTypes.DepthBound
543548
, depth
544549
, logs
545-
, state = toExecState p unsupported Nothing
550+
, state = toExecState p Nothing unsupported
546551
, nextStates = Nothing
547552
, rule = Nothing
548553
, unknownPredicate = Nothing
@@ -559,7 +564,7 @@ execResponse req (d, traces, rr) unsupported = case rr of
559564
(logSuccessfulRewrites, logFailedRewrites)
560565
(RewriteStepFailed failure)
561566
in logs <|> abortRewriteLog
562-
, state = toExecState p unsupported Nothing
567+
, state = toExecState p Nothing unsupported
563568
, nextStates = Nothing
564569
, rule = Nothing
565570
, unknownPredicate = Nothing
@@ -582,23 +587,37 @@ execResponse req (d, traces, rr) unsupported = case rr of
582587
xs@(_ : _) -> Just xs
583588

584589
toExecState ::
585-
Pattern -> [Syntax.KorePattern] -> Maybe UniqueId -> RpcTypes.ExecuteState
586-
toExecState pat unsupported muid =
590+
Pattern ->
591+
Maybe AppliedRuleMetadata ->
592+
[Syntax.KorePattern] ->
587593
RpcTypes.ExecuteState
588-
{ term = addHeader t
589-
, predicate = addHeader <$> addUnsupported p
590-
, substitution = addHeader <$> s
591-
, ruleSubstitution = Nothing
592-
, rulePredicate = Nothing
593-
, ruleId = getUniqueId <$> muid
594-
}
595-
where
596-
(t, p, s) = externalisePattern pat
597-
termSort = externaliseSort $ sortOfPattern pat
598-
allUnsupported = Syntax.KJAnd termSort unsupported
599-
addUnsupported
600-
| null unsupported = id
601-
| otherwise = maybe (Just allUnsupported) (Just . Syntax.KJAnd termSort . (: unsupported))
594+
toExecState
595+
pat
596+
mRuleMetadata
597+
unsupported =
598+
RpcTypes.ExecuteState
599+
{ term = addHeader t
600+
, predicate = addHeader <$> addUnsupported p
601+
, substitution = addHeader <$> s
602+
, ruleSubstitution = addHeader <$> mruleSubstExt
603+
, rulePredicate = addHeader <$> mrulePredExt
604+
, ruleId = getUniqueId . ruleUniqueId <$> mRuleMetadata
605+
}
606+
where
607+
mrulePredExt = externalisePredicate termSort . rulePredicate <$> mRuleMetadata
608+
mruleSubstExt =
609+
Syntax.KJAnd termSort
610+
. map
611+
(uncurry (externaliseSubstitution termSort) . first (modifyVarName externaliseRuleMarker))
612+
. Map.toList
613+
. ruleSubstitution
614+
<$> mRuleMetadata
615+
(t, p, s) = externalisePattern pat
616+
termSort = externaliseSort $ sortOfPattern pat
617+
allUnsupported = Syntax.KJAnd termSort unsupported
618+
addUnsupported
619+
| null unsupported = id
620+
| otherwise = maybe (Just allUnsupported) (Just . Syntax.KJAnd termSort . (: unsupported))
602621

603622
mkLogRewriteTrace ::
604623
(Bool, Bool) ->
@@ -639,6 +658,11 @@ mkLogRewriteTrace
639658
{ reason = "Uncertain about a condition in rule"
640659
, _ruleId = Just $ getUniqueId (uniqueId $ Definition.attributes r)
641660
}
661+
RewriteRemainderPredicate rs _ _ ->
662+
Failure
663+
{ reason = "Uncertain about the remainder after applying a rule"
664+
, _ruleId = Just $ getUniqueId (uniqueId $ Definition.attributes (head rs))
665+
}
642666
DefinednessUnclear r _ undefReasons ->
643667
Failure
644668
{ reason = "Uncertain about definedness of rule because of: " <> pack (show undefReasons)

booster/library/Booster/Pattern/Bool.hs

+11
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,11 @@ License : BSD-3-Clause
77
module Booster.Pattern.Bool (
88
foldAndBool,
99
isBottom,
10+
isFalse,
1011
negateBool,
1112
splitBoolPredicates,
1213
splitAndBools,
14+
collapseAndBools,
1315
-- patterns
1416
pattern TrueBool,
1517
pattern FalseBool,
@@ -188,6 +190,11 @@ foldAndBool (x : xs) = AndBool x $ foldAndBool xs
188190
isBottom :: Pattern -> Bool
189191
isBottom = (Predicate FalseBool `elem`) . constraints
190192

193+
isFalse :: Predicate -> Bool
194+
isFalse = \case
195+
(Predicate FalseBool) -> True
196+
_ -> False
197+
191198
{- | We want to break apart predicates of type `Y1 andBool ... Yn` apart, in case some of the `Y`s are abstract
192199
which prevents the original expression from being fed to the LLVM simplifyBool function
193200
-}
@@ -205,3 +212,7 @@ splitAndBools :: Predicate -> [Predicate]
205212
splitAndBools p@(Predicate t)
206213
| AndBool l r <- t = concatMap (splitAndBools . Predicate) [l, r]
207214
| otherwise = [p]
215+
216+
-- | Inverse of splitAndBools
217+
collapseAndBools :: [Predicate] -> Predicate
218+
collapseAndBools = Predicate . foldAndBool . map (\(Predicate p) -> p)

0 commit comments

Comments
 (0)