How to use PySCIPOpt for feasibility-only problem - feasibility

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.

Related

pyomo matrix product

I would like to use pyomo to solve a multiple linear regression under constraint in pyomo.
to do so I have 3 matrices :
X (noted tour1 in the following code) My inputs (600x13)(bureaux*t1 in pyomo)
Y (noted tour2 in the following code) the matrix I want to predict (6003)(bureauxt2 inpyomo)
T (noted transfer In the code) (13x3)(t1*t2 in pyomo)
I would like to do the following
ypred = XT
minimize (ypred-y)**2
subject to
0<T<1
and Sum_i(Tij)=1
To that effect, I started the following code
from pyomo.environ import *
tour1=pd.DataFrame(np.random.random(size=(60,13)),columns=["X"+str(i) for i in range(13)],index=["B"+str(i) for i in range(60)])
tour2=pd.DataFrame(np.random.random(size=(60,3)),columns=["Y"+str(i) for i in range(3)],index=["B"+str(i) for i in range(60)])
def gettour1(model,i,j):
return tour1.loc[i,j]
def gettour2(model,i,j):
return tour2.loc[i,j]
def cost(model):
return sum((sum(model.tour1[i,k] * model.transfer[k,j] for k in model.t1) - model.tour2[i,j] )**2 for i in model.bureaux for j in model.tour2)
model = ConcreteModel()
model.bureaux = Set(initialize=tour1.index.tolist())
model.t1 = Set(initialize=tour1.columns)
model.t2 = Set(initialize=tour2.columns)
model.tour1 = Param(model.bureaux, model.t1,initialize=gettour1)
model.tour2 = Param(model.bureaux, model.t2,initialize=gettour2)
model.transfer = Var(model.t1,model.t2,bounds=[0,1])
model.obj=Objective(rule=cost, sense=minimize)
I unfortunately get an error at this stage :
KeyError: "Index '('X0', 'B0', 'Y0')' is not valid for indexed component 'transfer'"
anyone knows how I can calculate the objective ?
furthermore any help for the constrains would be appreciated :-)
A couple things...
First, the error you are getting. There is information in that error statement that should help identify the problem. The construction appears to be trying to index transfer with a 3-part index (x, b, y). That clearly is outside of t1 x t2. If you look at the sum equation you have, you are mistakenly using model.tour2 instead of model.t2.
Also, your bounds parameter needs to be a tuple.
While building the model, you should be pprint()-ing the model very frequently to look for these types of issues. That only works well if you have "small" data. 60 x 13 may be the normal problem size, but it is a total pain to troubleshoot. So, start with something tiny, maybe 3 x 4. Make a Set, pprint(). Make a Constraint, pprint()... Once the model computes/solves with "tiny" data, just pop in the real stuff.

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

Set the objective of an optimizer as the standard deviation of the input (Nonlinear optimization using pymo)

I am trying to use pymo for a single objective nonlinear optimization problem.
The objective function is to minimize the variance (or standard deviation) of the input variables following certain constraints (which I was able to do in Excel).
Following is a code example of what I am trying to do
model = pyo.ConcreteModel()
# declare decision variables
model.x1 = pyo.Var(domain=pyo.NonNegativeReals)
model.x2 = pyo.Var(domain=pyo.NonNegativeReals)
model.x3 = pyo.Var(domain=pyo.NonNegativeReals)
model.x4 = pyo.Var(domain=pyo.NonNegativeReals)
# declare objective
from statistics import stdev
model.variance = pyo.Objective(
expr = stdev([model.x1, model.x2, model.x3, model.x4]),
sense = pyo.minimize)
# declare constraints
model.max_charging = pyo.Constraint(expr = model.x1 + model.x2 + model.x3 + model.x4 >= 500)
model.max_x1 = pyo.Constraint(expr = model.x1 <= 300)
model.max_x2 = pyo.Constraint(expr = model.x2 <= 200)
model.max_x3 = pyo.Constraint(expr = model.x3 <= 100)
model.max_x4 = pyo.Constraint(expr = model.x4 <= 200)
# solve
pyo.SolverFactory('glpk').solve(model).write()
#print
print("energy_price = ", model.variance())
print(f'Variables = [{model.x1()},{model.x2()},{model.x3()},{model.x4()}]')
The error I get is TypeError: can't convert type 'ScalarVar' to numerator/denominator
The problem seems to be caused by using the stdev function from statistics.
My assumption is that the models variables x1-x4 are yet to have been assigned a value and that is the main issue. However, I am not sure how to approach this?
First: stdev is nonlinear. So why even try to solve this with a linear solver?
Pyomo does not know about the statistics package. You'll have to program the standard deviation using elementary operations, use an external function approach, or use an approximation (like minimizing the range).
So I managed to solve this issue and I am including the solution below. But first, there are a couple of points I would like to highlight
As #Erwin Kalvelagen mentioned, 'stdev' is nonlinear so a linear solver like 'glpk' would always result in an error. For my problem, 'ipopt' worked fine but be careful as it can perform poorly in some cases.
Also, as #Erwin Kalvelagen mentioned, Pyomo does not know about the statistics package. So When you try to use a function from that package (e.g., 'stdev', 'variance', etc.), it will try to evaluate the model variables before the solver assigns them any value and that will cause an error.
A pyomo objective function needs an expression. The code sample below shows how to dynamically generate an expression for the variance without using an external package. The code is also agnostic to the number of model variables you have.
Using either the variance or the standard deviation will serve the same purpose for my project. I opted for using the variance to avoid calculating its square root (as the standard deviation is the square root of the variance).
Variability Objective Function
import pyomo.environ as pyo
def variabilityRule(model):
#Calculate mean of all model variables
for index in model.x:
mean += model.x[index]
mean = mean/len(model.x)
#Calculate the difference between each model variable and the mean
obj_exp = ((model.x[1])-mean) * ((model.x[1])-mean)
for i in range(2, len(model.x)+1): #note that pyomo variables start from 1 not zero
obj_exp += ((model.x[i])-mean) * ((model.x[i])-mean)
#Divide by number of items
obj_exp = (obj_exp/(len(model.x)))
return obj_exp
model = pyo.ConcreteModel()
model.objective = pyo.Objective(
rule = variabilityRule,
sense = pyo.maximize)
EDIT: Standard Deviation Calculation
You can use the same approach to calculate the standard deviation as I found out. Just multiply the final expression (`obj_exp`) by power 0.5
obj_exp = obj_exp ** 0.5
...
P.S. If you are interested, this is how I dynamically generated my model variables based on an input array
model.x = pyo.VarList(domain=pyo.NonNegativeReals)
for i in range(0, len(input_array)):
model.x.add()

Setting constraints with variables as exponents in PySCIPOpt

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.

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).