├── EVA.png ├── rEVA.png └── EVA.ipynb /EVA.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KetpuntoG/EVA/main/EVA.png -------------------------------------------------------------------------------- /rEVA.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KetpuntoG/EVA/main/rEVA.png -------------------------------------------------------------------------------- /EVA.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Exponential Value Approximation (EVA)\n", 8 | "\n", 9 | "\n", 10 | "\n", 11 | "The first step will be to generate the Hamiltonian with which we will test. Here is shown the construction of a Hamiltonian of order 3 in which each term with probability p will appear. In case we want to test with the Hamiltonian of order 2 we will have to comment the last for." 12 | ] 13 | }, 14 | { 15 | "cell_type": "code", 16 | "execution_count": 1, 17 | "metadata": {}, 18 | "outputs": [], 19 | "source": [ 20 | "import pennylane as qml\n", 21 | "from pennylane import numpy as np\n", 22 | "\n", 23 | "p = 0.75 \n", 24 | "size = 10 # number of qubits\n", 25 | "\n", 26 | "obs = []\n", 27 | "for j in range(size):\n", 28 | " if np.random.rand() < p :obs.append(qml.PauliZ(wires = j))\n", 29 | " \n", 30 | " for i in range(j+1,size):\n", 31 | " if np.random.rand() < p :obs.append(qml.PauliZ(wires = j) @ qml.PauliZ(wires = i))\n", 32 | " \n", 33 | " for k in range(i+1,size):\n", 34 | " if np.random.rand() < p :obs.append(qml.PauliZ(wires = j) @ qml.PauliZ(wires = i) @ qml.PauliZ(wires = k))\n", 35 | " \n", 36 | "\n", 37 | "coefs = (np.random.rand(len(obs))-0.5)*2\n", 38 | "coefs = coefs / sum([abs(i) for i in coefs]) # we normalize the coefficients\n", 39 | "\n", 40 | "\n", 41 | "H = qml.Hamiltonian(coefs, obs)" 42 | ] 43 | }, 44 | { 45 | "cell_type": "markdown", 46 | "metadata": {}, 47 | "source": [ 48 | "Our objective will be to calculate the expected value of a state $\\phi$ through the Hamiltonian. To do this we will first define the ansantz that we will use to generate the $\\phi$ state." 49 | ] 50 | }, 51 | { 52 | "cell_type": "code", 53 | "execution_count": 2, 54 | "metadata": {}, 55 | "outputs": [], 56 | "source": [ 57 | "w = np.random.rand(size) * np.pi\n", 58 | "\n", 59 | "def ansantz(w, wires = list(range(size))):\n", 60 | " for i in wires:\n", 61 | " qml.RX(w[i], wires = i)\n", 62 | " qml.CNOT(wires = [i, (i + 1) % size])" 63 | ] 64 | }, 65 | { 66 | "cell_type": "markdown", 67 | "metadata": {}, 68 | "source": [ 69 | "We will start by implementing EVA. Recall that it had the following structure:\n", 70 | "\n", 71 | "\n", 72 | "" 73 | ] 74 | }, 75 | { 76 | "cell_type": "code", 77 | "execution_count": 3, 78 | "metadata": {}, 79 | "outputs": [ 80 | { 81 | "name": "stdout", 82 | "output_type": "stream", 83 | "text": [ 84 | "expected value: -0.04998235294117647\n" 85 | ] 86 | } 87 | ], 88 | "source": [ 89 | "from pennylane import numpy as np\n", 90 | "from pennylane.templates import ApproxTimeEvolution\n", 91 | "\n", 92 | "shots = 5000\n", 93 | "k = 4\n", 94 | " \n", 95 | "@qml.template\n", 96 | "def evolution():\n", 97 | " ApproxTimeEvolution(H, -1/k, 1)\n", 98 | " \n", 99 | "ops = qml.ctrl(evolution, control = size)\n", 100 | "dev = qml.device(\"default.qubit\", size + 1, shots = int(len(H.coeffs) * shots * k ** 2))\n", 101 | "\n", 102 | "@qml.qnode(dev)\n", 103 | "def model(w):\n", 104 | " ansantz(w)\n", 105 | " qml.Hadamard(wires = size)\n", 106 | " qml.RZ(-np.pi/2, wires = size)\n", 107 | " ops()\n", 108 | " qml.Hadamard(wires = size)\n", 109 | " return qml.expval(qml.PauliZ(wires = size))\n", 110 | "\n", 111 | "def EVA(w):\n", 112 | " return model(w) * k \n", 113 | "\n", 114 | "print(\"expected value:\", EVA(w))" 115 | ] 116 | }, 117 | { 118 | "cell_type": "markdown", 119 | "metadata": {}, 120 | "source": [ 121 | "We will now move on to implement the second version, the reduced EVA. In this case the circuit was as follows:\n", 122 | "\n", 123 | "" 124 | ] 125 | }, 126 | { 127 | "cell_type": "code", 128 | "execution_count": 4, 129 | "metadata": {}, 130 | "outputs": [ 131 | { 132 | "name": "stdout", 133 | "output_type": "stream", 134 | "text": [ 135 | "expected value: -0.051958823529411766\n" 136 | ] 137 | } 138 | ], 139 | "source": [ 140 | "@qml.template\n", 141 | "def hadamards():\n", 142 | " for i in range(size):\n", 143 | " qml.Hadamard(wires = i)\n", 144 | " \n", 145 | " \n", 146 | "ops2 = qml.ctrl(hadamards, control = size)\n", 147 | "\n", 148 | "@qml.qnode(dev)\n", 149 | "def model2(w):\n", 150 | " ansantz(w)\n", 151 | " qml.Hadamard(wires = size)\n", 152 | " qml.RZ(np.pi/2, wires = size)\n", 153 | " ops2()\n", 154 | " ApproxTimeEvolution(H, -1/k, 1)\n", 155 | " ops2()\n", 156 | " qml.Hadamard(wires = size)\n", 157 | " return qml.expval(qml.PauliZ(wires = size))\n", 158 | "\n", 159 | "def reducedEVA(w):\n", 160 | " return model2(w) * k \n", 161 | "\n", 162 | "print(\"expected value:\", reducedEVA(w))" 163 | ] 164 | }, 165 | { 166 | "cell_type": "markdown", 167 | "metadata": {}, 168 | "source": [ 169 | "Finally, we will implement the VQE and its optimized version to check the results through this other approach.\n" 170 | ] 171 | }, 172 | { 173 | "cell_type": "code", 174 | "execution_count": 5, 175 | "metadata": {}, 176 | "outputs": [ 177 | { 178 | "name": "stdout", 179 | "output_type": "stream", 180 | "text": [ 181 | "VQE, expected value: -0.05167444310684194\n", 182 | "VQE optimize, expected value: -0.05088705702260766\n" 183 | ] 184 | } 185 | ], 186 | "source": [ 187 | "def vqe(w):\n", 188 | " dev2 = qml.device(\"default.qubit\", size, shots = shots)\n", 189 | " cost_fn = qml.ExpvalCost(ansantz, H, dev2, optimize = False)\n", 190 | " return cost_fn(w)\n", 191 | "\n", 192 | "def vqe_compact(w):\n", 193 | " dev2 = qml.device(\"default.qubit\", size , shots = shots)\n", 194 | " cost_fn = qml.ExpvalCost(ansantz, H, dev2, optimize = True)\n", 195 | " return cost_fn(w)\n", 196 | "\n", 197 | "print(\"VQE, expected value:\", vqe(w))\n", 198 | "print(\"VQE optimize, expected value:\", vqe_compact(w))" 199 | ] 200 | }, 201 | { 202 | "cell_type": "markdown", 203 | "metadata": {}, 204 | "source": [ 205 | "As we can see, the four methods approximate the expected value in a similar way." 206 | ] 207 | } 208 | ], 209 | "metadata": { 210 | "kernelspec": { 211 | "display_name": "Python 3", 212 | "language": "python", 213 | "name": "python3" 214 | }, 215 | "language_info": { 216 | "codemirror_mode": { 217 | "name": "ipython", 218 | "version": 3 219 | }, 220 | "file_extension": ".py", 221 | "mimetype": "text/x-python", 222 | "name": "python", 223 | "nbconvert_exporter": "python", 224 | "pygments_lexer": "ipython3", 225 | "version": "3.8.3" 226 | } 227 | }, 228 | "nbformat": 4, 229 | "nbformat_minor": 4 230 | } 231 | --------------------------------------------------------------------------------