lb and ub of variables
AnsweredHi!
Recently when I used gurobipy a problem bothered me for a long time. If i write
addVars(20,30,vtype=GRB.BINARY,name='aij')
addVars(20,30,vtype=GRB.CONTINUOUS,name='fij')
addConstrs(fij[i,t]<=aij[i,j] for i in range(0,20) for t in range(0,30))
addConstrs(fij[i,t]>=aij[i,j] for i in range(0,20) for t in range(0,30))
......(other constraints are omitted here)
the model is infeasible,however, it is feasible when i write
addVars(20,30,vtype=GRB.BINARY,name='aij')
addVars(20,30,vtype=GRB.CONTINUOUS,lb=1,ub=1,name='fij')
addConstrs(fij[i,t]<=aij[i,j] for i in range(0,20) for t in range(0,30))
addConstrs(fij[i,t]>=aij[i,j] for i in range(0,20) for t in range(0,30))
......(other constraints are omitted here)
but it is still infeasible when i write
addVars(20,30,vtype=GRB.BINARY,name='aij')
addVars(20,30,vtype=GRB.CONTINUOUS,name='fij')
addConstrs(fij[i,t]<=aij[i,j] for i in range(0,20) for t in range(0,30))
addConstrs(fij[i,t]>=aij[i,j] for i in range(0,20) for t in range(0,30))
addConstrs(fij[i,t]<=1 for i in range(0,20) for t in range(0,30))
addConstrs(fij[i,t]>=1 for i in range(0,20) for t in range(0,30))
......(other constraints are omitted here)
i think the three codes express the same thing. Why it influences the solving process? Previously , I use Yalmip in matlab, it does not need to set the lb and ub of a variable, the bounds can be deduced by the constraints.

