Skip to main content

How to arrange the same task to start at the same time?

Answered

Comments

18 comments

  • Riley Clement
    Gurobi Staff Gurobi Staff

    Hi Harichai,

    In order to answer your question we will need to understand how you have modelled the problem. What are your variables, what are your constraints, what is the objective function?

    Please also describe the data you have posted - what do the rows mean, what do the columns mean, how do we interpret the values in the cells?

    - Riley

    0
  • Harichai Sae-yong
    Gurobi-versary
    Conversationalist
    First Question

    Hello Riley,
    Thank you for answering my question.
    These are the VARIABLES that I use, where manpower_list is a list of workers' names, order_list is the order numbers, and calendar_list is the day the work will be performed.

    Next is the part of the CONSTRAINTS, most of which are time-related, are related to the amount of work.


    And finally, the Objective Function is to minimize free time in order to maximize the amount of work that can be done in one day.

    In the previous display that I posted, it shows the values from the gp_manpower_worktime variable, but what I actually want is to display it as a Gantt chart, with Y-axis being the names of the workers, X-axis being the dates and time, and in the cells, the order numbers. And orders with the same number will be performed at the same time.

    0
  • Riley Clement
    Gurobi Staff Gurobi Staff

    Hi Harichai,

    Would constraints of the form

    gp_order_status.sum("*", order) == 1 for order in order_list

    work?  Then an order could only be done on a specific date?


    As an aside, looking at the code you posted:

    Constraints on line 105 should be modelled as

    gp_manpower_status[date, manpower, order] <= gp_order_status[date, order] 

    (for each date, manpower, order combination) which models the if-then relationship correctly and is a much stronger set of constraints.

    - Riley

     

     

     

     

    0
  • Harichai Sae-yong
    Gurobi-versary
    Conversationalist
    First Question
    Hello Riley,
    model.addConstrs(gp_order_status.sum("*", order) == 1 for order in order_list)
    model.addConstrs(gp_manpower_status[date, manpower, order] <= gp_order_status[date, order] for date in calendar_list for manpower in manpower_list for order in order_list)

    After implementing your code try it out. It was found that the results are as follows.

    But the result I want is that you will see that there are total 38 orders if A and B are included.

    Which can be seen that in many orders there is a division of labor for employees to jointly do.

    Therefore, I want the shared work to be done at the same time.

    0
  • Riley Clement
    Gurobi Staff Gurobi Staff

    Hi Harichai,

    If B19 appears in both "three" and "four", doesn't this mean that 

    gp_order_status[three, B19] == 1
    gp_order_status[four, B19] == 1

    or have I incorrectly assumed what these variables are supposed to mean?

    - Riley

    0
  • Harichai Sae-yong
    Gurobi-versary
    Conversationalist
    First Question

    What is needed is not to make each order no division of labor.

    But I just want the command to work with division work start in the same column. If you look at it in terms of time, you have to start doing it together.

    The order can be divided or not divided depending on the suitability.

    0
  • Riley Clement
    Gurobi Staff Gurobi Staff

    Hi Harichai,

    But I just want the command to work with division work start in the same column. If you look at it in terms of time, you have to start doing it together.

    I understand this, but I don't understand the meaning of your variables and how you are using their solution values to construct your table.

    - Riley

     

    0
  • Harichai Sae-yong
    Gurobi-versary
    Conversationalist
    First Question

    This is my table code.

    time_list = ["one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten", "eleven", "twelve"]

    rows = manpower_list.copy()

    columns = calendar_list.copy()

    sub_columns = pd.MultiIndex.from_product([(columns), (time_list)])

    worktime_obj = {}

    manpower_plan_by_order_ref = pd.DataFrame(columns=sub_columns, index=rows, data="")

    for year, mine, order in gp_manpower_worktime.keys():

        try:

            worktime_obj[order].loc[mine, year] = np.round(gp_manpower_worktime[year, mine, order].x, 1)

            if worktime_obj[order].loc[mine, year] > 0:

                for t in time_list:

                     if manpower_plan_by_order_ref.loc[mine, (year, t)] == "":

                        manpower_plan_by_order_ref.loc[mine, (year, t)] = f"{order}={np.round(gp_manpower_worktime[year, mine, order].x, 1)}"

                        break

        except:

            worktime_obj[order] = pd.DataFrame(columns=columns, index=rows, data=0.0)

            worktime_obj[order].loc[mine, year] = np.round(gp_manpower_worktime[year, mine, order].x, 1)

            if worktime_obj[order].loc[mine, year] > 0:

                for t in time_list:

                     if manpower_plan_by_order_ref.loc[mine, (year, t)] == "":

                        manpower_plan_by_order_ref.loc[mine, (year, t)] = f"{order}={np.round(gp_manpower_worktime[year, mine, order].x, 1)}"

                      break

    pd.set_option('display.max_columns', 50)

    manpower_plan_by_order_ref
    0
  • Riley Clement
    Gurobi Staff Gurobi Staff

    If I understand correctly, timelist does not feature in your model - it is only used in construction of the table?

    In which case this problem is to do with displaying of data, and nothing to do with gurobi?  I'm happy to help either way, just making sure I understand the situation.

    - Riley

    0
  • Harichai Sae-yong
    Gurobi-versary
    Conversationalist
    First Question

    Yes you understand correctly time list is not included in the model.

    The desired result will be a Gantt chart that will be the work schedule.

    I'm still not sure about defining conditions that are executed in the same order and executed at the same time. Can this be fixed in the model or in the Gantt chart creation comma.

    0
  • Riley Clement
    Gurobi Staff Gurobi Staff

    I'm wondering if this is possible for this chart.

    Referring to the first chart there is a B14 in cell (Supachai, five) and (Phonlawat, six).  So you have to shift everything in Supachai row from B14 to the right to line B14 up.  But that row is already full and can't be shifted.

    Unless the orders don't have to be in numerical order, i.e. can B2 appear before B1 in the same row?  If that is the case, it might be possible, but you will have another optimization problem to solve to arrange them, or you will need to reformulate your problem to include assigning of orders to times, and not just dates.

    - Riley

     

    0
  • Harichai Sae-yong
    Gurobi-versary
    Conversationalist
    First Question

    In fact, the work in each order will have different importance in repairing. This is given in priority score, but if the orders are optimized to be executed on the same day, the order can be swapped, i.e. B36 is the first instruction of the day and A01 is the last instruction of the day.

    But you will have another optimization problem to solve to arrange them, or you will need to reformulate your problem to include assigning of orders to times, and not just dates.

    If it needs to be adjusted like you mentioned. What fixes do I need? Can you advise me?

    0
  • Riley Clement
    Gurobi Staff Gurobi Staff

    If I was to formulate this problem I think I would index most variables by a timeslot for every day, i.e.

    gp_manpower_status = model.addVars(timeslot_list, manpower_list, order_list, ...)

    timeslot_list[0] will correspond to 2021-11-01 one,
    timeslot_list[1] will correspond to 2021-11-01 two,
    etc

    You will have 12x as many gp_manpower_status variables as you did before.

    I'd index gp_manpower_worktime in the same way.  This should make the modeling easier and probably lead to a tighter formulation.  It certainly helps with being able to enforce that everybody who is working on order is working at the same time.

    - Riley

    0
  • Harichai Sae-yong
    Gurobi-versary
    Conversationalist
    First Question

    Hello Riley,

    I’m not sure I understand, This is the constraint after adding timeslot_list.

    # CONSTRAINTS
    # Number of manpowers should be less than or equal to the capacity
    model.addConstrs(gp_manpower_status.sum(date, "*", "*", order) <= capacity_manpowers[(order)]
    for date in calendar_list for order in order_list)

    # Order Status should be 1 if any manpower working on that order
    model.addConstrs(gp_order_status.sum("*", order) == 1 for order in order_list)
    model.addConstrs(gp_manpower_status[(date, slot, manpower, order)] <= gp_order_status[(date, order)] for date in calendar_list
                     for slot in timeslot_list for manpower in manpower_list for order in order_list)

    # Work Time Balance for any order is calculated by cycle time / summing up all manpowers status working on that order
    model.addConstrs(gp_balance_worktime[(order)] * gp_manpower_status.sum("*", "*", "*", order) == order_requirements[(order)]
                     for order in order_list)

    # Work Time for each manpower should be equal to the balance work time but considered with manpower status
    model.addConstrs(gp_manpower_worktime[(date, slot, manpower, order)] == gp_manpower_status[(date, slot, manpower, order)]
                     * gp_balance_worktime[(order)] for date in calendar_list for slot in timeslot_list for manpower in manpower_list for order in order_list)

    # Total work time of all orders for each of manpower in each day should not exceed the regular work time
    model.addConstrs(gp_manpower_worktime.sum(date, "*", manpower, "*") <= regular_work_mins for date in calendar_list
                     for manpower in manpower_list)

    # Free Time for each manpower should be equal to the regular work time minus the work time
    model.addConstrs(gp_manpower_freetime[(date, manpower)] == regular_work_mins - gp_manpower_worktime.sum(date, "*", manpower, "*")
                     for date in calendar_list for manpower in manpower_list)

    # Total work time = all required work time
    model.addConstr(gp.quicksum(gp_manpower_worktime[(date, slot, manpower, order)] for date in calendar_list for slot in timeslot_list
                   for manpower in manpower_list for order in order_list) == (gp.quicksum(daily_requirements[(date, order)]
                     for date in calendar_list for order in order_list)))

    # The same order should be done in the same day
    model.addConstrs(gp_manpower_worktime.sum(date, "*", "*", order) == order_requirements[(order)] * gp_order_status[(date, order)]
                     for date in calendar_list for order in order_list)

    # Average working hours per day
    model.addConstrs(gp_manpower_worktime.sum(date, "*", manpower, "*")
                   <= gp_manpower_worktime.sum(date, "*", "*", "*")
                     / max_manpower_possible + different_work_mins for date in calendar_list for manpower in manpower_list)

    model.addConstrs(gp_manpower_worktime.sum(date, "*", manpower, "*")
                   >= gp_manpower_worktime.sum(date, "*", "*", "*")
                     / max_manpower_possible - different_work_mins for date in calendar_list for manpower in manpower_list)

    # Set the value of gap worktime (positive for early, negative for late)
    for l in range(len(calendar_list)):
      model.addConstrs(gp_gap_worktime[(calendar_list[l], order)] == gp.quicksum(gp_manpower_worktime[(date, slot, manpower, order)]
                      for date in calendar_list[: l + 1] for slot in timeslot_list for manpower in manpower_list)
                       - (gp.quicksum(daily_requirements[(date, order)] for date in calendar_list[: l + 1])) for order in order_list)

    # Set the value of ABS(gap worktime)
    model.addConstrs(abs_gp_gap_worktime[(date, order)] == gp.abs_(gp_gap_worktime[(date, order)])
    for date in calendar_list for order in order_list)

    # Set the value of early worktime
    model.addConstrs(early_worktime[(date, order)] == (gp_gap_worktime[(date, order)] + abs_gp_gap_worktime[(date, order)]) / 2
    for date in calendar_list for order in order_list)

    # Set the value of early benefits
    model.addConstrs(early_benefit[(date, order)] == early_worktime[(date, order)] * priority_scores[order]
    for date in calendar_list for order in order_list)

    # Set the value of late worktime
    model.addConstrs(late_worktime[(date, order)] == (abs_gp_gap_worktime[(date, order)] - gp_gap_worktime[(date, order)]) / 2
    for date in calendar_list for order in order_list)

    # Set the value of late costs
    model.addConstrs(late_costs[(date, order)] == late_worktime[(date, order)] * priority_scores[order]
    for date in calendar_list for order in order_list)

    The result I got from gp_manpower_worktime now is that some orders have not been executed, some purchase orders did not meet the deadline, and some purchase orders did not match the slots.

    How do I set up a constraint so that everyone working on the same order at the same slot?

     

    0
  • Riley Clement
    Gurobi Staff Gurobi Staff

    Hi Harichai,

    I meant for the timeslot list to include dates as well, not be separate list from dates. If you look closely at what I wrote then I think you will realize this.

    - Riley

    0
  • Harichai Sae-yong
    Gurobi-versary
    Conversationalist
    First Question

    How should I solve this constraint?

    for l in range(len(calendar_list)):
          model.addConstrs(gp_gap_worktime[(calendar_list[l], order)] == gp.quicksum(gp_manpower_worktime[(date, manpower, order)]
                          for date in calendar_list[: l + 1] for manpower in manpower_list)
                          - (gp.quicksum(daily_requirements[(date, order)] for date in calendar_list[: l + 1])) for order in order_list)
    since daily_requirements is a dict imported from excel with calendar_list as keys. i.e.
    {('2021-11-01', 'A01'): 0, ('2021-11-01', 'A02'): 100, ('2021-11-01', 'B01'): 60, ('2021-11-01', 'B02'): 0 ....
     
    after changing to timeslot_list
    for l in range(len(timeslot_list)):
          model.addConstrs(gp_gap_worktime[(timeslot_list[l], order)] == gp.quicksum(gp_manpower_worktime[(date, manpower, order)]
                          for date in timeslot_list[: l + 1] for manpower in manpower_list)
                            - (gp.quicksum(daily_requirements[(date, order)] for date in timeslot_list[: l + 1])) for order in order_list)
    An error will occur.
     
     
    0
  • Riley Clement
    Gurobi Staff Gurobi Staff

    Hi Harichai,

    If I understand your model correctly then I think you will want to sum the variables who timeslots occur on the same date.

    - Riley

    0
  • Harichai Sae-yong
    Gurobi-versary
    Conversationalist
    First Question

    Hello Riley,

    Constraint in this section. It will look for advance jobs or late jobs.
    The result is that if the result is positive, it indicates that the work is completed before the deadline.
    But if it's negative, the work will be completed later than scheduled.

    This is the equation I came up with:

     

    0

Please sign in to leave a comment.