Global Logistics Network Optimization with Genetic Algorithms

Case Study: Saving $10.8M USD and Reducing 35k Tons of CO2

Python Genetic Algorithms Plotly Folium Pandas

# Introduction: The Fictitious Contract

This project presents a high-complexity fictitious simulation designed to model the logistics of a 24-node international distribution network. The goal is not to dictate a sports calendar, but to demonstrate how Operations Research and Data Science solve the core dilemma of modern management: How to be profitable without sacrificing ESG goals?

In supply chain management, the 'intuitive route' is often the most expensive. When operating complex global networks, human planning tends to follow inefficient historical patterns.

The Challenge: F1 is a global 'logistics circus' moving tons of cargo across 24 venues in 9 months. The core problem is legacy 'spaghetti routes' involving redundant trans-Atlantic jumps.

The Goal: Develop a mathematical model capable of minimizing total travel distance while respecting strict climate constraints and non-negotiable commercial rules.

# The Result: Quantifiable Efficiency

Applying a proprietary mathematical optimization model, we challenged the operational baseline. Here is the financial and operational impact achieved after the final algorithm validation:

💰
Net Savings
$10.8M USD
Logistics OpEx Reduction
📉
Distance
-26.5%
From 114k km to 84k km
🌿
CO2 Avoided
35,420 t
Carbon Footprint
Validation
100%
0 Regional Violations

# The Solution: Computational Evolution

To solve the factorial complexity (24! combinations), we developed a Genetic Algorithm that simulates evolution to find the most efficient solution. We implemented a fixed seed (Random Seed 42) to guarantee the scientific reproducibility of the results.

Why can't we just travel in a straight line? Because the real world has rules. Adverse weather, delivery dates, and fixed contracts. To solve this, I didn't use a rigid model. I developed a Risk Traffic Light Model.

# Tiered Risk Management

The algorithm has 'permission' to negotiate: if arriving at a destination on a 'non-ideal' date saves millions in air freight, the system evaluates if it's worth paying the mitigation cost.

Green Zone

Deviation ≤ 7 Days

Standard operation in ideal window.

$0

Yellow Zone

Deviation ≤ 45 Days

Risk accepted by paying mitigation costs.

Penalty: $2.5M

Red Zone

Deviation > 45 Days

Hard constraint (Snow/Monsoons). Infeasible.

Penalty: $100M

This logic allowed the algorithm to find temporal 'shortcuts' that a human planner would have discarded out of fear of risk, achieving a mathematical balance between safety and savings.

# Geospatial Visualization

The result is not just numerical, it's physical. The optimization eliminated redundant trans-Atlantic crossings, creating a fluid route that sweeps geographic regions (Oceania, Asia, Middle East, Americas, Europe) efficiently.

F1 Map Optimization
Open Interactive Simulation 🌍

*Note: Opens in a new tab. Compare the original route (red) vs. optimized (green) with free zoom.

A Glimpse into the Algorithmic Core

This is the simplified 'Fitness' function that evaluates each route. Observe how financial penalties are integrated directly into the total cost calculation, forcing the algorithm's DNA to avoid the Red Zone.

sustainable_optimizer.py
# --- 3. MOTOR DE OPTIMIZACIÓN (CON EARLY STOPPING AJUSTADO) ---
class SustainableOptimizer:
    def __init__(self, data_manager, pop_size=100, generations=500, mutation_rate=0.20):
        self.dm = data_manager
        self.pop_size = pop_size
        self.generations = generations
        self.mutation_rate = mutation_rate
        self.history = []
        
        # OBTENER ANCLAS
        self.fixed_start, self.fixed_end = self.dm.get_fixed_start_end_indices()
        all_indices = set(range(self.dm.num_races))
        self.middle_indices = list(all_indices - {self.fixed_start, self.fixed_end})

    def _calculate_logistics_kpi(self, total_dist_km):
        p = self.dm.params
        fuel_liters = total_dist_km * 12 
        total_co2_ton = (fuel_liters * 3.16) / 1000
        costo_fuel = fuel_liters * p['Costo_JetFuel_USD_L']
        costo_ops = total_dist_km * 250 
        total_cost_usd = costo_fuel + costo_ops
        return total_cost_usd, total_co2_ton, fuel_liters

    def _check_date_constraints(self, route):
        penalty_score = 0
        violations = 0
        current_date = datetime(2025, 3, 1) 
        
        for race_idx in route:
            # Lógica de ventanas de tiempo...
            if win_start <= current_date <= win_end: days_diff = 0
            else:
                diff_start = abs((current_date - win_start).days)
                diff_end = abs((current_date - win_end).days)
                days_diff = min(diff_start, diff_end)
            
            # SEMÁFORO DE RIESGO
            if days_diff <= 7: penalty_score += 0
            elif days_diff <= 45: penalty_score += 2_500_000 
            else:
                penalty_score += 100_000_000 
                violations += 1
            current_date += timedelta(days=11)
        return penalty_score, violations

    def fitness(self, route):
        total_dist = 0
        for i in range(len(route) - 1):
            total_dist += self.dm.distance_matrix[route[i]][route[i+1]]
        cost_usd, co2_ton, fuel_L = self._calculate_logistics_kpi(total_dist)
        date_penalty, _ = self._check_date_constraints(route)
        total_score = cost_usd + date_penalty
        return total_score, total_dist, cost_usd

    # --- MÉTODO RUN CON PACIENCIA (150) ---
    def run(self):
        population = []
        # Inicialización de población...
        
        best_route = None
        best_fitness = float('inf')
        
        # CONFIGURACIÓN DE PARADA
        generations_without_improvement = 0
        PATIENCE_LIMIT = 150 
        
        for gen in range(self.generations):
            pop_fitness = []
            for indiv in population:
                score, _, _ = self.fitness(indiv)
                pop_fitness.append((score, indiv))
                
                if score < best_fitness:
                    best_fitness = score
                    best_route = indiv
                    generations_without_improvement = 0
            
            if pop_fitness[0][0] >= best_fitness:
                generations_without_improvement += 1
            
            # EARLY STOPPING
            if generations_without_improvement >= PATIENCE_LIMIT:
                break

            # Selección, Cruce y Mutación...
            # (Código abreviado para visualización)

        return best_route, best_fitness
