From 66a68f1c99604820b266be4357680c4222c7cf0d Mon Sep 17 00:00:00 2001 From: EC2 Default User Date: Wed, 3 Aug 2022 18:30:22 +0000 Subject: [PATCH 1/5] add deutsch jozsa aglorithm --- .../Deutsch Jozsa Algorithm.ipynb | 909 ++++++++++++++++++ 1 file changed, 909 insertions(+) create mode 100644 examples/advanced_circuits_algorithms/Deutsch_Jozsa_Algorithm/Deutsch Jozsa Algorithm.ipynb diff --git a/examples/advanced_circuits_algorithms/Deutsch_Jozsa_Algorithm/Deutsch Jozsa Algorithm.ipynb b/examples/advanced_circuits_algorithms/Deutsch_Jozsa_Algorithm/Deutsch Jozsa Algorithm.ipynb new file mode 100644 index 000000000..8dfbbc2ba --- /dev/null +++ b/examples/advanced_circuits_algorithms/Deutsch_Jozsa_Algorithm/Deutsch Jozsa Algorithm.ipynb @@ -0,0 +1,909 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 322, + "id": "2ae735a6", + "metadata": {}, + "outputs": [], + "source": [ + "# general imports\n", + "import matplotlib.pyplot as plt\n", + "# magic word for producing visualizations in notebook\n", + "%matplotlib inline\n", + "import string\n", + "import time\n", + "import numpy as np\n", + "import random\n", + "from scipy.linalg import expm\n", + "\n", + "# AWS imports: Import Braket SDK modules\n", + "from braket.circuits import Circuit, Gate, Observable\n", + "from braket.devices import LocalSimulator\n", + "from braket.aws import AwsDevice" + ] + }, + { + "cell_type": "code", + "execution_count": 323, + "id": "e8a92069", + "metadata": {}, + "outputs": [], + "source": [ + "# function to initialize the input qubits and output qubit\n", + "\n", + "def init_states(n_qubits): \n", + " \n", + " # define the output qubit\n", + " output_qubit = n_qubits \n", + " \n", + " # create circuit and initialize states\n", + " circuit = Circuit().h(range(n_qubits)).x(output_qubit).h(output_qubit)\n", + " \n", + " return circuit" + ] + }, + { + "cell_type": "code", + "execution_count": 324, + "id": "c2b97565", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "T : |0|1|\n", + " \n", + "q0 : -H---\n", + " \n", + "q1 : -H---\n", + " \n", + "q2 : -H---\n", + " \n", + "q3 : -X-H-\n", + "\n", + "T : |0|1|\n" + ] + } + ], + "source": [ + "# example circuit initializition for 3 qubits \n", + "n_qubits = 3\n", + "init = init_states(n_qubits)\n", + "print(init)" + ] + }, + { + "cell_type": "code", + "execution_count": 325, + "id": "e4be33e5", + "metadata": {}, + "outputs": [], + "source": [ + "# function to create a constant oracle \n", + "\n", + "def constant_oracle(n_qubits):\n", + " \n", + " # define the output qubit \n", + " output_qubit = n_qubits \n", + " \n", + " # create circuit \n", + " circuit = Circuit()\n", + " \n", + " # set output to either 0 or 1 \n", + " rand_output = np.random.randint(0, 2)\n", + " \n", + " # if output qubit is 0, apply i gate to not change value \n", + " if rand_output == 0:\n", + " circuit.i(output_qubit)\n", + " # if output is 1, apply x gate to change value to 0 \n", + " if rand_output == 1: \n", + " circuit.x(output_qubit)\n", + " \n", + " return circuit" + ] + }, + { + "cell_type": "code", + "execution_count": 326, + "id": "35c4e846", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "T : |0|\n", + " \n", + "q5 : -I-\n", + "\n", + "T : |0|\n" + ] + } + ], + "source": [ + "# example circuit for constant oracle \n", + "n_qubits = 5\n", + "const = constant_oracle(n_qubits)\n", + "print(const) " + ] + }, + { + "cell_type": "code", + "execution_count": 327, + "id": "dd0362f5", + "metadata": {}, + "outputs": [], + "source": [ + "# function to create a balanced oracle \n", + "\n", + "def balanced_oracle(n_qubits): \n", + " \n", + " # define the output qubit \n", + " output_qubit = n_qubits \n", + " \n", + " # create circuit \n", + " circuit = Circuit()\n", + " \n", + " # generate a random array of 0s and 1s to figure out where to place x gates\n", + " random_num = np.random.randint(2, size=n_qubits)\n", + " \n", + " # place x gates \n", + " for qubit in range(len(random_num)):\n", + " if random_num[qubit] == 1:\n", + " circuit.x(qubit) \n", + " \n", + " # place cnot gates\n", + " for qubit in range(n_qubits):\n", + " circuit.cnot(control=qubit, target=output_qubit)\n", + " \n", + " # place x gates \n", + " for qubit in range(len(random_num)): \n", + " if random_num[qubit] == 1:\n", + " circuit.x(qubit)\n", + " \n", + " return circuit" + ] + }, + { + "cell_type": "code", + "execution_count": 328, + "id": "e6ac4231", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "T : |0|1|2|3|4|5|6|7|8|9|10|11|\n", + " \n", + "q0 : -X-C-X---------------------\n", + " | \n", + "q1 : -X-|-C-X-------------------\n", + " | | \n", + "q2 : ---|-|-C-------------------\n", + " | | | \n", + "q3 : ---|-|-|-C-----------------\n", + " | | | | \n", + "q4 : -X-|-|-|-|-C-X-------------\n", + " | | | | | \n", + "q5 : -X-|-|-|-|-|-C-X-----------\n", + " | | | | | | \n", + "q6 : ---|-|-|-|-|-|-C-----------\n", + " | | | | | | | \n", + "q7 : ---|-|-|-|-|-|-|-C---------\n", + " | | | | | | | | \n", + "q8 : ---|-|-|-|-|-|-|-|-C-------\n", + " | | | | | | | | | \n", + "q9 : -X-|-|-|-|-|-|-|-|-|-C--X--\n", + " | | | | | | | | | | \n", + "q10 : ---X-X-X-X-X-X-X-X-X-X-----\n", + "\n", + "T : |0|1|2|3|4|5|6|7|8|9|10|11|\n" + ] + } + ], + "source": [ + "# example circuit for balanced oracle\n", + "n_qubits = 10\n", + "bal = balanced_oracle(n_qubits)\n", + "print(bal)" + ] + }, + { + "cell_type": "code", + "execution_count": 329, + "id": "17382baa", + "metadata": {}, + "outputs": [], + "source": [ + "def random_oracle(n_qubits): \n", + " \n", + " # create circuit \n", + " circuit = Circuit()\n", + " \n", + " # define the output qubit \n", + " output_qubit = n_qubits \n", + " \n", + " # create a random array of 0s and 1s to determine where to place the gates\n", + " random_array = np.random.randint(2, size=n_qubits)\n", + " \n", + " # define the single gate set \n", + " single_gate_set = \"x\"\n", + " \n", + " # define the multiple qubit gate set\n", + " multiple_gate_set = [\"cnot\", \"ccnot\"]\n", + " \n", + " # create a list combining single and multiple qubit gates to randomly choose from\n", + " choice_gate_set = [\"single_gate_set\", \"multiple_gate_set\"]\n", + " \n", + " # random oracle circuit generator\n", + " \n", + " circuit = Circuit()\n", + " \n", + " # implement all the gate options \n", + " for qubit in range(len(random_array)):\n", + " \n", + " # randomly choose to apply a single qubit or multiple qubit gate \n", + " random_gate_set = np.random.choice(choice_gate_set, p=[0.30, 0.70])\n", + " \n", + " # if single qubit gate then implement x gate accordingly \n", + " if random_gate_set == \"single_gate_set\": \n", + " if random_array[qubit] == 1:\n", + " circuit.x(qubit)\n", + " \n", + " # if multiple qubit gate then implement cnot and ccnot gates \n", + " if random_gate_set == \"multiple_gate_set\": \n", + " \n", + " # randomly choose to implement a cnot or ccnot gate\n", + " random_gate_m = np.random.choice(multiple_gate_set)\n", + " if random_gate_m == \"cnot\":\n", + " if random_array[qubit] == 0:\n", + " #randomly choose where the target qubit is\n", + " targetf = np.random.randint(n_qubits+1)\n", + " if qubit!= targetf:\n", + " circuit.cnot(control=qubit, target=targetf)\n", + " del targetf\n", + " else: \n", + " #randomly choose where the target qubit is\n", + " targetf = np.random.randint(n_qubits+1)\n", + " circuit.x(qubit)\n", + " if qubit!= targetf:\n", + " circuit.cnot(control=qubit, target=targetf)\n", + " circuit.x(qubit) \n", + " del targetf\n", + " if random_gate_m == \"ccnot\":\n", + " #randomly choose where the first and second controls are\n", + " control1 = np.random.randint(n_qubits+1)\n", + " control2 = np.random.randint(n_qubits+1)\n", + " #randomly choose where the target qubit is\n", + " targetf = np.random.randint(n_qubits+1)\n", + " if control1 != control2 and control1 != targetf and control2 != targetf:\n", + " circuit.ccnot(control1, control2, targetf) \n", + " del control1\n", + " del control2\n", + " del targetf\n", + " \n", + " return circuit" + ] + }, + { + "cell_type": "code", + "execution_count": 330, + "id": "a6d3a71d", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "T : |0|\n", + " \n", + "q1 : -X-\n", + " | \n", + "q3 : -C-\n", + " | \n", + "q4 : -C-\n", + "\n", + "T : |0|\n" + ] + } + ], + "source": [ + "n_qubits = 4 \n", + "random = random_oracle(n_qubits)\n", + "print(random)" + ] + }, + { + "cell_type": "code", + "execution_count": 349, + "id": "54146daa", + "metadata": {}, + "outputs": [], + "source": [ + "# general function for taking an dj-algorithm \n", + "\n", + "def dj_algorithm(case, n_qubits):\n", + " \n", + " # create circuit \n", + " circuit = Circuit()\n", + " \n", + " # define the output qubit \n", + " output_qubit = n_qubits \n", + " \n", + " # create circuit and initialize states\n", + " circuit = Circuit().h(range(n_qubits)).x(output_qubit).h(output_qubit)\n", + " \n", + " # creating a circuit for constant oracle\n", + " if case == \"constant\":\n", + " \n", + " # set output to either 0 or 1 \n", + " rand_output = np.random.randint(0, 2)\n", + " \n", + " # if output qubit is 0, apply i gate to not change value \n", + " if rand_output == 0:\n", + " circuit.i(output_qubit)\n", + " # if output is 1, apply x gate to change value to 0 \n", + " if rand_output == 1: \n", + " circuit.x(output_qubit)\n", + " \n", + " # create a circuit for balanced oracle\n", + " if case == \"balanced\":\n", + " \n", + " # generate a random array of 0s and 1s to figure out where to place x gates\n", + " random_num = np.random.randint(2, size=n_qubits)\n", + " \n", + " # place x gates \n", + " for qubit in range(len(random_num)):\n", + " if random_num[qubit] == 1:\n", + " circuit.x(qubit)\n", + " \n", + " # place cnot gates\n", + " for qubit in range(n_qubits):\n", + " circuit.cnot(control=qubit, target=output_qubit)\n", + " \n", + " # place x gates \n", + " for qubit in range(len(random_num)): \n", + " if random_num[qubit] == 1:\n", + " circuit.x(qubit)\n", + " \n", + " # create a completely random oracle \n", + " if case == \"random\":\n", + " \n", + " # create a random array of 0s and 1s to determine where to place the gates\n", + " random_array = np.random.randint(2, size=n_qubits)\n", + " \n", + " # define the single gate set \n", + " single_gate_set = \"x\"\n", + " \n", + " # define the multiple qubit gate set\n", + " multiple_gate_set = [\"cnot\", \"ccnot\"]\n", + " \n", + " # create a list combining single and multiple qubit gates to randomly choose from\n", + " choice_gate_set = [\"single_gate_set\", \"multiple_gate_set\"]\n", + " \n", + " # random oracle circuit generator\n", + " \n", + " circuit = Circuit()\n", + " \n", + " # implement all the gate options \n", + " for qubit in range(len(random_array)):\n", + " \n", + " # randomly choose to apply a single qubit or multiple qubit gate \n", + " random_gate_set = np.random.choice(choice_gate_set, p=[0.30, 0.70])\n", + " \n", + " # if single qubit gate then implement x gate accordingly \n", + " if random_gate_set == \"single_gate_set\": \n", + " if random_array[qubit] == 1:\n", + " circuit.x(qubit)\n", + " \n", + " # if multiple qubit gate then implement cnot and ccnot gates \n", + " if random_gate_set == \"multiple_gate_set\": \n", + " \n", + " # randomly choose to implement a cnot or ccnot gate\n", + " random_gate_m = np.random.choice(multiple_gate_set)\n", + " if random_gate_m == \"cnot\":\n", + " if random_array[qubit] == 0:\n", + " #randomly choose where the target qubit is\n", + " targetf = np.random.randint(n_qubits+1)\n", + " if qubit!= targetf:\n", + " circuit.cnot(control=qubit, target=targetf)\n", + " del targetf\n", + " else: \n", + " #randomly choose where the target qubit is\n", + " targetf = np.random.randint(n_qubits+1)\n", + " circuit.x(qubit)\n", + " if qubit!= targetf:\n", + " circuit.cnot(control=qubit, target=targetf)\n", + " circuit.x(qubit) \n", + " del targetf\n", + " if random_gate_m == \"ccnot\":\n", + " #randomly choose where the first and second controls are\n", + " control1 = np.random.randint(n_qubits+1)\n", + " control2 = np.random.randint(n_qubits+1)\n", + " #randomly choose where the target qubit is\n", + " targetf = np.random.randint(n_qubits+1)\n", + " if control1 != control2 and control1 != targetf and control2 != targetf:\n", + " circuit.ccnot(control1, control2, targetf) \n", + " del control1\n", + " del control2\n", + " del targetf\n", + " \n", + " # place the h-gates again\n", + " circuit.h(range(n_qubits))\n", + " \n", + " # measure the results\n", + " for qubit in range(n_qubits):\n", + " circuit.sample(observable=Observable.Z(), target=qubit)\n", + " Shots = 10\n", + " #Designate the device being used as the local simulator\n", + " #Feel free to use another device\n", + " device = LocalSimulator()\n", + " #Submit the task\n", + " my_task = device.run(circuit, shots=Shots)\n", + " #Retrieve the result\n", + " result = my_task.result()\n", + " #print the measurement probabilities\n", + " print('Measurement results:\\n',result.measurement_probabilities) \n", + " \n", + " return circuit\n", + " " + ] + }, + { + "cell_type": "code", + "execution_count": 350, + "id": "6ae43cd7", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Measurement results:\n", + " {'11110': 0.7, '11111': 0.3}\n", + "T : |0|1|2|3|4|5|6|Result Types|\n", + " \n", + "q0 : -H---C-H-------Sample(Z)----\n", + " | \n", + "q1 : -H---|-C-H-----Sample(Z)----\n", + " | | \n", + "q2 : -H-X-|-|-C-X-H-Sample(Z)----\n", + " | | | \n", + "q3 : -H---|-|-|-C-H-Sample(Z)----\n", + " | | | | \n", + "q4 : -X-H-X-X-X-X----------------\n", + "\n", + "T : |0|1|2|3|4|5|6|Result Types|\n" + ] + } + ], + "source": [ + "n_qubits = 4\n", + "dj = dj_algorithm(\"balanced\", n_qubits)\n", + "print(dj)" + ] + }, + { + "cell_type": "code", + "execution_count": 351, + "id": "755c1cf7", + "metadata": {}, + "outputs": [], + "source": [ + "# run initialized states through circuit and add random_oracle \n", + "def classical_checker(n_qubits):\n", + " \n", + " # define the output qubit \n", + " output_qubit = n_qubits \n", + "\n", + " n = n_qubits\n", + " \n", + " matrix = []\n", + " \n", + " for i in range(0, 2**n):\n", + " # convert integer to bitstring and into an integer\n", + " bit_str = [int(x) for x in str(format(i, \"b\"))]\n", + " # if len of bitstring less than n then pad with zeros\n", + " if len(bit_str) < n:\n", + " num_zero = n - len(bit_str)\n", + " bit_str = np.pad(bit_str, (num_zero, 0), 'constant')\n", + " # append bit_str to matrix \n", + " matrix.append(bit_str)\n", + " \n", + " # turn matix into an numpy array\n", + " matrix_bitout = np.array(matrix)\n", + " # create a random array of 0s and 1s to determine where to place the gates\n", + " random_array = np.random.randint(2, size=n_qubits)\n", + " \n", + " # define the single gate set \n", + " single_gate_set = \"x\"\n", + " \n", + " # define the multiple qubit gate set\n", + " multiple_gate_set = [\"cnot\", \"ccnot\"]\n", + " \n", + " # create a list combining single and multiple qubit gates to randomly choose from\n", + " choice_gate_set = [\"single_gate_set\", \"multiple_gate_set\"]\n", + " \n", + " # random oracle circuit generator\n", + " \n", + " random_circuit = Circuit()\n", + " \n", + " # implement all the gate options \n", + " for qubit in range(len(random_array)):\n", + " \n", + " # randomly choose to apply a single qubit or multiple qubit gate \n", + " random_gate_set = np.random.choice(choice_gate_set, p=[0.30, 0.70])\n", + " \n", + " # if single qubit gate then implement x gate accordingly \n", + " if random_gate_set == \"single_gate_set\": \n", + " if random_array[qubit] == 1:\n", + " random_circuit.x(qubit)\n", + " \n", + " # if multiple qubit gate then implement cnot and ccnot gates \n", + " if random_gate_set == \"multiple_gate_set\": \n", + " \n", + " # randomly choose to implement a cnot or ccnot gate\n", + " random_gate_m = np.random.choice(multiple_gate_set)\n", + " if random_gate_m == \"cnot\":\n", + " if random_array[qubit] == 0:\n", + " #randomly choose where the target qubit is\n", + " targetf = np.random.randint(n_qubits+1)\n", + " if qubit!= targetf:\n", + " random_circuit.cnot(control=qubit, target=targetf)\n", + " del targetf\n", + " else: \n", + " #randomly choose where the target qubit is\n", + " targetf = np.random.randint(n_qubits+1)\n", + " random_circuit.x(qubit)\n", + " if qubit!= targetf:\n", + " random_circuit.cnot(control=qubit, target=targetf)\n", + " random_circuit.x(qubit) \n", + " del targetf\n", + " if random_gate_m == \"ccnot\":\n", + " #randomly choose where the first and second controls are\n", + " control1 = np.random.randint(n_qubits+1)\n", + " control2 = np.random.randint(n_qubits+1)\n", + " #randomly choose where the target qubit is\n", + " targetf = np.random.randint(n_qubits+1)\n", + " if control1 != control2 and control1 != targetf and control2 != targetf:\n", + " random_circuit.ccnot(control1, control2, targetf) \n", + " del control1\n", + " del control2\n", + " del targetf\n", + " \n", + " \n", + " measurement_results_classical = []\n", + " \n", + " \n", + " for row in matrix_bitout:\n", + " circuit = Circuit()\n", + " #retrieve the bit string that initializes the qubits for this iteration\n", + " qubit_info = row.tolist()\n", + " print(qubit_info) \n", + " # creating initial states of our classical circuit\n", + " for qubit in range(len(qubit_info)):\n", + " if qubit_info[qubit] == 1:\n", + " circuit.x(qubit)\n", + " else: \n", + " circuit.i(qubit)\n", + " # adding random circuit to our initial states \n", + " circuit.add_circuit(random_circuit, range(n_qubits))\n", + " circuit.sample(observable=Observable.Z(), target=output_qubit)\n", + " print(circuit)\n", + " \n", + " Shots = 1\n", + " #Designate the device being used as the local simulator\n", + " #Feel free to use another device\n", + " device = LocalSimulator()\n", + " #Submit the task\n", + " my_task = device.run(circuit, shots=Shots)\n", + " \n", + " #Retrieve the result\n", + " result = my_task.result()\n", + " #print the measurement probabilities\n", + " print('Measurement results:\\n',result.measurement_probabilities)\n", + " del circuit\n", + " \n", + " # store results in a measurement variable \n", + " measurement_classical = result.measurement_probabilities\n", + " for k, v in measurement_classical.items(): \n", + " int(k)\n", + " measurement_list = (list(k))\n", + " measurement_results_classical.append(measurement_list)\n", + " # classical checker circuits \n", + " classical_results = np.array(measurement_results_classical)\n", + " final_rc = []\n", + " for row in classical_results: \n", + " result = int(row[-1])\n", + " final_rc.append(result)\n", + " \n", + " total_rc = len(final_rc)\n", + " count_0 = 0\n", + " count_1 = 0\n", + " \n", + " for val in final_rc:\n", + " if val == 0: \n", + " count_0 += 1\n", + " if val == 1:\n", + " count_1 += 1\n", + " \n", + " if total_rc == count_0: \n", + " print(\"This is a constant function\")\n", + " \n", + " elif count_0 == total_rc/2 and count_1 == total_rc/2: \n", + " print(\"This is a balanced function\")\n", + " else:\n", + " print(\"This is neither a constant nor balanced function\")\n", + " \n", + " \n", + " print(\"These are the final outputs from the random circuits\", final_rc)\n", + " return random_circuit" + ] + }, + { + "cell_type": "code", + "execution_count": 352, + "id": "0c2c1cec", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[0, 0, 0]\n", + "T : |0|1|Result Types|\n", + " \n", + "q0 : -I-X--------------\n", + " \n", + "q1 : -I----------------\n", + " \n", + "q2 : -I----------------\n", + " \n", + "q3 : -----Sample(Z)----\n", + "\n", + "T : |0|1|Result Types|\n", + "Measurement results:\n", + " {'1000': 1.0}\n", + "[0, 0, 1]\n", + "T : |0|1|Result Types|\n", + " \n", + "q0 : -I-X--------------\n", + " \n", + "q1 : -I----------------\n", + " \n", + "q2 : -X----------------\n", + " \n", + "q3 : -----Sample(Z)----\n", + "\n", + "T : |0|1|Result Types|\n", + "Measurement results:\n", + " {'1010': 1.0}\n", + "[0, 1, 0]\n", + "T : |0|1|Result Types|\n", + " \n", + "q0 : -I-X--------------\n", + " \n", + "q1 : -X----------------\n", + " \n", + "q2 : -I----------------\n", + " \n", + "q3 : -----Sample(Z)----\n", + "\n", + "T : |0|1|Result Types|\n", + "Measurement results:\n", + " {'1100': 1.0}\n", + "[0, 1, 1]\n", + "T : |0|1|Result Types|\n", + " \n", + "q0 : -I-X--------------\n", + " \n", + "q1 : -X----------------\n", + " \n", + "q2 : -X----------------\n", + " \n", + "q3 : -----Sample(Z)----\n", + "\n", + "T : |0|1|Result Types|\n", + "Measurement results:\n", + " {'1110': 1.0}\n", + "[1, 0, 0]\n", + "T : |0|1|Result Types|\n", + " \n", + "q0 : -X-X--------------\n", + " \n", + "q1 : -I----------------\n", + " \n", + "q2 : -I----------------\n", + " \n", + "q3 : -----Sample(Z)----\n", + "\n", + "T : |0|1|Result Types|\n", + "Measurement results:\n", + " {'0000': 1.0}\n", + "[1, 0, 1]\n", + "T : |0|1|Result Types|\n", + " \n", + "q0 : -X-X--------------\n", + " \n", + "q1 : -I----------------\n", + " \n", + "q2 : -X----------------\n", + " \n", + "q3 : -----Sample(Z)----\n", + "\n", + "T : |0|1|Result Types|\n", + "Measurement results:\n", + " {'0010': 1.0}\n", + "[1, 1, 0]\n", + "T : |0|1|Result Types|\n", + " \n", + "q0 : -X-X--------------\n", + " \n", + "q1 : -X----------------\n", + " \n", + "q2 : -I----------------\n", + " \n", + "q3 : -----Sample(Z)----\n", + "\n", + "T : |0|1|Result Types|\n", + "Measurement results:\n", + " {'0100': 1.0}\n", + "[1, 1, 1]\n", + "T : |0|1|Result Types|\n", + " \n", + "q0 : -X-X--------------\n", + " \n", + "q1 : -X----------------\n", + " \n", + "q2 : -X----------------\n", + " \n", + "q3 : -----Sample(Z)----\n", + "\n", + "T : |0|1|Result Types|\n", + "Measurement results:\n", + " {'0110': 1.0}\n", + "This is a constant function\n", + "These are the final outputs from the random circuits [0, 0, 0, 0, 0, 0, 0, 0]\n" + ] + } + ], + "source": [ + "n_qubits = 3\n", + "run_circuit = classical_checker(n_qubits)" + ] + }, + { + "cell_type": "code", + "execution_count": 353, + "id": "765c5d73", + "metadata": {}, + "outputs": [], + "source": [ + "def random_oracle(n_qubits,random_circuit):\n", + " # create circuit \n", + " circuit2 = Circuit()\n", + " \n", + " # define the output qubit \n", + " output_qubit = n_qubits \n", + " \n", + " # create circuit and initialize states\n", + " circuit2 = Circuit().h(range(n_qubits)).x(output_qubit).h(output_qubit)\n", + " #add the random oracle to this circuit\n", + " circuit2.add_circuit(random_circuit, range(n_qubits))\n", + " # place the h-gates again\n", + " circuit2.h(range(n_qubits))\n", + " \n", + " measurement_results_quantum = []\n", + " \n", + " # measure the results\n", + " for qubit in range(n_qubits):\n", + " circuit2.sample(observable=Observable.Z(), target=qubit)\n", + " print(circuit2)\n", + " Shots = 100\n", + " #Designate the device being used as the local simulator\n", + " #Feel free to use another device\n", + " device = LocalSimulator()\n", + " #Submit the task\n", + " my_task2 = device.run(circuit2, shots=Shots)\n", + " #Retrieve the result\n", + " result2 = my_task2.result()\n", + " measurement_quantum = result2.measurement_probabilities\n", + " #print the measurement probabilities\n", + " print('Measurement results:\\n',result2.measurement_probabilities)\n", + " \n", + " measurement_keys = []\n", + " for k, v in measurement_quantum.items():\n", + " measurement_keys.append(list(k))\n", + " quantum_results = np.array(measurement_keys)\n", + " final_rq = []\n", + " all_measurements = []\n", + " for row in quantum_results:\n", + " func = []\n", + " for val in row[:-1]:\n", + " func.append(int(val))\n", + " all_measurements.append(func)\n", + " \n", + " num_outputs = len(all_measurements)\n", + " \n", + " type_func = 0\n", + " \n", + " for row in all_measurements:\n", + " if sum(row) == 0: \n", + " type_func += 0\n", + " else: \n", + " type_func += 1\n", + "\n", + " if type_func == 0: \n", + " print(\"This is a constant function\")\n", + " elif type_func == num_outputs: \n", + " print(\"This is a balanced function\")\n", + " else: \n", + " print(\"This is neither a balanced or constant function\")" + ] + }, + { + "cell_type": "code", + "execution_count": 354, + "id": "06cdac44", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "T : |0|1|2|Result Types|\n", + " \n", + "q0 : -H-X-H-Sample(Z)----\n", + " \n", + "q1 : -H-H---Sample(Z)----\n", + " \n", + "q2 : -H-H---Sample(Z)----\n", + " \n", + "q3 : -X-H----------------\n", + "\n", + "T : |0|1|2|Result Types|\n", + "Measurement results:\n", + " {'0001': 0.48, '0000': 0.52}\n", + "This is a constant function\n" + ] + } + ], + "source": [ + "n_qubits = 3 \n", + "oracle = random_oracle(n_qubits,run_circuit)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "af86cf12", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "conda_braket", + "language": "python", + "name": "conda_braket" + }, + "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.7.13" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} From a5f48f1a188d12988a04cff937b2dd0ee619d4b7 Mon Sep 17 00:00:00 2001 From: tanishabassan Date: Mon, 8 Aug 2022 17:15:20 +0000 Subject: [PATCH 2/5] adding introduction exposition to deustch-jozsa algorithm --- .../Deutsch Jozsa Algorithm.ipynb | 208 ++++++++++++++++-- 1 file changed, 185 insertions(+), 23 deletions(-) diff --git a/examples/advanced_circuits_algorithms/Deutsch_Jozsa_Algorithm/Deutsch Jozsa Algorithm.ipynb b/examples/advanced_circuits_algorithms/Deutsch_Jozsa_Algorithm/Deutsch Jozsa Algorithm.ipynb index 8dfbbc2ba..8906cf632 100644 --- a/examples/advanced_circuits_algorithms/Deutsch_Jozsa_Algorithm/Deutsch Jozsa Algorithm.ipynb +++ b/examples/advanced_circuits_algorithms/Deutsch_Jozsa_Algorithm/Deutsch Jozsa Algorithm.ipynb @@ -1,9 +1,179 @@ { "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "id": "7f8b04b6", + "metadata": {}, + "outputs": [], + "source": [ + "# Use Braket SDK Cost Tracking to estimate the cost to run this example\n", + "from braket.tracking import Tracker\n", + "t = Tracker().start()" + ] + }, + { + "cell_type": "markdown", + "id": "9eeb6fed", + "metadata": {}, + "source": [ + "# Deutsch-Jozsa Algorithm" + ] + }, + { + "cell_type": "markdown", + "id": "e3fcea1f", + "metadata": {}, + "source": [ + "In this tutorial we introduce one of the first quantum algorithm’s developed by pioneers David Deutsch and Richard Jozsa. This algorithm showcases an efficient quantum solution to a problem that cannot be solved classically but instead can be solved using a quantum device. \n", + "\n", + "**The goal of this tutorial to:**\n", + "\n", + "1. Give an introduction to quantum algorithms\n", + "2. Implement the Deutsch-Jozsa algorithm on a hardware device \n", + "3. Gain a deeper understanding of how this algorithm works and why quantum is advantageous over a classical analog. \n", + "\n", + "We make the assumption that the user is comfortable with the Python programming language, linear algebra and has some background knowledge about quantum computing. It is not necessary to have a physics background to understand this tutorial but if you’d like to dive deeper, some resources will be linked at the end of the tutorial. \n", + "## Overview \n", + "1. Introduction to quantum algorithms \n", + "2. Deutsch's problem\n", + "3. Technical background for Deustch-Jozsa Algorithm \n", + "4. Circuit setup \n", + "5. Code \n", + " a. initialize circuit \n", + " b. create constant and balanced oracle \n", + " c. create random oracle \n", + " d. create general deustch-jozsa algorithm \n", + " e. create a classical random circuit generator \n", + " f. run random circuit through a deutsch-jozsa algorithm \n", + "6. Summary, next steps and resources\n", + "7. References" + ] + }, + { + "cell_type": "markdown", + "id": "d018ba23", + "metadata": {}, + "source": [ + "## Quantum Algorithms\n", + "Quantum algorithms is an area of research closely tied to quantum computing. We develop quantum algorithms that can natively be implemented on a quantum device, usually in the form of creating quantum circuits. Just like classical circuits, quantum circuits allow for implementation of algorithms in a set of instructions usually in the form of gates that can manipulate the state of the qubit (quantum bit). Quantum algorithms take advantage of the natural quantum mechanical properties like superposition and entanglement and are inherently quantum in nature. These algorithms allow us to solve problems that cannot be attempted classically, such as the Deutsch-Jozsa Algorithm. " + ] + }, + { + "cell_type": "markdown", + "id": "0665c676", + "metadata": {}, + "source": [ + "## Deutsch's Problem \n", + "The algorithm proposed is solving a black box problem, trying to determine what the black box is the task at hand. The problem itself is not very applicable in real life but showcases an occasion where a quantum algorithm performs exponentially better than a classical one. \n", + "\n", + "Let $Uf$ be an oracle (black box) that computes a Boolean function which only takes binary inputs (0’s or 1’s). These functions can be represented as $f: {0, 1}^n → {0, 1}$. This oracle evaluates two types of functions, constant or balanced. \n", + "\n", + "A constant function takes any input and returns only 0’s or only 1’s and a balanced function takes any input and returns exactly half 0’s and half 1’s. \n", + "\n", + "**Constant:** 011010 → $Uf$ → 000000 \n", + "**Balanced:** 000011 → $Uf$ → 111000\n", + "\n", + "The goal is to determine what type of function is $Uf$ based on only the outputs. If the input is as large as $2^n$ then the amount of queries a classical computer will have to make is $2n/2+1$. We can see for a large enough n this problem scales exponentially and becomes inefficient to solve classically. However, leveraging a quantum algorithm we only need to query the oracle once to determine the type of function for $Uf$. This is possible because the state of its output might be in a coherent superposition of states corresponding to different answers, each which solves the problem (Deutsch 1992). \n" + ] + }, + { + "cell_type": "markdown", + "id": "1d9b2aac", + "metadata": {}, + "source": [ + "## Technical Background for Deutsch-Jozsa Algorithm\n", + "\n", + "*If you are a beginner, feel free to skip this section and go straight to the circuit setup.* \n", + "\n", + "To build the algorithm we first prepare our qubits according to our input, the input state prepares n-qubits in the $|0〉$state for query register and an extra qubit as the answer register prepared in the $|1〉$ \n", + "\n", + "$$|ψ_0〉 = |0〉^{⊗n}|1〉$$\n", + "\n", + "The Hadamard gate is applied to the query and answer register, this puts the qubits into a superposition state\n", + "\n", + "$$|ψ_1〉 = ∑_{x∈{0,1}^n} \\frac{|x〉}{√2^n} \\biggl[\\frac{ |0〉 − |1〉}{√2}\\biggr]$$\n", + "\n", + "The query register is in a superposition of all possible values and the answer register is in a superposition of 0 and 1. The next step is to evaluate function $f$ for the oracle $Uf$ for the inputs $∣x,y〉→∣x,y⊕f(x)〉$giving you an output of\n", + "\n", + "$$ |ψ_2〉 =∑_x\\frac{(-1)^{f(x)}|x〉}{√2^n}\\biggl[\\frac{ |0〉 − |1〉}{√2}\\biggr]$$\n", + "\n", + "The evaluation of the function is stored in the amplitude of the qubit in superposition state. We apply Hadamard gates to the query register to interfere and essentially remove the qubits from their superposition state. The effect of the Hadamard gates on the n-qubits can be summarized as follows\n", + "\n", + "$$ H^{⊕n}|x〉= \\frac{∑_z(-1)^{x\\cdot{z}}|z〉}{√2^n}$$\n", + "\n", + "where $x⋅z$ is the bitwise inner product of $x$ and $z$, modulo 2. We can calculate the state as\n", + "\n", + "$$|ψ_3〉=∑_z∑_x\\frac{(-1)^{x\\cdot{z} + f(x)}|z〉}{2^n}\\biggl[\\frac{ |0〉 − |1〉}{√2}\\biggr]$$\n", + "\n", + "We can now measure and observe the results for the possible functions. For the two possible cases, if the function is constant then the measurement will observe all 0’s and if the function is anything else then it’s balanced. \n", + "\n", + "*Reference: Nielsen & Chuang*\n" + ] + }, + { + "attachments": { + "Screen%20Shot%202022-06-17%20at%2011.10.56%20AM.png": { + "image/png": "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wsNjkDsChx12WO7KlKYCnXzyyWnKDnmBAAQg0GsEbr755l67dyfcePTo0ZkrZqc9E3POOadbccUVU19PKDypryIyWC+BU045pd4ohK+DAApPHbAICgEI5JrAmDFjcl2+3i5cFv1qddozIWVn0qRJvf2oVL0/TguqIiIABCAAAQhAAAIQgAAEIJBVAszwZLXmyHdVAlqEftppp1UNR4DqBA4++GD3xBNPVA9ICAhAAAIdSGCBBRZw22yzTQeWvPVF1nrKPEjen4ms1RMKTx5+VZShJAF53Oq0qeWSIFpw8thjj21BKiQBAQhAIJ8EBg8e7DCnbk3dZq0jXa7UeX8mslZPmLSVe1I5DwEIQAACEIAABCAAAQhkngAKT+arMD8F+PTTT91tt93mzjrrLPfGG28kBfvvf//rrr32WnfZZZe5jz/+ODnPAQQgAAEIQAACEIAABKoRwKStGiGu9wiBKa9McaPHjHaPPfZYuN+ECRPco48+6s4991x3+OGHu/feey+cn2eeedzLL7/sZp555h7JFzeBAAQgAAEIQAACEMg2AWZ4sl1/ucj9hx9+6FYZuYqbffbZ3eWXXx7KJMVH9tB77723O+KII4Liowua+bnllltyUW4KAQEIQAACEIAABCDQfgLM8LSfMXeoQmC22WYL3tRGrzfavfPuO0lobSB63XXXuU022SSc03fN9LzzzldhksAcQAACEIAABCAAAQhAoAQBZnhKQOFUzxPYfPPNXb/Z+xW4PpaCY8rOJ598kpi1jRgxouczyB0hAAEIQAACEIAABDJJAIUnk9WW30zfd999oXBf//rX3XHHHZcU9MEHH0yOUXgSFBxAAAIQgAAEIAABCFQhgMJTBRCXe5aAKTya8Zl11lmTm991113heLXVVnOzzDJLcp4DCEAAAhCAAAQgAAEIVCLAGp5KdLjWUgKvvvqqkyIjD2zf/va3u6X9+eefu8mTJ4fzG2ywQcH1O++8M3yXwoNAAAIQgAAEIACBTiegPtO7774bMPz73/923/zmN8PxnHPO6VZcccVOx1NQfhSeAhx8aRcBKTsjR45006dPL+tSWm6ozf30SiutVJAVM2lTGggEIAABCEAAAhDoNAJScM4//3x37733uscff7xq8bUEYOzYsW7ttdd2o0ePrho+zwEwactz7aakbBp1kKKijUXvuOMOV24Njn7A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CEAAAjkmMFNayzZ58mT37rvvum9+85tukUUWaUs2p7491b099e22pd+WTJMoBCAAAQhAAAIQgAAEIFAzgdTO8Bx44IFuzJgx7te//nXNhaknoJSd4YsMdzvuuGM90QgLAQhAAAIQgAAEIAABCGSIQGoVnmYYPvTQQ+7BBx+smMSAgQPcfPPN5yZNmuSeeeaZimG5CAEIQAAC+SfwySefuKefftrdc889Tu2IBsZ6SqZ/MN298MIL7s0336z7lp9//rn7xz/+UXe8chFkXfHiiy+Wu8x5CEAAApkjkCuF57XXXgszNsstt5zbd999q1bG9773vRDmqKOOqhqWABBolsBnn31WcxJdXV1OfwgEINBeAlJuNNM/77zzullnndUttthibtSoUU7tyMC5B7o555zTjRw50k2cONFJKWmlPPfcc2677bZzQ4YMcbP3n90NHTrUzTPPPOGeUmKqiRSyI444wi2wwAJu+eWXdy+//HK1KDVdP/fcc91CCy3k1EY+9thjNcUhEAQgAIE0E8iFwvPpp5+60047zS2++OLu0ksvDbxnm222qty33nrrEOaqq67q0ZG8qhkjQK4IqFOjTtNMM83k1l577apl22effdwMM8wQ/u66666q4QkAAQjUT+D66693I0aMCMqN2o033nijZCLvvfeeu++++9yee+7phsw/xB188MHu448/Lhm2npMXXHCBGz58uLvsssvcggsu6HbbbTf39a9/PSShdat6B1QStVtLjFjCjR8/3k2ZMsVtvvnmQWGrFKfWayussEJYP/u73/3OLbXUUm6jjTZixqdWeISDAARSSaDyGzWVWS7MlDqEGok75JBDnBomE3Uuq4kalfXWWy8EO2ncSdWCcx0CDRHQCLI9mwMGDKiaxl/+8pckjEadkXQS0Aj8W2+9lc7MkauyBDRAduihh4ZO/BNPPBHCSdE44IADgvKx7bbbhnNymHPzzTe7k08+2UkBkOh3/Itf/MJ95zvfcU8++WQ418i/2267LSg4iqv73X///e68885z+++/f0hOM0qV5Pzzz3dbbbVVUNKUt7/+9a/u6quvdnPPPXelaDVf08CMyqeyio2UQ62p7UkTv5ozS0AIQAACNRDIrMLz6quvhoZijTXWCFPuSy65ZDAFsDLXovAo7CabbBKiqAFBINAOAn/729+SZGV2Ukneeecd9+9/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" + } + }, + "cell_type": "markdown", + "id": "54640e26", + "metadata": {}, + "source": [ + "## Circuit setup \n", + "\n", + "![Screen%20Shot%202022-06-17%20at%2011.10.56%20AM.png](attachment:Screen%20Shot%202022-06-17%20at%2011.10.56%20AM.png)\n", + "\n", + "**1. Setting up our qubits**\n", + "\n", + "We begin by first setting up our qubits, these are represented by the lines or “wires” on the diagram above. We can separate our qubits into two registers. \n", + "\n", + "The first register is our n-qubits initalized to the basis state of $∣0⟩$. The number of qubits initialized to state $∣0⟩$ is determined by how many bits long our input is. So if our input is 2 bits long then we would use two qubits in our first register.\n", + "\n", + "For the second register we initialize one qubit to state $∣1⟩$ by applying the X gate. \n", + "\n", + "**2. Apply Hadamard gates**\n", + "\n", + "Now for both our qubit registers we apply a Hadamard gate. The H-gate is a transformation that takes a qubit at a ground state like $∣0⟩$ or $∣1⟩$ and puts it into a superposition of 0 and 1. \n", + "\n", + "For example, if you have a coin you only have two sides, either heads or tails. Now imagine if you apply some force to this coin and balance it on its thin side, now its neither head or tails but in a superposition of both possible sides. A Hadamard gate is like this force or transformation that puts a qubit into superposition of 0 and 1.\n", + "\n", + "The first register is now in a superposition of all possible input values and the second register is in a superposition of 0 and 1. \n", + "\n", + "**3. Apply the oracle**\n", + "\n", + "The oracle is the Boolean function that is applied to the n-qubits in the query register. \n", + "\n", + "You can create this oracle using a unitary matrix which allows us to store the answer to the Boolean function in the amplitude of a qubit in the superposition state. A unitary operation allows any function $f(x)$ to be encoded on a quantum computer using specific quantum gates. \n", + "\n", + "There are many different ways to implement this oracle because we can create constant or balanced functions using different combinations of gate operations. Below is one example of creating constant and balanced functions. \n", + "\n", + "*For a constant function:* \n", + "1. if $f(x) = 0$, then apply the I gate to the qubit in second register. \n", + "2. if $f(x) = 1$, then apply the X gate to the qubit in second register. \n", + "\n", + "*For a balanced function:* \n", + "\n", + "Apply a CNOT gate to every qubit in the first register and set the qubit in the second register as the target. Use a random number generator to randomly choose which qubits to add an X - gate before and after the CNOT gate.\n", + "\n", + "The I and X gates are single qubit gates, they only perform on one qubit. The I gate is an “identity-gate” which essentially does nothing, it leaves the qubit as is. The X gate switches the amplitudes of the states $∣0⟩$ and $∣1⟩$. The CNOT gate is a two qubit gate, it is used to entangle two qubits in superposition together, it takes in control qubit and decides based on that if it needs to flip the spin of the target qubit. \n", + "\n", + "**4. Apply Hadamard gate to first qubit register**\n", + "\n", + "After applying the quantum oracle a H-gate is applied to all the qubits in the first register. This is because applying the H-gate again takes the qubits out of a superposition state. \n", + "\n", + "If the function was constant then the quantum state after the H-gate is applied should be the same as it’s initial state. \n", + "\n", + "If the function is balanced a negative phase is added to exactly half the quantum states. This means the quantum states are orthogonal or perpendicular to each other. So when a H-gate is applied, the quantum state we end up with is orthogonal to the original state. \n", + "\n", + "When we measure the circuit, if the function was constant then the output will be all 0’s and if the function is balanced will be anything but all 0’s.\n" + ] + }, { "cell_type": "code", "execution_count": 322, - "id": "2ae735a6", + "id": "ad60b871", "metadata": {}, "outputs": [], "source": [ @@ -26,7 +196,7 @@ { "cell_type": "code", "execution_count": 323, - "id": "e8a92069", + "id": "5526cca2", "metadata": {}, "outputs": [], "source": [ @@ -46,7 +216,7 @@ { "cell_type": "code", "execution_count": 324, - "id": "c2b97565", + "id": "40f48b76", "metadata": {}, "outputs": [ { @@ -77,7 +247,7 @@ { "cell_type": "code", "execution_count": 325, - "id": "e4be33e5", + "id": "2325ec13", "metadata": {}, "outputs": [], "source": [ @@ -107,7 +277,7 @@ { "cell_type": "code", "execution_count": 326, - "id": "35c4e846", + "id": "69bd28ea", "metadata": {}, "outputs": [ { @@ -132,7 +302,7 @@ { "cell_type": "code", "execution_count": 327, - "id": "dd0362f5", + "id": "5a1b1f14", "metadata": {}, "outputs": [], "source": [ @@ -169,7 +339,7 @@ { "cell_type": "code", "execution_count": 328, - "id": "e6ac4231", + "id": "d739075a", "metadata": {}, "outputs": [ { @@ -214,7 +384,7 @@ { "cell_type": "code", "execution_count": 329, - "id": "17382baa", + "id": "1bb1b492", "metadata": {}, "outputs": [], "source": [ @@ -291,7 +461,7 @@ { "cell_type": "code", "execution_count": 330, - "id": "a6d3a71d", + "id": "b716adef", "metadata": {}, "outputs": [ { @@ -319,7 +489,7 @@ { "cell_type": "code", "execution_count": 349, - "id": "54146daa", + "id": "45bb6b2b", "metadata": {}, "outputs": [], "source": [ @@ -455,7 +625,7 @@ { "cell_type": "code", "execution_count": 350, - "id": "6ae43cd7", + "id": "bac7b6ab", "metadata": {}, "outputs": [ { @@ -489,7 +659,7 @@ { "cell_type": "code", "execution_count": 351, - "id": "755c1cf7", + "id": "2a1d73aa", "metadata": {}, "outputs": [], "source": [ @@ -646,7 +816,7 @@ { "cell_type": "code", "execution_count": 352, - "id": "0c2c1cec", + "id": "4ff754cc", "metadata": {}, "outputs": [ { @@ -778,7 +948,7 @@ { "cell_type": "code", "execution_count": 353, - "id": "765c5d73", + "id": "fc7519f0", "metadata": {}, "outputs": [], "source": [ @@ -847,7 +1017,7 @@ { "cell_type": "code", "execution_count": 354, - "id": "06cdac44", + "id": "b5976a3c", "metadata": {}, "outputs": [ { @@ -875,14 +1045,6 @@ "n_qubits = 3 \n", "oracle = random_oracle(n_qubits,run_circuit)" ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "af86cf12", - "metadata": {}, - "outputs": [], - "source": [] } ], "metadata": { From 9bc7e7d838563dc81ffd346a4ac9d14a91c2d038 Mon Sep 17 00:00:00 2001 From: tanishabassan Date: Wed, 17 Aug 2022 03:43:27 +0000 Subject: [PATCH 3/5] adding more markdown in between the code and made some changes to the code --- .../Deutsch Jozsa Algorithm.ipynb | 761 ++++++++---------- 1 file changed, 346 insertions(+), 415 deletions(-) diff --git a/examples/advanced_circuits_algorithms/Deutsch_Jozsa_Algorithm/Deutsch Jozsa Algorithm.ipynb b/examples/advanced_circuits_algorithms/Deutsch_Jozsa_Algorithm/Deutsch Jozsa Algorithm.ipynb index 8906cf632..e5a12a54c 100644 --- a/examples/advanced_circuits_algorithms/Deutsch_Jozsa_Algorithm/Deutsch Jozsa Algorithm.ipynb +++ b/examples/advanced_circuits_algorithms/Deutsch_Jozsa_Algorithm/Deutsch Jozsa Algorithm.ipynb @@ -2,8 +2,8 @@ "cells": [ { "cell_type": "code", - "execution_count": 1, - "id": "7f8b04b6", + "execution_count": 52, + "id": "4cba78b7", "metadata": {}, "outputs": [], "source": [ @@ -14,7 +14,7 @@ }, { "cell_type": "markdown", - "id": "9eeb6fed", + "id": "7cd50489", "metadata": {}, "source": [ "# Deutsch-Jozsa Algorithm" @@ -22,7 +22,7 @@ }, { "cell_type": "markdown", - "id": "e3fcea1f", + "id": "d755f2f3", "metadata": {}, "source": [ "In this tutorial we introduce one of the first quantum algorithm’s developed by pioneers David Deutsch and Richard Jozsa. This algorithm showcases an efficient quantum solution to a problem that cannot be solved classically but instead can be solved using a quantum device. \n", @@ -52,7 +52,7 @@ }, { "cell_type": "markdown", - "id": "d018ba23", + "id": "24570bf4", "metadata": {}, "source": [ "## Quantum Algorithms\n", @@ -61,7 +61,7 @@ }, { "cell_type": "markdown", - "id": "0665c676", + "id": "2cb0d8b7", "metadata": {}, "source": [ "## Deutsch's Problem \n", @@ -79,12 +79,12 @@ }, { "cell_type": "markdown", - "id": "1d9b2aac", + "id": "323cd2c4", "metadata": {}, "source": [ "## Technical Background for Deutsch-Jozsa Algorithm\n", "\n", - "*If you are a beginner, feel free to skip this section and go straight to the circuit setup.* \n", + "*If you are a unfamiliar with quantum mechanics, feel free to skip this section and go straight to the circuit setup.* \n", "\n", "To build the algorithm we first prepare our qubits according to our input, the input state prepares n-qubits in the $|0〉$state for query register and an extra qubit as the answer register prepared in the $|1〉$ \n", "\n", @@ -111,6 +111,29 @@ "*Reference: Nielsen & Chuang*\n" ] }, + { + "cell_type": "code", + "execution_count": 109, + "id": "6f81de36", + "metadata": {}, + "outputs": [], + "source": [ + "# general imports\n", + "import matplotlib.pyplot as plt\n", + "# magic word for producing visualizations in notebook\n", + "%matplotlib inline\n", + "import string\n", + "import time\n", + "import numpy as np\n", + "import random\n", + "from scipy.linalg import expm\n", + "\n", + "# AWS imports: Import Braket SDK modules\n", + "from braket.circuits import Circuit, Gate, Observable\n", + "from braket.devices import LocalSimulator\n", + "from braket.aws import AwsDevice" + ] + }, { "attachments": { "Screen%20Shot%202022-06-17%20at%2011.10.56%20AM.png": { @@ -118,85 +141,40 @@ } }, "cell_type": "markdown", - "id": "54640e26", + "id": "c79a1b57", "metadata": {}, "source": [ "## Circuit setup \n", "\n", "![Screen%20Shot%202022-06-17%20at%2011.10.56%20AM.png](attachment:Screen%20Shot%202022-06-17%20at%2011.10.56%20AM.png)\n", "\n", - "**1. Setting up our qubits**\n", + "## 1. Setting up our qubits\n", "\n", "We begin by first setting up our qubits, these are represented by the lines or “wires” on the diagram above. We can separate our qubits into two registers. \n", "\n", "The first register is our n-qubits initalized to the basis state of $∣0⟩$. The number of qubits initialized to state $∣0⟩$ is determined by how many bits long our input is. So if our input is 2 bits long then we would use two qubits in our first register.\n", "\n", - "For the second register we initialize one qubit to state $∣1⟩$ by applying the X gate. \n", - "\n", - "**2. Apply Hadamard gates**\n", - "\n", - "Now for both our qubit registers we apply a Hadamard gate. The H-gate is a transformation that takes a qubit at a ground state like $∣0⟩$ or $∣1⟩$ and puts it into a superposition of 0 and 1. \n", - "\n", - "For example, if you have a coin you only have two sides, either heads or tails. Now imagine if you apply some force to this coin and balance it on its thin side, now its neither head or tails but in a superposition of both possible sides. A Hadamard gate is like this force or transformation that puts a qubit into superposition of 0 and 1.\n", - "\n", - "The first register is now in a superposition of all possible input values and the second register is in a superposition of 0 and 1. \n", - "\n", - "**3. Apply the oracle**\n", - "\n", - "The oracle is the Boolean function that is applied to the n-qubits in the query register. \n", - "\n", - "You can create this oracle using a unitary matrix which allows us to store the answer to the Boolean function in the amplitude of a qubit in the superposition state. A unitary operation allows any function $f(x)$ to be encoded on a quantum computer using specific quantum gates. \n", - "\n", - "There are many different ways to implement this oracle because we can create constant or balanced functions using different combinations of gate operations. Below is one example of creating constant and balanced functions. \n", - "\n", - "*For a constant function:* \n", - "1. if $f(x) = 0$, then apply the I gate to the qubit in second register. \n", - "2. if $f(x) = 1$, then apply the X gate to the qubit in second register. \n", - "\n", - "*For a balanced function:* \n", - "\n", - "Apply a CNOT gate to every qubit in the first register and set the qubit in the second register as the target. Use a random number generator to randomly choose which qubits to add an X - gate before and after the CNOT gate.\n", - "\n", - "The I and X gates are single qubit gates, they only perform on one qubit. The I gate is an “identity-gate” which essentially does nothing, it leaves the qubit as is. The X gate switches the amplitudes of the states $∣0⟩$ and $∣1⟩$. The CNOT gate is a two qubit gate, it is used to entangle two qubits in superposition together, it takes in control qubit and decides based on that if it needs to flip the spin of the target qubit. \n", - "\n", - "**4. Apply Hadamard gate to first qubit register**\n", - "\n", - "After applying the quantum oracle a H-gate is applied to all the qubits in the first register. This is because applying the H-gate again takes the qubits out of a superposition state. \n", - "\n", - "If the function was constant then the quantum state after the H-gate is applied should be the same as it’s initial state. \n", - "\n", - "If the function is balanced a negative phase is added to exactly half the quantum states. This means the quantum states are orthogonal or perpendicular to each other. So when a H-gate is applied, the quantum state we end up with is orthogonal to the original state. \n", - "\n", - "When we measure the circuit, if the function was constant then the output will be all 0’s and if the function is balanced will be anything but all 0’s.\n" + "For the second register we initialize one qubit to state $∣1⟩$ by applying the X gate. \n" ] }, { - "cell_type": "code", - "execution_count": 322, - "id": "ad60b871", + "cell_type": "markdown", + "id": "65e8e672", "metadata": {}, - "outputs": [], "source": [ - "# general imports\n", - "import matplotlib.pyplot as plt\n", - "# magic word for producing visualizations in notebook\n", - "%matplotlib inline\n", - "import string\n", - "import time\n", - "import numpy as np\n", - "import random\n", - "from scipy.linalg import expm\n", + "## 2. Apply Hadamard gates\n", "\n", - "# AWS imports: Import Braket SDK modules\n", - "from braket.circuits import Circuit, Gate, Observable\n", - "from braket.devices import LocalSimulator\n", - "from braket.aws import AwsDevice" + "Now for both our qubit registers we apply a Hadamard gate. The H-gate is a transformation that takes a qubit at a ground state like $∣0⟩$ or $∣1⟩$ and puts it into a superposition of 0 and 1. \n", + "\n", + "For example, if you have a coin you only have two sides, either heads or tails. Now imagine if you apply some force to this coin and balance it on its thin side, now its neither head or tails but in a superposition of both possible sides. A Hadamard gate is like this force or transformation that puts a qubit into superposition of 0 and 1.\n", + "\n", + "The first register is now in a superposition of all possible input values and the second register is in a superposition of 0 and 1. " ] }, { "cell_type": "code", - "execution_count": 323, - "id": "5526cca2", + "execution_count": 110, + "id": "a98931c1", "metadata": {}, "outputs": [], "source": [ @@ -215,8 +193,8 @@ }, { "cell_type": "code", - "execution_count": 324, - "id": "40f48b76", + "execution_count": 111, + "id": "f7a70e2a", "metadata": {}, "outputs": [ { @@ -244,10 +222,37 @@ "print(init)" ] }, + { + "cell_type": "markdown", + "id": "8831afbf", + "metadata": {}, + "source": [ + "---------------------------------------------------------------------------------------------------------------------\n", + "## 3. Apply the oracle\n", + "\n", + "The oracle is the Boolean function that is applied to the n-qubits in the query register. \n", + "\n", + "You can create this oracle using a unitary matrix which allows us to store the answer to the Boolean function in the amplitude of a qubit in the superposition state. A unitary operation allows any function $f(x)$ to be encoded on a quantum computer using specific quantum gates. \n", + "\n", + "There are many different ways to implement this oracle because we can create constant or balanced functions using different combinations of gate operations. To showcase this, we've created a random oracle that can will either implement a constant oracle, balanced oracle or none using a random assortment of x, cnot and ccnot gates. \n", + "\n", + "The I and X gates are single qubit gates, they only perform on one qubit. The I gate is an “identity-gate” which essentially does nothing, it leaves the qubit as is. The X gate switches the amplitudes of the states $∣0⟩$ and $∣1⟩$. The CNOT gate is a two qubit gate, it is used to entangle two qubits in superposition together, it takes in control qubit and decides based on that if it needs to flip the spin of the target qubit. " + ] + }, + { + "cell_type": "markdown", + "id": "7a9468a8", + "metadata": {}, + "source": [ + "## For a constant function: \n", + "1. if $f(x) = 0$, then apply the I gate to the qubit in second register. \n", + "2. if $f(x) = 1$, then apply the X gate to the qubit in second register. " + ] + }, { "cell_type": "code", - "execution_count": 325, - "id": "2325ec13", + "execution_count": 112, + "id": "ad568b15", "metadata": {}, "outputs": [], "source": [ @@ -276,8 +281,8 @@ }, { "cell_type": "code", - "execution_count": 326, - "id": "69bd28ea", + "execution_count": 113, + "id": "c2d8ccf3", "metadata": {}, "outputs": [ { @@ -295,14 +300,25 @@ "source": [ "# example circuit for constant oracle \n", "n_qubits = 5\n", - "const = constant_oracle(n_qubits)\n", + "constant = constant_oracle(n_qubits)\n", "print(const) " ] }, + { + "cell_type": "markdown", + "id": "c649c8dc", + "metadata": {}, + "source": [ + "---------------------------------------------------------------------------------------------------------------------\n", + "## For a balanced function:\n", + "\n", + "Apply a CNOT gate to every qubit in the first register and set the qubit in the second register as the target. Use a random number generator to randomly choose which qubits to add an X - gate before and after the CNOT gate." + ] + }, { "cell_type": "code", - "execution_count": 327, - "id": "5a1b1f14", + "execution_count": 114, + "id": "118771e3", "metadata": {}, "outputs": [], "source": [ @@ -338,53 +354,69 @@ }, { "cell_type": "code", - "execution_count": 328, - "id": "d739075a", + "execution_count": 115, + "id": "57251c30", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "T : |0|1|2|3|4|5|6|7|8|9|10|11|\n", - " \n", - "q0 : -X-C-X---------------------\n", - " | \n", - "q1 : -X-|-C-X-------------------\n", - " | | \n", - "q2 : ---|-|-C-------------------\n", - " | | | \n", - "q3 : ---|-|-|-C-----------------\n", - " | | | | \n", - "q4 : -X-|-|-|-|-C-X-------------\n", - " | | | | | \n", - "q5 : -X-|-|-|-|-|-C-X-----------\n", - " | | | | | | \n", - "q6 : ---|-|-|-|-|-|-C-----------\n", - " | | | | | | | \n", - "q7 : ---|-|-|-|-|-|-|-C---------\n", - " | | | | | | | | \n", - "q8 : ---|-|-|-|-|-|-|-|-C-------\n", - " | | | | | | | | | \n", - "q9 : -X-|-|-|-|-|-|-|-|-|-C--X--\n", - " | | | | | | | | | | \n", - "q10 : ---X-X-X-X-X-X-X-X-X-X-----\n", + "T : | 0 |1|2|3|4|5|6|7|8|9|\n", + " \n", + "q0 : ---C-------------------\n", + " | \n", + "q1 : ---|-C-----------------\n", + " | | \n", + "q2 : ---|-|-C---------------\n", + " | | | \n", + "q3 : -X-|-|-|-C-X-----------\n", + " | | | | \n", + "q4 : -X-|-|-|-|-C-X---------\n", + " | | | | | \n", + "q5 : ---|-|-|-|-|-C---------\n", + " | | | | | | \n", + "q6 : ---|-|-|-|-|-|-C-------\n", + " | | | | | | | \n", + "q7 : ---|-|-|-|-|-|-|-C-----\n", + " | | | | | | | | \n", + "q8 : ---|-|-|-|-|-|-|-|-C---\n", + " | | | | | | | | | \n", + "q9 : ---|-|-|-|-|-|-|-|-|-C-\n", + " | | | | | | | | | | \n", + "q10 : ---X-X-X-X-X-X-X-X-X-X-\n", "\n", - "T : |0|1|2|3|4|5|6|7|8|9|10|11|\n" + "T : | 0 |1|2|3|4|5|6|7|8|9|\n" ] } ], "source": [ "# example circuit for balanced oracle\n", "n_qubits = 10\n", - "bal = balanced_oracle(n_qubits)\n", + "balanced = balanced_oracle(n_qubits)\n", "print(bal)" ] }, + { + "cell_type": "markdown", + "id": "f930e359", + "metadata": {}, + "source": [ + "---------------------------------------------------------------------------------------------------------------------\n", + "\n", + "## For a random function:\n", + "\n", + "We have created a random oracle generator to showcase the many different ways a constant or balanced oracle can be made using just X, CNOT and CCNOT gates. When running this function, you can have 3 different outcomes. Either a constant function, a balanced function or neither. \n", + "\n", + "We create a list of different types of gates you can apply, the X gate a single gate and CNOT and CCNOT require multiple gates. The CCNOT is a 3 qubit gate, it's similar to CNOT except you have 2 control qubits and 1 target qubit. \n", + "\n", + "We randomly choose which type of gates to apply and then randomly apply gates on different qubits to see what kind of function has been created. " + ] + }, { "cell_type": "code", - "execution_count": 329, - "id": "1bb1b492", + "execution_count": 116, + "id": "1953aacb", "metadata": {}, "outputs": [], "source": [ @@ -410,8 +442,6 @@ " \n", " # random oracle circuit generator\n", " \n", - " circuit = Circuit()\n", - " \n", " # implement all the gate options \n", " for qubit in range(len(random_array)):\n", " \n", @@ -434,7 +464,6 @@ " targetf = np.random.randint(n_qubits+1)\n", " if qubit!= targetf:\n", " circuit.cnot(control=qubit, target=targetf)\n", - " del targetf\n", " else: \n", " #randomly choose where the target qubit is\n", " targetf = np.random.randint(n_qubits+1)\n", @@ -442,7 +471,6 @@ " if qubit!= targetf:\n", " circuit.cnot(control=qubit, target=targetf)\n", " circuit.x(qubit) \n", - " del targetf\n", " if random_gate_m == \"ccnot\":\n", " #randomly choose where the first and second controls are\n", " control1 = np.random.randint(n_qubits+1)\n", @@ -451,32 +479,27 @@ " targetf = np.random.randint(n_qubits+1)\n", " if control1 != control2 and control1 != targetf and control2 != targetf:\n", " circuit.ccnot(control1, control2, targetf) \n", - " del control1\n", - " del control2\n", - " del targetf\n", " \n", " return circuit" ] }, { "cell_type": "code", - "execution_count": 330, - "id": "b716adef", + "execution_count": 117, + "id": "60add186", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "T : |0|\n", - " \n", - "q1 : -X-\n", - " | \n", - "q3 : -C-\n", - " | \n", - "q4 : -C-\n", + "T : |0|1|2|\n", + " \n", + "q2 : ---X---\n", + " | \n", + "q3 : -X-C-X-\n", "\n", - "T : |0|\n" + "T : |0|1|2|\n" ] } ], @@ -486,19 +509,32 @@ "print(random)" ] }, + { + "cell_type": "markdown", + "id": "b5a19f12", + "metadata": {}, + "source": [ + "## 4. Apply Hadamard gate to first qubit register\n", + "\n", + "After applying the quantum oracle a H-gate is applied to all the qubits in the first register. This is because applying the H-gate again takes the qubits out of a superposition state. \n", + "\n", + "If the function was constant then the quantum state after the H-gate is applied should be the same as it’s initial state. \n", + "\n", + "If the function is balanced a negative phase is added to exactly half the quantum states. This means the quantum states are orthogonal or perpendicular to each other. So when a H-gate is applied, the quantum state we end up with is orthogonal to the original state. \n", + "\n", + "When we measure the circuit, if the function was constant then the output will be all 0’s and if the function is balanced will be anything but all 0’s." + ] + }, { "cell_type": "code", - "execution_count": 349, - "id": "45bb6b2b", + "execution_count": 118, + "id": "de78817c", "metadata": {}, "outputs": [], "source": [ - "# general function for taking an dj-algorithm \n", + "# general deutsch-jozsa algorithm \n", "\n", - "def dj_algorithm(case, n_qubits):\n", - " \n", - " # create circuit \n", - " circuit = Circuit()\n", + "def dj_algorithm(oracle, n_qubits):\n", " \n", " # define the output qubit \n", " output_qubit = n_qubits \n", @@ -506,100 +542,8 @@ " # create circuit and initialize states\n", " circuit = Circuit().h(range(n_qubits)).x(output_qubit).h(output_qubit)\n", " \n", - " # creating a circuit for constant oracle\n", - " if case == \"constant\":\n", - " \n", - " # set output to either 0 or 1 \n", - " rand_output = np.random.randint(0, 2)\n", - " \n", - " # if output qubit is 0, apply i gate to not change value \n", - " if rand_output == 0:\n", - " circuit.i(output_qubit)\n", - " # if output is 1, apply x gate to change value to 0 \n", - " if rand_output == 1: \n", - " circuit.x(output_qubit)\n", - " \n", - " # create a circuit for balanced oracle\n", - " if case == \"balanced\":\n", - " \n", - " # generate a random array of 0s and 1s to figure out where to place x gates\n", - " random_num = np.random.randint(2, size=n_qubits)\n", - " \n", - " # place x gates \n", - " for qubit in range(len(random_num)):\n", - " if random_num[qubit] == 1:\n", - " circuit.x(qubit)\n", - " \n", - " # place cnot gates\n", - " for qubit in range(n_qubits):\n", - " circuit.cnot(control=qubit, target=output_qubit)\n", - " \n", - " # place x gates \n", - " for qubit in range(len(random_num)): \n", - " if random_num[qubit] == 1:\n", - " circuit.x(qubit)\n", - " \n", - " # create a completely random oracle \n", - " if case == \"random\":\n", - " \n", - " # create a random array of 0s and 1s to determine where to place the gates\n", - " random_array = np.random.randint(2, size=n_qubits)\n", - " \n", - " # define the single gate set \n", - " single_gate_set = \"x\"\n", - " \n", - " # define the multiple qubit gate set\n", - " multiple_gate_set = [\"cnot\", \"ccnot\"]\n", - " \n", - " # create a list combining single and multiple qubit gates to randomly choose from\n", - " choice_gate_set = [\"single_gate_set\", \"multiple_gate_set\"]\n", - " \n", - " # random oracle circuit generator\n", - " \n", - " circuit = Circuit()\n", - " \n", - " # implement all the gate options \n", - " for qubit in range(len(random_array)):\n", - " \n", - " # randomly choose to apply a single qubit or multiple qubit gate \n", - " random_gate_set = np.random.choice(choice_gate_set, p=[0.30, 0.70])\n", - " \n", - " # if single qubit gate then implement x gate accordingly \n", - " if random_gate_set == \"single_gate_set\": \n", - " if random_array[qubit] == 1:\n", - " circuit.x(qubit)\n", - " \n", - " # if multiple qubit gate then implement cnot and ccnot gates \n", - " if random_gate_set == \"multiple_gate_set\": \n", - " \n", - " # randomly choose to implement a cnot or ccnot gate\n", - " random_gate_m = np.random.choice(multiple_gate_set)\n", - " if random_gate_m == \"cnot\":\n", - " if random_array[qubit] == 0:\n", - " #randomly choose where the target qubit is\n", - " targetf = np.random.randint(n_qubits+1)\n", - " if qubit!= targetf:\n", - " circuit.cnot(control=qubit, target=targetf)\n", - " del targetf\n", - " else: \n", - " #randomly choose where the target qubit is\n", - " targetf = np.random.randint(n_qubits+1)\n", - " circuit.x(qubit)\n", - " if qubit!= targetf:\n", - " circuit.cnot(control=qubit, target=targetf)\n", - " circuit.x(qubit) \n", - " del targetf\n", - " if random_gate_m == \"ccnot\":\n", - " #randomly choose where the first and second controls are\n", - " control1 = np.random.randint(n_qubits+1)\n", - " control2 = np.random.randint(n_qubits+1)\n", - " #randomly choose where the target qubit is\n", - " targetf = np.random.randint(n_qubits+1)\n", - " if control1 != control2 and control1 != targetf and control2 != targetf:\n", - " circuit.ccnot(control1, control2, targetf) \n", - " del control1\n", - " del control2\n", - " del targetf\n", + " # add the oracle circuit \n", + " circuit.add_circuit(oracle, range(n_qubits + output_qubit))\n", " \n", " # place the h-gates again\n", " circuit.h(range(n_qubits))\n", @@ -607,9 +551,9 @@ " # measure the results\n", " for qubit in range(n_qubits):\n", " circuit.sample(observable=Observable.Z(), target=qubit)\n", - " Shots = 10\n", - " #Designate the device being used as the local simulator\n", - " #Feel free to use another device\n", + " \n", + " Shots = 100\n", + " #Designate the device being used as the local simulator, feel free to use another device\n", " device = LocalSimulator()\n", " #Submit the task\n", " my_task = device.run(circuit, shots=Shots)\n", @@ -618,14 +562,13 @@ " #print the measurement probabilities\n", " print('Measurement results:\\n',result.measurement_probabilities) \n", " \n", - " return circuit\n", - " " + " return circuit" ] }, { "cell_type": "code", - "execution_count": 350, - "id": "bac7b6ab", + "execution_count": 119, + "id": "3b699922", "metadata": {}, "outputs": [ { @@ -633,38 +576,65 @@ "output_type": "stream", "text": [ "Measurement results:\n", - " {'11110': 0.7, '11111': 0.3}\n", - "T : |0|1|2|3|4|5|6|Result Types|\n", - " \n", - "q0 : -H---C-H-------Sample(Z)----\n", - " | \n", - "q1 : -H---|-C-H-----Sample(Z)----\n", - " | | \n", - "q2 : -H-X-|-|-C-X-H-Sample(Z)----\n", - " | | | \n", - "q3 : -H---|-|-|-C-H-Sample(Z)----\n", - " | | | | \n", - "q4 : -X-H-X-X-X-X----------------\n", + " {'00000000000': 0.14, '00000000001': 0.19, '00001000000': 0.13, '00001000001': 0.08, '11111000000': 0.12, '11111000001': 0.11, '11110000000': 0.15, '11110000001': 0.08}\n", + "T : |0|1| 2 |3|4|5|6|7|8|9|10|11|12|Result Types|\n", + " \n", + "q0 : -H-X---C-X-H--------------------Sample(Z)----\n", + " | \n", + "q1 : -H-X---|-C-X-H------------------Sample(Z)----\n", + " | | \n", + "q2 : -H-X---|-|-C-X-H----------------Sample(Z)----\n", + " | | | \n", + "q3 : -H-----|-|-|-C-H----------------Sample(Z)----\n", + " | | | | \n", + "q4 : -X-H-X-|-|-|-|-C-X---------------------------\n", + " | | | | | \n", + "q5 : -X-----|-|-|-|-|-C-X-------------------------\n", + " | | | | | | \n", + "q6 : -X-----|-|-|-|-|-|-C-X-----------------------\n", + " | | | | | | | \n", + "q7 : -------|-|-|-|-|-|-|-C-----------------------\n", + " | | | | | | | | \n", + "q8 : -------|-|-|-|-|-|-|-|-C---------------------\n", + " | | | | | | | | | \n", + "q9 : -X-----|-|-|-|-|-|-|-|-|--C--X---------------\n", + " | | | | | | | | | | \n", + "q10 : -------X-X-X-X-X-X-X-X-X--X------------------\n", "\n", - "T : |0|1|2|3|4|5|6|Result Types|\n" + "T : |0|1| 2 |3|4|5|6|7|8|9|10|11|12|Result Types|\n" ] } ], "source": [ "n_qubits = 4\n", - "dj = dj_algorithm(\"balanced\", n_qubits)\n", - "print(dj)" + "# randomly choose the type of oracle to implement in your algorithm\n", + "dj_algo = dj_algorithm(np.random.choice([constant, balanced, random]), n_qubits)\n", + "print(dj_algo)" + ] + }, + { + "cell_type": "markdown", + "id": "f9f6b4e7", + "metadata": {}, + "source": [ + "## Classicaly Run the Random Circuit Generator \n", + "\n", + "The function classical_generator takes a random oracle and applies it to $2^n-1$ possible combinations where n is the number of qubits you've initialized. We can create a classical circuit by removing the Hadamard gates because without putting any qubits in superposition, the circuit can't display quantum mechanical properties. \n", + "\n", + "If n = 3 then we get a result of 8 different circuits. We then determine if these circuits are constant, balanced or neither at the end so we can compare it with results when we run this circuit but this time on a quantum circuit.\n", + "\n", + "#### *To generate a random circuit again run the random_oracle function again!*" ] }, { "cell_type": "code", - "execution_count": 351, - "id": "2a1d73aa", + "execution_count": 120, + "id": "6f18e776", "metadata": {}, "outputs": [], "source": [ "# run initialized states through circuit and add random_oracle \n", - "def classical_checker(n_qubits):\n", + "def classical_generator(n_qubits, random_oracle):\n", " \n", " # define the output qubit \n", " output_qubit = n_qubits \n", @@ -685,69 +655,9 @@ " \n", " # turn matix into an numpy array\n", " matrix_bitout = np.array(matrix)\n", - " # create a random array of 0s and 1s to determine where to place the gates\n", - " random_array = np.random.randint(2, size=n_qubits)\n", - " \n", - " # define the single gate set \n", - " single_gate_set = \"x\"\n", - " \n", - " # define the multiple qubit gate set\n", - " multiple_gate_set = [\"cnot\", \"ccnot\"]\n", - " \n", - " # create a list combining single and multiple qubit gates to randomly choose from\n", - " choice_gate_set = [\"single_gate_set\", \"multiple_gate_set\"]\n", - " \n", - " # random oracle circuit generator\n", - " \n", - " random_circuit = Circuit()\n", - " \n", - " # implement all the gate options \n", - " for qubit in range(len(random_array)):\n", - " \n", - " # randomly choose to apply a single qubit or multiple qubit gate \n", - " random_gate_set = np.random.choice(choice_gate_set, p=[0.30, 0.70])\n", - " \n", - " # if single qubit gate then implement x gate accordingly \n", - " if random_gate_set == \"single_gate_set\": \n", - " if random_array[qubit] == 1:\n", - " random_circuit.x(qubit)\n", - " \n", - " # if multiple qubit gate then implement cnot and ccnot gates \n", - " if random_gate_set == \"multiple_gate_set\": \n", - " \n", - " # randomly choose to implement a cnot or ccnot gate\n", - " random_gate_m = np.random.choice(multiple_gate_set)\n", - " if random_gate_m == \"cnot\":\n", - " if random_array[qubit] == 0:\n", - " #randomly choose where the target qubit is\n", - " targetf = np.random.randint(n_qubits+1)\n", - " if qubit!= targetf:\n", - " random_circuit.cnot(control=qubit, target=targetf)\n", - " del targetf\n", - " else: \n", - " #randomly choose where the target qubit is\n", - " targetf = np.random.randint(n_qubits+1)\n", - " random_circuit.x(qubit)\n", - " if qubit!= targetf:\n", - " random_circuit.cnot(control=qubit, target=targetf)\n", - " random_circuit.x(qubit) \n", - " del targetf\n", - " if random_gate_m == \"ccnot\":\n", - " #randomly choose where the first and second controls are\n", - " control1 = np.random.randint(n_qubits+1)\n", - " control2 = np.random.randint(n_qubits+1)\n", - " #randomly choose where the target qubit is\n", - " targetf = np.random.randint(n_qubits+1)\n", - " if control1 != control2 and control1 != targetf and control2 != targetf:\n", - " random_circuit.ccnot(control1, control2, targetf) \n", - " del control1\n", - " del control2\n", - " del targetf\n", - " \n", " \n", " measurement_results_classical = []\n", " \n", - " \n", " for row in matrix_bitout:\n", " circuit = Circuit()\n", " #retrieve the bit string that initializes the qubits for this iteration\n", @@ -760,13 +670,12 @@ " else: \n", " circuit.i(qubit)\n", " # adding random circuit to our initial states \n", - " circuit.add_circuit(random_circuit, range(n_qubits))\n", + " circuit.add_circuit(random_oracle, range(n_qubits))\n", " circuit.sample(observable=Observable.Z(), target=output_qubit)\n", " print(circuit)\n", " \n", " Shots = 1\n", - " #Designate the device being used as the local simulator\n", - " #Feel free to use another device\n", + " #Designate the device being used as the local simulator, feel free to use another device\n", " device = LocalSimulator()\n", " #Submit the task\n", " my_task = device.run(circuit, shots=Shots)\n", @@ -810,13 +719,13 @@ " \n", " \n", " print(\"These are the final outputs from the random circuits\", final_rc)\n", - " return random_circuit" + " return random_oracle" ] }, { "cell_type": "code", - "execution_count": 352, - "id": "4ff754cc", + "execution_count": 124, + "id": "adaf82c5", "metadata": {}, "outputs": [ { @@ -824,117 +733,117 @@ "output_type": "stream", "text": [ "[0, 0, 0]\n", - "T : |0|1|Result Types|\n", - " \n", - "q0 : -I-X--------------\n", - " \n", - "q1 : -I----------------\n", - " \n", - "q2 : -I----------------\n", - " \n", - "q3 : -----Sample(Z)----\n", + "T : |0|1|2|3|Result Types|\n", + " \n", + "q0 : -I---X----------------\n", + " | \n", + "q1 : -I-X-C-X--------------\n", + " \n", + "q2 : -I--------------------\n", + " \n", + "q3 : ---------Sample(Z)----\n", "\n", - "T : |0|1|Result Types|\n", + "T : |0|1|2|3|Result Types|\n", "Measurement results:\n", " {'1000': 1.0}\n", "[0, 0, 1]\n", - "T : |0|1|Result Types|\n", - " \n", - "q0 : -I-X--------------\n", - " \n", - "q1 : -I----------------\n", - " \n", - "q2 : -X----------------\n", - " \n", - "q3 : -----Sample(Z)----\n", + "T : |0|1|2|3|Result Types|\n", + " \n", + "q0 : -I---X----------------\n", + " | \n", + "q1 : -I-X-C-X--------------\n", + " \n", + "q2 : -X--------------------\n", + " \n", + "q3 : ---------Sample(Z)----\n", "\n", - "T : |0|1|Result Types|\n", + "T : |0|1|2|3|Result Types|\n", "Measurement results:\n", " {'1010': 1.0}\n", "[0, 1, 0]\n", - "T : |0|1|Result Types|\n", - " \n", - "q0 : -I-X--------------\n", - " \n", - "q1 : -X----------------\n", - " \n", - "q2 : -I----------------\n", - " \n", - "q3 : -----Sample(Z)----\n", + "T : |0|1|2|3|Result Types|\n", + " \n", + "q0 : -I---X----------------\n", + " | \n", + "q1 : -X-X-C-X--------------\n", + " \n", + "q2 : -I--------------------\n", + " \n", + "q3 : ---------Sample(Z)----\n", "\n", - "T : |0|1|Result Types|\n", + "T : |0|1|2|3|Result Types|\n", "Measurement results:\n", - " {'1100': 1.0}\n", + " {'0100': 1.0}\n", "[0, 1, 1]\n", - "T : |0|1|Result Types|\n", - " \n", - "q0 : -I-X--------------\n", - " \n", - "q1 : -X----------------\n", - " \n", - "q2 : -X----------------\n", - " \n", - "q3 : -----Sample(Z)----\n", + "T : |0|1|2|3|Result Types|\n", + " \n", + "q0 : -I---X----------------\n", + " | \n", + "q1 : -X-X-C-X--------------\n", + " \n", + "q2 : -X--------------------\n", + " \n", + "q3 : ---------Sample(Z)----\n", "\n", - "T : |0|1|Result Types|\n", + "T : |0|1|2|3|Result Types|\n", "Measurement results:\n", - " {'1110': 1.0}\n", + " {'0110': 1.0}\n", "[1, 0, 0]\n", - "T : |0|1|Result Types|\n", - " \n", - "q0 : -X-X--------------\n", - " \n", - "q1 : -I----------------\n", - " \n", - "q2 : -I----------------\n", - " \n", - "q3 : -----Sample(Z)----\n", + "T : |0|1|2|3|Result Types|\n", + " \n", + "q0 : -X---X----------------\n", + " | \n", + "q1 : -I-X-C-X--------------\n", + " \n", + "q2 : -I--------------------\n", + " \n", + "q3 : ---------Sample(Z)----\n", "\n", - "T : |0|1|Result Types|\n", + "T : |0|1|2|3|Result Types|\n", "Measurement results:\n", " {'0000': 1.0}\n", "[1, 0, 1]\n", - "T : |0|1|Result Types|\n", - " \n", - "q0 : -X-X--------------\n", - " \n", - "q1 : -I----------------\n", - " \n", - "q2 : -X----------------\n", - " \n", - "q3 : -----Sample(Z)----\n", + "T : |0|1|2|3|Result Types|\n", + " \n", + "q0 : -X---X----------------\n", + " | \n", + "q1 : -I-X-C-X--------------\n", + " \n", + "q2 : -X--------------------\n", + " \n", + "q3 : ---------Sample(Z)----\n", "\n", - "T : |0|1|Result Types|\n", + "T : |0|1|2|3|Result Types|\n", "Measurement results:\n", " {'0010': 1.0}\n", "[1, 1, 0]\n", - "T : |0|1|Result Types|\n", - " \n", - "q0 : -X-X--------------\n", - " \n", - "q1 : -X----------------\n", - " \n", - "q2 : -I----------------\n", - " \n", - "q3 : -----Sample(Z)----\n", + "T : |0|1|2|3|Result Types|\n", + " \n", + "q0 : -X---X----------------\n", + " | \n", + "q1 : -X-X-C-X--------------\n", + " \n", + "q2 : -I--------------------\n", + " \n", + "q3 : ---------Sample(Z)----\n", "\n", - "T : |0|1|Result Types|\n", + "T : |0|1|2|3|Result Types|\n", "Measurement results:\n", - " {'0100': 1.0}\n", + " {'1100': 1.0}\n", "[1, 1, 1]\n", - "T : |0|1|Result Types|\n", - " \n", - "q0 : -X-X--------------\n", - " \n", - "q1 : -X----------------\n", - " \n", - "q2 : -X----------------\n", - " \n", - "q3 : -----Sample(Z)----\n", + "T : |0|1|2|3|Result Types|\n", + " \n", + "q0 : -X---X----------------\n", + " | \n", + "q1 : -X-X-C-X--------------\n", + " \n", + "q2 : -X--------------------\n", + " \n", + "q3 : ---------Sample(Z)----\n", "\n", - "T : |0|1|Result Types|\n", + "T : |0|1|2|3|Result Types|\n", "Measurement results:\n", - " {'0110': 1.0}\n", + " {'1110': 1.0}\n", "This is a constant function\n", "These are the final outputs from the random circuits [0, 0, 0, 0, 0, 0, 0, 0]\n" ] @@ -942,17 +851,27 @@ ], "source": [ "n_qubits = 3\n", - "run_circuit = classical_checker(n_qubits)" + "run_circuit = classical_generator(n_qubits, random)" + ] + }, + { + "cell_type": "markdown", + "id": "aad4c729", + "metadata": {}, + "source": [ + "## Run Random Circuit Generator on Quantum Circuit\n", + "\n", + "Now we can run the random circuit we generated classically on a quantum circuit to compare and see if the results are the same. We measure the results and based on the output we can determine what type of function the random circuit was." ] }, { "cell_type": "code", - "execution_count": 353, - "id": "fc7519f0", + "execution_count": 122, + "id": "938174a9", "metadata": {}, "outputs": [], "source": [ - "def random_oracle(n_qubits,random_circuit):\n", + "def random_oracle(n_qubits, random_oracle):\n", " # create circuit \n", " circuit2 = Circuit()\n", " \n", @@ -962,7 +881,7 @@ " # create circuit and initialize states\n", " circuit2 = Circuit().h(range(n_qubits)).x(output_qubit).h(output_qubit)\n", " #add the random oracle to this circuit\n", - " circuit2.add_circuit(random_circuit, range(n_qubits))\n", + " circuit2.add_circuit(random_oracle, range(n_qubits))\n", " # place the h-gates again\n", " circuit2.h(range(n_qubits))\n", " \n", @@ -1016,27 +935,27 @@ }, { "cell_type": "code", - "execution_count": 354, - "id": "b5976a3c", + "execution_count": 123, + "id": "20002819", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "T : |0|1|2|Result Types|\n", - " \n", - "q0 : -H-X-H-Sample(Z)----\n", - " \n", - "q1 : -H-H---Sample(Z)----\n", - " \n", - "q2 : -H-H---Sample(Z)----\n", - " \n", - "q3 : -X-H----------------\n", + "T : |0|1|2|3|4|Result Types|\n", + " \n", + "q0 : -H---X-H---Sample(Z)----\n", + " | \n", + "q1 : -H-X-C-X-H-Sample(Z)----\n", + " \n", + "q2 : -H-H-------Sample(Z)----\n", + " \n", + "q3 : -X-H--------------------\n", "\n", - "T : |0|1|2|Result Types|\n", + "T : |0|1|2|3|4|Result Types|\n", "Measurement results:\n", - " {'0001': 0.48, '0000': 0.52}\n", + " {'0001': 0.52, '0000': 0.48}\n", "This is a constant function\n" ] } @@ -1045,6 +964,18 @@ "n_qubits = 3 \n", "oracle = random_oracle(n_qubits,run_circuit)" ] + }, + { + "cell_type": "markdown", + "id": "46748043", + "metadata": {}, + "source": [ + "## Comparing the Classical and Quantum Results\n", + "\n", + "Once you've run the classical and quantum version of the random circuit you can compare the results. If both correspond to the same type of function then we have found another to implement the constant or balanced function! \n", + "\n", + "You can keep generating more random circuits to see how the constant and balanced functions can be created including for circuits that are extremely large, example 10 qubits! " + ] } ], "metadata": { From 171421251f9b9a5cf049346f614fa557e7e25b08 Mon Sep 17 00:00:00 2001 From: tanishabassan Date: Thu, 18 Aug 2022 12:32:06 +0000 Subject: [PATCH 4/5] adding a deeper explanation for the measurement outcomes and a summary section --- .../Deutsch Jozsa Algorithm.ipynb | 431 ++++++++++-------- 1 file changed, 238 insertions(+), 193 deletions(-) diff --git a/examples/advanced_circuits_algorithms/Deutsch_Jozsa_Algorithm/Deutsch Jozsa Algorithm.ipynb b/examples/advanced_circuits_algorithms/Deutsch_Jozsa_Algorithm/Deutsch Jozsa Algorithm.ipynb index e5a12a54c..979ece8bc 100644 --- a/examples/advanced_circuits_algorithms/Deutsch_Jozsa_Algorithm/Deutsch Jozsa Algorithm.ipynb +++ b/examples/advanced_circuits_algorithms/Deutsch_Jozsa_Algorithm/Deutsch Jozsa Algorithm.ipynb @@ -2,8 +2,8 @@ "cells": [ { "cell_type": "code", - "execution_count": 52, - "id": "4cba78b7", + "execution_count": 126, + "id": "149c5945", "metadata": {}, "outputs": [], "source": [ @@ -14,7 +14,7 @@ }, { "cell_type": "markdown", - "id": "7cd50489", + "id": "cf89beab", "metadata": {}, "source": [ "# Deutsch-Jozsa Algorithm" @@ -22,7 +22,7 @@ }, { "cell_type": "markdown", - "id": "d755f2f3", + "id": "efa9159d", "metadata": {}, "source": [ "In this tutorial we introduce one of the first quantum algorithm’s developed by pioneers David Deutsch and Richard Jozsa. This algorithm showcases an efficient quantum solution to a problem that cannot be solved classically but instead can be solved using a quantum device. \n", @@ -35,35 +35,32 @@ "\n", "We make the assumption that the user is comfortable with the Python programming language, linear algebra and has some background knowledge about quantum computing. It is not necessary to have a physics background to understand this tutorial but if you’d like to dive deeper, some resources will be linked at the end of the tutorial. \n", "## Overview \n", - "1. Introduction to quantum algorithms \n", - "2. Deutsch's problem\n", - "3. Technical background for Deustch-Jozsa Algorithm \n", - "4. Circuit setup \n", - "5. Code \n", - " a. initialize circuit \n", - " b. create constant and balanced oracle \n", - " c. create random oracle \n", - " d. create general deustch-jozsa algorithm \n", - " e. create a classical random circuit generator \n", - " f. run random circuit through a deutsch-jozsa algorithm \n", - "6. Summary, next steps and resources\n", - "7. References" + "1. [Introduction to quantum algorithms](#quantum_algo) \n", + "2. [Deutsch's problem](#deutsch_problem)\n", + "3. [Technical background for Deustch-Jozsa Algorithm](#technical) \n", + "4. [Circuit setup](#setup) \n", + "5. [Code](#setup) \n", + "6. [Summary, next steps and resources](#summary)" ] }, { "cell_type": "markdown", - "id": "24570bf4", + "id": "305510e6", "metadata": {}, "source": [ + "\n", + "\n", "## Quantum Algorithms\n", "Quantum algorithms is an area of research closely tied to quantum computing. We develop quantum algorithms that can natively be implemented on a quantum device, usually in the form of creating quantum circuits. Just like classical circuits, quantum circuits allow for implementation of algorithms in a set of instructions usually in the form of gates that can manipulate the state of the qubit (quantum bit). Quantum algorithms take advantage of the natural quantum mechanical properties like superposition and entanglement and are inherently quantum in nature. These algorithms allow us to solve problems that cannot be attempted classically, such as the Deutsch-Jozsa Algorithm. " ] }, { "cell_type": "markdown", - "id": "2cb0d8b7", + "id": "032fc5fb", "metadata": {}, "source": [ + "\n", + "\n", "## Deutsch's Problem \n", "The algorithm proposed is solving a black box problem, trying to determine what the black box is the task at hand. The problem itself is not very applicable in real life but showcases an occasion where a quantum algorithm performs exponentially better than a classical one. \n", "\n", @@ -79,9 +76,11 @@ }, { "cell_type": "markdown", - "id": "323cd2c4", + "id": "fc4c47bc", "metadata": {}, "source": [ + "\n", + "\n", "## Technical Background for Deutsch-Jozsa Algorithm\n", "\n", "*If you are a unfamiliar with quantum mechanics, feel free to skip this section and go straight to the circuit setup.* \n", @@ -106,15 +105,15 @@ "\n", "$$|ψ_3〉=∑_z∑_x\\frac{(-1)^{x\\cdot{z} + f(x)}|z〉}{2^n}\\biggl[\\frac{ |0〉 − |1〉}{√2}\\biggr]$$\n", "\n", - "We can now measure and observe the results for the possible functions. For the two possible cases, if the function is constant then the measurement will observe all 0’s and if the function is anything else then it’s balanced. \n", + "We can now measure and observe the results for the possible functions. For the two possible cases, if the function is constant then the measurement will observe all 0’s, if the function is balanced then you will observe a mix of 1's and 0's and if you have both measurements present for a function the it's neither constant or balanced. \n", "\n", "*Reference: Nielsen & Chuang*\n" ] }, { "cell_type": "code", - "execution_count": 109, - "id": "6f81de36", + "execution_count": 127, + "id": "141694d4", "metadata": {}, "outputs": [], "source": [ @@ -141,9 +140,11 @@ } }, "cell_type": "markdown", - "id": "c79a1b57", + "id": "11cd78b0", "metadata": {}, "source": [ + "\n", + "\n", "## Circuit setup \n", "\n", "![Screen%20Shot%202022-06-17%20at%2011.10.56%20AM.png](attachment:Screen%20Shot%202022-06-17%20at%2011.10.56%20AM.png)\n", @@ -159,9 +160,10 @@ }, { "cell_type": "markdown", - "id": "65e8e672", + "id": "2c17c927", "metadata": {}, "source": [ + "\n", "## 2. Apply Hadamard gates\n", "\n", "Now for both our qubit registers we apply a Hadamard gate. The H-gate is a transformation that takes a qubit at a ground state like $∣0⟩$ or $∣1⟩$ and puts it into a superposition of 0 and 1. \n", @@ -173,8 +175,8 @@ }, { "cell_type": "code", - "execution_count": 110, - "id": "a98931c1", + "execution_count": 128, + "id": "c9720fbf", "metadata": {}, "outputs": [], "source": [ @@ -193,8 +195,8 @@ }, { "cell_type": "code", - "execution_count": 111, - "id": "f7a70e2a", + "execution_count": 129, + "id": "cd7164f7", "metadata": {}, "outputs": [ { @@ -224,7 +226,7 @@ }, { "cell_type": "markdown", - "id": "8831afbf", + "id": "c3e9dc4f", "metadata": {}, "source": [ "---------------------------------------------------------------------------------------------------------------------\n", @@ -241,7 +243,7 @@ }, { "cell_type": "markdown", - "id": "7a9468a8", + "id": "095dbfcb", "metadata": {}, "source": [ "## For a constant function: \n", @@ -251,8 +253,8 @@ }, { "cell_type": "code", - "execution_count": 112, - "id": "ad568b15", + "execution_count": 130, + "id": "b7d50ff1", "metadata": {}, "outputs": [], "source": [ @@ -281,8 +283,8 @@ }, { "cell_type": "code", - "execution_count": 113, - "id": "c2d8ccf3", + "execution_count": 131, + "id": "cfe24084", "metadata": {}, "outputs": [ { @@ -306,7 +308,7 @@ }, { "cell_type": "markdown", - "id": "c649c8dc", + "id": "d5466f14", "metadata": {}, "source": [ "---------------------------------------------------------------------------------------------------------------------\n", @@ -317,8 +319,8 @@ }, { "cell_type": "code", - "execution_count": 114, - "id": "118771e3", + "execution_count": 132, + "id": "4fb95f81", "metadata": {}, "outputs": [], "source": [ @@ -354,8 +356,8 @@ }, { "cell_type": "code", - "execution_count": 115, - "id": "57251c30", + "execution_count": 133, + "id": "629e798f", "metadata": {}, "outputs": [ { @@ -399,7 +401,7 @@ }, { "cell_type": "markdown", - "id": "f930e359", + "id": "d46b41fd", "metadata": {}, "source": [ "---------------------------------------------------------------------------------------------------------------------\n", @@ -415,8 +417,8 @@ }, { "cell_type": "code", - "execution_count": 116, - "id": "1953aacb", + "execution_count": 141, + "id": "280bd5e1", "metadata": {}, "outputs": [], "source": [ @@ -485,21 +487,23 @@ }, { "cell_type": "code", - "execution_count": 117, - "id": "60add186", + "execution_count": 142, + "id": "17eccc67", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "T : |0|1|2|\n", - " \n", - "q2 : ---X---\n", - " | \n", - "q3 : -X-C-X-\n", + "T : |0|1|\n", + " \n", + "q0 : -C---\n", + " | \n", + "q1 : -C---\n", + " | \n", + "q2 : -X-X-\n", "\n", - "T : |0|1|2|\n" + "T : |0|1|\n" ] } ], @@ -511,24 +515,46 @@ }, { "cell_type": "markdown", - "id": "b5a19f12", + "id": "257daa9b", "metadata": {}, "source": [ "## 4. Apply Hadamard gate to first qubit register\n", "\n", "After applying the quantum oracle a H-gate is applied to all the qubits in the first register. This is because applying the H-gate again takes the qubits out of a superposition state. \n", "\n", - "If the function was constant then the quantum state after the H-gate is applied should be the same as it’s initial state. \n", + "If the function was constant then the quantum state after the H-gate is applied should be the same as it’s initial state. This is because, if there are three qubits in the first register, then the initial quantum state looks as follows after the first set of H-gates have acted on it:\n", + "\n", + "$$\\frac{1}{\\sqrt{8}} \\times \\begin{bmatrix} 1\\\\ 1\\\\ 1\\\\ 1\\\\ 1\\\\ 1\\\\ 1\\\\ 1\\\\ \\end{bmatrix}$$\n", + "\n", + "But if the Boolean function returns all zeros or, alternatively, all ones then the state vector becomes equal to the left and right state vectors, respectively, as shown below:\n", + "\n", + "$$\\frac{1}{\\sqrt{8}} \\times \\begin{bmatrix} 1\\\\ 1\\\\ 1\\\\ 1\\\\ 1\\\\ 1\\\\ 1\\\\ 1\\\\ \\end{bmatrix}, \\frac{1}{\\sqrt{8}} \\times \\begin{bmatrix} -1\\\\ -1\\\\ -1\\\\ -1\\\\ -1\\\\ -1\\\\ -1\\\\ -1\\\\ \\end{bmatrix}$$\n", "\n", - "If the function is balanced a negative phase is added to exactly half the quantum states. This means the quantum states are orthogonal or perpendicular to each other. So when a H-gate is applied, the quantum state we end up with is orthogonal to the original state. \n", + "This means that when the Boolean function is constant, the state vector either remains the same or acquires a global phase, which in both cases results in the system returning back to its initial state.\n", "\n", - "When we measure the circuit, if the function was constant then the output will be all 0’s and if the function is balanced will be anything but all 0’s." + "If the function is balanced a negative phase is added to exactly half the quantum states which can be seen in the following example state vector:\n", + "\n", + "$$\\frac{1}{\\sqrt{8}} \\times \\begin{bmatrix} 1\\\\ -1\\\\ 1\\\\ -1\\\\ 1\\\\ -1\\\\ 1\\\\ -1\\\\ \\end{bmatrix}$$\n", + "\n", + "This can be easily shown to be orthogonal to the original state vector by projecting the resulting state vector onto the original state vector:\n", + "\n", + "$$\\frac{1}{\\sqrt{8}}\\times \\begin{bmatrix} 1 & -1 & 1 & -1 & 1 & -1 & 1 & -1 \\end{bmatrix} \\times \\frac{1}{\\sqrt{8}} \\times \\begin{bmatrix} 1\\\\ 1\\\\ 1\\\\ 1\\\\ 1\\\\ 1\\\\ 1\\\\ 1\\\\ \\end{bmatrix}=0$$\n", + "\n", + "which means that the resulting state vector is completely orthogonal to the original state vector and the resulting state vector will be anything but ∣000⟩ after the final set of H-gates are applied.\n", + "\n", + "Meanwhile, if the Boolean function is neither constant or balanced, then the resulting state vector becomes similar to the following:\n", + "\n", + "$$\\frac{1}{\\sqrt{8}}\\times \\begin{bmatrix} 1\\\\ 1\\\\ 1\\\\ 1\\\\ 1\\\\ -1\\\\ 1\\\\ -1\\\\ \\end{bmatrix}$$\n", + "\n", + "which can be easily seen to be neither zero or one when this state is projected onto the original state. This means that the resulting output (after the final set of H-gates have been applied) will be a combination of the ∣000⟩ state and an orthogonal state.\n", + "\n", + "**Note:** You have to keep in mind that in addition to the qubits in the first register, there is also the additional output qubit. This additional output qubit is not used for determining the classification of this Boolean function (constant, balanced, or neither) using this setup. " ] }, { "cell_type": "code", - "execution_count": 118, - "id": "de78817c", + "execution_count": 136, + "id": "4aad417b", "metadata": {}, "outputs": [], "source": [ @@ -567,8 +593,8 @@ }, { "cell_type": "code", - "execution_count": 119, - "id": "3b699922", + "execution_count": 137, + "id": "487c2dc1", "metadata": {}, "outputs": [ { @@ -576,32 +602,32 @@ "output_type": "stream", "text": [ "Measurement results:\n", - " {'00000000000': 0.14, '00000000001': 0.19, '00001000000': 0.13, '00001000001': 0.08, '11111000000': 0.12, '11111000001': 0.11, '11110000000': 0.15, '11110000001': 0.08}\n", - "T : |0|1| 2 |3|4|5|6|7|8|9|10|11|12|Result Types|\n", - " \n", - "q0 : -H-X---C-X-H--------------------Sample(Z)----\n", - " | \n", - "q1 : -H-X---|-C-X-H------------------Sample(Z)----\n", - " | | \n", - "q2 : -H-X---|-|-C-X-H----------------Sample(Z)----\n", - " | | | \n", - "q3 : -H-----|-|-|-C-H----------------Sample(Z)----\n", - " | | | | \n", - "q4 : -X-H-X-|-|-|-|-C-X---------------------------\n", - " | | | | | \n", - "q5 : -X-----|-|-|-|-|-C-X-------------------------\n", - " | | | | | | \n", - "q6 : -X-----|-|-|-|-|-|-C-X-----------------------\n", - " | | | | | | | \n", - "q7 : -------|-|-|-|-|-|-|-C-----------------------\n", - " | | | | | | | | \n", - "q8 : -------|-|-|-|-|-|-|-|-C---------------------\n", - " | | | | | | | | | \n", - "q9 : -X-----|-|-|-|-|-|-|-|-|--C--X---------------\n", - " | | | | | | | | | | \n", - "q10 : -------X-X-X-X-X-X-X-X-X--X------------------\n", + " {'00000000001': 0.17, '11111000000': 0.06, '11110000001': 0.08, '11110000000': 0.17, '00000000000': 0.13, '00001000001': 0.11, '11111000001': 0.11, '00001000000': 0.17}\n", + "T : |0| 1 | 2 |3|4|5|6|7|8|9|10|Result Types|\n", + " \n", + "q0 : -H---C-H--------------------Sample(Z)----\n", + " | \n", + "q1 : -H-X-|---C-X-H--------------Sample(Z)----\n", + " | | \n", + "q2 : -H-X-|---|-C-X-H------------Sample(Z)----\n", + " | | | \n", + "q3 : -H---|---|-|-C-H------------Sample(Z)----\n", + " | | | | \n", + "q4 : -X-H-|-X-|-|-|-C-X-----------------------\n", + " | | | | | \n", + "q5 : -X---|---|-|-|-|-C-X---------------------\n", + " | | | | | | \n", + "q6 : -----|---|-|-|-|-|-C---------------------\n", + " | | | | | | | \n", + "q7 : -----|---|-|-|-|-|-|-C-------------------\n", + " | | | | | | | | \n", + "q8 : -X---|---|-|-|-|-|-|-|-C-X---------------\n", + " | | | | | | | | | \n", + "q9 : -----|---|-|-|-|-|-|-|-|-C---------------\n", + " | | | | | | | | | | \n", + "q10 : -----X---X-X-X-X-X-X-X-X-X---------------\n", "\n", - "T : |0|1| 2 |3|4|5|6|7|8|9|10|11|12|Result Types|\n" + "T : |0| 1 | 2 |3|4|5|6|7|8|9|10|Result Types|\n" ] } ], @@ -614,7 +640,7 @@ }, { "cell_type": "markdown", - "id": "f9f6b4e7", + "id": "4c48de35", "metadata": {}, "source": [ "## Classicaly Run the Random Circuit Generator \n", @@ -623,13 +649,13 @@ "\n", "If n = 3 then we get a result of 8 different circuits. We then determine if these circuits are constant, balanced or neither at the end so we can compare it with results when we run this circuit but this time on a quantum circuit.\n", "\n", - "#### *To generate a random circuit again run the random_oracle function again!*" + "#### *To generate a new random circuit run the random_oracle function again!*" ] }, { "cell_type": "code", - "execution_count": 120, - "id": "6f18e776", + "execution_count": 143, + "id": "9bcab5a1", "metadata": {}, "outputs": [], "source": [ @@ -724,8 +750,8 @@ }, { "cell_type": "code", - "execution_count": 124, - "id": "adaf82c5", + "execution_count": 144, + "id": "0e162664", "metadata": {}, "outputs": [ { @@ -733,115 +759,115 @@ "output_type": "stream", "text": [ "[0, 0, 0]\n", - "T : |0|1|2|3|Result Types|\n", - " \n", - "q0 : -I---X----------------\n", - " | \n", - "q1 : -I-X-C-X--------------\n", - " \n", - "q2 : -I--------------------\n", - " \n", - "q3 : ---------Sample(Z)----\n", + "T : |0|1|2|Result Types|\n", + " \n", + "q0 : -I-C----------------\n", + " | \n", + "q1 : -I-C----------------\n", + " | \n", + "q2 : -I-X-X--------------\n", + " \n", + "q3 : -------Sample(Z)----\n", "\n", - "T : |0|1|2|3|Result Types|\n", + "T : |0|1|2|Result Types|\n", "Measurement results:\n", - " {'1000': 1.0}\n", + " {'0010': 1.0}\n", "[0, 0, 1]\n", - "T : |0|1|2|3|Result Types|\n", - " \n", - "q0 : -I---X----------------\n", - " | \n", - "q1 : -I-X-C-X--------------\n", - " \n", - "q2 : -X--------------------\n", - " \n", - "q3 : ---------Sample(Z)----\n", + "T : |0|1|2|Result Types|\n", + " \n", + "q0 : -I-C----------------\n", + " | \n", + "q1 : -I-C----------------\n", + " | \n", + "q2 : -X-X-X--------------\n", + " \n", + "q3 : -------Sample(Z)----\n", "\n", - "T : |0|1|2|3|Result Types|\n", + "T : |0|1|2|Result Types|\n", "Measurement results:\n", - " {'1010': 1.0}\n", + " {'0000': 1.0}\n", "[0, 1, 0]\n", - "T : |0|1|2|3|Result Types|\n", - " \n", - "q0 : -I---X----------------\n", - " | \n", - "q1 : -X-X-C-X--------------\n", - " \n", - "q2 : -I--------------------\n", - " \n", - "q3 : ---------Sample(Z)----\n", + "T : |0|1|2|Result Types|\n", + " \n", + "q0 : -I-C----------------\n", + " | \n", + "q1 : -X-C----------------\n", + " | \n", + "q2 : -I-X-X--------------\n", + " \n", + "q3 : -------Sample(Z)----\n", "\n", - "T : |0|1|2|3|Result Types|\n", + "T : |0|1|2|Result Types|\n", "Measurement results:\n", - " {'0100': 1.0}\n", + " {'0110': 1.0}\n", "[0, 1, 1]\n", - "T : |0|1|2|3|Result Types|\n", - " \n", - "q0 : -I---X----------------\n", - " | \n", - "q1 : -X-X-C-X--------------\n", - " \n", - "q2 : -X--------------------\n", - " \n", - "q3 : ---------Sample(Z)----\n", + "T : |0|1|2|Result Types|\n", + " \n", + "q0 : -I-C----------------\n", + " | \n", + "q1 : -X-C----------------\n", + " | \n", + "q2 : -X-X-X--------------\n", + " \n", + "q3 : -------Sample(Z)----\n", "\n", - "T : |0|1|2|3|Result Types|\n", + "T : |0|1|2|Result Types|\n", "Measurement results:\n", - " {'0110': 1.0}\n", + " {'0100': 1.0}\n", "[1, 0, 0]\n", - "T : |0|1|2|3|Result Types|\n", - " \n", - "q0 : -X---X----------------\n", - " | \n", - "q1 : -I-X-C-X--------------\n", - " \n", - "q2 : -I--------------------\n", - " \n", - "q3 : ---------Sample(Z)----\n", + "T : |0|1|2|Result Types|\n", + " \n", + "q0 : -X-C----------------\n", + " | \n", + "q1 : -I-C----------------\n", + " | \n", + "q2 : -I-X-X--------------\n", + " \n", + "q3 : -------Sample(Z)----\n", "\n", - "T : |0|1|2|3|Result Types|\n", + "T : |0|1|2|Result Types|\n", "Measurement results:\n", - " {'0000': 1.0}\n", + " {'1010': 1.0}\n", "[1, 0, 1]\n", - "T : |0|1|2|3|Result Types|\n", - " \n", - "q0 : -X---X----------------\n", - " | \n", - "q1 : -I-X-C-X--------------\n", - " \n", - "q2 : -X--------------------\n", - " \n", - "q3 : ---------Sample(Z)----\n", + "T : |0|1|2|Result Types|\n", + " \n", + "q0 : -X-C----------------\n", + " | \n", + "q1 : -I-C----------------\n", + " | \n", + "q2 : -X-X-X--------------\n", + " \n", + "q3 : -------Sample(Z)----\n", "\n", - "T : |0|1|2|3|Result Types|\n", + "T : |0|1|2|Result Types|\n", "Measurement results:\n", - " {'0010': 1.0}\n", + " {'1000': 1.0}\n", "[1, 1, 0]\n", - "T : |0|1|2|3|Result Types|\n", - " \n", - "q0 : -X---X----------------\n", - " | \n", - "q1 : -X-X-C-X--------------\n", - " \n", - "q2 : -I--------------------\n", - " \n", - "q3 : ---------Sample(Z)----\n", + "T : |0|1|2|Result Types|\n", + " \n", + "q0 : -X-C----------------\n", + " | \n", + "q1 : -X-C----------------\n", + " | \n", + "q2 : -I-X-X--------------\n", + " \n", + "q3 : -------Sample(Z)----\n", "\n", - "T : |0|1|2|3|Result Types|\n", + "T : |0|1|2|Result Types|\n", "Measurement results:\n", " {'1100': 1.0}\n", "[1, 1, 1]\n", - "T : |0|1|2|3|Result Types|\n", - " \n", - "q0 : -X---X----------------\n", - " | \n", - "q1 : -X-X-C-X--------------\n", - " \n", - "q2 : -X--------------------\n", - " \n", - "q3 : ---------Sample(Z)----\n", + "T : |0|1|2|Result Types|\n", + " \n", + "q0 : -X-C----------------\n", + " | \n", + "q1 : -X-C----------------\n", + " | \n", + "q2 : -X-X-X--------------\n", + " \n", + "q3 : -------Sample(Z)----\n", "\n", - "T : |0|1|2|3|Result Types|\n", + "T : |0|1|2|Result Types|\n", "Measurement results:\n", " {'1110': 1.0}\n", "This is a constant function\n", @@ -856,7 +882,7 @@ }, { "cell_type": "markdown", - "id": "aad4c729", + "id": "a516d933", "metadata": {}, "source": [ "## Run Random Circuit Generator on Quantum Circuit\n", @@ -866,8 +892,8 @@ }, { "cell_type": "code", - "execution_count": 122, - "id": "938174a9", + "execution_count": 145, + "id": "6bebb980", "metadata": {}, "outputs": [], "source": [ @@ -935,27 +961,27 @@ }, { "cell_type": "code", - "execution_count": 123, - "id": "20002819", + "execution_count": 146, + "id": "99f22a56", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "T : |0|1|2|3|4|Result Types|\n", - " \n", - "q0 : -H---X-H---Sample(Z)----\n", - " | \n", - "q1 : -H-X-C-X-H-Sample(Z)----\n", - " \n", - "q2 : -H-H-------Sample(Z)----\n", - " \n", - "q3 : -X-H--------------------\n", + "T : |0|1|2|3|Result Types|\n", + " \n", + "q0 : -H-C-H---Sample(Z)----\n", + " | \n", + "q1 : -H-C-H---Sample(Z)----\n", + " | \n", + "q2 : -H-X-X-H-Sample(Z)----\n", + " \n", + "q3 : -X-H------------------\n", "\n", - "T : |0|1|2|3|4|Result Types|\n", + "T : |0|1|2|3|Result Types|\n", "Measurement results:\n", - " {'0001': 0.52, '0000': 0.48}\n", + " {'0001': 0.53, '0000': 0.47}\n", "This is a constant function\n" ] } @@ -967,15 +993,34 @@ }, { "cell_type": "markdown", - "id": "46748043", + "id": "c582dc85", "metadata": {}, "source": [ + "\n", + "\n", "## Comparing the Classical and Quantum Results\n", "\n", "Once you've run the classical and quantum version of the random circuit you can compare the results. If both correspond to the same type of function then we have found another to implement the constant or balanced function! \n", "\n", "You can keep generating more random circuits to see how the constant and balanced functions can be created including for circuits that are extremely large, example 10 qubits! " ] + }, + { + "cell_type": "markdown", + "id": "82a23325", + "metadata": {}, + "source": [ + "## Next Steps \n", + "\n", + "This was an introduction to one of the first quantum computing algorithms implemented as a circuit. The goal of this tutorial is to give an in-depth explantion on how quantum algorithms are developed, where we achieve computational speedup and how to create your own version of the Deutsch-Jozsa aglorithm. \n", + "\n", + "**Here are some resources to dive deeper:** \n", + "[Introduction to quantum computing using Qiskit](https://qiskit.org/textbook/ch-states/introduction.html) \n", + "\n", + "[Introduction to quantum computing TED Talk](https://www.youtube.com/watch?v=QuR969uMICM) \n", + "\n", + "[PDF version of Michael A. Nielsen & Isaac L. Chuang Quantum Computation and Quantim Information textbook](http://mmrc.amss.cas.cn/tlb/201702/W020170224608149940643.pdf)\n" + ] } ], "metadata": { From 160a044608f102239abfcdcf7d774c698297e9f1 Mon Sep 17 00:00:00 2001 From: tanishabassan Date: Tue, 23 Aug 2022 05:18:53 +0000 Subject: [PATCH 5/5] making minor editorial and grammar changes --- .../Deutsch Jozsa Algorithm.ipynb | 376 +++++++++--------- 1 file changed, 183 insertions(+), 193 deletions(-) diff --git a/examples/advanced_circuits_algorithms/Deutsch_Jozsa_Algorithm/Deutsch Jozsa Algorithm.ipynb b/examples/advanced_circuits_algorithms/Deutsch_Jozsa_Algorithm/Deutsch Jozsa Algorithm.ipynb index 979ece8bc..90b29f911 100644 --- a/examples/advanced_circuits_algorithms/Deutsch_Jozsa_Algorithm/Deutsch Jozsa Algorithm.ipynb +++ b/examples/advanced_circuits_algorithms/Deutsch_Jozsa_Algorithm/Deutsch Jozsa Algorithm.ipynb @@ -2,8 +2,8 @@ "cells": [ { "cell_type": "code", - "execution_count": 126, - "id": "149c5945", + "execution_count": 152, + "id": "1c2b7f83", "metadata": {}, "outputs": [], "source": [ @@ -14,7 +14,7 @@ }, { "cell_type": "markdown", - "id": "cf89beab", + "id": "7447cb91", "metadata": {}, "source": [ "# Deutsch-Jozsa Algorithm" @@ -22,7 +22,7 @@ }, { "cell_type": "markdown", - "id": "efa9159d", + "id": "5fc92ae8", "metadata": {}, "source": [ "In this tutorial we introduce one of the first quantum algorithm’s developed by pioneers David Deutsch and Richard Jozsa. This algorithm showcases an efficient quantum solution to a problem that cannot be solved classically but instead can be solved using a quantum device. \n", @@ -45,7 +45,7 @@ }, { "cell_type": "markdown", - "id": "305510e6", + "id": "6f30de00", "metadata": {}, "source": [ "\n", @@ -56,7 +56,7 @@ }, { "cell_type": "markdown", - "id": "032fc5fb", + "id": "b54b6e03", "metadata": {}, "source": [ "\n", @@ -64,19 +64,19 @@ "## Deutsch's Problem \n", "The algorithm proposed is solving a black box problem, trying to determine what the black box is the task at hand. The problem itself is not very applicable in real life but showcases an occasion where a quantum algorithm performs exponentially better than a classical one. \n", "\n", - "Let $Uf$ be an oracle (black box) that computes a Boolean function which only takes binary inputs (0’s or 1’s). These functions can be represented as $f: {0, 1}^n → {0, 1}$. This oracle evaluates two types of functions, constant or balanced. \n", + "Let $U_f$ be an oracle (black box) that computes a Boolean function which only takes binary inputs (0’s or 1’s). These functions can be represented as $f: {0, 1}^n → {0, 1}$. This oracle evaluates two types of functions, constant or balanced. \n", "\n", "A constant function takes any input and returns only 0’s or only 1’s and a balanced function takes any input and returns exactly half 0’s and half 1’s. \n", "\n", - "**Constant:** 011010 → $Uf$ → 000000 \n", - "**Balanced:** 000011 → $Uf$ → 111000\n", + "**Constant:** 011010 → $U_f$ → 000000 \n", + "**Balanced:** 000011 → $U_f$ → 111000\n", "\n", - "The goal is to determine what type of function is $Uf$ based on only the outputs. If the input is as large as $2^n$ then the amount of queries a classical computer will have to make is $2n/2+1$. We can see for a large enough n this problem scales exponentially and becomes inefficient to solve classically. However, leveraging a quantum algorithm we only need to query the oracle once to determine the type of function for $Uf$. This is possible because the state of its output might be in a coherent superposition of states corresponding to different answers, each which solves the problem (Deutsch 1992). \n" + "The goal is to determine what type of function is $U_f$ based on only the outputs. If the input is as large as $2^n$ then the amount of queries a classical computer will have to make is $2n/2+1$. We can see for a large enough n this problem scales exponentially and becomes inefficient to solve classically. However, leveraging a quantum algorithm we only need to query the oracle once to determine the type of function for $U_f$. This is possible because the state of its output might be in a coherent superposition of states corresponding to different answers, each which solves the problem (Deutsch 1992). \n" ] }, { "cell_type": "markdown", - "id": "fc4c47bc", + "id": "e1be5198", "metadata": {}, "source": [ "\n", @@ -93,7 +93,7 @@ "\n", "$$|ψ_1〉 = ∑_{x∈{0,1}^n} \\frac{|x〉}{√2^n} \\biggl[\\frac{ |0〉 − |1〉}{√2}\\biggr]$$\n", "\n", - "The query register is in a superposition of all possible values and the answer register is in a superposition of 0 and 1. The next step is to evaluate function $f$ for the oracle $Uf$ for the inputs $∣x,y〉→∣x,y⊕f(x)〉$giving you an output of\n", + "The query register is in a superposition of all possible values and the answer register is in a superposition of 0 and 1. The next step is to evaluate function $f$ for the oracle $U_f$ for the inputs $∣x,y〉→∣x,y⊕f(x)〉$giving you an output of\n", "\n", "$$ |ψ_2〉 =∑_x\\frac{(-1)^{f(x)}|x〉}{√2^n}\\biggl[\\frac{ |0〉 − |1〉}{√2}\\biggr]$$\n", "\n", @@ -105,15 +105,15 @@ "\n", "$$|ψ_3〉=∑_z∑_x\\frac{(-1)^{x\\cdot{z} + f(x)}|z〉}{2^n}\\biggl[\\frac{ |0〉 − |1〉}{√2}\\biggr]$$\n", "\n", - "We can now measure and observe the results for the possible functions. For the two possible cases, if the function is constant then the measurement will observe all 0’s, if the function is balanced then you will observe a mix of 1's and 0's and if you have both measurements present for a function the it's neither constant or balanced. \n", + "We can now measure and observe the results for the possible functions. For the two possible cases, if the function is constant then the measurement will observe all 0’s for the first qubit register and if the function is balanced then you will observe an equal mix of 1's and 0's for the first register and if you have both types of measurements present for a function the it's neither constant or balanced. \n", "\n", "*Reference: Nielsen & Chuang*\n" ] }, { "cell_type": "code", - "execution_count": 127, - "id": "141694d4", + "execution_count": 153, + "id": "bf749e4c", "metadata": {}, "outputs": [], "source": [ @@ -140,7 +140,7 @@ } }, "cell_type": "markdown", - "id": "11cd78b0", + "id": "9e9266c2", "metadata": {}, "source": [ "\n", @@ -160,7 +160,7 @@ }, { "cell_type": "markdown", - "id": "2c17c927", + "id": "6c9d7774", "metadata": {}, "source": [ "\n", @@ -175,8 +175,8 @@ }, { "cell_type": "code", - "execution_count": 128, - "id": "c9720fbf", + "execution_count": 154, + "id": "0e246d07", "metadata": {}, "outputs": [], "source": [ @@ -195,8 +195,8 @@ }, { "cell_type": "code", - "execution_count": 129, - "id": "cd7164f7", + "execution_count": 155, + "id": "f8476b46", "metadata": {}, "outputs": [ { @@ -226,7 +226,7 @@ }, { "cell_type": "markdown", - "id": "c3e9dc4f", + "id": "3e3c3216", "metadata": {}, "source": [ "---------------------------------------------------------------------------------------------------------------------\n", @@ -243,18 +243,18 @@ }, { "cell_type": "markdown", - "id": "095dbfcb", + "id": "e6361357", "metadata": {}, "source": [ - "## For a constant function: \n", + "### For a constant function \n", "1. if $f(x) = 0$, then apply the I gate to the qubit in second register. \n", "2. if $f(x) = 1$, then apply the X gate to the qubit in second register. " ] }, { "cell_type": "code", - "execution_count": 130, - "id": "b7d50ff1", + "execution_count": 156, + "id": "f0e0b238", "metadata": {}, "outputs": [], "source": [ @@ -283,8 +283,8 @@ }, { "cell_type": "code", - "execution_count": 131, - "id": "cfe24084", + "execution_count": 157, + "id": "309e238a", "metadata": {}, "outputs": [ { @@ -308,19 +308,19 @@ }, { "cell_type": "markdown", - "id": "d5466f14", + "id": "953b206b", "metadata": {}, "source": [ "---------------------------------------------------------------------------------------------------------------------\n", - "## For a balanced function:\n", + "### For a balanced function\n", "\n", "Apply a CNOT gate to every qubit in the first register and set the qubit in the second register as the target. Use a random number generator to randomly choose which qubits to add an X - gate before and after the CNOT gate." ] }, { "cell_type": "code", - "execution_count": 132, - "id": "4fb95f81", + "execution_count": 158, + "id": "72a2d2b8", "metadata": {}, "outputs": [], "source": [ @@ -356,8 +356,8 @@ }, { "cell_type": "code", - "execution_count": 133, - "id": "629e798f", + "execution_count": 159, + "id": "428a40cc", "metadata": {}, "outputs": [ { @@ -401,24 +401,26 @@ }, { "cell_type": "markdown", - "id": "d46b41fd", + "id": "916d1bdd", "metadata": {}, "source": [ "---------------------------------------------------------------------------------------------------------------------\n", "\n", - "## For a random function:\n", + "\n", + "\n", + "### For a random function\n", "\n", "We have created a random oracle generator to showcase the many different ways a constant or balanced oracle can be made using just X, CNOT and CCNOT gates. When running this function, you can have 3 different outcomes. Either a constant function, a balanced function or neither. \n", "\n", - "We create a list of different types of gates you can apply, the X gate a single gate and CNOT and CCNOT require multiple gates. The CCNOT is a 3 qubit gate, it's similar to CNOT except you have 2 control qubits and 1 target qubit. \n", + "We create a list of different types of gates you can apply, the X gate, which is a single qubit gate, and CNOT and CCNOT gates, which are multiple qubit gates. \n", "\n", "We randomly choose which type of gates to apply and then randomly apply gates on different qubits to see what kind of function has been created. " ] }, { "cell_type": "code", - "execution_count": 141, - "id": "280bd5e1", + "execution_count": 170, + "id": "3147f8d1", "metadata": {}, "outputs": [], "source": [ @@ -487,23 +489,21 @@ }, { "cell_type": "code", - "execution_count": 142, - "id": "17eccc67", + "execution_count": 171, + "id": "6aa1159b", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "T : |0|1|\n", - " \n", - "q0 : -C---\n", - " | \n", - "q1 : -C---\n", - " | \n", - "q2 : -X-X-\n", + "T : |0|1|2|\n", + " \n", + "q2 : -X-C-X-\n", + " | \n", + "q4 : ---X---\n", "\n", - "T : |0|1|\n" + "T : |0|1|2|\n" ] } ], @@ -515,14 +515,14 @@ }, { "cell_type": "markdown", - "id": "257daa9b", + "id": "84eb4276", "metadata": {}, "source": [ "## 4. Apply Hadamard gate to first qubit register\n", "\n", "After applying the quantum oracle a H-gate is applied to all the qubits in the first register. This is because applying the H-gate again takes the qubits out of a superposition state. \n", "\n", - "If the function was constant then the quantum state after the H-gate is applied should be the same as it’s initial state. This is because, if there are three qubits in the first register, then the initial quantum state looks as follows after the first set of H-gates have acted on it:\n", + "If the function was constant then the quantum state after the H-gates are applied should be the same as it’s initial state. This is because, if there are three qubits in the first register, then the initial quantum state looks as follows after the first set of H-gates have acted on it:\n", "\n", "$$\\frac{1}{\\sqrt{8}} \\times \\begin{bmatrix} 1\\\\ 1\\\\ 1\\\\ 1\\\\ 1\\\\ 1\\\\ 1\\\\ 1\\\\ \\end{bmatrix}$$\n", "\n", @@ -553,8 +553,8 @@ }, { "cell_type": "code", - "execution_count": 136, - "id": "4aad417b", + "execution_count": 162, + "id": "9fbfab91", "metadata": {}, "outputs": [], "source": [ @@ -593,8 +593,8 @@ }, { "cell_type": "code", - "execution_count": 137, - "id": "487c2dc1", + "execution_count": 163, + "id": "7b0dc6da", "metadata": {}, "outputs": [ { @@ -602,32 +602,20 @@ "output_type": "stream", "text": [ "Measurement results:\n", - " {'00000000001': 0.17, '11111000000': 0.06, '11110000001': 0.08, '11110000000': 0.17, '00000000000': 0.13, '00001000001': 0.11, '11111000001': 0.11, '00001000000': 0.17}\n", - "T : |0| 1 | 2 |3|4|5|6|7|8|9|10|Result Types|\n", - " \n", - "q0 : -H---C-H--------------------Sample(Z)----\n", - " | \n", - "q1 : -H-X-|---C-X-H--------------Sample(Z)----\n", - " | | \n", - "q2 : -H-X-|---|-C-X-H------------Sample(Z)----\n", - " | | | \n", - "q3 : -H---|---|-|-C-H------------Sample(Z)----\n", - " | | | | \n", - "q4 : -X-H-|-X-|-|-|-C-X-----------------------\n", - " | | | | | \n", - "q5 : -X---|---|-|-|-|-C-X---------------------\n", - " | | | | | | \n", - "q6 : -----|---|-|-|-|-|-C---------------------\n", - " | | | | | | | \n", - "q7 : -----|---|-|-|-|-|-|-C-------------------\n", - " | | | | | | | | \n", - "q8 : -X---|---|-|-|-|-|-|-|-C-X---------------\n", - " | | | | | | | | | \n", - "q9 : -----|---|-|-|-|-|-|-|-|-C---------------\n", - " | | | | | | | | | | \n", - "q10 : -----X---X-X-X-X-X-X-X-X-X---------------\n", + " {'00000': 0.52, '00001': 0.48}\n", + "T : |0|1|2|Result Types|\n", + " \n", + "q0 : -H-X-H-Sample(Z)----\n", + " \n", + "q1 : -H-H---Sample(Z)----\n", + " \n", + "q2 : -H-H---Sample(Z)----\n", + " \n", + "q3 : -H-H---Sample(Z)----\n", + " \n", + "q4 : -X-H----------------\n", "\n", - "T : |0| 1 | 2 |3|4|5|6|7|8|9|10|Result Types|\n" + "T : |0|1|2|Result Types|\n" ] } ], @@ -640,22 +628,22 @@ }, { "cell_type": "markdown", - "id": "4c48de35", + "id": "bca3e73d", "metadata": {}, "source": [ "## Classicaly Run the Random Circuit Generator \n", "\n", - "The function classical_generator takes a random oracle and applies it to $2^n-1$ possible combinations where n is the number of qubits you've initialized. We can create a classical circuit by removing the Hadamard gates because without putting any qubits in superposition, the circuit can't display quantum mechanical properties. \n", + "The function classical_generator takes a random oracle and applies it to $2^n$ possible combinations where n is the number of qubits you've initialized. We can create a classical circuit by removing the Hadamard gates because without putting any qubits in superposition, the circuit can't display quantum mechanical properties. \n", "\n", "If n = 3 then we get a result of 8 different circuits. We then determine if these circuits are constant, balanced or neither at the end so we can compare it with results when we run this circuit but this time on a quantum circuit.\n", "\n", - "#### *To generate a new random circuit run the random_oracle function again!*" + "#### *To generate a new random circuit run the [random oracle](#random) again!*" ] }, { "cell_type": "code", - "execution_count": 143, - "id": "9bcab5a1", + "execution_count": 172, + "id": "9ce8d8a9", "metadata": {}, "outputs": [], "source": [ @@ -750,8 +738,8 @@ }, { "cell_type": "code", - "execution_count": 144, - "id": "0e162664", + "execution_count": 173, + "id": "7a252e2b", "metadata": {}, "outputs": [ { @@ -759,115 +747,115 @@ "output_type": "stream", "text": [ "[0, 0, 0]\n", - "T : |0|1|2|Result Types|\n", - " \n", - "q0 : -I-C----------------\n", - " | \n", - "q1 : -I-C----------------\n", - " | \n", - "q2 : -I-X-X--------------\n", - " \n", - "q3 : -------Sample(Z)----\n", + "T : |0|1|2|3|Result Types|\n", + " \n", + "q0 : -I-X-C-X--------------\n", + " | \n", + "q1 : -I---X----------------\n", + " \n", + "q2 : -I--------------------\n", + " \n", + "q3 : ---------Sample(Z)----\n", "\n", - "T : |0|1|2|Result Types|\n", + "T : |0|1|2|3|Result Types|\n", "Measurement results:\n", - " {'0010': 1.0}\n", + " {'0100': 1.0}\n", "[0, 0, 1]\n", - "T : |0|1|2|Result Types|\n", - " \n", - "q0 : -I-C----------------\n", - " | \n", - "q1 : -I-C----------------\n", - " | \n", - "q2 : -X-X-X--------------\n", - " \n", - "q3 : -------Sample(Z)----\n", + "T : |0|1|2|3|Result Types|\n", + " \n", + "q0 : -I-X-C-X--------------\n", + " | \n", + "q1 : -I---X----------------\n", + " \n", + "q2 : -X--------------------\n", + " \n", + "q3 : ---------Sample(Z)----\n", "\n", - "T : |0|1|2|Result Types|\n", + "T : |0|1|2|3|Result Types|\n", "Measurement results:\n", - " {'0000': 1.0}\n", + " {'0110': 1.0}\n", "[0, 1, 0]\n", - "T : |0|1|2|Result Types|\n", - " \n", - "q0 : -I-C----------------\n", - " | \n", - "q1 : -X-C----------------\n", - " | \n", - "q2 : -I-X-X--------------\n", - " \n", - "q3 : -------Sample(Z)----\n", + "T : |0|1|2|3|Result Types|\n", + " \n", + "q0 : -I-X-C-X--------------\n", + " | \n", + "q1 : -X---X----------------\n", + " \n", + "q2 : -I--------------------\n", + " \n", + "q3 : ---------Sample(Z)----\n", "\n", - "T : |0|1|2|Result Types|\n", + "T : |0|1|2|3|Result Types|\n", "Measurement results:\n", - " {'0110': 1.0}\n", + " {'0000': 1.0}\n", "[0, 1, 1]\n", - "T : |0|1|2|Result Types|\n", - " \n", - "q0 : -I-C----------------\n", - " | \n", - "q1 : -X-C----------------\n", - " | \n", - "q2 : -X-X-X--------------\n", - " \n", - "q3 : -------Sample(Z)----\n", + "T : |0|1|2|3|Result Types|\n", + " \n", + "q0 : -I-X-C-X--------------\n", + " | \n", + "q1 : -X---X----------------\n", + " \n", + "q2 : -X--------------------\n", + " \n", + "q3 : ---------Sample(Z)----\n", "\n", - "T : |0|1|2|Result Types|\n", + "T : |0|1|2|3|Result Types|\n", "Measurement results:\n", - " {'0100': 1.0}\n", + " {'0010': 1.0}\n", "[1, 0, 0]\n", - "T : |0|1|2|Result Types|\n", - " \n", - "q0 : -X-C----------------\n", - " | \n", - "q1 : -I-C----------------\n", - " | \n", - "q2 : -I-X-X--------------\n", - " \n", - "q3 : -------Sample(Z)----\n", + "T : |0|1|2|3|Result Types|\n", + " \n", + "q0 : -X-X-C-X--------------\n", + " | \n", + "q1 : -I---X----------------\n", + " \n", + "q2 : -I--------------------\n", + " \n", + "q3 : ---------Sample(Z)----\n", "\n", - "T : |0|1|2|Result Types|\n", + "T : |0|1|2|3|Result Types|\n", "Measurement results:\n", - " {'1010': 1.0}\n", + " {'1000': 1.0}\n", "[1, 0, 1]\n", - "T : |0|1|2|Result Types|\n", - " \n", - "q0 : -X-C----------------\n", - " | \n", - "q1 : -I-C----------------\n", - " | \n", - "q2 : -X-X-X--------------\n", - " \n", - "q3 : -------Sample(Z)----\n", + "T : |0|1|2|3|Result Types|\n", + " \n", + "q0 : -X-X-C-X--------------\n", + " | \n", + "q1 : -I---X----------------\n", + " \n", + "q2 : -X--------------------\n", + " \n", + "q3 : ---------Sample(Z)----\n", "\n", - "T : |0|1|2|Result Types|\n", + "T : |0|1|2|3|Result Types|\n", "Measurement results:\n", - " {'1000': 1.0}\n", + " {'1010': 1.0}\n", "[1, 1, 0]\n", - "T : |0|1|2|Result Types|\n", - " \n", - "q0 : -X-C----------------\n", - " | \n", - "q1 : -X-C----------------\n", - " | \n", - "q2 : -I-X-X--------------\n", - " \n", - "q3 : -------Sample(Z)----\n", + "T : |0|1|2|3|Result Types|\n", + " \n", + "q0 : -X-X-C-X--------------\n", + " | \n", + "q1 : -X---X----------------\n", + " \n", + "q2 : -I--------------------\n", + " \n", + "q3 : ---------Sample(Z)----\n", "\n", - "T : |0|1|2|Result Types|\n", + "T : |0|1|2|3|Result Types|\n", "Measurement results:\n", " {'1100': 1.0}\n", "[1, 1, 1]\n", - "T : |0|1|2|Result Types|\n", - " \n", - "q0 : -X-C----------------\n", - " | \n", - "q1 : -X-C----------------\n", - " | \n", - "q2 : -X-X-X--------------\n", - " \n", - "q3 : -------Sample(Z)----\n", + "T : |0|1|2|3|Result Types|\n", + " \n", + "q0 : -X-X-C-X--------------\n", + " | \n", + "q1 : -X---X----------------\n", + " \n", + "q2 : -X--------------------\n", + " \n", + "q3 : ---------Sample(Z)----\n", "\n", - "T : |0|1|2|Result Types|\n", + "T : |0|1|2|3|Result Types|\n", "Measurement results:\n", " {'1110': 1.0}\n", "This is a constant function\n", @@ -882,7 +870,7 @@ }, { "cell_type": "markdown", - "id": "a516d933", + "id": "a7e8dda4", "metadata": {}, "source": [ "## Run Random Circuit Generator on Quantum Circuit\n", @@ -892,8 +880,8 @@ }, { "cell_type": "code", - "execution_count": 145, - "id": "6bebb980", + "execution_count": 174, + "id": "5a99d176", "metadata": {}, "outputs": [], "source": [ @@ -961,27 +949,27 @@ }, { "cell_type": "code", - "execution_count": 146, - "id": "99f22a56", + "execution_count": 175, + "id": "2799b85d", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "T : |0|1|2|3|Result Types|\n", - " \n", - "q0 : -H-C-H---Sample(Z)----\n", - " | \n", - "q1 : -H-C-H---Sample(Z)----\n", - " | \n", - "q2 : -H-X-X-H-Sample(Z)----\n", - " \n", - "q3 : -X-H------------------\n", + "T : |0|1|2|3|4|Result Types|\n", + " \n", + "q0 : -H-X-C-X-H-Sample(Z)----\n", + " | \n", + "q1 : -H---X-H---Sample(Z)----\n", + " \n", + "q2 : -H-H-------Sample(Z)----\n", + " \n", + "q3 : -X-H--------------------\n", "\n", - "T : |0|1|2|3|Result Types|\n", + "T : |0|1|2|3|4|Result Types|\n", "Measurement results:\n", - " {'0001': 0.53, '0000': 0.47}\n", + " {'0000': 0.6, '0001': 0.4}\n", "This is a constant function\n" ] } @@ -993,21 +981,23 @@ }, { "cell_type": "markdown", - "id": "c582dc85", + "id": "9f9df8bc", "metadata": {}, "source": [ "\n", "\n", "## Comparing the Classical and Quantum Results\n", "\n", - "Once you've run the classical and quantum version of the random circuit you can compare the results. If both correspond to the same type of function then we have found another to implement the constant or balanced function! \n", + "Once you've run the classical and quantum version of the random circuit you can compare the results. If both correspond to the same type of function then we have found another way to implement the constant or balanced function! \n", + "\n", + "You can keep generating more random circuits to see how the constant and balanced functions can be created including circuits that are extremely large, for example 10 qubits! There is also a possibility that you can generate a random circuit that is neither a constant or balanced function. \n", "\n", - "You can keep generating more random circuits to see how the constant and balanced functions can be created including for circuits that are extremely large, example 10 qubits! " + "To test new random circuits, remember to run the [random oracle](#random) once again." ] }, { "cell_type": "markdown", - "id": "82a23325", + "id": "b117a477", "metadata": {}, "source": [ "## Next Steps \n",