2

I have the following python code:

from z3 import *
import time

s = Solver()
p = Array("p", BitVecSort(11), BitVecSort(8))


for m in range(200):
    start_time = time.time()

    for i in range(20):
        s.add(Or([p[m*20 + i] % 72 == BitVecVal(x, 8) for x in [k * 6 for k in [0,2,4,5,7,9,11]]]))

    s.check()
    model = s.model()
    pre_push = time.time()
    s.push()
    push_time = time.time() - pre_push

    if m % 5 == 0:
        print((m, (time.time() - start_time - push_time)))

As can be seen from the code, during every cycle m I put constraints on values m*20 to m*20+19 of my array. Therefore, there is never an added constraint which involves a variable from a previous valuation of m. However, even disregarding the time it takes to do ``s.push’’, z3 still slows enormously most rounds:

Output:
(0, 0.23836421966552734)
(5, 1.3699274063110352)
(10, 4.132023096084595)
(15, 3.884359836578369)
(20, 4.81259298324585)
(25, 7.442332029342651)
(30, 12.25448989868164)
(35, 15.96577787399292)
(40, 16.90854024887085)
(45, 22.725850105285645)
(50, 29.525628328323364)
(55, 23.494187355041504)
(60, 31.887953996658325)

My intuition would be that push would save the values of the previous model, and each model has the same number of constraints added to previously unconstrained variables, so besides the time It takes to push the time for each cycle should be relatively similar. Why am I getting so much slowdown?

lightning
  • 389
  • 1
  • 9
  • 1
    Even if you're adding "irrelevant" constraints as you put it, the solver still needs to establish this independence. And that process can easily be quadratic in the number of constraints. Having said that, perhaps this points to a possible optimization that the solver can put in to detect these cases faster. Reporting this at the z3 github site might be a good idea so developers can opine. Please report back what you find out! – alias Jun 05 '20 at 20:55
  • 1
    I don't see any `s.pop()` there, so the number of constraints grows and it is normal that the solving time grows as well. Also, `push()` merely creates a *backtrack point*, it doesn't save any model value. Have you tried not using `s.push()`? It doesn't seem necessary, given the snippet you have shown us. – Patrick Trentin Jun 06 '20 at 09:59
  • 1
    Also worth keeping in mind: not all of Z3's theory subsolvers can be used in incremental mode, and Z3 therefore might have to resort to subsolvers that are less performant (or less complete). – Malte Schwerhoff Jun 06 '20 at 13:52
  • Yes, in this case push() doesn't help. I assumed that push(), by saving the current state, would save satisfying variables - is this not true? – lightning Jun 07 '20 at 20:15
  • @lightning No, that isn't what push() is there for. I would advice skimming through this http://disi.unitn.it/rseba/papers/JSAT-2007.pdf – Patrick Trentin Jun 07 '20 at 21:00

0 Answers0