Skip to main content

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

Answered

Comments

209 comments

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

    Hi Jaromil,

    I don't have a LP file generated rather I have the code. Do you want me to share the link to it?

    And yes, I will also write how Resource balance constraint should look like. Give me 10 mins.

    0
  • Jaromił Najman
    • Gurobi Staff Gurobi Staff

    I don't have a LP file generated rather I have the code. Do you want me to share the link to it?

    No, this would not help. I think that your description should be enough.

     

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

    Hi Jaromil,

    I have tried to formulate the constraint: I have examined one thing, Wherever Tasks[x,0] takes place, there is an issue. I mean whenever in the formulation if we have Task[x,0], there is an issue.

    I will state below first few constraints:

    Resourcebalance[1,0]: Resources[1,0] = 2

    Resourcebalane[1,1]: - Resources[1,0] + Resources[1,1] + Tasks[1,1]
       + Tasks[2,1] + Tasks[3,1] + Tasks[4,1] + Tasks[5,1] + Tasks[6,1]
       + Tasks[7,1] + Tasks[8,1] + Tasks[9,1] + Tasks[10,1] + Tasks[11,1]
       + Tasks[12,1] + Tasks[13,1] + Tasks[14,1] + Tasks[15,1] + Tasks[16,1]
       + Tasks[17,1] + Tasks[18,1] + Tasks[19,1] + Tasks[20,1] + Tasks[21,1]
       + Tasks[22,1] + Tasks[23,1] + Tasks[24,1] = 0

     Resourcebalane[1,2]: - Resources[1,1] + Resources[1,2] + Tasks[1,2]
       + Tasks[2,2] + Tasks[3,2] + Tasks[4,2] + Tasks[5,2] + Tasks[6,2]
       + Tasks[7,2] + Tasks[8,2] + Tasks[9,2] + Tasks[10,2] + Tasks[11,2]
       + Tasks[12,2] + Tasks[13,2] + Tasks[14,2] + Tasks[15,2] + Tasks[16,2]
       + Tasks[17,2] + Tasks[18,2] + Tasks[19,2] + Tasks[20,2] + Tasks[21,2]
       + Tasks[22,2] + Tasks[23,2] + Tasks[24,2] = 0

     Resourcebalane[1,3]: - Resources[1,2] + Resources[1,3] + Tasks[1,3]
       + Tasks[2,3] + Tasks[3,3] + Tasks[4,3] + Tasks[5,3] + Tasks[6,3]
       + Tasks[7,3] + Tasks[8,3] + Tasks[9,3] + Tasks[10,3] + Tasks[11,3]
       + Tasks[12,3] + Tasks[13,3] + Tasks[14,3] + Tasks[15,3] + Tasks[16,3]
       + Tasks[17,3] + Tasks[18,3] + Tasks[19,3] + Tasks[20,3] + Tasks[21,3]
       + Tasks[22,3] + Tasks[23,3] + Tasks[24,3] = 0

     Resourcebalane[1,4]: - Resources[1,3] + Resources[1,4] + Tasks[1,4]
       + Tasks[2,4] + Tasks[3,4] + Tasks[4,4] + Tasks[5,4] + Tasks[6,4]
       + Tasks[7,4] + Tasks[8,4] + Tasks[9,4] + Tasks[10,4] + Tasks[11,4]
       + Tasks[12,4] + Tasks[13,4] + Tasks[14,4] + Tasks[15,4] + Tasks[16,4]
       + Tasks[17,4] + Tasks[18,4] + Tasks[19,4] + Tasks[20,4] + Tasks[21,4]
       + Tasks[22,4] + Tasks[23,4] + Tasks[24,4] = 0

     Resourcebalane[1,5]: - Resources[1,4] + Resources[1,5] + Tasks[1,5]
       + Tasks[2,5] + Tasks[3,5] + Tasks[4,5] + Tasks[5,5] + Tasks[6,5]
       + Tasks[7,5] + Tasks[8,5] + Tasks[9,5] + Tasks[10,5] + Tasks[11,5]
       + Tasks[12,5] + Tasks[13,5] + Tasks[14,5] + Tasks[15,5] + Tasks[16,5]
       + Tasks[17,5] + Tasks[18,5] + Tasks[19,5] + Tasks[20,5] + Tasks[21,5]
       + Tasks[22,5] + Tasks[23,5] + Tasks[24,5] = 0

     Resourcebalane[1,6]: - Resources[1,5] + Resources[1,6] + Tasks[1,6]
       + Tasks[2,6] + Tasks[3,6] + Tasks[4,6] + Tasks[5,6] + Tasks[6,6]
       + Tasks[7,6] + Tasks[8,6] + Tasks[9,6] + Tasks[10,6] + Tasks[11,6]
       + Tasks[12,6] + Tasks[13,6] + Tasks[14,6] + Tasks[15,6] + Tasks[16,6]
       + Tasks[17,6] + Tasks[18,6] + Tasks[19,6] + Tasks[20,6] + Tasks[21,6]
       + Tasks[22,6] + Tasks[23,6] + Tasks[24,6] = 0

    Wrong Formulation:
     Resourcebalane[1,6]: - Resources[1,5] + Resources[1,6] + Tasks[1,6] -Task[1,0]
     + Tasks[2,6] -Task[2,0]+ Tasks[3,6]-Task[3,0] + Tasks[4,6]-Task[4,0] + Tasks[5,6]-Task[5,0] + Tasks[6,6]-Task[6,0]
     + Tasks[7,6] -Task[7,0]+ Tasks[8,6]-Task[8,0] + Tasks[9,6]-Task[9,0] + Tasks[10,6]-Task[10,0] + Tasks[11,6]-Task[11,0]
     + Tasks[12,6] -Task[12,0]+ Tasks[13,6] -Task[13,0]+ Tasks[14,6]-Task[14,0] + Tasks[15,6]-Task[15,0] + Tasks[16,6]-Task[16,0]
     + Tasks[17,6]-Task[17,0] + Tasks[18,6]-Task[18,0] + Tasks[19,6]-Task[19,0] + Tasks[20,6]-Task[20,0] + Tasks[21,6]-Task[21,0]
     + Tasks[22,6] -Task[22,0]+ Tasks[23,6]-Task[23,0] + Tasks[24,6]-Task[24,0] = 0


     Resourcebalane[1,7]: - Resources[1,6] + Resources[1,7] - Tasks[1,1]
       + Tasks[1,7] - Tasks[2,1] + Tasks[2,7] - Tasks[3,1] + Tasks[3,7]
       - Tasks[4,1] + Tasks[4,7] - Tasks[5,1] + Tasks[5,7] - Tasks[6,1]
       + Tasks[6,7] - Tasks[7,1] + Tasks[7,7] - Tasks[8,1] + Tasks[8,7]
       - Tasks[9,1] + Tasks[9,7] - Tasks[10,1] + Tasks[10,7] - Tasks[11,1]
       + Tasks[11,7] - Tasks[12,1] + Tasks[12,7] - Tasks[13,1] + Tasks[13,7]
       - Tasks[14,1] + Tasks[14,7] - Tasks[15,1] + Tasks[15,7] - Tasks[16,1]
       + Tasks[16,7] - Tasks[17,1] + Tasks[17,7] - Tasks[18,1] + Tasks[18,7]
       - Tasks[19,1] + Tasks[19,7] - Tasks[20,1] + Tasks[20,7] - Tasks[21,1]
       + Tasks[21,7] - Tasks[22,1] + Tasks[22,7] - Tasks[23,1] + Tasks[23,7]
       - Tasks[24,1] + Tasks[24,7] = 0

    In the above constraint (Resourcebalane[1,7])- It can take max value 2 or minimum value 0 ,
    As no more than 2 task will be executed.

    Jaromil I am attaching .sol file of the model which very first went feasible and gave such incorrect values of variables, You will understand what I am trying to say.

    https://docs.google.com/document/d/16U4-soyEtV27T9Z7x4vlpeTvc7hhqaer/edit?usp=sharing&ouid=104556000005791842995&rtpof=true&sd=true
    0
  • Jaromił Najman
    • Gurobi Staff Gurobi Staff

    Could you tell me whether this works

    Resourcebalance = {}
    for res in res_list1:
        for t in time:
                if t == 0 and 1 <= res and res <= 3:
                    Resourcebalance[res,0] = steel.addConstr(Resources[res,0] == 2, name="Resourcebalance[%s,%d]"%(res,t))
                elif t == 0 and 4 <= res and res<=5:
                    Resourcebalance[res,0] = steel.addConstr(Resources[res,0] == 1, name="Resourcebalance[%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):
                            if (t-theta) != 0:
                                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="Resourcebalance[%s,%d]"%(res,t))

    Note that I added the \(\texttt{t == 0}\) check to the \(\texttt{res}\) \(\texttt{if}\)-clause. It might be possible that you might have to remove it, but please check it first.

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

    Hi Jaromil,

    I dont know but it doesnt work , I will share the .sol file in which you can see that Task[1,0]= 1 

    Do you prefer I should change the time list & run all constraints from time = 1 ? 

    This is the .sol file, 

    https://drive.google.com/file/d/168sMIzyxTKtldMyRR5iK9SqvQzI4utan/view?usp=sharing

    I think, lets deal with it patiently, We will find the exact reason:

    Fundamentally What are we desiring?

    - That is: Entire Algorithm should start from T=1,Just for resource balance constraint, as we need to give some initial value? It will take some initial value at 0,

    I think there is some problem with the time assignment ? Could you try in my code with some of your logics? I think it will work.

    0
  • Jaromił Najman
    • Gurobi Staff Gurobi Staff

    I dont know but it doesnt work , I will share the .sol file in which you can see that Task[1,0]= 1 

    Please check the LP file and not the solution file. The values for Task[1,0] can still be set via other constraints such as Taskexecution or Energyusage.

    You have to define a time1 as your tried

    time1 = list()
    for x in range(1,int(num_t + 1)):
       time1.append(x)

    then go through your variable and constraint definitions and check which time list you have to use. For example, if only Resources variables can take a value for t = 0, then you should define your variables as

    Resources=steel.addVars(res_list1,time,vtype=GRB.INTEGER,name="Resources")            
    Tasks=steel.addVars(task_list,time1,vtype= GRB.BINARY,name="Tasks")
    EnergyResource=steel.addVars(res_list4,time1,vtype=GRB.CONTINUOUS,name="EnergyResource")

    You then have to carefully go through all constraints and adjust time to time1 if necessary.

    An easy example would be Taskexecution where you can just change time to time1

    Taskexecution=steel.addConstrs((gp.quicksum(Tasks[task,t] for t in time1)==1 for task in heat2tasks),name="Taskexecution")

    A more complex one where you have to think about it is Transfertime. Here I don't know whether you have to use time or time1. This is something you have to adjust.

    Transfertime = {}
    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")

    time would produce constraints Resources[res,0] = 0 for res in y_list, while time1 would not produce them.

    From here, you should go through every constraint one by one and adjust time to time1 if necessary. It is possible that you also might have to skip something as you did for Resourcebalance. For example, in the Energyusage constraint, you might have to add something like

    for ti in time1:
        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):
                    if ti-theta != 0:
                      sumexpression.add(rtn_profile[res][task][theta]* Tasks[task,ti-theta] )
        Energyusage[res,ti] = steel.addConstr(EnergyResource[res,ti] ==sumexpression,name="Energyusage[%s,%d]"%(res,ti))

    to avoid accesses to undefined variables.

    Again, after every change, you should take a look at the model's LP file to see whether the changes are what you expect them to be.

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

    Hi Jaromil,

    I tried doing so.Then there is an infeasibility problem.

    I think I need some moral support in form of you.

    I will execute each constraint one by one as per my best understanding and see what happens.

     

    0
  • Jaromił Najman
    • Gurobi Staff Gurobi Staff

    You have managed to solve the infeasibility problem before changing the time step setup so I am sure you will manage it this time as well.

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

    Hi Jaromil,

    Many thanks for motivating me. I have made minor changes in the code related to time step.

    I realized one thing, which specifically relates to Resource Balance constraint:

    Before that let me share the updated code& also the .sol file, to explain you what I am trying to convey:

    Code: https://drive.google.com/file/d/1-6ga6imsAIhCiBExdq6vHlih8UV4Z1ac/view?usp=sharing

    Sol file: https://drive.google.com/file/d/1FqNCmVyfKFOr-59kumPJDeL-Dv_y2i-O/view?usp=sharing

    If you see, in Optimization, Variables are something whose values we intend to get after optimization.

    I intend to get all variables values (Resources, Tasks, Energy Resource) from time step 1.

    But as you see, I have defined variable Resource from time step 0, I understand why it is because of Resourcebalance [1,0].

    But, due to this in the .sol file I get some values of resources at time step 0 which is not at all intended.

    So, my question is,

    If you see the equation of Resourcebalance constraint (lp file) :

    https://drive.google.com/file/d/1-Zn2R02BMtPwLU2TpfFrognX4TJ8CfH1/view?usp=sharing

    It contains initial constant value which is fed in next constraint at time step 1.

    i.e R[1,1]= R[1,0]- T[1,1] 

    We have treated R[1,0] as a constraint ,

    But, How to treat such constant variable so that I can define Resource variables also from time step 1?

    As that is not a constraint, rather just a constant value.

    I searched some related literature of Gurobi, I found some "GRBLinExpr.Constant".

    Also some post like, "Constant Variable – Gurobi Help Center"

    I think this is the only reason, because if I treat resources from time step 0, Optimizer will give me the values at that time step even though all the constraints are starting from time step 1(Reference code is shared)

    How to deal with this issue?

    I think this is the last thing needs to be paid attention. All other things I triple checked it. It is correct.

    Please Would you mind helping me?

    Many thanks Jaromil.

    Kind regards,

    -Margi

    0
  • Jaromił Najman
    • Gurobi Staff Gurobi Staff

    Hi Margi,

    Just for my understanding. The issue is now that you defined variables Resource[res,0] but you don't want to have them as optimization variables, is this correct?

    If this is the case, then I think that the issue comes from the fact that you only fix variables Resources[1,0] - Resources[5,0] instead of all variables Resources[res,0]. In your code I see

    if t == 0:
                if 1 <= res and res <= 3:
                    Resourcebalance[res,t] = steel.addConstr(Resources[res,t] == 2, name="Resourcebalance[%s,%d]"%(res,t))
                elif 4<= res and res<=5:
                    Resourcebalance[res,t] = steel.addConstr(Resources[res,t] == 1, name="Resourcebalance[%s,%d]"%(res,t))
    #else:
                   # Resourcebalance[res,t] = steel.addConstr(Resources[res,t] == 0, name="Resourcebalane[%s,%d]"%(res,t))

    So you commented out the part, where you fix all other Resources variables to 0. Is this on purpose?

    Best regards, 
    Jaromił

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

    Hi Jaromil,

    1. "The issue is now that you defined variables Resource[res,0] but you don't want to have them as optimization variables, is this correct?"

    Yes, Jaromil, 100 % correct. I do not intend to define Resources[res,0] as the Optimization Variables.

    Optimization variables starts from Resources[res,1].

    2. "So you commented out the part, where you fix all other Resources variables to 0. Is this on purpose?"

    Yes, I commented this on purpose as you can see the end resource constraint, it has to be 1 at last time step. If I keep them, it will create a conflict, so I mandatorily commented the line.

    Resources[1,0], Resources[2,0], Resources[3,0], Resources[4,0], Resources[5,0] are only some constant values rather than treating them as a constraint.

    Also, if you see in the .sol file, Resources [6,0] has some value. It is because we are treating Resources [res,0] as Optimization variables but Resource variables too start from Resources[res,1].

    Jaromil, I hope I made you understand where the problem lies. I think this is the only issue.

    Hoping to hear from you.

    -Best Regards,

    Margi

     

     

     

     

    0
  • Jaromił Najman
    • Gurobi Staff Gurobi Staff

    Hi Margi,

    Also, if you see in the .sol file, Resources [6,0] has some value. It is because we are treating Resources [res,0] as Optimization variables but Resource variables too start from Resources[res,1].

    But what is the problem in having Resources[res,0] as optimization variables? You can just ignore them if you are not interested in their final values.

    You fix the first 5 Resources[res,0] values, so they will definitely have the expected value in the final solution. The problem with not having those Resources[res,0] variables is that you use them in the t=1 case because you are accessing Resources[res,time[time.index(t)-1]]. Thus, all Resouces[res,0] have to be somehow defined, whether via a fixed value or they have to be a free variable. So you either have to fix all Resources[res,0] to some value, let them just be free variables, or adjust the Resourcebalance constraint to not access Resources[res,0] for res > 5 via Resources[res,time[time.index(t)-1]].

    Best regards, 
    Jaromił

     

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

    Hi Jaromil,

    1."You can just ignore them if you are not interested in their final values".

    y={}
    for res_cat, resources in res_cat2idx.items():
            if 'H_A_S' not in res_cat or 'H_A_S4' in res_cat:
                continue

            y[res_cat]= list(resources)

    Transfertime = {}
    for key in y:
        y_list = y[key]
      Transfertime=steel.addConstrs((Resources[res,t] == 0 for res in y_list for t in time1),name ="Transfertime")

    As, you can see in this constraint, Resources (6-30) has to be zero at every time step. But in the .sol file, Resources (6,0) has some value. This will cause a problem in Resource balance constraint.

    Is there any way Gurobi handles such Constant Varibales?

    Resources=steel.addVars(res_list1, time1,vtype=GRB.INTEGER,name="Resources")

    Can I use time step (1-96) in variable assignment of resources and use some extra loop to ignore Resources[res,0] in Resource balance constraint?

    For those resources for which initial value is not defined i.e.(from Resource 6), I think Python automatically takes it as 0, so no need to define it.

     

    Best Regards,

    Margi

     

     

    0
  • Jaromił Najman
    • Gurobi Staff Gurobi Staff

    Hi Margi,

    You could construct the Resources variable dictionary by hand, i.e., instead of

    Resources=steel.addVars(res_list1,time,vtype=GRB.INTEGER,name="Resources")

    you could go with

    Resources = {}
    for res in res_list1:
    for t in time:
    if t == 0:
    if 1 <= res and res <= 3:
    Resources[res,t] = steel.addVar(lb=2, ub=2, vtype=GRB.INTEGER, name="Resources[%d,%d]"%(res,t))
    if 4 <= res and res <= 5:
    Resources[res,t] = steel.addVar(lb=1, ub=1, vtype=GRB.INTEGER, name="Resources[%d,%d]"%(res,t))
    if 6 <= res and res <= 30:
    Resources[res,t] = steel.addVar(lb=0, ub=0, vtype=GRB.INTEGER, name="Resources[%d,%d]"%(res,t))
    # variables Resources[31,0] - Resources[96,0] will no be defined
    else:
         Resources[res,t] = steel.addVar(vtype=GRB.INTEGER, name="Resources[%d,%d]"%(res,t))

    The above will define the Resources dictionary "by hand" You will have variables

    Resouces[i,0] = 2  with 1<= i <= 3
    Resouces[i,0] = 1 with 4<= i <= 5
    Resouces[i,0] = 0 with 6<= i <= 30

    All other variables Resources[res,t] with t > 0 are non-negative integer variables. Note that variables Resources[i,0] with 31 <= i <= 96 are not defined which means that you cannot access them.

    With this definition, you don't have to check for t=0 in your Resourcebalance constraints

    Resourcebalance = {}
    for res in res_list1:
      for t in time1:
                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)+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="Resourcebalance[%s,%d]"%(res,t))

    You have to make sure that  Resources[res,time[time.index(t)-1]] never accesses values with Resources[res,t] with t=0 and 31 <= res <= 96, because they are not defined. You could use an if-statement for this

    if 31 <= res and res <= 96 and time[time.index(t)-1]==0:
    continue

    Best regards, 
    Jaromił

     

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

    Hi Jaromil,

    I need not need to access any resource value (from 6 to 173) at time step = 0. So, Shall I do this?


    Resources = {}
    for res in res_list1:
    for t in time:
    if t == 0:
    if 1 <= res and res <= 3:
    Resources[res,t] = steel.addVar(lb=2, ub=2, vtype=GRB.INTEGER, name="Resources[%d,%d]"%(res,t))
    if 4 <= res and res <= 5:
    Resources[res,t] = steel.addVar(lb=1, ub=1, vtype=GRB.INTEGER, name="Resources[%d,%d]"%(res,t))
    if 6 <= res and res <= 173:
    Resources[res,t] = steel.addVar(lb=0, ub=0, vtype=GRB.INTEGER, name="Resources[%d,%d]"%(res,t))

    #else:
       #  Resources[res,t] = steel.addVar(vtype=GRB.INTEGER, name="Resources[%d,%d]"%(res,t))

     

    If this is the case, then do I need to do this?

    "You have to make sure that  Resources[res,time[time.index(t)-1]] never accesses values with Resources[res,t] with t=0 and 31 <= res <= 96, because they are not defined. You could use an if-statement for this"

    or

    Any other changes in Resourcebalance constraint?

     

    - Best Regards,

    Margi

    0
  • Jaromił Najman
    • Gurobi Staff Gurobi Staff

    I need not need to access any resource value (from 6 to 173) at time step = 0. So, Shall I do this?

    Yes, this is fine if you don't access those value anywhere in your model. However, you need the #else case which you currently commented out. Otherwise, you won't define any other variables than Resources[res,0].

    Any other changes in Resourcebalance constraint?

    Only the ones I mentioned in my previous comment. If you are sure that you never access Resources[res,0] for 31 <= res <= 96, then you don't need the additional if - continue block.

    Please note that this is quite some change so your model can become infeasible (hopefully not) so you will have to go through the debugging process again.

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

    Hi Jaromil,

    So, the Resource Variable Dictionary will look like:

    Resources = {}
    for res in res_list1:
    for t in time:
    if t == 0:
    if 1 <= res and res <= 3:
    Resources[res,t] = steel.addVar(lb=2, ub=2, vtype=GRB.INTEGER, name="Resources[%d,%d]"%(res,t))
    if 4 <= res and res <= 5:
    Resources[res,t] = steel.addVar(lb=1, ub=1, vtype=GRB.INTEGER, name="Resources[%d,%d]"%(res,t))
    if 6 <= res and res <= 173:
    Resources[res,t] = steel.addVar(lb=0, ub=0, vtype=GRB.INTEGER, name="Resources[%d,%d]"%(res,t))

    else:
         Resources[res,t] = steel.addVar(vtype=GRB.INTEGER, name="Resources[%d,%d]"%(res,t))

     

    Resource balance constraint will look like:

    Resourcebalance = {}
    for res in res_list1:
      for t in time1:
                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)+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="Resourcebalance[%s,%d]"%(res,t))

     

    Is it making sense?

    Also,

    "Please note that this is quite some change so your model can become infeasible"

    May I ask why you feel so?

     

    0
  • Jaromił Najman
    • Gurobi Staff Gurobi Staff

    Is it making sense?

    Yes, this looks good.

    May I ask why you feel so?

    Just a gut feeling, nothing in particular. Your model changed so much that I cannot tell which change has what effect. This was just a guess so I would not put any weight into it.

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

    Hi Jaromil,

    You are truly an inspiration.

    I hope this works, I will implement & let you know.

    -Best Regards,

    Margi

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

    Hi Jaromil,

    I ran the model, fortunately it was feasible.

    But I just have one confusion with one of the constraints named as Transfer task in which we used binary variables to see which task is taking place.

    for key in group2tasks:
        b = steel.addVar(vtype=GRB.BINARY, name="b[%d]"%key)
        Taskexecution1= steel.addConstr((gp.quicksum(Tasks[group2tasks[key][0],t] for t in time1 ) == b),
                         name="constr1[%d]"%key)
                             
        Taskexecution2= steel.addConstr((gp.quicksum(Tasks[group2tasks[key][1],t] for t in time1 ) == 1 - b),
                         name="constr2[%d]"%key)

    Either of the two tasks should take place. Means either of the one should be 1.

    But in the .sol file, 

    b[1] 0
    b[2] 0
    b[3] 1
    b[4] 0
    b[5] 1
    b[6] 1

    Is this correct?

    The code: https://drive.google.com/file/d/1w77ac20tJZx4FZACb9EBrGTt-zvdL4uw/view?usp=sharing 

    It takes now only fraction of seconds to complete. If you could just run on your device to see if it is correct?

    Because now there is no infeasibility problem but just wanted to doublecheck with you if it is correctly executed?

     

    -Kind Regards,

    Margi

    0
  • Jaromił Najman
    • Gurobi Staff Gurobi Staff

    Hi Margi,

    We discussed this constraint before. If \(b_1=0\) then \(\sum_{t in time1} Tasks_{145,t} = 0\) and \(\sum_{t in time1} Tasks_{151,t} = 1\). You can verify this by checking the solution values of the respective Tasks variables and indeed variable \(\texttt{Tasks[151,82]}\) is 1 (at least for the solution on my machine) so the equality \(\sum_{t in time1} Tasks_{151,t} = 1\) is fulfilled as expected.

    It takes now only fraction of seconds to complete. If you could just run on your device to see if it is correct?

    Because now there is no infeasibility problem but just wanted to doublecheck with you if it is correctly executed?

    Just because it's quick, it does not mean that it's wrong. You should now use the solution point values and check whether they make sense for your application.

    You can also now set the MIPGap parameter value to something lower. I would recommend leaving it at its default value, i.e., not setting it at all.

    Best regards, 
    Jaromił

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

    Hi Jaromil,

    May I ask how much time it took on your machine?

    "You should now use the solution point values and check whether they make sense for your application."

    Yes, you are right, I will do that.

    Also, I have one question regarding the Log file that Gurobi generates, i.e I am using matplotlib to plot the results suppose, 

    How do I extract quantities "Obj Function value" i.e here is Elec cost vs "time step" values from this Log file?

    This file generally has the iteration values.

     

    -Kind Regards,

    Margi

    0
  • Jaromił Najman
    • Gurobi Staff Gurobi Staff

    Hi Margi,

    May I ask how much time it took on your machine?

    Only a couple of seconds, between 6-8s.

    Also, I have one question regarding the Log file that Gurobi generates, i.e I am using matplotlib to plot the results suppose, 

    How do I extract quantities "Obj Function value" i.e here is Elec cost vs "time step" values from this Log file?

    Do you mean that you want to extract the information of each log line? Or do you want to just have the final information about objective value, time needed, etc.?

    Best regards, 
    Jaromił

     

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

    Hi Jaromil,

    Many thanks for informing me. 

    "Do you mean that you want to extract the information of each log line? Or do you want to just have the final information about objective value, time needed, etc.?"

    No, What I mean is,

    I want to plot the graph between (Electricity cost- Objective Func value) and (time- which is a instance of gurobi variable object)

    i.e:For ex: I am talking about this time values: From 0 to 96

    Resources=steel.addVars(res_list1, time,vtype=GRB.INTEGER,name="Resources")

    This is the objective function:

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

    So, how do I extract these values from Gurobi log file or is there any other way of doing so?

    0
  • Jaromił Najman
    • Gurobi Staff Gurobi Staff

    After the optimization is complete, you can access all attributes listed in the respective documentation. There you can find a list of all values that are accessible after a successful optimization run.

    For example, \(\texttt{model.ObjVal}\) gives you the objective value of the final solution. Note that it is a model attribute, cf. table in the attribute documentation, so you have to access this value via the model. You can access the solution point value of some variable via \(\texttt{Resources[1,1].X}\). Note that X is a variable attribute, cf. table in the attribute documentation, so you have to access this value via the respective variable.

     

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

    Hi Jaromil,

    Thanks for the information. I searched all necessary information from the Gurobi website that what necessary attributes I require.

    I am taking this: portfolio.py (gurobi.com) as a reference example on how to use model and variable attributes.

    In my case,

    1. Variables: 

    Resources = {}
    for res in res_list1:
        for t in time:
            if t == 0:
                if 1 <= res and res <= 3:
                    Resources[res,t] = steel.addVar(lb=2, ub=2, vtype=GRB.INTEGER, name="Resources[%d,%d]"%(res,t))
                if 4 <= res and res <= 5:
                    Resources[res,t] = steel.addVar(lb=1, ub=1, vtype=GRB.INTEGER, name="Resources[%d,%d]"%(res,t))
                if 6 <= res and res <= 173:
                    Resources[res,t] = steel.addVar(lb=0, ub=0, vtype=GRB.INTEGER, name="Resources[%d,%d]"%(res,t))
            else:
                Resources[res,t] = steel.addVar(vtype=GRB.INTEGER, name="Resources[%d,%d]"%(res,t))

    Tasks=steel.addVars(task_list,time1,vtype= GRB.BINARY,name="Tasks")
    EnergyResource=steel.addVars(res_list4,time1,vtype=GRB.CONTINUOUS,name="EnergyResource")

    Objective function:

    obj=gp.quicksum(price_energy[t-1]*EnergyResource[res,t] for res in reslist2 for t in time1)

    However,

    When I am doing this "steel.ObjVal ", I am getting one solution point value.i.e Final objective func value.

    But where I am facing problem is , How do I plot Electricity costs(objvalue) at different time slots?

    for ex: objvalue at time step 1: price_energy[0]*EnergyResource[res,1]

               objvalue at time step 2: price_energy[1]*EnergyResource[res,2]

    EnergyResource is variable.

    I am trying to get some help from this example of gurobi but unable to get some detail information.

    Jaromil, could you throw some light?

     

    Kind Regards,

    Margi

     

     

     

    0
  • Jaromił Najman
    • Gurobi Staff Gurobi Staff

    Hi Margi,

    You have to access the solution point value via the X attribute, cf. my previous comment.

    So

    print(price_energy[0]*EnergyResource[1,1].X)

    will give you the value of at time step 1 using resource 1. If you want the sum over all resources at time 1 then

    print(price_energy[0]* sum(EnergyResource[res,1].X for res in reslist2))

    should work.

    Best regards, 
    Jaromił

     

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

    Hi Jaromil,

    Yes , you are right, but that isn't a tedious task? I mean doing this, 

    print(price_energy[1]*EnergyResource[174,2].X)
    print(price_energy[2]*EnergyResource[174,3].X)
    print(price_energy[3]*EnergyResource[174,4].X)
    print(price_energy[4]*EnergyResource[174,5].X)
    print(price_energy[5]*EnergyResource[174,6].X)
    print(price_energy[6]*EnergyResource[174,7].X)
    print(price_energy[7]*EnergyResource[174,8].X)
    print(price_energy[8]*EnergyResource[174,9].X)
    print(price_energy[9]*EnergyResource[174,10].X)
    print(price_energy[10]*EnergyResource[174,11].X)

    Then, storing it as a data frame(df) and then plotting, Isn't it not efficient?

    Does Gurobi has some other features to handle such values as dataframes?

    Also, If i see the above example, (very nice ex), they have used .csv as data file but I dont have that file in the example folder where the Gurobi is installed in my machine. Is it open source?

     

    For ex: It has used this, 

    Would you mind help me to understand what it is being done here?It is pretty hard to figure it out as I cant run this ex because of unavaibility of .csv file.

    ax = plt.gca()
    ax.scatter(x=stock_volatility, y=stock_return,
               color='Blue', label='Individual Stocks')
    for i, stock in enumerate(stocks):
        ax.annotate(stock, (stock_volatility[i], stock_return[i]))
    0
  • Jaromił Najman
    • Gurobi Staff Gurobi Staff

    Hi Margi,

    Yes , you are right, but that isn't a tedious task? I mean doing this, 

    print(price_energy[1]*EnergyResource[174,2].X)
    print(price_energy[2]*EnergyResource[174,3].X)
    print(price_energy[3]*EnergyResource[174,4].X)
    print(price_energy[4]*EnergyResource[174,5].X)
    print(price_energy[5]*EnergyResource[174,6].X)
    print(price_energy[6]*EnergyResource[174,7].X)
    print(price_energy[7]*EnergyResource[174,8].X)
    print(price_energy[8]*EnergyResource[174,9].X)
    print(price_energy[9]*EnergyResource[174,10].X)
    print(price_energy[10]*EnergyResource[174,11].X)

    Then, storing it as a data frame(df) and then plotting, Isn't it not efficient?

    You are using Python so you shouldn't write it by hand one by one. You can use a for-loop

    for t in time1:
     print(price_energy[i-1]*EnergyResource[174,t].X)

    Does Gurobi has some other features to handle such values as dataframes?

    No, currently Gurobi does not have such feature.

    Also, If i see the above example, (very nice ex), they have used .csv as data file but I dont have that file in the example folder where the Gurobi is installed in my machine. Is it open source?

    I guess you installed Gurobi via PIP. This does not include all files. You have to download the full Gurobi Optimizer package to have access to all files.

    For ex: It has used this, 

    Would you mind help me to understand what it is being done here?It is pretty hard to figure it out as I cant run this ex because of unavaibility of .csv file.

    ax = plt.gca()ax.scatter(x=stock_volatility, y=stock_return,           color='Blue', label='Individual Stocks')for i, stock in enumerate(stocks):    ax.annotate(stock, (stock_volatility[i], stock_return[i]))

    I don't use plot libraries often so I can only point you to the corresponding documentation matplotlib.pyplot.gca, matplotlib.pyplot.scatter. For best plotting and pandas advice, I would recommend asking in a corresponding Python forum.

    Best regards, 
    Jaromił

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

    Hi Jaromil, 

    Thanks for the information. I will surely look into it.

    0

Please sign in to leave a comment.