Floor and Ceiling Function implementation in Z3 - z3

I have tried to implement Floor and Ceiling Function as defined in the following link
https://math.stackexchange.com/questions/3619044/floor-or-ceiling-function-encoding-in-first-order-logic/3619320#3619320
But Z3 query returning counterexample.
Floor Function
_X=Real('_X')
_Y=Int('_Y')
_W=Int('_W')
_n=Int('_n')
_Floor=Function('_Floor',RealSort(),IntSort())
..
_s.add(_X>=0)
_s.add(_Y>=0)
_s.add(Implies(_Floor(_X)==_Y,And(Or(_Y==_X,_Y<_X),ForAll(_W,Implies(And(_W>=0,_W<_X),And(_W ==_Y,_W<_Y))))))
_s.add(Implies(And(Or(_Y==_X,_Y<_X),ForAll(_W,Implies(And(_W>=0,_W<_X),And(_W==_Y,_W<_Y))),_Floor(_X)==_Y))
_s.add(Not(_Floor(0.5)==0))
Expected Result - Unsat
Actual Result - Sat
Ceiling Function
_X=Real('_X')
_Y=Int('_Y')
_W=Int('_W')
_Ceiling=Function('_Ceiling',RealSort(),IntSort())
..
..
_s.add(_X>=0)
_s.add(_Y>=0)
_s.add(Implies(_Ceiling(_X)==_Y,And(Or(_Y==_X,_Y<_X),ForAll(_W,Implies(And(_W>=0,_W<_X),And(_W ==_Y,_Y<_W))))))
_s.add(Implies(And(Or(_Y==_X,_Y<_X),ForAll(_W,Implies(And(_W>=0,_W<_X),And(_W==_Y,_Y<_W)))),_Ceiling(_X)==_Y))
_s.add(Not(_Ceilng(0.5)==1))
Expected Result - Unsat
Actual Result - Sat

[Your encoding doesn't load to z3, it gives a syntax error even after eliminating the '..', as your call to Implies needs an extra argument. But I'll ignore all that.]
The short answer is, you can't really do this sort of thing in an SMT-Solver. If you could, then you can solve arbitrary Diophantine equations. Simply cast it in terms of Reals, solve it (there is a decision procedure for Reals), and then add the extra constraint that the result is an integer by saying Floor(solution) = solution. So, by this argument, you can see that modeling such functions will be beyond the capabilities of an SMT solver.
See this answer for details: Get fractional part of real in QF_UFNRA
Having said that, this does not mean you cannot code this up in Z3. It just means that it will be more or less useless. Here's how I would go about it:
from z3 import *
s = Solver()
Floor = Function('Floor',RealSort(),IntSort())
r = Real('R')
f = Int('f')
s.add(ForAll([r, f], Implies(And(f <= r, r < f+1), Floor(r) == f)))
Now, if I do this:
s.add(Not(Floor(0.5) == 0))
print(s.check())
you'll get unsat, which is correct. If you do this instead:
s.add(Not(Floor(0.5) == 1))
print(s.check())
you'll see that z3 simply loops forever. To make this usefull, you'd want the following to work as well:
test = Real('test')
s.add(test == 2.4)
result = Int('result')
s.add(Floor(test) == result)
print(s.check())
but again, you'll see that z3 simply loops forever.
So, bottom line: Yes, you can model such constructs, and z3 will correctly answer the simplest of queries. But with anything interesting, it'll simply loop forever. (Essentially whenever you'd expect sat and most of the unsat scenarios unless they can be constant-folded away, I'd expect z3 to simply loop.) And there's a very good reason for that, as I mentioned: Such theories are just not decidable and fall well out of the range of what an SMT solver can do.
If you are interested in modeling such functions, your best bet is to use a more traditional theorem prover, like Isabelle, Coq, ACL2, HOL, HOL-Light, amongst others. They are much more suited for working on these sorts of problems. And also, give a read to Get fractional part of real in QF_UFNRA as it goes into some of the other details of how you can go about modeling such functions using non-linear real arithmetic.

Related

How to compare two expression in z3?

I am wondering how to compare two expressions in C++ z3. The following code generates two equal expressions, but the result shows they do not share the same id, which is different from this post. A way to do this is to simplify before checking but the speed is slow due to the simplify overhead. Is there an efficient way to solve it?
z3::context c;
z3::expr z1 = c.bool_const("z1");
z3::expr z2 = c.bool_const("z2");
z3::expr z11 = z1 && z2;
z3::expr z22 = z2 && z1;
auto res = Z3_is_eq_ast(c, z11, z22);
Simple answer: No.
Note that two terms that are semantically identical can still yield False, even after a call to simplify. The only way to check equivalence for sure is to call check_sat.
The way to think about Z3_is_eq_ast is that if it says True, then you absolutely have the same term. If it says False, then it may or may not be the same term, you just don't know. (It's essentially hash-consing, an old idea, and all the caveats apply. See here: https://en.wikipedia.org/wiki/Hash_consing).

What is the most efficient way of checking N-way equation equivalence in Z3?

Suppose I have a set of Z3 expressions:
exprs = [A, B, C, D, E, F]
I want to check whether any of them are equivalent and, if so, determine which. The most obvious way is just an N×N comparison (assume exprs is composed of some arbitrarily-complicated boolean expressions instead of the simple numbers in the example):
from z3 import *
exprs = [IntVal(1), IntVal(2), IntVal(3), IntVal(4), IntVal(3)]
for i in range(len(exprs) - 1):
for j in range(i+1, len(exprs)):
s = Solver()
s.add(exprs[i] != exprs[j])
if unsat == s.check():
quit(f'{(i, j)} are equivalent')
Is this the most efficient method, or is there some way of quantifying over a set of arbitrary expressions? It would also be acceptable for this to be a two-step process where I first learn whether any of the expressions are equivalent, and then do a longer check to see which specific expressions are equivalent.
As with anything performance related, the answer is "it depends." Before delving into options, though, note that z3 supports Distinct, which can check whether any number of expressions are all different: https://z3prover.github.io/api/html/namespacez3py.html#a9eae89dd394c71948e36b5b01a7f3cd0
Though of course, you've a more complicated query here. I think the following two algorithms are your options:
Explicit pairwise checks
Depending on your constraints, the simplest thing to do might be to call the solver multiple times, as you alluded to. To start with, use Distinct and make a call to see if its negation is satisfiable. (i.e., check if some of these expressions can be made equal.) If the answer comes unsat, you know you can't make any equal. Otherwise, go with your loop as before till you hit the pair that can be made equal to each other.
Doing multiple checks together
You can also solve your problem using a modified algorithm, though with more complicated constraints, and hopefully faster.
To do so, create Nx(N-1)/2 booleans, one for each pair, which is equal to that pair not being equivalent. To illustrate, let's say you have the expressions A, B, and C. Create:
X0 = A != B
X1 = A != C
X2 = B != C
Now loop:
Ask if X0 || X1 || X2 is satisfiable.
If the solver comes back unsat, then all of A, B, and C are equivalent. You're done.
If the solver comes back sat, then at least one of the disjuncts X0, X1 or X2 is true. Use the model the solver gives you to determine which ones are false, and continue with those until you get unsat.
Here's a simple concrete example. Let's say the expressions are {1, 1, 2}:
Ask if 1 != 1 || 1 != 2 || 1 != 2 is sat.
It'll be sat. In the model, you'll have at least one of these disjuncts true, and it won't be the first one! In this case the last two. Drop them from your list, leaving you with 1 != 1.
Ask again if 1 != 1 is satisfiable. The answer will be unsat and you're done.
In the worst case you'll make Nx(N-1)/2 calls to the solver, if it happens that none of them can be made equivalent with you eliminating one at a time. This is where the first call to Not (Distinct(A, B, C, ...)) is important; i.e., you will start knowing that some pair is equivalent; hopefully iterating faster.
Summary
My initial hunch is that the second algorithm above will be more performant; though it really depends on what your expressions really look like. I suggest some experimentation to find out what works the best in your particular case.
A Python solution
Here's the algorithm coded:
from z3 import *
exprs = [IntVal(i) for i in [1, 2, 3, 4, 3, 2, 10, 10, 1]]
s = Solver()
bools = []
for i in range(len(exprs) - 1):
for j in range(i+1, len(exprs)):
b = Bool(f'eq_{i}_{j}')
bools.append(b)
s.add(b == (exprs[i] != exprs[j]))
# First check if they're all distinct
s.push()
s.add(Not(Distinct(*exprs)))
if(s.check()== unsat):
quit("They're all distinct")
s.pop()
while True:
# Be defensive, bools should not ever become empty here.
if not bools:
quit("This shouldn't have happened! Something is wrong.")
if s.check(Or(*bools)) == unsat:
print("Equivalent expressions:")
for b in bools:
print(f' {b}')
quit('Done')
else:
# Use the model to keep bools that are false:
m = s.model()
bools = [b for b in bools if not(m.evaluate(b, model_completion=True))]
This prints:
Equivalent expressions:
eq_0_8
eq_1_5
eq_2_4
eq_6_7
Done
which looks correct to me! Note that this should work correctly even if you have 3 (or more) items that are equivalent; of course you'll see the output one-pair at a time. So, some post-processing might be needed to clean that up, depending on the needs of the upstream algorithm.
Note that I only tested this for a few test values; there might be corner case gotchas. Please do a more thorough test and report if there're any bugs!

Simplify product of roots containing goniometric functions

In Maxima, I am trying to simplify the expression
sqrt(1 - sin(x)) * sqrt(1 + sin(x))
to yield
cos(x)
I properly restricted the definition of x
declare(x, real) $
assume(x > 0, x < %pi/2) $
and tried several simplification commands including radcan, trigsimp, trigreduce and trigexpand, but without any success. How can this be done?
Try trigsimp(rootscontract(expr))
The restrictions you assert do not uniquely determine the simplified result you request.
It would seem both harmless and obviously unnecessary to declare or assume the following:
declare(9, real)
assume(9>0)
and yet, sqrt(9) is still the set {-3, +3}, mathematically speaking, as opposed to "what I learned in 6th grade".
Stavros' suggestion give |cos(x)|, which is not quite what the original questioner wanted.
Another way of getting the same result, one which may more explicitly exhibit the -in general falseness - of the result, is to square and then use the semi-bogus sqrt, that attempts to pick the positive answer.
trigsimp (sqrt(expand(expr^2)));
If you think this is a way of simplifying expr, note that it changes -3 to 3.

Z3: implementing "Model Checking Using SMT and Theory of Lists" solver hanging

I'm trying to implement some code from this paper: Model Checking Using SMT and Theory of Lists to prove facts about a simple machine. I wrote the following code using the Python Z3 API, mirroring the code described in the paper: the code and problem was intentionally simplified in order to show the problem better:
from z3 import *
MachineIntSort = BitVecSort(16)
MachineInt = lambda x: BitVec(x, 16)
def DeclareLinkedList(sort):
LinkedList = Datatype(f'{sort.name()}_LinkedList')
LinkedList.declare('nil')
LinkedList.declare('cons', ('car', sort), ('cdr', LinkedList))
return LinkedList.create()
State = Datatype('State')
State.declare('state',
('A', MachineIntSort),
('B', MachineIntSort),
('C', MachineIntSort),
('D', MachineIntSort))
State = State.create()
StateList = DeclareLinkedList(State)
def transition_condition(initial, next):
return State.A(next) == State.A(initial) + 1
def final_condition(lst):
return State.A(StateList.car(lst)) == 2
solver = Solver()
check_execution_trace = Function('check_execution_trace', StateList, BoolSort())
execution_list = Const('execution_list', StateList)
solver.add(ForAll(execution_list, check_execution_trace(execution_list) ==
If(And(execution_list != StateList.nil, StateList.cdr(execution_list) != StateList.nil),
And(
transition_condition(StateList.car(execution_list), StateList.car(StateList.cdr(execution_list))),
check_execution_trace(StateList.cdr(execution_list)),
If(final_condition(StateList.cdr(execution_list)),
StateList.nil == StateList.cdr(StateList.cdr(execution_list)),
StateList.nil != StateList.cdr(StateList.cdr(execution_list))
)
),
True), # If False, unsat but incorrect. If True, it hangs
))
states = Const('states', StateList)
# Execution trace cannot be empty
solver.add(StateList.nil != states)
# Initial condition
solver.add(State.A(StateList.car(states)) == 0)
# Transition axiom
solver.add(check_execution_trace(states))
print(solver.check())
print(solver.model())
The problem is that model step hangs instead of giving the (trivial) solution. I think I might not have implemented everything the paper describes: I don't understand what "Finally, it is important to stress the purpose of the instantiation pattern ( PAT:
{check tr (lst)} ) in the FORALL clause. This axiom states something about all
lists. However, it would be impossible for the SMT solver to try to prove that the
statement indeed holds for all possible lists. Instead, the common approach is to
provide an instantiation pattern to basically say in which cases the axiom should
be instantiated and therefore enforced by the solver." means, so I didn't implement it.
My goal now is not to have pretty code (I know the star-import is ugly, ...) but to have working code.
Quantified formulas are hard for SMT solvers to deal with, as they make the logic semi-decidable. SMT solvers usually rely on "heuristics" to deal with such problems. Patterns are one way to "help" those heuristics to converge faster, when dealing with quantifiers.
You might want to read Section 13.2 of http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.225.8231&rep=rep1&type=pdf
To see an example of how to add patterns in the z3py bindings, look at this page: https://ericpony.github.io/z3py-tutorial/advanced-examples.htm (Search for "Patterns" when the page comes up.)

