I want to solve constraints that contain quantifiers using Z3 C API.
I am struggling to use the functions like "Z3_mk_exists()" as I don't find any example either online or in the test examples in the tar file.
I don't exactly understand all the arguments required by these functions and exact significance of them.
Can anyone help?
Thanks.
Kaustubh.
Here is a complete example with universal quantifiers. Comments are inline:
Z3_config cfg = Z3_mk_config();
Z3_set_param_value(cfg, "MODEL", "true");
Z3_context ctx = Z3_mk_context(cfg);
Z3_sort intSort = Z3_mk_int_sort(ctx);
/* Some constant integers */
Z3_ast zero = Z3_mk_int(ctx, 0, intSort);
Z3_ast one = Z3_mk_int(ctx, 1, intSort);
Z3_ast two = Z3_mk_int(ctx, 2, intSort);
Z3_ast three = Z3_mk_int(ctx, 3, intSort);
Z3_ast four = Z3_mk_int(ctx, 4, intSort);
Z3_ast five = Z3_mk_int(ctx, 5, intSort);
We create an uninterpreted function for fibonacci: fib(n). We'll specify its meaning with a universal quantifier.
Z3_func_decl fibonacci = Z3_mk_fresh_func_decl(ctx, "fib", 1, &intSort, intSort);
/* fib(0) and fib(1) */
Z3_ast fzero = Z3_mk_app(ctx, fibonacci, 1, &zero);
Z3_ast fone = Z3_mk_app(ctx, fibonacci, 1, &one);
We're starting to specify the meaning of fib(n). The base cases don't require quantifiers. We have fib(0) = 0 and fib(1) = 1.
Z3_ast fib0 = Z3_mk_eq(ctx, fzero, zero);
Z3_ast fib1 = Z3_mk_eq(ctx, fone, one);
This is a bound variable. They're used within quantified expressions. Indices should start from 0. We have only one in this case.
Z3_ast x = Z3_mk_bound(ctx, 0, intSort);
This represents fib(_), where _ is the bound variable.
Z3_ast fibX = Z3_mk_app(ctx, fibonacci, 1, &x);
The pattern is what will trigger the instantiation. We use fib(_) again. This means (more or less) that Z3 will instantiate the axiom whenever it sees fib("some term").
Z3_pattern pattern = Z3_mk_pattern(ctx, 1, &fibX);
This symbol is only used for debugging as far as I understand. It gives a name to the _.
Z3_symbol someName = Z3_mk_int_symbol(ctx, 0);
/* _ > 1 */
Z3_ast xGTone = Z3_mk_gt(ctx, x, one);
Z3_ast xOne[2] = { x, one };
Z3_ast xTwo[2] = { x, two };
/* _ - 1 */
Z3_ast fibXminusOne = Z3_mk_sub(ctx, 2, xOne);
/* _ - 2 */
Z3_ast fibXminusTwo = Z3_mk_sub(ctx, 2, xTwo);
Z3_ast toSum[2] = { Z3_mk_app(ctx, fibonacci, 1, &fibXminusOne), Z3_mk_app(ctx, fibonacci, 1, &fibXminusTwo) };
/* f(_ - 1) + f(_ - 2) */
Z3_ast fibSum = Z3_mk_add(ctx, 2, toSum);
This is now the body of the axiom. It says: _ > 1 => (fib(_) = fib(_ - 1) + fib(_ - 2), where _ is the bound variable.
Z3_ast axiomTree = Z3_mk_implies(ctx, xGTone, Z3_mk_eq(ctx, fibX, fibSum));
At last we can build a quantifier tree, using the pattern, the bound variable, its name and the axiom body. (Z3_TRUE says its a forall quantifier). The 0 in the argument list specifies the priority. The Z3 doc recommends to use 0 if you don't know what to put.
Z3_ast fibN = Z3_mk_quantifier(ctx, Z3_TRUE, 0, 1, &pattern, 1, &intSort, &someName, axiomTree);
We finally add the axiom(s) the to context.
Z3_assert_cnstr(ctx, fib0);
Z3_assert_cnstr(ctx, fib1);
Z3_assert_cnstr(ctx, fibN);
Related
I have a finite set of pairs of type (int a, int b). The exact values of the pairs are explicitly present in the knowledge base. For example it could be represented by a function (int a, int b) -> (bool exists) which is fully defined on a finite domain.
I would like to write a function f with signature (int b) -> (int count), representing the number of pairs containing the specified b value as its second member. I would like to do this in z3 python, though it would also be useful to know how to do this in the z3 language
For example, my pairs could be:
(0, 0)
(0, 1)
(1, 1)
(1, 2)
(2, 1)
then f(0) = 1, f(1) = 3, f(2) = 1
This is a bit of an odd thing to do in z3: If the exact values of the pairs are in your knowledge base, then why do you need an SMT solver? You can just search and count using your regular programming techniques, whichever language you are in.
But perhaps you have some other constraints that come into play, and want a generic answer. Here's how one would code this problem in z3py:
from z3 import *
pairs = [(0, 0), (0, 1), (1, 1), (1, 2), (2, 1)]
def count(snd):
return sum([If(snd == p[1], 1, 0) for p in pairs])
s = Solver()
searchFor = Int('searchFor')
result = Int('result')
s.add(Or(*[searchFor == d[0] for d in pairs]))
s.add(result == count(searchFor))
while s.check() == sat:
m = s.model()
print("f(" + str(m[searchFor]) + ") = " + str(m[result]))
s.add(searchFor != m[searchFor])
When run, this prints:
f(0) = 1
f(1) = 3
f(2) = 1
as you predicted.
Again; if your pairs are exactly known (i.e., they are concrete numbers), don't use z3 for this problem: Simply write a program to count as needed. If the database values, however, are not necessarily concrete but have other constraints, then above would be the way to go.
To find out how this is coded in SMTLib (the native language z3 speaks), you can insert print(s.sexpr()) in the program before the while loop starts. That's one way. Of course, if you were writing this by hand, you might want to code it differently in SMTLib; but I'd strongly recommend sticking to higher-level languages instead of SMTLib as it tends to be hard to read/write for anyone except machines.
I have a brute force optimization algorithm with the objective function of the form:
np.clip(x # M, a_min=0, a_max=1) # P
where x is a Boolean decision vector, M is a Boolean matrix/tensor and P is a probability vector. As you can guess, x # M as an inner product can have values higher than 1 where is not allowed as the obj value should be a probability scalar or vector (if M is a tensor) between 0 to 1. So, I have used numpy.clip to fix the x # M to 0 and 1 values. How can I set up a mechanism like clip in cvxpy to achieve the same result? I have spent ours on internet with no lock so I appreciate any hint. I have been trying to use this to replicate clip but it raises Exception: Cannot evaluate the truth value of a constraint or chain constraints, e.g., 1 >= x >= 0. As a side note, since cvxpy cannot handle tensors, I loop through tensor slices with M[s].
n = M.shape[0]
m = M.shape[1]
w = M.shape[2]
max_budget_of_decision_variable = 7
x = cp.Variable(n, boolean=True)
obj = 0
for s in range(m):
for w in range(w):
if (x # M[s])[w] >= 1:
(x # M[s])[w] = 1
obj += x # M[s] # P
objective = cp.Maximize(obj)
cst = []
cst += [cp.sum(y) <= max_budget_of_decision_variable ]
prob = cp.Problem(objective, constraints = cst)
As an example, consider M = np.array([ [1, 0, 0, 1, 1, 0], [0, 0, 1, 0, 1, 0], [1, 1, 1, 0, 1, 0]]) and P = np.array([0.05, 0.15, 0.1, 0.15, 0.5, 0.05]).
I am new in cplex. I want to use the two arrays that I have in my code as indexes for my decision variables and parameters. I need the values of the arrays as indices, not the sizes of the arrays, too. I saw these links: "https://github.com/AlexFleischerParis/zooopl/blob/master/zooarrayvariableindexerunion.mod" and other examples in https://stackoverflow.com for my problem but I don't know How should I change my code?
.mod
{int} V = {11, 12, 13, 21, 22, 23, 31, 32, 33, 41, 42, 43, 51, 52, 53};
range F=1..20;
int sizeFlow[f in F]=2+rand(3);
int n=card(V);
int m=4;
range r=1..n;
// scripting way that will get m times 1
range subr=1..m;
int t[f in F][i in subr]=1+rand(n+1-i);
{int} setn[f in F]=asSet(r);
int x2[F][i in r];
execute
{
for (var f in F) for(var i in subr)
{
var e=t[f][i];
var e2=Opl.item(setn[f],e-1);
x2[f][e2]=1;
setn[f].remove(e2);
}
}
{int} result[f in F]={i | i in r:x2[f][i]==1};
{int} Flow4[f in F]=union (i in result[f]) {item(V,i-1)};
{int} Flow[f in F]={item(Flow4[f],j-1) | j in 1..sizeFlow[f]};
assert forall(f in F) forall(ordered i,j in Flow[f]) i!=j;
execute{ writeln(Flow); }
Now I want to use arrays sizeFlow[f] and Flow[f] in rest of my code, For example:
range Nunode1 = 0..10;
tuple edge{
key int origin;
key int destination;}
{edge} Edges with origin,destination in Nunode1 = {<0,1>,<1,3>,<2,3>,<3,4>,<3,5>,<3,6>,
<4,5>,<4,6>,<4,8>,<5,6>,<6,7>,<6,9>,<9,10>};
//transmission rate.
float C[Edges]=...;
float landa[Flow[f]] = 0.5 +rand(2);
//DECISION VARIABLES
dvar boolean IL[Edges][Flow[f]][sizeFlow[f]][Nunode1][sizeFlow[f]][Nunode1]; //denotes
that link l is used by flow f to route from the j-th to (j + 1)-th NF service, hosted at
node nj and nj+1.
//Objective function
dexpr float objmodel2 = sum(l in Edges, c in 1..Flow[f], j in 1..sizeFlow[f]: (j+1) in
1..sizeFlow[f] && (j+1)>j, n in Nunode1: (n+1) in Nunode1 && (n+1)>n) ((IL[l][c][j][n]
[j+1][n+1] * landa[c]) / C[l]); //to minimize the utilization of link capacities.
minimize objmodel2;
subject to{
forall (l in Edges)
cons1: sum(c in 1..Flow[f], j in 1..sizeFlow[f]: j+1 in 1..sizeFlow[f], n in Nunode1:
(n+1) in Nunode1) (IL[l][c][j][n][j+1][n+1] * landa[c]) <= C[l];}
I have been experimenting with z3 (version '4.8.7' obtained through pip3) and found this (apparent) discrepancy.
t, s0, s, u, a, v = Reals('t s0 s u a v')
equations = [v == u + a*t, s == s0 + u*t + a*t**2/2,
v**2 - u**2 == 2*a*s]
problem = [t == 10, s0 == 0, u == 0, a == 9.81]
solve(equations+problem)
This gives the correct output for s:
[a = 981/100, u = 0, s0 = 0, t = 10, s = 981/2, v = 981/10]
But when I use the Solver, the result is different:
solver = Solver()
solver.check(equations+problem)
solver.model()
This gives a wrong output for s, though it gets v right.
[t = 10, u = 0, s0 = 0, s = 0, a = 981/100, v = 981/10]
s should be (1/2) * (981/100) * 100 which is the result in solve.
Am I missing something obvious in z3's Solver or is this a bug? Thank you.
The issue here is that the argument to solver.check are extra assumptions the solver can make as it solves the constraints, not the actual constraints to check. See the documentation here: https://z3prover.github.io/api/html/z3py_8py_source.html#l06628
The correct call would be:
solver = Solver()
solver.add(equations+problem)
print solver.check()
print solver.model()
that is, you add the constraints, and then call check with no arguments. This would match what solve does. The argument to check are used if you want to check validity under some extra assumptions only.
I am currently learning Racket (just for fun) and I stumbled upon this example:
(define doubles
(stream-cons
1
(stream-map
(lambda (x)
(begin
(display "map applied to: ")
(display x)
(newline)
(* x 2)))
doubles)))
It produces 1 2 4 8 16 ...
I do not quite understand how it works.
So it creates 1 as a first element; when I call (stream-ref doubles 1) it creates a second element which is obviously 2.
Then I call (stream-ref doubles 2) which should force creating the third element so it calls stream-map for a stream which already has 2 elements – (1 2) – so it should produce (2 4) then and append this result to the stream.
Why is this stream-map always applied to the last created element? How it works?
Thank you for your help!
This is a standard trick that makes it possible for lazy streams to be defined in terms of their previous element. Consider a stream as an infinite sequence of values:
s = x0, x1, x2, ...
Now, when you map over a stream, you provide a function and produce a new stream with the function applied to each element of the stream:
map(f, s) = f(x0), f(x1), f(x2), ...
But what happens when a stream is defined in terms of a mapping over itself? Well, if we have a stream s = 1, map(f, s), we can expand that definition:
s = 1, map(f, s)
= 1, f(x0), f(x1), f(x2), ...
Now, when we actually go to evaluate the second element of the stream, f(x0), then x0 is clearly 1, since we defined the first element of the stream to be 1. But when we go to evaluate the third element of the stream, f(x1), we need to know x1. Fortunately, we just evaluated x1, since it is f(x0)! This means we can “unfold” the sequence one element at a time, where each element is defined in terms of the previous one:
f(x) = x * 2
s = 1, map(f, s)
= 1, f(x0), f(x1), f(x2), ...
= 1, f(1), f(x1), f(x2), ...
= 1, 2, f(x1), f(x2), ...
= 1, 2, f(2), f(x2), ...
= 1, 2, 4, f(x2), ...
= 1, 2, 4, f(4), ...
= 1, 2, 4, 8, ...
This knot-tying works because streams are evaluated lazily, so each value is computed on-demand, left-to-right. Therefore, each previous element has been computed by the time the subsequent one is demanded, and the self-reference doesn’t cause any problems.