From 867e07107d49b3b3fc0b2972f63caf920ac93e0e Mon Sep 17 00:00:00 2001 From: //va Date: Thu, 9 Mar 2023 12:24:28 -0500 Subject: [PATCH] qiskit programming - aus (#1968) * initial commit * add grader metadata * added grading * update prob1-ex3, prob2-ex1, prob2-ex2 * Updates to wording/imports and to_numpy_array fix * Fix exercise 1.1 Needed to move plot_bloch_sphere out as this was changing the coord values * Update to exercise 2.2 for sampler refactor * added helpful imports, added N param to function template --------- Co-authored-by: Astri <65373070+Astri-Cornish@users.noreply.github.com> Co-authored-by: Astri-Cornish --- .../qiskit_programming_australia.ipynb | 509 ++++++++++++++++++ notebooks/toc.yaml | 4 + 2 files changed, 513 insertions(+) create mode 100644 notebooks/problem-sets/qiskit_programming_australia.ipynb diff --git a/notebooks/problem-sets/qiskit_programming_australia.ipynb b/notebooks/problem-sets/qiskit_programming_australia.ipynb new file mode 100644 index 000000000..8346aea3b --- /dev/null +++ b/notebooks/problem-sets/qiskit_programming_australia.ipynb @@ -0,0 +1,509 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "4f422325", + "metadata": {}, + "source": [ + "# Qiskit Programming Challenge - Australia" + ] + }, + { + "cell_type": "markdown", + "id": "eaa58c26", + "metadata": {}, + "source": [ + "## Problem Set 1 - Beginners' Introduction" + ] + }, + { + "cell_type": "markdown", + "id": "f8e4b2ed", + "metadata": {}, + "source": [ + "### Exercise 1: Spinning Around the Bloch Sphere\n", + "\n", + "In quantum computing, information is stored in qubits, which are quantum bits that can exist in a superposition of states rather than either just the state of 0 or the state of 1. \n", + "\n", + "We use the Bloch Sphere to visualize individual qubit states and the rotations around qubits that occur when quantum gates act on qubits. The state of a qubit is represented as a point on the surface of the sphere, where the 0 state points upwards in the positive z-direction (you can think of this as the north pole of the sphere) and the 1 state points downwards in the negative z-direction (the south pole). Any other point on the sphere represents some superposition of the one and zero states. When rotations occur around a qubit, rotations with a positive value move anti-clockwise around the sphere.\n", + "\n", + "In this problem, you will need to determine the spherical coordinates to visualize what the Hadamard quantum gate does on a qubit initially in the zero state. The Hadamard gate puts a qubit, initially in the zero state, into an equal superposition between 0 and 1 where the state will be pointing in the positive x direction on a bloch sphere (see image below in \"output\"). You will need to create a list of three values whereby the ordering is: `radius`, `theta`, `phi`, where each value is specified in **radians**. Remember that 180 degrees = $\\pi$ radians. After you submit your answer, we will show your qubit and its state using the [plot_bloch_vector](https://qiskit.org/documentation/stubs/qiskit.visualization.plot_bloch_vector.html) function.\n", + "\n", + "**Tips:** Radius determines how far out of the center of the sphere the arrow indicating the qubit's state reaches. What will the radius need to be for this unit sphere such that the arrow points to the surface of the sphere? Theta is the value of the arrow's angle when starting from the zero state. If you think about tracing the lines of longitude on the qubit, what's the angular value required to put the qubit in equal superposition between the zero and one states (or the north and south pole)? Lastly, you can think of phi as the phase angle. It is the angle of rotation that the arrow is from the positive x-direction. Does the Hadamard gate involve any change in the qubit's phase?" + ] + }, + { + "cell_type": "markdown", + "id": "2ebf4d60", + "metadata": {}, + "source": [ + "
\n", + " \n", + "
\n", + "Image: The bloch sphere showing generalised spherical coordinate measurements. \n" + ] + }, + { + "cell_type": "markdown", + "id": "6eee7128", + "metadata": {}, + "source": [ + "\n", + "**Input:** \n", + "Your qubit will start in the zero state, i.e. pointing in the positive z direction. \n", + " \n", + "**Output:** \n", + "
\n", + " \n", + "
\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f3730151", + "metadata": { + "goals": [ + { + "id": "aus-prob1-ex1" + } + ], + "grader_answer": "coords", + "grader_id": "programming_challenge_aus/prob1-ex1" + }, + "outputs": [], + "source": [ + "import math\n", + "from qiskit.visualization import plot_bloch_vector\n", + "\n", + "###### INSERT YOUR CODE BELOW #####\n", + "\n", + "coords = #create a list of your coordinates\n", + "\n", + "###### INSERT YOUR CODE ABOVE #####\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c03855e0-0293-405a-a0a1-2b4a133099f7", + "metadata": {}, + "outputs": [], + "source": [ + "#Run this cell to visualise your qubit and its state\n", + "\n", + "plot_bloch_vector(coords, coord_type='spherical')" + ] + }, + { + "cell_type": "markdown", + "id": "2683b339", + "metadata": {}, + "source": [ + "### Exercise 2: Let's Create a Quantum Circuit!\n", + "\n", + "Create a quantum circuit with one qubit and two or more quantum gates that encodes the qubit a state of equal superposition between zero and one with a phase rotation of $\\pi$ (i.e. -1). One of your gates must be the Z gate. See the image below for a visual representation of this state." + ] + }, + { + "cell_type": "markdown", + "id": "2b869d04", + "metadata": {}, + "source": [ + "
\n", + "\n", + "
" + ] + }, + { + "cell_type": "markdown", + "id": "89aacd31", + "metadata": {}, + "source": [ + "Tip: Look at Qiskit's [Quantum Circuit documentation](https://qiskit.org/documentation/stubs/qiskit.circuit.QuantumCircuit.html) for help with constructing your circuit. \n", + "\n", + "----\n", + "**Output:** \n", + "A quantum circuit of type QuantumCircuit with one qubit in the provided state using two or more quantum gates to make the appropriate rotations. Your circuit must not have any measurement gates on it. " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d50275fa", + "metadata": { + "goals": [ + { + "id": "aus-prob1-ex2" + } + ], + "grader_answer": "qc", + "grader_id": "programming_challenge_aus/prob1-ex2" + }, + "outputs": [], + "source": [ + "from qiskit import QuantumCircuit\n", + "\n", + "###### INSERT YOUR CODE BELOW #####\n", + "\n", + "qc = #create your quantum circuit\n", + "\n", + "###### INSERT YOUR CODE ABOVE #####\n", + "\n", + "qc.draw('mpl')" + ] + }, + { + "cell_type": "markdown", + "id": "f4b78967", + "metadata": {}, + "source": [ + "### Exercise 3: Exploring Entanglement\n", + "\n", + "In the exercises _Spinning around the Bloch Sphere_ and _Let's Create a Quantum Circuit!_, you created two qubits that had the property of superposition. If you repetitively measured either qubit in superposition, your results would have a mixture of zeroes and ones. You can think of the Hadamard gate as creating an equal likelihood that a qubit will either be measured as a zero or one. Superposition allows a qubit to represent multiple values at once, which is important for quantum computing to provide larger computing power. \n", + "\n", + "Qubit entanglement is the phenomenon whereby two or more qubits can become connected; the state of one system is dependent on the other systems. These networks of qubits allow more complex calculations to be undertaken.\n", + "\n", + "So, superposition and entanglement work together to allow for the significant processing power of quantum computers. \n", + "\n", + "In this exercise, create a quantum circuit with two qubits and entangle the qubits such that the circuit, when measured, will either result in the state 01 or 10 with 50% probability of obtaining either state. This means that when the first qubit (the qubit on the right of a single pair since Qiskit flips the ordering of qubits) is measured as 1, the second qubit will always be in the 0 state, and vice versa. Run the circuit using the aer_simulator with 1024 shots (i.e. 1024 runs of the circuit) and set `seed_simulator = 123` to obtain a dictionary of the counts against each possible state. \n", + "\n", + "Some useful documentation:\n", + "- [Quantum Circuits](https://qiskit.org/documentation/stubs/qiskit.circuit.QuantumCircuit.html)\n", + "- [Running Quantum Circuits on Simulators]()\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "67555e8e", + "metadata": { + "goals": [ + { + "id": "aus-prob1-ex3" + } + ], + "grader_function": "grade_prob1_ex3(qc, counts)", + "grader_import": "from qc_grader.challenges.programming_challenge_aus import grade_prob1_ex3" + }, + "outputs": [], + "source": [ + "from qiskit import Aer, execute, QuantumCircuit\n", + "from qiskit.tools.visualization import plot_histogram\n", + "seed = 123 # DO NOT REMOVE THIS # Remember to set seed_simulator = seed or seed_simulator = 123 when you call the execute function\n", + "\n", + "###### INSERT YOUR CODE BELOW #####\n", + "\n", + "qc = #create your quantum circuit\n", + "\n", + "\n", + "backend = \n", + "job = \n", + "result = \n", + "counts = \n", + "\n", + "###### INSERT YOUR CODE ABOVE #####\n", + "\n", + "plot_histogram(counts)\n" + ] + }, + { + "cell_type": "markdown", + "id": "fcb8d348", + "metadata": {}, + "source": [ + "### Exercise 4: Needle in a Haystack\n", + "\n", + "In this exercise, you are going to code part of Grover's Algorithm. Grover's Algorithm is a quantum search algorithm that can be used to find something in a large database quickly. If you think about searching for a needle in a haystack, many classical algorithms search through each item (a piece of hay) in the word list (the haystack) iteratively until they find the target word (the needle) in the list. With Grover's algorithm, you can think of this method as starting off by considering all the pieces of hay as possible needles and using clues given to us to narrow down where the needle is. \n", + "\n", + "When we use Grover's algorithm with a quantum computer, we start with encoding an initial state onto the qubits we need to solve this problem; a state whereby all possible answers are equally likely to be chosen as the correct answer. We then apply a process (using quantum gates) to those qubits, whereby the probability of the correct answer's state will be amplified. In simpler terms, the properties of quantum computers are used to first spread out the search to all possible answers then narrow down the answer, then choose the correct outcome (i.e. the state with the highest probability) using measurement techniques. \n", + "\n", + "The step-by-step process for Grover's Algorithm:\n", + "1. Apply Hadamard gates to all the qubits. This makes all states - the possible answers - equally likely.\n", + "2. Apply an oracle function to the qubits (the focus of this problem!). You can think of an oracle function as a quantum circuit segment that marks some desired state with a negative phase. The desired state corresponds to the answer we want to find and it is possible to have multiple desired states that require marking. Phase is simply a property of a quantum state, which you can think of as its direction and how that state is going to interact with other states. For example, the state you saw in _Spinning around the Bloch Sphere_ had a positive direction, whereas the state you saw in _Let's create a Quantum Circuit!_ is the same but has a relative change in phase of -1. Think about what gate you used or can use to create the phase change in that problem (hint: also consider a controlled version of that gate). In this problem, you will be marking the states 01 and 11 both with a -1 phase after placing Hardamard gates on all the qubits. You can reference the useful links below to see examples of how other states have been marked. \n", + "3. Amplify the amplitude. You can think of all the possible answers as vectors and amplification involves rotating the vectors such that the marked one/s increases in length while all the others decrease in length. The longer the length of the marked vector, the higher the probability of finding the correct answer. \n", + "4. Measure your quantum circuit to obtain your answer! It is best to run and measure the circuit multiple times to ensure you are confident in the final answer. \n", + "\n", + "Now it's up to you to create a 2-qubit quantum circuit to mark both the states 01 and 11 (the oracle function)! Do not attempt steps 3 or 4 in this problem; you are only required to determine an appropriate oracle function after placing Hadamard gates on all the qubits (steps 1 & 2). Only your circuit will be marked, but you can check that you have created the correct circuit by adding measurement gates and running the circuit on the aer_simulator with `seed_simulator = 123`. You should get `counts = {'01': 255, '00': 252, '11': 259, '10': 258}`.\n", + "\n", + "\n", + "Useful links:\n", + "\n", + "- [Grover's algorithm - Qiskit Textbook](https://qiskit.org/textbook/ch-algorithms/grover.html)\n", + "\n", + "\n", + "----\n", + " \n", + "**Outputs:** \n", + "Quantum Circuit\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "178f560f", + "metadata": { + "goals": [ + { + "id": "aus-prob1-ex4" + } + ], + "grader_answer": "grover", + "grader_id": "programming_challenge_aus/prob1-ex4" + }, + "outputs": [], + "source": [ + "from qiskit import QuantumCircuit\n", + "\n", + "###### INSERT YOUR CODE BELOW #####\n", + "\n", + "grover = #create your quantum circuit\n", + "\n", + "###### INSERT YOUR CODE ABOVE #####\n", + "\n", + "grover.draw()" + ] + }, + { + "cell_type": "markdown", + "id": "fdf06871", + "metadata": {}, + "source": [ + "Congratulations on completing these problems!" + ] + }, + { + "cell_type": "markdown", + "id": "9352fda2", + "metadata": {}, + "source": [ + "## Problem Set 2 - TSP for Intermediate" + ] + }, + { + "cell_type": "markdown", + "id": "fc986fd2", + "metadata": {}, + "source": [ + "### Exercise 1: Solving the Travelling Salesman Problem Classically\n", + "\n", + "The Travelling Salesman Problem (TSP) is a well known NP hard optimisation problem in computer science. The problem is set up as a set of nodes in a graph, where the goal is to traverse through each node only once via the shortest path possible. Create a function that will find a solution to the travelling salesman problem finding the shortest path for n number of nodes. See the graph produced below:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b7fdbb3d", + "metadata": {}, + "outputs": [], + "source": [ + "import matplotlib.pyplot as plt\n", + "import networkx as nx\n", + "from qiskit_optimization.applications import Tsp\n", + "\n", + "#A couple of helper functions\n", + "def draw_graph(graph):\n", + " pos = [tsp.graph.nodes[node][\"pos\"] for node in tsp.graph.nodes]\n", + " nx.draw_networkx(graph, node_size=600, pos=pos)\n", + " edge_labels = nx.get_edge_attributes(graph, \"weight\")\n", + " nx.draw_networkx_edge_labels(graph, pos=pos, edge_labels=edge_labels)\n", + " \n", + "def draw_tsp_solution(G, solution_order):\n", + " pos = [tsp.graph.nodes[node][\"pos\"] for node in tsp.graph.nodes]\n", + " G2 = nx.DiGraph()\n", + " G2.add_nodes_from(G)\n", + " n = len(solution_order)\n", + " for i in range(n):\n", + " j = (i + 1) % n\n", + " G2.add_edge(solution_order[i], solution_order[j], weight=G[solution_order[i]][solution_order[j]][\"weight\"])\n", + " default_axes = plt.axes(frameon=True)\n", + " nx.draw_networkx(\n", + " G2, node_size=600, ax=default_axes, pos=pos\n", + " )\n", + " edge_labels = nx.get_edge_attributes(G2, \"weight\")\n", + " nx.draw_networkx_edge_labels(G2, pos, edge_labels=edge_labels)\n", + "\n", + "n = 6\n", + "tsp = Tsp.create_random_instance(n, seed=123)\n", + "adj_matrix = nx.to_numpy_array(tsp.graph)\n", + "\n", + "draw_graph(tsp.graph)\n" + ] + }, + { + "cell_type": "markdown", + "id": "ba614593", + "metadata": {}, + "source": [ + "For this problem you will need to create a function relying only using classical methods, that will solve the travelling salesman problem for any number number of nodes. " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "571939c3", + "metadata": { + "goals": [ + { + "id": "aus-prob2-ex1" + } + ], + "grader_function": "grade_prob2_ex1(classical_tsp)", + "grader_import": "from qc_grader.challenges.programming_challenge_aus import grade_prob2_ex1" + }, + "outputs": [], + "source": [ + "from itertools import permutations #this may be helpful to you\n", + "\n", + "def classical_tsp(adj_matrix, N):\n", + " \n", + " ###### INSERT YOUR CODE HERE #####\n", + " \n", + " return solution_distance, solution_order\n", + "\n", + "solution_distance, solution_order = classical_tsp(adj_matrix, n)\n", + "print(solution_distance, solution_order)\n", + "\n", + "draw_tsp_solution(tsp.graph, solution_order)" + ] + }, + { + "cell_type": "markdown", + "id": "90da0fc3", + "metadata": {}, + "source": [ + "### Exercise 2: Solving the Travelling Salesman Problem Using Qiskit\n", + "\n", + "The TSP on the nodes of a graph ask for the shortest Hamiltonian cycle (closed path using each node once) that can be taken through each of the nodes.\n", + "\n", + "A general solution and an algorithm that could efficiently find the solution to this problem in polynomial time does not exist, which is why the brute force classical method of solving this problem is unsustainable for graphs with a large number of nodes.\n", + "\n", + "It is relatively simple to map the problem of finding the shortest Hamiltonian cycle to a quantum computer and finding the solution by minimizing an Ising Hamiltonian, which is what this exercise will be asking you to do.\n", + "\n", + "To begin with, we have provided the correct TSP module import from Qiskit as well as the number of nodes in the graph (n=3) and the tsp variable which will create a random graph with three nodes with different weights. DO NOT change the seed value or any of the template code, otherwise your solution will be incorrect. " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3688e9eb", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "from qiskit_optimization.applications import Tsp\n", + "import networkx as nx\n", + "\n", + "n = 3\n", + "tsp = Tsp.create_random_instance(n, seed=123)\n", + "adj_matrix = nx.to_numpy_array(tsp.graph)" + ] + }, + { + "cell_type": "markdown", + "id": "e74701a2", + "metadata": {}, + "source": [ + "To solve this problem, we need to convert our quadratic program into a form that a quantum computer can work with. In this case we will generate an Ising Hamiltonian, which is simply a representation (i.e. model) of the energy of this particular system (i.e. problem). We can use eigensolvers to find the minimum energy of the Ising hamiltonian, which corresponds to the shortest path and the solution of our problem." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9b20ca17", + "metadata": {}, + "outputs": [], + "source": [ + "from qiskit_optimization.converters import QuadraticProgramToQubo\n", + "\n", + "qp = ## FILL IN YOUR CODE HERE\n", + "qp2qubo = ## FILL IN YOUR CODE HERE\n", + "qubo = ## FILL IN YOUR CODE HERE\n", + "qubitOp, offset = ## FILL IN YOUR CODE HERE" + ] + }, + { + "cell_type": "markdown", + "id": "66ce58c6", + "metadata": {}, + "source": [ + "Next you will be creating a Variational Quantum Eigensolver, which will be used to iteratively attempt to calculate the minimum energy of the hamiltonian. VQEs can be used to model a complex wavefunction in polynomial time, meaning a speed-up over conventional computation methods.\n", + "\n", + "You will need to select an optimizer, an ansatz and then use [SamplingVQE](https://qiskit.org/documentation/stubs/qiskit.algorithms.minimum_eigensolvers.SamplingVQE.html) class with the chosen optimiser and ansatz to build the VQE.\n", + "\n", + ">Arguments of Sampling VQE:\n", + ">- `sampler`: The [sampler](https://qiskit.org/documentation/stubs/qiskit.primitives.Sampler.html) primitive to sample the circuits. Simply put in a sampler instance here.\n", + ">- `ansatz`: A parameterized quantum circuit to prepare the trial state (you can think of this like a \"first good guess\"). Check out the [TwoLocal](https://qiskit.org/documentation/stubs/qiskit.circuit.library.TwoLocal.html) ansatz example. You can find other different types of ansatz from the qiskit circuit library here for your reference: - **Ansatz**: [[n-local-circuits]](https://qiskit.org/documentation/apidoc/circuit_library.html#n-local-circuits)\n", + ">- `optimizer`: A classical optimizer to find the minimum energy. This can either be a Qiskit.Optimizer or a callable implementing the .Minimizer protocol. You may check out the [SPSA optimizer](https://qiskit.org/documentation/stubs/qiskit.algorithms.optimizers.SPSA.html) or other optimizers [here](https://qiskit.org/documentation/stubs/qiskit.algorithms.optimizers.html).\n", + "\n", + "If you are sure of your solution but the grader initially says your answer is incorrect, try grading your answer again as your VQE may not have converged well." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0ef4518c", + "metadata": { + "goals": [ + { + "id": "aus-prob2-ex2" + } + ], + "grader_function": "grade_prob2_ex2(result)", + "grader_import": "from qc_grader.challenges.programming_challenge_aus import grade_prob2_ex2" + }, + "outputs": [], + "source": [ + "from qiskit.primitives import Sampler\n", + "from qiskit.algorithms.minimum_eigensolvers import SamplingVQE\n", + "\n", + "#don't forget to import any necessary packages for your optimizer and ansatz\n", + "\n", + "optimizer = ## FILL IN YOUR CODE HERE\n", + "ansatz = ## FILL IN YOUR CODE HERE\n", + "vqe = ## FILL IN YOUR CODE HERE\n", + "result = vqe.compute_minimum_eigenvalue(qubitOp)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c1807402", + "metadata": {}, + "outputs": [], + "source": [ + "print(\"energy:\", result.eigenvalue.real)\n", + "print(\"time:\", result.optimizer_time)\n", + "x = tsp.sample_most_likely(result.eigenstate)\n", + "print(\"feasible:\", qubo.is_feasible(x))\n", + "solution_order = tsp.interpret(x)\n", + "print(\"solution:\", solution_order)\n", + "solution_distance = tsp.tsp_value(solution_order, adj_matrix)\n", + "print(solution_distance, solution_order)\n", + "draw_tsp_solution(tsp.graph, solution_order)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.12" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} \ No newline at end of file diff --git a/notebooks/toc.yaml b/notebooks/toc.yaml index cf1394601..f2fcc5465 100644 --- a/notebooks/toc.yaml +++ b/notebooks/toc.yaml @@ -389,6 +389,10 @@ id: qiskit_beginner_proficiency uuid: 687732ae-70a8-11ed-a1eb-0242ac120002 url: /problem-sets/qiskit_beginner_problem_set + - title: Qiskit Programming Challenge - Australia + id: qiskit_programming_australia + uuid: 38c0c49c-6921-4cb5-bdf9-75d592edc3fc + url: /problem-sets/qiskit_programming_australia - title: Examples