{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "63e5131b",
   "metadata": {
    "id": "63e5131b"
   },
   "source": "# ✈️ Airline Crew Pairing & Rostering — Applied QML (Salt IBM Qiskit)\n\n**Eğitim şablonu:** POC / Pilot — Quantum avantajını **gerçek IBM Quantum** üzerinde göstermek.\n**Hedef kitle:** Havayolu operasyonları, optimizasyon ve QML POC üretmek isteyen ekipler\n**Ortam:** Google Colab · **Mimari:** Salt IBM Qiskit (Runtime, SamplerV2, FidelityKernel)\n**API Key'ler:** IBM Quantum Token (zorunlu) + Wukong (Secrets'ta saklanır, bu şablonda çalışmaz)\n\n---\n\n## 📚 Problem Primer — Havacılığın Görünmez Bulmacası\n\n> **Kaynaklar:** Bahadır Zeren, İTÜ Doktora Tezi (THY destekli, 2017) + Aviation Crew Optimization PDF\n\n### Neden Önemli?\n| Metrik | Değer |\n|--------|-------|\n| Murettebat maliyeti | Yakıttan sonra **en büyük 2. kalem** (%20-30) |\n| Önlenebilir gecikme | **%80** (optimizasyon ile) |\n| Küresel finansal sızıntı | **Milyarlarca $** |\n\n### Planlama Döngüsü (T-6 Ay → Operasyon Günü)\n| Faz | Zaman | Ne Yapar? | Bu Notebook'ta |\n|-----|-------|-----------|----------------|\n| Uçuş Tarife | T-6 Ay | Hangi rotalara, hangi saatlerde? | — |\n| **Crew Pairing** | T-2 Ay | Bacakları yasal turlara böler (Set-Covering, NP-hard) | `is_feasible` QSVC |\n| **Crew Rostering** | T-1 Ay | Pairing'leri kişilere atar (Kıdem, Lisans, Adalet) | Yorgunluk sinyalleri |\n| IROPS | Operasyon Günü | Kesinti kurtarma (Kelebek etkisi) | — |\n\n### Temel Kavramlar (PDF + Tez §1.2)\n| Kavram | Tanım |\n|--------|-------|\n| **FDP** (Flight Duty Period) | Check-in'den son uçuş bitimine kadar geçen süre |\n| **8-in-24 Kuralı** | 24 saatlik döngüde 8 saatten fazla uçuş → dinlenme uzatılır |\n| **Deadhead (Pas Uçuş)** | Ekibin yolcu olarak taşınması (gelir getirmez, maliyet yazar) |\n| **Base Return / Domicile** | Pairing başladığı üste bitmelidir |\n| **Sit Time** | İki bacak arası yer süresi (min/max sınırları var) |\n| **Layover / Rest** | İki görev arası mecburi otel/dinlenme |\n\n### Yasal Kısıtlar (EASA / SHGM FTL)\n| Kural | Örnek Sınır |\n|-------|-------------|\n| Max FDP (gündüz, 1-4 iniş) | ~14 saat |\n| Max FDP (gece dilimi) | ~11-12 saat |\n| Min Rest (görev ≤6 sa) | 8 saat |\n| Min Rest (görev >11 sa) | 12+ saat |\n| Uzun menzil rest | 2 yerel gece / ~36 saat |\n\n### FSC vs LCC Yaklaşımı (PDF)\n- **FSC (Full Service):** Kıdemli/Kidemsiz karışımı, çoklu uçak tipi, sendikal kısıtlar\n- **LCC (Low Cost):** Tek tip filo, git-gel uçuşlar, agresif esneklik, otel yatisı sıfırlama\n\n### Neden QML?\nPairing uygunluk kararı **kombinatoryal kısıtlar** içerir (FDP, 8-in-24, base return, tip sertifikası).\nQuantum kernel (fidelity) ile düşük boyutlu özellik uzayında klasik RBF'den **farklı bir karar sınırı** aranır.\nGerçek QPU'da kernel matrisi gürültülü hesaplanır → **simülatör vs donanım** farkı quantum avantaj tartışmasının merkezidir.\n\n### Matematiksel Ana Model (Set-Covering — Tez §1.4)\n$$\\min_{x} \\sum_{p \\in P} c_p x_p \\quad \\text{s.t.} \\quad \\sum_{p: i \\in p} x_p \\ge 1 \\;\\; \\forall i \\in F, \\quad x_p \\in \\{0,1\\}$$\n\n### Mantık Sırası (tek yönlü, back-and-forth yok)\n1→Path 2→Kurulum 3→API 4→**Donanım** 5→Profil 6→Veri 7→CSV 8→EDA 9→KVKK 10→Ön İşleme 11→Klasik 12→Encoding 13→**QSVC** 14→CM/ROC 15→Karşılaştırma 16→Kayıt 17→QAOA Lab\n"
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "c054f194",
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "c054f194",
    "executionInfo": {
     "status": "ok",
     "timestamp": 1788452047545,
     "user_tz": -180,
     "elapsed": 29154,
     "user": {
      "displayName": "Joseph Volkan ÖZCAN",
      "userId": "11389530967736397480"
     }
    },
    "outputId": "85c81b1d-7162-442d-fa57-bab0e6174935"
   },
   "outputs": [
    {
     "output_type": "stream",
     "name": "stdout",
     "text": [
      "Python: 3.13.15\n",
      "Mounted at /content/drive\n",
      "✅ Google Drive bağlandı → /content/drive/MyDrive\n",
      "Proje Kökü : /content/drive/MyDrive/QML_Aviation_Crew\n",
      "Çıktı Dizin: /content/drive/MyDrive/QML_Aviation_Crew/outputs\n",
      "✅ AŞAMA 1 tamamlandı.\n"
     ]
    }
   ],
   "source": "# ============================================================\n# AŞAMA 1: DRIVE / PATH\n# Amaç: Çıktı dosyalarının (CSV, JSON, PNG) kaydedileceği\n#       dizini belirler. Colab'da Drive, lokalde ./ klasörü.\n# ============================================================\n\n# İşletim sistemi modülü — dosya yolu işlemleri için\nimport os\n# Sistem modülü — Python versiyonunu öğrenmek için\nimport sys\n\n# Kullanılan Python versiyonunu ekrana yazdır (Qiskit uyumluluğu kontrolü)\nprint(f\"Python: {sys.version.split()[0]}\")\n\n# Değişkenleri None olarak başlat (henüz yol belli değil)\nDRIVE_ROOT = None      # Google Drive kök dizini\nPROJECT_PATH = None    # Proje ana klasörü\nOUTPUT_PATH = None     # Çıktıların yazılacağı alt klasör\n\ntry:\n    # Google Colab ortamındaysa Drive bağlama modülünü içe aktar\n    from google.colab import drive\n    # Drive'ı /content/drive dizinine bağla (kullanıcıdan izin ister)\n    drive.mount(\"/content/drive\")\n    # Drive kök dizinini ata\n    DRIVE_ROOT = \"/content/drive/MyDrive\"\n    # Proje klasörünün tam yolunu oluştur\n    PROJECT_PATH = os.path.join(DRIVE_ROOT, \"QML_Aviation_Crew\")\n    # Çıktı alt klasörünün tam yolunu oluştur\n    OUTPUT_PATH = os.path.join(PROJECT_PATH, \"outputs\")\n    # Klasörler yoksa oluştur (exist_ok=True hata vermez)\n    os.makedirs(OUTPUT_PATH, exist_ok=True)\n    # Başarı mesajı\n    print(f\"✅ Google Drive bağlandı → {DRIVE_ROOT}\")\n\nexcept Exception as e:\n    # Colab dışındaysa (lokal Jupyter) bu blok çalışır\n    print(f\"⚠️ Drive atlandı: {e}. Lokal dizin kullanılıyor.\")\n    # Mevcut çalışma dizininde proje klasörü oluştur\n    PROJECT_PATH = os.path.abspath(\"./qml_aviation_crew\")\n    # Çıktı alt klasörü\n    OUTPUT_PATH = os.path.join(PROJECT_PATH, \"outputs\")\n    # Klasörleri oluştur\n    os.makedirs(OUTPUT_PATH, exist_ok=True)\n\n# Sonuçları ekrana yazdır\nprint(f\"Proje Kökü : {PROJECT_PATH}\")\nprint(f\"Çıktı Dizin: {OUTPUT_PATH}\")\nprint(\"✅ AŞAMA 1 tamamlandı.\")\n"
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "3e30305a",
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "3e30305a",
    "executionInfo": {
     "status": "ok",
     "timestamp": 1788452129093,
     "user_tz": -180,
     "elapsed": 70944,
     "user": {
      "displayName": "Joseph Volkan ÖZCAN",
      "userId": "11389530967736397480"
     }
    },
    "outputId": "003326b5-b70c-49c8-ce96-7800ddbbbb8f"
   },
   "outputs": [
    {
     "output_type": "stream",
     "name": "stdout",
     "text": [
      "📦 Paketler kuruluyor...\n",
      "\u001b[2K   \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m1.8/1.8 MB\u001b[0m \u001b[31m2.1 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
      "\u001b[?25h✅ Kurulum tamamlandı.\n",
      "   Not: Wukong/QPanda 'Salt IBM Qiskit' mimarisi gereği KURULMADI.\n",
      "Python: 3.13.15\n",
      "✅ Ortak kütüphaneler yüklendi.\n",
      "✅ AŞAMA 2 tamamlandı.\n"
     ]
    }
   ],
   "source": "# ============================================================\n# AŞAMA 2a: PAKET KURULUMU (Sadece IBM Qiskit Ekosistemi)\n# Amaç: Colab oturumu her seferinde temiz başlar; gerekli\n#       paketleri bir kez kurar. Wukong/QPanda KURULMAZ.\n# ============================================================\n\n# Kurulum başlangıç mesajı\nprint(\"📦 Paketler kuruluyor...\")\n\n# Pip paket yöneticisini en son sürüme güncelle (sessiz mod)\n!pip install -q --upgrade pip\n\n# IBM Qiskit çekirdek kütüphanesi (devre, transpiler, primitives)\n!pip install -q qiskit\n# Qiskit Aer — yüksek performanslı simülatör (statevector, density matrix)\n!pip install -q qiskit-aer\n# Qiskit Machine Learning — Quantum Kernel, QSVC, VQC gibi ML araçları\n!pip install -q qiskit-machine-learning\n# Qiskit Algorithms — QAOA, VQE, Grover gibi algoritmalar\n!pip install -q qiskit-algorithms\n# Qiskit IBM Runtime — gerçek IBM QPU'ya bağlanma (SamplerV2, EstimatorV2)\n!pip install -q qiskit-ibm-runtime\n\n# NumPy — sayısal hesaplama (vektör, matris, rastgele sayı)\n!pip install -q numpy\n# Pandas — tablo verisi (DataFrame, CSV okuma/yazma)\n!pip install -q pandas\n# Scikit-Learn — klasik ML modelleri ve metrikler\n!pip install -q scikit-learn\n# XGBoost — gradient boosting (güçlü klasik baseline)\n!pip install -q xgboost\n# Matplotlib — grafik çizimi\n!pip install -q matplotlib\n# Seaborn — istatistiksel görselleştirme (Matplotlib üstüne)\n!pip install -q seaborn\n# pylatexenc — Qiskit devre çiziminde LaTeX desteği\n!pip install -q pylatexenc\n\n# Kurulum tamamlandı mesajı\nprint(\"✅ Kurulum tamamlandı.\")\nprint(\"   Not: Wukong/QPanda 'Salt IBM Qiskit' mimarisi gereği KURULMADI.\")\n\n# ============================================================\n# AŞAMA 2b: ORTAK IMPORT\n# Amaç: Tüm hücrelerde kullanılacak kütüphaneleri tek seferde\n#       içe aktarır. Quantum import'ları ilgili hücrelerde tekrar\n#       edilebilir (güvenli, idempotent).\n# ============================================================\n\n# İşletim sistemi — dosya/yol işlemleri\nimport os\n# Sistem — Python versiyonu\nimport sys\n# JSON — sonuç kaydı için\nimport json\n# Uyarılar — gereksiz uyarıları kapatmak için\nimport warnings\n# Zaman — süre ölçümü\nimport time\n# İterasyon araçları — brute-force kombinasyonlar için\nimport itertools\n# Tarih/saat — run_id oluşturma\nfrom datetime import datetime\n# Hash — KVKK anonimleştirme\nfrom hashlib import sha256\n\n# NumPy — sayısal hesaplama\nimport numpy as np\n# Pandas — DataFrame\nimport pandas as pd\n# Matplotlib — grafik\nimport matplotlib.pyplot as plt\n# Seaborn — istatistiksel görselleştirme\nimport seaborn as sns\n\n# Scikit-Learn: Train/Test ayırma\nfrom sklearn.model_selection import train_test_split\n# Scikit-Learn: Özellik ölçekleme (Standard, MinMax)\nfrom sklearn.preprocessing import StandardScaler, MinMaxScaler\n# Scikit-Learn: Sınıflandırma metrikleri\nfrom sklearn.metrics import (\n    accuracy_score,      # Doğruluk oranı\n    precision_score,     # Kesinlik (FP maliyeti yüksek havacılıkta kritik)\n    recall_score,        # Duyarlılık (FN = operasyonel kayıp)\n    f1_score,            # Precision-Recall dengesi\n    roc_auc_score,       # ROC eğrisi altı alan\n    roc_curve,           # ROC eğrisi noktaları\n    confusion_matrix,    # Karmaşıklık matrisi\n    ConfusionMatrixDisplay,  # CM görselleştirme\n)\n# Scikit-Learn: Lojistik Regresyon (basit baseline)\nfrom sklearn.linear_model import LogisticRegression\n# Scikit-Learn: Rastgele Orman (güçlü ensemble)\nfrom sklearn.ensemble import RandomForestClassifier\n# Scikit-Learn: Destek Vektör Makinesi (RBF kernel karşılaştırması)\nfrom sklearn.svm import SVC\n# XGBoost: Gradient Boosting (endüstri standardı)\nfrom xgboost import XGBClassifier\n\n# Tüm uyarıları kapat (Qiskit deprecation uyarıları vs.)\nwarnings.filterwarnings(\"ignore\")\n# Seaborn grafik stili — beyaz ızgara\nsns.set_style(\"whitegrid\")\n# Varsayılan grafik boyutu\nplt.rcParams[\"figure.figsize\"] = (10, 6)\n\n# Python versiyonunu tekrar yazdır (doğrulama)\nprint(f\"Python: {sys.version.split()[0]}\")\nprint(\"✅ Ortak kütüphaneler yüklendi.\")\nprint(\"✅ AŞAMA 2 tamamlandı.\")\n"
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "f9f6bcf7",
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "f9f6bcf7",
    "executionInfo": {
     "status": "ok",
     "timestamp": 1788452194738,
     "user_tz": -180,
     "elapsed": 1914,
     "user": {
      "displayName": "Joseph Volkan ÖZCAN",
      "userId": "11389530967736397480"
     }
    },
    "outputId": "61c1a481-cfc0-483a-948f-6f7a13c3b410"
   },
   "outputs": [
    {
     "output_type": "stream",
     "name": "stdout",
     "text": [
      "✅ IBM Token bulundu (Uzunluk: 44).\n",
      "   Channel: ibm_quantum_platform\n",
      "   Instance: yok (auto denenecek)\n",
      "ℹ️ Wukong API Key Secrets'ta tanımlı (uzunluk 96).\n",
      "   Bu şablon 'Salt IBM Qiskit' olduğu için ÇALIŞTIRILMAYACAK.\n",
      "✅ AŞAMA 3 tamamlandı.\n"
     ]
    }
   ],
   "source": "# ============================================================\n# AŞAMA 3: API KEYS (Güvenli Okuma)\n# Amaç: IBM Quantum Token'ı Colab Secrets / env / .env / api.json\n#       kaynaklarından sırayla okur. Wukong key'i sadece envanter\n#       için tutulur, bu şablonda ÇALIŞTIRILMAZ.\n# GÜVENLİK: Token'ı notebook'a düz metin YAZMAYIN.\n# ============================================================\n\n# IBM Token değişkenini başlat (henüz okunmadı)\nIBM_TOKEN = None\n# IBM Instance (Open Plan vs Standard — CRN veya isim)\nIBM_INSTANCE = None\n# IBM kanal türü (2025+ için ibm_quantum_platform)\nIBM_CHANNEL = \"ibm_quantum_platform\"\n# Wukong API key — sadece referans, bu şablonda kullanılmaz\nWUKONG_API_KEY = None\n\n# ── 1) Colab Secrets'tan oku (EN GÜVENLİ YÖNTEM) ──\ntry:\n    # Colab'ın güvenli anahtar deposu modülü\n    from google.colab import userdata\n    # IBM Token'ı Secrets'tan oku (iki olası isim dene)\n    IBM_TOKEN = userdata.get(\"IBM_QUANTUM_TOKEN\") or userdata.get(\"QISKIT_IBM_TOKEN\")\n    # Instance bilgisini oku (opsiyonel, yoksa hata verme)\n    try:\n        IBM_INSTANCE = userdata.get(\"IBM_QUANTUM_INSTANCE\") or userdata.get(\"QISKIT_IBM_INSTANCE\")\n    except Exception:\n        pass  # Instance yoksa None kalır, auto denenecek\n    # Wukong key'ini oku (sadece envanter — çalıştırılmayacak)\n    try:\n        WUKONG_API_KEY = userdata.get(\"WUKONG_API_KEY\") or userdata.get(\"ORIGIN_API_KEY\")\n    except Exception:\n        pass  # Wukong key yoksa sorun değil\nexcept Exception as e:\n    # Colab dışındaysa Secrets modülü yoktur\n    print(f\"⚠️ Colab Secrets okunamadı: {e}\")\n\n# ── 2) Ortam değişkeninden oku (YEDEK PLAN) ──\nif not IBM_TOKEN:\n    # OS ortam değişkenlerinden token ara\n    IBM_TOKEN = os.environ.get(\"IBM_QUANTUM_TOKEN\") or os.environ.get(\"QISKIT_IBM_TOKEN\")\nif not IBM_INSTANCE:\n    # Instance bilgisini ortam değişkeninden ara\n    IBM_INSTANCE = os.environ.get(\"IBM_QUANTUM_INSTANCE\") or os.environ.get(\"QISKIT_IBM_INSTANCE\")\nif not WUKONG_API_KEY:\n    # Wukong key'ini ortam değişkeninden ara\n    WUKONG_API_KEY = os.environ.get(\"WUKONG_API_KEY\") or os.environ.get(\"ORIGIN_API_KEY\")\n\n# ── 3) .env dosyasından oku (lokal geliştirme) ──\nif not IBM_TOKEN:\n    try:\n        # python-dotenv kütüphanesi ile .env dosyasını yükle\n        from dotenv import load_dotenv\n        load_dotenv()  # .env dosyasındaki değişkenleri os.environ'a ekle\n        IBM_TOKEN = os.environ.get(\"IBM_QUANTUM_TOKEN\")\n        IBM_INSTANCE = IBM_INSTANCE or os.environ.get(\"IBM_QUANTUM_INSTANCE\")\n        WUKONG_API_KEY = WUKONG_API_KEY or os.environ.get(\"WUKONG_API_KEY\")\n    except Exception:\n        pass  # dotenv yüklü değilse atla\n\n# ── Durum Raporu ──\nif IBM_TOKEN:\n    # Token bulundu — uzunluğunu göster (değerin kendisi basılmaz!)\n    print(f\"✅ IBM Token bulundu (Uzunluk: {len(IBM_TOKEN)}).\")\n    print(f\"   Channel: {IBM_CHANNEL}\")\n    print(f\"   Instance: {'ayarlı' if IBM_INSTANCE else 'yok (auto denenecek)'}\")\nelse:\n    # Token bulunamadı — simülatör ile devam edilecek\n    print(\"❌ IBM Token bulunamadı! Gerçek donanım kullanılamayacak.\")\n    print(\"   Colab Secrets'a 'IBM_QUANTUM_TOKEN' ekleyin.\")\n\nif WUKONG_API_KEY:\n    # Wukong key var ama bu şablonda kullanılmayacak\n    print(f\"ℹ️ Wukong API Key Secrets'ta tanımlı (uzunluk {len(WUKONG_API_KEY)}).\")\n    print(\"   Bu şablon 'Salt IBM Qiskit' olduğu için ÇALIŞTIRILMAYACAK.\")\nelse:\n    print(\"ℹ️ Wukong API Key tanımlı değil.\")\n\nprint(\"✅ AŞAMA 3 tamamlandı.\")\n"
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "a7ceec8b",
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "a7ceec8b",
    "executionInfo": {
     "status": "ok",
     "timestamp": 1788452218632,
     "user_tz": -180,
     "elapsed": 12080,
     "user": {
      "displayName": "Joseph Volkan ÖZCAN",
      "userId": "11389530967736397480"
     }
    },
    "outputId": "7b990dc5-7229-498b-eea7-d1d4f307f101"
   },
   "outputs": [
    {
     "output_type": "stream",
     "name": "stderr",
     "text": [
      "qiskit_runtime_service._discover_account:WARNING:2026-09-03 16:16:48,234: Loading account with the given token. A saved account will not be used.\n",
      "qiskit_runtime_service.__init__:WARNING:2026-09-03 16:16:54,284: Instance was not set at service instantiation. Free and trial plan instances will be prioritized. Based on the following filters: (tags: None, region: us-east, eu-de), and available plans: (open), the available account instances are: Miuul-QML-2, Miuul-QML-1, open-instance. If you need a specific instance set it explicitly either by using a saved account with a saved default instance or passing it in directly to QiskitRuntimeService(). Alternatively, pass instance='auto' or save it to your account for auto-selection without warning.\n"
     ]
    },
    {
     "output_type": "stream",
     "name": "stdout",
     "text": [
      "✅ IBM Quantum Servisine bağlanıldı.\n"
     ]
    },
    {
     "output_type": "stream",
     "name": "stderr",
     "text": [
      "qiskit_runtime_service.backends:WARNING:2026-09-03 16:16:55,784: Loading instance: Miuul-QML-2, plan: open\n",
      "qiskit_runtime_service.backends:WARNING:2026-09-03 16:16:57,204: Loading instance: Miuul-QML-1, plan: open\n",
      "qiskit_runtime_service.backends:WARNING:2026-09-03 16:16:57,205: Loading instance: open-instance, plan: open\n",
      "qiskit_runtime_service.backends:WARNING:2026-09-03 16:16:58,662: Using instance: Miuul-QML-2, plan: open\n"
     ]
    },
    {
     "output_type": "stream",
     "name": "stdout",
     "text": [
      "⚠️ ibm_phoenix bulunamadı → en az meşgul: ibm_marrakesh\n",
      "\n",
      "🎯 Aktif Profil:\n",
      "   Provider : IBM\n",
      "   Backend  : ibm_marrakesh\n",
      "   Real HW  : True\n",
      "✅ AŞAMA 4 tamamlandı.\n"
     ]
    }
   ],
   "source": "# ============================================================\n# AŞAMA 4: IBM QPU BACKEND SEÇİMİ\n# Amaç: IBM Quantum servisine bağlanır ve gerçek bir QPU seçer.\n#       Önce tercih edilen makine (ibm_phoenix), yoksa en az\n#       meşgul olan. Başarısız olursa Aer simülatöre düşer.\n# Öncelik: ibm_phoenix > least_busy > backends listesi > Aer\n# ============================================================\n\n# Gerçek donanım kullanılsın mı? (Token yoksa otomatik False)\nUSE_REAL_HARDWARE = True if IBM_TOKEN else False\n# Tercih edilen IBM makine adı (127 qubit Eagle işlemci)\nPREFERRED_BACKEND = \"ibm_phoenix\"\n# Backend için minimum qubit sayısı\nMIN_QUBITS = 4\n\n# Varsayılan değerler (simülatör modu)\nBACKEND_NAME = \"aer_simulator\"   # Aktif backend adı\nSERVICE = None                   # QiskitRuntimeService nesnesi\nBACKEND = None                   # Seçilen backend nesnesi\nHARDWARE_PROVIDER = \"aer\"        # \"aer\" | \"ibm\"\n\n# ── Gerçek IBM donanımına bağlanma denemesi ──\nif USE_REAL_HARDWARE:\n    try:\n        # IBM Runtime servisini içe aktar (2025+ mimari)\n        from qiskit_ibm_runtime import QiskitRuntimeService, SamplerV2\n\n        # Servis bağlantı parametrelerini hazırla\n        kwargs = {\"channel\": IBM_CHANNEL, \"token\": IBM_TOKEN}\n        if IBM_INSTANCE:\n            kwargs[\"instance\"] = IBM_INSTANCE  # Belirli instance kullan\n\n        # IBM Quantum servisine bağlan\n        SERVICE = QiskitRuntimeService(**kwargs)\n        print(\"✅ IBM Quantum Servisine bağlanıldı.\")\n\n        # ── Backend seçimi: Önce tercih edilen ──\n        try:\n            BACKEND = SERVICE.backend(PREFERRED_BACKEND)\n            print(f\"✅ Tercih edilen backend: {PREFERRED_BACKEND}\")\n        except Exception:\n            # Tercih edilen bulunamadıysa en az meşgul olanı seç\n            BACKEND = SERVICE.least_busy(\n                operational=True,       # Çalışır durumda olan\n                simulator=False,        # Simülatör olmayan (gerçek QPU)\n                min_num_qubits=MIN_QUBITS  # En az bu kadar qubit\n            )\n            print(f\"⚠️ {PREFERRED_BACKEND} bulunamadı → en az meşgul: {BACKEND.name}\")\n\n        # Seçilen backend'in adını kaydet\n        BACKEND_NAME = BACKEND.name\n        # Sağlayıcıyı IBM olarak işaretle\n        HARDWARE_PROVIDER = \"ibm\"\n\n    except Exception as e:\n        # Bağlantı başarısız — simülatöre düş\n        print(f\"❌ IBM Backend hatası: {e}\")\n        print(\"   Aer simülatöre düşülüyor.\")\n        USE_REAL_HARDWARE = False\n        HARDWARE_PROVIDER = \"aer\"\nelse:\n    print(\"ℹ️ Simülatör modu aktif (Token yok).\")\n\n# Aktif profili raporla\nprint(f\"\\n🎯 Aktif Profil:\")\nprint(f\"   Provider : {HARDWARE_PROVIDER.upper()}\")\nprint(f\"   Backend  : {BACKEND_NAME}\")\nprint(f\"   Real HW  : {USE_REAL_HARDWARE}\")\nprint(\"✅ AŞAMA 4 tamamlandı.\")\n"
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "ea02b5f9",
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "ea02b5f9",
    "executionInfo": {
     "status": "ok",
     "timestamp": 1788452228042,
     "user_tz": -180,
     "elapsed": 52,
     "user": {
      "displayName": "Joseph Volkan ÖZCAN",
      "userId": "11389530967736397480"
     }
    },
    "outputId": "a12eddaf-d4ca-4a2b-f2eb-592db38b776d"
   },
   "outputs": [
    {
     "output_type": "stream",
     "name": "stdout",
     "text": [
      "Problem   : Crew Pairing Feasibility & Rostering Fatigue\n",
      "Algoritma : QSVC (Fidelity Quantum Kernel)\n",
      "Donanım   : IBM → ibm_marrakesh\n",
      "Matematik : K(x,x') = |⟨φ(x)|φ(x')⟩|²  (Fidelity Kernel)\n",
      "\n",
      "📖 Domain Bağlamı (PDF + Tez):\n",
      "  • Pairing: Set-covering, Deadhead minimizasyonu, Base return\n",
      "  • Rostering: FDP limitleri, 8-in-24 kuralı, Yorgunluk, Kıdem\n",
      "  • FSC vs LCC: Çoklu tip (FSC) vs tek tip (LCC) filo etkisi\n",
      "  • IROPS: Kelebek etkisi — gecikme → FDP ihlali → kaskad\n",
      "  • Hedef: Yasal ve operasyonel 'Uygun' (Feasible) dizilimi tahmin etmek\n",
      "✅ AŞAMA 5 tamamlandı.\n"
     ]
    }
   ],
   "source": "# ============================================================\n# AŞAMA 5: PROBLEM VE ALGORİTMA PROFİLİ\n# Amaç: Bu POC'un ne çözdüğünü ve hangi algoritmayı kullandığını\n#       belgeler. Domain bağlamını PDF'ten özetler.\n# ============================================================\n\n# Problem adı (QSVC sınıflandırma)\nSELECTED_PROBLEM = \"Crew Pairing Feasibility & Rostering Fatigue\"\n# Kullanılan quantum algoritması\nSELECTED_ALGO = \"QSVC (Fidelity Quantum Kernel)\"\n# Donanım bilgisi (AŞAMA 4'ten gelen)\nSELECTED_HARDWARE = f\"{HARDWARE_PROVIDER.upper()} → {BACKEND_NAME}\"\n\n# Profili ekrana yazdır\nprint(f\"Problem   : {SELECTED_PROBLEM}\")\nprint(f\"Algoritma : {SELECTED_ALGO}\")\nprint(f\"Donanım   : {SELECTED_HARDWARE}\")\nprint(f\"Matematik : K(x,x') = |⟨φ(x)|φ(x')⟩|²  (Fidelity Kernel)\")\nprint()\nprint(\"📖 Domain Bağlamı (PDF + Tez):\")\nprint(\"  • Pairing: Set-covering, Deadhead minimizasyonu, Base return\")\nprint(\"  • Rostering: FDP limitleri, 8-in-24 kuralı, Yorgunluk, Kıdem\")\nprint(\"  • FSC vs LCC: Çoklu tip (FSC) vs tek tip (LCC) filo etkisi\")\nprint(\"  • IROPS: Kelebek etkisi — gecikme → FDP ihlali → kaskad\")\nprint(\"  • Hedef: Yasal ve operasyonel 'Uygun' (Feasible) dizilimi tahmin etmek\")\nprint(\"✅ AŞAMA 5 tamamlandı.\")\n"
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "46d17e27",
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/",
     "height": 292
    },
    "id": "46d17e27",
    "executionInfo": {
     "status": "ok",
     "timestamp": 1788452236017,
     "user_tz": -180,
     "elapsed": 211,
     "user": {
      "displayName": "Joseph Volkan ÖZCAN",
      "userId": "11389530967736397480"
     }
    },
    "outputId": "ff05cda0-55e7-4a86-f22f-002a9252fef0"
   },
   "outputs": [
    {
     "output_type": "stream",
     "name": "stdout",
     "text": [
      "=== Sentetik Havacılık Verisi ===\n",
      "Satır: 15000 | Uygun (Feasible) Oranı: 98.51%\n"
     ]
    },
    {
     "output_type": "display_data",
     "data": {
      "text/plain": [
       "  pairing_id  fdp_hours  num_legs  min_connection_min  night_hours  \\\n",
       "0     P10000      10.74         1                  28         0.18   \n",
       "1     P10001       9.15         2                  40         0.75   \n",
       "2     P10002      11.12         5                  40         3.27   \n",
       "3     P10003      13.31         2                  69         3.46   \n",
       "4     P10004       8.91         5                  35         1.96   \n",
       "\n",
       "   deadhead_hours  rest_before_hours  type_rating_match  base_return_ok  \\\n",
       "0            0.09               8.00                  1               1   \n",
       "1            0.68              15.26                  1               1   \n",
       "2            0.88              12.20                  1               1   \n",
       "3            1.46              12.89                  1               1   \n",
       "4            0.35              10.94                  1               1   \n",
       "\n",
       "   fatigue_score  is_feasible  \n",
       "0          0.000            1  \n",
       "1          0.000            1  \n",
       "2          0.000            1  \n",
       "3          0.241            1  \n",
       "4          0.000            1  "
      ],
      "text/html": [
       "\n",
       "  <div id=\"df-164945d6-7385-465e-bd88-6192fee3aeab\" 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>pairing_id</th>\n",
       "      <th>fdp_hours</th>\n",
       "      <th>num_legs</th>\n",
       "      <th>min_connection_min</th>\n",
       "      <th>night_hours</th>\n",
       "      <th>deadhead_hours</th>\n",
       "      <th>rest_before_hours</th>\n",
       "      <th>type_rating_match</th>\n",
       "      <th>base_return_ok</th>\n",
       "      <th>fatigue_score</th>\n",
       "      <th>is_feasible</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>P10000</td>\n",
       "      <td>10.74</td>\n",
       "      <td>1</td>\n",
       "      <td>28</td>\n",
       "      <td>0.18</td>\n",
       "      <td>0.09</td>\n",
       "      <td>8.00</td>\n",
       "      <td>1</td>\n",
       "      <td>1</td>\n",
       "      <td>0.000</td>\n",
       "      <td>1</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>P10001</td>\n",
       "      <td>9.15</td>\n",
       "      <td>2</td>\n",
       "      <td>40</td>\n",
       "      <td>0.75</td>\n",
       "      <td>0.68</td>\n",
       "      <td>15.26</td>\n",
       "      <td>1</td>\n",
       "      <td>1</td>\n",
       "      <td>0.000</td>\n",
       "      <td>1</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>P10002</td>\n",
       "      <td>11.12</td>\n",
       "      <td>5</td>\n",
       "      <td>40</td>\n",
       "      <td>3.27</td>\n",
       "      <td>0.88</td>\n",
       "      <td>12.20</td>\n",
       "      <td>1</td>\n",
       "      <td>1</td>\n",
       "      <td>0.000</td>\n",
       "      <td>1</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>P10003</td>\n",
       "      <td>13.31</td>\n",
       "      <td>2</td>\n",
       "      <td>69</td>\n",
       "      <td>3.46</td>\n",
       "      <td>1.46</td>\n",
       "      <td>12.89</td>\n",
       "      <td>1</td>\n",
       "      <td>1</td>\n",
       "      <td>0.241</td>\n",
       "      <td>1</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>P10004</td>\n",
       "      <td>8.91</td>\n",
       "      <td>5</td>\n",
       "      <td>35</td>\n",
       "      <td>1.96</td>\n",
       "      <td>0.35</td>\n",
       "      <td>10.94</td>\n",
       "      <td>1</td>\n",
       "      <td>1</td>\n",
       "      <td>0.000</td>\n",
       "      <td>1</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-164945d6-7385-465e-bd88-6192fee3aeab')\"\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-164945d6-7385-465e-bd88-6192fee3aeab 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-164945d6-7385-465e-bd88-6192fee3aeab');\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\": \"print(\\\"\\u2705 A\\u015eAMA 6 tamamland\\u0131\",\n  \"rows\": 5,\n  \"fields\": [\n    {\n      \"column\": \"pairing_id\",\n      \"properties\": {\n        \"dtype\": \"string\",\n        \"num_unique_values\": 5,\n        \"samples\": [\n          \"P10001\",\n          \"P10004\",\n          \"P10002\"\n        ],\n        \"semantic_type\": \"\",\n        \"description\": \"\"\n      }\n    },\n    {\n      \"column\": \"fdp_hours\",\n      \"properties\": {\n        \"dtype\": \"number\",\n        \"std\": 1.7735642080285676,\n        \"min\": 8.91,\n        \"max\": 13.31,\n        \"num_unique_values\": 5,\n        \"samples\": [\n          9.15,\n          8.91,\n          11.12\n        ],\n        \"semantic_type\": \"\",\n        \"description\": \"\"\n      }\n    },\n    {\n      \"column\": \"num_legs\",\n      \"properties\": {\n        \"dtype\": \"number\",\n        \"std\": 1,\n        \"min\": 1,\n        \"max\": 5,\n        \"num_unique_values\": 3,\n        \"samples\": [\n          1,\n          2,\n          5\n        ],\n        \"semantic_type\": \"\",\n        \"description\": \"\"\n      }\n    },\n    {\n      \"column\": \"min_connection_min\",\n      \"properties\": {\n        \"dtype\": \"number\",\n        \"std\": 15,\n        \"min\": 28,\n        \"max\": 69,\n        \"num_unique_values\": 4,\n        \"samples\": [\n          40,\n          35,\n          28\n        ],\n        \"semantic_type\": \"\",\n        \"description\": \"\"\n      }\n    },\n    {\n      \"column\": \"night_hours\",\n      \"properties\": {\n        \"dtype\": \"number\",\n        \"std\": 1.46561591148568,\n        \"min\": 0.18,\n        \"max\": 3.46,\n        \"num_unique_values\": 5,\n        \"samples\": [\n          0.75,\n          1.96,\n          3.27\n        ],\n        \"semantic_type\": \"\",\n        \"description\": \"\"\n      }\n    },\n    {\n      \"column\": \"deadhead_hours\",\n      \"properties\": {\n        \"dtype\": \"number\",\n        \"std\": 0.5255187912910442,\n        \"min\": 0.09,\n        \"max\": 1.46,\n        \"num_unique_values\": 5,\n        \"samples\": [\n          0.68,\n          0.35,\n          0.88\n        ],\n        \"semantic_type\": \"\",\n        \"description\": \"\"\n      }\n    },\n    {\n      \"column\": \"rest_before_hours\",\n      \"properties\": {\n        \"dtype\": \"number\",\n        \"std\": 2.6684489877080284,\n        \"min\": 8.0,\n        \"max\": 15.26,\n        \"num_unique_values\": 5,\n        \"samples\": [\n          15.26,\n          10.94,\n          12.2\n        ],\n        \"semantic_type\": \"\",\n        \"description\": \"\"\n      }\n    },\n    {\n      \"column\": \"type_rating_match\",\n      \"properties\": {\n        \"dtype\": \"number\",\n        \"std\": 0,\n        \"min\": 1,\n        \"max\": 1,\n        \"num_unique_values\": 1,\n        \"samples\": [\n          1\n        ],\n        \"semantic_type\": \"\",\n        \"description\": \"\"\n      }\n    },\n    {\n      \"column\": \"base_return_ok\",\n      \"properties\": {\n        \"dtype\": \"number\",\n        \"std\": 0,\n        \"min\": 1,\n        \"max\": 1,\n        \"num_unique_values\": 1,\n        \"samples\": [\n          1\n        ],\n        \"semantic_type\": \"\",\n        \"description\": \"\"\n      }\n    },\n    {\n      \"column\": \"fatigue_score\",\n      \"properties\": {\n        \"dtype\": \"number\",\n        \"std\": 0.10777847651548986,\n        \"min\": 0.0,\n        \"max\": 0.241,\n        \"num_unique_values\": 2,\n        \"samples\": [\n          0.241\n        ],\n        \"semantic_type\": \"\",\n        \"description\": \"\"\n      }\n    },\n    {\n      \"column\": \"is_feasible\",\n      \"properties\": {\n        \"dtype\": \"number\",\n        \"std\": 0,\n        \"min\": 1,\n        \"max\": 1,\n        \"num_unique_values\": 1,\n        \"samples\": [\n          1\n        ],\n        \"semantic_type\": \"\",\n        \"description\": \"\"\n      }\n    }\n  ]\n}"
      }
     },
     "metadata": {}
    },
    {
     "output_type": "stream",
     "name": "stdout",
     "text": [
      "✅ Veri kaydedildi: /content/drive/MyDrive/QML_Aviation_Crew/outputs/aviation_crew_synthetic.csv\n",
      "✅ AŞAMA 6 tamamlandı.\n"
     ]
    }
   ],
   "source": "# ============================================================\n# AŞAMA 6: SENTETİK VERİ (PDF + Tez Kurallarıyla)\n# Amaç: Gerçek havayolu verisi olmadığı için, PDF'teki FDP,\n#       8-in-24, Deadhead, Base Return, Tip Sertifikası kurallarını\n#       yansıtan sentetik bir veri seti üretir.\n# Hedef değişken: is_feasible (0=Uygun değil, 1=Uygun)\n# ============================================================\n\n# Rastgele sayı tohumu — tekrarlanabilir sonuçlar için\nnp.random.seed(42)\n# Toplam örnek sayısı (NISQ için makul)\nN_SAMPLES = 15000\n\n# ── Özellik 1: Görev Süresi (FDP - Flight Duty Period) ──\n# PDF: Max 14 saat (gündüz), 11-12 saat (gece)\n# Normal dağılım, ortalama 9.5 saat, std 2.5, [4, 15] arası kırpılmış\nfdp_hours = np.clip(np.random.normal(9.5, 2.5, N_SAMPLES), 4.0, 15.0)\n\n# ── Özellik 2: Uçuş Bacak Sayısı ──\n# Tez: Bir duty'de 1-5 bacak (uniform dağılım)\nnum_legs = np.random.randint(1, 6, N_SAMPLES)\n\n# ── Özellik 3: Minimum Bağlantı Süresi (Min Connection Time) ──\n# PDF: İki bacak arası min yer süresi (sit time)\n# Normal dağılım, ortalama 55 dk, std 20, [20, 180] arası\nmin_connection_min = np.clip(np.random.normal(55, 20, N_SAMPLES), 20, 180).astype(int)\n\n# ── Özellik 4: Gece Uçuşu Saati ──\n# PDF: Gece dilimi kısıtları daha sıkı (FDP 11-12 saate düşer)\n# Üstel dağılım, ortalama 1.5 saat, max 8 saat\nnight_hours = np.clip(np.random.exponential(1.5, N_SAMPLES), 0, 8)\n\n# ── Özellik 5: Pas Uçuş / Deadhead Saati ──\n# PDF: Gelir getirmeyen, maliyetli pozisyonlama uçuşu\n# Üstel dağılım, ortalama 1.0 saat, max 6 saat\ndeadhead_hours = np.clip(np.random.exponential(1.0, N_SAMPLES), 0, 6)\n\n# ── Özellik 6: Görev Öncesi Dinlenme Süresi ──\n# PDF: Min 8 saat (kısa görev), 12+ saat (uzun görev)\n# Normal dağılım, ortalama 12 saat, std 2.5, [8, 24] arası\nrest_before_hours = np.clip(np.random.normal(12.0, 2.5, N_SAMPLES), 8.0, 24.0)\n\n# ── Özellik 7: Tip Sertifikası Uyumu (Rostering) ──\n# PDF: A320 vs B737 lisans uyumu (binary: 1=uyumlu, 0=uyumsuz)\n# %90 uyum oranı (gerçekçi)\ntype_rating_match = np.random.binomial(1, 0.90, N_SAMPLES)\n\n# ── Özellik 8: Base Return (Domicile) ──\n# PDF: Pairing başladığı üste bitmelidir (IST→...→IST)\n# %85 base return oranı\nbase_return_ok = np.random.binomial(1, 0.85, N_SAMPLES)\n\n# ── Özellik 9: Yorgunluk Skoru (PDF: 8-in-24 + Gece + FDP) ──\n# Bileşik skor: FDP ihlali + gece uçuşu + deadhead - dinlenme\nfatigue_score = np.clip(\n    0.20 * (fdp_hours > 11)       # 8-in-24 kuralı tetikleyicisi\n    + 0.30 * night_hours          # Gece uçuşu etkisi (baskın)\n    + 0.15 * deadhead_hours       # Pas uçuş yorgunluğu\n    - 0.10 * rest_before_hours    # Dinlenme azaltıcı etki\n    + np.random.normal(0, 0.1, N_SAMPLES),  # Rastgele gürültü\n    0, 1  # [0, 1] arası kırp\n)\n\n# ── HEDEF DEĞİŞKEN: is_feasible (Yasal + Operasyonel Uygunluk) ──\n# Logit model: PDF'teki kısıtları ihlal edenlere ceza uygular\nlogit = (\n    -2.5                              # Baz olasılık (negatif = çoğu uygun)\n    + 1.20 * (fdp_hours > 13.0)       # FDP ihlali → KRİTİK ceza\n    + 0.80 * (min_connection_min < 35) # Min bağlantı ihlali\n    + 0.90 * (rest_before_hours < 10)  # Min dinlenme ihlali\n    + 1.10 * (fatigue_score > 0.65)    # Yüksek yorgunluk → redd\n    + 0.60 * (night_hours > 4.5)       # Gece kısıtları\n    - 2.00 * type_rating_match         # Lisans uyuşmazsa KESİN redd\n    - 1.50 * base_return_ok            # Base return yoksa redd\n    + np.random.logistic(0, 0.5, N_SAMPLES)  # Stokastik gürültü\n)\n# Logit → olasılık dönüşümü (sigmoid)\nprob_infeasible = 1 / (1 + np.exp(-logit))\n# Olasılığa göre binary etiket ata\nis_feasible = (np.random.rand(N_SAMPLES) > prob_infeasible).astype(int)\n\n# ── DataFrame Oluştur ──\ndf = pd.DataFrame({\n    \"pairing_id\": [f\"P{10000+i}\" for i in range(N_SAMPLES)],  # Anonim pairing ID\n    \"fdp_hours\": np.round(fdp_hours, 2),          # Görev süresi (saat)\n    \"num_legs\": num_legs,                          # Bacak sayısı\n    \"min_connection_min\": min_connection_min,      # Min bağlantı (dk)\n    \"night_hours\": np.round(night_hours, 2),       # Gece uçuşu (saat)\n    \"deadhead_hours\": np.round(deadhead_hours, 2), # Pas uçuş (saat)\n    \"rest_before_hours\": np.round(rest_before_hours, 2),  # Dinlenme (saat)\n    \"type_rating_match\": type_rating_match,        # Lisans uyumu (0/1)\n    \"base_return_ok\": base_return_ok,              # Base return (0/1)\n    \"fatigue_score\": np.round(fatigue_score, 3),   # Yorgunluk skoru\n    \"is_feasible\": is_feasible,                    # HEDEF: Uygun mu?\n})\n\n# Özet istatistikleri yazdır\nprint(\"=== Sentetik Havacılık Verisi ===\")\nprint(f\"Satır: {len(df)} | Uygun (Feasible) Oranı: {df['is_feasible'].mean():.2%}\")\ndisplay(df.head(5))\n\n# CSV olarak kaydet\nsynth_path = os.path.join(OUTPUT_PATH, \"aviation_crew_synthetic.csv\")\ndf.to_csv(synth_path, index=False)\nprint(f\"✅ Veri kaydedildi: {synth_path}\")\nprint(\"✅ AŞAMA 6 tamamlandı.\")\n"
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "2fef1957",
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/",
     "height": 1000
    },
    "id": "2fef1957",
    "executionInfo": {
     "status": "error",
     "timestamp": 1788452255400,
     "user_tz": -180,
     "elapsed": 1190,
     "user": {
      "displayName": "Joseph Volkan ÖZCAN",
      "userId": "11389530967736397480"
     }
    },
    "outputId": "d426bb40-b6ff-4c5e-9db7-0b32b3350981"
   },
   "outputs": [
    {
     "output_type": "stream",
     "name": "stdout",
     "text": [
      "ℹ️ Sentetik veri kullanılıyor → (15000, 11)\n",
      "=== Temel İstatistikler ===\n"
     ]
    },
    {
     "output_type": "display_data",
     "data": {
      "text/plain": [
       "                      count       mean        std   min    25%    50%    75%  \\\n",
       "fdp_hours           15000.0   9.505669   2.437329   4.0   7.83   9.50  11.18   \n",
       "num_legs            15000.0   3.033400   1.417657   1.0   2.00   3.00   4.00   \n",
       "min_connection_min  15000.0  54.783667  19.431093  20.0  41.00  54.00  68.00   \n",
       "night_hours         15000.0   1.518292   1.466996   0.0   0.44   1.05   2.14   \n",
       "deadhead_hours      15000.0   1.002015   1.001648   0.0   0.28   0.68   1.40   \n",
       "rest_before_hours   15000.0  12.060238   2.391754   8.0  10.31  12.01  13.72   \n",
       "type_rating_match   15000.0   0.898800   0.301603   0.0   1.00   1.00   1.00   \n",
       "base_return_ok      15000.0   0.849933   0.357149   0.0   1.00   1.00   1.00   \n",
       "fatigue_score       15000.0   0.057349   0.185316   0.0   0.00   0.00   0.00   \n",
       "is_feasible         15000.0   0.985133   0.121023   0.0   1.00   1.00   1.00   \n",
       "\n",
       "                       max  \n",
       "fdp_hours            15.00  \n",
       "num_legs              5.00  \n",
       "min_connection_min  131.00  \n",
       "night_hours           8.00  \n",
       "deadhead_hours        6.00  \n",
       "rest_before_hours    21.46  \n",
       "type_rating_match     1.00  \n",
       "base_return_ok        1.00  \n",
       "fatigue_score         1.00  \n",
       "is_feasible           1.00  "
      ],
      "text/html": [
       "\n",
       "  <div id=\"df-b90f8e3a-76b9-43bf-94e9-3faae82ba95f\" 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>count</th>\n",
       "      <th>mean</th>\n",
       "      <th>std</th>\n",
       "      <th>min</th>\n",
       "      <th>25%</th>\n",
       "      <th>50%</th>\n",
       "      <th>75%</th>\n",
       "      <th>max</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>fdp_hours</th>\n",
       "      <td>15000.0</td>\n",
       "      <td>9.505669</td>\n",
       "      <td>2.437329</td>\n",
       "      <td>4.0</td>\n",
       "      <td>7.83</td>\n",
       "      <td>9.50</td>\n",
       "      <td>11.18</td>\n",
       "      <td>15.00</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>num_legs</th>\n",
       "      <td>15000.0</td>\n",
       "      <td>3.033400</td>\n",
       "      <td>1.417657</td>\n",
       "      <td>1.0</td>\n",
       "      <td>2.00</td>\n",
       "      <td>3.00</td>\n",
       "      <td>4.00</td>\n",
       "      <td>5.00</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>min_connection_min</th>\n",
       "      <td>15000.0</td>\n",
       "      <td>54.783667</td>\n",
       "      <td>19.431093</td>\n",
       "      <td>20.0</td>\n",
       "      <td>41.00</td>\n",
       "      <td>54.00</td>\n",
       "      <td>68.00</td>\n",
       "      <td>131.00</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>night_hours</th>\n",
       "      <td>15000.0</td>\n",
       "      <td>1.518292</td>\n",
       "      <td>1.466996</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.44</td>\n",
       "      <td>1.05</td>\n",
       "      <td>2.14</td>\n",
       "      <td>8.00</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>deadhead_hours</th>\n",
       "      <td>15000.0</td>\n",
       "      <td>1.002015</td>\n",
       "      <td>1.001648</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.28</td>\n",
       "      <td>0.68</td>\n",
       "      <td>1.40</td>\n",
       "      <td>6.00</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>rest_before_hours</th>\n",
       "      <td>15000.0</td>\n",
       "      <td>12.060238</td>\n",
       "      <td>2.391754</td>\n",
       "      <td>8.0</td>\n",
       "      <td>10.31</td>\n",
       "      <td>12.01</td>\n",
       "      <td>13.72</td>\n",
       "      <td>21.46</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>type_rating_match</th>\n",
       "      <td>15000.0</td>\n",
       "      <td>0.898800</td>\n",
       "      <td>0.301603</td>\n",
       "      <td>0.0</td>\n",
       "      <td>1.00</td>\n",
       "      <td>1.00</td>\n",
       "      <td>1.00</td>\n",
       "      <td>1.00</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>base_return_ok</th>\n",
       "      <td>15000.0</td>\n",
       "      <td>0.849933</td>\n",
       "      <td>0.357149</td>\n",
       "      <td>0.0</td>\n",
       "      <td>1.00</td>\n",
       "      <td>1.00</td>\n",
       "      <td>1.00</td>\n",
       "      <td>1.00</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>fatigue_score</th>\n",
       "      <td>15000.0</td>\n",
       "      <td>0.057349</td>\n",
       "      <td>0.185316</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.00</td>\n",
       "      <td>0.00</td>\n",
       "      <td>0.00</td>\n",
       "      <td>1.00</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>is_feasible</th>\n",
       "      <td>15000.0</td>\n",
       "      <td>0.985133</td>\n",
       "      <td>0.121023</td>\n",
       "      <td>0.0</td>\n",
       "      <td>1.00</td>\n",
       "      <td>1.00</td>\n",
       "      <td>1.00</td>\n",
       "      <td>1.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-b90f8e3a-76b9-43bf-94e9-3faae82ba95f')\"\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-b90f8e3a-76b9-43bf-94e9-3faae82ba95f 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-b90f8e3a-76b9-43bf-94e9-3faae82ba95f');\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\": \"print(\\\"\\u2705 A\\u015eAMA 7 & 8 tamamland\\u0131\",\n  \"rows\": 10,\n  \"fields\": [\n    {\n      \"column\": \"count\",\n      \"properties\": {\n        \"dtype\": \"number\",\n        \"std\": 0.0,\n        \"min\": 15000.0,\n        \"max\": 15000.0,\n        \"num_unique_values\": 1,\n        \"samples\": [\n          15000.0\n        ],\n        \"semantic_type\": \"\",\n        \"description\": \"\"\n      }\n    },\n    {\n      \"column\": \"mean\",\n      \"properties\": {\n        \"dtype\": \"number\",\n        \"std\": 16.782120781448896,\n        \"min\": 0.057349333333333335,\n        \"max\": 54.78366666666667,\n        \"num_unique_values\": 10,\n        \"samples\": [\n          0.057349333333333335\n        ],\n        \"semantic_type\": \"\",\n        \"description\": \"\"\n      }\n    },\n    {\n      \"column\": \"std\",\n      \"properties\": {\n        \"dtype\": \"number\",\n        \"std\": 5.868112741184955,\n        \"min\": 0.12102324293532196,\n        \"max\": 19.43109289378658,\n        \"num_unique_values\": 10,\n        \"samples\": [\n          0.18531604311358044\n        ],\n        \"semantic_type\": \"\",\n        \"description\": \"\"\n      }\n    },\n    {\n      \"column\": \"min\",\n      \"properties\": {\n        \"dtype\": \"number\",\n        \"std\": 6.429964575675704,\n        \"min\": 0.0,\n        \"max\": 20.0,\n        \"num_unique_values\": 5,\n        \"samples\": [\n          1.0\n        ],\n        \"semantic_type\": \"\",\n        \"description\": \"\"\n      }\n    },\n    {\n      \"column\": \"25%\",\n      \"properties\": {\n        \"dtype\": \"number\",\n        \"std\": 12.627989371058069,\n        \"min\": 0.0,\n        \"max\": 41.0,\n        \"num_unique_values\": 8,\n        \"samples\": [\n          2.0\n        ],\n        \"semantic_type\": \"\",\n        \"description\": \"\"\n      }\n    },\n    {\n      \"column\": \"50%\",\n      \"properties\": {\n        \"dtype\": \"number\",\n        \"std\": 16.57027204229175,\n        \"min\": 0.0,\n        \"max\": 54.0,\n        \"num_unique_values\": 8,\n        \"samples\": [\n          3.0\n        ],\n        \"semantic_type\": \"\",\n        \"description\": \"\"\n      }\n    },\n    {\n      \"column\": \"75%\",\n      \"properties\": {\n        \"dtype\": \"number\",\n        \"std\": 20.797401119691212,\n        \"min\": 0.0,\n        \"max\": 68.0,\n        \"num_unique_values\": 8,\n        \"samples\": [\n          4.0\n        ],\n        \"semantic_type\": \"\",\n        \"description\": \"\"\n      }\n    },\n    {\n      \"column\": \"max\",\n      \"properties\": {\n        \"dtype\": \"number\",\n        \"std\": 39.92775481346835,\n        \"min\": 1.0,\n        \"max\": 131.0,\n        \"num_unique_values\": 7,\n        \"samples\": [\n          15.0\n        ],\n        \"semantic_type\": \"\",\n        \"description\": \"\"\n      }\n    }\n  ]\n}"
      }
     },
     "metadata": {}
    },
    {
     "output_type": "stream",
     "name": "stdout",
     "text": [
      "\n",
      "=== Sınıf Dağılımı ===\n",
      "is_feasible\n",
      "Uygun          0.985133\n",
      "Uygun Değil    0.014867\n",
      "Name: proportion, dtype: float64\n"
     ]
    },
    {
     "output_type": "error",
     "ename": "ValueError",
     "evalue": "Could not interpret value `deadhead_hours` for `x`. Value is a string, but `data` was not passed.",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mValueError\u001b[0m                                Traceback (most recent call last)",
      "\u001b[0;32m/tmp/ipykernel_4349/3150354013.py\u001b[0m in \u001b[0;36m<cell line: 0>\u001b[0;34m()\u001b[0m\n\u001b[1;32m     55\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m     56\u001b[0m \u001b[0;31m# Grafik 3: Deadhead vs FDP (Scatter, renk=uygunluk)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 57\u001b[0;31m sns.scatterplot(x=\"deadhead_hours\", y=\"fdp_hours\", hue=\"is_feasible\",\n\u001b[0m\u001b[1;32m     58\u001b[0m                 ax=axes[2], alpha=0.5, s=15)\n\u001b[1;32m     59\u001b[0m \u001b[0maxes\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m2\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mset_title\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"Deadhead vs FDP (Renk: Uygunluk)\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;32m/usr/local/lib/python3.13/dist-packages/seaborn/relational.py\u001b[0m in \u001b[0;36mscatterplot\u001b[0;34m(data, x, y, hue, size, style, palette, hue_order, hue_norm, sizes, size_order, size_norm, markers, style_order, legend, ax, **kwargs)\u001b[0m\n\u001b[1;32m    613\u001b[0m ):\n\u001b[1;32m    614\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 615\u001b[0;31m     p = _ScatterPlotter(\n\u001b[0m\u001b[1;32m    616\u001b[0m         \u001b[0mdata\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mdata\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    617\u001b[0m         \u001b[0mvariables\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mdict\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mx\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mx\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0my\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0my\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mhue\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mhue\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0msize\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0msize\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mstyle\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mstyle\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;32m/usr/local/lib/python3.13/dist-packages/seaborn/relational.py\u001b[0m in \u001b[0;36m__init__\u001b[0;34m(self, data, variables, legend)\u001b[0m\n\u001b[1;32m    394\u001b[0m         )\n\u001b[1;32m    395\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 396\u001b[0;31m         \u001b[0msuper\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m__init__\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mdata\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mdata\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mvariables\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mvariables\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m    397\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    398\u001b[0m         \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mlegend\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mlegend\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;32m/usr/local/lib/python3.13/dist-packages/seaborn/_base.py\u001b[0m in \u001b[0;36m__init__\u001b[0;34m(self, data, variables)\u001b[0m\n\u001b[1;32m    632\u001b[0m         \u001b[0;31m# information for numeric axes would be information about log scales.\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    633\u001b[0m         \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_var_ordered\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m{\u001b[0m\u001b[0;34m\"x\"\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0;32mFalse\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m\"y\"\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0;32mFalse\u001b[0m\u001b[0;34m}\u001b[0m  \u001b[0;31m# alt., used DefaultDict\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 634\u001b[0;31m         \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0massign_variables\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mdata\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mvariables\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m    635\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    636\u001b[0m         \u001b[0;31m# TODO Lots of tests assume that these are called to initialize the\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;32m/usr/local/lib/python3.13/dist-packages/seaborn/_base.py\u001b[0m in \u001b[0;36massign_variables\u001b[0;34m(self, data, variables)\u001b[0m\n\u001b[1;32m    677\u001b[0m             \u001b[0;31m# to centralize / standardize data consumption logic.\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    678\u001b[0m             \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0minput_format\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m\"long\"\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 679\u001b[0;31m             \u001b[0mplot_data\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mPlotData\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mdata\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mvariables\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m    680\u001b[0m             \u001b[0mframe\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mplot_data\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mframe\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    681\u001b[0m             \u001b[0mnames\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mplot_data\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mnames\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;32m/usr/local/lib/python3.13/dist-packages/seaborn/_core/data.py\u001b[0m in \u001b[0;36m__init__\u001b[0;34m(self, data, variables)\u001b[0m\n\u001b[1;32m     56\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m     57\u001b[0m         \u001b[0mdata\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mhandle_data_source\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mdata\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 58\u001b[0;31m         \u001b[0mframe\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mnames\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mids\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_assign_variables\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mdata\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mvariables\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m     59\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m     60\u001b[0m         \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mframe\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mframe\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;32m/usr/local/lib/python3.13/dist-packages/seaborn/_core/data.py\u001b[0m in \u001b[0;36m_assign_variables\u001b[0;34m(self, data, variables)\u001b[0m\n\u001b[1;32m    230\u001b[0m                 \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    231\u001b[0m                     \u001b[0merr\u001b[0m \u001b[0;34m+=\u001b[0m \u001b[0;34m\"An entry with this name does not appear in `data`.\"\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 232\u001b[0;31m                 \u001b[0;32mraise\u001b[0m \u001b[0mValueError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0merr\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m    233\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    234\u001b[0m             \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;31mValueError\u001b[0m: Could not interpret value `deadhead_hours` for `x`. Value is a string, but `data` was not passed."
     ]
    },
    {
     "output_type": "display_data",
     "data": {
      "text/plain": [
       "<Figure size 1500x400 with 3 Axes>"
      ],
      "image/png": "iVBORw0KGgoAAAANSUhEUgAABOEAAAGJCAYAAADMuid7AAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjAsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvlHJYcgAAAAlwSFlzAAAPYQAAD2EBqD+naQAAzk1JREFUeJzs3Xd4U2X7B/BvZvegg7aU1VIooy0tDiijTEWWLAEFBNSfDBm+AiIqUqosfUFEBVFElggqU2Sp+EJByhBaW/bedO+VpMn5/REbCG0hbdOcNv1+risXyTnPObnPIclp7tzP80gEQRBAREREREREREREVUYqdgBERERERERERETWjkk4IiIiIiIiIiKiKsYkHBERERERERERURVjEo6IiIiIiIiIiKiKMQlHRERERERERERUxZiEIyIiIiIiIiIiqmJMwhEREREREREREVUxJuGIiIiIiIiIiIiqGJNwREREREREREREVYxJODKrbt26YebMmYbHx44dQ2BgII4dO1bufRVvu3fvXnOGSI9Rmf+zssycORPdunUzqa1Op0Pfvn3x1Vdfme35K0uj0aBz587YsGGD2KEQ0QNefvllvPzyy2KHQVautOviyy+/jL59+z5229u3byMwMBBbt241LPviiy8QGBho1O7hv5+IiIjIOsnFDoBqhq1bt+Ldd98tdd3rr7+O6dOnWzgiYzt37kRaWhrGjBljUvtu3brhzp07AACJRAJHR0f4+PggNDQUL7zwAlq3bl3hWA4ePIj4+HhMnjy5wvsozYMxA4Cbmxv8/Pzwyiuv4JlnnjHrc4np119/xb179zBy5EjDMlNffxX5f33wi5BEIoGHhweaNWuGcePGoW3btgAAhUKBV155BStWrMALL7wAGxsbsx0vkbUy13Xj8uXL2LNnDwYOHIj69eubM0SL+fPPP/Hdd9/hypUryM/Ph4eHB4KCgjB48GBERESIHV618nByqpiHhwf++usvC0cjHmt43RMREVFJTMJRuUyZMqXEH4PNmjUrs/1TTz2F+Ph4KBSKKo3r119/xaVLl0xOwgFAixYt8MorrwAA8vLycPXqVezduxc//fQTxowZU+aXx8c5ePAgNmzYYPYkHGAcc3JyMn788UdMmjQJc+bMwUsvvWSW57DU/1lZVq1ahT59+sDJyanEOlNefxX5f+3QoQP69+8PQRBw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Jk2aAACysrLg7OysXp6VlQVXV1cAgJOTE7KzszXqlZaWIi8vT12fiMiYKQXgh4TcSteP8bSrs1hI/9LT05GXlyd2GAbh9u3bGv/TI40bN9Z6TlwiIiIiqhsGm4Rr1aoVmjRpgpiYGLi5uQEACgoKcPHiRYwZMwYA4OPjgwcPHiAhIQEeHh4AgNOnT0OlUsHLy0u02InIuMmKCjFs4qM5J6MjjkBpYSVyRNQQpKenY/yEiShRFD+9cAOyZMkSsUMwKKZm5ti5I4KJOCIiIiIDJGoS7uHDh7hz5476dUpKCi5fvozGjRujRYsWmDhxIjZu3Ig2bdqgVatWWLNmDZydndVPS+3QoQN69+6NL774AsHBwSgpKcGiRYswZMgQfvgkIr2RCAIcbl5R/0xUF/Ly8lCiKIa8fV+oLBqLHQ4ZIGlRHnDjOPLy8vg5iIiIiMgAiZqES0hIwMSJE9WvQ0JCAADDhg3D0qVL8e6770Iul2PBggV48OABunfvjrCwMJibm6vrrFixAosWLcLbb78NqVSKgQMHYv78+XXeFiIiQyQBkF+srHCdivnDekll0RgqayexwyAiIiIiIi2JmoTr2bMnrly5Uul6iUSCOXPmYM6cOZWWsbOzw8qVK/URHhFRvVfVnHFvedjVaSxEREREREQNmcHOCWdM2BOFiIiIiIiIiKhhYxKuDrAnChERERERERFRwyYVOwAiIiIiIiIiIiJjx55wRERaEiQS5Ddvrf6ZiIiIiIiI6GmYhCMi0pLSwgq79seKHQYRERERERHVIxyOSkREREREREREpGdMwhEREREREREREekZk3BERFqSFcnxxsQBeGPiAMiK5GKHQ0RERERERPUA54QjItKSRFDB+fIF9c9ERERERERET8OecERERERERERERHrGJBwREREREREREZGeMQlHRERERERERESkZ0zCERERERERERER6RmTcERERERERERERHrGp6MSEdWA3M5R7BCIiIiIiIioHmESjohIS6WW1thx5IrYYRAREREREVE9wuGoREREREREREREesYkHBERERERERERkZ4xCUdEpCVZkRyvTnsNr057DbIiudjhEBERERERUT3AJBwRkZYkggotzp9Ci/OnIBFUYodDNRAZGYn+/fvD09MTo0aNQlxcXJXlf/nlFwwaNAienp4YOnQojh8/XkeREhERERGRsWASjoiIGpRDhw4hJCQEM2fORHR0NFxdXREQEICsrKwKy58/fx5z587FyJEjsW/fPrz44ouYOXMmrl69WseRExERERFRfcYkHBERNSjh4eF48803MWLECHTs2BHBwcGwsLDAnj17KiwfERGB3r1745133kGHDh3wwQcfoEuXLti5c2cdR05ERERERPWZidgBEBER1RWFQoHExERMmzZNvUwqlcLPzw+xsbEV1rlw4QImTZqksczf3x+//vqr1vtXKpVa13myriwvBVJ5bo23oxMlckhUpeLGYGAEqQlgailqDBJFAYBH75XavNd04fr167h165aoMQDA7du3kZ+fL3YYlVq5cmWd79PW1hZt2rSp8/0+qW3btujYsWON64v9HiciIqoJJuGIiKjByMnJgVKphKOjo8ZyR0dH3Lhxo8I6mZmZcHJyKlc+MzNT6/3Hx8drXadMTk4OJFIpLO6er/E2yPhJpFLcvXsXhYWFosYRGhpa6d8U/evAgQNihyCa9u3bY+bMmWKHQUREVKeYhCMiIqojnp6ekMlkNa7fvHlzpKSk6DCimsnJyUFxcbHYYRgUc3Nz2Nvbix0GWrVqBVdXV7HDwLx58xpsT7iCggIcO3bsqeX69esHGxubOohIkzH1hKvNFxtERERiYBKOiKgGSiysxA6BasDe3h4ymazcQxiysrLK9XYr4+TkVK7XW1XlqyKTyWqVhHN3d4e7u3uN6xPVFRcXF7i4uIgdhmhOnDhR5XBJmUyGoKCgOoyIiIiIDAEfzEBEpKVSS2uEn7yD8JN3UGppLXY4pAUzMzO4u7sjJiZGvUylUiEmJgY+Pj4V1vH29sbp06c1lp06dQre3t76DJWI6rGjR49WmnCXyWQ4evRoHUdEREREhoBJOCIialAmT56MqKgoREdHIykpCQsXLoRcLsfw4cMBAIGBgRqTpU+cOBEnT57Et99+i6SkJKxbtw4JCQkYP368WE0gonrg6NGj2LlzJywsLCCRSGBhYYGdO3cyAUdERNSAcTgqERE1KIMHD0Z2djbWrl2LjIwMuLm5ISwsTD28NC0tDVLpv99RdevWDStWrMDq1auxatUqtG3bFqGhoejcubNYTSCieqJVq1Y4fPiw2GEQERGRgWASjohIS7LiIrw0bxIA4Miy7VCaW4gbEGlt/PjxlfZk27FjR7llr7zyCl55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u7Zac8WtWbMG7u7u6NSpExQKBX7//XedJQ+JiKi8Y8eOITk5GT169ECjRo1w/PhxqFSqCqc6eBobGxtMmTIFISEhEAQB3bt3R35+Ps6fPw8bGxsMGzYMbdq0wb59+3Dy5Em0atUKP/30E+Lj49VzgCYnJyMqKgr9+/eHs7Mzbt68iVu3blX4RNQyCoUCn3/+OaZPn467d+9i3bp1GD9+fIXXnXbt2mHo0KEIDAzEp59+Cjc3N+Tk5CAmJgYuLi544YUXtG43ERERkaFiEo6oFgIDA1FYWIjp06fD2toakydPRkFBQblykydPRkJCAkJDQ2FjY4NPP/0UvXv31kkMTZs2xZYtW7B8+XJERUXBzs4OI0eOxPTp09Vlpk2bhpSUFEybNg22traYM2dOtXrCmZqaYtWqVbh79y4sLCzQvXt3rFq1SidxExFReba2tjhy5AjWr1+P4uJitGnTBitXrkSnTp1qtL0PPvgADg4O2Lx5M1JSUmBra4suXbrgvffeAwCMHj0aly9fxocffgiJRIIhQ4Zg7NixOHHiBADA0tISN27cQHR0NHJzc+Hs7Ixx48Zh9OjRle7T19cXbdq0wbhx46BQKPDqq69W+bTukJAQbNy4EUuXLsX9+/dhZ2cHb29vJuCIiIjI6EiEx8ewEZHO9e/fHxMnTsSkSZPEDoWIiIiIiIiIRMI54YiIiIiIiIiIiPSMw1GJRLR//34EBQVVuK5FixY4ePBgHUdERESGKDU1FUOGDKl0/cGDB9GiRYs6jIiIiIiItMXhqEQiKigoQFZWVoXrTExM0LJlyzqOiIiIDFFpaSnu3r1b6fqWLVvCxITfrRIREREZMibhiIiIiIiIiIiI9IxzwhEREREREREREekZk3BERERERERERER6xiQcERERERERERGRnjEJR0REREREREREpGdMwhEREREREREREekZk3BERERERERERER6xiQcERERERERERGRnv0/vnFFn37pZ1QAAAAASUVORK5CYII=\n"
     },
     "metadata": {}
    }
   ],
   "source": "# ============================================================\n# AŞAMA 7: OPSİYONEL CSV YÜKLEME\n# Amaç: Kendi gerçek havayolu veriniz varsa yükleyin.\n#       Yoksa AŞAMA 6'daki sentetik veri kullanılır.\n# ============================================================\n\n# True yaparsanız Colab'dan dosya yükleme penceresi açılır\nUSE_UPLOADED = False\n\nif USE_UPLOADED:\n    try:\n        # Colab dosya yükleme modülü\n        from google.colab import files\n        # Dosya yükleme penceresi aç (kullanıcı CSV seçer)\n        uploaded = files.upload()\n        if uploaded:\n            # Yüklenen ilk dosyayı oku\n            fname = list(uploaded.keys())[0]\n            df = pd.read_csv(fname)\n            print(f\"✅ Yüklendi: {fname} → {df.shape}\")\n        else:\n            print(\"Dosya seçilmedi; sentetik devam.\")\n    except Exception as e:\n        print(f\"Upload atlandı: {e}\")\nelse:\n    print(f\"ℹ️ Sentetik veri kullanılıyor → {df.shape}\")\n\n# ============================================================\n# AŞAMA 8: EDA (Keşifsel Veri Analizi — Havacılık Metrikleri)\n# Amaç: Verinin dağılımını, sınıf dengesini ve özellik ilişkilerini\n#       görselleştirir. PDF'teki FDP, Yorgunluk, Deadhead odaklı.\n# ============================================================\n\n# Temel istatistikler (ortalama, std, min, max)\nprint(\"=== Temel İstatistikler ===\")\ndisplay(df.describe().T)\n\n# Sınıf dağılımı (Uygun vs Uygun Değil)\nprint(\"\\n=== Sınıf Dağılımı ===\")\nprint(df[\"is_feasible\"].value_counts(normalize=True).rename({0: \"Uygun Değil\", 1: \"Uygun\"}))\n\n# ── Görselleştirme: 3 grafik ──\nfig, axes = plt.subplots(1, 3, figsize=(15, 4))\n\n# Grafik 1: FDP Dağılımı (PDF: 13 saat üstü kritik)\nsns.histplot(df[\"fdp_hours\"], kde=True, ax=axes[0], color=\"#3498db\")\naxes[0].axvline(13.0, color=\"red\", linestyle=\"--\", label=\"FDP Limit (13h)\")\naxes[0].set_title(\"Flight Duty Period (FDP)\")\naxes[0].legend()\n\n# Grafik 2: Yorgunluk Skoru vs Uygunluk (Box plot)\nsns.boxplot(x=\"is_feasible\", y=\"fatigue_score\", data=df, ax=axes[1])\naxes[1].set_title(\"Fatigue Score vs Feasibility\")\naxes[1].set_xticklabels([\"Uygun Değil (0)\", \"Uygun (1)\"])\n\n# Grafik 3: Deadhead vs FDP (Scatter, renk=uygunluk)\nsns.scatterplot(x=\"deadhead_hours\", y=\"fdp_hours\", hue=\"is_feasible\",\n                ax=axes[2], alpha=0.5, s=15)\naxes[2].set_title(\"Deadhead vs FDP (Renk: Uygunluk)\")\n\nplt.tight_layout()\nplt.show()\n\n# Korelasyon matrisi (sayısal özellikler arası ilişki)\nnum_cols = df.select_dtypes(include=[np.number]).columns.tolist()\ncorr = df[num_cols].corr()\nplt.figure(figsize=(10, 8))\nsns.heatmap(corr, annot=True, fmt=\".2f\", cmap=\"RdBu_r\", center=0)\nplt.title(\"Özellik Korelasyon Matrisi (Havacılık)\")\nplt.tight_layout()\nplt.show()\n\nprint(\"✅ AŞAMA 7 & 8 tamamlandı.\")\n"
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "f8db6c39",
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "f8db6c39",
    "executionInfo": {
     "status": "ok",
     "timestamp": 1788452276532,
     "user_tz": -180,
     "elapsed": 197,
     "user": {
      "displayName": "Joseph Volkan ÖZCAN",
      "userId": "11389530967736397480"
     }
    },
    "outputId": "3cad67a0-ce9a-4e62-df69-76a0d58fd877"
   },
   "outputs": [
    {
     "output_type": "stream",
     "name": "stdout",
     "text": [
      "Örnek maskelenmiş ID'ler:\n",
      "  pairing_id pairing_id_masked\n",
      "0     P10000      4ce775cea844\n",
      "1     P10001      0e86136989b6\n",
      "2     P10002      b61cea600a47\n",
      "✅ AŞAMA 9 tamamlandı (KVKK).\n"
     ]
    }
   ],
   "source": "# ============================================================\n# AŞAMA 9: KVKK / GDPR ANONİMLEŞTİRME\n# Amaç: Pairing ID'lerini SHA-256 hash ile maskeler.\n#       Gerçek veride kişi isimleri, sicil no vb. de maskelenir.\n# ============================================================\n\n# Maskeleme fonksiyonu: ID'yi salt ile hash'ler, ilk 12 karakteri alır\ndef mask_id(val: str, salt: str = \"aviation_salt\") -> str:\n    # SHA-256 hash hesapla ve ilk 12 hex karakteri döndür\n    return sha256(f\"{salt}{val}\".encode()).hexdigest()[:12]\n\n# Pairing ID'lerini maskelenmiş versiyonlarıyla değiştir\ndf[\"pairing_id_masked\"] = df[\"pairing_id\"].apply(mask_id)\n\n# Örnek göster\nprint(\"Örnek maskelenmiş ID'ler:\")\nprint(df[[\"pairing_id\", \"pairing_id_masked\"]].head(3))\nprint(\"✅ AŞAMA 9 tamamlandı (KVKK).\")\n"
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "c9bb31c8",
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "c9bb31c8",
    "executionInfo": {
     "status": "ok",
     "timestamp": 1788452283539,
     "user_tz": -180,
     "elapsed": 1680,
     "user": {
      "displayName": "Joseph Volkan ÖZCAN",
      "userId": "11389530967736397480"
     }
    },
    "outputId": "37cf5233-b256-443f-8337-17bd46dcef8e"
   },
   "outputs": [
    {
     "output_type": "stream",
     "name": "stdout",
     "text": [
      "🎯 Quantum Özellik Sayısı (Qubit): 9\n",
      "📊 Seçilen Özellikler: ['type_rating_match', 'base_return_ok', 'fatigue_score', 'night_hours', 'rest_before_hours', 'fdp_hours', 'deadhead_hours', 'num_legs', 'min_connection_min']\n",
      "   Backend: ibm_marrakesh | Provider: ibm\n",
      "✅ Quantum Subset: Train (60, 9), Test (30, 9)\n",
      "   Feasible oranı: Train=50.00%, Test=96.67%\n",
      "✅ AŞAMA 10 tamamlandı.\n"
     ]
    }
   ],
   "source": "# ============================================================\n# AŞAMA 10: ÖN İŞLEME + MAX QUBIT UTILIZATION\n# Amaç: Klasik modeller TÜM özelliklerle eğitilir.\n#       Quantum tarafında özellik sayısı backend qubit kapasitesine\n#       göre belirlenir (max utilization). En ayırt edici özellikler\n#       korelasyon + domain önceliği ile seçilir.\n# ============================================================\n\n# Tüm özellik kolonları (PDF domain bilgisine göre seçildi)\nFEATURE_COLS = [\n    \"fdp_hours\",           # Görev süresi (en kritik kısıt)\n    \"num_legs\",            # Bacak sayısı\n    \"min_connection_min\",  # Min bağlantı süresi\n    \"night_hours\",         # Gece uçuşu (8-in-24 tetikleyicisi)\n    \"deadhead_hours\",      # Pas uçuş (maliyet)\n    \"rest_before_hours\",   # Dinlenme süresi\n    \"type_rating_match\",   # Lisans uyumu (Rostering)\n    \"base_return_ok\",      # Base return (Pairing kuralı)\n    \"fatigue_score\",       # Bileşik yorgunluk skoru\n]\n# Hedef değişken adı\nTARGET = \"is_feasible\"\n\n# Özellik matrisi (X) ve hedef vektörü (y) ayır\nX = df[FEATURE_COLS].copy()\ny = df[TARGET].copy()\n\n# Train/Test ayrımı (%75 eğitim, %25 test, tabakalı)\nX_train, X_test, y_train, y_test = train_test_split(\n    X, y, test_size=0.25, random_state=42, stratify=y\n)\n\n# Klasik ML için StandardScaler (ortalama=0, std=1)\nscaler = StandardScaler()\nX_train_sc = scaler.fit_transform(X_train)  # Eğitime fit + transform\nX_test_sc = scaler.transform(X_test)        # Teste sadece transform\n\n# ── Qubit sayısı belirleme (Backend kapasitesine göre) ──\nMAX_Q_CAP = 9  # NISQ gürültüsü ve kernel maliyeti için üst sınır\n\n# Backend qubit sayısını al (IBM ise gerçek, yoksa varsayılan)\nbackend_qubits = getattr(BACKEND, \"num_qubits\", MAX_Q_CAP) if HARDWARE_PROVIDER == \"ibm\" else MAX_Q_CAP\n# Hedef qubit sayısı: min(özellik havuzu, backend kapasitesi, üst sınır)\nn_qubits = min(len(FEATURE_COLS), backend_qubits, MAX_Q_CAP)\n\n# ── Özellik sıralama: |korelasyon| + domain boost ──\n# Her özelliğin hedef ile mutlak korelasyonunu hesapla\ncorr_scores = {}\nfor col in FEATURE_COLS:\n    c = abs(np.corrcoef(X_train[col], y_train)[0, 1])  # Pearson korelasyonu\n    corr_scores[col] = c if not np.isnan(c) else 0.0\n\n# En yüksek korelasyonlu n_qubits özelliği seç\nQ_FEATURES = sorted(corr_scores, key=corr_scores.get, reverse=True)[:n_qubits]\n\nprint(f\"🎯 Quantum Özellik Sayısı (Qubit): {n_qubits}\")\nprint(f\"📊 Seçilen Özellikler: {Q_FEATURES}\")\nprint(f\"   Backend: {BACKEND_NAME} | Provider: {HARDWARE_PROVIDER}\")\n\n# ── Quantum veri hazırlama (MinMax → [0, π] aralığı) ──\n# Phase encoding için özellikleri [0, π] aralığına çek\nX_train_q_raw = X_train[Q_FEATURES].values\nX_test_q_raw = X_test[Q_FEATURES].values\n\n# MinMaxScaler ile [0, π] aralığına ölçekle\nscaler_q = MinMaxScaler(feature_range=(0, np.pi))\nX_train_q = scaler_q.fit_transform(X_train_q_raw)\nX_test_q = scaler_q.transform(X_test_q_raw)\n\n# ── NISQ kota koruması: Eğitim setini küçült ──\n# Gerçek HW'de O(N²) kernel job maliyeti → küçük subset\nN_TRAIN_Q = 60   # Eğitim subset boyutu\nN_TEST_Q = 30    # Test subset boyutu\n\n# Dengeli subset seç (eşit sayıda pozitif/negatif)\nidx_pos = np.where(y_train.values == 1)[0]  # Uygun örneklerin indeksleri\nidx_neg = np.where(y_train.values == 0)[0]  # Uygun olmayanların indeksleri\nsel = np.concatenate([\n    np.random.choice(idx_pos, N_TRAIN_Q // 2, replace=False),  # Pozitif yarısı\n    np.random.choice(idx_neg, N_TRAIN_Q // 2, replace=False),  # Negatif yarısı\n])\nnp.random.shuffle(sel)  # Karıştır\n\n# Subset'leri oluştur\nX_train_q_sub = X_train_q[sel]\ny_train_q = y_train.values[sel]\n\n# Test subset'i\nidx_t = np.random.choice(len(y_test), size=N_TEST_Q, replace=False)\nX_test_q_sub = X_test_q[idx_t]\ny_test_q = y_test.values[idx_t]\n\nprint(f\"✅ Quantum Subset: Train {X_train_q_sub.shape}, Test {X_test_q_sub.shape}\")\nprint(f\"   Feasible oranı: Train={y_train_q.mean():.2%}, Test={y_test_q.mean():.2%}\")\nprint(\"✅ AŞAMA 10 tamamlandı.\")\n"
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "02109fd6",
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "02109fd6",
    "executionInfo": {
     "status": "ok",
     "timestamp": 1788452296734,
     "user_tz": -180,
     "elapsed": 6730,
     "user": {
      "displayName": "Joseph Volkan ÖZCAN",
      "userId": "11389530967736397480"
     }
    },
    "outputId": "7c15f260-d821-4ce3-8807-fb03f2ffc00a"
   },
   "outputs": [
    {
     "output_type": "stream",
     "name": "stdout",
     "text": [
      "=== Klasik Baseline Eğitim ===\n",
      "  Logistic Regression  | AUC: 0.7990 | F1: 0.9925\n",
      "  Random Forest        | AUC: 0.7956 | F1: 0.9925\n",
      "  SVM (RBF)            | AUC: 0.5391 | F1: 0.9925\n",
      "  XGBoost              | AUC: 0.7793 | F1: 0.9926\n",
      "✅ AŞAMA 11 tamamlandı.\n"
     ]
    }
   ],
   "source": "# ============================================================\n# AŞAMA 11: KLASİK BASELINE MODELLER\n# Amaç: Quantum modelin karşılaştırılacağı referans modelleri\n#       eğitir. TÜM özelliklerle (9 adet) çalışır.\n# Modeller: Logistic Regression, Random Forest, SVM (RBF), XGBoost\n# ============================================================\n\n# Model sözlüğü — isim: model nesnesi\nmodels = {\n    # Lojistik Regresyon — en basit lineer sınıflandırıcı\n    \"Logistic Regression\": LogisticRegression(max_iter=1000, random_state=42),\n    # Rastgele Orman — 100 ağaç, max derinlik 6\n    \"Random Forest\": RandomForestClassifier(n_estimators=100, max_depth=6, random_state=42),\n    # SVM — RBF kernel (Quantum kernel ile karşılaştırma için)\n    \"SVM (RBF)\": SVC(kernel=\"rbf\", probability=True, random_state=42),\n    # XGBoost — Gradient boosting (endüstri standardı)\n    \"XGBoost\": XGBClassifier(\n        n_estimators=100, max_depth=4, learning_rate=0.1,\n        random_state=42, verbosity=0\n    ),\n}\n\n# Sonuçları saklayacak sözlük\nresults = {}\nprint(\"=== Klasik Baseline Eğitim ===\")\n\n# Her modeli eğit ve değerlendir\nfor name, model in models.items():\n    # Modeli eğitim verisiyle eğit (tüm 9 özellik)\n    model.fit(X_train_sc, y_train)\n    # Test seti üzerinde tahmin yap\n    y_pred = model.predict(X_test_sc)\n    # Olasılık tahminleri (ROC-AUC için)\n    y_prob = model.predict_proba(X_test_sc)[:, 1] if hasattr(model, \"predict_proba\") else y_pred\n\n    # Metrikleri hesapla ve kaydet\n    results[name] = {\n        \"accuracy\": accuracy_score(y_test, y_pred),\n        \"precision\": precision_score(y_test, y_pred, zero_division=0),\n        \"recall\": recall_score(y_test, y_pred, zero_division=0),\n        \"f1\": f1_score(y_test, y_pred, zero_division=0),\n        \"roc_auc\": roc_auc_score(y_test, y_prob),\n        \"y_pred\": y_pred,   # Tahminler (CM için sakla)\n        \"y_prob\": y_prob,   # Olasılıklar (ROC için sakla)\n    }\n    # Sonucu ekrana yazdır\n    print(f\"  {name:20s} | AUC: {results[name]['roc_auc']:.4f} | F1: {results[name]['f1']:.4f}\")\n\nprint(\"✅ AŞAMA 11 tamamlandı.\")\n"
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "192284f3",
   "metadata": {
    "id": "192284f3"
   },
   "outputs": [],
   "source": "# ============================================================\n# AŞAMA 12: FEATURE MAP + BLOCH GÖRSELLEŞTİRME + FIDELITY\n# Amaç: Quantum encoding'in nasıl çalıştığını gösterir.\n#       ZZFeatureMap ile veriyi Hilbert uzayına map eder,\n#       Bloch küresi üzerinde görselleştirir, fidelity hesaplar.\n# Matematik: K(x,x') = |⟨φ(x)|φ(x')⟩|²\n# ============================================================\n\n# Qiskit kütüphanelerini içe aktar\nfrom qiskit.circuit.library import ZZFeatureMap  # Parametreli devre şablonu\nfrom qiskit_machine_learning.kernels import FidelityQuantumKernel  # Kernel\nfrom qiskit.quantum_info import Statevector  # Durum vektörü hesaplama\nfrom qiskit.visualization import plot_bloch_multivector  # Bloch görselleştirme\nfrom IPython.display import display  # Jupyter içi gösterim\n\n# ── Feature Map Tasarımı ──\n# ZZFeatureMap: Her qubit'e Ry rotasyonu + qubitler arası ZZ etkileşimi\n# feature_dimension = qubit sayısı = özellik sayısı\n# reps = 2 katman (daha fazla = daha zengin encoding ama daha gürültülü)\n# entanglement = \"linear\" (qubit 0-1, 1-2, ... bağlantısı)\nfeature_map = ZZFeatureMap(feature_dimension=n_qubits, reps=2, entanglement=\"linear\")\nprint(f\"🔹 Feature Map: {n_qubits} qubit, reps=2, linear entanglement\")\n\n# Devre şemasını çiz (decompose = temel kapılara ayrıştır)\ndisplay(feature_map.decompose().draw(output=\"mpl\", style=\"clifford\"))\n\n# ── Fidelity Quantum Kernel (Statevector — gürültüsüz) ──\nquantum_kernel = FidelityQuantumKernel(feature_map=feature_map)\nprint(\"✅ FidelityQuantumKernel (statevector) hazır.\\n\")\n\n# ── Bloch Küresi Görselleştirmesi ──\nprint(\"=\" * 60)\nprint(\"BLOCH KÜRESİ — Örnek Encoding (gürültüsüz üst sınır)\")\nprint(\"=\" * 60)\n\n# Farklı sınıflardan örnekler seç (1 uygun, 1 uygun değil, 1 rastgele)\npos_idx = np.where(y_train_q == 1)[0]  # Uygun örnekler\nneg_idx = np.where(y_train_q == 0)[0]  # Uygun olmayanlar\nchosen = []\nif len(pos_idx): chosen.append(pos_idx[0])  # İlk uygun\nif len(neg_idx): chosen.append(neg_idx[0])  # İlk uygun değil\nfor i in range(len(X_train_q_sub)):\n    if i not in chosen:\n        chosen.append(i)  # Üçüncü örnek\n        break\nchosen = chosen[:3]  # En fazla 3 örnek\n\n# Her örnek için Bloch küresini çiz\nfor k, idx in enumerate(chosen):\n    x_vec = X_train_q_sub[idx]          # Özellik vektörü\n    label = int(y_train_q[idx])         # Sınıf etiketi\n    label_str = \"Uygun (1)\" if label == 1 else \"Uygun Değil (0)\"\n    # Feature map'e parametreleri ata → devre oluştur\n    qc = feature_map.assign_parameters(x_vec)\n    # Devrenin durum vektörünü hesapla (simülatör)\n    sv = Statevector.from_instruction(qc)\n    print(f\"\\n--- Örnek {k+1}: {label_str} | x={np.round(x_vec, 3)} ---\")\n    # Bloch küresini çiz ve göster\n    fig = plot_bloch_multivector(sv, title=f\"Örnek {k+1} | {label_str}\")\n    display(fig)\n    plt.close(fig)\n\n# ── Fidelity Hesaplama (İki örnek arası benzerlik) ──\nif len(chosen) >= 2:\n    # İki örneğin durum vektörlerini hesapla\n    sv0 = Statevector.from_instruction(feature_map.assign_parameters(X_train_q_sub[chosen[0]]))\n    sv1 = Statevector.from_instruction(feature_map.assign_parameters(X_train_q_sub[chosen[1]]))\n    # Fidelity = |⟨ψ₀|ψ₁⟩|² (1=aynı, 0=dik/ortogonal)\n    fid = np.abs(np.vdot(sv0.data, sv1.data)) ** 2\n    print(f\"\\nÖrnek1 ↔ Örnek2 fidelity ≈ {fid:.4f}\")\n    print(\"  (1.0 = aynı durum, 0.0 = tamamen farklı)\")\n\nprint(\"✅ AŞAMA 12 tamamlandı.\")\n"
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "93004536",
   "metadata": {
    "id": "93004536"
   },
   "outputs": [],
   "source": "# ============================================================\n# AŞAMA 13: QSVC EĞİTİMİ (Simülatör + Tek Gerçek QPU Job)\n# Amaç: Fidelity Quantum Kernel ile QSVC sınıflandırıcıyı eğitir.\n#       1) Simülatörde tam QSVC (hızlı, birincil metrikler)\n#       2) Gerçek IBM QPU'da TEK Bell State job (duman testi)\n# TASARIM: Tam QSVC.fit HW'de KAPALI — O(N²) job kuyruğu yok.\n# ============================================================\n\n# QSVC algoritmasını içe aktar\nfrom qiskit_machine_learning.algorithms import QSVC\nfrom qiskit_machine_learning.kernels import FidelityQuantumKernel\nfrom qiskit import QuantumCircuit\n\n# ── 1) Simülatör QSVC (Birincil) ──\nprint(\"🔹 QSVC Simülatör eğitiliyor...\")\n# Statevector tabanlı kernel (gürültüsüz, hızlı)\nkernel_sim = FidelityQuantumKernel(feature_map=feature_map)\n# QSVC nesnesi oluştur (kernel + SVC arka uç)\nqsvc_sim = QSVC(quantum_kernel=kernel_sim)\n# Eğitim: Kernel matrisini hesapla + SVM çöz\nqsvc_sim.fit(X_train_q_sub, y_train_q)\n# Test tahminleri\ny_pred_sim = qsvc_sim.predict(X_test_q_sub)\n# Karar fonksiyonu (ROC için)\ntry:\n    y_score_sim = qsvc_sim.decision_function(X_test_q_sub)\nexcept Exception:\n    y_score_sim = y_pred_sim.astype(float)\n\n# Simülatör metriklerini hesapla\nq_metrics_sim = {\n    \"accuracy\": accuracy_score(y_test_q, y_pred_sim),\n    \"precision\": precision_score(y_test_q, y_pred_sim, zero_division=0),\n    \"recall\": recall_score(y_test_q, y_pred_sim, zero_division=0),\n    \"f1\": f1_score(y_test_q, y_pred_sim, zero_division=0),\n    \"roc_auc\": roc_auc_score(y_test_q, y_score_sim) if len(np.unique(y_test_q)) > 1 else 0.5,\n}\nprint(\"=== QSVC Simülatör Metrikleri ===\")\nfor k, v in q_metrics_sim.items():\n    print(f\"  {k:12s}: {v:.4f}\")\n\n# ── 2) Gerçek IBM QPU — Tek Bell State Job (Duman Testi) ──\nHW_JOB_DONE = False  # HW job başarılı mı?\nif USE_REAL_HARDWARE and HARDWARE_PROVIDER == \"ibm\":\n    print(f\"\\n🔹 IBM Gerçek Donanım ({BACKEND_NAME}) — Bell State duman testi...\")\n    try:\n        # Transpiler ve Sampler import\n        from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager\n        from qiskit_ibm_runtime import SamplerV2\n\n        # Basit Bell State devresi (2 qubit dolanıklık kanıtı)\n        qc = QuantumCircuit(2)\n        qc.h(0)          # Qubit 0'a Hadamard (süperpozisyon)\n        qc.cx(0, 1)      # CNOT (dolanıklık oluştur)\n        qc.measure_all()  # Tüm qubit'leri ölç\n\n        # Devreyi backend topolojisine göre derle (ISA uyumlu)\n        pm = generate_preset_pass_manager(optimization_level=1, backend=BACKEND)\n        isa_qc = pm.run(qc)\n\n        # SamplerV2 ile gerçek QPU'ya gönder\n        sampler = SamplerV2(mode=BACKEND)\n        job = sampler.run([isa_qc], shots=128)\n        print(f\"   Job ID: {job.job_id()} | Sonuç bekleniyor...\")\n\n        # Sonucu al ve parse et\n        res = job.result()\n        counts = res[0].data.meas.get_counts()\n        print(f\"   ✅ HW Counts (Bell State): {counts}\")\n        print(\"   (İdeal: ~%50 '00', ~%50 '11')\")\n        HW_JOB_DONE = True\n    except Exception as e:\n        print(f\"   ⚠️ HW Job başarısız (Kota/Kuyruk): {e}\")\nelse:\n    print(\"\\nℹ️ Gerçek donanım job'ı atlandı.\")\n\nprint(f\"\\n📌 Birincil metrik: Sim QSVC | HW duman testi: {'OK' if HW_JOB_DONE else 'yok'}\")\nprint(\"✅ AŞAMA 13 tamamlandı.\")\n"
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "1dc342b0",
   "metadata": {
    "id": "1dc342b0"
   },
   "outputs": [],
   "source": "# ============================================================\n# AŞAMA 14: CONFUSION MATRIX + ROC EĞRİSİ\n# Amaç: En iyi klasik model ile QSVC'yi görsel olarak karşılaştırır.\n#       Havacılık bağlamında Precision (yasal ihlal riski) ve\n#       Recall (operasyonel esneklik kaybı) kritik metriklerdir.\n# ============================================================\n\n# En iyi klasik modeli AUC'ye göre seç\nbest_classic = max(results, key=lambda n: results[n][\"roc_auc\"])\nbest_c = results[best_classic]\n\n# ── Confusion Matrix (2 model yan yana) ──\nfig, axes = plt.subplots(1, 2, figsize=(10, 4))\n\n# Sol: En iyi klasik model CM\ncm_c = confusion_matrix(y_test, best_c[\"y_pred\"])\nConfusionMatrixDisplay(cm_c, display_labels=[\"Uygun Değil\", \"Uygun\"]).plot(\n    ax=axes[0], colorbar=False\n)\naxes[0].set_title(f\"Klasik: {best_classic}\")\n\n# Sağ: QSVC Simülatör CM\ncm_s = confusion_matrix(y_test_q, y_pred_sim)\nConfusionMatrixDisplay(cm_s, display_labels=[\"Uygun Değil\", \"Uygun\"]).plot(\n    ax=axes[1], colorbar=False\n)\naxes[1].set_title(\"QSVC Simülatör\")\n\nplt.tight_layout()\nplt.show()\n\n# ── ROC Eğrisi ──\nfig, ax = plt.subplots(figsize=(8, 6))\n\n# Klasik model ROC\nfpr_c, tpr_c, _ = roc_curve(y_test, best_c[\"y_prob\"])\nax.plot(fpr_c, tpr_c, label=f\"Klasik: {best_classic} (AUC={best_c['roc_auc']:.3f})\")\n\n# QSVC Sim ROC\nif len(np.unique(y_test_q)) > 1:\n    fpr_s, tpr_s, _ = roc_curve(y_test_q, y_score_sim)\n    ax.plot(fpr_s, tpr_s, label=f\"QSVC Sim (AUC={q_metrics_sim['roc_auc']:.3f})\", linestyle=\"--\")\n\n# Rastgele tahmin çizgisi (referans)\nax.plot([0, 1], [0, 1], \"k--\", alpha=0.4)\nax.set_xlabel(\"False Positive Rate (Yasal İhlal Riski)\")\nax.set_ylabel(\"True Positive Rate (Doğru Fizibilite)\")\nax.set_title(\"ROC — Havacılık Ekip Fizibilite Tahmini\")\nax.legend(loc=\"lower right\")\nplt.tight_layout()\nplt.show()\n\n# Havacılık operasyon yorumu\nprint(\"📖 Havacılık Operasyon Yorumu:\")\nprint(\"  • Precision: 'Uygun' denilen pairing gerçekten yasal mı?\")\nprint(\"    (Düşük precision → Regülasyon ihlali → Cezalar)\")\nprint(\"  • Recall: Gerçekten uygun pairing'leri kaçırmama\")\nprint(\"    (Düşük recall → Operasyonel esneklik kaybı → Maliyet)\")\nprint(\"✅ AŞAMA 14 tamamlandı.\")\n"
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "f16a963b",
   "metadata": {
    "id": "f16a963b"
   },
   "outputs": [],
   "source": "# ============================================================\n# AŞAMA 15: MODEL KARŞILAŞTIRMA TABLOSU\n# Amaç: Tüm klasik modeller + QSVC'yi tek tabloda karşılaştırır.\n#       En iyi skoru yeşil ile vurgular.\n# ============================================================\n\n# Karşılaştırma DataFrame'i oluştur\ncomparison = pd.DataFrame({\n    name: {\n        \"ROC-AUC\": r[\"roc_auc\"],\n        \"F1\": r[\"f1\"],\n        \"Precision\": r[\"precision\"],\n        \"Recall\": r[\"recall\"],\n        \"Accuracy\": r[\"accuracy\"],\n    }\n    for name, r in results.items()\n})\n# QSVC Sim satırını ekle\ncomparison[\"QSVC (Sim)\"] = {\n    \"ROC-AUC\": q_metrics_sim[\"roc_auc\"],\n    \"F1\": q_metrics_sim[\"f1\"],\n    \"Precision\": q_metrics_sim[\"precision\"],\n    \"Recall\": q_metrics_sim[\"recall\"],\n    \"Accuracy\": q_metrics_sim[\"accuracy\"],\n}\n# Transpoz (satır=model, sütun=metrik) ve yuvarla\ncomparison = comparison.T.round(4)\n\n# Tabloyu göster (en yüksek skorlar yeşil)\nprint(\"=== Model Karşılaştırma (Crew Feasibility) ===\")\ndisplay(comparison.style.highlight_max(axis=0, color=\"lightgreen\"))\n\n# Bar grafik (ROC-AUC ve F1)\nfig, ax = plt.subplots(figsize=(12, 5))\ncomparison[[\"ROC-AUC\", \"F1\"]].plot(kind=\"bar\", ax=ax, color=[\"#3498db\", \"#e74c3c\"])\nax.set_title(\"Model Karşılaştırması — ROC-AUC & F1\")\nax.set_ylabel(\"Skor\")\nax.set_ylim(0, 1.05)\nax.legend(loc=\"lower right\")\nplt.xticks(rotation=25, ha=\"right\")\nplt.tight_layout()\nplt.show()\n\nprint(\"✅ AŞAMA 15 tamamlandı.\")\n"
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "1b979036",
   "metadata": {
    "id": "1b979036"
   },
   "outputs": [],
   "source": "# ============================================================\n# AŞAMA 16: SONUÇ KAYDI (JSON + CSV)\n# Amaç: Tüm metrikleri ve konfigürasyonu OUTPUT_PATH altına\n#       kaydeder. Tekrarlanabilirlik ve raporlama için.\n# ============================================================\n\n# Benzersiz run ID (tarih + saat)\nrun_id = datetime.now().strftime(\"%Y%m%d_%H%M%S\")\n# Çıktı klasörünü garanti et\nos.makedirs(OUTPUT_PATH, exist_ok=True)\n\n# Özet sözlük (JSON olarak kaydedilecek)\nsummary = {\n    \"run_id\": run_id,\n    \"problem\": \"Aviation_Crew_Feasibility\",\n    \"n_samples\": len(df),\n    \"n_qubits\": n_qubits,\n    \"q_features\": Q_FEATURES,\n    \"backend\": BACKEND_NAME,\n    \"hardware_provider\": HARDWARE_PROVIDER,\n    \"use_real_hardware\": USE_REAL_HARDWARE,\n    \"hw_job_success\": HW_JOB_DONE,\n    \"classical_best\": best_classic,\n    \"classical_auc\": float(best_c[\"roc_auc\"]),\n    \"quantum_sim_auc\": float(q_metrics_sim[\"roc_auc\"]),\n    \"quantum_sim_f1\": float(q_metrics_sim[\"f1\"]),\n}\n\n# JSON dosyasına yaz\nsummary_path = os.path.join(OUTPUT_PATH, f\"summary_{run_id}.json\")\nwith open(summary_path, \"w\") as f:\n    json.dump(summary, f, indent=2, default=str)\nprint(f\"✅ Özet kaydedildi: {summary_path}\")\n\n# Metrikleri CSV olarak da kaydet\nmetric_rows = []\nfor name, r in results.items():\n    metric_rows.append({\n        \"model\": name, \"type\": \"classical\",\n        \"roc_auc\": r[\"roc_auc\"], \"f1\": r[\"f1\"],\n    })\nmetric_rows.append({\n    \"model\": \"QSVC Sim\", \"type\": \"quantum_sim\",\n    \"roc_auc\": q_metrics_sim[\"roc_auc\"], \"f1\": q_metrics_sim[\"f1\"],\n})\nmetrics_df = pd.DataFrame(metric_rows)\nmetrics_path = os.path.join(OUTPUT_PATH, f\"metrics_{run_id}.csv\")\nmetrics_df.to_csv(metrics_path, index=False)\nprint(f\"✅ Metrikler kaydedildi: {metrics_path}\")\nprint(\"✅ AŞAMA 16 tamamlandı.\")\n"
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "0f0fdb35",
   "metadata": {
    "id": "0f0fdb35"
   },
   "outputs": [],
   "source": "# ============================================================\n# AŞAMA 17: QUANTUM ADVANTAGE LAB — Set-Partitioning (QAOA)\n# Amaç: PDF'teki Crew Pairing set-covering problemini küçük bir\n#       QUBO'ya dönüştürür ve QAOA ile çözer.\n# PDF Bağlamı: Milyonlarca pairing adayı arasından tüm uçuş\n#       bacaklarını kapsayan min maliyetli seti bulmak.\n# NOT: Üretimde Column Generation + MIP birincil kalır;\n#      QAOA hibrit aday üretici olarak konumlanır.\n# ============================================================\n\n# Qiskit QAOA bileşenlerini içe aktar\nfrom qiskit.quantum_info import SparsePauliOp  # Pauli operatörleri\nfrom qiskit.circuit.library import QAOAAnsatz   # QAOA devre şablonu\nfrom qiskit.primitives import StatevectorSampler  # Simülatör sampler\n\n# ── Toy Problem: 4 bacak, 6 aday pairing ──\nN_LEGS = 4      # Uçuş bacağı sayısı (satır)\nN_PAIRINGS = 6  # Aday pairing sayısı (sütun / qubit)\n\n# Coverage matrisi A[leg, pairing]: 1 = pairing bu bacağı kapsar\nA = np.array([\n    [1, 1, 0, 0, 1, 0],  # Bacak 0: Pairing 0,1,4 kapsıyor\n    [0, 1, 1, 0, 0, 1],  # Bacak 1: Pairing 1,2,5 kapsıyor\n    [1, 0, 1, 1, 0, 0],  # Bacak 2: Pairing 0,2,3 kapsıyor\n    [0, 0, 0, 1, 1, 1],  # Bacak 3: Pairing 3,4,5 kapsıyor\n], dtype=float)\n\n# Pairing maliyetleri (düşük = iyi)\nc = np.array([10.0, 12.0, 9.0, 11.0, 14.0, 8.0])\n\n# ── QUBO Matrisi Oluştur ──\n# Hedef: min c^T x + λ * ||Ax - 1||²\nLAM = 20.0  # Kapsama cezası (maliyet ölçeğinden büyük)\nQ = np.zeros((N_PAIRINGS, N_PAIRINGS))\n\n# Lineer maliyet terimi (diyagonal)\nfor j in range(N_PAIRINGS):\n    Q[j, j] += c[j]\n\n# Ceza terimi: λ * (Σ A_ij x_j - 1)² açılımı\nfor i in range(N_LEGS):\n    row = A[i].astype(float)\n    for j in range(N_PAIRINGS):\n        # Diyagonal ceza: λ * (A_ij² - 2*A_ij)\n        Q[j, j] += LAM * (row[j]**2 - 2*row[j])\n        for k in range(j+1, N_PAIRINGS):\n            # Off-diagonal ceza: λ * 2 * A_ij * A_ik\n            val = LAM * 2 * row[j] * row[k]\n            Q[j, k] += val\n            Q[k, j] += val\n\nprint(f\"✅ QUBO Matrisi ({N_PAIRINGS}x{N_PAIRINGS}) oluşturuldu. λ={LAM}\")\n\n# ── QUBO → Ising Hamiltonian (SparsePauliOp) ──\n# Dönüşüm: x = (1-Z)/2\npauli_list = []\nfor j in range(N_PAIRINGS):\n    z = [\"I\"] * N_PAIRINGS\n    z[j] = \"Z\"\n    coef = -0.5 * Q[j, j]\n    for k in range(N_PAIRINGS):\n        if k != j:\n            coef -= 0.25 * Q[j, k]\n    if abs(coef) > 1e-9:\n        pauli_list.append((\"\".join(z[::-1]), float(coef)))\n\nfor j in range(N_PAIRINGS):\n    for k in range(j+1, N_PAIRINGS):\n        if abs(Q[j, k]) < 1e-12:\n            continue\n        z = [\"I\"] * N_PAIRINGS\n        z[j] = \"Z\"\n        z[k] = \"Z\"\n        pauli_list.append((\"\".join(z[::-1]), float(0.25 * Q[j, k])))\n\nif not pauli_list:\n    pauli_list = [(\"Z\" + \"I\"*(N_PAIRINGS-1), 1.0)]\n\n# Cost Hamiltonian oluştur\nH_C = SparsePauliOp.from_list(pauli_list)\nprint(f\"Cost Hamiltonian: {len(H_C)} terim\")\n\n# ── QAOA Ansatz (1 katman) ──\nreps = 1  # QAOA katman sayısı (p=1, hızlı demo)\nansatz = QAOAAnsatz(cost_operator=H_C, reps=reps)\nprint(f\"QAOA Ansatz: {ansatz.num_qubits} qubit, {ansatz.num_parameters} parametre\")\n\n# ── Simülatör Sampling ──\nsampler = StatevectorSampler()\n# Rastgele başlangıç parametreleri (optimize edilmemiş)\nrng = np.random.default_rng(42)\ntheta = rng.uniform(0, 2*np.pi, size=ansatz.num_parameters)\n# Devreyi parametrelerle doldur ve ölçüm ekle\nqc = ansatz.assign_parameters(theta)\nqc_meas = qc.measure_all(inplace=False)\n\n# Sampler ile çalıştır\njob = sampler.run([qc_meas], shots=1024)\nres = job.result()\n# Sonuçları parse et\ntry:\n    counts = res[0].data.meas.get_counts()\nexcept Exception:\n    counts = {\"demo\": 1024}\n\n# En sık 5 bitstring'i göster\ntop = sorted(counts.items(), key=lambda kv: -kv[1])[:5]\nprint(\"\\nTop bitstring'ler (QAOA sim, optimize edilmemiş):\")\nfor bit, cnt in top:\n    print(f\"  {bit}: {cnt}\")\n\n# ── Klasik Brute-Force Referans (küçük n için) ──\nprint(f\"\\n🔹 Klasik brute-force referans (2^{N_PAIRINGS}={2**N_PAIRINGS} aday)...\")\nbest_bf = {\"cost\": np.inf, \"violation\": np.inf, \"x\": None}\nfor bits in itertools.product([0, 1], repeat=N_PAIRINGS):\n    x = np.array(bits, dtype=float)\n    cover = A @ x\n    violation = float(np.abs(cover - 1.0).sum())\n    cost = float(c @ x)\n    if violation < best_bf[\"violation\"] or (violation == best_bf[\"violation\"] and cost < best_bf[\"cost\"]):\n        best_bf = {\"cost\": cost, \"violation\": violation, \"x\": bits}\n\nprint(f\"  Brute-force en iyi: cost={best_bf['cost']:.1f}, violation={best_bf['violation']:.0f}\")\nprint(f\"  x* = {best_bf['x']}\")\n\nprint(\"\\n📌 Sonraki adımlar (üretim):\")\nprint(\"  • COBYLA/SPSA ile QAOA parametre optimizasyonu\")\nprint(\"  • Gerçek pairing sütunlarını (Column Generation) QUBO'ya map\")\nprint(\"  • Hibrit: Klasik MIP master + Quantum pricing subproblem\")\nprint(\"  • Error Mitigation (ZNE) ile HW kernel gürültüsünü azalt\")\nprint(\"✅ AŞAMA 17 tamamlandı.\")\n"
  },
  {
   "cell_type": "markdown",
   "id": "ec444ca7",
   "metadata": {
    "id": "ec444ca7"
   },
   "source": "## 🎯 POC Tamamlandı: Airline Crew Pairing & Rostering\n\n### Mimari Özeti\n| Bileşen | Detay |\n|---------|-------|\n| **Ekosistem** | Salt IBM Qiskit (Runtime, SamplerV2, FidelityKernel) |\n| **Donanım** | IBM QPU (tercih: `ibm_phoenix`) + Aer simülatör yedek |\n| **Algoritma** | QSVC (Fidelity Quantum Kernel) + QAOA (Set-Partitioning) |\n| **Domain** | PDF: FDP, 8-in-24, Deadhead, Base Return, FSC/LCC, IROPS |\n\n### Havacılık Metrik Yorumu\n| Metrik | Operasyonel Anlam |\n|--------|-------------------|\n| **Precision** | \"Uygun\" denilen pairing yasal mı? (FP = regülasyon cezası) |\n| **Recall** | Uygun pairing'leri kaçırmama (FN = esneklik kaybı) |\n| **ROC-AUC** | Genel ayrım gücü |\n\n### Sonraki Adımlar (Üretim)\n1. ✅ Gerçek havayolu CSV verisi ile AŞAMA 7'yi aktif edin\n2. ✅ QAOA parametre optimizasyonu (COBYLA/SPSA)\n3. ✅ Error Mitigation (ZNE, PEC) ile HW kernel iyileştirme\n4. ✅ Wukong API key ile çapraz donanım POC (ayrı notebook)\n5. ✅ Column Generation + Quantum Pricing hibrit mimari\n\n### Kontrol Listesi\n- [ ] IBM Token + Instance doğru mu?\n- [ ] `USE_REAL_HARDWARE=True` iken HW job tamamlandı mı?\n- [ ] Precision operasyon eşiğine uygun mu?\n- [ ] KVKK maskeleme pipeline'da mı?\n- [ ] Sonuç JSON/CSV `OUTPUT_PATH` altında mı?\n\n---\n*Hazırlayan: Applied QML — Airline Crew Pairing (Salt IBM Qiskit)*\n*Ortam: Google Colab · IBM Quantum · 2026*\n"
  }
 ],
 "metadata": {
  "colab": {
   "provenance": []
  },
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}