Skip to main content

Using a for loop for a single or specific value in variable list in constraint formulation

Answered

Comments

210 comments

  • Jaromił Najman
    • Gurobi Staff

    When you loop over a dictionary such as \(\texttt{group2tasks}\) via, e.g., \(\texttt{for task in group2tasks}\) then \(\texttt{tasks}\) will attain the key values of the dictionary and not its actual item values. You can add an additional \(\texttt{for}\)-loop to actually go over the dictionary items which are lists.

    for key in group2tasks:
      Taskexecution1=steel.addConstrs(
                     (gp.quicksum(Tasks[task,t] for t in time ) ==1 
                     for task in group2tasks[key]),name="Taskexecution1")

    I would recommend to have a look at some Python tutorials to better understand how basic Python data structures work which would help you avoid such issues. I fully understand that working with Gurobi for the first time can be overwhelming (I have been there myself). This is the reason why understanding the programming language behavior as good as possible is a tremendous help.

    0
  • Margi Shah
    • Gurobi-versary
    • Thought Leader
    • Curious

    Hi Jaromil, you are probably telling the truth .I respect that. This is definitely an overwhelming experience. 

    I have tried to look Gurobi learning materials from the website too.. Apart from examples do you recommend any other materials?

    "When you loop over a dictionary such as group2tasks via, e.g., for task in group2tasks then tasks will attain the key values of the dictionary and not its actual item values. You can add an additional for-loop to actually go over the dictionary items which are lists." - I got this point. 

    We shall now move to another issue.

     

    0
  • Jaromił Najman
    • Gurobi Staff

    Apart from examples do you recommend any other materials?

    Python I: Introduction to Modeling with Python - Gurobi. This is your best place to start.  It includes a video tutorial and examples with jupyter notebooks for you to follow.  It also includes an example of using nested summations.

     

    0
  • Margi Shah
    • Gurobi-versary
    • Thought Leader
    • Curious

    Many thanks Jaromil for your reply:

    Constraint:

    What is formulated is:

    res = res_cat2idx['EN'][0]
    Energyusage = {}
    for ti in range(int(num_t)):
        
        sumexpression = gp.LinExpr(0)
        for task_cat, task_list1 in tasks.items():
            if 'TR' in task_cat:  # transportation has no energy consumption
                        continue
            for task in task_list1:
                duration = task_duration[task]
                for theta in range(0, min(duration, ti) + 1):
                    sumexpression.add(rtn_profile[res][task][theta]* Tasks[task,ti-theta] )
        Energyusage[res,ti] = steel.addConstr(Resources[res,ti] ==sumexpression,name="Energyusage[%s,%d]"%(res,ti)) 

    What is the OUTPUT (WRONG):

    Energyusage[174,0]: Resources[174,0] - 21.25 Tasks[1,0] - 21.25 Tasks[2,0]
       - 21.25 Tasks[3,0] - 21.25 Tasks[4,0] - 21.25 Tasks[5,0]
       - 21.25 Tasks[6,0] - 21.25 Tasks[7,0] - 21.25 Tasks[8,0]
       - 21.25 Tasks[9,0] - 21.25 Tasks[10,0] - 21.25 Tasks[11,0]
       - 21.25 Tasks[12,0] - 21.25 Tasks[13,0] - 21.25 Tasks[14,0]
       - 21.25 Tasks[15,0] - 21.25 Tasks[16,0] - 21.25 Tasks[17,0]
       - 21.25 Tasks[18,0] - 21.25 Tasks[19,0] - 21.25 Tasks[20,0]
       - 21.25 Tasks[21,0] - 21.25 Tasks[22,0] - 21.25 Tasks[23,0]
       - 21.25 Tasks[24,0] - 0.5 Tasks[49,0]........
    Energyusage[174,1]: Resources[174,1] - 21.25 Tasks[1,0] - 21.25 Tasks[1,1]
       - 21.25 Tasks[2,0] - 21.25 Tasks[2,1] - 21.25 Tasks[3,0]
       - 21.25 Tasks[3,1] - 21.25 Tasks[4,0] - 21.25 Tasks[4,1]
       - 21.25 Tasks[5,0] - 21.25 Tasks[5,1] - 21.25 Tasks[6,0]
       - 21.25 Tasks[6,1] - 21.25 Tasks[7,0] - 21.25 Tasks[7,1]
       - 21.25 Tasks[8,0] - 21.25 Tasks[8,1] - 21.25 Tasks[9,0]
       - 21.25 Tasks[9,1] - 21.25 Tasks[10,0] - 21.25 Tasks[10,1]
       - 21.25 Tasks[11,0] - 21.25 Tasks[11,1] - 21.25 Tasks[12,0]
       - 21.25 Tasks[12,1] - 21.25 Tasks[13,0] - 21.25 Tasks[13,1]
       - 21.25 Tasks[14,0] - 21.25 Tasks[14,1] - 21.25 Tasks[15,0].......

    It should look like:

    Energyusage[174,0]:  21.25 Tasks[1,0] + 21.25 Tasks[2,0]
     + 21.25 Tasks[3,0] + 21.25 Tasks[4,0] + 21.25 Tasks[5,0]
     + 21.25 Tasks[6,0] + 21.25 Tasks[7,0] + 21.25 Tasks[8,0]
     + 21.25 Tasks[9,0] + 21.25 Tasks[10,0] + 21.25 Tasks[11,0]
    .................

    Energyusage[174,1]: 21.25 Tasks[1,1] + 21.25 Tasks[2,1]
    + 21.25 Tasks[3,1] + 21.25 Tasks[4,1] + 21.25 Tasks[5,1]
    + 21.25 Tasks[6,1] + 21.25 Tasks[7,1] + 21.25 Tasks[8,1]
    + 21.25 Tasks[9,1] + 21.25 Tasks[10,1] + 21.25 Tasks[11,1]
    .................

    I am not sure about some of the wrong mathematical signs appearing here 

    Energyusage[174,1]: Resources[174,1] - 21.25 Tasks[1,0] - 21.25 Tasks[1,1]
       - 21.25 Tasks[2,0] - 21.25 Tasks[2,1] - 21.25 Tasks[3,0]

     

    0
  • Jaromił Najman
    • Gurobi Staff

    The output is correct, you have to carefully look at the whole constraint which reads

    Energyusage[174,0]: Resources[174,0] - 21.25 Tasks[1,0] - ... = 0

    This is equivalent to

    Energyusage[174,0]: Resources[174,0] = 21.25 Tasks[1,0] + ...

    Gurobi always moves all variable terms to the left hand side and all constant values to the right hand side in an LP file.

    0
  • Margi Shah
    • Gurobi-versary
    • Thought Leader
    • Curious

    Hi Jaromil, 

    You are right. The terms are stated left side.

    But there is a problem with variables of time.

    THE OUTPUT LOOKS LIKE THIS:

    Energyusage[174,1]: Resources[174,1] - 21.25 Tasks[1,0] - 21.25 Tasks[1,1]
       - 21.25 Tasks[2,0] - 21.25 Tasks[2,1] - 21.25 Tasks[3,0]
       - 21.25 Tasks[3,1] - 21.25 Tasks[4,0] - 21.25 Tasks[4,1]
       - 21.25 Tasks[5,0] - 21.25 Tasks[5,1] - 21.25 Tasks[6,0]
       - 21.25 Tasks[6,1] - 21.25 Tasks[7,0] - 21.25 Tasks[7,1]

    IT SHOULD BE:

    Energyusage[174,1]
    : Resources[174,1] - 21.25 Tasks[1,1]
       - 21.25 Tasks[2,1] - 21.25 Tasks[3,1]
      - 21.25 Tasks[4,1] - 21.25 Tasks[5,1] ...........


    0
  • Jaromił Najman
    • Gurobi Staff

    Please double check your code first to avoid those simple mistakes.

    You want to fix the \(\texttt{ti}\) value for this constraint. However you sum over \(\texttt{Tasks[task,ti-theta]}\) when it should be

    sumexpression.add(rtn_profile[res][task][theta]* Tasks[task,ti])

     

    0
  • Margi Shah
    • Gurobi-versary
    • Thought Leader
    • Curious

    Hi Jaromil,

    Give me sometime. Let me analyse the solution.

    0
  • Margi Shah
    • Gurobi-versary
    • Thought Leader
    • Curious

    Hi Jaromil, I am facing some issue with the below constraint:

    Constraint:

    End Resources:

    res_list3 = [res for cat, cat_res in res_cat2idx.items() if cat == 'H_B_S4' for res in cat_res]
    Endresources=steel.addConstr((gp.quicksum(Resources[res,time[95]] for res in res_list3)==1 ),name="Endresources_time[95]") 

    OUTPUT:

    Either it should be:

    Endresources_time[95]= Resources[150,95] =1

                         Resources[151,95]=1

                        Resources[152,95]=1..........Resources[173,95]=1

    0
  • Margi Shah
    • Gurobi-versary
    • Thought Leader
    • Curious
    Resourcebalance = {}
    for res in res_list1:
        for t in time:
    Is it possible to have a specific set of values for t=0 case? here in this loop?
    Like I want:

    Resourcebalance[1,0]=2,
    Resourcebalance[2,0]=2,
    Resourcebalance[3,0]=2,
    Resourcebalance[4,0]=2,
    Resourcebalance[5,0]=2,
    Resourcebalance[(6-174),0]=0

    Is it possible to have so here?


            sumexpression = gp.LinExpr(0)
            for task in task_list:
                if task not in rtn_profile[res]:
                    continue
                duration =  len(rtn_profile[res][task]) - 1
                for theta in range(0, min(duration, t) + 1):
                    sumexpression.add(rtn_profile[res][task][theta]* Tasks[task,t-theta] )
            Resourcebalance[res,t] = steel.addConstr(Resources[res,t] == Resources[res,time[time.index(t)-1]] + sumexpression, name="Resourcebalane[%s,%d]"%(res,t))

     

     

    0
  • Jaromił Najman
    • Gurobi Staff

    Hi Margi,

    Regarding the \(\texttt{Endresources}\) constraint, you should really try to start analyzing such issues on your own. This issue is the same as with your \(\texttt{Transfertime}\), so we discussed this already.

    You can see that currently your \(\texttt{Endresources}\) constraints contain a sum, so you have to remove the quicksum. For naming, please see the discussion on \(\texttt{Transfertime}\).

    Endresources=steel.addConstr((Resources[res,time[95]] ==1 ) for res in res_list3, name="Endresources_time[95]")

     

    0
  • Jaromił Najman
    • Gurobi Staff
    Is it possible to have a specific set of values for t=0 case? here in this loop?

    Yes, it is possible. You can use \(\texttt{if}\)-statements the same way as you are already using it in \(\texttt{if task not in rtn_profile[res]}\)

    for res in res_list1:
        for t in time:
    if t == 0:
    if 1 <= res and res <= 5:
                Resourcebalance[res,t] = steel.addConstr(Resources[res,t] == 2, name="Resourcebalane[%s,%d]"%(res,t))
    else:
                   Resourcebalance[res,t] = steel.addConstr(Resources[res,t] == 0, name="Resourcebalane[%s,%d]"%(res,t))
    else:
    sumexpression = gp.LinExpr(0)
          for task in task_list:
              if task not in rtn_profile[res]:
                  continue
              duration =  len(rtn_profile[res][task]) - 1
              for theta in range(0, min(duration, t) + 1):
                  sumexpression.add(rtn_profile[res][task][theta]* Tasks[task,t-theta] )
          Resourcebalance[res,t] = steel.addConstr(Resources[res,t] == Resources[res,time[time.index(t)-1]] + sumexpression, name="Resourcebalane[%s,%d]"%(res,t))
     
     
    0
  • Margi Shah
    • Gurobi-versary
    • Thought Leader
    • Curious

    Hi Jaromil, 

    I tried doing this before posting it here, but I was having the same error as now:

    0
  • Jaromił Najman
    • Gurobi Staff

    As the error states the object \(\texttt{Resourcebalance}\) is not defined. It looks like you deleted the

    Resourcebalance = {}

    line when copy pasting.

    0
  • Margi Shah
    • Gurobi-versary
    • Thought Leader
    • Curious

    To my knowledge,

    I haven't defined any other constraint as an empty dictionary before.

    Still they works.

    How come here it is stating that it is not defined?

    Also, without doing model.update() after defining variables causes any problem?

     

    0
  • Jaromił Najman
    • Gurobi Staff

    I haven't defined any other constraint as an empty dictionary before.

    Still they works.

    How come here it is stating that it is not defined?

    In this case, you are filling the \(\texttt{Resourcebalance}\) dictionary by hand. In other cases, you are using the addConstrs method, which returns a dictionary so you don't have to pre-define it.

    Also, without doing model.update() after defining variables causes any problem?

    No, this is not a problem as long as you don't want to access any variable attributes such as, e.g., variable names.

    0
  • Margi Shah
    • Gurobi-versary
    • Thought Leader
    • Curious

    Ok Jaromil,

    Also can we use two quicksum in an objective function like below?

    I doubt doing so.

    reslist2=[]
    reslist2.append(res_cat2idx['EN'][0])

    obj=gp.quicksum(price_energy[t] for t in time)*gp.quicksum(Resources[res,t] for res in reslist2 for t in time)
    i.e for t=0:

    obj = Resources[res,0]*price_energy[0]

    ...........
    0
  • Jaromił Najman
    • Gurobi Staff

    In the objective you have written, is the energy price an optimization variables or are these constant values?

    Do you actually mean to construct an objective like

    \[\begin{align*}
    \sum_t \sum_{res} eprice_t \cdot \pi_{res,t}
    \end{align*}\]

    0
  • Margi Shah
    • Gurobi-versary
    • Thought Leader
    • Curious

     

    Price_energy = list(of 96 values for each t) =  
    [33, 33, 33, 33, 30, 30, 30, 30, 29, 29, 29, 29, 28, 28, 28, 28, 34, 34, 34, 34, 50, 50, 50, 50, 71, 71, 71, 71, 77, 77, 77, 77, 81, 81, 81, 81, 87, 87, 87, 87, 92, 92, 92, 92, 94, 94, 94, 94, 92, 92, 92, 92, 90, 90, 90, 90, 90, 90, 90, 90, 87, 87, 87, 87, 85, 85, 85, 85, 79, 79, 79, 79, 79, 79, 79, 79, 77, 77, 77, 77, 76, 76, 76, 76, 65, 65, 65, 65, 53, 53, 53, 53, 34, 34, 34, 34]

    res has only one value.
    Resources are optimization variables.

    Yes thats how objective function will look like ,
    0
  • Jaromił Najman
    • Gurobi Staff

    For the objective function you showed

    \[\begin{align*}
    \sum_t eprice_t \cdot \sum_t \pi_{res,t}
    \end{align*}\]

    your code

    price_energy = [...]
    obj=gp.quicksum(price_energy[t] for t in time)*gp.quicksum(Resources[res,t] for res in reslist2 for t in time)

    will work.

    But I really doubt that you actually want to model this objective function, because this will multiply every \(\texttt{Resources[174,t]}\) with the sum over all \(\texttt{Price_energy}\) entries, which is a quite uncommon modeling approach.

    My guess is that you would like to model the objective function

    \[\begin{align*}
    \sum_t (eprice_t \cdot \pi_{res,t})
    \end{align*}\]

    which is implemented via

    reslist2=[]
    reslist2.append(res_cat2idx['EN'][0])
    price_energy = [...]

    obj=gp.quicksum(price_energy[t]*Resources[res,t] for res in reslist2 for t in time)
    0
  • Margi Shah
    • Gurobi-versary
    • Thought Leader
    • Curious

    Ok Jaromil, I got your point.

    With all your understandings, I checked by writing.lp files after my each constraint.It showed me correct formulations.

    Now after optimising it, it is showing me infeasible. How can it be possible?

    Then I did below:

    How do I resolve this?

     

    0
  • Jaromił Najman
    • Gurobi Staff

    After you computed the IIS via steel.computeIIS(), you can write the IIS model to a file via

    steel.write("steelIIS.ilp")

    which will generate a file called \(\texttt{steelIIS.ilp}\). This file will hold 2 constraints which together make the model infeasible. This means that removing one of the 2 constraints in this file will make the model feasible. This file should give you an idea of what went wrong during model formulation. For more information see How do I determine why my model is infeasible? and the documentation of the computeIIS method.

    0
  • Margi Shah
    • Gurobi-versary
    • Thought Leader
    • Curious

    Can you explain me what the below .lp file means to say?

    \ Model steel RTN_copy
    \ LP format - for model browsing. Use MPS format to capture full model detail.
    Minimize
     
    Subject To
     Transfertime[126,95]: Resources[126,95] = 0
     Endresources_time[95][126]: Resources[126,95] = 1
    Bounds
     Resources[126,95] free
    Generals
     Resources[126,95]
    End
    0
  • Jaromił Najman
    • Gurobi Staff

    The file means, that in your model, you simultaneously have the constraints

     Transfertime[126,95]: Resources[126,95] = 0
     Endresources_time[95][126]: Resources[126,95] = 1

    which obviously cannot both be true at the same time resulting in an infeasible model.

    You can search for those constraints in your \(\texttt{steel.lp}\) file and you will find those constraints there.

    0
  • Margi Shah
    • Gurobi-versary
    • Thought Leader
    • Curious

    Gurobi has this nice feature of analyzing things.

    I understood why this is happening.

    I am trying to resolve it.

     

    [res_cat2idx, res_num] = [OrderedDict([('EAF', [1]),
                  ('AOD', [2]),
                  ('LF', [3]),
                  ('CC1', [4]),
                  ('CC2', [5]),
                  ('H_A_S1',
                   [6,
                    7,
                    8,
                    9,
                    10,
                    11,
                    12,
                    13,
                    14,
                    15,
                    16,
                    17,
                    18,
                    19,
                    20,
                    21,
                    22,
                    23,
                    24,
                    25,
                    26,
                    27,
                    28,
                    29]),
                  ('H_A_S2',
                   [30,
                    31,
                    32,
                    33,
                    34,
                    35,
                    36,
                    37,
                    38,
                    39,
                    40,
                    41,
                    42,
                    43,
                    44,
                    45,
                    46,
                    47,
                    48,
                    49,
                    50,
                    51,
                    52,
                    53]),
                  ('H_B_S2',
                   [54,
                    55,
                    56,
                    57,
                    58,
                    59,
                    60,
                    61,
                    62,
                    63,
                    64,
                    65,
                    66,
                    67,
                    68,
                    69,
                    70,
                    71,
                    72,
                    73,
                    74,
                    75,
                    76,
                    77]),
                  ('H_A_S3',
                   [78,
                    79,
                    80,
                    81,
                    82,
                    83,
                    84,
                    85,
                    86,
                    87,
                    88,
                    89,
                    90,
                    91,
                    92,
                    93,
                    94,
                    95,
                    96,
                    97,
                    98,
                    99,
                    100,
                    101]),
                  ('H_B_S3',
                   [102,
                    103,
                    104,
                    105,
                    106,
                    107,
                    108,
                    109,
                    110,
                    111,
                    112,
                    113,
                    114,
                    115,
                    116,
                    117,
                    118,
                    119,
                    120,
                    121,
                    122,
                    123,
                    124,
                    125]),
                  ('H_A_S4',
                   [126,
                    127,
                    128,
                    129,
                    130,
                    131,
                    132,
                    133,
                    134,
                    135,
                    136,
                    137,
                    138,
                    139,
                    140,
                    141,
                    142,
                    143,
                    144,
                    145,
                    146,
                    147,
                    148,
                    149]),
                  ('H_B_S4',
                   [150,
                    151,
                    152,
                    153,
                    154,
                    155,
                    156,
                    157,
                    158,
                    159,
                    160,
                    161,
                    162,
                    163,
                    164,
                    165,
                    166,
                    167,
                    168,
                    169,
                    170,
                    171,
                    172,
                    173]),
                  ('EN', [174])]),
     174]
    y={}
    for res_cat, resources in res_cat2idx.items():
            if 'H_A_' not in res_cat:
                continue
           y[res_cat]= list(resources)

    Instead I am trying :

    for res_cat, resources in res_cat2idx.items():
          if 'H_A_S1'and'H_A_S2'and 'H_A_S3' not in res_cat:
                continue
            print(res_cat)
            y[res_cat]= list(resources)

    As I don't want 'H_A_S4'[THIS IS NOT WORKING]

    for key in y:
     y_list = y[key]
     Transfertime=steel.addConstrs((Resources[res,t]  == 0 for res in y_list for t in time),name ="Transfertime")
    0
  • Jaromił Najman
    • Gurobi Staff

    If you want to not skip \(\texttt{H_A_SX}\) except for \(\texttt{H_A_S4}\), you could use

    if 'H_A_S' not in res_cat or 'H_A_S4' in res_cat:
    continue
    0
  • Margi Shah
    • Gurobi-versary
    • Thought Leader
    • Curious

    Hi Jaromil,

    I made sure my constraints are not violated.

    But there is something unusual happening here. There is an objective function value & still it shows model is infeasible. Can you please tell what is happening?

    I searched equivalent literature on Gurobi website, but unable to get the required information.

     

    0
  • Jaromił Najman
    • Gurobi Staff

    There is an objective function value & still it shows model is infeasible. Can you please tell what is happening?

    It is not the objective value. It is the best lower bound that can be proven. Feasible points are listed in the "Incumbent" column.

    For good books about how Gurobi works, in particular how mixed integer programming works, I recommend having a look at our resources, mip basics, and our MIP tutorials.

    0
  • Margi Shah
    • Gurobi-versary
    • Thought Leader
    • Curious

    "It is not the objective value. It is the best lower bound that can be proven. Feasible points are listed in the "Incumbent" column" -

    What is incumbent column?

    I looked though the basics but here as the process is still going on, I am not able to find what error has caused this.

    As my constraints are also not violated, How can I try fixing this?

     

    0
  • Jaromił Najman
    • Gurobi Staff

    What is incumbent column?

    The incumbent column shows the currently best feasible point found. In your case, there is no feasible point found, thus Gurobi prints a "-", see Gurobi MIP logging, and your model is declared infeasible.

    As my constraints are also not violated, How can I try fixing this?

    You can wait for Gurobi to compute an IIS as you did before. This can take quite some time. Otherwise, you can try removing some constraints by hand to check whether the model still remains infeasible. You could also try a feasrelax approach as described in How do I determine why my model is infeasible?

    To make the process easier for you, you should try decreasing the size of your model. You should test the model with less time steps and less data. Debugging such a big model is not practicable.

    0

Post is closed for comments.