Soft/Hard constraints in Z3 - z3

How do I express soft and hard constraints in Z3? I know from the API that it is possible to have assumptions (soft constraints), but I can't express this when using the command line tool. I am calling it using z3 /smt2 /si

Assumptions are available in the SMT 2.0 frontend. They are used to extract unsatisfiable cores. They may be also used to “retract” assumptions.
Note that, assumptions are not really “soft constraints”, but they can be used to implement them. See the maxsat example (subdir maxsat) in the Z3 distribution.
That being said, here is an example on how to use assumptions in the Z3 SMT 2.0 frontend.
;; Must enable unsat core generation
(set-option :produce-unsat-cores true)
(set-option :produce-models true)
;; Declare three Boolean constants to "assumptions"
(declare-const p1 Bool)
(declare-const p2 Bool)
(declare-const p3 Bool)
;; We assert (=> p C) to track C using p
(declare-const x Int)
(declare-const y Int)
(assert (=> p1 (> x 10)))
;; An Boolean constant may track more than one formula
(assert (=> p1 (> y x)))
(assert (=> p2 (< y 5)))
(assert (=> p3 (> y 0)))
(check-sat p1 p2 p3)
(get-unsat-core) ;; produce core (p1 p2)
(check-sat p1 p3) ;; "retrack" p2
(get-model)

Related

Are equations with products of uninterpreted functions unsolvable in Z3

The following code
(declare-fun f (Int) Real)
(declare-fun g (Int) Real)
(declare-const x Int)
(declare-const y Int)
(assert (= (* (f x) (g y)) 1.0))
(check-sat)
(get-model)
returns "unknown", even though there is an obvious solution. Eliminating arguments to f and g (effectively making them constants?) results in "sat" with expected assignments. I guess, my question is: what is special about arithmetic with uninterpreted functions?
BTW, replacing * with + also results in "sat", so the issue is not about uninterpreted functions, per se, but about how they are combined.
Additional thoughts
Making the domain (very) finite does not help, e.g.,
(declare-fun f (Bool) Real)
(declare-fun g (Bool) Real)
(declare-const x Bool)
(declare-const y Bool)
(assert (= (* (f x) (g y)) 1.0))
(check-sat)
(get-model)
returns "unknown". This is odd given that f:Bool->Real is essentially just two variables f(False) and f(True) (of course, the solver has to recognize this).
Inability to handle non-linear arithmetic over real-valued uninterpreted functions is a very severe limitation because arrays are implemented as uninterpreted functions. So, for example,
(declare-const a (Array Int Real))
(assert (= (* (select a 1) (select a 1)) 1))
(check-sat)
(get-model)
returns "unknown". In other words, any non-linear algebraic expression on real array elements involving multiplication is unsolvable:'(
It's the non-liearity introduced by the multiplication that makes the problem hard to solve, not the uninterpreted functions. In fact, you can ask the solvers why by using the get-info command:
(set-logic QF_UFNIRA)
(declare-fun f (Int) Real)
(declare-fun g (Int) Real)
(declare-const x Int)
(declare-const y Int)
(assert (= (* (f x) (g y)) 1.0))
(check-sat)
(get-info :reason-unknown)
Here're some responses I got from various solvers:
Z3:
(:reason-unknown smt tactic failed to show goal to be sat/unsat (incomplete (theory arithmetic)))
CVC4:
(:reason-unknown incomplete)
MathSAT:
(error "sat, but with non-linear terms")
So, as the solvers themselves improve and start handling more nonliear arithmetic, you might get models eventually. But, in general, nonlinear problems will always be problematic as they are undecidable when integers are involved. (Since you can code Diophantine equations using non-linear terms.)
See also How does Z3 handle non-linear integer arithmetic? for a relevant discussion from 2012.
Removing uninterpreted functions
Even if you get rid of the uninterpreted functions, you'd still be in the unknown land, so long as you mix Int and Real types and non-linear terms:
(set-logic QF_NIRA)
(declare-const f Real)
(declare-const g Real)
(declare-const x Int)
(declare-const y Int)
(assert (= (+ (* f g) (to_real (+ x y))) 1.0))
(check-sat)
(get-info :reason-unknown)
Z3 says:
(:reason-unknown "smt tactic failed to show goal to be sat/unsat (incomplete (theory arithmetic))")
So, the issue would arise with mixed types and non-linear terms.

