Setting constraints with variables as exponents in PySCIPOpt - scip

I want to solve an MINLP problem with SCIP in Python and therefore use PySCIPOpt.
I already introduced the variables, the objective function, and set the constraints (as far as it was possible, given my issue).
Within one constraint, there is a variable in the exponent of another pair of variables. Currently, it looks like this (x_1, x_2, y_1, y_2, z, v all are variables):
model.addCons( x_1 * x_2 * ( (y_1/y_2)**((z-1)/z) -1 ) - v == 0 )
This gives back the following error:
NotImplementedError: exponents must be numbers
I was reading about a builtin exp() method, but did not find a good example of how to use it in my specific code.
The only alternative I could imagine would be using the constraint handler, which of course is more work than just putting in exp().
Does anyone has an idea on how to implement the respective constraint in PySCIPOpt?
Thanks for your help in advance!

I believe you can model this with PySCIPOpt, by taking into account that
Which for your exponential yields
So I think your constraint can then be modeled like this:
model.addCons( x_1 * x_2 * (exp(((z-1)/z)*log(y_1/y_2))-1) - v == 0 )
At least the code runs, and if I'm not mistaken, it's mathematically equivalent to what you wanted.

Related

I use gurobipy to solve a simple problem,but after adding constraints containing exponential terms and solving them, I got a wrong result

I had trouble solving a simple problem with gurobi:
e^x+x=lnP
x=1
In Gurobipy,it transforms into this form:
x+y=temp
y=e^x
lnP=temp
x=1
The result is here:
Variable X
x 1
P 749.103
y 2.71828
Temp 3.71828
The code is as follows:
from gurobipy import *
model = Model('Antoine')
P = model.addVar(vtype=GRB.CONTINUOUS, name='P',lb=0)
x = model.addVar(vtype=GRB.CONTINUOUS, name='x',lb=0)
y = model.addVar(vtype=GRB.CONTINUOUS, name='y',lb=-GRB.INFINITY)
temp = model.addVar(vtype=GRB.CONTINUOUS, name='Temp1',lb=-GRB.INFINITY)
model.addConstr(x == 1)
model.addGenConstrExp(x,y)
model.addConstr(x+y == temp)
model.addGenConstrLog(P,temp)
model.setObjective(P, GRB.MINIMIZE)
model.write("test.lp")
model.optimize()
I don't know why the result of P is wrong
Gurobi represents nonlinear functions by piecewise linear approximations. When I solve the original model on my computer using Gurobi Optimizer 9.5.2, I get the following warning:
Warning: max constraint violation (2.9006e+00) exceeds tolerance
Warning: max general constraint violation (2.9006e+00) exceeds tolerance
Piecewise linearization of function constraints often causes big violation.
Try to adjust the settings of the related parameters, such as FuncPieces.
This means the default automatic linearization is not sufficiently accurate for this model. As suggested in the warning message, adjust the FuncPieces parameter to get a more accurate representation for this model. For example, with model.Params.FuncPieces=-1 on my computer, I get this more accurate result:
Variable X
-------------------------
P 41.29
x 1
y 2.71828
Temp1 3.71828

induction for SCIPopt's setppc

Regarding SCIP's "constraint handler for the set partitioning / packing / covering":
Is it smart enough to deduce all forms that it supports without me having to call the setppc functions directly?
Can it handle/detect forms of sum(x) == y where x is a list of binary variables and y is also a binary variable? Same question for less than or equal?
The docs for it state that it requires a right-hand-side equal to 1. What about RHS=0?
If I understand you correctly you are asking if SCIP will see that a linear constraint is a setppc constraint and automatically upgrade it? Yes.
Yes, it should not matter how you write it.
A sum of binary variables with rhs = 0 will just propagate and fix all variables to 0. (if only lhs is 0 then that is redundant)
If some of the coefficients are -1 instead of +1 SCIP will still try to make it work by negating all negative variables (or all positive ones and multiply by -1 afterwards). SCIP will check for any linear constraint that has only binary variables and +1/-1 coefficients if it can be upgraded in such a way.

How to use PySCIPOpt for feasibility-only problem

