{
  "cells": [
    {
      "cell_type": "markdown",
      "id": "a9fc5202-9641-4db3-ac1a-9986f28854bc",
      "metadata": {},
      "source": [
        "---\n",
        "title: \"Variationaler Quanten-Eigensolver\"\n",
        "description: \"Erfahren Sie, was ein variationaler Quanten-Eigensolver ist, und berechnen Sie damit die Aktivierungsenergie der Reaktion „ H+H=H2 “.\"\n",
        "---\n",
        "\n",
        "{/* cspell:ignore arrowstyle UCCSD verticalalignment horizontalalignment  xytext arrowprops preparable ansätze Marov Aspuru Guzik Hartrees ansä */}\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "bafc481a-d2d4-4668-8389-acbe9cd3f615",
      "metadata": {},
      "source": [
        "<span id=\"variational-quantum-eigensolver-vqe\" />\n",
        "\n",
        "# Variational Quantum Eigensolver (VQE)\n",
        "\n",
        "Für dieses Modul müssen die Teilnehmer über eine funktionierende Python Umgebung verfügen und die neuesten Versionen der folgenden Pakete installiert haben:\n",
        "\n",
        "* `qiskit`\n",
        "* `qiskit_ibm_runtime`\n",
        "* `qiskit-aer`\n",
        "* `qiskit.visualization`\n",
        "* `numpy`\n",
        "* `pylatexenc`\n",
        "\n",
        "Um diese Pakete einzurichten und zu installieren, lesen Sie die Anleitung [Qiskit installieren](/docs/guides/install-qiskit). Um Jobs auf echten Quantencomputern ausführen zu können, müssen die Schüler ein IBM Cloud -Konto einrichten. Folgen Sie dazu den Schritten in der Anleitung zum [Einrichten Ihres IBM Cloud -Kontos](/docs/guides/cloud-setup).\n",
        "\n",
        "*Dieses Modul wurde getestet und verbraucht etwa 8 Minuten QPU-Zeit. Dies ist eine Schätzung, und Ihr tatsächlicher Verbrauch kann davon abweichen.*\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "cda95261-1473-492c-8a1d-1e29773086c9",
      "metadata": {},
      "outputs": [],
      "source": [
        "# Uncomment and modify this line as needed to install dependencies\n",
        "#!pip install 'qiskit>=2.1.0' 'qiskit-ibm-runtime>=0.40.1' 'qiskit-aer>=0.17.0' 'numpy' 'pylatexenc'"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "127021b2-3419-4b9d-bf13-7ef940b50029",
      "metadata": {},
      "source": [
        "<span id=\"introduction\" />\n",
        "\n",
        "## Einführung\n",
        "\n",
        "Seit der Entwicklung des quantenmechanischen Modells zu Beginn des 20. Jahrhunderts wissen die Wissenschaftler, dass die Elektronen nicht auf festen Bahnen um den Atomkern kreisen, sondern in Wahrscheinlichkeitsbereichen, den sogenannten Orbitalen, existieren. Diese Orbitale entsprechen bestimmten, diskreten Energieniveaus, die Elektronen einnehmen können. Elektronen befinden sich natürlicherweise in den niedrigsten verfügbaren Energieniveaus, dem so genannten Grundzustand. Wenn ein Elektron jedoch genügend Energie absorbiert, kann es auf ein höheres Energieniveau springen und in einen angeregten Zustand übergehen. Dieser angeregte Zustand ist vorübergehend, und das Elektron kehrt schließlich auf ein niedrigeres Energieniveau zurück und gibt die absorbierte Energie frei, oft in Form von Licht. Dieser grundlegende Prozess der Energieabsorption und -emission ist wichtig, um zu verstehen, wie Atome interagieren und Bindungen eingehen.\n",
        "\n",
        "Wenn sich Atome zu Molekülen zusammenschließen, verbinden sich ihre Atomorbitale zu Molekülorbitalen. Die Anordnung und die Energieniveaus der Elektronen in diesen Molekülorbitalen bestimmen die Eigenschaften des entstehenden Moleküls und die Stärke der chemischen Bindungen. Bei der Bildung eines Wasserstoffmoleküls ( $H_2$ ) aus zwei einzelnen Wasserstoffatomen zum Beispiel besetzt das Elektron jedes Atoms ein Atomorbital. Wenn sich die Atome einander nähern, überschneiden sich diese Atomorbitale und verbinden sich zu neuen Molekülorbitalen - einem mit niedrigerer Energie (einem Bindungsorbital) und einem mit höherer Energie (einem Anti-Bindungsorbital). Die beiden Elektronen, jeweils eines von jedem Wasserstoffatom, besetzen bevorzugt das Bindungsorbital mit niedrigerer Energie, was zur Bildung einer stabilen kovalenten Bindung führt, die das $H_2$ Molekül zusammenhält. Der Energieunterschied zwischen den getrennten Atomen und dem gebildeten Molekül, insbesondere die Energie der Elektronen in den Molekülorbitalen, bestimmt die Stabilität und die Eigenschaften der Bindung.\n",
        "\n",
        "In den folgenden Abschnitten werden wir diesen Prozess der Molekülbildung untersuchen und uns dabei auf das Molekül $H_2$ konzentrieren. Wir werden einen echten Quantencomputer in Kombination mit klassischen Optimierungstechniken verwenden, um die Energie dieses einfachen, aber grundlegenden Prozesses zu ermitteln. Mit diesem Experiment wird praktisch demonstriert, wie die Quantenberechnung zur Lösung von Problemen in der Computerchemie eingesetzt werden kann, und es werden Erkenntnisse über die Rolle der Elektronenenergie gewonnen.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "eef4da0c-8f48-47fc-88a2-9a2979c1dbc1",
      "metadata": {},
      "source": [
        "<span id=\"vqe---a-variational-quantum-algorithm-for-eigenvalue-problems\" />\n",
        "\n",
        "## VQE – Ein variationaler Quantenalgorithmus für Eigenwertprobleme\n",
        "\n",
        "<span id=\"approximation-techniques-for-chemistry---variational-principle-and-the-basis-set\" />\n",
        "\n",
        "### Approximationstechniken für die Chemie – Variationsprinzip und Basissatz\n",
        "\n",
        "Erwin Schrödingers Beiträge zur Quantenmechanik beschränken sich nicht auf die Einführung eines neuen elektronischen Modells; im Grunde hat er die Wellenmechanik durch die Entwicklung der berühmten zeitabhängigen Schrödingergleichung begründet:\n",
        "\n",
        "$$\n",
        "i\\hbar \\frac{d}{dt}|\\psi\\rangle = \\hat{H}|\\psi\\rangle\n",
        "$$\n",
        "\n",
        "Dabei ist $\\hat{H}$ der Hamilton-Operator, der die Gesamtenergie des Systems darstellt, und $|\\psi\\rangle$ ist die Wellenfunktion, die alle Informationen über den Quantenzustand des Systems enthält. (Hinweis: $\\frac{d}{dt}$ ist die gesamte Zeitableitung, und wir beziehen den Energieeigenwert $E$ hier nicht explizit mit ein)\n",
        "\n",
        "In vielen praktischen Anwendungen - z. B. bei der Bestimmung der zulässigen Energieniveaus von Atomen und Molekülen - verwenden wir jedoch stattdessen die zeitunabhängige Schrödingergleichung (Energieeigenwertgleichung), die von der zeitabhängigen Form abgeleitet wird, indem ein stationärer Zustand angenommen wird. Ein stationärer Zustand ist ein Quantenzustand, in dem sich die Wahrscheinlichkeitsdichte, ein Teilchen an einem bestimmten Punkt im Raum zu finden, im Laufe der Zeit nicht ändert.\n",
        "\n",
        "$\\hat{H}|\\psi\\rangle = E|\\psi\\rangle$\n",
        "\n",
        "In dieser Form stellt $E$ den Energieeigenwert dar, der dem Quantenzustand $|\\psi\\rangle$ entspricht. Der Hamiltonian enthält verschiedene Energiebeiträge, wie die kinetische Energie von Elektronen und Kernen, die Anziehungskräfte zwischen Elektronen und Kernen und die Abstoßungskräfte zwischen Elektronen.\n",
        "\n",
        "Die Lösung der Energieeigenwertgleichung ermöglicht es uns, die quantisierten Energieniveaus von atomaren und molekularen Systemen zu berechnen. Bei Molekülen ist es jedoch schwierig, sie genau zu lösen, da die Wellenfunktion $\\Psi$, die die räumliche Verteilung der Elektronen beschreibt, komplex und hochdimensional ist.\n",
        "\n",
        "Daher verwenden die Wissenschaftler Näherungstechniken, um praktische und genaue Lösungen zu erhalten. In dieser Arbeit werden wir uns auf zwei Schlüsselmethoden konzentrieren:\n",
        "\n",
        "1. Variationsprinzip\n",
        "\n",
        "   Mit dieser Methode wird die Wellenfunktion angenähert und so angepasst, dass sie der Zielenergie, in der Regel der Grundzustandsenergie des Systems, so nahe wie möglich kommt. Der Grundgedanke des Variationsprinzips ist einfach:\n",
        "\n",
        "   * Wenn wir eine Wellenfunktion $\\Psi_\\text{trial}$ (eine \"Versuchsfunktion\") erraten, wird die daraus berechnete Energie immer gleich oder höher sein als die Grundzustandsenergie ( $E_0$ ) des Systems. $E_\\text{approx} = \\frac{\\langle \\Psi_\\text{trial}|\\hat{H}|\\Psi_\\text{trial}\\rangle}{\\langle \\Psi_\\text{trial}|\\Psi_\\text{trial}\\rangle} \\geq E_0$\n",
        "   * Durch Anpassung der Parameter $\\theta$ in der Versuchsfunktion $|\\Psi_\\text{trial}(\\theta)\\rangle$ können wir eine immer bessere Annäherung an die Energie des Grundzustands erreichen.\n",
        "   * Ihre Genauigkeit hängt stark von der Wahl der Versuchswellenfunktion $\\Psi_\\text{trial}$ ab. Eine schlecht gewählte Versuchsfunktion kann zu einer Energieschätzung führen, die alles andere als genau ist.\n",
        "\n",
        "2. Annäherung an die Basismenge\n",
        "\n",
        "   Die zweite Annäherungsmethode kommt in der Phase der Konstruktion der Wellenfunktion zum Einsatz - der Basismengenansatz. In der Quantenchemie ist es fast unmöglich, die Schrödinger-Gleichung für Moleküle exakt zu lösen. Stattdessen nähern wir uns der komplexen Multi-Elektronen-Wellenfunktion an, indem wir sie aus einfacheren, vordefinierten mathematischen Funktionen aufbauen. Ein Basissatz ist im Wesentlichen eine Sammlung dieser bekannten mathematischen Funktionen, in der Regel zentriert auf die Atome im Molekül, die als Bausteine zur Darstellung der Form und des Verhaltens der Elektronen im System verwendet werden. Stellen Sie sich vor, Sie versuchen, eine detaillierte Skulptur nur mit einer Sammlung von Standard-LEGO-Steinen nachzubauen - je mehr Arten und Größen von Steinen Sie haben (je größer das Basisset), desto genauer können Sie die ursprüngliche Form nachbilden.\n",
        "\n",
        "   Diese Basisfunktionen orientieren sich häufig an den analytischen Lösungen für einfache Systeme wie das Wasserstoffatom und nehmen Formen wie Gauß- oder Slater-Funktionen an, obwohl es sich dabei immer noch um Näherungen handelt. Anstatt mit den theoretisch \"exakten\", aber schwer zu handhabenden vollständigen Molekülorbitalen zu arbeiten, drücken wir sie als Linearkombination (eine Summe mit Koeffizienten) dieser Basisfunktionen aus. Diese Methode wird als Linearkombination von Atomorbitalen (LCAO) bezeichnet, wenn die Basisfunktionen Atomorbitalen ähneln. Durch Optimierung der Koeffizienten in dieser Linearkombination können wir die bestmögliche Näherungswellenfunktion und Energie innerhalb der Grenzen des gewählten Basissatzes finden.\n",
        "\n",
        "   * Je mehr Funktionen im Basissatz enthalten sind, desto besser ist die Annäherung, aber dies geht mit einem höheren Rechenaufwand einher.\n",
        "   * Ein kleiner Basissatz liefert eine grobe Schätzung, während ein großer Basissatz genauere Ergebnisse liefert, die allerdings mehr Rechenressourcen erfordern.\n",
        "\n",
        "Zusammenfassend lässt sich sagen, dass wir, um die Berechnungen durchführbar zu machen und die Rechenkosten zu senken, das Variationsprinzip anwenden, indem wir die Wellenfunktion annähern, was den Rechenaufwand verringert und eine iterative Optimierung zur Minimierung der Energie ermöglicht. Der Basissatz-Ansatz vereinfacht die Berechnungen, indem er die Atomorbitale als eine Kombination von vordefinierten Funktionen darstellt, anstatt direkt eine kontinuierliche Wellenfunktion zu berechnen.\n",
        "\n",
        "<span id=\"check-your-understanding\" />\n",
        "\n",
        "#### Überprüfen Sie Ihr Verständnis\n",
        "\n",
        "Betrachten Sie die Versuchswellenfunktion $\\Psi_\\text{trial}(\\alpha,x) = Ae^{- \\alpha x^2}$, wobei $A$ eine Normalisierungskonstante und $\\alpha$ ein einstellbarer Parameter ist.\n",
        "\n",
        "(a) Normalisieren Sie die Wellenfunktion des Versuchs, indem Sie $A$ so bestimmen, dass $\\int_{-\\infty}^{\\infty} |\\Psi_\\text{trial}|^2 dx = 1$ gilt.\n",
        "\n",
        "<Accordion>\n",
        "  <AccordionItem title=\"Antwort\">\n",
        "    Um die gegebene Versuchswellenfunktion zu normalisieren:\n",
        "\n",
        "    $\\int_{-\\infty}^{\\infty} |\\Psi_\\text{trial}|^2 dx = \\int_{-\\infty}^{\\infty} A^2 e^{-2 \\alpha x^2} dx = 1$\n",
        "\n",
        "    Verwenden Sie das Gaußsche Integral:\n",
        "\n",
        "    $ \\int_{-\\infty}^{\\infty} e^{-a x^2} dx = \\sqrt{\\frac{\\pi}{a}} \\text{,   for } a>0$\n",
        "\n",
        "    $a = 2\\alpha$ einstellen und dann erhalten: $A^2\\sqrt{\\frac{\\pi}{a}} = 1$ $\\therefore A = (\\frac{2\\alpha}{\\pi})^{1/4}$\n",
        "  </AccordionItem>\n",
        "</Accordion>\n",
        "\n",
        "(b) Berechnen Sie den Erwartungswert des Hamilton-Operators $\\hat{H}$, der durch folgende Gleichung gegeben ist: $ \\hat{H} = -\\frac{\\hbar^2}{2m} \\frac{d^2}{dx^2} + V(x)$, wobei $V(x)  = \\frac{1}{2}m\\omega^2x^2$ gilt, was einem Potential für einen einfachen harmonischen Oszillator entspricht.\n",
        "\n",
        "<Accordion>\n",
        "  <AccordionItem title=\"Antwort\">\n",
        "    Der Hamilton-Operator für einen harmonischen Oszillator lautet:\n",
        "\n",
        "    $\\hat{H} = -\\frac{\\hbar^2}{2m} \\frac{d^2}{dx^2} + \\frac{1}{2} m \\omega^2 x^2$\n",
        "\n",
        "    **Erwartungswert der kinetischen Energie**\n",
        "\n",
        "    $ \\langle T \\rangle = -\\frac{\\hbar^2}{2m} \\int_{-\\infty}^{\\infty} \\Psi_\\text{trial}^* \\frac{d^2}{dx^2} \\Psi_\\text{trial} dx$\n",
        "\n",
        "    Nehmen Sie die zweite Ableitung:\n",
        "\n",
        "    $\\frac{d}{dx} \\Psi_\\text{trial} = -2\\alpha x A e^{-\\alpha x^2}$\n",
        "\n",
        "    $\\frac{d^2}{dx^2} \\Psi_\\text{trial} = A e^{-\\alpha x^2} (4\\alpha^2 x^2 - 2\\alpha)$\n",
        "\n",
        "    So:\n",
        "\n",
        "    $T = -\\frac{\\hbar^2}{2m} \\int_{-\\infty}^{\\infty} A^2 e^{-2\\alpha x^2} (4\\alpha^2 x^2 - 2\\alpha) dx$\n",
        "\n",
        "    Verwendung der Standardergebnisse des Gaußschen Integrals:\n",
        "\n",
        "    $\\langle T \\rangle = \\frac{\\hbar^2 \\alpha}{2m}$\n",
        "\n",
        "    **Erwartungswert der potenziellen Energie**\n",
        "\n",
        "    $\\langle V \\rangle = \\frac{1}{2} m \\omega^2 \\int_{-\\infty}^{\\infty} x^2 |\\Psi_\\text{trial}|^2 dx$\n",
        "\n",
        "    Verwenden:\n",
        "\n",
        "    $\\int_{-\\infty}^{\\infty} x^2 e^{-a x^2} dx = \\frac{\\sqrt{\\pi}}{2a^{3/2}}$\n",
        "\n",
        "    erhalten wir:\n",
        "\n",
        "    $\\langle V \\rangle = \\frac{m \\omega^2}{4\\alpha}$\n",
        "\n",
        "    **Erwartungswert der Gesamtenergie**\n",
        "\n",
        "    $\\therefore E_\\text{approx}(\\alpha) = \\frac{\\hbar^2 \\alpha}{2m} + \\frac{m \\omega^2}{4\\alpha}$\n",
        "  </AccordionItem>\n",
        "</Accordion>\n",
        "\n",
        "(c) Bestimme mithilfe des Variationsprinzips die optimale Funktion $\\alpha$, indem du $E_\\text{approx}(\\alpha)$ minimierst.\n",
        "\n",
        "<Accordion>\n",
        "  <AccordionItem title=\"Antwort\">\n",
        "    Optimieren Sie „ $\\alpha$ “ für minimalen Energieverbrauch\n",
        "\n",
        "    **Unterscheiden**\n",
        "\n",
        "    $\\frac{d}{d\\alpha} \\left( \\frac{\\hbar^2 \\alpha}{2m} + \\frac{m \\omega^2}{4\\alpha} \\right) = 0$\n",
        "\n",
        "    Lösen:\n",
        "\n",
        "    $\\frac{\\hbar^2}{2m} - \\frac{m \\omega^2}{4\\alpha^2} = 0$\n",
        "\n",
        "    $\\alpha_\\text{opt} = \\frac{m\\omega}{2\\hbar}$\n",
        "\n",
        "    Ersetzen Sie $\\alpha_\\text{opt}$ durch $E_\\text{approx}$ :\n",
        "\n",
        "    $\\therefore E_\\text{approx} = \\frac{\\hbar \\omega}{2}$\n",
        "\n",
        "    die genau der Energie des Grundzustands des harmonischen Quantenoszillators entspricht.\n",
        "  </AccordionItem>\n",
        "</Accordion>\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "ed2bd1ba-73ad-42d3-94ad-c1d4a7db0a6f",
      "metadata": {},
      "source": [
        "<span id=\"vqe-variational-quantum-eigensolver\" />\n",
        "\n",
        "### VQE (Variational Quantum Eigensolver)\n",
        "\n",
        "Der Variations-Quanten-Eigensolver (VQE) ist die Hauptmethode, mit der wir den $H+H = H_2$ Prozess erforschen werden, und hier werden wir einen Blick darauf werfen, was VQE ist und wie es funktioniert. Aber lassen Sie uns zunächst innehalten und eine sehr wichtige Sache durch die Check-in-Frage betrachten.\n",
        "\n",
        "<span id=\"check-your-understanding\" />\n",
        "\n",
        "#### Überprüfen Sie Ihr Verständnis\n",
        "\n",
        "Wenn wir bereits so viele Strategien für chemische Probleme haben, warum brauchen wir dann einen Quantencomputer? Und welchen Sinn hat es, Quantencomputer und klassische Computer gemeinsam zu nutzen?\n",
        "\n",
        "<Accordion>\n",
        "  <AccordionItem title=\"Antwort\">\n",
        "    Die Quanteninformatik hat die Chance, die Chemie zu revolutionieren, indem sie Probleme löst, mit denen klassische Computer aufgrund der exponentiellen Skalierung von Quantenzuständen zu kämpfen haben. Richard Feynman bemerkte berühmt, dass Berechnungen, die die Natur simulieren sollen, auch Quantenrechnungen sein müssen \\[ref 1].\n",
        "\n",
        "    Beispielsweise würde die Simulation von Koffein mit dem einfachsten Basissatz ( STO-3G ) $10^{48}$ Bits erfordern, viel mehr als die Gesamtzahl der Sterne im beobachtbaren Universum ( $10^{24}$ ) \\[ref 2]. Ein Quantencomputer kann die elektronischen Orbitale von Koffein mit 160 Qubits beschreiben.\n",
        "\n",
        "    Quantencomputer verarbeiten auf natürliche Weise Quantenwechselwirkungen unter Verwendung von Überlagerung und Verschränkung, was eine vielversprechende Möglichkeit für genaue Molekularsimulationen darstellt. Darüber hinaus können wir die Vorteile von Quantencomputern (Elektronensimulation) und klassischen Computern (Datenvor- und -nachverarbeitung, Verwaltung von Algorithmusprozessen, Optimierung usw.) kombinieren. Es wird erwartet, dass sie die Materialentdeckung, den Entwurf von Arzneimitteln und die Reaktionsvorhersage verbessern und kostspielige Versuch-und-Irrtum-Experimente reduzieren werden. \\[ref 3]\\[ref 4]\n",
        "\n",
        "    Wenn Sie wissen möchten, warum Quantencomputer für chemische Probleme benötigt werden und warum man sowohl Quanten- als auch klassische Rechenressourcen nutzen sollte, lesen Sie die folgenden Artikel:\n",
        "\n",
        "    * [Neue Algorithmen für das Quantencomputing in der Quantenchemie](https://arxiv.org/abs/2109.02873)\n",
        "    * [Chemie jenseits exakter Lösungen auf einem quantenzentrierten Supercomputer](https://arxiv.org/html/2405.05068v1)\n",
        "    * [Quantenzentriertes Supercomputing für die Materialwissenschaft: Eine Perspektive auf Herausforderungen und künftige Richtungen](https://www.sciencedirect.com/science/article/pii/S0167739X24002012)\n",
        "  </AccordionItem>\n",
        "</Accordion>\n",
        "\n",
        "Kehren wir nun zu VQE zurück.\n",
        "\n",
        "VQE kombiniert die Leistung von Quantencomputern mit klassischen Computern, wobei im Wesentlichen Variationsprinzipien verwendet werden, um die Grundzustandsenergie des Systems zu ermitteln. Um VQE zu verstehen, muss man es zunächst in drei Teile zerlegen:\n",
        "\n",
        "![VQE-Arbeitsablauf](https://quantum.cloud.ibm.com/learning/images/modules/computer-science/vqe/vqe.avif)\n",
        "\n",
        "<span id=\"quantum-observable-the-molecular-hamiltonian-energy-of-a-molecule\" />\n",
        "\n",
        "#### (Quanten-)Beobachtbare Größe: Der molekulare Hamilton-Operator (Energie eines Moleküls)\n",
        "\n",
        "In der VQE ist der molekulare/atomare Hamiltonian eine Beobachtungsgröße, das heißt, wir können seinen Wert durch ein Experiment messen. Unser Ziel ist es, die niedrigstmögliche Energie (die Grundzustandsenergie) des Moleküls zu finden. Dazu verwenden wir einen Versuchsquantenzustand, der durch eine parametrisierte Quantenschaltung (Ansatz) erzeugt wird. Wir messen die Beobachtungsgröße und optimieren den Quantenzustand, bis wir die niedrigstmögliche Energie erreichen.\n",
        "\n",
        "Der für den molekularen Hamiltonian verwendete Basissatz bestimmt die Anzahl der erforderlichen Qubits und wirkt sich direkt auf die Genauigkeit der VQE aus. Die Wahl des richtigen Basissatzes ist entscheidend für das Gleichgewicht zwischen Effizienz und Präzision. Um die Berechnungen zu vereinfachen, ohne den Basissatz zu ändern, können wir Strategien wie die Auferlegung von Symmetrie und die Reduzierung des aktiven Raums anwenden. Viele Moleküle haben eine symmetrische Form (wie ein Schmetterling oder eine Schneeflocke), d. h., einige Teile verhalten sich auf die gleiche Weise. Anstatt alles einzeln zu berechnen, können wir uns nur auf einzelne Teile konzentrieren und so Quantenressourcen einsparen und die Symmetrie nutzen. Bei der Aktivraumreduktion werden nur die wichtigen Orbitale berücksichtigt, da nicht alle Elektronen einen signifikanten Einfluss auf die Molekülenergie haben. Die Elektronen in der Nähe des Kerns bleiben meist unverändert, während andere die Bindung beeinflussen. Durch die Anwendung dieser Methoden können wir die VQE effizienter gestalten und gleichzeitig die Genauigkeit beibehalten.\n",
        "\n",
        "Sobald wir einen molekularen Hamiltonian mit dem richtigen Basissatz und den oben genannten Strategien erhalten haben, müssen wir diesen Hamiltonian in einen für Quantencomputer geeigneten umwandeln. Die Zuordnung von Problemen zu Pauli-Operatoren kann recht kompliziert sein. Dies gilt insbesondere für die Quantenchemie, die mit ununterscheidbaren Teilchen (Elektronen) arbeitet, da Qubits unterscheidbar sind. Wir werden hier nicht auf die Einzelheiten der Zuordnungen eingehen, sondern verweisen Sie auf die folgenden Ressourcen. Eine allgemeine Diskussion über die Zuordnung eines Problems zu Quantenoperatoren findet sich in [Quantum computing in practice](/learning/courses/quantum-computing-in-practice/index). Eine ausführlichere Diskussion über die Abbildung von Chemieproblemen in Quantenoperatoren findet sich in [Quantenchemie mit VQE](/learning/courses/quantum-chem-with-vqe/index).\n",
        "\n",
        "Für dieses Modul werden wir Ihnen die entsprechenden (Ein-Qubit-)Hamiltonianer für $H$ und $H_2$ zur Verfügung stellen, damit wir uns auf die Verwendung des Quantencomputers konzentrieren können. Diese Ein-Qubit-Hamiltonianer werden mit Hilfe des [STO-6G](https://en.wikipedia.org/wiki/STO-nG_basis_sets) basissatzes und der [Jordan-Wigner-Abbildung](https://en.wikipedia.org/wiki/Jordan%E2%80%93Wigner_transformation), die die einfachste Abbildung mit der einfachsten physikalischen Interpretation ist, weil sie die Besetzung eines Spin-Orbitals auf die Besetzung eines Qubits abbildet. Außerdem haben wir eine [Qubit-Reduktionstechnik verwendet, indem wir eine Symmetrie des Hamilton-Operators ausnutzten](https://arxiv.org/abs/1701.08213), die die Muster im Verhalten von Spin-Besetzungen nutzt, um die Anzahl der Qubits zu reduzieren. Für das Molekül $H_2$ nehmen wir an, dass der Abstand zwischen den beiden Wasserstoffatomen `0.735` $\\mathring A$ ist.\n",
        "\n",
        "<span id=\"quantum-ansatz-the-trial-wave-function-how-to-build-a-trivial-quantum-state-with-a-quantum-circuit\" />\n",
        "\n",
        "#### (Quanten-)Ansatz: Die Testwellenfunktion (Wie man mit einem Quantenschaltkreis einen trivialen Quantenzustand aufbaut)\n",
        "\n",
        "Bei VQE besteht der Ansatz (Plural: Ansätze) aus zwei Hauptkomponenten. Die erste ist die Vorbereitung des Anfangszustands, bei der der Zustand des Qubits durch die Anwendung von Quantengattern ohne Variationsparameter hergestellt wird. Die zweite Komponente ist der parametrisierte Quantenschaltkreis, ein spezieller Quantenschaltkreis mit einstellbaren Parametern, ähnlich den Reglern eines Radios. Diese Parameter werden für den letzten Teil - den klassischen Optimierer - verwendet, um den bestmöglichen Grundzustand zu erreichen.\n",
        "\n",
        "Im Abschnitt über das Variationsprinzip haben wir gelernt, dass die Qualität des Versuchszustands die Qualität der Ergebnisse des Variationsalgorithmus beeinflusst. Dies bedeutet, dass die Wahl eines guten Ansatzes bei VQE wichtig ist. Auch hier handelt es sich um ein umfangreiches und komplexes Thema. Wir werden hier nicht auf die verschiedenen Arten von Ansätzen oder ihre Ursprünge eingehen. Wenn Sie daran interessiert sind, mehr über parametrisierte Quantenschaltungen und Ansätze zu erfahren, können Sie die Lektion [Ansätze und Variationsformen](/learning/courses/variational-algorithm-design/ansaetze-and-variational-forms) aus dem [Kurs Entwurf von Variationsalgorithmen](/learning/courses/variational-algorithm-design/index) erkunden, die detaillierte Erklärungen und Beispiele zu Ansätzen enthält.\n",
        "\n",
        "Da wir in diesem Modul einen Ein-Qubit-Hamiltonian verwenden werden, benötigen wir einen parametrisierten Ein-Qubit-Quantenkreis als Ansatz. Wir werden im folgenden Abschnitt drei Arten von Ein-Qubit-Ansätzen sehen. Wir werden sie vergleichen und die wichtigsten Überlegungen bei der Auswahl eines Ansatzes diskutieren.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "a8fae507-41e6-4585-8e9d-b45db5055fb9",
      "metadata": {},
      "source": [
        "<span id=\"classical-optimizer-fine-tuning-the-quantum-circuit\" />\n",
        "\n",
        "#### (Klassischer) Optimierer: Feinabstimmung des Quantenschaltkreises\n",
        "\n",
        "Sobald der Quantencomputer die Energie der Beobachtungsgröße aus dem Ansatz misst, werden die Parameter des Ansatzes und der Energiewert zur Abstimmung an den klassischen Optimierer geschickt. Dieser Optimierungsprozess wird auf einem klassischen Computer durchgeführt, typischerweise mit wissenschaftlichen Allzweckpaketen wie SciPy.\n",
        "\n",
        "Der klassische Optimierer behandelt die gemessene Energie als eine Kostenfunktion. Bei Optimierungsproblemen ist eine Kostenfunktion (manchmal auch Zielfunktion genannt) eine mathematische Funktion, die misst, wie \"gut\" eine bestimmte Lösung ist. Das Ziel des Optimierers ist es, den Satz von Parametern zu finden, der diese Kostenfunktion minimiert. Im Zusammenhang mit der Suche nach der Grundzustandsenergie eines Moleküls dient die Energie selbst als Kostenfunktion - wir wollen die Parameter für unseren Quantenkreislauf (unsere \"Lösung\") finden, die die geringstmögliche Energie ergeben. Der klassische Optimierer verwendet diesen gemessenen Energiewert (die Kosten) und bestimmt den nächsten Satz von optimierten Parametern für den Quantenansatz. Diese aktualisierten Parameter werden dann an den Quantenschaltkreis zurückgesendet, und der Vorgang wird wiederholt. Bei jeder Iteration passt der klassische Optimierer die Parameter an, um zu versuchen, die Energie zu reduzieren (die Kostenfunktion zu minimieren), bis ein vordefiniertes Konvergenzkriterium erfüllt ist, das im Idealfall sicherstellt, dass die niedrigstmögliche Energie (die dem Grundzustand des Moleküls für diesen Bindungsabstand und Basissatz entspricht) gefunden wird.\n",
        "\n",
        "Es gibt viele Optimierungsstrategien, die von wissenschaftlichen Paketen wie SciPy bereitgestellt werden. Weitere Informationen finden Sie in der Lektion [Optimierungsschleifen](/learning/courses/variational-algorithm-design/optimization-loops) des Kurses [Entwurf von Variationsalgorithmen](/learning/courses/variational-algorithm-design/index). Hier werden wir COBYLA (Constrained Optimization BY Linear Approximations) verwenden, einen Optimierungsalgorithmus, der für komplizierte Energielandschaften geeignet ist. Insbesondere versucht COBYLA nicht, einen Gradienten der untersuchten Funktion zu berechnen; dies wird als gradientenfreier Optimierer bezeichnet. Stellen Sie sich vor, Sie versuchen, mit geschlossenen Augen den höchsten Gipfel eines Gebirges zu finden. Da man nicht die ganze Landschaft überblicken kann, macht man kleine Schritte in verschiedene Richtungen und prüft dabei, ob man auf- oder absteigt. COBYLA arbeitet auf ähnliche Weise - es bewegt sich durch den Parameterraum, testet verschiedene Werte und verbessert allmählich das Ergebnis, bis es den besten Wert gefunden hat.\n",
        "\n",
        "Jetzt können Sie eine VQE-Berechnung durchführen. Probieren Sie zu diesem Zweck die folgende Check-in-Frage aus, die den gesamten Prozess zusammenfasst.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "8cdcfcc0-a6ca-4153-a11a-bd7b598f9b35",
      "metadata": {},
      "source": [
        "<span id=\"check-your-understanding\" />\n",
        "\n",
        "#### Überprüfen Sie Ihr Verständnis\n",
        "\n",
        "Füllen Sie die Lücken mit den richtigen Begriffen aus, um die Zusammenfassung des VQE-Prozesses zu vervollständigen, und klicken Sie anschließend, um Ihre Antworten zu überprüfen.\n",
        "\n",
        "VQE ist ein Quantenvariationsalgorithmus, der die Möglichkeiten von (1) \\_\\_\\_\\_\\_\\_\\_\\_\\_ und klassischem Rechnen kombiniert, um die (2) \\_\\_\\_\\_\\_\\_\\_\\_\\_\\_\\_\\_\\_ eines Moleküls zu finden. Der Prozess beginnt mit der Definition der (3) \\_\\_\\_\\_\\_\\_\\_\\_\\_\\_\\_\\_, die die Gesamtenergie des Systems darstellt und bei Quantenmessungen als Observable dient. Als Nächstes bereiten wir einen (4) \\_\\_\\_\\_\\_\\_\\_\\_\\_\\_\\_\\_ vor, eine Quantenschaltung mit einstellbaren Parametern, die die Versuchswellenfunktion des Moleküls darstellt. Diese Parameter werden mit einem (5) \\_\\_\\_\\_\\_\\_\\_\\_\\_\\_\\_\\_, einem klassischen Algorithmus, der die Parameter iterativ anpasst, um die gemessene Energie zu minimieren, optimiert. In der obigen Diskussion haben wir den (6) \\_\\_\\_\\_\\_\\_\\_\\_\\_\\_\\_ Optimierer verwendet, der die Ansatzparameter verfeinert, ohne dass Ableitungsrechnungen erforderlich sind. Der Prozess wird fortgesetzt, bis wir (7) \\_\\_\\_\\_\\_\\_\\_\\_\\_\\_\\_\\_ erreichen, was bedeutet, dass wir die niedrigste mögliche Energie des Moleküls gefunden haben.\n",
        "\n",
        "Wortbank:\n",
        "\n",
        "* klassischer Optimierer\n",
        "* grundzustandsenergie\n",
        "* hardware-effizient\n",
        "* ansatz\n",
        "* molekularer Hamiltonian\n",
        "* COBYLA\n",
        "* Quantencomputing\n",
        "* Konvergenz\n",
        "\n",
        "<Accordion>\n",
        "  <AccordionItem title=\"Antwort\">\n",
        "    1 → Quantencomputer\n",
        "\n",
        "    2 → Grundzustandsenergie\n",
        "\n",
        "    3 → molekularer Hamiltonian\n",
        "\n",
        "    4 → Ansatz\n",
        "\n",
        "    5 → klassischer Optimierer\n",
        "\n",
        "    6 → COBYLA\n",
        "\n",
        "    7 → Konvergenz\n",
        "  </AccordionItem>\n",
        "</Accordion>\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "64a090f7-1d18-4edb-bef3-4cea0f4cec2c",
      "metadata": {},
      "source": [
        "<span id=\"compute-the-ground-state-energy-of-a-hydrogen-atom-with-vqe\" />\n",
        "\n",
        "## Berechnen Sie die Grundzustandsenergie eines Wasserstoffatoms mit VQE\n",
        "\n",
        "Nun wollen wir das Gelernte nutzen, um die Energie des Grundzustands eines Wasserstoffatoms zu berechnen. Während des gesamten Moduls werden wir einen Rahmen für das Quantencomputing verwenden, der als \"Qiskit-Muster\" bekannt ist und Arbeitsabläufe in die folgenden Schritte unterteilt:\n",
        "\n",
        "* Schritt 1: Abbildung klassischer Eingaben auf ein Quantenproblem\n",
        "* Schritt 2: Optimieren des Problems für die Quantenausführung\n",
        "* Schritt 3: Ausführung mithilfe von „ IBM Quantum “-Primitiven\n",
        "* Schritt 4: Nachbearbeitung und klassische Analyse\n",
        "\n",
        "![Qiskit-Muster](https://quantum.cloud.ibm.com/learning/images/modules/computer-science/vqe/patterns.svg)\n",
        "\n",
        "Im Allgemeinen werden wir diese Schritte befolgen.\n",
        "\n",
        "Beginnen wir damit, einige erforderliche Pakete zu installieren, darunter die Primitive aus „ IBM Quantum “. Außerdem werden wir den am wenigsten ausgelasteten Quantencomputer auswählen, der uns zur Verfügung steht.\n",
        "\n",
        "Unten finden Sie einen Code, mit dem Sie Ihre Anmeldedaten bei der ersten Verwendung speichern können. Achten Sie darauf, dass Sie diese Informationen aus dem Notebook löschen, nachdem Sie es in Ihrer Umgebung gespeichert haben, damit Ihre Anmeldedaten nicht versehentlich weitergegeben werden, wenn Sie das Notebook freigeben. Weitere Anleitungen finden Sie unter [Einrichten Ihres IBM Cloud Kontos](/docs/guides/initialize-account) und [Initialisieren des Dienstes in einer nicht vertrauenswürdigen Umgebung](/docs/guides/cloud-setup-untrusted).\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "18d9c613-ee5f-4e38-bc83-57d25197b200",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "ibm_brisbane\n"
          ]
        }
      ],
      "source": [
        "# Load IBM Quantum Compute Service\n",
        "from qiskit_ibm_runtime import QiskitRuntimeService\n",
        "\n",
        "# Load the Runtime primitive and session\n",
        "from qiskit_ibm_runtime import EstimatorV2 as Estimator\n",
        "\n",
        "# Syntax for first saving your token.  Delete these lines after saving your credentials.\n",
        "# QiskitRuntimeService.save_account(channel='ibm_quantum_platform',\n",
        "# instance = '<YOUR_IBM_INSTANCE_CRN>', token='<YOUR-API_KEY>', overwrite=True, set_as_default=True)\n",
        "# service = QiskitRuntimeService(channel='ibm_quantum_platform')\n",
        "\n",
        "# Load saved credentials\n",
        "service = QiskitRuntimeService()\n",
        "\n",
        "# Use the least busy backend, or uncomment the loading of a specific backend like \"ibm_brisbane\".\n",
        "backend = service.least_busy(operational=True, simulator=False, min_num_qubits=127)\n",
        "# backend = service.backend(\"ibm_brisbane\")\n",
        "print(backend.name)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "0c4e0ac4-7f4c-4cab-b726-1d6fe1ca10ac",
      "metadata": {},
      "source": [
        "Die Zelle unten ermöglicht es Ihnen, zwischen der Verwendung des Simulators und der realen Hardware während des gesamten Notebooks zu wechseln. Wir empfehlen, ihn jetzt auszuführen:\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 5,
      "id": "4c38f002-c6e6-4fe2-acf1-3cccf3d1f525",
      "metadata": {},
      "outputs": [],
      "source": [
        "# Load the Aer simulator and generate a noise model based on the currently-selected backend.\n",
        "from qiskit_aer import AerSimulator\n",
        "from qiskit_aer.noise import NoiseModel\n",
        "\n",
        "# Alternatively, load a fake backend with generic properties and define a simulator.\n",
        "\n",
        "\n",
        "noise_model = NoiseModel.from_backend(backend)\n",
        "\n",
        "# Define a simulator using Aer, and use it in Sampler.\n",
        "backend_sim = AerSimulator(noise_model=noise_model)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "497acce3-f34c-43b3-a014-630702a3620b",
      "metadata": {},
      "source": [
        "<span id=\"step-1-map-the-problem-to-quantum-circuits-and-operators\" />\n",
        "\n",
        "### Schritt 1: Das Problem auf Quantenschaltungen und Operatoren abbilden\n",
        "\n",
        "Wir beginnen unsere VQE-Berechnung mit der Definition des Hamilton-Operators für das Wasserstoffmolekül ( $H_2$ ) bei einem bestimmten Bindungsabstand. Dieser Hamilton-Operator stellt die Gesamtenergie des Systems in Form von Qubit-Operatoren dar und wurde anhand eines Standardverfahrens aus dem molekularen System abgeleitet und abgebildet: 1) unter Verwendung des Basis-Satzes von STO-6G (einer spezifischen Sammlung mathematischer Funktionen zur Approximation der Elektronenorbitale), 2) Anwendung der Jordan-Wigner-Abbildung (eine Technik zur Übersetzung von Fermionenoperatoren, die Elektronen beschreiben, in Qubit-Operatoren) und 3) Durchführung einer Qubit-Reduktion unter Verwendung der Parität des Hamilton-Operators zur Vereinfachung des Problems.\n",
        "\n",
        "Wie wir bereits erläutert haben, hängen die berechneten Grundzustandsenergien stark von der Auswahl des Basissatzes und der Molekülgeometrie (wie dem Bindungsabstand) ab. Für diese spezifische Konfiguration und nach diesen Transformationen ist der resultierende Qubit-Hamiltonian einfach:\n",
        "\n",
        "$\\hat{H} = -0.2355 I + 0.2355 Z$\n",
        "\n",
        "Dabei steht $I$ für den Identitätsoperator und $Z$ für den Pauli-Z-Operator, der auf ein einzelnes Qubit wirkt. Die Koeffizienten werden aus den Integralen abgeleitet, die unter Verwendung des STO-6G Basissatzes bei diesem bestimmten Bindungsabstand mit der richtigen Transformation berechnet wurden.\n",
        "\n",
        "Mit diesem definierten Hamiltonian können wir nun die VQE verwenden, um die Energie im Grundzustand zu berechnen. Es ist sinnvoll, die von uns berechnete Grundzustandsenergie mit den erwarteten Werten zu vergleichen. Für ein einzelnes, isoliertes Wasserstoffatom (H) beträgt die Grundzustandsenergie genau -0.5 Hartree (bei Abwesenheit relativistischer Effekte). Berechnen wir die exakte Grundzustandsenergie *unseres spezifischen Qubit-Hamiltonianers*, wie er oben definiert wurde, und vergleichen wir sie mit den einschlägigen bekannten Werten.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 6,
      "id": "aaef7daa-6dbe-4a2e-abe2-3ad2a0baa860",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "The exact ground state energy of the Hamiltonian is  -0.471 hartree\n"
          ]
        }
      ],
      "source": [
        "from qiskit.quantum_info import SparsePauliOp\n",
        "import numpy as np\n",
        "\n",
        "# Qubit Hamiltonian of the hydrogen atom generated by using STO-3G basis set and parity mapping\n",
        "Hamiltonian = SparsePauliOp.from_list([(\"I\", -0.2355), (\"Z\", 0.2355)])\n",
        "\n",
        "# exact ground state energy of Hamiltonian\n",
        "\n",
        "A = np.array(Hamiltonian)\n",
        "eigenvalues, eigenvectors = np.linalg.eig(A)\n",
        "print(\n",
        "    \"The exact ground state energy of the Hamiltonian is \",\n",
        "    min(eigenvalues).real,\n",
        "    \"hartree\",\n",
        ")\n",
        "h = min(eigenvalues.real)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "ec53e133-d8ab-4e5d-a44a-428fe8095aee",
      "metadata": {},
      "source": [
        "Als Nächstes benötigen wir einen parametrisierten Quantenschaltkreis, einen Ansatz, um eine Versuchswellenfunktion $\\Psi_\\text{trial}$ für den Grundzustand zu erstellen. Das Ziel ist es, die Parameter $\\theta$ zu finden, die den Energieerwartungswert $\\langle\\psi(\\theta)|\\hat{H}|\\psi(\\theta)\\rangle$ minimieren. Die Wahl des Ansatzes ist von entscheidender Bedeutung, denn sie bestimmt die Menge der möglichen Quantenzustände, die unser Schaltkreis vorbereiten kann. Ein \"guter\" Ansatz ist ein Ansatz, der flexibel genug ist, um einen Zustand darzustellen, der dem wahren Grundzustand des von uns untersuchten Hamiltonianers sehr nahe kommt, der aber nicht so komplex ist, dass er zu viele Parameter oder zu tiefe Schaltkreise für aktuelle Quantencomputer erfordert.\n",
        "\n",
        "Hier werden wir drei verschiedene Ein-Qubit-Ansätze ausprobieren, um zu sehen, welcher davon die möglichen Quantenzustände, die ein einzelnes Qubit einnehmen kann, besser \"abdeckt\". Die \"Abdeckung\" bezieht sich auf den Bereich der Quantenzustände, die der Ansatzschaltkreis durch Variation seiner Parameter erzeugen kann.\n",
        "\n",
        "Wir werden drei Ansätze verwenden, die auf verschiedenen Kombinationen von Ein-Qubit-Rotationsgattern basieren:\n",
        "\n",
        "* Ein 1-Achsen-Rotationstor-Ansatz: Dieser Ansatz verwendet Rotationen um nur eine einzige Achse ( $R_x(\\theta)$ ). Auf der Bloch-Kugel entspricht dies einer Bewegung nur entlang eines bestimmten Kreises. Diese Option ist am wenigsten flexibel und deckt nur eine begrenzte Anzahl von Staaten ab.\n",
        "* Zwei 2-Achsen-Rotationsgatteransätze: Diese Ansätze kombinieren Rotationen um zwei verschiedene Achsen ( $R_x(\\theta_1) R_z(\\theta_2)$ und $R_x(\\theta_1) R_z(\\theta_2) R_x(\\theta_3)$ ). Dadurch können wir einen größeren Teil der Bloch-Kugel erreichen als mit einer einachsigen Drehung.\n",
        "\n",
        "Der Vergleich der mit diesen drei Ansätzen erzielten VQE-Ergebnisse zeigt, wie sich die Flexibilität und die Zustandsraumabdeckung des Ansatzes auf unsere Fähigkeit auswirken, die wahre Grundzustandsenergie unseres vereinfachten Hamiltonians zu finden. Ein flexiblerer Ansatz hat das *Potenzial,* eine bessere Annäherung zu finden, aber er könnte auch schwieriger für den klassischen Optimierer sein.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 7,
      "id": "653b257f-9975-4bd3-9c48-a046ec4a9fae",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<qiskit.circuit.instructionset.InstructionSet at 0x1059def80>"
            ]
          },
          "execution_count": 7,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "from qiskit import QuantumCircuit\n",
        "from qiskit.circuit import Parameter\n",
        "from qiskit.quantum_info import Statevector, DensityMatrix, Pauli\n",
        "\n",
        "theta = Parameter(\"θ\")\n",
        "phi = Parameter(\"φ\")\n",
        "lam = Parameter(\"λ\")\n",
        "\n",
        "ansatz1 = QuantumCircuit(1)\n",
        "ansatz1.rx(theta, 0)\n",
        "\n",
        "ansatz2 = QuantumCircuit(1)\n",
        "ansatz2.rx(theta, 0)\n",
        "ansatz2.rz(phi, 0)\n",
        "\n",
        "ansatz3 = QuantumCircuit(1)\n",
        "ansatz3.rx(theta, 0)\n",
        "ansatz3.rz(phi, 0)\n",
        "ansatz3.rx(lam, 0)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "26707a66-7098-4f57-93fc-eb1cb4c305f7",
      "metadata": {},
      "source": [
        "Erzeugen wir nun 5000 Zufallszahlen für jeden Parameter und zeichnen wir die Verteilung der zufälligen Quantenzustände auf, die von den drei Ansätzen mit diesen Zufallsparametern erzeugt werden. Sie können sich diese Parameter wie Drehungen um verschiedene Achsen auf einer Kugeloberfläche vorstellen. Um die Verteilung des Quantenzustands zu sehen, verwenden wir [die Bloch-Kugel](https://en.wikipedia.org/wiki/Bloch_sphere), eine dreidimensionale Kugel, die den Zustand eines einzelnen Qubits darstellt. Jeder Punkt auf der Kugel stellt einen möglichen Zustand des Qubits dar, wobei der Nord- und der Südpol wie die klassische \"0\" und \"1\" sind, das Qubit aber auch irgendwo dazwischen liegen kann, was spezielle Quanteneigenschaften wie Überlagerung zeigt. Bereiten Sie zunächst die notwendigen Funktionen für die Darstellung der 3D Bloch-Kugel vor und bereiten Sie 5000 Zufallsparameter vor.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 8,
      "id": "6e47463b-b0c2-44cd-b099-9f50f38ebd0e",
      "metadata": {},
      "outputs": [],
      "source": [
        "import matplotlib.pyplot as plt\n",
        "\n",
        "\n",
        "def plot_bloch(bloch_vectors):\n",
        "    # Extract X, Y, Z coordinates for 3D projection\n",
        "    X_coords = bloch_vectors[:, 0]\n",
        "    Z_coords = bloch_vectors[:, 2]\n",
        "\n",
        "    # Compute Y coordinates from X and Z to approximate the full Bloch sphere projection\n",
        "    Y_coords = bloch_vectors[:, 1]\n",
        "\n",
        "    # Create 3D plot\n",
        "    fig = plt.figure(figsize=(8, 8))\n",
        "    ax = fig.add_subplot(111, projection=\"3d\")\n",
        "    ax.scatter(X_coords, Y_coords, Z_coords, color=\"blue\", alpha=0.6)\n",
        "\n",
        "    # Labels and title\n",
        "    ax.set_xlabel(\"X\")\n",
        "    ax.set_ylabel(\"Y\")\n",
        "    ax.set_zlabel(\"Z\")\n",
        "    ax.set_title(\"Parameterized 1-Qubit Circuit on 3D Bloch Sphere\")\n",
        "\n",
        "    # Set axis limits and make them equal\n",
        "    ax.set_xlim([-1, 1])\n",
        "    ax.set_ylim([-1, 1])\n",
        "    ax.set_zlim([-1, 1])\n",
        "\n",
        "    # Ensure equal aspect ratio for all axes\n",
        "    ax.set_box_aspect([1, 1, 1])  # Equal scaling for x, y, z axes\n",
        "\n",
        "    # Show grid\n",
        "    ax.grid(True)\n",
        "\n",
        "    plt.show()\n",
        "\n",
        "\n",
        "num_samples = 5000  # Number of random states\n",
        "theta_vals = np.random.uniform(0, 2 * np.pi, num_samples)\n",
        "phi_vals = np.random.uniform(0, 2 * np.pi, num_samples)\n",
        "lam_vals = np.random.uniform(0, 2 * np.pi, num_samples)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "af24b916-fa42-4c4c-8e22-098adfb4fcd5",
      "metadata": {},
      "source": [
        "Schauen wir uns an, wie unser erster Ansatz funktioniert.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 9,
      "id": "6471a5d1-287a-4726-9e65-e23ef77ccf75",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/modules/computer-science/vqe/extracted-outputs/f7d886a0-d410-418d-a7a3-81a9134cbfd0-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "# List to store Bloch Sphere XZ coordinates\n",
        "bloch_vectors = []\n",
        "\n",
        "# Generate quantum states and extract Bloch vectors\n",
        "for i in range(num_samples):\n",
        "    # Create a circuit and bind parameters\n",
        "    qc = ansatz1\n",
        "    bound_qc = qc.assign_parameters({theta: theta_vals[i]})  # , lam: lam_vals[i]})\n",
        "    state = Statevector.from_instruction(bound_qc)\n",
        "    rho = DensityMatrix(state)\n",
        "\n",
        "    X = rho.expectation_value(Pauli(\"X\")).real\n",
        "    Y = rho.expectation_value(Pauli(\"Y\")).real\n",
        "    Z = rho.expectation_value(Pauli(\"Z\")).real\n",
        "    bloch_vectors.append([X, Y, Z])  # Store X, Z components\n",
        "\n",
        "# Convert to a numpy array for plotting\n",
        "bloch_vectors = np.array(bloch_vectors)\n",
        "\n",
        "plot_bloch(bloch_vectors)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "9cb7d81e-8df5-4557-8452-98f794bdc5cd",
      "metadata": {},
      "source": [
        "Wir können sehen, dass unser erster Ansatz einen ringförmig verteilten Quantenzustand der Bloch-Kugel ergibt. Dies ist sinnvoll, da wir dem Ansatz nur einen einzigen Rotationsparameter gegeben haben. Sie kann daher nur um eine Achse gedrehte Zustände erzeugen. Ausgehend von dem Punkt $(0,0,1)$ und einer Drehung um eine Achse ergibt sich immer ein Ring. Prüfen wir nun unseren zweiten Ansatz, der zwei orthogonale Drehtore hat - `Rx` und `Rz`.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 10,
      "id": "9cd86049-f652-4e76-a68a-2780cb7782db",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/modules/computer-science/vqe/extracted-outputs/607e4c0f-cb14-4036-901b-021cc8e11b79-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "bloch_vectors = []\n",
        "\n",
        "# Generate quantum states and extract Bloch vectors\n",
        "for i in range(num_samples):\n",
        "    # Create circuit and bind parameters\n",
        "    qc = ansatz2\n",
        "    bound_qc = qc.assign_parameters(\n",
        "        {theta: theta_vals[i], phi: phi_vals[i]}\n",
        "    )  # , lam: lam_vals[i]})\n",
        "    state = Statevector.from_instruction(bound_qc)\n",
        "    rho = DensityMatrix(state)\n",
        "\n",
        "    X = rho.expectation_value(Pauli(\"X\")).real\n",
        "    Y = rho.expectation_value(Pauli(\"Y\")).real\n",
        "    Z = rho.expectation_value(Pauli(\"Z\")).real\n",
        "    bloch_vectors.append([X, Y, Z])  # Store X, Z components\n",
        "\n",
        "# Convert to numpy array for plotting\n",
        "bloch_vectors = np.array(bloch_vectors)\n",
        "\n",
        "plot_bloch(bloch_vectors)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "e3fde737-d565-4200-a968-c6a6c78dfe30",
      "metadata": {},
      "source": [
        "Hier können wir sehen, dass unser zweiter Ansatz einen größeren Teil der Bloch-Kugel abdeckt - aber beachten Sie, dass die Punkte um die Pole konzentrierter und um den Äquator verteilter sind. Nun ist es an der Zeit, unseren letzten Ansatz zu überprüfen.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 11,
      "id": "ec2e9a84-46b2-4143-8cde-d981e9edd3ce",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/modules/computer-science/vqe/extracted-outputs/21ff021a-7cfe-4ba9-a827-edac71c0871c-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "bloch_vectors = []\n",
        "\n",
        "# Generate quantum states and extract Bloch vectors\n",
        "for i in range(num_samples):\n",
        "    # Create circuit and bind parameters\n",
        "    qc = ansatz3\n",
        "    bound_qc = qc.assign_parameters(\n",
        "        {theta: theta_vals[i], phi: phi_vals[i], lam: lam_vals[i]}\n",
        "    )\n",
        "    state = Statevector.from_instruction(bound_qc)\n",
        "    rho = DensityMatrix(state)\n",
        "\n",
        "    X = rho.expectation_value(Pauli(\"X\")).real\n",
        "    Y = rho.expectation_value(Pauli(\"Y\")).real\n",
        "    Z = rho.expectation_value(Pauli(\"Z\")).real\n",
        "    bloch_vectors.append([X, Y, Z])  # Store X, Z components\n",
        "\n",
        "# Convert to numpy array for plotting\n",
        "bloch_vectors = np.array(bloch_vectors)\n",
        "\n",
        "plot_bloch(bloch_vectors)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "ca886db5-e7c7-4f5c-8594-50f79fbc61dd",
      "metadata": {},
      "source": [
        "Hier sehen Sie gleichmäßig verteilte Quantenzustände, die durch unseren letzten Ansatz erzeugt wurden.\n",
        "\n",
        "Wie bereits erwähnt, ist es am besten, Kenntnisse über den gesuchten Grundzustand zu erlangen und einen Ansatz zu verwenden, der gut geeignet ist, um Zustände in der Nähe dieses Grundzustands zu untersuchen. Wenn wir zum Beispiel wüssten, dass unser Grundzustand in der Nähe eines Pols liegt, könnten wir Satz 2 wählen. Der Einfachheit halber bleiben wir bei Satz 3, der die gesamte Bloch-Sphäre gleichmäßig abtastet.\n",
        "\n",
        "Nachdem wir nun unseren Ansatz ausgewählt haben, zeichnen wir die Schaltung.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "9f0c76d9-b4b2-46dc-a261-7c624c031177",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "This circuit has  3 parameters\n"
          ]
        },
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/modules/computer-science/vqe/extracted-outputs/20221e72-51dc-49d9-8a09-9b64de7f535f-1.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 12,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "# Pre-defined ansatz circuit and operator class for Hamiltonian\n",
        "\n",
        "ansatz = ansatz3\n",
        "\n",
        "num_params = ansatz.num_parameters\n",
        "print(\"This circuit has \", num_params, \"parameters\")\n",
        "\n",
        "ansatz.draw(\"mpl\", style=\"iqp\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "b7dc624b-37bc-4523-8532-e45c7826ce64",
      "metadata": {},
      "source": [
        "<span id=\"step-2-optimize-for-target-hardware\" />\n",
        "\n",
        "### Schritt 2: Für die Zielhardware optimieren\n",
        "\n",
        "Wenn wir eine Berechnung auf einem echten Quantencomputer durchführen, interessiert uns nicht nur die Logik der Quantenschaltung. Es geht auch darum, welche Operationen der jeweilige Quantencomputer ausführen kann und wo auf dem Quantencomputer sich die Qubits befinden, die wir verwenden. Stehen sie direkt nebeneinander? Sind sie weit voneinander entfernt? Daher besteht der nächste Schritt darin, unsere Schaltung mit Gattern umzuschreiben, die für den von uns verwendeten Quantencomputer geeignet sind, und die Anordnung der Qubits zu berücksichtigen. Dies kann durch `transpilation` geschehen - nach diesem Prozess können Sie sehen, wie unser einfacher Ansatz in einen anderen Satz von Gattern umgewandelt wird, und unsere abstrakten Qubits werden auf einem realen Quantencomputer in physikalische Qubits abgebildet.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 13,
      "id": "d4f50ff9-cdf4-483f-9bb8-5814fe5acc53",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Backend: {config.backend_name}\n",
            "Native gates:  ['ecr', 'id', 'delay', 'measure', 'reset', 'rz', 'sx', 'x'] ,\n"
          ]
        },
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/modules/computer-science/vqe/extracted-outputs/b5e08232-d651-4df4-bcb7-533513144eff-1.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 13,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager\n",
        "\n",
        "config = backend.configuration()\n",
        "\n",
        "print(\"Backend: {config.backend_name}\")\n",
        "print(\"Native gates: \", config.supported_instructions, \",\")\n",
        "\n",
        "\n",
        "target = backend.target\n",
        "\n",
        "pm = generate_preset_pass_manager(target=target, optimization_level=3)\n",
        "\n",
        "ansatz_isa = pm.run(ansatz)\n",
        "\n",
        "ansatz_isa.draw(output=\"mpl\", idle_wires=False, style=\"iqp\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "04feccf8-4591-4919-90ba-9b0d72e1b436",
      "metadata": {},
      "source": [
        "Sie können sehen, dass die `rx, rz` Gatter unseres Ansatzes in eine Reihe von `rz, sx` Gattern umgewandelt wurden, die die nativen Gatter unseres Backends sind. Außerdem können Sie sehen, dass unsere `q0` jetzt auf das fünfte physikalische Qubit abgebildet ist. Wir müssen auch unseren Hamiltonian entsprechend diesen Änderungen abbilden, wie im folgenden Code:\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 14,
      "id": "2e105b4d-8c3c-4b1e-9652-9857ee9e5465",
      "metadata": {},
      "outputs": [],
      "source": [
        "Hamiltonian_isa = Hamiltonian.apply_layout(layout=ansatz_isa.layout)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "d3212dfa-da89-43d6-85ce-6200ecf9ca09",
      "metadata": {},
      "source": [
        "<span id=\"step-3-execute-on-target-hardware\" />\n",
        "\n",
        "### Schritt 3: Auf der Zielhardware ausführen\n",
        "\n",
        "Nun ist es an der Zeit, unsere VQE auf einer echten QPU laufen zu lassen. Dazu benötigen wir zunächst eine Kostenfunktion für den Optimierungsprozess, die den Erwartungswert des Hamiltonianers mit einem Quantenzustand, der durch den Ansatz erzeugt wird, auswertet. Kein Problem! Sie brauchen nicht alles selbst zu programmieren. Wir haben dafür eine Funktion vorbereitet, und alles, was Sie tun müssen, ist, die Zelle unten auszuführen.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 15,
      "id": "6b2178bd-6e86-4178-b82b-f7a6d7e95022",
      "metadata": {},
      "outputs": [],
      "source": [
        "def cost_func(params, ansatz, hamiltonian, estimator):\n",
        "    \"\"\"Return estimate of energy from estimator\n",
        "\n",
        "    Parameters:\n",
        "        params (ndarray): Array of ansatz parameters\n",
        "        ansatz (QuantumCircuit): Parameterized ansatz circuit\n",
        "        hamiltonian (SparsePauliOp): Operator representation of Hamiltonian\n",
        "        estimator (EstimatorV2): Estimator primitive instance\n",
        "        cost_history_dict: Dictionary for storing intermediate results\n",
        "\n",
        "    Returns:\n",
        "        float: Energy estimate\n",
        "    \"\"\"\n",
        "    pub = (ansatz, [hamiltonian], [params])\n",
        "    result = estimator.run(pubs=[pub]).result()\n",
        "    energy = result[0].data.evs[0]\n",
        "\n",
        "    cost_history_dict[\"iters\"] += 1\n",
        "    cost_history_dict[\"prev_vector\"] = params\n",
        "    cost_history_dict[\"cost_history\"].append(energy)\n",
        "    print(f\"Iters. done: {cost_history_dict['iters']} [Current cost: {energy}]\")\n",
        "\n",
        "    return energy"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "83ed09be-d475-4d66-b55f-b25bbf3412c8",
      "metadata": {},
      "source": [
        "Schließlich bereiten wir Anfangsparameter für unseren Ansatz und seinen Optimierungsprozess vor. Sie können einfach alle Nullen oder Zufallswerte verwenden. Wir haben unten die Anfangsparameter ausgewählt, aber es steht Ihnen frei, die Zeilen in der Zelle zu kommentieren oder zu entkommentieren, um die Parameter nach dem Zufallsprinzip und gleichmäßig von 0 bis $2\\pi$ zu wählen.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 16,
      "id": "b2a5dab1-f724-48df-b84b-20749ffd5261",
      "metadata": {},
      "outputs": [],
      "source": [
        "# x0 = np.random.uniform(0, 2*pi, 3)\n",
        "x0 = [1, 1, 0]"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "5b48b37d-1f1e-4aef-9fd5-ba594db832b0",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Iters. done: 1 [Current cost: -0.3361517318448143]\n",
            "Iters. done: 2 [Current cost: -0.4682546422099432]\n",
            "Iters. done: 3 [Current cost: -0.38985802144149584]\n",
            "Iters. done: 4 [Current cost: -0.38319217316749354]\n",
            "Iters. done: 5 [Current cost: -0.4628720756579032]\n",
            "Iters. done: 6 [Current cost: -0.4683301936226905]\n",
            "Iters. done: 7 [Current cost: -0.45480498699294747]\n",
            "Iters. done: 8 [Current cost: -0.4690533242050814]\n",
            "Iters. done: 9 [Current cost: -0.465867415110354]\n",
            "Iters. done: 10 [Current cost: -0.4606882723137227]\n"
          ]
        }
      ],
      "source": [
        "# QPU Est. 2min for ibm_brisbane\n",
        "\n",
        "from scipy.optimize import minimize\n",
        "from qiskit_ibm_runtime import Batch\n",
        "\n",
        "batch = Batch(backend=backend)\n",
        "\n",
        "cost_history_dict = {\n",
        "    \"prev_vector\": None,\n",
        "    \"iters\": 0,\n",
        "    \"cost_history\": [],\n",
        "}\n",
        "estimator = Estimator(mode=batch)\n",
        "estimator.options.default_shots = 10000\n",
        "\n",
        "res = minimize(\n",
        "    cost_func,\n",
        "    x0,\n",
        "    args=(ansatz_isa, Hamiltonian_isa, estimator),\n",
        "    method=\"cobyla\",\n",
        "    options={\"maxiter\": 10, \"tol\": 0.01},\n",
        ")\n",
        "\n",
        "batch.close()"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 19,
      "id": "124e15d2-ddce-4201-9f69-03c9e5612644",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "The reference ground state energy is  (-0.471+0j)\n",
            "The computed ground state energy is  -0.4690533242050814\n"
          ]
        }
      ],
      "source": [
        "h_vqe = res.fun\n",
        "print(\"The reference ground state energy is \", min(eigenvalues))\n",
        "print(\"The computed ground state energy is \", h_vqe)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "79bce65c-d84e-4bed-bfe8-71f448290fd1",
      "metadata": {},
      "source": [
        "Glückwunsch! Sie haben gerade Ihr erstes quantenchemisches Experiment erfolgreich abgeschlossen. Es ist ein Unterschied zwischen der exakten Grundzustandsenergie des Hamiltonian und unserer zu erkennen, aber da wir eine Standard-Fehlerminderungstechnik verwendet haben (die Auslesefehler korrigiert), ist der Unterschied gering. Das ist ein sehr guter Anfang!\n",
        "\n",
        "Hinweis: Sie können ein besseres Ergebnis erzielen, indem Sie mit die Stufe der [`resilience_level`](/docs/guides/error-mitigation-and-suppression-techniques)Fehlerbehebung festlegen. Der Standardwert ist 1. Wenn Sie einen höheren Wert festlegen, wird mehr QPU-Zeit benötigt, aber möglicherweise ein besseres Ergebnis erzielt.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "dae9eeb5-a2ac-4632-90cf-d2ac70182c7b",
      "metadata": {},
      "source": [
        "<span id=\"step-4-post-process\" />\n",
        "\n",
        "### Schritt 4: Nachbearbeitung\n",
        "\n",
        "Es ist an der Zeit, einen Blick darauf zu werfen, wie unser klassischer Optimierer funktioniert. Führen Sie die untenstehende Zelle aus und sehen Sie sich das Konvergenzmuster an.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 20,
      "id": "b6b32cce-cbfa-4566-9d77-e511f54cc558",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/modules/computer-science/vqe/extracted-outputs/bee036cf-1255-4b4c-881b-cae6e903e09a-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "fig, ax = plt.subplots()\n",
        "x = np.linspace(0, 10, 10)\n",
        "\n",
        "# Define the constant function\n",
        "y_constant = np.full_like(x, h)\n",
        "ax.plot(\n",
        "    range(cost_history_dict[\"iters\"]), cost_history_dict[\"cost_history\"], label=\"VQE\"\n",
        ")\n",
        "ax.set_xlabel(\"Iterations\")\n",
        "ax.set_ylabel(\"Cost (Hartree)\")\n",
        "ax.plot(y_constant, label=\"Target\")\n",
        "plt.legend()\n",
        "plt.draw()"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "909ed768-080d-42b2-aae5-0fe6fa4f088b",
      "metadata": {},
      "source": [
        "Wir begannen mit einem recht guten Ausgangswert, so dass wir in nur 10 Schritten einen guten Endwert erreichten. Sie können große und kleine Spitzen sehen, und das ist das typische Merkmal des COBYLA-Optimierers - er durchsucht den Raum, als ob er die Landschaft nicht sehen könnte, und passt die Schrittgrößen mit jeder Messung an.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "4b3fe46b-fb4e-48d4-a891-732231429926",
      "metadata": {},
      "source": [
        "<span id=\"check-your-understanding\" />\n",
        "\n",
        "#### Überprüfen Sie Ihr Verständnis\n",
        "\n",
        "Was ist Ihre Beobachtung? Welcher Teil des obigen Prozesses kann verbessert werden, um Ergebnisse zu erhalten, die näher an den theoretischen Werten oder näher an der genauen Grundzustandsenergie des Hamiltonianers liegen? Was gibt es dabei zu beachten?\n",
        "\n",
        "<Accordion>\n",
        "  <AccordionItem title=\"Antwort\">\n",
        "    Der erste Punkt ist die Änderung der Basen, die für die Berechnung des Hamiltonian der Moleküle verwendet werden. Wie bereits erwähnt, ist die Grundzustandsenergie des H-Atoms bekanntlich -0.5 Hartree, und die von uns gewählte Basis STO-6G reicht nicht aus, um diesen Wert genau abzuleiten.\n",
        "\n",
        "    Die Wahl einer komplexeren Basis erhöht die Anzahl der vom Hamiltonian verwendeten Qubits; daher müssen wir einen komplexeren und geeigneteren Ansatz für chemische Probleme wählen.\n",
        "\n",
        "    Als Nächstes muss die Rauschunterdrückung in der QPU optimiert werden. Fortschrittlichere Techniken zur Fehlerbegrenzung führen zu besseren Ergebnissen, können aber länger dauern. Berücksichtigen Sie auch, wie die Website `shot_number` die Ergebnisse beeinflusst.\n",
        "\n",
        "    Schließlich kann eine bessere Konvergenzleistung auch durch das Ausprobieren verschiedener Optimierer erreicht werden.\n",
        "  </AccordionItem>\n",
        "</Accordion>\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "52e936bb-a9af-4355-94a1-82393a25124e",
      "metadata": {},
      "source": [
        "<span id=\"compute-the-ground-state-energy-of-the-hydrogen-molecule-with-vqe\" />\n",
        "\n",
        "## Berechnen Sie die Grundzustandsenergie des Wasserstoffmoleküls mit VQE\n",
        "\n",
        "Nachdem wir uns den Gesamtprozess der VQE anhand von $H$ Atomen angesehen haben, werden wir nun die Grundzustandsenergie des $H_2$ Moleküls schneller berechnen.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "bcd4b1e5-aea5-4509-af22-661937b4286d",
      "metadata": {},
      "source": [
        "<span id=\"step-1-map-the-problem-to-quantum-circuits-and-operators\" />\n",
        "\n",
        "### Schritt 1: Das Problem auf Quantenschaltungen und Operatoren abbilden\n",
        "\n",
        "Hier stellen wir Ihnen auch einen Ein-Qubit-Hamiltonian zur Verfügung, der die Basis STO-6G und die Jordan-Wigner-Transformation verwendet, mit einer Qubit-Reduktion durch Verwendung einer Symmetrie des Hamiltonian. Beachten Sie, dass wir einen atomaren Abstand zwischen zwei Wasserstoffatomen von `0.735` $\\mathring A$ verwendet haben.\n",
        "\n",
        "Anders als bei der Berechnung eines einzelnen Wasserstoffatoms ( $H$ ) muss bei der Berechnung des Grundzustands eines Wasserstoffmoleküls ( $H_2$ ) neben der Energie der elektronischen Orbitale auch die Abstoßungskraft zwischen den Kernen der beiden Wasserstoffatome berücksichtigt werden. In diesem Schritt geben wir diesen Wert als Konstante an, und wir werden diesen Wert im Check-in-Problem tatsächlich berechnen. $\\hat{H} = -1.04886 I + -0.79674 Z + 0.18122 X$\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 21,
      "id": "3722816b-8710-4c61-9da9-a347556496e6",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Electronic ground state energy (Hartree):  -1.8659468547627318\n",
            "Nuclear repulsion energy (Hartree):  0.71997\n",
            "Total ground state energy (Hartree):  -1.1459768547627318\n"
          ]
        }
      ],
      "source": [
        "h2_hamiltonian = SparsePauliOp.from_list(\n",
        "    [(\"I\", -1.04886087), (\"Z\", -0.7967368), (\"X\", 0.18121804)]\n",
        ")\n",
        "\n",
        "# exact ground state energy of hamiltonian\n",
        "nuclear_repulsion = 0.71997\n",
        "A = np.array(h2_hamiltonian)\n",
        "eigenvalues, eigenvectors = np.linalg.eig(A)\n",
        "print(\"Electronic ground state energy (Hartree): \", min(eigenvalues).real)\n",
        "print(\"Nuclear repulsion energy (Hartree): \", nuclear_repulsion)\n",
        "print(\n",
        "    \"Total ground state energy (Hartree): \", min(eigenvalues).real + nuclear_repulsion\n",
        ")\n",
        "h2 = min(eigenvalues).real + nuclear_repulsion"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "7e275302-80ea-454b-83c1-d70b09b37442",
      "metadata": {},
      "source": [
        "<span id=\"step-2-optimize-for-target-hardware\" />\n",
        "\n",
        "### Schritt 2: Für die Zielhardware optimieren\n",
        "\n",
        "Da die Anzahl der Qubits, die von der vorherigen VQE und dem Hamiltonian verwendet werden, die gleiche ist wie das Backend, das für die Ausführung verwendet werden soll, werden wir den bestehenden Ansatz und seine optimierte Form verwenden.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 22,
      "id": "6a461ab3-fbd7-493a-aaad-e47d6bfd0079",
      "metadata": {},
      "outputs": [],
      "source": [
        "h2_hamiltonian_isa = h2_hamiltonian.apply_layout(layout=ansatz_isa.layout)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "da36cda3-94a8-4b2d-9e3d-3b5ac957c180",
      "metadata": {},
      "source": [
        "<span id=\"step-3-execute-on-target-hardware\" />\n",
        "\n",
        "### Schritt 3: Auf der Zielhardware ausführen\n",
        "\n",
        "Jetzt ist es an der Zeit, die Berechnungen für die eigentliche QPU durchzuführen. Fast alles ist gleich, aber wir werden den entsprechenden Ausgangspunkt verwenden, um den Hamiltonian anzupassen. Außerdem werden in einem iterativen Teil einige der Einstellungen von `Estimator`, die zur Berechnung der Erwartungen des Hamiltonianers für den Ansatz in der QPU verwendet werden, etwas anders eingestellt als in den vorherigen Berechnungen. Wir werden diese Änderung in einer Check-in-Frage weiter erörtern.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 23,
      "id": "b5afe148-bfdc-4d77-895c-d58afc118d9e",
      "metadata": {},
      "outputs": [],
      "source": [
        "x0 = [2, 0, 0]"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 45,
      "id": "3fb2e079-1413-4fd2-a3db-da5d11fe58d5",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Iters. done: 1 [Current cost: -0.710621837568328]\n",
            "Iters. done: 2 [Current cost: -0.2603208441168329]\n",
            "Iters. done: 3 [Current cost: -0.25548711201326424]\n",
            "Iters. done: 4 [Current cost: -0.581129450619904]\n",
            "Iters. done: 5 [Current cost: -1.722920997605439]\n",
            "Iters. done: 6 [Current cost: -1.6633324849371915]\n",
            "Iters. done: 7 [Current cost: -1.8066989598929164]\n",
            "Iters. done: 8 [Current cost: -1.8051093803839542]\n",
            "Iters. done: 9 [Current cost: -1.802692217571555]\n",
            "Iters. done: 10 [Current cost: -1.8233585485263144]\n",
            "Iters. done: 11 [Current cost: -1.6904116652617205]\n",
            "Iters. done: 12 [Current cost: -1.8245120321245392]\n",
            "Iters. done: 13 [Current cost: -1.6837021361383608]\n",
            "Iters. done: 14 [Current cost: -1.8166632606115467]\n",
            "Iters. done: 15 [Current cost: -1.863446212658907]\n"
          ]
        }
      ],
      "source": [
        "# QPU time 4min for ibm_brisbane\n",
        "batch = Batch(backend=backend)\n",
        "\n",
        "cost_history_dict = {\n",
        "    \"prev_vector\": None,\n",
        "    \"iters\": 0,\n",
        "    \"cost_history\": [],\n",
        "}\n",
        "estimator = Estimator(mode=batch)\n",
        "estimator.options.default_shots = 10000\n",
        "\n",
        "res = minimize(\n",
        "    cost_func,\n",
        "    x0,\n",
        "    args=(ansatz_isa, h2_hamiltonian_isa, estimator),\n",
        "    method=\"cobyla\",\n",
        "    options={\"maxiter\": 15},\n",
        ")\n",
        "\n",
        "batch.close()"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 46,
      "id": "4edf1dbd-8363-4d0d-a4ca-2223719c7059",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "The reference ground state energy is  -1.1459768547627318\n",
            "The computed ground state energy is  -1.143476212658907\n"
          ]
        }
      ],
      "source": [
        "h2_vqe = res.fun + nuclear_repulsion\n",
        "print(\n",
        "    \"The reference ground state energy is \", min(eigenvalues).real + nuclear_repulsion\n",
        ")\n",
        "print(\"The computed ground state energy is \", h2_vqe)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "0d30fbc5-8f52-4b84-b9a6-55b3432bbec5",
      "metadata": {},
      "source": [
        "Obwohl die VQE theoretisch eine obere Schranke für die wahre Grundzustandsenergie darstellt, können praktische Implementierungen auf realer oder verrauschter simulierter Quantenhardware sowie Näherungen bei der Erstellung des Hamiltonians (wie Basissätze oder Qubit-Reduktion) Fehler einführen, die manchmal zu einer gemessenen Energie führen, die geringfügig niedriger ist als der exakte theoretische Wert oder eine bestimmte numerische Referenz. Trotz einiger Fehler scheinen die Ergebnisse zufriedenstellend zu sein, insbesondere in Anbetracht der geringen Anzahl von Schritten. Lassen Sie uns nun diese VQE-Berechnung abschließen, indem wir uns ansehen, wie der Optimierer arbeitet.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "5d5c88de-fcd1-4ef6-8055-01505d86d07e",
      "metadata": {},
      "source": [
        "<span id=\"step-4-post-process\" />\n",
        "\n",
        "### Schritt 4: Nachbearbeitung\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 52,
      "id": "b20dda12-dad9-4585-9a56-31611aa00930",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/modules/computer-science/vqe/extracted-outputs/4b82b644-e030-4983-9fd3-83c3e9dbf307-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "fig, ax = plt.subplots()\n",
        "x = np.linspace(0, 5, 15)\n",
        "\n",
        "# Define the constant function\n",
        "y_constant = np.full_like(x, min(eigenvalues))\n",
        "ax.plot(\n",
        "    range(cost_history_dict[\"iters\"]), cost_history_dict[\"cost_history\"], label=\"VQE\"\n",
        ")\n",
        "ax.set_xlabel(\"Iterations\")\n",
        "ax.set_ylabel(\"Cost (Hartree)\")\n",
        "ax.plot(y_constant, label=\"Target\")\n",
        "plt.legend()\n",
        "plt.draw()"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "8eab4184-b5dd-494e-9e67-c209b3f835f3",
      "metadata": {},
      "source": [
        "<span id=\"check-your-understanding\" />\n",
        "\n",
        "#### Überprüfen Sie Ihr Verständnis\n",
        "\n",
        "Berechnen wir die Kernabstoßungsenergie des Moleküls $H_2$, die wir als konstanten Wert einbeziehen ( 0.71997 Hartree).\n",
        "\n",
        "![H2 molekül](https://quantum.cloud.ibm.com/learning/images/modules/computer-science/vqe/h2.avif)\n",
        "\n",
        "Bitte wende [das Coulomb-Gesetz](https://en.wikipedia.org/wiki/Coulomb%27s_law) und [die atomare Einheit](https://en.wikipedia.org/wiki/Atomic_units) an, um sicherzustellen, dass du den Wert in `Hartree`erhältst.\n",
        "\n",
        "<Accordion>\n",
        "  <AccordionItem title=\"Antwort\">\n",
        "    Da beide Wasserstoffkerne positiv geladen sind, stoßen sie sich aufgrund der elektrostatischen Kraft gegenseitig ab. Diese Abstoßung wird durch das Coulombsche Gesetz beschrieben:\n",
        "\n",
        "    $E_{repulsive} = \\frac{e^2}{4\\pi\\epsilon_0R}$\n",
        "\n",
        "    wobei $e$ die Ladung des Protons, $\\epsilon_0$ die Dielektrizitätskonstante des Vakuums und $R$ der Abstand zwischen den beiden Kernen ist, gemessen in Metern oder Bohr-Radien in der Einheit Joule (J).\n",
        "\n",
        "    Um diese Energie in Hartrees zu berechnen, müssen wir die obige Gleichung in das System der atomaren Einheiten (AU) umrechnen. In AU ist $e^2 = 1$, $4\\pi\\epsilon_0=1$ und der Bohr-Radius ( $a_0$ ) 1 und wird zur fundamentalen Längenskala in AU. Mit diesen Vereinfachungen reduziert sich das Coulombsche Gesetz auf:\n",
        "\n",
        "    $E_{repulsion} = \\frac{1}{R}$\n",
        "\n",
        "    wobei $R$ in Bohr-Radien ( $a_0$ ) gemessen werden muss.\n",
        "\n",
        "    Um den angegebenen Kernabstand in $\\r{A}$ in $a_0$ umzurechnen, benötigen wir diese Umrechnungsrelation:\n",
        "\n",
        "    $1\\r{A} = 1.88973 a_0$\n",
        "\n",
        "    so wird aus $0.735\\r{A}$ $0.735 * 1.88973 = 1.38895 a_0$.\n",
        "\n",
        "    Daher ist die Kernabstoßungsenergie einer gegebenen $H_2$\n",
        "\n",
        "    $E_{repulsion} = \\frac{1}{R} = \\frac{1}{1.38895} = 0.71997 Hartree$\n",
        "  </AccordionItem>\n",
        "</Accordion>\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "f75e4a10-dfdc-4416-8087-a41c1eac039c",
      "metadata": {},
      "source": [
        "<span id=\"compute-reaction-energy-of-$h-+-h-=-h_2$\" />\n",
        "\n",
        "## Berechne die Reaktionsenergie von $H + H = H_2$\n",
        "\n",
        "Nutzen wir nun das, was wir erhalten haben! Sie haben VQE, einen Variationsquanten-Eigensolver, verwendet, um die Grundzustandsenergie des Atoms $H$ und des Moleküls $H_2$ zu berechnen. Es bleibt nur noch, die berechneten Werte zu verwenden, um die Reaktionsenergie des Prozesses $H+H=H_2$ zu erhalten.\n",
        "\n",
        "Reaktionsenergie ist die Energieänderung, die auftritt, wenn Stoffe reagieren und neue Stoffe bilden. Stellen Sie sich vor, Sie bauen etwas: Manchmal müssen Sie Energie hineinstecken (wie beim Stapeln von Blöcken), und manchmal wird Energie freigesetzt (wie bei einer Kugel, die bergab rollt). In der Chemie nehmen Reaktionen entweder Energie auf (endotherm) oder setzen Energie frei (exotherm).\n",
        "\n",
        "Die Reaktionsenergie des $H+H = H_2$ Prozesses kann mit der folgenden Formel berechnet werden:\n",
        "\n",
        "$E_{reaction} = E_{H_2} - (E_H + E_H)$\n",
        "\n",
        "Führen Sie die nachstehende Zelle aus, um dies visuell zu veranschaulichen. Hier werden wir den exakten Grundzustandswert jedes Hamiltonianers verwenden und die Reaktionsenergie der exakten Lösung mit den VQE-Ergebnissen vergleichen.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 53,
      "id": "aa8d1a29-fbfe-41bf-8ed7-947827d0f0e6",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/modules/computer-science/vqe/extracted-outputs/87e1e660-ae81-43f4-adbe-a229b9d9c889-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "# Theoretical values\n",
        "E_H_theo = h.real\n",
        "E_H2_theo = h2\n",
        "\n",
        "# Experimental values\n",
        "E_H_exp = h_vqe\n",
        "E_H2_exp = h2_vqe\n",
        "\n",
        "# Calculate reaction energies\n",
        "E_reaction_theo = E_H2_theo - (2 * E_H_theo)\n",
        "E_reaction_exp = E_H2_exp - (2 * E_H_exp)\n",
        "\n",
        "# Set up the plot\n",
        "fig, ax = plt.subplots(figsize=(8, 6))\n",
        "ax.set_xlim(0, 3)\n",
        "ax.set_ylim(-1.16, -0.93)  # Adjust y-axis range to highlight differences\n",
        "ax.set_xticks([])\n",
        "ax.set_ylabel(\"Energy (Hartree)\")\n",
        "ax.set_title(\"H + H → H₂ Reaction Energy Diagram\")\n",
        "\n",
        "# Plot theoretical energy levels\n",
        "ax.hlines(\n",
        "    y=2 * E_H_theo, xmin=0.5, xmax=1.3, linewidth=2, color=\"r\", label=\"2H (Exact)\"\n",
        ")\n",
        "ax.hlines(y=E_H2_theo, xmin=1.3, xmax=2, linewidth=2, color=\"b\", label=\"H₂ (Exact)\")\n",
        "\n",
        "# Plot experimental energy levels\n",
        "ax.hlines(\n",
        "    y=2 * E_H_exp,\n",
        "    xmin=0.5,\n",
        "    xmax=1.5,\n",
        "    linewidth=2,\n",
        "    color=\"r\",\n",
        "    linestyle=\"dashed\",\n",
        "    label=\"2H (VQE)\",\n",
        ")\n",
        "ax.hlines(\n",
        "    y=E_H2_exp,\n",
        "    xmin=1.5,\n",
        "    xmax=2.5,\n",
        "    linewidth=2,\n",
        "    color=\"b\",\n",
        "    linestyle=\"dashed\",\n",
        "    label=\"H₂ (VQE)\",\n",
        ")\n",
        "\n",
        "# Add labels\n",
        "ax.text(\n",
        "    1,\n",
        "    2 * E_H_theo,\n",
        "    f\"2H: {2*E_H_theo:.4f}\",\n",
        "    verticalalignment=\"top\",\n",
        "    horizontalalignment=\"left\",\n",
        ")\n",
        "ax.text(\n",
        "    2,\n",
        "    E_H2_theo,\n",
        "    f\"H₂: {E_H2_theo:.4f}\",\n",
        "    verticalalignment=\"top\",\n",
        "    horizontalalignment=\"left\",\n",
        ")\n",
        "ax.text(\n",
        "    1,\n",
        "    2 * E_H_exp,\n",
        "    f\"2H_VQE: {2*E_H_exp:.4f}\",\n",
        "    verticalalignment=\"bottom\",\n",
        "    horizontalalignment=\"right\",\n",
        ")\n",
        "ax.text(\n",
        "    2,\n",
        "    E_H2_exp,\n",
        "    f\"H₂_VQE: {E_H2_exp:.4f}\",\n",
        "    verticalalignment=\"bottom\",\n",
        "    horizontalalignment=\"right\",\n",
        ")\n",
        "\n",
        "# Add arrows for reaction energy with ΔE label in the middle\n",
        "mid_y_theo = (2 * E_H_theo + E_H2_theo) / 2\n",
        "mid_y_exp = (2 * E_H_exp + E_H2_exp) / 2\n",
        "ax.annotate(\n",
        "    \"\",\n",
        "    xy=(1.3, E_H2_theo),\n",
        "    xytext=(1.3, 2 * E_H_theo),\n",
        "    arrowprops=dict(arrowstyle=\"<->\", color=\"g\"),\n",
        ")\n",
        "ax.text(\n",
        "    1.35, mid_y_theo, f\"ΔE: {E_reaction_theo:.4f}\", color=\"g\", verticalalignment=\"top\"\n",
        ")\n",
        "\n",
        "ax.annotate(\n",
        "    \"\",\n",
        "    xy=(1.5, E_H2_exp),\n",
        "    xytext=(1.5, 2 * E_H_exp),\n",
        "    arrowprops=dict(arrowstyle=\"<->\", color=\"g\", linestyle=\"dashed\"),\n",
        ")\n",
        "ax.text(\n",
        "    1.55,\n",
        "    mid_y_exp,\n",
        "    f\"ΔE_VQE: {E_reaction_exp:.4f}\",\n",
        "    color=\"g\",\n",
        "    verticalalignment=\"center\",\n",
        ")\n",
        "\n",
        "# Add legend\n",
        "ax.legend()\n",
        "\n",
        "plt.show()"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "f1a87af7-0c69-42c5-a415-87c95752d678",
      "metadata": {},
      "source": [
        "Wie die Abbildung zeigt, sind die exakte Grundzustandsenergie der Hamiltonianer und die mit den VQE-Ergebnissen berechnete Reaktionsenergie trotz einiger Fehler ähnlich und liegen nahe an -0.2 Hartree.\n",
        "\n",
        "Dabei ist zu beachten, dass die Reaktionsenergie dieses Prozesses einen negativen Wert hat, was bedeutet, dass die Energie durch den Prozess freigesetzt wird und das entstehende Molekül eine geringere Energie hat als zwei einzelne Atome.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "006ded34-29e0-4702-a46a-0459ee49f416",
      "metadata": {},
      "source": [
        "6. Fazit\n",
        "\n",
        "Lassen Sie uns zusammenfassen, was wir bisher gelernt haben.\n",
        "\n",
        "Zunächst haben wir uns zwei wichtige Näherungstechniken angesehen, die zur Lösung quantenchemischer Probleme benötigt werden: das Variationsprinzip und die Wahl der Basismengen, die beide für die VQE von grundlegender Bedeutung sind. Wir haben das Variationsprinzip von Hand erforscht und die Grundzustandsenergie des einfachen harmonischen Oszillators berechnet.\n",
        "\n",
        "Als nächstes untersuchten wir VQE, einen weit verbreiteten Algorithmus zur Berechnung der Grundzustandsenergie eines Quantensystems. Wir haben den Code zur Berechnung der Grundzustandsenergien für atomaren Wasserstoff ( $H$ ) und das Wasserstoffmolekül ( $H_2$ ) ausgeführt. Insbesondere haben wir gelernt, dass es notwendig ist, den geeigneten molekularen Hamiltonian für das System zu erhalten und ihn in eine Form zu transformieren, die auf einem Quantencomputer ausführbar ist. Wir haben auch gesehen, dass der Ansatz, eine parametrisierte Quantenschaltung, benötigt wird, um Versuchsquantenzustände innerhalb der VQE vorzubereiten, und wir haben die Bedeutung der Wahl einer geeigneten Ansatz-Schaltungsstruktur diskutiert. Wir lernten auch, dass VQE auf einem iterativen Optimierungsprozess beruht, bei dem ein klassischer Computer den Quantenschaltkreis anleitet, den niedrigsten Energiezustand zu finden, und sahen, wie der Prozess konvergiert.\n",
        "\n",
        "Schließlich verwendeten wir die berechneten Grundzustandsenergien von $H$ und $H_2$, die durch VQE erhalten wurden, um die Reaktionsenergie für den Prozess $H + H \\rightarrow H_2$ zu berechnen.\n",
        "\n",
        "VQE ist ein leistungsfähiger Quantenalgorithmus, der in naher Zukunft zum Einsatz kommen wird, aber es ist wichtig, sich seiner Grenzen bewusst zu sein. Die Leistung der VQE hängt in hohem Maße von der Wahl des Ansatzes ab - für größere, komplexere Moleküle wird es schwierig, einen effizient präparierbaren Ansatz zu finden, der den wahren Grundzustand genau darstellen kann. Außerdem ist die derzeitige Quanten-Hardware anfällig für Rauschen, was die Genauigkeit der VQE-Ergebnisse beeinträchtigen kann, insbesondere bei tieferen Schaltkreisen oder einer größeren Anzahl von Qubits. Trotz dieser Herausforderungen dient VQE als grundlegender Algorithmus, und in der laufenden Forschung werden anspruchsvollere Variationsmethoden und Techniken zur Fehlerminderung erforscht, um die Grenzen dessen zu erweitern, was in der Quantenchemie auf baldigen Quantencomputern möglich ist. So werden beispielsweise Algorithmen wie die Sample-basierte Quantendiagonalisierung (SQD) entwickelt, die die aus Quantenschaltungen gewonnenen Samples in Kombination mit der klassischen Diagonalisierung in einem Unterraum nutzen, um die Energieschätzung zu verbessern und einige der Einschränkungen der VQE, insbesondere hinsichtlich der Messeffizienz und der Rauschrobustheit, zu beheben.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "03c9dfc1-7367-4d71-9598-f02288c30ac0",
      "metadata": {},
      "source": [
        "<span id=\"review-and-questions\" />\n",
        "\n",
        "## Überprüfung und Fragen\n",
        "\n",
        "<span id=\"critical-concepts\" />\n",
        "\n",
        "### Wichtige Konzepte:\n",
        "\n",
        "* Der Variations-Quantenalgorithmus ist ein Rechenparadigma, bei dem ein klassischer Computer und ein Quantencomputer zusammenarbeiten, um ein Problem zu lösen.\n",
        "* Bei VQE beginnen wir mit einem Hamiltonian unseres Systems und bilden ihn auf Qubits ab, die auf dem Quantencomputer ausgeführt werden. Wir wählen einen parametrisierten Quantenschaltkreis, einen Ansatz, und führen wiederholte Messungen durch, wobei wir die Parameter des Ansatzes variieren, bis der niedrigste Energiewert erreicht ist. Die Suche im Parameterraum erfolgt mit einem klassischen Optimierer. Um gute Ergebnisse zu erzielen, ist es notwendig, einen guten Ansatz und einen geeigneten Optimierer zu wählen.\n",
        "* Die Reaktionsenergie ist die gesamte Energieänderung bei einer chemischen Reaktion, die durch die Differenz zwischen der Energie der Reaktanten und der Produkte bestimmt wird.\n",
        "\n",
        "<span id=\"true/false\" />\n",
        "\n",
        "### True/false\n",
        "\n",
        "1. Das Variationsprinzip besagt, dass der Erwartungswert der Energie für jede Versuchswellenfunktion immer größer oder gleich der wahren Grundzustandsenergie ist.\n",
        "2. Ein Basissatz ist eine Sammlung von Funktionen, die zur Annäherung von Quantenwellenfunktionen verwendet werden.\n",
        "3. VQE ist ein Quantenalgorithmus, der zur exakten Lösung der Schrödinger-Gleichung für einen gegebenen Hamiltonian verwendet wird.\n",
        "4. Bei der VQE wird eine parametrisierte Quantenschaltung (ein Ansatz) zur Vorbereitung von Versuchswellenfunktionen verwendet.\n",
        "5. Die Wahl des Optimierers in VQE (z. B. COBYLA, SPSA oder ADAM) hat keinen Einfluss auf die Qualität des Ergebnisses.\n",
        "6. Qiskit's `Estimator` wird zur direkten Berechnung von Erwartungswerten von Hamiltonianern in VQE verwendet.\n",
        "\n",
        "<span id=\"multiple-choice-questions\" />\n",
        "\n",
        "### Multiple-Choice-Fragen:\n",
        "\n",
        "1. Welchen Zweck erfüllt der Hamiltonian in der VQE?\n",
        "\n",
        "* A) Erzeugung zufälliger Quantenzustände\n",
        "* B) Bestimmung der Energie von Quantenzuständen\n",
        "* C) Zur Optimierung von Quantenschaltungen\n",
        "* D) Um Verschränkung zu erzeugen\n",
        "\n",
        "2. Was ist das Hauptziel des VQE-Algorithmus?\n",
        "\n",
        "* A) Ermittlung der Grundzustandsenergie eines Hamiltonianers\n",
        "* B) Verschränkung zwischen Qubits erzeugen\n",
        "* C) Grovers Suche durchführen\n",
        "* D) Um die RSA-Verschlüsselung zu brechen\n",
        "\n",
        "3. Wie viele Quantenzustände werden in diesem Notizbuch erzeugt, um den Ansatz zu vergleichen?\n",
        "\n",
        "* A) 100\n",
        "* B) 1000\n",
        "* C) 5000\n",
        "* D) 10,000\n",
        "\n",
        "4. Warum ist ein klassischer Optimierer in VQE erforderlich?\n",
        "\n",
        "* A) Zur Durchführung von Quantenmessungen\n",
        "* B) Aktualisierung der Ansatzparameter zur Minimierung der Energie\n",
        "* C) Qubits verschränken\n",
        "* D) Zur Erzeugung von Quantenzufälligkeit\n",
        "\n",
        "5. Warum soll der Ansatz parametrisiert werden?\n",
        "\n",
        "* A) Ermöglichung der Vorbereitung von Quantenzuständen\n",
        "* B) Ermöglichung der Suche nach einem breiten Raum von Quantenzuständen\n",
        "* C) Reduzierung der Komplexität der Schaltung\n",
        "* D) Direkte Messung von Eigenwerten\n",
        "\n",
        "6. Welche der folgenden Aussagen über die Wahl eines guten Ansatzes ist am ehesten richtig?\n",
        "\n",
        "* A) Ein Ansatz muss Zustände erzeugen, die gleichmäßig über die Bloch-Sphäre verteilt sind, sonst ist er nicht erfolgreich.\n",
        "* B) Ein Ansatz sollte auf Ihr System zugeschnitten sein, um sicherzustellen, dass er Zustände nahe dem Grundzustand erzeugen kann.\n",
        "* C) Ein Ansatz sollte mit Hilfe seiner Variationsparameter Zufallszustände erzeugen.\n",
        "* D) Ein besserer Ansatz hat immer mehr Variationsparameter.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "7f44807a-45f6-4e36-9d19-faa77f7c0c79",
      "metadata": {},
      "source": [
        "<span id=\"optional-appendix-optimizer-overhead-by-ansatz-complexity\" />\n",
        "\n",
        "## (Optional) Anhang: Optimierungsaufwand nach Ansatzkomplexität\n",
        "\n",
        "VQE steht vor mehreren bekannten Herausforderungenref \\[6], und die folgenden stehen im Zusammenhang mit dem, was wir oben gelernt haben.\n",
        "\n",
        "1. Herausforderungen bei der Ansatzauswahl\n",
        "\n",
        "Die Auswahl des richtigen Variationsansatzes stellt eine Herausforderung dar. Chemisch inspirierte Ansätze (wie UCCSD) bieten physikalische Genauigkeit, erfordern aber tiefe Schaltkreise, während hardware-effiziente Ansätze flache Schaltkreise haben, aber möglicherweise nicht physikalisch interpretierbar sind. Außerdem führen viele Ansätze übermäßige Variationsparameter ein, die nur wenig zur Verbesserung der Genauigkeit beitragen, aber die Optimierung erheblich erschweren.\n",
        "\n",
        "2. Schwierigkeiten bei der Optimierung\n",
        "\n",
        "Die Optimierungslandschaft der VQE kann Regionen aufweisen, in denen die Gradienten exponentiell verschwinden (unfruchtbare Plateaus), was es für klassische Optimierer schwierig macht, die Variationsparameter effizient zu aktualisieren. Zu diesem Zweck haben die Forscher versucht, verschiedene Arten von Optimierern zu verwenden - gradientenbasierte und gradientenfreie, aber beide stehen vor Herausforderungen. Gradientenbasierte Optimierer leiden unter unfruchtbaren Plateaus, während gradientenfreie Methoden eine große Anzahl von Funktionsbewertungen erfordern.\n",
        "\n",
        "3. Optimierungs-Overhead\n",
        "\n",
        "Eine weitere bekannte Herausforderung ist der Overhead des Optimierers, der mit dem Umfang des Problems zusammenhängt. Die für die VQE erforderlichen Quantenschaltungen werden mit zunehmender Problemgröße immer umfangreicher und komplexer, wodurch sich in der Regel auch die Anzahl der zu optimierenden Parameter erhöht. Der Optimierungsprozess wird mit zunehmender Anzahl von Parametern immer schwieriger, was zu einer langsamen Konvergenz und Schwierigkeiten bei der Suche nach der optimalen Lösung führt.\n",
        "\n",
        "Hier werden wir diese Herausforderungen anhand der VQE für ein $H_2$ Molekül mit zwei verschiedenen Arten von Ansätzen untersuchen.\n",
        "\n",
        "(Hinweis: Dies kann mehr QPU-Zeit in Anspruch nehmen; verwenden Sie daher einen Simulator, wenn Sie nicht genügend Zeit haben)\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 54,
      "id": "96179a4e-33f9-43ff-a791-f5ac8114dd29",
      "metadata": {},
      "outputs": [],
      "source": [
        "from qiskit.circuit import ParameterVector\n",
        "\n",
        "num_iter = 4\n",
        "alpha = ParameterVector(\"alpha\", 3)\n",
        "beta = ParameterVector(\"beta\", 3 * num_iter)\n",
        "\n",
        "# step1: Map problem to quantum circuits and operators\n",
        "hamiltonian = SparsePauliOp.from_list(\n",
        "    [(\"I\", -1.04886087), (\"Z\", -0.7967368), (\"X\", 0.18121804)]\n",
        ")\n",
        "\n",
        "ansatz_1 = ansatz3\n",
        "ansatz_2 = QuantumCircuit(1)\n",
        "for i in range(num_iter):\n",
        "    ansatz_2.rx(beta[i * 3 + 0], 0)\n",
        "    ansatz_2.rz(beta[i * 3 + 1], 0)\n",
        "    ansatz_2.rx(beta[i * 3 + 2], 0)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 55,
      "id": "0eeb0370-0ec7-490e-962b-55f746c4e4a3",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/modules/computer-science/vqe/extracted-outputs/faf0cf47-e48d-44aa-8119-af56c2ba94df-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 55,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "ansatz_1.draw(\"mpl\")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 56,
      "id": "105b8557-861c-4fcc-a84e-82d382ad730f",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/modules/computer-science/vqe/extracted-outputs/0edacb57-b03d-4850-8698-9b8d9f1338c4-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 56,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "ansatz_2.draw(\"mpl\")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 57,
      "id": "2f3f5e3f-d41b-45af-a14f-d2f1ef506037",
      "metadata": {},
      "outputs": [],
      "source": [
        "# Step 2: Optimize for target hardware\n",
        "\n",
        "target = backend.target\n",
        "pm = generate_preset_pass_manager(target=target, optimization_level=3)\n",
        "\n",
        "ansatz_isa_1 = pm.run(ansatz_1)\n",
        "ansatz_isa_2 = pm.run(ansatz_2)\n",
        "hamiltonian_isa_1 = hamiltonian.apply_layout(layout=ansatz_isa_1.layout)\n",
        "hamiltonian_isa_2 = hamiltonian.apply_layout(layout=ansatz_isa_2.layout)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "1433eb47-1fcc-4e2e-8738-2d2818be8824",
      "metadata": {},
      "source": [
        "Führen wir nun eine VQE mit einem Anfangspunkt aus lauter Einsen durch, mit maximal 20 Schritten, und vergleichen wir die Konvergenz beider Durchläufe.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 60,
      "id": "693444f0-5835-471f-b9f7-20b5158b3d45",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Iters. done: 1 [Current cost: -0.8782202668652658]\n",
            "Iters. done: 2 [Current cost: -0.43473160695469165]\n",
            "Iters. done: 3 [Current cost: -0.4076372093159749]\n",
            "Iters. done: 4 [Current cost: -1.3587839859772106]\n",
            "Iters. done: 5 [Current cost: -1.774529906754082]\n",
            "Iters. done: 6 [Current cost: -1.541934983115727]\n",
            "Iters. done: 7 [Current cost: -1.2732403113465345]\n",
            "Iters. done: 8 [Current cost: -1.820842221085785]\n",
            "Iters. done: 9 [Current cost: -1.8065762857059005]\n",
            "Iters. done: 10 [Current cost: -1.8126394095981146]\n",
            "Iters. done: 11 [Current cost: -1.8205831886180421]\n",
            "Iters. done: 12 [Current cost: -1.8086715778994924]\n",
            "Iters. done: 13 [Current cost: -1.8307676638629322]\n",
            "Iters. done: 14 [Current cost: -1.8177328827556327]\n",
            "Iters. done: 15 [Current cost: -1.8179426218088064]\n",
            "Iters. done: 16 [Current cost: -1.8109239667991088]\n",
            "Iters. done: 17 [Current cost: -1.824271872489647]\n",
            "Iters. done: 18 [Current cost: -1.813167587671394]\n",
            "Iters. done: 19 [Current cost: -1.824647343397313]\n",
            "Iters. done: 20 [Current cost: -1.8219785311686143]\n"
          ]
        }
      ],
      "source": [
        "# QPU time 3m 40s for ibm_brisbane\n",
        "# Step 3: Execute on target hardware\n",
        "\n",
        "from scipy.optimize import minimize\n",
        "\n",
        "x0 = np.ones(ansatz_1.num_parameters)\n",
        "\n",
        "batch = Batch(backend=backend)\n",
        "\n",
        "\n",
        "cost_history_dict = {\n",
        "    \"prev_vector\": None,\n",
        "    \"iters\": 0,\n",
        "    \"cost_history\": [],\n",
        "}\n",
        "estimator = Estimator(mode=batch)\n",
        "estimator.options.default_shots = 2048\n",
        "\n",
        "res = minimize(\n",
        "    cost_func,\n",
        "    x0,\n",
        "    args=(ansatz_isa_1, hamiltonian_isa_1, estimator),\n",
        "    method=\"cobyla\",\n",
        "    options={\"maxiter\": 20},\n",
        ")\n",
        "\n",
        "batch.close()"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 61,
      "id": "6922c55c-6a4f-41d8-8aad-69fa432ddf14",
      "metadata": {},
      "outputs": [],
      "source": [
        "# Save Cost_history as a new list\n",
        "ansatz_1_history = cost_history_dict[\"cost_history\"]"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 62,
      "id": "5ba0affa-8641-4a15-9408-a99dff0c7f8c",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Iters. done: 1 [Current cost: -0.738191173881188]\n",
            "Iters. done: 2 [Current cost: -0.42636037194506304]\n",
            "Iters. done: 3 [Current cost: -1.3503788613797374]\n",
            "Iters. done: 4 [Current cost: -0.9109204349776897]\n",
            "Iters. done: 5 [Current cost: -0.9060873157510835]\n",
            "Iters. done: 6 [Current cost: -0.7735065414083984]\n",
            "Iters. done: 7 [Current cost: -1.586889197437709]\n",
            "Iters. done: 8 [Current cost: -1.659215191584943]\n",
            "Iters. done: 9 [Current cost: -1.245445981794618]\n",
            "Iters. done: 10 [Current cost: -1.1608385766138023]\n",
            "Iters. done: 11 [Current cost: -1.1551733876027737]\n",
            "Iters. done: 12 [Current cost: -1.8143337768286332]\n",
            "Iters. done: 13 [Current cost: -1.2510951563756598]\n",
            "Iters. done: 14 [Current cost: -1.6918311531865413]\n",
            "Iters. done: 15 [Current cost: -1.8163783305531838]\n",
            "Iters. done: 16 [Current cost: -1.8434877732947152]\n",
            "Iters. done: 17 [Current cost: -1.8461898233304472]\n",
            "Iters. done: 18 [Current cost: -1.0346471214915485]\n",
            "Iters. done: 19 [Current cost: -1.8322518854150687]\n",
            "Iters. done: 20 [Current cost: -1.717144678705999]\n"
          ]
        }
      ],
      "source": [
        "# QPU time 3m 40s for ibm_brisbane\n",
        "\n",
        "x0 = np.ones(ansatz_2.num_parameters)\n",
        "\n",
        "batch = Batch(backend=backend)\n",
        "\n",
        "\n",
        "cost_history_dict = {\n",
        "    \"prev_vector\": None,\n",
        "    \"iters\": 0,\n",
        "    \"cost_history\": [],\n",
        "}\n",
        "estimator = Estimator(mode=batch)\n",
        "estimator.options.default_shots = 2048\n",
        "\n",
        "res = minimize(\n",
        "    cost_func,\n",
        "    x0,\n",
        "    args=(ansatz_isa_2, hamiltonian_isa_2, estimator),\n",
        "    method=\"cobyla\",\n",
        "    options={\"maxiter\": 20},\n",
        ")\n",
        "\n",
        "batch.close()"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 63,
      "id": "7354f299-cab6-4d43-a0e3-38c6c19f0486",
      "metadata": {},
      "outputs": [],
      "source": [
        "ansatz_2_history = cost_history_dict[\"cost_history\"]"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 64,
      "id": "2c6d2eb4-197b-4811-bb0b-377e445ff3a8",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/modules/computer-science/vqe/extracted-outputs/fb572c33-f3be-4ea8-959c-0891c9da947a-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "fig, ax = plt.subplots()\n",
        "\n",
        "# Define the constant function)\n",
        "ax.plot(\n",
        "    range(cost_history_dict[\"iters\"]),\n",
        "    ansatz_1_history,\n",
        "    label=\"Ansatz with 3 parameters\",\n",
        ")\n",
        "ax.plot(\n",
        "    range(cost_history_dict[\"iters\"]),\n",
        "    ansatz_2_history,\n",
        "    label=\"Ansatz with 12 parameters\",\n",
        ")\n",
        "ax.set_xlabel(\"Iterations\")\n",
        "ax.set_ylabel(\"Cost (Hartree)\")\n",
        "plt.legend()\n",
        "plt.draw()"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "b6a9fcdb-020f-429a-8b6e-17d67b0caaf9",
      "metadata": {},
      "source": [
        "Die obige Grafik zeigt deutlich, dass der Optimierungsprozess des Ansatzes mit mehr Variablen mehr Zeit benötigt, um eine stabile Konvergenz zu erreichen.\n",
        "\n",
        "Anstatt sich auf einfache Ein-Qubit-Schaltungen und einen unkomplizierten Ansatz zu verlassen, steigt die Komplexität der Optimierung, wenn größere Quantenschaltungen und komplexere strukturierte Ansätze erforderlich sind. Dies verdeutlicht eine bekannte Herausforderung bei VQEs: den Overhead des Optimierers.\n",
        "\n",
        "Forscher entwickeln weiterhin verschiedene fortschrittliche Methoden, mit denen Quantencomputer für chemische Probleme eingesetzt werden können. Unter können Sie auf eine Vielzahl [IBM Quantum Learning](/learning) von Lehrmaterialien zugreifen.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "f7c6d9a5-c2cc-4674-9d54-1f9809cfde51",
      "metadata": {},
      "source": [
        "<span id=\"references\" />\n",
        "\n",
        "## Referenzen\n",
        "\n",
        "* \\[[ref 1](https://link.springer.com/article/10.1007/BF02650179) ] Richard P. Feynman, Simulating Physics with Computers, International Journal of Theoretical Physics, 1982.\n",
        "* [\\[ref 2\\]](https://link.springer.com/chapter/10.1007/978-1-4614-8730-2_10) Marov, M.Y. (2015). Die Struktur des Universums. In: Die Grundlagen der modernen Astrophysik. Springer, New York, NY.\n",
        "* \\[[ref 3](https://www.ibm.com/quantum/blog/photoresists-quantum-chemistry-jsr) ] Wie man schwierige verfahrenstechnische Probleme mit Quantencomputern löst, IBM Research Blog, 2023.\n",
        "* \\[[ref 4](https://ieeexplore.ieee.org/document/8585034) ] Y. Cao, J. Romero und A. Aspuru-Guzik, \"Potential of quantum computing for drug discovery\", in IBM Journal of Research and Development, vol. 62, no. 6, pp. 6:1-6:20, 1 Nov.-Dec. 2018\n",
        "* \\[[ref 5](https://journals.aps.org/rmp/abstract/10.1103/RevModPhys.32.170) ] Present State of Molecular Structure Calculation, REv. Mod. Phys. 32, 170, 1960\n",
        "* \\[[ref 6](https://jmsh.springeropen.com/articles/10.1186/s41313-021-00032-6) ] Fedorov, D.A., Peng, B., Govind, N. et al. VQE-Methode: ein kurzer Überblick und aktuelle Entwicklungen. Mater-Theorie 6, 2 (2022)\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "id": "a1b8767d",
      "source": "© IBM Corp., 2017-2026"
    }
  ],
  "metadata": {
    "in_page_toc_max_heading_level": 2,
    "in_page_toc_min_heading_level": 2,
    "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"
    },
    "widgets": {
      "application/vnd.jupyter.widget-state+json": {
        "state": {},
        "version_major": 2,
        "version_minor": 0
      }
    }
  },
  "nbformat": 4,
  "nbformat_minor": 4
}