Hi Yansong,
Note that the default lower bound for a variable is 0.0, so the first and third code block is more restrictive on the lower bound than in the second one, see the addVars() description. Your solution might require negative values which should explain infeasibility.
Best regards,
Mario1 
Thank you very much for your prompt reply. It means if i don't set the lb or ub bound for a variable, the default value is 0? But when i export the model corresponding to the first code and the third code,it shows "fij free" ,and it looks like there is no default limit of "fij" .
0 
Yes, if you don't set LB and UB, the default values will be 0 and infinity, respectively.
Did you export the model with write()? Which file format did you use? Could you please post the file for the first model variant (with default bounds)?
0 
Hi,Mario
Yes, i export the model with write.
\ LP format  for model browsing. Use MPS format to capture full model detail.
Maximize
....
Subject To
R0: ai[0,0] = 1
.....(the constraints are omitted)
R663:  0.01 ai[1,1] + fij[0,1]  fij[2,1]  fij[3,1]  fij[4,1] = 0
Bounds
fij[0,0] free,......
Binaries
ai[0,0],.......
Endthe .lp file shows something like this if i don't set the lb and ub. I thought "free" means no boundaries before, but the result seems like to be the default boundaries(fij>=0)
0 
Hi Yansong,
This is indeed strange. I just tried to reproduce your issue on my side but when I create variables and constraints as you did it in your first block, then the LP file contains no information in the corresponding "Bounds" section which implies that default bounds 0 and infinity are used.
Your assumption is correct that "free" should mean no bounds at all, i.e., inf to +inf.Which Gurobi and Python version are you using? I used Gurobi 9.1.2 and Python 3.8.
0 
Gurobi version is 9.1.2 and Python is 3.7. The environment used is PyCharm.
0 
Could you produce a small version of your Python script in which you still see the "free" variables in the LP file and post it here?
0 
import numpy as np
import math
import pandas as pd
import gurobipy as gp
from gurobipy import GRB
set1 = range(0,46)
set3 = range(0,39)
set4 = range(0,10)
set5 = range(29,39)
set2 = range(0,20)
index = np.array(set5)
CU = np.setdiff1d(set3,set5)
CU = CU.tolist()
CW = [2,6,6,6,6,6,6,6,6,6];CW = np.array(CW)
bu1 = [1,1,2,2,2,3,3,4,4,5,5,6,6,6,7,8,9,10,10,10,12,12,13,14,15,16,16,16,16,17,17,19,19,20,21,22,22,23,23,25,25,26,26,26,28,29]
bu1 = np.array(bu1)  1
bu2 = [2,39,3,25,30,4,18,5,14,6,8,7,11,31,8,9,39,11,13,32,11,13,14,15,16,17,19,21,24,18,27,20,33,34,22,23,35,24,36,26,37,27,28,29,29,38]
bu2 = np.array(bu2)  1
ac = gp.tuplelist([(bu1[i],bu2[i]) for i in set1])
data1 = [0.560900000000000,1.01650000000000,1.06770000000000,1.10840000000000,0.924000000000000,0.879500000000000,0.500000000000000,0.678400000000000,0.536300000000000,0.698700000000000,0.674300000000000,0.530200000000000,0.762300000000000,1.08070000000000,0.910500000000000,1.50000000000000,1.05160000000000,0.771800000000000,0.702800000000000,0.520500000000000,0.633900000000000,0.690500000000000,0.690500000000000,0.633900000000000,0.807600000000000,0.952400000000000,0.739200000000000,0.520500000000000,0.659600000000000]
m = gp.Model("model1")
a1 = m.addVars(10,20,vtype=GRB.BINARY)
a0 = m.addVars(10,20,vtype=GRB.BINARY)
a3 = m.addVars(39,20,vtype=GRB.BINARY)
a2 = m.addVars(46,20,vtype=GRB.BINARY)
so = m.addVars(1,20,vtype=GRB.CONTINUOUS)
w = m.addVars(46,20,vtype=GRB.CONTINUOUS,name='free_V')#lb=1,ub=1,
m.addConstr(a0[0,0]==1)#name=a0+str(1_1)
m.addConstrs(a0[i,j]>=a0[i,j1] for i in set4 for j in range(1,20))
m.addConstrs(a1[i,j]>=a1[i,j1] for i in set4 for j in range(1,20))
m.addConstrs(a0[i,j]<=a3[index[i],j] for i in set4 for j in set2)
m.addConstrs(so[0,j]>=0 for j in set2)
m.addConstrs(so[0,j]<=1 for j in set2)
for i in set3:
fi = ac.select('*',i)
fi = [ac.index(i) for i in fi]
fo = ac.select(i,'*')
fo = [ac.index(i) for i in fo]
if i in set5:
gen_index = set5.index(i)
if gen_index == 0:
if fi == [] and fo != []:
m.addConstrs((gp.quicksum(w[a, j] for a in fo) + so[0, j] == 0.01 * a3[i, j]) for j in set2)
elif fi != [] and fo == []:
m.addConstrs((gp.quicksum(w[a, j] for a in fi) + so[0, j] == 0.01 * a3[i, j]) for j in set2)
else:
m.addConstrs((gp.quicksum(w[a, j] for a in fi)  gp.quicksum(w[a, j] for a in fo) + so[0, j] == 0.01 * a3[i, j]) for t in set2)
else:
if fi==[] and fo!=[]:
m.addConstrs((gp.quicksum(w[a, j] for a in fo) == 0.01 * a3[i,j]) for j in set2)
elif fi!=[] and fo==[]:
m.addConstrs((gp.quicksum(w[a, j] for a in fi) == 0.01 * a3[i, j]) for j in set2)
else:
m.addConstrs((gp.quicksum(w[a, j] for a in fi)  gp.quicksum(w[a, j] for a in fo) == 0.01 * a3[i, j]) for j in set2)
else:
if fi == [] and fo != []:
m.addConstrs((gp.quicksum(w[a, j] for a in fo) == 0.01 * a3[i, j]) for j in set2)
elif fi != [] and fo == []:
m.addConstrs((gp.quicksum(w[a, j] for a in fi) == 0.01 * a3[i, j]) for j in set2)
else:
m.addConstrs((gp.quicksum(w[a, j] for a in fi)  gp.quicksum(w[a, j] for a in fo) == 0.01 * a3[i, j]) for j in set2)
m.addConstrs(a3[i,j]>=a3[i,j1] for i in set3 for j in range(1,20))
m.addConstrs(a2[i,j]<=a3[bu1[i],j] for i in set1 for j in set2)
m.addConstrs(a2[i,j]<=a3[bu2[i],j] for i in set1 for j in set2)
m.addConstrs(a2[i,j]<=a3[bu1[i],j1]+a3[bu2[i],j1] for i in set1 for j in range(1,20))
m.addConstrs(a2[i,j]>=a2[i,j1] for i in set1 for j in range(1,20))
m.addConstrs(a2[i,j]<=w[i,j] for i in set1 for j in set2)
m.addConstrs(w[i,j]<=a2[i,j] for i in set1 for j in set2)
m.addConstrs(gp.quicksum((1a1[i,j]) for j in set2)>=gp.quicksum((1a0[i,j]) for j in set2)+CW[i] for i in set4)
obj = gp.LinExpr(0)
for i in CU:
for j in set2:
obj.add(a3[i,j],100*data1[CU.index(i)])
m.setObjective(obj, GRB.MINIMIZE)
m.optimize()
m.computeIIS()
m.write('D:\model.ilp')I have produces the reduced codes. Finally, the some variables named 'free_V' seems to be free in the .ilp files.
\ Model model1_copy
\ LP format  for model browsing. Use MPS format to capture full model detail.
Minimize
Subject To
R46:  C247 + C248 >= 0
R47:  C248 + C249 >= 0
R48:  C249 + C250 >= 0
R49:  C250 + C251 >= 0
R50:  C251 + C252 >= 0
R421: C240  C1020 <= 0
R424: C243  C1023 <= 0
R433: C252  C1032 <= 0
R434: C253  C1033 <= 0
R435: C254  C1034 <= 0
R436: C255  C1035 <= 0
R437: C256  C1036 <= 0
R438: C257  C1037 <= 0
R439: C258  C1038 <= 0
R440: C259  C1039 <= 0
R806:  0.01 C585  free_V[17,5]  free_V[18,5]  free_V[19,5] = 0
R814:  0.01 C593  free_V[17,13]  free_V[18,13]  free_V[19,13] = 0
R815:  0.01 C594  free_V[17,14]  free_V[18,14]  free_V[19,14] = 0
R820:  0.01 C599  free_V[17,19]  free_V[18,19]  free_V[19,19] = 0
R1246:  0.01 C1025 + free_V[19,5] = 0
R1254:  0.01 C1033 + free_V[19,13] = 0
R1255:  0.01 C1034 + free_V[19,14] = 0
R1260:  0.01 C1039 + free_V[19,19] = 0
R1990:  C1020 + C1021 >= 0
R1991:  C1021 + C1022 >= 0
R1992:  C1022 + C1023 >= 0
R1993:  C1023 + C1024 >= 0
R1994:  C1024 + C1025 >= 0
R2002:  C1032 + C1033 >= 0
R2005:  C1035 + C1036 >= 0
R2006:  C1036 + C1037 >= 0
R2007:  C1037 + C1038 >= 0
R2008:  C1038 + C1039 >= 0
R7572:  C40  C41  C42  C43  C44  C45  C46  C47  C48  C49  C50
 C51  C52  C53  C54  C55  C56  C57  C58  C59 + C240 + C241
