Skip to main content

How to achieve appliance duration with no interruptions

Answered

Comments

5 comments

  • David Torres Sanchez
    • Gurobi Staff Gurobi Staff

    Hi Aaesha,

    It seems your durations are fixed, so your duration constraint can simply be written as `=1` and then variables represent the start time of the activity (you know that the end time is just the start time plus the duration). This is normally enough.

    I think what you need is a precedence constraint (finish-to-start). This basically says activity `j` cannot start until `i` finishes. This can be enforced by the following constraint:
    $$\sum_{t'=t} x_{it'} + \sum_{t'=0}^{t+d_i-1}x_{jt'} \leq 1~\forall t$$
    where `x_{it}` is a binary variable with value 1 if activity `i` starts at time `t`, and `d_i` is the duration of the activity.

    In your case, you need to declare `x` to be binary (as we can't turn half the washing machine on) and, for example, if you want the "WashingMachine" activity to be performed before the "ClothesDryer", I would write:

    # MILP Model initialization:
    model = Model("schedule")

    # Decision Variables:
    x = model.addVars(availability, vtype=GRB.BINARY, name="x")

    # Objective Function: minimize cost of electricity
    model.setObjective(
        quicksum(Cost[w, s] * x[w, s] * Total_power[w, s] for w, s in availability),
        GRB.MINIMIZE,
    )

    # Constraints:
    # Each appliance must be ON at least once (we know that it remains on for its duration)
    reqCts = model.addConstrs((x.sum(w, "*") == 1 for w in appliances), name="assignment")


    range_wm = range(20, 81) # just range of feasible washing machine start times
    range_dryer = range(48, 71) # dryer start times
    model.addConstrs(
        (
            sum(x["WashingMachine", str(td)] for td in range(t, range_wm[-1]))
            + sum(
                x["ClothesDryer", str(td)]
                for td in range(
                    range_dryer[0], min(range_dryer[-1], t + duration["WashingMachine"] - 1)
                )
            )
            <= 1
            for t in range_wm
        ),  # range of times WashingMachine
        name="precedence",
    )
    # Optimize the model:
    model.optimize()

    for k in availability:
        if x[k].X > 0:
            print(x[k])
    0
  • Aaesha Alshehhi
    • Gurobi-versary
    • First Comment
    • First Question

    Hi David,

    Thank you so much for your reply. 

    I agree that the duration can be specified by a single 1, and following duration plus end time can easily be determined. But because we want the program to calculate the cost for us, and we want it to consider the full duration when minimizing the cost, we need it to consider the full duration when it comes to the variable x, and print out all the slots where it would be ON for an appliance.

    Is there any chance this aspect can still be maintained?

    0
  • David Torres Sanchez
    • Gurobi Staff Gurobi Staff

    Of course, you can just associate the objective value of a given variable as the sum of the costs for the duration. i.e. 
    $$\textbf{min}~ \sum_i\sum_t \left(\sum_{t'=t}^{t+d_i} c_{it'}\right)x_{it}$$
    Where `c_{it}` is the cost times power for you.

    Also, another interpretation of your initial question, you can also exclude that no appliances can be on at the same time (and other similar constraints) using the exclusion:
    $$\sum_i\sum_{t'=t-d_i+1}^t x_{it'} \leq 1 ~ \forall t$$
    This will ensure that only one activity is being processed at any given time (including the whole duration of that activity).

    0
  • Aaesha Alshehhi
    • Gurobi-versary
    • First Comment
    • First Question

    Hi David,

    I will definitely take your suggestion and try it out. However, I was wondering if it is still possible to have a sequential, or consecutive, run of the appliances in the form of a constraint that can be added to my original code?

    Thank you for your suggestions, and your patience.

    0
  • David Torres Sanchez
    • Gurobi Staff Gurobi Staff

    Hi Aaesha,

    That last constraint I mentioned does exactly that. In some order, the appliances will be sequential without any overlap. If only one appliance can be scheduled at any given time, your problem is a "single machine scheduling problem". And there are other, more efficient ways of modelling this, so I'd recommend you have a look at some scheduling literature: in [1] you can model this as a max-flow problem on page 173, [2] for a general overview.

    The constraint would look like this:

    # Sample exclusion constraint. At most one appliance can be on at any given
    # point in time and during the execution of that appliance.
    model.addConstrs(
      quicksum(
            x[w, td]
            for w in appliances
            for td in range(max(t - duration[w], ranges[w][0]), ranges[w][-1])
        )
        <= 1
        for t in range(1, 97)
    )

    Where \(\texttt{ranges}\) is a dict of ranges indexed by appliance with the range of times when it can be processed.

    Best,
    David

    [1] : Magnanti, T., Ahuja, R., and Orlin, J. (1993), Network flows: theory, algorithms, and applications, PrenticeHall, Upper Saddle River, NJ.
    [2]: Brucker, P. and Knust, S. (2012), Complex Scheduling, GOR-Publications, 2nd edn, Springer, Berlin, Heidelberg.

    0

Please sign in to leave a comment.