{
  "cells": [
    {
      "cell_type": "markdown",
      "id": "24576595",
      "metadata": {},
      "source": [
        "---\n",
        "title: \"Quantenkerne mit fraktionalen Gattern\"\n",
        "description: \"Verwenden Sie fraktionale Gatter – parametrisierte Gatter, die Rotationen um beliebige Winkel direkt ausführen –, um die Tiefe und Dauer von Quantenkern-Schaltkreisen zu reduzieren.\"\n",
        "---\n",
        "\n",
        "<span id=\"quantum-kernels-with-fractional-gates\" />\n",
        "\n",
        "# Quantenkerne mit fraktionalen Gattern\n",
        "\n",
        "*Geschätzte Nutzungsdauer: unter 30 Sekunden auf einem Heron r2 Prozessor (HINWEIS: Dies ist nur eine Schätzung. Ihre Laufzeit kann variieren.)*\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "983da41e",
      "metadata": {},
      "source": [
        "<span id=\"learning-outcomes\" />\n",
        "\n",
        "## Lernziele\n",
        "\n",
        "* Was sind „Fractional Gates“ und wie reduzieren sie die Schaltungstiefe und die Ausführungsdauer auf den QPUs v IBM®?\n",
        "* Die mit der Verwendung von Fractional-Gates verbundenen Einschränkungen (insbesondere der RZZ-Winkelbereich)\n",
        "* So erstellen Sie einen Quantum-Kernel-Workflow, der fraktionale Gatter mit dem „ IBM Quantum “-Compute-Service nutzt\n",
        "* Wie man Metriken zur Hardware-Ausführung (Tiefe, Dauer, Anzahl nicht-lokaler Gatter, Genauigkeit) mit und ohne fraktionierte Gatter vergleicht\n",
        "* Wie man ausschließlich fraktionierte RX-Gates verwendet und dabei den Standard-Workflow von Qiskit beibehält\n",
        "\n",
        "<span id=\"prerequisites\" />\n",
        "\n",
        "## Voraussetzungen\n",
        "\n",
        "* Der [Qiskit-Patterns](/docs/guides/intro-to-patterns) -Workflow\n",
        "* Leitfaden zu den [Fractional-Gates](/docs/guides/fractional-gates)\n",
        "* Das Tutorial [zum Training von Quantenkernen](/docs/tutorials/quantum-kernel-training) und die Lektion [zu Quantenkernen](/learning/courses/quantum-machine-learning/quantum-kernel-methods) im Kurs „Quanten-Maschinelles Lernen“\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "155eab76",
      "metadata": {},
      "source": [
        "<span id=\"background\" />\n",
        "\n",
        "## Hintergrund\n",
        "\n",
        "<span id=\"fractional-gates-on-ibm-qpus\" />\n",
        "\n",
        "### Fractional Gates auf QPUs v IBM\n",
        "\n",
        "Fraktionale Gatter sind parametrisierte Quantengatter, die die direkte Ausführung von Drehungen mit beliebigen Winkeln (innerhalb bestimmter Grenzen) ermöglichen,\n",
        "wodurch die Notwendigkeit entfällt, diese in mehrere Basisgatter zu zerlegen.\n",
        "Durch die Nutzung der nativen Wechselwirkungen zwischen physikalischen Qubits lassen sich bestimmte unitäre Operationen auf der Hardware effizienter umsetzen.\n",
        "\n",
        "IBM Quantum® Heron QPUs unterstützen die folgenden fraktionalen Gatter:\n",
        "\n",
        "* $R_{ZZ}(\\theta)$ für $0 < \\theta < \\pi / 2$\n",
        "* $R_X(\\theta)$ für jeden realen Wert $\\theta$\n",
        "\n",
        "Diese Gatter können sowohl die Tiefe als auch die Dauer von Quantenschaltungen erheblich reduzieren.\n",
        "Sie sind besonders vorteilhaft bei Anwendungen, die sich stark auf $R_{ZZ}$ und $R_X$ stützen, wie die Hamilton-Simulation, der Quantum Approximate Optimization Algorithm (QAOA) und Quantenkernverfahren.\n",
        "In diesem Tutorium konzentrieren wir uns auf den Quantenkernel als praktisches Beispiel.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "fe5675f3",
      "metadata": {},
      "source": [
        "<span id=\"limitations\" />\n",
        "\n",
        "### Einschränkungen\n",
        "\n",
        "Fractional Gates sind derzeit eine experimentelle Funktion, die mit einigen Einschränkungen verbunden ist:\n",
        "\n",
        "* $R_{ZZ}$ ist auf Winkel im Bereich $0 < \\theta < \\pi / 2$ beschränkt.\n",
        "* Die Verwendung von gebrochenen Gattern wird nicht unterstützt für [dynamische Schaltungen](/docs/guides/classical-feedforward-and-control-flow), [Pauli-Twirling](/docs/guides/error-mitigation-and-suppression-techniques#pauli-twirling), [probabilistische Fehlerauslöschung](/docs/guides/error-mitigation-and-suppression-techniques#probabilistic-error-cancellation-pec) (PEC) und [rauschfreie Extrapolation](/docs/guides/error-mitigation-and-suppression-techniques#zero-noise-extrapolation-zne) (ZNE) (unter Verwendung [probabilistischer Fehlerverstärkung](/docs/guides/error-mitigation-and-suppression-techniques#probabilistic-error-amplification-pea) (PEA)).\n",
        "\n",
        "Fractional Gates erfordern einen anderen Arbeitsablauf als der Standardansatz.\n",
        "In diesem Tutorium wird anhand einer praktischen Anwendung erklärt, wie man mit gebrochenen Gattern arbeitet.\n",
        "\n",
        "Im Folgenden finden Sie weitere Einzelheiten zu Fractional Gates.\n",
        "\n",
        "* [Fractional Gates](/docs/guides/fractional-gates)\n",
        "* [Wann sollten fraktionierte Gates *nicht* verwendet werden?](/docs/guides/fractional-gates#when-not-to-use)\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "a4bdab87",
      "metadata": {},
      "source": [
        "<span id=\"workflow-approaches-for-the-rzz-angle-constraint\" />\n",
        "\n",
        "### Workflow-Ansätze für die RZZ-Winkelbeschränkung\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "db213506",
      "metadata": {},
      "source": [
        "Der Arbeitsablauf für die Verwendung von Fractional Gates folgt im Allgemeinen dem [Qiskit-Patterns](/docs/guides/intro-to-patterns) -Workflow.\n",
        "Der wesentliche Unterschied besteht darin, dass alle RZZ-Winkel die Nebenbedingung „ $0 < \\theta \\leq \\pi/2$ “ erfüllen müssen.\n",
        "Es gibt zwei Ansätze, um sicherzustellen, dass diese Bedingung erfüllt ist, wie wir im Folgenden erläutern werden. Wir empfehlen den zweiten Ansatz und veranschaulichen ihn in diesem Tutorial anhand eines Beispiels, das von der Quantenkernel-Methode inspiriert ist.\n",
        "Um besser zu verstehen, in welchen Bereichen Quantenkerne voraussichtlich nützlich sein könnten, empfehlen wir die Lektüre [von Liu, Arunachalam & Temme (2021)](https://www.nature.com/articles/s41567-021-01287-z).\n",
        "\n",
        "Sie können auch das Tutorial [zum Quantum-Kernel-Training](/docs/tutorials/quantum-kernel-training) und die Lektion [zu Quantum-Kerneln](/learning/courses/quantum-machine-learning/quantum-kernel-methods) im Kurs „Quantum Machine Learning“ auf IBM Quantum® Learning durcharbeiten.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "5797ed7e",
      "metadata": {},
      "source": [
        "<span id=\"1-generate-parameter-values-that-satisfy-the-rzz-angle-constraint\" />\n",
        "\n",
        "#### 1. Generieren Sie Parameterwerte, die die RZZ-Winkelbeschränkung erfüllen\n",
        "\n",
        "Wenn Sie sicher sind, dass alle RZZ-Winkel innerhalb des gültigen Bereichs liegen, können Sie den Standardarbeitsablauf für Qiskit-Muster befolgen.\n",
        "In diesem Fall übermitteln Sie die Parameterwerte einfach als Teil einer PUB. Der Arbeitsablauf läuft folgendermaßen ab.\n",
        "\n",
        "```python\n",
        "pm = generate_preset_pass_manager(backend=backend, ...)\n",
        "t_circuit = pm.run(circuit)\n",
        "t_observable = observable.apply_layout(t_circuit.layout)\n",
        "sampler.run([(t_circuit, parameter_values)])\n",
        "estimator.run([(t_circuit, t_observable, parameter_values)])\n",
        "```\n",
        "\n",
        "Wenn Sie versuchen, ein PUB zu übermitteln, das ein RZZ-Tor mit einem Winkel außerhalb des gültigen Bereichs enthält, erhalten Sie eine Fehlermeldung wie diese:\n",
        "\n",
        "```\n",
        "'The instruction rzz is supported only for angles in the range [0, pi/2], but an angle (20.0) outside of this range has been requested; via parameter value(s) γ[0]=10.0, substituted in parameter expression 2.0*γ[0].'\n",
        "```\n",
        "\n",
        "Um diesen Fehler zu vermeiden, wenden Sie die zweite, im Folgenden beschriebene Vorgehensweise an.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "d3e00f37",
      "metadata": {},
      "source": [
        "<span id=\"2-assign-parameter-values-to-circuits-before-transpilation\" />\n",
        "\n",
        "#### 2. Weisen Sie den Schaltkreisen vor der Transpilation Parameterwerte zu\n",
        "\n",
        "Das `qiskit-ibm-runtime` Paket bietet einen speziellen Transpiler-Durchlauf namens [`FoldRzzAngle`](/docs/api/qiskit-ibm-runtime/transpiler-passes-fold-rzz-angle).\n",
        "Dieser Durchlauf transformiert Quantenschaltungen so, dass alle RZZ-Winkel die RZZ-Winkelbeschränkung erfüllen.\n",
        "`transpile`Wenn Sie das Backend für `generate_preset_pass_manager` oder bereitstellen, wendet `FoldRzzAngle` Qiskit automatisch auf die Quantenschaltungen an.\n",
        "Bei diesem Ansatz müssen Sie den Quantenschaltungen vor der Transpilierung Parameterwerte zuweisen.\n",
        "Der Arbeitsablauf verläuft wie folgt.\n",
        "\n",
        "```python\n",
        "pm = generate_preset_pass_manager(backend=backend, ...)\n",
        "b_circuit = circuit.assign_parameters(parameter_values)\n",
        "t_circuit = pm.run(b_circuit)\n",
        "t_observable = observable.apply_layout(t_circuit.layout)\n",
        "sampler.run([(t_circuit,)])\n",
        "estimator.run([(t_circuit, t_observable)])\n",
        "```\n",
        "\n",
        "Beachten Sie, dass dieser Arbeitsablauf einen höheren Rechenaufwand verursacht als der erste Ansatz, da dabei den Quantenschaltungen Parameterwerte zugewiesen und die mit Parametern versehenen Schaltungen lokal gespeichert werden müssen.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "b7cb1bd2",
      "metadata": {},
      "source": [
        "<Admonition type=\"caution\">\n",
        "  **Beachten Sie ein bekanntes Problem unter `qiskit-ibm-runtime`v0.47.0,** bei dem in bestimmten Szenarien RZZ-Gates mit ungültigen Winkeln auch nach der Transpilierung in den Schaltkreisen verbleiben können.\n",
        "\n",
        "  Unter [qiskit-ibm-runtime#2441](https://github.com/Qiskit/qiskit-ibm-runtime/issues/2441) können Sie den Fortschritt in dieser Angelegenheit verfolgen.\n",
        "  Bis zur Behebung des Problems empfehlen wir folgende Abhilfe.\n",
        "\n",
        "  ```python\n",
        "  pm = generate_preset_pass_manager(backend=backend, ...)\n",
        "  pm.post_optimization = PassManager(\n",
        "      [\n",
        "          FoldRzzAngle(),\n",
        "          Optimize1qGatesDecomposition(target=backend.target),\n",
        "          RemoveIdentityEquivalent(target=backend.target),\n",
        "      ]\n",
        "  )\n",
        "  ... = pm.run(...)\n",
        "  ```\n",
        "</Admonition>\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "aaa153e7",
      "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.0 oder später, mit [Visual](/docs/api/qiskit/visualization) isierungsunterstützung\n",
        "* Qiskit Runtime v0.41 oder später (`pip install qiskit-ibm-runtime`)\n",
        "* Qiskit Aer v0.17 oder höher (`pip install qiskit-aer`)\n",
        "* Qiskit Basis Constructor (`pip install qiskit_basis_constructor`)\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "5f43ce5d",
      "metadata": {},
      "source": [
        "<span id=\"setup\" />\n",
        "\n",
        "## Einrichtung\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 1,
      "id": "a6a15694",
      "metadata": {},
      "outputs": [],
      "source": [
        "import matplotlib.pyplot as plt\n",
        "import numpy as np\n",
        "from qiskit import QuantumCircuit, generate_preset_pass_manager\n",
        "from qiskit.circuit import ParameterVector\n",
        "from qiskit.circuit.library import UGate, n_local, unitary_overlap\n",
        "from qiskit.transpiler import Target, PassManager\n",
        "from qiskit.transpiler.passes import (\n",
        "    Optimize1qGatesDecomposition,\n",
        "    RemoveIdentityEquivalent,\n",
        ")\n",
        "from qiskit_aer.primitives import SamplerV2 as AerSampler\n",
        "from qiskit_basis_constructor import DEFAULT_EQUIVALENCE_LIBRARY\n",
        "from qiskit_ibm_runtime import QiskitRuntimeService, SamplerV2\n",
        "from qiskit_ibm_runtime.transpiler.passes import FoldRzzAngle"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "3e94382d",
      "metadata": {},
      "source": [
        "<span id=\"enable-fractional-gates-and-check-basis-gates\" />\n",
        "\n",
        "### Fraktionale Gatter aktivieren und Basisgatter überprüfen\n",
        "\n",
        "Um gebrochene Gatter zu verwenden, können Sie ein Backend erhalten, das diese unterstützt, indem Sie die Option `use_fractional_gates=True` setzen.\n",
        "Wenn das Backend gebrochene Gatter unterstützt, werden Sie `rzz` und `rx` unter den Basisgattern finden.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 2,
      "id": "fd577102",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Backend: ibm_marrakesh\n",
            "No fractional gates: ['cz', 'id', 'rz', 'sx', 'x']\n",
            "With fractional gates: ['cz', 'id', 'rx', 'rz', 'rzz', 'sx', 'x']\n"
          ]
        }
      ],
      "source": [
        "service = QiskitRuntimeService()\n",
        "backend = service.least_busy(\n",
        "    operational=True, simulator=False, min_num_qubits=133\n",
        ")  # backend should be a heron device or later\n",
        "backend_name = backend.name\n",
        "backend_c = service.backend(backend_name)  # w/o fractional gates\n",
        "backend_f = service.backend(\n",
        "    backend_name, use_fractional_gates=True\n",
        ")  # w/ fractional gates\n",
        "print(f\"Backend: {backend_name}\")\n",
        "print(f\"No fractional gates: {backend_c.basis_gates}\")\n",
        "print(f\"With fractional gates: {backend_f.basis_gates}\")\n",
        "if \"rzz\" not in backend_f.basis_gates:\n",
        "    print(f\"Backend {backend_name} does not support fractional gates\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "3f11c5a3",
      "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-Patterns](/docs/guides/intro-to-patterns) -Workflows auf einem Simulator durch und verwenden dabei die Quantenkernel-Schaltung als praktisches Beispiel.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "7bfd6a97",
      "metadata": {},
      "source": [
        "<span id=\"step-1-map-classical-inputs-to-a-quantum-problem\" />\n",
        "\n",
        "### Schritt 1: Klassische Eingaben auf ein Quantenproblem abbilden\n",
        "\n",
        "<span id=\"quantum-kernel-circuit\" />\n",
        "\n",
        "#### Quanten-Kernel-Schaltung\n",
        "\n",
        "In diesem Abschnitt wird die Quantenkernschaltung mit RZZ-Gattern untersucht, um den Arbeitsablauf für fraktionale Gatter vorzustellen.\n",
        "\n",
        "Wir beginnen mit der Konstruktion eines Quantenschaltkreises zur Berechnung der einzelnen Einträge der Kernelmatrix.\n",
        "Dies geschieht durch die Kombination von ZZ-Merkmalskreisen mit einer einheitlichen Überlappung.\n",
        "Die Kernel-Funktion nimmt Vektoren im Merkmalsraum auf und gibt ihr inneres Produkt als einen Eintrag der Kernel-Matrix zurück: $K(x, y) = \\langle \\Phi(x) | \\Phi(y) \\rangle,$ wobei $|\\Phi(x)\\rangle$ für den Quantenzustand steht, der durch die Merkmale abgebildet wird.\n",
        "\n",
        "Wir bauen manuell eine ZZ-Feature-Map-Schaltung unter Verwendung von RZZ-Gattern auf.\n",
        "`zz_feature_map`Obwohl Qiskit eine integrierte Funktion bereitstellt, werden RZZ-Gatter zum Stand von Qiskit v2.4.1 derzeit noch nicht unterstützt ( [siehe Issue](https://github.com/Qiskit/qiskit/issues/14469) ).\n",
        "\n",
        "Als nächstes berechnen wir die Kernel-Funktion für identische Eingaben - zum Beispiel $K(x, x) = 1$. Auf verrauschten Quantencomputern kann dieser Wert aufgrund von Rauschen kleiner als 1 sein.\n",
        "Ein Ergebnis, das näher bei 1 liegt, deutet auf ein geringeres Rauschen in der Ausführung hin.\n",
        "In diesem Lernprogramm wird dieser Wert als *Treue* bezeichnet und wie folgt definiert $\\text{fidelity} = K(x, x).$\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 3,
      "id": "e7d5b52a",
      "metadata": {},
      "outputs": [],
      "source": [
        "optimization_level = 2\n",
        "shots = 2000\n",
        "reps = 3\n",
        "rng = np.random.default_rng(seed=123)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 4,
      "id": "2e9ab33d",
      "metadata": {},
      "outputs": [],
      "source": [
        "def my_zz_feature_map(num_qubits: int, reps: int = 1) -> QuantumCircuit:\n",
        "    x = ParameterVector(\"x\", num_qubits * reps)\n",
        "    qc = QuantumCircuit(num_qubits)\n",
        "    qc.h(range(num_qubits))\n",
        "    for k in range(reps):\n",
        "        K = k * num_qubits\n",
        "        for i in range(num_qubits):\n",
        "            qc.rz(x[i + K], i)\n",
        "        pairs = [(i, i + 1) for i in range(num_qubits - 1)]\n",
        "        for i, j in pairs[0::2] + pairs[1::2]:\n",
        "            qc.rzz((np.pi - x[i + K]) * (np.pi - x[j + K]), i, j)\n",
        "    return qc\n",
        "\n",
        "\n",
        "def quantum_kernel(num_qubits: int, reps: int = 1) -> QuantumCircuit:\n",
        "    qc = my_zz_feature_map(num_qubits, reps=reps)\n",
        "    inner_product = unitary_overlap(qc, qc, \"x\", \"y\", insert_barrier=True)\n",
        "    inner_product.measure_all()\n",
        "    return inner_product\n",
        "\n",
        "\n",
        "def random_parameters(inner_product: QuantumCircuit) -> np.ndarray:\n",
        "    return np.tile(rng.random(inner_product.num_parameters // 2), 2)\n",
        "\n",
        "\n",
        "def fidelity(result) -> float:\n",
        "    ba = result.data.meas\n",
        "    return ba.get_int_counts().get(0, 0) / ba.num_shots"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "f676ff81",
      "metadata": {},
      "source": [
        "Für Systeme mit 4 bis 40 Qubits werden Quantenkernschaltungen und die entsprechenden Parameterwerte generiert und anschließend deren Treue bewertet.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 5,
      "id": "24116973",
      "metadata": {},
      "outputs": [],
      "source": [
        "qubits = list(range(4, 12, 2))\n",
        "circuits = [quantum_kernel(i, reps=reps) for i in qubits]\n",
        "params = [random_parameters(circ) for circ in circuits]"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "30a7c442",
      "metadata": {},
      "source": [
        "Die Vier-Qubit-Schaltung ist unten abgebildet.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 6,
      "id": "b3d6341a",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/fractional-gates/extracted-outputs/b3d6341a-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 6,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "circuits[0].draw(\"mpl\", fold=-1)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "07f31cbe",
      "metadata": {},
      "source": [
        "Im Standardarbeitsablauf von Qiskit Patterns werden die Parameterwerte normalerweise als Teil eines PUB an das Sampler- oder Estimator-Primitiv übergeben.\n",
        "Wenn jedoch ein Backend verwendet wird, das gebrochene Gatter unterstützt, müssen diese Parameterwerte dem Quantenschaltkreis vor der Transpilierung explizit zugewiesen werden.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 7,
      "id": "6c9c1977",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/fractional-gates/extracted-outputs/6c9c1977-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 7,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "b_qc = [\n",
        "    circ.assign_parameters(param) for circ, param in zip(circuits, params)\n",
        "]\n",
        "b_qc[0].draw(\"mpl\", fold=-1)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "7513072b",
      "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"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "804ba317",
      "metadata": {},
      "source": [
        "Anschließend wird die Schaltung mit Hilfe des Pass-Managers nach dem üblichen Qiskit-Muster umgesetzt.\n",
        "Durch die Bereitstellung eines Backends, das gebrochene Gates unterstützt, an `generate_preset_pass_manager` ist automatisch ein spezieller Pass namens `FoldRzzAngle` enthalten.\n",
        "Mit diesem Durchgang wird die Schaltung so verändert, dass sie die RZZ-Winkelvorgaben erfüllt.\n",
        "Infolgedessen werden die RZZ-Gatter mit negativen Werten in der vorherigen Abbildung in positive Werte umgewandelt, und es werden einige zusätzliche X-Gatter hinzugefügt.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 8,
      "id": "6054bdea",
      "metadata": {},
      "outputs": [],
      "source": [
        "backend_f = service.backend(name=backend_name, use_fractional_gates=True)\n",
        "# pm_f includes `FoldRzzAngle` pass\n",
        "pm_f = generate_preset_pass_manager(\n",
        "    optimization_level=optimization_level, backend=backend_f\n",
        ")\n",
        "pm_f.post_optimization = PassManager(\n",
        "    [\n",
        "        FoldRzzAngle(),\n",
        "        Optimize1qGatesDecomposition(target=backend_f.target),\n",
        "        RemoveIdentityEquivalent(target=backend_f.target),\n",
        "    ]\n",
        ")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 9,
      "id": "a18e5c70",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "OrderedDict({'rz': 35, 'rzz': 18, 'x': 13, 'rx': 9, 'measure': 4, 'barrier': 2})\n"
          ]
        },
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/fractional-gates/extracted-outputs/a18e5c70-1.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 9,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "t_qc_f = pm_f.run(b_qc)\n",
        "print(t_qc_f[0].count_ops())\n",
        "t_qc_f[0].draw(\"mpl\", fold=-1)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "a4cd07d1",
      "metadata": {},
      "source": [
        "Um die Auswirkungen von Teilgattern zu beurteilen, bewerten wir die Anzahl der nichtlokalen Gatter (CZ und RZZ für dieses Backend), zusammen mit der Tiefe und Dauer der Schaltkreise und vergleichen diese Metriken später mit denen eines Standard-Workflows.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 10,
      "id": "b5bcf9ad",
      "metadata": {},
      "outputs": [],
      "source": [
        "nnl_f = [qc.num_nonlocal_gates() for qc in t_qc_f]\n",
        "depth_f = [qc.depth() for qc in t_qc_f]\n",
        "duration_f = [\n",
        "    qc.estimate_duration(backend_f.target, unit=\"u\") for qc in t_qc_f\n",
        "]"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "629406cc",
      "metadata": {},
      "source": [
        "<span id=\"step-3-execute-using-qiskit-primitives\" />\n",
        "\n",
        "### Schritt 3: Mit „ Qiskit primitives “ ausführen\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "87926539",
      "metadata": {},
      "source": [
        "Wir führen die transpilierte Schaltung mit dem Backend aus, das fraktionale Gatter unterstützt.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 11,
      "id": "a68acf11",
      "metadata": {},
      "outputs": [],
      "source": [
        "sampler_f = AerSampler.from_backend(backend_f)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 12,
      "id": "a703b939",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "085ce928-767e-4200-93bf-3905e5411cfe\n"
          ]
        }
      ],
      "source": [
        "job = sampler_f.run(t_qc_f, shots=shots)\n",
        "print(job.job_id())"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "6c9fd10d",
      "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"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "7a865036",
      "metadata": {},
      "source": [
        "Sie können den Kernel-Funktionswert $K(x, x)$ erhalten, indem Sie die Wahrscheinlichkeit der Null-Bitfolge `00...00` in der Ausgabe messen.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 13,
      "id": "1f0d9c51",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "[0.929, 0.882, 0.8645, 0.817]\n"
          ]
        }
      ],
      "source": [
        "result = job.result()\n",
        "fidelity_f = [fidelity(result=res) for res in result]\n",
        "print(fidelity_f)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "a5bcd1a8",
      "metadata": {},
      "source": [
        "<span id=\"comparison-of-workflow-and-circuit-without-fractional-gates\" />\n",
        "\n",
        "### Vergleich von Arbeitsablauf und Schaltkreis ohne fraktionierte Gatter\n",
        "\n",
        "In diesem Abschnitt stellen wir den Standard-Workflow für Qiskit-Muster unter Verwendung eines Backends vor, das keine gebrochenen Gatter unterstützt.\n",
        "Wenn Sie die transpilierten Schaltungen vergleichen, werden Sie feststellen, dass die Version mit fraktionierten Gatterelementen (aus dem vorherigen Abschnitt) kompakter ist als die ohne fraktionierte Gatterelemente.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 14,
      "id": "e97fd0d5",
      "metadata": {},
      "outputs": [],
      "source": [
        "# step 1: map classical inputs to quantum problem\n",
        "# `circuits` and `params` from the previous section are reused here"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 15,
      "id": "a10f2d95",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "OrderedDict({'rz': 130, 'sx': 80, 'cz': 36, 'measure': 4, 'barrier': 2})\n"
          ]
        },
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/fractional-gates/extracted-outputs/a10f2d95-1.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 15,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "# step 2: optimize circuits\n",
        "backend_c = service.backend(backend_name)  # w/o fractional gates\n",
        "pm_c = generate_preset_pass_manager(\n",
        "    optimization_level=optimization_level, backend=backend_c\n",
        ")\n",
        "t_qc_c = pm_c.run(circuits)\n",
        "print(t_qc_c[0].count_ops())\n",
        "t_qc_c[0].draw(\"mpl\", fold=-1)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 16,
      "id": "bb3475df",
      "metadata": {},
      "outputs": [],
      "source": [
        "nnl_c = [qc.num_nonlocal_gates() for qc in t_qc_c]\n",
        "depth_c = [qc.depth() for qc in t_qc_c]\n",
        "duration_c = [\n",
        "    qc.estimate_duration(backend_c.target, unit=\"u\") for qc in t_qc_c\n",
        "]"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 17,
      "id": "e8d307c0",
      "metadata": {},
      "outputs": [],
      "source": [
        "# step 3: execute\n",
        "sampler_c = AerSampler.from_backend(backend_c)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 18,
      "id": "983dd26f",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "f2cca29d-7263-4976-9e51-13a91b75c3ae\n"
          ]
        }
      ],
      "source": [
        "job = sampler_c.run(pubs=zip(t_qc_c, params), shots=shots)\n",
        "print(job.job_id())"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 19,
      "id": "a6a6fa77",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "[0.8625, 0.7605, 0.702, 0.671]\n"
          ]
        }
      ],
      "source": [
        "# step 4: post-processing\n",
        "result = job.result()\n",
        "fidelity_c = [fidelity(res) for res in result]\n",
        "print(fidelity_c)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "765a7980",
      "metadata": {},
      "source": [
        "<span id=\"comparison-of-depths-durations-and-fidelities\" />\n",
        "\n",
        "### Vergleich von Tiefe, Dauer und Genauigkeit\n",
        "\n",
        "In diesem Abschnitt vergleichen wir die Anzahl der nichtlokalen Gatter und die Treue zwischen Schaltungen mit und ohne fraktionierte Gatter.\n",
        "Dies verdeutlicht die potenziellen Vorteile der Verwendung von Teilgattern in Bezug auf Ausführungseffizienz und Qualität.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 20,
      "id": "ef343a53",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<matplotlib.legend.Legend at 0x116af3cb0>"
            ]
          },
          "execution_count": 20,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/fractional-gates/extracted-outputs/ef343a53-1.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "plt.plot(qubits, depth_c, \"-o\", label=\"no fractional gates\")\n",
        "plt.plot(qubits, depth_f, \"-o\", label=\"with fractional gates\")\n",
        "plt.xlabel(\"number of qubits\")\n",
        "plt.ylabel(\"depth\")\n",
        "plt.title(\"Comparison of depths\")\n",
        "plt.grid()\n",
        "plt.legend()"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 21,
      "id": "98bb2cd0",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<matplotlib.legend.Legend at 0x11ea4f4d0>"
            ]
          },
          "execution_count": 21,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/fractional-gates/extracted-outputs/98bb2cd0-1.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "plt.plot(qubits, duration_c, \"-o\", label=\"no fractional gates\")\n",
        "plt.plot(qubits, duration_f, \"-o\", label=\"with fractional gates\")\n",
        "plt.xlabel(\"number of qubits\")\n",
        "plt.ylabel(\"duration (µs)\")\n",
        "plt.title(\"Comparison of durations\")\n",
        "plt.grid()\n",
        "plt.legend()"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 22,
      "id": "1383b242",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<matplotlib.legend.Legend at 0x1247fc440>"
            ]
          },
          "execution_count": 22,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/fractional-gates/extracted-outputs/1383b242-1.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "plt.plot(qubits, nnl_c, \"-o\", label=\"no fractional gates\")\n",
        "plt.plot(qubits, nnl_f, \"-o\", label=\"with fractional gates\")\n",
        "plt.xlabel(\"number of qubits\")\n",
        "plt.ylabel(\"number of non-local gates\")\n",
        "plt.title(\"Comparison of numbers of non-local gates\")\n",
        "plt.grid()\n",
        "plt.legend()"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 23,
      "id": "8b4594f5",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<matplotlib.legend.Legend at 0x120b792b0>"
            ]
          },
          "execution_count": 23,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/fractional-gates/extracted-outputs/8b4594f5-1.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "plt.plot(qubits, fidelity_c, \"-o\", label=\"no fractional gates\")\n",
        "plt.plot(qubits, fidelity_f, \"-o\", label=\"with fractional gates\")\n",
        "plt.xlabel(\"number of qubits\")\n",
        "plt.ylabel(\"fidelity\")\n",
        "plt.title(\"Comparison of fidelities\")\n",
        "plt.grid()\n",
        "plt.legend()"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "9f17acd5",
      "metadata": {},
      "source": [
        "<span id=\"large-scale-hardware-example\" />\n",
        "\n",
        "## Beispiel für groß angelegte Hardware\n",
        "\n",
        "In diesem Abschnitt führen wir Vergleichstests des Quantum-Kernel-Workflows mit und ohne fraktionierte Gatter auf Quantenhardware mit bis zu 40 Qubits durch.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "fd68378c",
      "metadata": {},
      "source": [
        "<span id=\"step-1-4-combined\" />\n",
        "\n",
        "### Schritte 1–4 zusammengefasst\n",
        "\n",
        "Der Arbeitsablauf folgt derselben Struktur wie das Beispiel im kleinen Maßstab. Wir transpilieren alle Schaltkreise mit und ohne fraktionale Gatter, erfassen Metriken und lassen die Schaltkreise anschließend auf echter Quantenhardware ausführen.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 24,
      "id": "4431bf56",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "job id (w/ fractional gates): d8uasitbh0os73eqnpig\n"
          ]
        }
      ],
      "source": [
        "# -------------------------Step 1-------------------------\n",
        "qubits = list(range(4, 44, 4))\n",
        "circuits = [quantum_kernel(i, reps=reps) for i in qubits]\n",
        "params = [random_parameters(circ) for circ in circuits]\n",
        "b_qc = [\n",
        "    circ.assign_parameters(param) for circ, param in zip(circuits, params)\n",
        "]\n",
        "\n",
        "\n",
        "def benchmark(b_qc, backend):\n",
        "    # -------------------------Step 2-------------------------\n",
        "    pm = generate_preset_pass_manager(optimization_level, backend=backend)\n",
        "    if \"rzz\" in backend.target.operation_names:\n",
        "        # workaround until https://github.com/Qiskit/qiskit-ibm-runtime/issues/2441 is resolved\n",
        "        pm.post_optimization = PassManager(\n",
        "            [\n",
        "                FoldRzzAngle(),\n",
        "                Optimize1qGatesDecomposition(target=backend.target),\n",
        "                RemoveIdentityEquivalent(target=backend.target),\n",
        "            ]\n",
        "        )\n",
        "    t_qc = pm.run(b_qc)\n",
        "    nnl = [qc.num_nonlocal_gates() for qc in t_qc]\n",
        "    depth = [qc.depth() for qc in t_qc]\n",
        "    duration = [\n",
        "        qc.estimate_duration(backend_f.target, unit=\"u\") for qc in t_qc\n",
        "    ]\n",
        "\n",
        "    # -------------------------Step 3-------------------------\n",
        "    sampler = SamplerV2(mode=backend)\n",
        "    sampler.options.dynamical_decoupling.enable = True\n",
        "    sampler.options.dynamical_decoupling.sequence_type = \"XY4\"\n",
        "    sampler.options.dynamical_decoupling.skip_reset_qubits = True\n",
        "    sampler.options.environment.job_tags = [\"TUT_FG\"]\n",
        "    job = sampler.run(t_qc, shots=shots)\n",
        "    job_id = job.job_id()\n",
        "    return nnl, depth, duration, job_id\n",
        "\n",
        "\n",
        "def postprocessing(job_id: str):\n",
        "    # -------------------------Step 4-------------------------\n",
        "    job = service.job(job_id)\n",
        "    result = job.result()\n",
        "    fidelities = [fidelity(result=res) for res in result]\n",
        "    usage = job.usage()\n",
        "    return fidelities, usage\n",
        "\n",
        "\n",
        "backend_f = service.backend(backend_name, use_fractional_gates=True)\n",
        "nnl_f, depth_f, duration_f, job_id_f = benchmark(\n",
        "    b_qc, backend_f\n",
        ")  # step 2 & 3\n",
        "print(\"job id (w/ fractional gates):\", job_id_f)\n",
        "fidelity_f, usage_f = postprocessing(job_id_f)  # step 4"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 25,
      "id": "4a5d15a2",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "job id (w/o fractional gates): d8uav3lposuc738pruug\n"
          ]
        }
      ],
      "source": [
        "backend_c = service.backend(backend_name, use_fractional_gates=False)\n",
        "nnl_c, depth_c, duration_c, job_id_c = benchmark(b_qc, backend_c)\n",
        "print(\"job id (w/o fractional gates):\", job_id_c)\n",
        "fidelity_c, usage_c = postprocessing(job_id_c)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "9f78441e",
      "metadata": {},
      "source": [
        "Anschließend vergleichen wir die Kennzahlen.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 26,
      "id": "b409e8d3",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<matplotlib.legend.Legend at 0x12461e660>"
            ]
          },
          "execution_count": 26,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/fractional-gates/extracted-outputs/b409e8d3-1.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "plt.plot(qubits, depth_c, \"-o\", label=\"no fractional gates\")\n",
        "plt.plot(qubits, depth_f, \"-o\", label=\"with fractional gates\")\n",
        "plt.xlabel(\"number of qubits\")\n",
        "plt.ylabel(\"depth\")\n",
        "plt.title(\"Comparison of depths\")\n",
        "plt.grid()\n",
        "plt.legend()"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 27,
      "id": "09f91f0f",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<matplotlib.legend.Legend at 0x11f2ac980>"
            ]
          },
          "execution_count": 27,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/fractional-gates/extracted-outputs/09f91f0f-1.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "plt.plot(qubits, duration_c, \"-o\", label=\"no fractional gates\")\n",
        "plt.plot(qubits, duration_f, \"-o\", label=\"with fractional gates\")\n",
        "plt.xlabel(\"number of qubits\")\n",
        "plt.ylabel(\"duration (µs)\")\n",
        "plt.title(\"Comparison of durations\")\n",
        "plt.grid()\n",
        "plt.legend()"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 28,
      "id": "c9308517",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<matplotlib.legend.Legend at 0x125c91be0>"
            ]
          },
          "execution_count": 28,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/fractional-gates/extracted-outputs/c9308517-1.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "plt.plot(qubits, nnl_c, \"-o\", label=\"no fractional gates\")\n",
        "plt.plot(qubits, nnl_f, \"-o\", label=\"with fractional gates\")\n",
        "plt.xlabel(\"number of qubits\")\n",
        "plt.ylabel(\"number of non-local gates\")\n",
        "plt.title(\"Comparison of numbers of non-local gates\")\n",
        "plt.grid()\n",
        "plt.legend()"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 29,
      "id": "234731d4",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<matplotlib.legend.Legend at 0x11fcf6e40>"
            ]
          },
          "execution_count": 29,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/fractional-gates/extracted-outputs/234731d4-1.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "plt.plot(qubits, fidelity_c, \"-o\", label=\"no fractional gates\")\n",
        "plt.plot(qubits, fidelity_f, \"-o\", label=\"with fractional gates\")\n",
        "plt.xlabel(\"number of qubits\")\n",
        "plt.ylabel(\"fidelity\")\n",
        "plt.title(\"Comparison of fidelities\")\n",
        "plt.grid()\n",
        "plt.legend()"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "d38b9fe1",
      "metadata": {},
      "source": [
        "Wir vergleichen die QPU-Nutzungszeit mit und ohne Fractional Gates. Die Ergebnisse in der folgenden Zelle zeigen, dass die QPU-Nutzungszeiten fast identisch sind.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 30,
      "id": "793326ca",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "no fractional gates: 8 seconds\n",
            "fractional gates: 8 seconds\n"
          ]
        }
      ],
      "source": [
        "print(f\"no fractional gates: {usage_c} seconds\")\n",
        "print(f\"fractional gates: {usage_f} seconds\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "efe18f80",
      "metadata": {},
      "source": [
        "<span id=\"advanced-topic-using-only-fractional-rx-gates\" />\n",
        "\n",
        "## Fortgeschrittenes Thema: Verwendung nur von gebrochenen RX-Gates\n",
        "\n",
        "Die Notwendigkeit des geänderten Arbeitsablaufs bei der Verwendung von fraktionierten Gattern ergibt sich in erster Linie aus der Beschränkung der RZZ-Gate-Winkel.\n",
        "Wenn Sie jedoch nur die gebrochenen RX-Gatter verwenden und die gebrochenen RZZ-Gatter ausschließen, können Sie weiterhin dem Standardarbeitsablauf für Qiskit-Muster folgen.\n",
        "Dieser Ansatz kann insbesondere bei Schaltungen mit einer großen Anzahl von RX-Gattern und U-Gattern erhebliche Vorteile bieten, da er die Gesamtzahl der Gatter reduziert und die Leistung potenziell verbessert.\n",
        "In diesem Abschnitt zeigen wir Ihnen, wie Sie Ihre Schaltungen optimieren können, indem Sie nur gebrochene RX-Gatter verwenden und auf RZZ-Gatter verzichten.\n",
        "\n",
        "Um dies zu unterstützen, stellen wir eine Utility-Funktion zur Verfügung, mit der Sie ein bestimmtes Basis-Gate in einem Target-Objekt deaktivieren können.\n",
        "Hier verwenden wir sie, um RZZ-Tore zu deaktivieren.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 31,
      "id": "ab43ba23",
      "metadata": {},
      "outputs": [],
      "source": [
        "def remove_instruction_from_target(target: Target, gate_name: str) -> Target:\n",
        "    new_target = Target(\n",
        "        description=target.description,\n",
        "        num_qubits=target.num_qubits,\n",
        "        dt=target.dt,\n",
        "        granularity=target.granularity,\n",
        "        min_length=target.min_length,\n",
        "        pulse_alignment=target.pulse_alignment,\n",
        "        acquire_alignment=target.acquire_alignment,\n",
        "        qubit_properties=target.qubit_properties,\n",
        "        concurrent_measurements=target.concurrent_measurements,\n",
        "    )\n",
        "\n",
        "    for name, qarg_map in target.items():\n",
        "        if name == gate_name:\n",
        "            continue\n",
        "        instruction = target.operation_from_name(name)\n",
        "        if qarg_map == {None: None}:\n",
        "            qarg_map = None\n",
        "        new_target.add_instruction(instruction, qarg_map, name=name)\n",
        "    return new_target"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "7f689a02",
      "metadata": {},
      "source": [
        "Wir verwenden eine Schaltung, die aus U-, CZ- und RZZ-Gattern besteht, als Beispiel.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 32,
      "id": "6b812497",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/fractional-gates/extracted-outputs/6b812497-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 32,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "qc = n_local(3, \"u\", \"cz\", \"linear\", reps=1)\n",
        "qc.rzz(1.1, 0, 1)\n",
        "qc.draw(\"mpl\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "fa9dc1c4",
      "metadata": {},
      "source": [
        "Zunächst transpilieren wir die Schaltung für ein Backend, das keine fraktionalen Gatter unterstützt.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 33,
      "id": "9e8e0709",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "OrderedDict({'rz': 23, 'sx': 16, 'cz': 4})\n"
          ]
        },
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/fractional-gates/extracted-outputs/9e8e0709-1.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 33,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "pm_c = generate_preset_pass_manager(\n",
        "    optimization_level=optimization_level, backend=backend_c\n",
        ")\n",
        "t_qc = pm_c.run(qc)\n",
        "print(t_qc.count_ops())\n",
        "t_qc.draw(\"mpl\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "bd0e24da",
      "metadata": {},
      "source": [
        "Dann transpilieren wir dieselbe Schaltung mit gebrochenen RX-Gattern, wobei RZZ-Gatter ausgeschlossen werden.\n",
        "Dies führt zu einer leichten Verringerung der Gesamtzahl der Gatter dank der effizienteren Implementierung der RX-Gatter.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 34,
      "id": "db45feb0",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "OrderedDict({'rz': 22, 'sx': 14, 'cz': 4, 'rx': 1})\n"
          ]
        },
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/fractional-gates/extracted-outputs/db45feb0-1.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 34,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "backend_f = service.backend(backend_name, use_fractional_gates=True)\n",
        "target = remove_instruction_from_target(backend_f.target, \"rzz\")\n",
        "pm_f = generate_preset_pass_manager(\n",
        "    optimization_level=optimization_level,\n",
        "    target=target,\n",
        ")\n",
        "t_qc = pm_f.run(qc)\n",
        "print(t_qc.count_ops())\n",
        "t_qc.draw(\"mpl\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "15140636",
      "metadata": {},
      "source": [
        "<span id=\"optimize-u-gates-with-fractional-rx-gates\" />\n",
        "\n",
        "### Optimieren Sie U-Gatter mit gebrochenen RX-Gattern\n",
        "\n",
        "In diesem Abschnitt zeigen wir, wie man U-Gatter mit fraktionalen RX-Gattern optimieren kann, wobei wir auf derselben Schaltung aufbauen, die im vorherigen Abschnitt vorgestellt wurde.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "3f73cbda",
      "metadata": {},
      "source": [
        "Wir setzen die Schaltung nur mit gebrochenen RX-Gattern um, ohne RZZ-Gatter.\n",
        "Durch die Einführung einer benutzerdefinierten Zerlegungsregel, wie sie im Folgenden gezeigt wird, können wir die Anzahl der Ein-Qubit-Gatter reduzieren, die zur Implementierung eines U-Gatters erforderlich sind.\n",
        "\n",
        "Diese Funktion wird derzeit in diesem [GitHub -Ticket](https://github.com/Qiskit/qiskit/issues/13455) diskutiert.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 35,
      "id": "0f0c6d87",
      "metadata": {},
      "outputs": [],
      "source": [
        "# special decomposition rule for UGate\n",
        "x = ParameterVector(\"x\", 3)\n",
        "zxz = QuantumCircuit(1)\n",
        "zxz.rz(x[2] - np.pi / 2, 0)\n",
        "zxz.rx(x[0], 0)\n",
        "zxz.rz(x[1] + np.pi / 2, 0)\n",
        "DEFAULT_EQUIVALENCE_LIBRARY.add_equivalence(UGate(x[0], x[1], x[2]), zxz)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "91c824d8",
      "metadata": {},
      "source": [
        "Als Nächstes wenden wir den Transpiler unter Verwendung `constructor-beta` der vom Paket `qiskit-basis-constructor` bereitgestellten Übersetzung an.\n",
        "Dadurch verringert sich die Gesamtzahl der Gatter im Vergleich zur vorherigen Transpilierung.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 36,
      "id": "b19aae7c",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "OrderedDict({'rz': 16, 'rx': 9, 'cz': 4})\n"
          ]
        },
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/fractional-gates/extracted-outputs/b19aae7c-1.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 36,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "pm_f = generate_preset_pass_manager(\n",
        "    optimization_level=optimization_level,\n",
        "    target=target,\n",
        "    translation_method=\"constructor-beta\",\n",
        ")\n",
        "t_qc = pm_f.run(qc)\n",
        "print(t_qc.count_ops())\n",
        "t_qc.draw(\"mpl\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "23ad4615",
      "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",
        "  * Leitfaden [zu fraktionierten Gates](/docs/guides/fractional-gates)\n",
        "  * [Wann sollten fraktionierte Gates *nicht* verwendet werden?](/docs/guides/fractional-gates#when-not-to-use)\n",
        "  * [`FoldRzzAngle`](/docs/api/qiskit-ibm-runtime/transpiler-passes-fold-rzz-angle) API-Referenz zum Transpiler-Durchlauf\n",
        "  * Das Tutorial [zum Quantum-Kernel-Training](/docs/tutorials/quantum-kernel-training)\n",
        "  * Die Lektion [„Quantum-Kernel“](/learning/courses/quantum-machine-learning/quantum-kernel-methods) im Kurs „Quantum Machine Learning“\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": 30
  },
  "nbformat": 4,
  "nbformat_minor": 5
}