Z3 can output the model and we can extract the values when the input is satisfiable.
Is there a way to obtain values for our model when we want unsatisfiability? (note: I'm using the c++ API)
Another way to see this question: when z3 proves that the equations return false, can we print a combination that lead to that unsat (false) value?
If your input is unsat, no assignment to inputs will make it true, i.e., all assignments will lead to false. So, you can just pick arbitrary values for your inputs.
From a practical perspective, however, one easy way to achieve what you want is to assert the negation of your original goal and ask for a model of that from the solver. The model that "satisfies" the negation of your goal will make your original goal "false."
/* Comment the below line while solving for Unsatisfiable */
solver.add(constr);
/* This block gets us Unsatisfiable Constraints, Uncomment the below line */
/*
* BoolExpr negConstr = ctx.mkNot(constr); solver.add(negConstr);
*/
So what we are effectively doing is negating the constraint for which we were solving and this will produce us UN-satisfiable contraint values while extracting from Model values as shown below:
Status checkResult = solver.check();
if (checkResult == Status.SATISFIABLE) {
System.out.println("Satisfiable");
// Get the model for the constraints
Model model = solver.getModel();
// Extract the values for the string variables
System.out.println("s = " + model.eval(xExpr, false));
System.out.println("t = " + model.eval(yExpr, false));
}
Related
Once I have a constraint problem, I would like to see if it is satisfiable. Based on the returned model (when it is sat) I would like to add assertions and then run the solver again. However, it seems like I am misunderstanding some of the types/values contained in the returned model. Consider the following example:
solv = z3.Solver()
n = z3.Int("n")
solv.add(n >= 42)
solv.check() # This is satisfiable
model = solv.model()
for var in model:
# do something
solv.add(var == model[var])
solv.check() # This is unsat
I would expect that after the loop i essentially have the two constraints n >= 42 and n == 42, assuming of course that z3 produces the model n=42 in the first call. Despite this, in the second call check() returns unsat. What am I missing?
Sidenote: when replacing solv.add(var == model[var]) with solv.add(var >= model[var]) I get a z3.z3types.Z3Exception: Python value cannot be used as a Z3 integer. Why is that?
When you loop over a model, you do not get a variable that you can directly query. What you get is an internal representation, which can correspond to a constant, or it can correspond to something more complicated like a function or an array. Typically, you should query the model with the variables you have, i.e., with n. (As in model[n].)
You can fix your immediate problem like this:
for var in model:
solve.add(var() == model[var()])
but this'll only work assuming you have simple variables in the model, i.e., no uninterpreted-functions, arrays, or other objects. See this question for a detailed discussion: https://stackoverflow.com/a/11869410/936310
Similarly, your second expression throws an exception because while == is defined over arbitrary objects (though doing the wrong thing here), >= isn't. So, in a sense it's the "right" thing to do to throw an exception here. (That is, == should've thrown an exception as well.) Alas, the Python bindings are loosely typed, meaning it'll try to make sense of what you wrote, not necessarily always doing what you intended along the way.
Drake has an interface where you can give it a generic function as a constraint and it can set up the nonlinearly-constrained mathematical program automatically (as long as it supports AutoDiff). I have a situation where my constraint does not support AutoDiff (the constraint function conducts a line search to approximate the maximum value of some function), but I have a closed-form expression for the gradient of the constraint. In my case, the math works out so that it's difficult to find a point on this function, but once you have that point it's easy to linearize around it.
I know many optimization libraries will allow you to provide your own analytical gradient when available; can you do this with Drake's MathematicalProgram as well? I could not find mention of it in the MathematicalProgram class documentation.
Any help is appreciated!
It's definitely possible, but I admit we haven't provided helper functions that make it pretty yet. Please let me know if/how this helps; I will plan to tidy it up and add it as an example or code snippet that we can reference in drake.
Consider the following code:
from pydrake.all import AutoDiffXd, MathematicalProgram, Solve
prog = MathematicalProgram()
x = prog.NewContinuousVariables(1, 'x')
def cost(x):
return (x[0]-1.)*(x[0]-1.)
def constraint(x):
if isinstance(x[0], AutoDiffXd):
print(x[0].value())
print(x[0].derivatives())
return x
cost_binding = prog.AddCost(cost, vars=x)
constraint_binding = prog.AddConstraint(
constraint, lb=[0.], ub=[2.], vars=x)
result = Solve(prog)
When we register the cost or constraint with MathematicalProgram in this way, we are allowing that it can get called with either x being a float, or x being an AutoDiffXd -- which is simply a wrapping of Eigen's AutoDiffScalar (with dynamically allocated derivatives of type double). The snippet above shows you roughly how it works -- every scalar value has a vector of (partial) derivatives associated with it. On entry to the function, you are passed x with the derivatives of x set to dx/dx (which will be 1 or zero).
Your job is to return a value, call it y, with the value set to the value of your cost/constraint, and the derivatives set to dy/dx. Normally, all of this happens magically for you. But it sounds like you get to do it yourself.
Here's a very simple code snippet that, I hope, gets you started:
from pydrake.all import AutoDiffXd, MathematicalProgram, Solve
prog = MathematicalProgram()
x = prog.NewContinuousVariables(1, 'x')
def cost(x):
return (x[0]-1.)*(x[0]-1.)
def constraint(x):
if isinstance(x[0], AutoDiffXd):
y = AutoDiffXd(2*x[0].value(), 2*x[0].derivatives())
return [y]
return 2*x
cost_binding = prog.AddCost(cost, vars=x)
constraint_binding = prog.AddConstraint(
constraint, lb=[0.], ub=[2.], vars=x)
result = Solve(prog)
Let me know?
For solving a SAT-problem I decided to use the Z3-solver from Microsoft and Python 3. The aim is to take a long model (up to 500,000 features) and find all possible solutions. To find them I want to add the first solution S1 to the initial equation and exclude S1 it and so forth. I will do it using a while-loop.
Solving a SAT-problem is important for me, because I wanna analyse feature models.
But I'm facing a problem with adding sth to the initial equation. I will share a minimal example:
# Import statements
import sys
sys.path.insert(0,'/.../z3/bin')
from z3 import * # https://github.com/Z3Prover/z3/wiki
def main():
'''
Solves after transformation a given boolean equation by using the Z3-Solver from Microsoft.
'''
fd = dict()
fd['_r'] = Bool('_r')
fd['_r_1'] = Bool('_r_1')
equation = '''And(fd.get("_r"),Or(Not(fd.get("_r")),fd.get("_r_1")))'''
# Solve the equation
s = Solver()
exec('s.add(' + equation + ')')
s.check()
print(s.model())
###################################
# Successfull until here.
###################################
s.add(Or(fd['_r'] != bool(s.model()[fd.get('_r')])))
# s.add(Or(fd['_r'] != False))
s.check()
print(s.model())
if __name__=='__main__':
main()
The first coded line after # Successfull... throws an z3types.Z3Exception: model is not available error. So i tried the line above adding simply false to the model. That works just fine.
I'm stucked here. I believe the error is easy to solve, but I don't see the solution. Does one of you? Thanks!
Models become available only after s.check() returns 'sat'.
The model maps Boolean propositions to {True, False} and
generally maps constants and functions to fixed values.
The requirement is that the model provides an interpretation
that satisfies the formula that is added to the solver 's'.
We don't know whether the solver state is satisfiable before
we have called 's.check()'.
Suppose you want to say:
s.add(Or(fd['_r'] != bool(s.model()[fd.get('_r')])))
meaning that in the model that satisfies the constraint should
have the property that if '_r' is true under the model, then
fd['_r'] != True, and if '_r' is false under the model, then
fd['_r'] != False. This is equivalent to saying
fd['_r'] != '_r'. So it isn't really necessary to access the value
of '_r' in whatever model may evaluate '_r' in order to say something
about the evaluation of it.
I'm new to Z3 and still couldn't find how I can express conditional new assignments based on the different possible evaluations. In If-then-else example in
https://github.com/Z3Prover/z3/blob/master/examples/c/test_capi.c#L1846
I still need to make the assignment to true or false, and when I want to make it true or false based on possible evaluations of another variable. How can I do this?
In the evaluation example I want the value calculated to be used to affect the still not evaluated values that are going to be checked by assertion later. So if this is the way how I can return back the model UN-evaluated with the new (evaluation based) conditions to the context again? i.e. I want to do composite conditions without final evaluations. Is that possible?
The following line from ite_example():
ite = Z3_mk_ite(ctx, f, one, zero)
creates an expression that will evaluate to whatever the (symbolic) term one evaluates to, if f evaluates to true, or alternatively to whatever zero evaluates to, if f evalautes to false. In ite_example, f always evaluates to false, but it may be any other (symbolic) term of Boolean sort.
For example,
x = mk_int_var(ctx, "x");
y = mk_int_var(ctx, "y");
x_eq_y = Z3_mk_eq(ctx, x, y);
will create a term called x_eq_y, representing "x = y", which is of Boolean sort.
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.