How can I reduce the following assert statements? - z3

I am struggling to reduce the current assert statements I looked at z3 research and multiple other related research papers with no progress.
I need the output to be SAT as well after reducing the assert statement. The purpose of reducing the assert statement is to reduce the file size.
(set-logic ALL)
(declare-fun f()Int)
(declare-fun g()Int)
(declare-fun d()Int)
(declare-fun j()Int)
(declare-fun b()Int)
(declare-fun C()Int)
(declare-fun e()Int)
(declare-fun h()Int)
(declare-fun i()Int)
(declare-fun k()Int)
(declare-fun l()Int)
(assert (or(<= a 0)(<= f 0)))
(assert (or(and(=(* i (- 1))(* b j))(>= i 0)(> g h i(* e j))(=(+ g (* d j))0)(= h (* C k)))(>= l 0)))
(check-sat)
(exit)

Related

Datalog with negation in Z3 using Pure SMT-LIB2

I'm trying to write this Datalog program in Z3:
p :- r.
q :- \r.
As per this tutorial, I wrote:
(set-logic HORN)
(declare-const p Bool)
(declare-const q Bool)
(declare-const r Bool)
(assert (=> r p))
(assert (=> (not r) q))
(assert r)
(check-sat)
(get-model)
But check-sat yields unknown. How come ?
Removing the rule defining q yields sat.

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.

Executing get-model or unsat-core depending on solver's decision

I wonder, if there is a possibility in a SMT-LIB 2.0 script to access the last satisfiability decision of a solver (sat, unsat, ...). For example, the following code:
(set-option :produce-unsat-cores true)
(set-option :produce-models true)
(set-logic QF_UF)
(declare-fun p () Bool)
(declare-fun q () Bool)
(declare-fun r () Bool)
(assert (! (=> p q) :named PQ))
(assert (! (=> q r) :named QR))
(assert (! (not (=> p r)) :named nPR))
(check-sat)
(get-model)
(get-unsat-core)
ran in Z3 returns:
unsat
(error "line 15 column 10: model is not available")
(PQ QR nPR)
and ran in MathSAT returns:
unsat
(error "model generation not enabled")
In MathSAT 5 it just breaks on (get-model) and doesn't even reach (get-unsat-core).
Is there any way in SMT-LIB 2.0 language to get-model iff the decision was SAT and unsat-core iff the decision was UNSAT? Solution could for example look like this:
(check-sat)
(ite (= (was-sat) true) (get-model) (get-unsat-core))
I searched SMT-LIB 2.0 language documentation, but I did not found any hint.
EDIT:
I also tried the code below, and unfortunately it did not work.
(ite (= (check-sat) "sat") (get-model) (get-unsat-core))
The SMT language does not let you write commands like this.
The way that tools, such as Boogie, deal with this is to use
a two-way text pipe: It reads back the result from (check-sat).
If the resulting string is "unsat" models are not available, but
cores would be if the check uses asssumptions. If the resulting
string is "sat" the tool can expect that a (get-model) command
succeeds.
As Nikolaj said in his answer, the right way to do this is to parse the solver output and conditionally generate either a (get-model) or a (get-unsat-core) statement.
However, with mathsat you can use the code without the (get-model) statement, and call mathsat with the -model option. For example:
$ cat demo_sat.smt2
(set-option :produce-unsat-cores true)
(set-option :produce-models true)
(set-logic QF_UF)
(declare-fun p () Bool)
(declare-fun q () Bool)
(declare-fun r () Bool)
(assert (! (=> p q) :named PQ))
(assert (! (=> q r) :named QR))
; (assert (! (not (=> p r)) :named nPR))
(check-sat)
(get-unsat-core)
$ mathsat -model demo_sat.smt2
sat
( (p false)
(q false)
(r false) )
(error "no unsatisfiability proof, impossible to compute unsat core")
And in the unsat case:
$ cat demo_unsat.smt2
(set-option :produce-unsat-cores true)
(set-option :produce-models true)
(set-logic QF_UF)
(declare-fun p () Bool)
(declare-fun q () Bool)
(declare-fun r () Bool)
(assert (! (=> p q) :named PQ))
(assert (! (=> q r) :named QR))
(assert (! (not (=> p r)) :named nPR))
(check-sat)
(get-unsat-core)
$ mathsat -model demo_unsat.smt2
unsat
( PQ
QR
nPR )
Unfortunately there does not seem to exist an option like -model for producing unsat cores. So this hack won't work if you want to use it with an incremental problem, unless you are OK with the solver terminating after the first sat result. (Because at the first sat result the solver will exit on the error for (get-unsat-core).)

Bitvector arithmetics on Z3

