Z3 ArithRef type: is there a way to show value once model evaluated? - optimization

Using Z3Py, once a model has been checked for an optimization problem, is there a way to convert ArithRef expressions into values?
Such as
y = If(x > 5, 0, 0.5 * x)
Once values have been found for x, can I get the evaluated value for y, without having to calculate again based on the given values for x?
Many thanks.

You need to evaluate, but it can be done by the model for you automatically:
from z3 import *
x = Real('x')
y = If(x > 5, 0, 0.5 * x)
s = Solver()
r = s.check()
if r == sat:
m = s.model();
print("x =", m.eval(x, model_completion=True))
print("y =", m.eval(y, model_completion=True))
else:
print("Solver said:", r)
This prints:
x = 0
y = 0
Note that we used the parameter model_completion=True since there are no constraints to force x (and consequently y) to any value in this model. If you have sufficient constraints added, you wouldn't need that parameter. (Of course, having it does not hurt.)

Related

syntax in defining constraints in CVXPY

I am new to CVXPY, I learn by running examples and I found this post: How to construct a SOCP problem and solve using cvxpy and cvxpylayers #ben
The author provided the codes (Below I've corrected the line that caused an error in OP's EDIT 2):
import cvxpy as cp
import numpy as np
N = 5
Q_sqrt = cp.Parameter((N, N))
Q = cp.Parameter((N, N))
x = cp.Variable(N)
z = cp.Variable(N)
p = cp.Variable()
t = cp.Variable()
objective = cp.Minimize(p - t)
constraint_soc = [z == Q # x, x.value * z >= t ** 2, z >= 0, x >= 0] # <-- my question
constraint_other = [cp.quad_over_lin(Q_sqrt # x, p) <= N * p, cp.sum(x) == 1, p >= 0, t >= 0]
constraint_all = constraint_other + constraint_soc
matrix = np.random.random((N, N))
a_matrix = matrix.T # matrix
Q.value = a_matrix
Q_sqrt.value = np.sqrt(a_matrix)
prob = cp.Problem(objective, constraint_all)
prob.solve(verbose=True)
print("status:", prob.status)
print("optimal value", prob.value)
My question is here: x.value * z >= t ** 2
why only x.value while z not?
Actually I tried x * z, x.value * z.value, they both throw out errors, only the one in the original post works, which is x.value * z.
I googled and found this page and this, looks most relevant, but still failed to find an answer.
But both x and z are variables and defined as such
x = cp.Variable(N)
z = cp.Variable(N)
why only x needs a .value after?? Maybe it's a trivial question to experienced users, but I really don't get it. Thank you.
Update: two follow-up questions
Thanks to #MichalAdamaszek the first question above is clear: x.value didn't make sense here. A suggestion is using constraint_soc = [z == Q # x] + [ z[i]>=cp.quad_over_lin(t, x[i]) for i in range(N) ]
I have two following questions:
is it better to write the second of the soc constraint as : [ x[i]>=cp.quad_over_lin(t, z[i]) for i in range(N) ]? because in the question we only know that z[i] > 0 for sure. Or it doesn't matter at all in cvxpy? I tired both, both returned a similar optimal value.
I noticed that for the two constraints:
$x^TQx <= Np^2 $ and $ x_i z_i >= t^2 $
the quadratic terms were always intentionally split into two linear terms:
cp.quad_over_lin(Q_sqrt # x, p) <= N * p and z[i]>=cp.quad_over_lin(t, x[i]) respectively.
Is it because that in cvxpy, it is not allowed to have quadratic terms in (in)equality constraints? Is there an documentation to those basic rules?
Thank you.

Linear programming if/then modification to cost function?

I'm setting up a linear programming optimization model using CPLEX and am wondering if it's possible to accomplish a modification of the cost function dependent upon which binary decision variables are 'active' in an arbitrary solution. This is mostly a question about how to formulate the LP model (if it's even possible), but responses in the context of CPLEX are welcome or even preferred.
Say I have an LP problem in canonical form:
minimize cTx
s.t. Ax <= b
With cost function:
c = [c_1, c_2,...,c_100]
All variables are binary. I have this basic setup modeled and running effectively in CPLEX.
Now say I have a subset of variables:
efficiency_set = [x_1, x_2,...,x_5]
With the condition:
if any x_n in efficiency_set == 1
then c_n for all other x_n in the set = 0.9 * c_n
Essentially there is a dependency where if any x_n in the efficiency set is 'active', it becomes 10% less expensive for other variables in the set to appear in the solution.
I thought that CPLEX indicator constraints were what I was looking for, but after reading through documentation, I don't think I can enforce an on-the-fly change to cost function with them (I could be wrong). So I feel like it needs to be done through formulation of the LP, but I can't reason how to accomplish it. Any ideas?. Thanks.
In CPLEX you have many APIs, let me answer you with the easiest one OPL.
Your canonical form can be written
int n=3;
int m=4;
range N=1..n;
range M=1..m;
float A[N][M]=[[1,4,9,6],[8,5,0,8],[2,9,0,2]];
float B[M]=[3,1,3,0];
float C[N]=[1,1,1];
dvar boolean x[N];
minimize sum(i in N) C[i]*x[i];
subject to
{
forall(j in M) sum(i in N) A[i,j]*x[i]>=B[j];
}
and then you can you write logical constraints:
int n=3;
int m=4;
range N=1..n;
range M=1..m;
float A[N][M]=[[1,4,9,6],[8,5,0,8],[2,9,0,2]];
float B[M]=[3,1,3,0];
float C[N]=[1,1,1];
{int} efficiencySet={1,2};
dvar boolean activeEfficiencySet;
dvar boolean x[N];
minimize sum(i in N) C[i]*x[i]*(1-0.1*activeEfficiencySet*(i not in efficiencySet));
subject to
{
forall(j in M) sum(i in N) A[i,j]*x[i]>=B[j];
activeEfficiencySet==(1<=sum(i in efficiencySet) x[i]);
}
Using Alex's data, I have written the program in docplex (cplex python API)
from docplex.mp.model import Model
n = 3
m = 4
A = {}
A[0, 0] = 1
A[0, 1] = 4
A[0, 2] = 9
A[0, 3] = 6
A[1, 0] = 8
A[1, 1] = 5
A[1, 2] = 0
A[1, 3] = 8
A[2, 0] = 2
A[2, 1] = 9
A[2, 2] = 0
A[2, 3] = 2
B = {}
B[0] = 3
B[1] = 1
B[2] = 3
B[3] = 0
C = {}
C[0] = 1
C[1] = 1
C[2] = 1
efficiencySet = [0, 1]
mdl = Model(name="")
activeEfficiencySet = mdl.binary_var()
x = mdl.binary_var_dict(range(n), name="x")
# constraint 1:
for j in range(m):
mdl.add_constraint(mdl.sum(A[i, j] * x[i] for i in range(n)) >= B[j])
# constraint 2:
mdl.add(activeEfficiencySet == (mdl.sum(x) >= 1))
# objective function:
# expr = mdl.linear_expr()
lst = []
for i in range(n):
if i not in efficiencySet:
lst.append((C[i] * x[i] * (1 - 0.1 * activeEfficiencySet)))
else:
lst.append(C[i] * x[i])
mdl.minimize(mdl.sum(lst))
mdl.solve()
for i in range(n):
print(str(x[i]) + " : " + str(x[i].solution_value))
activeEfficiencySet.solution_value

How to sample from a sum of two distributions: binomial and poisson

Is there a way to predict a value from a sum of two distributions? I am getting a syntax error on rstan when I try to estimate y here: y ~ binomial(,) + poisson()
library(rstan)
BH_model_block <- "
data{
int y;
int a;
}
parameters{
real <lower = 0, upper = 1> c;
real <lower = 0, upper = 1> b;
}
model{
y ~ binomial(a,b)+ poisson(c);
}
"
BH_model <- stan_model(model_code = BH_model_block)
BH_fit <- sampling(BH_model,
data = list(y = 5,
a = 2),
iter= 1000)
Produces this error:
SYNTAX ERROR, MESSAGE(S) FROM PARSER:
error in 'model2c6022623d56_457bd7ab767c318c1db686d1edf0b8f6' at line 13, column 20
-------------------------------------------------
11:
12: model{
13: y ~ binomial(a,b)+ poisson(c);
^
14: }
-------------------------------------------------
PARSER EXPECTED: ";"
Error in stanc(file = file, model_code = model_code, model_name = model_name, :
failed to parse Stan model '457bd7ab767c318c1db686d1edf0b8f6' due to the above error.
Stan doesn't support integer parameters, so you can't technically do that. For two real variables, it'd look like this:
parameters {
real x;
real y;
}
transformed parameters {
real z = x + y;
}
model {
x ~ normal(0, 1);
y ~ gamma(0.1, 2);
}
Then you get the sum distribution for z. If the variables are discrete, it won't compile.
If you don't need z in the model, then you can do this in the generated quantities block,
generated quantities {
int x = binomial_rng(a, b);
int y = poisson_rng(c);
int z = x + y;
}
The drawback of doing this is that none of the variables are available in the model block. If you need discrete parameters, they need to be marginalized as described in the user's guide chapter on latent discrete parameters (also in the chapter on mixtures and HMMs). This is not so easy with a Poisson, because support isn't bounded. If the expectations of the two discrete distributions is small, then you can do it approximately with a loop over plausible values.
It looked from the example in the original post that z is data. That's a slightly different marginalization over x and y, but you only sum over the x and y such that x + y = z, so the combinatorics are greatly reduced.
An alternative is to substitute the Binomial with a Poisson, and use Poisson additivity:
BH_model_block <- "
data{
int y;
int a;
}
parameters{
real <lower = 0, upper = 1> c;
real <lower = 0, upper = 1> b;
}
model{
y ~ poisson(a * b + c);
}
"
This differs in that if b is not small, the Binomial has a lower variance than the Poisson, but maybe there is overdispersion anyhow?

Is it a bug in Z3? Incorrect answer on Real and ForAll applied

I'm trying to find the minimal value of the Parabola y=(x+2)**2-3, apparently, the answer should be y==-3, when x ==-2.
But z3 gives the answer [x = 0, y = 1], which doesn't meet the ForAll assertion.
Am I assuming wrongly with something?
Here is the python code:
from z3 import *
x, y, z = Reals('x y z')
print(Tactic('qe').apply(And(y == (x + 2) ** 2 - 3,
ForAll([z], y <= (z + 2) ** 2 - 3))))
solve(y == x * x + 4 * x +1,
ForAll([z], y <= z * z + 4 * z +1))
And the result:
[[y == (x + 2)**2 - 3, True]]
[x = 0, y = 1]
The result shows that 'qe' tactic eliminated that ForAll assertion into True, although it's NOT always true.
Is that the reason that solver gives a wrong answer?
What should I code to find the minimal (or maximal) value of such an expression?
BTW, the Z3 version is 4.3.2 for Mac.
I refered
How does Z3 handle non-linear integer arithmetic?
and found a partial solution, using 'qfnra-nlsat' and 'smt' tactics.
from z3 import *
x, y, z = Reals('x y z')
s1 = Then('qfnra-nlsat','smt').solver()
print s1.check(And(y == (x + 2) ** 2 - 3,
ForAll([z], y <= (z + 2) ** 2 - 3)))
print s1.model()
s2 = Then('qe', 'qfnra-nlsat','smt').solver()
print s2.check(And(y == (x + 2) ** 2 - 3,
ForAll([z], y <= (z + 2) ** 2 - 3)))
print s2.model()
And the result:
sat
[x = -2, y = -3]
sat
[x = 0, y = 1]
Still the 'qe' tactic and the default solver seem buggy. They don't give the correct result.
Further comments and discussions are needed.

Processing: conditional to test for variable change

My question pertains to the environment of Processing 2.0.
I need to write a conditional (or set of conditionals) in void draw() that tests if the variable x has increased by 1 or decreased by 1 and adjust the variable y depending on the increase/decrease in x. For example if x decreases 1, y should increase by 10, and if x increases by 1 y should decrease by 10. How would I accomplish this?
The most obvious answer is to try to think of y as a multiple of x plus maybe an offset? So if you have your x going up and down every time you enter the draw() method you should do y = x * 10; or y = 400 + x * 10 if you have an offset (int this case 400) of some sorts...
If you absolutely have to do it like that, then the way is to store the previous value of x and check each at each draw() call. So create a new variable int prevX and in your draw() method do:
y = y + (x-prevX) * 10;
or
int diff = x - prevX;
if(diff == -1) y = y - 10;
else if (diff == 1) y = y + 10;