diff --git a/notebooks/algorithms/images/Deutsch-Jozsa.png b/notebooks/algorithms/01.query-algorithms/images/Deutsch-Jozsa.png similarity index 100% rename from notebooks/algorithms/images/Deutsch-Jozsa.png rename to notebooks/algorithms/01.query-algorithms/images/Deutsch-Jozsa.png diff --git a/notebooks/algorithms/images/Deutsch-circuit-states.png b/notebooks/algorithms/01.query-algorithms/images/Deutsch-circuit-states.png similarity index 100% rename from notebooks/algorithms/images/Deutsch-circuit-states.png rename to notebooks/algorithms/01.query-algorithms/images/Deutsch-circuit-states.png diff --git a/notebooks/algorithms/images/Deutsch-circuit.png b/notebooks/algorithms/01.query-algorithms/images/Deutsch-circuit.png similarity index 100% rename from notebooks/algorithms/images/Deutsch-circuit.png rename to notebooks/algorithms/01.query-algorithms/images/Deutsch-circuit.png diff --git a/notebooks/algorithms/images/Simon.png b/notebooks/algorithms/01.query-algorithms/images/Simon.png similarity index 100% rename from notebooks/algorithms/images/Simon.png rename to notebooks/algorithms/01.query-algorithms/images/Simon.png diff --git a/notebooks/algorithms/images/classical-parity.png b/notebooks/algorithms/01.query-algorithms/images/classical-parity.png similarity index 100% rename from notebooks/algorithms/images/classical-parity.png rename to notebooks/algorithms/01.query-algorithms/images/classical-parity.png diff --git a/notebooks/algorithms/images/classical-query-gate.png b/notebooks/algorithms/01.query-algorithms/images/classical-query-gate.png similarity index 100% rename from notebooks/algorithms/images/classical-query-gate.png rename to notebooks/algorithms/01.query-algorithms/images/classical-query-gate.png diff --git a/notebooks/algorithms/images/query-computation.png b/notebooks/algorithms/01.query-algorithms/images/query-computation.png similarity index 100% rename from notebooks/algorithms/images/query-computation.png rename to notebooks/algorithms/01.query-algorithms/images/query-computation.png diff --git a/notebooks/algorithms/images/standard-computation.png b/notebooks/algorithms/01.query-algorithms/images/standard-computation.png similarity index 100% rename from notebooks/algorithms/images/standard-computation.png rename to notebooks/algorithms/01.query-algorithms/images/standard-computation.png diff --git a/notebooks/algorithms/images/unitary-query-gate.png b/notebooks/algorithms/01.query-algorithms/images/unitary-query-gate.png similarity index 100% rename from notebooks/algorithms/images/unitary-query-gate.png rename to notebooks/algorithms/01.query-algorithms/images/unitary-query-gate.png diff --git a/notebooks/algorithms/quantum-query-algorithms.ipynb b/notebooks/algorithms/01.query-algorithms/quantum-query-algorithms.ipynb similarity index 55% rename from notebooks/algorithms/quantum-query-algorithms.ipynb rename to notebooks/algorithms/01.query-algorithms/quantum-query-algorithms.ipynb index 54c916c..eaf9290 100644 --- a/notebooks/algorithms/quantum-query-algorithms.ipynb +++ b/notebooks/algorithms/01.query-algorithms/quantum-query-algorithms.ipynb @@ -31,7 +31,7 @@ "While the time required to solve problems is our main concern, we will deviate slightly from this focus for the purposes of this first lesson.\n", "What we will do is to formulate a simple algorithmic framework — known as the *query model* — and explore the advantages that quantum computers offer within this framework.\n", "\n", - "The query model of computation is like a Petri dish for quantum algorithmic ideas.\n", + "The query model of computation is like a petri dish for quantum algorithmic ideas.\n", "It is rigid and unnatural, in the sense that it does not accurately represent the sorts of computational problems we generally care about in practice.\n", "Nevertheless, it has proved to be incredibly useful as a tool for developing quantum algorithmic techniques, including ones that power the most well-known quantum algorithms (such as Shor's factoring algorithm).\n", "It also happens to be a very useful framework for *explaining* these techniques.\n", @@ -438,18 +438,17 @@ "source": [ "from qiskit import QuantumCircuit\n", "\n", - "\n", "def deutsch_function(case: int):\n", " \"\"\"\n", " Generate a valid Deutsch function as a `QuantumCircuit`.\n", " \"\"\"\n", - " if case not in [1, 2, 3, 4]:\n", + " if case not in [1,2,3,4]:\n", " raise ValueError(\"`case` must be 1, 2, 3, or 4.\")\n", "\n", " f = QuantumCircuit(2)\n", - " if case in [2, 3]:\n", + " if case in [2,3]:\n", " f.cx(0, 1)\n", - " if case in [3, 4]:\n", + " if case in [3,4]:\n", " f.x(1)\n", " return f" ] @@ -470,11 +469,9 @@ "outputs": [ { "data": { - "image/svg+xml": [ - "" - ], + "image/png": "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\n", "text/plain": [ - "
" + "
" ] }, "execution_count": 2, @@ -506,11 +503,11 @@ " \"\"\"\n", " Compiles a circuit for use in Deutsch's algorithm.\n", " \"\"\"\n", - " n = function.num_qubits - 1\n", - " qc = QuantumCircuit(n + 1, n)\n", + " n = function.num_qubits-1\n", + " qc = QuantumCircuit(n+1, n)\n", "\n", " qc.x(n)\n", - " qc.h(range(n + 1))\n", + " qc.h(range(n+1))\n", "\n", " qc.barrier()\n", " qc.compose(function, inplace=True)\n", @@ -538,11 +535,9 @@ "outputs": [ { "data": { - "image/svg+xml": [ - "" - ], + "image/png": "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\n", "text/plain": [ - "
" + "
" ] }, "execution_count": 4, @@ -551,7 +546,9 @@ } ], "source": [ - "compile_circuit(deutsch_function(3)).draw()" + "compile_circuit(\n", + " deutsch_function(3)\n", + ").draw()" ] }, { @@ -571,16 +568,15 @@ "source": [ "from qiskit_aer import AerSimulator\n", "\n", - "\n", "def deutsch_algorithm(function: QuantumCircuit):\n", " \"\"\"\n", " Determine if a Deutsch function is constant or balanced.\n", " \"\"\"\n", " qc = compile_circuit(function)\n", - "\n", - " result = AerSimulator().run(qc, shots=1, memory=True).result()\n", + " \n", + " result = AerSimulator().run(qc,shots=1,memory=True).result()\n", " measurements = result.get_memory()\n", - " if measurements[0] == \"0\":\n", + " if measurements[0] == '0':\n", " return \"constant\"\n", " return \"balanced\"" ] @@ -601,11 +597,9 @@ "outputs": [ { "data": { - "image/svg+xml": [ - "" - ], + "image/png": "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\n", "text/plain": [ - "
" + "
" ] }, "metadata": {}, @@ -833,41 +827,40 @@ "from qiskit import QuantumCircuit\n", "import numpy as np\n", "\n", - "\n", "def dj_function(num_qubits):\n", " \"\"\"\n", " Create a random Deutsch-Jozsa function.\n", " \"\"\"\n", "\n", - " qc = QuantumCircuit(num_qubits + 1)\n", + " qc = QuantumCircuit(num_qubits+1)\n", " if np.random.randint(0, 2):\n", " # Flip output qubit with 50% chance\n", " qc.x(num_qubits)\n", " if np.random.randint(0, 2):\n", " # return constant circuit with 50% chance\n", " return qc\n", - "\n", + " \n", " # next, choose half the possible input states\n", " on_states = np.random.choice(\n", " range(2**num_qubits), # numbers to sample from\n", - " 2**num_qubits // 2, # number of samples\n", - " replace=False, # makes sure states are only sampled once\n", + " 2**num_qubits // 2, # number of samples\n", + " replace=False # makes sure states are only sampled once\n", " )\n", "\n", " def add_cx(qc, bit_string):\n", " for qubit, bit in enumerate(reversed(bit_string)):\n", - " if bit == \"1\":\n", + " if bit == '1':\n", " qc.x(qubit)\n", " return qc\n", "\n", " for state in on_states:\n", - " qc.barrier() # Barriers are added to help visualize how the functions are created. They can safely be removed.\n", + " qc.barrier() # Barriers are added to help visualize how the functions are created. They can safely be removed.\n", " qc = add_cx(qc, f\"{state:0b}\")\n", " qc.mct(list(range(num_qubits)), num_qubits)\n", " qc = add_cx(qc, f\"{state:0b}\")\n", "\n", " qc.barrier()\n", - "\n", + " \n", " return qc" ] }, @@ -887,11 +880,9 @@ "outputs": [ { "data": { - "image/svg+xml": [ - "" - ], + "image/png": "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jRTm2no9U803nhdPmBe0flUDXL1kfiBjbCfzzcetd5nr8a5ykSFzrrt0A7KmAldrzaNrX50C6s4CeqN5nVHX283PKemRZq4rO5l77USuGHMw6XePee3axSrzd2PDFXM4jU8089G9n/kl68DqdLLlmoMJkY263g4M5AV7pBBNA27rbX4RBdIp0TxiRhSIOwZITje/iHgqFxERERERCcfBhPyUlpaKLoHIcsw1qYi5tg97TSqSLdc8lSuE7MTEqHvttWvXIi8vT8hrE0UKc00qYq7tw16TimTLNW8XHIVC3T4uIyMj5ATNWyKSTMK5JSJzTU7DXNuHvSYVOTHXPJWLiIiIiIiE42BCRERERETCcTAhPytXrhRdApHlmGtSEXNtH/aaVCRbrjmYkB+PxyO6BCLLMdekIubaPuw1qUi2XHMwIT+5ubmiSyCyHHNNKmKu7cNek4pkyzUHEyIiIiIiEo6fYxKFQt327YknnuAtD8lRwskrc01Ow1zbh70mFTkx1/wcEyIiIiIiEo6nchERERERkXAcTIiIiIiISDgOJkREREREJBwHEyIiIiIiEo6DCRERERERCcfBhIiIiIiIhONgQkREREREwnEwISIiIiIi4TiYEBERERGRcBxMiIiIiIhIuP8Pv1domhP7CFEAAAAASUVORK5CYII=\n", "text/plain": [ - "
" + "
" ] }, "execution_count": 8, @@ -922,10 +913,10 @@ " \"\"\"\n", " Compiles a circuit for use in the Deutsch-Jozsa algorithm.\n", " \"\"\"\n", - " n = function.num_qubits - 1\n", - " qc = QuantumCircuit(n + 1, n)\n", + " n = function.num_qubits-1\n", + " qc = QuantumCircuit(n+1, n)\n", " qc.x(n)\n", - " qc.h(range(n + 1))\n", + " qc.h(range(n+1))\n", " qc.compose(function, inplace=True)\n", " qc.h(range(n))\n", " qc.measure(range(n), range(n))\n", @@ -949,18 +940,17 @@ "source": [ "from qiskit_aer import AerSimulator\n", "\n", - "\n", "def dj_algorithm(function: QuantumCircuit):\n", " \"\"\"\n", " Determine if a Deutsch-Jozsa function is constant or balanced.\n", " \"\"\"\n", " qc = compile_circuit(function)\n", - "\n", - " result = AerSimulator().run(qc, shots=1, memory=True).result()\n", + " \n", + " result = AerSimulator().run(qc,shots=1,memory=True).result()\n", " measurements = result.get_memory()\n", - " if \"1\" in measurements[0]:\n", - " return \"balanced\"\n", - " return \"constant\"" + " if '1' in measurements[0]:\n", + " return 'balanced'\n", + " return 'constant'" ] }, { @@ -973,17 +963,15 @@ }, { "cell_type": "code", - "execution_count": 11, + "execution_count": 18, "id": "46392e96", "metadata": {}, "outputs": [ { "data": { - "image/svg+xml": [ - "" - ], + "image/png": "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\n", "text/plain": [ - "
" + "
" ] }, "metadata": {}, @@ -995,7 +983,7 @@ "'balanced'" ] }, - "execution_count": 11, + "execution_count": 18, "metadata": {}, "output_type": "execute_result" } @@ -1182,20 +1170,18 @@ }, { "cell_type": "code", - "execution_count": 12, + "execution_count": 19, "id": "689ab37a", "metadata": {}, "outputs": [ { "data": { - "image/svg+xml": [ - "" - ], + "image/png": "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\n", "text/plain": [ - "
" + "
" ] }, - "execution_count": 12, + "execution_count": 19, "metadata": {}, "output_type": "execute_result" } @@ -1205,14 +1191,13 @@ " \"\"\"\n", " Create a Bernstein-Vazirani function from a string of 1s and 0s.\n", " \"\"\"\n", - " qc = QuantumCircuit(len(s) + 1)\n", + " qc = QuantumCircuit(len(s)+1)\n", " for index, bit in enumerate(reversed(s)):\n", - " if bit == \"1\":\n", + " if bit == '1':\n", " qc.cx(index, len(s))\n", " return qc\n", "\n", - "\n", - "bv_function(\"1001\").draw()" + "bv_function('1001').draw()" ] }, { @@ -1226,7 +1211,7 @@ }, { "cell_type": "code", - "execution_count": 13, + "execution_count": 20, "id": "d015d981", "metadata": {}, "outputs": [ @@ -1236,7 +1221,7 @@ "'1001'" ] }, - "execution_count": 13, + "execution_count": 20, "metadata": {}, "output_type": "execute_result" } @@ -1244,11 +1229,12 @@ "source": [ "def bv_algorithm(function: QuantumCircuit):\n", " qc = compile_circuit(function)\n", - " result = AerSimulator().run(qc, shots=1, memory=True).result()\n", + " result = AerSimulator().run(qc,shots=1,memory=True).result()\n", " return result.get_memory()[0]\n", "\n", - "\n", - "bv_algorithm(bv_function(\"1001\"))" + "bv_algorithm(\n", + " bv_function('1001')\n", + ")" ] }, { @@ -1305,7 +1291,8 @@ "\n", "> **Simon's problem** \\\n", "> Input: a function $f:\\Sigma^n \\rightarrow \\Sigma^m$ \\\n", - "> Promise: there exists a string $s\\in\\Sigma^n$ such that $[f(x) = f(y)] \\Leftrightarrow [(x = y) \\vee (x \\oplus s = y)]$ for all $x,y\\in\\Sigma^n$ \\\n", + "> Promise: there exists a string $s\\in\\Sigma^n$ such that $[f(x) = f(y)] \\Leftrightarrow \n", + "[(x = y) \\vee (x \\oplus s = y)]$ for all $x,y\\in\\Sigma^n$ \\\n", "> Output: the string $s$\n", "\n", "We'll unpack the promise to better understand what says momentarily, but before doing this let's be clear that most functions don't satisfy this promise; it requires that $f$ has a very special structure.\n", @@ -1355,7 +1342,7 @@ "\n", "### Analysis\n", "\n", - "The analysis of Simon's algorithm begins along similar lines to the Deutsch-Jozsa algorithm.\n", + "The analysis of Simon's algorithm begins along similar lines to the Deutsch-Jozsa algortithm.\n", "After the first layer of Hadamard gates is performed on the top $n$ qubits, the state becomes\n", "\n", "$$\n", @@ -1611,7 +1598,7 @@ }, { "cell_type": "code", - "execution_count": 14, + "execution_count": 21, "id": "d17ea0f7", "metadata": {}, "outputs": [], @@ -1621,33 +1608,29 @@ "from qiskit import QuantumCircuit\n", "import numpy as np\n", "\n", - "\n", "def simon_function(s: str):\n", " \"\"\"\n", - " Create a QuantumCircuit implementing a query gate for Simon problem\n", - " obeying the promise for the hidden string `s`\n", + " Create a QuantumCircuit implementing a query gate for Simon problem obeying the promise for the hidden string `s`\n", " \"\"\"\n", " # Our quantum circuit has 2n qubits for n = len(s)\n", " n = len(s)\n", - " qc = QuantumCircuit(2 * n)\n", - "\n", - " # Define a random permutation of all n bit strings. This permutation\n", - " # will effectively hide the string s.\n", + " qc = QuantumCircuit(2*n)\n", + " \n", + " # Define a random permutation of all n bit strings. This permutation will effectively hide the string s.\n", " pi = np.random.permutation(2**n)\n", - "\n", - " # Now we'll define a query gate explicitly. The idea is to first define\n", - " # a function g(x) = min{x,x ^ s}, which is a simple function that\n", - " # satisfies the promise. Then we take f to be the composition of g and\n", - " # the random permutation pi. This gives us a random function satisfying\n", - " # the promise for s.\n", - " query_gate = np.zeros((4**n, 4**n))\n", + " \n", + " # Now we'll define a query gate explicitly. The idea is to first define a function g(x) = min{x,x ^ s}, which\n", + " # is a simple function that satisfies the promise, and then we take f to be the composition of g and the random\n", + " # permutation pi. This gives us a random function satisfying the promise for s.\n", + " \n", + " query_gate = np.zeros((4**n,4**n))\n", " for x in range(2**n):\n", - " for y in range(2**n):\n", - " z = y ^ pi[min(x, x ^ int(s, 2))]\n", - " query_gate[x + 2**n * z, x + 2**n * y] = 1\n", + " for y in range(2**n): \n", + " z = y ^ pi[min(x,x ^ int(s,2))]\n", + " query_gate[x + 2**n *z, x + 2**n *y] = 1 \n", "\n", " # Our circuit has just this one query gate\n", - " qc.unitary(query_gate, range(2 * n))\n", + " qc.unitary(query_gate,range(2*n))\n", " return qc" ] }, @@ -1661,7 +1644,7 @@ }, { "cell_type": "code", - "execution_count": 15, + "execution_count": 23, "id": "29be9b92", "metadata": {}, "outputs": [], @@ -1669,7 +1652,6 @@ "from qiskit_aer import AerSimulator\n", "from qiskit import ClassicalRegister\n", "\n", - "\n", "def simon_measurements(problem: QuantumCircuit, k: int):\n", " \"\"\"\n", " Quantum part of Simon's algorithm. Given a `QuantumCircuit` that\n", @@ -1677,13 +1659,13 @@ " \"\"\"\n", " n = problem.num_qubits // 2\n", "\n", - " qc = QuantumCircuit(2 * n, n)\n", + " qc = QuantumCircuit(2*n,n)\n", " qc.h(range(n))\n", " qc.compose(problem, inplace=True)\n", " qc.h(range(n))\n", " qc.measure(range(n), range(n))\n", - "\n", - " result = AerSimulator().run(qc, shots=k, memory=True).result()\n", + " \n", + " result = AerSimulator().run(qc,shots=k,memory=True).result()\n", " return result.get_memory()" ] }, @@ -1698,34 +1680,37 @@ }, { "cell_type": "code", - "execution_count": 16, + "execution_count": 24, "id": "5b3513c3", "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "['11111',\n", - " '01001',\n", + "['00111',\n", + " '10001',\n", " '01101',\n", - " '10101',\n", - " '00000',\n", - " '11011',\n", - " '01110',\n", + " '11111',\n", + " '01010',\n", + " '00111',\n", + " '00011',\n", + " '10110',\n", + " '10110',\n", " '00000',\n", - " '00100',\n", - " '10010',\n", - " '00100',\n", - " '01010']" + " '00111',\n", + " '11111']" ] }, - "execution_count": 16, + "execution_count": 24, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "simon_measurements(simon_function(\"11011\"), k=12)" + "simon_measurements(\n", + " simon_function('11011'),\n", + " k=12\n", + ")" ] }, { @@ -1738,7 +1723,7 @@ }, { "cell_type": "code", - "execution_count": 17, + "execution_count": 25, "id": "0f74e289", "metadata": {}, "outputs": [], @@ -1746,34 +1731,33 @@ "import numpy as np\n", "import galois\n", "\n", - "\n", "def simon_algorithm(problem: QuantumCircuit):\n", " \"\"\"\n", - " Given a `QuantumCircuit` that implements a query gate for Simon problem,\n", - " return the hidden string `s`.\n", + " Given a `QuantumCircuit` that implements a query gate for Simon problem, return the hidden string `s`.\n", " \"\"\"\n", - " # Quantum part: run the circuit defined previously k times and gather\n", - " # the measurement results. Replace +10 by +r for any nonnegative\n", - " # integer r depending on desired confidence.\n", + " \n", + " # Quantum part: run the circuit defined previously k times and gather the measurement results.\n", + " # Replace +10 by +r for any nonnegative integer r depending on desired confidence.\n", + "\n", " measurements = simon_measurements(problem, k=problem.num_qubits // 2 + 10)\n", - " print(\"Measurement results:\")\n", + " print('Measurement results:')\n", " display(measurements)\n", - "\n", + " \n", " # Classical post-processing:\n", - "\n", + " \n", " # 1. Convert measurements of form '11101' to 2D-array of integers\n", - " matrix = np.array([list(bitstring) for bitstring in measurements]).astype(int)\n", - "\n", + " matrix = np.array([list(bitstring) for bitstring in measurements]).astype(int) \n", + " \n", " # 2. Interpret matrix as using arithmetic mod 2, and find null space\n", - " null_space = galois.GF(2)(matrix).null_space()\n", - " print(\"Null space:\")\n", + " null_space = galois.GF(2)(matrix).null_space() \n", + " print('Null space:')\n", " display(null_space)\n", - "\n", + " \n", " # 3. Convert back to a string\n", " if len(null_space) == 0:\n", " # No non-trivial solution; `s` is all-zeros\n", - " return \"0\" * len(measurements[0])\n", - " return \"\".join(np.array(null_space[0]).astype(str))" + " return '0'*len(measurements[0])\n", + " return ''.join(np.array(null_space[0]).astype(str))" ] }, { @@ -1786,10 +1770,10 @@ }, { "cell_type": "code", - "execution_count": 18, + "execution_count": 28, "id": "2d77b5fd", "metadata": { - "scrolled": false + "scrolled": true }, "outputs": [ { @@ -1802,33 +1786,26 @@ { "data": { "text/plain": [ - "['01100',\n", - " '11001',\n", - " '11110',\n", - " '00100',\n", - " '01100',\n", + "['01111',\n", + " '10010',\n", + " '11101',\n", + " '10010',\n", + " '00000',\n", " '11110',\n", " '10110',\n", " '11010',\n", - " '01000',\n", " '10001',\n", - " '10001',\n", - " '10010',\n", - " '11101',\n", + " '01011',\n", + " '01000',\n", " '00011',\n", - " '10010']" + " '00100',\n", + " '11101',\n", + " '01011']" ] }, "metadata": {}, "output_type": "display_data" }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "OMP: Info #271: omp_set_nested routine deprecated, please use omp_set_max_active_levels instead.\n" - ] - }, { "name": "stdout", "output_type": "stream", @@ -1851,13 +1828,32 @@ "'10011'" ] }, - "execution_count": 18, + "execution_count": 28, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "simon_algorithm(simon_function(\"10011\"))" + "simon_algorithm(\n", + " simon_function('10011')\n", + ")\n" + ] + }, + { + "cell_type": "markdown", + "id": "823ef32b", + "metadata": {}, + "source": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n" ] } ], diff --git a/notebooks/algorithms/02.algorithmic-foundations/algorithmic-foundations.ipynb b/notebooks/algorithms/02.algorithmic-foundations/algorithmic-foundations.ipynb new file mode 100644 index 0000000..734485a --- /dev/null +++ b/notebooks/algorithms/02.algorithmic-foundations/algorithmic-foundations.ipynb @@ -0,0 +1,1208 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "b929937e", + "metadata": {}, + "source": [ + "# Algorithmic foundations\n", + "\n", + "## Introduction\n", + "\n", + "Quantum algorithms provide provable advantages over classical algorithms in the query model — but what about more standard models of computation, where problem inputs are given explicitly rather than in the form of an oracle or black box?\n", + "This turns out to be a much more difficult question to answer, and to address it we must first establish a solid foundation upon which to base our investigation.\n", + "That's the purpose of this lesson.\n", + "\n", + "We'll begin by discussing *computational cost*, for both classical and quantum computations, and how it can be measured.\n", + "This is a general notion that can be applied to a wide range of computational problems — but to keep things simple we'll mainly examine it through the lens of *computational number theory*, which addresses problems including basic arithmetic, computing greatest common divisors, and integer factorization, which are computational tasks that are likely to be familiar to most readers.\n", + "While computational number theory is a narrow application domain, these problems serve well to illustrate the basic issues — and as a bonus they happen to be highly relevant to the lesson following this one.\n", + "\n", + "Our focus will be on *algorithms*, as opposed to the ever-improving hardware on which they're run — so we'll be more concerned with how the cost of running an algorithm scales as the specific problem instances it is run on grow in size, rather than how many seconds, minutes, or hours some particular computation requires.\n", + "We focus on this aspect of computational cost in recognition of the fact that algorithms have fundamental importance, and will naturally be deployed against larger and larger problem instances using faster and more reliable hardware as technology develops.\n", + "\n", + "Finally, we turn to a critically important task, which is running *classical* computations on quantum computers.\n", + "The reason this task is important is not because we hope to replace classical computers with quantum computers (which seems extremely unlikely to happen any time soon, if ever), but rather because it opens up many interesting possibilities for quantum algorithms.\n", + "Specifically, classical computations running on quantum computers become available as *subroutines* — effectively leveraging decades of research and development on classical algorithms in pursuit of quantum computational advantages." + ] + }, + { + "cell_type": "markdown", + "id": "e4566cc2", + "metadata": {}, + "source": [ + "## Two examples: factoring and GCDs\n", + "\n", + "The classical computers that exist today are incredibly fast, and their speed seems to be ever increasing.\n", + "For this reason, some might be inclined to believe that computers are so fast that no computational problem is beyond their reach.\n", + "\n", + "This belief is false.\n", + "Some computational problems are so inherently difficult that, although there exist algorithms to solve them, no computer on the planet Earth today is fast enough to run these algorithms to completion on even moderately sized inputs within the lifetime of a human — or even within the lifetime of the Earth itself.\n", + "\n", + "To explain further, let's introduce the *integer factorization* problem.\n", + "\n", + "\n", + "\n", + "**Integer factorization**\n", + "\n", + "Input: an integer $N\\geq 2$\n", + "\n", + "Output: the prime factorization of $N$\n", + "\n", + "\n", + "\n", + "By the *prime factorization* of $N$, we mean a list of the prime factors of $N$ and the powers to which they must be raised to obtain $N$ by multiplication.\n", + "For example, the prime factors of $12$ are $2$ and $3$, and to obtain $12$ we must take the product of $2$ to the power $2$ and $3$ to the power $1:$\n", + "\n", + "$$\n", + "12 = 2^2 \\cdot 3\n", + "$$\n", + "\n", + "Up to the ordering of the prime factors, there is only one prime factorization for each positive integer $N\\geq 2$, which is a fact known as the *fundamental theorem of arithmetic*.\n", + "\n", + "The `SymPy` symbolic mathematics package for Python includes a function `factorint` that solves the integer factorization problem for whatever input $N$ we choose." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "999fdebb", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{2: 2, 3: 1}" + ] + }, + "execution_count": 1, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "from sympy.ntheory import factorint\n", + "N = 12\n", + "factorint(N)" + ] + }, + { + "cell_type": "markdown", + "id": "8aea3921", + "metadata": {}, + "source": [ + "Factoring small numbers like $12$ is easy, but when the number $N$ to be factored gets larger, the problem becomes more difficult.\n", + "For example, running `factorint` on a significantly larger number will cause a noticeable delay." + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "e5f7c10f", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{3: 2, 74519450661011221: 1, 5073729280707932631243580787: 1}" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "N = 3402823669209384634633740743176823109843098343\n", + "factorint(N)" + ] + }, + { + "cell_type": "markdown", + "id": "0e3cd1ac", + "metadata": {}, + "source": [ + "For even larger values of $N$, things become impossibly difficult, at least as far as we know.\n", + "For example, the *RSA Factoring Challenge*, which was run by RSA Laboratories from 1991 to 2007, offered a cash prize of $100,000 to factor the following number, which has 309 decimal digits (and 1024 bits when written in binary).\n", + "The prize for this number was never collected and its prime factors remain unknown." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "074752ae", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "135066410865995223349603216278805969938881475605667027524485143851526510604859533833940287150571909441798207282164471551373680419703964191743046496589274256239341020864383202110372958725762358509643110564073501508187510676594629205563685529475213500852879416377328533906109750544334999811150056977236890927563\n" + ] + } + ], + "source": [ + "RSA1024 = 135066410865995223349603216278805969938881475605667027524485143851526510604859533833940287150571909441798207282164471551373680419703964191743046496589274256239341020864383202110372958725762358509643110564073501508187510676594629205563685529475213500852879416377328533906109750544334999811150056977236890927563\n", + "print(RSA1024)\n" + ] + }, + { + "cell_type": "markdown", + "id": "2d2655a2", + "metadata": {}, + "source": [ + "We need not bother running `factorint` on RSA1024, it wouldn't finish within our lifetimes." + ] + }, + { + "cell_type": "markdown", + "id": "3fbc4923", + "metadata": {}, + "source": [ + "The fastest known algorithm for factoring large integers is known as the *number field sieve*.\n", + "As an example of this algorithm's use, the RSA challenge number RSA250, which has 250 decimal digits (and 829 bits in its binary representation), was factored using the number field sieve in 2020.\n", + "The computation required thousands of CPU core-years, distributed across tens of thousands of machines around the world." + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "2568ca8e", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "True\n" + ] + } + ], + "source": [ + "RSA250 = 2140324650240744961264423072839333563008614715144755017797754920881418023447140136643345519095804679610992851872470914587687396261921557363047454770520805119056493106687691590019759405693457452230589325976697471681738069364894699871578494975937497937\n", + "\n", + "p = 64135289477071580278790190170577389084825014742943447208116859632024532344630238623598752668347708737661925585694639798853367\n", + "q = 33372027594978156556226010605355114227940760344767554666784520987023841729210037080257448673296881877565718986258036932062711\n", + "\n", + "print(RSA250 == p*q)" + ] + }, + { + "cell_type": "markdown", + "id": "37d39e3c", + "metadata": {}, + "source": [ + "The security of the RSA public-key cryptosystem is based on the computational difficulty of integer factoring;\n", + "an efficient algorithm for integer factoring would break it." + ] + }, + { + "cell_type": "markdown", + "id": "fa3150ec", + "metadata": {}, + "source": [ + "Next let's consider a related but very different problem, which is computing the greatest common divisor (or GCD) of two integers.\n", + "\n", + "\n", + "\n", + "**Greatest common divisor (GCD)**\n", + "\n", + "Input: nonnegative integers $N$ and $M$, at least one of which is positive\n", + "\n", + "Output: the greatest common divisor of $N$ and $M$\n", + "\n", + "\n", + "\n", + "The greatest common divisor of two numbers is the largest integer that evenly divides both of them.\n", + "\n", + "This problem is easy for computers — it has roughly the same computational cost as multiplying the two input numbers together.\n", + "The following code cell runs the `gcd` function from the Python `math` module on two numbers that are both quite a bit larger than RSA1024 in the blink of an eye. (In fact, RSA1024 is the GCD of the two numbers in this example.)" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "33786838", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "135066410865995223349603216278805969938881475605667027524485143851526510604859533833940287150571909441798207282164471551373680419703964191743046496589274256239341020864383202110372958725762358509643110564073501508187510676594629205563685529475213500852879416377328533906109750544334999811150056977236890927563" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "import math\n", + "\n", + "N = 4636759690183918349682239573236686632636353319755818421393667064929987310592347460711767784882455889983961546491666129915628431549982893638464243493812487979530329460863532041588297885958272943021122033997933550246447236884738870576045537199814804920281890355275625050796526864093092006894744790739778376848205654332434378295899591539239698896074\n", + "M = 5056714874804877864225164843977749374751021379176083540426461360945653967249306494545888621353613218518084414930846655066495767441010526886803458300440345782982127522212209489410315422285463057656809702949608368597012967321172325810519806487247195259818074918082416290513738155834341957254558278151385588990304622183174568167973121179585331770773\n", + "\n", + "math.gcd(N,M)" + ] + }, + { + "cell_type": "markdown", + "id": "a404015e", + "metadata": {}, + "source": [ + "We can push it even further and compute GCDs for numbers with thousands of digits in no time." + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "9c012920", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "113" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "math.gcd(N**200 + 1 ,M**100 + M**2)" + ] + }, + { + "cell_type": "markdown", + "id": "4f884bdd", + "metadata": {}, + "source": [ + "This is possible because we have very efficient algorithms for computing GCDs, the most well-known of which is\n", + "*Euclid's algorithm*, discovered over 2,000 years ago.\n", + "\n", + "Could there be a fast algorithm for integer factorization that we just haven't discovered yet, allowing large numbers like RSA1024 to be factored in the blink of an eye?\n", + "The answer is yes.\n", + "Although we might expect that an efficient algorithm for factoring as simple and elegant as Euclid's algorithm for computing GCDs would have been discovered by now, there is nothing that rules out the existence of a very fast classical algorithm for integer factoring, beyond the fact that we've failed to find one thus far.\n", + "One could be discovered tomorrow — but don't hold your breath.\n", + "Generations of mathematicians and computer scientists have searched, and factoring numbers like RSA1024 remains beyond our reach." + ] + }, + { + "cell_type": "markdown", + "id": "a3db50dd", + "metadata": {}, + "source": [ + "## Measuring computational cost\n", + "\n", + "Next we'll discuss a mathematical framework through which computational cost can be measured.\n", + "It should be understood that this discussion is narrowly focused on the needs of this series — the *analysis of algorithms* and *computational complexity* are entire subjects onto themselves, and have much more to say about these notions.\n", + "\n", + "As a starting point, consider the following figure (which first appeared in Lesson 5), which represents a very high level abstraction of a computation.\n", + "\n", + "![Illustration of a standard computation.](images/standard-computation.png)\n", + "\n", + "The computation itself could be modeled or described in a variety of ways, such as by a computer program written in Python, a Turing machine, a Boolean circuit, or a quantum circuit.\n", + "Our focus will be on circuits (both Boolean and quantum)." + ] + }, + { + "cell_type": "markdown", + "id": "3ee7705d", + "metadata": {}, + "source": [ + "### Encodings and input length\n", + "\n", + "Let's begin with the input and output of a computational problem, which we'll assume are *binary strings*.\n", + "Different symbols could be used, but we'll keep things simple for the purposes of this discussion by restricting our attention to binary string inputs and outputs.\n", + "\n", + "Through binary strings, we can *encode* a variety of interesting objects that the problems we're interested in solving might concern, such as numbers, vectors, matrices, and graphs, as well as lists of these and other objects.\n", + "For example, to encode nonnegative integers, we can use *binary notation*.\n", + "The following table lists the binary encoding of the first nine nonnegative integers, along with the *length* (meaning the total number of bits) of each encoding. \n", + "\n", + "| number | binary encoding | length |\n", + "| :-- | :-- | :-- |\n", + "| 0 | 0 | 1 |\n", + "| 1 | 1 | 1 |\n", + "| 2 | 10 | 2 |\n", + "| 3 | 11 | 2 |\n", + "| 4 | 100 | 3 |\n", + "| 5 | 101 | 3 |\n", + "| 6 | 110 | 3 |\n", + "| 7 | 111 | 3 |\n", + "| 8 | 1000 | 4 |\n", + "\n", + "We can easily extend this encoding to handle both positive and negative integers by appending a *sign bit* to the representations if we choose.\n", + "Sometimes it's also convenient to allow binary representations of nonnegative integers to have leading zeros, which don't change the value being encoded but can allow representations to fill up a string or word of a fixed size.\n", + "\n", + "Using binary notation to represent nonnegative integers is both common and efficient, but if we wanted to we could choose a different way to represent nonnegative integers using binary strings, such as the ones suggested in the following table.\n", + "The specifics of these alternatives are not important to this discussion — the point is only to clarify that we do have choices for the encodings we use.\n", + "(In this table, the symbol $\\varepsilon$ represents the *empty string*, which has no symbols in it and length equal to zero. Naturally, to avoid an obvious source of confusion, we use a special symbol such as $\\varepsilon$ to represent the empty string rather than literally writing nothing.)\n", + "\n", + "| number | unary encoding | lexicographic encoding |\n", + "| :-- | :-- | :-- | \n", + "| 0 | $\\varepsilon$ | $\\varepsilon$ |\n", + "| 1 | 0 | 0 |\n", + "| 2 | 00 | 1 |\n", + "| 3 | 000 | 00 |\n", + "| 4 | 0000 | 01 |\n", + "| 5 | 00000 | 10 |\n", + "| 6 | 000000 | 11 |\n", + "| 7 | 0000000 | 000 |\n", + "| 8 | 00000000 | 001 |\n", + "\n", + "Other types of inputs, such as vectors and matrices, or more complicated objects like descriptions of molecules, can also be encoded as binary strings.\n", + "Just like we have for nonnegative integers, a variety of different encoding schemes can be selected or invented.\n", + "For whatever scheme we come up with to encode inputs to a given problem, we interpret the *length* of an input string as representing the size of the problem instance being solved.\n", + "\n", + "For example, the number of bits required to express a nonnegative integer $N$ in binary notation, which is sometimes denoted $\\operatorname{lg}(N)$, is given by the following formula.\n", + "\n", + "$$\n", + "\\operatorname{lg}(N) = \n", + "\\begin{cases}\n", + "1 & N = 0\\\\\n", + "1 + \\lfloor \\log_2 (N) \\rfloor & N \\geq 1\n", + "\\end{cases}\n", + "$$\n", + "\n", + "Assuming that we use binary notation to encode the input to the integer factoring problem, the *input length* for the number $N$ is therefore $\\operatorname{lg}(N)$.\n", + "Note, in particular, that the length (or size) of the input $N$ is not $N$ itself — when $N$ is large we don't need nearly this many bits to express $N$ in binary notation.\n", + "\n", + "From a strictly formal viewpoint, whenever we consider a computational problem or task, it should be understood that a specific scheme has been selected for encoding whatever objects are given as input or produced as output.\n", + "This allows computations that solve interesting problems to be viewed abstractly as transformations from binary string inputs to binary string outputs — and naturally the details of how objects are encoded as binary strings must be important to computations at some level.\n", + "\n", + "Usually, though, we don't worry all that much about these details when we're analyzing computational cost, so that we can avoid getting into details of secondary importance.\n", + "The basic reasoning is that we expect the computational cost of converting back and forth between \"reasonable\" encoding schemes to be insignificant compared with the cost of solving the actual problem.\n", + "In those situation in which this is not the case, the details can (and should) be clarified.\n", + "\n", + "For example, a very simple computation with low cost converts between the binary representation of a nonnegative integer and its lexicographic encoding (which we have not explained in detail, but it can be inferred from the table). For this reason, the computational cost of integer factoring wouldn't differ significantly if we decided to switch from using one of these encodings to the other for the input $N$.\n", + "On the other hand, encoding nonnegative integers in unary notation incurs an exponential blow-up in the total number of symbols required, and we would not consider it to be a \"reasonable\" encoding scheme." + ] + }, + { + "cell_type": "markdown", + "id": "d2f61183", + "metadata": {}, + "source": [ + "### Elementary operations\n", + "\n", + "Now let's consider the computation itself, which is represented by the blue rectangle in the figure above.\n", + "The way that we'll measure computational cost is to count the number of *elementary operations* that each computation requires.\n", + "Intuitively speaking, an elementary operation is one involving a small, fixed number of bits or qubits that can be performed quickly and easily — such as computing the AND of two bits.\n", + "(In contrast, running the `factorint` function is not reasonably viewed as being an elementary operation.)\n", + "\n", + "Formally speaking, there are different choices for what constitutes an elementary operation depending on the computational model being used.\n", + "Our focus will be on circuit models, and specifically quantum and Boolean circuits.\n", + "\n", + "#### Universal gate sets\n", + "\n", + "For circuit-based models of computation, it is typical that each *gate* is viewed as an elementary operation.\n", + "This leads to the question of precisely which gates we allow.\n", + "\n", + "Focusing for the moment on quantum circuits, we've seen several gates thus far in the series, including $X$, $Y$, $Z$, $H$, $S$, and $T$ gates, *swap* gates, controlled versions of gates (including *controlled-NOT*, *Toffoli*, and *Fredkin* gates), as well as gates that represent standard basis measurements.\n", + "In the context of the CHSH game we also saw a few additional *rotation* gates.\n", + "\n", + "We also discussed *query gates* (within the query model), and saw that any unitary operation $U$, acting on any number of qubits, can be viewed as being a gate if we so choose.\n", + "We'll disregard both of these options for the sake of this discussion.\n", + "We won't be working in the query model (although the implementation of query gates using elementary operations is discussed later in the lesson), and viewing arbitrary unitary gates, potentially acting on millions of qubits, as being elementary operations does not lead to meaningful or realistic notions of computational cost.\n", + "\n", + "Sticking with quantum gates that operate on small numbers of qubits, one approach to deciding which ones are to be considered elementary is to tease out a precise criterion — but this is not the standard approach or the one we'll take.\n", + "Rather, we simply make a choice.\n", + "\n", + "Here's one standard choice, which we shall adopt as the *default* gate set for quantum circuits:\n", + "\n", + " - Single-qubit unitary gates from this list: $X$, $Y$, $Z$, $H$, $S$, $S^{\\dagger}$, $T$, and $T^{\\dagger}$\n", + " - Controlled-NOT gates\n", + " - Single-qubit standard basis measurements\n", + "\n", + "A common alternative is to view Toffoli, Hadamard, and $S$ gates as being elementary, in addition to standard basis measurements.\n", + "(Sometimes all single-qubit gates are viewed as being elementary, although this does lead to an unrealistically powerful model when noise and inaccuracies are not properly accounted for.)\n", + "\n", + "The unitary gates in our default collection form what's called a *universal* gate set.\n", + "This means that we can approximate any unitary operation, on any number of qubits, and to any degree of accuracy we wish, with circuits composed of these gates alone.\n", + "To be clear, the definition of universality places no requirements on the cost of such approximations, meaning the number of gates from our set that we need.\n", + "Indeed, a fairly simple argument based on the mathematical notion of *measure* reveals that most unitary operations must have extremely high cost.\n", + "Proving the universality of quantum gate sets is not a simple matter and won't be covered in this series.\n", + "\n", + "For Boolean circuits, we'll take AND, OR, NOT, and FANOUT gates to be the ones representing elementary operations.\n", + "We don't actually need both AND gates and OR gates — we can use *De Morgan's laws* to convert from either one to the other by placing NOT gates on all three input and output wires — but nevertheless it's both typical and convenient to allow both AND and OR gates.\n", + "AND, OR, NOT, and FANOUT gates form a universal set for deterministic computations, meaning that any function from any fixed number of input bits to any fixed number of output bits can be implemented with these gates.\n", + "\n", + "#### The principle of deferred measurement\n", + "\n", + "Standard measurement gates can appear within quantum circuits — but sometimes it's convenient to delay them until the end, so that we can view quantum computations as consisting of a unitary part (representing the computation itself), followed by a simple read-out phase where qubits are measured and the results are output.\n", + "\n", + "This can always be done, provided that we're willing to add an additional qubit for each standard basis measurement.\n", + "In the following figure, the circuit on the right illustrates how this can be done for the gate on the left.\n", + "\n", + "![Deferring measurements](images/deferred-measurement.png)\n", + "\n", + "Specifically, the classical bit in the circuit on the left is replaced by a qubit on the right (initialized to the $\\vert 0\\rangle$ state), and the standard basis measurement is replaced by a controlled-NOT gate, followed by a standard basis measurement on the bottom qubit.\n", + "The point is that the standard basis measurement in the right-hand circuit can be pushed all the way to the end of the circuit.\n", + "If the classical bit in the circuit on the left is later used as a control bit, we can use the bottom *qubit* in the circuit on the right as a control instead, and the overall effect will be the same.\n", + "(We are assuming that the classical bit in the circuit on the left doesn't get overwritten after the measurement takes place by another measurement — but if it did we could always just use a new classical bit rather than overwriting one that was used for a previous measurement.)" + ] + }, + { + "cell_type": "markdown", + "id": "78ea8a62", + "metadata": {}, + "source": [ + "### Circuit size and depth\n", + "\n", + "#### Circuit size\n", + "\n", + "The total number of gates in a circuit is referred to as that circuit's *size*.\n", + "Thus, presuming that the gates in our circuits represent elementary operations, we have that a circuit's size represents the number of elementary operations it requires — or, in other words, its *computational cost*.\n", + "We write $\\operatorname{size}(C)$ to refer to the size of a given circuit $C$.\n", + "\n", + "For example, consider the following Boolean circuit (from Lesson 3) for computing the XOR of two bits.\n", + "\n", + "![Boolean circuit for XOR](images/Boolean-circuit-XOR.png)\n", + "\n", + "The size of this circuit is 7, because there are 7 gates in total.\n", + "(Fanout operations are not always counted as being gates, but for the purposes of this lesson we will count FANOUT operations as being gates.)\n", + "\n", + "#### Time, cost, and circuit depth\n", + "\n", + "In the previous lesson we discussed the importance of *time* as a resource, or limiting constraint, on computations.\n", + "The examples above, such as the task of factoring RSA1024, reinforce this viewpoint.\n", + "The `factorint` function doesn't fail to factor RSA1024 per se, it's just that we don't have enough time to let it finish.\n", + "\n", + "The notion of computational cost, as the number of elementary operations required to perform a computation, is\n", + "intended to be an abstract proxy for the time required to implement a computation.\n", + "Each elementary operation requires a certain amount of time to perform, and the more of them a computation needs to perform the longer it's going to take, at least in general.\n", + "In the interest of simplicity, we'll continue to make this association between computational cost and the time required to run algorithms as we continue on in the series.\n", + "\n", + "But notice that the size of a circuit doesn't necessarily correspond directly to how long it takes to run.\n", + "In our Boolean circuit for computing the XOR of two bits, for instance, the two FANOUT gates could be performed simultaneously, as could the two NOT gates, as well as the two AND gates.\n", + "\n", + "A different way to measure efficiency for circuits, which takes this possibility of *parallelization* into account, is by their *depth*.\n", + "This is the minimum number of *layers* of gates needed within the circuit, where the gates within in each layer operate on different wires.\n", + "Equivalently, the depth of a circuit is the maximum number of gates encountered on any path from an input wire to an output wire.\n", + "For the circuit above, for instance, the depth is 4.\n", + "\n", + "Circuit depth is one way to formalize the running time of parallel computations.\n", + "It's an advanced topic, and there exist very sophisticated circuit constructions known to minimize the depth required for certain computations.\n", + "There are also some fascinating unanswered questions concerning circuit depth.\n", + "(For example, much remains unknown about the circuit depth required to compute GCDs.)\n", + "We won't have too much more to say about circuit depth in this series, aside from including a few interesting facts concerning circuit depth as we go along, but it should be clearly acknowledged that parallelization is a potential source of computational advantages.\n", + "\n", + "#### Assigning costs to different gates\n", + "\n", + "One final note concerning circuit size and computational cost is that it is possible to assign different costs to different gates, rather than viewing every gate as contributing equally to cost.\n", + "\n", + "For example, as was already mentioned, FANOUT gates are often viewed as being free for Boolean circuits — which is to say that we could choose that FANOUT gates have zero cost.\n", + "As another example, when we're working in the query model and we count the number of queries that a circuit makes to an input function (in the form of a black box), we're effectively assigning unit cost to query gates and zero cost to other gates, such as Hadamard gates.\n", + "A final example is that we sometimes weigh the costs of different gates depending on how difficult they are to implement, depending on the particular hardware implementation we have in mind.\n", + "\n", + "While all of these options are sensible in different contexts, for this lesson we'll keep things simple and stick with circuit size as a representation of computational cost." + ] + }, + { + "cell_type": "markdown", + "id": "2f0684fe", + "metadata": {}, + "source": [ + "### Cost as a function of input length\n", + "\n", + "We're primarily interested in how computational cost scales as inputs become larger and larger.\n", + "This leads us to represent the costs of algorithms as *functions* of the input length.\n", + "\n", + "#### Families of circuits\n", + "\n", + "Inputs to a given computational problem can vary in length, potentially becoming arbitrarily large.\n", + "Every circuit, on the other hand, has a fixed number of gates and wires.\n", + "For this reason, when we think about algorithms in terms of circuits, we generally need infinitely large *families* of circuits to represent algorithms.\n", + "By a family of circuits, we mean a sequence of circuits that grow in size, allowing larger and larger inputs to be accommodated.\n", + "\n", + "For example, imagine that we have a classical algorithm for integer factorization, such as the one used by `factorint`.\n", + "Like all classical algorithms, it is possible to implement this algorithm using Boolean circuits — but to do it we'll need a separate circuit for each possible input length.\n", + "If we looked at the resulting circuits for different input lengths, we would see that their sizes naturally grow as the input length grows — reflecting the fact that factoring 4-bit integers is much easier and requires far fewer elementary operations than factoring 1024-bit integers, for instance.\n", + "\n", + "This leads us to represent the computational cost of an algorithm by a function $t$, defined so that $t(n)$ is the number of gates in the circuit that implements the algorithm for $n$ bit inputs.\n", + "In more formal terms, an algorithm in the Boolean circuit model is described by a sequence of circuits\n", + "$\\{C_1, C_2, C_3,\\ldots\\}$, where $C_n$ solves whatever problem we're talking about for $n$-bit inputs (or, more generally, for inputs whose size is parameterized in some way by $n$), and the function $t$ representing the cost of this algorithm is defined as \n", + "\n", + "$$\n", + "t(n) = \\operatorname{size}(C_n).\n", + "$$\n", + "\n", + "For quantum circuits the situation is similar, where larger and larger circuits are needed to accommodate longer and longer input strings.\n", + "\n", + "#### Example: integer addition\n", + "\n", + "To explain this further, let's take a moment to consider a much simpler problem than integer factoring, or even computing GCDs, which is the problem of addition.\n", + "\n", + "\n", + "\n", + "**Integer addition**\n", + "\n", + "Input: integers $N$ and $M$\n", + "\n", + "Output: $N+M$\n", + "\n", + "\n", + "\n", + "How might we design Boolean circuits for solving this problem?\n", + "\n", + "Just to keep things simple, let's restrict our attention to the case where $N$ and $M$ are both nonnegative integers represented by $n$-bit registers using binary notation.\n", + "We'll allow for any number of leading zeros in these encodings, so that $0\\leq N,M\\leq 2^n - 1$.\n", + "The output will be an $(n+1)$-bit binary string representing the sum, which is the maximum number of bits we need to express the result.\n", + "\n", + "We begin with an algorithm — the *standard* algorithm for addition of binary representations — which is the base $2$ analogue to the way addition is taught in elementary/primary schools around the world.\n", + "This algorithm can be implemented with Boolean circuits as follows.\n", + "\n", + "Starting from the least significant bits, we can compute their XOR to determine the least significant bit for the sum.\n", + "Then we can compute the carry bit, which is the AND of the two least significant bits of $N$ and $M$.\n", + "Sometimes these two operations together are known as a *half adder*.\n", + "Using the XOR circuit we've now seen a few times together with an AND gate and two FANOUT gates, we can build a half adder with 10 gates.\n", + "If for some reason we changed our minds and decided to include XOR gates in our set of elementary operations, we would need 1 AND gate, 1 XOR gate, and 2 FANOUT gates to build a half adder.\n", + "\n", + "![A half-adder](images/half-adder.png)\n", + "\n", + "Moving on to the more significant bits we can use a similar procedure, but this time including the carry bit from each previous position into our calculation.\n", + "By cascading 2 half adders and taking the OR of the carry bits they produce, we can create what's known as a *full adder*.\n", + "(Fortunately both carry bits can't be $1$, so we don't need to worry about that case.)\n", + "This requires 21 gates in total: 2 AND gates, 2 XOR gates (each requiring 7 gates to implement), one OR gate, and 4 FANOUT gates.\n", + "\n", + "![A full-adder](images/full-adder.png)\n", + "\n", + "Finally, by cascading the full adders, we obtain a Boolean circuit for nonnegative integer addition having \n", + "$21 (n-1) + 10 = 21 n - 11$ gates.\n", + "Had we decided to include XOR gates in our set of elementary operations, we'd need \n", + "$2n-1$ AND gates, $2n-1$ XOR gates, $n-1$ OR gates, and $4n-2$ FANOUT gates, for a total of $9n-5$ gates.\n", + "If in addition we decide not to count FANOUT gates, it's $5n-3$ gates.\n", + "\n", + "For example, the following circuit computes the sum of two 4-bit integers.\n", + "\n", + "![A circuit for addition of two 4-bit integers](images/addition-circuit.png)\n", + "\n", + "\n", + "#### Asymptotic notation\n", + "\n", + "On the one hand, it is good to know precisely how many gates are needed to perform various computations, like in the example of integer addition above.\n", + "These details are important for actually building the circuits.\n", + "\n", + "On the other hand, if we perform analyses at this level of detail for all the computations we're interested in, including ones for tasks that are much more complicated than addition, we'll very quickly be buried in details.\n", + "To keep things manageable, and to intentionally suppress details of secondary importance, we typically use *Big-O* notation when analyzing algorithms.\n", + "Through this notation we can express the *order* at which functions grow.\n", + "\n", + "Formally speaking, if we have two functions $g(n)$ and $h(n)$, we write that $g(n) = O(h(n))$ if there exists a positive real number $c > 0$ and a positive integer $n_0$ such that\n", + "\n", + "$$\n", + "g(n) \\leq c\\cdot h(n)\n", + "$$\n", + "\n", + "for all $n \\geq n_0$.\n", + "Typically $h(n)$ is chosen to be as simple an expression as possible, so that the notation can be used to reveal the limiting behavior of a function in simple terms.\n", + "For example, $17 n^3 - 257 n^2 + 65537 = O(n^3)$.\n", + "\n", + "This notation can be extended to functions having multiple arguments in a fairly straightforward way.\n", + "For instance, if we have two functions $g(n,m)$ and $h(n,m)$ defined on positive integers $n$ and $m$, we write that $g(n,m) = O(h(n,m))$ if there exists a positive real number $c > 0$ and a positive integer $k_0$ such that\n", + "\n", + "$$\n", + "g(n,m) \\leq c\\cdot h(n,m)\n", + "$$\n", + "\n", + "whenever $n+m \\geq k_0$.\n", + "\n", + "Connecting this notation to the example of nonnegative integer addition, we conclude that there exists a family of\n", + "Boolean circuits $\\{C_1, C_2,\\ldots,\\}$, where $C_n$ adds two $n$-bit nonnegative integers together, such that\n", + "$\\operatorname{size}(C_n) = O(n)$.\n", + "This reveals the most essential feature of how the cost of addition scales with the input size: it scales *linearly*.\n", + "Notice also that it doesn't depend on the specific detail of whether we consider XOR gates to have unit cost or cost $7$.\n", + "In general, using Big-O notation allows us to make statements about computational costs that aren't sensitive to such low-level details." + ] + }, + { + "cell_type": "markdown", + "id": "22e69f48", + "metadata": {}, + "source": [ + "#### More examples\n", + "\n", + "Here are a few more examples of problems from computational number theory, beginning with *multiplication*.\n", + "\n", + "\n", + "\n", + "**Integer multiplication**\n", + "\n", + "Input: integers $N$ and $M$\n", + "\n", + "Output: $NM$\n", + "\n", + "\n", + "\n", + "Creating Boolean circuits for this problem is more difficult than creating circuits for addition — but by thinking about the standard multiplication algorithm, we can come up with circuits having size $O(n^2)$ for this problem (assuming $N$ and $M$ are both represented by $n$-bit binary representations).\n", + "More generally, if $N$ has $n$ bits and $M$ has $m$ bits, there are Boolean circuits of size $O(nm)$ for multiplying $N$ and $M$.\n", + "\n", + "There are, in fact, other ways to multiply that scale better.\n", + "For instance, the Schönhage-Strassen multiplication algorithm can be used to create a Boolean circuits for multiplying two $n$-bit integers having size $O(n \\operatorname{lg}(n) \\operatorname{lg}(\\operatorname{lg}(n)))$.\n", + "The intricacy of this method causes a lot of overhead, however, making it only practical for numbers having tens of thousands of bits.\n", + "\n", + "Another basic problem is *division*, which we interpret to mean computing both the quotient and remainder given an integer divisor and dividend.\n", + "\n", + "\n", + "\n", + "**Integer division**\n", + "\n", + "Input: integers $N$ and $M\\neq0$\n", + "\n", + "Output: integers $q$ and $r$ satisfying $0\\leq r < |M|$ and $N = q M + r$\n", + "\n", + "\n", + "\n", + "The cost of integer division is similar to multiplication: if $N$ has $n$ bits and $M$ has $m$ bits, there are Boolean circuits of size $O(nm)$ for solving this problem.\n", + "Like multiplication, there are asymptotically superior methods.\n", + "\n", + "We can now compare known algorithms for computing GCDs with those for addition and multiplication.\n", + "Euclid's algorithm for computing the GCD of an $n$-bit number $N$ and an $m$-bit number $M$ requires Boolean circuits of size $O(nm)$, similar to the standard algorithms for multiplication and division.\n", + "Also similar to multiplication and division, there are asymptotically faster GCD algorithms — including ones requiring $O(n(\\operatorname{lg}(n))^2 \\operatorname{lg}(\\operatorname{lg}(n)))$ elementary operations to compute the GCD of two $n$-bit numbers.\n", + "\n", + "A somewhat more expensive computation that arises in number theory is *modular exponentiation*.\n", + "\n", + "\n", + "\n", + "**Integer modular exponentiation**\n", + "\n", + "Input: integers $N$, $K$, and $M$ with $K\\geq 0$ and $M\\geq 1$\n", + "\n", + "Output: $N^K \\hspace{1mm} (\\text{mod }M)$\n", + "\n", + "\n", + "\n", + "By $N^K\\hspace{1mm} (\\text{mod }M)$ we mean the remainder when $N^K$ is divided by $M$ — meaning the unique integer $r$ satisfying $0\\leq r < M$ and $N^K = q M + r$ for some integer $q$.\n", + "\n", + "If $N$ has $n$ bits, $M$ has $m$ bits, and $K$ has $k$ bits, this problem can solved by Boolean circuits having size $O(k m^2 + nm)$ — which is not at all obvious at first glance.\n", + "The solution is not to first compute $N^K$ and then take the remainder — that would require exponentially many bits just to store the number $N^K$.\n", + "Rather, we can use the *power algorithm* (known alternatively as the *binary method* and *repeated squaring*), where we use the binary representation of $K$ to perform the entire computation modulo $M$.\n", + "Assuming $N$, $M$, and $K$ are all $n$-bit numbers, we obtain an $O(n^3)$ algorithm — or a *cubic* time algorithm.\n", + "(Once again, there are asymptotically faster algorithms.)\n", + "\n", + "Here's a code cell that computes a modular exponent for fairly large input numbers." + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "79c8b245", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "5420808908959774060288987536719770456217318912094898225713892936909049029205875268391016773496273016272919329382669533127141405381618319955871147811133071683113976741106560564348611362839209748910974112799894385464900617664468329271717655067495341858822704829649579551724483155264208314048742469387847020407987537873027379036515942355206425576104942394452390040081069041858525217985044712018028991394635458870225358476099232040714610377672598679720015462702833934580459151626243131178465271884695260294198503010478207039551370657556801980546328939683389782893101937977023160027020824612118350981172299997784862364914426784395705304625946981620876565903630321426713564601636615003526450559450988257054265576673783996389684225946503950767764911765912500478971120407712043832726706539999202935732936820400534970855338294653369081634048804115320256182211145544094816107629124112742249226319353536843143250675559791743355892993051078488285292927178023438402583054839832109503781471596500072959107707020065782555861325253891174468479828455070701800024212593144971400832140786063620665224339027746048978496589265602430286475229240500730395030244167373760773225724090156004049352594635867027935465962414764456373585290956999305794964617561548270565216080421238370652518997421499178722058617256564053290758153841574743341020230723665105568383923335524981262395314837292291351213579853233800664543959697570668968932545105391200894345122403901126855808339292892144618034647640594129638891809347433516954054255735374114229687467253661509404329081038467536976485314005457794642793240728907716748113582623047896927299525364803461784339899349011331842366119834985254767022797817541982842136038797346045524543446837609691961446346898034481960162369906547207851740703325595273724313509866798139791862738941412435088490790473992542655256187359052648995226579813780101763700632784177318998593960123977376065188642849714402071821332656099246595192273548124579308954369379166791375504366177963367167357734204250134523901012053728414505662083719483277149998297345600850207968594611610502058119754052458059616153460321784141539990056380808571117172677389938997159425776949065037133138197247161115127659585109470076784212846689843449874294528288829117435818727532583190741742686601090580534050289592016761135679603364904072305569448382741870366244397396582565453282641402195407023981530691751496898222633942198230270907098913253995651978611545066193950188718245653197837791596426329560941347753939650429611447245577078846931722372616367550006355620360276455568080512099035179175416756143233950934214736621950039902506644221443998435341460452476466171419972558395644689971465747907674896790822097660307109062931957694684033978412952567599593488687529011526359106169809555979667401866723277931201510177630302133847932158278990312682334549377652520626935835739547712983314320798573894229076437190704856364396327795151484278956526648597260084828697308427169704251546673832583609705456575281533722178029103192256765343504645112826902073960223407989624481672668703972408414665894403347181679160774217536153364422436840721557202572348021932511877708639899866042064925150997870115610130091923308716372491505600234638328560252998561255435872867079194898819838898311502430190295512215594677576275248220954675704199712880196887650126401810574270118295619216693001247689245264372564423355830421087279204264834276290790089692636984198176930764597788529620410821188522782016777910796700483449826" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "K = 64135289477071580278790190170577389084825014742943447208116859632024532344630238623598752668347708737661925585694639798853367\n", + "N = 4636759690183918349682239573236686632636353319755818421393667064929987310592347460711767784882455889983961546491666129915628431549982893638464243493812487979530329460863532041588297885958272943021122033997933550246447236884738870576045537199814804920281890355275625050796526864093092006894744790739778376848205654332434378295899591539239698896074\n", + "M = 5056714874804877864225164843977749374751021379176083540426461360945653967249306494545888621353613218518084414930846655066495767441010526886803458300440345782982127522212209489410315422285463057656809702949608368597012967321172325810519806487247195259818074918082416290513738155834341957254558278151385588990304622183174568167973121179585331770773\n", + "\n", + "pow(N,K**10+1,M**10 + 1)\n" + ] + }, + { + "cell_type": "markdown", + "id": "5a21c198", + "metadata": {}, + "source": [ + "It's a little bit slower than computing GCDs, but it's still fast." + ] + }, + { + "cell_type": "markdown", + "id": "8691fa99", + "metadata": {}, + "source": [ + "A different example, outside of the domain of computational number theory, arose in the previous lesson.\n", + "For the post-processing step of Simon's algorithm, we need to compute the null space modulo $2$ of an $n\\times m$ matrix of binary values (so here the input length is $nm$ bits in total).\n", + "We can do this using Gaussian elimination with $O(n m \\min\\{n,m\\})$ elementary operations, which is $O(n^3)$ elementary operations if $m=O(n)$.\n", + "Even for a $1000\\times 1000$ binary matrix, which is a million bits of input, the computation time is on the order of seconds." + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "75327a9d", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "OMP: Info #276: omp_set_nested routine deprecated, please use omp_set_max_active_levels instead.\n" + ] + }, + { + "data": { + "text/plain": [ + "GF([[1, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0,\n", + " 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0,\n", + " 1, 0, 1, 1, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1,\n", + " 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1,\n", + " 1, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1,\n", + " 0, 1, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 1, 1, 0, 0, 1, 0, 1, 0, 1, 1, 0,\n", + " 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1,\n", + " 0, 1, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1,\n", + " 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0,\n", + " 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 1,\n", + " 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1,\n", + " 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 1,\n", + " 1, 1, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0,\n", + " 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1,\n", + " 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1,\n", + " 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1,\n", + " 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 0,\n", + " 1, 0, 0, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1,\n", + " 1, 0, 1, 1, 1, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 1,\n", + " 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0,\n", + " 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0,\n", + " 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0,\n", + " 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0,\n", + " 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0,\n", + " 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1,\n", + " 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1,\n", + " 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0,\n", + " 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0,\n", + " 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1,\n", + " 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1, 1, 1,\n", + " 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 0, 1,\n", + " 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0,\n", + " 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0,\n", + " 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 0,\n", + " 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0,\n", + " 1, 0, 1, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1,\n", + " 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1,\n", + " 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0,\n", + " 1, 0, 0, 0, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 0,\n", + " 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1,\n", + " 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1,\n", + " 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0,\n", + " 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1,\n", + " 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0]], order=2)" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "import galois\n", + "GF = galois.GF(2)\n", + "\n", + "N, n = 1000, 1000\n", + "\n", + "A = GF.Random((N, n))\n", + "B = A.null_space()\n", + "display(B)" + ] + }, + { + "cell_type": "markdown", + "id": "3ab95746", + "metadata": {}, + "source": [ + "#### Cost of integer factorization\n", + "\n", + "In contrast to the algorithms just discussed, known algorithms for integer factorization are much more expensive — as we might expect from the examples in the first section of the lesson.\n", + "\n", + "If we consider a simple *trial division* algorithm that searches through the list $2,\\ldots,\\sqrt{N}$ for prime factors of an input number $N$, then we have $\\sqrt{N}$ iterations — which means $O(2^{n/2})$ iterations when $N$ is an $n$-bit number.\n", + "Each iteration requires a trial division, which means $O(n^2)$ elementary operations for each iteration (using a standard algorithm for integer division).\n", + "So we end up with circuits of size $O(n^2 2^{n/2})$, which is *exponential* in the input size $n$.\n", + "\n", + "There are algorithms for integer factorization having better scaling.\n", + "The number field sieve mentioned earlier, for instance, which is an algorithm that makes use of randomness, is generally believed (but not rigorously proven) to require\n", + "\n", + "$$\n", + "2^{O\\bigl(n^{1/3} \\operatorname{lg}^{2/3}(n)\\bigr)}\n", + "$$\n", + "\n", + "elementary operations to factor $n$-bit integers with high probability.\n", + "While it is quite significant that $n$ is raised to the power $1/3$, the fact that $n^{1/3}$ appears in the exponent is still a problem that causes poor scaling — and explains in part why RSA1024 remains outside of its domain of applicability." + ] + }, + { + "cell_type": "markdown", + "id": "38d29b7e", + "metadata": {}, + "source": [ + "#### Polynomial versus exponential cost\n", + "\n", + "As we have seen, classical algorithms for integer addition, multiplication, division, and computing greatest common divisors allow us to solve these problems in the blink of an eye for inputs with thousands of bits.\n", + "Addition has *linear* cost while the other three problems have *quadratic* cost (or *subquadratic* cost using asymptotically fast algorithms).\n", + "Modular exponentiation is more expensive but can still be done pretty efficiently, with *cubic* cost (or sub-cubic cost using asymptotically fast algorithms).\n", + "Computing the null space modulo $2$ of an $n\\times n$ binary matrix has cost $O(n^3)$ (bearing in mind that there are $n^2$ input bits for this problem).\n", + "\n", + "All of these algorithms are examples having *polynomial* cost, meaning that they have cost $O(n^c)$ for some choice of a fixed constant $c > 0$.\n", + "As a rough, first-order approximation, algorithms having polynomial cost are abstractly viewed as representing *efficient* algorithms.\n", + "\n", + "In contrast, known classical algorithms for integer factoring have *exponential* cost.\n", + "Sometimes the cost of the number field sieve is described as *sub-exponential*, but in complexity theory it is more typical to reserve this term for algorithms whose cost is\n", + "\n", + "$$\n", + "O\\left(2^{n^{\\varepsilon}}\\right)\n", + "$$\n", + "\n", + "for *every* $\\varepsilon > 0$.\n", + "\n", + "The so-called *NP-complete* problems are a class of problems not known to (and widely conjectured not to) have polynomial-cost algorithms.\n", + "A circuit-based formulation of the *exponential-time hypothesis* posits something even stronger, which is that no NP-complete problem can have a sub-exponential cost algorithm.\n", + "\n", + "The association of polynomial-cost algorithms with efficient algorithms must be understood as being a loose abstraction.\n", + "Of course, if an algorithm's cost scales as $n^{1000}$ or $n^{1000000}$ for inputs of size $n$, then it's a stretch to describe that algorithm as efficient.\n", + "\n", + "However, even an algorithm having cost that scales as $n^{1000000}$ must be doing something clever to avoid having *exponential* cost, which is generally what we expect of algorithms based in some way on \"brute force\" or \"exhaustive search.\"\n", + "Even the sophisticated refinements of the number field sieve, for instance, fail to avoid this exponential scaling in cost.\n", + "Polynomial-cost algorithms, on the other hand, manage take advantage of the problem structure in some way that avoids an exponential scaling.\n", + "\n", + "In practice, the identification of a polynomial cost algorithm for a problem is just a first step toward actual efficiency.\n", + "Through algorithmic refinements, polynomial-cost algorithms with large exponents can sometimes be improved dramatically, lowering the cost to a more \"reasonable\" polynomial scaling.\n", + "Sometimes things become easier when they're known to be possible — so the identification of a polynomial-cost algorithm for a problem can also have the effect of inspiring new, more efficient algorithms.\n", + "\n", + "As we consider advantages of quantum computing over classical computing, our eyes are generally turned first toward *exponential* advantages, or at least *super-polynomial* advantages — ideally finding polynomial-cost quantum algorithms for problems not known to have polynomial-cost classical algorithms.\n", + "Theoretical advantages on this order have the greatest chances to lead to actual practical advantages — but identifying such advantages is an extremely difficult challenge.\n", + "Only a few examples are currently known, but the search continues.\n", + "\n", + "Polynomial (but not super-polynomial) advantages in computational cost of quantum over classical are also interesting and should not be dismissed — but given the current gap between quantum and classical computing technology, they do seem rather less compelling at the present time.\n", + "One day, though, they could become significant.\n", + "Grover's algorithm, which is covered in Lesson 8, provides an example of a *quadratic* advantage of quantum over classical for so-called *unstructured searching*, which could potentially be broadly applicable." + ] + }, + { + "cell_type": "markdown", + "id": "740332ac", + "metadata": {}, + "source": [ + "#### A hidden cost of circuit computation\n", + "\n", + "There is one final issue that is worth mentioning, although we will not concern ourselves with it further in this series.\n", + "There's a \"hidden\" computational cost when we're working with circuits, and it concerns the specifications of the circuits themselves.\n", + "As inputs get longer, we need larger and larger circuits — but somehow we're going to need to get our hands on the descriptions of these circuits if we're going to implement them.\n", + "\n", + "For all of the examples we've discussed, or will discuss later in the series, there's some underlying algorithm from which the circuits are derived.\n", + "Usually the circuits in a family follow some basic pattern that's easy to extrapolate to larger and larger inputs\n", + "— such as cascading full adders to create Boolean circuits for addition or performing layers of Hadamard gates and other gates in some simple to describe pattern.\n", + "\n", + "But what happens if there are prohibitive computational costs associated with the patterns of the circuits themselves?\n", + "For instance, the description of each member $C_n$ in a circuit family could, in principle, be determined by some extremely difficult to compute function of $n$.\n", + "\n", + "The answer is that this is a problem, and we must place additional restrictions on families of circuits beyond having polynomial cost in order for them to truly represent efficient algorithms.\n", + "The property of *uniformity* for circuits does this by stipulating that it must (in various precise formulations) be computationally easy to obtain the description of each circuit in a family.\n", + "All of the circuit families we'll discuss do indeed have this property, so we won't concern ourselves with it further — but this is an important issue to be aware of when studying circuit models of computation from a formal viewpoint." + ] + }, + { + "cell_type": "markdown", + "id": "d15daf3e", + "metadata": {}, + "source": [ + "## Classical computations on quantum computers\n", + "\n", + "We'll now turn our attention to implementing classical algorithms on quantum computers.\n", + "We'll see that any computation that can be performed with a classical Boolean circuit can also be performed by a quantum circuit with asymptotically the same computational cost.\n", + "Moreover, this can be done in a \"clean\" manner, which is an important requirement for using these computations as subroutines inside of larger quantum computations.\n", + "\n", + "### Simulating Boolean circuits with quantum circuits\n", + "\n", + "Boolean circuits are composed of AND, OR, NOT, and FANOUT gates.\n", + "To simulate Boolean circuit with quantum circuit, we'll begin by showing how each of these four gates can be simulated by quantum gates.\n", + "Once that's done, converting a given Boolean circuit to a quantum circuit is a simple matter of simulating one gate at a time.\n", + "We'll only need NOT gates, controlled-NOT gates, and Toffoli gates to do this, which are all deterministic operations in addition to being unitary.\n", + "\n", + "#### Toffoli gates\n", + "\n", + "Toffoli gates can alternatively be described as controlled-controlled-NOT (or CCX) gates, whose action on standard basis states is as the following figure suggests.\n", + "\n", + "![Toffoli gate](images/Toffoli-gate.png)\n", + "\n", + "The matrix representation of this gate is as follows.\n", + "\n", + "$$\n", + "\\mathrm{CCX} =\n", + "\\begin{pmatrix}\n", + "1 & 0 & 0 & 0 & 0 & 0 & 0 & 0 \\\\\n", + "0 & 1 & 0 & 0 & 0 & 0 & 0 & 0 \\\\\n", + "0 & 0 & 1 & 0 & 0 & 0 & 0 & 0 \\\\\n", + "0 & 0 & 0 & 0 & 0 & 0 & 0 & 1 \\\\\n", + "0 & 0 & 0 & 0 & 1 & 0 & 0 & 0 \\\\\n", + "0 & 0 & 0 & 0 & 0 & 1 & 0 & 0 \\\\\n", + "0 & 0 & 0 & 0 & 0 & 0 & 1 & 0 \\\\\n", + "0 & 0 & 0 & 1 & 0 & 0 & 0 & 0 \n", + "\\end{pmatrix}\n", + "$$" + ] + }, + { + "cell_type": "markdown", + "id": "c32ef23e", + "metadata": {}, + "source": [ + "Another way to think about Toffoli gates is that they're essentially query gates for the AND function, in the sense that they follow exactly the same pattern we saw in the previous lesson for the unitary query gate implementation of arbitrary functions with binary string inputs and outputs.\n", + "\n", + "Toffoli gates are not included in the default gate set discussed earlier in the lesson, but it is possible to construct a Tofolli gate from $H$, $T$, $T^{\\dagger}$, and CNOT gates as the following Qiskit code cell illustrates." + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "9e36d499", + "metadata": {}, + "outputs": [ + { + "data": { + "image/svg+xml": [ + "" + ], + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/latex": [ + "$$\n", + "\n", + "\\begin{bmatrix}\n", + "1 & 0 & 0 & 0 & 0 & 0 & 0 & 0 \\\\\n", + " 0 & 1 & 0 & 0 & 0 & 0 & 0 & 0 \\\\\n", + " 0 & 0 & 1 & 0 & 0 & 0 & 0 & 0 \\\\\n", + " 0 & 0 & 0 & 0 & 0 & 0 & 0 & 1 \\\\\n", + " 0 & 0 & 0 & 0 & 1 & 0 & 0 & 0 \\\\\n", + " 0 & 0 & 0 & 0 & 0 & 1 & 0 & 0 \\\\\n", + " 0 & 0 & 0 & 0 & 0 & 0 & 1 & 0 \\\\\n", + " 0 & 0 & 0 & 1 & 0 & 0 & 0 & 0 \\\\\n", + " \\end{bmatrix}\n", + "$$" + ], + "text/plain": [ + "" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "from qiskit import QuantumCircuit\n", + "from qiskit.quantum_info import Statevector, Operator\n", + "from qiskit.visualization import array_to_latex\n", + "\n", + "Toffoli = QuantumCircuit(3)\n", + "\n", + "Toffoli.h(2)\n", + "Toffoli.cx(1, 2)\n", + "Toffoli.tdg(2)\n", + "Toffoli.cx(0, 2)\n", + "Toffoli.t(2)\n", + "Toffoli.cx(1, 2)\n", + "Toffoli.tdg(2)\n", + "Toffoli.cx(0, 2)\n", + "Toffoli.t(1)\n", + "Toffoli.t(2)\n", + "Toffoli.cx(0, 1)\n", + "Toffoli.t(0)\n", + "Toffoli.tdg(1)\n", + "Toffoli.h(2)\n", + "Toffoli.cx(0, 1)\n", + "\n", + "display(Toffoli.draw())\n", + "U = Operator(Toffoli)\n", + "\n", + "array_to_latex(U)" + ] + }, + { + "cell_type": "markdown", + "id": "66991522", + "metadata": {}, + "source": [ + "#### Simulating Boolean gates with Toffoli, controlled-NOT, and NOT gates\n", + "\n", + "A single Toffoli gate, used in conjunction with a few NOT gates, can implement an AND and OR gate, as the following diagrams suggest.\n", + "\n", + "![Simulating AND and OR gates with Toffoli gates](images/AND-and-OR-with-Toffoli.png)\n", + "\n", + "FANOUT gates can easily be implemented using controlled-NOT gates like this:\n", + "\n", + "![Simulating FANOUT gates with CNOT gates](images/FANOUT-with-CNOT.png)\n", + "\n", + "In all three cases, the bits that the AND, OR, and FANOUT gates act upon come in from the left as inputs, and in addition we require one *workspace* qubit initialized to the zero state.\n", + "These workspace qubits appear within the dotted rectangles to illustrate that they're new, and one of the costs\n", + "of implementing Boolean gates and circuits through the method being described is the inclusion of these new qubits.\n", + "\n", + "For the AND and OR gates, in addition to the output bits we also have two additional qubits left over.\n", + "For example, inside the dotted rectangle in the diagram for an AND gate, the top two qubits are left in the states $\\vert a\\rangle$ and $\\vert b\\rangle$.\n", + "These bits appear inside the dotted rectangles to illustrate that they're no longer needed — they aren't output by the Boolean logic gates we're simulating, and we can simply ignore them (for now at least).\n", + "\n", + "The remaining Boolean gate, the NOT gate, is also a gate in our default set of quantum gates, so we don't need to worry about simulating them in a special way." + ] + }, + { + "cell_type": "markdown", + "id": "50f183c2", + "metadata": {}, + "source": [ + "#### Gate-by-gate simulation of Boolean circuits\n", + "\n", + "Now suppose that we have an ordinary Boolean circuit named $C$, composed of AND, OR, NOT, and FANOUT gates, and having\n", + "$n$ input bits and $m$ of output bits.\n", + "We'll let $t$ be the total number of gates in $C$, and we'll give the name $f$ to the function that $C$ computes — so this function takes the form $f:\\Sigma^n\\rightarrow\\Sigma^m$ where $\\Sigma = \\{0,1\\}$.\n", + "\n", + "Now consider what happens when we go one at a time through the AND, OR, and FANOUT gates of $C$, replacing each one by the simulation described above, including the addition of a workspace qubit.\n", + "We'll arrange the qubits of $R$ so that the $n$ input bits of $C$ are on the top and the workspace qubits are on the bottom.\n", + "As a result of performing these substitutions, we obtain a new circuit $R$ that operates as this figure suggests:\n", + "\n", + "![Reversible circuit simulation](images/reversible-circuit-simulation.png)\n", + "\n", + "Here, $k$ is the number of workspace qubits that need to be added, and $g$ is a function of the form\n", + "$g:\\Sigma^n \\rightarrow \\Sigma^{n+k-m}$ that describes the states of the leftover qubits after $R$ is executed.\n", + "\n", + "In the figure, the qubits corresponding to the output $f(x)$ are on the top and the remaining, leftover qubits storing $g(x)$ are on the bottom.\n", + "We can force this to happen if we wish by rearranging the qubits using swap gates.\n", + "A swap gate can be implemented with three controlled-NOT gates like this:\n", + "\n", + "![Swapping with cNOT gates](images/swap.png)\n", + "\n", + "As we'll see in the next section, it isn't essential to rearrange the output qubits like this, but it's easy enough to do it if we choose.\n", + "\n", + "The function $g$ that describes the classical states of the leftover qubits is determined somehow by the circuit $C$, but we don't really need to worry all that much about it, because we really don't care specifically what state these qubits are in when the computation finishes.\n", + "The letter $g$ comes after $f$, so it is a reasonable name for this function on that account, but there's a better reason to pick the name $g;$ \n", + "it's short for *garbage* — or stuff left over from the simulation that's cluttering up these qubits." + ] + }, + { + "cell_type": "markdown", + "id": "ca1e5224", + "metadata": {}, + "source": [ + "### Cleaning up the garbage\n", + "\n", + "If our only interest is in computing whatever function $f$ is computed by a given Boolean circuit $C$ with a quantum circuit, we don't need to proceed any further than the gate-by-gate simulation just described — and we can accept that in addition to the answer we'll have a bunch of garbage left over.\n", + "\n", + "This, however, won't be good enough if we want to perform classical computations as subroutines within larger quantum computations, because those garbage qubits will cause problems.\n", + "As we saw in the previous lesson, the phenomenon of *interference* is critically important to quantum algorithms, and garbage qubits can ruin the interference patterns needed to make quantum algorithms work.\n", + "\n", + "Fortunately, it's not to difficult to clean up the garbage, so-to-speak.\n", + "The key is to use the fact that because $R$ is a quantum circuit, we can run it in reverse — by simply replacing each gate with its inverse and applying them in the reverse order — thereby obtaining a quantum circuit for the operation $R^{\\dagger}$.\n", + "(Toffoli gates, CNOT gates, and NOT gates are their own inverses, so in this case running $R$ in reverse is just a matter of applying the gates in the reverse order — but more generally any quantum circuit can be reversed as just described.)\n", + "\n", + "So, what we can do is to add $m$ more qubits (recalling that $m$ is the number of output bits of the function $f$), use CNOT gates to copy the output of $R$ onto these qubits, and then reverse $R$ to clean up the garbage.\n", + "The following figure illustrates the resulting circuit and describes its action on standard basis states.\n", + "\n", + "![Garbage-free computation](images/garbage-free-computation.png)\n", + "\n", + "If we put a box around the entire circuit and call it $Q$, it looks like this:\n", + "\n", + "![Simulation as a query gate](images/simulation-as-query-gate.png)\n", + "\n", + "If $C$ has $t$ gates, then $Q$ has $O(t)$ gates.\n", + "\n", + "If we disregard the $k$ additional workspace qubits, what we have is a circuit $Q$ that functions exactly like a query gate for the function $f$.\n", + "If we simply want to compute the function $f$ on some string $x$, we can set $y = 0^m$ and the resulting value $f(x)$ will appear on the bottom $m$ qubits — or we can feed in a different state to the bottom $m$ qubits if we wish\n", + "(perhaps to make use of a phase kickback, like in Deutsch's or the Deutsch-Jozsa algorithm).\n", + "This means that for any query algorithm, if we have a Boolean circuit that computes the input function, we can replace each query gate with a unitary implementation as just described and the query algorithm will function correctly.\n", + "\n", + "Note that the workspace qubits are needed to make this process work — but they are, in fact, returned to their initial states once the combined circuit is executed, so they could be used again as workspace qubits for other purposes.\n", + "There are strategies that reduce the number of workspace qubits required, but we won't discuss those strategies here." + ] + }, + { + "cell_type": "markdown", + "id": "9aca4d6f", + "metadata": {}, + "source": [ + "#### Implementing invertible functions\n", + "\n", + "The construction just described allows us to simulate any Boolean circuit with a quantum circuit in a garbage-free manner, following this basic pattern:\n", + "if $C$ is a Boolean circuit implementing a function $f:\\Sigma^n \\rightarrow \\Sigma^m$, then \n", + "we obtain a quantum circuit $Q$ that operates as the next equation describes on standard basis states.\n", + "\n", + "$$\n", + "Q \\bigl( \\vert y \\rangle \\vert 0^k \\rangle \\vert x\\rangle\\bigr)\n", + "= \\vert y \\oplus f(x) \\rangle \\vert 0^k \\rangle \\vert x\\rangle\n", + "$$\n", + "\n", + "The number $k$ indicates how many workspace qubits are required, and depends on how many gates $C$ has and which ones they are.\n", + "\n", + "This will be enough for the purposes of this series, but it is possible to take this one step further when the \n", + "function $f$ itself is invertible.\n", + "To be precise, suppose that the function $f$ takes the form $f:\\Sigma^n \\rightarrow \\Sigma^n$, and suppose furthermore there exists a function $f^{-1}$ such that $f^{-1}(f(x)) = x$ for every $x\\in\\Sigma^n$.\n", + "(The function $f^{-1}$ is necessarily unique when it exists.)\n", + "\n", + "This means that the operation that transforms $\\vert x \\rangle$ into $\\vert f(x) \\rangle$ for every $x\\in\\Sigma^n$ is unitary — so we might hope to build a quantum circuit that implements the unitary operation defined by\n", + "\n", + "$$\n", + "U \\vert x \\rangle = \\vert f(x) \\rangle\n", + "$$\n", + "\n", + "for every $x\\in\\Sigma^n$.\n", + "To be clear, the fact that this is a unitary operation relies on $f$ being invertible — it's not unitary when $f$ isn't invertible.\n", + "Disregarding the workspace qubits, $U$ is different from the operation that the circuit $Q$ implements because we're not keeping a copy of the input around and XORing it to an arbitrary string, we're *replacing* $x$ by $f(x)$.\n", + "\n", + "So the question is: when $f$ is invertible, can we do this?\n", + "The answer is yes — provided that in addition to having a Boolean circuit that computes $f$, we also have one that computes $f^{-1}$.\n", + "(So this won't be a shortcut to inverting functions computationally if we don't already know how to do that.)\n", + "The following diagram illustrates how it can be done by composing two quantum circuits, $Q_f$ and $Q_{f^{-1}}$, which are obtained individually for the functions $f$ and $f^{-1}$ through the method described above.\n", + "\n", + "![Simulation of an invertible function](images/fully-reversible-simulation.png)\n" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "id": "afe4325b", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "

Version Information

Qiskit SoftwareVersion
qiskit-terra0.24.1
qiskit-aer0.12.1
qiskit-ibmq-provider0.20.2
qiskit0.43.2
qiskit-nature0.6.0
qiskit-finance0.3.4
qiskit-optimization0.5.0
qiskit-machine-learning0.6.1
System information
Python version3.10.11
Python compilerClang 14.0.0 (clang-1400.0.29.202)
Python buildmain, Apr 7 2023 07:31:31
OSDarwin
CPUs8
Memory (Gb)32.0
Tue Jul 18 12:32:10 2023 BST
" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# pylint: disable=unused-import\n", + "import qiskit.tools.jupyter\n", + "%qiskit_version_table" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/notebooks/algorithms/02.algorithmic-foundations/images/AND-and-OR-with-Toffoli.png b/notebooks/algorithms/02.algorithmic-foundations/images/AND-and-OR-with-Toffoli.png new file mode 100644 index 0000000..5ebaa02 Binary files /dev/null and b/notebooks/algorithms/02.algorithmic-foundations/images/AND-and-OR-with-Toffoli.png differ diff --git a/notebooks/algorithms/02.algorithmic-foundations/images/Boolean-circuit-XOR.png b/notebooks/algorithms/02.algorithmic-foundations/images/Boolean-circuit-XOR.png new file mode 100644 index 0000000..90bf15d Binary files /dev/null and b/notebooks/algorithms/02.algorithmic-foundations/images/Boolean-circuit-XOR.png differ diff --git a/notebooks/algorithms/02.algorithmic-foundations/images/FANOUT-with-CNOT.png b/notebooks/algorithms/02.algorithmic-foundations/images/FANOUT-with-CNOT.png new file mode 100644 index 0000000..3e131c6 Binary files /dev/null and b/notebooks/algorithms/02.algorithmic-foundations/images/FANOUT-with-CNOT.png differ diff --git a/notebooks/algorithms/02.algorithmic-foundations/images/Toffoli-gate.png b/notebooks/algorithms/02.algorithmic-foundations/images/Toffoli-gate.png new file mode 100644 index 0000000..fb4cb1a Binary files /dev/null and b/notebooks/algorithms/02.algorithmic-foundations/images/Toffoli-gate.png differ diff --git a/notebooks/algorithms/02.algorithmic-foundations/images/addition-circuit.png b/notebooks/algorithms/02.algorithmic-foundations/images/addition-circuit.png new file mode 100644 index 0000000..bb80705 Binary files /dev/null and b/notebooks/algorithms/02.algorithmic-foundations/images/addition-circuit.png differ diff --git a/notebooks/algorithms/02.algorithmic-foundations/images/deferred-measurement.png b/notebooks/algorithms/02.algorithmic-foundations/images/deferred-measurement.png new file mode 100644 index 0000000..62f0d78 Binary files /dev/null and b/notebooks/algorithms/02.algorithmic-foundations/images/deferred-measurement.png differ diff --git a/notebooks/algorithms/02.algorithmic-foundations/images/full-adder.png b/notebooks/algorithms/02.algorithmic-foundations/images/full-adder.png new file mode 100644 index 0000000..483f214 Binary files /dev/null and b/notebooks/algorithms/02.algorithmic-foundations/images/full-adder.png differ diff --git a/notebooks/algorithms/02.algorithmic-foundations/images/fully-reversible-simulation.png b/notebooks/algorithms/02.algorithmic-foundations/images/fully-reversible-simulation.png new file mode 100644 index 0000000..b35cfcb Binary files /dev/null and b/notebooks/algorithms/02.algorithmic-foundations/images/fully-reversible-simulation.png differ diff --git a/notebooks/algorithms/02.algorithmic-foundations/images/garbage-free-computation.png b/notebooks/algorithms/02.algorithmic-foundations/images/garbage-free-computation.png new file mode 100644 index 0000000..870efd0 Binary files /dev/null and b/notebooks/algorithms/02.algorithmic-foundations/images/garbage-free-computation.png differ diff --git a/notebooks/algorithms/02.algorithmic-foundations/images/half-adder.png b/notebooks/algorithms/02.algorithmic-foundations/images/half-adder.png new file mode 100644 index 0000000..36b081d Binary files /dev/null and b/notebooks/algorithms/02.algorithmic-foundations/images/half-adder.png differ diff --git a/notebooks/algorithms/02.algorithmic-foundations/images/reversible-circuit-simulation.png b/notebooks/algorithms/02.algorithmic-foundations/images/reversible-circuit-simulation.png new file mode 100644 index 0000000..a50dabb Binary files /dev/null and b/notebooks/algorithms/02.algorithmic-foundations/images/reversible-circuit-simulation.png differ diff --git a/notebooks/algorithms/02.algorithmic-foundations/images/simulation-as-query-gate.png b/notebooks/algorithms/02.algorithmic-foundations/images/simulation-as-query-gate.png new file mode 100644 index 0000000..02aefbe Binary files /dev/null and b/notebooks/algorithms/02.algorithmic-foundations/images/simulation-as-query-gate.png differ diff --git a/notebooks/algorithms/02.algorithmic-foundations/images/standard-computation.png b/notebooks/algorithms/02.algorithmic-foundations/images/standard-computation.png new file mode 100644 index 0000000..559e16e Binary files /dev/null and b/notebooks/algorithms/02.algorithmic-foundations/images/standard-computation.png differ diff --git a/notebooks/algorithms/02.algorithmic-foundations/images/swap.png b/notebooks/algorithms/02.algorithmic-foundations/images/swap.png new file mode 100644 index 0000000..dea1f54 Binary files /dev/null and b/notebooks/algorithms/02.algorithmic-foundations/images/swap.png differ diff --git a/notebooks/algorithms/03.phase-estimation/images/QFT_32.png b/notebooks/algorithms/03.phase-estimation/images/QFT_32.png new file mode 100644 index 0000000..f590eec Binary files /dev/null and b/notebooks/algorithms/03.phase-estimation/images/QFT_32.png differ diff --git a/notebooks/algorithms/03.phase-estimation/images/arc-and-chord.png b/notebooks/algorithms/03.phase-estimation/images/arc-and-chord.png new file mode 100644 index 0000000..a0e4852 Binary files /dev/null and b/notebooks/algorithms/03.phase-estimation/images/arc-and-chord.png differ diff --git a/notebooks/algorithms/03.phase-estimation/images/controlled-phase-gates.png b/notebooks/algorithms/03.phase-estimation/images/controlled-phase-gates.png new file mode 100644 index 0000000..1ef482d Binary files /dev/null and b/notebooks/algorithms/03.phase-estimation/images/controlled-phase-gates.png differ diff --git a/notebooks/algorithms/03.phase-estimation/images/double-kickback-probabilities.png b/notebooks/algorithms/03.phase-estimation/images/double-kickback-probabilities.png new file mode 100644 index 0000000..353261d Binary files /dev/null and b/notebooks/algorithms/03.phase-estimation/images/double-kickback-probabilities.png differ diff --git a/notebooks/algorithms/03.phase-estimation/images/double-phase-kickback.png b/notebooks/algorithms/03.phase-estimation/images/double-phase-kickback.png new file mode 100644 index 0000000..017d9a7 Binary files /dev/null and b/notebooks/algorithms/03.phase-estimation/images/double-phase-kickback.png differ diff --git a/notebooks/algorithms/03.phase-estimation/images/estimate-phase-with-kickback-analysis.png b/notebooks/algorithms/03.phase-estimation/images/estimate-phase-with-kickback-analysis.png new file mode 100644 index 0000000..3bb58af Binary files /dev/null and b/notebooks/algorithms/03.phase-estimation/images/estimate-phase-with-kickback-analysis.png differ diff --git a/notebooks/algorithms/03.phase-estimation/images/estimate-phase-with-kickback.png b/notebooks/algorithms/03.phase-estimation/images/estimate-phase-with-kickback.png new file mode 100644 index 0000000..ece00e8 Binary files /dev/null and b/notebooks/algorithms/03.phase-estimation/images/estimate-phase-with-kickback.png differ diff --git a/notebooks/algorithms/03.phase-estimation/images/four-bit-probabilities.png b/notebooks/algorithms/03.phase-estimation/images/four-bit-probabilities.png new file mode 100644 index 0000000..0472cfc Binary files /dev/null and b/notebooks/algorithms/03.phase-estimation/images/four-bit-probabilities.png differ diff --git a/notebooks/algorithms/03.phase-estimation/images/kickback-probabilities.png b/notebooks/algorithms/03.phase-estimation/images/kickback-probabilities.png new file mode 100644 index 0000000..509da1d Binary files /dev/null and b/notebooks/algorithms/03.phase-estimation/images/kickback-probabilities.png differ diff --git a/notebooks/algorithms/03.phase-estimation/images/phase-estimation-procedure.png b/notebooks/algorithms/03.phase-estimation/images/phase-estimation-procedure.png new file mode 100644 index 0000000..59467fd Binary files /dev/null and b/notebooks/algorithms/03.phase-estimation/images/phase-estimation-procedure.png differ diff --git a/notebooks/algorithms/03.phase-estimation/images/phase-injection.png b/notebooks/algorithms/03.phase-estimation/images/phase-injection.png new file mode 100644 index 0000000..2081d72 Binary files /dev/null and b/notebooks/algorithms/03.phase-estimation/images/phase-injection.png differ diff --git a/notebooks/algorithms/03.phase-estimation/images/roots-of-unity.png b/notebooks/algorithms/03.phase-estimation/images/roots-of-unity.png new file mode 100644 index 0000000..0431e66 Binary files /dev/null and b/notebooks/algorithms/03.phase-estimation/images/roots-of-unity.png differ diff --git a/notebooks/algorithms/03.phase-estimation/images/three-bit-phase-estimation.png b/notebooks/algorithms/03.phase-estimation/images/three-bit-phase-estimation.png new file mode 100644 index 0000000..ce0b709 Binary files /dev/null and b/notebooks/algorithms/03.phase-estimation/images/three-bit-phase-estimation.png differ diff --git a/notebooks/algorithms/03.phase-estimation/images/three-bit-probabilities.png b/notebooks/algorithms/03.phase-estimation/images/three-bit-probabilities.png new file mode 100644 index 0000000..2019ecd Binary files /dev/null and b/notebooks/algorithms/03.phase-estimation/images/three-bit-probabilities.png differ diff --git a/notebooks/algorithms/03.phase-estimation/images/two-bit-phase-estimation-initial.png b/notebooks/algorithms/03.phase-estimation/images/two-bit-phase-estimation-initial.png new file mode 100644 index 0000000..8b23b51 Binary files /dev/null and b/notebooks/algorithms/03.phase-estimation/images/two-bit-phase-estimation-initial.png differ diff --git a/notebooks/algorithms/03.phase-estimation/images/two-bit-phase-estimation-states.png b/notebooks/algorithms/03.phase-estimation/images/two-bit-phase-estimation-states.png new file mode 100644 index 0000000..0f15fc4 Binary files /dev/null and b/notebooks/algorithms/03.phase-estimation/images/two-bit-phase-estimation-states.png differ diff --git a/notebooks/algorithms/03.phase-estimation/images/two-bit-phase-estimation.png b/notebooks/algorithms/03.phase-estimation/images/two-bit-phase-estimation.png new file mode 100644 index 0000000..3a1d4b7 Binary files /dev/null and b/notebooks/algorithms/03.phase-estimation/images/two-bit-phase-estimation.png differ diff --git a/notebooks/algorithms/03.phase-estimation/images/two-bit-probabilities.png b/notebooks/algorithms/03.phase-estimation/images/two-bit-probabilities.png new file mode 100644 index 0000000..bee60ce Binary files /dev/null and b/notebooks/algorithms/03.phase-estimation/images/two-bit-probabilities.png differ diff --git a/notebooks/algorithms/03.phase-estimation/images/uncontrolled-and-controlled-unitary.png b/notebooks/algorithms/03.phase-estimation/images/uncontrolled-and-controlled-unitary.png new file mode 100644 index 0000000..8ec4854 Binary files /dev/null and b/notebooks/algorithms/03.phase-estimation/images/uncontrolled-and-controlled-unitary.png differ diff --git a/notebooks/algorithms/03.phase-estimation/phase-estimation-and-factoring.ipynb b/notebooks/algorithms/03.phase-estimation/phase-estimation-and-factoring.ipynb new file mode 100644 index 0000000..873316d --- /dev/null +++ b/notebooks/algorithms/03.phase-estimation/phase-estimation-and-factoring.ipynb @@ -0,0 +1,2864 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "b1cea6ac", + "metadata": {}, + "source": [ + "# Phase estimation and factoring" + ] + }, + { + "cell_type": "markdown", + "id": "7dd56c6c", + "metadata": { + "gloss": { + "shor-algorithm-comment": { + "text": "In addition to his integer factorization algorithm, Peter Shor also discovered an efficient quantum algorithm for the different but related problem of computing discrete logarithms. The two algorithms appeared in the same paper, first published as a conference paper in 1994 and then as a journal paper in 1997.", + "title": "Shor's algorithm" + } + } + }, + "source": [ + "## Introduction\n", + "\n", + "In this lesson we'll discuss the phase estimation problem and a quantum algorithm to solve it.\n", + "We'll then apply the solution to obtain [Shor's algorithm](gloss:shor-algorithm-comment) — an efficient quantum algorithm for the integer factorization problem.\n", + "\n", + "Along the way, we'll encounter the quantum Fourier transform, and we'll see how it can be implemented efficiently by a quantum circuit." + ] + }, + { + "cell_type": "markdown", + "id": "bc37795e", + "metadata": {}, + "source": [ + "## Phase estimation problem\n", + "\n", + "This section explains the *phase estimation problem*.\n", + "We'll begin with a short discussion of the *spectral theorem* from linear algebra, and then move on to a statement of the phase estimation problem itself." + ] + }, + { + "cell_type": "markdown", + "id": "db278fe0", + "metadata": {}, + "source": [ + "### Spectral theorem\n", + "\n", + "The *spectral theorem* is an important fact in linear algebra that states that matrices of a certain type (called *normal matrices*) can be expressed in a simple and useful way.\n", + "We're only going to use this theorem for unitary matrices in this lesson, but later on we'll need it for Hermitian matrices as well.\n", + "\n", + "#### Normal matrices\n", + "\n", + "Suppose that $M$ is an $n\\times n$ matrix with complex number entries.\n", + "We say that $M$ is a *normal* matrix if it commutes with its conjugate transpose:\n", + "$M M^{\\dagger} = M^{\\dagger} M$.\n", + "\n", + "Every unitary matrix $U$ is normal because\n", + "\n", + "$$\n", + "U U^{\\dagger} = I = U^{\\dagger} U.\n", + "$$\n", + "\n", + "Hermitian matrices, which are matrices that equal their own conjugate transpose, are another important class of normal matrices.\n", + "If $H$ is a Hermitian matrix, then\n", + "\n", + "$$\n", + "H H^{\\dagger} = H^2 = H^{\\dagger} H,\n", + "$$ \n", + "\n", + "so $H$ is normal.\n", + "We'll see the spectral theorem being applied to Hermitian matrices later in the series.\n", + "\n", + "Not every square matrix is normal.\n", + "For instance, this matrix isn't normal:\n", + "\n", + "$$\n", + "\\begin{pmatrix}\n", + "0 & 1\\\\\n", + "0 & 0\n", + "\\end{pmatrix}\n", + "$$\n", + "\n", + "(This is a simple but great example of a matrix that's always good to keep in mind.)\n", + "This matrix isn't normal because\n", + "\n", + "$$\n", + "\\begin{pmatrix}\n", + "0 & 1\\\\\n", + "0 & 0\n", + "\\end{pmatrix}\n", + "\\begin{pmatrix}\n", + "0 & 1\\\\\n", + "0 & 0\n", + "\\end{pmatrix}^{\\dagger}\n", + "=\n", + "\\begin{pmatrix}\n", + "0 & 1\\\\\n", + "0 & 0\n", + "\\end{pmatrix}\n", + "\\begin{pmatrix}\n", + "0 & 0\\\\\n", + "1 & 0\n", + "\\end{pmatrix}\n", + "=\n", + "\\begin{pmatrix}\n", + "1 & 0\\\\\n", + "0 & 0\n", + "\\end{pmatrix}\n", + "$$\n", + "\n", + "while\n", + "\n", + "$$\n", + "\\begin{pmatrix}\n", + "0 & 1\\\\\n", + "0 & 0\n", + "\\end{pmatrix}^{\\dagger}\n", + "\\begin{pmatrix}\n", + "0 & 1\\\\\n", + "0 & 0\n", + "\\end{pmatrix}\n", + "=\n", + "\\begin{pmatrix}\n", + "0 & 0\\\\\n", + "1 & 0\n", + "\\end{pmatrix}\n", + "\\begin{pmatrix}\n", + "0 & 1\\\\\n", + "0 & 0\n", + "\\end{pmatrix}\n", + "=\n", + "\\begin{pmatrix}\n", + "0 & 0\\\\\n", + "0 & 1\n", + "\\end{pmatrix}.\n", + "$$\n", + "\n", + "#### Theorem statement\n", + "\n", + "Now here's a statement of the spectral theorem.\n", + "\n", + "\n", + "\n", + "**Theorem** (spectral theorem)\n", + "\n", + "Let $M$ be a *normal* $N\\times N$ complex matrix.\n", + "\n", + "There exists an orthonormal basis of $N$ dimensional complex vectors $\\bigl\\{ \\vert\\psi_1\\rangle,\\ldots,\\vert\\psi_N\\rangle \\bigr\\}$ along with complex numbers $\\lambda_1,\\ldots,\\lambda_N$ such that $M = \\lambda_1 \\vert \\psi_1\\rangle\\langle \\psi_1\\vert + \\cdots + \\lambda_N \\vert \\psi_N\\rangle\\langle \\psi_N\\vert$.\n", + "\n", + "\n", + "\n", + "The expression of a matrix in the form\n", + "\n", + "$$\n", + "M = \\sum_{k = 1}^N \\lambda_k \\vert \\psi_k\\rangle\\langle \\psi_k\\vert \\tag{1}\n", + "$$\n", + "\n", + "is commonly called a *spectral decomposition*.\n", + "Notice that if $M$ is a normal matrix expressed in the form $(1)$, then the equation\n", + "\n", + "$$ \n", + "M \\vert \\psi_j \\rangle = \\lambda_j \\vert \\psi_j \\rangle\n", + "$$\n", + "\n", + "must true for every $j = 1,\\ldots,N$.\n", + "This is a consequence of the fact that $\\bigl\\{ \\vert\\psi_1\\rangle,\\ldots,\\vert\\psi_N\\rangle \\bigr\\}$ is orthonormal:\n", + "\n", + "$$ \n", + "M \\vert \\psi_j \\rangle \n", + "= \\left(\\sum_{k = 1}^N \\lambda_k \\vert \\psi_k\\rangle\\langle \\psi_k\\vert\\right)\\vert \\psi_j\\rangle\n", + "= \\sum_{k = 1}^n \\lambda_k \\vert \\psi_k\\rangle\\langle \\psi_k\\vert\\psi_j \\rangle\n", + "= \\lambda_j \\vert\\psi_j \\rangle\n", + "$$\n", + "\n", + "That is to say, each number $\\lambda_j$ is an *eigenvalue* of $M$ and $\\vert\\psi_j\\rangle$ is an *eigenvector* corresponding to that eigenvalue." + ] + }, + { + "cell_type": "markdown", + "id": "92aaac48", + "metadata": {}, + "source": [ + " - **Example 1**.\n", + " Let\n", + " \n", + " $$\n", + " I = \\begin{pmatrix}1 & 0\\\\0 & 1\\end{pmatrix},\n", + " $$\n", + " \n", + " which is normal.\n", + " The theorem implies that $I$ can be written in the form $(1)$ for some choice \n", + " of $\\lambda_1$, $\\lambda_2$, $\\vert\\psi_1\\rangle$, and $\\vert\\psi_2\\rangle$ — and in particular \n", + " the equation is true for\n", + "\n", + " $$\n", + " \\lambda_1 = 1, \\hspace{5pt} \n", + " \\lambda_2 = 1, \\hspace{5pt} \n", + " \\vert\\psi_1\\rangle = \\vert 0\\rangle, \\hspace{5pt}\n", + " \\vert\\psi_2\\rangle = \\vert 1\\rangle.\n", + " $$\n", + " \n", + " (Notice that the theorem does not say that the complex numbers $\\lambda_1,\\ldots,\\lambda_n$ are \n", + " distinct — we can have the same complex number repeated.)\n", + " \n", + " These choices work because\n", + " $$\n", + " I = \\vert 0\\rangle\\langle 0\\vert + \\vert 1\\rangle\\langle 1\\vert.\n", + " $$\n", + " \n", + " Indeed, we could choose $\\{\\vert\\psi_1\\rangle,\\vert\\psi_2\\rangle\\}$ to be *any* orthonormal basis and the \n", + " equation will be true. For instance,\n", + " \n", + " $$\n", + " I = \\vert +\\rangle\\langle +\\vert + \\vert -\\rangle\\langle -\\vert.\n", + " $$\n", + "\n", + " - **Example 2**. Consider a Hadamard operation.\n", + "\n", + " $$\n", + " H = \\frac{1}{\\sqrt{2}}\n", + " \\begin{pmatrix}\n", + " 1 & 1\\\\[1mm] \n", + " 1 & -1\n", + " \\end{pmatrix}\n", + " $$\n", + " \n", + " This is a unitary matrix, so it is normal. The spectral theorem implies that $H$ can be written in the \n", + " form $(1)$, and in particular we have\n", + "\n", + " $$\n", + " H = \n", + " \\vert\\psi_{\\pi/8}\\rangle \\langle \\psi_{\\pi/8}\\vert \n", + " - \\vert\\psi_{5\\pi/8}\\rangle \\langle \\psi_{5\\pi/8}\\vert\n", + " $$\n", + " \n", + " where\n", + " \n", + " $$\n", + " \\vert\\psi_{\\theta}\\rangle \n", + " = \\cos(\\theta)\\vert 0\\rangle + \\sin(\\theta) \\vert 1\\rangle.\n", + " $$\n", + "\n", + " More explicitly,\n", + " \n", + " $$\n", + " \\begin{aligned}\n", + " \\vert\\psi_{\\pi/8}\\rangle & = \\frac{\\sqrt{2 + \\sqrt{2}}}{2}\\vert 0\\rangle \n", + " + \\frac{\\sqrt{2 - \\sqrt{2}}}{2}\\vert 1\\rangle \\\\[3mm]\n", + " \\vert\\psi_{5\\pi/8}\\rangle & = -\\frac{\\sqrt{2 - \\sqrt{2}}}{2}\\vert 0\\rangle \n", + " + \\frac{\\sqrt{2 + \\sqrt{2}}}{2}\\vert 1\\rangle.\n", + " \\end{aligned}\n", + " $$\n", + "\n", + " We can check that this decomposition is correct by performing the required calculations:\n", + " \n", + " $$\n", + " \\vert\\psi_{\\pi/8}\\rangle \\langle \\psi_{\\pi/8}\\vert \n", + " - \\vert\\psi_{5\\pi/8}\\rangle \\langle \\psi_{5\\pi/8}\\vert\n", + " = \\begin{pmatrix}\n", + " \\frac{2 + \\sqrt{2}}{4} & \\frac{\\sqrt{2}}{4}\\\\[2mm]\n", + " \\frac{\\sqrt{2}}{4} & \\frac{2 - \\sqrt{2}}{4}\n", + " \\end{pmatrix}\n", + " -\n", + " \\begin{pmatrix}\n", + " \\frac{2 - \\sqrt{2}}{4} & -\\frac{\\sqrt{2}}{4}\\\\[2mm]\n", + " -\\frac{\\sqrt{2}}{4} & \\frac{2 + \\sqrt{2}}{4}\n", + " \\end{pmatrix}\n", + " = H.\n", + " $$\n", + " \n", + " We can also use Qiskit to check that this decomposition is correct, as the following code cell demonstrates." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "69b7665f", + "metadata": {}, + "outputs": [ + { + "data": { + "text/latex": [ + "$$\n", + "\n", + "\\begin{bmatrix}\n", + "\\frac{\\sqrt{2}}{2} & \\frac{\\sqrt{2}}{2} \\\\\n", + " \\frac{\\sqrt{2}}{2} & - \\frac{\\sqrt{2}}{2} \\\\\n", + " \\end{bmatrix}\n", + "$$" + ], + "text/plain": [ + "" + ] + }, + "execution_count": 1, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "from qiskit.visualization import array_to_latex\n", + "from qiskit.quantum_info import Statevector\n", + "from qiskit.quantum_info.operators import Operator\n", + "import math\n", + "\n", + "psi1 = Statevector([math.cos(math.pi/8),math.sin(math.pi/8)])\n", + "psi2 = Statevector([math.cos(5*math.pi/8),math.sin(5*math.pi/8)])\n", + "\n", + "# When given a Statevector input, the Operator function returns the outer\n", + "# product of that state vector with itself — or, in other words, the\n", + "# product of the vector times its conjugate transpose.\n", + "\n", + "H = Operator(psi1) - Operator(psi2)\n", + "array_to_latex(H)" + ] + }, + { + "cell_type": "markdown", + "id": "d37cf02d", + "metadata": {}, + "source": [ + "As the first example reveals, there can be some freedom in how eigenvectors are selected.\n", + "There is, however, no freedom at all in how the eigenvalues are chosen (except for their ordering).\n", + "For any given matrix $M$, the same $n$ complex numbers $\\lambda_1,\\ldots,\\lambda_N$ (which can include repetitions of the same complex number) will always occur in the equation $(1)$.\n", + "\n", + "Now let's focus in on unitary matrices.\n", + "Using the same terminology that was just mentioned, if we have a complex number $\\lambda$ and a non-zero vector $\\vert\\psi\\rangle$ that satisfy the equation\n", + "\n", + "$$\n", + "U\\vert\\psi\\rangle = \\lambda\\vert\\psi\\rangle,\n", + "\\tag{2}\n", + "$$\n", + "\n", + "then we say that $\\lambda$ is an *eigenvalue* of $U$ and $\\vert\\psi\\rangle$ is an *eigenvector* corresponding to the eigenvalue $\\lambda$.\n", + "\n", + "Unitary matrices preserve Euclidean norm.\n", + "So, if the equation $(2)$ is true, then because $U$ is unitary we conclude\n", + "\n", + "$$\n", + "\\bigl\\| \\vert\\psi\\rangle \\bigr\\|\n", + "= \\bigl\\| U \\vert\\psi\\rangle \\bigr\\|\n", + "= \\bigl\\| \\lambda \\vert\\psi\\rangle \\bigr\\|\n", + "= \\vert \\lambda \\vert \\bigl\\| \\vert\\psi\\rangle \\bigr\\|.\n", + "$$\n", + "\n", + "The condition that $\\vert\\psi\\rangle$ is non-zero implies that $\\bigl\\| \\vert\\psi\\rangle \\bigr\\|\\not=0$, so we can cancel it from both sides to obtain\n", + "\n", + "$$\n", + "\\vert \\lambda \\vert = 1.\n", + "$$\n", + "\n", + "So, eigenvalues of unitary matrices must always have absolute value equal to one.\n", + "That is to say, they lie on the *unit circle* \n", + "\n", + "$$\n", + "\\mathbb{T} = \\{\\alpha\\in\\mathbb{C} : \\vert\\alpha\\vert = 1\\}.\n", + "$$\n", + "\n", + "The symbol $\\mathbb{T}$ is a common name for the complex unit circle.\n", + "The name is $S^1$ is also common." + ] + }, + { + "cell_type": "markdown", + "id": "33b0a480", + "metadata": {}, + "source": [ + "### Problem statement\n", + "\n", + "In the *phase estimation problem*, we're given a quantum state $\\vert \\psi\\rangle$ of $n$ qubits, along with a unitary quantum circuit that acts on $n$ qubits.\n", + "We're *promised* that $\\vert \\psi\\rangle$ is an eigenvector of the unitary matrix $U$ that describes the action of the circuit, and our goal is to either identify or approximate the eigenvalue $\\lambda$ to which $\\vert \\psi\\rangle$ corresponds.\n", + "\n", + "More precisely, because $\\lambda$ lies on the complex unit circle we can write\n", + "\n", + "$$\n", + "\\lambda = e^{2\\pi i \\theta}\n", + "$$\n", + "\n", + "for a unique real number $\\theta$ satisfying $0\\leq\\theta<1$.\n", + "The goal of the problem is to compute or approximate this real number $\\theta$.\n", + "\n", + "\n", + "\n", + "**Phase estimation problem**\n", + "\n", + "Input: An $n$ qubit quantum state $\\vert\\psi\\rangle$ and a unitary quantum circuit for an $n$-qubit operation $U$\n", + "\n", + "Promise: $\\vert\\psi\\rangle$ is an eigenvector of $U$\n", + "\n", + "Output: an approximation to the number $\\theta\\in[0,1)$ satisfying $U\\vert\\psi\\rangle = e^{2\\pi i \\theta}\\vert\\psi\\rangle$\n", + "\n", + "\n", + "\n", + "\n", + "#### Remarks\n", + "\n", + "1. The phase estimation problem is different from other problems we've seen so far in the series in that the input includes a quantum state. Typically we're focused on problems having classical inputs and outputs, but nothing prevents us from considering quantum state inputs like this. In terms of its practical relevance, the phase estimation problem tends to appear as a *subproblem* inside of larger computations. We'll see this happening in the context of integer factorization later in the lesson.\n", + "\n", + "2. The statement of the phase estimation problem above isn't specific about what constitutes an approximation of $\\theta$, but we can formulate more precise problem statements depending on our needs and interests. In the context of integer factorization we'll demand a very precise approximation to $\\theta$, but in other cases we might be satisfied with a very rough approximation. We'll discuss shortly how the precision we require affects the computational cost of a solution.\n", + "\n", + "3. Notice that as we go from $\\theta = 0$ toward $\\theta = 1$ in the phase estimation problem, we're going all the way around the unit circle, starting from $e^{2\\pi i \\cdot 0} = 1$ and moving counter-clockwise — and as we get closer to $\\theta = 1$ we're moving toward $e^{2\\pi i \\cdot 1} = 1$, which is back where we started at $\\theta = 0$. So, as we consider the accuracy of approximations, choices of $\\theta$ near $1$ should be considered as being near $0$. For example, an approximation $\\theta = 0.999$ should be considered as being within $1/1000$ of $\\theta = 0$." + ] + }, + { + "cell_type": "markdown", + "id": "20118913", + "metadata": {}, + "source": [ + "## Phase estimation procedure\n", + "\n", + "Next we'll discuss the *phase-estimation procedure*, which is a quantum algorithm for solving the phase estimation problem.\n", + "We'll begin with a low-precision warm-up, which explains some of the basic intuition behind the method.\n", + "We'll then talk about the *quantum Fourier transform*, which is an important quantum operation used in the phase-estimation procedure, as well as its quantum circuit implementation.\n", + "And finally, we'll describe the phase-estimation procedure in general and analyze its performance." + ] + }, + { + "cell_type": "markdown", + "id": "014a6154", + "metadata": {}, + "source": [ + "### Warm-up: approximating phases with low precision\n", + "\n", + "We'll begin with a warm-up: a couple of simple versions of the phase-estimation procedure that provide low-precision solutions to the phase-estimation problem.\n", + "This is helpful for explaining the intuition behind the general procedure that we'll see a bit later in the lesson." + ] + }, + { + "cell_type": "markdown", + "id": "3a25f7b4", + "metadata": {}, + "source": [ + "#### Using the phase kickback\n", + "\n", + "A simple approach to the phase-estimation problem, which allows us to learn something about the value $\\theta$ we seek, is based on the *phase kick-back* phenomenon.\n", + "As we will see, this is essentially a single-qubit version of the general phase-estimation procedure to be discussed later in the lesson.\n", + "\n", + "As part of the input to the phase estimation problem, we have a unitary quantum circuit for the operation $U$.\n", + "We can use the description of this circuit to create a circuit for a *controlled*-$U$ operation, which can be depicted as this figure suggests (with the operation $U$, viewed as a quantum gate, on the left and a controlled-$U$ operation on the right).\n", + "\n", + "![Uncontrolled and controlled versions of a unitary operation](images/uncontrolled-and-controlled-unitary.png)\n", + "\n", + "We can create a quantum circuit for a controlled-$U$ operation by first adding a control qubit to the circuit for $U$, and then replacing every gate in the circuit for $U$ with a controlled version of that gate — so our one new control qubit effectively controls every single gate in the circuit for $U$.\n", + "This requires that we have a controlled version of every gate in our circuit, but if we want to restrict ourselves to a standard gate set, we can always build circuits for these controlled operations rather than insisting that they're single gates.\n", + "\n", + "Now let's consider the following circuit, where the input state $\\vert\\psi\\rangle$ of all the qubits except the top one is the quantum state eigenvector of $U:$\n", + "\n", + "![A single-qubit circuit for phase-estimation](images/estimate-phase-with-kickback.png)\n", + "\n", + "The eigenvalue of $U$ corresponding to the eigenvector $\\vert\\psi\\rangle$ determines the measurement outcome probabilities.\n", + "To see exactly how, let's analyze the circuit.\n", + "\n", + "![States of a single-qubit circuit for phase-estimation](images/estimate-phase-with-kickback-analysis.png)\n", + "\n", + "The initial state of the circuit is\n", + "\n", + "$$\n", + "\\vert\\pi_0\\rangle = \\vert\\psi\\rangle \\vert 0\\rangle\n", + "$$\n", + "\n", + "and the first Hadamard gate transforms this state to\n", + "\n", + "$$\n", + "\\vert\\pi_1\\rangle = \\vert\\psi\\rangle \\vert +\\rangle \n", + "= \\frac{1}{\\sqrt{2}} \\vert\\psi\\rangle \\vert 0\\rangle + \\frac{1}{\\sqrt{2}} \\vert\\psi\\rangle \\vert 1\\rangle.\n", + "$$\n", + "\n", + "Next, the controlled-$U$ operation is performed, which results in the state\n", + "\n", + "$$\n", + "\\vert\\pi_2\\rangle \n", + "= \\frac{1}{\\sqrt{2}} \\vert\\psi\\rangle \\vert 0\\rangle + \\frac{1}{\\sqrt{2}} \\bigl(U \\vert\\psi\\rangle\\bigr) \\vert 1\\rangle.\n", + "$$\n", + "\n", + "Using the assumption that $\\vert\\psi\\rangle$ is an eigenvector of $U$ having eigenvalue $\\lambda = e^{2\\pi i\\theta}$,\n", + "we can alternatively express this state as follows.\n", + "\n", + "$$\n", + "\\vert\\pi_2\\rangle\n", + "= \\frac{1}{\\sqrt{2}} \\vert\\psi\\rangle \\vert 0\\rangle + \\frac{e^{2\\pi i \\theta}}{\\sqrt{2}} \\vert\\psi\\rangle \\vert 1\\rangle = \\vert\\psi\\rangle \\otimes \\left( \\frac{1}{\\sqrt{2}} \\vert 0\\rangle + \\frac{e^{2\\pi i \\theta}}{\\sqrt{2}} \\vert 1\\rangle\\right)\n", + "$$\n", + "\n", + "Here we see the phase kickback phenomenon taking place.\n", + "It is slightly different this time than it was for Deutsch's algorithm and the Deutsch-Jozsa algorithm because we're not working with a query gate — but the idea is the similar.\n", + "\n", + "Finally, the second Hadamard gate is performed, which results in the state\n", + "\n", + "$$\n", + "\\vert\\pi_3\\rangle\n", + "= \\vert\\psi\\rangle \\otimes \\left( \\frac{1+ e^{2\\pi i \\theta}}{2} \\vert 0\\rangle + \\frac{1 - e^{2\\pi i \\theta}}{2} \\vert 1\\rangle\\right).\n", + "$$\n", + "\n", + "The measurement therefore yields the outcomes $0$ and $1$ with these probabilities:\n", + "\n", + "$$\n", + "\\begin{aligned}\n", + "p_0 &= \\left\\vert \\frac{1+ e^{2\\pi i \\theta}}{2} \\right\\vert^2 = \\cos^2(\\pi\\theta)\\\\[1mm]\n", + "p_1 &= \\left\\vert \\frac{1- e^{2\\pi i \\theta}}{2} \\right\\vert^2 = \\sin^2(\\pi\\theta).\n", + "\\end{aligned}\n", + "$$" + ] + }, + { + "cell_type": "markdown", + "id": "1f287001", + "metadata": {}, + "source": [ + "Here's a table that lists the probabilities for the two possible measurement outcomes for various choices of the number $\\theta$.\n", + "\n", + "| $\\theta$ | $\\cos^2(\\pi\\theta)$ | $\\sin^2(\\pi\\theta)$ |\n", + "| :--: | :--: | :--: |\n", + "| 0.0000 | 1.0000 | 0.0000 |\n", + "| 0.1250 | 0.8536 | 0.1464 |\n", + "| 0.2500 | 0.5000 | 0.5000 |\n", + "| 0.3750 | 0.1464 | 0.8536 |\n", + "| 0.5000 | 0.0000 | 1.0000 |\n", + "| 0.6250 | 0.1464 | 0.8536 |\n", + "| 0.7500 | 0.5000 | 0.5000 |\n", + "| 0.8750 | 0.8536 | 0.1464 |\n", + "\n", + "We can also plot the probabilities for the two possible outcomes, $0$ and $1$, as follows:\n", + "\n", + "![Outcome probabilities from phase kickback](images/kickback-probabilities.png)\n", + "\n", + "Naturally, the two probabilities always sum to $1$.\n", + "Notice that when $\\theta = 0$, the measurement outcome is always $0$, and when $\\theta = 1/2$, the measurement outcome is always $1$.\n", + "So, although the measurement result doesn't reveal exactly what $\\theta$ is, it does provide us with some information about it — and if we were promised that either $\\theta = 0$ or $\\theta = 1/2$, we could learn from the circuit which one is correct without error." + ] + }, + { + "cell_type": "markdown", + "id": "103ae33e", + "metadata": { + "gloss": { + "binary-point": { + "text": "The binary point is analogous to the decimal point when we express numbers with a fractional part in ordinary, decimal notation.", + "title": "Binary point" + } + } + }, + "source": [ + "Intuitively speaking, we can think of the circuit's measurement outcome as being a guess for $\\theta$ to \"one bit of accuracy.\"\n", + "In other words, if we were to write $\\theta$ in *binary notation* and round it off to one bit after the [binary point](gloss:binary-point), we'd have a number like this:\n", + "\n", + "$$\n", + "0.a = \\begin{cases}\n", + "0 & a = 0\\\\\n", + "\\frac{1}{2} & a = 1.\n", + "\\end{cases}\n", + "$$\n", + "\n", + "The measurement outcome can be viewed as a guess for the bit $a$.\n", + "When $\\theta$ is neither $0$ nor $1/2$, there's a nonzero probability that the guess will be wrong — but the \n", + "probability of making an error becomes smaller and smaller as we get closer to $0$ or $1/2$.\n", + "\n", + "It's natural to ask what role the two Hadamard gates play in this procedure:\n", + "\n", + " - The first Hadamard gate sets the control qubit to a uniform superposition of $\\vert 0\\rangle$ and $\\vert 1\\rangle$, so that when the phase kickback occurs, it happens for the $\\vert 1\\rangle$ state and not the $\\vert 0\\rangle$ state, creating a *relative* phase difference that affects the measurement outcomes. If we didn't do this and the phase kickback produced a *global* phase, it would have no effect on the probabilities of obtaining different measurement outcomes.\n", + "\n", + " - The second Hadamard gate allows us to learn something about the number $\\theta$ through the phenomenon of *interference*. Prior to the second Hadamard gate, the state of the top qubit is\n", + "\n", + " $$\n", + " \\frac{1}{\\sqrt{2}} \\vert 0\\rangle + \\frac{e^{2\\pi i \\theta}}{\\sqrt{2}} \\vert 1\\rangle,\n", + " $$\n", + "\n", + " and if we were to measure this state, we would obtain $0$ and $1$ each with probability $1/2$ — which tells us nothing at all about $\\theta$. Performing the second Hadamard gate allows the number $\\theta$ to affect the output probabilities." + ] + }, + { + "cell_type": "markdown", + "id": "4eae75c7", + "metadata": {}, + "source": [ + "#### Qiskit implementation\n", + "\n", + "Here's an implementation of this circuit in Qiskit.\n", + "(For this implementation we're using a phase gate for the unitary operation, just in the interest of simplicity, so the relevant eigenvector is the $\\vert 1\\rangle$ state.)" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "5d1a710b", + "metadata": {}, + "outputs": [ + { + "data": { + "image/svg+xml": [ + "" + ], + "text/plain": [ + "
" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "from math import pi, cos, sin\n", + "from qiskit import QuantumCircuit\n", + "\n", + "theta = 0.7 # Can be changed to any value between 0 and 1\n", + "\n", + "qc = QuantumCircuit(2, 1)\n", + "\n", + "# Prepare eigenvector, which is the |1> state\n", + "\n", + "qc.x(1)\n", + "qc.barrier()\n", + "\n", + "# Implement the estimation procedure\n", + "qc.h(0)\n", + "qc.cp(2*pi*theta, 0, 1)\n", + "qc.h(0)\n", + "qc.barrier()\n", + "\n", + "# Perform the final measurement\n", + "qc.measure(0, 0)\n", + "\n", + "# Draw the circuit\n", + "qc.draw()" + ] + }, + { + "cell_type": "markdown", + "id": "fbb2e85d", + "metadata": {}, + "source": [ + "Now we'll run the circuit using the `Sampler` primitive." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "50c7117b", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "SamplerResult(quasi_dists=[{0: 0.3454915028125262, 1: 0.6545084971874736}], metadata=[{}])" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "from qiskit.primitives import Sampler\n", + "Sampler().run(qc).result()" + ] + }, + { + "cell_type": "markdown", + "id": "89543d57", + "metadata": {}, + "source": [ + "We can now compare the results to the predicted values to see that they're correct." + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "c011fc3d", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{0: 0.34549150281252616, 1: 0.6545084971874737}" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "{ # Calculate predicted results\n", + " 0: cos(pi * theta) ** 2, \n", + " 1: sin(pi * theta) ** 2\n", + "}" + ] + }, + { + "cell_type": "markdown", + "id": "7d78c61f", + "metadata": {}, + "source": [ + "
\n", + "\n", + "#### Doubling the phase" + ] + }, + { + "cell_type": "markdown", + "id": "6c7c3d3c", + "metadata": {}, + "source": [ + "The circuit described above uses the phase kickback phenomenon to approximate $\\theta$ to a single bit of accuracy.\n", + "One bit of accuracy may be all we need in some situations — but for factoring we're going to need a lot more accuracy than that.\n", + "The natural question is, how can we learn more about $\\theta?$\n", + "\n", + "One simple thing we could do is to replace the controlled-$U$ operation in our circuit with *two copies* of this operation, like in this circuit:\n", + "\n", + "![Single-bit phase estimation doubled](images/double-phase-kickback.png)\n", + "\n", + "Two copies of a controlled-$U$ operation is equivalent to a controlled-$U^2$ operation.\n", + "If $\\vert\\psi\\rangle$ is an eigenvector of $U$ having eigenvalue $\\lambda = e^{2\\pi i \\theta}$, then this state is also an eigenvector of $U^2$, this time having eigenvalue $\\lambda^2 = e^{2\\pi i (2\\theta)}$.\n", + "\n", + "So, if we run this version of the circuit, we're effectively performing the same computation as before, except that the number $\\theta$ is replaced by $2\\theta$.\n", + "The following plot illustrates the output probabilities as $\\theta$ ranges from $0$ to $1$.\n", + "\n", + "![Outcome probabilities from double-phase kickback](images/double-kickback-probabilities.png)\n", + "\n", + "Doing this can indeed provide us with some additional information about $\\theta$.\n", + "If the binary representation of $\\theta$ is\n", + "\n", + "$$\n", + "\\theta = 0.a_1 a_2 a_3\\cdots\n", + "$$\n", + "\n", + "then doubling $\\theta$ effectively shifts the binary point one position to the right:\n", + "\n", + "$$\n", + "2\\theta = a_1. a_2 a_3\\cdots\n", + "$$\n", + "\n", + "And because we're equating $\\theta = 1$ with $\\theta = 0$ as we move around the unit circle, we see that the bit $a_1$ has no influence on our probabilities — so we're effectively obtaining a guess for what we would get for the *second* bit after the binary point if we were to round $\\theta$ to two bits.\n", + "For instance, if we knew in advance that $\\theta$ was either $0$ or $1/4$, then we could fully trust the measurement outcome to tell us which.\n", + "\n", + "It's not immediately clear, though, how this estimation should be reconciled with what we learned from the original (non-doubled) phase kickback circuit to give us the most accurate information possible about $\\theta$.\n", + "So let's take a step back and consider how to proceed." + ] + }, + { + "cell_type": "markdown", + "id": "7e1f8f05", + "metadata": {}, + "source": [ + "#### Two-qubit phase estimation" + ] + }, + { + "cell_type": "markdown", + "id": "634e708b", + "metadata": {}, + "source": [ + "Rather than considering the two options described above separately, let's combine them into a single circuit like this:\n", + "\n", + "![The initial set-up for phase estimation with two qubits](images/two-bit-phase-estimation-initial.png)\n", + "\n", + "The Hadamard gates after the controlled operations have been removed and there are no measurements here yet.\n", + "We'll add more to the circuit as we consider our options for learning as much as we can about $\\theta$.\n", + "\n", + "If we run this circuit for $\\vert\\psi\\rangle$ being an eigenvector of $U$, the state of the bottom qubits will remain $\\vert\\psi\\rangle$ throughout the entire circuit — and phases will be \"kicked\" into the state of the top two qubits.\n", + "Let's analyze the circuit carefully, by means of the following figure.\n", + "\n", + "\n", + "![States for phase estimation with two qubits](images/two-bit-phase-estimation-states.png)\n", + "\n", + "We can write the state $\\vert\\pi_1\\rangle$ like this:\n", + "\n", + "$$\n", + "\\vert\\pi_1\\rangle = \\vert \\psi\\rangle \\otimes \\frac{1}{2} \\sum_{a_0 = 0}^1 \\sum_{a_1 = 0}^1 \\vert a_1 a_0 \\rangle.\n", + "$$\n", + "\n", + "When the first controlled-$U$ operation is performed, the eigenvalue $\\lambda = e^{2\\pi i\\theta}$ gets kicked into the phase when $a_0$ (the top qubit) is equal to $1$, but not when it's $0$.\n", + "So, we can express the resulting state like this:\n", + "\n", + "$$\n", + "\\vert\\pi_2\\rangle \n", + "= \\vert\\psi\\rangle \\otimes \\frac{1}{2} \\sum_{a_0=0}^1 \\sum_{a_1=0}^1 e^{2 \\pi i a_0 \\theta} \\vert a_1 a_0 \\rangle.\n", + "$$\n", + "\n", + "The second and third controlled-$U$ gates do something similar, except for $a_1$ rather than $a_0$, and with $\\theta$ replaced by $2\\theta$.\n", + "We can express the resulting state like this:\n", + "\n", + "$$\n", + "\\vert\\pi_3\\rangle\n", + "= \\vert\\psi\\rangle\\otimes\\frac{1}{2}\\sum_{a_0 = 0}^1 \\sum_{a_1 = 0}^1 \n", + "e^{2\\pi i (2 a_1 + a_0)\\theta} \\vert a_1 a_0 \\rangle.\n", + "$$\n", + "\n", + "If we think about the binary string $a_1 a_0$ as representing an integer $x \\in \\{0,1,2,3\\}$ in binary notation, which is $x = 2 a_1 + a_0$, we can alternatively express this state as follows:\n", + "\n", + "$$\n", + "\\vert\\pi_3\\rangle \n", + "= \\vert \\psi\\rangle \\otimes \\frac{1}{2} \\sum_{x = 0}^3 e^{2\\pi i x \\theta} \\vert x \\rangle.\n", + "$$\n", + "\n", + "Our goal is to extract as much information about $\\theta$ as we can from this state." + ] + }, + { + "cell_type": "markdown", + "id": "a9b61f7b", + "metadata": {}, + "source": [ + "At this point, we'll consider a special case, where we're promised that $\\theta = \\frac{y}{4}$ for some integer $y\\in\\{0,1,2,3\\}$. \n", + "In other words, we have $\\theta\\in \\{0, 1/4, 1/2, 3/4\\}$, so we can express this number exactly using binary notation with two bits, as $.00$, $.01$, $.10$, or $.11$.\n", + "In general, $\\theta$ might not be one of these four values — but thinking about this special case will help us to figure out how to most effectively extract information about this value.\n", + "\n", + "Let's define one two-qubit state vector for each possible value $y \\in \\{0, 1, 2, 3\\}$.\n", + "\n", + "$$\n", + "\\vert \\phi_y\\rangle = \\frac{1}{2} \\sum_{x = 0}^3 e^{2\\pi i x \\bigl(\\frac{y}{4}\\bigr)} \\vert x \\rangle = \\frac{1}{2} \\sum_{x = 0}^3 e^{2\\pi i \\frac{x y}{4}} \\vert x \\rangle\n", + "$$\n", + "\n", + "After simplifying the exponentials, we can write these vectors as follows:\n", + "\n", + "$$\n", + "\\begin{aligned}\n", + "\\vert\\phi_0\\rangle & = \\frac{1}{2} \\vert 0 \\rangle + \\frac{1}{2} \\vert 1 \\rangle + \\frac{1}{2} \\vert 2 \\rangle + \\frac{1}{2} \\vert 3 \\rangle \\\\[2mm]\n", + "\\vert\\phi_1\\rangle & = \\frac{1}{2} \\vert 0 \\rangle + \\frac{i}{2} \\vert 1 \\rangle - \\frac{1}{2} \\vert 2 \\rangle - \\frac{i}{2} \\vert 3 \\rangle \\\\[2mm]\n", + "\\vert\\phi_2\\rangle & = \\frac{1}{2} \\vert 0 \\rangle - \\frac{1}{2} \\vert 1 \\rangle + \\frac{1}{2} \\vert 2 \\rangle - \\frac{1}{2} \\vert 3 \\rangle \\\\[2mm]\n", + "\\vert\\phi_3\\rangle & = \\frac{1}{2} \\vert 0 \\rangle - \\frac{i}{2} \\vert 1 \\rangle - \\frac{1}{2} \\vert 2 \\rangle + \\frac{i}{2} \\vert 3 \\rangle\n", + "\\end{aligned}\n", + "$$\n", + "\n", + "These vectors are orthogonal: if we choose any pair of them and compute their inner product, we get $0$.\n", + "Each one is also a unit vector, so this implies that $\\{\\vert\\phi_0\\rangle, \\vert\\phi_1\\rangle, \\vert\\phi_2\\rangle, \\vert\\phi_3\\rangle\\}$ is an orthonormal basis.\n", + "So, we know right away that there is a measurement that can discriminate them perfectly — meaning that if we're given one of them but we don't know which, then we can figure out which one it is without error.\n", + "\n", + "To perform such a discrimination with a quantum circuit, let's first define a unitary operation $V$ that transforms standard basis states into the four states listed above:\n", + "\n", + "$$\n", + "\\begin{aligned}\n", + "V \\vert 00 \\rangle & = \\vert\\phi_0\\rangle \\\\\n", + "V \\vert 01 \\rangle & = \\vert\\phi_1\\rangle \\\\\n", + "V \\vert 10 \\rangle & = \\vert\\phi_2\\rangle \\\\\n", + "V \\vert 11 \\rangle & = \\vert\\phi_3\\rangle \\\\\n", + "\\end{aligned}\n", + "$$\n", + "\n", + "To write down $V$ as a $4\\times 4$ matrix, it's just a matter of taking the columns of $V$ to be the states $\\vert\\phi_0\\rangle,\\ldots,\\vert\\phi_3\\rangle$.\n", + "\n", + "$$\n", + "V =\n", + "\\frac{1}{2}\n", + "\\begin{pmatrix}\n", + "1 & 1 & 1 & 1\\\\\n", + "1 & i & -1 & -i\\\\\n", + "1 & -1 & 1 & -1\\\\\n", + "1 & -i & -1 & i\n", + "\\end{pmatrix}\n", + "$$\n", + "\n", + "We saw this matrix as an example at the end of Lesson 1.\n", + "It's a special matrix, and some readers will have seen it before:\n", + "it's the matrix associated with the $4$-dimensional *discrete Fourier transform*.\n", + "\n", + "In light of this fact, let us call it by the name $\\mathrm{QFT}_4$ rather than $V$.\n", + "The name $\\mathrm{QFT}$ is short for *quantum Fourier transform* — which is essentially just the discrete Fourier transform, viewed as a quantum operation.\n", + "We'll discuss the quantum Fourier transform in greater detail and generality shortly.\n", + "\n", + "$$\n", + "\\mathrm{QFT}_4 =\n", + "\\frac{1}{2}\n", + "\\begin{pmatrix}\n", + "1 & 1 & 1 & 1\\\\\n", + "1 & i & -1 & -i\\\\\n", + "1 & -1 & 1 & -1\\\\\n", + "1 & -i & -1 & i\n", + "\\end{pmatrix}\n", + "$$\n", + "\n", + "So, the operation $\\mathrm{QFT}_4$ maps standard basis states to the four possible states we have above.\n", + "We can perform this operation in reverse to go the other way, to transform the states $\\vert\\phi_0\\rangle,\\ldots,\\vert\\phi_3\\rangle$ into the standard basis states $\\vert 0\\rangle,\\ldots,\\vert 3\\rangle$.\n", + "If we do this, then we can measure to learn which value $y\\in\\{0,1,2,3\\}$ describes $\\theta$ as $\\theta = y/4$.\n", + "\n", + "Here's a diagram of the quantum circuit that does this.\n", + "\n", + "![Phase estimation with two qubits](images/two-bit-phase-estimation.png)\n", + "\n", + "To summarize, if we run this circuit when $\\theta = y/4$ for $y\\in\\{0,1,2,3\\}$, the state immediately before the measurements take place will be $\\vert \\psi\\rangle \\vert y\\rangle$ (for $y$ encoded as a two-bit binary string), so the measurements will reveal the value $y$ without error." + ] + }, + { + "cell_type": "markdown", + "id": "ff7f0eed", + "metadata": {}, + "source": [ + "This circuit is motivated by the special case that $\\theta \\in \\{0,1/4,1/2,3/4\\}$ — but we can run it for any choice of $U$ and $\\vert \\psi\\rangle$, and hence any value of $\\theta$, that we wish.\n", + "Here's a plot of the output probabilities the circuit produces for arbitrary choices of $\\theta:$\n", + "\n", + "![Outcome probabilities from two-qubit phase estimation](images/two-bit-probabilities.png)\n", + "\n", + "This is a clear improvement over the single-qubit variant described earlier in the lesson.\n", + "It's not perfect — it can give us the wrong answer — but the answer is heavily skewed toward values of $y$ for which $y/4$ is close to $\\theta$.\n", + "In particular, the most likely outcome always corresponds to the closest value of $y/4$ to $\\theta$ (equating $\\theta = 0$ and $\\theta = 1$ as before), and it appears from the plot that this closest value for $x$ always appears with probability above $40\\%$.\n", + "When $\\theta$ is exactly halfway between two such values, like $\\theta = 0.375$ for instance, the two equally close values of $y$ are equally likely." + ] + }, + { + "cell_type": "markdown", + "id": "32664572", + "metadata": {}, + "source": [ + "#### Qiskit implementation\n", + "\n", + "Here's an implementation of this procedure in Qiskit.\n", + "Similar to the previous implementation, we'll use a phase gate with a chosen angle $\\theta$ for the unitary operation and $\\vert 1\\rangle$ for the eigenvector." + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "945240a6", + "metadata": {}, + "outputs": [ + { + "data": { + "image/svg+xml": [ + "" + ], + "text/plain": [ + "
" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "from math import pi\n", + "from qiskit import QuantumCircuit\n", + "\n", + "theta = .7\n", + "qc = QuantumCircuit(3, 2)\n", + "\n", + "# Prepare the eigenvector\n", + "qc.x(2)\n", + "qc.barrier()\n", + "\n", + "# The initial Hadamard gates\n", + "qc.h(0)\n", + "qc.h(1)\n", + "qc.barrier()\n", + "\n", + "# The controlled unitary gates\n", + "qc.cp(2*pi*theta,0,2)\n", + "qc.cp(2*pi*(2*theta),1,2)\n", + "qc.barrier()\n", + "\n", + "# An implementation of the inverse of the two-qubit QFT\n", + "qc.swap(0,1)\n", + "qc.h(0)\n", + "qc.cp(-pi/2,0,1)\n", + "qc.h(1)\n", + "qc.barrier()\n", + "\n", + "# And finally the measurements\n", + "qc.measure([0, 1], [0, 1])\n", + "qc.draw()\n" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "712b60f1", + "metadata": {}, + "outputs": [ + { + "data": { + "image/svg+xml": [ + "" + ], + "text/plain": [ + "
" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "from qiskit.visualization import plot_histogram\n", + "result = Sampler().run(qc).result()\n", + "plot_histogram(result.quasi_dists)" + ] + }, + { + "cell_type": "markdown", + "id": "813fc3de", + "metadata": {}, + "source": [ + "#### Generalizing to many qubits\n", + "\n", + "Given the improvement we've just obtained by using two control qubits rather than one, in conjunction with the $4$-dimensional quantum Fourier transform, it's natural to consider generalizing it further — by adding more control qubits.\n", + "When we do this, we obtain the general *phase estimation procedure*.\n", + "We'll see how this works shortly, but in order to describe it precisely we're going to need to discuss the quantum Fourier transform in greater generality, to see how it's defined for other dimensions and to see how we can implement it with a quantum circuit." + ] + }, + { + "cell_type": "markdown", + "id": "20367e3c", + "metadata": {}, + "source": [ + "### Quantum Fourier transform\n", + "\n", + "The quantum Fourier transform is a unitary operation that can be defined for any positive integer dimension $N$.\n", + "In this subsection we'll see how this operation is defined, and we'll see how it can be implemented with a quantum circuit on $m$ qubits with cost $O(m^2)$ when $N = 2^m$.\n", + "\n", + "The matrices that describe this operation are derived from an analogous operation on $N$ dimensional vectors known as the *discrete Fourier transform*.\n", + "We can think about the discrete Fourier transform abstractly, in purely mathematical terms, but we can also think about it as a computational problem, where we're given an $N$ dimensional vector of complex numbers (using binary notation to encode the real and imaginary parts of the entries, let us suppose), and our goal is to calculate the result, which is again an $N$ dimensional vector.\n", + "An efficient algorithm for performing this computation known as the *fast Fourier transform* is considered by many to be one of the most important algorithms ever discovered — it's critical in signal processing and has wide-ranging applications.\n", + "\n", + "Our focus, however, is on viewing this transform as a unitary operation that can be performed on a quantum system." + ] + }, + { + "cell_type": "markdown", + "id": "6902f80b", + "metadata": {}, + "source": [ + "#### Definition of the quantum Fourier transform\n", + "\n", + "To define the quantum Fourier transform, we'll first define a complex number $\\omega_N$, for each positive integer $N$, like this:\n", + "\n", + "$$\n", + "\\omega_N = e^{\\frac{2\\pi i}{N}} = \\cos\\left(\\frac{2\\pi}{N}\\right) + i \\sin\\left(\\frac{2\\pi}{N}\\right).\n", + "$$\n", + "\n", + "This is the number on the complex unit circle we obtain if we start at $1$ and move counter-clockwise by an angle of $2\\pi/N$ — or \"one click\" if we imagine that $N$ discrete \"clicks\" would take us all the way around the circle.\n", + "\n", + "Here are a few examples:\n", + "\n", + "$$\n", + "\\begin{gathered}\n", + "\\omega_1 = 1\\\\[1mm]\n", + "\\omega_2 = -1\\\\[1mm]\n", + "\\omega_3 = -\\frac{1}{2} + \\frac{\\sqrt{3}}{2} i\\\\[1mm]\n", + "\\omega_4 = i\\\\[1mm]\n", + "\\omega_8 = \\frac{1+i}{\\sqrt{2}}\\\\[1mm]\n", + "\\omega_{16} = \\frac{\\sqrt{2 + \\sqrt{2}}}{2} + \\frac{\\sqrt{2 - \\sqrt{2}}}{2} i\\\\[1mm]\n", + "\\omega_{100} \\approx 0.998 + 0.063 i\n", + "\\end{gathered}\n", + "$$\n" + ] + }, + { + "cell_type": "markdown", + "id": "c1bc8d2e", + "metadata": {}, + "source": [ + "Now we can define the $N$-dimensional quantum Fourier transform, which is described by an $N\\times N$ matrix whose rows and columns are associated with the standard basis states $\\vert 0\\rangle,\\ldots,\\vert N-1\\rangle$.\n", + "\n", + "$$\n", + "\\mathrm{QFT}_N = \\frac{1}{\\sqrt{N}} \\sum_{x = 0}^{N-1} \\sum_{y = 0}^{N-1} \\omega_N^{xy} \\vert x \\rangle\\langle y\\vert\n", + "$$\n", + "\n", + "For phase estimation we're only going to need this operation for when $N = 2^m$ is a power of $2$, but the operation can be defined for any positive integer $N$.\n", + "\n", + "As was already stated, this is the matrix associated with the $N$-dimensional *discrete Fourier transform*.\n", + "(Often the leading factor of $1/\\sqrt{N}$ is not included in the definition of the matrix associated with the discrete Fourier transform, but we need to include it to obtain a unitary matrix.\n", + "Sometimes a minus sign appears in the exponent of $\\omega_N$ as well — different people define it in slightly different ways, but these differences are superficial and easily reconciled.)\n", + "\n", + "Here's the quantum Fourier transform written as a matrix for some small values of $N$.\n", + "\n", + "$$\n", + "\\mathrm{QFT}_1 = \\begin{pmatrix} 1 \\end{pmatrix}\n", + "$$\n", + "\n", + "$$\n", + "\\mathrm{QFT}_2 = \n", + "\\frac{1}{\\sqrt{2}} \\begin{pmatrix} 1 & 1\\\\ 1 & -1 \\end{pmatrix}\n", + "$$\n", + "\n", + "$$\n", + "\\mathrm{QFT}_3 = \n", + "\\frac{1}{\\sqrt{3}} \n", + "\\begin{pmatrix} \n", + " 1 & 1 & 1\\\\[2mm]\n", + " 1 & \\frac{-1 + i\\sqrt{3}}{2} & \\frac{-1 - i\\sqrt{3}}{2}\\\\[2mm]\n", + " 1 & \\frac{-1 - i\\sqrt{3}}{2} & \\frac{-1 + i\\sqrt{3}}{2}\n", + "\\end{pmatrix}\n", + "$$\n", + "\n", + "$$\n", + "\\mathrm{QFT}_4 =\n", + "\\frac{1}{2}\n", + "\\begin{pmatrix}\n", + "1 & 1 & 1 & 1\\\\\n", + "1 & i & -1 & -i\\\\\n", + "1 & -1 & 1 & -1\\\\\n", + "1 & -i & -1 & i\n", + "\\end{pmatrix}\n", + "$$\n", + "\n", + "$$\n", + "\\mathrm{QFT}_8 =\n", + "\\frac{1}{2\\sqrt{2}}\n", + "\\begin{pmatrix}\n", + " 1 & 1 & 1 & 1 & 1 & 1 & 1 & 1\\\\[2mm]\n", + " 1 & \\frac{1+i}{\\sqrt{2}} & i & \\frac{-1+i}{\\sqrt{2}} & -1 & \\frac{-1-i}{\\sqrt{2}} & -i & \\frac{1-i}{\\sqrt{2}}\\\\[2mm]\n", + " 1 & i & -1 & -i & 1 & i & -1 & -i\\\\[2mm]\n", + " 1 & \\frac{-1+i}{\\sqrt{2}} & -i & \\frac{1+i}{\\sqrt{2}} & -1 & \\frac{1-i}{\\sqrt{2}} & i & \\frac{-1-i}{\\sqrt{2}}\\\\[2mm]\n", + " 1 & -1 & 1 & -1 & 1 & -1 & 1 & -1\\\\[2mm]\n", + " 1 & \\frac{-1-i}{\\sqrt{2}} & i & \\frac{1-i}{\\sqrt{2}} & -1 & \\frac{1+i}{\\sqrt{2}} & -i & \\frac{-1+i}{\\sqrt{2}}\\\\[2mm]\n", + " 1 & -i & -1 & i & 1 & -i & -1 & i\\\\[2mm]\n", + " 1 & \\frac{1-i}{\\sqrt{2}} & -i & \\frac{-1-i}{\\sqrt{2}} & -1 & \\frac{-1+i}{\\sqrt{2}} & i & \\frac{1+i}{\\sqrt{2}}\\\\[2mm]\n", + "\\end{pmatrix}\n", + "$$\n", + "\n", + "Notice, in particular, that $\\mathrm{QFT}_2$ is another name for a Hadamard operation." + ] + }, + { + "cell_type": "markdown", + "id": "979df05e", + "metadata": {}, + "source": [ + "#### Unitarity\n", + "\n", + "Let's check that $\\mathrm{QFT}_N$ is indeed unitary, for any selection of $N$.\n", + "One way to do this is to show that the columns form an orthonormal basis.\n", + "We can define column number $y$, starting from $y = 0$ and going up to $y = N-1$, like this:\n", + "\n", + "$$\n", + "\\vert\\phi_y\\rangle = \\frac{1}{\\sqrt{N}} \\sum_{x = 0}^{N-1} \\omega_N^{xy} \\vert x \\rangle.\n", + "$$\n", + "\n", + "Taking the inner product between any two columns gives us this expression:\n", + "\n", + "$$\n", + "\\langle \\phi_z \\vert \\phi_y \\rangle = \\frac{1}{N} \\sum_{x = 0}^{N-1} \\omega_N^{x (y - z)}\n", + "$$\n", + "\n", + "One way to evaluate sums like this is to use the following formula for the sum of the first $N$ terms of a geometric series.\n", + "\n", + "$$\n", + "1 + \\alpha + \\alpha^2 + \\cdots + \\alpha^{N-1} =\n", + "\\begin{cases}\n", + "\\frac{\\alpha^N - 1}{\\alpha - 1} & \\text{if } \\alpha\\not=1\\\\[2mm]\n", + "N & \\text{if } \\alpha=1\n", + "\\end{cases}\n", + "$$\n", + "\n", + "Specifically, we can use this formula when $\\alpha = \\omega_N^{y-z}$.\n", + "When $y = z$, we have $\\alpha = 1$, so using the formula and dividing by $N$ gives\n", + "\n", + "$$\n", + "\\langle \\phi_y \\vert \\phi_y \\rangle = 1.\n", + "$$\n", + "\n", + "When $y\\neq z$, we have $\\alpha \\neq 1$, so using the formula reveals this:\n", + "\n", + "$$\n", + "\\langle \\phi_z \\vert \\phi_y \\rangle = \\frac{1}{N} \\frac{\\omega_N^{N(y-z)} - 1}{\\omega_N^{y-z} - 1} \n", + "= \\frac{1}{N} \\frac{1 - 1}{\\omega_N^{y-z} - 1} = 0.\n", + "$$\n", + "\n", + "This happens because $\\omega_N^N = e^{2\\pi i} = 1$, so $\\omega_N^{N(y-z)} = 1^{y-z} = 1$, and the numerator becomes $0$ (while the denominator is nonzero because $\\omega_N^{y-z} \\neq 1)$.\n", + "\n", + "At a more intuitive level, what we're effectively doing in the formula for $\\langle \\phi_z\\vert\\phi_y\\rangle$ is summing a bunch of points that are evenly spread around the unit circle — so that they cancel each other out, leaving $0$ when we sum them.\n", + "\n", + "So, we have established that $\\{\\vert\\phi_0\\rangle,\\ldots,\\vert\\phi_{N-1}\\rangle\\}$ is an orthonormal set.\n", + "\n", + "$$\n", + "\\langle \\phi_z \\vert \\phi_y \\rangle =\n", + "\\begin{cases}\n", + "0 & y=z\\\\\n", + "1 & y\\not=z\n", + "\\end{cases}\n", + "$$\n", + "\n", + "This reveals that $\\mathrm{QFT}_N$ is unitary." + ] + }, + { + "cell_type": "markdown", + "id": "22732ff6", + "metadata": {}, + "source": [ + "#### Controlled-phase gates\n", + "\n", + "In order to implement the quantum Fourier transform as a quantum circuit, we're going to need to make use of *controlled-phase* gates.\n", + "\n", + "Recall from Lesson 1 that a *phase operation* is a single-qubit quantum operation of the form\n", + "\n", + "$$\n", + "P_{\\alpha} = \n", + "\\begin{pmatrix}\n", + "1 & 0\\\\\n", + "0 & e^{i\\alpha}\n", + "\\end{pmatrix}\n", + "$$\n", + "\n", + "for any real number $\\alpha$.\n", + "(In Lesson 1 we used the name $\\theta$ in place of $\\alpha$, but in this lesson we'll reserve the letter $\\theta$ for the parameter in phase estimation.)\n", + "\n", + "A controlled version of this gate has the following matrix:\n", + "\n", + "$$\n", + "CP_{\\alpha} = \n", + "\\begin{pmatrix}\n", + "1 & 0 & 0 & 0\\\\\n", + "0 & 1 & 0 & 0\\\\\n", + "0 & 0 & 1 & 0\\\\\n", + "0 & 0 & 0 & e^{i\\alpha}\n", + "\\end{pmatrix}\n", + "$$\n", + "\n", + "For this controlled gate, it doesn't actually matter which qubit is the control and which is the target — the two possibilities are equivalent.\n", + "We can use any of the following symbols to represent this gate in quantum circuit diagrams:\n", + "\n", + "![Quantum circuit diagram representation for controlled-phase gates](images/controlled-phase-gates.png)\n", + "\n", + "For the third form, the label $\\alpha$ is also sometimes placed on the side of the control line or under the lower control when that's convenient.\n", + "\n", + "Using controlled-phase gates we can perform the following transformation,\n", + "where $a$ is a bit and $y \\in \\{0,\\ldots,2^{m-1} - 1\\}$ is a number encoded in binary notation as a string of $m-1$ bits.\n", + "\n", + "$$\n", + "\\vert y \\rangle \\vert a \\rangle \\mapsto \\omega_{2^m}^{ay} \\vert y \\rangle \\vert a \\rangle\n", + "$$\n", + "\n", + "As an example, here's for how this is done for $m=5$.\n", + "\n", + "![Quantum circuit diagram for phase injection](images/phase-injection.png)\n", + "\n", + "This can be naturally generalized for any $m$ — the phase gates always start from $\\frac{\\pi}{2}$ on the most significant bit of $x$ down to $\\pi/2^{m-1}$ on the least significant bit." + ] + }, + { + "cell_type": "markdown", + "id": "b00638a6", + "metadata": {}, + "source": [ + "#### Circuit implementation of the QFT\n", + "\n", + "Now we'll see how we can implement the quantum Fourier transform with a circuit when the dimension $N = 2^m$ is a power of $2$.\n", + "There are, in fact, multiple ways to implement the quantum Fourier transform, but this is arguably the simplest method.\n", + "\n", + "The implementation is recursive in nature, and so that's how it's most naturally described.\n", + "The base case is that the quantum Fourier transform on a single qubit is a Hadamard operation.\n", + "\n", + "To perform the quantum Fourier transform on $m$ qubits when $m \\geq 2$, we can perform the following steps, whose actions we'll describe for standard basis states of the form $\\vert x \\rangle \\vert a\\rangle$, where $x\\in\\{0,\\ldots,2^{m-1} - 1\\}$ is an integer encoded as $m-1$ bits using binary notation and $a$ is a single bit.\n", + "\n", + "1. First apply the $2^{m-1}$-dimensional quantum Fourier transform to the bottom/leftmost $m-1$ qubits to obtain \n", + " this state:\n", + "\n", + " $$\n", + " \\Bigl(\\mathrm{QFT}_{2^{m-1}} \\vert x \\rangle\\Bigr) \\vert a\\rangle\n", + " = \\frac{1}{\\sqrt{2^{m-1}}} \\sum_{y = 0}^{2^{m-1} - 1} \\omega_{2^{m-1}}^{xy} \\vert y \\rangle \\vert a \\rangle\n", + " $$\n", + "\n", + " This is done by recursively applying the method being described for one fewer qubit, using the Hadamard \n", + " operation on a single qubit as the base case.\n", + "\n", + "2. Use the top/rightmost qubit as a control to inject the phase $\\omega_{2^m}^y$ for each standard basis \n", + " state $\\vert y\\rangle$ of the remaining $m-1$ qubits (as described above) to obtain this state:\n", + "\n", + " $$\n", + " \\frac{1}{\\sqrt{2^{m-1}}} \\sum_{y = 0}^{2^{m-1} - 1} \\omega_{2^{m-1}}^{xy}\n", + " \\omega_{2^m}^{ay} \\vert y \\rangle \\vert a \\rangle\n", + " $$\n", + " \n", + "3. Perform a Hadamard gate on the top/rightmost qubit to obtain this state:\n", + "\n", + " $$\n", + " \\frac{1}{\\sqrt{2^{m}}} \\sum_{y = 0}^{2^{m-1} - 1} \\sum_{b=0}^1 \n", + " (-1)^{ab} \\omega_{2^{m-1}}^{xy} \\omega_{2^m}^{ay} \n", + " \\vert y \\rangle \\vert b \\rangle\n", + " $$\n", + "\n", + "4. Permute the order of the qubits so that the least significant bit becomes the most significant bit, with \n", + " all others shifted:\n", + "\n", + " $$\n", + " \\frac{1}{\\sqrt{2^{m}}} \\sum_{y = 0}^{2^{m-1} - 1} \\sum_{b=0}^1 \n", + " (-1)^{ab} \\omega_{2^{m-1}}^{xy} \\omega_{2^m}^{ay} \n", + " \\vert b \\rangle \\vert y \\rangle \n", + " $$" + ] + }, + { + "cell_type": "markdown", + "id": "b7315ca9", + "metadata": {}, + "source": [ + "For example, here's the circuit we obtain for $N = 32 = 2^5$.\n", + "In this diagram, the qubits are given names that correspond to the standard basis vectors $\\vert x\\rangle \\vert a\\rangle$ (for the input) and $\\vert b\\rangle \\vert y\\rangle$ (for the output) for clarity.\n", + "\n", + "![Quantum circuit diagram for the 32-dimensional quantum Fourier transform](images/QFT_32.png)" + ] + }, + { + "cell_type": "markdown", + "id": "34486329", + "metadata": {}, + "source": [ + "
\n", + "\n", + "#### Analysis\n", + "\n", + "The key formula we need to verify that the circuit just described implements the $2^m$-dimensional quantum Fourier transform is this one:\n", + "\n", + "$$\n", + "(-1)^{ab}\n", + "\\omega_{2^{m-1}}^{xy}\n", + "\\omega_{2^m}^{ay}\n", + "=\n", + "\\omega_{2^m}^{(2x+ a)(2^{m-1}b + y)}.\n", + "$$\n", + "\n", + "This formula works for any choice of integers $a$, $b$, $x$, and $y$, but we'll only need it for\n", + "$a,b\\in\\{0,1\\}$ and $x,y\\in\\{0,\\ldots,2^{m-1}-1\\}$.\n", + "We can check the formula by expanding the product in the exponent on the right-hand side,\n", + "\n", + "$$\n", + " \\omega_{2^m}^{(2x+ a)(2^{m-1}b + y)}\n", + " = \\omega_{2^m}^{2^m xb} \\omega_{2^m}^{2xy} \\omega_{2^m}^{2^{m-1}ab} \\omega_{2^m}^{ay}\n", + " = (-1)^{ab} \\omega_{2^{m-1}}^{xy} \\omega_{2^m}^{ay},\n", + "$$\n", + "\n", + "where the second equality makes use of the observation that\n", + "\n", + "$$\n", + "\\omega_{2^m}^{2^m xb} = \\bigl(\\omega_{2^m}^{2^m}\\bigr)^{xb} = 1^{xb} = 1.\n", + "$$\n", + "\n", + "Now, the $2^m$-dimensional quantum Fourier transform is defined as follows for every $u\\in\\{0,\\ldots,2^m - 1\\}$.\n", + "\n", + "$$\n", + "\\mathrm{QFT}_{2^m} \\vert u\\rangle = \\frac{1}{\\sqrt{2^m}}\n", + "\\sum_{v = 0}^{2^m - 1} \\omega_{2^m}^{uv} \\vert v\\rangle\n", + "$$\n", + "\n", + "If we write $u$ and $v$ as\n", + "\n", + "$$\n", + "\\begin{aligned}\n", + "u & = 2x + a\\\\\n", + "v & = 2^{m-1}b + y\n", + "\\end{aligned}\n", + "$$\n", + "\n", + "for $a,b\\in\\{0,1\\}$ and $x,y\\in\\{0,\\ldots,2^{m-1} - 1\\}$, we obtain\n", + "\n", + "$$\n", + "\\begin{aligned}\n", + "\\mathrm{QFT}_{2^m} \\vert 2x + a\\rangle\n", + "& = \n", + "\\frac{1}{\\sqrt{2^m}}\n", + "\\sum_{y = 0}^{2^{m-1} - 1}\n", + "\\sum_{b=0}^1 \n", + "\\omega_{2^m}^{(2x+ a)(2^{m-1}b + y)} \\vert b 2^{m-1} + y\\rangle\\\\[2mm]\n", + "& =\n", + "\\frac{1}{\\sqrt{2^m}}\n", + "\\sum_{y = 0}^{2^{m-1} - 1}\n", + "\\sum_{b=0}^1 \n", + "(-1)^{ab}\n", + "\\omega_{2^{m-1}}^{xy}\n", + "\\omega_{2^m}^{ay}\n", + "\\vert b 2^{m-1} + y\\rangle.\n", + "\\end{aligned}\n", + "$$\n", + "\n", + "Finally, by thinking about the standard basis states $\\vert x \\rangle \\vert a\\rangle$ and $\\vert b \\rangle \\vert y \\rangle$ as binary encodings of integers in the range $\\{0,\\ldots,2^m-1\\}$,\n", + "\n", + "$$\n", + "\\begin{aligned}\n", + "\\vert x \\rangle \\vert a\\rangle & = \\vert 2x + a \\rangle\\\\\n", + "\\vert b \\rangle \\vert y \\rangle & = \\vert 2^{m-1}b + y\\rangle,\n", + "\\end{aligned}\n", + "$$\n", + "\n", + "we see that the circuit above implements the required operation.\n", + "\n", + "If this method for performing the quantum Fourier transform seems remarkable, it's because it is.\n", + "It's essentially the same methodology that underlies the fast Fourier transform — one of the most important and useful classical algorithms ever discovered — in the form of a quantum circuit." + ] + }, + { + "cell_type": "markdown", + "id": "11c6351c", + "metadata": {}, + "source": [ + "#### Computational cost\n", + "\n", + "Now let's count how many gates are used in the circuit just described.\n", + "The controlled-phase gates aren't in the standard gate set that we discussed in the previous lesson, but to begin we'll ignore this and count each of them as a single gate.\n", + "\n", + "Let's let $s_m$ denote the number of gates we need for each possible choice of $m$.\n", + "If $m=1$, the quantum Fourier transform is just a Hadamard operation, so\n", + "\n", + "$$\n", + "s_1 = 1.\n", + "$$\n", + "\n", + "If $m\\geq 2$, then in the circuit above we need $s_{m-1}$ gates for the quantum Fourier transform on $m-1$ qubits, plus $m-1$ controlled-phase gates, plus a Hadamard gate, plus $m-1$ swap gates, so\n", + "\n", + "$$\n", + "s_m = s_{m-1} + (2m - 1).\n", + "$$\n", + "\n", + "We can obtain a closed-form expression by summing:\n", + "\n", + "$$\n", + "s_m = \\sum_{k = 1}^m (2k - 1) = m^2.\n", + "$$\n", + "\n", + "We don't actually need as many swap gates as the method describes — if we rearrange the gates just a bit, we can push all of the swap gates out to the right and reduce the number of swap gates required to $\\lfloor m/2\\rfloor$.\n", + "Asymptotically speaking this isn't a major improvement: we still obtain circuits with size $O(m^2)$ for performing $\\mathrm{QFT}_{2^m}$.\n", + "\n", + "If we wish to implement the quantum Fourier transform using only gates from our standard gate set, we need to either build or approximate each of the controlled-phase gates with gates from our set.\n", + "The number required depends on how much accuracy we require, but the total number remains quadratic in the number $m$.\n", + "(We can even come up with a pretty good approximation to the quantum Fourier transform with a sub-quadratic number of gates by using the fact that when $\\alpha$ is very small, we have $e^{i\\alpha} \\approx 1$, so the controlled-phase gate $CP_{\\alpha}$ can be very well approximated by doing nothing at all in such cases.)" + ] + }, + { + "cell_type": "markdown", + "id": "793c8ec5", + "metadata": {}, + "source": [ + "#### QFTs in Qiskit\n", + "\n", + "A circuit implementation of the QFT on any number of qubits can be obtained from Qiskit's circuit library.\n", + "(Note that for three or more qubits the circuit will differ slightly from the general description above because it incorporates some minor optimizations. In particular, the number of swap gates required can be reduced significantly by effectively pushing them to the end of the circuit and adjusting the controlled-phase gates accordingly.)" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "adbb2d1a", + "metadata": {}, + "outputs": [ + { + "data": { + "image/svg+xml": [ + "" + ], + "text/plain": [ + "
" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "from qiskit.circuit.library import QFT\n", + "QFT(4).decompose().draw()" + ] + }, + { + "cell_type": "markdown", + "id": "25964ba6", + "metadata": {}, + "source": [ + "### General procedure and analysis\n", + "\n", + "Now we'll examine the phase-estimation procedure in general.\n", + "The idea is to extend the single- and double-qubit versions of phase estimation that we considered above in the natural way, as suggested by the following diagram.\n", + "\n", + "![Phase estimation procedure](images/phase-estimation-procedure.png)\n", + "\n", + "Notice that for each new control qubit added on the top, we *double* the number of times the unitary operation $U$ is performed.\n", + "Rather than drawing however many copies of the controlled-$U$ operation are needed to do this in the diagram, we've instead raised $U$ to the required powers.\n", + "\n", + "In general, adding additional control qubits on the top like this will contribute significantly to the size of the circuit: if we have $m$ control qubits, like the diagram depicts, a total of $2^m - 1$ copies of the controlled-$U$ operation are required.\n", + "This means that a significant computational cost is incurred as $m$ is increased — but as we will see, it also leads to a significantly more accurate approximation of $\\theta$.\n", + "\n", + "It is important to note, however, that for *some* choices of $U$ it may be possible to create a circuit that implements the operation $U^k$ for large values of $k$ in a more efficient way than simply repeating $k$ times the circuit for $U$.\n", + "We'll see a specific example of this in the context of integer factorization later in the lesson, where the efficient algorithm for *modular exponentiation* discussed in the previous lesson comes to the rescue.\n", + "\n", + "Now let us analyze the circuit just described.\n", + "The state immediately prior to the quantum Fourier transform looks like this:\n", + "\n", + "$$\n", + "\\frac{1}{\\sqrt{2^m}} \\sum_{x = 0}^{2^m - 1} \\bigl( U^x \\vert\\psi\\rangle \\bigr) \\vert x\\rangle\n", + "= \\vert\\psi\\rangle \\otimes \\frac{1}{\\sqrt{2^m}} \\sum_{x = 0}^{2^m - 1} e^{2\\pi i x\\theta} \\vert x\\rangle.\n", + "$$\n", + "\n", + "#### A special case\n", + "\n", + "Along similar lines to what we did in the $m=2$ case above, we can consider the special case that\n", + "$\\theta = y/2^m$ for $y\\in\\{0,\\ldots,2^m-1\\}$, and we see that this state can alternatively be written like this:\n", + "\n", + "$$\n", + "\\vert\\psi\\rangle \\otimes \\frac{1}{\\sqrt{2^m}} \\sum_{x = 0}^{2^m - 1} e^{2\\pi i \\frac{xy}{2^m}} \\vert x\\rangle\n", + "= \\vert\\psi\\rangle \\otimes \\frac{1}{\\sqrt{2^m}} \\sum_{x = 0}^{2^m - 1} \\omega_{2^m}^{xy} \\vert x\\rangle\n", + "= \\vert\\psi\\rangle \\otimes \\mathrm{QFT}_{2^m} \\vert y\\rangle.\n", + "$$\n", + "\n", + "So, when the inverse of the quantum Fourier transform is applied, the state becomes\n", + "\n", + "$$\n", + "\\vert\\psi\\rangle \\vert y\\rangle\n", + "$$\n", + "\n", + "and the measurements reveal $y$ (encoded in binary).\n" + ] + }, + { + "cell_type": "markdown", + "id": "7e14c809", + "metadata": {}, + "source": [ + "#### Bounding the probabilities\n", + "\n", + "For other values of $\\theta$, meaning ones that don't take the form $y/2^m$ for an integer $y$, the measurement outcomes won't be certain, but we can prove certain bounds on the probabilities for different outcomes.\n", + "Going forward, let's consider an arbitrary choice of $\\theta$ satisfying $0\\leq \\theta < 1$.\n", + "\n", + "After the quantum Fourier transform is performed, the state of the circuit is this:\n", + "\n", + "$$\n", + "\\vert \\psi \\rangle \\otimes \n", + "\\frac{1}{2^m} \\sum_{y=0}^{2^m - 1} \\sum_{x=0}^{2^m-1} e^{2\\pi i x (\\theta - y/2^m)} \\vert y\\rangle.\n", + "$$\n", + "\n", + "So, when the measurements on the top $m$ qubits are performed, we see each outcome $y$ with probability\n", + "\n", + "$$\n", + "p_y = \n", + "\\left\\vert \n", + "\\frac{1}{2^m} \\sum_{x=0}^{2^m - 1} e^{2\\pi i x (\\theta - y/2^m)} \\right|^2\n", + "$$\n", + "\n", + "To get a better handle on these probabilities, we'll make use of the same formula that we saw before, for the sum of the initial portion of a geometric series.\n", + "\n", + "$$\n", + "1 + \\alpha + \\alpha^2 + \\cdots + \\alpha^{N-1} =\n", + "\\begin{cases}\n", + "\\frac{\\alpha^N - 1}{\\alpha - 1} & \\text{if } \\alpha\\not=1\\\\[2mm]\n", + "N & \\text{if } \\alpha=1\n", + "\\end{cases}\n", + "$$\n", + "\n", + "We can simplify the sum appearing in the formula for $p_y$ by taking $\\alpha = e^{2\\pi i (\\theta - y/2^m)}$.\n", + "Here's what we obtain.\n", + "\n", + "$$\n", + "\\sum_{x=0}^{2^m - 1} e^{2\\pi i x (\\theta - y/2^m)}\n", + "=\n", + "\\begin{cases}\n", + "2^m & \\theta = y/2^m\\\\[2mm]\n", + "\\frac{e^{2\\pi (2^m \\theta - y)} - 1}{e^{2\\pi (\\theta - y/2^m)} - 1}\n", + "& \\theta\\neq y/2^m\n", + "\\end{cases}\n", + "$$\n", + "\n", + "So, in the case that $\\theta = y/2^m$, we find that $p_y = 1$ (as we already knew from considering this special case),\n", + "and in the case that $\\theta \\neq y/2^m$, we find that\n", + "\n", + "$$\n", + "p_y = \\frac{1}{2^{2m}} \\left\\vert \\frac{e^{2\\pi i (2^m \\theta - y)} - 1}{e^{2\\pi i (\\theta - y/2^m)} - 1}\\right\\vert^2.\n", + "$$" + ] + }, + { + "cell_type": "markdown", + "id": "c8ce0834", + "metadata": {}, + "source": [ + "We can learn more about these probabilities by thinking about how arc length and chord length on the unit circle are related.\n", + "Here's a figure that illustrates the relationships we need for any real number $\\delta\\in \\bigl[ -\\frac{1}{2},\\frac{1}{2}\\bigr]$." + ] + }, + { + "cell_type": "markdown", + "id": "07b4b461", + "metadata": {}, + "source": [ + "![Illustration of the relationship between arc and chord lengths](images/arc-and-chord.png)\n" + ] + }, + { + "cell_type": "markdown", + "id": "d5cf40a2", + "metadata": {}, + "source": [ + "First, the chord length (drawn in blue) can't possibly be larger than the arc length (drawn in purple):\n", + "\n", + "$$\n", + "\\bigl\\vert e^{2\\pi i \\delta} - 1\\bigr\\vert \\leq 2\\pi\\vert\\delta\\vert.\n", + "$$\n", + "\n", + "Relating these lengths in the other direction, we see that the ratio of the arc length to the chord length is greatest when $\\delta = \\pm 1/2$, and in this case the ratio is half the circumference of the circle divided by the diameter, which is $\\pi/2$.\n", + "Thus, we can write\n", + "\n", + "$$\n", + "4\\vert\\delta\\vert \\leq\n", + "\\bigl\\vert e^{2\\pi i \\delta} - 1\\bigr\\vert.\n", + "$$" + ] + }, + { + "cell_type": "markdown", + "id": "d0c45343", + "metadata": {}, + "source": [ + "An analysis based on this relation reveals the following two facts.\n", + "\n", + "1. Suppose that $\\theta$ is a real number and $y\\in \\{0,\\ldots,2^m-1\\}$ satisfies\n", + " \n", + " $$\n", + " \\Bigl\\vert \\theta - \\frac{y}{2^m}\\Bigr\\vert \\leq 2^{-(m+1)}.\n", + " $$\n", + " \n", + " This means that $y/2^m$ is either the best $m$-bit approximation to $\\theta$, or it's one of the two best approximations in case $\\theta$ is exactly halfway between $y/2^m$ and either $(y-1)/2^m$ or $(y+1)/2^m$.\n", + "\n", + " We'll prove that $p_y$ has to be pretty large in this case.\n", + " By the assumption we're considering, it follows that $\\vert 2^m \\theta - y \\vert \\leq 1/2$, so we can use the second observation above relating arc and chord lengths to conclude that\n", + " \n", + " $$\n", + " \\left\\vert e^{2\\pi (2^m \\theta - y)} - 1\\right\\vert \n", + " \\geq 4 \\vert 2^m \\theta - y \\vert = 4 \\cdot 2^m \\cdot \\Bigl\\vert \\theta - \\frac{y}{2^m}\\Bigr\\vert.\n", + " $$\n", + " \n", + " We can also use the first observation about arc and chord lengths to conclude that\n", + " \n", + " $$\n", + " \\left\\vert e^{2\\pi (\\theta - y/2^m)} - 1\\right\\vert \\leq 2\\pi \\Bigl\\vert \\theta - \\frac{y}{2^m}\\Bigr\\vert.\n", + " $$\n", + " \n", + " Putting these two inequalities to use on $p_y$ reveals\n", + " \n", + " $$\n", + " p_y \\geq \\frac{1}{2^{2m}} \\frac{16 \\cdot 2^{2m}}{4 \\pi^2} = \\frac{4}{\\pi^2} \\approx 0.405.\n", + " $$\n", + " \n", + " (So, our observation that the best outcome occurs with probability greater than $40\\%$ in the $m=2$ version of phase estimation discussed earlier in fact holds for every choice of $m$.)" + ] + }, + { + "cell_type": "markdown", + "id": "83e02530", + "metadata": {}, + "source": [ + "2. Now suppose that $y\\in \\{0,\\ldots,2^m-1\\}$ satisfies\n", + "\n", + " $$\n", + " 2^{-m} \\leq \\Bigl\\vert \\theta - \\frac{y}{2^m}\\Bigr\\vert \\leq \\frac{1}{2}.\n", + " $$\n", + "\n", + " This means that there's a better approximation $z/2^m$ to $\\theta$ in between $\\theta$ and $y/2^m$.\n", + " \n", + " This time we'll prove that $p_y$ can't be too big.\n", + " We can start with the simple observation that\n", + " \n", + " $$\n", + " \\left\\vert e^{2\\pi (2^m \\theta - y)} - 1\\right\\vert \\leq 2,\n", + " $$\n", + " \n", + " which follows from the fact that any two points on the unit circle can differ in absolute value by at most $2$.\n", + " \n", + " We can also use the second observation about arc and chord lengths from above, this time working with the denominator of $p_y$ rather than the numerator, to conclude\n", + " \n", + " $$\n", + " \\left\\vert e^{2\\pi (\\theta - y/2^m)} - 1\\right\\vert \\geq 4\\Bigl\\vert \\theta - \\frac{y}{2^m}\\Bigr\\vert\n", + " \\geq 4 \\cdot 2^{-m}.\n", + " $$\n", + " \n", + " Putting the two inequalities together reveals\n", + " \n", + " $$\n", + " p_y \\leq \\frac{1}{2^{2m}} \\frac{4}{16 \\cdot 2^{-2m}} = \\frac{1}{4}.\n", + " $$\n" + ] + }, + { + "cell_type": "markdown", + "id": "fb142a09", + "metadata": {}, + "source": [ + "This is quite good, in the sense that very close approximations to $\\theta$ are likely to occur, with probability greater than $40\\%$, whereas approximations off by more than $2^{-m}$ are less likely, with probability at most $25\\%$.\n", + "\n", + "We may, however, wish to boost our confidence.\n", + "One way to do this is to repeat the phase estimation procedure several times to gather statistical evidence about $\\theta$.\n", + "Notice that the state $\\vert\\psi\\rangle$ of the bottom collection of qubits is unchanged by the phase estimation procedure, so it can be used to run the procedure as many times as we like.\n", + "\n", + "Each time we rum the circuit, we get a best $m$-bit approximation to $\\theta$ with probability greater than $40\\%$, while the probability of being off by more than $2^{-m}$ is bounded by $25\\%$.\n", + "So, if we run the circuit several times and take the most commonly appearing outcome of the runs, it's exceedingly likely that the outcome that appears most commonly will not be one that occurs at most $25\\%$ of the time.\n", + "As a result, we'll be very likely to obtain an approximation $y/2^m$ that's within $1/2^m$ of the value $\\theta$, and indeed the unlikely chance that we're off by more than $1/2^m$ decreases exponentially in the number of times the procedure is run." + ] + }, + { + "cell_type": "markdown", + "id": "1eb0ce8d", + "metadata": {}, + "source": [ + "#### Qiskit implementation\n", + "\n", + "Here's an implementation of phase estimation in Qiskit.\n", + "Try adjusting $\\theta$ and the number of control qubits $m$ to see how the results change." + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "349571e1", + "metadata": {}, + "outputs": [ + { + "data": { + "image/svg+xml": [ + "" + ], + "text/plain": [ + "
" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "from qiskit import QuantumCircuit, QuantumRegister, ClassicalRegister\n", + "from qiskit.circuit.library import QFT\n", + "\n", + "theta = .7\n", + "m = 3 # Number of control qubits\n", + "\n", + "control_register = QuantumRegister(m, name=\"Control\")\n", + "target_register = QuantumRegister(1, name=\"|ψ>\")\n", + "output_register = ClassicalRegister(m, name=\"Result\")\n", + "qc = QuantumCircuit(control_register, target_register, output_register)\n", + "\n", + "# Prepare the eigenvector |ψ>\n", + "qc.x(target_register)\n", + "qc.barrier()\n", + "\n", + "# Perform phase estimation\n", + "for index, qubit in enumerate(control_register):\n", + " qc.h(qubit)\n", + " for _ in range(2**index):\n", + " qc.cp(2*pi*theta, qubit, target_register)\n", + "qc.barrier()\n", + "\n", + "# Do inverse quantum Fourier transform\n", + "qc.compose(\n", + " QFT(m, inverse=True),\n", + " inplace=True\n", + ")\n", + "\n", + "# Measure everything\n", + "qc.measure(range(m), range(m))\n", + "qc.draw()" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "61f7f268", + "metadata": {}, + "outputs": [ + { + "data": { + "image/svg+xml": [ + "" + ], + "text/plain": [ + "
" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "result = Sampler().run(qc).result()\n", + "plot_histogram(result.quasi_dists)" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "id": "b614e0fc", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Most probable output: 6\n", + "Estimated theta: 0.75\n" + ] + } + ], + "source": [ + "most_probable = max(result.quasi_dists[0],\n", + " key=result.quasi_dists[0].get)\n", + "\n", + "print(f\"Most probable output: {most_probable}\")\n", + "print(f\"Estimated theta: {most_probable/2**m}\")" + ] + }, + { + "cell_type": "markdown", + "id": "8c3bd3a7", + "metadata": {}, + "source": [ + "## Shor's algorithm" + ] + }, + { + "cell_type": "markdown", + "id": "0074c9ef", + "metadata": {}, + "source": [ + "Now we'll turn our attention to the integer factorization problem, and see how it can be solved efficiently on a quantum computer using phase estimation.\n", + "The algorithm we'll obtain is *Shor's algorithm for integer factorization*.\n", + "Shor didn't describe his algorithm specifically in terms of phase estimation, but it is a natural and intuitive way to explain how it works.\n", + "\n", + "In the two subsections that follow we'll describe the two main parts of Shor's algorithm.\n", + "In the first subsection we'll define an intermediate problem known as the *order-finding problem* and see how phase estimation provides a solution to this problem.\n", + "In the second subsection we'll explain how an efficient solution to the order-finding problem also gives us an efficient solution to the integer factorization problem.\n", + "(When a solution to one problem provides a solution to another problem like this, we say that the second problem *reduces* to the first — so in this case we're reducing integer factorization to order finding.)\n", + "This part of Shor's algorithm doesn't make use of quantum computing at all — it's completely classical." + ] + }, + { + "cell_type": "markdown", + "id": "b3be9237", + "metadata": {}, + "source": [ + "### Order finding\n", + "\n", + "#### Some basic number theory\n", + "\n", + "To explain the order-finding problem and how it can be solved using phase estimation, it will be very helpful to explain a couple of basic concepts in number theory and introduce some handy notation along the way.\n", + "\n", + "To begin, for any given positive integer $N$, we'll define a set\n", + "\n", + "$$\n", + "\\mathbb{Z}_N = \\{0,1,\\ldots,N-1\\}.\n", + "$$\n", + "\n", + "For instance, $\\mathbb{Z}_1 = \\{0\\}$, $\\mathbb{Z}_2 = \\{0,1\\}$, $\\mathbb{Z}_3 = \\{0,1,2\\}$,\n", + "and so on.\n", + "\n", + "These are sets of numbers, but we can think of them as more than sets.\n", + "In particular, we can think about *arithmetic operations* on $\\mathbb{Z}_N$ such as addition and multiplication — and if we agree to always take our answers modulo $N$, we'll always stay within this set when we perform these operations.\n", + "(The two specific operations of addition and multiplication, both taken modulo $N$, turn $\\mathbb{Z}_N$ into a *ring*, which is a fundamentally important type of object in algebra.)\n", + "\n", + "For example, $3$ and $5$ are elements of $\\mathbb{Z}_7$, and if we multiply them together we get $3\\cdot 5 = 15$, which leaves a remainder of $1$ when divided by $7$.\n", + "Sometimes we express this as follows.\n", + "\n", + "$$\n", + "3 \\cdot 5 \\equiv 1 \\; (\\textrm{mod } 7)\n", + "$$\n", + "\n", + "But we can also simply write $3 \\cdot 5 = 1$, provided that it's been made clear that we're working in $\\mathbb{Z}_7$, just to keep our notation as simple and clear as possible.\n", + "\n", + "As an example, here are the addition and multiplication tables for $\\mathbb{Z}_6$.\n", + "\n", + "$$\n", + "\\begin{array}{c|cccccc}\n", + " + & 0 & 1 & 2 & 3 & 4 & 5 \\\\\\hline\n", + " 0 & 0 & 1 & 2 & 3 & 4 & 5 \\\\\n", + " 1 & 1 & 2 & 3 & 4 & 5 & 0 \\\\\n", + " 2 & 2 & 3 & 4 & 5 & 0 & 1 \\\\\n", + " 3 & 4 & 5 & 0 & 1 & 2 & 3 \\\\\n", + " 4 & 5 & 0 & 1 & 2 & 3 & 4 \\\\\n", + " 5 & 0 & 1 & 2 & 3 & 4 & 5 \\\\\n", + "\\end{array}\n", + "\\qquad\n", + "\\begin{array}{c|cccccc}\n", + "\\cdot & 0 & 1 & 2 & 3 & 4 & 5 \\\\\\hline\n", + " 0 & 0 & 0 & 0 & 0 & 0 & 0 \\\\\n", + " 1 & 0 & 1 & 2 & 3 & 4 & 5 \\\\\n", + " 2 & 0 & 2 & 4 & 0 & 2 & 4 \\\\\n", + " 3 & 0 & 3 & 0 & 3 & 0 & 3 \\\\\n", + " 4 & 0 & 4 & 2 & 0 & 4 & 2 \\\\\n", + " 5 & 0 & 5 & 4 & 3 & 2 & 1 \\\\\n", + "\\end{array}\n", + "$$\n", + "\n", + "Among the $N$ elements of $\\mathbb{Z}_N$, the elements $a\\in\\mathbb{Z}_N$ that satisfy $\\gcd(a,N) = 1$ are special.\n", + "Frequently the set containing these elements is denoted with a star like this:\n", + "\n", + "$$\n", + "\\mathbb{Z}_N^{\\ast} = \\{a\\in \\mathbb{Z}_N : \\gcd(a,N) = 1\\}.\n", + "$$\n", + "\n", + "If we focus our attention on the operation of multiplication, the set $\\mathbb{Z}_N^{\\ast}$ forms a *group* — and specifically an *abelian group* — which is another important type of object in algebra.\n", + "It's a basic fact about these sets (and indeed about finite groups in general), that if we pick any element $a\\in\\mathbb{Z}_N^{\\ast}$ and repeatedly multiply $a$ to itself, we'll always eventually get the number $1$.\n", + "\n", + "For a first example, let's take $N=6$.\n", + "We have that $5\\in\\mathbb{Z}_6^{\\ast}$ because $\\gcd(5,6) = 1$, and if we multiply $5$ to itself we get $1$\n", + "(as the table above confirms).\n", + "\n", + "$$\n", + "5^2 = 1 \\quad \\text{(working within $\\mathbb{Z}_6$)}\n", + "$$\n", + "\n", + "As a second example, let's take $N = 21$.\n", + "If we go through the numbers from $0$ to $20$, these are the ones that have GCD equal to $1$ with $21:$\n", + "\n", + "$$\n", + "\\mathbb{Z}_{21}^{\\ast} = \\{1,2,4,5,8,10,11,13,16,17,19,20\\}.\n", + "$$\n", + "\n", + "For each of these elements, it is possible to raise that number to a positive integer power to get $1$.\n", + "Here are the smallest powers for which this works:\n", + "\n", + "$$\n", + "\\begin{aligned}\n", + "1^{1} = 1\\\\\n", + "2^{6} = 1\\\\\n", + "4^{3} = 1\\\\\n", + "5^{6} = 1\\\\\n", + "8^{2} = 1\\\\\n", + "10^{6} = 1\\\\\n", + "11^{6} = 1\\\\\n", + "13^{2} = 1\\\\\n", + "16^{3} = 1\\\\\n", + "17^{6} = 1\\\\\n", + "19^{6} = 1\\\\\n", + "20^{2} = 1\\\\\n", + "\\end{aligned}\n", + "$$\n", + "\n", + "Naturally we're working within $\\mathbb{Z}_{21}$ for all of these equations, which we haven't bothered to write — we take it to be implicit to avoid cluttering things up. We'll continue to do that throughout the rest of the lesson.\n", + "\n", + "You can check each of these equations above, as well as the fact that these are the smallest positive integer powers for which the equations work, using the following code cell (changing the numbers as needed)." + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "id": "64db66b1", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "k \t a^k \n", + "\n", + " 1 \t 17\n", + " 2 \t 16\n", + " 3 \t 20\n", + " 4 \t 4\n", + " 5 \t 5\n", + " 6 \t 1\n", + " 7 \t 17\n", + " 8 \t 16\n", + " 9 \t 20\n", + "10 \t 4\n", + "11 \t 5\n", + "12 \t 1\n" + ] + } + ], + "source": [ + "N = 21\n", + "a = 17\n", + "max_power = 12\n", + "\n", + "print(\"k \\t a^k \\n\")\n", + "for k in range(1,max_power+1):\n", + " print(\"%2d \\t %2d\" %(k, a**k % N)) # The % operation computes the remainder modulo N" + ] + }, + { + "cell_type": "markdown", + "id": "53484e4c", + "metadata": {}, + "source": [ + "Notice that after we get back to $1$, the cycle repeats — which makes sense because multiplying $1$ by $a$ brings us back to $a$, which is where we started.\n", + "\n", + "Although it isn't essential for the sake of the lesson, we can also check that we never get back to $1$ when $\\gcd(a,N)\\neq 1$ — so we're relying on the fact that $a\\in\\mathbb{Z}_N^{\\ast}$ for this to work." + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "id": "4df0ffff", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "k \t a^k \n", + "\n", + " 1 \t 18\n", + " 2 \t 9\n", + " 3 \t 15\n", + " 4 \t 18\n", + " 5 \t 9\n", + " 6 \t 15\n", + " 7 \t 18\n", + " 8 \t 9\n", + " 9 \t 15\n", + "10 \t 18\n", + "11 \t 9\n", + "12 \t 15\n" + ] + } + ], + "source": [ + "N = 21\n", + "a = 18\n", + "max_power = 12\n", + "\n", + "print(\"k \\t a^k \\n\")\n", + "for k in range(1,max_power+1):\n", + " print(\"%2d \\t %2d\" %(k, a**k % N))\n", + " " + ] + }, + { + "cell_type": "markdown", + "id": "db405808", + "metadata": {}, + "source": [ + "
\n", + "\n", + "#### Problem statement\n", + "\n", + "Now we can state the order-finding problem.\n", + "\n", + "\n", + "\n", + "**Order finding**\n", + "\n", + "Input: positive integers $N$ and $a$ satisfying $\\gcd(N, a) = 1$\n", + "\n", + "Output: the smallest positive integer $r$ such that $a^r \\equiv 1 \\pmod N$\n", + "\n", + "\n", + "\n", + "Alternatively, in terms of the notation we just introduced above, we're given $a \\in \\mathbb{Z}_N^{\\ast}$, and we're looking for the smallest positive integer $r$ such that $a^r = 1$.\n", + "This number $r$ is called the *order* of $a$ modulo $N$." + ] + }, + { + "cell_type": "markdown", + "id": "a12335d6", + "metadata": {}, + "source": [ + "#### Multiplication by an element in $\\mathbb{Z}_N^{\\ast}$\n", + "\n", + "To connect the order-finding problem to phase estimation, let's think about the operation defined on a system whose classical states correspond to $\\mathbb{Z}_N$, where we multiply by a fixed element $a\\in\\mathbb{Z}_N^{\\ast}$.\n", + "\n", + "$$\n", + "M_a \\vert x\\rangle = \\vert ax \\rangle \\qquad \\text{(for each $x\\in\\mathbb{Z}_N$)}\n", + "$$\n", + "\n", + "To be clear, we're doing the multiplication in $\\mathbb{Z}_N$, so it's implicit that we're taking the remainder modulo $N$ inside of the ket on the right-hand side of the equation.\n", + "\n", + "For example, if $N = 15$ and $a=2$, we have\n", + "\n", + "$$\n", + "\\begin{aligned}\n", + "M_{2} \\vert 0 \\rangle & = \\vert 0\\rangle \\\\[1mm]\n", + "M_{2} \\vert 1 \\rangle & = \\vert 2\\rangle \\\\[1mm]\n", + "M_{2} \\vert 2 \\rangle & = \\vert 4\\rangle \\\\[1mm]\n", + "M_{2} \\vert 3 \\rangle & = \\vert 6\\rangle \\\\[1mm]\n", + "M_{2} \\vert 4 \\rangle & = \\vert 8\\rangle \\\\[1mm]\n", + "M_{2} \\vert 5 \\rangle & = \\vert 10\\rangle \\\\[1mm]\n", + "M_{2} \\vert 6 \\rangle & = \\vert 12\\rangle \\\\[1mm]\n", + "M_{2} \\vert 7 \\rangle & = \\vert 14\\rangle \\\\[1mm]\n", + "M_{2} \\vert 8 \\rangle & = \\vert 1\\rangle \\\\[1mm]\n", + "M_{2} \\vert 9 \\rangle & = \\vert 3\\rangle \\\\[1mm]\n", + "M_{2} \\vert 10 \\rangle & = \\vert 5\\rangle \\\\[1mm]\n", + "M_{2} \\vert 11 \\rangle & = \\vert 7\\rangle \\\\[1mm]\n", + "M_{2} \\vert 12 \\rangle & = \\vert 9\\rangle \\\\[1mm]\n", + "M_{2} \\vert 13 \\rangle & = \\vert 11\\rangle \\\\[1mm]\n", + "M_{2} \\vert 14 \\rangle & = \\vert 13\\rangle\n", + "\\end{aligned}\n", + "$$\n", + "\n", + "So long as $\\gcd(a,N)=1$, this is a unitary operation.\n", + "It shuffles the elements of the standard basis\n", + "$\\{\\vert 0\\rangle,\\ldots,\\vert N-1\\rangle\\}$, so as a matrix it's a *permutation matrix*.\n", + "It's evident from its definition that this operation is deterministic, and a simple way to see that it's invertible is to think about the order $r$ of $a$ modulo $N$, and to recognize that the inverse of $M_a$ is $M_a^{r-1}$.\n", + "\n", + "$$\n", + "M_a^{r-1} M_a = M_a^r = M_{a^r} = M_1 = I\n", + "$$" + ] + }, + { + "cell_type": "markdown", + "id": "bf37dea7", + "metadata": {}, + "source": [ + "There's another way to think about the inverse that doesn't require any knowledge of $r$ — which, after all, is what we're trying to compute.\n", + "For every element $a\\in\\mathbb{Z}_N^{\\ast}$ there's always a unique element $b\\in\\mathbb{Z}_N^{\\ast}$ that satisfies $ab=1$. \n", + "We denote this element $b$ by $a^{-1}$, and it can be computed efficiently.\n", + "(An extension of Euclid's GCD algorithm does it at cost quadratic in $\\operatorname{lg}(N)$.)\n", + "And thus\n", + "\n", + "$$\n", + "M_{a^{-1}} M_a = M_{a^{-1}a} = M_1 = I.\n", + "$$\n", + "\n", + "So, the operation $M_a$ is both deterministic and invertible.\n", + "That implies that it's described by a permutation matrix, and it's therefore unitary." + ] + }, + { + "cell_type": "markdown", + "id": "6fcc4a86", + "metadata": {}, + "source": [ + "#### Eigenvectors and eigenvalues of multiplication operations\n", + "\n", + "Now let's think about the eigenvectors and eigenvalues of the operation $M_a$, assuming that $a\\in\\mathbb{Z}_N^{\\ast}$. \n", + "As was just argued, this assumption tells us that $M_a$ is unitary.\n", + "\n", + "There are $N$ eigenvalues of $M_a$, possibly including the same eigenvalue repeated multiple times, and in general there's some freedom in selecting corresponding eigenvectors — but we won't need to worry about all of the possibilities.\n", + "Let's start simple and identify just one eigenvector of $M_a$.\n", + "\n", + "$$\n", + "\\vert \\psi_0 \\rangle = \\frac{\\vert 1 \\rangle + \\vert a \\rangle + \\cdots + \\vert a^{r-1} \\rangle}{\\sqrt{r}}\n", + "$$\n", + "\n", + "The number $r$ is the order of $a$ modulo $N$ — here and throughout the remainder of the lesson.\n", + "The eigenvalue associated with this eigenvector is $1$ because it isn't changed when we multiply by $a$.\n", + "\n", + "$$\n", + "M_a \\vert \\psi_0 \\rangle \n", + "= \\frac{\\vert a \\rangle + \\cdots + \\vert a^{r-1} \\rangle + \\vert a^r \\rangle}{\\sqrt{r}}\n", + "= \\frac{\\vert a \\rangle + \\cdots + \\vert a^{r-1} \\rangle + \\vert 1 \\rangle}{\\sqrt{r}}\n", + "= \\vert \\psi_0 \\rangle\n", + "$$\n", + "\n", + "This happens because $a^r = 1$, so each standard basis state $\\vert a^k \\rangle$ gets shifted to $\\vert a^{k+1} \\rangle$ for $k\\leq r-1$, and $\\vert a^{r-1} \\rangle$ gets shifted back to $\\vert 1\\rangle$.\n", + "Informally speaking, it's like we're slowly stirring $\\vert \\psi_0 \\rangle$, but it's already completely stirred so nothing changes.\n", + "\n", + "Here's another example of an eigenvector of $M_a$.\n", + "This one happens to be more interesting in the context of order finding and phase estimation.\n", + "\n", + "$$\n", + "\\vert \\psi_1 \\rangle = \\frac{\\vert 1 \\rangle + \\omega_r^{-1} \\vert a \\rangle + \\cdots + \\omega_r^{r-1}\\vert a^{r-1} \\rangle}{\\sqrt{r}}\n", + "$$\n", + "\n", + "Alternatively, we can write this vector using a summation as follows.\n", + "\n", + "$$\n", + "\\vert \\psi_1 \\rangle = \\frac{1}{\\sqrt{r}}\n", + "\\sum_{k = 0}^{r-1} \\omega_r^{-k} \\vert a^k \\rangle \n", + "$$\n", + "\n", + "Here we see the complex number $\\omega_r = e^{2\\pi i/r}$ showing up naturally, due to the underlying structure of multiplication by $a$ modulo $N$.\n", + "This time the corresponding eigenvalue is $\\omega_r$.\n", + "To see this, we can first compute like this:\n", + "\n", + "$$\n", + "M_a \\vert \\psi_1 \\rangle \n", + "= \\sum_{k = 0}^{r-1} \\omega_r^{-k} M_a\\vert a^k \\rangle \n", + "= \\sum_{k = 0}^{r-1} \\omega_r^{-k} \\vert a^{k+1} \\rangle \n", + "= \\sum_{k = 1}^{r} \\omega_r^{-(k - 1)} \\vert a^{k} \\rangle \n", + "= \\omega_r \\sum_{k = 1}^{r} \\omega_r^{-k} \\vert a^{k} \\rangle.\n", + "$$\n", + "\n", + "Then, because $\\omega_r^{-r} = 1 = \\omega_r^0$ and $\\vert a^r \\rangle = \\vert 1\\rangle = \\vert a^0\\rangle$, we see that\n", + "\n", + "$$\n", + "\\sum_{k = 1}^{r} \\omega_r^{-k} \\vert a^{k} \\rangle = \\sum_{k = 0}^{r-1} \\omega_r^{-k} \\vert a^k \\rangle\n", + "= \\vert\\psi_1\\rangle,\n", + "$$\n", + "\n", + "so $M_a \\vert\\psi_1\\rangle = \\omega_r \\vert\\psi_1\\rangle$.\n", + "\n", + "Using the same reasoning, we can identify additional eigenvector/eigenvalue pairs for $M_a$.\n", + "Indeed, for any choice of $j\\in\\{0,\\ldots,r-1\\}$ we have that\n", + "\n", + "$$\n", + "\\vert \\psi_j \\rangle = \\frac{1}{\\sqrt{r}}\n", + "\\sum_{k = 0}^{r-1} \\omega_r^{-jk} \\vert a^k \\rangle \n", + "$$\n", + "\n", + "is an eigenvector of $M_a$ whose corresponding eigenvalue is $\\omega_r^j$.\n", + "\n", + "$$\n", + "M_a \\vert \\psi_j \\rangle = \\omega_r^j \\vert \\psi_j \\rangle\n", + "$$\n", + "\n", + "There are other eigenvectors, such as $\\vert 0 \\rangle$, which has eigenvalue $1$, but we'll only be concerned with the eigenvectors $\\vert\\psi_0\\rangle,\\ldots,\\vert\\psi_{r-1}\\rangle$ that we've just identified." + ] + }, + { + "cell_type": "markdown", + "id": "3534900a", + "metadata": {}, + "source": [ + "#### Applying phase estimation\n", + "\n", + "To solve the order-finding problem for a given choice of $a\\in\\mathbb{Z}_N^{\\ast}$, we can apply the phase-estimation procedure to the operation $M_a$.\n", + "\n", + "To do this, we need to implement not only $M_a$ efficiently with a quantum circuit, but also $M_a^2$, $M_a^4$, $M_a^8$, and so on, going as far as needed to obtain a precise enough estimate from the phase estimation procedure.\n", + "Here we'll explain how this can be done, and we'll figure out exactly how much precision is needed a bit later.\n", + "\n", + "Let's start with the operation $M_a$ by itself.\n", + "Naturally, because we're working with the quantum circuit model, we'll use binary notation to encode the numbers between $0$ and $N-1$.\n", + "The largest number we need to encode is $N-1$, so the number of bits we need is\n", + "\n", + "$$\n", + "n = \\operatorname{lg}(N-1) = \\lfloor \\log(N-1) \\rfloor + 1.\n", + "$$\n", + "\n", + "For example, if $N = 21$ we have $n = \\operatorname{lg}(N-1) = 5$.\n", + "Here's what the encoding of elements of $\\mathbb{Z}_{20}$ as binary strings of length $5$ looks like.\n", + "\n", + "$$\n", + "\\begin{gathered}\n", + "0 \\mapsto 00000\\\\[1mm]\n", + "1 \\mapsto 00001\\\\[1mm]\n", + "\\vdots\\\\[1mm]\n", + "20 \\mapsto 10100\n", + "\\end{gathered}\n", + "$$\n", + "\n", + "And now, here's a precise definition of how $M_a$ is defined as an $n$-qubit operation.\n", + "\n", + "$$\n", + "M_a \\vert x\\rangle = \n", + "\\begin{cases}\n", + "\\vert ax \\; (\\textrm{mod}\\;N)\\rangle & 0\\leq x < N\\\\[1mm]\n", + "\\vert x\\rangle & N\\leq x < 2^n\n", + "\\end{cases}\n", + "$$\n", + "\n", + "The point is that although we only care about how $M_a$ works for $\\vert 0\\rangle,\\ldots,\\vert N-1\\rangle$, we do have to specify how it works for the remaining $2^n - N$ standard basis states — and we need to do this in a way that still gives us a unitary operation.\n", + "Defining $M_a$ so that it does nothing to the remaining standard basis states accomplishes this.\n", + "\n", + "Using the algorithms for integer multiplication and division discussed in the previous lesson, together with the methodology for reversible, garbage-free implementations of them, we can build a quantum circuit that performs $M_a$, for any choice of $a\\in\\mathbb{Z}_N^{\\ast}$, at cost $O(n^2)$.\n", + "Here's one way that this can be done.\n", + "\n", + "1. We build a circuit for performing the operation\n", + "\n", + " $$\n", + " \\vert x \\rangle \\vert y \\rangle \\mapsto \\vert x \\rangle \\vert y \\oplus f_a(x)\\rangle\n", + " $$\n", + "\n", + " where\n", + "\n", + " $$\n", + " f_a(x) = \n", + " \\begin{cases}\n", + " ax \\; (\\textrm{mod}\\;N) & 0\\leq x < N\\\\[1mm]\n", + " x & N\\leq x < 2^n\n", + " \\end{cases}\n", + " $$\n", + "\n", + " using the method described in the previous lesson.\n", + " This gives us a circuit of size $O(n^2)$.\n", + "\n", + "2. We swap the two $n$-qubit systems using $n$ swap gates to swap the qubits individually.\n", + "\n", + "3. Along similar lines to the first step, we can build a circuit for the operation\n", + "\n", + " $$\n", + " \\vert x \\rangle \\vert y \\rangle \\mapsto \\vert x \\rangle \\bigl\\vert y \\oplus f_{a^{-1}}(x)\\bigr\\rangle\n", + " $$\n", + "\n", + " where $a^{-1}$ is the inverse of $a$ in $\\mathbb{Z}_N^{\\ast}$.\n", + "\n", + "By initializing the bottom $n$ qubits and composing the three steps, we obtain this transformation:\n", + "\n", + "$$\n", + "\\vert x \\rangle \\vert 0^n \\rangle \n", + "\\stackrel{\\text{step 1}}{\\mapsto} \n", + "\\vert x \\rangle \\vert f_a(x)\\rangle\n", + "\\stackrel{\\text{step 2}}{\\mapsto}\n", + "\\vert f_a(x)\\rangle \\vert x \\rangle\n", + "\\stackrel{\\text{step 3}}{\\mapsto}\n", + "\\vert f_a(x)\\rangle \\bigl\\vert x \\oplus f_{a^{-1}}(f_a(x)) \\bigr\\rangle\n", + "= \\vert f_a(x)\\rangle\\vert 0^n \\rangle \n", + "$$\n", + "\n", + "The total cost of the circuit we obtain is $O(n^2)$.\n", + "\n", + "To perform $M_a^2$, $M_a^4$, $M_a^8$, and so on, we can use exactly the same method, except that we replace $a$ with $a^2$, $a^4$, $a^8$, and so on, as elements of $\\mathbb{Z}_N^{\\ast}$.\n", + "That is, for any power $k$ we choose, we can create a circuit for $M_a^k$ not by iterating $k$ times the circuit for $M_a$, but instead by computing $b = a^k \\in \\mathbb{Z}_N^{\\ast}$ and then using the circuit for $M_b$.\n", + "\n", + "The computation of powers $a^k \\in \\mathbb{Z}_N$ is the *modular exponentiation* problem mentioned in the previous lesson.\n", + "This computation can be done *classically*, using the algorithm for modular exponentiation mentioned in the previous lesson (often called the *power algorithm* in computational number theory).\n", + "This time we don't need to implement this algorithm reversibly with a quantum circuit, we just need to do it classically.\n", + "\n", + "And we're fortunate that this is possible.\n", + "We're effectively offloading the problem of iterating $M_a$ a huge number of times, which can be exponential in the number $m$ we choose in phase estimation, to an efficient classical computation.\n", + "In terms of the quantum circuit we're running, the cost of $M_a$ iterated $k$ times is simply the cost of $M_b$, for $b = a^k$ — and so the cost is $O(n^2)$.\n", + "\n", + "For an arbitrary choice of a quantum circuit in the phase estimation problem this won't be possible, resulting in a cost for phase estimation that's *exponential* in the number $m$ we use in phase estimation. \n", + "By the power of computational number theory, the cost in the case at hand is *linear* in $m$." + ] + }, + { + "cell_type": "markdown", + "id": "c804ee0d", + "metadata": {}, + "source": [ + "#### A convenient eigenvector/eigenvalue pair\n", + "\n", + "To understand how we can solve the order-finding problem using phase estimation, let's start by supposing that\n", + "we run the phase estimation procedure on the operation $M_a$ using the eigenvector $\\vert\\psi_1\\rangle$.\n", + "Getting our hands on this eigenvector isn't easy, as it turns out, so this won't be the end of the story — but it's helpful to start here.\n", + "\n", + "The eigenvalue of $M_a$ corresponding to the eigenvector $\\vert \\psi_1\\rangle$ is\n", + "\n", + "$$\n", + "\\omega_r = e^{2\\pi i \\frac{1}{r}}.\n", + "$$\n", + "\n", + "That is, $\\omega_r = e^{2\\pi i \\theta}$ for $\\theta = 1/r$.\n", + "So, if we run the phase estimation procedure on $M_a$ using the eigenvector $\\vert\\psi_1\\rangle$, we'll get an approximation to $1/r$.\n", + "By computing the reciprocal we'll be able to learn $r$ — provided that our approximation is good enough.\n", + "\n", + "To be more precise, when we run the phase-estimation procedure using $m$ control qubits, what we obtain is a number\n", + "$y\\in\\{0,\\ldots,2^m-1\\}$, and we take $y/2^m$ as a guess for $\\theta$, which is $1/r$ in the case at hand.\n", + "To figure out what $r$ is from this approximation, the natural thing to do is to compute the reciprocal of our approximation and round to the nearest integer.\n", + "\n", + "$$\n", + "\\left\\lfloor \\frac{2^m}{y} + \\frac{1}{2} \\right\\rfloor\n", + "$$\n", + "\n", + "For example, let's suppose $r = 6$ and we perform phase estimation on $M_a$ with the eigenvector $\\vert\\psi_1\\rangle$ using $m = 5$ control bits.\n", + "The best $5$-bit approximation to $1/r = 1/6$ is $5/32$, and we have a pretty good chance (about $68\\%$ in this case) to obtain the outcome $y=5$ from phase estimation.\n", + "We have\n", + "\n", + "$$\n", + "\\frac{2^m}{y} = \\frac{32}{5} = 6.4\n", + "$$\n", + "\n", + "and rounding to the nearest integer gives $6$, which is the correct answer.\n", + "\n", + "On the other hand, if we don't use enough precision we may not get the right answer.\n", + "For instance, if we take $m = 4$ control qubits in phase estimation, we might obtain the best $4$-bit approximation to $1/r = 1/6$, which is $3/16$.\n", + "Taking the reciprocal yields\n", + "\n", + "$$\n", + "\\frac{2^m}{y} = \\frac{16}{3} = 5.333 \\cdots\n", + "$$\n", + "\n", + "and rounding to the nearest integer gives an incorrect answer of $5$.\n", + "\n", + "How much precision do we need to get the right answer?\n", + "We know that the order $r$ is an integer, and intuitively speaking what we need is enough precision to distinguish $1/r$ from nearby possibilities, including $1/(r+1)$ and $1/(r-1)$.\n", + "The closest number to $1/r$ that we need to be concerned with is $1/(r+1)$, and the distance between these two numbers is\n", + "\n", + "$$\n", + "\\frac{1}{r} - \\frac{1}{r+1} = \\frac{1}{r(r+1)}.\n", + "$$\n", + "\n", + "So, if we want to make sure that we don't mistake $1/r$ for $1/(r+1)$, it suffices to use enough precision to guarantee that a best approximation $y/2^m$ to $1/r$ is closer to $1/r$ than it is to $1/(r+1)$.\n", + "If we use enough precision so that\n", + "\n", + "$$\n", + "\\left\\vert\n", + "\\frac{y}{2^m} - \\frac{1}{r}\n", + "\\right\\vert\n", + "< \\frac{1}{2 r (r+1)},\n", + "$$\n", + "\n", + "so that the error is less than half of the distance between $1/r$ and $1/(r+1)$, then $y/2^m$ will be closer to $1/r$ than to any other possibility, including $1/(r+1)$ and $1/(r-1)$.\n", + "\n", + "We can double-check this as follows.\n", + "Suppose that \n", + "\n", + "$$\n", + "\\frac{y}{2^m} = \\frac{1}{r} + \\varepsilon\n", + "$$\n", + "\n", + "for $\\varepsilon$ satisfying\n", + "\n", + "$$\n", + "\\vert\\varepsilon\\vert < \\frac{1}{2 r (r+1)}.\n", + "$$\n", + "\n", + "When we take the reciprocal we obtain\n", + "\n", + "$$\n", + "\\frac{2^m}{y} = \\frac{1}{\\frac{1}{r} + \\varepsilon} = \\frac{r}{1+\\varepsilon r} = r - \\frac{\\varepsilon r^2}{1+\\varepsilon r}.\n", + "$$\n", + "\n", + "By maximizing in the numerator and minimizing in the denominator, we can bound how far away we are from $r$ as follows.\n", + "\n", + "$$\n", + "\\left\\vert\n", + "\\frac{\\varepsilon r^2}{1+\\varepsilon r}\n", + "\\right\\vert\n", + "\\leq \\frac{ \\frac{r^2}{2 r(r+1)}}{1 - \\frac{r}{2r(r+1)}}\n", + "%= \\frac{r^2}{2 r (r+1) - r}\n", + "= \\frac{r}{2 r + 1}\n", + "< \\frac{1}{2}\n", + "$$\n", + "\n", + "We're less than $1/2$ away from $r$, so as expected we'll get $r$ when we round.\n", + "\n", + "Unfortunately, because we don't yet know what $r$ is, we can't use it to tell us how much accuracy we need.\n", + "What we can do instead is to use the fact that $r$ must be smaller than $N$ to ensure that we use enough precision.\n", + "In particular, if we use enough accuracy to guarantee that the best approximation $y/2^m$ to $1/r$ satisfies\n", + "\n", + "$$\n", + "\\left\\vert \\frac{y}{2^m} - \\frac{1}{r} \\right\\vert \\leq \\frac{1}{2N^2},\n", + "$$\n", + "\n", + "then we'll have enough precision to correctly determine $r$ when we take the reciprocal.\n", + "Taking $m = 2\\operatorname{lg}(N)+1$ ensures that we have a high chance to obtain an estimation with this precision using the method described previously.\n", + "(Taking $m = 2\\operatorname{lg}(N)$ is good enough if we're comfortable with a lower-bound of 40% on the probability of success.)" + ] + }, + { + "cell_type": "markdown", + "id": "8f67a3de", + "metadata": {}, + "source": [ + "#### Other eigenvector/eigenvalue pairs\n", + "\n", + "As we just saw, if we had the eigenvector $\\vert \\psi_1 \\rangle$ of $M_a$, we would be able to learn $r$ through phase estimation, so long as we use enough control qubits to get sufficient precision to do this.\n", + "Unfortunately it's not easy to get our hands on the eigenvector $\\vert\\psi_1\\rangle$, so we need to figure out how to proceed.\n", + "\n", + "Let's suppose we proceed just like we did above, except with the eigenvector $\\vert\\psi_k\\rangle$ in place of $\\vert\\psi_1\\rangle$, for any choice of $k\\in\\{0,\\ldots,r-1\\}$ that we choose to think about.\n", + "The result we get from the phase estimation procedure will be an approximation\n", + "\n", + "$$\n", + "\\frac{y}{2^m} \\approx \\frac{k}{r}.\n", + "$$\n", + "\n", + "Working under the assumption that we don't know either $k$ or $r$, this might or might not allow us to identify $r$.\n", + "For example, if $k = 0$ we'll get an approximation $y/2^m$ to $0$, which unfortunately tells us nothing.\n", + "This, however, is an unusual case; for other values of $k$, we'll at least be able to learn something about $r$.\n", + "\n", + "We can use an algorithm known as the *continued fraction algorithm* to turn our approximation $y/2^m$ into nearby fractions — including $k/r$ if the approximation is good enough.\n", + "We won't explain the continued fraction algorithm here.\n", + "Instead, here's a statement of a known fact about this algorithm.\n", + "\n", + "\n", + "\n", + "\n", + "**Fact**\n", + "\n", + "Given an integer $N\\geq 2$ and a real number $\\alpha\\in(0,1)$, there is at most choice of integers $u,v\\in\\{0,\\ldots,N-1\\}$ with $v\\neq 0$ and $\\gcd(u,v)=1$ satisfying $\\vert \\alpha - u/v\\vert < \\frac{1}{2N^2}$.\n", + "\n", + "Given $\\alpha$ and $N$, the *continued fraction algorithm* finds $u$ and $v$ (or reports that they don't exist). \n", + "\n", + "This algorithm can be implemented as a Boolean circuit having size $O((\\operatorname{lg}(N))^3)$.\n", + "\n", + "\n", + "\n", + "If we have a very close approximation $y/2^m$ to $r/k$, and we run the continued fraction algorithm for $N$ and $\\alpha = y/2^m$, we'll get $u$ and $v$, as they're described in the fact.\n", + "A careful reading of the fact allows us to conclude that\n", + "\n", + "$$\n", + "\\frac{u}{v} = \\frac{k}{r}.\n", + "$$\n", + "\n", + "So we don't necessarily learn $k$ and $r$, we only learn $k/r$ in lowest terms.\n", + "\n", + "For example, and as we've already noticed, we're not going to learn anything from $k=0$.\n", + "But that's the only value of $k$ where that happens.\n", + "When $k$ is nonzero, it might have common factors with $r$ — but the number $v$ we obtain from the continued fraction algorithm must divide $r$.\n", + "\n", + "It's far from obvious, but it is a known fact that if we have the ability to learn $u$ and $v$ for $u/v = k/r$ for $k\\in\\{0,\\ldots,r-1\\}$ chosen *uniformly at random*, then we're very likely to recover $r$ after just a few samples.\n", + "In particular, if our guess for $r$ is the *least common multiple* of all the values for $v$ that we observe, we'll be right with high probability.\n", + "Some values of $k$ aren't good because they share common factors with $r$, and those common factors are hidden to us when we learn $u$ and $v$.\n", + "But *random* choices of $k$ aren't likely to hide factors of $r$ for long, and the probability that we don't guess $r$ correctly drops exponentially in the number of samples." + ] + }, + { + "cell_type": "markdown", + "id": "697531be", + "metadata": {}, + "source": [ + "#### Proceeding without an eigenvector\n", + "\n", + "So far we haven't addressed the issue of how we get our hands on an eigenvector $\\vert\\psi_k\\rangle$ of $M_a$ to run the phase estimation procedure on.\n", + "As it turns out, we don't need to create them.\n", + "What we will do instead is to run the phase estimation procedure on the state $\\vert 1\\rangle$, by which we mean the $n$-bit binary encoding of the number $1$, in place of an eigenvector $\\vert\\psi\\rangle$ of $M_a$.\n", + "\n", + "So far, we've talked about running the phase estimation procedure on a particular eigenvector, but nothing prevents us from running the procedure on an input state that isn't an eigenvector of $M_a$, and that's what we're doing here with the state $\\vert 1\\rangle$.\n", + "(This isn't an eigenvector of $M_a$ for $a\\in\\mathbb{Z}_N^{\\ast}$ unless $a=1$, which is a choice for $a$ that we'll avoid.)\n", + "\n", + "The following equation helps to explain why we choose the state $\\vert 1\\rangle$ in place of an eigenvector.\n", + "\n", + "$$\n", + "\\vert 1\\rangle = \\frac{1}{\\sqrt{r}} \\sum_{k = 0}^{r-1} \\vert \\psi_k\\rangle\n", + "$$\n", + "\n", + "This can be verified by taking the inner product of the right-hand side with standard basis states and using formulas mentioned previously.\n", + "\n", + "In greater detail, let's imagine that we run the phase estimation procedure with the state $\\vert 1\\rangle$ in place of one of the eigenvectors $\\vert\\psi_k\\rangle$.\n", + "After the quantum Fourier transform is performed, this leaves us with the state\n", + "\n", + "$$\n", + "\\frac{1}{\\sqrt{r}} \\sum_{k = 0}^{r-1} \\vert \\psi_k\\rangle \\vert \\gamma_k\\rangle,\n", + "$$\n", + "\n", + "where\n", + "\n", + "$$\n", + "\\vert\\gamma_k\\rangle = \n", + "\\frac{1}{2^m} \\sum_{y=0}^{2^m - 1} \\sum_{x=0}^{2^m-1} e^{2\\pi i x (k/r - y/2^m)} \\vert y\\rangle\n", + "$$\n", + "\n", + "represents the state of the top $m$ qubits after the inverse of the quantum Fourier transform is performed.\n", + "When the top $m$ qubits are measured, we therefore obtain an approximation $y/2^m$ to the value $k/r$ where $k\\in\\{0,\\ldots,r-1\\}$ is chosen uniformly at random.\n", + "\n", + "As we've already discussed, this allows us to learn $r$ with a high degree of confidence after several independent runs, which was our goal." + ] + }, + { + "cell_type": "markdown", + "id": "342f425e", + "metadata": {}, + "source": [ + "#### Total cost\n", + "\n", + "The cost to implement each controlled-unitary $M_a^k$ is $O(n^2)$.\n", + "There are $m$ controlled-unitary operations, so the total cost for the controlled-unitary operations is $O(n^3)$.\n", + "In addition, we have $m$ Hadamard gates (which contribute $O(n)$ to the cost), and the quantum Fourier transform contributes $O(n^2)$ to the cost.\n", + "Thus, the cost of the controlled-unitary operations dominates the cost of the entire procedure — which is therefore $O(n^3)$.\n", + "\n", + "In addition to the quantum circuit itself, there are a few classical computations that need to be performed along the way.\n", + "This includes computing the powers $a^k$ in $\\mathbb{Z}_N$ for $k = 2, 4, 8, \\ldots, 2^{m-1}$, which are needed to create the controlled-unitary gates, as well as the continued fraction algorithm that converts approximations of $\\theta$ into fractions.\n", + "In both cases, these computations can be performed by Boolean circuits having cost $O(n^3)$.\n", + "\n", + "As is typical, all of these bounds can be improved using asymptotically fast algorithms; these bounds assume we're using standard algorithms for basic arithmetic operations." + ] + }, + { + "cell_type": "markdown", + "id": "5259f80f", + "metadata": {}, + "source": [ + "### Factoring by order-finding\n", + "\n", + "The very last thing we need to discuss is how solving the order-finding problem helps us to factor.\n", + "This part is completely classical — it has nothing specifically to do with quantum computing.\n", + "\n", + "Here's the basic idea.\n", + "We want to factorize the number $N$, and we can do this *recursively*.\n", + "Specifically, we can focus on the task of *splitting* $N$, which means finding any two integers $b,c\\geq 2$ for which $N = bc$. \n", + "This isn't possible if $N$ is a prime number, but we can efficiently test to see if $N$ is prime using a primality testing algorithm first, and if $N$ isn't prime we'll try to split it.\n", + "Once we split $N$, we can simply recurse on $b$ and $c$ until all of our factors are prime and we obtain the prime factorization of $N$.\n", + "\n", + "Splitting even integers is easy: we just output $2$ and $N/2$.\n", + "\n", + "It's also easy to split perfect powers, meaning numbers of the form $N = s^j$ for integers $s,j\\geq 2$, just by \n", + "approximating the roots $N^{1/2}$, $N^{1/3}$, $N^{1/4}$, etc., and checking nearby integers as suspects for $s$.\n", + "We don't need to go further than $\\log(N)$ steps into this sequence, because at that point the root drops below $2$ and won't reveal additional candidates.\n", + "\n", + "It's good that we can do both of these things because order-finding won't help us for even numbers or for *prime* powers, where the number $s$ happens to be prime.\n", + "\n", + "If $N$ is odd and not a prime power, order-finding allows us to split $N$.\n", + "\n", + "\n", + "\n", + "Input an odd, composite integer N that is not a prime power.\n", + "\n", + "Iterate the following steps:\n", + "\n", + "1. Randomly choose $a\\in\\{2,\\ldots,N-1\\}$. \n", + "2. Compute $d=\\gcd(a,N)$.\n", + "3. If $d > 1$ then output $b = d$ and $c = N/d$ and stop. Otherwise continue to the next step knowing that $a\\in\\mathbb{Z}_N^{\\ast}$.\n", + "4. Let $r$ be the order of $a$ modulo $N$. (Here's where we need order-finding.) \n", + "5. If $r$ is even: \\\n", + " 5.1 Compute $x = a^{r/2} - 1$ (modulo $N$) \\\n", + " 5.2 Compute $d = \\gcd(x,N)$. \\\n", + " 5.3 If $d>1$ then output $b=d$ and $c = N/d$ and stop.\n", + "6. If this point is reached, the iteration has failed to find a factor of $N$.\n", + "\n", + "\n", + "\n", + "An iteration of this algorithm may fail to find a factor of $N$.\n", + "Specifically, this happens in two situations:\n", + "- The order of $a$ modulo $N$ is odd.\n", + "- The order of $a$ modulo $N$ is even and $\\gcd\\bigl(a^{r/2} - 1, N\\bigr) = 1$.\n", + "\n", + "Using basic number theory it can be proved that, for a random choice of $a$, with probability at least $1/2$ neither of these events happens.\n", + "In fact, the probability is at most $2^{-(m-1)}$ for $m$ being the number of distinct prime factors of $N$.\n", + "This is why the assumption that $N$ is not a prime power is important.\n", + "The assumption that $N$ is odd is also required for this to be true, which is why the (easy) case that $N$ is even has to be handled separately.\n", + "\n", + "So, if we repeat the process $t$ times, randomly choosing $a$ each time, we'll succeed in splitting $N$ with probability at least $1 - 2^{-t}$.\n", + "\n", + "We won't go through this analysis in detail, but here's the basic idea.\n", + "If we have a choice of $a$ for which the order $r$ of $a$ modulo $N$ is even, then it makes sense to consider the\n", + "numbers\n", + "\n", + "$$\n", + "a^{r/2} - 1\\; (\\textrm{mod}\\; N) \\quad \\text{and} \\quad a^{r/2} + 1\\; (\\textrm{mod}\\; N).\n", + "$$\n", + "\n", + "Using the formula $Z^2 - 1 = (Z+1)(Z-1)$, we conclude that\n", + "\n", + "$$\n", + "\\bigl(a^{r/2} - 1\\bigr) \\bigl(a^{r/2} + 1\\bigr) = a^r - 1.\n", + "$$\n", + "\n", + "We know that $a^r \\; (\\textrm{mod}\\; N) = 1$ by the definition of the order, which is another way of saying that\n", + "$N$ evenly divides $a^r - 1$.\n", + "So, $N$ evenly divides the number\n", + "\n", + "$$\n", + "\\bigl(a^{r/2} - 1\\bigr) \\bigl(a^{r/2} + 1\\bigr),\n", + "$$\n", + "\n", + "which means that every prime factor of $N$ must divide either $a^{r/2} - 1$ or $a^{r/2} + 1$ (or both).\n", + "For a randomly selected $a$, we're likely to have prime factors of $N$ dividing both terms, which allows us to split $N$ by computing the GCD." + ] + }, + { + "cell_type": "markdown", + "id": "e31d3e27", + "metadata": {}, + "source": [ + "### Implementation in Qiskit\n", + "\n", + "Here we'll implement Shor's algorithm in Qiskit to factor number $15$.\n", + "First we'll hard code a controlled-multiplication operation for a given element $a\\in\\mathbb{Z}_{15}^{\\ast}$." + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "id": "708b8242", + "metadata": {}, + "outputs": [], + "source": [ + "def c_amod15(a):\n", + " \"\"\"\n", + " Controlled multiplication by a mod 15.\n", + " This is hard-coded for simplicity.\n", + " \"\"\"\n", + " if a not in [2,4,7,8,11,13]:\n", + " raise ValueError(\"'a' must not have common factors with 15\")\n", + " U = QuantumCircuit(4)\n", + " if a in [2,13]:\n", + " U.swap(2,3)\n", + " U.swap(1,2)\n", + " U.swap(0,1)\n", + " if a in [7,8]:\n", + " U.swap(0,1)\n", + " U.swap(1,2)\n", + " U.swap(2,3)\n", + " if a in [4, 11]:\n", + " U.swap(1,3)\n", + " U.swap(0,2)\n", + " if a in [7,11,13]:\n", + " for q in range(4):\n", + " U.x(q)\n", + " U = U.to_gate()\n", + " U.name = f\"{a} mod 15\"\n", + " c_U = U.control()\n", + " return c_U" + ] + }, + { + "cell_type": "markdown", + "id": "952577bc", + "metadata": {}, + "source": [ + "Here's the phase estimation procedure from earlier implemented as a function." + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "id": "09cc6893", + "metadata": {}, + "outputs": [], + "source": [ + "def phase_estimation(\n", + " controlled_operation: QuantumCircuit,\n", + " psi_prep: QuantumCircuit,\n", + " precision: int\n", + " ):\n", + " \"\"\"\n", + " Carry out phase estimation on a simulator.\n", + " Args:\n", + " controlled_operation: The operation to perform phase estimation on,\n", + " controlled by one qubit.\n", + " psi_prep: Circuit to prepare |ψ>\n", + " precision: Number of counting qubits to use\n", + " Returns:\n", + " float: Best guess for phase of U|ψ>\n", + " \"\"\"\n", + " control_register = QuantumRegister(precision)\n", + " output_register = ClassicalRegister(precision)\n", + " \n", + " target_register = QuantumRegister(psi_prep.num_qubits)\n", + " qc = QuantumCircuit(control_register, target_register, output_register)\n", + "\n", + " # Prepare |ψ>\n", + " qc.compose(psi_prep,\n", + " qubits=target_register,\n", + " inplace=True)\n", + "\n", + " # Do phase estimation\n", + " for index, qubit in enumerate(control_register):\n", + " qc.h(qubit)\n", + " for _ in range(2**index):\n", + " qc.compose(\n", + " controlled_operation,\n", + " qubits=[qubit] + list(target_register),\n", + " inplace=True\n", + " )\n", + "\n", + " qc.compose(\n", + " QFT(precision, inverse=True),\n", + " qubits=control_register,\n", + " inplace=True\n", + " )\n", + "\n", + " qc.measure(control_register, output_register)\n", + " \n", + " measurement = Sampler().run(qc, shots=1).result().quasi_dists[0].popitem()[0]\n", + " return measurement / 2**precision" + ] + }, + { + "cell_type": "markdown", + "id": "d9c82f40", + "metadata": {}, + "source": [ + "We can't easily prepare eigenvectors of the multiplication by $a\\in\\mathbb{Z}_{15}^{\\ast}$ operation, so we use $\\vert 1\\rangle$ as suggested above." + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "id": "0acc851d", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 15, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "psi_prep = QuantumCircuit(4)\n", + "psi_prep.x(0)" + ] + }, + { + "cell_type": "markdown", + "id": "35181600", + "metadata": {}, + "source": [ + "And finally we can run the circuit to try to find a nontrivial factor of $15$." + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "id": "1d1e7c7b", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "Attempt 1\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "Attempt 2\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Non-trivial factor found: 3\n" + ] + } + ], + "source": [ + "from fractions import Fraction\n", + "from math import gcd\n", + "\n", + "a = 8\n", + "N = 15\n", + "\n", + "FACTOR_FOUND = False\n", + "ATTEMPT = 0\n", + "while not FACTOR_FOUND:\n", + " ATTEMPT += 1\n", + " print(f\"\\nAttempt {ATTEMPT}\")\n", + " \n", + " phase = phase_estimation(\n", + " c_amod15(a),\n", + " psi_prep,\n", + " precision=8\n", + " )\n", + " frac = Fraction(phase).limit_denominator(N)\n", + " r = frac.denominator\n", + " if phase != 0:\n", + " # Guess for a factor is gcd(x^{r/2} - 1 , 15)\n", + " guess = gcd(a**(r//2)-1, N)\n", + " if guess not in [1,N] and (N % guess) == 0:\n", + " # Guess is a factor!\n", + " print(f\"Non-trivial factor found: {guess}\")\n", + " FACTOR_FOUND = True " + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "id": "37933870", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "

Version Information

Qiskit SoftwareVersion
qiskit-terra0.24.1
qiskit-aer0.12.1
qiskit-ibmq-provider0.20.2
qiskit0.43.2
qiskit-nature0.6.0
qiskit-finance0.3.4
qiskit-optimization0.5.0
qiskit-machine-learning0.6.1
System information
Python version3.10.11
Python compilerClang 14.0.0 (clang-1400.0.29.202)
Python buildmain, Apr 7 2023 07:31:31
OSDarwin
CPUs8
Memory (Gb)32.0
Tue Jul 18 12:32:18 2023 BST
" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# pylint: disable=unused-import\n", + "import qiskit.tools.jupyter\n", + "%qiskit_version_table" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/notebooks/toc.yaml b/notebooks/toc.yaml index 9245e9f..b397f2e 100644 --- a/notebooks/toc.yaml +++ b/notebooks/toc.yaml @@ -169,7 +169,15 @@ - title: Quantum query algorithms id: query-algorithms uuid: f236ed68-91f2-470a-8152-29f09e60a30c - url: /algorithms/quantum-query-algorithms + url: /algorithms/01.query-algorithms/quantum-query-algorithms + - title: Algorithmic foundations + id: algorithmic-foundations + uuid: 00b26932-7d64-436c-86a9-56091c0419ac + url: /algorithms/02.algorithmic-foundations/algorithmic-foundations + - title: Phase estimation + id: phase-estimation + uuid: b49f2ca0-240d-417a-8f51-a6288d504ca3 + url: /algorithms/03.phase-estimation/phase-estimation-and-factoring - title: Introduction to Quantum Computing id: introduction-course