How to index a dictionary or list with a list?
AnsweredHello,
In my optimization problem, I have a constraint like below "Constraint 2" within which K at every iteration depends on SC[i] at that particular iteration or the next one. SC[i] is also generated on another constraint such as Constraint 1. Apparently, it is not possible to index the K list with another list as written below. Also, as the relationship between K[i] and SC[i] involves non-integer powers, it also seems that the equation of their relationship cannot be directly embedded into constraints 2 or as a separate constraint. So, one straightforward method that comes to mind is building a K dictionary or list as a piece of data at the beginning of code and then index it with SC[i] values (which are between 0 and 100) at each iteration of Constraint 2 as shown below. But, this does not seem to be possible. So, I would be thankful if you could tell me how to address this problem.
Constraint1=m.addConstrs(SC[i]==SE[i] / SEmax for i in range(Na,Nb))
Constraint2=m.addConstrs(DE[i]==SEmax * abs (K[ SC[i] ] * (1-SC[i]) - K[ SC[i+1] ] * (1-SC[i+1])) for i in range(Na,Nb))
-
Why not just write a for loop and call Model.addConstr() to add the constraints one at a time?
1 -
Thank you Greg for your response.
if you mean to calculate K[SC[i]] in a loop similar to the below code, it leads to the same "power" error. As you can see there is non-integer power in the K equation which probably causes the error. In fact, this error prevents me from calculating K[i] values directly from SC[i]. So, on one hand I can't calculate K[i] from SC[i] and on the other hand it is not possible to create a dictionary for K[i] and index it with SC[i]. What do you think I should do?TypeError: unsupported operand type(s) for ** or pow(): 'gurobipy.LinExpr' and 'float'
for i in range (Na,Nb):
Constraint1=m.addConstrs(SC[i]==SE[i] / SEmax for i in range(Na,Nb))
K[i]== ((1/1-(SC[i]/100))*(1-(0.4)**(((1-(SC[i]/100))**0.575)/374)))Constraint2=m.addConstrs(DE[i]==SEmax * abs (K[i] * (1-SC[i]) - K[i+1] * (1-SC[i+1])) for i in range(Na,Nb))
0 -
Looks like K or SC are either decision variables or linear expressions. This isn't supported.
1 -
Dear Greg,
I really appreciate your response. But in order to clear up the problem for myself let me explain a bit more. K is not a decision variable. But, SC, SE and DE are. K is a parameter that depends on SC and in my algorithm it needs to be obtained at every interval (N) to be used in calculation of DE. Logically, in regular programming K could be calculated for every SC and then be called when needed. But, in optimization programming I am not sure if this approach is logically correct. I can think of 3 approaches to take in order to deal with K:
1. Generate K for every possible SC as a list or dictionary and call it with the SC[i] as index on the constraint 2. (If possible at all).
2. Generate K by using list comprehension or a for loop for every N.
3. Linearize K(SC) so I can declare it as another constraint.Having that said, I have a few of questions:
A. Are approaches 1 and 2 incorrect and logically false in this case?
B. Is approach 3 is correct?
C. If none of the three approaches are correct, how can I modify the problem so that it can be solved by Gurobi?
Thank you
0 -
I'm sure there are a lot of details which we can't get into on this discussion forum, but let me point you in a direction that hopefully should help.
Most importantly, you must formulate your model in a form that Gurobi can solve. The exponents in your second version look like a typo, but more importantly, the subscript from your first version (ex: K[SC[i]]) is not in a form that Gurobi can solve.
It sounds like SC[i] takes discrete (specific) values. To keep things simple, let's say that it is constrained to the values 2,3,5,7. Then you can say:
SC = 2*y1 + 3*y2 + 5*y3 + 7*y4
y1+y2+y3+y4=1
yi binary
Then when you need K[SC[i]], you use:
y1*K[2] + y2*K[3] + y3*K[5] + y4*K[7].
Finally, I would step away from Python code for a bit while you write up the mathematical representation. Once you are sure it fits into a form that Gurobi can solve, then it's safe to return to the Python code.
Again, that's about the limit what we can do in a discussion forum, but hopefully this is helpful.
1 -
Thanks again and your explanation was very helpful. However, when I implement the way you mentioned, I get an error saying :
TypeError: unhashable type: 'tupledict'
That's probably because i is a tupledict. But, I don't know how to address it. The error shows up for the constraint 2 which implements the last line of your algorithm. (y1*K[2] + y2*K[3] + y3*K[5] + y4*K[7])
constraint 1=m.addConstr((sum(x[i]) for i in range(0,100))==1) # x: Binary
constraint 2=m.addConstrs(SC[i]==sum(x[i] * i for i in range(100)))
constraint 3=m.addConstrs(K[i]==(x[i]*Ks[i] for i in range(100))) # Ks: the known list of K
P.S: I need to point out that exponents of my K[i] equation were not typos and there is actually such a nonlinearity in my equation.0 -
Hi Hooman,
Can you please post a small, self-contained code example that reproduces the problem? It's not clear exactly how you define everything.
Also, Gurobi does not support raising variables to arbitrary powers. Did you take a look at the link Greg posted? Your constraint expressions should be comprised of linear and/or quadratic terms.
Thanks,
Eli
0 -
Dear Eli,
Thank you very much for your reply. As you mentioned, since the relationship between SC and K in my code is nonlinear and cannot be included as a constraint, I think I have to take one of the following approaches:
1. Produce K for every possible SC as a list and use it when needed. (Similar to the method Greg mentioned which is written below).
2. Linearize K(SC) so I can declare it as another constraint.
I tried the first way but it keeps showing up the "unhashable type" error. Here is a small part of my code which is responsible for generating DE, so it can be used in the objective function of the problem.#Parameters:
# Generating all the possible values of SC
Ks=[((1/1-(s/100))*(1-(0.4)**(((1-(s/100))**0.575)/374))) for s in range (0,100)]
#Variables:
SE= m.addVars(24,name="SE")
SC= m.addVars(100,name="SC")
DE= m.addVars(24,name="DE")
x= m.addVars(100,vtype=GRB.BINARY,name="x")
# Constraints :
# A is a constant, Na is a constant
constraint 1=m.addConstr(SE[Na]==A)
# CE is a constant, Pc and Pd are other decision variable which are generated and constrained in another parts of the code.
constraint 2=m.addConstrs(SE[i] == SE[i-1]+(CE*Pc[i])-Pd[i] for i in range(Na+1,24)):
# SEmax is a constant
constraint 3=m.addConstrs(SC[i]==SE[i]/SEmax for i in range (0,24))
constraint 4=m.addConstrs(SC[i]==0 for i in range(24,100))
constraint 5=m.addConstr((sum(x[i]) for i in range(0,100))==1)
constraint 6=m.addConstrs(SC[i]==sum(x[i] * i for i in range(100)))
# Ks: Generated in the parameters
constraint 7=m.addConstrs(K[i]==sum(x[i]*Ks[i] for i in range(100)))
# SEmax is a constant, DE is used in the objective function.
constraint 8=m.addConstrs(DE[i]==SEmax*abs(K[i]*(1-SC[i])-K[i+1]*(1-SC[i+1])) for i in range (Na,24)):0 -
Hi Hooman,
Sorry, it is still not clear to me exactly how to reproduce the error. The code you posted does not run by itself, since there is spacing in Python variable names, trailing colons at the end of lines, and many variable definitions are missing. I am guessing that somewhere you are using a variable to index another variable, which won't work.
Also, constraints 6 and 7 don't quite make sense. For example, constraint 6:
m.addConstrs(SC[i]==sum(x[i] * i for i in range(100)))
is equivalent to:
$$\begin{align*} SC_i = \sum_{i = 1}^{100} i \cdot x_i \end{align*}$$
The \( i \) on the left-hand side is not defined, because \( i \) is the index for the right-hand side summation.
Finally, you cannot use the built-in Python \( \texttt{abs} \) function in constraint 8. You will have to replace this with a general absolute value constraint (see Model.addGenConstrAbs()).
Thanks,
Eli
0 -
Dear Eli,
Your comment was very helpful. I changed my code and modified the typos of the below code. The error was resolved. However, now constraints 4-7 have made the problem infeasible. Even if I remove the constraints 5,6,7, then constraint 4 alone makes the problem infeasible. I wonder if there is any problem with these constraints that causes this issue.
Thanks#Parameters:
# Generating all the possible values of SC
Ks=[((1/1-(s/100))*(1-(0.4)**(((1-(s/100))**0.575)/374))) for s in range (0,100)]
#Variables:
SE= m.addVars(24,name="SE")
SC= m.addVars(24,name="SC")
DE= m.addVars(24,name="DE")
K= m.addVars(24,name="K")
x= m.addVars(100,vtype=GRB.BINARY,name="x")
# Constraints :
# A is a constant, Na is a constant
constraint1=m.addConstr(SE[Na]==A)
# CE is a constant, Pc and Pd are other decision variable which are generated and constrained in another parts of the code.
constraint2=m.addConstrs(SE[i] == SE[i-1]+(CE*Pc[i])-Pd[i] for i in range(Na+1,24)):
# SEmax is a constant
constraint3=m.addConstrs(SC[i]==SE[i]/SEmax for i in range (0,24))
constraint4=m.addConstr((sum(x[i]) for i in range(0,100))==1)
constraint5=m.addConstrs(SC[j]==sum(x[i] * i for i in range(100)) for j in range (0,24))
# Ks: Generated in the parameters
constraint6=m.addConstrs(K[j]==sum(x[i]*Ks[i] for i in range(100))for j in range (0,24))
# SEmax is a constant, DE is used in the objective function.
constraint7=m.addConstrs(DE[i]==SEmax*(K[i]*(1-SC[i])-K[i+1]*(1-SC[i+1])) for i in range (Na,23))0 -
Hi Hooman,
It looks like the parentheses on \( \texttt{constraint4} \) are not placed correctly. The \( \texttt{for} \) loop should be inside of the \( \texttt{sum} \) function. You can write this constraint as:
m.addConstr(sum(x[i] for i in range(100)) == 1)
Or better yet:
m.addConstr(x.sum() == 1)
Thanks,
Eli
0 -
Thank you Eli, it was modified. Now, constraints 5,6,7 cause the infeasibility.
0 -
Hi Hooman,
You can try to compute an irreducible inconsistent subsystem with Model.computeIIS(). This is a subsystem of constraints/bounds that together is infeasible, but is feasible if any one of the constraints/bounds in the subsystem is removed. E.g.:
m.computeIIS()
m.write('model.ilp')You can visually inspect the .ilp file to identify which constraints are contributing to the infeasibility.
If you are trying to model a piecewise-linear function, it may be easier to use the Model.addGenConstrPWL() method than manually constructing the piecewise-linear constraints.
Thanks,
Eli
0 -
Dear Eli,
I found the problem using the method you suggested. The problem is that SE and consequently SC take float values. While on the right-hand side of constraint5, it only takes integer values. I tried to introduce another constraint similar to below "constraintX" to turn SC to integer and use the integer value on constraint5, but Gurobi does not allow me saying:int() argument must be a string, a bytes-like object or a number, not 'Var'
constraintX=m.addConstrs(SC_int[i]==int(SC[i]) for i in range (0,24))
Do you have any suggestion for this issue?
Thank you0 -
Hi Hooman,
In general, it's okay to set a continuous expression equal to an integer-valued expression. This would just force the continuous expression to take on an integer value at a feasible solution.
You can't use arbitrary Python functions like \( \texttt{int()} \) in your constraints. Instead, you will have to handle this logic within the mathematical modeling framework. If you want the \( \texttt{SC} \) variables to be integer-valued, you can use \( \texttt{vtype=GRB.INTEGER} \) in Model.addVars().
However, should not resolve the infeasibility. You would only be changing the \( \texttt{SC} \) variables to be integers. This further restricts the feasible region of an already infeasible model, so the model will remain infeasible.
What were the contents of the .ilp file that you generated?
Eli
0 -
Hello Eli,
Here is the content of my .ilp file. Obviously, SC[11] is a decimal value and it cannot satisfy R423. It is also not possible to relax SE[11]. At most I can change the value of SE[11] which will not help. Even if I change the structure of the whole problem in such a way that SE is obtained as integer value, once it is multiplied by a decimal factor (as in R398), the result will be decimal.
P.S: At this point I am not sure if this method of using (x[i]*i) is proper for this particular problem. Maybe I should linearize Ks and incorporate it as a separate constraint. What do you think?Subject To
R219: SE[11] = 11
R398: - 0.0454545454545455 SE[11] + SC[11] = 0
R423: SC[11] - x[1] - 2 x[2] - 3 x[3] - 4 x[4] - 5 x[5] - 6 x[6]
- 7 x[7] - 8 x[8] - 9 x[9] - 10 x[10] - 11 x[11] - 12 x[12] - 13 x[13]
- 14 x[14] - 15 x[15] - 16 x[16] - 17 x[17] - 18 x[18] - 19 x[19]
- 20 x[20] - 21 x[21] - 22 x[22] - 23 x[23] - 24 x[24] - 25 x[25]
- 26 x[26] - 27 x[27] - 28 x[28] - 29 x[29] - 30 x[30] - 31 x[31]
- 32 x[32] - 33 x[33] - 34 x[34] - 35 x[35] - 36 x[36] - 37 x[37]
- 38 x[38] - 39 x[39] - 40 x[40] - 41 x[41] - 42 x[42] - 43 x[43]
- 44 x[44] - 45 x[45] - 46 x[46] - 47 x[47] - 48 x[48] - 49 x[49]
- 50 x[50] - 51 x[51] - 52 x[52] - 53 x[53] - 54 x[54] - 55 x[55]
- 56 x[56] - 57 x[57] - 58 x[58] - 59 x[59] - 60 x[60] - 61 x[61]
- 62 x[62] - 63 x[63] - 64 x[64] - 65 x[65] - 66 x[66] - 67 x[67]
- 68 x[68] - 69 x[69] - 70 x[70] - 71 x[71] - 72 x[72] - 73 x[73]
- 74 x[74] - 75 x[75] - 76 x[76] - 77 x[77] - 78 x[78] - 79 x[79]
- 80 x[80] - 81 x[81] - 82 x[82] - 83 x[83] - 84 x[84] - 85 x[85]
- 86 x[86] - 87 x[87] - 88 x[88] - 89 x[89] - 90 x[90] - 91 x[91]
- 92 x[92] - 93 x[93] - 94 x[94] - 95 x[95] - 96 x[96] - 97 x[97]
- 98 x[98] - 99 x[99] = 0
Bounds
SE[11] free
SC[11] free
Binaries
x[1] x[2] x[3] x[4] x[5] x[6] x[7] x[8] x[9] x[10] x[11] x[12] x[13] x[14]
x[15] x[16] x[17] x[18] x[19] x[20] x[21] x[22] x[23] x[24] x[25] x[26]
x[27] x[28] x[29] x[30] x[31] x[32] x[33] x[34] x[35] x[36] x[37] x[38]
x[39] x[40] x[41] x[42] x[43] x[44] x[45] x[46] x[47] x[48] x[49] x[50]
x[51] x[52] x[53] x[54] x[55] x[56] x[57] x[58] x[59] x[60] x[61] x[62]
x[63] x[64] x[65] x[66] x[67] x[68] x[69] x[70] x[71] x[72] x[73] x[74]
x[75] x[76] x[77] x[78] x[79] x[80] x[81] x[82] x[83] x[84] x[85] x[86]
x[87] x[88] x[89] x[90] x[91] x[92] x[93] x[94] x[95] x[96] x[97] x[98]
x[99]
End
0 -
Hi Hooman,
I'm not entirely sure what each of these constraints is trying to do, but you're right that the current constraints don't make sense together. Is there a mathematical formulation you are following? Like Greg suggested, it's much easier to work through problems like this if you take a step back and write down the mathematical formulation first.
Are you adding these constraints to handle some nonlinearity in the model? If so, have you looked at Model.addGenConstrPWL()? This is a helper function for adding piecewise-linear constraints to your model.
Eli
0
Please sign in to leave a comment.
Comments
17 comments