{
  "cells": [
    {
      "cell_type": "markdown",
      "id": "78090c95-8fea-4731-a74a-515150e4f899",
      "metadata": {},
      "source": [
        "---\n",
        "title: \"Shor-Algorithmus\"\n",
        "description: \"Lernen Sie, wie man mit dem Shor-Algorithmus zusammengesetzte Zahlen faktorisiert.\"\n",
        "---\n",
        "\n",
        "{/* cspell:ignore checkmark */}\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "64abf08d-8e69-41f9-b802-8c0fbbc37555",
      "metadata": {},
      "source": [
        "<span id=\"shors-algorithm\" />\n",
        "\n",
        "# Shor-Algorithmus\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "c257cbc3-7730-40cc-a240-19e57033d582",
      "metadata": {},
      "source": [
        "Für dieses Qiskit in Classrooms-Modul müssen die Schüler über eine funktionierende Python Umgebung verfügen, in der die folgenden Pakete installiert sind:\n",
        "\n",
        "* v2.1.0`qiskit` oder neuer\n",
        "* v0.40.1`qiskit-ibm-runtime` oder neuer\n",
        "* v0.17.0`qiskit-aer` oder neuer\n",
        "* `qiskit.visualization`\n",
        "* `numpy`\n",
        "* `pylatexenc`\n",
        "\n",
        "Informationen zum Einrichten und Installieren der oben genannten Pakete finden Sie im Leitfaden [zur Installation von Qiskit](/docs/guides/install-qiskit).\n",
        "Um Jobs auf echten Quantencomputern auszuführen, müssen die Studierenden ein Konto einrichten, IBM Quantum® indem sie die Schritte in der Anleitung [zum Einrichten Ihres IBM Cloud Kontos](/docs/guides/cloud-setup) befolgen.\n",
        "\n",
        "Dieses Modul wurde getestet und benötigte drei Sekunden QPU-Zeit. Dies ist nur eine Schätzung. Ihre tatsächliche Nutzung kann davon abweichen.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "500d10c9-17ca-4787-90e0-4c57bf86c80d",
      "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'"
      ]
    },
    {
      "attachments": {},
      "cell_type": "markdown",
      "id": "72231ac3-5b60-4bcb-a072-0c2ecdd176aa",
      "metadata": {
        "jp-MarkdownHeadingCollapsed": true
      },
      "source": [
        "<span id=\"intro\" />\n",
        "\n",
        "## Einführung\n",
        "\n",
        "In den frühen 1990s Jahren wuchs die Begeisterung für das Potenzial von Quantencomputern, Probleme zu lösen, die für klassische Computer schwierig waren. Einige talentierte Informatiker hatten Algorithmen entwickelt, die die Leistungsfähigkeit des Quantencomputings für bestimmte Nischenprobleme demonstrierten, aber niemand hatte eine einzige „Killer-App” für das Quantencomputing gefunden, die dieses Gebiet revolutionieren würde. Das war bis 1994, als Peter Shor den heute als Shor-Algorithmus bekannten Algorithmus zur Faktorisierung großer Zahlen entwickelte.\n",
        "\n",
        "Es war damals allgemein bekannt, dass es für einen klassischen Computer äußerst schwierig war, die Primfaktoren einer großen Zahl zu finden. Tatsächlich basierten Internet-Sicherheitsprotokolle auf dieser Schwierigkeit. Shor fand einen Weg, diese Faktoren exponentiell effizienter zu ermitteln, indem er einige der schwierigeren Schritte auf einen theoretischen, zukünftigen Quantencomputer auslagerte.\n",
        "\n",
        "In diesem Modul werden wir den Shor-Algorithmus untersuchen. Zunächst werden wir etwas mehr Kontext zum Algorithmus liefern, indem wir das Problem, das er löst, formalisieren und die Relevanz für die Cybersicherheit erläutern. Als Nächstes geben wir eine Einführung in die modulare Mathematik und ihre Anwendung auf das Faktorisierungsproblem und zeigen, wie sich die Faktorisierung auf ein anderes Problem namens „Ordnungsfindung” reduzieren lässt Wir zeigen, wie die Quanten-Fourier-Transformation und die Quantenphasenabschätzung, die wir im vorherigen Modul kennengelernt haben, zum Einsatz kommen und wie man sie zur Lösung des Ordnungsfindungsproblems verwendet.\n",
        "\n",
        "Endlich werden wir Shors Algorithmus auf einem echten Quantencomputer ausführen! Beachten Sie jedoch, dass dieser Algorithmus wirklich nur dann nützlich sein wird, wenn wir über einen großen, fehlertoleranten Quantencomputer verfügen, was noch einige Jahre dauern wird. Also werden wir nur eine kleine Zahl faktorisieren, um zu zeigen, wie der Algorithmus funktioniert.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "22a38013-7bd5-46db-9a44-e89d66c2d06b",
      "metadata": {},
      "source": [
        "<span id=\"the-factoring-problem\" />\n",
        "\n",
        "## Das Factoring-Problem\n",
        "\n",
        "Das Ziel des Faktorisierungsproblems ist es, die Primfaktoren einer Zahl $N$ zu finden. Für einige Zahlen $N$ ist dies ziemlich einfach. Wenn beispielsweise $N$ gerade ist, ist einer seiner Primfaktoren 2. Wenn $N$ eine Primzahlpotenz ist, d. h. $N=p^k$ für eine Primzahl $p$, ist es auch relativ einfach, $p$ zu finden: Wir approximieren einfach die $k^{\\text{th}}$ Wurzel von $N$ und suchen nach nahegelegenen Primzahlen, die $p$ sein könnten.\n",
        "\n",
        "Klassische Computer haben jedoch Schwierigkeiten, wenn ungerade und $N$\\* keine\\* Primzahlpotenz ist. Dies ist der Fall, mit dem sich der Shor-Algorithmus befasst. Der Algorithmus findet zwei Faktoren $p$ und $q$ derart, dass $N=pq$. Er kann rekursiv angewendet werden, bis alle Faktoren Primzahlen sind. In den nächsten Abschnitten werden wir sehen, wie dieses Problem angegangen wird.\n",
        "\n",
        "<span id=\"relevance-to-cyber-security\" />\n",
        "\n",
        "### Relevanz für die Cybersicherheit\n",
        "\n",
        "Viele kryptografische Verfahren basieren auf der Tatsache, dass die Faktorisierung großer Zahlen schwierig ist, darunter auch ein heute häufig verwendetes Verfahren namens RSA. Bei RSA wird ein öffentlicher Schlüssel erstellt, indem zwei große Primzahlen miteinander multipliziert werden, um zu erhalten $N = p\\cdot q$. Dann kann jeder diesen öffentlichen Schlüssel zum Verschlüsseln von Daten verwenden. Aber nur jemand, der über den privaten Schlüssel verfügt, $p$ und $q$, kann diese Daten entschlüsseln.\n",
        "\n",
        "Wenn leicht zu $N$ faktorisieren wäre, könnte jeder bestimmen, was $p$ und $q$ sind, und die Verschlüsselung knacken. Aber das ist es nicht. Dies ist ein bekanntermaßen schwieriges Problem. Tatsächlich sind die Primfaktoren einer Zahl namens RSA1024, die 1024 Binärziffern und 309 Dezimalziffern lang ist, immer noch nicht gefunden worden, obwohl bereits 1991 eine Belohnung von 100.000 Dollar für ihre Faktorisierung ausgesetzt wurde.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "01a0c5d4-922b-47af-8a8b-d87df8d520b0",
      "metadata": {},
      "source": [
        "<span id=\"shors-solution\" />\n",
        "\n",
        "## Shores Lösung\n",
        "\n",
        "Im Jahr 1994 erkannte Peter Shor, dass ein Quantencomputer eine große Zahl exponentiell effizienter faktorisieren kann als ein klassischer Computer. Seine Erkenntnis beruhte auf dem Zusammenhang zwischen diesem Faktorisierungsproblem und *der modularen Arithmetik*. Wir werden eine kurze Einführung in die modulare Arithmetik geben und dann sehen, wie wir diese zum Faktorisieren $N$ verwenden können.\n",
        "\n",
        "<span id=\"modular-arithmetic\" />\n",
        "\n",
        "### Modulare Arithmetik\n",
        "\n",
        "Modulare Arithmetik ist ein zyklisches Zählsystem, was bedeutet, dass das Zählen zwar wie gewohnt mit den ganzen Zahlen 0, 1, 2 usw. beginnt, Nach einer gewissen Zeit beginnt die $N$ Zählung von vorne. Schauen wir uns anhand eines Beispiels an, wie das funktioniert. Angenommen, unsere Periode beträgt 5. Dann, während wir zählen, beginnen wir anstelle von 5 wieder bei 0:\n",
        "\n",
        "$0, 1, 2, 3, 4, 0, 1, 2, 3, 4, 0, 1, 2, ...$\n",
        "\n",
        "Das liegt daran, dass in der „“ modulo-5 Welt 5 gleich 0 ist. Wir sagen, dass $5\\bmod 5 \\ = 0$. Tatsächlich sind alle Vielfachen von 5 gleich $0\\bmod 5$.\n",
        "\n",
        "<span id=\"check-your-understanding\" />\n",
        "\n",
        "#### Überprüfen Sie Ihr Verständnis\n",
        "\n",
        "Verwenden Sie modulare Arithmetik, um das folgende Problem zu lösen:\n",
        "\n",
        "Sie brechen um 8 Uhr morgens zu einer langen transkontinentalen Zugfahrt auf. Die Zugfahrt dauert 60 Stunden. Wie spät ist es, wenn Sie ankommen?\n",
        "\n",
        "<Accordion>\n",
        "  <AccordionItem title=\"Antwort\">\n",
        "    Der Zeitraum beträgt 24, da ein Tag 24 Stunden hat. Dieses Problem lässt sich also in modularer Arithmetik wie folgt schreiben:\n",
        "\n",
        "    $(8+60)\\text{mod}(24) = 20$\n",
        "\n",
        "    Sie würden also um 20:00 Uhr, also um 8 Uhr abends, an Ihrem Ziel ankommen.\n",
        "  </AccordionItem>\n",
        "</Accordion>\n",
        "\n",
        "<span id=\"$mathbb{z}_n$-and-$mathbb{z}_n^*$\" />\n",
        "\n",
        "#### $\\mathbb{Z}_N$ und $\\mathbb{Z}_N^*$\n",
        "\n",
        "Es ist oft sinnvoll, zwei Mengen einzuführen: $\\mathbb{Z}_N$ und $\\mathbb{Z}_N^*$. $\\mathbb{Z}_N$ ist einfach die Menge der Zahlen, die in einer $N$ „Modulo-Welt” existieren. Wenn wir beispielsweise zählen modulo-5, wäre die Menge $\\mathbb{Z}_5=\\{0,1,2,3,4\\}$. Ein weiteres Beispiel: $\\mathbb{Z}_{15} = \\{0,1,2,3,4,5,6,7,8,9,10,11,12,13,14\\}$. Wir können Addition und Multiplikation (modulo $N$ ) mit den Elementen in durchführen, und das Ergebnis jeder $\\mathbb{Z}_N$ dieser Operationen ist ebenfalls ein Element in $\\mathbb{Z}_N$, wodurch $\\mathbb{Z}_N$ zu einem mathematischen Objekt wird, das als *Ring* bezeichnet wird.\n",
        "\n",
        "Es gibt eine spezielle Untergruppe von $\\mathbb{Z}_N$, die für Shors Algorithmus für uns von besonderem Interesse ist. Das ist die Teilmenge der Zahlen in $\\mathbb{Z}_N$, sodass der größte gemeinsame Teiler zwischen jedem Element und 1 $N$ ist, sodass jedes Element zu „relativ $N$ prim“ ist. Wenn wir die Menge dieser Zahlen zusammen mit der modularen Multiplikationsoperation nehmen, bildet dies ein weiteres mathematisches Objekt, das als *Gruppe* bezeichnet wird. Wir nennen diese Gruppe $\\mathbb{Z}_N^*$. Es stellt sich heraus, dass wir bei $\\mathbb{Z}_N^*$ (und endlichen Gruppen im Allgemeinen), wenn wir ein beliebiges Element auswählen $a \\in \\mathbb{Z}_N^*$ und wiederholt mit sich $a$ selbst multiplizieren, immer irgendwann die Zahl erhalten $1$. Die minimale Anzahl von Multiplikationen $a$ mit sich selbst, die erforderlich ist, um zu erhalten, wird $1$ als $a$\\*\\* Ordnung\\*\\* von bezeichnet. Diese Tatsache ist für unsere nachfolgende Erörterung der Faktorisierung von Zahlen von großer Bedeutung.\n",
        "\n",
        "<span id=\"check-your-understanding-1\" />\n",
        "\n",
        "#### Überprüfen Sie Ihr Verständnis\n",
        "\n",
        "Was ist das $\\mathbb{Z}_{15}^*$?\n",
        "\n",
        "<Accordion>\n",
        "  <AccordionItem title=\"Antwort\">\n",
        "    $\\mathbb{Z}_{15}^* = \\{1,2,4,7,8,11,13,14\\} $\n",
        "\n",
        "    Wir haben die folgenden Nummern ausgeschlossen:\n",
        "\n",
        "    $$\n",
        "    \\begin{aligned}\n",
        "    3: GCD(3,15)=3 \\\\\n",
        "    5: GCD(5,15)=5 \\\\\n",
        "    6: GCD(6,15)=3 \\\\\n",
        "    9: GCD(9,15)=3 \\\\\n",
        "    10: GCD(10,15)=5 \\\\\n",
        "    12: GCD(12,15)=3 \\\\\n",
        "    \\end{aligned}\n",
        "    $$\n",
        "  </AccordionItem>\n",
        "</Accordion>\n",
        "\n",
        "Wie lautet die Reihenfolge der einzelnen Elemente in $\\mathbb{Z}_{15}^*$?\n",
        "\n",
        "<Accordion>\n",
        "  <AccordionItem title=\"Antwort\">\n",
        "    Die Ordnung $r$ ist die kleinste Zahl, sodass $a^r\\text{mod}(15)=1$ für jedes Element $a$ gilt.\n",
        "\n",
        "    $$\n",
        "    \\begin{aligned}\n",
        "    1^1\\text{mod}(15) = 1, r=1 \\\\\n",
        "    2^4\\text{mod}(15) = 1, r=4 \\\\\n",
        "    4^2\\text{mod}(15) = 1, r=2 \\\\\n",
        "    7^4\\text{mod}(15) = 1, r=4 \\\\\n",
        "    8^4\\text{mod}(15) = 1, r=4 \\\\\n",
        "    11^2\\text{mod}(15) = 1, r=2 \\\\\n",
        "    13^4\\text{mod}(15) = 1, r=4 \\\\\n",
        "    14^2\\text{mod}(15) = 1, r=2 \\\\\n",
        "    \\end{aligned}\n",
        "    $$\n",
        "\n",
        "    Beachten Sie, dass wir zwar die Reihenfolge der Zahlen in finden $\\mathbb{Z}_{15}^*$ konnten, dies jedoch im Allgemeinen für größere Zahlen KEINE leichte Aufgabe ist. Dies ist der Kern des $N$ Faktorisierungsproblems und der Grund, warum wir einen Quantencomputer benötigen. Wir werden sehen, warum, wenn wir den Rest des Notizbuchs durcharbeiten.\n",
        "  </AccordionItem>\n",
        "</Accordion>\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "c19d2032-3c40-48ee-823b-607b1ed8b4f0",
      "metadata": {},
      "source": [
        "<span id=\"apply-modular-arithmetic-to-the-factoring-problem\" />\n",
        "\n",
        "### Wende die modulare Arithmetik auf das Faktorisierungsproblem an\n",
        "\n",
        "Der Schlüssel zum Finden von Faktoren $p$ und $q$ derart, dass $N=pq$ ist, einen *anderen* ganzzahligen Wert zu $x$ finden, sodass\n",
        "\n",
        "$x^2 \\equiv 1 \\bmod N$ und $x \\not\\equiv \\pm 1 \\bmod N.$\n",
        "\n",
        "Wie hilft uns $x$ die Ermittlung von dabei, die Faktoren $p$ und zu finden $q$? Lassen Sie uns nun die Argumentation durchgehen. Da $x^2 \\equiv 1 \\bmod N$ gilt, bedeutet dies, dass $x^2 - 1 \\equiv 0 \\bmod N $. Mit anderen Worten: $x^2 - 1$ ist ein Vielfaches von $N$. Für eine ganze Zahl $l$ gilt also\n",
        "\n",
        "$x^2 - 1 = l N$\n",
        "\n",
        "Wir können faktorisieren, $x^2 - 1$ um zu erhalten:\n",
        "\n",
        "$(x+1)(x-1) = l N$\n",
        "\n",
        "Aus unseren anfänglichen Annahmen wissen wir, $x \\not\\equiv \\pm 1 \\bmod N$ dass $N$ nicht gleichmäßig durch oder $x+1$ teilbar ist. Daher müssen die beiden $x-1$ Faktoren von $N$, $p$ und, jeweils $q$ $x+1$ durch $x-1$ und teilbar sein. Entweder $p$ ist ein $q$ Faktor von $x-1$ und ein Faktor von $x+1$, oder umgekehrt. Wenn wir also die größten gemeinsamen Teiler (GCDs) zwischen $N$ und sowohl $x-1$ als auch $x+1$ berechnen, erhalten wir die Faktoren $p$ und $q$. Die Berechnung des GCD zwischen zwei Zahlen ist eine klassisch einfache Aufgabe, die beispielsweise mit Hilfe [des Euklidischen Algorithmus](https://en.wikipedia.org/wiki/Euclidean_algorithm) gelöst werden kann.\n",
        "\n",
        "<span id=\"check-your-understanding\" />\n",
        "\n",
        "#### Überprüfen Sie Ihr Verständnis\n",
        "\n",
        "Es könnte schwierig sein, jeden Schritt der oben genannten Logik zu verstehen, daher versuchen Sie es anhand eines Beispiels. Verwenden Sie $N=15$ und $x=11$. Überprüfen Sie zunächst, ob $x^2 \\equiv 1 \\text{mod}(N)$ und $x \\not\\equiv \\pm 1 \\bmod N$. Fahren Sie dann fort, jeden Schritt zu überprüfen. Berechnen Sie schließlich $\\text{GCD}(11\\pm1,15)$ und überprüfen Sie, ob dies die Faktoren von sind $15$.\n",
        "\n",
        "<Accordion>\n",
        "  <AccordionItem title=\"Antwort\">\n",
        "    $11^2 = 121$, das ist $15*8 + 1$, also $11^2\\bmod 15 = 1$. $\\checkmark$\n",
        "\n",
        "    $ 11 - 1 = 10$, was nicht gleichbedeutend mit ist $0\\bmod 15$. $\\checkmark$\n",
        "\n",
        "    $ 11 + 1 = 12$, was nicht gleichbedeutend mit ist $0\\bmod 15$. $\\checkmark$\n",
        "\n",
        "    Nun wissen wir, dass $(x+1)(x-1) = l N$ für eine ganze Zahl gilt $l$. Dies lässt sich überprüfen, indem wir und $x$ $N$ einsetzen: $(12)(10) = l 15$ wenn $l = 8$. $\\checkmark$\n",
        "\n",
        "    Nun müssen wir und $\\text{GCD}(12,15)$ $\\text{GCD}(10,15)$ berechnen.\n",
        "\n",
        "    $$\n",
        "    \\begin{aligned}\n",
        "    \\text{GCD}(12,15) = 3 \\\\\n",
        "    \\text{GCD}(10,15) = 5\n",
        "    \\end{aligned}\n",
        "    $$\n",
        "\n",
        "    Also, wir haben unsere Faktoren von gefunden $15$!\n",
        "  </AccordionItem>\n",
        "</Accordion>\n",
        "\n",
        "<span id=\"the-algorithm\" />\n",
        "\n",
        "### Der Algorithmus\n",
        "\n",
        "Nachdem wir nun gesehen haben, wie uns das Finden einer ganzen $N$ Zahl $x$ so, dass uns beim $x^2 \\equiv 1\\bmod N$ Faktorisieren hilft, können wir Shors Algorithmus durchgehen. Im Wesentlichen läuft es darauf hinaus, Folgendes zu finden $x$ :\n",
        "\n",
        "1. **Wähle eine zufällige ganze** Zahl\n",
        "   Wähle eine zufällige ganze Zahl $a$ so, dass $1 < a < N$.\n",
        "\n",
        "* Klassisch $\\text{GCD}(a, N)$ berechnen.\n",
        "  * Wenn $\\text{GCD}(a, N) > 1$, haben Sie bereits einen Faktor gefunden. Halt.\n",
        "  * Andernfalls fahren Sie fort.\n",
        "\n",
        "2. **Finde die Ordnung $r$ von $a$ modulo**\n",
        "   $N$ Finde die kleinste positive ganze Zahl, $r$ die erfüllt $a^r \\equiv 1 \\pmod N$.\n",
        "\n",
        "3. **Überprüfen Sie, ob die Bestellung gerade ist.**\n",
        "\n",
        "* Wenn $r$ ungerade ist, gehe zurück zu Schritt 1 und wähle ein neues $a$.\n",
        "* Wenn $r$ gerade ist, fahren Sie mit Schritt 4 fort.\n",
        "\n",
        "4. **Berechnen $x = a^{r/2} \\bmod N$**\n",
        "\n",
        "* Überprüfen Sie, ob $x \\not\\equiv 1 \\pmod N$ und $x \\not\\equiv -1 \\pmod N$.\n",
        "  * Wenn $x \\equiv \\pm 1 \\pmod N$, gehen Sie zurück zu Schritt 1 und wählen Sie einen neuen $a$.\n",
        "* Andernfalls berechnen Sie die gcds, um die Faktoren zu extrahieren:\n",
        "\n",
        "$$\n",
        "p = \\text{GCD}(x-1, N), \\quad q = \\text{GCD}(x+1, N)\n",
        "$$\n",
        "\n",
        "Dies sind nicht triviale Faktoren von $N$.\n",
        "\n",
        "5. **Bei Bedarf rekursiv faktorisieren**\n",
        "\n",
        "* Wenn $p$ und/oder keine $q$ Primzahlen sind, wenden Sie den Algorithmus rekursiv an, um sie vollständig zu faktorisieren.\n",
        "* Sobald alle Faktoren prim sind, ist die Faktorisierung abgeschlossen.\n",
        "\n",
        "Aufgrund dieses Verfahrens ist möglicherweise nicht ersichtlich, warum für die Ausführung dieser Aufgabe ein Quantencomputer erforderlich ist. Dies ist notwendig, da Schritt 2, das Ermitteln der Ordnung von $a$ modulo $N$, klassischerweise ein sehr schwieriges Problem darstellt. Die Komplexität steigt exponentiell mit der Anzahl $N$. Mit einem Quantencomputer müssen wir jedoch nur die Quantenphasenabschätzung nutzen, um das Problem zu lösen. Schritt 4, das Ermitteln des GGD zweier ganzer Zahlen, ist klassischerweise eigentlich ziemlich einfach. Der einzige Schritt, für den tatsächlich die Leistung eines Quantencomputers erforderlich ist, ist also der Schritt der Ordnungsfindung. Wir sagen, dass sich das Factoring-Problem auf das Ordnungsfindungsproblem „reduzieren“ lässt.\n",
        "\n"
      ]
    },
    {
      "attachments": {},
      "cell_type": "markdown",
      "id": "d4771244-0604-4b2e-bd99-a52280456f43",
      "metadata": {},
      "source": [
        "<span id=\"the-hard-part-order-finding\" />\n",
        "\n",
        "### Der schwierige Teil: die Auftragssuche\n",
        "\n",
        "Nun werden wir uns damit befassen, wie wir einen Quantencomputer für die Suche einsetzen können. Lassen Sie uns zunächst klären, was wir unter „Reihenfolge“ verstehen Natürlich habe ich euch bereits erklärt, was die Ordnung mathematisch bedeutet: Es ist die erste von Null verschiedene ganze Zahl $r$, für die gilt: $a^r = 1 \\pmod N$. Aber lasst uns mal schauen, ob wir ein wenig mehr Intuition für dieses Konzept entwickeln können.\n",
        "\n",
        "Für ausreichend kleine können wir die Ordnung $N$ einfach bestimmen, indem wir jede $a$ Potenz von berechnen, den Modulus $N$ dieser Zahl nehmen und dann aufhören, wenn wir die Potenz finden $r$, die erfüllt $a^r = 1 \\text{mod}(N)$. Das haben wir in $N=15$ unserem obigen Beispiel getan. Sehen wir uns einige Grafiken dieser modularen Potenzen für einige Beispielwerte von $a$ und an $N$ :\n",
        "\n",
        "![Wert von a hoch k modulo N gegenüber der Potenz k, wobei a=2 und N=15. Wir sehen, dass sich mit steigendem k ein sich wiederholendes Muster ergibt, das zeigt, dass a^k modulo N in k periodisch ist.](https://quantum.cloud.ibm.com/learning/images/modules/computer-science/shors-algorithm/a2n15.avif)\n",
        "\n",
        "![Wert von a hoch k modulo N gegenüber der Potenz k, wobei a=5 und N=21. Wir sehen, dass sich mit steigendem k ein sich wiederholendes Muster ergibt, das zeigt, dass a^k modulo N in k periodisch ist.](https://quantum.cloud.ibm.com/learning/images/modules/computer-science/shors-algorithm/a5n21.avif)\n",
        "\n",
        "Fällt Ihnen etwas auf? Das sind periodische Funktionen! Und die Reihenfolge $r$ ist dieselbe wie die Periode! **Die Ordnungsfindung entspricht also der Periodenfindung.**\n",
        "\n",
        "Quantencomputer eignen sich sehr gut zum Ermitteln der Periode von Funktionen. Hierfür können wir eine algorithmische Subroutine namens „Quantum Phase Estimation” (Quantenphasenabschätzung) verwenden. Im vorherigen Modul haben wir QPE und dessen Zusammenhang mit der Quanten-Fourier-Transformation behandelt. Eine ausführliche Auffrischung finden Sie im QFT-Modul oder in John Watrous' Lektion zur [Quantenphasenabschätzung](/learning/courses/fundamentals-of-quantum-algorithms/phase-estimation-and-factoring/shor-algorithm) in seinem Kurs „Quantenalgorithmen”. Wir werden nun die wichtigsten Punkte des Verfahrens durchgehen:\n",
        "\n",
        "Bei der Quantenphasenabschätzung (QPE) beginnen wir mit einer unitären $U$ und einem Eigenzustand dieser unitären $|\\psi\\rangle$. Dann verwenden wir QPE, um den entsprechenden Eigenwert zu approximieren, der, da der Operator unitär ist, die Form hat. Das Finden des Eigenwerts entspricht also dem $e^{2\\pi i \\theta}$ Finden des Werts $\\theta$ in der periodischen Funktion. Der Schaltkreis sieht wie folgt aus:\n",
        "\n",
        "![Schaltplan des Verfahrens zur Quantenphasenabschätzung. Die oberen m Kontrollqubits werden mit Hadamard-Gates in Superpositionen vorbereitet, dann werden kontrollierte unitäre Gates auf die unteren Qubits angewendet, die sich in einem Eigenzustand des unitären Gates befinden. Schließlich wird eine inverse Quanten-Fourier-Transformation auf die obersten Qubits angewendet und diese werden gemessen.](https://quantum.cloud.ibm.com/learning/images/modules/computer-science/shors-algorithm/QPE.avif)\n",
        "\n",
        "wobei die Anzahl der Steuerqubits (die oberen $m$ Qubits in der Abbildung oben) die Genauigkeit der Annäherung bestimmt.\n",
        "\n",
        "Im Shor-Algorithmus verwenden wir QPE für den unitären Operator $M_a$ :\n",
        "\n",
        "$ M_a|y\\rangle \\equiv |ay \\mod N \\rangle .$\n",
        "\n",
        "Hier bezeichnet einen Rechenbasis-Zustand $|y\\rangle$ des Multi-Qubit-Registers, wobei der Binärwert der Qubits der ganzen Zahl entspricht $y$. Wenn beispielsweise $N=15$ und $y = 2$, dann $|y\\rangle$ wird durch den Vier-Qubit-Basis-Zustand dargestellt, da vier $|0010\\rangle$ Qubits erforderlich sind, um Zahlen bis zu 15 zu codieren. (Wenn Ihnen dieses Konzept unbekannt ist, finden Sie [im](/learning/modules/quantum-mechanics/get-started-with-qiskit) Einführungsmodul „Qiskit im Unterricht“ eine Auffrischung zum Thema binäre Kodierung von Quantenzuständen.)\n",
        "\n",
        "Nun müssen wir einen Eigenzustand dieser Unitarität herausfinden. Wenn wir im Zustand $|1\\rangle$ begonnen haben, können wir sehen, dass jede aufeinanderfolgende $a \\pmod N$ Anwendung von den Zustand $U$ unseres Registers mit multipliziert und wir nach $r$ Anwendungen wieder im $|1\\rangle$ Zustand ankommen. Zum Beispiel mit $a = 3$ und $N = 35$ :\n",
        "\n",
        "$$\n",
        "\\begin{aligned}\n",
        "M_3|1\\rangle &= |3\\rangle & \\\\\n",
        "M_3^2|1\\rangle &= |9\\rangle \\\\\n",
        "M_3^3|1\\rangle &= |27\\rangle \\\\\n",
        "& \\vdots \\\\\n",
        "M_3^{(r-1)}|1\\rangle &= |12\\rangle \\\\\n",
        "M_3^r|1\\rangle &= |1\\rangle\n",
        "\\end{aligned}\n",
        "$$\n",
        "\n",
        "Also Überlagerungen der Zustände in diesem Zyklus ( $|\\psi_j\\rangle$ ) der Form:\n",
        "\n",
        "$|\\psi_j\\rangle = \\tfrac{1}{\\sqrt{r}}\\sum_{k=0}^{r-1}{e^{\\frac{2 \\pi i j k}{r}} |a^k \\rangle} $\n",
        "\n",
        "sind alle Eigenzustände von $M_a$. (Es gibt noch weitere Eigenzustände außer diesen. Aber uns interessieren nur diejenigen der oben genannten Form.)\n",
        "\n",
        "<span id=\"check-your-understanding\" />\n",
        "\n",
        "#### Überprüfen Sie Ihr Verständnis\n",
        "\n",
        "Finden Sie einen Eigenzustand der Unitarität, der $a=2$ und entspricht $N = 15$.\n",
        "\n",
        "<Accordion>\n",
        "  <AccordionItem title=\"Antwort\">\n",
        "    $$\n",
        "    \\begin{aligned}\n",
        "    M_2|1\\rangle &= |2\\rangle & \\\\\n",
        "    M_2^2|1\\rangle &= |4\\rangle \\\\\n",
        "    M_2^3|1\\rangle &= |8\\rangle \\\\\n",
        "    M_2^4|1\\rangle &= |1\\rangle \\\\\n",
        "    \\end{aligned}\n",
        "    $$\n",
        "\n",
        "    Also, die Reihenfolge $r=4$. Die Eigenzustände, die uns interessieren, sind eine gleichmäßige Überlagerung aller oben durchlaufenen Zustände mit verschiedenen Phasen:\n",
        "\n",
        "    $$\n",
        "    \\begin{aligned}\n",
        "    |\\psi_0\\rangle &= \\frac{1}{2}(|1\\rangle+|2\\rangle+|4\\rangle+|8\\rangle) \\\\\n",
        "    |\\psi_1\\rangle &= \\frac{1}{2}(e^{2 \\pi i \\frac{0}{4}}|1\\rangle+e^{2 \\pi i \\frac{1}{4}}|2\\rangle+e^{2 \\pi i \\frac{2}{4}}|4\\rangle+e^{2 \\pi i \\frac{3}{4}}|8\\rangle) \\\\\n",
        "    &= \\frac{1}{2}(|1\\rangle+i|2\\rangle-|4\\rangle-i|8\\rangle) \\\\\n",
        "    |\\psi_2\\rangle &= \\frac{1}{2}(e^{2 \\pi i \\frac{0}{4}}|1\\rangle+e^{2 \\pi i \\frac{2}{4}}|2\\rangle+e^{2 \\pi i \\frac{4}{4}}|4\\rangle+e^{2 \\pi i \\frac{6}{4}}|8\\rangle) \\\\\n",
        "    &= \\frac{1}{2}(|1\\rangle-|2\\rangle+|4\\rangle-|8\\rangle) \\\\\n",
        "    |\\psi_3\\rangle &= \\frac{1}{2}(e^{2 \\pi i \\frac{0}{4}}|1\\rangle+e^{2 \\pi i \\frac{3}{4}}|2\\rangle+e^{2 \\pi i \\frac{6}{4}}|4\\rangle+e^{2 \\pi i \\frac{9}{4}}|8\\rangle) \\\\\n",
        "    &= \\frac{1}{2}(|1\\rangle-i|2\\rangle-|4\\rangle+i|8\\rangle) \\\\\n",
        "    \\end{aligned}\n",
        "    $$\n",
        "  </AccordionItem>\n",
        "</Accordion>\n",
        "\n",
        "Nehmen wir an, wir könnten unseren Qubit-Zustand in einen dieser Eigenzustände initialisieren (Spoiler: Das können wir nicht). Oder zumindest nicht ohne Weiteres. Wir werden in Kürze erklären, warum und was wir stattdessen tun können. Dann könnten wir QPE verwenden, um den entsprechenden Eigenwert zu schätzen, $\\omega_j = e^{2 \\pi i \\theta_j}$ wobei $\\theta_j = \\frac{j}{r}$. Dann können wir die Ordnung $r$ mit der folgenden einfachen Gleichung bestimmen:\n",
        "\n",
        "$r = \\frac{j}{\\theta_j}.$\n",
        "\n",
        "Aber denken Sie daran, ich habe gesagt, dass es sich um QPE *-Schätzungen* $\\theta_j$ handelt – sie liefern uns keinen genauen Wert. Die Schätzung muss gut genug sein, um zwischen $r$ und unterscheiden $r+1$ zu können. Je mehr $m$ Kontrollqubits wir haben, desto besser wird die Schätzung sein. In den Aufgaben am Ende der Lektion werden Sie gebeten, das Minimum zu bestimmen $m$, das erforderlich ist, um eine Zahl zu $N$ faktorisieren.\n",
        "\n",
        "Jetzt müssen wir ein Problem lösen. Alle oben genannten Erklärungen dazu, wie man findet, $r$ beginnen mit der Vorbereitung des Eigenzustands $|\\psi_j\\rangle = \\tfrac{1}{\\sqrt{r}}\\sum_{k=0}^{r-1}{e^{\\frac{2 \\pi i j k}{r}} |a^k \\rangle}$. Aber wir wissen nicht, wie wir das machen sollen, ohne bereits zu wissen, was $r$ ist. Die Logik ist zirkulär. Wir brauchen eine Möglichkeit, den Eigenwert zu schätzen\\*, ohne\\* den Eigenzustand zu initialisieren.\n",
        "\n",
        "Anstatt mit einem Eigenzustand von $M_a$ zu beginnen, können wir den Anfangszustand in den $n$ -Qubit-Zustand vorbereiten, der $|1\\rangle$ in Binärform entspricht (wie in ) $|000...01\\rangle$. Obwohl dieser Zustand selbst offensichtlich kein Eigenzustand von ist $M_a$, handelt es sich um eine Überlagerung aller Eigenzustände $|\\psi_k\\rangle$ :\n",
        "\n",
        "$|1\\rangle = \\frac{1}{\\sqrt{r}} \\sum\\limits_{k=0}^{r-1}{|\\psi_k\\rangle}$\n",
        "\n",
        "<span id=\"check-your-understanding-1\" />\n",
        "\n",
        "#### Überprüfen Sie Ihr Verständnis\n",
        "\n",
        "Überprüfen Sie, ob der Superposition über $|1\\rangle$ den Eigenzuständen entspricht, die Sie für $N=15$ und $a=2$ in der vorherigen Kontrollfrage gefunden haben.\n",
        "\n",
        "<Accordion>\n",
        "  <AccordionItem title=\"Antwort\">\n",
        "    Die vier Eigenzustände waren:\n",
        "\n",
        "    $$\n",
        "    \\begin{aligned}\n",
        "    |\\psi_0\\rangle &= \\frac{1}{2}(|1\\rangle+|2\\rangle+|4\\rangle+|8\\rangle) \\\\\n",
        "    |\\psi_1\\rangle &= \\frac{1}{2}(|1\\rangle+i|2\\rangle-|4\\rangle-i|8\\rangle) \\\\\n",
        "    |\\psi_2\\rangle &= \\frac{1}{2}(|1\\rangle-|2\\rangle+|4\\rangle-|8\\rangle) \\\\\n",
        "    |\\psi_3\\rangle &= \\frac{1}{2}(|1\\rangle-i|2\\rangle-|4\\rangle+i|8\\rangle) \\\\\n",
        "    \\end{aligned}\n",
        "    $$\n",
        "\n",
        "    Also\n",
        "\n",
        "    $$\n",
        "    \\begin{aligned}\n",
        "    \\frac{1}{\\sqrt{r}} \\sum\\limits_{k=0}^{r-1}{|\\psi_k\\rangle} &= \\frac{1}{2}(|\\psi_0\\rangle + |\\psi_1\\rangle + |\\psi_2\\rangle + |\\psi_3\\rangle ) \\\\\n",
        "    &= \\frac{1}{4}(|1\\rangle+|2\\rangle+|4\\rangle+|8\\rangle+|1\\rangle+i|2\\rangle-|4\\rangle-i|8\\rangle+|1\\rangle-|2\\rangle+|4\\rangle-|8\\rangle + |1\\rangle-i|2\\rangle-|4\\rangle+i|8\\rangle) \\\\\n",
        "    &= \\frac{1}{4}(4|1\\rangle) = |1\\rangle\n",
        "    \\end{aligned}\n",
        "    $$\n",
        "  </AccordionItem>\n",
        "</Accordion>\n",
        "\n",
        "Wie können wir damit die Reihenfolge ermitteln $r$? Da der Ausgangszustand eine Überlagerung aller Eigenzustände der oben aufgeführten Form ist, schätzt der QPE-Algorithmus gleichzeitig jeden der, die $\\theta_k$ diesen Eigenzuständen entsprechen. Die Messung der $m$ Kontrollqubits am Ende ergibt also eine Annäherung an den Wert $k/r$, wobei einer der zufällig ausgewählten $k \\in \\{0,1,2,...,r-1\\}$ Eigenwerte ist. Wenn wir diesen Kreislauf einige Male wiederholen und einige Proben mit unterschiedlichen Werten von erhalten $k$, können wir schnell ableiten $r$.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "099389d1-1370-472c-af29-a642532beff4",
      "metadata": {},
      "source": [
        "<span id=\"implement-in-qiskit\" />\n",
        "\n",
        "## Implementierung in Qiskit\n",
        "\n",
        "Wie bereits erwähnt, ist unsere Hardware noch nicht so weit, dass wir riesige Zahlen wie RSA1024. Wir werden nur eine kleine Zahl faktorisieren, um zu zeigen, wie der Algorithmus funktioniert. Für diese Demo verwenden wir eine vereinfachte Version des Codes, der im [Tutorial](/docs/tutorials/shors-algorithm) zum Shor-Algorithmus vorgestellt wurde. Wenn Sie weitere Informationen wünschen, besuchen Sie bitte das Tutorial.\n",
        "\n",
        "Wir werden den Algorithmus unter Verwendung unseres Standard-Frameworks zur Lösung von Quantenproblemen ausführen, das als Qiskit-Patterns-Framework bezeichnet wird. Dies umfasst vier Schritte:\n",
        "\n",
        "1. Ihr Problem auf einen Quantenschaltkreis abbilden\n",
        "2. Optimieren Sie den Schaltkreis für den Betrieb auf Quantenhardware\n",
        "3. Führen Sie Ihren Schaltkreis auf dem Quantencomputer aus\n",
        "4. Die Messungen nachbearbeiten\n",
        "\n",
        "<span id=\"1-map\" />\n",
        "\n",
        "### 1. Karte\n",
        "\n",
        "Lassen Sie uns faktorisieren $N=15$ und als unsere $a=2$ teilerfremde ganze Zahl wählen.\n",
        "\n",
        "Zunächst müssen wir die Schaltung konstruieren, die die modulare Multiplikations-Unität implementiert. Dies ist tatsächlich der schwierigste Teil der gesamten $M_a$ Implementierung und kann je nach Vorgehensweise sehr rechenintensiv sein. Dazu schummeln wir ein wenig: Wir wissen, dass wir $|1\\rangle$ im Zustand beginnen, und aus einer früheren Check-in-Frage wissen wir, dass\n",
        "\n",
        "$$\n",
        "\\begin{aligned}\n",
        "M_2|1\\rangle &= |2\\rangle & \\\\\n",
        "M_2|2\\rangle &= |4\\rangle \\\\\n",
        "M_2|4\\rangle &= |8\\rangle \\\\\n",
        "M_2|8\\rangle &= |1\\rangle \\\\\n",
        "\\end{aligned}\n",
        "$$\n",
        "\n",
        "Wir werden also eine Einheit konstruieren, die die richtigen Operationen auf diesen vier Zuständen ausführt, alle anderen Zustände jedoch unverändert lässt. Das ist Betrug, weil wir unser Wissen über die Reihenfolge von nutzen, um die $2\\bmod 15$ Unitarität zu vereinfachen. Wenn wir tatsächlich versuchen würden, eine Zahl zu faktorisieren, deren Faktoren uns unbekannt sind, wäre uns dies nicht möglich.\n",
        "\n",
        "<span id=\"check-your-understanding\" />\n",
        "\n",
        "#### Überprüfen Sie Ihr Verständnis\n",
        "\n",
        "Konstruieren Sie anhand Ihres Wissens darüber, wie der $M_2$ Operator die oben genannten Zustände transformiert, den Operator aus einer Reihe von SWAP-Gattern, die die Zustände zweier Qubits austauschen. (Hinweis: Es ist hilfreich, jeden Zustand $|i\\rangle$ in Binärform zu schreiben.)\n",
        "\n",
        "<Accordion>\n",
        "  <AccordionItem title=\"Antwort\">\n",
        "    Schreiben wir die Aktion von $M_2$ auf die Zustände in Binärform um:\n",
        "\n",
        "    $$\n",
        "    \\begin{aligned}\n",
        "    M_2|0001\\rangle &= |0010\\rangle \\\\\n",
        "    M_2|0010\\rangle &= |0100\\rangle \\\\\n",
        "    M_2|0100\\rangle &= |1000\\rangle \\\\\n",
        "    M_2|1000\\rangle &= |0001\\rangle \\\\\n",
        "    \\end{aligned}\n",
        "    $$\n",
        "\n",
        "    Jede dieser Aktionen kann mit einem einfachen SWAP durchgeführt werden. $M_2|0001\\rangle$ wird durch Vertauschen $1$ der Zustände von Qubit $0$ und erreicht. $M_2|0010\\rangle$ wird durch Vertauschen der Zustände von Qubit $1$ und erreicht. Und $2$ so weiter. Wir können also die $M_2$ Matrix in die folgende Reihe von SWAP-Gattern zerlegen:\n",
        "\n",
        "    $$\n",
        "    M_2 = SWAP(0,1)SWAP(1,2)SWAP(2,3)\n",
        "    $$\n",
        "\n",
        "    Da wir uns daran erinnern, dass Operatoren von rechts nach links wirken, überprüfen wir, ob dies auf jeden der Zustände die gewünschte Wirkung hat:\n",
        "\n",
        "    $$\n",
        "    \\begin{aligned}\n",
        "    M_2|0001\\rangle &= SWAP(0,1)SWAP(1,2)SWAP(2,3)|0001\\rangle \\\\\n",
        "    &= SWAP(0,1)SWAP(1,2)|0001\\rangle \\\\\n",
        "    &= SWAP(0,1)|0001\\rangle \\\\\n",
        "    &=|0010\\rangle  \\checkmark \\\\\n",
        "    M_2|0010\\rangle &= SWAP(0,1)SWAP(1,2)SWAP(2,3)|0010\\rangle \\\\\n",
        "    &= SWAP(0,1)SWAP(1,2)|0010\\rangle \\\\\n",
        "    &= SWAP(0,1)|0100\\rangle \\\\\n",
        "    &=|0100\\rangle  \\checkmark \\\\\n",
        "    M_2|0100\\rangle &= SWAP(0,1)SWAP(1,2)SWAP(2,3)|0100\\rangle \\\\\n",
        "    &= SWAP(0,1)SWAP(1,2)|1000\\rangle \\\\\n",
        "    &= SWAP(0,1)|1000\\rangle \\\\\n",
        "    &=|1000\\rangle  \\checkmark \\\\\n",
        "    M_2|1000\\rangle &= SWAP(0,1)SWAP(1,2)SWAP(2,3)|1000\\rangle \\\\\n",
        "    &= SWAP(0,1)SWAP(1,2)|0100\\rangle \\\\\n",
        "    &= SWAP(0,1)|0010\\rangle \\\\\n",
        "    &=|0001\\rangle  \\checkmark \\\\\n",
        "    \\end{aligned}\n",
        "    $$\n",
        "  </AccordionItem>\n",
        "</Accordion>\n",
        "\n",
        "Wir können nun die Schaltung codieren, die diesem Operator in Qiskit entspricht.\n",
        "\n",
        "Zunächst importieren wir die erforderlichen Pakete:\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 29,
      "id": "95c8d21b-d2e6-45c3-a2d2-a7288db4171f",
      "metadata": {},
      "outputs": [],
      "source": [
        "# Import necessary packages\n",
        "\n",
        "import numpy as np\n",
        "from fractions import Fraction\n",
        "from math import floor, gcd, log\n",
        "\n",
        "from qiskit import QuantumCircuit, QuantumRegister, ClassicalRegister\n",
        "from qiskit.circuit.library import QFTGate\n",
        "from qiskit.transpiler import generate_preset_pass_manager\n",
        "from qiskit.visualization import plot_histogram\n",
        "\n",
        "from qiskit_ibm_runtime import QiskitRuntimeService\n",
        "from qiskit_ibm_runtime import SamplerV2 as Sampler"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "f8d46443-d3d3-4d27-8026-27974f5d6702",
      "metadata": {},
      "source": [
        "Dann erstellen wir den $M_2$ Operator:\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 30,
      "id": "1396a7ff-718a-4169-9c63-85ae218b58a4",
      "metadata": {},
      "outputs": [],
      "source": [
        "def M2mod15():\n",
        "    \"\"\"\n",
        "    M2 (mod 15)\n",
        "    \"\"\"\n",
        "    b = 2\n",
        "    U = QuantumCircuit(4)\n",
        "\n",
        "    U.swap(2, 3)\n",
        "    U.swap(1, 2)\n",
        "    U.swap(0, 1)\n",
        "\n",
        "    U = U.to_gate()\n",
        "    U.name = f\"M_{b}\"\n",
        "\n",
        "    return U"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 31,
      "id": "e7521fba-fe3e-45bc-b9ce-fe876bddad33",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/modules/computer-science/shors-algorithm/extracted-outputs/e7521fba-fe3e-45bc-b9ce-fe876bddad33-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 31,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "# Get the M2 operator\n",
        "M2 = M2mod15()\n",
        "\n",
        "# Add it to a circuit and plot\n",
        "circ = QuantumCircuit(4)\n",
        "circ.compose(M2, inplace=True)\n",
        "circ.decompose(reps=2).draw(output=\"mpl\", fold=-1)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "6f1e1a5d-bd34-4379-9237-d91ecba9d435",
      "metadata": {},
      "source": [
        "Der QPE-Algorithmus verwendet ein gesteuertes $U$ Gate. Nun, da wir einen $M_2$ Schaltkreis haben, müssen wir ihn zu einem *geregelten*$M_2$ Schaltkreis machen:\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 32,
      "id": "36d1020c-c0af-4211-bd50-be865d057f75",
      "metadata": {},
      "outputs": [],
      "source": [
        "def controlled_M2mod15():\n",
        "    \"\"\"\n",
        "    Controlled M2 (mod 15)\n",
        "    \"\"\"\n",
        "    b = 2\n",
        "    U = QuantumCircuit(4)\n",
        "\n",
        "    U.swap(2, 3)\n",
        "    U.swap(1, 2)\n",
        "    U.swap(0, 1)\n",
        "\n",
        "    U = U.to_gate()\n",
        "    U.name = f\"M_{b}\"\n",
        "    c_U = U.control()\n",
        "\n",
        "    return c_U"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 33,
      "id": "5bf4f10d-5d52-406d-b62d-ad4a8d366c02",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/modules/computer-science/shors-algorithm/extracted-outputs/5bf4f10d-5d52-406d-b62d-ad4a8d366c02-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 33,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "# Get the controlled-M2 operator\n",
        "controlled_M2 = controlled_M2mod15()\n",
        "\n",
        "# Add it to a circuit and plot\n",
        "circ = QuantumCircuit(5)\n",
        "circ.compose(controlled_M2, inplace=True)\n",
        "circ.decompose(reps=1).draw(output=\"mpl\", fold=-1)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "fd98c560-530f-424f-b8f8-0f9fe9615c5e",
      "metadata": {},
      "source": [
        "Jetzt haben wir unser gesteuertes $U$ Gate. Um jedoch den Quantenphasen-Schätzungsalgorithmus auszuführen, benötigen wir kontrollierte $U^2$, kontrollierte $U^4$, bis zu kontrollierte $U^{2^{m-1}}$, wobei die Anzahl $m$ der Qubits ist, die zur Schätzung der Phase verwendet werden. Je mehr Qubits, desto präziser wird die Phasenschätzung sein. Wir verwenden $m=8$ Kontroll-Qubits für unser Phasenschätzungsverfahren. Also brauchen wir:\n",
        "\n",
        "$$\n",
        "M_{a^{2^k}}|y\\rangle \\equiv |a^{2^k} y \\bmod N \\rangle\n",
        "$$\n",
        "\n",
        "wobei der Index $k$ mit dem $0 \\le k \\le m-1 = 7$ Steuerqubit entspricht. Berechnen wir nun $a^{2^k}\\bmod N $ für jeden Wert von $k$ :\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 34,
      "id": "1463f000-c7ab-4e09-b111-5cb3d279e06b",
      "metadata": {},
      "outputs": [],
      "source": [
        "def a2kmodN(a, k, N):\n",
        "    \"\"\"Compute a^{2^k} (mod N) by repeated squaring\"\"\"\n",
        "    for _ in range(k):\n",
        "        a = int(np.mod(a**2, N))\n",
        "    return a"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 35,
      "id": "ac0f44f1-e5fa-46b8-a1d2-5255ed63e3b9",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "[2, 4, 1, 1, 1, 1, 1, 1]\n"
          ]
        }
      ],
      "source": [
        "k_list = range(8)\n",
        "b_list = [a2kmodN(2, k, 15) for k in k_list]\n",
        "\n",
        "print(b_list)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "a2654cb9-a2ad-4947-8441-a1e2799501b8",
      "metadata": {},
      "source": [
        "Da $a^{2^k} \\bmod N = 1$ für $k \\ge 2$ gilt, sind alle entsprechenden Operatoren ( $M_8$ und höher) äquivalent zur Identitätsfunktion. Wir müssen also nur noch eine weitere Matrix bilden, nämlich $M_4$.\n",
        "\n",
        "**Hinweis:** Diese Vereinfachung funktioniert hier nur, weil die Reihenfolge von $2 \\bmod 15 $ ist $4$. Sobald $k=2$ (also $2^k = 4$ ), ist jede nachfolgende Potenz des Operators die Identität. Im Allgemeinen kann man bei größeren Zahlen $N$ oder anderen Werten für die Bildung der höheren $a$ Potenzen nicht überspringen. Dies ist ein Grund, warum dies als *Spiel* zeugbeispiel betrachtet wird: Die kleinen Zahlen ermöglichen Abkürzungen, die bei größeren Fällen nicht funktionieren würden.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 36,
      "id": "29bc2fb5-511d-4593-8c48-7b1c7c7eeed0",
      "metadata": {},
      "outputs": [],
      "source": [
        "def M4mod15():\n",
        "    \"\"\"\n",
        "    M4 (mod 15)\n",
        "    \"\"\"\n",
        "    b = 4\n",
        "    U = QuantumCircuit(4)\n",
        "\n",
        "    U.swap(1, 3)\n",
        "    U.swap(0, 2)\n",
        "\n",
        "    U = U.to_gate()\n",
        "    U.name = f\"M_{b}\"\n",
        "\n",
        "    return U"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 37,
      "id": "ea4fc641-e97c-400d-a761-5f67a0b7d65e",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/modules/computer-science/shors-algorithm/extracted-outputs/ea4fc641-e97c-400d-a761-5f67a0b7d65e-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 37,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "# Get the M4 operator\n",
        "M4 = M4mod15()\n",
        "\n",
        "# Add it to a circuit and plot\n",
        "circ = QuantumCircuit(4)\n",
        "circ.compose(M4, inplace=True)\n",
        "circ.decompose(reps=2).draw(output=\"mpl\", fold=-1)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "f6712a0c-a695-4c1d-a99a-a9fd67a95c92",
      "metadata": {},
      "source": [
        "Und wie zuvor machen wir es zu einem *kontrollierten*$M_4$ Operator:\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 38,
      "id": "c8ec99c7-5e03-4623-b6f7-22dae558de04",
      "metadata": {},
      "outputs": [],
      "source": [
        "def controlled_M4mod15():\n",
        "    \"\"\"\n",
        "    Controlled M4 (mod 15)\n",
        "    \"\"\"\n",
        "    b = 4\n",
        "    U = QuantumCircuit(4)\n",
        "\n",
        "    U.swap(1, 3)\n",
        "    U.swap(0, 2)\n",
        "\n",
        "    U = U.to_gate()\n",
        "    U.name = f\"M_{b}\"\n",
        "    c_U = U.control()\n",
        "\n",
        "    return c_U"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 39,
      "id": "37caf888-276e-4f19-a0d0-59517c5ee44e",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/modules/computer-science/shors-algorithm/extracted-outputs/37caf888-276e-4f19-a0d0-59517c5ee44e-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 39,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "# Get the controlled-M4 operator\n",
        "controlled_M4 = controlled_M4mod15()\n",
        "\n",
        "# Add it to a circuit and plot\n",
        "circ = QuantumCircuit(5)\n",
        "circ.compose(controlled_M4, inplace=True)\n",
        "circ.decompose(reps=1).draw(output=\"mpl\", fold=-1)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "db3f989d-ef17-48af-99c6-aae08eb59001",
      "metadata": {},
      "source": [
        "Nun können wir alles zusammenfügen, um die Ordnung von $2\\bmod 15$ mit einem Quantenschaltkreis unter Verwendung der Phasenschätzung zu ermitteln:\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 48,
      "id": "d1b111c8-1a12-420b-bbc2-4ecdd1ac5a97",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/modules/computer-science/shors-algorithm/extracted-outputs/d1b111c8-1a12-420b-bbc2-4ecdd1ac5a97-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 48,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "# Order finding problem for N = 15 with a = 2\n",
        "N = 15\n",
        "a = 2\n",
        "\n",
        "# Number of qubits\n",
        "num_target = floor(log(N - 1, 2)) + 1  # for modular exponentiation operators\n",
        "num_control = 2 * num_target  # for enough precision of estimation\n",
        "\n",
        "# List of M_b operators in order\n",
        "k_list = range(num_control)\n",
        "b_list = [a2kmodN(2, k, 15) for k in k_list]\n",
        "\n",
        "# Initialize the circuit\n",
        "control = QuantumRegister(num_control, name=\"C\")\n",
        "target = QuantumRegister(num_target, name=\"T\")\n",
        "output = ClassicalRegister(num_control, name=\"out\")\n",
        "circuit = QuantumCircuit(control, target, output)\n",
        "\n",
        "# Initialize the target register to the state |1>\n",
        "circuit.x(num_control)\n",
        "\n",
        "# Add the Hadamard gates and controlled versions of the\n",
        "# multiplication gates\n",
        "for k, qubit in enumerate(control):\n",
        "    circuit.h(k)\n",
        "    b = b_list[k]\n",
        "    if b == 2:\n",
        "        circuit.compose(\n",
        "            M2mod15().control(), qubits=[qubit] + list(target), inplace=True\n",
        "        )\n",
        "    elif b == 4:\n",
        "        circuit.compose(\n",
        "            M4mod15().control(), qubits=[qubit] + list(target), inplace=True\n",
        "        )\n",
        "    else:\n",
        "        continue  # M1 is the identity operator\n",
        "\n",
        "# Apply the inverse QFT to the control register\n",
        "circuit.compose(QFTGate(num_control).inverse(), qubits=control, inplace=True)\n",
        "\n",
        "# Measure the control register\n",
        "circuit.measure(control, output)\n",
        "\n",
        "circuit.draw(\"mpl\", fold=-1)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "b3659616-39b4-4544-8def-54012b40dbfa",
      "metadata": {},
      "source": [
        "<span id=\"2-optimize\" />\n",
        "\n",
        "### 2. Optimieren\n",
        "\n",
        "Nachdem wir nun unseren Schaltkreis abgebildet haben, besteht der nächste Schritt darin, ihn für den Betrieb auf einem bestimmten Quantencomputer zu optimieren. Zuerst müssen wir das Backend laden.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 49,
      "id": "92b92fd3-0dca-43db-a304-0a933f293d8f",
      "metadata": {},
      "outputs": [],
      "source": [
        "service = QiskitRuntimeService()\n",
        "\n",
        "backend = service.backend(\"ibm_marrakesh\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "a4e27bee-66de-4ffc-b1e3-40a458840e7a",
      "metadata": {},
      "source": [
        "Wenn Sie keine Zeit auf Ihrem Konto haben oder aus irgendeinem Grund einen Simulator verwenden möchten, können Sie die folgende Zelle ausführen, um einen Simulator einzurichten, der das oben ausgewählte Quanten-Gerät nachahmt:\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 50,
      "id": "4aa86bd6-1240-49cb-aad0-c3dbc64602c5",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "2q-depth: 188\n",
            "2q-size: 281\n",
            "Operator counts: OrderedDict({'sx': 548, 'rz': 380, 'cz': 281, 'measure': 8, 'x': 6})\n"
          ]
        },
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/modules/computer-science/shors-algorithm/extracted-outputs/4aa86bd6-1240-49cb-aad0-c3dbc64602c5-1.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 50,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "pm = generate_preset_pass_manager(optimization_level=2, backend=backend)\n",
        "\n",
        "transpiled_circuit = pm.run(circuit)\n",
        "\n",
        "print(f\"2q-depth: {transpiled_circuit.depth(lambda x: x.operation.num_qubits==2)}\")\n",
        "print(f\"2q-size: {transpiled_circuit.size(lambda x: x.operation.num_qubits==2)}\")\n",
        "print(f\"Operator counts: {transpiled_circuit.count_ops()}\")\n",
        "transpiled_circuit.draw(output=\"mpl\", fold=-1, style=\"clifford\", idle_wires=False)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "b0425c46-2f2e-436f-9d37-a29fbc3a0006",
      "metadata": {},
      "source": [
        "<span id=\"3-execute\" />\n",
        "\n",
        "### 3. Ausführen\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 51,
      "id": "6ee53841-d7e0-4a23-a3eb-bed31465374f",
      "metadata": {},
      "outputs": [],
      "source": [
        "# Sampler primitive to obtain the probability distribution\n",
        "sampler = Sampler(backend)\n",
        "\n",
        "# Turn on dynamical decoupling with sequence XpXm\n",
        "sampler.options.dynamical_decoupling.enable = True\n",
        "sampler.options.dynamical_decoupling.sequence_type = \"XpXm\"\n",
        "# Enable gate twirling\n",
        "sampler.options.twirling.enable_gates = True\n",
        "\n",
        "pub = transpiled_circuit\n",
        "job = sampler.run([pub], shots=1024)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 52,
      "id": "7fb6178e-76bd-4067-9607-1d7e0ac051f3",
      "metadata": {},
      "outputs": [],
      "source": [
        "result = job.result()[0]\n",
        "counts = result.data[\"out\"].get_counts()"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 53,
      "id": "6744e165-6929-46c6-9cad-55e78fe21f07",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/modules/computer-science/shors-algorithm/extracted-outputs/6744e165-6929-46c6-9cad-55e78fe21f07-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 53,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "plot_histogram(counts, figsize=(35, 5))"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "2eae47e9-1161-44e5-9e00-7b0d225bcf5f",
      "metadata": {},
      "source": [
        "Wir sehen vier deutliche Spitzen bei `00000000`, `01000000`, `10000000` und `11000000`, mit einigen Zählungen in anderen Bitstrings aufgrund von Rauschen im Quantencomputer. Wir ignorieren diese und behalten nur die vier dominanten, indem wir einen Schwellenwert festlegen: Nur Werte oberhalb dieses Schwellenwerts werden als echtes Signal oberhalb des Rauschens betrachtet.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "948f404b-a2a9-4645-a034-31b696ba24b7",
      "metadata": {},
      "outputs": [],
      "source": [
        "# Dictionary of bitstrings and their counts to keep\n",
        "counts_keep = {}\n",
        "# Threshold to filter\n",
        "threshold = np.max(list(counts.values())) / 2\n",
        "\n",
        "for key, value in counts.items():\n",
        "    if value > threshold:\n",
        "        counts_keep[key] = value\n",
        "\n",
        "print(counts_keep)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "f9bac651-2d89-4b4e-9930-ea585a4c042e",
      "metadata": {},
      "source": [
        "<span id=\"4-post-process\" />\n",
        "\n",
        "### 4. Nachbearbeitung\n",
        "\n",
        "Bei Shors Algorithmus wird ein Großteil des Algorithmus klassisch ausgeführt. Also werden wir den Rest in den Schritt „Nachbearbeitung“ einfügen, nachdem wir unsere Messungen vom Quantencomputer erhalten haben. Jede der oben genannten Messungen kann in ganze Zahlen umgewandelt werden, die nach der Division durch unsere Annäherungswerte für sind $2^m$ $\\frac{k}{r}$, wobei jedes Mal $k$ zufällig ist.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 55,
      "id": "aad78e69-adb8-416f-bc68-c2086f900bef",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "\n",
            "ATTEMPT 0:\n",
            "Phase: theta = 0.0\n",
            "Order of 2 modulo 15 estimated as: r = 1\n",
            "\n",
            "ATTEMPT 1:\n",
            "Phase: theta = 0.75\n",
            "Order of 2 modulo 15 estimated as: r = 4\n",
            "*** Non-trivial factor found: 3 ***\n"
          ]
        }
      ],
      "source": [
        "a = 2\n",
        "N = 15\n",
        "\n",
        "FACTOR_FOUND = False\n",
        "num_attempt = 0\n",
        "\n",
        "while not FACTOR_FOUND:\n",
        "    print(f\"\\nATTEMPT {num_attempt}:\")\n",
        "    # Here, we get the bitstring by iterating over outcomes\n",
        "    # of a previous hardware run with multiple shots.\n",
        "    # Instead, we can also perform a single-shot measurement\n",
        "    # here in the loop.\n",
        "    bitstring = list(counts_keep.keys())[num_attempt]\n",
        "    num_attempt += 1\n",
        "    # Find the phase from measurement\n",
        "    decimal = int(bitstring, 2)\n",
        "    phase = decimal / (2**num_control)  # phase = k / r\n",
        "    print(f\"Phase: theta = {phase}\")\n",
        "\n",
        "    # Guess the order from phase\n",
        "    frac = Fraction(phase).limit_denominator(N)\n",
        "    r = frac.denominator  # order = r\n",
        "    print(f\"Order of {a} modulo {N} estimated as: r = {r}\")\n",
        "\n",
        "    if phase != 0:\n",
        "        # Guesses for factors are gcd(a^{r / 2} ± 1, 15)\n",
        "        if r % 2 == 0:\n",
        "            x = pow(a, r // 2, N) - 1\n",
        "            d = gcd(x, N)\n",
        "            if d > 1:\n",
        "                FACTOR_FOUND = True\n",
        "                print(f\"*** Non-trivial factor found: {x} ***\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "c88c65c3-2dfb-47fd-bef9-59f02440f418",
      "metadata": {},
      "source": [
        "<span id=\"conclusion\" />\n",
        "\n",
        "## Fazit\n",
        "\n",
        "Nachdem Sie das Modul durchgearbeitet haben, werden Sie vielleicht eine neue Wertschätzung für die Genialität von Peter Shor entwickeln, der einen so cleveren Algorithmus entwickelt hat. Aber hoffentlich haben Sie auch ein neues Verständnis für seine trügerische Einfachheit gewonnen. Auch wenn der Algorithmus beeindruckend (oder einschüchternd) komplex erscheint, können Sie Shors Algorithmus ausführen, wenn Sie ihn in einzelne logische Schritte unterteilen und diese langsam durchgehen.\n",
        "\n",
        "Wir sind zwar noch weit davon entfernt, diesen Algorithmus zur Faktorisierung von Zahlen wie zu verwenden, aber unsere RSA1024 Quantencomputer werden von Tag zu Tag besser, und sobald eine bestimmte Schwelle, *die* sogenannte Fehlertoleranz, erreicht ist, werden Algorithmen wie diese bald folgen. Es ist eine spannende Zeit, um etwas über Quantencomputing zu lernen!\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "9f1e3bb2-9732-406f-9f17-862178724285",
      "metadata": {},
      "source": [
        "<span id=\"problems\" />\n",
        "\n",
        "## Fehler\n",
        "\n",
        "<span id=\"critical-concepts\" />\n",
        "\n",
        "### Wichtige Konzepte:\n",
        "\n",
        "* Moderne kryptografische Systeme basieren auf der klassischen Schwierigkeit, große ganze Zahlen zu faktorisieren.\n",
        "* Die modulare Arithmetik – einschließlich der Strukturen $\\mathbb{Z}_N$ und $\\mathbb{Z}_N^*$ – bildet die mathematische Grundlage für Shors Algorithmus.\n",
        "* Das Problem der Faktorisierung einer ganzen Zahl $N$ kann auf das Problem der Bestimmung der Ordnung einer Zahl modulo reduziert $N$ werden.\n",
        "* Die Quantumsuchfunktion verwendet Techniken zur Quantumsphasenabschätzung, um die Periode der Funktion zu bestimmen $a^x \\mod N$.\n",
        "* Der Shor-Algorithmus besteht aus einem hybriden klassisch-quantenmechanischen Arbeitsablauf, bei dem eine Basis ausgewählt, die Quantenreihenfolge ermittelt und anschließend die Faktoren aus dem Ergebnis klassisch berechnet werden.\n",
        "\n",
        "<span id=\"true/false\" />\n",
        "\n",
        "### Richtig/Falsch:\n",
        "\n",
        "1. Richtig oder falsch: Die Effizienz von Shors Algorithmus gefährdet die Sicherheit der RSA-Verschlüsselung.\n",
        "2. Richtig oder falsch: Der Shor-Algorithmus kann auf jedem modernen Quantencomputer effizient ausgeführt werden.\n",
        "3. T/F Der Shor-Algorithmus verwendet die Quantenphasenschätzung (QPE) als wichtige Unterroutine.\n",
        "4. Richtig oder falsch? Der klassische Teil von Shors Algorithmus umfasst die Berechnung des größten gemeinsamen Teilers (GCD).\n",
        "5. Richtig oder falsch: Der Shor-Algorithmus funktioniert nur für die Faktorisierung gerader Zahlen.\n",
        "6. Richtig oder falsch? Eine erfolgreiche Ausführung des Shor-Algorithmus garantiert immer die korrekten Faktoren.\n",
        "\n",
        "<span id=\"short-answer\" />\n",
        "\n",
        "### Kurze Antwort:\n",
        "\n",
        "1. Warum wird Shors Algorithmus als potenzielle zukünftige Bedrohung für die RSA-Verschlüsselung angesehen?\n",
        "2. Warum ist es für die Faktorisierung einer Zahl im Shor-Algorithmus hilfreich, die Periode oder Ordnung einer modularen Exponentialfunktion zu finden?\n",
        "\n",
        "<span id=\"challenge-problems\" />\n",
        "\n",
        "### Herausfordernde Probleme:\n",
        "\n",
        "1. Wie viele Kontrollqubits $m$ benötigen wir für eine bestimmte Zahl $N$, die wir faktorisieren möchten, um die erforderliche Genauigkeit im QPE zu erzielen, um den korrekten Wert der Ordnung zu finden $r$?\n",
        "\n",
        "2. Befolgen Sie die hier beschriebene Vorgehensweise, um 15 zu faktorisieren, und versuchen Sie nun, 21 zu faktorisieren.\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": 5
}