Skip to content

Capacity Constraints

Each vehicle has a limited capacity, and customer demands must not exceed it.


How It Works

  • Each customer has a delivery_load representing its demand
  • Each vehicle type has a capacity_load representing the maximum load it can carry
  • The solver ensures that the total delivery load on any route does not exceed its vehicle's capacity

Example

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

router = TQRouter()

instance = VRPInstance(
    customers=[
        Customer(location=Location(matrix_id=1), delivery_load=15),
        Customer(location=Location(matrix_id=2), delivery_load=12),
        Customer(location=Location(matrix_id=3), delivery_load=8),
        Customer(location=Location(matrix_id=4), delivery_load=20),
    ],
    fleet=[
        VehicleType(
            start_location=Location(matrix_id=0),
            end_location=Location(matrix_id=0),
            capacity_load=30,
            n_vehicles=3,
        ),
    ],
    distance_matrix=[
        [0, 5, 8, 12, 6],
        [5, 0, 4, 10, 9],
        [8, 4, 0, 7, 11],
        [12, 10, 7, 0, 3],
        [6, 9, 11, 3, 0],
    ],
)

solution = router.solve(instance)

for route in solution.routes:
    print(f"Route {route.id}: delivery load = {route.route_delivery_load} / 30")

Note

Unless the problem has a prize-collecting character, each customer's delivery_load should not exceed the capacity_load of the largest vehicle type.


Two-Dimensional Capacity (weight + volume)

Capacity can constrain two independent dimensions at once — typically weight and volume. Add the *_volume fields:

  • customers: delivery_volume / pickup_volume
  • vehicle types: capacity_volume
instance = VRPInstance(
    customers=[
        Customer(location=Location(matrix_id=1), delivery_load=15, delivery_volume=1.2),
        Customer(location=Location(matrix_id=2), delivery_load=12, delivery_volume=2.0),
    ],
    fleet=[
        VehicleType(
            start_location=Location(matrix_id=0),
            end_location=Location(matrix_id=0),
            capacity_load=30,            # weight limit
            capacity_volume=4.0,    # volume limit
            n_vehicles=3,
        ),
    ],
    distance_matrix=...,
)

You can constrain just weight, just volume, or both — set the fields you need. When both quantities appear in the instance — in customer demands or in vehicle capacities — every vehicle type must declare the capacity of each quantity your customers carry; omitting one raises a ValidationError. With a single quantity, a vehicle type without its capacity carries unlimited load, and the SDK warns about it. The two limits are enforced independently.

When you use both, the output loads (route_delivery_load, route_peak_load, total_delivery_load, …) are returned as [weight, volume] lists, and capacity constraint violations carry a dimension field (0 = weight, 1 = volume).


Pickup & Delivery

If customers also have pickup demands, the capacity model changes — see Pickup & Delivery for details.


Tuning

If the solver struggles to find feasible solutions with tight capacity constraints, you can increase the capacity penalty weights — each dimension has its own:

solution = router.solve(
    instance,
    penalty_capacity_load=100.0,
    penalty_capacity_volume=50.0,
)

Different Rules per Dimension

Weight and volume are fully independent: each has its own penalty, and either can be soft while the other stays hard. A common setup — weight is a legal limit (hard), volume is a packing preference (soft, priced per m³ of overflow):

solution = router.solve(
    instance,
    soft_constraints=["capacity_volume"],   # volume may overflow, at a price
    penalty_capacity_volume=200.0,          # objective units per unit of overflow
)

for v in solution.constraint_violations:
    print(f"{v.constraint} (dimension {v.dimension}): excess {v.excess_value}")

Weight violations still make a solution infeasible; volume violations are priced into the objective and reported in constraint_violations.


Interactive Example

See the quickstart notebook for a runnable CVRP example with visualization, and the constraints notebook for 2-D capacity.