Skip to content

Multi-Trip Routes (Reload)

A vehicle with limited capacity can serve more demand than it carries: allow it to return to its depot mid-route, reload, and continue. One vehicle then runs several trips within a single route.


How It Works

  • Set reload on a vehicle type to allow mid-route reloads and to define the turnaround time spent at the depot per reload (0 = instant).
  • The solver decides where and how often to reload — trips are priced and optimized together with the rest of the route.
  • Reloading resets the carried load (both dimensions on two-dimensional instances; with pickup & delivery, peak-load tracking restarts per trip).
  • The vehicle always reloads at its own start_location.
  • reload requires a capacity — reloading an uncapacitated vehicle is meaningless, and validation rejects it.

The turnaround time counts toward route duration exactly like a customer's service_time: it delays all later arrivals and is included in max_duration, shift_end, and time-window feasibility. The two extra travel legs (to and from the depot) count toward route duration and distance.


Example

from tqrouting import TQRouter, VRPInstance, Customer, VehicleType, Location

router = TQRouter()

instance = VRPInstance(
    customers=[
        Customer(location=Location(matrix_id=1), delivery_load=6),
        Customer(location=Location(matrix_id=2), delivery_load=6),
        Customer(location=Location(matrix_id=3), delivery_load=6),
    ],
    fleet=[
        VehicleType(
            start_location=Location(matrix_id=0),
            end_location=Location(matrix_id=0),
            capacity_load=12,        # total demand is 18 -> a reload is needed
            reload="00:05:00",       # allowed, 5 min turnaround per reload
            n_vehicles=1,
        ),
    ],
    duration_matrix=[                # seconds
        [0, 600, 600, 600],
        [600, 0, 240, 240],
        [600, 240, 0, 240],
        [600, 240, 240, 0],
    ],
)

solution = router.solve(instance, time_limit=2)

Reading the Results

On multi-trip routes, route.customer_sequence contains ReloadStop entries between customer visits, in stop order. A ReloadStop mirrors a visit's timing fields:

  • eta — arrival time at the depot
  • end_service_time — eta + turnaround (when the vehicle is ready to leave)

Use the filtered views when you only need one kind of stop:

route = solution.routes[0]

route.visits          # customer visits only
route.reload_stops    # reload stops only

for stop in route.customer_sequence:      # full stop order
    print(stop)
# CustomerVisit(customer_id=0, eta=600, service=[600..600])
# ReloadStop(eta=1200, end_service_time=1500)
# CustomerVisit(customer_id=1, eta=2100, service=[2100..2100])
# CustomerVisit(customer_id=2, eta=2340, service=[2340..2340])

The vehicle delivers customer 0's six units first, returns to the depot (arriving at 1200, leaving after the 300 s turnaround at 1500), and serves the remaining twelve units in a second trip.

route.n_visits counts customers only — reload stops are not visits.

Note

compute_schedule arrival windows and set_departure_time are not yet available on routes that contain reload stops.