+ C242 + C243 + C244 + C245 + C246 + C247 + C248 + C249 + C250 + C251
+ C252 + C253 + C254 + C255 + C256 + C257 + C258 + C259 >= 6
Bounds
free_V[19,5] free
free_V[19,13] free
free_V[19,14] free
free_V[19,19] free
Binaries
C40 C41 C42 C43 C44 C45 C46 C47 C48 C49 C50 C51 C52 C53 C54 C55 C56 C57
C58 C59 C240 C241 C242 C243 C244 C245 C246 C247 C248 C249 C250 C251 C252
C253 C254 C255 C256 C257 C258 C259 C585 C593 C594 C599 C1020 C1021 C1022
C1023 C1024 C1025 C1032 C1033 C1034 C1035 C1036 C1037 C1038 C1039
End0 
Oh, you are computing an IIS after infeasibility is shown. Then, with
m.write('D:\model.ilp')
you are writing out the IIS, not the original model. Note that the file ending ILP does not mean "integer linear program", it refers to writing the IIS in LPformat. If you want to write the original model, you could use
m.write('D:\model.lp')
immediately before calling optimize(). Please check if the bounds are correct in that file.
But the fact that the IIS does not include the bounds is definitely strange. Especially, since the output of the script says
IIS computed: 34 constraints, 8 bounds
But there are only 34 constraints and no bounds in the file. I will investigate this further and come back to you as soon as I know more.
0 
Ok, thank you Mario.
0 
Ok, the explanation is in fact easier that I thought.
The ILP file containing the IIS for your infeasible model is correct. The output says that 34 constraints and 8 bounds are needed to define the IIS. In total, there are 12 different "free_V" variables included in the IIS, and all of them had 0 as default lower bound in the original model. But in the IIS only 8 of the 12 lower bounds are needed, 4 variables can be free and still the model is infeasible. The residual 8 variables are not mentioned in the "Bounds" section, just because again the default lower bound of 0 applies.
0 
Hello, I think you can try to check whether the data and model constraints are correct. It is better to add names to variables and constraints, so that you can see the changes of variables more intuitively after you export the file.
0
Please sign in to leave a comment.
Comments
12 comments