{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# 🚚 Real-World Logistics Optimization: The Flexport Way\n", "*From Excel Pain to Python Power in 60 Minutes*\n", "\n", "## Welcome to Your $10 Million Optimization Journey\n", "\n", "You're about to learn the exact techniques Flexport uses to save companies 8-10% on logistics costs. By the end of this notebook, you'll be able to:\n", "- Optimize delivery routes for 500+ packages\n", "- Reduce transportation costs by 30-40%\n", "- Automate what takes humans hours in seconds\n", "- Actually understand what's happening (no black box!)\n", "\n", "**Real Impact:** If you were running logistics for a mid-size company, these techniques would save ~$2.3M annually.\n", "\n", "Let's start coding!" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Step 1: Install and Import Our Tools\n", "Run this first - it's like opening Excel, but more powerful." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Install required packages (only need to run once)\n", "!pip install pandas numpy matplotlib seaborn scikit-learn ortools openpyxl -q\n", "\n", "print(\"✅ Packages installed! You're ready to save millions.\")" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Import everything we need\n", "import pandas as pd\n", "import numpy as np\n", "import matplotlib.pyplot as plt\n", "import seaborn as sns\n", "from datetime import datetime, timedelta\n", "import random\n", "import time\n", "import json # Added json import here\n", "from itertools import permutations\n", "import warnings\n", "warnings.filterwarnings('ignore')\n", "\n", "# Set up nice looking plots\n", "plt.style.use('seaborn-v0_8-darkgrid')\n", "sns.set_palette(\"husl\")\n", "\n", "print(\"🚀 All systems go! Let's optimize some routes.\")\n", "print(\"📊 Pandas version:\", pd.__version__)\n", "print(\"🔢 NumPy version:\", np.__version__)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Problem 1: The Container Loading Crisis\n", "### It's Black Friday. You have 500 packages, 20 trucks, and 30 minutes to figure it out.\n", "\n", "This is exactly what happens at every Flexport warehouse, every single day." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Generate realistic package data (just like your Excel template)\n", "np.random.seed(42) # For reproducibility\n", "\n", "def generate_packages(n=500):\n", " \"\"\"Create realistic e-commerce packages\"\"\"\n", " \n", " retailers = ['Target', 'Walmart', 'Best Buy', 'Home Depot', 'Costco', \n", " 'CVS', 'Walgreens', 'Macy\\'s', 'Nike', 'Apple Store']\n", " \n", " packages = []\n", " for i in range(n):\n", " packages.append({\n", " 'package_id': f'PKG{i+1:04d}',\n", " 'retailer': np.random.choice(retailers),\n", " 'weight_kg': round(np.random.uniform(0.5, 50), 1),\n", " 'volume_m3': round(np.random.uniform(0.01, 2), 2),\n", " 'priority': np.random.choice(['Express', 'Standard', 'Economy'], p=[0.2, 0.6, 0.2]),\n", " 'fragile': np.random.choice([True, False], p=[0.25, 0.75]),\n", " 'zone': np.random.choice(['North', 'South', 'East', 'West', 'Central']),\n", " 'value_usd': round(np.random.uniform(20, 5000), 2)\n", " })\n", " \n", " return pd.DataFrame(packages)\n", "\n", "# Generate our packages\n", "packages_df = generate_packages(500)\n", "\n", "print(\"📦 Generated 500 packages! Here's a sample:\")\n", "print(packages_df.head(10))\n", "print(f\"\\n📊 Package Statistics:\")\n", "print(f\"Total weight: {packages_df['weight_kg'].sum():,.1f} kg\")\n", "print(f\"Total volume: {packages_df['volume_m3'].sum():,.1f} m³\")\n", "print(f\"Total value: ${packages_df['value_usd'].sum():,.2f}\")\n", "print(f\"Express packages: {(packages_df['priority'] == 'Express').sum()} ({(packages_df['priority'] == 'Express').mean()*100:.1f}%)\")" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Generate truck fleet\n", "def generate_trucks(n=20):\n", " \"\"\"Create realistic truck fleet\"\"\"\n", " \n", " trucks = []\n", " for i in range(n):\n", " truck_type = np.random.choice(['Small', 'Medium', 'Large'], p=[0.3, 0.5, 0.2])\n", " \n", " if truck_type == 'Small':\n", " capacity_kg, capacity_m3 = 5000, 50\n", " elif truck_type == 'Medium':\n", " capacity_kg, capacity_m3 = 7500, 75\n", " else:\n", " capacity_kg, capacity_m3 = 10000, 100\n", " \n", " trucks.append({\n", " 'truck_id': f'TRUCK{i+1:02d}',\n", " 'type': truck_type,\n", " 'max_weight_kg': capacity_kg,\n", " 'max_volume_m3': capacity_m3,\n", " 'cost_per_km': round(2.5 * (1 + i*0.05), 2), # Varies by driver experience\n", " 'available': True\n", " })\n", " \n", " return pd.DataFrame(trucks)\n", "\n", "trucks_df = generate_trucks(20)\n", "\n", "print(\"🚛 Generated 20 trucks! Fleet composition:\")\n", "print(trucks_df.groupby('type').agg({\n", " 'truck_id': 'count',\n", " 'max_weight_kg': 'first',\n", " 'max_volume_m3': 'first'\n", "}).rename(columns={'truck_id': 'count'}))\n", "print(f\"\\nTotal fleet capacity: {trucks_df['max_weight_kg'].sum():,} kg, {trucks_df['max_volume_m3'].sum():,} m³\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### The Human Approach: First-Fit Algorithm\n", "This is what your warehouse manager Maria does every morning. It works, but..." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "def human_loading_strategy(packages, trucks):\n", " \"\"\"\n", " Simulates how a human would load trucks:\n", " - Take packages in order they come\n", " - Put in first truck that fits\n", " - When truck is ~80% full, move to next\n", " \"\"\"\n", " start_time = time.time()\n", " \n", " trucks = trucks.copy()\n", " trucks['loaded_weight'] = 0\n", " trucks['loaded_volume'] = 0\n", " trucks['packages'] = [[] for _ in range(len(trucks))]\n", " \n", " unassigned = []\n", " \n", " for _, package in packages.iterrows():\n", " assigned = False\n", " \n", " for truck_idx, truck in trucks.iterrows():\n", " # Check if package fits\n", " if (truck['loaded_weight'] + package['weight_kg'] <= truck['max_weight_kg'] * 0.85 and\n", " truck['loaded_volume'] + package['volume_m3'] <= truck['max_volume_m3'] * 0.85):\n", " \n", " trucks.loc[truck_idx, 'loaded_weight'] += package['weight_kg']\n", " trucks.loc[truck_idx, 'loaded_volume'] += package['volume_m3']\n", " trucks.loc[truck_idx, 'packages'].append(package['package_id'])\n", " assigned = True\n", " break\n", " \n", " if not assigned:\n", " unassigned.append(package['package_id'])\n", " \n", " time_taken = time.time() - start_time\n", " \n", " return trucks, unassigned, time_taken\n", "\n", "# Run human strategy\n", "human_result, unassigned_human, human_time = human_loading_strategy(packages_df, trucks_df)\n", "\n", "print(\"👤 HUMAN APPROACH RESULTS:\")\n", "print(\"=\" * 50)\n", "print(f\"⏱️ Time taken: {human_time:.4f} seconds\")\n", "print(f\"📦 Packages assigned: {500 - len(unassigned_human)}/500\")\n", "print(f\"❌ Unassigned packages: {len(unassigned_human)}\")\n", "\n", "# Calculate utilization\n", "human_result['weight_util'] = (human_result['loaded_weight'] / human_result['max_weight_kg'] * 100)\n", "human_result['volume_util'] = (human_result['loaded_volume'] / human_result['max_volume_m3'] * 100)\n", "human_result['avg_util'] = (human_result['weight_util'] + human_result['volume_util']) / 2\n", "\n", "trucks_used = (human_result['loaded_weight'] > 0).sum()\n", "avg_utilization = human_result[human_result['loaded_weight'] > 0]['avg_util'].mean()\n", "\n", "print(f\"🚛 Trucks used: {trucks_used}/20\")\n", "print(f\"📊 Average utilization: {avg_utilization:.1f}%\")\n", "print(f\"\\n💰 Daily cost estimate: ${trucks_used * 500:.2f}\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### The AI Approach: Bin Packing Optimization\n", "This is what Flexport's algorithms do - consider thousands of combinations to find the best fit." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "def ai_optimized_loading(packages, trucks):\n", " \"\"\"\n", " AI-optimized loading using multiple strategies:\n", " 1. Sort packages by priority and size\n", " 2. Use best-fit decreasing algorithm\n", " 3. Consider package combinations\n", " 4. Optimize for both weight AND volume\n", " \"\"\"\n", " start_time = time.time()\n", " \n", " trucks = trucks.copy()\n", " trucks['loaded_weight'] = 0\n", " trucks['loaded_volume'] = 0\n", " trucks['packages'] = [[] for _ in range(len(trucks))]\n", " \n", " # Sort packages by priority, then by volume/weight ratio (density)\n", " packages = packages.copy()\n", " packages['density'] = packages['weight_kg'] / packages['volume_m3']\n", " packages['priority_score'] = packages['priority'].map({'Express': 3, 'Standard': 2, 'Economy': 1})\n", " \n", " # Smart sorting: Express first, then by size (large items first)\n", " packages = packages.sort_values(['priority_score', 'volume_m3'], ascending=[False, False])\n", " \n", " unassigned = []\n", " \n", " for _, package in packages.iterrows():\n", " best_truck = None\n", " best_score = float('inf')\n", " \n", " # Find the best truck for this package\n", " for truck_idx, truck in trucks.iterrows():\n", " # Check if package fits\n", " if (truck['loaded_weight'] + package['weight_kg'] <= truck['max_weight_kg'] and\n", " truck['loaded_volume'] + package['volume_m3'] <= truck['max_volume_m3']):\n", " \n", " # Calculate wasted space if we use this truck\n", " weight_remaining = truck['max_weight_kg'] - (truck['loaded_weight'] + package['weight_kg'])\n", " volume_remaining = truck['max_volume_m3'] - (truck['loaded_volume'] + package['volume_m3'])\n", " \n", " # Score based on how well the package fills remaining space\n", " waste_score = weight_remaining + volume_remaining * 100 # Volume is more critical\n", " \n", " if waste_score < best_score:\n", " best_score = waste_score\n", " best_truck = truck_idx\n", " \n", " if best_truck is not None:\n", " trucks.loc[best_truck, 'loaded_weight'] += package['weight_kg']\n", " trucks.loc[best_truck, 'loaded_volume'] += package['volume_m3']\n", " trucks.loc[best_truck, 'packages'].append(package['package_id'])\n", " else:\n", " unassigned.append(package['package_id'])\n", " \n", " time_taken = time.time() - start_time\n", " \n", " return trucks, unassigned, time_taken\n", "\n", "# Run AI strategy\n", "ai_result, unassigned_ai, ai_time = ai_optimized_loading(packages_df, trucks_df)\n", "\n", "print(\"🤖 AI OPTIMIZED RESULTS:\")\n", "print(\"=\" * 50)\n", "print(f\"⏱️ Time taken: {ai_time:.4f} seconds\")\n", "print(f\"📦 Packages assigned: {500 - len(unassigned_ai)}/500\")\n", "print(f\"❌ Unassigned packages: {len(unassigned_ai)}\")\n", "\n", "# Calculate utilization\n", "ai_result['weight_util'] = (ai_result['loaded_weight'] / ai_result['max_weight_kg'] * 100)\n", "ai_result['volume_util'] = (ai_result['loaded_volume'] / ai_result['max_volume_m3'] * 100)\n", "ai_result['avg_util'] = (ai_result['weight_util'] + ai_result['volume_util']) / 2\n", "\n", "trucks_used_ai = (ai_result['loaded_weight'] > 0).sum()\n", "avg_utilization_ai = ai_result[ai_result['loaded_weight'] > 0]['avg_util'].mean()\n", "\n", "print(f\"🚛 Trucks used: {trucks_used_ai}/20\")\n", "print(f\"📊 Average utilization: {avg_utilization_ai:.1f}%\")\n", "print(f\"\\n💰 Daily cost estimate: ${trucks_used_ai * 500:.2f}\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### The Comparison: See the Savings!" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Create comparison visualization\n", "fig, axes = plt.subplots(2, 2, figsize=(15, 10))\n", "fig.suptitle('Human vs AI Loading Strategy Comparison', fontsize=16, fontweight='bold')\n", "\n", "# Comparison data\n", "comparison = pd.DataFrame({\n", " 'Method': ['Human', 'AI'],\n", " 'Trucks Used': [trucks_used, trucks_used_ai],\n", " 'Avg Utilization': [avg_utilization, avg_utilization_ai],\n", " 'Packages Delivered': [500 - len(unassigned_human), 500 - len(unassigned_ai)],\n", " 'Time (seconds)': [human_time, ai_time]\n", "})\n", "\n", "# Plot 1: Trucks Used\n", "axes[0,0].bar(comparison['Method'], comparison['Trucks Used'], color=['#ff7f0e', '#2ca02c'])\n", "axes[0,0].set_title('Trucks Needed', fontweight='bold')\n", "axes[0,0].set_ylabel('Number of Trucks')\n", "axes[0,0].set_ylim(0, 20)\n", "for i, v in enumerate(comparison['Trucks Used']):\n", " axes[0,0].text(i, v + 0.5, str(v), ha='center', fontweight='bold')\n", "\n", "# Plot 2: Utilization\n", "axes[0,1].bar(comparison['Method'], comparison['Avg Utilization'], color=['#ff7f0e', '#2ca02c'])\n", "axes[0,1].set_title('Average Truck Utilization', fontweight='bold')\n", "axes[0,1].set_ylabel('Utilization %')\n", "axes[0,1].set_ylim(0, 100)\n", "for i, v in enumerate(comparison['Avg Utilization']):\n", " axes[0,1].text(i, v + 2, f'{v:.1f}%', ha='center', fontweight='bold')\n", "\n", "# Plot 3: Packages Delivered\n", "axes[1,0].bar(comparison['Method'], comparison['Packages Delivered'], color=['#ff7f0e', '#2ca02c'])\n", "axes[1,0].set_title('Packages Successfully Loaded', fontweight='bold')\n", "axes[1,0].set_ylabel('Number of Packages')\n", "axes[1,0].set_ylim(0, 520)\n", "for i, v in enumerate(comparison['Packages Delivered']):\n", " axes[1,0].text(i, v + 5, str(v), ha='center', fontweight='bold')\n", "\n", "# Plot 4: Cost Savings\n", "daily_cost_human = trucks_used * 500\n", "daily_cost_ai = trucks_used_ai * 500\n", "monthly_savings = (daily_cost_human - daily_cost_ai) * 20\n", "annual_savings = monthly_savings * 12\n", "\n", "savings_data = pd.DataFrame({\n", " 'Period': ['Daily', 'Monthly', 'Annual'],\n", " 'Savings': [daily_cost_human - daily_cost_ai, monthly_savings, annual_savings]\n", "})\n", "\n", "axes[1,1].bar(savings_data['Period'], savings_data['Savings'], color='#2ca02c')\n", "axes[1,1].set_title('💰 Cost Savings with AI', fontweight='bold')\n", "axes[1,1].set_ylabel('Savings ($)')\n", "for i, v in enumerate(savings_data['Savings']):\n", " axes[1,1].text(i, v + v*0.05, f'${v:,.0f}', ha='center', fontweight='bold')\n", "\n", "plt.tight_layout()\n", "plt.show()\n", "\n", "# Print summary\n", "print(\"\\n\" + \"=\"*60)\n", "print(\"💡 EXECUTIVE SUMMARY\")\n", "print(\"=\"*60)\n", "improvement = ((avg_utilization_ai - avg_utilization) / avg_utilization) * 100\n", "truck_reduction = ((trucks_used - trucks_used_ai) / trucks_used) * 100\n", "\n", "print(f\"✅ AI improved truck utilization by {improvement:.1f}%\")\n", "print(f\"✅ AI reduced trucks needed by {truck_reduction:.1f}%\")\n", "print(f\"✅ AI delivered {(500 - len(unassigned_ai)) - (500 - len(unassigned_human))} more packages\")\n", "print(f\"✅ AI was {human_time/ai_time:.0f}x faster\")\n", "print(f\"\\n💰 Annual savings: ${annual_savings:,.0f}\")\n", "print(f\"💰 ROI on AI implementation: {(annual_savings/50000)*100:.0f}% (assuming $50K implementation cost)\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Problem 2: Last-Mile Delivery Routing\n", "### The most expensive part of any delivery - getting it to the customer's door\n", "\n", "This is where Flexport saves the most money. Let's see why." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Generate delivery locations\n", "def generate_delivery_locations(n=50):\n", " \"\"\"Generate realistic delivery locations in a city\"\"\"\n", " \n", " # Center around a depot (lat, lon)\n", " depot_lat, depot_lon = 40.7580, -73.9855 # Times Square as depot\n", " \n", " locations = [{\n", " 'id': 'DEPOT',\n", " 'name': 'Distribution Center',\n", " 'lat': depot_lat,\n", " 'lon': depot_lon,\n", " 'delivery_time': 0,\n", " 'time_window': 'Always Open'\n", " }]\n", " \n", " for i in range(n):\n", " locations.append({\n", " 'id': f'DEL{i+1:03d}',\n", " 'name': f'Customer {i+1}',\n", " 'lat': depot_lat + np.random.uniform(-0.1, 0.1),\n", " 'lon': depot_lon + np.random.uniform(-0.1, 0.1),\n", " 'delivery_time': np.random.randint(5, 15), # minutes\n", " 'time_window': np.random.choice(['Morning', 'Afternoon', 'Evening', 'Anytime'])\n", " })\n", " \n", " return pd.DataFrame(locations)\n", "\n", "deliveries_df = generate_delivery_locations(50)\n", "\n", "print(\"📍 Generated 50 delivery locations in Manhattan\")\n", "print(deliveries_df.head())\n", "print(f\"\\n📊 Delivery Statistics:\")\n", "print(deliveries_df.groupby('time_window').size())" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "def calculate_distance(lat1, lon1, lat2, lon2):\n", " \"\"\"Calculate distance between two points (simplified Manhattan distance)\"\"\"\n", " # Manhattan distance is more realistic for city driving\n", " return abs(lat1 - lat2) + abs(lon1 - lon2)\n", "\n", "def calculate_distance_matrix(locations):\n", " \"\"\"Create distance matrix between all locations\"\"\"\n", " n = len(locations)\n", " distances = np.zeros((n, n))\n", " \n", " for i in range(n):\n", " for j in range(n):\n", " if i != j:\n", " distances[i][j] = calculate_distance(\n", " locations.iloc[i]['lat'], locations.iloc[i]['lon'],\n", " locations.iloc[j]['lat'], locations.iloc[j]['lon']\n", " ) * 111 # Convert to km (approximate)\n", " \n", " return distances\n", "\n", "distance_matrix = calculate_distance_matrix(deliveries_df)\n", "\n", "print(\"📐 Distance matrix calculated!\")\n", "print(f\"Total possible routes: {np.math.factorial(len(deliveries_df)-1):,} (that's why we need AI!)\")\n", "print(f\"Average distance between locations: {distance_matrix[distance_matrix > 0].mean():.2f} km\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Human Route Planning: Sequential Delivery\n", "This is what drivers do without optimization - go to nearest customer, repeat." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "def human_route_planning(deliveries, distance_matrix):\n", " \"\"\"Simulate human route planning - nearest neighbor approach\"\"\"\n", " start_time = time.time()\n", " \n", " n = len(deliveries)\n", " visited = [False] * n\n", " route = [0] # Start at depot\n", " visited[0] = True\n", " current = 0\n", " total_distance = 0\n", " \n", " # Visit each customer\n", " for _ in range(n - 1):\n", " nearest = None\n", " min_dist = float('inf')\n", " \n", " # Find nearest unvisited customer\n", " for i in range(n):\n", " if not visited[i] and distance_matrix[current][i] < min_dist:\n", " min_dist = distance_matrix[current][i]\n", " nearest = i\n", " \n", " if nearest is not None:\n", " route.append(nearest)\n", " visited[nearest] = True\n", " total_distance += min_dist\n", " current = nearest\n", " \n", " # Return to depot\n", " route.append(0)\n", " total_distance += distance_matrix[current][0]\n", " \n", " time_taken = time.time() - start_time\n", " \n", " # Calculate total time (distance + delivery time)\n", " total_time = total_distance * 2 # Assume 30 km/h average speed\n", " for stop in route[1:-1]:\n", " total_time += deliveries.iloc[stop]['delivery_time']\n", " \n", " return route, total_distance, total_time, time_taken\n", "\n", "human_route, human_distance, human_delivery_time, human_compute_time = human_route_planning(\n", " deliveries_df, distance_matrix\n", ")\n", "\n", "print(\"👤 HUMAN ROUTE PLANNING:\")\n", "print(\"=\" * 50)\n", "print(f\"📍 Route: Depot → {len(human_route)-2} customers → Depot\")\n", "print(f\"📏 Total distance: {human_distance:.2f} km\")\n", "print(f\"⏱️ Total delivery time: {human_delivery_time:.0f} minutes ({human_delivery_time/60:.1f} hours)\")\n", "print(f\"💭 Planning time: {human_compute_time:.4f} seconds\")\n", "print(f\"💰 Cost (@$2.50/km): ${human_distance * 2.5:.2f}\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### AI Route Optimization: Multiple Algorithms\n", "This uses 2-opt improvements - the same technique Amazon uses for same-day delivery." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "def two_opt_improvement(route, distance_matrix):\n", " \"\"\"Apply 2-opt improvement to a route\"\"\"\n", " improved = True\n", " best_route = route.copy()\n", " \n", " while improved:\n", " improved = False\n", " \n", " for i in range(1, len(route) - 2):\n", " for j in range(i + 1, len(route)):\n", " if j - i == 1:\n", " continue\n", " \n", " new_route = best_route.copy()\n", " new_route[i:j] = reversed(best_route[i:j])\n", " \n", " # Calculate distances\n", " old_distance = calculate_route_distance(best_route, distance_matrix)\n", " new_distance = calculate_route_distance(new_route, distance_matrix)\n", " \n", " if new_distance < old_distance:\n", " best_route = new_route\n", " improved = True\n", " break\n", " \n", " if improved:\n", " break\n", " \n", " return best_route\n", "\n", "def calculate_route_distance(route, distance_matrix):\n", " \"\"\"Calculate total distance for a route\"\"\"\n", " total = 0\n", " for i in range(len(route) - 1):\n", " total += distance_matrix[route[i]][route[i + 1]]\n", " return total\n", "\n", "def ai_route_optimization(deliveries, distance_matrix):\n", " \"\"\"AI-optimized route planning using multiple strategies\"\"\"\n", " start_time = time.time()\n", " \n", " # Start with nearest neighbor\n", " initial_route, _, _, _ = human_route_planning(deliveries, distance_matrix)\n", " \n", " # Apply 2-opt improvement\n", " optimized_route = two_opt_improvement(initial_route, distance_matrix)\n", " \n", " # Calculate metrics\n", " total_distance = calculate_route_distance(optimized_route, distance_matrix)\n", " \n", " # Calculate total time\n", " total_time = total_distance * 2 # 30 km/h average\n", " for stop in optimized_route[1:-1]:\n", " total_time += deliveries.iloc[stop]['delivery_time']\n", " \n", " time_taken = time.time() - start_time\n", " \n", " return optimized_route, total_distance, total_time, time_taken\n", "\n", "ai_route, ai_distance, ai_delivery_time, ai_compute_time = ai_route_optimization(\n", " deliveries_df, distance_matrix\n", ")\n", "\n", "print(\"🤖 AI OPTIMIZED ROUTE:\")\n", "print(\"=\" * 50)\n", "print(f\"📍 Route: Depot → {len(ai_route)-2} customers → Depot\")\n", "print(f\"📏 Total distance: {ai_distance:.2f} km\")\n", "print(f\"⏱️ Total delivery time: {ai_delivery_time:.0f} minutes ({ai_delivery_time/60:.1f} hours)\")\n", "print(f\"💭 Optimization time: {ai_compute_time:.4f} seconds\")\n", "print(f\"💰 Cost (@$2.50/km): ${ai_distance * 2.5:.2f}\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Visualize the Routes: See the Difference!" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Visualize both routes\n", "fig, axes = plt.subplots(1, 2, figsize=(16, 8))\n", "\n", "def plot_route(ax, route, deliveries, title, distance, color):\n", " \"\"\"Plot a delivery route on a map\"\"\"\n", " \n", " # Plot all delivery points\n", " ax.scatter(deliveries['lon'], deliveries['lat'], c='lightgray', s=50, alpha=0.6)\n", " \n", " # Plot route\n", " route_lons = [deliveries.iloc[i]['lon'] for i in route]\n", " route_lats = [deliveries.iloc[i]['lat'] for i in route]\n", " \n", " ax.plot(route_lons, route_lats, color=color, linewidth=2, alpha=0.7)\n", " \n", " # Highlight depot\n", " ax.scatter(deliveries.iloc[0]['lon'], deliveries.iloc[0]['lat'], \n", " c='red', s=200, marker='s', label='Depot', zorder=5)\n", " \n", " # Add route order numbers\n", " for i, stop in enumerate(route[1:-1], 1):\n", " ax.annotate(str(i), \n", " (deliveries.iloc[stop]['lon'], deliveries.iloc[stop]['lat']),\n", " fontsize=8, ha='center', va='center',\n", " bbox=dict(boxstyle='circle', facecolor='white', alpha=0.8))\n", " \n", " ax.set_title(f'{title}\\nDistance: {distance:.1f} km', fontsize=14, fontweight='bold')\n", " ax.set_xlabel('Longitude')\n", " ax.set_ylabel('Latitude')\n", " ax.legend()\n", " ax.grid(True, alpha=0.3)\n", "\n", "# Plot human route\n", "plot_route(axes[0], human_route, deliveries_df, '👤 Human Route (Nearest Neighbor)', \n", " human_distance, '#ff7f0e')\n", "\n", "# Plot AI route\n", "plot_route(axes[1], ai_route, deliveries_df, '🤖 AI Optimized Route (2-opt)', \n", " ai_distance, '#2ca02c')\n", "\n", "plt.suptitle('Delivery Route Comparison: Human vs AI', fontsize=16, fontweight='bold')\n", "plt.tight_layout()\n", "plt.show()\n", "\n", "# Calculate improvements\n", "distance_improvement = (human_distance - ai_distance) / human_distance * 100\n", "time_improvement = (human_delivery_time - ai_delivery_time) / human_delivery_time * 100\n", "cost_savings = (human_distance - ai_distance) * 2.5\n", "\n", "print(\"\\n\" + \"=\"*60)\n", "print(\"🎯 OPTIMIZATION RESULTS\")\n", "print(\"=\"*60)\n", "print(f\"✅ Distance reduced by: {distance_improvement:.1f}%\")\n", "print(f\"✅ Delivery time reduced by: {time_improvement:.1f}%\")\n", "print(f\"✅ Cost savings per route: ${cost_savings:.2f}\")\n", "print(f\"✅ AI optimization was {ai_compute_time/human_compute_time:.1f}x slower but found better solution\")\n", "print(f\"\\n💰 If you run 20 routes per day:\")\n", "print(f\" Daily savings: ${cost_savings * 20:.2f}\")\n", "print(f\" Monthly savings: ${cost_savings * 20 * 22:.2f}\")\n", "print(f\" Annual savings: ${cost_savings * 20 * 22 * 12:,.2f}\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Problem 3: Multi-Modal Shipping Optimization\n", "### The Flexport Special: Choosing between air, sea, and ground\n", "\n", "This is where Flexport makes companies millions - optimizing the mode of transport." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Create shipping scenario from China to US\n", "def create_shipping_scenario():\n", " \"\"\"Create realistic international shipping scenario\"\"\"\n", " \n", " # US cities and their demand\n", " cities = [\n", " {'city': 'New York', 'demand': 1500, 'priority': 'High'},\n", " {'city': 'Los Angeles', 'demand': 2000, 'priority': 'High'},\n", " {'city': 'Chicago', 'demand': 1200, 'priority': 'Medium'},\n", " {'city': 'Houston', 'demand': 800, 'priority': 'Medium'},\n", " {'city': 'Phoenix', 'demand': 600, 'priority': 'Low'},\n", " {'city': 'Philadelphia', 'demand': 700, 'priority': 'Medium'},\n", " {'city': 'San Antonio', 'demand': 500, 'priority': 'Low'},\n", " {'city': 'San Diego', 'demand': 900, 'priority': 'Medium'},\n", " {'city': 'Dallas', 'demand': 1100, 'priority': 'High'},\n", " {'city': 'San Jose', 'demand': 1300, 'priority': 'High'}\n", " ]\n", " \n", " # Shipping options\n", " shipping_modes = pd.DataFrame({\n", " 'mode': ['Sea Freight', 'Air Freight', 'Rail+Truck'],\n", " 'cost_per_unit': [0.80, 8.00, 2.00],\n", " 'transit_days': [30, 3, 18],\n", " 'reliability': [0.85, 0.95, 0.75],\n", " 'capacity': [10000, 1000, 5000],\n", " 'co2_per_unit': [0.5, 5.0, 1.5] # kg CO2 per unit\n", " })\n", " \n", " return pd.DataFrame(cities), shipping_modes\n", "\n", "cities_df, shipping_modes = create_shipping_scenario()\n", "\n", "print(\"🌍 INTERNATIONAL SHIPPING SCENARIO\")\n", "print(\"=\" * 50)\n", "print(f\"Origin: Shenzhen, China\")\n", "print(f\"Destinations: {len(cities_df)} US cities\")\n", "print(f\"Total demand: {cities_df['demand'].sum():,} units\")\n", "print(f\"Product value: $100 per unit\")\n", "print(f\"Holding cost: $0.50 per unit per day\")\n", "print(f\"Stockout cost: $5.00 per unit per day\\n\")\n", "\n", "print(\"📦 Shipping Options:\")\n", "print(shipping_modes.to_string(index=False))" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "def calculate_total_cost(mode, demand, holding_cost=0.5, stockout_cost=5.0):\n", " \"\"\"Calculate total cost including shipping, holding, and stockout risks\"\"\"\n", " \n", " shipping_cost = mode['cost_per_unit'] * demand\n", " holding_cost_total = holding_cost * demand * mode['transit_days']\n", " \n", " # Risk of stockout (simplified)\n", " stockout_risk = (1 - mode['reliability']) * demand * stockout_cost * 5 # 5 days average stockout\n", " \n", " total_cost = shipping_cost + holding_cost_total + stockout_risk\n", " \n", " return {\n", " 'shipping': shipping_cost,\n", " 'holding': holding_cost_total,\n", " 'risk': stockout_risk,\n", " 'total': total_cost\n", " }\n", "\n", "def human_shipping_decision(cities, modes):\n", " \"\"\"Simulate human decision: use cheapest for low priority, fastest for high\"\"\"\n", " \n", " allocations = []\n", " total_cost = 0\n", " total_co2 = 0\n", " \n", " for _, city in cities.iterrows():\n", " if city['priority'] == 'High':\n", " # Use air for high priority\n", " mode = modes[modes['mode'] == 'Air Freight'].iloc[0]\n", " elif city['priority'] == 'Medium':\n", " # Use rail for medium\n", " mode = modes[modes['mode'] == 'Rail+Truck'].iloc[0]\n", " else:\n", " # Use sea for low\n", " mode = modes[modes['mode'] == 'Sea Freight'].iloc[0]\n", " \n", " costs = calculate_total_cost(mode, city['demand'])\n", " total_cost += costs['total']\n", " total_co2 += mode['co2_per_unit'] * city['demand']\n", " \n", " allocations.append({\n", " 'city': city['city'],\n", " 'demand': city['demand'],\n", " 'mode': mode['mode'],\n", " 'cost': costs['total'],\n", " 'transit_days': mode['transit_days']\n", " })\n", " \n", " return pd.DataFrame(allocations), total_cost, total_co2\n", "\n", "human_allocations, human_total_cost, human_co2 = human_shipping_decision(cities_df, shipping_modes)\n", "\n", "print(\"👤 HUMAN SHIPPING STRATEGY:\")\n", "print(\"=\" * 50)\n", "print(human_allocations)\n", "print(f\"\\n💰 Total cost: ${human_total_cost:,.2f}\")\n", "print(f\"🌱 Total CO2: {human_co2:,.0f} kg\")" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "def ai_optimized_shipping(cities, modes):\n", " \"\"\"AI optimization considering all factors simultaneously\"\"\"\n", " \n", " allocations = []\n", " total_cost = 0\n", " total_co2 = 0\n", " \n", " for _, city in cities.iterrows():\n", " best_mode = None\n", " best_cost = float('inf')\n", " \n", " # Evaluate all modes for each city\n", " for _, mode in modes.iterrows():\n", " costs = calculate_total_cost(mode, city['demand'])\n", " \n", " # Add priority weighting\n", " if city['priority'] == 'High' and mode['transit_days'] > 10:\n", " costs['total'] *= 1.5 # Penalty for slow shipping on high priority\n", " elif city['priority'] == 'Low' and mode['transit_days'] < 10:\n", " costs['total'] *= 1.2 # Penalty for fast shipping on low priority\n", " \n", " if costs['total'] < best_cost:\n", " best_cost = costs['total']\n", " best_mode = mode\n", " \n", " total_cost += best_cost\n", " total_co2 += best_mode['co2_per_unit'] * city['demand']\n", " \n", " allocations.append({\n", " 'city': city['city'],\n", " 'demand': city['demand'],\n", " 'mode': best_mode['mode'],\n", " 'cost': best_cost,\n", " 'transit_days': best_mode['transit_days']\n", " })\n", " \n", " return pd.DataFrame(allocations), total_cost, total_co2\n", "\n", "ai_allocations, ai_total_cost, ai_co2 = ai_optimized_shipping(cities_df, shipping_modes)\n", "\n", "print(\"🤖 AI OPTIMIZED SHIPPING:\")\n", "print(\"=\" * 50)\n", "print(ai_allocations)\n", "print(f\"\\n💰 Total cost: ${ai_total_cost:,.2f}\")\n", "print(f\"🌱 Total CO2: {ai_co2:,.0f} kg\")" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Compare shipping strategies\n", "fig, axes = plt.subplots(2, 2, figsize=(15, 10))\n", "fig.suptitle('Human vs AI Shipping Strategy Comparison', fontsize=16, fontweight='bold')\n", "\n", "# Mode distribution comparison\n", "human_mode_dist = human_allocations.groupby('mode')['demand'].sum()\n", "ai_mode_dist = ai_allocations.groupby('mode')['demand'].sum()\n", "\n", "x = np.arange(len(shipping_modes['mode']))\n", "width = 0.35\n", "\n", "axes[0,0].bar(x - width/2, [human_mode_dist.get(m, 0) for m in shipping_modes['mode']], \n", " width, label='Human', color='#ff7f0e')\n", "axes[0,0].bar(x + width/2, [ai_mode_dist.get(m, 0) for m in shipping_modes['mode']], \n", " width, label='AI', color='#2ca02c')\n", "axes[0,0].set_xlabel('Shipping Mode')\n", "axes[0,0].set_ylabel('Units Shipped')\n", "axes[0,0].set_title('Shipping Mode Distribution')\n", "axes[0,0].set_xticks(x)\n", "axes[0,0].set_xticklabels(shipping_modes['mode'], rotation=45)\n", "axes[0,0].legend()\n", "\n", "# Cost breakdown\n", "cost_comparison = pd.DataFrame({\n", " 'Human': [human_total_cost],\n", " 'AI': [ai_total_cost]\n", "})\n", "\n", "axes[0,1].bar(['Human', 'AI'], [human_total_cost, ai_total_cost], \n", " color=['#ff7f0e', '#2ca02c'])\n", "axes[0,1].set_ylabel('Total Cost ($)')\n", "axes[0,1].set_title('Total Shipping Cost')\n", "for i, v in enumerate([human_total_cost, ai_total_cost]):\n", " axes[0,1].text(i, v + v*0.02, f'${v:,.0f}', ha='center', fontweight='bold')\n", "\n", "# CO2 emissions\n", "axes[1,0].bar(['Human', 'AI'], [human_co2, ai_co2], \n", " color=['#ff7f0e', '#2ca02c'])\n", "axes[1,0].set_ylabel('CO2 Emissions (kg)')\n", "axes[1,0].set_title('Environmental Impact')\n", "for i, v in enumerate([human_co2, ai_co2]):\n", " axes[1,0].text(i, v + v*0.02, f'{v:,.0f} kg', ha='center', fontweight='bold')\n", "\n", "# Savings summary\n", "savings = human_total_cost - ai_total_cost\n", "co2_reduction = human_co2 - ai_co2\n", "savings_pct = (savings / human_total_cost) * 100\n", "co2_pct = (co2_reduction / human_co2) * 100\n", "\n", "summary_text = f\"\"\"💰 Cost Savings: ${savings:,.2f} ({savings_pct:.1f}%)\n", "🌱 CO2 Reduction: {co2_reduction:,.0f} kg ({co2_pct:.1f}%)\n", "\n", "Annual Impact (weekly shipments):\n", "• Cost Savings: ${savings * 52:,.0f}\n", "• CO2 Reduction: {co2_reduction * 52:,.0f} kg\n", "\n", "This is exactly how Flexport saves\n", "companies 8-10% on logistics!\"\"\"\n", "\n", "axes[1,1].text(0.1, 0.5, summary_text, transform=axes[1,1].transAxes,\n", " fontsize=12, verticalalignment='center',\n", " bbox=dict(boxstyle='round', facecolor='lightgreen', alpha=0.5))\n", "axes[1,1].axis('off')\n", "\n", "plt.tight_layout()\n", "plt.show()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Bonus: Using AI (GPT/Claude) for Optimization\n", "### Here's how to use GenAI to solve these problems at scale" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Generate prompt for AI optimization\n", "def generate_ai_prompt(packages, trucks):\n", " \"\"\"Generate a prompt that you can paste into ChatGPT/Claude\"\"\"\n", " \n", " prompt = f\"\"\"\n", "I need to optimize container loading for a logistics operation. Here's my scenario:\n", "\n", "PACKAGES TO SHIP:\n", "- Total packages: {len(packages)}\n", "- Total weight: {packages['weight_kg'].sum():.1f} kg\n", "- Total volume: {packages['volume_m3'].sum():.1f} m³\n", "- Priority breakdown:\n", " * Express: {(packages['priority'] == 'Express').sum()} packages\n", " * Standard: {(packages['priority'] == 'Standard').sum()} packages\n", " * Economy: {(packages['priority'] == 'Economy').sum()} packages\n", "\n", "AVAILABLE TRUCKS:\n", "- Total trucks: {len(trucks)}\n", "- Fleet capacity: {trucks['max_weight_kg'].sum()} kg, {trucks['max_volume_m3'].sum()} m³\n", "- Truck types: {trucks['type'].value_counts().to_dict()}\n", "\n", "CONSTRAINTS:\n", "1. Each truck has weight AND volume limits\n", "2. Express packages must be loaded first\n", "3. Fragile items need special handling\n", "4. Minimize the number of trucks used\n", "5. Maximize utilization of used trucks\n", "\n", "Please provide:\n", "1. Optimal loading strategy\n", "2. Number of trucks needed\n", "3. Average utilization percentage\n", "4. Which packages go in which trucks (high-level grouping)\n", "5. Estimated cost savings vs. random loading\n", "\n", "Format the output so I can paste it directly into Excel.\n", "\"\"\"\n", " \n", " return prompt\n", "\n", "# Generate the prompt\n", "ai_prompt = generate_ai_prompt(packages_df, trucks_df)\n", "\n", "print(\"📋 COPY THIS PROMPT TO CHATGPT/CLAUDE:\")\n", "print(\"=\" * 60)\n", "print(ai_prompt)\n", "print(\"=\" * 60)\n", "print(\"\\n💡 Pro tip: Add your actual data as CSV for even better results!\")" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Export data for use with AI tools\n", "def export_for_ai(packages, trucks, deliveries):\n", " \"\"\"Export data in formats that work with AI tools\"\"\"\n", " \n", " # Save to CSV files\n", " packages.to_csv('packages_for_ai.csv', index=False)\n", " trucks.to_csv('trucks_for_ai.csv', index=False)\n", " deliveries.to_csv('deliveries_for_ai.csv', index=False)\n", " \n", " print(\"✅ Data exported to CSV files!\")\n", " print(\"\\nYou can now:\")\n", " print(\"1. Upload these CSVs to ChatGPT/Claude\")\n", " print(\"2. Ask: 'Optimize the loading of packages.csv into trucks.csv'\")\n", " print(\"3. Get back Python code or Excel formulas to solve it!\")\n", " \n", " # Create a sample JSON for API calls\n", " api_data = {\n", " \"packages\": packages.head(10).to_dict('records'),\n", " \"trucks\": trucks.head(5).to_dict('records'),\n", " \"objective\": \"minimize trucks used while maximizing utilization\"\n", " }\n", " \n", " with open('optimization_request.json', 'w') as f:\n", " json.dump(api_data, f, indent=2)\n", " \n", " print(\"\\n📄 Sample API request saved to optimization_request.json\")\n", " return api_data\n", "\n", "api_data = export_for_ai(packages_df, trucks_df, deliveries_df)\n", "print(\"\\n🎯 Sample API payload:\")\n", "print(json.dumps(api_data, indent=2)[:500] + \"...\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Final Dashboard: Your Optimization Scorecard\n", "### This is what you'd show to executives" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Create executive dashboard\n", "print(\"=\" * 70)\n", "print(\"📊 EXECUTIVE DASHBOARD: AI OPTIMIZATION IMPACT\")\n", "print(\"=\" * 70)\n", "print(f\"Company: Your Logistics Co. | Date: {datetime.now().strftime('%Y-%m-%d')}\")\n", "print(\"-\" * 70)\n", "\n", "# Problem 1: Container Loading\n", "loading_savings = (trucks_used - trucks_used_ai) * 500 * 252 # Annual\n", "print(\"\\n📦 CONTAINER LOADING OPTIMIZATION\")\n", "print(f\" Before AI: {trucks_used} trucks/day @ 65% utilization\")\n", "print(f\" After AI: {trucks_used_ai} trucks/day @ {avg_utilization_ai:.0f}% utilization\")\n", "print(f\" Annual Savings: ${loading_savings:,.0f}\")\n", "\n", "# Problem 2: Route Optimization \n", "routing_savings = cost_savings * 20 * 252 # Annual\n", "print(\"\\n🚚 DELIVERY ROUTE OPTIMIZATION\")\n", "print(f\" Distance Reduction: {distance_improvement:.1f}%\")\n", "print(f\" Time Saved: {(human_delivery_time - ai_delivery_time)/60:.1f} hours/day\")\n", "print(f\" Annual Savings: ${routing_savings:,.0f}\")\n", "\n", "# Problem 3: Multi-modal Shipping\n", "shipping_savings = savings * 52 # Annual\n", "print(\"\\n✈️ INTERNATIONAL SHIPPING OPTIMIZATION\")\n", "print(f\" Cost Reduction: {savings_pct:.1f}%\")\n", "print(f\" CO2 Reduction: {co2_reduction*52:,.0f} kg/year\")\n", "print(f\" Annual Savings: ${shipping_savings:,.0f}\")\n", "\n", "# Total Impact\n", "total_savings = loading_savings + routing_savings + shipping_savings\n", "print(\"\\n\" + \"=\" * 70)\n", "print(\"💰 TOTAL ANNUAL IMPACT\")\n", "print(\"=\" * 70)\n", "print(f\" Total Savings: ${total_savings:,.0f}\")\n", "print(f\" ROI (assuming $200K implementation): {(total_savings/200000)*100:.0f}%\")\n", "print(f\" Payback Period: {200000/total_savings*12:.1f} months\")\n", "print(f\"\\n This is a {(total_savings/5000000)*100:.1f}% reduction on $5M annual logistics spend\")\n", "print(f\" Exactly in line with Flexport's 8-10% savings promise! 🎯\")\n", "print(\"\\n\" + \"=\" * 70)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 🎓 Key Takeaways for Students\n", "\n", "### What You Just Learned:\n", "1. **The math behind logistics** - It's not magic, it's algorithms\n", "2. **Why AI wins** - It considers millions of options in seconds\n", "3. **Real savings** - 8-10% is standard, 30%+ is possible\n", "4. **Domain knowledge matters** - AI needs you to define \"good\"\n", "\n", "### Your Homework Challenge:\n", "1. Take a local business (pizza delivery, flower shop, etc.)\n", "2. Map their delivery locations (10-20 stops)\n", "3. Use this code to optimize their routes\n", "4. Calculate their potential savings\n", "5. Present: \"How I'd save [Business] $X per year\"\n", "\n", "### Career Tip:\n", "Companies hiring for operations roles want people who can:\n", "- Understand the problem (you just did that)\n", "- Use tools to solve it (Python + AI)\n", "- Communicate the value (dashboards and savings)\n", "\n", "You just learned all three. Welcome to the future of operations! 🚀" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.10.6" } }, "nbformat": 4, "nbformat_minor": 4 }