z3py sometimes hangs on Solver.check() on formulas that it can solve - z3

In my usecase I try to use the solver to solve multiple formulas one after the other. Sometimes, the solver hangs on a certain formula, but when I try to run it again on the very same formula it succeeds immediately.
Below is a minimal example in which I run the solver on the same formula multiple times, and after a few attempts it hangs indefinitely.
from z3 import *
def test_solve():
s, s1, s2 = Strings('s s1 s2')
i, t = Ints('i t')
sl = Solver()
start = datetime.now()
sl.add(Not(Implies(And(i < t,
Contains(s, s1),
Not(SuffixOf(s1, s)),
Or(0 < i, PrefixOf(s1, s))),
Or(PrefixOf(s2, s), PrefixOf(s1, s)))))
print(f"{attempt}: {sl.check()}. Solved in {datetime.now() - start}")
for attempt in range(20):
test_solve()
This is its output:
0: sat. Solved in 0:00:00.504905
1: sat. Solved in 0:00:01.313257
2: sat. Solved in 0:00:00.543546
3: sat. Solved in 0:00:00.137668
4: sat. Solved in 0:00:00.268307
5: sat. Solved in 0:00:00.189427
It hangs on the 6th attempt. Is this an expected behavior? Is there anything I can do to mitigate this?

No, I'd say this is not expected. It is true that there are "random" seeds etc. that are in play which can affect performance in each run; but the differences you're seeing (and I can replicate) are way too much to chalk it up to random seeds. The string solver that you are using has its problems, and I think this'd be a good test-case to report to the developers so they can take a look and see if they can spot why there's so much discrepancy. Please file it at: https://github.com/Z3prover/z3/issues

Related

Capture timeout exception with Mosek + Cvxpy

