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)