{
  "cells": [
    {
      "cell_type": "markdown",
      "id": "4ba97b35-a453-42fb-a59a-e9f0c129283f",
      "metadata": {},
      "source": [
        "---\n",
        "title: \"Quantum-Kernel-Training\"\n",
        "description: \"Erstellen Sie ein Qiskit-Muster zur Auswertung von Einträgen in eine Quanten-Kernel-Matrix, die für die binäre Klassifizierung verwendet wird.\"\n",
        "---\n",
        "\n",
        "{/* cspell:ignore mapsto forall */}\n",
        "\n",
        "<span id=\"quantum-kernel-training\" />\n",
        "\n",
        "# Quantum-Kernel-Training\n",
        "\n",
        "*Geschätzte Laufzeit: weniger als eine Minute auf einem Heron- r3 -Prozessor (HINWEIS: Dies ist lediglich eine Schätzung. (Die Laufzeit kann variieren.)*\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "bd3bec67",
      "metadata": {},
      "source": [
        "<span id=\"learning-outcomes\" />\n",
        "\n",
        "## Lernziele\n",
        "\n",
        "* Kernel-Methoden und ihre Anwendungsbereiche\n",
        "* Quantenkerne und wie sie verbesserte Merkmalsräume bieten können\n",
        "* Aufbau von Quantenkern-Schaltungen\n",
        "* So trainiert man einen Quantenkernel mit einem [Qiskit-Muster](/docs/guides/intro-to-patterns) : Zuordnen, Optimieren, Ausführen und Nachbearbeiten\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "ba36136c",
      "metadata": {},
      "source": [
        "<span id=\"prerequisites\" />\n",
        "\n",
        "## Voraussetzungen\n",
        "\n",
        "* Quantenkerne: Warum sie wichtig sind und wie sie in der Praxis eingesetzt werden\n",
        "* [Kovarianten-Quantenkerne für Daten mit Gruppenstruktur](https://arxiv.org/abs/2105.03406) (Artikel)\n",
        "* [Einführung in Quantenkerne und Support-Vektor-Maschinen](https://www.youtube.com/watch?v=GVhCOTzAkCM) (Video)\n",
        "* [Quantenkerne in der Praxis](https://www.youtube.com/watch?v=LmQcSxgINis) (Video)\n",
        "\n",
        "Es ist außerdem hilfreich, über Grundkenntnisse in der Gruppentheorie zu verfügen.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "c2d486a5",
      "metadata": {},
      "source": [
        "<span id=\"background\" />\n",
        "\n",
        "## Hintergrund\n",
        "\n",
        "Kernel-Verfahren sind in Anwendungen des maschinellen Lernens weit verbreitet.\n",
        "In diesem Zusammenhang bezieht sich „Kernel“ auf die Kernel-Matrix oder einzelne Einträge darin.\n",
        "Allgemein gesagt ist ein Kernel ein Ähnlichkeitsmaß zwischen Daten, die in einem hochdimensionalen *Merkmalsraum* kodiert sind, und kann beispielsweise bei Klassifizierungsaufgaben mit Support-Vektor-Maschinen eingesetzt werden.\n",
        "\n",
        "Quantenkernel-Methoden sind solche, bei denen Quantencomputer zur Schätzung eines Kernels eingesetzt werden.\n",
        "Es ist bekannt, dass Quantencomputer Daten in quantenverstärkten Merkmalsräumen kodieren können und damit klassische Entsprechungen effektiv ersetzen.\n",
        "Für $\\vec{x} \\in \\mathbb{R}$ und $\\Psi(\\vec{x}) \\in \\mathbb{R}^{d'}$, typischerweise mit $d' >d$, ist $\\Psi(\\vec{x})$ eine Merkmalskarte, $\\vec{x} \\mapsto \\Psi(\\vec{x})$.\n",
        "Das Ziel von $\\Psi(\\vec{x})$ ist es, Datenkategorien durch eine Hyperfläche voneinander zu trennen.\n",
        "Nimmt man die Vektoren im Merkmalsabbildungsraum als Argumente, so liefert die Kernel-Funktions $K(\\vec{x}, \\vec{y}) = \\langle{\\Psi(\\vec{x}) | \\Psi(\\vec{y}) \\rangle{}}$ ihr Skalarprodukt: $K: \\mathbb{R}^d \\rightarrow$ $\\mathbb{R}^d$.\n",
        "Klassischerweise sind diejenigen Merkmalsabbildungen von Interesse, bei denen die Kernel-Funktion leicht berechnet werden kann;\n",
        "das heißt, wenn das Skalarprodukt im Merkmalsabbildungsraum in Bezug auf die ursprünglichen Datenvektoren ausgedrückt werden kann und $\\Psi(\\vec{x})$ sowie $\\Psi(\\vec{y})$ nicht konstruiert werden müssen.\n",
        "Bei Quantenkerneln erfolgt die Merkmalsabbildung durch einen Quantenschaltkreis, und der Kernel wird anhand der aus dem Schaltkreis abgetasteten Messwahrscheinlichkeiten geschätzt.\n",
        "\n",
        "Dieses Tutorial zeigt, wie man ein Qiskit-Muster erstellt, um Einträge in einer Quantenkernel-Matrix zu bewerten, die für die binäre Klassifizierung verwendet wird.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "ad7bc6f9",
      "metadata": {},
      "source": [
        "<span id=\"requirements\" />\n",
        "\n",
        "## Anforderungen\n",
        "\n",
        "Bevor Sie mit diesem Tutorial beginnen, sollten Sie sicherstellen, dass Sie Folgendes installiert haben:\n",
        "\n",
        "* Qiskit SDK v2.3.1 oder höher, mit [Visual](/docs/api/qiskit/visualization) isierungsunterstützung\n",
        "* Qiskit Runtime v0.44.0 oder später (`pip install qiskit-ibm-runtime`)\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "dfb22142-2377-40bf-801c-b2116f048a9a",
      "metadata": {},
      "source": [
        "<span id=\"setup\" />\n",
        "\n",
        "## Einrichtung\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "4405f2da-ce6e-4b97-960a-bb04730cfb6d",
      "metadata": {},
      "outputs": [],
      "source": [
        "# General Imports and helper functions\n",
        "import urllib.request\n",
        "\n",
        "import pandas as pd\n",
        "import numpy as np\n",
        "import matplotlib.pyplot as plt\n",
        "\n",
        "\n",
        "from qiskit.circuit import Parameter, ParameterVector, QuantumCircuit\n",
        "from qiskit.circuit.library import unitary_overlap\n",
        "from qiskit.primitives import StatevectorSampler\n",
        "from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager\n",
        "\n",
        "from qiskit_ibm_runtime import QiskitRuntimeService, Sampler\n",
        "\n",
        "# Download the dataset (portable across platforms)\n",
        "urllib.request.urlretrieve(\n",
        "    \"https://raw.githubusercontent.com/qiskit-community/prototype-quantum-kernel-training/main/data/dataset_graph7.csv\",\n",
        "    \"dataset_graph7.csv\",\n",
        ")\n",
        "\n",
        "\n",
        "def visualize_counts(res_counts, num_qubits, num_shots):\n",
        "    \"\"\"Visualize the outputs from the Qiskit Sampler primitive.\"\"\"\n",
        "    zero_prob = res_counts.get(0, 0.0)\n",
        "    top_10 = dict(\n",
        "        sorted(res_counts.items(), key=lambda item: item[1], reverse=True)[\n",
        "            :10\n",
        "        ]\n",
        "    )\n",
        "    top_10.update({0: zero_prob})\n",
        "    by_key = dict(sorted(top_10.items(), key=lambda item: item[0]))\n",
        "    x_vals, y_vals = list(zip(*by_key.items()))\n",
        "    x_vals = [bin(x_val)[2:].zfill(num_qubits) for x_val in x_vals]\n",
        "    y_vals_prob = []\n",
        "    for t in range(len(y_vals)):\n",
        "        y_vals_prob.append(y_vals[t] / num_shots)\n",
        "    y_vals = y_vals_prob\n",
        "    plt.bar(x_vals, y_vals)\n",
        "    plt.xticks(rotation=75)\n",
        "    plt.title(\"Results of sampling\")\n",
        "    plt.xlabel(\"Measured bitstring\")\n",
        "    plt.ylabel(\"Probability\")\n",
        "    plt.show()\n",
        "\n",
        "\n",
        "def get_training_data():\n",
        "    \"\"\"Read the training data.\"\"\"\n",
        "    df = pd.read_csv(\"dataset_graph7.csv\", sep=\",\", header=None)\n",
        "    training_data = df.values[:20, :]\n",
        "    ind = np.argsort(training_data[:, -1])\n",
        "    X_train = training_data[ind][:, :-1]\n",
        "\n",
        "    return X_train"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "small-scale-intro",
      "metadata": {},
      "source": [
        "<span id=\"small-scale-simulator-example\" />\n",
        "\n",
        "## Beispiel für einen Simulator im kleinen Maßstab\n",
        "\n",
        "In diesem Abschnitt gehen wir die vier Schritte des Qiskit-Musters anhand einer 7-Qubit-Instanz des Problems „Labeling Cosets with Error“ durch und berechnen einen einzelnen Eintrag der Kernel-Matrix unter Verwendung der `StatevectorSampler` Primitive aus Qiskit. Ein Zustandsvektor-Simulator ist (abgesehen vom Schrotrauschen) exakt und veranschaulicht uns die Methode von Anfang bis Ende, ohne QPU-Zeit zu beanspruchen. Im Abschnitt „Hardware-Beispiele“ wiederholen wir dann denselben Vorgang auf echter Hardware.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "6ddce42e-a365-451d-972d-24c1306ac47b",
      "metadata": {},
      "source": [
        "<span id=\"step-1-map-classical-inputs-to-a-quantum-problem\" />\n",
        "\n",
        "### Schritt 1: Klassische Eingaben einem Quantenproblem zuordnen\n",
        "\n",
        "* Eingabe: Trainingsdatensatz.\n",
        "* Ausgabe: Abstrakte Schaltung zur Berechnung eines Kernelmatrixeintrags.\n",
        "\n",
        "Das Problem der binären Klassifizierung, das wir hier lösen wollen, wird als [*„Fehlerbehaftete Klassifizierung von Nebenklassen*](https://arxiv.org/abs/2105.03406) “ bezeichnet Der Eingabedatensatz für das Training enthält eine Gruppenstruktur, die aus zwei Nebenklassen besteht, die durch eine Gruppe und eine Untergruppe gebildet werden.\n",
        "Als Gruppe wird für Qubits die Gruppe $G = SU(2)^{\\otimes n}$ angenommen, die die spezielle unitäre Gruppe der\n",
        "Matrizen der Form $2 \\times 2$ darstellt und in der Natur weit verbreitet ist, z. B. im Standardmodell der Teilchenphysik.\n",
        "Wir betrachten die (Graph-Stabilisator-)Untergruppe $S_\\text{graph} < G$ mit $S_\\text{graph} = \\langle \\{ X_i \\otimes _{k:(k,i) \\in \\mathcal{E}} Z_k\\} _{i \\in \\mathcal{V}} \\} \\rangle$ für einen Graphen mit Kanten $\\mathcal{E}$ und Knoten $\\mathcal{V}$.\n",
        "Beachte, dass die Stabilisatoren einen Stabilisatorzustand festlegen, sodass $D_s | \\psi \\rangle = | \\psi \\rangle,~ \\forall s \\in S_\\text{graph}$ gilt.\n",
        "Schließlich definieren wir zwei linke Nebenklassen $C_\\pm = c_\\pm S_\\text{graph}$, indem wir zufällig zwei $c_\\pm \\in G$ auswählen.\n",
        "\n",
        "Weitere Informationen zum Datensatz und zu seiner Erstellung finden Sie [in diesem Notebook](https://github.com/qiskit-community/prototype-quantum-kernel-training/blob/main/docs/background/qkernels_and_data_w_group_structure.ipynb) aus dem [Quantum Kernel Training Toolkit](https://github.com/qiskit-community/prototype-quantum-kernel-training/tree/main).\n",
        "\n",
        "Wir erstellen den Quantenschaltkreis, mit dem ein Eintrag in der Kernel-Matrix ausgewertet wird.\n",
        "Die Eingabedaten dienen zur Bestimmung der Drehwinkel für die parametrisierten Gatter der Schaltung.\n",
        "Der Einfachheit halber verwenden wir die Stichproben `x1=14` und `x2=19`.\n",
        "\n",
        "***Hinweis: Der in diesem Lernprogramm verwendete Datensatz kann [hier](https://github.com/qiskit-community/prototype-quantum-kernel-training/blob/main/data/dataset_graph7.csv) heruntergeladen werden.***\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "70d6faff-9a56-44bb-b26f-f573a8c90889",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/quantum-kernel-training/extracted-outputs/70d6faff-9a56-44bb-b26f-f573a8c90889-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 2,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "# Prepare training data\n",
        "X_train = get_training_data()\n",
        "\n",
        "# Empty kernel matrix\n",
        "num_samples = np.shape(X_train)[0]\n",
        "kernel_matrix = np.full((num_samples, num_samples), np.nan)\n",
        "\n",
        "# Prepare feature map for computing overlap\n",
        "num_features = np.shape(X_train)[1]\n",
        "num_qubits = int(num_features / 2)\n",
        "entangler_map = [[0, 2], [3, 4], [2, 5], [1, 4], [2, 3], [4, 6]]\n",
        "fm = QuantumCircuit(num_qubits)\n",
        "training_param = Parameter(\"θ\")\n",
        "feature_params = ParameterVector(\"x\", num_qubits * 2)\n",
        "fm.ry(training_param, fm.qubits)\n",
        "for cz in entangler_map:\n",
        "    fm.cz(cz[0], cz[1])\n",
        "for i in range(num_qubits):\n",
        "    fm.rz(-2 * feature_params[2 * i + 1], i)\n",
        "    fm.rx(-2 * feature_params[2 * i], i)\n",
        "\n",
        "# Assign tunable parameter to known optimal value and set the data params for\n",
        "# first two samples\n",
        "x1 = 14\n",
        "x2 = 19\n",
        "unitary1 = fm.assign_parameters(list(X_train[x1]) + [np.pi / 2])\n",
        "unitary2 = fm.assign_parameters(list(X_train[x2]) + [np.pi / 2])\n",
        "\n",
        "# Create the overlap circuit\n",
        "overlap_circ = unitary_overlap(unitary1, unitary2)\n",
        "overlap_circ.measure_all()\n",
        "overlap_circ.draw(\"mpl\", scale=0.6, style=\"iqp\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "step2-small-md",
      "metadata": {},
      "source": [
        "<span id=\"step-2-optimize-problem-for-quantum-hardware-execution\" />\n",
        "\n",
        "### Schritt 2: Optimierung des Problems für die Ausführung auf Quantenhardware\n",
        "\n",
        "* Eingabe: Abstrakte Schaltung, nicht für ein bestimmtes Backend optimiert.\n",
        "* Ergebnis: Zielschaltung, optimiert für die ausgewählte QPU.\n",
        "\n",
        "Für den in diesem Abschnitt verwendeten Statevector-Simulatorpfad ist keine backend-spezifische Optimierung erforderlich: Die abstrakte Schaltung kann direkt abgetastet werden. `optimization_level=3`Wir wenden diesen Schritt im folgenden Hardware-Beispiel an, bei dem die Schaltung mithilfe von `generate_preset_pass_manager` mit für eine echte QPU transpiliert wird.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "step3-small-md",
      "metadata": {},
      "source": [
        "<span id=\"step-3-execute-using-qiskit-primitives\" />\n",
        "\n",
        "### Schritt 3: Mit „ Qiskit primitives “ ausführen\n",
        "\n",
        "* Eingabe: Abstrakte Schaltung.\n",
        "* Ergebnis: Quasi-Wahrscheinlichkeitsverteilung.\n",
        "\n",
        "Verwenden Sie die `StatevectorSampler` Primitive aus Qiskit, um eine Quasi-Wahrscheinlichkeitsverteilung der Zustände zu rekonstruieren, die sich aus der Stichprobenentnahme aus dem Schaltkreis ergeben. Bei der Erstellung einer Kernelmatrix interessiert uns insbesondere die Wahrscheinlichkeit, den |0>-Zustand zu messen.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 3,
      "id": "step3-small-code",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/quantum-kernel-training/extracted-outputs/step3-small-code-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "sampler = StatevectorSampler()\n",
        "\n",
        "# Execute and get counts\n",
        "num_shots = 10_000\n",
        "results = sampler.run([overlap_circ], shots=num_shots).result()\n",
        "counts = results[0].data.meas.get_int_counts()\n",
        "\n",
        "# Plot counts\n",
        "visualize_counts(counts, num_qubits, num_shots)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "step4-small-md",
      "metadata": {},
      "source": [
        "<span id=\"step-4-post-process-and-return-result-in-desired-classical-format\" />\n",
        "\n",
        "### Schritt 4: Nachbearbeitung und Rückgabe des Ergebnisses im gewünschten klassischen Format\n",
        "\n",
        "* Eingabe: Wahrscheinlichkeitsverteilung.\n",
        "* Ausgabe: Ein einzelnes Element der Kernelmatrix.\n",
        "\n",
        "Berechne die Wahrscheinlichkeit, dass auf dem Überlappungskreis der Wert $|0 \\rangle$ gemessen wird, und trage die Kernelmatrix an der Stelle ein, die den durch diesen bestimmten Überlappungskreis dargestellten Messwerten entspricht (Zeile 15, Spalte 20).\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 4,
      "id": "step4-small-code",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Fidelity (simulator): 0.8261\n"
          ]
        }
      ],
      "source": [
        "kernel_matrix[x1, x2] = counts.get(0, 0.0) / num_shots\n",
        "print(f\"Fidelity (simulator): {kernel_matrix[x1, x2]}\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "large-scale-intro",
      "metadata": {},
      "source": [
        "<span id=\"hardware-example\" />\n",
        "\n",
        "## Beispiel für Hardware\n",
        "\n",
        "Eine Quantenkernel-Matrix hat $\\mathcal{O}(N^2)$ Einträge für $N$ Trainingsbeispiele, und jeder Eintrag erfordert die Ausführung einer Überlappungsschaltung, deren Tiefe an Zwei-Qubit-Gates mit der Größe der Merkmalskarte zunimmt. Folglich sind bei der Skalierung dieses Tutorials auf ein größeres Problem zwei sich verstärkende Kostenfaktoren zu berücksichtigen: Die QPU-Zeit pro Kernel-Matrix wächst quadratisch mit $N$, und die Tiefe von `unitary_overlap` (die die Merkmalskarte mit ihrer Adjunkten vermischt) beeinträchtigt die Genauigkeit bei der Systemgröße und Konnektivität aktueller Hardware. Um die Demo kurz zu halten und einen sauberen Vergleich zu ermöglichen, führen wir daher **dieselbe** 7-Qubit-Instanz aus dem Beispiel im kleinen Maßstab auf einer echten QPU aus und vergleichen die Genauigkeit eines einzelnen Eintrags in der Kernel-Matrix mit dem oben berechneten Simulatorwert.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "d2f4f6cf-067e-4d53-aa04-7ca9c803d3e1",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Using backend: ibm_pittsburgh\n"
          ]
        },
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/quantum-kernel-training/extracted-outputs/d2f4f6cf-067e-4d53-aa04-7ca9c803d3e1-1.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        },
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Fidelity (hardware): 0.7517\n"
          ]
        }
      ],
      "source": [
        "# ------------------------------ Step 1 ------------------------------\n",
        "# Prepare training data\n",
        "X_train = get_training_data()\n",
        "\n",
        "# Empty kernel matrix\n",
        "num_samples = np.shape(X_train)[0]\n",
        "kernel_matrix = np.full((num_samples, num_samples), np.nan)\n",
        "\n",
        "# Prepare feature map for computing overlap\n",
        "num_features = np.shape(X_train)[1]\n",
        "num_qubits = int(num_features / 2)\n",
        "entangler_map = [[0, 2], [3, 4], [2, 5], [1, 4], [2, 3], [4, 6]]\n",
        "fm = QuantumCircuit(num_qubits)\n",
        "training_param = Parameter(\"θ\")\n",
        "feature_params = ParameterVector(\"x\", num_qubits * 2)\n",
        "fm.ry(training_param, fm.qubits)\n",
        "for cz in entangler_map:\n",
        "    fm.cz(cz[0], cz[1])\n",
        "for i in range(num_qubits):\n",
        "    fm.rz(-2 * feature_params[2 * i + 1], i)\n",
        "    fm.rx(-2 * feature_params[2 * i], i)\n",
        "\n",
        "# Assign tunable parameter to known optimal value and\n",
        "# set the data params for first two samples\n",
        "x1 = 14\n",
        "x2 = 19\n",
        "unitary1 = fm.assign_parameters(list(X_train[x1]) + [np.pi / 2])\n",
        "unitary2 = fm.assign_parameters(list(X_train[x2]) + [np.pi / 2])\n",
        "\n",
        "# Create the overlap circuit\n",
        "overlap_circ = unitary_overlap(unitary1, unitary2)\n",
        "overlap_circ.measure_all()\n",
        "\n",
        "# ------------------------------ Step 2 ------------------------------\n",
        "service = QiskitRuntimeService()\n",
        "# backend = service.least_busy(\n",
        "#    operational=True, simulator=False, min_num_qubits=overlap_circ.num_qubits\n",
        "# )\n",
        "backend = service.backend(\"ibm_pittsburgh\")\n",
        "print(f\"Using backend: {backend.name}\")\n",
        "pm = generate_preset_pass_manager(optimization_level=3, backend=backend)\n",
        "overlap_ibm = pm.run(overlap_circ)\n",
        "\n",
        "# ------------------------------ Step 3 ------------------------------\n",
        "sampler = Sampler(mode=backend)\n",
        "sampler.options.environment.job_tags = [\"TUT_QKT\"]\n",
        "\n",
        "num_shots = 10_000\n",
        "results = sampler.run([overlap_ibm], shots=num_shots).result()\n",
        "counts = results[0].data.meas.get_int_counts()\n",
        "visualize_counts(counts, num_qubits, num_shots)\n",
        "\n",
        "# ------------------------------ Step 4 ------------------------------\n",
        "kernel_matrix[x1, x2] = counts.get(0, 0.0) / num_shots\n",
        "print(f\"Fidelity (hardware): {kernel_matrix[x1, x2]}\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "dec33657-9055-4fdc-b146-dba0e5882719",
      "metadata": {},
      "source": [
        "Um die gesamte Kernelmatrix auszufüllen, müssten wir für jeden ihrer $N(N+1)/2$ eindeutigen Einträge ein Quantenexperiment durchführen. Die folgende Abbildung zeigt die resultierende Matrix für diesen Datensatz; ein dunkleres Rot steht für Übereinstimmungen, die näher an 1.0 liegen.\n",
        "\n",
        "![kernel\\_matrix.png](https://quantum.cloud.ibm.com/docs/images/tutorials/quantum-kernel-training/kernel_matrix.avif)\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "6847b837",
      "metadata": {},
      "source": [
        "<span id=\"next-steps\" />\n",
        "\n",
        "## Nächste Schritte\n",
        "\n",
        "<Admonition type=\"tip\" title=\"Empfehlungen\">\n",
        "  Wenn Sie diese Arbeit interessant fanden, könnten Sie auch an folgenden Materialien interessiert sein:\n",
        "\n",
        "  * [Quantum Kernel Training Toolkit](https://github.com/qiskit-community/prototype-quantum-kernel-training/tree/main) – das Prototyp-Repository, auf dem dieses Tutorial basiert\n",
        "  * [Quantum-Kernel-Training für „ Machine Learning “-Anwendungen](https://qiskit-community.github.io/qiskit-machine-learning/tutorials/08_quantum_kernel_trainer.html) – ein Qiskit- Machine Learning -Tutorial, das zeigt, wie man den trainierbaren Parameter trainiert\n",
        "  * [Einführung in das Quanten- Machine Learning](/learning/courses/quantum-machine-learning/introduction) – ein Kurs zum maschinellen Lernen im Quantenbereich\n",
        "  * [Quanten Machine Learning us von IBM Research](https://research.ibm.com/topics/quantum-machine-learning) – ein Überblick über die QML-Forschung unter IBM\n",
        "  * [Kovarianten-Quantenkerne für Daten mit Gruppenstruktur](https://arxiv.org/abs/2105.03406) – der Artikel, auf dem dieses Tutorial basiert\n",
        "</Admonition>\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "id": "a1b8767d",
      "source": "© IBM Corp., 2017-2026"
    }
  ],
  "metadata": {
    "kernelspec": {
      "display_name": "Python 3",
      "language": "python",
      "name": "python3"
    },
    "language_info": {
      "codemirror_mode": {
        "name": "ipython",
        "version": 3
      },
      "file_extension": ".py",
      "mimetype": "text/x-python",
      "name": "python",
      "nbconvert_exporter": "python",
      "pygments_lexer": "ipython3",
      "version": "3"
    },
    "hours": 1,
    "qpuSeconds": 60
  },
  "nbformat": 4,
  "nbformat_minor": 5
}