Goal Unsupported by Tactic

I have some code, which I want to check with help of some tactics. Since I have lot of if-then-else statements, I want to apply elim-term-ite tactic.
I have made use of following tactics
(check-sat-using (then (! simplify :arith-lhs true) elim-term-ite solve-eqs lia2pb pb2bv bit-blast sat))
However, if I an error with this as - "goal is in a fragment unsupported by lia2pb"
So then, if I try to remove the tactics lia2pb and the ones next to them, I get another error as unknown "incomplete".
I tried to remove all the tactics except for the simplify, however I would still get an incomplete error.
What is that I should try to help the sat solver solve the problem?
Should I try another tactics?
To use lia2pb (aka linear integer arithmetic to pseudo-boolean), all integer variables must be bounded. That is, they must have a lower and upper bound.
The tactic sat is only complete if the input goal does not contain theory atoms. That is, the goal contains only Boolean connectives and Boolean constants. If that is not the case, then it will return "unknown" if it cannot show the (Boolean abstraction of the input) goal to be unsatisfiable.
You can ask Z3 to display the input goal for lia2pb by using the following command:
(apply (then (! simplify :arith-lhs true) elim-term-ite solve-eqs)
If some of your formulas contain unbounded integer variables, you can build a strategy that reduces to SAT when possible, and invokes a general purpose solver otherwise. This can be accomplished using the or-else combinator. Here is an example:
(check-sat-using (then (! simplify :arith-lhs true) elim-term-ite solve-eqs
(or-else (then lia2pb pb2bv bit-blast sat)
smt)))
EDIT: The tactic lia2pb also assumes that the lower bound of every bounded integer variable is zero. This is not a big problem in practice, since we can use the tactic normalize-bounds before applying lia2pb. The tactic normalize-bounds will replace a bound variable x with y + l_x, where y is a fresh variable and l_x is the lower bound for x. For example, in a goal containing 3 <= x, x is replaced with y+3, where y is a new fresh variable.

Resources