# --- 3. MOTOR DE OPTIMIZACIÓN (CON EARLY STOPPING AJUSTADO) ---
class SustainableOptimizer:
    def __init__(self, data_manager, pop_size=100, generations=500, mutation_rate=0.20):
        self.dm = data_manager
        self.pop_size = pop_size
        self.generations = generations
        self.mutation_rate = mutation_rate
        self.history = []
        
        # OBTENER ANCLAS
        self.fixed_start, self.fixed_end = self.dm.get_fixed_start_end_indices()
        all_indices = set(range(self.dm.num_races))
        self.middle_indices = list(all_indices - {self.fixed_start, self.fixed_end})

    def _calculate_logistics_kpi(self, total_dist_km):
        p = self.dm.params
        fuel_liters = total_dist_km * 12 
        total_co2_ton = (fuel_liters * 3.16) / 1000
        costo_fuel = fuel_liters * p['Costo_JetFuel_USD_L']
        costo_ops = total_dist_km * 250 
        total_cost_usd = costo_fuel + costo_ops
        return total_cost_usd, total_co2_ton, fuel_liters

    def _check_date_constraints(self, route):
        penalty_score = 0
        violations = 0
        current_date = datetime(2025, 3, 1) 
        
        for race_idx in route:
            # Lógica de ventanas de tiempo...
            if win_start <= current_date <= win_end: days_diff = 0
            else:
                diff_start = abs((current_date - win_start).days)
                diff_end = abs((current_date - win_end).days)
                days_diff = min(diff_start, diff_end)
            
            # SEMÁFORO DE RIESGO
            if days_diff <= 7: penalty_score += 0
            elif days_diff <= 45: penalty_score += 2_500_000 
            else:
                penalty_score += 100_000_000 
                violations += 1
            current_date += timedelta(days=11)
        return penalty_score, violations

    def fitness(self, route):
        total_dist = 0
        for i in range(len(route) - 1):
            total_dist += self.dm.distance_matrix[route[i]][route[i+1]]
        cost_usd, co2_ton, fuel_L = self._calculate_logistics_kpi(total_dist)
        date_penalty, _ = self._check_date_constraints(route)
        total_score = cost_usd + date_penalty
        return total_score, total_dist, cost_usd

    # --- MÉTODO RUN CON PACIENCIA (150) ---
    def run(self):
        population = []
        # Inicialización de población...
        
        best_route = None
        best_fitness = float('inf')
        
        # CONFIGURACIÓN DE PARADA
        generations_without_improvement = 0
        PATIENCE_LIMIT = 150 
        
        for gen in range(self.generations):
            pop_fitness = []
            for indiv in population:
                score, _, _ = self.fitness(indiv)
                pop_fitness.append((score, indiv))
                
                if score < best_fitness:
                    best_fitness = score
                    best_route = indiv
                    generations_without_improvement = 0
            
            if pop_fitness[0][0] >= best_fitness:
                generations_without_improvement += 1
            
            # EARLY STOPPING
            if generations_without_improvement >= PATIENCE_LIMIT:
                break

            # Selección, Cruce y Mutación...
            # (Código abreviado para visualización)

        return best_route, best_fitness

# Code Architecture

The project uses a modular Object-Oriented (OOP) architecture for scalability:

  • Data Management: Dynamic CSV loading and geographic anchors.
  • Optimization Engine: Genetic Algorithm with Early Stopping.
  • Visualization: Automated HTML dashboard generation with Plotly and Folium.

Want to audit the full repo?

View on GitHub