skills/dsd-route-optimization/SKILL.md
When the user wants to optimize Direct Store Delivery (DSD) routes, plan delivery schedules for retail stores, or improve route efficiency for CPG distribution. Also use when the user mentions "DSD routing," "store delivery optimization," "retail route planning," "delivery windows," "merchandising routes," or "field sales routing." For general vehicle routing, see vehicle-routing-problem. For last-mile delivery, see last-mile-delivery.
npx skillsauth add kishorkukreja/awesome-supply-chain dsd-route-optimizationInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
You are an expert in Direct Store Delivery (DSD) route optimization and retail distribution planning. Your goal is to help design efficient delivery routes that minimize costs while meeting strict retail delivery windows, merchandising requirements, and service level commitments.
Before optimizing DSD routes, understand:
Business Context
Operational Constraints
Vehicle Characteristics
Service Requirements
vs. Warehouse Delivery:
Typical Industries:
Service Patterns:
1. Fixed Routes
2. Dynamic Routes
3. Hybrid Routes
4. Pre-sell Routes
DSD routing is a special case of VRPTW with additional constraints:
Decision Variables:
x_ijk = 1 if vehicle k travels from store i to store j, 0 otherwise
t_ik = time vehicle k arrives at store i
y_ik = 1 if vehicle k serves store i, 0 otherwise
Objective Function:
Minimize:
Σ_i Σ_j Σ_k (c_ij * x_ijk) # Travel costs
+ Σ_k (fixed_cost_k * vehicle_used_k) # Fixed vehicle costs
+ Σ_i Σ_k (service_time_i * y_ik) # Service time costs
+ penalty * late_deliveries # Lateness penalties
Constraints:
1. Each store visited exactly once:
Σ_k y_ik = 1 ∀ stores i
2. Vehicle capacity (cube and weight):
Σ_i (demand_i * y_ik) <= capacity_k ∀ vehicles k
3. Time windows:
early_i <= t_ik <= late_i ∀ i, k where y_ik = 1
4. Route continuity (flow conservation):
Σ_j x_ijk = Σ_j x_jik = y_ik ∀ i, k
5. Time consistency:
t_ik + service_time_i + travel_time_ij <= t_jk + M(1 - x_ijk)
6. Driver shift length:
route_duration_k <= max_shift_k ∀ k
7. Merchandising time:
service_time_i = unload_time_i + merchandising_time_i
from ortools.constraint_solver import routing_enums_pb2
from ortools.constraint_solver import pywrapcp
import numpy as np
import pandas as pd
class DSDRouteOptimizer:
"""DSD route optimization using Google OR-Tools"""
def __init__(self, stores_df, depot_location, vehicle_config):
"""
Initialize DSD route optimizer
Parameters:
- stores_df: DataFrame with columns ['store_id', 'lat', 'lon',
'demand_cube', 'demand_weight', 'time_window_start',
'time_window_end', 'service_time', 'merchandising_time']
- depot_location: dict {'lat': x, 'lon': y}
- vehicle_config: dict with vehicle parameters
"""
self.stores = stores_df
self.depot = depot_location
self.vehicles = vehicle_config
# Calculate distance and time matrices
self.distance_matrix = self._compute_distance_matrix()
self.time_matrix = self._compute_time_matrix()
def _compute_distance_matrix(self):
"""Compute distance matrix between all locations"""
from scipy.spatial.distance import cdist
# Add depot as first location
all_locations = pd.concat([
pd.DataFrame([self.depot]),
self.stores[['lat', 'lon']]
], ignore_index=True)
# Calculate distances (haversine approximation)
coords = all_locations.values
distances = cdist(coords, coords, metric='euclidean') * 69 # miles
return distances.astype(int)
def _compute_time_matrix(self, avg_speed_mph=30):
"""Compute travel time matrix in minutes"""
return (self.distance_matrix / avg_speed_mph * 60).astype(int)
def optimize_routes(self, num_vehicles=None, max_route_time=480):
"""
Optimize DSD routes
Parameters:
- num_vehicles: number of available vehicles (None = unlimited)
- max_route_time: maximum route duration in minutes
Returns:
- routes: list of optimized routes
- metrics: route performance metrics
"""
if num_vehicles is None:
num_vehicles = len(self.stores) # Upper bound
# Create routing model
manager = pywrapcp.RoutingIndexManager(
len(self.distance_matrix),
num_vehicles,
0 # depot index
)
routing = pywrapcp.RoutingModel(manager)
# Distance callback
def distance_callback(from_index, to_index):
from_node = manager.IndexToNode(from_index)
to_node = manager.IndexToNode(to_index)
return self.distance_matrix[from_node][to_node]
transit_callback_index = routing.RegisterTransitCallback(distance_callback)
routing.SetArcCostEvaluatorOfAllVehicles(transit_callback_index)
# Time windows constraint
time_windows = [(0, max_route_time)] # Depot
for idx, row in self.stores.iterrows():
time_windows.append((
int(row['time_window_start']),
int(row['time_window_end'])
))
def time_callback(from_index, to_index):
from_node = manager.IndexToNode(from_index)
to_node = manager.IndexToNode(to_index)
travel_time = self.time_matrix[from_node][to_node]
# Add service time at from_node
if from_node > 0: # Not depot
service_time = self.stores.iloc[from_node - 1]['service_time']
merchandising = self.stores.iloc[from_node - 1]['merchandising_time']
return int(travel_time + service_time + merchandising)
return int(travel_time)
time_callback_index = routing.RegisterTransitCallback(time_callback)
routing.AddDimension(
time_callback_index,
30, # Allow 30 min waiting time
max_route_time, # Maximum route time
False, # Don't force start cumul to zero
'Time'
)
time_dimension = routing.GetDimensionOrDie('Time')
# Add time window constraints for each location
for location_idx, time_window in enumerate(time_windows):
if location_idx == 0: # Skip depot
continue
index = manager.NodeToIndex(location_idx)
time_dimension.CumulVar(index).SetRange(time_window[0], time_window[1])
# Add depot time window
for vehicle_id in range(num_vehicles):
index = routing.Start(vehicle_id)
time_dimension.CumulVar(index).SetRange(time_windows[0][0],
time_windows[0][1])
# Vehicle capacity constraints (cube)
def demand_callback(from_index):
from_node = manager.IndexToNode(from_index)
if from_node == 0: # Depot
return 0
return int(self.stores.iloc[from_node - 1]['demand_cube'])
demand_callback_index = routing.RegisterUnaryTransitCallback(demand_callback)
routing.AddDimensionWithVehicleCapacity(
demand_callback_index,
0, # No slack
[self.vehicles['capacity_cube']] * num_vehicles, # Vehicle capacities
True, # Start cumul to zero
'Capacity'
)
# Search parameters
search_parameters = pywrapcp.DefaultRoutingSearchParameters()
search_parameters.first_solution_strategy = (
routing_enums_pb2.FirstSolutionStrategy.PATH_CHEAPEST_ARC
)
search_parameters.local_search_metaheuristic = (
routing_enums_pb2.LocalSearchMetaheuristic.GUIDED_LOCAL_SEARCH
)
search_parameters.time_limit.seconds = 30
# Solve
solution = routing.SolveWithParameters(search_parameters)
if solution:
return self._extract_solution(manager, routing, solution)
else:
return None, None
def _extract_solution(self, manager, routing, solution):
"""Extract routes and metrics from solution"""
routes = []
total_distance = 0
total_time = 0
for vehicle_id in range(routing.vehicles()):
route = []
route_distance = 0
route_time = 0
index = routing.Start(vehicle_id)
while not routing.IsEnd(index):
node = manager.IndexToNode(index)
if node != 0: # Not depot
store = self.stores.iloc[node - 1]
route.append({
'store_id': store['store_id'],
'arrival_time': solution.Value(
routing.GetDimensionOrDie('Time').CumulVar(index)
),
'demand': store['demand_cube']
})
previous_index = index
index = solution.Value(routing.NextVar(index))
route_distance += routing.GetArcCostForVehicle(
previous_index, index, vehicle_id
)
if route: # Only include routes with stops
route_time = solution.Value(
routing.GetDimensionOrDie('Time').CumulVar(
routing.End(vehicle_id)
)
)
routes.append({
'vehicle_id': vehicle_id + 1,
'stops': route,
'distance_miles': route_distance,
'duration_minutes': route_time,
'num_stops': len(route)
})
total_distance += route_distance
total_time += route_time
metrics = {
'total_distance': total_distance,
'total_time': total_time,
'num_routes': len(routes),
'avg_stops_per_route': np.mean([r['num_stops'] for r in routes]),
'avg_distance_per_route': np.mean([r['distance_miles'] for r in routes])
}
return routes, metrics
# Example usage
stores = pd.DataFrame({
'store_id': ['Store_A', 'Store_B', 'Store_C', 'Store_D', 'Store_E'],
'lat': [34.05, 34.10, 34.15, 34.08, 34.12],
'lon': [-118.25, -118.30, -118.35, -118.28, -118.33],
'demand_cube': [50, 75, 60, 45, 80],
'demand_weight': [200, 300, 240, 180, 320],
'time_window_start': [360, 420, 480, 390, 450], # minutes from midnight
'time_window_end': [480, 540, 600, 510, 570],
'service_time': [15, 20, 18, 12, 22], # unload time
'merchandising_time': [30, 45, 35, 25, 40] # shelf stocking time
})
depot = {'lat': 34.00, 'lon': -118.20}
vehicle_config = {
'capacity_cube': 200,
'capacity_weight': 1000,
'max_shift_hours': 10
}
optimizer = DSDRouteOptimizer(stores, depot, vehicle_config)
routes, metrics = optimizer.optimize_routes(num_vehicles=3, max_route_time=600)
if routes:
print(f"Optimized {metrics['num_routes']} routes")
print(f"Total distance: {metrics['total_distance']} miles")
print(f"Average stops per route: {metrics['avg_stops_per_route']:.1f}")
for route in routes:
print(f"\nVehicle {route['vehicle_id']}: {route['num_stops']} stops, "
f"{route['distance_miles']} miles, {route['duration_minutes']} min")
for stop in route['stops']:
arrival = stop['arrival_time']
hours = arrival // 60
mins = arrival % 60
print(f" - {stop['store_id']} at {hours:02d}:{mins:02d}, "
f"demand: {stop['demand']} cu ft")
class PreSellRouteOptimizer:
"""
Optimize pre-sell and delivery routes for DSD
Pre-sell: Driver visits stores to take orders
Delivery: Driver returns to fulfill orders taken previously
"""
def __init__(self, stores_df, depot_location):
self.stores = stores_df
self.depot = depot_location
def optimize_presell_delivery(self, presell_days, delivery_days):
"""
Create coordinated pre-sell and delivery routes
Parameters:
- presell_days: days of week for pre-selling (0=Monday)
- delivery_days: days of week for delivery
Returns:
- presell_routes: routes for taking orders
- delivery_routes: routes for fulfilling orders
"""
# Pre-sell routes: shorter visits (no unloading)
presell_stores = self.stores.copy()
presell_stores['service_time'] = 10 # Quick order-taking
presell_stores['merchandising_time'] = 5 # Minimal shelf check
# Optimize pre-sell routes (can visit more stores)
presell_optimizer = DSDRouteOptimizer(
presell_stores,
self.depot,
{'capacity_cube': 0, 'max_shift_hours': 10} # No load
)
presell_routes, _ = presell_optimizer.optimize_routes()
# Delivery routes: full service including orders from pre-sell
delivery_stores = self.stores.copy()
# Add predicted order quantities from pre-sell
delivery_stores['demand_cube'] = presell_stores['demand_cube'] * 1.1
delivery_optimizer = DSDRouteOptimizer(
delivery_stores,
self.depot,
{'capacity_cube': 250, 'max_shift_hours': 10}
)
delivery_routes, _ = delivery_optimizer.optimize_routes()
return presell_routes, delivery_routes
Early Morning Delivery:
def generate_early_delivery_windows():
"""Typical early morning DSD windows"""
windows = {
'Grocery_Stores': (300, 420), # 5:00 AM - 7:00 AM
'Convenience_Stores': (360, 480), # 6:00 AM - 8:00 AM
'Gas_Stations': (300, 540), # 5:00 AM - 9:00 AM (flexible)
'Restaurants': (420, 600), # 7:00 AM - 10:00 AM
'Schools': (300, 420), # 5:00 AM - 7:00 AM (before students)
'Office_Buildings': (420, 540) # 7:00 AM - 9:00 AM
}
return windows
def check_time_window_feasibility(stores, max_route_time=480):
"""Check if time windows are feasible"""
# Calculate time required for all stops
total_service_time = stores['service_time'].sum()
total_merchandising = stores['merchandising_time'].sum()
# Estimate travel time (simplified)
avg_distance_between_stops = 5 # miles
avg_speed = 30 # mph
travel_time = (len(stores) * avg_distance_between_stops / avg_speed) * 60
total_time = total_service_time + total_merchandising + travel_time
return total_time <= max_route_time
Service Time Calculation:
def calculate_merchandising_time(store_type, delivery_volume, service_level):
"""
Calculate total service time at store
Parameters:
- store_type: 'grocery', 'convenience', 'gas_station', etc.
- delivery_volume: cubic feet or number of cases
- service_level: 'basic', 'full_service', 'premium'
Returns:
- total_time: minutes
"""
# Base unload time
unload_time = delivery_volume * 0.5 # 0.5 min per cubic foot
# Merchandising time by service level
merchandising_factors = {
'basic': 1.0, # Just unload to backroom
'full_service': 2.0, # Stock shelves, rotate
'premium': 3.0 # Stock, rotate, build displays, check inventory
}
base_merchandising = {
'grocery': 30,
'convenience': 20,
'gas_station': 15,
'wholesale': 45,
'restaurant': 25
}
merchandising_time = (
base_merchandising.get(store_type, 25) *
merchandising_factors.get(service_level, 1.0)
)
total_time = unload_time + merchandising_time
return total_time
# Example
time_required = calculate_merchandising_time(
store_type='grocery',
delivery_volume=75, # cubic feet
service_level='full_service'
)
print(f"Service time required: {time_required:.0f} minutes")
Load Planning for Route Efficiency:
def plan_vehicle_loading(route_stops):
"""
Plan vehicle loading sequence (LIFO for route efficiency)
Last stop should be loaded first (bottom/front of truck)
First stop should be loaded last (top/back of truck)
"""
# Reverse route order for loading
loading_sequence = route_stops[::-1]
loading_plan = []
for idx, stop in enumerate(loading_sequence):
loading_plan.append({
'load_position': idx + 1,
'route_position': len(route_stops) - idx,
'store_id': stop['store_id'],
'products': stop['products'],
'volume': stop['demand_cube'],
'special_handling': stop.get('refrigerated', False)
})
return loading_plan
def optimize_truck_load(stops, vehicle_config):
"""
Optimize truck loading considering weight distribution
"""
from ortools.linear_solver import pywraplp
solver = pywraplp.Solver.CreateSolver('SCIP')
# Zones in truck: front, middle, back
zones = ['front', 'middle', 'back']
# Variables: which stop's products go in which zone
x = {}
for stop_idx, stop in enumerate(stops):
for zone in zones:
x[stop_idx, zone] = solver.BoolVar(f'stop_{stop_idx}_{zone}')
# Objective: minimize rehandling (LIFO loading)
objective = solver.Objective()
for stop_idx, stop in enumerate(stops):
route_position = stop['route_position']
# Earlier stops should be in back/top
objective.SetCoefficient(x[stop_idx, 'back'], route_position)
objective.SetCoefficient(x[stop_idx, 'middle'], route_position * 1.5)
objective.SetCoefficient(x[stop_idx, 'front'], route_position * 2)
objective.SetMinimization()
# Constraints: each stop assigned to exactly one zone
for stop_idx in range(len(stops)):
solver.Add(sum(x[stop_idx, zone] for zone in zones) == 1)
# Capacity constraints per zone
for zone in zones:
solver.Add(
sum(x[stop_idx, zone] * stops[stop_idx]['volume']
for stop_idx in range(len(stops)))
<= vehicle_config['zone_capacity'][zone]
)
status = solver.Solve()
if status == pywraplp.Solver.OPTIMAL:
loading_plan = []
for stop_idx, stop in enumerate(stops):
for zone in zones:
if x[stop_idx, zone].solution_value() > 0.5:
loading_plan.append({
'stop': stop['store_id'],
'zone': zone,
'route_position': stop['route_position']
})
return loading_plan
return None
Efficiency Metrics:
def calculate_dsd_metrics(routes_df, stores_df, costs):
"""
Calculate comprehensive DSD route metrics
Parameters:
- routes_df: DataFrame with route details
- stores_df: DataFrame with store information
- costs: dict with cost parameters
"""
metrics = {}
# Miles per stop
metrics['miles_per_stop'] = (
routes_df['total_miles'].sum() / routes_df['num_stops'].sum()
)
# Stops per route
metrics['stops_per_route'] = routes_df['num_stops'].mean()
# Cases per mile
metrics['cases_per_mile'] = (
routes_df['total_cases'].sum() / routes_df['total_miles'].sum()
)
# Cost per delivery
fixed_cost_per_route = costs['driver_cost'] + costs['vehicle_cost']
variable_cost = routes_df['total_miles'].sum() * costs['cost_per_mile']
total_deliveries = routes_df['num_stops'].sum()
metrics['cost_per_delivery'] = (
(fixed_cost_per_route * len(routes_df) + variable_cost) /
total_deliveries
)
# Service time percentage
total_route_time = routes_df['total_time'].sum()
total_service_time = routes_df['service_time'].sum()
metrics['service_time_pct'] = (total_service_time / total_route_time) * 100
metrics['drive_time_pct'] = 100 - metrics['service_time_pct']
# On-time performance
metrics['on_time_pct'] = (
routes_df['on_time_deliveries'].sum() / total_deliveries * 100
)
# Utilization
metrics['cube_utilization'] = (
routes_df['loaded_cube'].mean() / routes_df['vehicle_capacity'].mean() * 100
)
return metrics
# Benchmark targets
benchmarks = {
'miles_per_stop': {'best': 2.5, 'good': 3.5, 'acceptable': 5.0},
'stops_per_route': {'best': 25, 'good': 20, 'acceptable': 15},
'cases_per_mile': {'best': 50, 'good': 40, 'acceptable': 30},
'cost_per_delivery': {'best': 15, 'good': 20, 'acceptable': 25},
'on_time_pct': {'best': 98, 'good': 95, 'acceptable': 90},
'cube_utilization': {'best': 85, 'good': 75, 'acceptable': 65}
}
from sklearn.cluster import KMeans
import numpy as np
def create_delivery_zones(stores_df, num_zones=5):
"""
Create geographic zones for route planning
Parameters:
- stores_df: DataFrame with store locations
- num_zones: number of zones to create
Returns:
- stores_df with 'zone' assignment
"""
# Extract coordinates
coords = stores_df[['lat', 'lon']].values
# K-means clustering
kmeans = KMeans(n_clusters=num_zones, random_state=42)
stores_df['zone'] = kmeans.fit_predict(coords)
# Calculate zone characteristics
zone_stats = stores_df.groupby('zone').agg({
'store_id': 'count',
'demand_cube': 'sum',
'lat': 'mean',
'lon': 'mean'
}).rename(columns={'store_id': 'num_stores'})
return stores_df, zone_stats
def assign_stores_to_days(stores_df, delivery_frequency):
"""
Assign stores to delivery days based on frequency
Parameters:
- stores_df: stores with zone assignments
- delivery_frequency: dict {store_id: frequency} where frequency in [1,2,3,5,7]
Returns:
- delivery_schedule: which stores on which days
"""
days_of_week = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri']
schedule = {day: [] for day in days_of_week}
for idx, store in stores_df.iterrows():
store_id = store['store_id']
freq = delivery_frequency.get(store_id, 1) # Default: once per week
if freq == 5: # Daily
for day in days_of_week:
schedule[day].append(store_id)
elif freq == 3: # 3x per week (Mon, Wed, Fri)
for day in ['Mon', 'Wed', 'Fri']:
schedule[day].append(store_id)
elif freq == 2: # 2x per week (Tue, Thu)
for day in ['Tue', 'Thu']:
schedule[day].append(store_id)
elif freq == 1: # Once per week
# Assign to day with least stores in same zone
zone = store['zone']
zone_counts = {
day: sum(1 for s in schedule[day]
if stores_df[stores_df['store_id']==s]['zone'].iloc[0]==zone)
for day in days_of_week
}
min_day = min(zone_counts, key=zone_counts.get)
schedule[min_day].append(store_id)
return schedule
class DynamicDSDRouter:
"""
Dynamic daily routing based on actual orders
"""
def __init__(self, stores_master, depot, vehicles):
self.stores_master = stores_master
self.depot = depot
self.vehicles = vehicles
self.historical_routes = []
def generate_daily_routes(self, orders_today):
"""
Generate routes based on today's actual orders
Parameters:
- orders_today: DataFrame with today's orders by store
Returns:
- optimized routes for today
"""
# Filter to stores with orders today
stores_today = self.stores_master[
self.stores_master['store_id'].isin(orders_today['store_id'])
].copy()
# Update demand from orders
stores_today = stores_today.merge(
orders_today[['store_id', 'order_cube', 'order_weight']],
on='store_id'
)
stores_today['demand_cube'] = stores_today['order_cube']
stores_today['demand_weight'] = stores_today['order_weight']
# Optimize routes
optimizer = DSDRouteOptimizer(stores_today, self.depot, self.vehicles)
routes, metrics = optimizer.optimize_routes()
# Store for learning
self.historical_routes.append({
'date': pd.Timestamp.today(),
'routes': routes,
'metrics': metrics
})
return routes, metrics
def predict_tomorrow_demand(self):
"""
Predict tomorrow's demand based on historical patterns
"""
if len(self.historical_routes) < 7:
# Not enough history, use average
return self.stores_master['demand_cube'].mean()
# Get same day of week from history
tomorrow_dow = (pd.Timestamp.today() + pd.Timedelta(days=1)).dayofweek
historical_same_dow = [
r for r in self.historical_routes
if r['date'].dayofweek == tomorrow_dow
]
# Average demand from same day of week
avg_demand_by_store = {}
for store_id in self.stores_master['store_id']:
demands = []
for hist in historical_same_dow[-4:]: # Last 4 weeks
for route in hist['routes']:
for stop in route['stops']:
if stop['store_id'] == store_id:
demands.append(stop['demand'])
if demands:
avg_demand_by_store[store_id] = np.mean(demands)
return avg_demand_by_store
Commercial:
Open Source:
# Key libraries for DSD routing
# Optimization
from ortools.constraint_solver import routing_enums_pb2, pywrapcp
import pulp
import pyomo.environ as pyo
# Geospatial
import geopandas as gpd
from shapely.geometry import Point
from scipy.spatial.distance import cdist
# Routing with real roads
import osmnx as ox
import networkx as nx
# Visualization
import folium
import plotly.express as px
import matplotlib.pyplot as plt
# Data processing
import pandas as pd
import numpy as np
def visualize_routes(routes, stores_df, depot, output_file='routes_map.html'):
"""
Create interactive map of routes
"""
import folium
from folium import plugins
# Create map centered on depot
m = folium.Map(
location=[depot['lat'], depot['lon']],
zoom_start=11,
tiles='OpenStreetMap'
)
# Add depot
folium.Marker(
[depot['lat'], depot['lon']],
popup='Depot',
icon=folium.Icon(color='red', icon='home')
).add_to(m)
# Colors for different routes
colors = ['blue', 'green', 'purple', 'orange', 'darkred',
'lightred', 'beige', 'darkblue', 'darkgreen', 'cadetblue']
for idx, route in enumerate(routes):
color = colors[idx % len(colors)]
# Add route line
route_coords = [[depot['lat'], depot['lon']]]
for stop in route['stops']:
store = stores_df[stores_df['store_id'] == stop['store_id']].iloc[0]
lat, lon = store['lat'], store['lon']
route_coords.append([lat, lon])
# Add store marker
folium.Marker(
[lat, lon],
popup=f"{stop['store_id']}<br>Arrival: {stop['arrival_time']} min",
icon=folium.Icon(color=color, icon='shopping-cart')
).add_to(m)
route_coords.append([depot['lat'], depot['lon']])
# Draw route line
folium.PolyLine(
route_coords,
color=color,
weight=3,
opacity=0.7,
popup=f"Route {route['vehicle_id']}: {route['num_stops']} stops"
).add_to(m)
# Add legend
legend_html = f'''
<div style="position: fixed;
bottom: 50px; left: 50px; width: 220px; height: auto;
background-color: white; border:2px solid grey; z-index:9999;
font-size:14px; padding: 10px">
<p><b>Routes Summary</b></p>
<p>Total Routes: {len(routes)}</p>
<p>Total Stops: {sum(r['num_stops'] for r in routes)}</p>
<p>Total Miles: {sum(r['distance_miles'] for r in routes):.0f}</p>
</div>
'''
m.get_root().html.add_child(folium.Element(legend_html))
m.save(output_file)
return m
Problem:
Solutions:
def optimize_with_staggered_starts(stores, depot, vehicles):
"""
Stagger vehicle start times to meet tight windows
"""
# Sort stores by window start time
stores_sorted = stores.sort_values('time_window_start')
routes = []
start_time = stores_sorted['time_window_start'].min()
for vehicle_id in range(vehicles['count']):
# Assign stores that can be served by this start time
vehicle_stores = stores_sorted.iloc[
vehicle_id::vehicles['count']
]
# Optimize route for this vehicle
optimizer = DSDRouteOptimizer(
vehicle_stores,
depot,
vehicles
)
route, _ = optimizer.optimize_routes(num_vehicles=1)
if route:
route[0]['start_time'] = start_time + (vehicle_id * 15) # 15 min stagger
routes.append(route[0])
return routes
Problem:
Solutions:
def calibrate_service_times(actual_times_df):
"""
Calibrate service times based on actual performance
Parameters:
- actual_times_df: historical data with planned vs actual times
Returns:
- calibrated service times by store type
"""
calibration = actual_times_df.groupby('store_type').agg({
'planned_time': 'mean',
'actual_time': 'mean',
'actual_time': 'std'
})
# Add buffer (mean + 1 std dev for 84% confidence)
calibration['recommended_time'] = (
calibration['actual_time'].mean() +
calibration['actual_time'].std()
)
# Calculate variance factor
calibration['variance_factor'] = (
calibration['actual_time'].mean() /
calibration['planned_time'].mean()
)
return calibration
Problem:
Solutions:
Problem:
Solutions:
def model_with_returns(stores, return_rates):
"""
Adjust capacity for return pickups
Parameters:
- stores: store data
- return_rates: dict {store_id: pct_returns}
Returns:
- adjusted capacity requirements
"""
for idx, store in stores.iterrows():
store_id = store['store_id']
delivery = store['demand_cube']
# Estimate returns
return_rate = return_rates.get(store_id, 0.05) # Default 5%
returns = delivery * return_rate
# Net capacity needed (can use return space after pickup)
# But need space for returns until picked up
stores.at[idx, 'capacity_needed'] = delivery
stores.at[idx, 'returns_expected'] = returns
return stores
Problem:
Solutions:
Executive Summary:
Route Details:
Route 1 - Driver: John Smith - Vehicle: T-101
Departure: 5:30 AM
Estimated Duration: 8.5 hours
Total Miles: 175
Total Stops: 24
Total Cases: 480
Stop Store ID Arrival Service Departure Cases Running Load
---- ----------- ------- ------- --------- ----- ------------
1 Store_A 6:15 AM 35 min 6:50 AM 25 25/480
2 Store_B 7:05 AM 25 min 7:30 AM 18 43/480
3 Store_C 7:50 AM 40 min 8:30 AM 32 75/480
...
Return to Depot: 3:15 PM
Performance Metrics:
| Metric | Value | Benchmark | Status | |--------|-------|-----------|--------| | Miles per Stop | 7.6 | < 8.0 | ✓ Good | | Stops per Route | 20.4 | > 18 | ✓ Good | | Cost per Delivery | $18.37 | < $20 | ✓ Good | | Cube Utilization | 78% | > 75% | ✓ Good | | On-Time % | 97% | > 95% | ✓ Good |
Zone Coverage:
| Zone | Routes | Stops | Miles | Avg Density | |------|--------|-------|-------|-------------| | North | 3 | 65 | 425 | 21.7 stops/route | | South | 4 | 88 | 520 | 22.0 stops/route | | East | 3 | 55 | 480 | 18.3 stops/route | | West | 2 | 37 | 425 | 18.5 stops/route |
Recommendations:
If you need more context:
documentation
When the user wants to optimize yard operations, manage trailer parking, or improve dock door utilization. Also use when the user mentions "yard management," "trailer tracking," "yard jockey," "drop trailer program," "trailer pool," "dock scheduling," or "gate management." For cross-dock operations, see cross-docking. For warehouse design, see warehouse-design.
tools
When the user wants to optimize workforce scheduling, create shift plans, or balance labor demand. Also use when the user mentions "staff scheduling," "labor planning," "shift optimization," "crew scheduling," "roster optimization," or "employee scheduling." For task assignment, see task-assignment-problem. For wave planning labor, see wave-planning-optimization.
testing
When the user wants to optimize pick wave planning, schedule warehouse operations, or improve order fulfillment efficiency. Also use when the user mentions "wave management," "batch picking," "pick wave scheduling," "order release optimization," "wave design," or "pick wave strategy." For order batching, see order-batching-optimization. For workforce scheduling, see workforce-scheduling.
testing
When the user wants to optimize warehouse slot assignments, improve pick efficiency, or design warehouse layouts. Also use when the user mentions "slotting optimization," "slot assignment," "ABC slotting," "pick path optimization," "storage location assignment," "warehouse layout optimization," or "forward pick locations." For picker routing, see picker-routing-optimization. For warehouse design, see warehouse-design.