The maxres
engine, presented in νZ - Maximal Satisfaction with Z3 and Maximum Satisfiability Using Core-Guided MaxSAT Resolution, approaches the optimal solution from the unsatisfiable region through a sequence of relaxations.
Therefore, the maxres
engine should not be able to find any sub-optimal model: the first model of the input formula that it finds is also the optimal model.
If you don't need a sub-optimal model but only a sub-optimal value, then you might consider taking the latest approximation of the upper-bound value found by maxres
.
From the command line, it appears that one can make maxres
print any lower/upper bound improvement by enabling the verbose
option:
~$ ./z3 -v:1 smtlib2_maxsmt.smt2
(optimize:check-sat)
(optimize:sat)
(maxsmt)
(opt.maxsat mutex size: 2 weight: 1)
(opt.maxres [1:2])
(opt.maxres [1:1])
found optimum
is-sat: l_true
Satisfying soft constraints
1: |(not (<= y 0))!1| |-> true
1: |(not (<= y 0))!2| |-> true
1: |(not (<= 0 y))!3| |-> false
sat
(objectives
(goal 1)
)
(model
(define-fun y () Int
1)
(define-fun x () Int
(- 1))
)
If I interpret it correctly, in (opt.maxres [1:2])
, 1
is the latest lower bound and 2
is the latest upper bound for the given objective. Note that in the linked post Nikolaj Bjorner states that maxres
may update the upper bound along the maxres
search, but I can't tell how frequently that happens so this solution might not be very effective in practice.
Alternatively, you might want to try to use some other MaxSMT engine which approaches the optimal solution from the satisfiable region, e.g. wmax
, though it might be slower than maxres
.
The MaxSAT engine used by z3
can be selected using the following option:
(set-option:opt.maxsat_engine [wmax|maxres|pd-maxres])
One can also set it through the command-line, as follows:
~$ ./z3 -v:1 opt.maxsat_engine=wmax smtlib2_maxsmt.smt2
(optimize:check-sat)
(optimize:sat)
(maxsmt)
(opt.maxsat mutex size: 2 weight: 1)
(opt.wmax [1:2])
(opt.wmax [1:1])
is-sat: l_true
Satisfying soft constraints
1: |(not (<= y 0))!1| |-> true
1: |(not (<= y 0))!2| |-> true
1: |(not (<= 0 y))!3| |-> false
sat
(objectives
(goal 1)
)
(model
(define-fun y () Int
1)
(define-fun x () Int
(- 1))
)
Note that there is also an option to enable wmax
within the maxres
engine, though I am unsure what it is supposed to do as the output doesn't seem to change:
(set-option:opt.maxres.wmax true)