{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "14b57b3c",
   "metadata": {
    "id": "14b57b3c"
   },
   "source": "# Natrium QML — Hesaplama Notebook'u (Colab: CPU / GPU / Kuantum donanım / Cerebras)\n\n`Natrium_Polatli_Veri_Analizi.ipynb`'nin ürettiği `processed/lithology_long.csv` üzerinde **\"bir sonraki metre yüksek tenardit (≥%45) mi?\"** sınıflandırıcısını, eldeki hesap kaynaklarının en uygun olanında çalıştırır.\n\n## Hangi iş hangi kaynakta?\n\n| İş | En uygun kaynak | Neden |\n|---|---|---|\n| ≤ 14 qubit simülasyon / hızlı deneme | **CPU** `lightning.qubit` | Durum vektörü küçük; GPU çekirdek başlatma maliyeti kazancı yiyor |\n| 16–30 qubit simülasyon + eğitim (ana model, 20 qubit) | **GPU (A100)** `lightning.gpu` (cuQuantum) + adjoint türev | 2²⁰ genlikte CPU örnek başına ~1,2 s; GPU'da on milisaniyeler mertebesi |\n| Eğitilmiş modelin gerçek donanımda doğrulanması | **QPU** (IBM / Braket üzerinden Rigetti-IonQ-IQM / QASM ile Wukong-SaxonQ) | Eğitim QPU'da değil simülatörde yapılır; QPU yalnız test çıkarımı → kuantum süresi dakikalarla sınırlı kalır |\n| Sonuçlardan SWOT + Best/Optimum/Worst senaryo metni (Wisdom AI katmanı) | **Cerebras** inference API | Cerebras LLM çıkarımı/eğitimi için tasarlandı; PennyLane devre simülasyonu çalıştırmaz |\n\n**Bu ortamda ölçülen CPU süreleri** (`lightning.qubit`, 2 vCPU — Colab CPU çalışma zamanıyla aynı sınıf, 3 katman, ileri + adjoint gradyan, ms/örnek):\n\n| qubit | 4 | 8 | 12 | 16 | 18 | 20 |\n|---|---|---|---|---|---|---|\n| ms/örnek | 3,7 | 8,4 | 13,4 | 64,9 | 299 | 1.214 |\n\n→ 20 qubit × ~1.300 örnek × 30 epoch CPU'da ≈ 13 saat. Bu yüzden `COMPUTE=\"auto\"` 16 qubit ve üstünde GPU'yu seçer; GPU süresi aşağıdaki benchmark hücresinde **sizin Colab'ınızda** ölçülür ve eğitim süresi bütçeye göre otomatik ayarlanır.\n\n**Sabit proje yolu:** `~/Documents/Zoom/Natrium_Notebook` (MacBook yerel disk). Jupyter'i bu klasörde açmak için `Jupyter_Baslat.command` dosyasına çift tıklayın. Mac'te CUDA yok → `auto` CPU'yu seçer; ≤ 12–14 qubit yerelde rahat çalışır.\n\n**20 qubit için Colab:** aynı `Zoom/Natrium_Notebook` klasörünü Drive'da `MyDrive/Zoom/Natrium_Notebook` olarak eşitleyin, Çalışma zamanı → **A100 GPU**. Gizli anahtarlar Colab **Secrets** (🔑) panelinden, yerelde ortam değişkenlerinden okunur: `IBM_QUANTUM_TOKEN`, `AWS_ACCESS_KEY_ID`/`AWS_SECRET_ACCESS_KEY`, `CEREBRAS_API_KEY`."
  },
  {
   "cell_type": "markdown",
   "id": "803709d3",
   "metadata": {
    "id": "803709d3"
   },
   "source": "## 1. Ayarlar — hangi kaynağı kullanacağınızı burada seçin"
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "91b85940",
   "metadata": {
    "id": "91b85940",
    "executionInfo": {
     "status": "ok",
     "timestamp": 1793739523112,
     "user_tz": -180,
     "elapsed": 8,
     "user": {
      "displayName": "Joseph Volkan ÖZCAN",
      "userId": "11389530967736397480"
     }
    }
   },
   "outputs": [],
   "source": "import os\n# ---------- Simülasyon / eğitim ----------\nCOMPUTE        = \"auto\"      # \"auto\" | \"cpu\" | \"gpu\"\nN_QUBITS_SIM   = 20          # ana model genişliği (özellik sayısı = qubit sayısı, en fazla 20)\nN_LAYERS_SIM   = 3\nEPOCHS         = 30\nBATCH          = 32\nLR             = 0.05\nMAX_TRAIN_MIN  = 25          # eğitim süre bütçesi (dk); tahmin aşarsa eğitim örneği otomatik azaltılır\nTEST_WELLS     = [\"ÜRT-1\", \"ÜRT-11\", \"ÜRT-16\"]   # kaverna verisi olan kuyular = bağımsız test\nTHR            = 45.0        # tenardit % eşiği\n\n# ---------- Kuantum donanım ----------\nQPU_PROVIDER   = \"dryrun\"    # \"dryrun\" (ücretsiz, shot'lu yerel taklit) | \"ibm\" | \"braket\" | \"qasm\" | None\nQPU_RUN        = True       # True olmadan gerçek QPU'ya iş GÖNDERİLMEZ (kuantum süresi koruması)\nQPU_MAX_WIDTH  = 8           # donanım modeli genişliği (derinlik/gürültü için küçük tutulur)\nQPU_LAYERS     = 2\nQPU_SHOTS      = 2000\nQPU_MAX_SAMPLES = 60         # QPU'da değerlendirilecek test örneği üst sınırı\nIBM_BACKEND    = None        # None → en az meşgul gerçek cihaz; ör. \"ibm_torino\"\nBRAKET_ARN     = \"arn:aws:braket:us-west-1::device/qpu/rigetti/Ankaa-3\"   # kendi cihaz ARN'inizle değiştirin\n\n# ---------- Cerebras (Wisdom AI metin katmanı) ----------\nUSE_CEREBRAS   = False\nCEREBRAS_MODEL = None        # None → hesabınızdaki modellerden otomatik seçilir\n\nSEED = 7\n\n# yalnızca otomatik duman testi için (Colab'da etkisiz)\nif os.environ.get(\"NATRIUM_SMOKE\"):\n    N_QUBITS_SIM, EPOCHS, MAX_TRAIN_MIN, QPU_MAX_SAMPLES = 8, 6, 3, 40"
  },
  {
   "cell_type": "markdown",
   "id": "670d0249",
   "metadata": {
    "id": "670d0249"
   },
   "source": "## 2. Ortam tespiti ve gerekli paketler"
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "c30ba051",
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "c30ba051",
    "executionInfo": {
     "status": "ok",
     "timestamp": 1793739547467,
     "user_tz": -180,
     "elapsed": 17953,
     "user": {
      "displayName": "Joseph Volkan ÖZCAN",
      "userId": "11389530967736397480"
     }
    },
    "outputId": "56f7a22a-6dbe-497f-fd3e-36dc43dac787"
   },
   "outputs": [
    {
     "output_type": "stream",
     "name": "stdout",
     "text": [
      "Tesla T4, 15360 MiB\n",
      "PennyLane 0.45.1 | Colab: True | GPU: True | CPU çekirdek: 8\n"
     ]
    }
   ],
   "source": "import sys, subprocess, importlib, shutil, time, json, glob, warnings\nwarnings.filterwarnings(\"ignore\")\nIN_COLAB = \"google.colab\" in sys.modules\n\ndef pip_install(*pkgs):\n    cmd = [sys.executable, \"-m\", \"pip\", \"install\", \"-q\", *pkgs]\n    import sysconfig   # yalnızca sistem Python'u \"externally managed\" ise (Homebrew/Linux) bayrak ekle\n    if os.path.exists(os.path.join(sysconfig.get_paths()[\"stdlib\"], \"EXTERNALLY-MANAGED\")) and sys.prefix == sys.base_prefix:\n        cmd.append(\"--break-system-packages\")\n    subprocess.run(cmd, check=False)\n\ndef ensure(module, *pkgs):\n    try: importlib.import_module(module)\n    except ImportError: pip_install(*(pkgs or (module,)))\n\nHAS_GPU = shutil.which(\"nvidia-smi\") is not None and subprocess.run([\"nvidia-smi\"], capture_output=True).returncode == 0\nif HAS_GPU:\n    print(subprocess.run([\"nvidia-smi\", \"--query-gpu=name,memory.total\", \"--format=csv,noheader\"], capture_output=True, text=True).stdout.strip())\n\nensure(\"pennylane\", \"pennylane\")\nensure(\"sklearn\", \"scikit-learn\")\nif HAS_GPU and COMPUTE in (\"auto\", \"gpu\"):\n    ensure(\"pennylane_lightning.lightning_gpu_ops\", \"pennylane-lightning-gpu\", \"custatevec-cu12\")\nif QPU_PROVIDER == \"ibm\":    ensure(\"pennylane_qiskit\", \"pennylane-qiskit\", \"qiskit-ibm-runtime\")\nif QPU_PROVIDER == \"braket\": ensure(\"braket\", \"amazon-braket-pennylane-plugin\")\nif USE_CEREBRAS:             ensure(\"openai\", \"openai\")\n\nimport numpy as np, pandas as pd, matplotlib.pyplot as plt\nimport pennylane as qml\nfrom pennylane import numpy as pnp\nprint(f\"PennyLane {qml.__version__} | Colab: {IN_COLAB} | GPU: {HAS_GPU} | CPU çekirdek: {os.cpu_count()}\")\n\ndef secret(name):\n    if IN_COLAB:\n        try:\n            from google.colab import userdata\n            return userdata.get(name)\n        except Exception: pass\n    return os.environ.get(name)"
  },
  {
   "cell_type": "markdown",
   "id": "c2f9f7f0",
   "metadata": {
    "id": "c2f9f7f0"
   },
   "source": "## 3. Veri"
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "d9e37248",
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/",
     "height": 230
    },
    "id": "d9e37248",
    "executionInfo": {
     "status": "error",
     "timestamp": 1793739579225,
     "user_tz": -180,
     "elapsed": 25003,
     "user": {
      "displayName": "Joseph Volkan ÖZCAN",
      "userId": "11389530967736397480"
     }
    },
    "outputId": "5bfdcee1-bac9-42e8-ba6d-f378e37bb192"
   },
   "outputs": [
    {
     "output_type": "stream",
     "name": "stdout",
     "text": [
      "Mounted at /content/drive\n"
     ]
    },
    {
     "output_type": "error",
     "ename": "AssertionError",
     "evalue": "Proje klasörü yok: /content/drive/MyDrive/Zoom/Natrium_Notebook",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mAssertionError\u001b[0m                            Traceback (most recent call last)",
      "\u001b[0;32m/tmp/ipykernel_992/3608126893.py\u001b[0m in \u001b[0;36m<cell line: 0>\u001b[0;34m()\u001b[0m\n\u001b[1;32m      5\u001b[0m     \u001b[0mdrive\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mmount\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"/content/drive\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m;\u001b[0m \u001b[0mZOOM_DIR\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m\"/content/drive/MyDrive/Zoom\"\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m      6\u001b[0m \u001b[0mPROJECT_DIR\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mos\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mpath\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mjoin\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mZOOM_DIR\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m\"Natrium_Notebook\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 7\u001b[0;31m \u001b[0;32massert\u001b[0m \u001b[0mos\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mpath\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0misdir\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mPROJECT_DIR\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34mf\"Proje klasörü yok: {PROJECT_DIR}\"\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m      8\u001b[0m \u001b[0mos\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mchdir\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mPROJECT_DIR\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m      9\u001b[0m \u001b[0mF_LITH\u001b[0m  \u001b[0;34m=\u001b[0m \u001b[0mos\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mpath\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mjoin\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mPROJECT_DIR\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m\"processed\"\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m\"lithology_long.csv\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;31mAssertionError\u001b[0m: Proje klasörü yok: /content/drive/MyDrive/Zoom/Natrium_Notebook"
     ]
    }
   ],
   "source": "# ---- SABİT PROJE YOLU: MacBook ~/Documents/Zoom/Natrium_Notebook ----\nZOOM_DIR = os.environ.get(\"NATRIUM_ZOOM_DIR\", os.path.expanduser(\"~/Documents/Zoom\"))\nif IN_COLAB:   # Colab'da aynı klasör yapısı Drive'da: MyDrive/Zoom/Natrium_Notebook\n    from google.colab import drive\n    drive.mount(\"/content/drive\"); ZOOM_DIR = \"/content/drive/MyDrive/Zoom\"\nPROJECT_DIR = os.path.join(ZOOM_DIR, \"Natrium_Notebook\")\nassert os.path.isdir(PROJECT_DIR), f\"Proje klasörü yok: {PROJECT_DIR}\"\nos.chdir(PROJECT_DIR)\nF_LITH  = os.path.join(PROJECT_DIR, \"processed\", \"lithology_long.csv\")\nassert os.path.exists(F_LITH), f\"{F_LITH} yok — önce Natrium_Polatli_Veri_Analizi.ipynb'yi çalıştırın\"\nRUN_DIR = os.path.join(PROJECT_DIR, \"results\"); os.makedirs(RUN_DIR, exist_ok=True)\nlith = pd.read_csv(F_LITH)\nprint(\"Proje:\", PROJECT_DIR); print(\"Veri :\", F_LITH, \"→\", len(lith), \"aralık,\", lith.well.nunique(), \"kuyu\"); print(\"Sonuç:\", RUN_DIR)"
  },
  {
   "cell_type": "markdown",
   "id": "332b82ef",
   "metadata": {
    "id": "332b82ef"
   },
   "source": "### Özellikler (sızıntısız, en fazla 20)\nHepsi yalnızca **sondaj sırasında bilinen** bilgiden türetilir: cevher tavanından itibaren derinlik ve üstteki aralıkların bileşimi (gecikmeli/lag değerler, kayan ortalamalar). Liste öncelik sırasındadır: donanım `k` qubit'e izin veriyorsa ilk `k` özellik kullanılır (açı kodlaması, 1 özellik = 1 qubit). Ölçekleyici yalnız **eğitim kuyularında** fit edilir."
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "19dd8844",
   "metadata": {
    "id": "19dd8844"
   },
   "outputs": [],
   "source": "FEATURE_PRIORITY = [\n    \"dist_from_top_m\", \"then_lag1\", \"then_lag2\", \"glob_lag1\", \"then_roll3\", \"then_roll5\",\n    \"clay_lag1\", \"then_lag3\", \"glob_then_lag1\", \"then_diff1\", \"then_lag4\", \"then_lag5\",\n    \"glob_lag2\", \"clay_lag2\", \"then_std5\", \"then_max5\", \"glob_clay_lag1\", \"glob_lag3\", \"clay_lag3\", \"depth_abs_m\",\n]\n\ndef build_features(lith, thr):\n    L = lith.sort_values([\"well_no\", \"depth_from\"]).copy(); g = L.groupby(\"well\")\n    L[\"dist_from_top_m\"] = L.depth_mid - g.depth_from.transform(\"min\"); L[\"depth_abs_m\"] = L.depth_mid\n    for k in range(1, 6): L[f\"then_lag{k}\"] = g.thenardite_pct.shift(k)\n    for k in range(1, 4):\n        L[f\"glob_lag{k}\"] = g.glauberite_total_pct.shift(k); L[f\"clay_lag{k}\"] = g.clay_pct.shift(k)\n    L[\"glob_then_lag1\"] = g.glauberite_thenardite_pct.shift(1); L[\"glob_clay_lag1\"] = g.glauberite_clay_pct.shift(1)\n    lags = L[[f\"then_lag{k}\" for k in range(1, 6)]]\n    L[\"then_roll3\"] = lags.iloc[:, :3].mean(axis=1); L[\"then_roll5\"] = lags.mean(axis=1)\n    L[\"then_std5\"] = lags.std(axis=1); L[\"then_max5\"] = lags.max(axis=1); L[\"then_diff1\"] = L.then_lag1 - L.then_lag2\n    L[\"y\"] = (L.thenardite_pct >= thr).astype(int)\n    return L\n\ndef make_dataset(L, n_features, test_wells):\n    feats = FEATURE_PRIORITY[:n_features]\n    ds = L.dropna(subset=feats + [\"thenardite_pct\"]).reset_index(drop=True)\n    te = ds.well.isin(test_wells).to_numpy()\n    X = ds[feats].to_numpy(float); lo, hi = X[~te].min(0), X[~te].max(0)\n    X01 = np.clip((X - lo) / (hi - lo + 1e-9), 0, 1)\n    return dict(ds=ds, feats=feats, X01=X01, Xang=X01*np.pi, y=ds.y.to_numpy(int), te=te, lo=lo, hi=hi)\n\nL = build_features(lith, THR)\nN_QUBITS_SIM = int(min(N_QUBITS_SIM, len(FEATURE_PRIORITY)))\nD = make_dataset(L, N_QUBITS_SIM, TEST_WELLS)\nprint(f\"{N_QUBITS_SIM} özellik: {D['feats']}\")\nprint(f\"örnek {len(D['y'])} | eğitim {(~D['te']).sum()} | test {D['te'].sum()} | pozitif oranı {D['y'].mean():.1%}\")"
  },
  {
   "cell_type": "markdown",
   "id": "2276deff",
   "metadata": {
    "id": "2276deff"
   },
   "source": "## 4. Simülatör seçimi\n`auto`: GPU varsa ve qubit ≥ 16 ise `lightning.gpu`, aksi hâlde `lightning.qubit` (C++ CPU). Türev yöntemi her ikisinde **adjoint** (parametre sayısından bağımsız tek geri geçiş)."
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "068728d5",
   "metadata": {
    "id": "068728d5"
   },
   "outputs": [],
   "source": "GPU_THRESHOLD = 16\ndef pick_sim_device(n_qubits):\n    want_gpu = COMPUTE == \"gpu\" or (COMPUTE == \"auto\" and n_qubits >= GPU_THRESHOLD)\n    if want_gpu and HAS_GPU:\n        try:\n            qml.device(\"lightning.gpu\", wires=2); return \"lightning.gpu\"\n        except Exception as e:\n            print(\"lightning.gpu açılamadı → CPU'ya düşülüyor:\", str(e)[:120])\n    if want_gpu and not HAS_GPU:\n        print(\"⚠ GPU yok (Colab: Çalışma zamanı → A100 GPU). CPU kullanılacak; 20 qubit CPU'da çok yavaş.\")\n    return \"lightning.qubit\"\n\ndef linear_layers(w, n):\n    # donanım dostu ansatz: her katmanda Rot + doğrusal CNOT zinciri (heavy-hex/kare ızgarada SWAP gerektirmez)\n    for l in range(w.shape[0]):\n        for i in range(n): qml.Rot(*w[l, i], wires=i)\n        for i in range(n - 1): qml.CNOT(wires=[i, i + 1])\n\ndef make_circuit(dev, n, ansatz=\"sel\", diff=\"adjoint\"):\n    @qml.qnode(dev, diff_method=diff)\n    def circ(w, x):\n        qml.AngleEmbedding(x, wires=range(n), rotation=\"Y\")\n        if ansatz == \"sel\": qml.StronglyEntanglingLayers(w, wires=range(n))\n        else: linear_layers(w, n)\n        return qml.expval(qml.PauliZ(0))\n    return circ\n\nSIM_DEVICE = pick_sim_device(N_QUBITS_SIM)\nprint(\"Simülatör:\", SIM_DEVICE, \"|\", N_QUBITS_SIM, \"qubit\")"
  },
  {
   "cell_type": "markdown",
   "id": "10e3f831",
   "metadata": {
    "id": "10e3f831"
   },
   "source": "## 5. Benchmark → süre tahmini → bütçeye göre eğitim boyutu"
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "24f4e415",
   "metadata": {
    "id": "24f4e415"
   },
   "outputs": [],
   "source": "def bench_ms_per_sample(circ, shape, n, batch=8, reps=2):\n    w = pnp.array(0.1*np.random.randn(*shape), requires_grad=True)\n    X = pnp.array(np.random.rand(batch, n)*np.pi, requires_grad=False)\n    f = lambda w: pnp.mean((circ(w, X) - 1)**2)\n    qml.grad(f)(w); t = time.time()\n    for _ in range(reps): qml.grad(f)(w)\n    return (time.time() - t) / reps / batch * 1000\n\nsim_dev  = qml.device(SIM_DEVICE, wires=N_QUBITS_SIM)\nsim_circ = make_circuit(sim_dev, N_QUBITS_SIM, \"sel\")\nSIM_SHAPE = qml.StronglyEntanglingLayers.shape(n_layers=N_LAYERS_SIM, n_wires=N_QUBITS_SIM)\nms = bench_ms_per_sample(sim_circ, SIM_SHAPE, N_QUBITS_SIM, batch=8 if N_QUBITS_SIM < 18 else 4, reps=2 if N_QUBITS_SIM < 18 else 1)\nn_train_all = int((~D[\"te\"]).sum())\neta_min = ms * n_train_all * EPOCHS * 1.15 / 60000          # +%15 değerlendirme payı\nN_TRAIN = n_train_all if eta_min <= MAX_TRAIN_MIN else max(64, int(n_train_all * MAX_TRAIN_MIN / eta_min))\nprint(f\"{SIM_DEVICE}: {ms:.1f} ms/örnek | tam eğitim tahmini {eta_min:.1f} dk | bütçe {MAX_TRAIN_MIN} dk → N_TRAIN={N_TRAIN}/{n_train_all}\")"
  },
  {
   "cell_type": "markdown",
   "id": "8e76e427",
   "metadata": {
    "id": "8e76e427"
   },
   "source": "## 6. Eğitim fonksiyonları (sınıf ağırlıklı kayıp, toplu yayın/broadcasting)"
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "0de15e06",
   "metadata": {
    "id": "0de15e06"
   },
   "outputs": [],
   "source": "from sklearn.metrics import accuracy_score, balanced_accuracy_score, roc_auc_score, f1_score\n\ndef predict(circ, w, b, X, chunk=64):\n    return np.concatenate([np.asarray(circ(w, X[i:i+chunk])) + float(b) for i in range(0, len(X), chunk)])\n\ndef metrics(y, score, name):\n    pred = (score > 0).astype(int)\n    return dict(model=name, accuracy=accuracy_score(y, pred), balanced_acc=balanced_accuracy_score(y, pred),\n                f1=f1_score(y, pred, zero_division=0), auc=roc_auc_score(y, score))\n\ndef train_vqc(circ, shape, Xtr, ytr, Xte, yte, epochs, batch, lr, seed, log_every=5, tag=\"\"):\n    rng = np.random.default_rng(seed)\n    w = pnp.array(0.1*rng.standard_normal(shape), requires_grad=True); b = pnp.array(0.0, requires_grad=True)\n    Y = 2*ytr - 1; pos = ytr.mean(); W = np.where(ytr == 1, 0.5/pos, 0.5/(1-pos))\n    def cost(w, b, Xb, Yb, Wb): return pnp.sum(Wb*(Yb - (circ(w, Xb) + b))**2) / pnp.sum(Wb)\n    opt = qml.AdamOptimizer(stepsize=lr); hist = []; t0 = time.time()\n    for ep in range(epochs):\n        perm = rng.permutation(len(Xtr))\n        for i in range(0, len(Xtr), batch):\n            bi = perm[i:i+batch]\n            args = [pnp.array(a, requires_grad=False) for a in (Xtr[bi], Y[bi], W[bi])]\n            w, b, *_ = opt.step(cost, w, b, *args)\n        if ep % log_every == 0 or ep == epochs - 1:\n            m = metrics(yte, predict(circ, w, b, Xte), tag); m.update(epoch=ep, minutes=(time.time()-t0)/60); hist.append(m)\n            print(f\"{tag} epoch {ep:3d} | test bal.acc {m['balanced_acc']:.3f} | AUC {m['auc']:.3f} | {m['minutes']:.1f} dk\")\n    return w, b, pd.DataFrame(hist)"
  },
  {
   "cell_type": "markdown",
   "id": "1cc67394",
   "metadata": {
    "id": "1cc67394"
   },
   "source": "## 7. Ana model: N-qubit VQC (varsayılan 20) simülatörde + klasik karşılaştırma"
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "626f9290",
   "metadata": {
    "id": "626f9290"
   },
   "outputs": [],
   "source": "rng = np.random.default_rng(SEED)\ntr_idx = np.where(~D[\"te\"])[0]; tr_idx = rng.choice(tr_idx, size=min(N_TRAIN, len(tr_idx)), replace=False)\nXtr, ytr = D[\"Xang\"][tr_idx], D[\"y\"][tr_idx]; Xte, yte = D[\"Xang\"][D[\"te\"]], D[\"y\"][D[\"te\"]]\nprint(f\"{SIM_DEVICE} | {N_QUBITS_SIM}q × {N_LAYERS_SIM}L | {int(np.prod(SIM_SHAPE))} parametre | eğitim {len(Xtr)} | test {len(Xte)}\")\nprint(qml.draw(sim_circ, max_length=100, show_matrices=False)(pnp.zeros(SIM_SHAPE), Xtr[0]))\nw_sim, b_sim, hist_sim = train_vqc(sim_circ, SIM_SHAPE, Xtr, ytr, Xte, yte, EPOCHS, BATCH, LR, SEED, tag=f\"SIM-{N_QUBITS_SIM}q\")\nscore_sim = predict(sim_circ, w_sim, b_sim, Xte)"
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "8914f800",
   "metadata": {
    "id": "8914f800"
   },
   "outputs": [],
   "source": "from sklearn.linear_model import LogisticRegression\nfrom sklearn.ensemble import RandomForestClassifier\nrows = [metrics(yte, score_sim, f\"VQC {N_QUBITS_SIM}q ({SIM_DEVICE})\")]\nfor name, mdl in [(\"Lojistik regresyon\", LogisticRegression(max_iter=2000, class_weight=\"balanced\")),\n                  (\"Random forest\", RandomForestClassifier(n_estimators=400, min_samples_leaf=5, class_weight=\"balanced\", random_state=SEED))]:\n    mdl.fit(D[\"X01\"][~D[\"te\"]], D[\"y\"][~D[\"te\"]]); p = mdl.predict_proba(D[\"X01\"][D[\"te\"]])[:, 1]\n    rows.append(metrics(yte, p - 0.5, f\"{name} ({N_QUBITS_SIM} özellik)\"))\nresults = pd.DataFrame(rows).set_index(\"model\").round(3); results"
  },
  {
   "cell_type": "markdown",
   "id": "4d1a61fa",
   "metadata": {
    "id": "4d1a61fa"
   },
   "source": "## 8. Kuantum donanım: kompakt model → QPU çıkarımı\nAna 20-qubit modelin ağırlıkları daha dar bir devreye aktarılamaz; bu yüzden donanım için ayrı, **dar ve sığ** bir model (`QPU_MAX_WIDTH` qubit, doğrusal CNOT zinciri, `QPU_LAYERS` katman) simülatörde eğitilir, ardından **yalnız test örnekleri** QPU'da çalıştırılır. Simülatör (gürültüsüz) ile QPU skorları karşılaştırılarak donanım gürültüsünün sınıflandırmaya etkisi ölçülür.\n\n| `QPU_PROVIDER` | Ne yapar | Gerekli gizli anahtar |\n|---|---|---|\n| `\"dryrun\"` | Aynı devre, `QPU_SHOTS` atışla yerel örnekleme (ücretsiz prova) | — |\n| `\"ibm\"` | IBM Quantum Runtime, `qiskit.remote` cihazı; tüm devreler tek işte | `IBM_QUANTUM_TOKEN` (+ ops. `IBM_INSTANCE`) |\n| `\"braket\"` | Amazon Braket (Rigetti / IonQ / IQM), `BRAKET_ARN` | `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, `AWS_DEFAULT_REGION` |\n| `\"qasm\"` | Her test örneği için OpenQASM 2.0 dosyası (Wukong/Origin, SaxonQ vb. kendi SDK'sıyla gönderim) | — |\n\nAnalog nötr-atom cihazları (QuEra Aquila, Pasqal) kapı tabanlı bu devreyi çalıştırmaz."
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "9725a756",
   "metadata": {
    "id": "9725a756"
   },
   "outputs": [],
   "source": "QPU_W = int(min(QPU_MAX_WIDTH, N_QUBITS_SIM))\nDq = make_dataset(L, QPU_W, TEST_WELLS)\nq_dev  = qml.device(\"lightning.qubit\", wires=QPU_W)          # dar model CPU'da en hızlısı\nq_circ = make_circuit(q_dev, QPU_W, \"linear\")\nQ_SHAPE = (QPU_LAYERS, QPU_W, 3)\nqtr = np.where(~Dq[\"te\"])[0]\nXq_tr, yq_tr = Dq[\"Xang\"][qtr], Dq[\"y\"][qtr]; Xq_te, yq_te = Dq[\"Xang\"][Dq[\"te\"]], Dq[\"y\"][Dq[\"te\"]]\nw_q, b_q, hist_q = train_vqc(q_circ, Q_SHAPE, Xq_tr, yq_tr, Xq_te, yq_te, max(EPOCHS, 20), BATCH, LR, SEED, tag=f\"QPU-model-{QPU_W}q\")\nscore_q_exact = predict(q_circ, w_q, b_q, Xq_te)\nresults.loc[f\"VQC {QPU_W}q donanım-ansatz (gürültüsüz sim)\"] = pd.Series(metrics(yq_te, score_q_exact, \"\")).drop(\"model\").astype(float).round(3)\n\n# QPU'ya gidecek alt küme: sınıf dengeli\nrng = np.random.default_rng(SEED); idx_pos, idx_neg = np.where(yq_te == 1)[0], np.where(yq_te == 0)[0]\nk = min(QPU_MAX_SAMPLES // 2, len(idx_pos), len(idx_neg))\nQIDX = np.sort(np.concatenate([rng.choice(idx_pos, k, replace=False), rng.choice(idx_neg, k, replace=False)]))\ntape = qml.workflow.construct_tape(q_circ)(w_q, Xq_te[0])\nspecs = dict(qubits=QPU_W, gates=len(tape.operations), cnots=sum(op.name == \"CNOT\" for op in tape.operations))\nprint(f\"Donanım devresi: {specs} | QPU'ya gidecek {len(QIDX)} devre × {QPU_SHOTS} shot = {len(QIDX)*QPU_SHOTS:,} atış\")"
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "153fbb0c",
   "metadata": {
    "id": "153fbb0c"
   },
   "outputs": [],
   "source": "def run_on_provider(provider):\n    if provider == \"dryrun\":\n        dev = qml.device(\"default.qubit\", wires=QPU_W)\n        circ = qml.set_shots(make_circuit(dev, QPU_W, \"linear\", diff=None), shots=QPU_SHOTS)\n        return predict(circ, w_q, b_q, Xq_te[QIDX], chunk=len(QIDX)), \"yerel shot'lu taklit\"\n    if provider == \"ibm\":\n        from qiskit_ibm_runtime import QiskitRuntimeService\n        kw = dict(channel=\"ibm_quantum_platform\", token=secret(\"IBM_QUANTUM_TOKEN\"))\n        if secret(\"IBM_INSTANCE\"): kw[\"instance\"] = secret(\"IBM_INSTANCE\")\n        service = QiskitRuntimeService(**kw)\n        backend = service.backend(IBM_BACKEND) if IBM_BACKEND else service.least_busy(operational=True, simulator=False, min_num_qubits=QPU_W)\n        print(\"IBM cihazı:\", backend.name, \"| bekleyen iş:\", backend.status().pending_jobs)\n        dev = qml.device(\"qiskit.remote\", wires=QPU_W, backend=backend)\n        circ = qml.set_shots(make_circuit(dev, QPU_W, \"linear\", diff=None), shots=QPU_SHOTS)\n        return predict(circ, w_q, b_q, Xq_te[QIDX], chunk=len(QIDX)), backend.name\n    if provider == \"braket\":\n        for kname in (\"AWS_ACCESS_KEY_ID\", \"AWS_SECRET_ACCESS_KEY\", \"AWS_DEFAULT_REGION\"):\n            if secret(kname): os.environ[kname] = secret(kname)\n        dev = qml.device(\"braket.aws.qubit\", device_arn=BRAKET_ARN, wires=QPU_W, parallel=True)\n        circ = qml.set_shots(make_circuit(dev, QPU_W, \"linear\", diff=None), shots=QPU_SHOTS)\n        return predict(circ, w_q, b_q, Xq_te[QIDX], chunk=len(QIDX)), BRAKET_ARN.split(\"/\")[-1]\n    raise ValueError(provider)\n\nscore_qpu, qpu_name = None, None\nif QPU_PROVIDER == \"qasm\":\n    qdir = os.path.join(RUN_DIR, \"qasm_export\"); os.makedirs(qdir, exist_ok=True)\n    for j, i in enumerate(QIDX):\n        open(os.path.join(qdir, f\"sample_{j:03d}.qasm\"), \"w\").write(qml.to_openqasm(q_circ, measure_all=True)(w_q, Xq_te[i]))\n    json.dump(dict(bias=float(b_q), readout=\"<Z0> = P(q0=0) - P(q0=1); skor = <Z0> + bias; skor>0 → yüksek tenardit\",\n                   labels=yq_te[QIDX].tolist(), shots=QPU_SHOTS), open(os.path.join(qdir, \"meta.json\"), \"w\"), indent=2)\n    print(len(QIDX), \"QASM dosyası →\", qdir)\nelif QPU_PROVIDER:\n    if QPU_PROVIDER != \"dryrun\" and not QPU_RUN:\n        print(f\"QPU_RUN=False → {QPU_PROVIDER} cihazına iş gönderilmedi. Gönderim için ayarlarda QPU_RUN=True yapın.\")\n    else:\n        t0 = time.time(); score_qpu, qpu_name = run_on_provider(QPU_PROVIDER)\n        print(f\"{qpu_name}: {len(QIDX)} devre {time.time()-t0:.1f} s'de döndü\")\n\nif score_qpu is not None:\n    ref = score_q_exact[QIDX]\n    agree = np.mean((score_qpu > 0) == (ref > 0))\n    results.loc[f\"VQC {QPU_W}q @ {qpu_name} ({len(QIDX)} örnek)\"] = pd.Series(metrics(yq_te[QIDX], score_qpu, \"\")).drop(\"model\").astype(float).round(3)\n    fig, ax = plt.subplots(figsize=(5, 5))\n    ax.scatter(ref, score_qpu, c=yq_te[QIDX], cmap=\"coolwarm\", s=25); ax.axhline(0, color=\"k\", lw=.5); ax.axvline(0, color=\"k\", lw=.5)\n    lim = [min(ref.min(), score_qpu.min())-.1, max(ref.max(), score_qpu.max())+.1]; ax.plot(lim, lim, \"k--\", lw=1)\n    ax.set_xlabel(\"gürültüsüz simülatör skoru\"); ax.set_ylabel(f\"{qpu_name} skoru\"); ax.set_title(f\"Karar uyumu: %{100*agree:.0f}\")\n    plt.tight_layout(); plt.savefig(os.path.join(RUN_DIR, \"qpu_vs_sim.png\")); plt.show()\nresults"
  },
  {
   "cell_type": "markdown",
   "id": "4dae1cdd",
   "metadata": {
    "id": "4dae1cdd"
   },
   "source": "## 9. Karşılaştırma ve kayıt"
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "0ae7f85f",
   "metadata": {
    "id": "0ae7f85f"
   },
   "outputs": [],
   "source": "fig, axes = plt.subplots(1, 2, figsize=(13, 4))\nfor h, lab in [(hist_sim, f\"SIM {N_QUBITS_SIM}q\"), (hist_q, f\"donanım-ansatz {QPU_W}q\")]:\n    axes[0].plot(h.epoch, h.balanced_acc, \"o-\", label=lab)\naxes[0].set_xlabel(\"epoch\"); axes[0].set_ylabel(\"test balanced acc.\"); axes[0].legend(); axes[0].set_title(\"Eğitim seyri (test kuyuları)\")\nresults[[\"balanced_acc\", \"auc\"]].plot.barh(ax=axes[1]); axes[1].set_xlim(0, 1); axes[1].invert_yaxis(); axes[1].set_title(\"Test kuyuları: \" + \", \".join(TEST_WELLS))\nplt.tight_layout(); plt.savefig(os.path.join(RUN_DIR, \"comparison.png\")); plt.show()\n\nstamp = time.strftime(\"%Y%m%d_%H%M\")\nrun = dict(timestamp=stamp, compute=dict(sim_device=SIM_DEVICE, gpu=HAS_GPU, ms_per_sample=round(ms, 2), n_train=int(len(Xtr))),\n           sim=dict(n_qubits=N_QUBITS_SIM, layers=N_LAYERS_SIM, features=D[\"feats\"], epochs=EPOCHS),\n           qpu=dict(provider=QPU_PROVIDER, device=qpu_name, width=QPU_W, layers=QPU_LAYERS, shots=QPU_SHOTS, n_circuits=int(len(QIDX)), circuit=specs),\n           threshold_pct=THR, test_wells=TEST_WELLS, results=results.reset_index().to_dict(orient=\"records\"))\njson.dump(run, open(os.path.join(RUN_DIR, f\"run_{stamp}.json\"), \"w\"), ensure_ascii=False, indent=2)\nnp.savez(os.path.join(RUN_DIR, f\"weights_{stamp}.npz\"), w_sim=np.asarray(w_sim), b_sim=float(b_sim), w_qpu=np.asarray(w_q), b_qpu=float(b_q),\n         feats_sim=np.array(D[\"feats\"]), feats_qpu=np.array(Dq[\"feats\"]), lo_sim=D[\"lo\"], hi_sim=D[\"hi\"], lo_qpu=Dq[\"lo\"], hi_qpu=Dq[\"hi\"])\nprint(\"Kaydedildi →\", RUN_DIR); results"
  },
  {
   "cell_type": "markdown",
   "id": "e15c8d05",
   "metadata": {
    "id": "e15c8d05"
   },
   "source": "## 10. (İsteğe bağlı) Cerebras: sonuçlardan SWOT + Best / Optimum / Worst senaryo — Wisdom AI katmanı\nModel sonuçlarını, tubing aralığı kararı için yöneticiye yönelik SWOT ve üç senaryoya dönüştürür. `USE_CEREBRAS=True` ve `CEREBRAS_API_KEY` gerekir. Çıktı bir **karar önerisi taslağıdır**; saha mühendisliği onayı olmadan uygulanmamalıdır."
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "2b2914be",
   "metadata": {
    "id": "2b2914be"
   },
   "outputs": [],
   "source": "if USE_CEREBRAS:\n    from openai import OpenAI\n    client = OpenAI(base_url=\"https://api.cerebras.ai/v1\", api_key=secret(\"CEREBRAS_API_KEY\"))\n    available = [m.id for m in client.models.list().data]\n    model = CEREBRAS_MODEL or next((m for pref in (\"gpt-oss\", \"qwen\", \"llama\") for m in available if pref in m.lower()), available[0])\n    print(\"Cerebras modelleri:\", available, \"→\", model)\n    prompt = f'''Koyuncu Grubu Polatlı sodyum sülfat çözelti madenciliği sahası için karar destek raporu yaz (Türkçe).\nKarar konusu: Kaverna sirkülasyon (tubing) aralığının yukarı taşınması ve yeni kuyularda tubing konumunun karot tamamlanmadan belirlenmesi.\nModel: sondaj sırasında bir sonraki metrenin yüksek tenardit (>= %{THR:.0f}) olup olmayacağını tahmin eden kuantum/klasik sınıflandırıcılar.\nSonuçlar (bağımsız test kuyuları {TEST_WELLS}): {results.reset_index().to_dict(orient=\"records\")}\nBilinen saha bulguları: zengin tenardit bantları ~180-195 m ve ~205-230 m; mevcut sirkülasyon aralıkları karotun alt kısmında (%30-40 tenardit);\nÜRT-16 69 günde 24 °Bé, ÜRT-1 154 günde 19 °Bé; hedef 24-25 °Bé.\nİstenen çıktı: 1) SWOT (her başlıkta 3 madde), 2) Best / Optimum / Worst senaryo (varsayımlar, beklenen Bomé etkisi, risk),\n3) kural motoruna (ERP/CRM) aktarılabilecek 3 somut IF-THEN kuralı. Modelin doğruluk sınırlarını açıkça belirt; sayı uydurma.'''\n    resp = client.chat.completions.create(model=model, messages=[{\"role\": \"user\", \"content\": prompt}], temperature=0.3)\n    report = resp.choices[0].message.content\n    open(os.path.join(RUN_DIR, f\"wisdom_swot_{stamp}.md\"), \"w\", encoding=\"utf-8\").write(report)\n    from IPython.display import Markdown, display; display(Markdown(report))\nelse:\n    print(\"USE_CEREBRAS=False — atlandı.\")"
  }
 ],
 "metadata": {
  "accelerator": "GPU",
  "colab": {
   "gpuType": "T4",
   "provenance": [],
   "machine_shape": "hm"
  },
  "kernelspec": {
   "display_name": "Python 3",
   "name": "python3"
  },
  "language_info": {
   "name": "python"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}