0

When running the following code:

answer = do

    -- elts is a list of the values we're trying to satisfy for
    x <- doSomething

    {- ... constraints and other stuff ... -}

    query $ do cs <- checkSat
               case cs of
                    Sat    -> getValue x
                    Unsat  -> error "Solver couldn't find a satisfiable solution"
                    DSat{} -> error "Unexpected dsat result!"
                    Unk    -> error "Solver returned unknown!"

runSMT answer
-- output: one single satisfying solution

SBV/Z3 return a unique satisfying solution. How to get a list of all (possibly up to n) satisfying solutions instead? I know about sat versus allSat when running the hello-world examples but I'm not sure how to plug it into the more complex context above. I've also read about extractModels (note the plural) but documentation is not exactly abundant on this.

Alternatively, is there a way to get a "random" satisfying solution for the same problem instead of always the same one?

Jivan
  • 21,522
  • 15
  • 80
  • 131

1 Answers1

1

You do this by adding an assertion that rejects the previous value and looping around to get a new model. You can iterate as many times as you like, as long as there are solutions.

Incidentally, this is how allSat internally works. In the query mode, you have to code that logic yourself. The hackage documentation comes with an example: https://hackage.haskell.org/package/sbv-8.8/docs/src/Documentation.SBV.Examples.Queries.AllSat.html#demo

alias
  • 28,120
  • 2
  • 23
  • 40
  • When you say `adding an assertion that rejects the previous value`, when the value is a list of values (like in the example from my other question that you answered today), is there a way to store the previous value as an overall result, or do we need to manually add a constraint for every element of the list, while using `checkSatAssuming`? – Jivan Oct 27 '20 at 20:53
  • You don't need (and shouldn't use) `checkSatAssuming`. That one is particular to the example in the documentation and doesn't apply here. Instead, you need to write what it means to be a "different" in this case. That is, either different length, or differs in one of the values. This'll take some coding, but you have all the information you need from the extracted value. Note that SBV allows you to extract all sorts of models; for instance you can program to get only different length lists, or only same length but different values; it all depends on what sort of models you're interested in. – alias Oct 27 '20 at 21:02
  • I see. And by `you need to write what it means to be a "different" in this case`, the way to do so is to specify additional `constrain $ ...` within the loop, right? or is there another way? – Jivan Oct 27 '20 at 21:04
  • Correct; you just add new constraints as you go through the loop; which cumulatively outlaw all the "previous" models. – alias Oct 27 '20 at 21:52
  • Got it. Interestingly enough, each iteration does output a new (different) solution even though I comment out the additional constraint within the loop. Not sure why. – Jivan Oct 27 '20 at 22:02
  • Did you call `checkSat` each time around the loop? – alias Oct 27 '20 at 22:18
  • Are you sure the results are different? This loop simply will call `check-sat` without adding any new constraints, and the solver will surely return the same model. You can see what's going on by running `runSMTWith z3{verbose=True}` and look if there's anything interesting happening in between two consecutive `check-sat` calls. If there are no constraints introduced, it's very unlikely z3 will give you a new model. – alias Oct 27 '20 at 22:59
  • effectively I was just being stupid — my comparing function between two lists of `SState` was not working properly – Jivan Oct 28 '20 at 09:57