メインコンテンツへスキップ

Using a for loop which has range of values in the constraint formulation

回答済み

コメント

51件のコメント

  • Jaromił Najman
    Gurobi Staff Gurobi Staff

    Hi Margi,

    Your \(\texttt{x}\) is a list. So what you are trying to do is to set a sum of Resources equal to a list of values. This is not accepted unless you are indeed trying to add a range constraint, but given the number of elements in \(\texttt{x}\) I doubt it.

    You should introduce your \(\texttt{x}\) as a dictionary and insert a value for every \(\texttt{res}\)

    x={}
    for res_cat, resources in res_cat2idx.items():
    [...]
    for res in resources:   # each heat a constraint
      x[res] = (math.ceil((max_wait_time-min_tran_time)/1))

    Transfertime= steel.addConstrs((gp.quicksum(Resources[res,t] for t in time )==x[res] for res in resources),name="Transfertime")

    However, please note that you add values for \(\texttt{x}\) in 2 \(\texttt{for}\)-loops, so you might override some \(\texttt{x}\) in the inner loop.

    Best regards, 
    Jaromił

    0
  • Margi Shah
    Gurobi-versary
    Thought Leader
    Curious

    Hi Jaromil ,

    Thanks for the reply.

    You mean to say that if I want to assign a value to a range of keys, I need to initialize it as a dictionary rather than list?

    Also , there is only one for loop for res: (stated below)

    So my res will go till 173, i.e ('H_B_S4  range(150-174))

    for res in resources:   # each heat a constraint
      x[res] = (math.ceil((max_wait_time-min_tran_time)/1))

    There is no other for loop than this. Is it correct?

    0
  • Jaromił Najman
    Gurobi Staff Gurobi Staff

    What happen currently in your code is the following

    x=[]
    for res_cat, resources in res_cat2idx.items():
            if 'H_B_' not in res_cat:
                continue
            max_wait_time = trans_time_max['TR_S%d' % (int(res_cat[-1]) - 1)]
            min_tran_time = trans_time['TR_S%d' % (int(res_cat[-1]) - 1)]
            for res in resources:   # each heat a constraint
                x.append(math.ceil((max_wait_time-min_tran_time)/rtn_t0)) 

    You append some value into the list \(\texttt{x}\) for every \(\texttt{res}\) in \(\texttt{resources}\) which is looped again over \(\texttt{res_cat2idx.items()}\). This means that the final list \(\texttt{x}\) will hold more items than the number of \(\texttt{resources}\).

    With a dictionary, you can easily re-assign values for a specific \(\texttt{res}\)

    x={}
    for res_cat, resources in res_cat2idx.items():
    [...]
    for res in resources:   # each heat a constraint
      x[res] = (math.ceil((max_wait_time-min_tran_time)/1))

    You should print your \(\texttt{x}\) object to better understand what is happening

    print(x)

    Once you have an filled dictionary or list \(\texttt{x}\), you have to actually access its values when constructing constraints via \(\texttt{x[res]}\)

    Transfertime= steel.addConstrs(
    (gp.quicksum(Resources[res,t] for t in time ) == x[res]
    for res in resources),name="Transfertime")

    Best regards, 
    Jaromił

    0
  • Margi Shah
    Gurobi-versary
    Thought Leader
    Curious

    Hi Jaromil,

    I completely understand the working of model.I dont know I am missing a little thing.

    What I expect is same as :

    x[res]
    Transfertime= steel.addConstrs(
    (gp.quicksum(Resources[res,t] for t in time ) == x[res]
    for res in resources),name="Transfertime")

    This loop should go from 54 to 173 ,

    & It should give same result as x[res]

    It is same as x[res]

    However When I run this,I get below error:

    0
  • Jaromił Najman
    Gurobi Staff Gurobi Staff

    If you print \(\texttt{x}\), you see that all values from 54-173 are set. The error states that you are trying to access \(\texttt{x[174]}\) which is not defined. I used \(\texttt{rtn_t0=1}\)

    print(x)
    {54: 230, 55: 230, 56: 230, 57: 230, 58: 230, 59: 230, 60: 230, 61: 230, 62: 230, 63: 230, 64: 230, 65: 230, 66: 230, 67: 230, 68: 230, 69: 230, 70: 230, 71: 230, 72: 230, 73: 230, 74: 230, 75: 230, 76: 230, 77: 230, 102: 236, 103: 236, 104: 236, 105: 236, 106: 236, 107: 236, 108: 236, 109: 236, 110: 236, 111: 236, 112: 236, 113: 236, 114: 236, 115: 236, 116: 236, 117: 236, 118: 236, 119: 236, 120: 236, 121: 236, 122: 236, 123: 236, 124: 236, 125: 236, 150: 110, 151: 110, 152: 110, 153: 110, 154: 110, 155: 110, 156: 110, 157: 110, 158: 110, 159: 110, 160: 110, 161: 110, 162: 110, 163: 110, 164: 110, 165: 110, 166: 110, 167: 110, 168: 110, 169: 110, 170: 110, 171: 110, 172: 110, 173: 110}
    0
  • Margi Shah
    Gurobi-versary
    Thought Leader
    Curious

    rtn_to has no relation with it.

    Jaromil, It should not try to access 174 , Right?

    Because res goes from 54 to 173.

    Why is it happening so ?

     

    0
  • Jaromił Najman
    Gurobi Staff Gurobi Staff

    I cannot tell because you did not post the \(\texttt{resources}\) object used when constructing the constraints.

    Note that the \(\texttt{resources}\) object used in the addConstrs method is not the same as the one used in the double \(\texttt{for}\)-loop where you fill \(\texttt{x}\).

    You could try

    Transfertime= steel.addConstrs((gp.quicksum(Resources[res,t] for t in time )==x[res] for res in x.keys()),name="Transfertime")
    0
  • Margi Shah
    Gurobi-versary
    Thought Leader
    Curious

    I think that is the issue.

    How can I use same resource object in the addConstrs method? 

    I shall create a different list and use that or Is there any other way?

    0
  • Jaromił Najman
    Gurobi Staff Gurobi Staff

    I shall create a different list and use that or Is there any other way?

    You could try to directly use the keys of the \(\texttt{x}\) dictionary

    Transfertime= steel.addConstrs((gp.quicksum(Resources[res,t] for t in time )==x[res] for res in x.keys()),name="Transfertime")
    0
  • Margi Shah
    Gurobi-versary
    Thought Leader
    Curious

    Many thanks Jaromil.

    You cleared my many fundamentals related to Gurobi. Helpful.

    Also last one general thing I needed to ask:

    Like If I have built my model. How can I see the value of variables, constraints, objective function?

    I tried to see variables using get.Var , It runs but doesn't print anything.

    For ex:

    Is there any online material on the website to check for this?

    As I searched a lot, but to see how your variables look, constraints are build up, which is important. Can you please throw some light on it?

    0
  • Jaromił Najman
    Gurobi Staff Gurobi Staff

    Like If I have built my model. How can I see the value of variables, constraints, objective function?

    I tried to see variables using get.Var , It runs but doesn't print anything.

    Variable and constraint objects don't have any value. Thus, you cannot just print it. You have to optimize your model  first via model.optimize(). You can then access the X attribute of each variable to access the solution point values and the ObjVal attribute of the model to access the objective value, cf. Attributes documentation.

    I would recommend to have a look at our Python webinar series and our Python examples. There we cover most of all basic functionalities of Gurobi in Python.

    Best regards, 
    Jaromił

    0
  • Margi Shah
    Gurobi-versary
    Thought Leader
    Curious

    Many thanks Jaromil.

    I will surely look upon that.

    0
  • Margi Shah
    Gurobi-versary
    Thought Leader
    Curious

    Hi Jaromił Najman,

    I am trying to make some modifications in the Gurobi model and I wonder if such constraint and objective function could be written in Gurobi.

    The variable I defined is:

    SpinningResource=steel.addVars(res_list5,time1,vtype=GRB.CONTINUOUS,name="SpinningResource")

    Time :

    time1 = list()

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

    It is a list of 96 starting from 1, i.e [1,2,3......96] representing 96 time slots.

    The constraint that I have is : https://docs.google.com/document/d/1aJfhTM6ngtpMvgM3nflo2mq4OzwdPhFj/edit?usp=sharing&ouid=104556000005791842995&rtpof=true&sd=true 

    What I did is aggregate the time slots belonging to the same hour like below:

    grouped_time_slots = {i: time1[i*4:i*4+4] for i in range(len(time1) // 4)}

    Output of it is:

    {0: [1, 2, 3, 4], 1: [5, 6, 7, 8], 2: [9, 10, 11, 12], 3: [13, 14, 15, 16], 4: [17, 18, 19, 20], 5: [21, 22, 23, 24], 6: [25, 26, 27, 28], 7: [29, 30, 31, 32], 8: [33, 34, 35, 36], 9: [37, 38, 39, 40], 10: [41, 42, 43, 44], 11: [45, 46, 47, 48], 12: [49, 50, 51, 52], 13: [53, 54, 55, 56], 14: [57, 58, 59, 60], 15: [61, 62, 63, 64], 16: [65, 66, 67, 68], 17: [69, 70, 71, 72], 18: [73, 74, 75, 76], 19: [77, 78, 79, 80], 20: [81, 82, 83, 84], 21: [85, 86, 87, 88], 22: [89, 90, 91, 92], 23: [93, 94, 95, 96]}

    1. My question is how to still represent this constraint?

    2. The second question is related to the objective function. 

    The Objective function is here: https://docs.google.com/document/d/1aJfhTM6ngtpMvgM3nflo2mq4OzwdPhFj/edit?usp=sharing&ouid=104556000005791842995&rtpof=true&sd=true  

    As it is seen, Ysp takes a range of values between 0 and ys which total amount of spiining resource in the time slot.

    It is given by the below constraint:

    res = res_cat2idx['SP'][0]
    Spinningusage = {}

    for ti in time1:
        # if ti == 0: # skip the t = 0 case
        # continue
        sumexpression = gp.LinExpr(0)
        for task_cat, task_list1 in tasks.items():
            if task_cat == 'EAF':
                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)):
                        sumexpression.add(rtn_profile[res][task][theta] * Tasks[task, ti - theta])
        Spinningusage[res, ti] = steel.addConstr(SpinningResource[res, ti] <= sumexpression, name="Spinningusage[%s,%d]" % (res, ti))

     

    I hope it helps. Can you please guide me on writing this constraint and the objective function? 

    Best regards,
    Margi.

    0
  • Jaromił Najman
    Gurobi Staff Gurobi Staff

    Hi Margi,

    1. My question is how to still represent this constraint?

    Once you have grouped the time slots by the hour, you can loop over each hour and within each hour over all slots. Your code would look similar to the following

    for index in grouped_time_slots:
    group = grouped_time_slots[index] # this gives you an hourly grouped list

    To construct all pairs for an hourly grouped list, you could use itertools.combinations.

      group_pairs = list(itertools.combinations(group, 2)) # this gives a list with all pairs for a given group
    for pair in group_pairs:
    # add constraint
    # you can access the entries of the pair by pair[0] and pair[1]

    The second question is related to the objective function. 

     

    If I understand correctly, the issue with the objective function is that the upper bound of \(y\) variables is to be determined during the optimization process and is thus an optimization variable itself, is this correct? If yes, then in that case, you can just add additional constraints making sure that \(y_{s,t} \leq \bar{y}_s\) and define the upper bound for \(y_{s,t}\) variables as infinity.

    Best regards, 
    Jaromił

    0
  • Margi Shah
    Gurobi-versary
    Thought Leader
    Curious

    Hi Jaromil,

    Thank you for the input. 

    I have defined the constraint as :




    grouped_time_slots = {i: time1[i * 4:i * 4 + 4] for i in range(len(time1) // 4)}

    res = res_cat2idx['SP'][0]
    Spinningprovision = {}

    for index in grouped_time_slots:
    group = grouped_time_slots[index]
    group_pairs = list(itertools.combinations(group, 2))
    print(group_pairs)
    for pair in group_pairs:
    steel.addConstr(Spinningprovision[res, pair[0]] - Spinningprovision[res, pair[1]] == 0)

    Is this correct? I was unsure if the representation seems to be correct?
    Other constraints have this L.H.S part like below , will this constraint also require?

    Spinningusage[res, ti] = steel.addConstr(SpinningResource[res, ti] <= sumexpression, name="Spinningusage[%s,%d]" % (res, ti))

    2. Regarding the objective function:

    You are correct. ys_bar is defined by the following constraint. It represents total spiining usage in that time slot. So in the objective function, it can take any value between 0 and ys_bar.

    res = res_cat2idx['SP'][0]
    Spinningusage = {}

    for ti in time1:
        # if ti == 0: # skip the t = 0 case
        # continue
        sumexpression = gp.LinExpr(0)
        for task_cat, task_list1 in tasks.items():
            if task_cat == 'EAF':
                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)):
                        sumexpression.add(rtn_profile[res][task][theta] * Tasks[task, ti - theta])
        Spinningusage[res, ti] = steel.addConstr(SpinningResource[res, ti] <= sumexpression, name="Spinningusage[%s,%d]" % (res, ti))

     

    How to define another constraint like the one you mentioned whose value is dependent on the previosu constraint itself ? 

    This is the objective function. Upto the first half part of the objective function, I have written. I am not able to write the second part. 

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

     

    Regards,
    Margi

    0
  • Jaromił Najman
    Gurobi Staff Gurobi Staff

    Hi Margi,

    Is this correct? I was unsure if the representation seems to be correct?

    It looks incorrect, because the \(\texttt{Spinningprovision}\) dictionary is empty and then accessed in the \(\texttt{for}\)-loop. If you want to use it to access the \(y\) variables, you first have to fill it with those.

    Other constraints have this L.H.S part like below , will this constraint also require?

    According to the document you linked, this constraint will not require any additional terms.

    How to define another constraint like the one you mentioned whose value is dependent on the previosu constraint itself ? 

    You have to add a constraint to define the value of \(\bar{y}_s\)

    model.addConstr(y_sbar == ...)

    Then you can add a constraint to bound \(y_{s,t}\)

    model.addConstr(y_st <= y_sbar)

    Best regards, 
    Jaromił

    0
  • Margi Shah
    Gurobi-versary
    Thought Leader
    Curious

    Hi Jaromił Najman,

    For this constraint:

    I have coded up:

    res = res_cat2idx['SP'][0]
    Spinningusage = {}

    for ti in time1:
        # if ti == 0: # skip the t = 0 case
        # continue
        sumexpression = gp.LinExpr(0)
        for task_cat, task_list1 in tasks.items():
            if task_cat == 'EAF':
                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)):
                        sumexpression.add(rtn_profile[res][task][theta] * Tasks[task, ti - theta])
        Spinningusage[res, ti] = steel.addConstr(SpinningResource[res, ti] <= sumexpression, name="Spinningusage[%s,%d]" % (res, ti))

    Now the constraint I am talking about:

    This is same y variables:
    So I just wrote it as now:

    grouped_time_slots = {i: time1[i * 4:i * 4 + 4] for i in range(len(time1) // 4)}

    res = res_cat2idx['SP'][0]


    for index in grouped_time_slots:
        group = grouped_time_slots[index]
        group_pairs = list(itertools.combinations(group, 2))
        for pair in group_pairs:
            steel.addConstr(Spinningusage[res, pair[0]] - Spinningusage[res, pair[1]] == 0)

    It shows the below error:



     

    I used the same term Spinningusage , How do I correct this?

    For the objective function:

    I have written as below but I am still unsure how  SpinningResource[res,t] will take values between 0 and y_sbar?

    steel.addConstr(y_sbar == Spinningusage[res, ti] )

    steel.addConstr(y_st <= y_sbar)

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

     

     

     

     

    0
  • Jaromił Najman
    Gurobi Staff Gurobi Staff

    Hi Margi,

    This is same y variables:
    So I just wrote it as now:

    ...

    You cannot do that because \(\texttt{Spinningusage[res, ti]}\) is a constraint object an not an expression. Each \(\texttt{Spinningusage[res, ti]}\) is a constraint \(\texttt{SpinningResource[res, ti] <= sumexpression}\).

    You first need to clarify what exactly the \(y_{SP,t}\) variables are in your case. Is it \(\texttt{y[SP, t] == SpinningResource[res, ti]} \)? This is what you need to find out first.

    I have written as below but I am still unsure how  SpinningResource[res,t] will take values between 0 and y_sbar?

    This will not work for the same reason as above. Again, you need to make clear what are your \(y_{s,t}\) variables here. Is it \(\texttt{y[s,t] == EnergyResource[res,t]}\)? This is again something you need to find out for yourself first.

    Best regards, 
    Jaromił

    0
  • Margi Shah
    Gurobi-versary
    Thought Leader
    Curious

    Hi Jaromił Najman,

    I think I cleared that y[SP,t] == SpinningResource[res,ti]


    So the code now becomes:

    Variable declaration:

    SpinningResource=steel.addVars(res_list5,time1,vtype=GRB.CONTINUOUS,name="SpinningResource")

    Constraints definition:
    Constraint 1:

    res = res_cat2idx['SP'][0]
    Spinningusage = {}

    for ti in time1:
        # if ti == 0: # skip the t = 0 case
        # continue
        sumexpression = gp.LinExpr(0)
        for task_cat, task_list1 in tasks.items():
            if task_cat == 'EAF':
                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)):
                        sumexpression.add(rtn_profile[res][task][theta] * Tasks[task, ti - theta])
        Spinningusage[res, ti] = steel.addConstr(SpinningResource[res, ti] <= sumexpression, name="Spinningusage[%s,%d]" % (res, ti))

    Constraint 2:


    grouped_time_slots = {i: time1[i * 4:i * 4 + 4] for i in range(len(time1) // 4)}

    res = res_cat2idx['SP'][0]


    for index in grouped_time_slots:
        group = grouped_time_slots[index]
        group_pairs = list(itertools.combinations(group, 2))
        for pair in group_pairs:
            steel.addConstr(SpinningResource[res, pair[0]] - SpinningResource[res, pair[1]] == 0)

    The only issue is in the objective function now :

    Code as follows:

    steel.addConstr(y_sbar == SpinningResource[res, ti])
    steel.addConstr(y_st <= y_sbar)
    obj=gp.quicksum(price_energy[t-1]*EnergyResource[res,t] for res in reslist2 for t in time1) - gp.quicksum(sp_price[t-1]*SpinningResource[res,t] for res in res_list5 for t in time1)

    There are errors and how do I make sure that that SpinningResource[res,t] takes any value between 0 and SpinningResource[res,t] in the equation of the objective function?

     

    Errors:



    Thank You for the help.
    Many regards,
    Margi.

     

     

     

     

    0
  • Jaromił Najman
    Gurobi Staff Gurobi Staff

    The only issue is in the objective function now :

     

    Code as follows:

    steel.addConstr(y_sbar == SpinningResource[res, ti])
    steel.addConstr(y_st <= y_sbar)
    obj=gp.quicksum(price_energy[t-1]*EnergyResource[res,t] for res in reslist2 for t in time1) - gp.quicksum(sp_price[t-1]*SpinningResource[res,t] for res in res_list5 for t in time1)

    The code cannot work because you did not define what y_sbar and y_st are.

    There are errors and how do I make sure that that SpinningResource[res,t] takes any value between 0 and SpinningResource[res,t] in the equation of the objective function?

    I would guess that it is a typo and you mean

    EnergyResource[res,t] takes any value between 0 and SpinningResource[res,t]

    Is this correct? If yes, then you can just add constraints

    steel.addConstr(EnergyResource[res,t] <= SpinningResource[res,t])

    Note that you do not need any new variables y_sbar and y_st because you can directly use the variables you already have defined. The introduction of these variables in my previous comments had solely the purpose of explaining what the constraints should look like, not what your actual code should look like.

    Best regards, 
    Jaromił

    0
  • Margi Shah
    Gurobi-versary
    Thought Leader
    Curious

    Hi Jaromił Najman,

    In the code of objective function below:

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

    EnergyResource[res,t] is a constant value.
    But, although SpinningResource[res,t] is a constant value, but in the objective function , it can take any value between 0 to that constant value(SpinningResource[res,t]).

    Regards,

    Margi

    0
  • Jaromił Najman
    Gurobi Staff Gurobi Staff

    Hi Margi,

    But, although SpinningResource[res,t] is a constant value, but in the objective function , it can take any value between 0 to that constant value(SpinningResource[res,t]).

    Sorry, I have overlooked the 

    sp_price[t-1]*SpinningResource[res,t]

    term in your objective.

    In this case, you only need to add an auxiliary variable for each \(\texttt{[res,t]}\), add the constraints

    auxiliaryVariable[res,t] <= SpinningResource[res,t]

    and use the \(\texttt{auxiliaryVariable}\) in the objective instead of \(\texttt{SpinningResource}\).

    Best regards, 
    Jaromił

    0
  • Margi Shah
    Gurobi-versary
    Thought Leader
    Curious

    Hi Jaromił Najman,

    Thanks for this.

    Just out of curiosity, auxiliaryVariable should take any number between 0 and SpinningResource[res,t]

    In my code when I see solution:
    I see its value in all 96 slots as 0. Is it because of anything I am missing in the logic or the way I coded up in the model?

    auxiliaryVariable[125,1] 0
    auxiliaryVariable[125,2] 0
    auxiliaryVariable[125,3] 0
    auxiliaryVariable[125,4] 0
    auxiliaryVariable[125,5] 0
    ...
    auxiliaryVariable[125,95] 0
    auxiliaryVariable[125,96] 0

     

    0
  • Jaromił Najman
    Gurobi Staff Gurobi Staff

    Hi Margi,

    I see its value in all 96 slots as 0. Is it because of anything I am missing in the logic or the way I coded up in the model?

    Could you please share the way you added the auxiliaries and how you are using them right now?

    Before you did the change, did SpinningResource[res,t] take a value different of 0?

    I think that it might be that you don't need to introduce the auxiliary variables and that using SpinningResource directly in the objective is the correct way. Please try to verify whether this is the case.

    0
  • Margi Shah
    Gurobi-versary
    Thought Leader
    Curious

    Hi Jaromił Najman,

    When I use :

    auxiliaryVariable = steel.addVars(res_list5, time1, name="auxiliaryVariable")

    for res in res_list5:
        for t in time1:
            steel.addConstr(auxiliaryVariable[res,t] <= SpinningResource[res,t],name="auxiliaryVariable_%s_%d"%(res,t))

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

    Output:

    auxiliaryVariable[125,1] 0
    auxiliaryVariable[125,2] 0
    auxiliaryVariable[125,3] 0
    auxiliaryVariable[125,4] 0
    auxiliaryVariable[125,5] 0
    ...
    auxiliaryVariable[125,95] 0
    auxiliaryVariable[125,96] 0

    When I use:

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

    Output:

    SpinningResource[125,1] 0
    SpinningResource[125,2] 0
    SpinningResource[125,3] 0
    ...
    SpinningResource[125,94] 0
    SpinningResource[125,95] 0
    SpinningResource[125,96] 0

     

    0
  • Jaromił Najman
    Gurobi Staff Gurobi Staff

    Hi Margi,

    So the new code with auxiliary variables is working as expected, because all \(\texttt{SpinningResource}\) values are \(0\).

    If you expect that at least one \(\texttt{SpinningResource}\) variable is \(> 0\), then you should have a look at the whole optimal solution point and try to understand why all \(\texttt{SpinningResource}\)  are set to \(0\). Is there any constraint which would try to push at least one \(\texttt{SpinningResource}\) variable away from \(0\)? Why would you expect at least \(\texttt{SpinningResource}\) variable to be \(> 0\)? This is something you should try to figure out as you are the one knowing the model and code best.

    Best regards, 
    Jaromił

    0
  • Margi Shah
    Gurobi-versary
    Thought Leader
    Curious

    Hi Jaromił Najman,

    Thanks for your advice. I'll look into it. 
    The only constraint through which the value of SpinningResource variable is calculated is through this:

    res = res_cat2idx['SP'][0]
    Spinningusage = {}

    for ti in time1:
        # if ti == 0: # skip the t = 0 case
        # continue
        sumexpression = gp.LinExpr(0)
        for task_cat, task_list1 in tasks.items():
            if task_cat == 'EAF':
                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)):
                        sumexpression.add(rtn_profile[res][task][theta] * Tasks[task, ti - theta])
        Spinningusage[res, ti] = steel.addConstr(SpinningResource[res, ti] <= sumexpression, name="Spinningusage[%s,%d]" % (res, ti))

    So, I am just not sure how the value of SpinningResource in the objective function is determined.

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

    As this is the constraint for EnergyResource:

    res = res_cat2idx['EN'][0]
    Energyusage = {}

    for ti in time1:
        #if ti == 0: # skip the t = 0 case
            #continue
        
        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)):
                    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)) 

    EnergyResource and SpinningResource has a single value at each time slot. But the difference of its usage in the objective function is : EnergyResource is still that constant value and SpinningResource can take any value between 0 and the value determined by the Spinningusage[res, ti] constraint.

    This is what something I expect for SpinningResource variable:

     

    0
  • Jaromił Najman
    Gurobi Staff Gurobi Staff

    Hi Margi,

    Note that \(y_{SP,t}\) is in an inequality, i.e., in contrast to \(y_{EN,t}\) it is not forced to attain the value of the right-hand side summation.

    In your objective function you have the term

    - gp.quicksum(sp_price[t-1]*SpinningResource[res, t] for res in reslist6 for t in time1)

    I assume you want to minimize the objective function. If now all coefficients \(\texttt{sp_price[t-1]}\) are negative, then it is the obvious choice to set all \(\texttt{SpinningResource}\) values to \(0\) in order to minimize the objective value.

    I see two possibilities for the cause of the issue here. Either the inequality \(y_{SP,t} \leq \dots\) should actually be an equality constraint or the coefficients \(\texttt{sp_price[t-1]}\) should be positive.

    Best regards, 
    Jaromił

    0
  • Margi Shah
    Gurobi-versary
    Thought Leader
    Curious

    Hi Jaromił Najman,

    I suspect it can be an issue of inequality constraints. However, I checked by making it to equality, but it seems the model is showing weird performance. 

    Thank you for the direction. Also, the coefficients sp_price[t-1] are all positive. 

    I shall have a double check. I think the only one constraint remaining to be validated is this one: Do you want to  make sure is its correct? 

    grouped_time_slots = {i: time1[i * 4:i * 4 + 4] for i in range(len(time1) // 4)}

    res = res_cat2idx['SP'][0]


    for index in grouped_time_slots:
        group = grouped_time_slots[index]
        group_pairs = list(itertools.combinations(group, 2))
        for pair in group_pairs:
            steel.addConstr(SpinningResource[res, pair[0]] - SpinningResource[res, pair[1]] == 0)
    0
  • Jaromił Najman
    Gurobi Staff Gurobi Staff

    From an implementation point of view, the constraint looks correct. To double check I would recommend that you use the write method and write out the model you created

    model.write("myLP.lp")

    You can open the generated \(\texttt{myLP.lp}\) file with any standard text editor and analyze whether it looks as expected.

    0

サインインしてコメントを残してください。