using gurobi variable as index in 2d array
AnsweredA=[1,2,3,4,5,1,2,3,4,5,1,2,3,4,5]
L Is 2d matrix of size M * M # L[1][1], L[1][2],......L[5][5]
E=m.addMVar(3,vtype=GRB.INTEGER,lb=1,ub=5, name="E") #E[1], E[2], E[0] unused
how to model this equation t[i]=L[A[i]][E[j]] for i in range(1,16) and j in range(1,3)
main objective is to find max(t[i] for in range(1,16))
-
I am not sure I understand your intentions correctly.
Do you want to access the values of a given matrix \(L\) via \(\texttt{L[A[i]][E[j]]}\)? This is not possible, because \(E\) is an optimization variable and not an index. Could you clarify what exactly are you trying to model? Did you have a look at our gurobipy introduction videos? You might also want to have a look at our Matrix example and our webinar about the Matrix API.
1 -
thank you for your quick reply, yes E is an optimization variable, it has initial values, for example, E array contains E[1]=2,E[2]=5. First problem is how to initialize the optimization variable and second how can i use E[j] as a index for matrix L. In this example matrix L is given. Actually, i want to maximize t[i] by finding the optimal value for E[1] and E[2]. I am novice user, please help thank you.
0 -
To initialize your variables, I think you should better use the addVars method instead of the addMVar method.
Using optimization variables as indices for other entries is not easy and is discussed in the post use a decision variable as an index. In general, I would not recommend using optimization variables as an index but rather try to reformulate the model to avoid it. However, this is not always possible and/or easy at all.
1 -
Thank you for you valuable suggestion, i changed array E from addMVar to addVars and initialize the value of E[1]=2, E[2]=5. Then the following code is not giving the eror. It is optimizing the E to E[1]=1, E[2]=1. So in this case using optimization variable E as index not giving error. Please verify whether i have interepreted correctly or not. Thank you
import gurobipy as gp
from gurobipy import GRB
import numpy as nmp1
import numpy.random as nmp
A=nmp1.array([0,1,2,3,1,2,3,1,2,3,4,3,4,3,4,3,4]) #1 to 16, index 0 is unused
PN= nmp1.array([[0,0,0,0,0,0,0,0,0],[0,1,2,3,4,5,6,7,8],[0,9,10,11,12,13,14,15,16]]) # PN[1], PN[2], PN[0] unused
L= nmp.uniform(2,5,size=(6,6)) # L[1][1], L[1][2],......L[5][5]
for i in range(1,6): # diagonal entries are zeros
for j in range(1,6):
if(i==j):
L[i][j]=0
print(L[i][j])
print("\n")
E_initial=nmp1.array([0,2,5])
# Create a new model
m = gp.Model("mip1")
E=m.addVars(3,lb=1,ub=5, vtype=GRB.INTEGER,name="E") #E[1], E[2], E[0] unused
t=m.addMVar(17, vtype=GRB.CONTINUOUS,name="t") #E[1], E[2], E[0] unused
rt=m.addVar(vtype=GRB.CONTINUOUS,name="rt")
for i in range(1,3):
E[i]=E_initial[i]
m.setObjective(rt, GRB.MINIMIZE)
m.addConstr(rt==gp.max_(t[i] for i in range(1,16)), name="c2")
for j in range(1,3):
for i in PN[j]:
if i!=0:
m.addConstr((t[i]==L[A[i]][E[j]]),name="c1" )m.optimize()
for v in m.getVars():
print('%s %g' % (v.VarName, v.X))
print('Obj: %g' % m.ObjVal)0 -
Please verify whether i have interepreted correctly or not.
The model you optimize is not what you expect. You are first defining \(\texttt{E}\) to be a tupledict of optimization variables.
E=m.addVars(3,lb=1,ub=5, vtype=GRB.INTEGER,name="E") #E[1], E[2], E[0] unused
But then, you override each entry of this dictionary by constant values
for i in range(1,3):
E[i]=E_initial[i]From here on, the entries \(\texttt{E[1],E[2]}\) are no longer optimization variables but just constant integer values. Please also note that you don't use \(\texttt{E[0]}\) because you loop over \(\texttt{range(1,3)}\) instead of \(\texttt{range(0,3)}\).
If you want to provide an initial value for the optimization variables (also called a MIP start, cf. How do I use MIP starts?), you have to set the Start attribute of the variables
for i in range(1,3):
E[i].Start = E_initial[i]With the above change, you will get an expected error from numpy stating that you cannot access the index by using an optimization variable. This is where the post use a decision variable as an index is needed.
Maybe you could try to reformulate the model in a way that you multiply each entry of \(L\) with the corresponding variable \(E_j\). Maybe by introducing some auxiliary binary variables, you can achieve what you want.
1 -
Thank you for valuable suggestion, i tried to remove optimization variable E from array index. I have added new decision variable E_decision ( E_decision[1][1], E_decision[1][2],....E_decision[1][5]
E_decision[2][1], E_decision[2][2],....E_decision[2][5]). i have changed following constraint "m.addConstr((t[i]==L[A[i]][E[j]]),name="c1" )m.optimize()" as
"m.addConstr(t[i]==sum(L[A[i]][k] *E_decision[j][k] for k in range(1,6)),name="c1" )"
Here in updated constraint i want right hand side optimized value for k (i.e., L[A[i]][k]) assigned to t[i], so what function should i use?, using sum is right or not. Earliear E[j] was given inplace of k, and E[j] may have values from 1 to 5. Now i have given k, k also have values from 1 to 5. How to take optimize value from rhs and assigne to lhs in this constraints. Further, one more new contraint is added
for j in range(1,3):
m.addConstr(sum(E_decision[j][k] for k in range(1,6))==1)This constraint is use to make sure only one k is decided for j the default value is
0,1,0,0,0 #sum can be only 1
0,0,0,0,1 # sum can be only 1
Please answer my doubt whether i have done modified correctly or not.
import gurobipy as gp
from gurobipy import GRB
import numpy as nmp1
import numpy.random as nmp
M=5
A=nmp1.array([0,1,2,3,1,2,3,1,2,3,4,5,3,4,5,3,4]) #1 to 16, index 0 is unused
PN= nmp1.array([[0,0,0,0,0,0,0,0,0],[0,1,2,3,4,5,6,7,8],[0,9,10,11,12,13,14,15,16]]) # PN[1], PN[2], PN[0] unused
L_initial= nmp.uniform(2,5,size=(6,6)) # L[1][1], L[1][2],......L[5][5]for i in range(1,6): # diagonal entries are zeros
E=nmp1.array([0,2,5])
# Create a new model
m = gp.Model("mip1")
t=m.addMVar(17, vtype=GRB.CONTINUOUS,name="t") #E[1], E[2], E[0] unused
rt=m.addVar(vtype=GRB.CONTINUOUS,name="rt")
E_decision=m.addMVar((3,6),lb=0,ub=1,vtype=GRB.BINARY, name="E_decision")
L=m.addMVar((6,6),vtype=GRB.CONTINUOUS,name="latency_mec_host")
#initializing the optimization variable
for j in range(1,3):
for k in range(1,6):
E_decision[j][k].Start=0
for j in range(1,3):
E_decision[j][E[j]].Start=1
m.setObjective(rt, GRB.MINIMIZE)
m.addConstr(rt==gp.max_(t[i] for i in range(1,16)), name="c2")
for i in range(1,6):
for j in range(1,6):
m.addConstr(L[i][j]==L_initial[i][j],name="l_1")
for j in range(1,3):
for i in PN[j]:
if i!=0:
m.addConstr(t[i]==sum(L[A[i]][k] *E_decision[j][k] for k in range(1,6)),name="c1" )
#new constraints
for j in range(1,3):
m.addConstr(sum(E_decision[j][k] for k in range(1,6))==1) # Optimize model
m.optimize()
for v in m.getVars():
print('%s %g' % (v.VarName, v.X))
print('Obj: %g' % m.ObjVal)0 -
Hi Ramesh,
Your idea is definitely correct and your code looks like it does what it should.
To be sure, you should double check the correctness of the optimal solution point and optimal objective value.
One side note. You are always starting your loops with index 1. However, all your variables are defined starting with index 0 such that all those variables are defined but never used. This is not an issue in general as long as you stay consistent but could lead to potential issues when you try to extend the code or some variable with index 0 slips into some constraint. You are currently using addMVar to define matrix variables. This is not necessary as you don't use the Matrix API. Since you want to start indexing with 1, you can use the addVars method and provide the respective range.
t=m.addVars(range(1,17), vtype=GRB.CONTINUOUS,name="t") #E[1], E[2], E[0] unused
rt=m.addVar(vtype=GRB.CONTINUOUS,name="rt")
E_decision=m.addVars(range(1,3),range(1,6),lb=0,ub=1,vtype=GRB.BINARY, name="E_decision")
L=m.addVars(range(1,6),range(1,6),vtype=GRB.CONTINUOUS,name="latency_mec_host")Note that the addVars method returns a tupledict and not an MVar object. Thus, you have to access the entries differently, e.g., \(\texttt{E_decision[j,k]}\) instead of \(\texttt{E_decision[j][k]}\). The adjusted code should look similar to
import gurobipy as gp
from gurobipy import GRB
import numpy as nmp1
import numpy.random as nmp
M=5
A=nmp1.array([0,1,2,3,1,2,3,1,2,3,4,5,3,4,5,3,4]) #1 to 16, index 0 is unused
PN= nmp1.array([[0,0,0,0,0,0,0,0,0],[0,1,2,3,4,5,6,7,8],[0,9,10,11,12,13,14,15,16]]) # PN[1], PN[2], PN[0] unused
L_initial= nmp.uniform(2,5,size=(6,6)) # L[1][1], L[1][2],......L[5][5]for i in range(1,6): # diagonal entries are zeros
E=nmp1.array([0,2,5])
# Create a new model
m = gp.Model("mip1")
t=m.addVars(range(1,17), vtype=GRB.CONTINUOUS,name="t") #E[1], E[2], E[0] unused
rt=m.addVar(vtype=GRB.CONTINUOUS,name="rt")
E_decision=m.addVars(range(1,3),range(1,6),lb=0,ub=1,vtype=GRB.BINARY, name="E_decision")
L=m.addVars(range(1,6),range(1,6),vtype=GRB.CONTINUOUS,name="latency_mec_host")
#initializing the optimization variable
for j in range(1,3):
for k in range(1,6):
E_decision[j,k].Start=0
for j in range(1,3):
E_decision[j,E[j]].Start=1
m.setObjective(rt, GRB.MINIMIZE)
m.addConstr(rt==gp.max_(t[i] for i in range(1,16)), name="c2")
for i in range(1,6):
for j in range(1,6):
m.addConstr(L[i,j]==L_initial[i][j],name="l_1")
for j in range(1,3):
for i in PN[j]:
if i!=0:
m.addConstr(t[i]==sum(L[A[i],k] *E_decision[j,k] for k in range(1,6)),name="c1" )
#new constraints
for j in range(1,3):
m.addConstr(sum(E_decision[j,k] for k in range(1,6))==1) # Optimize model
m.optimize()
m.write("myLP.lp")
for v in m.getVars():
print('%s %g' % (v.VarName, v.X))
print('Obj: %g' % m.ObjVal)Note that I added the write method call which will generate a human readable LP file called \(\texttt{myLP.lp}\). You can open this file in any text editor and analyze whether the model looks what you expect it to be. This is helpful when analyzing the correctness of the model.
Best regards,
Jaromił1 -
Thank you so much for your help and valuable suggestion and correction. It is working fine now. One more doubt, when i prints optimize binary variable E_decision, it is printing -0, whereas it is defined binary and lb=0, ub=1, why so, will it be a problem. Thank you
E_decision[1,1] 1
E_decision[1,2] -0
E_decision[1,3] 0
E_decision[1,4] 0
E_decision[1,5] 0
E_decision[2,1] 0
E_decision[2,2] 0
E_decision[2,3] 0
E_decision[2,4] 0
E_decision[2,5] 11 -
Gurobi handles binaries internally as double values and works with tolerances such as IntFeasTol. Thus, it is possible that a binary variable is not truly 0 or 1 but only "almost" 0 or 1.
Please refer to the stackoverflow post Double value as a negative zero for more details.
0 -
okay thank you so much.
0
Please sign in to leave a comment.
Comments
10 comments