I'm trying to use Z3 to solve arithmetic equations using bitvector arithmetic. I was wondering if there is a way to handle also Real numbers. For example if I can specify a constant different from #x1 and use real number instead.
(set-option :pp.bv-literals false)
(declare-const x (_ BitVec 4))
(declare-const y (_ BitVec 4))
(assert (= (bvadd x y) #x1))
(check-sat)
(get-model)
Yes, both SMT-Lib (and Z3) fully support real numbers: http://smtlib.cs.uiowa.edu/theories-Reals.shtml
You can simply write your example as follows:
(declare-const x Real)
(declare-const y Real)
(assert (= (+ x y) 1))
(check-sat)
(get-model)
You can also mix/match Int/Real/Bitvector, so long as everything is properly typed. Here's an example showing how to use Ints and Reals together:
(declare-const a Int)
(declare-const b Int)
(declare-const c Int)
(declare-const d Real)
(declare-const e Real)
(assert (> e (+ (to_real (+ a b)) 2.0)))
(assert (= d (+ (to_real c) 0.5)))
(assert (> a b))
(check-sat)
(get-model)
However, note that conversion from bit-vectors to integers is usually uninterpreted. See here for a discussion: Z3 int2bv operation

Why is E-matching for conjunctions sensitive to order / case-splitting strategy?

Given the following simplified quantifiers, with the Z3 options set according to those generated by Boogie (full details below), I get "unknown" as a result:
(declare-fun F (Int) Bool)
(declare-fun G (Int) Bool)
(assert (forall ((x Int)) (! (and
(F x) (G x))
:pattern ((F x))
)))
(assert (not (forall ((x Int)) (! (and
(G x) (F x))
:pattern ((F x))
))))
(check-sat)
My understanding for what (I think) Z3 would do with this problem, is skolemise the existential (not forall), which would yield ground instances of both F and G. Given these in the e-graph, we should be able to instantiate the other quantifier, and get unsat. I can see that Z3 probably has to case-split to do this, but I would expect this case-splitting to take place after removing the quantifier and populating the e-graph.
Instead, the first quantifier doesn't get instantiated in the above problem. I've made a number of observations:
Swapping the order of the (F x) and (G x) terms in the first quantifier results in "unsat" without any quantifier instantiations (I suppose some simplification spots the similarity between the two quantified assertions?).
Swapping the order of the (G x) and (F x) terms in the second quantifier (as well as those in the first) results in "unsat" with a single quantifier instantiation (which is the behaviour I'd expect in general).
Changing the smt.case_split option affects the behaviour. Set to 3 (as chosen by Boogie) or 5, we get "unknown". Set to 0,1,2 or 4, I get "unsat".
It would be great to understand the scenarios above, and why (in the failing cases) these terms don't always make it to the e-graph after skolemisation. I'm not sure what the effects of changing the case_split option are in general. At the moment, I don't think Boogie allows that to be changed (and overrides any choice made on the command-line). But I have the feeling that the e-graph should get the information in all cases, ideally.
Here's the full file (removing most of the options set doesn't seem to make a difference to the failing cases, except for the smt.case_split one):
(set-option :print-success false)
(set-info :smt-lib-version 2.0)
(set-option :AUTO_CONFIG false)
;(set-option :MODEL.V2 true)
(set-option :smt.PHASE_SELECTION 0)
(set-option :smt.RESTART_STRATEGY 0)
(set-option :smt.RESTART_FACTOR |1.5|)
(set-option :smt.ARITH.RANDOM_INITIAL_VALUE true)
(set-option :smt.DELAY_UNITS true)
(set-option :NNF.SK_HACK true)
(set-option :smt.MBQI false)
(set-option :smt.QI.EAGER_THRESHOLD 100)
(set-option :smt.QI.COST |"(+ weight generation)"|)
(set-option :TYPE_CHECK true)
(set-option :smt.BV.REFLECT true)
(set-option :TIMEOUT 0)
(set-option :smt.QI.PROFILE true)
(set-option :smt.CASE_SPLIT 3)
; done setting options
(declare-fun F (Int) Bool)
(declare-fun G (Int) Bool)
(assert (forall ((x Int)) (! (and
(F x) (G x))
:pattern ((F x))
)))
(assert (not (forall ((x Int)) (! (and
(G x) (F x))
:pattern ((F x))
))))
(check-sat)
This is settled by the answer from https://stackoverflow.com/users/1096362/nikolaj-bjorner to this question:
Surprising behaviour when trying to prove a forall
The translation of the proof obligation into a disjunction, followed by corresponding relevancy of the clauses, explains why Z3 doesn't see both conjuncts as potential triggers.

Resources