{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# QDK Visualization Tools\n", "\n", "This tutorial introduces you to a variety of tools offered by the Microsoft Quantum Development Kit to visualize various elements of Q# programs. \n", "These tools are extremely helpful both for learners seeking to confirm their understanding of the behavior of the program and for experienced quantum software developers debugging their programs. \n", "\n", "This tutorial covers the following topics:\n", "* Displaying the quantum state of the program: DumpMachine and DumpRegister.\n", "* Displaying the matrix implemented by the quantum operation: DumpOperation.\n", "* Drawing the circuit of an execution path of the program: %trace.\n", "* Running through the quantum program step-by-step: %debug." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Display the quantum state of a single-qubit program\n", "\n", "Let's start with a simple scenario: a program that acts on a single qubit. \n", "The state of the quantum system used by this program can be represented as a complex vector of length 2, or, using Dirac notation,\n", "\n", "$$\\begin{bmatrix} \\alpha \\\\ \\beta \\end{bmatrix} = \\alpha|0\\rangle + \\beta|1\\rangle$$\n", "\n", "> If you need a refresher on single-qubit quantum systems and their states, please see the tutorial on [the concept of a qubit](../Qubit/Qubit.ipynb).\n", "\n", "If this program runs on a physical quantum system, there is no way to get the information about the values of $\\alpha$ and $\\beta$ at a certain point of the program execution from a single observation. \n", "You would need to run the program repeatedly up to this point, perform a measurement on the system, and aggregate the results of multiple measurements to estimate $\\alpha$ and $\\beta$.\n", "\n", "However, at the early stages of quantum program development the program typically runs on a simulator - a classical program which simulates the behavior of a small quantum system while having complete information about its internal state. \n", "You can take advantage of this to do some non-physical things, such as peeking at the internals of the quantum system to observe its exact state without disturbing it!\n", "\n", "[DumpMachine](https://docs.microsoft.com/qsharp/api/qsharp/microsoft.quantum.diagnostics.dumpmachine) function from [Microsoft.Quantum.Diagnostics namespace](https://docs.microsoft.com/qsharp/api/qsharp/microsoft.quantum.diagnostics) allows you to do exactly that. This function is available in standalone Q# applications as well.\n", "\n", "### Demo: DumpMachine for single-qubit systems\n", "\n", "The following demo shows how to use `DumpMachine` to output the state of the system at any point in the program without affecting the state.\n", "\n", "> Note that the Q# code doesn't have access to the output of `DumpMachine`, so you cannot write any non-physical code in Q#!\n", "\n", "The output of `DumpMachine` is accurate up to a global phase: sometimes you'll see that all amplitudes are multiplied by some complex number compared to the state you're expecting." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "// Run this cell using Ctrl+Enter (⌘+Enter on Mac)\n", "// Then run the next cell to see the output\n", "\n", "open Microsoft.Quantum.Diagnostics;\n", "\n", "operation SingleQubitDumpMachineDemo () : Unit {\n", " // This line allocates a qubit in state |0⟩.\n", " use q = Qubit();\n", " Message(\"State |0⟩:\");\n", "\n", " // This line prints out the state of the quantum system.\n", " // Since only one qubit is allocated, only its state is printed.\n", " DumpMachine();\n", "\n", " // This line changes the qubit to state |+⟩ = (1/sqrt(2))(|0⟩ + |1⟩).\n", " // 1/sqrt(2) is approximately 0.707107.\n", " H(q);\n", "\n", " Message(\"State |+⟩:\");\n", " DumpMachine();\n", "\n", " // This will put the qubit into an uneven superposition,\n", " // where the amplitudes of |0⟩ and |1⟩ have different absolute values and relative phases.\n", " Rx(1.0, q);\n", " Ry(2.0, q);\n", " Rz(3.0, q);\n", "\n", " Message(\"Uneven superposition state:\");\n", " DumpMachine();\n", "\n", " // This line returns the qubit to state |0⟩ before releasing it.\n", " Reset(q);\n", "}" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "%simulate SingleQubitDumpMachineDemo" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Exercise 1: Learn the state of the qubit without measurements\n", "\n", "**Input:** A qubit in an unknown state $|\\psi\\rangle = \\alpha|0\\rangle + \\beta|1\\rangle$. The amplitudes $\\alpha$ and $\\beta$ will be real and non-negative.\n", "\n", "**Output:** A tuple of two numbers $(\\alpha', \\beta')$ - your estimates of the amplitudes $\\alpha$ and $\\beta$.\n", "The absolute errors $|\\alpha - \\alpha'|$ and $|\\beta - \\beta'|$ should be less than or equal to 0.001.\n", "\n", "The test will call your code exactly once, with the fixed state parameter that will not change if you run the cell several times." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "%kata T1_LearnSingleQubitState\n", "\n", "operation LearnSingleQubitState (q : Qubit) : (Double, Double) {\n", " // ...\n", "}" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Display the quantum state of a multi-qubit program\n", "\n", "Now let's take a look at the general case: a program that acts on $N$ qubits. \n", "The state of the quantum system used by this program can be represented as a complex vector of length $2^N$, or, using Dirac notation,\n", "\n", "$$\\begin{bmatrix} x_0 \\\\ x_1 \\\\ \\vdots \\\\ x_{2^N-1}\\end{bmatrix} = \\sum_{k = 0}^{2^N-1} x_k |k\\rangle$$\n", "\n", "Same as in the single-qubit case, `DumpMachine` allows you to see the amplitudes $x_k$ for all basis states $|k\\rangle$ directly.\n", "\n", "> Note the use of an integer in the ket notation instead of a bit string with one bit per qubit. \n", "By default, `DumpMachine` uses little-endian to convert bit strings to integers in the ket notation.\n", "For more details on endiannes, see [the multi-qubit systems tutorial](../MultiQubitSystems/MultiQubitSystems.ipynb#Endianness).\n", "\n", "### Demo: DumpMachine for multi-qubit systems" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "open Microsoft.Quantum.Diagnostics;\n", "\n", "operation MultiQubitDumpMachineDemo () : Unit {\n", " // This line allocates two qubits in state |00⟩.\n", " use qs = Qubit[2];\n", " Message(\"State |00⟩:\");\n", "\n", " // This line prints out the state of the quantum system.\n", " DumpMachine();\n", "\n", " // X gate changes the second qubit into state |1⟩.\n", " // The entire system is now in state |01⟩, or, in little-endian notation, |2⟩.\n", " X(qs[1]);\n", " Message(\"State |01⟩:\");\n", " DumpMachine();\n", "\n", " CNOT(qs[1], qs[0]);\n", " Rx(1.0, qs[0]);\n", " Ry(2.0, qs[1]);\n", " Rz(3.0, qs[1]);\n", "\n", " Message(\"Uneven superposition state:\");\n", " DumpMachine();\n", "\n", " // This line returns the qubits to state |0⟩ before releasing them.\n", " ResetAll(qs);\n", "}" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "scrolled": true }, "outputs": [], "source": [ "%simulate MultiQubitDumpMachineDemo" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Exercise 2: Learn the amplitude of a basis state without measurements\n", "\n", "**Input:** 2 qubits in an unknown state $|\\psi\\rangle = \\sum_{k = 0}^{3} x_k |k\\rangle$. The amplitudes $x_k$ will be real and non-negative.\n", "\n", "**Output:** A tuple of two numbers $(x_1', x_2')$ - your estimates of the amplitudes of the state $|1\\rangle$ and $|2\\rangle$, respectively.\n", "The absolute errors $|x_1 - x_1'|$ and $|x_2 - x_2'|$ should be less than or equal to 0.001.\n", "\n", "The test will call your code exactly once, with the fixed state parameter that will not change if you run the cell several times." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "%kata T2_LearnBasisStateAmplitudes\n", "\n", "operation LearnBasisStateAmplitudes (qs : Qubit[]) : (Double, Double) {\n", " // ...\n", "}" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Configure DumpMachine output\n", "\n", "Sometimes you want to focus on certain properties of the quantum state, such as the relative phases of individual basis states, or on certain parts of the state, such as the basis states with larger amplitudes associated with them. \n", "[%config](https://docs.microsoft.com/qsharp/api/iqsharp-magic/config) magic command allows you to tweak the format of `DumpMachine` output (available in Q# Jupyter Notebooks only). \n", "Here are some useful options that help you extract the right information:\n", "\n", "* `dump.basisStateLabelingConvention` sets the way the basis states are labeled in the output. Here is how the basis state $|10\\rangle$ will look like with different settings:\n", "\n", "
dump.basisStateLabelingConvention value | \n", "DumpMachine output (first two columns) | \n", "
---|---|
\"LittleEndian\" (default) | \n", "\n", " |
\"BigEndian\" | \n", "\n", " |
\"Bitstring\" | \n", "\n", " |