We are solving our large scale MI optimization problems with Cvxpy and Mosek.
Often times it happens that Mosek consumes higher runtime then our stipulated timeout of two hours.
Is there a way to systematically capture those timeout exception?
Minimum reproducible example:
import cvxpy as cp
import numpy as np
import mosek
m = 15
n = 10
np.random.seed(1)
s0 = np.random.randn(m)
lamb0 = np.maximum(-s0, 0)
s0 = np.maximum(s0, 0)
x0 = np.random.randn(n)
A = np.random.randn(m, n)
b = A # x0 + s0
c = -A.T # lamb0
# Define and solve the CVXPY problem.
x = cp.Variable(n)
prob = cp.Problem(cp.Minimize(c.T#x),
[A # x <= b])
# try:
prob.solve(cp.MOSEK, mosek_params={mosek.dparam.optimizer_max_time: 0.01}) # set verbose=True (to see actual error in solver logs)
# except Timeout exception
# print('Timeout occured')
print(prob.value)
def execute_other_important_stuff():
print("Hello world")
execute_other_important_stuff() # Not executed currently
When MOSEK terminates because of a timeout there will never be any exception - you set a timeout, so terminating at that point is a normal, not an abnormal, situation. I am not sure what "Error" you are referring to.
If you mean something like
Cannot unpack invalid solution: Solution(status=UNKNOWN
then it is not related to the timeout itself, but to the fact that there is no solution available (yet, so the only available "solution" has UNKNOWN status), and CVXPY handles this by throwing an exception. So the question is, has any solution at all to your problem been found after those 2 hours? If yes, it should be returned without problem. If not, you might see the above and I would guess the only way is to catch the ValueError CVXPY happens to throw.
If you were using the native Mosek interface then you could find out why it terminated from various response codes, but I CVXPY does not propagate them.
I am not sure if this is a Cvxpy issue.
However, a general comment is that Mosek cannot check the time limit continuously so it will most likely go over time.
For instance for a SDP it has to compute eigenvalues of a potentially large matrix and the time limit cannot be checked before it is completed.
I have no other insights (other than what ErlingMOSEK suggested) on why it happened, but you can use signals library to force the .solve method to stop.
This is an independent way to make sure you can stop the function after whenever time you wise.
See example in Timeout a function call

Floor and Ceiling Function implementation in 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.

Save and reload z3py solver constraints

Can I save the constraints I created for a z3 solver and later reload them to continue looking for more solutions?
I have learned there is the SMT-LIB2 format for such things and that z3 and z3py have an API for saving and loading in that format. Unfortunately I cannot make it work.
Here's my example program which pointlessly saves and reloads:
import z3
filename = 'z3test.smt'
# Make a solver with some arbitrary useless constraint
solver = z3.Solver()
solver.add(True)
# Save to file
smt2 = solver.sexpr()
with open(filename, mode='w', encoding='ascii') as f: # overwrite
f.write(smt2)
f.close()
# Load from file
solver.reset()
solver.from_file(filename)
It fails with:
Exception has occurred: ctypes.ArgumentError
argument 3: <class 'TypeError'>: wrong type
File "C:\Users\Marian Aldenhövel\Desktop\FridgeIQ\z3\z3-4.8.4.d6df51951f4c-x64-win\bin\python\z3\z3core.py", line 3449, in Z3_solver_from_file
_elems.f(a0, a1, _to_ascii(a2))
File "C:\Users\Marian Aldenhövel\Desktop\FridgeIQ\z3\z3-4.8.4.d6df51951f4c-x64-win\bin\python\z3\z3.py", line 6670, in from_file
_handle_parse_error(e, self.ctx)
File "C:\Users\Marian Aldenhövel\Desktop\FridgeIQ\src\z3test.py", line 17, in <module>
solver.from_file(filename)
Is this a problem with my understanding or my code? Can it be done like this? Are sexpr() and from_file() the right pair of API calls?
I am using z3 and z3py 4.8.4 from https://github.com/z3prover/z3/releases on Windows 10 64bit.
More detail if required:
I am playing with z3 in Python to find solutions for a large disection-puzzle.
To find all solutions I am calling solver.check(). When it returns a sat verdict I interpret the model as image of my puzzle solution. I then add a blocking clause ruling out that specific solution and call solver.check() again.
This works fine and I am delighted.
The runtime to find all solutions will be on the order of many days or until I get bored. I am concerned that my machine will not be running continuously for that long. It may crash, run out of power, or be rebooted for other reasons.
I can easily recreate the initial constraints which is the whole point of the program. But the blocking clauses are a runtime product and a function of how far we have gotten.
I thought I could save the state of the solver and if at runtime I find such a file restart by loading that with the blocking clauses intact and go on finding more solutions instead of having to start over.
Thank you for taking your time reading and thinking.
Marian
With z3 4.4.1 and z3 4.8.5, I would dump (and reload) the constraints in smt2 format as follows:
import z3
filename = "z3test.smt2"
x1 = z3.Real("x1")
x2 = z3.Real("x2")
solver = z3.Solver()
solver.add(x1 != x2)
#
# STORE
#
with open(filename, mode='w') as f:
f.write(solver.to_smt2())
#
# RELOAD
#
solver.reset()
constraints = z3.parse_smt2_file(filename, sorts={}, decls={})
solver.add(constraints)
print(solver)
output:
~$ python t.py
[And(x1 != x2, True)]
file z3test.smt2:
(set-info :status unknown)
(declare-fun x2 () Real)
(declare-fun x1 () Real)
(assert
(and (distinct x1 x2) true))
(check-sat)
I have no idea whether the API changed in the version you are using. Feedback is welcome.

Project Euler #3 Ruby Solution - What is wrong with my code?

This is my code:
def is_prime(i)
j = 2
while j < i do
if i % j == 0
return false
end
j += 1
end
true
end
i = (600851475143 / 2)
while i >= 0 do
if (600851475143 % i == 0) && (is_prime(i) == true)
largest_prime = i
break
end
i -= 1
end
puts largest_prime
Why is it not returning anything? Is it too large of a calculation going through all the numbers? Is there a simple way of doing it without utilizing the Ruby prime library(defeats the purpose)?
All the solutions I found online were too advanced for me, does anyone have a solution that a beginner would be able to understand?
"premature optimization is (the root of all) evil". :)
Here you go right away for the (1) biggest, (2) prime, factor. How about finding all the factors, prime or not, and then taking the last (biggest) of them that is prime. When we solve that, we can start optimizing it.
A factor a of a number n is such that there exists some b (we assume a <= b to avoid duplication) that a * b = n. But that means that for a <= b it will also be a*a <= a*b == n.
So, for each b = n/2, n/2-1, ... the potential corresponding factor is known automatically as a = n / b, there's no need to test a for divisibility at all ... and perhaps you can figure out which of as don't have to be tested for primality as well.
Lastly, if p is the smallest prime factor of n, then the prime factors of n are p and all the prime factors of n / p. Right?
Now you can complete the task.
update: you can find more discussion and a pseudocode of sorts here. Also, search for "600851475143" here on Stack Overflow.
I'll address not so much the answer, but how YOU can pursue the answer.
The most elegant troubleshooting approach is to use a debugger to get insight as to what is actually happening: How do I debug Ruby scripts?
That said, I rarely use a debugger -- I just stick in puts here and there to see what's going on.
Start with adding puts "testing #{i}" as the first line inside the loop. While the screen I/O will be a million times slower than a silent calculation, it will at least give you confidence that it's doing what you think it's doing, and perhaps some insight into how long the whole problem will take. Or it may reveal an error, such as the counter not changing, incrementing in the wrong direction, overshooting the break conditional, etc. Basic sanity check stuff.
If that doesn't set off a lightbulb, go deeper and puts inside the if statement. No revelations yet? Next puts inside is_prime(), then inside is_prime()'s loop. You get the idea.
Also, there's no reason in the world to start with 600851475143 during development! 17, 51, 100 and 1024 will work just as well. (And don't forget edge cases like 0, 1, 2, -1 and such, just for fun.) These will all complete before your finger is off the enter key -- or demonstrate that your algorithm truly never returns and send you back to the drawing board.
Use these two approaches and I'm sure you'll find your answers in a minute or two. Good luck!
Do you know you can solve this with one line of code in Ruby?
Prime.prime_division(600851475143).flatten.max
=> 6857

eliminating "not "in the expression using z3

I try to eliminate "not" in the expression using the script http://rise4fun.com/Z3/XwGt however, it doesn't work, there is still not in the result, would someone help me?
The output goals in your example are in simplified formula. There is no redundant assertion in any goal. The Z3 simplified form always use non-strict inequalities such as t1 <= t2 and t1 >= t2. Strict inequalities such as t1 < 0 are encoded using negation. That is, t1 < 0 is encoded as not t1 >= 0. The idea is to reduce the number of atoms used to encode a big formula.
It would be useful to understand why you need to eliminate the nots in the output. If there is an useful application for that, we will include a new tactic (in the next release) that performs the transformation.

Resources