As per my knowledge, since z3 doesn't recognize transcendental functions its throwing me an error while conversion using following code.
def convertor(f, status="unknown", name="benchmark", logic=""):
v = (Ast * 0)()
if isinstance(f, Solver):
a = f.assertions()
if len(a) == 0:
f = BoolVal(True)
else:
f = And(*a)
return Z3_benchmark_to_smtlib_string(f.ctx_ref(), name, logic, status, "", 0, v, f.as_ast())
pi, EI, kA , kB, N = Reals('pi EI kA kB N')
s= Solver()
s.add(pi == 3.1415926525)
s.add(EI == 175.2481)
s.add(kA>= 0)
s.add(kA<= 100)
s.add(kB>= 0)
s.add(kB<= 100)
s.add(N>= 100)
s.add(N<= 200)
please change the path of the input file "beamfinv3.bch", which can be found at: link
continue_read=False
input_file = open('/home/mani/downloads/new_z3/beamfinv3.bch', 'r')
for line in input_file:
if line.strip()=="Constraints":
continue_read=True
continue
if line.strip()=="end":
continue_read=False
if continue_read==True:
parts = line.split(';')
if (parts[0]!="end"):
#print parts[0]
s.add(eval(parts[0]))
input_file.close()
file=open('cyber.smt2','w')
result=convertor(s, logic="None")
file.write (result)
error:
File "<string>", line 1, in <module>
NameError: name 'sin' is not defined
Any way out? or help?
Thanks.
The core of this problem is that eval tries to execute a Python script, i.e., all functions that occur within parts[0] must have a corresponding Python function of the same name, which is not the case for the trigonometric functions (the are neither in the Python API nor the C API, the former being based on the latter). For now you could try to add those functions yourself, perhaps with an implementation based on parse_smt2_string, or perhaps by replacing the Python strings with SMT2 strings altogether.
Z3 can represent expressions containing trigonometric functions, but it will refuse to do so when the logic is set to something; see arith_decl_plugin. I don't know Python well enough, but it might have to be None instead of "".
While Z3 can represent these expressions, it's probably not very good at solving them. See comments on the limitations in Can Z3 handle sinusoidal and exponential functions, Z3 supports for nonlinear arithmetics, and Z3 Performance with Non-Linear Arithmetic.
Related
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.
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.)
Let's assume that we have the following files:
func.smt
(declare-datatypes (T) ((AVL leafA (nodeA (val T) (alt Int) (izq AVL) (der AVL)))))
espec.smt
(declare-const t (AVL Int))
And the following code:
from z3 import *
s = Solver()
s.from_file("func.smt")
s.from_file("espec.smt")
When instruction "s.from_file("espec.smt")" is executed, z3 throws the next exception:
z3.z3types.Z3Exception: b'(error "line 1 column 18: unknown sort \'AVL\'")\n'
It seems that the Solver "s" doesn't save the information of datatypes (and functions too). That is why he throws the exception (I guess).
The following code is a way to solve it:
s = Solver()
file = open("func.smt", "r")
func = file.read()
file.close()
file = open("espec.smt", "r")
espec = file.read()
file.close()
s.from_string(func + espec)
But this way it's not efficient.
Is there another more efficient way to solve this and make z3 save datatypes and functions for future asserts and declarations?
Edit:
In my real case for example, the file "func.smt" has a total of 54 declarations between functions and datatypes (some quite complex). The "spec.smt" file has few declarations and asserts. And finally I have a file in which there are many asserts which I have to read little by little and generate a model.
That is, imagine that I have 600 lines of asserts, and I read from 10 to 10, so every 10 lines I generate a model. That is, if we assume that those asserts that I have read are stored in a variable called "aux", every time I want to get a new model, I will have to do "s.from_string (func + spec + aux)" 60 times in total, and I don't know if that could be made more efficient.
Separately reading the files and loading to solver is your best bet, as you found out.
Unless efficiency is of paramount importance, I would not worry about trying to optimize this any further. For any reasonable problem, your solver time will dominate any time spent in loading the assertions from a few (or a few thousand!) files. Do you have a use case that really requires this part to be significantly faster?
I am trying to solve a problem, for example I have a 4 point and each two point has a cost between them. Now I want to find a sequence of nodes which total cost would be less than a bound. I have written a code but it seems not working. The main problem is I have define a python function and trying to call it with in a constraint.
Here is my code: I have a function def getVal(n1,n2): where n1, n2 are Int Sort. The line Nodes = [ Int("n_%s" % (i)) for i in range(totalNodeNumber) ] defines 4 points as Int sort and when I am adding a constraint s.add(getVal(Nodes[0], Nodes[1]) + getVal(Nodes[1], Nodes[2]) < 100) then it calls getVal function immediately. But I want that, when Z3 will decide a value for Nodes[0], Nodes[1], Nodes[2], Nodes[3] then the function should be called for getting the cost between to points.
from z3 import *
import random
totalNodeNumber = 4
Nodes = [ Int("n_%s" % (i)) for i in range(totalNodeNumber) ]
def getVal(n1,n2):
# I need n1 and n2 values those assigned by Z3
cost = random.randint(1,20)
print cost
return IntVal(cost)
s = Solver()
#constraint: Each Nodes value should be distinct
nodes_index_distinct_constraint = Distinct(Nodes)
s.add(nodes_index_distinct_constraint)
#constraint: Each Nodes value should be between 0 and totalNodeNumber
def get_node_index_value_constraint(i):
return And(Nodes[i] >= 0, Nodes[i] < totalNodeNumber)
nodes_index_constraint = [ get_node_index_value_constraint(i) for i in range(totalNodeNumber)]
s.add(nodes_index_constraint)
#constraint: Problem with this constraint
# Here is the problem it's just called python getVal function twice without assiging Nodes[0],Nodes[1],Nodes[2] values
# But I want to implement that - Z3 will call python function during his decission making of variables
s.add(getVal(Nodes[0], Nodes[1]) + getVal(Nodes[1], Nodes[2]) + getVal(Nodes[2], Nodes[3]) < 100)
if s.check() == sat:
print "SAT"
print "Model: "
m = s.model()
nodeIndex = [ m.evaluate(Nodes[i]) for i in range(totalNodeNumber) ]
print nodeIndex
else:
print "UNSAT"
print "No solution found !!"
If this is not a right way to solve the problem then could you please tell me what would be other alternative way to solve it. Can I encode this kind of problem to find optimal sequence of way points using Z3 solver?
I don't understand what problem you need to solve. Definitely, the way getVal is formulated does not make sense. It does not use the arguments n1, n2. If you want to examine values produced by a model, then you do this after Z3 returns from a call to check().
I don't think you can use a python function in your SMT logic. What you could alternatively is define getVal as a Function like this
getVal = Function('getVal',IntSort(),IntSort(),IntSort())
And constraint the edge weights as
s.add(And(getVal(0,1)==1,getVal(1,2)==2,getVal(0,2)==3))
The first two input parameters of getVal represent the node ids and the last integer represents the weight.
Given an expression in Z3py, can I convert that to SMT-LIB2 language? (So I can feed this SMT-LIB2 expression to other SMT solvers that support SMT-LIB2)
If this is possible, please give one example.
Thanks a lot.
We can use the C API Z3_benchmark_to_smtlib_string. Every function in the C API is available in Z3Py. This function was initially used to dump benchmarks in SMT 1.0 format, and it predates SMT 2.0. That is why it has some parameters that may seem unnecessary. Now, by default, it will display benchmarks in SMT 2.0 format. The output is not meant to be human readable.
We can write the following Python function to make it more convenient to use:
def toSMT2Benchmark(f, status="unknown", name="benchmark", logic=""):
v = (Ast * 0)()
return Z3_benchmark_to_smtlib_string(f.ctx_ref(), name, logic, status, "", 0, v, f.as_ast())
Here is a small example using it (also available online here)
a = Int('a')
b = Int('b')
f = And(Or(a > If(b > 0, -b, b) + 1, a <= 0), b > 0)
print toSMT2Benchmark(f, logic="QF_LIA")