0
votes

I think there's two different relevant cases here:

Case 1:

I have a set of boolean variables and I want another boolean variable which is true if any of these variables are true. I'm currently doing this by making the boolean variables integers which are then set using expressions of the form:

(ite (boolean_expr) 1 0)

I then set the overall boolean just using a sum and a greater than

(> (+ b1 b2 b3...) 0)

Case 2 (this may not really be pseudoboolean):

I have two sets of boolean variables:

set1 = n_1,n_2....

set2 = m_1,m_2....

I'd like to add a constraint that says the number of variables set to true in set1 is equal to the number set to true in set2.

As above, I'm currently doing this by using integers instead of booleans and setting each one with an ite of the form:

n_1 = (ite (boolean_expr) 1 0)

and then saying that:

n_1+n_2+.... = m_1+m_2......

In each case, is using integer variables the most efficient way to do it, or is there a better way?

Thanks.

2

2 Answers

1
votes

You can currently use integers to encode PB constraints. You have to bound the variables to be in the interval 0, 1. For example:

 (set-logic QF_LIA)
 (declare-const n1 Int)
 (declare-const n2 Int)
 (assert (<= 0 n1))
 (assert (<= n1 1))
 (assert (<= 0 n2))
 (assert (<= n2 1))
 (assert (>= (+ n1 n2) 1))
 (check-sat)

If you set the logic to QF_LIA, then Z3 will automatically try to re-encode these constraints using bit-vectors. In the verbose output you will see that Z3 invokes a tactic pb2bv that does the rewriting for you

z3 ty.smt2 /v:10
(simplifier :num-exprs 10 :num-asts 171 :time 0.00 :before-memory 0.77 :after-memory 0.77)
(propagate-values :num-exprs 10 :num-asts 171 :time 0.00 :before-memory 0.77 :after-memory 0.77)
(ctx-simplify :num-steps 17)
(ctx-simplify :num-exprs 10 :num-asts 171 :time 0.00 :before-memory 0.77 :after-memory 0.77)
(simplifier :num-exprs 10 :num-asts 171 :time 0.00 :before-memory 0.77 :after-memory 0.77)
(solve_eqs :num-exprs 10 :num-asts 171 :time 0.00 :before-memory 0.77 :after-memory 0.77)
(elim-uncnstr-vars :num-exprs 10 :num-asts 171 :time 0.00 :before-memory 0.77 :after-memory 0.77)
(simplifier :num-exprs 10 :num-asts 173 :time 0.00 :before-memory 0.77 :after-memory 0.77)
(pb2bv :num-exprs 4 :num-asts 180 :time 0.00 :before-memory 0.77 :after-memory 0.77)
(simplifier :num-exprs 3 :num-asts 178 :time 0.00 :before-memory 0.77 :after-memory 0.77)
(propagate-values :num-exprs 3 :num-asts 178 :time 0.00 :before-memory 0.77 :after-memory 0.77)
(solve_eqs :num-exprs 3 :num-asts 178 :time 0.00 :before-memory 0.77 :after-memory 0.77)
(max-bv-sharing :num-exprs 3 :num-asts 178 :time 0.00 :before-memory 0.77 :after-memory 0.77)
(bit-blaster :num-exprs 3 :num-asts 178 :time 0.00 :before-memory 0.77 :after-memory 0.77)
(aig :num-exprs 3 :num-asts 178 :time 0.00 :before-memory 0.77 :after-memory 0.77)
(ast-table :capacity 640 :size 178)
(sat-status
  :inconsistent    false
   :vars            2
  :elim-vars       0
  :lits            2
  :assigned        0
  :binary-clauses  1
  :ternary-clauses 0
  :clauses         0
  :del-clause      0
  :avg-clause-size 2.00
  :memory          0.77)
1
votes

z3 at some point added native pseudo-boolean constraints

def AtMost(args)
def AtLeast(args)
def PbLe(args, k)
def PbGe(args, k)
def PbEq(args, k, ctx=None)

(Python Docs)

SMTLib2:

(declare-fun a () Bool)
(declare-fun b () Bool)
(declare-fun c () Bool)
(declare-fun d () Bool)
; 9 = 1a + 2b + 4c + 8d
(assert ((_ pbeq 9 1 2 4 8) a b c d))
(check-sat)
(get-model) ; 0 1 0 1
(exit)