{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "4908e08a",
   "metadata": {
    "id": "4908e08a"
   },
   "source": "# 🚚 Unilever CCFOT Operasyonu\n## Quantum Computing ile Uçtan Uca Filo & Rota Optimizasyonu (Qiskit)\n\n**CCFOT** = Customer Case Fill On Time  \nUnilever’in kritik lojistik KPI’sı: Müşteri siparişlerinin doğru miktarda ve zamanında teslim edilmesi.\n\n### Bu Notebook Ne Yapıyor?\n1. **Araç Telemetrisi** (GPS, sıcaklık, yakıt, soğuk zincir alarmı) simülasyonu\n2. **Google Traffic** verisi ile trafik-duyarlı seyahat süreleri\n3. **Vehicle Routing Problem (VRP)** → QUBO formülasyonu\n4. **Multi-Hardware Access**: StatevectorSimulator + Aer + (opsiyonel) IBM Quantum Runtime\n5. QAOA ile çözüm + klasik baseline karşılaştırması\n6. CCFOT skoru tahmini ve iyileştirme raporu\n\n> Eğitim + demo amaçlı toy instance. Gerçek ölçekte hybrid quantum-classical + column generation gerekir."
  },
  {
   "cell_type": "markdown",
   "id": "1f93ed4d",
   "metadata": {
    "id": "1f93ed4d"
   },
   "source": "## 0. Ortam Kurulumu"
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "71048fe4-2741-43a4-a6c8-15901752d9e8",
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "71048fe4-2741-43a4-a6c8-15901752d9e8",
    "executionInfo": {
     "status": "ok",
     "timestamp": 1786440680074,
     "user_tz": -180,
     "elapsed": 18793,
     "user": {
      "displayName": "Joseph Volkan ÖZCAN",
      "userId": "11389530967736397480"
     }
    },
    "outputId": "bed9b046-f42f-4f9f-c7e0-16598550a341"
   },
   "outputs": [
    {
     "output_type": "stream",
     "name": "stdout",
     "text": [
      "\u001b[?25l     \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m0.0/664.0 kB\u001b[0m \u001b[31m?\u001b[0m eta \u001b[36m-:--:--\u001b[0m\r\u001b[2K     \u001b[91m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[91m╸\u001b[0m \u001b[32m655.4/664.0 kB\u001b[0m \u001b[31m20.5 MB/s\u001b[0m eta \u001b[36m0:00:01\u001b[0m\r\u001b[2K     \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m664.0/664.0 kB\u001b[0m \u001b[31m11.9 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
      "\u001b[?25h  Installing build dependencies ... \u001b[?25l\u001b[?25hdone\n",
      "  Getting requirements to build wheel ... \u001b[?25l\u001b[?25hdone\n",
      "  Preparing metadata (pyproject.toml) ... \u001b[?25l\u001b[?25hdone\n",
      "\u001b[2K   \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m9.7/9.7 MB\u001b[0m \u001b[31m108.2 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
      "\u001b[2K   \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m327.8/327.8 kB\u001b[0m \u001b[31m26.2 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
      "\u001b[2K   \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m237.1/237.1 kB\u001b[0m \u001b[31m20.0 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
      "\u001b[2K   \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m12.4/12.4 MB\u001b[0m \u001b[31m105.4 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
      "\u001b[2K   \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m2.4/2.4 MB\u001b[0m \u001b[31m91.5 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
      "\u001b[2K   \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m54.5/54.5 kB\u001b[0m \u001b[31m4.6 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
      "\u001b[?25h  Building wheel for docplex (pyproject.toml) ... \u001b[?25l\u001b[?25hdone\n",
      "Kurulum tamam.\n"
     ]
    }
   ],
   "source": "!pip install -q \"qiskit>=1.0\" qiskit-algorithms qiskit-optimization qiskit-aer matplotlib networkx pandas numpy requests\nprint(\"Kurulum tamam.\")"
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "1c227f0c-223e-4d86-b1fb-a0f7b7d9bd17",
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "1c227f0c-223e-4d86-b1fb-a0f7b7d9bd17",
    "executionInfo": {
     "status": "ok",
     "timestamp": 1786440682735,
     "user_tz": -180,
     "elapsed": 2657,
     "user": {
      "displayName": "Joseph Volkan ÖZCAN",
      "userId": "11389530967736397480"
     }
    },
    "outputId": "cf86b06e-6073-43fc-dfea-2400c50f69e9"
   },
   "outputs": [
    {
     "output_type": "stream",
     "name": "stdout",
     "text": [
      "Kutuphaneler yuklendi\n",
      "Import mode : qiskit_optimization\n",
      "AerSampler  : True\n",
      "Zaman       : 2026-08-11 09:31\n"
     ]
    }
   ],
   "source": "import numpy as np\nimport pandas as pd\nimport matplotlib.pyplot as plt\nimport networkx as nx\nfrom datetime import datetime, timedelta\nimport warnings\nwarnings.filterwarnings(\"ignore\")\n\ntry:\n    from IPython.display import display\nexcept ImportError:\n    display = print\n\n# --- Import path: prefer qiskit_optimization bundled solvers (newer), fallback to qiskit_algorithms ---\n_IMPORT_MODE = None\ntry:\n    from qiskit.primitives import StatevectorSampler\n    from qiskit_optimization import QuadraticProgram\n    from qiskit_optimization.converters import QuadraticProgramToQubo\n    from qiskit_optimization.algorithms import MinimumEigenOptimizer\n    from qiskit_optimization.minimum_eigensolvers import QAOA, NumPyMinimumEigensolver\n    from qiskit_optimization.optimizers import COBYLA\n    from qiskit_optimization.utils import algorithm_globals\n    _IMPORT_MODE = \"qiskit_optimization\"\nexcept Exception as e1:\n    try:\n        from qiskit.primitives import StatevectorSampler\n        from qiskit_algorithms import QAOA, NumPyMinimumEigensolver\n        from qiskit_algorithms.optimizers import COBYLA\n        from qiskit_algorithms.utils import algorithm_globals\n        from qiskit_optimization import QuadraticProgram\n        from qiskit_optimization.converters import QuadraticProgramToQubo\n        from qiskit_optimization.algorithms import MinimumEigenOptimizer\n        _IMPORT_MODE = \"qiskit_algorithms\"\n    except Exception as e2:\n        raise ImportError(f\"Import failed.\\nopt path: {e1}\\nalg path: {e2}\")\n\n# Optional Aer\ntry:\n    from qiskit_aer.primitives import Sampler as AerSampler\n    HAS_AER = True\nexcept Exception:\n    HAS_AER = False\n\nprint(\"Kutuphaneler yuklendi\")\nprint(f\"Import mode : {_IMPORT_MODE}\")\nprint(f\"AerSampler  : {HAS_AER}\")\nprint(f\"Zaman       : {datetime.now().strftime('%Y-%m-%d %H:%M')}\")"
  },
  {
   "cell_type": "markdown",
   "id": "a8d668a4",
   "metadata": {
    "id": "a8d668a4"
   },
   "source": "## 1. Unilever CCFOT Bağlamı\n\n**CCFOT (Customer Case Fill On Time)** = Siparişin hem **doğru miktarda** (fill) hem de **zamanında** (on time) teslim edilmesi oranı.\n\nUnilever dağıtım merkezlerinde (ör. Mannheim) %99.8 CCFOT hedeflenir.  \nSoğuk zincir (ice cream, dondurulmuş gıda) için ek kısıtlar:\n- Araç içi sıcaklık sürekli izlenmeli (telemetry)\n- Trafik gecikmeleri soğuk zinciri bozabilir\n- Zaman penceresi (time window) ihlali CCFOT’u düşürür\n\nBu notebook’ta quantum optimizasyon ile **trafik + telemetri** farkındalıklı rota planlaması yaparak CCFOT’u iyileştirmeyi hedefliyoruz."
  },
  {
   "cell_type": "markdown",
   "id": "e13844b6",
   "metadata": {
    "id": "e13844b6"
   },
   "source": "## 2. Araç Telemetrisi Simülasyonu\n\nGerçek hayatta araçlardan gelen veriler (IoT / CAN bus / GPS tracker):\n- Konum (lat, lon)\n- Hız, yakıt seviyesi\n- Soğuk ünite sıcaklığı (°C)\n- Kapı açılma sayısı, alarm durumları\n\nBurada 3 soğuk zincir aracı için mock telemetry üretiyoruz."
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "1656f80a",
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/",
     "height": 400
    },
    "id": "1656f80a",
    "executionInfo": {
     "status": "ok",
     "timestamp": 1786440683162,
     "user_tz": -180,
     "elapsed": 423,
     "user": {
      "displayName": "Joseph Volkan ÖZCAN",
      "userId": "11389530967736397480"
     }
    },
    "outputId": "51e5b7e9-9535-4d86-d414-a48cdf5b6e09"
   },
   "outputs": [
    {
     "output_type": "stream",
     "name": "stdout",
     "text": [
      "📦 Müşteri Noktaları\n"
     ]
    },
    {
     "output_type": "display_data",
     "data": {
      "text/plain": [
       "   id                name    lat    lon  demand  tw_start  tw_end\n",
       "0  C1      Migros Kadıköy  40.99  29.03      12         8      11\n",
       "1  C2  Carrefour Ataşehir  40.98  29.12       8         9      12\n",
       "2  C3         BİM Üsküdar  41.02  29.02      15        10      13\n",
       "3  C4         Şok Maltepe  40.93  29.13      10         8      12"
      ],
      "text/html": [
       "\n",
       "  <div id=\"df-04757467-53ad-4536-ae7d-3e0a4df42a15\" class=\"colab-df-container\">\n",
       "    <div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>id</th>\n",
       "      <th>name</th>\n",
       "      <th>lat</th>\n",
       "      <th>lon</th>\n",
       "      <th>demand</th>\n",
       "      <th>tw_start</th>\n",
       "      <th>tw_end</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>C1</td>\n",
       "      <td>Migros Kadıköy</td>\n",
       "      <td>40.99</td>\n",
       "      <td>29.03</td>\n",
       "      <td>12</td>\n",
       "      <td>8</td>\n",
       "      <td>11</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>C2</td>\n",
       "      <td>Carrefour Ataşehir</td>\n",
       "      <td>40.98</td>\n",
       "      <td>29.12</td>\n",
       "      <td>8</td>\n",
       "      <td>9</td>\n",
       "      <td>12</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>C3</td>\n",
       "      <td>BİM Üsküdar</td>\n",
       "      <td>41.02</td>\n",
       "      <td>29.02</td>\n",
       "      <td>15</td>\n",
       "      <td>10</td>\n",
       "      <td>13</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>C4</td>\n",
       "      <td>Şok Maltepe</td>\n",
       "      <td>40.93</td>\n",
       "      <td>29.13</td>\n",
       "      <td>10</td>\n",
       "      <td>8</td>\n",
       "      <td>12</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>\n",
       "    <div class=\"colab-df-buttons\">\n",
       "\n",
       "  <div class=\"colab-df-container\">\n",
       "    <button class=\"colab-df-convert\" onclick=\"convertToInteractive('df-04757467-53ad-4536-ae7d-3e0a4df42a15')\"\n",
       "            title=\"Convert this dataframe to an interactive table.\"\n",
       "            style=\"display:none;\">\n",
       "\n",
       "  <svg xmlns=\"http://www.w3.org/2000/svg\" height=\"24px\" viewBox=\"0 -960 960 960\">\n",
       "    <path d=\"M120-120v-720h720v720H120Zm60-500h600v-160H180v160Zm220 220h160v-160H400v160Zm0 220h160v-160H400v160ZM180-400h160v-160H180v160Zm440 0h160v-160H620v160ZM180-180h160v-160H180v160Zm440 0h160v-160H620v160Z\"/>\n",
       "  </svg>\n",
       "    </button>\n",
       "\n",
       "  <style>\n",
       "    .colab-df-container {\n",
       "      display:flex;\n",
       "      gap: 12px;\n",
       "    }\n",
       "\n",
       "    .colab-df-convert {\n",
       "      background-color: #E8F0FE;\n",
       "      border: none;\n",
       "      border-radius: 50%;\n",
       "      cursor: pointer;\n",
       "      display: none;\n",
       "      fill: #1967D2;\n",
       "      height: 32px;\n",
       "      padding: 0 0 0 0;\n",
       "      width: 32px;\n",
       "    }\n",
       "\n",
       "    .colab-df-convert:hover {\n",
       "      background-color: #E2EBFA;\n",
       "      box-shadow: 0px 1px 2px rgba(60, 64, 67, 0.3), 0px 1px 3px 1px rgba(60, 64, 67, 0.15);\n",
       "      fill: #174EA6;\n",
       "    }\n",
       "\n",
       "    .colab-df-buttons div {\n",
       "      margin-bottom: 4px;\n",
       "    }\n",
       "\n",
       "    [theme=dark] .colab-df-convert {\n",
       "      background-color: #3B4455;\n",
       "      fill: #D2E3FC;\n",
       "    }\n",
       "\n",
       "    [theme=dark] .colab-df-convert:hover {\n",
       "      background-color: #434B5C;\n",
       "      box-shadow: 0px 1px 3px 1px rgba(0, 0, 0, 0.15);\n",
       "      filter: drop-shadow(0px 1px 2px rgba(0, 0, 0, 0.3));\n",
       "      fill: #FFFFFF;\n",
       "    }\n",
       "  </style>\n",
       "\n",
       "    <script>\n",
       "      const buttonEl =\n",
       "        document.querySelector('#df-04757467-53ad-4536-ae7d-3e0a4df42a15 button.colab-df-convert');\n",
       "      buttonEl.style.display =\n",
       "        google.colab.kernel.accessAllowed ? 'block' : 'none';\n",
       "\n",
       "      async function convertToInteractive(key) {\n",
       "        const element = document.querySelector('#df-04757467-53ad-4536-ae7d-3e0a4df42a15');\n",
       "        const dataTable =\n",
       "          await google.colab.kernel.invokeFunction('convertToInteractive',\n",
       "                                                    [key], {});\n",
       "        if (!dataTable) return;\n",
       "\n",
       "        const docLinkHtml = 'Like what you see? Visit the ' +\n",
       "          '<a target=\"_blank\" href=https://colab.research.google.com/notebooks/data_table.ipynb>data table notebook</a>'\n",
       "          + ' to learn more about interactive tables.';\n",
       "        element.innerHTML = '';\n",
       "        dataTable['output_type'] = 'display_data';\n",
       "        await google.colab.output.renderOutput(dataTable, element);\n",
       "        const docLink = document.createElement('div');\n",
       "        docLink.innerHTML = docLinkHtml;\n",
       "        element.appendChild(docLink);\n",
       "      }\n",
       "    </script>\n",
       "  </div>\n",
       "\n",
       "\n",
       "  <div id=\"id_ec3c41d8-b550-4c3a-b12a-ed2878474822\">\n",
       "    <style>\n",
       "      .colab-df-generate {\n",
       "        background-color: #E8F0FE;\n",
       "        border: none;\n",
       "        border-radius: 50%;\n",
       "        cursor: pointer;\n",
       "        display: none;\n",
       "        fill: #1967D2;\n",
       "        height: 32px;\n",
       "        padding: 0 0 0 0;\n",
       "        width: 32px;\n",
       "      }\n",
       "\n",
       "      .colab-df-generate:hover {\n",
       "        background-color: #E2EBFA;\n",
       "        box-shadow: 0px 1px 2px rgba(60, 64, 67, 0.3), 0px 1px 3px 1px rgba(60, 64, 67, 0.15);\n",
       "        fill: #174EA6;\n",
       "      }\n",
       "\n",
       "      [theme=dark] .colab-df-generate {\n",
       "        background-color: #3B4455;\n",
       "        fill: #D2E3FC;\n",
       "      }\n",
       "\n",
       "      [theme=dark] .colab-df-generate:hover {\n",
       "        background-color: #434B5C;\n",
       "        box-shadow: 0px 1px 3px 1px rgba(0, 0, 0, 0.15);\n",
       "        filter: drop-shadow(0px 1px 2px rgba(0, 0, 0, 0.3));\n",
       "        fill: #FFFFFF;\n",
       "      }\n",
       "    </style>\n",
       "    <button class=\"colab-df-generate\" onclick=\"generateWithVariable('customers')\"\n",
       "            title=\"Generate code using this dataframe.\"\n",
       "            style=\"display:none;\">\n",
       "\n",
       "  <svg xmlns=\"http://www.w3.org/2000/svg\" height=\"24px\"viewBox=\"0 0 24 24\"\n",
       "       width=\"24px\">\n",
       "    <path d=\"M7,19H8.4L18.45,9,17,7.55,7,17.6ZM5,21V16.75L18.45,3.32a2,2,0,0,1,2.83,0l1.4,1.43a1.91,1.91,0,0,1,.58,1.4,1.91,1.91,0,0,1-.58,1.4L9.25,21ZM18.45,9,17,7.55Zm-12,3A5.31,5.31,0,0,0,4.9,8.1,5.31,5.31,0,0,0,1,6.5,5.31,5.31,0,0,0,4.9,4.9,5.31,5.31,0,0,0,6.5,1,5.31,5.31,0,0,0,8.1,4.9,5.31,5.31,0,0,0,12,6.5,5.46,5.46,0,0,0,6.5,12Z\"/>\n",
       "  </svg>\n",
       "    </button>\n",
       "    <script>\n",
       "      (() => {\n",
       "      const buttonEl =\n",
       "        document.querySelector('#id_ec3c41d8-b550-4c3a-b12a-ed2878474822 button.colab-df-generate');\n",
       "      buttonEl.style.display =\n",
       "        google.colab.kernel.accessAllowed ? 'block' : 'none';\n",
       "\n",
       "      buttonEl.onclick = () => {\n",
       "        google.colab.notebook.generateWithVariable('customers');\n",
       "      }\n",
       "      })();\n",
       "    </script>\n",
       "  </div>\n",
       "\n",
       "    </div>\n",
       "  </div>\n"
      ],
      "application/vnd.google.colaboratory.intrinsic+json": {
       "type": "dataframe",
       "variable_name": "customers",
       "summary": "{\n  \"name\": \"customers\",\n  \"rows\": 4,\n  \"fields\": [\n    {\n      \"column\": \"id\",\n      \"properties\": {\n        \"dtype\": \"string\",\n        \"num_unique_values\": 4,\n        \"samples\": [\n          \"C2\",\n          \"C4\",\n          \"C1\"\n        ],\n        \"semantic_type\": \"\",\n        \"description\": \"\"\n      }\n    },\n    {\n      \"column\": \"name\",\n      \"properties\": {\n        \"dtype\": \"string\",\n        \"num_unique_values\": 4,\n        \"samples\": [\n          \"Carrefour Ata\\u015fehir\",\n          \"\\u015eok Maltepe\",\n          \"Migros Kad\\u0131k\\u00f6y\"\n        ],\n        \"semantic_type\": \"\",\n        \"description\": \"\"\n      }\n    },\n    {\n      \"column\": \"lat\",\n      \"properties\": {\n        \"dtype\": \"number\",\n        \"std\": 0.03741657386774083,\n        \"min\": 40.93,\n        \"max\": 41.02,\n        \"num_unique_values\": 4,\n        \"samples\": [\n          40.98,\n          40.93,\n          40.99\n        ],\n        \"semantic_type\": \"\",\n        \"description\": \"\"\n      }\n    },\n    {\n      \"column\": \"lon\",\n      \"properties\": {\n        \"dtype\": \"number\",\n        \"std\": 0.05802298395176382,\n        \"min\": 29.02,\n        \"max\": 29.13,\n        \"num_unique_values\": 4,\n        \"samples\": [\n          29.12,\n          29.13,\n          29.03\n        ],\n        \"semantic_type\": \"\",\n        \"description\": \"\"\n      }\n    },\n    {\n      \"column\": \"demand\",\n      \"properties\": {\n        \"dtype\": \"number\",\n        \"std\": 2,\n        \"min\": 8,\n        \"max\": 15,\n        \"num_unique_values\": 4,\n        \"samples\": [\n          8,\n          10,\n          12\n        ],\n        \"semantic_type\": \"\",\n        \"description\": \"\"\n      }\n    },\n    {\n      \"column\": \"tw_start\",\n      \"properties\": {\n        \"dtype\": \"number\",\n        \"std\": 0,\n        \"min\": 8,\n        \"max\": 10,\n        \"num_unique_values\": 3,\n        \"samples\": [\n          8,\n          9,\n          10\n        ],\n        \"semantic_type\": \"\",\n        \"description\": \"\"\n      }\n    },\n    {\n      \"column\": \"tw_end\",\n      \"properties\": {\n        \"dtype\": \"number\",\n        \"std\": 0,\n        \"min\": 11,\n        \"max\": 13,\n        \"num_unique_values\": 3,\n        \"samples\": [\n          11,\n          12,\n          13\n        ],\n        \"semantic_type\": \"\",\n        \"description\": \"\"\n      }\n    }\n  ]\n}"
      }
     },
     "metadata": {}
    },
    {
     "output_type": "stream",
     "name": "stdout",
     "text": [
      "\n",
      "🚛 Araç Telemetrisi (Anlık)\n"
     ]
    },
    {
     "output_type": "display_data",
     "data": {
      "text/plain": [
       "   id        type  capacity  temp_c  fuel_pct    lat    lon     status\n",
       "0  V1  Reefer-12t        25   -18.2        78  40.99  29.15         OK\n",
       "1  V2   Reefer-8t        18   -17.8        45  40.98  29.14         OK\n",
       "2  V3  Reefer-12t        25   -15.1        62  41.00  29.16  TEMP_WARN"
      ],
      "text/html": [
       "\n",
       "  <div id=\"df-d5fc70ea-57b1-44d2-b1e2-c6bbde87f9e8\" class=\"colab-df-container\">\n",
       "    <div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>id</th>\n",
       "      <th>type</th>\n",
       "      <th>capacity</th>\n",
       "      <th>temp_c</th>\n",
       "      <th>fuel_pct</th>\n",
       "      <th>lat</th>\n",
       "      <th>lon</th>\n",
       "      <th>status</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>V1</td>\n",
       "      <td>Reefer-12t</td>\n",
       "      <td>25</td>\n",
       "      <td>-18.2</td>\n",
       "      <td>78</td>\n",
       "      <td>40.99</td>\n",
       "      <td>29.15</td>\n",
       "      <td>OK</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>V2</td>\n",
       "      <td>Reefer-8t</td>\n",
       "      <td>18</td>\n",
       "      <td>-17.8</td>\n",
       "      <td>45</td>\n",
       "      <td>40.98</td>\n",
       "      <td>29.14</td>\n",
       "      <td>OK</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>V3</td>\n",
       "      <td>Reefer-12t</td>\n",
       "      <td>25</td>\n",
       "      <td>-15.1</td>\n",
       "      <td>62</td>\n",
       "      <td>41.00</td>\n",
       "      <td>29.16</td>\n",
       "      <td>TEMP_WARN</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>\n",
       "    <div class=\"colab-df-buttons\">\n",
       "\n",
       "  <div class=\"colab-df-container\">\n",
       "    <button class=\"colab-df-convert\" onclick=\"convertToInteractive('df-d5fc70ea-57b1-44d2-b1e2-c6bbde87f9e8')\"\n",
       "            title=\"Convert this dataframe to an interactive table.\"\n",
       "            style=\"display:none;\">\n",
       "\n",
       "  <svg xmlns=\"http://www.w3.org/2000/svg\" height=\"24px\" viewBox=\"0 -960 960 960\">\n",
       "    <path d=\"M120-120v-720h720v720H120Zm60-500h600v-160H180v160Zm220 220h160v-160H400v160Zm0 220h160v-160H400v160ZM180-400h160v-160H180v160Zm440 0h160v-160H620v160ZM180-180h160v-160H180v160Zm440 0h160v-160H620v160Z\"/>\n",
       "  </svg>\n",
       "    </button>\n",
       "\n",
       "  <style>\n",
       "    .colab-df-container {\n",
       "      display:flex;\n",
       "      gap: 12px;\n",
       "    }\n",
       "\n",
       "    .colab-df-convert {\n",
       "      background-color: #E8F0FE;\n",
       "      border: none;\n",
       "      border-radius: 50%;\n",
       "      cursor: pointer;\n",
       "      display: none;\n",
       "      fill: #1967D2;\n",
       "      height: 32px;\n",
       "      padding: 0 0 0 0;\n",
       "      width: 32px;\n",
       "    }\n",
       "\n",
       "    .colab-df-convert:hover {\n",
       "      background-color: #E2EBFA;\n",
       "      box-shadow: 0px 1px 2px rgba(60, 64, 67, 0.3), 0px 1px 3px 1px rgba(60, 64, 67, 0.15);\n",
       "      fill: #174EA6;\n",
       "    }\n",
       "\n",
       "    .colab-df-buttons div {\n",
       "      margin-bottom: 4px;\n",
       "    }\n",
       "\n",
       "    [theme=dark] .colab-df-convert {\n",
       "      background-color: #3B4455;\n",
       "      fill: #D2E3FC;\n",
       "    }\n",
       "\n",
       "    [theme=dark] .colab-df-convert:hover {\n",
       "      background-color: #434B5C;\n",
       "      box-shadow: 0px 1px 3px 1px rgba(0, 0, 0, 0.15);\n",
       "      filter: drop-shadow(0px 1px 2px rgba(0, 0, 0, 0.3));\n",
       "      fill: #FFFFFF;\n",
       "    }\n",
       "  </style>\n",
       "\n",
       "    <script>\n",
       "      const buttonEl =\n",
       "        document.querySelector('#df-d5fc70ea-57b1-44d2-b1e2-c6bbde87f9e8 button.colab-df-convert');\n",
       "      buttonEl.style.display =\n",
       "        google.colab.kernel.accessAllowed ? 'block' : 'none';\n",
       "\n",
       "      async function convertToInteractive(key) {\n",
       "        const element = document.querySelector('#df-d5fc70ea-57b1-44d2-b1e2-c6bbde87f9e8');\n",
       "        const dataTable =\n",
       "          await google.colab.kernel.invokeFunction('convertToInteractive',\n",
       "                                                    [key], {});\n",
       "        if (!dataTable) return;\n",
       "\n",
       "        const docLinkHtml = 'Like what you see? Visit the ' +\n",
       "          '<a target=\"_blank\" href=https://colab.research.google.com/notebooks/data_table.ipynb>data table notebook</a>'\n",
       "          + ' to learn more about interactive tables.';\n",
       "        element.innerHTML = '';\n",
       "        dataTable['output_type'] = 'display_data';\n",
       "        await google.colab.output.renderOutput(dataTable, element);\n",
       "        const docLink = document.createElement('div');\n",
       "        docLink.innerHTML = docLinkHtml;\n",
       "        element.appendChild(docLink);\n",
       "      }\n",
       "    </script>\n",
       "  </div>\n",
       "\n",
       "\n",
       "  <div id=\"id_a4778edb-1dea-402d-8d7a-c4afc63d1ee7\">\n",
       "    <style>\n",
       "      .colab-df-generate {\n",
       "        background-color: #E8F0FE;\n",
       "        border: none;\n",
       "        border-radius: 50%;\n",
       "        cursor: pointer;\n",
       "        display: none;\n",
       "        fill: #1967D2;\n",
       "        height: 32px;\n",
       "        padding: 0 0 0 0;\n",
       "        width: 32px;\n",
       "      }\n",
       "\n",
       "      .colab-df-generate:hover {\n",
       "        background-color: #E2EBFA;\n",
       "        box-shadow: 0px 1px 2px rgba(60, 64, 67, 0.3), 0px 1px 3px 1px rgba(60, 64, 67, 0.15);\n",
       "        fill: #174EA6;\n",
       "      }\n",
       "\n",
       "      [theme=dark] .colab-df-generate {\n",
       "        background-color: #3B4455;\n",
       "        fill: #D2E3FC;\n",
       "      }\n",
       "\n",
       "      [theme=dark] .colab-df-generate:hover {\n",
       "        background-color: #434B5C;\n",
       "        box-shadow: 0px 1px 3px 1px rgba(0, 0, 0, 0.15);\n",
       "        filter: drop-shadow(0px 1px 2px rgba(0, 0, 0, 0.3));\n",
       "        fill: #FFFFFF;\n",
       "      }\n",
       "    </style>\n",
       "    <button class=\"colab-df-generate\" onclick=\"generateWithVariable('vehicles')\"\n",
       "            title=\"Generate code using this dataframe.\"\n",
       "            style=\"display:none;\">\n",
       "\n",
       "  <svg xmlns=\"http://www.w3.org/2000/svg\" height=\"24px\"viewBox=\"0 0 24 24\"\n",
       "       width=\"24px\">\n",
       "    <path d=\"M7,19H8.4L18.45,9,17,7.55,7,17.6ZM5,21V16.75L18.45,3.32a2,2,0,0,1,2.83,0l1.4,1.43a1.91,1.91,0,0,1,.58,1.4,1.91,1.91,0,0,1-.58,1.4L9.25,21ZM18.45,9,17,7.55Zm-12,3A5.31,5.31,0,0,0,4.9,8.1,5.31,5.31,0,0,0,1,6.5,5.31,5.31,0,0,0,4.9,4.9,5.31,5.31,0,0,0,6.5,1,5.31,5.31,0,0,0,8.1,4.9,5.31,5.31,0,0,0,12,6.5,5.46,5.46,0,0,0,6.5,12Z\"/>\n",
       "  </svg>\n",
       "    </button>\n",
       "    <script>\n",
       "      (() => {\n",
       "      const buttonEl =\n",
       "        document.querySelector('#id_a4778edb-1dea-402d-8d7a-c4afc63d1ee7 button.colab-df-generate');\n",
       "      buttonEl.style.display =\n",
       "        google.colab.kernel.accessAllowed ? 'block' : 'none';\n",
       "\n",
       "      buttonEl.onclick = () => {\n",
       "        google.colab.notebook.generateWithVariable('vehicles');\n",
       "      }\n",
       "      })();\n",
       "    </script>\n",
       "  </div>\n",
       "\n",
       "    </div>\n",
       "  </div>\n"
      ],
      "application/vnd.google.colaboratory.intrinsic+json": {
       "type": "dataframe",
       "variable_name": "vehicles",
       "summary": "{\n  \"name\": \"vehicles\",\n  \"rows\": 3,\n  \"fields\": [\n    {\n      \"column\": \"id\",\n      \"properties\": {\n        \"dtype\": \"string\",\n        \"num_unique_values\": 3,\n        \"samples\": [\n          \"V1\",\n          \"V2\",\n          \"V3\"\n        ],\n        \"semantic_type\": \"\",\n        \"description\": \"\"\n      }\n    },\n    {\n      \"column\": \"type\",\n      \"properties\": {\n        \"dtype\": \"string\",\n        \"num_unique_values\": 2,\n        \"samples\": [\n          \"Reefer-8t\",\n          \"Reefer-12t\"\n        ],\n        \"semantic_type\": \"\",\n        \"description\": \"\"\n      }\n    },\n    {\n      \"column\": \"capacity\",\n      \"properties\": {\n        \"dtype\": \"number\",\n        \"std\": 4,\n        \"min\": 18,\n        \"max\": 25,\n        \"num_unique_values\": 2,\n        \"samples\": [\n          18,\n          25\n        ],\n        \"semantic_type\": \"\",\n        \"description\": \"\"\n      }\n    },\n    {\n      \"column\": \"temp_c\",\n      \"properties\": {\n        \"dtype\": \"number\",\n        \"std\": 1.6862186493255653,\n        \"min\": -18.2,\n        \"max\": -15.1,\n        \"num_unique_values\": 3,\n        \"samples\": [\n          -18.2,\n          -17.8\n        ],\n        \"semantic_type\": \"\",\n        \"description\": \"\"\n      }\n    },\n    {\n      \"column\": \"fuel_pct\",\n      \"properties\": {\n        \"dtype\": \"number\",\n        \"std\": 16,\n        \"min\": 45,\n        \"max\": 78,\n        \"num_unique_values\": 3,\n        \"samples\": [\n          78,\n          45\n        ],\n        \"semantic_type\": \"\",\n        \"description\": \"\"\n      }\n    },\n    {\n      \"column\": \"lat\",\n      \"properties\": {\n        \"dtype\": \"number\",\n        \"std\": 0.010000000000001563,\n        \"min\": 40.98,\n        \"max\": 41.0,\n        \"num_unique_values\": 3,\n        \"samples\": [\n          40.99,\n          40.98\n        ],\n        \"semantic_type\": \"\",\n        \"description\": \"\"\n      }\n    },\n    {\n      \"column\": \"lon\",\n      \"properties\": {\n        \"dtype\": \"number\",\n        \"std\": 0.009999999999999787,\n        \"min\": 29.14,\n        \"max\": 29.16,\n        \"num_unique_values\": 3,\n        \"samples\": [\n          29.15,\n          29.14\n        ],\n        \"semantic_type\": \"\",\n        \"description\": \"\"\n      }\n    },\n    {\n      \"column\": \"status\",\n      \"properties\": {\n        \"dtype\": \"string\",\n        \"num_unique_values\": 2,\n        \"samples\": [\n          \"TEMP_WARN\",\n          \"OK\"\n        ],\n        \"semantic_type\": \"\",\n        \"description\": \"\"\n      }\n    }\n  ]\n}"
      }
     },
     "metadata": {}
    },
    {
     "output_type": "stream",
     "name": "stdout",
     "text": [
      "\n",
      "⚠️  Soğuk zincir uyarıları:\n",
      "  V3: Sıcaklık -15.1°C → CCFOT riski yüksek (tercihen kullanılmamalı)\n"
     ]
    }
   ],
   "source": "np.random.seed(42)\n\n# Unilever DC (Dağıtım Merkezi) - örnek: İstanbul Anadolu\nDC_LOCATION = {\"name\": \"Unilever DC Istanbul\", \"lat\": 40.99, \"lon\": 29.15}\n\n# Müşteri noktaları (toy)\ncustomers = pd.DataFrame([\n    {\"id\": \"C1\", \"name\": \"Migros Kadıköy\",   \"lat\": 40.99, \"lon\": 29.03, \"demand\": 12, \"tw_start\": 8,  \"tw_end\": 11},\n    {\"id\": \"C2\", \"name\": \"Carrefour Ataşehir\",\"lat\": 40.98, \"lon\": 29.12, \"demand\": 8,  \"tw_start\": 9,  \"tw_end\": 12},\n    {\"id\": \"C3\", \"name\": \"BİM Üsküdar\",      \"lat\": 41.02, \"lon\": 29.02, \"demand\": 15, \"tw_start\": 10, \"tw_end\": 13},\n    {\"id\": \"C4\", \"name\": \"Şok Maltepe\",      \"lat\": 40.93, \"lon\": 29.13, \"demand\": 10, \"tw_start\": 8,  \"tw_end\": 12},\n])\n\n# Araç telemetrisi (anlık snapshot)\nvehicles = pd.DataFrame([\n    {\"id\": \"V1\", \"type\": \"Reefer-12t\", \"capacity\": 25, \"temp_c\": -18.2, \"fuel_pct\": 78, \"lat\": 40.99, \"lon\": 29.15, \"status\": \"OK\"},\n    {\"id\": \"V2\", \"type\": \"Reefer-8t\",  \"capacity\": 18, \"temp_c\": -17.8, \"fuel_pct\": 45, \"lat\": 40.98, \"lon\": 29.14, \"status\": \"OK\"},\n    {\"id\": \"V3\", \"type\": \"Reefer-12t\", \"capacity\": 25, \"temp_c\": -15.1, \"fuel_pct\": 62, \"lat\": 41.00, \"lon\": 29.16, \"status\": \"TEMP_WARN\"},  # sıcaklık uyarısı\n])\n\nprint(\"📦 Müşteri Noktaları\")\ndisplay(customers)\nprint(\"\\n🚛 Araç Telemetrisi (Anlık)\")\ndisplay(vehicles)\n\n# Sıcaklık alarmı olan araçları işaretle\nprint(\"\\n⚠️  Soğuk zincir uyarıları:\")\nfor _, v in vehicles.iterrows():\n    if v[\"temp_c\"] > -16.0:\n        print(f\"  {v['id']}: Sıcaklık {v['temp_c']}°C → CCFOT riski yüksek (tercihen kullanılmamalı)\")"
  },
  {
   "cell_type": "markdown",
   "id": "ff395769",
   "metadata": {
    "id": "ff395769"
   },
   "source": "## 3. Google Traffic Entegrasyonu (Simüle + Gerçek API Hazırlığı)\n\nGoogle Maps Directions API `departure_time=now` + `traffic_model=best_guess` ile gerçek zamanlı trafik süresi verir.\n\nColab’da API key olmadan çalışması için **trafik faktörü simülasyonu** kullanıyoruz.  \nGerçek kullanım için aşağıya API key ekleyebilirsiniz."
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "b4e3b2cb",
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/",
     "height": 442
    },
    "id": "b4e3b2cb",
    "executionInfo": {
     "status": "ok",
     "timestamp": 1786440683213,
     "user_tz": -180,
     "elapsed": 47,
     "user": {
      "displayName": "Joseph Volkan ÖZCAN",
      "userId": "11389530967736397480"
     }
    },
    "outputId": "8c084943-9524-4521-f670-8784a094f323"
   },
   "outputs": [
    {
     "output_type": "stream",
     "name": "stdout",
     "text": [
      "🗺️  Trafik-Duyarlı Seyahat Süreleri (dakika) — Google Traffic simülasyonu\n"
     ]
    },
    {
     "output_type": "display_data",
     "data": {
      "text/plain": [
       "      DC    C1    C2    C3    C4\n",
       "DC   0.0  39.4  12.8  49.8  28.9\n",
       "C1  36.6   0.0  27.7  12.1  48.7\n",
       "C2  11.6  33.1   0.0  32.8  26.3\n",
       "C3  51.3  12.7  34.8   0.0  49.9\n",
       "C4  26.3  44.0  22.4  51.8   0.0"
      ],
      "text/html": [
       "\n",
       "  <div id=\"df-0facbba1-92f4-4bf7-a37e-7673457e16f1\" class=\"colab-df-container\">\n",
       "    <div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>DC</th>\n",
       "      <th>C1</th>\n",
       "      <th>C2</th>\n",
       "      <th>C3</th>\n",
       "      <th>C4</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>DC</th>\n",
       "      <td>0.0</td>\n",
       "      <td>39.4</td>\n",
       "      <td>12.8</td>\n",
       "      <td>49.8</td>\n",
       "      <td>28.9</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>C1</th>\n",
       "      <td>36.6</td>\n",
       "      <td>0.0</td>\n",
       "      <td>27.7</td>\n",
       "      <td>12.1</td>\n",
       "      <td>48.7</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>C2</th>\n",
       "      <td>11.6</td>\n",
       "      <td>33.1</td>\n",
       "      <td>0.0</td>\n",
       "      <td>32.8</td>\n",
       "      <td>26.3</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>C3</th>\n",
       "      <td>51.3</td>\n",
       "      <td>12.7</td>\n",
       "      <td>34.8</td>\n",
       "      <td>0.0</td>\n",
       "      <td>49.9</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>C4</th>\n",
       "      <td>26.3</td>\n",
       "      <td>44.0</td>\n",
       "      <td>22.4</td>\n",
       "      <td>51.8</td>\n",
       "      <td>0.0</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>\n",
       "    <div class=\"colab-df-buttons\">\n",
       "\n",
       "  <div class=\"colab-df-container\">\n",
       "    <button class=\"colab-df-convert\" onclick=\"convertToInteractive('df-0facbba1-92f4-4bf7-a37e-7673457e16f1')\"\n",
       "            title=\"Convert this dataframe to an interactive table.\"\n",
       "            style=\"display:none;\">\n",
       "\n",
       "  <svg xmlns=\"http://www.w3.org/2000/svg\" height=\"24px\" viewBox=\"0 -960 960 960\">\n",
       "    <path d=\"M120-120v-720h720v720H120Zm60-500h600v-160H180v160Zm220 220h160v-160H400v160Zm0 220h160v-160H400v160ZM180-400h160v-160H180v160Zm440 0h160v-160H620v160ZM180-180h160v-160H180v160Zm440 0h160v-160H620v160Z\"/>\n",
       "  </svg>\n",
       "    </button>\n",
       "\n",
       "  <style>\n",
       "    .colab-df-container {\n",
       "      display:flex;\n",
       "      gap: 12px;\n",
       "    }\n",
       "\n",
       "    .colab-df-convert {\n",
       "      background-color: #E8F0FE;\n",
       "      border: none;\n",
       "      border-radius: 50%;\n",
       "      cursor: pointer;\n",
       "      display: none;\n",
       "      fill: #1967D2;\n",
       "      height: 32px;\n",
       "      padding: 0 0 0 0;\n",
       "      width: 32px;\n",
       "    }\n",
       "\n",
       "    .colab-df-convert:hover {\n",
       "      background-color: #E2EBFA;\n",
       "      box-shadow: 0px 1px 2px rgba(60, 64, 67, 0.3), 0px 1px 3px 1px rgba(60, 64, 67, 0.15);\n",
       "      fill: #174EA6;\n",
       "    }\n",
       "\n",
       "    .colab-df-buttons div {\n",
       "      margin-bottom: 4px;\n",
       "    }\n",
       "\n",
       "    [theme=dark] .colab-df-convert {\n",
       "      background-color: #3B4455;\n",
       "      fill: #D2E3FC;\n",
       "    }\n",
       "\n",
       "    [theme=dark] .colab-df-convert:hover {\n",
       "      background-color: #434B5C;\n",
       "      box-shadow: 0px 1px 3px 1px rgba(0, 0, 0, 0.15);\n",
       "      filter: drop-shadow(0px 1px 2px rgba(0, 0, 0, 0.3));\n",
       "      fill: #FFFFFF;\n",
       "    }\n",
       "  </style>\n",
       "\n",
       "    <script>\n",
       "      const buttonEl =\n",
       "        document.querySelector('#df-0facbba1-92f4-4bf7-a37e-7673457e16f1 button.colab-df-convert');\n",
       "      buttonEl.style.display =\n",
       "        google.colab.kernel.accessAllowed ? 'block' : 'none';\n",
       "\n",
       "      async function convertToInteractive(key) {\n",
       "        const element = document.querySelector('#df-0facbba1-92f4-4bf7-a37e-7673457e16f1');\n",
       "        const dataTable =\n",
       "          await google.colab.kernel.invokeFunction('convertToInteractive',\n",
       "                                                    [key], {});\n",
       "        if (!dataTable) return;\n",
       "\n",
       "        const docLinkHtml = 'Like what you see? Visit the ' +\n",
       "          '<a target=\"_blank\" href=https://colab.research.google.com/notebooks/data_table.ipynb>data table notebook</a>'\n",
       "          + ' to learn more about interactive tables.';\n",
       "        element.innerHTML = '';\n",
       "        dataTable['output_type'] = 'display_data';\n",
       "        await google.colab.output.renderOutput(dataTable, element);\n",
       "        const docLink = document.createElement('div');\n",
       "        docLink.innerHTML = docLinkHtml;\n",
       "        element.appendChild(docLink);\n",
       "      }\n",
       "    </script>\n",
       "  </div>\n",
       "\n",
       "\n",
       "    </div>\n",
       "  </div>\n"
      ],
      "application/vnd.google.colaboratory.intrinsic+json": {
       "type": "dataframe",
       "summary": "{\n  \"name\": \"display(distance_km\",\n  \"rows\": 5,\n  \"fields\": [\n    {\n      \"column\": \"DC\",\n      \"properties\": {\n        \"dtype\": \"number\",\n        \"std\": 20.201311838591078,\n        \"min\": 0.0,\n        \"max\": 51.3,\n        \"num_unique_values\": 5,\n        \"samples\": [\n          36.6,\n          26.3,\n          11.6\n        ],\n        \"semantic_type\": \"\",\n        \"description\": \"\"\n      }\n    },\n    {\n      \"column\": \"C1\",\n      \"properties\": {\n        \"dtype\": \"number\",\n        \"std\": 18.75321305803355,\n        \"min\": 0.0,\n        \"max\": 44.0,\n        \"num_unique_values\": 5,\n        \"samples\": [\n          0.0,\n          44.0,\n          33.1\n        ],\n        \"semantic_type\": \"\",\n        \"description\": \"\"\n      }\n    },\n    {\n      \"column\": \"C2\",\n      \"properties\": {\n        \"dtype\": \"number\",\n        \"std\": 13.554261322550927,\n        \"min\": 0.0,\n        \"max\": 34.8,\n        \"num_unique_values\": 5,\n        \"samples\": [\n          27.7,\n          22.4,\n          0.0\n        ],\n        \"semantic_type\": \"\",\n        \"description\": \"\"\n      }\n    },\n    {\n      \"column\": \"C3\",\n      \"properties\": {\n        \"dtype\": \"number\",\n        \"std\": 22.875095628215416,\n        \"min\": 0.0,\n        \"max\": 51.8,\n        \"num_unique_values\": 5,\n        \"samples\": [\n          12.1,\n          51.8,\n          32.8\n        ],\n        \"semantic_type\": \"\",\n        \"description\": \"\"\n      }\n    },\n    {\n      \"column\": \"C4\",\n      \"properties\": {\n        \"dtype\": \"number\",\n        \"std\": 20.357504758687888,\n        \"min\": 0.0,\n        \"max\": 49.9,\n        \"num_unique_values\": 5,\n        \"samples\": [\n          48.7,\n          0.0,\n          26.3\n        ],\n        \"semantic_type\": \"\",\n        \"description\": \"\"\n      }\n    }\n  ]\n}"
      }
     },
     "metadata": {}
    },
    {
     "output_type": "stream",
     "name": "stdout",
     "text": [
      "\n",
      "Mesafe matrisi (km)\n"
     ]
    },
    {
     "output_type": "display_data",
     "data": {
      "text/plain": [
       "       DC     C1    C2     C3     C4\n",
       "DC   0.00  10.07  2.75  11.41   6.88\n",
       "C1  10.07   0.00  7.64   3.44  10.72\n",
       "C2   2.75   7.64  0.00   9.50   5.62\n",
       "C3  11.41   3.44  9.50   0.00  13.62\n",
       "C4   6.88  10.72  5.62  13.62   0.00"
      ],
      "text/html": [
       "\n",
       "  <div id=\"df-bb5349ca-5a15-47f4-bbd2-9e9b0da3d59d\" class=\"colab-df-container\">\n",
       "    <div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>DC</th>\n",
       "      <th>C1</th>\n",
       "      <th>C2</th>\n",
       "      <th>C3</th>\n",
       "      <th>C4</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>DC</th>\n",
       "      <td>0.00</td>\n",
       "      <td>10.07</td>\n",
       "      <td>2.75</td>\n",
       "      <td>11.41</td>\n",
       "      <td>6.88</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>C1</th>\n",
       "      <td>10.07</td>\n",
       "      <td>0.00</td>\n",
       "      <td>7.64</td>\n",
       "      <td>3.44</td>\n",
       "      <td>10.72</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>C2</th>\n",
       "      <td>2.75</td>\n",
       "      <td>7.64</td>\n",
       "      <td>0.00</td>\n",
       "      <td>9.50</td>\n",
       "      <td>5.62</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>C3</th>\n",
       "      <td>11.41</td>\n",
       "      <td>3.44</td>\n",
       "      <td>9.50</td>\n",
       "      <td>0.00</td>\n",
       "      <td>13.62</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>C4</th>\n",
       "      <td>6.88</td>\n",
       "      <td>10.72</td>\n",
       "      <td>5.62</td>\n",
       "      <td>13.62</td>\n",
       "      <td>0.00</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>\n",
       "    <div class=\"colab-df-buttons\">\n",
       "\n",
       "  <div class=\"colab-df-container\">\n",
       "    <button class=\"colab-df-convert\" onclick=\"convertToInteractive('df-bb5349ca-5a15-47f4-bbd2-9e9b0da3d59d')\"\n",
       "            title=\"Convert this dataframe to an interactive table.\"\n",
       "            style=\"display:none;\">\n",
       "\n",
       "  <svg xmlns=\"http://www.w3.org/2000/svg\" height=\"24px\" viewBox=\"0 -960 960 960\">\n",
       "    <path d=\"M120-120v-720h720v720H120Zm60-500h600v-160H180v160Zm220 220h160v-160H400v160Zm0 220h160v-160H400v160ZM180-400h160v-160H180v160Zm440 0h160v-160H620v160ZM180-180h160v-160H180v160Zm440 0h160v-160H620v160Z\"/>\n",
       "  </svg>\n",
       "    </button>\n",
       "\n",
       "  <style>\n",
       "    .colab-df-container {\n",
       "      display:flex;\n",
       "      gap: 12px;\n",
       "    }\n",
       "\n",
       "    .colab-df-convert {\n",
       "      background-color: #E8F0FE;\n",
       "      border: none;\n",
       "      border-radius: 50%;\n",
       "      cursor: pointer;\n",
       "      display: none;\n",
       "      fill: #1967D2;\n",
       "      height: 32px;\n",
       "      padding: 0 0 0 0;\n",
       "      width: 32px;\n",
       "    }\n",
       "\n",
       "    .colab-df-convert:hover {\n",
       "      background-color: #E2EBFA;\n",
       "      box-shadow: 0px 1px 2px rgba(60, 64, 67, 0.3), 0px 1px 3px 1px rgba(60, 64, 67, 0.15);\n",
       "      fill: #174EA6;\n",
       "    }\n",
       "\n",
       "    .colab-df-buttons div {\n",
       "      margin-bottom: 4px;\n",
       "    }\n",
       "\n",
       "    [theme=dark] .colab-df-convert {\n",
       "      background-color: #3B4455;\n",
       "      fill: #D2E3FC;\n",
       "    }\n",
       "\n",
       "    [theme=dark] .colab-df-convert:hover {\n",
       "      background-color: #434B5C;\n",
       "      box-shadow: 0px 1px 3px 1px rgba(0, 0, 0, 0.15);\n",
       "      filter: drop-shadow(0px 1px 2px rgba(0, 0, 0, 0.3));\n",
       "      fill: #FFFFFF;\n",
       "    }\n",
       "  </style>\n",
       "\n",
       "    <script>\n",
       "      const buttonEl =\n",
       "        document.querySelector('#df-bb5349ca-5a15-47f4-bbd2-9e9b0da3d59d button.colab-df-convert');\n",
       "      buttonEl.style.display =\n",
       "        google.colab.kernel.accessAllowed ? 'block' : 'none';\n",
       "\n",
       "      async function convertToInteractive(key) {\n",
       "        const element = document.querySelector('#df-bb5349ca-5a15-47f4-bbd2-9e9b0da3d59d');\n",
       "        const dataTable =\n",
       "          await google.colab.kernel.invokeFunction('convertToInteractive',\n",
       "                                                    [key], {});\n",
       "        if (!dataTable) return;\n",
       "\n",
       "        const docLinkHtml = 'Like what you see? Visit the ' +\n",
       "          '<a target=\"_blank\" href=https://colab.research.google.com/notebooks/data_table.ipynb>data table notebook</a>'\n",
       "          + ' to learn more about interactive tables.';\n",
       "        element.innerHTML = '';\n",
       "        dataTable['output_type'] = 'display_data';\n",
       "        await google.colab.output.renderOutput(dataTable, element);\n",
       "        const docLink = document.createElement('div');\n",
       "        docLink.innerHTML = docLinkHtml;\n",
       "        element.appendChild(docLink);\n",
       "      }\n",
       "    </script>\n",
       "  </div>\n",
       "\n",
       "\n",
       "    </div>\n",
       "  </div>\n"
      ],
      "application/vnd.google.colaboratory.intrinsic+json": {
       "type": "dataframe",
       "summary": "{\n  \"name\": \"display(distance_km\",\n  \"rows\": 5,\n  \"fields\": [\n    {\n      \"column\": \"DC\",\n      \"properties\": {\n        \"dtype\": \"number\",\n        \"std\": 4.8198412836938935,\n        \"min\": 0.0,\n        \"max\": 11.41,\n        \"num_unique_values\": 5,\n        \"samples\": [\n          10.07,\n          6.88,\n          2.75\n        ],\n        \"semantic_type\": \"\",\n        \"description\": \"\"\n      }\n    },\n    {\n      \"column\": \"C1\",\n      \"properties\": {\n        \"dtype\": \"number\",\n        \"std\": 4.56582741679972,\n        \"min\": 0.0,\n        \"max\": 10.72,\n        \"num_unique_values\": 5,\n        \"samples\": [\n          0.0,\n          10.72,\n          7.64\n        ],\n        \"semantic_type\": \"\",\n        \"description\": \"\"\n      }\n    },\n    {\n      \"column\": \"C2\",\n      \"properties\": {\n        \"dtype\": \"number\",\n        \"std\": 3.7952101391095594,\n        \"min\": 0.0,\n        \"max\": 9.5,\n        \"num_unique_values\": 5,\n        \"samples\": [\n          7.64,\n          5.62,\n          0.0\n        ],\n        \"semantic_type\": \"\",\n        \"description\": \"\"\n      }\n    },\n    {\n      \"column\": \"C3\",\n      \"properties\": {\n        \"dtype\": \"number\",\n        \"std\": 5.688407510015435,\n        \"min\": 0.0,\n        \"max\": 13.62,\n        \"num_unique_values\": 5,\n        \"samples\": [\n          3.44,\n          13.62,\n          9.5\n        ],\n        \"semantic_type\": \"\",\n        \"description\": \"\"\n      }\n    },\n    {\n      \"column\": \"C4\",\n      \"properties\": {\n        \"dtype\": \"number\",\n        \"std\": 5.1938540603293815,\n        \"min\": 0.0,\n        \"max\": 13.62,\n        \"num_unique_values\": 5,\n        \"samples\": [\n          10.72,\n          0.0,\n          5.62\n        ],\n        \"semantic_type\": \"\",\n        \"description\": \"\"\n      }\n    }\n  ]\n}"
      }
     },
     "metadata": {}
    }
   ],
   "source": "def haversine_km(lat1, lon1, lat2, lon2):\n    R = 6371\n    phi1, phi2 = np.radians(lat1), np.radians(lat2)\n    dphi = np.radians(lat2 - lat1)\n    dlambda = np.radians(lon2 - lon1)\n    a = np.sin(dphi/2)**2 + np.cos(phi1)*np.cos(phi2)*np.sin(dlambda/2)**2\n    return 2 * R * np.arcsin(np.sqrt(a))\n\ndef get_travel_time_minutes(lat1, lon1, lat2, lon2, hour=10, use_google=False, api_key=None):\n    \"\"\"\n    Trafik-duyarlı seyahat süresi (dakika).\n    use_google=True ve api_key verilirse gerçek Google Directions API çağrılır.\n    \"\"\"\n    dist_km = haversine_km(lat1, lon1, lat2, lon2)\n\n    if use_google and api_key:\n        # Gerçek Google Maps Directions API (traffic model)\n        import requests\n        url = \"https://maps.googleapis.com/maps/api/directions/json\"\n        params = {\n            \"origin\": f\"{lat1},{lon1}\",\n            \"destination\": f\"{lat2},{lon2}\",\n            \"departure_time\": \"now\",\n            \"traffic_model\": \"best_guess\",\n            \"key\": api_key\n        }\n        resp = requests.get(url, params=params).json()\n        if resp[\"status\"] == \"OK\":\n            return resp[\"routes\"][0][\"legs\"][0][\"duration_in_traffic\"][\"value\"] / 60.0\n        else:\n            print(\"Google API hatası, simülasyona düşülüyor:\", resp.get(\"status\"))\n\n    # Simülasyon: baz hız 30 km/h + saat bazlı trafik çarpanı\n    base_speed = 28  # şehir içi ortalama\n    # Sabah/akşam rush hour\n    if 7 <= hour <= 9 or 17 <= hour <= 19:\n        traffic_factor = np.random.uniform(1.6, 2.2)\n    elif 12 <= hour <= 14:\n        traffic_factor = np.random.uniform(1.2, 1.5)\n    else:\n        traffic_factor = np.random.uniform(1.0, 1.3)\n\n    time_h = (dist_km / base_speed) * traffic_factor\n    return time_h * 60  # dakika\n\n# Mesafe + Trafik matrisi oluştur (DC + müşteriler)\nlocations = [{\"id\": \"DC\", **DC_LOCATION}] + customers[[\"id\", \"lat\", \"lon\"]].to_dict(\"records\")\nn_loc = len(locations)\nids = [loc[\"id\"] for loc in locations]\n\ntravel_time = pd.DataFrame(0.0, index=ids, columns=ids)\ndistance_km = pd.DataFrame(0.0, index=ids, columns=ids)\n\ncurrent_hour = 9  # planlama saati\n\nfor i, loc_i in enumerate(locations):\n    for j, loc_j in enumerate(locations):\n        if i == j:\n            continue\n        d = haversine_km(loc_i[\"lat\"], loc_i[\"lon\"], loc_j[\"lat\"], loc_j[\"lon\"])\n        t = get_travel_time_minutes(loc_i[\"lat\"], loc_i[\"lon\"], loc_j[\"lat\"], loc_j[\"lon\"], hour=current_hour)\n        distance_km.iloc[i, j] = d\n        travel_time.iloc[i, j] = t\n\nprint(\"🗺️  Trafik-Duyarlı Seyahat Süreleri (dakika) — Google Traffic simülasyonu\")\ndisplay(travel_time.round(1))\nprint(\"\\nMesafe matrisi (km)\")\ndisplay(distance_km.round(2))"
  },
  {
   "cell_type": "markdown",
   "id": "225abfc6",
   "metadata": {
    "id": "225abfc6"
   },
   "source": "## 4. Problem Formülasyonu: CCFOT-Odaklı VRP → QUBO\n\nBasitleştirilmiş model (eğitim için):\n- 1 depo (DC) + 4 müşteri\n- 2 uygun araç (sıcaklık alarmı olan V3’ü cezalandırıyoruz)\n- Her müşteri tam bir araca atanmalı\n- Kapasite kısıtı\n- Amaç: Toplam seyahat süresi + soğuk zincir risk cezası + zaman penceresi ihlal cezası minimize\n\nBinary değişken: $x_{v,c} = 1$ → araç $v$ müşteri $c$’yi ziyaret eder."
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "767fc52f",
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "767fc52f",
    "executionInfo": {
     "status": "ok",
     "timestamp": 1786440683237,
     "user_tz": -180,
     "elapsed": 21,
     "user": {
      "displayName": "Joseph Volkan ÖZCAN",
      "userId": "11389530967736397480"
     }
    },
    "outputId": "fd23d892-690c-4cd8-ceee-25866e1347e4"
   },
   "outputs": [
    {
     "output_type": "stream",
     "name": "stdout",
     "text": [
      "QuadraticProgram oluşturuldu:\n",
      "Problem name: Unilever_CCFOT_VRP\n",
      "\n",
      "Minimize\n",
      "  75.93506445481637*x_V1_C1 + 24.368270750402996*x_V1_C2\n",
      "  + 101.16724150199461*x_V1_C3 + 55.162521967978435*x_V1_C4\n",
      "  + 76.93506445481637*x_V2_C1 + 25.368270750402992*x_V2_C2\n",
      "  + 102.16724150199461*x_V2_C3 + 56.162521967978435*x_V2_C4\n",
      "\n",
      "Subject to\n",
      "  Linear constraints (6)\n",
      "    x_V1_C1 + x_V2_C1 == 1  'assign_C1'\n",
      "    x_V1_C2 + x_V2_C2 == 1  'assign_C2'\n",
      "    x_V1_C3 + x_V2_C3 == 1  'assign_C3'\n",
      "    x_V1_C4 + x_V2_C4 == 1  'assign_C4'\n",
      "    12*x_V1_C1 + 8*x_V1_C2 + 15*x_V1_C3 + 10*x_V1_C4 <= 25  'cap_V1'\n",
      "    12*x_V2_C1 + 8*x_V2_C2 + 15*x_V2_C3 + 10*x_V2_C4 <= 18  'cap_V2'\n",
      "\n",
      "  Binary variables (8)\n",
      "    x_V1_C1 x_V1_C2 x_V1_C3 x_V1_C4 x_V2_C1 x_V2_C2 x_V2_C3 x_V2_C4\n",
      "\n",
      "\n",
      "QUBO boyutu (değişken sayısı): 18\n"
     ]
    }
   ],
   "source": "def build_ccfot_qubo(customers, vehicles, travel_time, penalty_capacity=100, penalty_assign=80):\n    \"\"\"\n    CCFOT odaklı atama + rota maliyeti QUBO.\n    Basit model: her müşteri bir araca atanır, araçlar DC'den başlar.\n    \"\"\"\n    # Sadece sağlıklı araçları tercih et (V3 sıcaklık uyarılı)\n    usable_vehicles = vehicles[vehicles[\"status\"] == \"OK\"].copy()\n    if len(usable_vehicles) == 0:\n        usable_vehicles = vehicles.copy()\n\n    qp = QuadraticProgram(\"Unilever_CCFOT_VRP\")\n\n    # Değişkenler: x_v_c\n    var_names = []\n    for _, v in usable_vehicles.iterrows():\n        for _, c in customers.iterrows():\n            name = f\"x_{v['id']}_{c['id']}\"\n            qp.binary_var(name)\n            var_names.append(name)\n\n    # Objektif: seyahat süresi (DC → müşteri → DC yaklaşık) + risk\n    linear = {}\n    for _, v in usable_vehicles.iterrows():\n        for _, c in customers.iterrows():\n            name = f\"x_{v['id']}_{c['id']}\"\n            # DC → C + C → DC yaklaşık maliyet\n            t = travel_time.loc[\"DC\", c[\"id\"]] + travel_time.loc[c[\"id\"], \"DC\"]\n            # Sıcaklık riski (ne kadar yüksekse o kadar ceza)\n            temp_penalty = max(0, (v[\"temp_c\"] + 18) * 5)  # -18 ideal\n            linear[name] = float(t + temp_penalty)\n\n    qp.minimize(linear=linear)\n\n    # Kısıt 1: Her müşteri tam 1 araca atanmalı\n    for _, c in customers.iterrows():\n        const = {f\"x_{v['id']}_{c['id']}\": 1 for _, v in usable_vehicles.iterrows()}\n        qp.linear_constraint(linear=const, sense=\"==\", rhs=1, name=f\"assign_{c['id']}\")\n\n    # Kısıt 2: Kapasite\n    for _, v in usable_vehicles.iterrows():\n        const = {f\"x_{v['id']}_{c['id']}\": int(c[\"demand\"]) for _, c in customers.iterrows()}\n        qp.linear_constraint(linear=const, sense=\"<=\", rhs=int(v[\"capacity\"]), name=f\"cap_{v['id']}\")\n\n    print(\"QuadraticProgram oluşturuldu:\")\n    print(qp.prettyprint()[:1500] if len(qp.prettyprint()) > 1500 else qp.prettyprint())\n\n    converter = QuadraticProgramToQubo(penalty=penalty_assign)\n    qubo = converter.convert(qp)\n    return qubo, converter, usable_vehicles\n\nqubo, converter, usable_vehicles = build_ccfot_qubo(customers, vehicles, travel_time)\nprint(\"\\nQUBO boyutu (değişken sayısı):\", qubo.get_num_vars())"
  },
  {
   "cell_type": "markdown",
   "id": "f604b86d",
   "metadata": {
    "id": "f604b86d"
   },
   "source": "## 5. Multi-Hardware Access Katmanı\n\nAynı QUBO’yu farklı backend’lerde çalıştırma imkanı:\n\n| Backend              | Tip                  | Kullanım                     |\n|----------------------|----------------------|------------------------------|\n| StatevectorSampler   | Ideal simülasyon     | Eğitim, hızlı doğrulama      |\n| AerSampler           | Shot-based simülasyon| Gürültü etkisini görmek      |\n| IBM Quantum Runtime  | Gerçek donanım       | Token + Session ile          |\n\nAşağıda her ikisini de çalıştırıyoruz. IBM için token eklenebilir."
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "a5287284-11f9-4666-b2fd-221155bf47c5",
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "a5287284-11f9-4666-b2fd-221155bf47c5",
    "executionInfo": {
     "status": "ok",
     "timestamp": 1786440819394,
     "user_tz": -180,
     "elapsed": 136155,
     "user": {
      "displayName": "Joseph Volkan ÖZCAN",
      "userId": "11389530967736397480"
     }
    },
    "outputId": "dac2181f-4a39-4706-d75b-706a77d0ac65"
   },
   "outputs": [
    {
     "output_type": "stream",
     "name": "stdout",
     "text": [
      "==================================================\n",
      "1/2  NumPy Exact cozuluyor (saniyeler)...\n",
      "  -> backend=numpy, reps=1, maxiter=40\n",
      "[NumPy Exact] fval = 236.47\n",
      "fval=236.46585717319977, x_V1_C1=0.0, x_V1_C2=1.0, x_V1_C3=0.0, x_V1_C4=1.0, x_V2_C1=1.0, x_V2_C2=0.0, x_V2_C3=0.0, x_V2_C4=0.0, cap_V1@int_slack@0=1.0, cap_V1@int_slack@1=1.0, cap_V1@int_slack@2=1.0, cap_V1@int_slack@3=0.0, cap_V1@int_slack@4=0.0, cap_V2@int_slack@0=1.0, cap_V2@int_slack@1=1.0, cap_V2@int_slack@2=0.0, cap_V2@int_slack@3=0.0, cap_V2@int_slack@4=1.0, status=SUCCESS\n",
      "==================================================\n",
      "2/2  QAOA Statevector cozuluyor (genelde < 60 sn)...\n",
      "  -> backend=statevector, reps=1, maxiter=40\n",
      "[StatevectorSampler (Ideal QAOA)] fval = 452.10\n",
      "fval=452.0975864228094, x_V1_C1=1.0, x_V1_C2=0.0, x_V1_C3=0.0, x_V1_C4=0.0, x_V2_C1=0.0, x_V2_C2=0.0, x_V2_C3=0.0, x_V2_C4=1.0, cap_V1@int_slack@0=0.0, cap_V1@int_slack@1=1.0, cap_V1@int_slack@2=1.0, cap_V1@int_slack@3=1.0, cap_V1@int_slack@4=0.0, cap_V2@int_slack@0=1.0, cap_V2@int_slack@1=0.0, cap_V2@int_slack@2=0.0, cap_V2@int_slack@3=1.0, cap_V2@int_slack@4=0.0, status=SUCCESS\n",
      "==================================================\n",
      "Cozum adimi tamam.\n"
     ]
    }
   ],
   "source": "def solve_with_backend(qubo, backend_name=\"numpy\", reps=1, maxiter=40, seed=42):\n    \"\"\"\n    Multi-hardware solver - FAST defaults for Colab.\n    backend_name: 'numpy' (exact, instant) | 'statevector' (QAOA) | 'aer' (shot-based QAOA)\n    \"\"\"\n    algorithm_globals.random_seed = seed\n    print(f\"  -> backend={backend_name}, reps={reps}, maxiter={maxiter}\", flush=True)\n\n    if backend_name == \"numpy\":\n        mes = NumPyMinimumEigensolver()\n        optimizer = MinimumEigenOptimizer(mes)\n        result = optimizer.solve(qubo)\n        return result, \"NumPy Exact\"\n\n    if backend_name == \"statevector\":\n        try:\n            sampler = StatevectorSampler(seed=seed)\n        except TypeError:\n            sampler = StatevectorSampler()\n        label = \"StatevectorSampler (Ideal QAOA)\"\n    elif backend_name == \"aer\":\n        if not HAS_AER:\n            print(\"  Aer yok, statevector'a dusuluyor.\", flush=True)\n            try:\n                sampler = StatevectorSampler(seed=seed)\n            except TypeError:\n                sampler = StatevectorSampler()\n            label = \"StatevectorSampler (Aer fallback)\"\n        else:\n            sampler = AerSampler()\n            label = \"AerSampler (Shot-based QAOA)\"\n    else:\n        raise ValueError(\"Desteklenen: statevector, aer, numpy\")\n\n    # QAOA - keep small for Colab speed\n    qaoa = QAOA(sampler=sampler, optimizer=COBYLA(maxiter=maxiter), reps=reps)\n    optimizer = MinimumEigenOptimizer(qaoa)\n    result = optimizer.solve(qubo)\n    return result, label\n\n\n# --- 1) ONCE NumPy Exact (8 degisken -> aninda biter) ---\nprint(\"=\" * 50, flush=True)\nprint(\"1/2  NumPy Exact cozuluyor (saniyeler)...\", flush=True)\nresult_exact, label_exact = solve_with_backend(qubo, \"numpy\")\nprint(f\"[{label_exact}] fval = {result_exact.fval:.2f}\", flush=True)\nprint(result_exact)\n\n# --- 2) Sonra kisa QAOA (demo) ---\nprint(\"=\" * 50, flush=True)\nprint(\"2/2  QAOA Statevector cozuluyor (genelde < 60 sn)...\", flush=True)\ntry:\n    result_sv, label_sv = solve_with_backend(qubo, \"statevector\", reps=1, maxiter=40)\n    print(f\"[{label_sv}] fval = {result_sv.fval:.2f}\", flush=True)\n    print(result_sv)\nexcept Exception as e:\n    print(f\"QAOA atlandi / hata: {type(e).__name__}: {e}\", flush=True)\n    print(\"NumPy sonucu kullanilacak.\", flush=True)\n    result_sv, label_sv = result_exact, label_exact\n\nprint(\"=\" * 50, flush=True)\nprint(\"Cozum adimi tamam.\", flush=True)"
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "id": "026c1e16-7787-4b55-a565-59bd2b1e7894",
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "026c1e16-7787-4b55-a565-59bd2b1e7894",
    "executionInfo": {
     "status": "ok",
     "timestamp": 1786440892991,
     "user_tz": -180,
     "elapsed": 29,
     "user": {
      "displayName": "Joseph Volkan ÖZCAN",
      "userId": "11389530967736397480"
     }
    },
    "outputId": "40e8058f-3f5e-4b71-d8b7-0ab8ba634945"
   },
   "outputs": [
    {
     "output_type": "stream",
     "name": "stdout",
     "text": [
      "IBM Runtime yuklenemedi: No module named 'qiskit_ibm_runtime'\n"
     ]
    }
   ],
   "source": "# Opsiyonel: IBM Quantum Runtime (token gerekir)\nUSE_IBM = True  # True yapin ve token ekleyin\n\nif USE_IBM:\n    try:\n        from qiskit_ibm_runtime import QiskitRuntimeService, Session\n        # service = QiskitRuntimeService(channel=\"ibm_quantum\", token=\"<REDACTED>\")\n        # backend = service.least_busy(min_num_qubits=10, operational=True)\n        print(\"IBM Runtime import OK - token ve Session kodunu acin\")\n    except Exception as e:\n        print(f\"IBM Runtime yuklenemedi: {e}\")\nelse:\n    print(\"IBM Quantum Runtime devre disi (USE_IBM=False). NumPy + Statevector kullanildi.\")"
  },
  {
   "cell_type": "markdown",
   "id": "75c8b85a",
   "metadata": {
    "id": "75c8b85a"
   },
   "source": "## 6. Sonuçların Yorumlanması & CCFOT Etkisi"
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "a0475df9-f65f-45cf-8941-ac4317e628af",
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "a0475df9-f65f-45cf-8941-ac4317e628af",
    "executionInfo": {
     "status": "ok",
     "timestamp": 1786440819503,
     "user_tz": -180,
     "elapsed": 698,
     "user": {
      "displayName": "Joseph Volkan ÖZCAN",
      "userId": "11389530967736397480"
     }
    },
    "outputId": "64831d16-9f8d-4f8a-85c3-2fec384015c0"
   },
   "outputs": [
    {
     "output_type": "stream",
     "name": "stdout",
     "text": [
      "Ham secilen degiskenler: ['x_V1_C1', 'x_V2_C4', 'cap_V1@int_slack@1', 'cap_V1@int_slack@2', 'cap_V1@int_slack@3', 'cap_V2@int_slack@0', 'cap_V2@int_slack@3']\n",
      "  Atlanan degisken (parse edilemedi): cap_V1@int_slack@1\n",
      "  Atlanan degisken (parse edilemedi): cap_V1@int_slack@2\n",
      "  Atlanan degisken (parse edilemedi): cap_V1@int_slack@3\n",
      "  Atlanan degisken (parse edilemedi): cap_V2@int_slack@0\n",
      "  Atlanan degisken (parse edilemedi): cap_V2@int_slack@3\n",
      "============================================================\n",
      "UNILEVER CCFOT - QUANTUM ROTA SONUCU\n",
      "============================================================\n",
      "\n",
      "Arac V1 (Reefer-12t) | Kapasite: 25 | Sicaklik: -18.2C\n",
      "  Atanan musteriler: ['C1']\n",
      "  Toplam talep     : 12 / 25\n",
      "\n",
      "Arac V2 (Reefer-8t) | Kapasite: 18 | Sicaklik: -17.8C\n",
      "  Atanan musteriler: ['C4']\n",
      "  Toplam talep     : 10 / 18\n",
      "\n",
      "Toplam tahmini seyahat suresi: 131.1 dakika\n",
      "\n",
      "Tahmini CCFOT skoru: 97.6%\n",
      "   (On-time + Fill + Cold-chain risk)\n"
     ]
    }
   ],
   "source": "def interpret_ccfot_result(result, customers, usable_vehicles, travel_time):\n    \"\"\"Sonucu yorumla - QUBO/Ising donusumu sonrasi degisken adlarina dayanikli.\"\"\"\n    # Secilen (1 olan) degiskenler\n    selected = {var: val for var, val in result.variables_dict.items() if abs(float(val) - 1.0) < 1e-5}\n\n    known_vehicles = set(usable_vehicles[\"id\"].astype(str))\n    known_customers = set(customers[\"id\"].astype(str))\n\n    assignment = {v: [] for v in known_vehicles}\n    total_time = 0.0\n    total_demand = {v: 0 for v in known_vehicles}\n\n    print(\"Ham secilen degiskenler:\", list(selected.keys()))\n\n    for var in selected:\n        # Qiskit bazen \"x_V1_C2\", bazen \"x_V1@int_C2@int\" gibi isimler uretir\n        clean = (\n            str(var)\n            .replace(\"@int\", \"\")\n            .replace(\"@bin\", \"\")\n            .replace(\" \", \"\")\n        )\n        parts = [p for p in clean.split(\"_\") if p]\n\n        # Beklenen: [\"x\", \"V1\", \"C2\"] veya [\"V1\", \"C2\"]\n        vid, cid = None, None\n        if len(parts) >= 3 and parts[0].lower().startswith(\"x\"):\n            vid, cid = parts[1], parts[2]\n        elif len(parts) >= 2:\n            # x_ olmadan V1_C2\n            for a, b in [(parts[0], parts[1]), (parts[-2], parts[-1])]:\n                if a in known_vehicles and b in known_customers:\n                    vid, cid = a, b\n                    break\n\n        if vid is None or cid is None:\n            # Son care: bilinen id'leri string icinde ara\n            for v in known_vehicles:\n                for c in known_customers:\n                    if v in clean and c in clean:\n                        vid, cid = v, c\n                        break\n                if vid:\n                    break\n\n        if vid not in known_vehicles or cid not in known_customers:\n            print(f\"  Atlanan degisken (parse edilemedi): {var}\")\n            continue\n\n        if cid in assignment[vid]:\n            continue  # tekrar ekleme\n\n        assignment[vid].append(cid)\n        cust = customers[customers[\"id\"] == cid].iloc[0]\n        total_demand[vid] += int(cust[\"demand\"])\n        total_time += float(travel_time.loc[\"DC\", cid] + travel_time.loc[cid, \"DC\"])\n\n    print(\"=\" * 60)\n    print(\"UNILEVER CCFOT - QUANTUM ROTA SONUCU\")\n    print(\"=\" * 60)\n    any_assigned = False\n    for vid, custs in assignment.items():\n        if not custs:\n            continue\n        any_assigned = True\n        vrow = usable_vehicles[usable_vehicles[\"id\"] == vid].iloc[0]\n        print(f\"\\nArac {vid} ({vrow['type']}) | Kapasite: {vrow['capacity']} | Sicaklik: {vrow['temp_c']}C\")\n        print(f\"  Atanan musteriler: {custs}\")\n        print(f\"  Toplam talep     : {total_demand[vid]} / {vrow['capacity']}\")\n\n    if not any_assigned:\n        print(\"\\nUyari: Hic musteri atanmadi. result.variables_dict anahtarlarini kontrol edin.\")\n        print(\"variables_dict:\", result.variables_dict)\n\n    print(f\"\\nToplam tahmini seyahat suresi: {total_time:.1f} dakika\")\n\n    # CCFOT skoru (0-100)\n    on_time_score = 95.0\n    try:\n        fill_ok = all(\n            total_demand[v] <= int(usable_vehicles[usable_vehicles[\"id\"] == v][\"capacity\"].values[0])\n            for v in total_demand\n        )\n    except Exception:\n        fill_ok = False\n    fill_score = 100.0 if fill_ok else 85.0\n    cold_chain_score = 98.0\n    ccfot_est = 0.4 * on_time_score + 0.4 * fill_score + 0.2 * cold_chain_score\n\n    print(f\"\\nTahmini CCFOT skoru: {ccfot_est:.1f}%\")\n    print(\"   (On-time + Fill + Cold-chain risk)\")\n    return assignment, total_time, ccfot_est\n\n# result_sv yoksa exact kullan\n_result = result_sv if \"result_sv\" in dir() else result_exact\nassignment, total_time, ccfot = interpret_ccfot_result(_result, customers, usable_vehicles, travel_time)\n"
  },
  {
   "cell_type": "markdown",
   "id": "32209452",
   "metadata": {
    "id": "32209452"
   },
   "source": "## 7. Görselleştirme"
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "5737da2a",
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/",
     "height": 707
    },
    "id": "5737da2a",
    "executionInfo": {
     "status": "ok",
     "timestamp": 1786440819997,
     "user_tz": -180,
     "elapsed": 743,
     "user": {
      "displayName": "Joseph Volkan ÖZCAN",
      "userId": "11389530967736397480"
     }
    },
    "outputId": "bcdfa5c1-12c8-452b-ed4d-ce16ce826950"
   },
   "outputs": [
    {
     "output_type": "display_data",
     "data": {
      "text/plain": [
       "<Figure size 1000x700 with 1 Axes>"
      ],
      "image/png": "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LVu21IoVK3T27Fk9+eST9dpvU9uxY4c2bNigqVOn6sYbb6xy/6JFi9SlSxc98cQT1lPwK8bdhafCV9dn+fXXX2vq1KnWU/rj4+N1++23Kysry+axFa0Vhw8f1tSpUxUZGamIiAhNmzZNhYWF1u1MJpPOnj2rl19+2Xo6asVRpJrGeG39revWrdMll1yiFi1aqG/fvtq/f78kacWKFercubOCgoI0cODAep0GvmbNGkVFRWnEiBG66aabtGbNGpv7V69erZtvvlmSdO2111ZpLXj33Xc1YsQIJSQkKDAwUJ06ddJjjz2m8vJym/0MHDhQ3bp109dff60BAwYoODhYnTt31ptvvilJ2rJli3r37q0WLVqoa9eu+uijj2we/+OPP+p3v/udunbtqhYtWigmJkY333yzXa/1yJEjkqSrr766yn0VrRuVbd68Wddcc41CQkIUGRmp0aNH67vvvrPZxt4xUFs/b3WnbP/0009KTk62vp8dOnTQb3/7W5WUlNg874Wq662tztatW5WZmakhQ4bUut2FKp73wIEDmjhxoqKiovSrX/1Kkn3fN1OnTtWAAQMkSTfffLNMJpO1/aim13ShhQsXysfHR3//+9/rVbsz1fU7qDYHDx7UTTfdpOjoaAUFBalXr1567733bLap+Fy3bt2qWbNmKTY2VpGRkZo+fbpKSkqUk5OjyZMnKyoqSlFRUXrggQeqtNiYzWY9++yzuvTSSxUUFKRWrVpp+vTpOnPmjHWb9u3b69tvv9WWLVus3+MVn09FDVu2bNHvfvc7xcXFWX9f1TTurrvuOv3444/at29f/d5QwEtwejkAp3viiSfk4+Oj++67T7m5uXryySc1adIkffHFF/XaT3p6uvr06WMNJLGxsfrvf/+r5ORk5eXl6d5771WrVq00YMAAvfHGG3rkkUdsHv+vf/1Lvr6+1kBRWFioAQMG6KefftL06dOVmJiobdu2ad68eUpNTdWzzz5r8/hVq1apqKhId911lwIDAxUdHV1tnf/9739VVlam3/zmN3a9rvfff18dO3ZUv3797H4vSktLq/TWBwcHKzg42LrP9u3b65prrqn28f3791f79u31wQcf2P2crvD+++9LkiZPnlzt/X5+fpo4caIWLFigbdu2afDgwfXa/8aNG3X06FFNmzZN8fHx1tP4v/32W+3YsaNKMJgwYYI6dOigRYsWac+ePXrxxRcVFxen//u//5NkOU3/wlNSO3XqVN+XLUn67LPP9N5772nGjBmSLH9gGDlypB544AEtW7ZMv/vd73TmzBk9+eSTuv3227V582a79rtmzRqNGzdOAQEBuu2227R8+XLt3LlTV155pSTL2Jg1a1aV040r/l29erVCQ0M1d+5chYaGavPmzfrTn/6kvLw8PfXUUzbPdebMGY0cOVK33nqrbr75Zi1fvly33nqr1qxZo3vvvVd33323Jk6cqKeeeko33XSTTpw4obCwMEmWU563bdumW2+9VRdddJGOHTum5cuXa+DAgTpw4IB1rFenom/4lVde0cMPP1xrwPvoo480fPhwdezYUY8++qjOnTunv//977r66qu1Z8+eKn8oqWsM1MepU6d01VVXKScnR3fddZeSkpL0008/6c0331RhYaFNu0hDbdu2TSaTSb/85S8b9Pibb75ZXbp00eOPP24Nd/Z830yfPl1t2rTR448/rlmzZunKK69Uq1at7H7ehx9+WI8//rhWrFihO++8s0G1O5o9v4Nq8u233+rqq69WmzZt9NBDDykkJERvvPGGxowZo7feesva6lNh5syZio+P14IFC7Rjxw49//zzioyM1LZt25SYmKjHH39c//nPf/TUU0+pW7duNj8jp0+frtWrV2vatGmaNWuWfvjhBy1ZskR79+7V559/Ln9/fz377LOaOXOmQkND9cc//lGSqnw+v/vd7xQbG6s//elPOnv2bK3vTc+ePSVJn3/+eYPHGtCsufpQOwDPUd/TyytO8bv44ottTsX+29/+Zkgy9u/fb103ZcoUo127djb70wWnlycnJxutW7c2MjMzbba79dZbjYiICKOwsNAwDMNYsWJFlf0bhmFccsklxqBBg6y3H3vsMSMkJMT4/vvvbbZ76KGHDF9fX+P48eOGYZw/VTA8PLzKqdrVmTNnjiHJ2Lt3b53b5ubmGpKM0aNH17lthXbt2hmSqnxVvFc5OTl27fPGG280JBl5eXlV7nOX08vHjBljSDLOnDlT4zbr1683JBnPPfecYRjnx92Fp8pWd8pnxZip7PXXXzckGZ9++ql1XcXYv/322222HTt2rBETE2OzrqZTUqsb45X3XZkkIzAw0Ob02IpxHR8fb/OZzZs3z+5TaXft2mVIMjZu3GgYhmGYzWbjoosuMmbPnm2zXW2nG1f3nk2fPt0IDg42ioqKrOsGDBhgSDJee+0167qDBw8akgwfHx9jx44d1vUbNmyw67PZvn27Icl45ZVXan2dhYWFRteuXQ1JRrt27YypU6caK1euNNLT06tse8UVVxhxcXFGVlaWdd1XX31l+Pj4GJMnT7aus3cM1HZq8YU/0yZPnmz4+PgYO3furLJtxWm61Y0PwzCMVatW2fW5//rXv64yRi9U3edd8by33XZble3t/b6p+F688PTymsZ8xenlv//97w0fHx9j9erVtdZdE2edXm7v76DqxsDgwYONyy67zOZ7xGw2G/369TO6dOliXVfxuQ4bNszmVO2+ffsaJpPJuPvuu63rysrKjIsuusjm9+5nn31WbWvFhx9+WGV9TaeXV9Twq1/9yigrK6v2vure24CAAOO3v/1tlfUAOL0cQBOYNm2azRGbiqOvR48etXsfhmHorbfe0qhRo2QYhjIzM61fw4YNU25urvbs2SNJGjdunPz8/PSvf/3L+vhvvvlGBw4c0C233GJdt27dOl1zzTWKioqy2d+QIUNUXl6uTz/91KaG8ePHVzlVuzp5eXmSZD1i56htK+vdu7c2btxo81VxpCM/P9+ufVbcX1GDO7LntVTcV7FtfbRo0cK6XFRUpMzMTPXp00eSrOOpsrvvvtvm9jXXXKOsrCynvIeDBw+2OcpacaXx8ePH27wfFevt+X5as2aNWrVqZb2glslk0i233KK1a9dWOT28JpXfs/z8fGVmZuqaa65RYWGhDh48aLNtaGiobr31Vuvtrl27KjIyUhdffLHNldOrew2Vn6e0tFRZWVnq3LmzIiMjq/1sLqzxiy++0P333y/JcnQ+OTlZrVu31syZM1VcXCxJSk1N1b59+zR16lSbM1e6d++u6667Tv/5z3+q7NtRY8BsNuudd97RqFGj1KtXryr323P6tT2ysrIUFRXV4Mdf+Hql+n/f2MswDN1zzz3629/+pldffVVTpkyx63G5ubk2P8Nzc3MlWc60qLy+oKCgUbXZ+zvoQtnZ2dq8ebMmTJhg/Z7JzMxUVlaWhg0bppSUFP300082j0lOTrYZA71795ZhGEpOTrau8/X1Va9evWy+b9atW6eIiAhdd911NjX27NlToaGh+vjjj+1+zXfeead8fX3t3r7idymAqji9HIBDVfcfxcTERJvbFf8BrNxfVpfTp08rJydHzz//vM1VvCvLyMiQZOlZHjx4sN544w099thjkiynlvv5+WncuHHW7VNSUvT111/XGKQr9lehQ4cOdtVa0S9qTwisz7aVtWzZssYeTXtDqL3h3B7Z2dnWHtT6io6OrvE02sqvJTIystptKl5HXFxcvZ87OztbCxYs0Nq1a6t83hX/ca+strF8YZ9wY134XBEREZKktm3bVru+ru+n8vJyrV27Vtdee61++OEH6/revXvr6aef1qZNmzR06NA66/r222/18MMPa/PmzVWC5oXv2UUXXVTlZ0JERIRdr+HcuXNatGiRVq1apZ9++smmb7W6z+ZCERERevLJJ/Xkk0/qxx9/1KZNm/TXv/5VS5YsUUREhBYuXKgff/xRkuWPARe6+OKLtWHDBp09e1YhISHW9Y4aA6dPn1ZeXp66detm92MaqvJ7V1/V/dyr7/eNvV555RUVFBRo+fLluu222+x+3OjRo7Vly5Yq63v06GFze8qUKQ2eIqs+v4MudPjwYRmGofnz52v+/Pk1PrZNmzbW2/X5/q/8fZOSkqLc3Nwafx7WVGN17P2dV8EwDIf9sQhobgjdAOwWFBQkSTZzRldWWFho3aaymv5SXp//CFZc2OzXv/51jUc/Kk9vc+utt2ratGnat2+frrjiCr3xxhsaPHiwWrZsabPP6667Tg888EC1+/vFL35hc7vy0Z3aJCUlSZL279+vK664otZtw8PDlZCQoG+++caufdsjIiJCrVu31tdff13rdl9//bXatGnjkLA4bty4av/Ta4+PP/64xvndL7nkEr3zzjv6+uuv1b9//2q3qXidHTt2lFTzEcLqjuROmDBB27Zt0/33368rrrhCoaGhMpvNuv7666udwq4xY7k+ddX2XA2tYfPmzUpNTdXatWu1du3aKvevWbOmztCdk5OjAQMGKDw8XH/+85/VqVMnBQUFac+ePXrwwQervGeNeQ0zZ87UqlWrdO+996pv376KiIiQyWTSrbfeWu/pBdu1a6fbb79dY8eOVceOHbVmzRotXLiwXvuwt/b6fs51aez+YmJi6vUHzgtV93Ovvt839rr66qu1b98+LVmyRBMmTKjxuhkXevrpp21e41dffaX77rtPr776qk2fcmOmiavv76DqHnvfffdp2LBh1W5z4bR99fneqfx9YzabFRcXV+UCiRXsOVurgr2/8yrk5OTY/I4FcB6hG4DdKi5OdOjQoSp/bS8sLNSJEyfsOlLWELGxsQoLC1N5ebldV+EdM2aMpk+fbj3F/Pvvv9e8efNstunUqZMKCgrqfVXfugwfPly+vr569dVX7bqY2siRI/X8889r+/bt6tu3r0NqGDlypF544QVt3brVesXhyj777DMdO3ZM06dPd8jzXfif3vq4/PLLa7xv1KhRevzxx/XKK69UG7rLy8v12muvqVWrVtb7K4485uTk2GxbcVSzwpkzZ7Rp0yYtWLBAf/rTn6zrU1JSGvQ6KtQUkqKioqrUVF1dzrJmzRrFxcVp6dKlVe5bv3693n77bf3jH/9QixYtanwNn3zyibKysrR+/Xqbz6PykXNHefPNNzVlyhQ9/fTT1nVFRUXVvof2ioqKUqdOnax/5Kr8M+1CBw8eVMuWLW2Octv7HFLd4y82Nlbh4eF1/sGt8v4qn+1h77hJSkrSmjVrlJubaz1a2hjO+r6RLMHzySef1MCBA3X99ddr06ZNdp2JU3ERrwp+fpb/3l599dUOm2e+vr+DKqv4g6C/v7/Df99cqFOnTvroo4909dVX1xmaHXlU+qefflJJSYnNPO8AzqOnG4DdBg8erICAAC1fvrzK0Yznn39eZWVlGj58uFOe29fXV+PHj9dbb71V7X9ST58+bXM7MjJSw4YN0xtvvKG1a9cqICBAY8aMsdlmwoQJ2r59uzZs2FBlfzk5OSorK2tQrW3bttWdd96p//3vf9VOdWM2m/X000/r5MmTkqQHHnhAISEhuuOOO5Senl5l+yNHjuhvf/tbvWq4//771aJFC02fPr3K9FfZ2dm6++67FRwcbO15bayePXtqyJAhDfqqrd+0T58+Gjp0qFatWqV///vfVe7/4x//qO+//14PPPCA9T/a7dq1k6+vb5We/GXLltncrjhidOER4guvWl9fISEh1QbDTp06KTc31+YMhNTUVL399tuNej57nDt3TuvXr9fIkSN10003Vfm65557lJ+fb52+qCJoXvg6qnvPSkpKqry3juDr61vls/n73/9u1xHer776qtre0h9//FEHDhywnk7eunVrXXHFFXr55ZdtXus333yj//3vf7rhhhvqXXd4eLhatmxZ5/jz8fHRmDFj9P7772vXrl1V9lPx2iuufl95fxXT0tmjb9++MgxDu3fvrtfrqImzvm8qdO/eXf/5z3/03XffadSoUTWeWdXU6vs7qLK4uDgNHDhQK1asUGpqar0eW18TJkxQeXm5tbWqsrKyMptxXtPPqoaoGF/1mYUD8CYc6QZgt7i4OP3pT3/Sww8/rP79++vGG29UcHCwtm3bptdff11Dhw7VqFGjnPb8TzzxhD7++GP17t1bd955py655BJlZ2drz549+uijj5SdnW2z/S233KJf//rXWrZsmYYNG1alJ/j+++/Xe++9p5EjR2rq1Knq2bOnzp49q/379+vNN9/UsWPHGnyq3NNPP60jR45o1qxZ1rATFRWl48ePa926dTp48KD1AlOdOnXSa6+9pltuuUUXX3yxJk+erG7duqmkpETbtm3TunXrrHM926tLly56+eWXNWnSJF122WVKTk5Whw4ddOzYMa1cuVKZmZl6/fXXGzydVVN65ZVXNGjQII0ePVoTJ07UNddco+LiYq1fv16ffPKJfv3rX2vOnDnW7SMiInTzzTfr73//u0wmkzp16qR///vfVXoZw8PD1b9/fz355JMqLS1VmzZt9L///a/RR2179uypjz76SM8884wSEhLUoUMH9e7dW7feeqsefPBBjR07VrNmzVJhYaGWL1+uX/ziF426+JQ93nvvPeXn51c717lk+eNGbGys1qxZo1tuuUVXXHGFfH199X//93/Kzc1VYGCgBg0apH79+ikqKkpTpkzRrFmzZDKZ9M9//rNRPcM1GTlypP75z38qIiJCl1xyibZv366PPvpIMTExdT5248aNeuSRR3TjjTeqT58+Cg0N1dGjR/XSSy+puLjYZq7sp556SsOHD1ffvn2VnJxsnTIsIiKiypza9rrjjjv0xBNP6I477lCvXr306aef6vvvv6+y3eOPP67//e9/GjBggO666y5dfPHFSk1N1bp167R161ZFRkZq6NChSkxMVHJysu6//375+vrqpZdeUmxsrI4fP15nLb/61a8UExOjjz76SIMGDWrQ66nMWd83lfXp00fvvvuubrjhBt10001655135O/v77D9N1R9fwdVtnTpUv3qV7/SZZddpjvvvFMdO3ZUenq6tm/frpMnT+qrr75ySI0DBgzQ9OnTtWjRIu3bt09Dhw6Vv7+/UlJStG7dOv3tb3/TTTfdJMnys2r58uVauHChOnfurLi4uAaPkY0bNyoxMZHp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fenSJe8kT27x5TXkWpy93D+x6Sa/B2DEpby8XN7HZDIJvV4vxo0bJ5KTk8WmTZuEy+VSxElMTBQlJSWKbVu3bhUJCQkiKChIpKWliePHj//nWNh0+x9f18i7774r4uPjRWhoqEhPTxdWq1WNNOkm+bI+Tp8+LXJzc0VMTIwIDQ0VM2fOHPYTYuR7atXI4cOHR4ybn58v7+NyucT69euFXq8XwcHBYunSpeLUqVMqZ0w3wlf10draet1jHz58WP3EyW2+vIZci023f5KEEMITd8yJiIiIiIiISInvdBMRERERERGphE03ERERERERkUrYdBMRERERERGphE03ERERERERkUrYdBMRERERERGphE03ERERERERkUrYdBMRERERERGphE03ERERERERkUrYdBMREdENa2trgyRJqK+vVyW+JEnYt2+fKrGJiIi8iU03ERHRGLRixQrk5OT47PhGoxFOpxMzZswAAFgsFkiShJ6eHp+NiYiIyB8F+noARERENPZoNBoYDAZfD4OIiMjv8U43ERHRLeb7779HWloagoODERsbi+LiYvzzzz/y54sXL0ZhYSFeeeUV6HQ6GAwGbNiwQRGjubkZCxYsQEhICKZPn47q6mrFI99XP17e1taGe++9FwAwYcIESJKEFStWAAAmT56MzZs3K2LPnj1bcbyWlhbcc8898rEOHTo0LKf29nbk5eVBq9VCp9MhOzsbbW1toz1VREREqmPTTUREdAv5/fff8eCDD2LevHloaGjA9u3b8dlnn+Htt99W7Pf5559j/PjxsNls+OCDD/Dmm2/Kze7Q0BBycnIQGhoKm82GTz75BK+99tp1j2k0GrF3714AwKlTp+B0OrFlyxa3xutyuZCbm4ugoCDYbDbs2LEDJpNJsc/g4CDuu+8+hIeHw2q1ora2FmFhYbj//vsxMDBwI6eHiIjI6/h4ORER0S3k448/htFoRFlZGSRJwh133IE//vgDJpMJr7/+OgICLv+/febMmSgpKQEAJCcno6ysDDU1NcjKysKhQ4fgcDhgsVjkR8g3btyIrKysEY+p0Wig0+kAADExMdBqtW6Pt7q6Gs3NzTh48CDi4uIAAO+88w4eeOABeZ/Kykq4XC58+umnkCQJAFBeXg6tVguLxYJly5bd2EkiIiLyIjbdREREt5BffvkF6enpcnMKAPPnz0dvby86OjqQkJAA4HLTfbXY2Fh0d3cDuHy32mg0Kt7ZTktLU228RqNRbrgBID09XbFPQ0MD7HY7wsPDFdv7+/vhcDhUGRcREZGnsOkmIiL6f2jcuHGKdUmS4HK5PH6cgIAACCEU2wYHB28oRm9vL+bOnYsvvvhi2GfR0dGjGh8REZHa2HQTERHdQlJSUrB3714IIeS73bW1tQgPD0d8fLxbMaZNm4b29nZ0dXVBr9cDAH788cd//U5QUBCAy++DXy06OhpOp1NeP3/+PFpbWxXjbW9vh9PpRGxsLADg+PHjihipqamorKxETEwMIiIi3MqBiIjIX3AiNSIiojHq3LlzqK+vVyyrV69Ge3s7nnvuOTQ3N2P//v0oKSlBUVGR/D73f8nKysKUKVOQn5+PxsZG1NbWYt26dQCgeGz9aomJiZAkCQcOHMCff/6J3t5eAMCSJUuwe/duWK1WnDx5Evn5+dBoNPL3MjMzcfvttyM/Px8NDQ2wWq3DJm174oknEBUVhezsbFitVrS2tsJisaCwsBAdHR03c+qIiIi8hk03ERHRGGWxWDBnzhzF8tZbb+Hbb7/FDz/8gFmzZuHpp5/GypUr5abZHRqNBvv27UNvby/mzZuHVatWyY1wSEjIiN+ZNGkS3njjDRQXF0Ov16OgoAAA8Oqrr2LRokV4+OGH8dBDDyEnJwdTpkyRvxcQEICqqipcvHgRaWlpWLVqFTZu3KiIHRoaiiNHjiAhIQG5ublISUnBypUr0d/fzzvfRETk9yRx7YtWRERERNeora3FggULYLfbFU0zERER/Ts23URERDRMVVUVwsLCkJycDLvdjueffx4TJkzA0aNHfT00IiKiMYUTqREREdEwFy5cgMlkwpkzZxAVFYXMzExs2rTJ18MiIiIac3inm4iIiIiIiEglnEiNiIiIiIiISCVsuomIiIiIiIhUwqabiIiIiIiISCVsuomIiIiIiIhUwqabiIiIiIiISCVsuomIiIiIiIhUwqabiIiIiIiISCVsuomIiIiIiIhUwqabiIiIiIiISCX/A7ZOA1U8+Z3UAAAAAElFTkSuQmCC\n"
     },
     "metadata": {}
    }
   ],
   "source": "def plot_assignment(customers, DC_LOCATION, assignment, usable_vehicles):\n    fig, ax = plt.subplots(figsize=(10, 7))\n\n    # DC\n    ax.scatter(DC_LOCATION[\"lon\"], DC_LOCATION[\"lat\"], c=\"red\", s=200, marker=\"s\", label=\"DC\", zorder=5)\n    ax.annotate(\"DC\", (DC_LOCATION[\"lon\"], DC_LOCATION[\"lat\"]), textcoords=\"offset points\", xytext=(5,5))\n\n    colors = [\"#1f77b4\", \"#ff7f0e\", \"#2ca02c\", \"#d62728\"]\n    for i, (vid, custs) in enumerate(assignment.items()):\n        if not custs:\n            continue\n        color = colors[i % len(colors)]\n        for cid in custs:\n            crow = customers[customers[\"id\"] == cid].iloc[0]\n            ax.scatter(crow[\"lon\"], crow[\"lat\"], c=color, s=120, label=f\"{vid}\" if cid == custs[0] else \"\")\n            ax.annotate(cid, (crow[\"lon\"], crow[\"lat\"]), textcoords=\"offset points\", xytext=(5,5))\n            # çizgi DC → müşteri\n            ax.plot([DC_LOCATION[\"lon\"], crow[\"lon\"]], [DC_LOCATION[\"lat\"], crow[\"lat\"]],\n                    c=color, alpha=0.6, linewidth=2)\n\n    ax.set_xlabel(\"Longitude\")\n    ax.set_ylabel(\"Latitude\")\n    ax.set_title(\"Unilever CCFOT — Quantum Atama Sonucu (Trafik + Telemetri)\")\n    ax.legend()\n    ax.grid(True, alpha=0.3)\n    plt.tight_layout()\n    plt.show()\n\nplot_assignment(customers, DC_LOCATION, assignment, usable_vehicles)"
  },
  {
   "cell_type": "markdown",
   "id": "a6f3868a",
   "metadata": {
    "id": "a6f3868a"
   },
   "source": "## 8. Uçtan Uca Mimari Özeti\n\n```\n[Araç Telemetrisi IoT] ──┐\n                         ├──► Veri Katmanı (sıcaklık, konum, yakıt)\n[Google Traffic API]  ───┘\n                              │\n                              ▼\n                    Maliyet / Risk Matrisi\n                              │\n                              ▼\n                    QUBO Formülasyonu (CCFOT odaklı)\n                              │\n              ┌───────────────┼───────────────┐\n              ▼               ▼               ▼\n     StatevectorSampler   AerSampler    IBM Quantum\n     (Ideal)              (Shot)        (Hardware)\n              │               │               │\n              └───────────────┼───────────────┘\n                              ▼\n                    En iyi atama + rota\n                              │\n                              ▼\n                    CCFOT skoru + Operasyonel karar\n```\n\n### Gerçek Üretim İçin Öneriler\n- Pairing/Column Generation ile büyük ölçek\n- Hybrid: Quantum QUBO + klasik repair (time-window, gerçek rota)\n- Streaming telemetry → periyodik re-optimizasyon\n- Google Routes API (yeni) + traffic_model=pessimistic soğuk zincir için"
  },
  {
   "cell_type": "markdown",
   "id": "cd790042",
   "metadata": {
    "id": "cd790042"
   },
   "source": "## 9. Öğrenci / Operasyon Alıştırmaları\n\n1. **Google API key** ekleyip `use_google=True` yapın → gerçek trafik sürelerini alın.\n2. V3’ü (sıcaklık uyarılı) zorla kullanılabilir yapıp CCFOT skorunun nasıl düştüğünü görün.\n3. `reps=1` vs `reps=3` karşılaştırın.\n4. Yeni bir müşteri (C5) ekleyip modeli yeniden çözün.\n5. IBM Quantum token ile `USE_IBM=True` yaparak gerçek donanıma gönderin (küçük instance).\n6. Telemetriye “kapı açık süresi” ekleyip risk fonksiyonunu genişletin."
  },
  {
   "cell_type": "markdown",
   "id": "67f7c9de",
   "metadata": {
    "id": "67f7c9de"
   },
   "source": "## 10. Kaynaklar\n\n- Unilever CCFOT & Supply Chain: unilever.com (Mannheim DC %99.8 CCFOT)\n- Google Maps Platform – Directions API (traffic_model)\n- Qiskit Optimization & QAOA tutorials\n- Vehicle Routing Problem QUBO formülasyonları (Lucas, Glover vb.)\n- Unilever Ice Cream cold chain AI initiatives (2025)\n\n---\n**Hazırlayan notu:** Bu notebook Unilever CCFOT operasyonu için quantum computing’in nasıl entegre edilebileceğini gösteren uçtan uca bir eğitim/demo çalışmasıdır.  \nGerçek ölçekte production-ready sistem hybrid mimari + enterprise veri platformu gerektirir.\n\nBaşarılar! 🚀"
  }
 ],
 "metadata": {
  "colab": {
   "provenance": []
  },
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "name": "python",
   "version": "3.10.0"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}