Skip to content

Commit 1103673

Browse files
geo2ajbertholdgithub-actions
authored
Fix SMT interaction in Booster (#3987)
- do not proceed if the ground truth is not SAT: - trigger retry on Unknown and log the predicates with context `[smt][detail] - fail hard on Unsat - post-process the validity check result to eliminate Unknowns where possible - remove duplicate log message --------- Co-authored-by: Jost Berthold <[email protected]> Co-authored-by: github-actions <[email protected]>
1 parent 6203f33 commit 1103673

File tree

1 file changed

+51
-31
lines changed

1 file changed

+51
-31
lines changed

booster/library/Booster/SMT/Interface.hs

Lines changed: 51 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import Control.Monad.IO.Class
2323
import Control.Monad.Trans.Class
2424
import Control.Monad.Trans.Except
2525
import Control.Monad.Trans.State
26+
import Data.Aeson (object, (.=))
2627
import Data.ByteString.Char8 qualified as BS
2728
import Data.Coerce
2829
import Data.Data (Proxy)
@@ -34,7 +35,7 @@ import Data.Map qualified as Map
3435
import Data.Set (Set)
3536
import Data.Set qualified as Set
3637
import Data.Text as Text (Text, pack, unlines, unwords)
37-
import Prettyprinter (Pretty, hsep)
38+
import Prettyprinter (Pretty, backslash, hsep, punctuate, slash, (<+>))
3839
import SMTLIB.Backends.Process qualified as Backend
3940

4041
import Booster.Definition.Base
@@ -46,6 +47,7 @@ import Booster.Prettyprinter qualified as Pretty
4647
import Booster.SMT.Base as SMT
4748
import Booster.SMT.Runner as SMT
4849
import Booster.SMT.Translate as SMT
50+
import Booster.Syntax.Json.Externalise (externaliseTerm)
4951

5052
data SMTError
5153
= GeneralSMTError Text
@@ -370,10 +372,6 @@ checkPredicates ctxt givenPs givenSubst psToCheck
370372
Log.logMessage . Pretty.renderOneLineText $
371373
hsep ("Predicates to check:" : map (pretty' @mods) (Set.toList psToCheck))
372374
result <- interactWithSolver smtGiven sexprsToCheck
373-
Log.logMessage $
374-
"Check of Given ∧ P and Given ∧ !P produced "
375-
<> (Text.pack $ show result)
376-
377375
case result of
378376
(Unsat, Unsat) -> pure Nothing -- defensive choice for inconsistent ground truth
379377
(Sat, Sat) -> do
@@ -435,29 +433,51 @@ checkPredicates ctxt givenPs givenSubst psToCheck
435433
-- assert ground truth
436434
mapM_ smtRun smtGiven
437435

438-
consistent <- smtRun CheckSat
439-
unless (consistent == Sat) $ do
440-
let errMsg = ("Inconsistent ground truth, check returns Nothing" :: Text)
441-
Log.logMessage errMsg
442-
let ifConsistent check = if (consistent == Sat) then check else pure Unsat
443-
444-
-- save ground truth for 2nd check
445-
smtRun_ Push
446-
447-
-- run check for K ∧ P and then for K ∧ !P
448-
let allToCheck = SMT.List (Atom "and" : sexprsToCheck)
449-
450-
positive <- ifConsistent $ do
451-
smtRun_ $ Assert "P" allToCheck
452-
smtRun CheckSat
453-
smtRun_ Pop
454-
negative <- ifConsistent $ do
455-
smtRun_ $ Assert "not P" (SMT.smtnot allToCheck)
456-
smtRun CheckSat
457-
smtRun_ Pop
458-
459-
Log.logMessage $
460-
"Check of Given ∧ P and Given ∧ !P produced "
461-
<> pack (show (positive, negative))
462-
463-
pure (positive, negative)
436+
groundTruthCheckSmtResult <- smtRun CheckSat
437+
Log.logMessage ("Ground truth check returned: " <> show groundTruthCheckSmtResult)
438+
case groundTruthCheckSmtResult of
439+
Unsat -> do
440+
Log.logMessage ("Inconsistent ground truth" :: Text)
441+
pure (Unsat, Unsat)
442+
Unknown -> do
443+
Log.getPrettyModifiers >>= \case
444+
ModifiersRep (_ :: FromModifiersT mods => Proxy mods) -> do
445+
Log.withContext Log.CtxDetail
446+
$ Log.logMessage
447+
$ Log.WithJsonMessage
448+
(object ["conditions" .= (map (externaliseTerm . coerce) . Set.toList $ givenPs)])
449+
$ Pretty.renderOneLineText
450+
$ "Unknown ground truth: "
451+
<+> (hsep . punctuate (slash <> backslash) . map (pretty' @mods) . Set.toList $ givenPs)
452+
pure (Unknown, Unknown)
453+
_ -> do
454+
-- save ground truth for 2nd check
455+
smtRun_ Push
456+
457+
-- run check for K ∧ P and then for K ∧ !P
458+
let allToCheck = SMT.List (Atom "and" : sexprsToCheck)
459+
460+
positive <- do
461+
smtRun_ $ Assert "P" allToCheck
462+
smtRun CheckSat
463+
smtRun_ Pop
464+
465+
negative <- do
466+
smtRun_ $ Assert "not P" (SMT.smtnot allToCheck)
467+
smtRun CheckSat
468+
smtRun_ Pop
469+
470+
Log.logMessage $
471+
"Check of Given ∧ P and Given ∧ !P produced "
472+
<> pack (show (positive, negative))
473+
474+
let (positive', negative') =
475+
case (positive, negative) of
476+
(Unsat, _) -> (Unsat, Sat)
477+
(_, Unsat) -> (Sat, Unsat)
478+
_ -> (positive, negative)
479+
unless ((positive, negative) == (positive', negative')) $
480+
Log.logMessage $
481+
"Given ∧ P and Given ∧ !P interpreted as "
482+
<> pack (show (positive', negative'))
483+
pure (positive', negative')

0 commit comments

Comments
 (0)