Polyhedron Use Case
Last-Mile Delivery Vehicle Routing
Discover how we collaborate with customers to model and solve complex problems such as the Vehicle Routing Problem with time windows. This example shows our joint approach to transforming real business challenges into efficient solutions.
Complete Vehicle Routing Implementation
This example demonstrates our approach to building and solving real-world enterprise problems. We work closely with customers to understand their unique challenges and create tailored optimization models that deliver advanced classical and quantum-ready solutions.
Import Libraries and Setup
A Portfolio of Modeling Libraries
We begin by importing the essential Polyhedron components for graph modeling, spatial calculations, and QUBO compilation - one of our own toolkits for tackling complex optimization problems.
import pandas as pd
from polyhedron import Graph, GraphEdge, GraphNode, Model
from polyhedron.spatial import DistanceMatrix, Location
from polyhedron_pro.qubo import QuboCompiler, QuboCompilerSettingsModel Abstraction
Define Domain Classes
We define custom classes that represent the key elements of our routing problem: RouteArc for connections between locations with travel costs, and Stop for delivery points with time windows and service requirements.
class RouteArc(GraphEdge):
used = Model.BinaryVar() # 1 if arc is used in route
travel_time: object # scenario-based
cost: float # Cost of traversing this arc
def objective_contribution(self):
return self.cost * self.used
class Stop(GraphNode):
arrival_time = Model.ContinuousVar(min=0, max=1000)
sequence = Model.IntegerVar(min=0, max=10000)
node_id: int
demand: float
service_time: float
time_window_start: int
time_window_end: int
is_depot: bool = FalseDefining Scenarios and Uncertainty
Load Data and Build Scenario Matrix
In this example, we define a distance matrix that accounts for travel time uncertainty. We ensure to capture relevant real-world operational constraints:
- •Location Mapping: We create location objects for depot and all customer sites to establish the routing network
- •Scenario Planning: We build multiple travel time scenarios (optimistic, most likely, pessimistic) with assigned probabilities to handle real-world variability
- •Matrix Population: We fill the distance matrix with travel times between all location pairs, drawing from your historical data or routing APIs
# Build scenario matrix with different travel time scenarios
scenario_matrix = DistanceMatrix()
scenario_matrix.add_scenario("optimistic", weight=0.2)
scenario_matrix.add_scenario("most_likely", weight=0.6)
scenario_matrix.add_scenario("pessimistic", weight=0.2)
# Populate matrix with scenario values from input data
for row_id, row in time_matrix_most_likely.iterrows():
for col_id, value in row.items():
scenario_matrix.set_scenarios(
locations[int(row_id)], locations[int(col_id)],
{
"optimistic": float(time_matrix_optimistic.loc[row_id, col_id]),
"most_likely": float(value),
"pessimistic": float(time_matrix_pessimistic.loc[row_id, col_id]),
}
)Defining the Logic
Add Core Constraints
We implement the fundamental business rules that make operations feasible and practical, ensuring every constraint from your operations is properly modeled. In this particular example:
- •Service Coverage: Guarantee each customer location is visited exactly once, preventing missed deliveries or duplicate visits
- •Time Window Compliance: Ensure deliveries arrive within your customers' specified time slots, respecting both start and end times
- •Route Continuity: Model how time accumulates along delivery routes, accounting for travel time, service time, and sequence dependencies
- •Logical Consistency: Use conditional constraints to ensure time propagation only applies when routes are actually used
@model.constraint(name="customer_service")
def customer_service():
# Each customer must be visited exactly once
return [sum(edge.used for edge in edges if edge.target == customer) == 1
for customer in customers]
@model.constraint(name="time_windows", foreach=customers)
def time_windows(customer: Stop):
# Respect customer time windows
return [customer.arrival_time >= customer.time_window_start,
customer.arrival_time + customer.service_time <= customer.time_window_end]
@model.constraint(name="time_propagation", foreach=edges)
def time_propagation(edge: RouteArc):
# Time accumulates along the route
if edge.target.is_depot:
return []
return (edge.target.arrival_time >=
edge.source.arrival_time + edge.source.service_time + edge.travel_time
- big_m + edge.used * big_m)Powerful Backend Abstraction
Classical & Quantum Execution
With the power of Polyhedron's unique dual-execution capability, we can materialize your optimization model to run on advanced classical optimizers, or compile it to quantum computing hardware - supporting both gate-based quantum computers and quantum annealing systems:
- •Flexible Execution: Choose between classical optimization engines or quantum computing platforms based on your needs and available hardware
- •Unified Framework: Single model definition that automatically adapts to run on classical solvers or quantum hardware
# Compile to QUBO for quantum annealing
compiler = QuboCompiler(QuboCompilerSettings(
continuous_step=1.0, # Discretization step
penalty_weight=10.0 # Penalty strength
))
compilation = compiler.compile(model)
qubo, offset = compilation.to_qubo()
# Solve the model
result = model.solve(time_limit=60)