Use index of decision variable in max_ constraint
AnsweredI have a set of decision variables to denote time, \(\texttt{T[n,i,k]}\), and for each \(\texttt{k}\), I want to get the maximum value of all the decision variables irrespective of \(\texttt{n,i}\).
For that, I introduced a new decision variable \(\texttt{V[k]}\) and use the \(\texttt{max_}\) constraint:
for each k in K:
m.addConstrs((V[k] == gp.max_(list(T.select('*','*',k)))),"Max_value")
Thus far it seems straightforward, and I get the constraint as desired.
The issue is that I need to do some follow up computations with \(\texttt{V[k]}\) for each \(\texttt{k}\), and for that I also require the index/value for \(\texttt{i}\) where \(\texttt{T[n,i,k]}\) is maximal.
Is it possible to extract this somehow? Maybe by adding another decision variable? I also looked if I could make the variable with two indices, \(\texttt{U[i,k]}\), but I couldn't figure out how to get the index information from the max_ constraint.
-
Official comment
This post is more than three years old. Some information may not be up to date. For current information, please check the Gurobi Documentation or Knowledge Base. If you need more help, please create a new post in the community forum. Or why not try our AI Gurobot?. -
You are on the right track. Here is one way to do this, though this formulation can certainly be modified a few different ways. I'll assume your index sets are \( N \), \( I \), and \( K \).
First, we introduce a variable \( y_{ik} \) for all \( i \in I \) and \( k \in K\). We set \( y_{ik} \) equal to \( \max_{n \in N} T_{nik} \):
y = m.addVars(I, K, name='y')
m.addConstrs((y[i, k] == gp.max_(T.select('*', i, k)) for i in I for k in K), name='max_value')Then, we add your \( V_k \) variables and set \( V_k \geq \max_{n \in N, i \in I} T_{nik} \) for all \( k \in K \):
V = m.addVars(K, name='V')
m.addConstrs((V[k] >= y[i, k] for i in I for k in K), name='v_con')Next, we introduce binary variables \( u_{ik} \) for all \( i \in I \) and \( k \in K \). For each \( k \), exactly one \( u_{ik} \) is \( 1 \). Additionally, \( u_{ik} \) is equal to \( 1 \) only if \( T_{nik} \) is "maximal" for some \( n \in N \). If multiple indices \( i \in I \) are maximal, then \( u_{ik} \) is \( 1 \) for only one of them.
u = m.addVars(I, K, vtype=gp.GRB.BINARY, name='u')
m.addConstrs((u.sum('*', k) == 1 for k in K), name='sum_to_one')Finally, for all \( i \in I \) and \( k \in K \), we add indicator constraints that set \( y_{ik} \geq V_k \) if \( u_{ik} = 1 \):
m.addConstrs(((u[i, k] == 1) >> (y[i, k] >= V[k]) for i in I for k in K), name='indicator')
Let's see if this formulation makes sense. Consider a fixed \( k \in K \). Let \( i \in I\) satisfy \( u_{ik} = 1 \). The indicator constraint gives us \( y_{ik} \geq V_{k} \). By our other constraints, \( \max_{n \in N} T_{nik} = y_{ik} \leq V_k \). Altogether, this gives us \( u_{ik} = 1 \implies \max_{n \in N} T_{nik} = V_k \), as desired.
Note that we moved the max_ constraints to the new \( y_{ik} \) variables instead of the \( V_k \) variables. We no longer need these constraints on the \( V_k \) variables. To see this, consider a fixed \( k \in K \). By the indicator constraints, there exists \( \hat{i} \in I \) such that \( \max_{n \in N} T_{n\hat{i}k} \geq V_k \). Together with the constraints \( V_k \geq \max_{n \in N} T_{nik} \) for all \( i \in I, \) this implies \( V_k = \max_{n \in N, i \in I} T_{nik} \).
Now, for a fixed \( k \in K \), we can use the expression \( \sum_{i \in I} i u_{ik} \) to obtain an \( i \in I \) satisfying \( \max_{n \in N} T_{nik} = V_k \).
0 -
Hi, I got the same problem but I´m doing it on Python, do you know how can I write this:
T.select('*', i, k)on python?
0 -
The code is written in Python. It assumes \( \texttt{T} \) is a tupledict object (see tupledict.select()), which is the type of object returned by Model.addVars(). For example:
>>> x = m.addVars(3, 4, 5, name='x')
>>> type(x)
<class 'gurobipy.tupledict'>
>>> m.update()
>>> x.select('*', 1, 2)
[<gurobi.Var x[0,1,2]>, <gurobi.Var x[1,1,2]>, <gurobi.Var x[2,1,2]>]0
Post is closed for comments.
Comments
4 comments