Does z3 support rational arithmetic for its input constraints?

In fact, does the SMT-LIB standard have a rational (not just real) sort? Going by its website, it does not.
If x is a rational and we have a constraint x^2 = 2, then we should get back ``unsatisfiable''. The closest I could get to encoding that constraint is the following:
;;(set-logic QF_NRA) ;; intentionally commented out
(declare-const x Real)
(assert (= (* x x) 2.0))
(check-sat)
(get-model)
for which z3 returns a solution, as there is a solution (irrational) in the reals. I do understand that z3 has its own rational library, which it uses, for instance, when solving QF_LRA constraints using an adaptation of the Simplex algorithm. On a related note, is there an SMT solver that supports rationals at the input level?
I'm sure it's possible to define a Rational sort using two integers as suggested by Nikolaj -- I would be interested to see that. It might be easier to just use the Real sort, and any time you want a rational, assert that it's equal to the ratio of two Ints. For example:
(set-option :pp.decimal true)
(declare-const x Real)
(declare-const p Int)
(declare-const q Int)
(assert (> q 0))
(assert (= x (/ p q)))
(assert (= x 0.5))
(check-sat)
(get-value (x p q))
This quickly comes back with
sat
((x 0.5)
(p 1)
(q 2))

Tracking nonlinear real arithmetic assertions using implications versus the :named mechanism gives different answers

While trying to solve large nonlinear real arithmetic problems, I track every assertion using answer literals and explicit implications, as recommended in other posts. It should be equivalent to using the (! (...) :named p1) syntax of the SMT2 format. It seems, though, that both methods are handled differently internally.
The following SMT2 code gives an UNKNOWN result, with explanation "(incomplete (theory arithmetic))":
(set-option :print-success false)
(set-option :produce-unsat-cores true) ; enable generation of unsat cores
(set-option :produce-models true) ; enable model generation
(declare-const p1 Bool)
(declare-const p2 Bool)
(declare-const p3 Bool)
(declare-const p4 Bool)
(declare-const p5 Bool)
(declare-const x1 Real)
(declare-const x2 Real)
(declare-const x3 Real)
(assert (=> p1 (= x1 (/ 1.0 (* x2 x2)))))
(assert (=> p2 (not (= x2 0.0))))
(assert (=> p3 (= x3 (* 2.0 x1))))
(assert (=> p4 (= x3 5.0)))
(assert (=> p5 (< x3 0.0)))
(check-sat p1 p2 p3)
(get-info:reason-unknown)
On the other hand, the following SMT2 code gives the correct answer, UNSAT, and produces an informative unsat core (p4, p5):
(set-option :print-success false)
(set-option :produce-unsat-cores true) ; enable generation of unsat cores
(set-option :produce-models true) ; enable model generation
(declare-const x1 Real)
(declare-const x2 Real)
(declare-const x3 Real)
(assert (! (= x1 (/ 1.0 (* x2 x2))) :named p1))
(assert (! (not (= x2 0.0)) :named p2))
(assert (! (= x3 (* 2.0 x1)) :named p3))
(assert (! (= x3 5.0) :named p4))
(assert (! (< x3 0) :named p5))
(check-sat)
(get-unsat-core)
;(get-model)
My specific questions are:
How can this differing behavior be explained? What is recommended practice for tracking nonlinear real equations and inequalities?
What would be the equivalent OCaml API call for the (! (...) :named p1) syntax of SMT2? Is it assert_and_track?
I am using Z3 version 4.3.2 from the ml-ng branch under Linux.
Many thanks!
The new ML API has been integrated into the unstable branch a couple months ago, and the ml-ng branch has been removed. A few bugfixes/extensions were added to it's worth updating.
assert_and_track does exactly what you suspect and it is internally translated to the first example given.
The difference in behavior is explained by (check-sat p1 p2 p3) which is missing p4 and p5. Once those are added, the two versions behave exactly the same and they produce the same unsat core.

