Search code examples
optimizationmathematical-optimizationz3z3py

Optimize() in z3py not finding optimal solutions


I'm trying to use z3py as an optimization solver to maximise the volume of a cuboid cut out from a piece of paper. The python API provides the Optimize() object but using it seems to be unreliable, giving me solutions that are obviously inaccurate.

I've tried using h = opt.maximise followed by opt.upper(h) as well as simply checking the model, as well as defining the volume of the cuboid before adding it to the model v = w*b*l and after, as well as setting the objective as w*b*l instead of v. None of them have given me anything resembling a good solution.

from z3 import *
l = Real("l")
w = Real("w")
b = Real("b")
v = Real("v")
opt = Optimize()
width = 63.6
height = 51

opt.add(b+l <= width)
opt.add(w+b+w+l+w <= height)
opt.add(w > 0)
opt.add(b > 0)
opt.add(l > 0)
opt.add(v == w*b*l)
opt.maximize(w * b * l)
# h = opt.maximize(v)


print(opt.check())
# print(opt.upper(h))
print(opt.model())

Outputs:

unknown
[w = 1, b = 1, l = 47, v = 47]

This definitely is not the maximum. Setting all values to 10 gives a greater solution that fulfills the constraints.


Solution

  • Z3's optimizer does not handle non-linear problems. And indeed, that's precisely why it prints unknown. When you see a call to check returning unknown it precisely means that: Z3 does not know whether the problem is satisfiable or not, let alone if it has found the optimum solution.

    If you add:

    print(opt.reason_unknown())
    

    after the call to check, you'll see:

    (incomplete (theory arithmetic))
    

    In these cases, the call to model will return some intermediate result z3 obtained as it worked on the problem, but by no means it is guaranteed to be optimal.

    Your problem is non-linear because you are multiplying variables. (w, b, and l.) Z3 can solve nonlinear satisfiability problems over reals, but not optimization problems. See, for instance, here: z3Opt optimize non-linear function using qfnra-nlsat

    (Note that nonlinear optimization is a significantly harder problem for reals as opposed to pure satisfiability. So, it's not just a matter of "not having implemented it yet.")