A bus company needs to schedule departures for a specific route during the morning peak hours (7:00 AM to 9:00 AM) to minimize the total passenger waiting time. Each bus has a minimum departure interval of 5 minutes and a maximum departure interval of 10 minutes, with a round-trip time of 30 minutes including stops. The company has a maximum of 5 buses available for scheduling. Passengers arrive at the station uniformly at a constant rate during the morning rush hour. The objective is to determine the optimal departure schedule by formulating an integer programming model that minimizes the total passenger waiting time while satisfying the given constraints.

Problem type: NLP (Medium: 121 variables, 232 constraints, 1380 nonzeros)

Mathematical model:
Set:
1. TimeSlots
The set of departure times in minutes from 6:00 AM to 9:00 AM, \( T = \{StartTime, 1, 2, \dots, EndTime\} \)

Parameter:
1. StartTime
0
2. EndTime
180
3. MinimumDepartureInterval
5
4. MaximumDepartureInterval
15
5. RoundtripTime
40
6. MaximumBuses
8
7. PassengerArrivalRate
30

Decision variable:
1. Departures
Binary variable \( x_t \in \{0, 1\} \) for all \( t \in T \), where \( x_t = 1 \) if there is a departure at time \( t \), and \( x_t = 0 \) otherwise.

Objective:
The total passenger waiting time
min: \sum_{s\in T}\sum_{t\in T,s>t}(s-t)^2\cdot x_t\cdot x_s

Constraint:
1. Minimum Departure Interval: The interval between consecutive departures must be at least 5 minutes
\sum_{i=t}^{t+MinimumDepartureInterval-1} x_t \leq 1, \forall t \in T \text{ such that } t+MinimumDepartureInterval-1 \leq EndTime

2. Maximum Departure Interval: The interval between consecutive departures must be at most 15 minutes
\sum_{s=t+MinimumDepartureInterval}^{t+MaximumDepartureInterval-1} x_s, \forall t \in T \text{ such that } t+MaximumDepartureInterval-1 \leq EndTime

3. Maximum departure times
\sum_{t\in T}x_t \leq (\left\lfloor\frac{EndTime-StartTime}{RoundtripTime}\right\rfloor+1)MaximumBuses

x_{StartTime} = 1
x_{EndTime} = 1


Type:
Binary, Quadratic, Linear
NLP

Gurobi implementation:
import gurobipy as gp
from gurobipy import GRB


def solve_bus_scheduling(
    StartTime=0,
    EndTime=120,
    MinimumDepartureInterval=5,
    MaximumDepartureInterval=10,
    RoundtripTime=30,
    MaximumBuses=5
):
    """
    Solves the bus scheduling problem to minimize passenger waiting time.
    """
    # --- Sets ---
    TimeSlots = range(StartTime, EndTime + 1)

    # --- Model Initialization ---
    model = gp.Model("BusScheduling")

    # --- Decision Variables ---
    Departures = model.addVars(TimeSlots, vtype=GRB.BINARY, name="Departures")

    # --- Objective Function ---
    obj = gp.quicksum(
        (s - t)**2 * Departures[t] * Departures[s]
        for t in TimeSlots for s in TimeSlots if s > t
    )
    model.setObjective(obj, GRB.MINIMIZE)

    # --- Constraints ---
    # Min departure interval
    for t in TimeSlots:
        if t + MinimumDepartureInterval - 1 <= EndTime:
            model.addConstr(
                gp.quicksum(Departures[i] for i in range(t, t + MinimumDepartureInterval)) <= 1
            )

    # Max departure interval
    for t in TimeSlots:
        if t + MaximumDepartureInterval - 1 <= EndTime:
            model.addConstr(
                Departures[t] <= gp.quicksum(
                    Departures[s] for s in range(t + MinimumDepartureInterval, t + MaximumDepartureInterval)
                )
            )

    # Max number of departures
    max_departures = ((EndTime - StartTime) // RoundtripTime + 1) * MaximumBuses
    model.addConstr(gp.quicksum(Departures[t] for t in TimeSlots) <= max_departures)

    # Fixed departures at start and end
    model.addConstr(Departures[StartTime] == 1)
    model.addConstr(Departures[EndTime] == 1)

    # --- Optimize the model ---
    model.optimize()

    # --- Results ---
    if model.status == GRB.OPTIMAL:
        return {"status": "optimal", "obj": model.ObjVal}
    else:
        return {"status": f"{model.status}"}


if __name__ == "__main__":
    result = solve_bus_scheduling()
    print(result)


Solution status: OPTIMAL
Optimal objective value: 296730