Skip to main content

Variable as an index of a dictionary

Answered

Comments

8 comments

  • Jaromił Najman
    Gurobi Staff Gurobi Staff

    Hi Ana,

    Since variable names are unique, you can use the variable's name as a dictionary key. This means that you could build and access your dictionary via

    dict['b'][var1.VarName]

    You will have to execute the update() function once after all variables have been added to ensure that you have access to updated variable attributes.

    Best regards,
    Jaromił

    0
  • Ana Guasque Ortega
    Gurobi-versary
    Investigator
    Conversationalist

    Many thanks for your response, Jaromil.

    Could I query the values of the attributes before the optimization is complete? I have tried to see (only for checking how it works) the name of the variables:

    for v in m.getVars():
         print('%s' % (v.varName)) but I don't get anything.

    If var1 depends on i,j,k, should I write var1[i,j,k].VarName ?? I have tried for example with "var1[0,0,0].VarName" but I get AttributeError: Index out of range for attribute 'VarName'

     

    Thanks again.

    0
  • Jaromił Najman
    Gurobi Staff Gurobi Staff

    Hi Ana,

    Yes, you can access the attribute VarName before an optimization has been performed. Just make sure that you execute the update() function after adding the variables.

    An example code would be

    import gurobipy as gp
    from gurobipy import GRB

    m = gp.Model("test")
    I = [0,1,2]
    J = [3,4,5]
    K = [6,7,8]
    vars = m.addVars(I,J,K,vtype=GRB.BINARY,name="v")
    m.update()

    # print names using the vars tupledict returned by addVars
    for i in I:
    for j in J:
    for k in K:
    print('%s' % (vars[i,j,k].varName))

    # print names using the list returned by getVars
    for v in m.getVars():
    print('%s' % (v.varName))

    Note that the getVars function returns a one dimensional list while the addVars function returns a Gurobi tupledict. That's why the accessing of the VarName attribute is different.

    Best regards,
    Jaromił

    0
  • Ana Guasque Ortega
    Gurobi-versary
    Investigator
    Conversationalist

    Hi again, Jaromil!

    Many thanks, it worked. 

    However, it does not solve my problem. Maybe I did not explain it well. What I want is to find the value of the variable. Imagine this:

    dict={'a':[12,24,36], 'b':[10,20,30,40]...} 

    m.addConstrs((dict['b'][var1] == var2[i] for i in I)  , "c1")

    For example, if the value of var1 is equal to 2, then dict['b'][var1] =var2=30. So what I want is to work with the value of the variable, not the name. And this is the error I get when I put directly the variable: TypeError: list indices must be integers or slices, not Var.

    I think that the problem is that I should I new variables as in https://support.gurobi.com/hc/en-us/community/posts/360071776111-use-a-decision-variable-as-an-index-?input_string=Variable%20as%20an%20index%20of%20a%20dictionary, but I don't know how to do it.

    Many thanks again.

    0
  • Jaromił Najman
    Gurobi Staff Gurobi Staff

    Hi Ana,

    Thank you for clarifying. Now I understand the issue.

    I think that the problem is that I should I new variables as in https://support.gurobi.com/hc/en-us/community/posts/360071776111-use-a-decision-variable-as-an-index-?input_string=Variable%20as%20an%20index%20of%20a%20dictionary, but I don't know how to do it.

    Yes, you will have to introduce additional variables and constraints in order to model this relationship.

    In you specific case, it seems like the values \(\texttt{dict['a'][var1]}\) are always multiples of integer values, e.g., the values of \(\texttt{dict['a']}\) are integer multiples of \(12\). In the following, for simplicity, I will assume that your \(\texttt{dict}\) only consists of

    dict={'a':[12,24,36], 'b':[10,20,30,40]}

    You could model the above as following:

    \[\begin{align}
    \sum_{i \in \{a,b\}} b_i &= 1\\
    v_a &\leq 3 b_a \\
    v_b &\leq 4 b_b \\
    v_2 &= 12 v_a + 10 v_b\\
    v_a &\in \{0,1,2,3\}\\
    v_b &\in \{0,1,2,3,4\}\\
    b_a,b_b &\in \{0,1\}
    \end{align}\]

    • You add binary variables \(b_a,b_b,\dots\) which are 1 when the first index of the dictionary equals the specific character and 0 otherwise. So \(b_a=1\) would mean that you are interested in the values of \(\texttt{dict['a']}\).
    • The sum over \(b_i\) constraint makes sure that you only choose exactly one dict entry.
    • You then add integer variables \(v_a,v_b,\dots\) which are only \(>0\) if the corresponding \(b_i=1\).
    • The value of \(v_2\) is then given as the sum over all \(v_i\) with appropriate coefficients.

    Best regards,
    Jaromił

    0
  • Ana Guasque Ortega
    Gurobi-versary
    Investigator
    Conversationalist

    Many many thanks, Jaromil!

    I get the point, I think I can do it. But, what if the values are not following any sequence? How to obtain the value of v2 in that case? for example:

    dict={'a':[1,1,2,2,1,1], 'b':[1,2,3,5,6]}
    0
  • Jaromił Najman
    Gurobi Staff Gurobi Staff

    Hi Ana,

    Modeling without any specific sequence of values makes the formulation a bit more complex so it is always better to use all knowledge given. Anyway, for the case where the values of \(\texttt{dict['a']}\) and \(\texttt{dict['b']}\) do not follow any sequence, you have to introduce a binary variable for every value. In the specific example

    dict={'a':[1,1,2,2,1,1], 'b':[1,2,3,5,6]}

    you would need 11 additional binary variables. Let's assume that the values in the lists are given as constants \(A_i, B_i\), i.e., \(A_0 = 1, B_4 = 6\).

    One possibility to model your problem would then be

    \[\begin{align}
    \sum_{i \in \{a,b\}} b_i &= 1\\
    \sum_{i \in \{0,\dots,5\}} b_{a,i} &=  b_a \\
    \sum_{j \in \{0,\dots,4\}} b_{b,j} &= b_b \\
    \sum_{i \in \{0,\dots,5\}} A_i b_{a,i} + \sum_{j \in \{0,\dots,4\}} B_j b_{b,j} &= v_2\\
    b_{a,i}, b_{b,j} &\in \{0,1\} \forall i \in \{0,\dots,5\}, j \in \{0,\dots,4\}\\
    b_a,b_b &\in \{0,1\}
    \end{align}\]

    • The first equality is as in my previous message
    • The following two equality constraints force to chose a value from either \(\texttt{dict['a']}\) or \(\texttt{dict['b']}\)
    • The fourth equality then computes the value of \(v_2\) given the constant values \(A_i, B_i\)

    Please note that this is only one possible formulation and there is no guarantee that this is the best one.

    Best regards,
    Jaromił

     

    0
  • Ana Guasque Ortega
    Gurobi-versary
    Investigator
    Conversationalist

    Many thanks, Jaromil, now it is totally understood. 

    Maybe I should consider another way of modelling the problem since each of the lists may have up to 100 values, approximatelly. Maybe it becames such a big problem. 

    Many thanks for all your help. Best, Ana.

    0

Please sign in to leave a comment.