I have used CVXPY and some of its LP solvers to determine whether a solution to an A*x <= b problem is feasible, and now I would like to try PySCIPOpt. I could not find an example of this in the docs, and I'm having trouble figuring out the right syntax. With CVXPY the code is simply:
def do_cvxpy(A, b, solver):
x = cvxpy.Variable(A.shape[1])
constraints = [A#x <= b] #The # denotes matrix multiplication in CVXPY
obj = cvxpy.Minimize(0)
prob = cvxpy.Problem(obj, constraints)
prob.solve(solver=solver)
return prob.status
I think with PySCIPOpt one cannot use matrix notation as above, but must treat vectors and matrices as collections of scalar variables, each of which has to be added individually, so I tried this:
def do_scip(A, b):
model = Model("XYZ")
x = {}
for i in range(A.shape[1]):
x[i] = model.addVar(vtype="C", name="x(%s)" % i)
model.setObjective(0) #Is this right for a feasibility-only problem?
model.addCons(A*x <= b) #This is certainly the wrong syntax
model.optimize()
return model.getStatus()
Could anyone please help me out with the correct form for the constraint in addCons() for this kind of problem, and confirm that an acceptable way to ask whether a solution is feasible is to simply pass 0 as the objective?
I'm still not positive about the setObjective(0), but at least I can get the code to run without errors by "unpacking" the A matrix and the b vector and adding each element as a constraint:
for i in range(ncols):
for j in range(nrows):
model.addCons(A[j,i]*x[i] <= b[i])
I also discovered that CVXPY actually has an interface to SCIP, but it gives me an error when I try to use it:
getSolObjVal cannot only be called in stage SOLVING without a valid solution
which seems to suggest that the interface cannot be used for feasibility-only problems.

How to set bounds and constraints on Tensorflow Variables (tf.Variable)

I am using Tensorflow to minimize a function. The function takes about 10 parameters. Every single parameter has bounds, e.g. a minimum and a maximum value the parameter is allowed to take. For example, the parameter x1 needs to be between 1 and 10.
I also have a pair of parameters that need to have the following constraint x2 > x3. In other words, x2 must always be bigger than x3. (In addition to this, x2 and x3 also have bounds, similarly to the example of x1 above.)
I know that tf.Variable has a "constraint" argument, however I can't really find any examples or documentation on how to use this to achieve the bounds and constraints as mentioned above.
Thank you!
It seems to me (I can be mistaken) that constrained optimization (you can google for it in tensorflow) is not exactly the case for which tensroflow was designed. You may want to take a look at this repo, it may satisfy your needs, but as far as I understand, it's still not solving arbitrary constrained optimization, just some classification problems with labels and features, compatible with precision/recall scores.
If you want to use constraints on the tensorflow variable (i.e. some function applied after gradient step - which you can do manually also - by taking variable values, doing manipulations, and reassigning then), it means that you will be cutting variables after each step done using gradient in general space. It's a question whether you will successfully reach the right optimization goal this way, or your variables will stuck at boundaries, because general gradient will point somewhere outside.
My approach 1
If your problem is simple enough. you can try to parametrize your x2 and x3 as x2 = x3 + t, and then try to do cutting in the graph:
x3 = tf.get_variable('x3',
dtype=tf.float32,
shape=(1,),
initializer=tf.random_uniform_initializer(minval=1., maxval=10.),
constraint=lambda z: tf.clip_by_value(z, 1, 10))
t = tf.get_variable('t',
dtype=tf.float32,
shape=(1,),
initializer=tf.random_uniform_initializer(minval=1., maxval=10.),
constraint=lambda z: tf.clip_by_value(z, 1, 10))
x2 = x3 + t
Then, on a separate call additionally do
sess.run(tf.assign(x2, tf.clip_by_value(x2, 1.0, 10.0)))
But my opinion is that it won't work well.
My approach 2
I would also try to invent some loss terms to keep variables within constraints, which is more likely to work. For example, constraint for x2 to be in the interval [1,10] will be:
loss += alpha*tf.abs(tf.math.tan(((x-5.5)/4.5)*pi/2))
Here the expression under tan is brought to -pi/2,pi/2 and then tan function is used to make it grow very rapidly when it reaches boundaries. In this case I think you're more likely to find your optimum, but again the loss weight alpha might be too big and training will stuck somewhere nearby, if required value of x2 lies near the boundary. In this case you can try to use smaller alpha.
In addition to the answer by Slowpoke, reparameterization is another option. E.g. let's say you have a param p which should be bounded in [lower_bound,upper_bound], you could write:
p_inner = tf.Variable(...) # unbounded
p = tf.sigmoid(p_inner) * (upper_bound - lower_bound) + lower_bound
However, this will change the behavior of gradient descent.

SCIP what is the function for sign?

I am new to SCIP and have read through some of the example problems and documentation, but am still unsure how to formulate the following problem for the SCIP solver:
argmax(w) sum(sign(Aw) == sign(b))
where A is a nxm matrix, w is a mx1 vector, and b is a nx1 vector. The data type is floats/real numbers, and it is a constraint-free problem.
Values for A and b are also contained row-wise in a .txt file. How can I import that?
Overall - I am new to SCIP and have no idea how to start creating variables (especially the objective function value parameter), importing data, formulate the objective function... It's a bit of a stretch for me to ask this question, but your help is appreciated!
This should work:
where beta(i) = sign(b(i)). The implication can be implemented using indicator constraints. This way we don't need big-M's.
Most likely the >= 0 constraint should be >= 0.0001 (otherwise we can set all w(j)=0).