├── qc_param.png
└── Simulated_Annealing_Tutorial_Pennylane.ipynb
/qc_param.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/KetpuntoG/simulated-annealing-pennylane/main/qc_param.png
--------------------------------------------------------------------------------
/Simulated_Annealing_Tutorial_Pennylane.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "id": "30ed889a",
6 | "metadata": {},
7 | "source": [
8 | "# Optimizing a Variational Quantum Circuit via Simulated Annealing \n",
9 | "by Mahnoor Fatima ([mahnoorf04@gmail.com](mailto:mahnoorf04@gmail.com)) "
10 | ]
11 | },
12 | {
13 | "cell_type": "markdown",
14 | "id": "275df39e",
15 | "metadata": {},
16 | "source": [
17 | "**Simulated annealing** is an optimization algorithm to find the global optima for both bounded and unbounded optimization problems. The algorithm is inspired from the metallic annealing process in which a metal is first heated and then gradually cooled. In this algorithm, the optimizer first explores the solution space haphazardly which allows it to explore a greater range of values; as the temperature 'drops,' the solution space becomes less scattered and the predicted points remain close to the current state of the system.\n",
18 | "\n",
19 | "The main advantage is that it allows the determination of the stochastic global maximum of an optimization problem. However, the dowside of this algorithm is that it might return the wrong optimal point. \n",
20 | "\n",
21 | "You can read more about simulated annealing and its applications in this [open-source paper](https://projecteuclid.org/journals/statistical-science/volume-8/issue-1/Simulated-Annealing/10.1214/ss/1177011077.full)."
22 | ]
23 | },
24 | {
25 | "cell_type": "markdown",
26 | "id": "1b2f4f7d",
27 | "metadata": {},
28 | "source": [
29 | "## Explore the Problem Statement\n",
30 | "\n",
31 | "A variational quantum circuit (VQC) is a quantum circuit having parametrized gates such that the behaviour of the circuit can be varied by varying the parameters. Thus, with appropraite parameters, a generic parametrized quantum circuit can be trained to perform a desired operation. \n",
32 | "\n",
33 | "This flexibility of VQCs is the inspiration for this problem: training an $n$-qubit VQC for evaluating the Quantum Fourier Transform of a number in the range 0 – $2^n-1$. **Quantum Fourier Transform (QFT)** is itself a unitary operation which evaluates the Fourier transform of a quantum statez. Its matrix representation is as follows:\n",
34 | "$$\\begin{bmatrix}\n",
35 | "1 & 1 & \\dots & 1\\\\\n",
36 | "1 & e^{\\frac{\\iota 2\\pi}{N}} & \\dots & e^{\\frac{\\iota2\\pi(N-1)}{N}}\\\\\n",
37 | "1 & e^{\\frac{\\iota 2\\pi. 2}{N}} & \\dots & e^{\\frac{\\iota2\\pi. 2(N-1)}{N}}\\\\\n",
38 | "1 & e^{\\frac{\\iota 2\\pi. 3}{N}} & \\dots & e^{\\frac{\\iota2\\pi.3(N-1)}{N}}\\\\\n",
39 | "\\vdots & \\vdots & \\dots & \\vdots \\\\\n",
40 | "1 & e^{\\frac{\\iota 2\\pi.(N-1)}{N}} & \\dots & e^{\\frac{\\iota2\\pi.(N-1)(N-1)}{N}}\\\\\n",
41 | "\\end{bmatrix},$$\n",
42 | "where $N$ is the number of qubits of the quantum state.\n",
43 | "\n",
44 | "For this tutorial, we will be making a generic $n$-qubit variational quantum circuit with a Hadamard gate and an $R_z(\\theta)$ gate to each qubit. The angle $\\theta$ of each $R_z$ gate comprise the list of parameters to be optimized. An inverse-QFT block is applied to evaluate the error such that the expected output is the input number itself. "
45 | ]
46 | },
47 | {
48 | "cell_type": "markdown",
49 | "id": "0d65c7d5",
50 | "metadata": {},
51 | "source": [
52 | "
\n",
53 | " \n",
54 | "
"
55 | ]
56 | },
57 | {
58 | "cell_type": "markdown",
59 | "id": "434f3969",
60 | "metadata": {},
61 | "source": [
62 | "## Import the Libraries \n",
63 | "\n",
64 | "Firstly, we will import the required libraries and packages. "
65 | ]
66 | },
67 | {
68 | "cell_type": "code",
69 | "execution_count": 1,
70 | "id": "7dc27b1f",
71 | "metadata": {},
72 | "outputs": [],
73 | "source": [
74 | "import pennylane as qml\n",
75 | "from pennylane import numpy as np\n",
76 | "from math import exp"
77 | ]
78 | },
79 | {
80 | "cell_type": "markdown",
81 | "id": "4a15a636",
82 | "metadata": {},
83 | "source": [
84 | "### Define the Quantum Device\n",
85 | "\n",
86 | "We will simulate the circuit on a noiseless simulator:"
87 | ]
88 | },
89 | {
90 | "cell_type": "markdown",
91 | "id": "41b28b25",
92 | "metadata": {},
93 | "source": [
94 | "```python\n",
95 | "dev = qml.device('default.qubit', wires = n)\n",
96 | "```"
97 | ]
98 | },
99 | {
100 | "cell_type": "markdown",
101 | "id": "0a2ff595",
102 | "metadata": {},
103 | "source": [
104 | "### Define the Quantum Node\n",
105 | "Next, we will construct the quantum circuit function and wrap it in a Quantum Node."
106 | ]
107 | },
108 | {
109 | "cell_type": "markdown",
110 | "id": "211f7628",
111 | "metadata": {},
112 | "source": [
113 | "```python\n",
114 | "@qml.qnode(dev)\n",
115 | "def circuit(theta):\n",
116 | " for i in range(n):\n",
117 | " qml.Hadamard(wires = i)\n",
118 | " qml.RZ(theta[i], wires = i)\n",
119 | " qml.adjoint(qml.QFT)(wires=range(n))\n",
120 | " return qml.probs(wires = range(n))\n",
121 | "```"
122 | ]
123 | },
124 | {
125 | "cell_type": "markdown",
126 | "id": "d655d8ac",
127 | "metadata": {},
128 | "source": [
129 | "### Define the Cost Function\n",
130 | "\n",
131 | "\n",
132 | "**Mean Square Error (MSE)** is one of the most common cost functions and is given by:\n",
133 | "$$MSE = \\sum_{i=0}^{N-1} (y_i-\\hat{y}_i)^2$$\n",
134 | "where `y` is the predicted output array and `ŷ` is the expected output array. \n",
135 | "\n",
136 | "For the given problem, the expected output `ŷ` is a $2^n$-sized array with all entries equal to zero except for the $m$-index entry, which is $1$, i.e., we want the number $m$ to be evaluated with an absolute certainty. "
137 | ]
138 | },
139 | {
140 | "cell_type": "markdown",
141 | "id": "75853026",
142 | "metadata": {},
143 | "source": [
144 | "```python\n",
145 | "def cost(params):\n",
146 | " y = np.zeros(2**n)\n",
147 | " y[m] = 1\n",
148 | " probs = circuit(params)\n",
149 | " return np.sum(np.square((y-probs)))\n",
150 | "```"
151 | ]
152 | },
153 | {
154 | "cell_type": "markdown",
155 | "id": "b5f09e56",
156 | "metadata": {},
157 | "source": [
158 | "## Implement the Simulated Annealing Algorithm\n",
159 | "\n",
160 | "The procedure for simulated annealing is as follows:\n",
161 | "- A random point is selected as the initial state of the system.\n",
162 | "\n",
163 | "- As the temperature is initially high, the algorithm searches the solution space haphazardly and evaluates the cost value for various states. \n",
164 | " - If the cost value for a certain state is less than for the current optimal state, the optimal state of the circuit is updated.\n",
165 | "- The new temperature of the system is evaluated by using the following equation:\n",
166 | " $$ t_{i} = \\frac{t_o}{i+1}$$\n",
167 | " where $i$ is the number of the current iteration. \n",
168 | " \n",
169 | " As the temperature of the system decreases, the algorithm takes smaller strides across the solution space.\n",
170 | "\n",
171 | "> **Note:** As discussed earlier, simulated annealing can optimize both bounded and unbounded problems. For this tutorial, we have not bounded the parameters because of the periodicity of the angle $\\theta \\epsilon [0, \\pi]$ of rotation. \n",
172 | "\n",
173 | "The code-based implementation of the algorithm is as follows:"
174 | ]
175 | },
176 | {
177 | "cell_type": "code",
178 | "execution_count": 9,
179 | "id": "329df99e",
180 | "metadata": {},
181 | "outputs": [],
182 | "source": [
183 | "def simulated_annealing(objective, param_range, temperature, iterations, learning_rate):\n",
184 | " # Define initial state\n",
185 | " s0 = np.empty(np.shape(param_range)[0])\n",
186 | " s_eval = 0 \n",
187 | " for i in range(len(s0)):\n",
188 | " s0[i] = param_range[i][0] + np.random.random()* (param_range[i][1] - param_range[i][0])\n",
189 | "\n",
190 | " # Evaluate current state of the system \n",
191 | " s = s0\n",
192 | " s_eval = objective(s0)\n",
193 | "\n",
194 | " for k in range(iterations):\n",
195 | " # Find a candidate element\n",
196 | " s_new = np.empty(np.shape(param_range)[0])\n",
197 | " for i in range(len(s_new)):\n",
198 | " rng = param_range[i][1] - param_range[i][0] # Range of the variable\n",
199 | " s_new[i] = s[i] + np.random.uniform(param_range[i][0] - rng/2, param_range[i][0] + rng/2)*learning_rate\n",
200 | "\n",
201 | " # Evaluate the candidate element \n",
202 | " s_new_eval = objective(s_new)\n",
203 | " # Update the state of the system\n",
204 | " if s_new_eval < s_eval:\n",
205 | " s = s_new\n",
206 | " s_eval = s_new_eval\n",
207 | "\n",
208 | " delta = s_new_eval - s_eval\n",
209 | " t = temperature/float(k+1) \n",
210 | "\n",
211 | " # Metropolis acceptance criterion\n",
212 | " metropolis = exp(-delta/t)\n",
213 | " if metropolis > np.random.uniform():\n",
214 | " s = s_new\n",
215 | " s_eval = s_new_eval\n",
216 | " return s, s_eval"
217 | ]
218 | },
219 | {
220 | "cell_type": "markdown",
221 | "id": "18f5ace7",
222 | "metadata": {},
223 | "source": [
224 | "## Optimization Module\n",
225 | "\n",
226 | "As a final step of implementing the solution of the given problem, we encapsulate the entire optimization problem in a function. This will allow us to quick-run the problem for different parameters without the hassle of updating the parameters. Also, the quantum circuit has been defined within the function to keep the variables (like `m` and `n`) accessible for all functions. (An alternate approach would be to pass these functions as an argument, but for this tutorial, the latter is the better approach.)"
227 | ]
228 | },
229 | {
230 | "cell_type": "code",
231 | "execution_count": 12,
232 | "id": "23956a90",
233 | "metadata": {},
234 | "outputs": [],
235 | "source": [
236 | "def quantum_fourier_transform(n, m, temperature, steps = 5000, learning_rate = 0.01):\n",
237 | " ''' A function to generate the Quantum Fourier Transform of a number m via a quantum circuit with n-qubits. \n",
238 | " \n",
239 | " Args:\n",
240 | " n: It is the number of qubits in the variational quantum circuit.\n",
241 | " m: It is the number used to train the variational quantum circuit. Its value ranges from 0 to 2^n - 1\n",
242 | " steps: It is the number of iterations of the optimzation process.\n",
243 | " learning_rate: This is the step size of the optimizer.\n",
244 | " \n",
245 | " Return value:\n",
246 | " circuit: The variational quantum circuit comprising n qubits.\n",
247 | " param_arr: Shape = (steps, n). It consists of the values of the parameters after each optimization step.\n",
248 | " cost_arr: Size = n. It consists of the cost value of the circuit after each optimization step.\n",
249 | " cost: The cost function\n",
250 | " '''\n",
251 | " # Task 2: Load a Quantum Device\n",
252 | " dev = qml.device('default.qubit', wires = n)\n",
253 | " \n",
254 | " # Task 3-6: Create the Quantum Circuit\n",
255 | " @qml.qnode(dev)\n",
256 | " def circuit(theta):\n",
257 | " for i in range(n):\n",
258 | " qml.Hadamard(wires = i)\n",
259 | " qml.RZ(theta[i], wires = i)\n",
260 | " qml.adjoint(qml.QFT)(wires=range(n))\n",
261 | " return qml.probs(wires = range(n))\n",
262 | " \n",
263 | " # Task 7: Create the Cost Function\n",
264 | " def cost(params):\n",
265 | " y = np.zeros(2**n)\n",
266 | " y[m] = 1\n",
267 | " probs = circuit(params)\n",
268 | " return np.sum(np.square((y-probs)))\n",
269 | " \n",
270 | " # Defining the bounds of the angles\n",
271 | " bounds = np.empty((n, 2))\n",
272 | " for bound in bounds:\n",
273 | " bound[0] = 0\n",
274 | " bound[1] = 2*np.pi\n",
275 | " \n",
276 | " angles, cost = simulated_annealing(cost, bounds, temperature, steps, learning_rate)\n",
277 | " angles = angles%(np.pi*2)\n",
278 | "\n",
279 | " # Print the results of optimization\n",
280 | " print(\"Optimized rotation angles: \", angles)\n",
281 | " print(\"Cost value at optimized parameters: \",cost)\n",
282 | " \n",
283 | " return circuit, angles, cost"
284 | ]
285 | },
286 | {
287 | "cell_type": "markdown",
288 | "id": "ba9ca33d",
289 | "metadata": {},
290 | "source": [
291 | "## Optimization of the Quantum Circuit\n",
292 | "\n",
293 | "Now, let's test-run the function for a random set of parameters to evaluate it's performance. "
294 | ]
295 | },
296 | {
297 | "cell_type": "code",
298 | "execution_count": 15,
299 | "id": "38a49783",
300 | "metadata": {},
301 | "outputs": [
302 | {
303 | "name": "stdout",
304 | "output_type": "stream",
305 | "text": [
306 | "Optimized rotation angles: [3.11822442 4.87195537]\n",
307 | "Cost value at optimized parameters: 8.24324861063424e-05\n"
308 | ]
309 | },
310 | {
311 | "data": {
312 | "text/plain": [
313 | "(, )"
314 | ]
315 | },
316 | "execution_count": 15,
317 | "metadata": {},
318 | "output_type": "execute_result"
319 | },
320 | {
321 | "data": {
322 | "image/png": "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\n",
323 | "text/plain": [
324 | ""
325 | ]
326 | },
327 | "metadata": {},
328 | "output_type": "display_data"
329 | }
330 | ],
331 | "source": [
332 | "circuit, angles, cost = quantum_fourier_transform(2, 3, 5, steps = 10000, learning_rate = 0.01)\n",
333 | "qml.draw_mpl(circuit)(angles)"
334 | ]
335 | }
336 | ],
337 | "metadata": {
338 | "kernelspec": {
339 | "display_name": "Python 3 (ipykernel)",
340 | "language": "python",
341 | "name": "python3"
342 | },
343 | "language_info": {
344 | "codemirror_mode": {
345 | "name": "ipython",
346 | "version": 3
347 | },
348 | "file_extension": ".py",
349 | "mimetype": "text/x-python",
350 | "name": "python",
351 | "nbconvert_exporter": "python",
352 | "pygments_lexer": "ipython3",
353 | "version": "3.8.10"
354 | }
355 | },
356 | "nbformat": 4,
357 | "nbformat_minor": 5
358 | }
359 |
--------------------------------------------------------------------------------