I don't think you can do this in general; that is, when you can have arbitrary constraints over arbitrary theories. You are asking a "meta"-question: "Maximize the number of models" is not a question about the problem itself, but rather about the models of the problem; something SMTLib cannot deal with.
Having said that, however, I think it should be possible to code it for specific problems. In the example you gave, the model space is maximized when a - b
is the greatest; so you can simply write:
(set-option :produce-models true)
(declare-fun a () Int)
(declare-fun b () Int)
(declare-fun c () Int)
(assert (< 5 a 10))
(assert (< 0 b 5))
(assert (< b c a))
(maximize (- a b))
(check-sat)
(get-value (a b))
To which z3 responds:
sat
((a 9)
(b 1))
as desired. Or, you can use the Python bindings:
from z3 import *
a, b, c = Ints('a b c')
o = Optimize()
o.add(And(5 < a, a < 10, 0 < b, b < 5, b < c, c < a))
o.maximize(a - b)
if o.check() == sat:
m = o.model()
print "a = %s, b = %s" % (m[a], m[b])
else:
print "unsatisfiable or unknown"
which prints:
a = 9, b = 1
There are also bindings for C/C++/Java/Scala/Haskell etc. that let you do more or less the same from those hosts as well.
But the crucial point here is that we had to manually come up with the goal that maximizing a - b
would solve the problem here. That step is something that needs human intervention as it applies to whatever your current problem is. (Imagine you're working with the theory of floats, or arbitrary data-types; coming up with such a measure might be impossible.) I don't think that part can be automated magically using traditional SMT solving. (Unless Patrick comes up with a clever encoding, he's quite clever that way!)