Narrowing scopes of quantifiers in Z3

There is a distribute-forall tactic that can be used for distributing universal quantifiers over conjunction. I'm interested in a more general procedure for both universal and existential quantifiers that would narrow the scope of quantifiers as much as possible.
For example, I'd want the formula
(exists ((x Int)) (and (= z (* 2 x)) (<= z y))) be transformed into
(and (exists ((x Int)) (= z (* 2 x)) (<= z y))).
Can this be done via some other tactic(s)?
The branch mcsat in the Z3 code base has a new tactic called miniscope. It does what you want. We can build the mcsat branch using these instructions. We just have to replace unstable with mcsat.
Here are some examples using this tactic.
(declare-const z Int)
(declare-const x Int)
(declare-const y Int)
(assert (exists ((x Int)) (and (= z (* 2 x)) (<= z y))))
(apply miniscope)
and the produced output
(goals
(goal
(<= z y)
(exists ((x!1 Int)) (= z (* 2 x!1)))
:precision precise :depth 3)
)
Here is a more complicated example:
(set-option :pp.max-depth 100)
(declare-fun p (Int) Bool)
(declare-fun q1 (Int Real) Bool)
(declare-fun q2 (Real Real) Bool)
(declare-fun q3 (Int Int) Bool)
(assert (forall ((x1 Int) (x2 Real))
(or (q2 x2 x2) (exists ((y Real)) (and (q1 y x2) (q1 x1 x2))))))
(apply miniscope)
and the produced output
(goals
(goal
(forall ((x2 Real))
(or (q2 x2 x2)
(and (forall ((x1 Int)) (q1 x1 x2))
(exists ((y Real)) (q1 (to_int y) x2)))))
:precision precise :depth 3)
)
EDIT
The mcsat branch contains work-in-progress that will be eventually merged into the master branch. However, the merge will probably not occur in the next official release (v4.3.2). When we release a new version, we merge unstable and contrib branches into the master branch.
The mcsat branch is essentially adding new functionality. It is not incompatible with the unstable and contrib branches.
We encourage advanced users (familiar with git) to use non-official releases and alternative branches. Of course, when reporting bugs/problems, the git hash associated with the commit should be used instead of the version number.
END EDIT

Quantifier in Z3

Basically, I want to ask Z3 to give me an arbitrary integer whose value is greater than 10. So I write the following statements:
(declare-const x (Int))
(assert (forall ((i Int)) (> i 10)))
(check-sat)
(get-value(x))
How can I apply this quantifier to my model? I know you can write (assert (> x 10)) to achieve this. But I mean I want a quantifier in my model so every time I declare an integer constant whose value is guaranteed to be over 10. So I don't have to insert statement (assert (> x 10)) for every integer constant that I declared.
When you use (assert (forall ((i Int)) (> i 10))), i is a bounded variable and the quantified formula is equivalent to a truth value, which is false in this case.
I think you want to define a macro using quantifiers:
(declare-fun greaterThan10 (Int) Bool)
(assert (forall ((i Int)) (= (greaterThan10 i) (> i 10))))
And you can use them to avoid code repetition:
(declare-const x (Int))
(declare-const y (Int))
(assert (greaterThan10 x))
(assert (greaterThan10 y))
(check-sat)
It is essentially the way to define macros using uninterpreted functions when you're working with Z3 API. Note that you have to set (set-option :macro-finder true) in order that Z3 replaces universal quantifiers with bodies of those functions.
However, if you're working with the textual interface, the macro define-fun in SMT-LIB v2 is an easier way to do what you want:
(define-fun greaterThan10 ((i Int)) Bool
(> i 10))

Resources