{
"cells": [
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"# This cell is added by sphinx-gallery\n# It can be customized to whatever you like\n%matplotlib inline"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Coherent Variational Quantum Linear Solver {#coherent_vqls}\n==========================================\n\n::: {.meta}\n:property=\\\"og:description\\\": This demonstration extends the variational\nquantum linear solver to solve linear equations defined by a\nprobabilistic coherent operation. :property=\\\"og:image\\\":\n\n:::\n\n::: {.related}\ntutorial\\_vqls Variational quantum linear solver\n:::\n\n*Author: Andrea Mari. Last updated: 15 Jan 2021.*\n\nIn this tutorial we propose and implement an algorithm that we call\n*coherent variational quantum linear solver* (CVQLS). This is inspired\nby the VQLS proposed in Ref. \\[1\\] (implemented in a\n`previous demo `{.interpreted-text role=\"doc\"}), with an\nimportant difference: the matrix $A$ associated to the problem is\nphysically applied as a probabilistic coherent operation. This approach\nhas some advantages and disadvantages and its practical convenience\ndepends on the specific linear problem to be solved and on experimental\nconstraints.\n\n![](../demonstrations/coherent_vqls/cvqls_circuit.png){.align-center\nwidth=\"100.0%\"}\n\nIntroduction\n------------\n\nWe first define the problem and the general structure of the CVQLS. As a\nsecond step, we consider a particular case and we solve it explicitly\nwith PennyLane.\n\n### The problem\n\nWe are given a $2^n \\times 2^n$ matrix $A$ which can be expressed as a\nlinear combination of $L$ unitary matrices $A_0, A_1, \\dots A_{L-1}$,\ni.e.,\n\n$$A = \\sum_{l=0}^{L-1} c_l A_l,$$\n\nwhere $c_l$ are arbitrary complex numbers. Importantly, we assume that\neach of the unitary components $A_l$ can be efficiently implemented with\na quantum circuit acting on $n$ qubits.\n\nWe are also given a normalized complex vector in the physical form of a\nquantum state $|b\\rangle$, which can be generated by a unitary operation\n$U$ applied to the ground state of $n$ qubits. , i.e.,\n\n$$|b\\rangle = U_b |0\\rangle,$$\n\nwhere again we assume that $U_b$ can be efficiently implemented with a\nquantum circuit.\n\nThe problem that we aim to solve is that of preparing a quantum state\n$|x\\rangle$, such that $A |x\\rangle$ is proportional to $|b\\rangle$ or,\nequivalently, such that\n\n$$|\\Psi\\rangle := \\frac{A |x\\rangle}{\\sqrt{\\langle x |A^\\dagger A |x\\rangle}} \\approx |b\\rangle.$$\n\n### Coherent Variational Quantum Linear Solver (CVQLS)\n\nWe approximate the solution $|x\\rangle$ with a variational quantum\ncircuit, i.e., a unitary circuit $V$ depending on a finite number of\nclassical real parameters $w = (w_0, w_1, \\dots)$:\n\n$$|x \\rangle = V(w) |0\\rangle.$$\n\nThe parameters should be optimized in order to maximize the overlap\nbetween the quantum states $|\\Psi\\rangle$ and $|b\\rangle$. We define the\nfollowing cost function,\n\n$$C = 1- |\\langle b | \\Psi \\rangle|^2,$$\n\nsuch that its minimization with respect to the variational parameters\nshould lead towards the problem solution.\n\nThe approach used in Ref. \\[1\\] is to decompose the cost function in\nterms of many expectation values associated to the individual components\n$A_l$ of the problem matrix $A$. For this reason, in the VQLS of Ref.\n\\[1\\], the state vector proportional to $A |x\\rangle$ is not physically\nprepared. On the contrary, the idea presented in this tutorial is to\nphysically implement the linear map $A$ as a coherent probabilistic\noperation. This approach allows to prepare the state\n$|\\Psi\\rangle := A |x\\rangle/\\sqrt{\\langle x |A^\\dagger A |x\\rangle}$\nwhich can be used to estimate the cost function of the problem in a more\ndirect way.\n\n#### Coherently applying $A$\n\nThe problem of coherently applying a liner combination of unitary\noperations has been already studied in Ref. \\[2\\] and here we follow a\nvery similar approach.\n\nWithout loss of generality we can assume that the coefficients\n$c=(c_1, c_2, \\dots c_L)$ appearing in the definition of $A$ represent a\npositive and normalized probability distribution, i.e.,\n\n$$c_l \\ge 0 \\quad \\forall l, \\qquad \\sum_{l=0}^{L-1} c_l=1.$$\n\nIndeed the complex phase of each coefficient $c_l$ can always be\nabsorbed into the associated unitary $A_l$, obtaining in this way a\nvector of positive values. Moreover, since the linear problem is defined\nup to a constant scaling factor, we can also normalize the coefficients\nto get a probability distribution.\n\nFor simplicity, since we can always pad $c$ with additional zeros, we\nassume that $L=2^m$ for some positive integer $m$.\n\nLet us consider a unitary circuit $U_c$, embedding the square root of\n$c$ into the quantum state $|\\sqrt{c}\\rangle$ of $m$ ancillary qubits:\n\n$$|\\sqrt{c} \\rangle = U_c |0\\rangle = \\sum_{l=0}^{L-1} \\sqrt{c_l} | l \\rangle,$$\n\nwhere $\\{ |l\\rangle \\}$ is the computational basis of the ancillary\nsystem.\n\nNow, for each component $A_l$ of the problem matrix $A$, we can define\nan associated controlled unitary operation $CA_l$, acting on the system\nand on the ancillary basis states as follows:\n\n$$\\begin{aligned}\nCA_l \\, |j\\rangle |l' \\rangle =\n\\Bigg\\{\n\\begin{array}{c}\n\\left(A_l \\otimes \\mathbb{I}\\right) \\; |j\\rangle |l \\rangle \\quad \\; \\mathrm{for}\\; l'=l \\\\\n\\qquad \\qquad |j\\rangle |l' \\rangle \\quad \\mathrm{for}\\; l'\\neq l\n\\end{array},\n\\end{aligned}$$\n\ni.e., the unitary $A_l$ is applied only when the ancillary system is in\nthe corresponding basis state $|l\\rangle$.\n\nA natural generalization of the [Hadamard\ntest](https://en.wikipedia.org/wiki/Hadamard_test_(quantum_computation)),\nto the case of multiple unitary operations, is the following (see also\nthe figure at the top of this tutorial):\n\n1. Prepare all qubits in the ground state.\n2. Apply $U_c$ to the ancillary qubits.\n3. Apply the variational circuit $V$ to the system qubits.\n4. Apply all the controlled unitaries $CA_l$ for all values of $l$.\n5. Apply $U_c^\\dagger$ to the ancillary qubits.\n6. Measure the ancillary qubits in the computational basis.\n7. If the outcome of the measurement is the ground state, the system\n collapses to\n $|\\Psi\\rangle := A |x\\rangle/\\sqrt{\\langle x |A^\\dagger A |x\\rangle}$.\n If the outcome is not the ground state, the experiment should be\n repeated.\n\n#### Estimating the cost function\n\nFrom a technical point of view, the previous steps represent the most\ndifficult part of the algorithm. Once we have at our disposal the\nquantum system prepared in the state $|\\Psi\\rangle$, it is very easy to\ncompute the cost function. Indeed one could simply continue the previous\nprotocol with the following two steps:\n\n8. Apply $U_b^\\dagger$ to the system.\n9. Measure the system in the computational basis. The probability of\n finding it in the ground state (given the ancillary qubits measured\n in their ground state), is\n $|\\langle 0 | U_b^\\dagger |\\Psi \\rangle|^2 = |\\langle b | \\Psi \\rangle|^2$.\n\nSo, with sufficiently many shots of the previous experiment, one can\ndirectly estimate the cost function of the problem.\n\nImportantly, the operations of steps 7 and 8 commute. Therefore all the\nmeasurements can be delayed until the end of the quantum circuit (as\nshown in the figure at the top of this tutorial), making the structure\nof the experiment more straightforward.\n\n### A simple example\n\nIn this tutorial we apply the previous theory to the following simple\nexample based on a system of 3 qubits, which was already considered in\nRef. \\[1\\] and also reproduced in PennyLane\n(`VQLS `{.interpreted-text role=\"doc\"}):\n\n$$\\begin{aligned}\n\\begin{align}\nA &= c_0 A_0 + c_1 A_1 + c_2 A_2 = \\mathbb{I} + 0.2 X_0 Z_1 + 0.2 X_0, \\\\\n\\\\\n|b\\rangle &= U_b |0 \\rangle = H_0 H_1 H_2 |0\\rangle,\n\\end{align}\n\\end{aligned}$$\n\nwhere $Z_j, X_j, H_j$ represent the Pauli $Z$, Pauli $X$ and Hadamard\ngates applied to the qubit with index $j$.\n\nThis problem is computationally quite easy since a single layer of local\nrotations is enough to generate the solution state, i.e., we can use the\nfollowing simple ansatz:\n\n$$|x\\rangle = V(w) |0\\rangle = \\Big [ R_y(w_0) \\otimes R_y(w_1) \\otimes R_y(w_2) \\Big ] H_0 H_1 H_2 |0\\rangle.$$\n\nIn the code presented below we solve this particular problem, by\nfollowing the general scheme of the CVQLS previously discussed.\nEventually we will compare the quantum solution with the classical one.\n\nGeneral setup\n-------------\n\nThis Python code requires *PennyLane* and the plotting library\n*matplotlib*.\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"import pennylane as qml\nfrom pennylane import numpy as np\nimport matplotlib.pyplot as plt"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Setting of the main hyper-parameters of the model\n=================================================\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"n_qubits = 3 # Number of system qubits\nm = 2 # Number of ancillary qubits\nn_shots = 10 ** 6 # Number of quantum measurements\ntot_qubits = n_qubits + m # System + ancillary qubits\nancilla_idx = n_qubits # Index of the first ancillary qubit\nsteps = 10 # Number of optimization steps\neta = 0.8 # Learning rate\nq_delta = 0.001 # Initial spread of random quantum weights\nrng_seed = 0 # Seed for random number generator"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Circuits of the quantum linear problem\n======================================\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We need to define the unitary operations associated to the simple\nexample presented in the introduction.\n\nThe coefficients of the linear combination are three positive numbers\n$(1, 0.2, 0.2)$. So we can embed them in the state of $m=2$ ancillary\nqubits by adding a final zero element and normalizing their sum to $1$:\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"c = np.array([1, 0.2, 0.2, 0])\nc = c / np.sum(c)\n# We also compute the square root of c\nsqrt_c = np.sqrt(c)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We need to embed the square root of the probability distribution `c`\ninto the amplitudes of the ancillary state. It is easy to check that one\ncan always embed 3 positive amplitudes with just three gates: a local\n$R_y$ rotation, a controlled-$R_y$ and a controlled-NOT.\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"def U_c():\n \"\"\"Unitary matrix rotating the ground state of the ancillary qubits\n to |sqrt(c)> = U_c |0>.\"\"\"\n # Circuit mapping |00> to sqrt_c[0] |00> + sqrt_c[1] |01> + sqrt_c[2] |10>\n qml.RY(-2 * np.arccos(sqrt_c[0]), wires=ancilla_idx)\n qml.CRY(-2 * np.arctan(sqrt_c[2] / sqrt_c[1]), wires=[ancilla_idx, ancilla_idx + 1])\n qml.CNOT(wires=[ancilla_idx + 1, ancilla_idx])\n\n\ndef U_c_dagger():\n \"\"\"Adjoint of U_c.\"\"\"\n qml.CNOT(wires=[ancilla_idx + 1, ancilla_idx])\n qml.CRY(2 * np.arctan(sqrt_c[2] / sqrt_c[1]), wires=[ancilla_idx, ancilla_idx + 1])\n qml.RY(2 * np.arccos(sqrt_c[0]), wires=ancilla_idx)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We are left to define the sequence of all controlled-unitaries $CA_l$,\nacting as $A_l$ on the system whenever the ancillary state is\n$|l\\rangle$. Since in our case $A_0=\\mathbb{I}$ and `c[3] = 0`, we only\nneed to apply $A_1$ and $A_2$ controlled by the first and second\nancillary qubits respectively.\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"def CA_all():\n \"\"\"Controlled application of all the unitary components A_l of the problem matrix A.\"\"\"\n # Controlled-A_1\n qml.CNOT(wires=[ancilla_idx, 0])\n qml.CZ(wires=[ancilla_idx, 1])\n\n # Controlled-A2\n qml.CNOT(wires=[ancilla_idx + 1, 0])"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The circuit for preparing the problem vector $|b\\rangle$ is very simple:\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"def U_b():\n \"\"\"Unitary matrix rotating the system ground state to the\n problem vector |b> = U_b |0>.\"\"\"\n for idx in range(n_qubits):\n qml.Hadamard(wires=idx)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Variational quantum circuit\n===========================\n\nWhat follows is the variational quantum circuit that should generate the\nsolution state $|x\\rangle= V(w)|0\\rangle$.\n\nThe first layer of the circuit is a product of Hadamard gates preparing\na balanced superposition of all basis states.\n\nAfter that, we apply a very simple variational ansatz which is just a\nsingle layer of qubit rotations\n$R_y(w_0) \\otimes R_y(w_1) \\otimes R_y(w_2)$. For solving more complex\nproblems, we suggest to use more expressive circuits as, e.g., the\nPennyLane `StronglyEntanglingLayers` template.\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"def variational_block(weights):\n \"\"\"Variational circuit mapping the ground state |0> to the ansatz state |x>.\"\"\"\n # We first prepare an equal superposition of all the states of the computational basis\n for idx in range(n_qubits):\n qml.Hadamard(wires=idx)\n\n # A very minimal variational circuit\n for idx, element in enumerate(weights):\n qml.RY(element, wires=idx)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Full quantum circuit\n====================\n\nNow, we can define the full circuit associated to the CVQLS protocol\npresented in the introduction and corresponding to the figure at the top\nof this tutorial.\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"def full_circuit(weights):\n \"\"\"Full quantum circuit necessary for the CVQLS protocol,\n without the final measurement.\"\"\"\n # U_c applied to the ancillary qubits\n U_c()\n\n # Variational circuit generating a guess for the solution vector |x>\n variational_block(weights)\n\n # Application of all the controlled-unitaries CA_l associated to the problem matrix A\n CA_all()\n\n # Adjoint of U_b, where U_b |0> = |b>\n # For this particular problem adjoint(U_b)=U_b\n U_b()\n\n # Adjoint of U_c, applied to the ancillary qubits\n U_c_dagger()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"To estimate the overlap of the ground state with the post-selected\nstate, one could directly make use of the measurement samples. However,\nsince we want to optimize the cost function, it is useful to express\neverything in terms of expectation values through Bayes\\' theorem:\n\n$$|\\langle b | \\Psi \\rangle|^2=\nP( \\mathrm{sys}=\\mathrm{ground}\\,|\\, \\mathrm{anc} = \\mathrm{ground}) =\nP( \\mathrm{all}=\\mathrm{ground})/P( \\mathrm{anc}=\\mathrm{ground})$$\n\nTo evaluate the two probabilities appearing on the right hand side of\nthe previous equation we initialize a `default.qubit` device and we\ndefine two different `qnode` circuits.\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"dev = qml.device(\"default.qubit\", wires=tot_qubits)\n\n@qml.qnode(dev)\ndef global_ground(weights):\n # Circuit gates\n full_circuit(weights)\n # Projector on the global ground state\n P = np.zeros((2 ** tot_qubits, 2 ** tot_qubits))\n P[0, 0] = 1.0\n return qml.expval(qml.Hermitian(P, wires=range(tot_qubits)))\n\n@qml.qnode(dev)\ndef ancilla_ground(weights):\n # Circuit gates\n full_circuit(weights)\n # Projector on the ground state of the ancillary system\n P_anc = np.zeros((2 ** m, 2 ** m))\n P_anc[0, 0] = 1.0\n return qml.expval(qml.Hermitian(P_anc, wires=range(n_qubits, tot_qubits)))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Variational optimization\n========================\n\nIn order to variationally solve our linear problem, we first define the\ncost function $C = 1- |\\langle b | \\Psi \\rangle|^2$ that we are going to\nminimize. As explained above, we express it in terms of expectation\nvalues through Bayes\\' theorem.\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"def cost(weights):\n \"\"\"Cost function which tends to zero when A |x> tends to |b>.\"\"\"\n\n p_global_ground = global_ground(weights)\n p_ancilla_ground = ancilla_ground(weights)\n p_cond = p_global_ground / p_ancilla_ground\n\n return 1 - p_cond"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"To minimize the cost function we use the gradient-descent optimizer.\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"opt = qml.GradientDescentOptimizer(eta)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We initialize the variational weights with random parameters (with a\nfixed seed).\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"np.random.seed(rng_seed)\nw = q_delta * np.random.randn(n_qubits, requires_grad=True)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We are ready to perform the optimization loop.\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"cost_history = []\nfor it in range(steps):\n w, _cost = opt.step_and_cost(cost, w)\n print(\"Step {:3d} Cost = {:9.7f}\".format(it, _cost))\n cost_history.append(_cost)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We plot the cost function with respect to the optimization steps. We\nremark that this is not an abstract mathematical quantity since it also\nrepresents a bound for the error between the generated state and the\nexact solution of the problem.\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"plt.style.use(\"seaborn\")\nplt.plot(cost_history, \"g\")\nplt.ylabel(\"Cost function\")\nplt.xlabel(\"Optimization steps\")\nplt.show()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Comparison of quantum and classical results\n===========================================\n\nSince the specific problem considered in this tutorial has a small size,\nwe can also solve it in a classical way and then compare the results\nwith our quantum solution.\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Classical algorithm\n===================\n\nTo solve the problem in a classical way, we use the explicit matrix\nrepresentation in terms of numerical NumPy arrays.\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"Id = np.identity(2)\nZ = np.array([[1, 0], [0, -1]])\nX = np.array([[0, 1], [1, 0]])\n\nA_0 = np.identity(8)\nA_1 = np.kron(np.kron(X, Z), Id)\nA_2 = np.kron(np.kron(X, Id), Id)\n\nA_num = c[0] * A_0 + c[1] * A_1 + c[2] * A_2\nb = np.ones(8) / np.sqrt(8)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We can print the explicit values of $A$ and $b$:\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"print(\"A = \\n\", A_num)\nprint(\"b = \\n\", b)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The solution can be computed via a matrix inversion:\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"A_inv = np.linalg.inv(A_num)\nx = np.dot(A_inv, b)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Finally, in order to compare $x$ with the quantum state $|x\\rangle$, we\nnormalize and square its elements.\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"c_probs = (x / np.linalg.norm(x)) ** 2"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Preparation of the quantum solution\n===================================\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Given the variational weights `w` that we have previously optimized, we\ncan generate the quantum state $|x\\rangle$. By measuring $|x\\rangle$ in\nthe computational basis we can estimate the probability of each basis\nstate.\n\nFor this task, we initialize a new PennyLane device and define the\nassociated QNode.\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"dev_x = qml.device(\"default.qubit\", wires=n_qubits, shots=n_shots)\n\n@qml.qnode(dev_x)\ndef prepare_and_sample(weights):\n\n # Variational circuit generating a guess for the solution vector |x>\n variational_block(weights)\n\n # We assume that the system is measured in the computational basis.\n # Therefore, sampling from the device will give us a value of 0 or 1 for each qubit (n_qubits)\n # this will be repeated for the total number of shots provided (n_shots).\n return qml.sample()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"To estimate the probability distribution over the basis states we first\ntake `n_shots` samples and then compute the relative frequency of each\noutcome.\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"raw_samples = prepare_and_sample(w)\n\n# convert the raw samples (bit strings) into integers and count them\nsamples = []\nfor sam in raw_samples:\n samples.append(int(\"\".join(str(bs) for bs in sam), base=2))\n\nq_probs = np.bincount(samples, minlength=2 ** n_qubits) / n_shots"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Comparison\n==========\n\nLet us print the classical result.\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"print(\"x_n^2 =\\n\", c_probs)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The previous probabilities should match the following quantum state\nprobabilities.\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"print(\"||^2=\\n\", q_probs)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Let us graphically visualize both distributions.\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(7, 4))\n\nax1.bar(np.arange(0, 2 ** n_qubits), c_probs, color=\"blue\")\nax1.set_xlim(-0.5, 2 ** n_qubits - 0.5)\nax1.set_xlabel(\"Vector space basis\")\nax1.set_title(\"Classical probabilities\")\n\nax2.bar(np.arange(0, 2 ** n_qubits), q_probs, color=\"green\")\nax2.set_xlim(-0.5, 2 ** n_qubits - 0.5)\nax2.set_xlabel(\"Hilbert space basis\")\nax2.set_title(\"Quantum probabilities\")\n\nplt.show()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"References\n==========\n\n1. Carlos Bravo-Prieto, Ryan LaRose, Marco Cerezo, Yigit Subasi, Lukasz\n Cincio, Patrick J. Coles. \\\"Variational Quantum Linear Solver: A\n Hybrid Algorithm for Linear Systems.\\\"\n [arXiv:1909.05820](https://arxiv.org/abs/1909.05820), 2019.\n2. Robin Kothari. \\\"Efficient algorithms in quantum query complexity.\\\"\n PhD thesis, University of Waterloo, 2014.\n"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.7.13"
}
},
"nbformat": 4,
"nbformat_minor": 0
}