diff --git a/README.md b/README.md index 6b5c51f0b..e8e77342f 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ In this repository, we've put together a collection of Jupyter notebooks aimed a The notebooks for these tutorials can be viewed here on GitHub. But for the full experience, you'll want to interact with them! -The easiest way to do this is using [the Binder image](https://mybinder.org/v2/gh/qiskit/qiskit-tutorials/master?filepath=index.ipynb), which lets you use the notebooks via the web. This means that you don't need to download or install anything, but it also means that you should not insert any private information into the notebooks (such as your API key). We recommend as pointed out in [issue #231](https://github.com/Qiskit/qiskit-tutorial/issues/231) that after you are done using mybinder that you regenerate your token. +The easiest way to do this is using [the Binder image](https://mybinder.org/v2/gh/qiskit/qiskit-tutorials/master?filepath=index.ipynb), which lets you use the notebooks via the web. This means that you don't need to download or install anything, but it also means that you should not insert any private information into the notebooks (such as your API key). We recommend as pointed out in [issue #231](https://github.com/Qiskit/qiskit-tutorials/issues/231) that after you are done using mybinder that you regenerate your token. Please refer to this [installation guide](INSTALL.md) for setting up Qiskit and the tutorials on your own machine (this is the recommended way). diff --git a/community/games/README.md b/community/games/README.md index f22b441ac..fa8aa2ec3 100644 --- a/community/games/README.md +++ b/community/games/README.md @@ -15,7 +15,9 @@ This is exactly what we'd like to replicate in this folder. Here you'll find bas * [Quantum Tic-tac-toe](quantum_tic_tac_toe.ipynb) - Tic-tac-toe was one of the first games for a classical computer. Now we have a quantum version too! -* [Quantum Awesomeness](quantum_awesomeness.ipynb) - Puzzles that aim to give hands-on experience of a quantum device's most important features: number of qubits, connectivity and noise +* [Quantum Awesomeness](quantum_awesomeness.ipynb) - Puzzles that aim to give hands-on experience of a quantum device's most important features: number of qubits, connectivity and noise. + +* [Random Terrain Generation](random_terrain_generation.ipynb) - A simple example of using quantum computers for the kind of procedural generation often used in games. ## Contributing diff --git a/community/games/random_terrain_generation.ipynb b/community/games/random_terrain_generation.ipynb new file mode 100644 index 000000000..3bbf6b703 --- /dev/null +++ b/community/games/random_terrain_generation.ipynb @@ -0,0 +1,793 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\"Note: Trusted Notebook (and the image needs to be where this notebook is expecting it)\" width=\"500 px\" align=\"left\">" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# _*Random Terrain Generation*_\n", + "\n", + "The latest version of this notebook is available on https://github.com/qiskit/qiskit-tutorial.\n", + "\n", + "***\n", + "### Contributors\n", + "James R. Wootton, IBM Research\n", + "***" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "From 1980's *Rogue* to recent games like *No Man's Sky*, [randomly generated content](https://en.wikipedia.org/wiki/Procedural_generation#Video_games) has become an important part of game design. This content is not generated in a completely random way, but is instead subject to a variety of constraints, like looking good, providing unique experiences for the player in every random sample, forming a solvable level and allowing this solvability to be efficiently verified.\n", + "\n", + "To satisfy these contraints, the procedure used to generate the random content can sometimes rely on reusing the same patterns over and over. Unfortunately this carries the risk of players recognising the patterns, which compromises the ability to keep providing unique experiences.\n", + "\n", + "Procedural generation is therefore another area in which quantum computers could be very useful. Not only can it be used for new methods of generating random content, it can also provide new algorithms to analyse the solvability of classical methods.\n", + "\n", + "In this notebook we perform a first experiment on quantum procedural generation. This will cover one of the simplest and most useful applications of procedural generation: the creation of random height maps.\n", + "\n", + "One of the current most popular methods to do this is [Perlin noise](https://en.wikipedia.org/wiki/Perlin_noise). Here's a sample ([source](https://commons.wikimedia.org/wiki/File:Perlin_noise.jpg)).\n", + "\n", + "![Perlin noise by Reedbeta on Wikimedia Commons](https://upload.wikimedia.org/wikipedia/commons/d/da/Perlin_noise.jpg)\n", + "\n", + "In this image, the white and black areas can be associated with mountains and valleys, respectively. This image could therefore be turned into mountainous terrain to explore in a game. In this notebook we will investigate how to generate something similar with Qiskit." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "First, let's choose how many qubits to use." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "n = 9" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Next, let's work out what to do with them. We will make a method designed for current and near-term devices, which means making the most out of a few qubits. However, we will also want to generate images with thousands of points. To allow this, we can measure the probabilities for each of the $2^n$ possible output bit strings that are possible for $n$ qubits. We can then associate each bit string with a point, and the height of the map can be the probability of that point.\n", + "\n", + "Getting all these probabilities will mean that we need a large number of shots, which is how many times we repeatedly run a quantum program to calculate statistics of the outputs." + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "shots = 4**n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "This method is therefore not scalable to large $n$: it has exactly the kind of exponentially increasing run time that quantum computers usually aim to free us from. Other quantum methods for procedural generation will therefore be needed in the [NISQ era](https://arxiv.org/abs/1801.00862) of quantum computing and beyond.\n", + "\n", + "For now, we need to choose a way of assigning each of the possible bit strings to a point. The most natural way to do this would be to respect the [Hamming distance](https://en.wikipedia.org/wiki/Hamming_distance) of the bit strings. This is because the basic operations of quantum computing, single qubit gates and `cx` gates, only have the effect of flipping a single bit in a bit string. Strings that differ by only a single bit can therefore be regarded as 'closer' to each other than those that differ by more.\n", + "\n", + "With this in mind, the set of all $n$-bit strings represents a hypercube: a shape that exists in $n$-dimensional space. This is a bit exotic for our needs, since we want the generate a 2D terrain map like the one depicted above. We therefore need a way to squash a hypercube onto a 2D surface.\n", + "\n", + "This is done in the following cell. The dictionary `strings` is created, which has 2D coordinates `(x,y)` as keys and the corresponding bit string as values. The squashing procedure essentially uses the fact that a cube is two squares, with each point in one connected to its partner in the other. A tesseract is then two cubes connected similarly, and so on for higher dimensional hypercubes. But if we don't include all the possible connections, we can keep our not-quite-a-cube flat, and then do the same with the corresponding not-quite-a-tesseract, and so on.\n", + "\n", + "The result is a square lattice. The four neighbours of each point are four of the $n$ hypercube neighbours of the corresponding string. So the strings are only close to strings that they should be close to, though at the cost of being far away from some of their hypercube neighbours." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [], + "source": [ + "import numpy as np\n", + "\n", + "Lx = int(2**np.ceil(n/2))\n", + "Ly = int(2**np.floor(n/2))\n", + "\n", + "strings = {}\n", + "for y in range(Ly):\n", + " for x in range(Lx):\n", + " strings[(x,y)] = ''\n", + "\n", + "for (x,y) in strings:\n", + " for j in range(n):\n", + " if (j%2)==0:\n", + " xx = np.floor(x/2**(j/2))\n", + " strings[(x,y)] = str( int( ( xx + np.floor(xx/2) )%2 ) ) + strings[(x,y)]\n", + " else:\n", + " yy = np.floor(y/2**((j-1)/2))\n", + " strings[(x,y)] = str( int( ( yy + np.floor(yy/2) )%2 ) ) + strings[(x,y)]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The squashed hypercube we obtain above is just one of exponentially many we could have got. To explore this space a bit, and not end up with the same grid every time, we can perform a suffle. This reorders the bits in all the bit strings in the same way. This ensures the resulting squashed hypercube has all the properties we need, while allowing for some variation with each run." + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [], + "source": [ + "import random\n", + "\n", + "order = [j for j in range(n)]\n", + "random.shuffle(order)\n", + "\n", + "for (x,y) in strings:\n", + " new_string = ''\n", + " for j in order:\n", + " new_string = strings[(x,y)][j] + new_string\n", + " strings[(x,y)] = new_string" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can also assert a bit of control over the hypercube by choosing which string lives at the center (actucally, it will be just to the top right of the center). By default, we choose this to be the string with all `0`s." + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [], + "source": [ + "center = '0'*n" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [], + "source": [ + "current_center = strings[ ( int(np.floor(Lx/2)),int(np.floor(Ly/2)) ) ]\n", + "diff = ''\n", + "for j in range(n):\n", + " diff += '0'*(current_center[j]==center[j]) + '1'*(current_center[j]!=center[j])\n", + "for (x,y) in strings:\n", + " newstring = ''\n", + " for j in range(n):\n", + " newstring += strings[(x,y)][j]*(diff[j]=='0') + ('0'*(strings[(x,y)][j]=='1')+'1'*(strings[(x,y)][j]=='0'))*(diff[j]=='1')\n", + " strings[(x,y)] = newstring" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "With these manipulations complete, we now create the dictionary `pos`, which is ordered in the opposite way to `strings`: it has the strings as keys and coordinates as values." + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [], + "source": [ + "pos = {}\n", + "for y in range(Ly):\n", + " for x in range(Lx):\n", + " pos[strings[(x,y)]] = (x,y)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now the grid is defined, we can deal with how to make an image of it. This is done with the following function, which will create a shaded block for each string at the positions defined by `pos`. It will also use `probs`, which will be a dictionary with the output strings as keys and their corresponding probabilities as values. The resulting shaded blockswill be darker for strings whose probability is low, and lighter for high probability strings.\n", + "\n", + "By default, the lowest probabilities are made black, the highest are white and the scaling of the shading is logarithmic. These can be turned off with the `log` and `normalize` kwargs." + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": { + "scrolled": false + }, + "outputs": [], + "source": [ + "import matplotlib\n", + "import matplotlib.pyplot as plt\n", + "\n", + "def plot_terrain(pos,probs,log=True,normalize=True):\n", + "\n", + " Z = {}\n", + " for node in probs:\n", + " if log:\n", + " Z[node] = np.log(probs[node])\n", + " else:\n", + " Z[node] = probs[node]\n", + " \n", + " minZ = min(Z.values())\n", + " maxZ = max(Z.values())\n", + " colors = {}\n", + " for node in Z:\n", + " if normalize:\n", + " z = (Z[node]-minZ)/(maxZ-minZ)\n", + " else:\n", + " z = Z[node]\n", + " colors[node] = (z,z,z,1)\n", + "\n", + " fig = plt.figure()\n", + " ax = fig.add_subplot(111)\n", + " \n", + " for node in pos:\n", + " rect = matplotlib.patches.Rectangle(pos[node], 1, 1, color=colors[node])\n", + " ax.add_patch(rect)\n", + " plt.xlim([0, Lx])\n", + " plt.ylim([0, Ly])\n", + " plt.axis('off')\n", + " plt.savefig('output.png',dpi=1000)\n", + " plt.show()\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Note that the plotting we are using won't be happy if all possible strings aren't present in `pos` with a non-zero probability. So we'll give all the outputs that don't appear a nominal probability of 1/`shots`.\n", + "\n", + "Here's a function to produce such a `probs` from the results contain in a `job` object." + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [], + "source": [ + "def get_probs(job):\n", + " counts = job.result().get_counts()\n", + " probs = {}\n", + " for string in pos:\n", + " try:\n", + " probs[string] = counts[string]/shots\n", + " except:\n", + " probs[string] = 1/shots\n", + " return probs" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "It's time to make and run a quantum circuit. Let's start with a trivial circuit, and so one that outputs all `0`s." + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": { + "scrolled": false + }, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAXQAAAD8CAYAAABn919SAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADl0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uIDIuMi4zLCBodHRwOi8vbWF0cGxvdGxpYi5vcmcvIxREBQAABBhJREFUeJzt3NFNwzAARVEbdYWK/bfLFDEboACtC5dzvqM4SOjSVOLNtdYA4O97e/UDAPAYgg4QIegAEYIOECHoABGCDhAh6AARgg4QIegAEbedh805jzHG+4VLz3H9j83Va92zc8/az+Oefj8+tdaaV66bO//1f85pZwDgi64G3VcuABGCDhAh6AARgg4QIegAEYIOECHoABGCDhAh6AARgg4QIegAEYIOELE76Ofm8wD+jd1B90YA8CQCCxAh6AARgg4QIegAEYIOECHoABGCDhAh6AARgg4QIegAEYIOECHoABHWFgEirC0CRAgsQISgA0QIOkCEoANECDpAhKADRAg6QISgA0QIOkCEoANECDpAhHEugAjjXAARAgsQIegAEYIOECHoABGCDhAh6AARgg4QIegAEYIOECHoABGCDhAh6AAR1hYBIqwtAkQILECEoANECDpAhKADRAg6QISgA0QIOkCEoANECDpAhKADRAg6QIRxLoAI41wAEQILECHoABGCDhAh6AARgg4QIegAEYIOECHoABGCDhAh6AARgg4QIegAEdYWASKsLQJECCxAhKADRAg6QISgA0QIOkCEoANECDpAhKADRAg6QISgA0QIOkCEcS4YY8w5X/0I8GO3zed5I+BXOs/rnzXEn99KYAEiBB0gQtABIgQdIELQASIEHSBC0AEiBB0gQtABIgQdIELQASIEHSDC2iKMMY7juHzt/X5/4pPA98211r7D5tx3GEDEWuvSxKevXAAiBB0gQtABIgQdIELQASIEHSBC0AEiBB0gQtABIgQdIELQASIEHSDC2iJAxO6geyMAeBKBBYgQdIAIQQeIEHSACEEHiBB0gAhBB4gQdIAIQQeIEHSACEEHiDDOBRBhnAsgQmABIgQdIELQASIEHSBC0AEiBB0gQtABIgQdIELQASIEHSBC0AEiBB0gwtoiQIS1RYAIgQWIEHSACEEHiBB0gAhBB4gQdIAIQQeIEHSACEEHiBB0gAhBB4gwzgUQYZwLIEJgASIEHSBC0AEiBB0gQtABIgQdIELQASIEHSBC0AEiBB0gQtABIgQdIMLaIkCEtUWACIEFiBB0gAhBB4gQdIAIQQeIEHSACEEHiBB0gAhBB4gQdIAIQQeIEHSACGuLABHWFgEiBBYgQtABIgQdIELQASIEHSBC0AEiBB0gQtABIgQdIELQASIEHSDCOBdAhHEugAiBBYgQdIAIQQeIEHSACEEHiBB0gAhBB4gQdIAIQQeIEHSACEEHiBB0gIi51nr1MwDwAD6hA0QIOkCEoANECDpAhKADRAg6QISgA0QIOkCEoANECDpAhKADRAg6QISgA0QIOkCEoANECDpAhKADRAg6QISgA0QIOkCEoANECDpAhKADRHwAPElN4mnmb1EAAAAASUVORK5CYII=\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "from qiskit import *\n", + "\n", + "q = QuantumRegister(n)\n", + "c = ClassicalRegister(n)\n", + "qc = QuantumCircuit(q, c)\n", + "\n", + "qc.measure(q, c)\n", + "\n", + "backend = Aer.get_backend('qasm_simulator')\n", + "\n", + "job = execute(qc, backend, shots=shots)\n", + "\n", + "probs = get_probs(job)\n", + "plot_terrain(pos,probs)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Here we just get a single peak in the center. Not very interesting. To make a mountain, we need to spread out the probability. One way to do this is to simply use the noise present in a real device." + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "from qiskit.providers.aer import noise\n", + "\n", + "IBMQ.load_accounts()\n", + "\n", + "backend_to_simulate = IBMQ.get_backend('ibmq_16_melbourne')\n", + "noise_model = noise.device.basic_device_noise_model(backend_to_simulate.properties())\n", + "job = execute(qc, backend, shots=shots,noise_model=noise_model,basis_gates=noise_model.basis_gates)\n", + "\n", + "probs = get_probs(job)\n", + "plot_terrain(pos,probs)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Here we have used noise in the system instead of trying to avoid it. This is another aspect of our method that makes it suitable for near-term devices.\n", + "\n", + "Now let's try another quantum circuit. This time with a GHZ state." + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAXQAAAD8CAYAAABn919SAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADl0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uIDIuMi4zLCBodHRwOi8vbWF0cGxvdGxpYi5vcmcvIxREBQAABEhJREFUeJzt3EFu2zAARUGyyBWE3v92OoXYXZeFWkd0+jKzFkwFCJ4tA/5zrTUA+P/9ePcNAPA5BB0gQtABIgQdIELQASIEHSBC0AEiBB0gQtABIj52HjbnPMcYP29ceo37bzZ3r/Wandes/T1e0//HH6215p3r5s6f/s857QwA/KW7QfeVC0CEoANECDpAhKADRAg6QISgA0QIOkCEoANECDpAhKADRAg6QISgA0TsDvq1+TyAb2N30D0RADxEYAEiBB0gQtABIgQdIELQASIEHSBC0AEiBB0gQtABIgQdIELQASIEHSDC2iJAhLVFgAiBBYgQdIAIQQeIEHSACEEHiBB0gAhBB4gQdIAIQQeIEHSACEEHiDDOBRBhnAsgQmABIgQdIELQASIEHSBC0AEiBB0gQtABIgQdIELQASIEHSBC0AEiBB0gwtoiQIS1RYAIgQWIEHSACEEHiBB0gAhBB4gQdIAIQQeIEHSACEEHiBB0gAhBB4gwzgUQYZwLIEJgASIEHSBC0AEiBB0gQtABIgQdIELQASIEHSBC0AEiBB0gQtABIgQdIMLaIkCEtUWACIEFiBB0gAhBB4gQdIAIQQeIEHSACEEHiBB0gAhBB4gQdIAIQQeIMM4FY4w557tvAV72sfk8TwR8Sdd1/7OG+PNVCSxAhKADRAg6QISgA0QIOkCEoANECDpAhKADRAg6QISgA0QIOkCEoANEWFuEMcZ5nrevPY7jwTuBfzfXWvsOm3PfYQARa61bE5++cgGIEHSACEEHiBB0gAhBB4gQdIAIQQeIEHSACEEHiBB0gAhBB4gQdIAIa4sAEbuD7okA4CECCxAh6AARgg4QIegAEYIOECHoABGCDhAh6AARgg4QIegAEYIOEGGcCyDCOBdAhMACRAg6QISgA0QIOkCEoANECDpAhKADRAg6QISgA0QIOkCEoANECDpAhLVFgAhriwARAgsQIegAEYIOECHoABGCDhAh6AARgg4QIegAEYIOECHoABGCDhBhnAsgwjgXQITAAkQIOkCEoANECDpAhKADRAg6QISgA0QIOkCEoANECDpAhKADRAg6QIS1xRfMOd99CwC/fWw+L/VEcF3335/EH3haKrAA35mgA0QIOkCEoANECDpAhKADRAg6QISgA0QIOkCEoANECDpAhKADRFhbfMF5nrevPY7jwTsBGGOutfYdNue+wwAi1lq35lp95QIQIegAEYIOECHoABGCDhAh6AARgg4QIegAEYIOECHoABGCDhBhnAsgYnfQPREAPERgASIEHSBC0AEiBB0gQtABIgQdIELQASIEHSBC0AEiBB0gQtABIgQdIGKutd59DwB8Ap/QASIEHSBC0AEiBB0gQtABIgQdIELQASIEHSBC0AEiBB0gQtABIgQdIELQASIEHSBC0AEiBB0gQtABIgQdIELQASIEHSBC0AEiBB0gQtABIn4BbGVa1aWP244AAAAASUVORK5CYII=\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "qc = QuantumCircuit(q, c)\n", + "qc.h(q[0])\n", + "for j in range(n-1):\n", + " qc.cx(q[j],q[j+1])\n", + "qc.measure(q, c)\n", + "\n", + "job = execute(qc, backend, shots=shots)\n", + "\n", + "probs = get_probs(job)\n", + "plot_terrain(pos,probs)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Again, it is not so interesting. This time, let's spread out the probability by adding in some single qubit gates. Specifically, we'll try rotations around the y axis by a few different angles." + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": { + "scrolled": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "For rotations around the y axis by 0.0*pi\n" + ] + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAXQAAAD8CAYAAABn919SAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADl0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uIDIuMi4zLCBodHRwOi8vbWF0cGxvdGxpYi5vcmcvIxREBQAABEhJREFUeJzt3EFu2zAARUGyyBWE3v92OoXYXZeFWkd0+jKzFkwFCJ4tA/5zrTUA+P/9ePcNAPA5BB0gQtABIgQdIELQASIEHSBC0AEiBB0gQtABIj52HjbnPMcYP29ceo37bzZ3r/Wandes/T1e0//HH6215p3r5s6f/s857QwA/KW7QfeVC0CEoANECDpAhKADRAg6QISgA0QIOkCEoANECDpAhKADRAg6QISgA0TsDvq1+TyAb2N30D0RADxEYAEiBB0gQtABIgQdIELQASIEHSBC0AEiBB0gQtABIgQdIELQASIEHSDC2iJAhLVFgAiBBYgQdIAIQQeIEHSACEEHiBB0gAhBB4gQdIAIQQeIEHSACEEHiDDOBRBhnAsgQmABIgQdIELQASIEHSBC0AEiBB0gQtABIgQdIELQASIEHSBC0AEiBB0gwtoiQIS1RYAIgQWIEHSACEEHiBB0gAhBB4gQdIAIQQeIEHSACEEHiBB0gAhBB4gwzgUQYZwLIEJgASIEHSBC0AEiBB0gQtABIgQdIELQASIEHSBC0AEiBB0gQtABIgQdIMLaIkCEtUWACIEFiBB0gAhBB4gQdIAIQQeIEHSACEEHiBB0gAhBB4gQdIAIQQeIMM4FY4w557tvAV72sfk8TwR8Sdd1/7OG+PNVCSxAhKADRAg6QISgA0QIOkCEoANECDpAhKADRAg6QISgA0QIOkCEoANEWFuEMcZ5nrevPY7jwTuBfzfXWvsOm3PfYQARa61bE5++cgGIEHSACEEHiBB0gAhBB4gQdIAIQQeIEHSACEEHiBB0gAhBB4gQdIAIa4sAEbuD7okA4CECCxAh6AARgg4QIegAEYIOECHoABGCDhAh6AARgg4QIegAEYIOEGGcCyDCOBdAhMACRAg6QISgA0QIOkCEoANECDpAhKADRAg6QISgA0QIOkCEoANECDpAhLVFgAhriwARAgsQIegAEYIOECHoABGCDhAh6AARgg4QIegAEYIOECHoABGCDhBhnAsgwjgXQITAAkQIOkCEoANECDpAhKADRAg6QISgA0QIOkCEoANECDpAhKADRAg6QIS1xRfMOd99CwC/fWw+L/VEcF3335/EH3haKrAA35mgA0QIOkCEoANECDpAhKADRAg6QISgA0QIOkCEoANECDpAhKADRFhbfMF5nrevPY7jwTsBGGOutfYdNue+wwAi1lq35lp95QIQIegAEYIOECHoABGCDhAh6AARgg4QIegAEYIOECHoABGCDhBhnAsgYnfQPREAPERgASIEHSBC0AEiBB0gQtABIgQdIELQASIEHSBC0AEiBB0gQtABIgQdIGKutd59DwB8Ap/QASIEHSBC0AEiBB0gQtABIgQdIELQASIEHSBC0AEiBB0gQtABIgQdIELQASIEHSBC0AEiBB0gQtABIgQdIELQASIEHSBC0AEiBB0gQtABIn4BbGVa1aWP244AAAAASUVORK5CYII=\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "For rotations around the y axis by 0.1*pi\n" + ] + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "For rotations around the y axis by 0.2*pi\n" + ] + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "For rotations around the y axis by 0.3*pi\n" + ] + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "For rotations around the y axis by 0.4*pi\n" + ] + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "For rotations around the y axis by 0.5*pi\n" + ] + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "for frac in [0.0,0.1,0.2,0.3,0.4,0.5]:\n", + " \n", + " qc = QuantumCircuit(q, c)\n", + " qc.h(q[0])\n", + " for j in range(n-1):\n", + " qc.cx(q[j],q[j+1])\n", + " qc.ry(np.pi*frac,q) \n", + " qc.measure(q, c)\n", + "\n", + " job = execute(qc, backend, shots=shots)\n", + "\n", + " probs = get_probs(job)\n", + " print('\\nFor rotations around the y axis by '+str(frac)+'*pi')\n", + " plot_terrain(pos,probs)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "These take us from the twin peaks of the GHZ state to a checkerboard pattern, thanks to the interference effects in quantum states. We find some interesting patterns along the way.\n", + "\n", + "These interference effects are one way that quantum procedural generation can avoid the playing 'seeing behind the curtain' and recognizing the way the random patterns are created: quantum effects are quite removed from human experience, and so we have less intuition that helps us recognize them." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "So far we've experimented with just one or two peaks. For something that looks like Perlin noise, we need a constant density. For this we can set a density `rho`, and then use it to pick a random set of points. This can then be turned into a vector representing the quantum superposition of the corresponding bit strings." + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [], + "source": [ + "rho = 0.1\n", + "N = int(rho*2**n)\n", + "state = [0]*(2**n)\n", + "for j in range(N):\n", + " state[ int(random.choice(list(pos.keys())),2) ] = 1\n", + "Z = sum(np.absolute(state)**2)\n", + "state = [amp / np.sqrt(Z) for amp in state]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can then initialize the circuit with this state, and again try using `ry` rotations by different angles." + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": { + "scrolled": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "For rotations around the y axis by 0.0*pi\n" + ] + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "For rotations around the y axis by 0.1*pi\n" + ] + }, + { + "data": { + "image/png": "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g/raEfx3L/k56ThYyU36WdL3KII/n4OdK8mWjI3Rm0cffTS+SVVKfvl/1+9//3v0YhdccAG++fTTT6Pcs88+i2+eeuqpKPfhhx/im42NjShXUgIPPPAAyj388MP45po1a1Duz3/+M7559tlno9yPf/xjlKP/kEVErFu3DuVKfp+Ojg6Ua2trwzfvv/9+lJs9eza+OXPmTJS766678E06XHfjjTfim9Q555yDcueeey6+SQe/6MhbRMTy5ctRrmQQbmBgAP0vxj+5SFISFrokJWGhS1ISFrokJWGhS1ISFrokJWGhS1ISFrokJWGhS1ISFrokJWGhS1ISFrokJVHTQu/u7kZri729vfhmQ0MDytE1u4ihWakbihE0uuB44MABfJOOiNHVvQi+dNnd3Y1yQ7FiWPL70M+9ZKGPDo6VrIbSbMnYGf2MWlpa8E26nkm/lzRX8tolz1xzczPK1dXV4ZsUf4oHwWOPPYa+CXv37sU37733XpT7yU9+gm/SFbSpU6fim2+//TbKTZs2Dd9sbm5GD8/NN9+Mb9JVudGjR+Ob27ZtQ7mPPvoI5UpW6qgpU6bgf8wWLlyIckuWLMGvT2eTS4py586dKPeLX/wC39y8eTPKLVu2DN+85pprUG716tUoV/L70H903333XXxz8eLFKFfSc5R/cpGkJCx0SUrCQpekJCx0SUrCQpekJCx0SUrCQpekJCx0SUrCQpekJCx0SUrCQpekJGpa6CNGjEDjXD09PSU3UY5uZUTw8aWSwR46xHP48GF8k44AlYyIVavoI8KjRiWvT197KEaN6GtH8Gepq6sL36TPccnPSd/3ksEvOnZWcpPuqQzFd52O5pV8h0qyg60yFCuAX2fTpk3oxV544QV88/3330c5Wn4REfPnz0e5kgfnww8/RLmrr74a33zooYdQbsyYMfjmP//5T5T7+OOP8U06+HXdddeh3P33349fmy7vTZw4Ed988MEHUW7UqFH45rHHHotys2bNwjfXrl2LciVjZ9deey3KlfzuGzZsQLmXX34Z5UpWLunI3B133IFvtre3oxz9zCMitm7div4H5Z9cJCkJC12SkrDQJSkJC12SkrDQJSkJC12SkrDQJSkJC12SkrDQJSkJC12SkrDQJSkJC12SkqhpodfX16OpOLroFsGX90pGyEpGtyi6wNbd3Y1vNjU1oVzJ707fz5K1RbpKSX93urpXomQ5k75+yftOVzZLVgwbGxtRrmS9kn43St5P+hzv27cP36TGjRuHciXLmfT3KXmPqPpBv/gvnH766ajV6IMYEXHMMceg3C233IJvvvjiiyg3Y8YMfPO0005DuVdffRXf3LRpE8pt3boV36SLdrfffju+ef7556McXWW8/PLL8Wv/9a9/RbmdO3fim5deeinKTZgwAd9csmQJyp1//vl4Qvedd95BuQULFqBcRERbWxvKNTQ04Jv79+9HuVdeeQXltm/fjl+7o6MD5To7O6OzsxNl6ftJF1hL+CcXSUrCQpekJCx0SUrCQpekJCx0SUrCQpekJCx0SUrCQpekJCx0SUrCQpekJCx0SUrCQpekJGpa6F1dXWhVqGT9jS6WNTc345t0/Kivrw/fLMlSdPXviy++wDfpez9y5Eh8k64o0lzJ0iNduSx55uiKYsmaXktLC8rRgagI/syXrIvS1cGSYbLPPvsM5ehnRD/zCP4elayg0uXMkp+Tquna4sqVK9FvMHHiRHxz0aJFKHfmmWfim3v27EG5uro6XP6//e1vUW7btm0oFxFx/fXXo9yKFSvwzfXr16McXamLiNi9ezfKHTx4EOWef/55/Np0OfO+++7DN3fs2IFyzzzzDL45duzYGDt27BFzI0aMwIWxbNkylCv5vlWrVfQ53XnnnfgmfT5/97vf4ZvUCSecgHKvvfYavnnSSSehHJ3ZLeGfXCQpCQtdkpKw0CUpCQtdkpKw0CUpCQtdkpKw0CUpCQtdkpKw0CUpCQtdkpKw0CUpiZoWend3Nxo+KRk1OnToEMo1Njbim3T8iW5qRETU17PZnIaGBnyT/u4lI0B0X6LkJv086QBSyXtEs3RHJoKPRNHPvAT9zCOGZkTsq6++Qrnhw4fjm/R9omN0Jeh3mL6XEfwzKhmZoyolP+i//WKVCnqxtrY2fJM+OM8++yy+OWbMGJR76qmn8E3qtttuG5IsRd/7kuEp6rLLLkO59vZ2fPPNN9/8pj/O15oxYwbKXXrppfjmrbfe+k1/nK+1b98+lFu7di2+Sfti7969+OaWLVtQbu7cuShXsmy6evVqlCtZa50yZQrKjRo1Ct/cvHkzan//5CJJSVjokpSEhS5JSVjokpSEhS5JSVjokpSEhS5JSVjokpSEhS5JSVjokpSEhS5JSVjokpRETce5JElDx/+hS1ISFrokJWGhS1ISFrokJWGhS1ISFrokJWGhS1ISFrokJWGhS1ISFrokJWGhS1ISFrokJWGhS1ISFrokJWGhS1ISFrokJWGhS1ISFrokJWGhS1ISFrokJWGhS1ISFrokJWGhS1IS/wm3CIrdUpjTvwAAAABJRU5ErkJggg==\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "For rotations around the y axis by 0.2*pi\n" + ] + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "For rotations around the y axis by 0.3*pi\n" + ] + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "For rotations around the y axis by 0.4*pi\n" + ] + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "For rotations around the y axis by 0.5*pi\n" + ] + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "for frac in [0.0,0.1,0.2,0.3,0.4,0.5]:\n", + " \n", + " qc = QuantumCircuit(q, c)\n", + " qc.initialize(state,q)\n", + " qc.ry(np.pi*frac,q) \n", + " qc.measure(q, c)\n", + "\n", + " job = execute(qc, backend, shots=shots)\n", + "\n", + " probs = get_probs(job)\n", + " print('\\nFor rotations around the y axis by '+str(frac)+'*pi')\n", + " plot_terrain(pos,probs)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We could also have spread out the peaks by simply using the noise of a real device. Since the process of creating our initial state is quite involved, this will have quite a lot of noise." + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "qc = QuantumCircuit(q, c)\n", + "qc.initialize(state,q)\n", + "qc.measure(q, c)\n", + "\n", + "job = execute(qc, backend, shots=shots,noise_model=noise_model,basis_gates=noise_model.basis_gates)\n", + "\n", + "probs = get_probs(job)\n", + "plot_terrain(pos,probs)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Clearly our Terrain maps are blockier than the example of Perlin noise shown at the top. This could be dealt with by adding more qubits, or simply by being careful in choosing how we apply the method. When generating terrain with Perlin noise, multiple layers are often used to create a good effect. Perhaps in future, some of those layers could be quantum." + ] + } + ], + "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.0" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/community/terra/qis_intro/entanglement_testing.ipynb b/community/terra/qis_intro/entanglement_testing.ipynb index bada089d6..e6d3559c3 100644 --- a/community/terra/qis_intro/entanglement_testing.ipynb +++ b/community/terra/qis_intro/entanglement_testing.ipynb @@ -110,7 +110,7 @@ ], "source": [ "from qiskit import IBMQ, BasicAer\n", - "from qiskit.backends.ibmq import least_busy\n", + "from qiskit.providers.ibmq import least_busy\n", "IBMQ.load_accounts()\n", "\n", "# use simulator to learn more about entangled quantum states where possible\n", diff --git a/index.ipynb b/index.ipynb index fd653c4a9..ba1a853d0 100644 --- a/index.ipynb +++ b/index.ipynb @@ -18,9 +18,9 @@ "\n", "Welcome Qiskitters.\n", "\n", - "The easiest way to get started is to use [the Binder image](https://mybinder.org/v2/gh/Qiskit/qiskit-tutorial/master?filepath=index.ipynb), which lets you use the notebooks via the web. This means that you don't need to download or install anything, but is also means that you should not insert any private information into the notebooks (such as your API key). We recommend that after you are done using mybinder that you regenerate your token. \n", + "The easiest way to get started is to use [the Binder image](https://mybinder.org/v2/gh/qiskit/qiskit-tutorials/master?filepath=index.ipynb), which lets you use the notebooks via the web. This means that you don't need to download or install anything, but is also means that you should not insert any private information into the notebooks (such as your API key). We recommend that after you are done using mybinder that you regenerate your token. \n", "\n", - "The tutorials can be downloaded by clicking [here](https://github.com/Qiskit/qiskit-tutorial/archive/master.zip) and to set them up follow the installation instructions [here](https://github.com/Qiskit/qiskit-tutorial/blob/master/INSTALL.md).\n", + "The tutorials can be downloaded by clicking [here](https://github.com/Qiskit/qiskit-tutorials/archive/master.zip) and to set them up follow the installation instructions [here](https://github.com/Qiskit/qiskit-tutorial/blob/master/INSTALL.md).\n", "\n", "***\n", "\n", @@ -109,7 +109,7 @@ "*** \n", "\n", "## License\n", - "This project is licensed under the Apache License 2.0 - see the [LICENSE](https://github.com/Qiskit/qiskit-tutorial/blob/master/LICENSE) file for details." + "This project is licensed under the Apache License 2.0 - see the [LICENSE](https://github.com/Qiskit/qiskit-tutorials/blob/master/LICENSE) file for details." ] }, { diff --git a/qiskit/aqua/general/generating_random_variates.ipynb b/qiskit/aqua/general/generating_random_variates.ipynb new file mode 100644 index 000000000..7d58c353c --- /dev/null +++ b/qiskit/aqua/general/generating_random_variates.ipynb @@ -0,0 +1,473 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\"Note: Trusted Notebook\" width=\"500 px\" align=\"left\">" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# _*Qiskit Aqua: Generating Random Variates*_ \n", + "\n", + "The latest version of this notebook is available on https://github.com/Qiskit/qiskit-tutorials.\n", + "\n", + "***\n", + "### Contributors\n", + "Albert Akhriev[1], Jakub Marecek[1]\n", + "\n", + "### Affliation\n", + "- [1]IBMQ" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Introduction\n", + "\n", + "While classical computers use only pseudo-random routines, quantum computers\n", + "can generate true random variates.\n", + "For example, the measurement of a quantum superposition is intrinsically random,\n", + "as suggested by Born's rule.\n", + "Consequently, some of the\n", + "best random-number generators are based on such quantum-mechanical effects. (See the \n", + "Further, with a logarithmic amount of random bits, quantum computers can produce\n", + "linearly many more bits, which is known as \n", + "randomness expansion protocols. \n", + "\n", + "In practical applications, one wishes to use random variates of well-known\n", + "distributions, rather than random bits.\n", + "In this notebook, we illustrate ways of generating random variates of several popular\n", + "distributions on IBM Q.\n", + "\n", + "## Random Bits and the Bernoulli distribution\n", + "\n", + "It is clear that there are many options for generating random bits (i.e., Bernoulli-distributed scalars, taking values either 0 or 1). Starting from a simple circuit such as a Hadamard gate followed by measurement, one can progress to vectors of Bernoulli-distributed elements. By addition of such random variates, we could get binomial distributions. By multiplication we could get geometric distributions, although perhaps leading to a circuit depth that may be impratical at the moment, though.\n", + "\n", + "Let us start by importing the basic modules and creating a quantum circuit for generating random bits:" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [], + "source": [ + "import matplotlib.pyplot as plt\n", + "%matplotlib inline\n", + "import numpy as np\n", + "import sys, math, time\n", + "import warnings\n", + "warnings.filterwarnings(\"ignore\", category=DeprecationWarning)\n", + "\n", + "from qiskit import BasicAer\n", + "from qiskit import QuantumCircuit, QuantumRegister, ClassicalRegister, execute\n", + "\n", + "# In this example we use 'qasm_simulator' backend.\n", + "glo_backend = BasicAer.get_backend(\"qasm_simulator\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "In the next step we create a quantum circuit, which will be used for generation:" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAArgAAAHiCAYAAAADPb8jAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADl0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uIDMuMC4zLCBodHRwOi8vbWF0cGxvdGxpYi5vcmcvnQurowAAIABJREFUeJzs3XtU1Ne9//8XDmpUGDBKNASRSGujBAWRWq+oSSTWWxKiTU+q0VRgJdLEeMkQbaMxlYLLEy85NeeLJ9E01J6l0gRsUkhjIq2J5YwasBptF/GCGM/XgMIY/UVPcX5/5OscR+5xZj7wmedjLZbDnv2Z/WaAmZeb/dmfAKfT6RQAAABgEp2MLgAAAADwJAIuAAAATIWACwAAAFMh4AIAAMBUCLgAAAAwFQIuAAAATIWACwAAAFMh4AIAAMBUCLgAAAAwFQIuAAAATIWACwAAAFMh4AIAAMBUCLgAAAAwFQIuAAAATIWACwAAAFMh4AIAAMBUCLgAAAAwFQIuAAAATIWACwAAAFMJNLoAwJOOHTvWYp9/+7d/U0ZGRrN97rnnHk+VBAAAfIwZXPidX//610aXAAAAvIiACwAAAFMh4AIAAMBUCLjwOzt37jS6BAAA4EUEXAAAAJgKARd+59FHHzW6BAAA4EVsE+bnFi5cqLKyMp+PGxcXp/Xr1/t8XDMy6nso8X0EALRPzOD6ubKyMp+HIyPGNDOjnk++jwCA9ooZXCguLk579uzx2Xjjx4/32ViNWbBggaHje4Ovv4eS8d9HAACawgwu/E5LVzEDAAAdGwEXfmfcuHFGlwAAALyIgAu/8+WXXxpdAgAA8CICLgAAAEyFgAu/M3jwYKNLAAAAXkTAhd/Jz883ugQAAOBFbBMGv/Piiy9q1apVRpdhmIsXL6qkpEQHDhzQiRMnVF9fr969eys+Pl5jxozRgAEDGhxz9uxZpaam6rXXXlO/fv0MqBoAgNbzmxncrVu3tnnfzoSEBL3//vveKQiG2bFjh9ElGKKyslJPP/20wsPDNW3aNL300kv68MMP9fHHHys3N1dPPPGEoqOjdf/996u4uNh13NmzZzVx4kTt2bNHp0+fNvArAACgdQwNuDabTTExMbJarQoPD1dqaqrOnz/vk7Hr6+u1dOlShYWFKTg4WCkpKaqurnbrM2PGDBUUFPikno4kPDxcr7/+ulub0+mU1WrV22+/bVBVaIrT6dR//Md/6N5779Ubb7yhlJQUffjhh3I4HKqsrNTx48flcDh05MgRrV69Wv/4xz/04IMPas6cOTp27JgmTpyo06dP649//KNGjRpl9JcDAECLDA24FotFeXl5qqmpUXl5uaqqqjRv3jyfjJ2dna2CggKVlpaqqqpKkjR79my3PjNmzFBhYaFP6ukozpw5o7Nnz2ro0KFu7cePH9fFixc1fPhwgypDY5xOp55//nmlpqYqISFBR48e1datWzVhwgQFBQW5+lksFg0ePFjLli1TRUWFfvGLX+i3v/2t4uLiVFlZqT/+8Y8aO3asgV8JAACt5/WAu337dsXGxiooKEiTJk3SokWLNHPmTElSVlaW4uPj1blzZ4WFhSkjI8NnlxvNzc2VzWbTgAEDFBISojVr1qioqEgnT5509Rk6dKgCAwN14MABn9TUEdjtdlksFsXExLi1l5eXq0+fPh1ifWZJSYnRJfjM2rVrtXbtWi1YsEC7d+/W3Xff3eIxXbp00VNPPaW77rpLV65cUb9+/TRixAgfVAsAgGd4NeC++eabWrx4sTZt2qS6ujpNnTpVGzduVHx8fKP9d+/erSFDhrR5nOzs7DYdV1dXp8rKSiUkJLjaoqOjZbVadejQIbe+06dPZ5nCDex2uwYOHKhu3bq5tZeXl3eY2dsjR44YXYJP/O1vf9Py5cuVkpKiV199VZ06te7X/fqa2/Pnz+vll1/W3//+d61evdrL1QIA4DleC7iXL1/WokWLlJubq7Fjx8pisWj+/Pmqr69vNODm5+dr8+bN2rBhg6stLy9PI0eO1MiRI7V79+4mx8rMzGwQTJvjcDgkSSEhIW7toaGhrvuumzJlit59991WP7bZ2e12VVRUqHfv3m4fOTk5SkxMNLq8Vnn66aeNLsEnFi5cqNDQUL322msKCAho1THXw+31Nbc///nP9ZOf/ERZWVmcYAYA6DC8tk1YSUmJrl27psmTJ7varl8i9eaAu2PHDqWnp6uwsFDDhg2TJNXW1uqVV17Rvn379NVXX2nChAn69NNPZbFYbrm24OBgSd/M5N6otrZWVqvVre3UqVOKjIy85TFb0toA4g1JSUmt7rt//36tXLlSc+bMcWuPjY1t0wxuSUmJV77m5557rlX9cnNzm71/3bp1nijHZ27+Hh49elQffvihfvWrXyksLKxVj3FzuL2+5vbll1/Wb3/7W+Xm5urll192O8Zb30cAAFridDqbvM9rAffcuXO644473Nq2bdumvn37qm/fvq62LVu2aPHixdq1a5dGjx7tai8tLdXYsWPVtWtXde3aVVFRUfr88881cODAW64tNDRUkZGROnjwoOLi4iTJdSb5zUsdCgsLlZKScstjtqS5b5I3tWXrtIqKCl24cEHJycmKiIhwa6+trW1TwE1KSvLKeutjx4612GfdunVKS0trts8rr7ziqZK8rrHv4X/+53+qU6dOevLJJ1v1GE2FW0mKiorSgw8+qG3btjUIuN76PgIAcCu8tkQhJiZGFRUVKikp0dWrV7Vt2zZlZ2e7AqUkbdy4UUuWLFFxcbFbuJWkmpoa9ezZ0/V5z549VVNT47H60tLSlJOToxMnTsjhcMhmsyk5OVlRUVGuPpcvX9ZHH32kqVOnemzcjsxut6t79+4NdlD45JNP1K9fP/Xp08egytrmpZdeMroEr7Pb7Ro8eHCD/2Q2prlwe11SUpKOHz/us238AAC4FV4LuMOHD9fy5cv1yCOPKCIiQqWlpRoxYoTb8oRnn31WDofDtWXR9Q9J6tWrly5cuODqe+HCBfXq1avRsbKyshqc1d+SzMxMTZs2TYmJibrrrrtUX1+vvLw8tz7FxcWKj49X79692/TYZmW325WYmKjAQPeJ/3379nWYE8wkadasWUaX4HWfffZZq068bE24leR6rKNHj3q0TgAAvMGrl+pdtWqV2yVRo6KilJqa6vq8uT/LjxgxQi+88IKuXLmiS5cu6cSJE4qOjm6077Jly7Rs2bI21WaxWFxbKDWlsLBQM2bMaNPjmllTf7Z/7bXXfFzJrRk0aJDpg9ry5ctbtXY8MzOzxXArSffee6/Wrl3rk/XoAADcKq8G3Bs5HA6dOnWqyS3CbhYaGqqFCxe61he+8sorHjnBrC369+/v2rMX6Ehu/I9kc1599VVlZGS0uANGv379tHjxYk+UBgCA1/ks4B4+fFjBwcFNzsI2Zs6cOQ3O1v+24uLiNHfu3DYds3LlSo+MDbRXVqu1w2zvBgBAa/ks4I4aNarBHrO+FBcX53aCG/xXW3aOAAAAHY/XL9ULtDcdbc0wAABoGwIu/M5TTz1ldAkAAMCLCLjwO1yYAAAAcyPgAgAAwFQIuAAAADAVAi78jtkv8gAAgL/z2TZhaL/Kysp8unVWWVmZoVu2bd++3XSX6/X19/D6mGy9BwBoj5jB9XNG7A9s9J7EK1asMGxsb7iV5/N45dlGb3t7XAAAvCnA6XQ6jS4C8JRjx4612GfQoEEtLlO45557PFVSu5aZk6tsW1qD2wAAdGTM4AIAAMBUCLjwO5s2bTK6BAAA4EUEXPidmJgYo0sAAABeRMCF30lKSjK6BAAA4EUEXAAAAJgKARcAAACmQsCF30lMTDS6BAAA4EUEXPgdu91udAkAAMCLCLgAAAAwFQIuAAAATIWAC7+zc+dOo0sAAABeRMAFAACAqRBw4XceffRRo0sAAABeFGh0ATDWwoULVVZW5vNx4+LitH79ep+PC9wKo35fJH5nAKAtmMH1c2VlZT5/wzZiTMATjPrZ5XcGANqGGVwoLi5Oe/bs8dl448eP99lYjVmwYIGh46Nj8/Xvi2T87wwAdDTM4MLvZGRkGF0CAADwIgIu/M64ceOMLgEAAHgRARd+58svvzS6BAAA4EUEXAAAAJgKARd+Z/DgwUaXAAAAvIiAC7+Tn59vdAnwMxcuXNDf/vY3HTp0SP/93//dbF+n06mPPvrIR5UBgDkRcOF3XnzxRaNLgB/429/+pqefflrR0dG6/fbbNWTIEA0dOlR33nmnwsPD9fjjj+vPf/6znE6n6xin06mMjAxNnDhRe/fuNbB6AOjY/Cbgbt26tc17SSYkJOj999/3TkEwzI4dO4wuASZ27tw5zZw5U0OGDNGWLVs0dOhQ/epXv9L27du1c+dOrVu3ThMnTtR7772npKQkjR07Vv/4xz9c4XbTpk1aunSpRo8ebfSXAgAdlqEB12azKSYmRlarVeHh4UpNTdX58+d9MnZ9fb2WLl2qsLAwBQcHKyUlRdXV1W59ZsyYoYKCAp/U05GEh4fr9ddfd2tzOp2yWq16++23DaoKMN7evXsVExOjwsJCvfTSS6qqqtLvf/97ZWZmaubMmUpJSdHChQuVl5enM2fO6N///d/12WefaciQIZo0aZIr3Obk5CggIMDoLwcAOixDA67FYlFeXp5qampUXl6uqqoqzZs3zydjZ2dnq6CgQKWlpaqqqpIkzZ49263PjBkzVFhY6JN6OoozZ87o7NmzGjp0qFv78ePHdfHiRQ0fPtygygBj7du3T8nJybr99tv16aef6sUXX1SvXr2a7N+9e3elp6fr8OHD6tWrlz744ANNnTqVcAsAHuD1gLt9+3bFxsYqKChIkyZN0qJFizRz5kxJUlZWluLj49W5c2eFhYUpIyPDZ5fAzM3Nlc1m04ABAxQSEqI1a9aoqKhIJ0+edPUZOnSoAgMDdeDAAZ/U1BHY7XZZLBbFxMS4tZeXl6tPnz7q16+fQZW1XklJidElwGTq6uo0a9Ys3XnnnSopKWn1Th1Op1OrV6/WF198oYiICH3wwQeqqKjwcrUAYH5eDbhvvvmmFi9erE2bNqmurk5Tp07Vxo0bFR8f32j/3bt3a8iQIW0eJzs7u03H1dXVqbKyUgkJCa626OhoWa1WHTp0yK3v9OnTWaZwA7vdroEDB6pbt25u7eXl5R1m9vbIkSNGlwCTef755/XFF1/od7/7nfr27duqY25ec/vXv/5Vt912m37605+6nXgGAGi7QG898OXLl7Vo0SLl5eVp7NixkqT58+fr2WefbTTg5ufna/PmzW6za/fff7/Kysq0cOFC/fznP29yrMzMTGVmZra6NofDIUkKCQlxaw8NDXXdd92UKVP0wgsvaNWqVa1+/G/DyD9JJiUltbqv3W5XRUWFevfu7db+1Vdf6YUXXmj145SUlHjla37uueda7LNu3boW+61bt85TJbV7OZnpjd5G427+ffnv//5vbdmyRU899ZQSExNb9Rg3h9vryxJWr16tBQsWaN++fRo1apTbMd76nQGAjqq5yQCvBdySkhJdu3ZNkydPdrVdv0TqzQF3x44dSk9PV2FhoYYNG+Zq37p1qz744APXGllPCQ4OlvTNTO6NamtrZbVa3dpOnTqlyMhIj47fGKNmbNq6s8T+/fu1cuVKzZkzx609Nja2TTO4SUlJXlmOcuzYsRb7rFu3Tmlpac32eeWVVzxVUruWmZOrbFtag9toXGO/L1u3btX//M//6JlnnmnVYzQVbiXpiSee0AsvvKB///d/bxBwvfU7AwBm5LUlCufOndMdd9zh1rZt2zb17dvX7U94W7ZsUXp6unbt2qUJEya49Y+IiPBKbaGhoYqMjNTBgwddbcePH5fD4Wiw1KGwsFAzZszwSh0dTUVFhS5cuKDk5GRFRES4Pr7++mvV1tZ2mCUKgCft2bNHsbGxGjhwYIt9mwu3ktSjRw9NnjyZdeIAcIu8FnBjYmJUUVGhkpISXb16Vdu2bVN2drbi4uJcfTZu3KglS5aouLjY53s+pqWlKScnRydOnJDD4ZDNZlNycrKioqJcfS5fvqyPPvpIU6dO9Wlt7ZXdblf37t0b7KDwySefqF+/furTp49BlbXNSy+9ZHQJMJGDBw+26j93LYXb6xISElRZWdlg20IAQOt5LeAOHz5cy5cv1yOPPKKIiAiVlpZqxIgRbssTnn32WTkcDk2YMEFBQUGuj7bKyspqcFZ/SzIzMzVt2jQlJibqrrvuUn19vfLy8tz6FBcXKz4+vsF6U39lt9uVmJiowED3lS379u3rULO3s2bNMroEmITT6VTXrl31ve99r8W+zz77bKv2uf3Od76j8PBw1dbWerpcAPAbXluDK0mrVq1yOzkrKipKqamprs89te502bJlWrZsWZuOsVgsWrt2rdauXdtkH5YnuGtqXeprr73m40puzaBBg3T06FGjy4AJBAQE6PTp063qGxcXp+eff17Z2dnNniz28MMP6+GHH/ZUiQDgl7wacG/kcDh06tSpJrcIa8yTTz6p0tJSXblyRaWlpdq1a5cXK2yof//+rj17AeBWPPnkk0aXAAB+w2cB9/DhwwoODlZ0dHSrj3njjTc8Nn5cXJzmzp3bpmNWrlzpsfEBAADgGz4LuKNGjWqwx6wvxcXFuZ3gBv/V1q3RAABAx+L1S/UC7U1HWzMMAADahoALv/PUU08ZXQIAAPAiAi78DleDAgDA3Ai4AAAAMBUCLgAAAEzFZ7sooP0qKyvz6c4CZWVlhu5owUUecCt8/ftyfUx2gQGA1mMG188ZsX2a0Vu2bd++3bCx0bHdys/u8cqzjd729rgA4I+YwfVz69evN7oEn1uxYoVmzZpldBnogG7l9yUzJ1fZtrQGtwEAnscMLgAAAEyFgAsAAABTIeDC72zatMnoEgAAgBcRcOF3YmJijC4BAAB4EQEXficpKcnoEgAAgBcRcAEAAGAqBFz4ncTERKNLAAAAXkTAhd+x2+1GlwAAALyIgAsAAABTIeACAADAVAi48Ds7d+40ugQAAOBFBFwAAACYCgEXfufRRx81ugQAAOBFgUYXAGMtXLhQZWVlPh83Li5O69ev9/m4ADoGo16bJF6fADNgBtfPlZWV+fxNxIgxAXQsRr1O8PoEmAMzuFBcXJz27Nnjs/HGjx/vs7Eas2DBAkPHB9A6vn5tkox/fQLgGczgwu9kZGQYXQIAAPAiAi78zrhx44wuAQAAeBEBF37nyy+/NLoEAADgRQRcAAAAmAoBF35n8ODBRpcAAAC8iIALv5Ofn290CQDaCafTaXQJALyAgAu/8+KLLxpdAgAPO3z4sDZs2KAnnnhCDzzwgCZNmqS5c+fq1Vdf1dGjRxs95oMPPtCYMWN0/vx5H1cLwNv8JuBu3bq1zfsbJiQk6P333/dOQTDMjh07jC4BgIcUFRVpzJgxio2N1cKFC/WnP/1JX331lS5evKiioiI988wzGjx4sMaPH6/du3e7jvvggw80bdo0Xbx4UdeuXTPwKwDgDYYGXJvNppiYGFmtVoWHhys1NdVn/5Our6/X0qVLFRYWpuDgYKWkpKi6utqtz4wZM1RQUOCTejqS8PBwvf76625tTqdTVqtVb7/9tkFVAfAnFy9e1Lx58zR58mSdPXtW//qv/6qqqip98cUX2rdvn/bt26ezZ8+qsrJSOTk5OnnypO6//36lpaXpD3/4g6ZNm6bvfve7+vDDD9W7d2+jvxwAHmZowLVYLMrLy1NNTY3Ky8tVVVWlefPm+WTs7OxsFRQUqLS0VFVVVZKk2bNnu/WZMWOGCgsLfVJPR3HmzBmdPXtWQ4cOdWs/fvy4Ll68qOHDhxtUGQB/UVdXp/vvv1+/+c1vtGzZMn322WdatGiR7rrrLrd+AQEB6tevn55//nkdPXpUS5cu1ebNmzVjxgxFR0cTbgET83rA3b59u2JjYxUUFKRJkyZp0aJFmjlzpiQpKytL8fHx6ty5s8LCwpSRkeGzyzLm5ubKZrNpwIABCgkJ0Zo1a1RUVKSTJ0+6+gwdOlSBgYE6cOCAT2rqCOx2uywWi2JiYtzay8vL1adPH/Xr18+gylqvpKTE6BIAfEvXrl3TrFmzdPDgQf3+97/X6tWr1bVr1xaP69atmyZNmqTOnTvr2rVrioiIUK9evXxQMQAjeDXgvvnmm1q8eLE2bdqkuro6TZ06VRs3blR8fHyj/Xfv3q0hQ4a0eZzs7Ow2HVdXV6fKykolJCS42qKjo2W1WnXo0CG3vtOnT2eZwg3sdrsGDhyobt26ubWXl5d3mNnbI0eOGF0CgG8pNzdX77//vl599VXNmDGj1cddX3N7zz33aNWqVSouLtZvfvMbL1YKwEheC7iXL1/WokWLlJubq7Fjx8pisWj+/Pmqr69vNODm5+dr8+bN2rBhgyTpwIEDGj16tMaNG6eJEyfq+PHjTY6VmZnZIJg2x+FwSJJCQkLc2kNDQ133XTdlyhS9++67rX5ss7Pb7aqoqFDv3r3dPnJycpSYmGh0ea3y9NNPG10CgG/h0qVLeuGFF3T//fcrPT291cddD7fX19wuX75cY8aM0ZIlS3TlyhUvVgzAKIHeeuCSkhJdu3ZNkydPdrVdv0TqzQF3x44dSk9PV2FhoYYNGybpmxOZioqKFBwcrPfee08rVqzQW2+95ZHagoODJX0zk3uj2tpaWa1Wt7ZTp04pMjLSI+M2JyAgwOtjNCUpKanVfffv36+VK1dqzpw5bu2xsbFtmsEtKSnxytf83HPPtapfbm5us/evW7fOE+V0CDmZ6Y3ehufxXLfNza9Nv/vd71RbW6uVK1e2+vXj5nB7fc3tihUr9MADD2jnzp16/PHH3Y7x1usTAM9qbh9rrwXcc+fO6Y477nBr27Ztm/r27au+ffu62rZs2aLFixdr165dGj16tKv9zjvvdN3u0qWLAgM9V2poaKgiIyN18OBBxcXFSfrmJCmHw9FgqUNhYaFSUlI8NnZTjNpsvC1bp1VUVOjChQtKTk5WRESEW3ttbW2bAm5SUpJX1lsfO3asxT7r1q1TWlpas31eeeUVT5XUrmXm5CrbltbgNjyP57ptGntt2rFjh+655x6NGjWqVY/RVLiVpIkTJyoqKkrbt29vEHC99foEwHe8tkQhJiZGFRUVKikp0dWrV7Vt2zZlZ2e7AqUkbdy4UUuWLFFxcbFbuL3RpUuXlJmZqSVLlni0vrS0NOXk5OjEiRNyOByy2WxKTk5WVFSUq8/ly5f10UcfaerUqR4du6Oy2+3q3r17gx0UPvnkE/Xr1099+vQxqLK2eemll4wuAUAbOZ1O7d+/X6NHj27V7Gpz4VaSOnXqpNGjR3MSMWBSXgu4w4cP1/Lly/XII48oIiJCpaWlGjFihNvyhGeffVYOh0MTJkxQUFCQ6+O6q1evaubMmfr5z3/e4Kz9G2VlZTV7f2MyMzM1bdo0JSYm6q677lJ9fb3y8vLc+hQXFys+Pp5tZP4fu92uxMTEBrPp+/bt6zAnmEnSrFmzjC4BQBvV1NTo/Pnzuvfee1vs21K4vS4mJkZnzpzRpUuXPF0uAIN5bYmCJK1atUqrVq1yfR4VFaXU1FTX5839Wb6+vl7/8i//okceeUQPPfRQs+MsW7ZMy5Yta1NtFotFa9eu1dq1a5vsU1hY2KazdM2uqT/bv/baaz6u5NYMGjSoyUt3AmifevTood/97neu8zSacu3aNWVmZrbqIg4PPfSQ7r77bnXu3NnT5QIwmFcD7o0cDodOnTrV5BZhN9uxY4eKiopUXV2tvLw8xcbG6tVXX/Vyle769+/v2rMXAGCcbt266bHHHmuxX6dOnfSHP/xBgYGBLf71bdCgQRo0aJCnSgTQjvgs4B4+fFjBwcGKjo5uVf/HHnusVS9mrRUXF6e5c+e26ZiVK1d6bHwAgG/ceCIzAP/ks4A7atSoBnvM+lJcXJzbCW7wX23ZOQIAAHQ8Xr9UL9DedLQ1wwAAoG0IuPA7Tz31lNElAAAALyLgwu+wgTsAAOZGwAUAAICpEHABAABgKgRc+B0u8gAAgLn5bJswtF9lZWU+3TqrrKzM0C3btm/fzuV6gQ7A169N18dkS0mg42MG188ZsT+w0XsSr1ixwrCxAbTOrbxOHK886/avr8YF0H4wg+vn1q9fb3QJANDArbw2ZebkKtuW5voXgP9hBhcAAACmQsCF39m0aZPRJQAAAC8i4MLvxMTEGF0CAADwIgIu/E5SUpLRJQAAAC8i4AIAAMBUCLgAAAAwFQIu/E5iYqLRJQAAAC8i4MLv2O12o0sAAABeRMAFAACAqRBwAQAAYCoEXPidnTt3Gl0CAADwIgIuAAAATIWAC7/z6KOPGl0CAADwokCjC4CxFi5cqLKyMp+PGxcXp/Xr1/t8XACAO6PeByTeC+A9zOD6ubKyMp+/sBkxJgCgcUa9JvNeAG9iBheKi4vTnj17fDbe+PHjfTZWYxYsWGDo+ADQ3vj6fUAy/r0A5sYMLvxORkaG0SUAAAAvIuDC74wbN87oEgAAgBcRcOF3vvzyS6NLAAAAXkTABQAAgKkQcOF3Bg8ebHQJAADAi9hFAX4nPz/f6BIAoEO7cuWKDh8+rOrqagUEBCgyMlIDBw5Up06Nz5udP39e+/bt05QpU3xcKfyV38zgbt26tc1bkiQkJOj999/3TkEwzIsvvmh0CQDQ4Vy5ckXbtm1TUlKSgoODNXz4cD344INKTk7WoEGDFBoaqkcffVQffvihnE6n67jz58/r/vvv149+9COdO3fOwK8A/sTQgGuz2RQTEyOr1arw8HClpqbq/PnzPhm7vr5eS5cuVVhYmIKDg5WSkqLq6mq3PjNmzFBBQYFP6ulIwsPD9frrr7u1OZ1OWa1Wvf322wZV1Xo7duwwugQA6FD+/Oc/KyYmRo8//ri++OILPffcc9q+fbs+/vhj/eUvf9Ebb7yhxx9/XHv27NF9992n++67TydOnHCF288++0w7d+7UHXfcYfSXAj9haMC1WCzKy8tTTU2NysvLVVVVpXnz5vlk7OzsbBUUFKi0tFRVVVWSpNmzZ7v1mTFjhgoLC31ST0dx5swZnT17VkP5UDCcAAAgAElEQVSHDnVrP378uC5evKjhw4cbVBkAwBuys7OVlJQkp9Opd999V3//+9+Vk5OjmTNnatSoURozZozmzZun1157TVVVVfr1r3+t/fv3695779X3v/99ffbZZ3rnnXf04IMPGv2lwI94PeBu375dsbGxCgoK0qRJk7Ro0SLNnDlTkpSVlaX4+Hh17txZYWFhysjI8NmVVHJzc2Wz2TRgwACFhIRozZo1Kioq0smTJ119hg4dqsDAQB04cMAnNXUEdrtdFotFMTExbu3l5eXq06eP+vXrZ1BlAABPW7NmjV544QX9+Mc/1qFDh/TDH/6wyXW2knTbbbfp6aef1t69e+V0OvX5559rxYoVhFv4nFcD7ptvvqnFixdr06ZNqqur09SpU7Vx40bFx8c32n/37t0aMmRIm8fJzs5u03F1dXWqrKxUQkKCqy06OlpWq1WHDh1y6zt9+nSWKdzAbrdr4MCB6tatm1t7eXl5h5m9LSkpMboEAGj3/vrXv+qFF17QrFmz9NZbb6lHjx6tOu78+fOaO3eurl27psjISG3YsMFnyw+B67wWcC9fvqxFixYpNzdXY8eOlcVi0fz581VfX99owM3Pz9fmzZu1YcMGSVJ1dbVGjhyppKQkJSYm6k9/+lOTY2VmZjYIps1xOBySpJCQELf20NBQ133XTZkyRe+++26rH9vs7Ha7Kioq1Lt3b7ePnJwcJSYmGl1eqxw5csToEgCgXauvr9eTTz6piIgIbd68WRaLpVXH3bjm9p133lFBQYFqamq0ZMkSL1cMuPPaNmElJSW6du2aJk+e7Gq7fgWpmwPujh07lJ6ersLCQg0bNkyS1LNnT+3du1cWi0UVFRX68Y9/rAceeMAjtQUHB0v6Zib3RrW1tbJarW5tp06dUmRkpEfGbU5AQIDXx2hKUlJSq/vu379fK1eu1Jw5c9zaY2Nj2zSDW1JS4pWv+bnnnmuxz7p161rst27dOk+V1O7lZKY3ehuex3PtO9efX57n1rn5feC9997T0aNHtX379gbvi025OdxeX5awYMEC/frXv1ZWVpb69u3rdoy33gvgH27creNmXgu4586da3C25LZt29S3b1+3H/AtW7Zo8eLF2rVrl0aPHu1qv/F/ixcvXmxwUtOtCA0NVWRkpA4ePKi4uDhJ35wk5XA4Gix1KCwsVEpKisfGbkpz3yRvasvWaRUVFbpw4YKSk5MVERHh1l5bW9umgJuUlOSV9dbHjh1rsc+6deuUlpbWbJ9XXnnFUyW1a5k5ucq2pTW4Dc/jufad688vz3PrNPY+sHnzZoWHh+vhhx9u1WM0FW6lbwLuhg0btHXrVmVmZrod5633AsBrSxRiYmJUUVGhkpISXb16Vdu2bVN2drYrUErSxo0btWTJEhUXF7uF2+tOnDihMWPGaNKkSXrooYc8Wl9aWppycnJ04sQJORwO2Ww2JScnKyoqytXn8uXL+uijjzR16lSPjt1R2e12de/evcF/Nj755BP169dPffr0MagyAICnOJ1O7d27V1OmTFFgYMvzYM2FW0n67ne/q8GDB2vv3r3eKhlowGsBd/jw4Vq+fLkeeeQRRUREqLS0VCNGjHBbnvDss8/K4XBowoQJCgoKcn1cd/fdd2vv3r2y2+3KyMhocqysrKwGZ/W3JDMzU9OmTVNiYqLuuusu1dfXKy8vz61PcXGx4uPj1bt37zY9tlnZ7XYlJiY2eMHbt29fhznBTJJeeuklo0sAgHbr1KlTunDhgtuJ2E1pKdxel5CQoE8//dTTpQJN8uqleletWqVVq1a5Po+KilJqaqrr8+b+LH/lyhV17dpVkmS1Wl3rZhuzbNkyLVu2rE21WSwWrV27VmvXrm2yT2FhoWbMmNGmxzWzpv5s/9prr/m4klsza9Yso0sAgHbr6tWrSkhI0MCBA5vt9/XXX7cq3ErfnHtz4sQJT5cKNMmrAfdGDodDp06danKLsJsdPHhQNptNFotF//znP7V+/XovV9hQ//79XXv2wjwGDRqko0ePGl0GALRLAwcO1P79+1vsd9ttt+lHP/qRhg4d2uI+t88991yrTgIGPMVnAffw4cMKDg5WdHR0q/qPHDlSf/7znz02flxcnObOndumY1auXOmx8QEAMBubzWZ0CUCjfBZwR40a1WCPWV+Ki4tzO8ENAAAA5uT1S/UC7U1btkYDAAAdDwEXfqejnRQHAADahoALv/PUU08ZXQIAAPAiAi78DlfNAQDA3Ai4AAAAMBUCLgAAAEzFZ9uEof0qKyvz6c4CZWVlhm7ZxkUeAMCdr98Hro/J9p3wFmZw/ZwR+wMbvSfx9u3bDRsbANqbb/uafLzybKO3vT0u0BrM4Po5Iy6BbLQVK1Zo1qxZRpcBAO3Ct30fyMzJVbYtrcFtoD1gBhcAAACmQsAFAACAqRBw4Xc2bdpkdAkAAMCLCLjwOzExMUaXAAAAvIiAC7+TlJRkdAkAAMCLCLgAAAAwFQIu/E5iYqLRJQAAAC8i4MLv2O12o0sAAABeRMAFAACAqRBwAQAAYCoEXPidnTt3Gl0CAADwIgIuAAAATIWAC7/z6KOPGl0CAADwokCjC4CxFi5cqLKyMp+PGxcXp/Xr1/t8XAAAjGLUe67kf++7zOD6ubKyMp//shkxJgAARjPq/c8f33eZwYXi4uK0Z88en403fvx4n43VmAULFhg6PgDAf/n6PVcy/n3XCMzgwu9kZGQYXQIAAPAiAi78zrhx44wuAQAAeBEBF37nyy+/NLoEAADgRQRcAAAAmAoBF35n8ODBRpcAAAC8iIALv5Ofn290CQAAeIXT6dTVq1eNLsNwBFz4nRdffNHoEgAAaNaVK1e0fft2PfPMMxo3bpxiYmI0dOhQPfzww/rlL3+p8vLyBsc4nU4tX75cDz74oL7++msDqm4//Cbgbt26tc37wCUkJOj999/3TkEwzI4dO4wuAQCARl25ckUvv/yyIiIi9KMf/UhvvPGGrl27pkGDBikqKkqfffaZfvGLXyguLk6jR4/WX/7yF0n/G25/9atfaeDAgerSpYvBX4mxDA24NptNMTExslqtCg8PV2pqqs6fP++Tsevr67V06VKFhYUpODhYKSkpqq6uduszY8YMFRQU+KSejiQ8PFyvv/66W5vT6ZTVatXbb79tUFUAAHRshw8f1vDhw/Xiiy9q1KhRev/991VXV6e9e/dq586dKigo0N///ndVV1frX//1X1VVVaWkpCQ9++yzyszM1K9+9Sulp6dr06ZN6tTJb+YwG2XoV2+xWJSXl6eamhqVl5erqqpK8+bN88nY2dnZKigoUGlpqaqqqiRJs2fPduszY8YMFRYW+qSejuLMmTM6e/ashg4d6tZ+/PhxXbx4UcOHDzeoMgAAOq4DBw5o7Nixqq6u1h/+8AcVFBTogQcekMViadC3V69eWrRokY4cOaKnn35aGzdu1Jo1a5Samkq4/X+8/gxs375dsbGxCgoK0qRJk7Ro0SLNnDlTkpSVlaX4+Hh17txZYWFhysjI8Nnl63Jzc2Wz2TRgwACFhIRozZo1Kioq0smTJ119hg4dqsDAQB04cMAnNXUEdrtdFotFMTExbu3l5eXq06eP+vXrZ1BlrVdSUmJ0CQAAuJw7d06TJ09WSEiI/vrXv2rKlCmtOq5Hjx6yWq2uz7t06UK4/X+8+iy8+eabWrx4sTZt2qS6ujpNnTpVGzduVHx8fKP9d+/erSFDhrR5nOzs7DYdV1dXp8rKSiUkJLjaoqOjZbVadejQIbe+06dPZ5nCDex2uwYOHKhu3bq5tZeXl3eY2dsjR44YXQIAAC4LFixQXV2d/vCHP6h///6tOubGNbfp6en62c9+pl//+tc+myhs77wWcC9fvqxFixYpNzdXY8eOlcVi0fz581VfX99owM3Pz9fmzZu1YcMGt/aamhr17NlTeXl5TY6VmZnZIJg2x+FwSJJCQkLc2kNDQ133XTdlyhS9++67rX5ss7Pb7aqoqFDv3r3dPnJycpSYmGh0ea3y9NNPG10CAACSpP/6r//Szp079eKLL+ree+9t1TE3h9tNmzYpOztbAwYM0PPPP+/lijuGQG89cElJia5du6bJkye72q5fIvXmgLtjxw6lp6ersLBQw4YNc7vvl7/8pcaMGePR2oKDgyV9M5N7o9raWrepfkk6deqUIiMjPTp+YwICArw+RlOSkpJa3Xf//v1auXKl5syZ49YeGxvbphnckpISr3zNzz33XKv65ebmNnv/unXrPFFOh5CTmd7obXgez7XvXH9+eZ69i5/ptrv5PXfTpk0KCgrSM88806rjGwu3nTp1Uvfu3fXcc8/pZz/7mfbv39/gPdlb77tGcjqdTd7ntYB77tw53XHHHW5t27ZtU9++fdW3b19X25YtW7R48WLt2rVLo0ePduv/+eefq6amxm0pgSeEhoYqMjJSBw8eVFxcnKRvTpJyOBwNljoUFhYqJSXFo+M3prlvkje1Zeu0iooKXbhwQcnJyYqIiHBrr62tbVPATUpK8sqfUY4dO9Zin3Xr1iktLa3ZPq+88oqnSmrXMnNylW1La3Abnsdz7TvXn1+eZ+/iZ7rtbn7PdTqdeueddzRz5kzX5Ftzmgq3182ePVsLFy7UO++80+A92Vvvu+2V15YoxMTEqKKiQiUlJbp69aq2bdum7OxsV6CUpI0bN2rJkiUqLi5uEG4l6Re/+IVWrFjhlfrS0tKUk5OjEydOyOFwyGazKTk5WVFRUa4+ly9f1kcffaSpU6d6pYaOxm63q3v37g12UPjkk0/Ur18/9enTx6DK2uall14yugQAAPT555+rrq5OI0eObLFvS+FW+mbpZUxMDCfHy4sBd/jw4Vq+fLkeeeQRRUREqLS0VCNGjHBbnvDss8/K4XBowoQJCgoKcn1I0r59+9SrVy9FR0e3OFZWVlaDs/pbkpmZqWnTpikxMVF33XWX6uvrG6zzLS4uVnx8vHr37t2mxzYru92uxMREBQa6T/zv27evw5xgJkmzZs0yugQAAPT5559LkgYNGtRsv9aE2+sGDRqkiooKj9fa0XhtiYIkrVq1SqtWrXJ9HhUVpdTUVNfnzf1Z3m6369ChQ3rwwQdVUVGhHj16KDo6utH/5SxbtkzLli1rU20Wi0Vr167V2rVrm+xTWFioGTNmtOlxzaypP9u/9tprPq7k1gwaNEhHjx41ugwAgJ9LTEzUhx9+qNjY2Gb71dTU6K233mrVRRx+8Ytf6NKlS54utcPxasC9kcPh0KlTp5rcIuxmzzzzjGvB9cqVK/Wd73ynVVP4ntS/f3/Xnr0AAACedPvtt2vChAkt9uvdu7fsdrvuuOOOFve5betftM3KZwH38OHDCg4ObtWSg5utXLnylsePi4vT3LlzfT4uAADArbrxBH20zGcBd9SoUQ32mPWluLg4txPc4L/asnMEAADoeLieG/xOR1szDAAA2oaAC7/z1FNPGV0CAADwIgIu/I4/bXQNAIA/IuACAADAVAi4AAAAMBUCLvwOF3kAAMDcfLZNGNqvsrIyn26dVVZWZuiWbdu3b+dyvQAAQ/j6Pff6mP62VSozuH7OiP2Bjd6TeMWKFYaNDQDwX9/2/e945dlGb3t73I6MGVw/t379eqNLAADAL3zb99zMnFxl29Ia3EbTmMEFAACAqRBw4Xc2bdpkdAkAAMCLCLjwOzExMUaXAAAAvIiAC7+TlJRkdAkAAMCLCLgAAAAwFQIuAAAATIVtwmAq99xzT4t9VqxY0ap+AACgY2IGF35n5cqVRpcAAAC8iIALAAAAUyHgAgAAwFQIuAAAADAVAi4AAABMhYALAAAAUyHgAgAAwFQIuAAAADAVAi4AAABMhYALAAAAU+FSvYCfuHLlquqvXWvQfvn/+7rR27fd1lWdAgJ8UhsAAJ5EwAX8RNnRCr1dvLdB+6qNv2lwOyqir9L/ZZrPagMAwJNYogD4ieFD7lHfsNtb7Bcgaep9IxXA7C0AoIMi4AJ+wtKpk6ZOHNliv2H3DlRE3zAfVAQAgHcQcAE/8p2ouzToO/2bvL9L50AlJ33fhxUBAOB57S7g2mw2xcTEyGq1Kjw8XKmpqTp//rxPxq6vr9fSpUsVFham4OBgpaSkqLq62idjA74yZcIPZOnU+K/+hJHxsgZ193FFAAB4VrsLuBaLRXl5eaqpqVF5ebmqqqo0b948n4ydnZ2tgoIClZaWqqqqSpI0e/Zsn4wN+Erv20M0KuHeBu2h1iCNGR5rQEUAAHiWYQH3448/VnJysvr06aPQ0FDNnDlTkpSVlaX4+Hh17txZYWFhysjI0J49e3xSU25urmw2mwYMGKCQkBCtWbNGRUVFOnnypE/GB3xl4qh49eh2m1vbDyf8QJ07s7EKAKDjMyTg5ufna/r06UpLS1NlZaVOnz6t+fPnN9p39+7dGjJkSJvHyM7ObtNxdXV1qqysVEJCgqstOjpaVqtVhw4davP4QHvW7bauemDscNfnURF9Ffu9uw2sCAAAz/F5wL106ZLS09O1YcMGpaSkqGvXrgoODlZycnKDvvn5+dq8ebM2bNjgasvLy9PIkSM1cuRI7d69u8lxMjMz2xRMHQ6HJCkkJMStPTQ01HUfYCaJQ7/ZNoxtwQAAZhPgdDqdvhzwvffe0xNPPKFz5841+4a6Y8cOpaenKz8/XxMmTJAk1dbWauLEidq3b5+++uorTZgwQZ9++qksFsst11VbW6uePXvq008/VVxcnKs9JCREb731lqZPn37LYzQnMyfXq48PAABgJtm2tKbvdPrYm2++6fzud7/bbJ833njD2bNnT+fevXvd2ouKipzPPPOM6/Np06Y5//73v3ustsjISOfrr7/u+vzzzz93SnKeOHHCY2MA7c2VK1eNLsEv2LL/T6O34XnXn1+eZ+/iZ9p3eK7bzudLFBISEnTixAnt2rVL165dU21trYqLi133b9y4UUuWLFFxcbFGjx7tdmxNTY169uzp+rxnz56qqanxWG1paWnKycnRiRMn5HA4ZLPZlJycrKioKI+NAbQ3Xbp0NroEAAA8yudLFCTpzTffVFZWls6cOaPg4GA9+eSTWr169TcFBQQoMDBQXbt2dTvmq6++UnFxsd577z3Xmtzp06dr7dq1GjhwYIMxsrKy9Nvf/lZHjhxpdV319fWy2WzaunWrrly5ogceeEC5ubnq3bv3LXy1rcMSBQAAgNZrV0sUbsWFCxec8fHxzq+//tpZU1PjvPfee53//Oc/jS4LAFrEnxh9hyUKvsHPtO/wXLddh9r0MjQ0VAsXLtT48eMlSa+88opHTjADAACAeXSogCtJc+bM0Zw5c4wuAwAAAO1Uu7tULwAAAHArCLgAAAAwFQIuAAAATIWACwAAAFMh4AIAAMBUCLgAAAAwFQIuAAAATIWACwAAAFMh4AIAAMBUCLgAAAAwFQIuAAAATIWACwAAAFMh4AIAAMBUCLgAAAAwFQIuAAAATIWACwAAAFMh4AIAAMBUCLgAAAAwFQIuAAAATIWACwAAAFMh4AIAAMBUCLgAAAAwFQIuAAAATIWACwAAAFMh4AIAAMBUCLgAAAAwFQIuAAAATIWACwAAAFMh4AIAAMBUAo0uAADMprTsM1V+ca5B+4739jS4HRocpAfGDvdRZQDgHwi4AOBhd/UN0zvFe+W8qf3A3/7R4PZj0yb6sDIA8A8sUQAAD4voG6ZhsQNb7BcZfoeGDor2QUUA4F8IuADgBcnjvq8unZv/I9nU+0YpICDARxUBgP8g4AKAF1iDumvCyPgm74+P+Y4iw+/wYUUA4D/aXcC12WyKiYmR1WpVeHi4UlNTdf78eZ+MXV9fr6VLlyosLEzBwcFKSUlRdXW1T8YGYD5jEmMVag1q0N450KIHx33fgIoAwD+0u4BrsViUl5enmpoalZeXq6qqSvPmzfPJ2NnZ2SooKFBpaamqqqokSbNnz/bJ2ADMp3NgoH444QcN2pNGxCmkkeALAPAMwwLuxx9/rOTkZPXp00ehoaGaOXOmJCkrK0vx8fHq3LmzwsLClJGRoT179vikptzcXNlsNg0YMEAhISFas2aNioqKdPLkSZ+MD8B8Yr93t6Ii+ro+DwnuoXEjhhpYEQCYnyEBNz8/X9OnT1daWpoqKyt1+vRpzZ8/v9G+u3fv1pAhQ9o8RnZ2dpuOq6urU2VlpRISElxt0dHRslqtOnToUJvHBwBJCggI0NT7Rur6qWSTx49o8eQzAMCtCXA6nTdv1ehVly5dUv/+/bV+/Xr95Cc/abZvfn6+5s6dq5KSEg0bNkySdP/996usrEwLFy7Uz3/+c4/Vdfr0aUVGRur48eO6++67Xe39+/fX6tWrW6z1VmXm5Hr18QEAAMwk25bW5H0+n0YoKSlRQECAHn/88Wb77dixQ+np6SosLHSFW0naunWrPvjgA9caWU8JDg6W9M1M7o1qa2tltVo9OlZjmvsmAej4HF9dluPiJUXcGWZ0KaaXmZOrbFua6194x43PL8+1d/Fct53PlyhUV1erZ8+eze79uGXLFqWnp2vXrl2aMGGC230RERFeqSs0NFSRkZE6ePCgq+348eNyOBzfaokEANzIGtSdcAsAPuLzJQpHjhxRXFycfv/732vKlClyOBwqLS1VcnKyJGnjxo166aWXVFRUpMTExEYfY+vWraqqqvLoEgVJWr16tX7zm9+oqKhIvXr10k9/+lNdvHhRRUVFHh2nMSxRAAAAaL1mZ7KdBti6datz4MCBzh49ejj79u3rXLZsmes+Sc7AwEBnjx493D5utGXLFufLL7/c7BirV692Dh48uE11/fOf/3QuXrzY2atXL2dQUJDz4Ycfdn755ZdtegwAgLFs2f/H7V94x43PL8+1d/Fct50hp/I+8cQTeuKJJxq9z+mhCeVly5Zp2bJlbTrGYrFo7dq1Wrt2rUdqAAAAgO91uL1qnnzySZWWlurKlSsqLS3Vrl27jC4JAAAA7UiHC7hvvPGG0SUAAACgHWt3l+oFAAAAbgUBFwAAAKZCwAUAAICpEHABAABgKgRcAAAAmAoBFwAAAKZCwAUAAICpEHABAABgKgRcAAAAmAoBFwAAAKZCwAUAAICpEHABAABgKgRcAAAAmAoBFwAAAKZCwAUAAICpEHABAABgKgRcAAAAmAoBFwAAAKZCwAUAAICpEHABAABgKgRcAAAAmAoBFwAAAKZCwAUAAICpEHABAABgKgRcAAAAmAoBFwAAAKZCwAUAAICpEHABAABgKoFGFwAAwLf15flaXau/1qD9/3553u1fSbJYLOp9e4jPagNgHAIuAKDD+q+yY/qL/VCD9nVv7HT7V5ImjozXpHGJPqsNgHFYogAA6LAmjopXj263tdgvOKi7kn4Q54OKALQHBFwAQIfV7baumjRueIv9Hkz6vrp26eyDigC0BwRcAECHNnzIPeobdnuT90f0DVN8zHd9WBEAo7W7gGuz2RQTEyOr1arw8HClpqbq/PnzLR/oAfX19Vq6dKnCwsIUHByslJQUVVdX+2RsAMC3Y+nUSVMnjmzy/qn3jVSngAAfVgTAaO0u4FosFuXl5ammpkbl5eWqqqrSvHnzfDJ2dna2CgoKVFpaqqqqKknS7NmzfTI2AODb+07UXRr83f4N2ocOilZURF8DKgJgJMMC7scff6zk5GT16dNHoaGhmjlzpiQpKytL8fHx6ty5s8LCwpSRkaE9e/b4pKbc3FzZbDYNGDBAISEhWrNmjYqKinTy5EmfjA8A+PZ+OP4HsnT637e1wECLHkz6voEVATCKIQE3Pz9f06dPV1pamiorK3X69GnNnz+/0b67d+/WkCFD2jxGdnZ2m46rq6tTZWWlEhISXG3R0dGyWq06dKjhFjQAgPal9+0hGpVwr+vzcYlD1DMk2MCKABjF5wH30qVLSk9P14YNG5SSkqKuXbsqODhYycnJDfrm5+dr8+bN2rBhgyTpwIEDGj16tMaNG6eJEyfq+PHjTY6TmZnZpmDqcDgkSSEh7puAh4aGuu4DALRv940eph7db5OVbcEAvxbgdDqdvhzwvffe0xNPPKFz584poJlF/zt27FB6erry8/M1YcIESdLZs2cVFBSk4OBgvffee/rd736nt956yyN11dbWqmfPnvr0008VF/e/L4ohISF66623NH36dI+M05TMnFyvPj4AAICZZNvSmrzP51cyq66uVs+ePZsNt1u2bNHixYu1a9cujR492tV+5513um536dJFgYGeKz80NFSRkZE6ePCgK+AeP35cDofjWy2RaKvmvkkAgNa7du2aFBDAzglelpmT63rvuvE2PI/nuu18vkQhISFBJ06c0K5du3Tt2jXV1taquLjYdf/GjRu1ZMkSFRcXu4XbG126dEmZmZlasmSJR2tLS0tTTk6OTpw4IYfDIZvNpuTkZEVFRXl0HACA93Tq1IlwC/g5ny9RkKQ333xTWVlZOnPmjIKDg/Xkk09q9erV3xQUEKDAwEB17drV7ZivvvpKknT16lU99NBDSktL00MPPdTkGFlZWfrtb3+rI0eOtLqu+vp62Ww2bd26VVeuXNEDDzyg3Nxc9e7d+1t8lW3DEgUAAIDWa24m25CA+23V19frRz/6kR588MEmd10AAADex5/NfYfnuu3a3YUemrNjxw4VFRUpLy9P48eP189+9jOjSwIAAEA74/OTzG7FY489pscee8zoMgAAANCOdagZXAAAAKAlBFwAAACYCgEXAAAApkLABQAAgKkQcAEAAGAqBFwAAACYCgEXAAAApkLABQAAgKkQcAEAAGAqBFwAAACYCgEXAAAApkLABQAAgKkQcAEAAGAqBFwAAACYCgEXAAAApkLABQAAgKkQcAEAAGAqBFwAAACYCgEXAAAApkLABQAAgKkQcAEAAGAqBFwAAACYCgEXAAAApkLABQAAgBparCMAAAnBSURBVKkQcAEAAGAqBFwAAACYCgEXAAAApkLABQAAgKkQcAEAAGAqgUYXAAAA2jen06mCP32s87UX3drf2P7HRm9/L7qfRifc67P6gJsRcAEAQLMCAgI0IDJcf/30A7f2f5w43eC2xdJJMyaN9ml9wM1YogAAAFoU+727FRXRt8V+Y4bHqleo1QcVAU0j4AIAgBYFBARo6n0jFdBMn6Ae3TRhZLzPagKaQsAFAACtEtE3TMNiBzZ5f/LYRN3WtYsPKwIa1+4Crs1mU0xMjKxWq8LDw5Wamqrz58/7ZOz6+notXbpUYWFhCg4OVkpKiqqrq30yNgAAHUHyuO+rS5fODdrvvKOXEpoJv4AvtbuAa7FYlJeXp5qaGpWXl6uqqkrz5s3zydjZ2dkqKChQaWmpqqqqJEmzZ8/2ydgAAHQE1qDumvCDuAbt0+4bqU6d2l2sgJ8y7Cfx448/VnJysvr06aPQ0FDNnDlTkpSVlaX4+Hh17txZYWFhysjI0J49e3xSU25urmw2mwYMGKCQkBCtWbNGRUVFOnnypE/GBwCgIxiTGKtQa5Dr83sH3q0BkeEGVgS4MyTg5ufna/r06UpLS1NlZaVOnz6t+fPnN9p39+7dGjJkSJvHyM7ObtNxdXV1qqysVEJCgqstOjpaVqtVhw4davP4AACYVefAQP1wwg8kfbMt2OQJIwyuCHAX4HQ6nb4c8NKlS+rfv7/Wr1+vn/zkJ832zc/P19y5c1VSUqJhw4apurpa06ZNU5cuXXT58mVlZWXpgQce8Ehdp0+fVmRkpI4fP667777b1d6/f3+tXr26xVpvVWZOrlcfHwAAwEyybWlN3ufzCz38/+3dX0jU6R7H8c84slaemWZS2WhBBY2FXEo02XVtqdmDK1R0cbxZM2HTcu5OFxnjTX9J0bucq7DACoUDg0EOgV50YRThzdAfXIjUKbPDgeOYjnYhpJ4LOYOi42qr8+fZ9+vKmd9veL7qzZvxmcf+/n5ZLBZVV1eveZ/P55Pb7VZPT4+KiookSU6nU0+ePJHVatXQ0JCqqqo2LXBtNpukxXdyl5qcnJTdvvXn+a31SwIAIBH9578Tctj/xskJW6yxtT3SCUu/RnQx36IwPj4up9MpiyX6SXodHR1yu93y+/1yuVyR561Wq6xWqyRpenpaBw4c2LS5HA6HsrOzFQgEIs+NjIwoHA5/0RYJAABMtztrF3GLhBTzLQqDg4MqLCzU/fv3dezYMYXDYQ0MDKiiokKS5PV6dfXqVfX29qqkpGTF64PBoGpqavT69Wt1dHTo+PHjmzZbU1OT7t27p97eXmVkZKiurk7T09Pq7e3dtDWiYYsCAADA+q31TnbMA1eS7t69q+bmZn348EE2m021tbVqampaHMhiUWpqqtLS0pa9ZmZmZtnjt2/f6siRI1FPOGhublZXV5cGBwfXPdfc3Jw8Ho/u3Lmj2dlZlZeXq729XZmZmRv7BgEAADYJWxQ2Li6B+6VmZ2cj4TsxMaHDhw/r1atXcZ4KAABg6xC4GxfzD5n9GYFAQB6PR1arVZ8/f9aNGzfiPRIAAAASTFIFbmlpqR4/fhzvMQAAAJDA+J96AAAAMAqBCwAAAKMQuAAAADAKgQsAAACjELgAAAAwCoELAAAAoxC4AAAAMAqBCwAAAKMQuAAAADAKgQsAAACjELgAAAAwCoELAAAAoxC4AAAAMAqBCwAAAKMQuAAAADAKgQsAAACjELgAAAAwCoELAAAAoxC4AAAAMAqBCwAAAKMQuAAAADAKgQsAAACjELgAAAAwCoELAAAAoxC4AAAAMAqBCwAAAKMQuAAAADAKgQsAAACjpMZ7AAAAACyam5/XyOi/Vzz/5u3Yql/b03fo66xdMZktmVgWFhYW4j0EAAAAFt2736ff37xb171nfj2m/Jxvtnii5MMWBQAAgARy1PWDrCl/nGj79uYSt1EQuAAAAAkk07lTZQe/W/Mea0qKjrq+j9FEyYfABQAASDA//1ik9B3bol4vO/idMp07YzhRckm4wPV4PCooKJDdbteePXt09uxZTUxMxGTtubk5XbhwQVlZWbLZbKqsrNT4+HhM1gYAAPi/bWlf6ZefSla9lr5jm37+sSjGEyWXhAtcq9Wqzs5OhUIhvXjxQmNjYzp9+nRM1m5padGDBw80MDCgsbHFTyjW1NTEZG0AAIClSvZ/q92rnJDwy08HtS3tqzhMlDzidorC06dPde3aNT1//lyzs7MqLy+Xz+dbcd/Dhw918uRJTU1NbflMOTk5unTpkurq6iRJw8PDys/PVzAYVG5u7pavDwAAsNTQuw+6/a+Hkce7s3bpn7/9Qynr+BDaX1lcfjrd3d06ceKE6uvrNTo6qvfv3+vMmTOr3vvo0SPt379/w2u0tLRs6HVTU1MaHR1VcXFx5Lm8vDzZ7Xa9fPlyw+sDAAD8Wfk532jf3tzI4+N/LyVu1yHmP6FPnz7J7Xarra1NlZWVSktLk81mU0VFxYp7u7u7devWLbW1tS17PhQKyel0qrOzM+o6jY2NGwrTcDgsSdq5c/mGbYfDEbkGAAAQa0dd38uakqJ9e3M4FmydYv6fzPr7+2WxWFRdXb3mfT6fT263Wz09PSoqWr6R+vr16zp06NCmzmWz2SRpxVaIyclJ2e32TV1rNY2t7Vu+BgAASF6/v3lHLyzR4qmPei3mgTs+Pi6n0ymLxRL1no6ODp0/f15+v19lZWXLrg0PDysUCi3bSrAZHA6HsrOzFQgEVFhYKEkaGRlROBz+oi0SG7XWLwkAAPy1LSwsrNlOWC7mWxSKi4sVDAbl9/s1Pz+vyclJ9fX1Ra57vV41NDSor69vRdxK0sWLF3X58uUtma2+vl6tra0KBoMKh8PyeDyqqKjgA2YAACCuiNuNifk7uAUFBbp9+7YaGhpUVVUlm82m2trayB7cc+fOKTU1VS6Xa9nrZmZm9OzZM2VkZCgvL+8P12lublZXV5cGBwfXPVtjY6M+fvyokpKSyMkOa+3z3Uz8yQEAAGD91vrrd9yOCfsSXq9X3d3d2r59u4aGhpSenq6bN2+qtLQ03qMBAAAgQSRV4C515coV5efn69SpU/EeBQAAAAkkaQMXAAAAWA0nBQMAAMAoBC4AAACMQuACAADAKAQuAAAAjELgAgAAwCgELgAAAIxC4AIAAMAoBC4AAACMQuACAADAKAQuAAAAjELgAgAAwCgELgAAAIxC4AIAAMAoBC4AAACMQuACAADAKAQuAAAAjELgAgAAwCgELgAAAIxC4AIAAMAoBC4AAACMQuACAADAKAQuAAAAjELgAgAAwCgELgAAAIzyP1pSwtZyDxPkAAAAAElFTkSuQmCC\n", + "text/plain": [ + "
" + ] + }, + "execution_count": 19, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Number of qubits utilised simultaneously.\n", + "glo_num_qubits = 5\n", + "\n", + "def create_circuit(num_target_qubits: int) -> QuantumCircuit:\n", + " \"\"\"\n", + " Creates and returns quantum circuit for random variate generation.\n", + " :param num_target_qubits: number of qubits to be used.\n", + " :return: quantum curcuit.\n", + " \"\"\"\n", + " assert isinstance(num_target_qubits, int) and num_target_qubits > 0\n", + " q = QuantumRegister(num_target_qubits)\n", + " c = ClassicalRegister(num_target_qubits)\n", + " circuit = QuantumCircuit(q, c)\n", + " circuit.h(q)\n", + " circuit.barrier()\n", + " circuit.measure(q, c)\n", + " return circuit\n", + "\n", + "# Create and plot generating quantum circuit.\n", + "circuit = create_circuit(glo_num_qubits)\n", + "#print(circuit)\n", + "circuit.draw(output='mpl')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Uniformly-distributed scalars and vectors\n", + "\n", + "It is clear that there are many options for approximating uniformly-distributed scalars by the choice of an integer from a finite range uniformly at random, e.g., by a binary-code construction from the Bernoulli-distributed vectors. In the following snippet, we generate random bits, which we then convert using the binary-code construction, up to the machine precision of a classical computer." + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [], + "source": [ + "def uniform_rand_float64(circuit: QuantumCircuit, num_target_qubits: int,\n", + " size: int, vmin: float, vmax: float) -> np.ndarray:\n", + " \"\"\"\n", + " Generates a vector of random float64 values in the range [vmin, vmax].\n", + " :param circuit: quantum circuit for random variate generation.\n", + " :param num_target_qubits: number of qubits to be used.\n", + " :param size: length of the vector.\n", + " :param vmin: lower bound.\n", + " :param vmax: upper bound.\n", + " :return: vector of random values.\n", + " \"\"\"\n", + " assert sys.maxsize == np.iinfo(np.int64).max # sizeof(int) == 64 bits\n", + " assert isinstance(size, int) and size > 0\n", + " assert isinstance(vmin, float) and isinstance(vmax, float) and vmin <= vmax\n", + " nbits = 7 * 8 # nbits > mantissa of float64\n", + " bit_str_len = (nbits * size + num_target_qubits - 1) // num_target_qubits\n", + " job = execute(circuit, glo_backend, shots=bit_str_len, memory=True)\n", + " bit_str = ''.join(job.result().get_memory())\n", + " scale = float(vmax - vmin) / float(2**nbits - 1)\n", + " return np.array([vmin + scale * float(int(bit_str[i:i+nbits], 2))\n", + " for i in range(0, nbits * size, nbits)], dtype=np.float64)\n", + "\n", + "def uniform_rand_int64(circuit: QuantumCircuit, num_target_qubits: int,\n", + " size: int, vmin: int, vmax: int) -> np.ndarray:\n", + " \"\"\"\n", + " Generates a vector of random int64 values in the range [vmin, vmax].\n", + " :param circuit: quantum circuit for random variate generation.\n", + " :param num_target_qubits: number of qubits to be used.\n", + " :param size: length of the vector.\n", + " :param vmin: lower bound.\n", + " :param vmax: upper bound.\n", + " :return: vector of random values.\n", + " \"\"\"\n", + " assert sys.maxsize == np.iinfo(np.int64).max # sizeof(int) == 64 bits\n", + " assert isinstance(size, int) and size > 0\n", + " assert isinstance(vmin, int) and isinstance(vmax, int) and vmin <= vmax\n", + " assert abs(vmin) <= 2**52 and abs(vmax) <= 2**52 # 52 == mantissa of float64\n", + " return np.rint(uniform_rand_float64(circuit, num_target_qubits,\n", + " size, float(vmin), float(vmax))).astype(np.int64)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Uniform distribution over floating point numbers.\n", + "In this example we draw a random vector of floating-point values uniformly distributed within some arbitrary selected interval:" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": { + "scrolled": true + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Uniform distribution over floating point numbers:\n", + " sample type: , element type: float64 , shape: (54321,)\n", + " sample min: -7.6698, max: 19.5196\n", + " sampling time: 6.65 secs\n" + ] + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "# Draw a sample from uniform distribution.\n", + "start_time = time.time()\n", + "sample = uniform_rand_float64(circuit, glo_num_qubits, size=54321, vmin=-7.67, vmax=19.52)\n", + "sampling_time = time.time() - start_time\n", + "\n", + "# Print out some details.\n", + "print(\"Uniform distribution over floating point numbers:\")\n", + "print(\" sample type:\", type(sample), \", element type:\", sample.dtype, \", shape:\", sample.shape)\n", + "print(\" sample min: {:.4f}, max: {:.4f}\".format(np.amin(sample), np.amax(sample)))\n", + "print(\" sampling time: {:.2f} secs\".format(sampling_time))\n", + "\n", + "# Plotting the distribution.\n", + "plt.hist(sample.ravel(),\n", + " bins=min(int(np.ceil(np.sqrt(sample.size))), 100),\n", + " density=True, facecolor='b', alpha=0.75)\n", + "plt.xlabel(\"value\", size=12)\n", + "plt.ylabel(\"probability\", size=12)\n", + "plt.title(\"Uniform distribution over float64 numbers in [{:.2f} ... {:.2f}]\".format(\n", + " np.amin(sample), np.amax(sample)), size=12)\n", + "plt.grid(True)\n", + "# plt.savefig(\"uniform_distrib_float.png\", bbox_inches=\"tight\")\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Uniform distribution over integers.\n", + "Our next example is similar to the previous one, but here we generate a random vector of integers:" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Uniform distribution over bounded integer numbers:\n", + " sample type: , element type: int64 , shape: (54321,)\n", + " sample min: 37, max: 841\n", + " sampling time: 6.62 secs\n" + ] + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "# Draw a sample from uniform distribution.\n", + "start_time = time.time()\n", + "sample = uniform_rand_int64(circuit, glo_num_qubits, size=54321, vmin=37, vmax=841)\n", + "sampling_time = time.time() - start_time\n", + "\n", + "# Print out some details.\n", + "print(\"Uniform distribution over bounded integer numbers:\")\n", + "print(\" sample type:\", type(sample), \", element type:\", sample.dtype, \", shape:\", sample.shape)\n", + "print(\" sample min: {:d}, max: {:d}\".format(np.amin(sample), np.amax(sample)))\n", + "print(\" sampling time: {:.2f} secs\".format(sampling_time))\n", + "\n", + "# Plotting the distribution.\n", + "plt.hist(sample.ravel(),\n", + " bins=min(int(np.ceil(np.sqrt(sample.size))), 100),\n", + " density=True, facecolor='g', alpha=0.75)\n", + "plt.xlabel(\"value\", size=12)\n", + "plt.ylabel(\"probability\", size=12)\n", + "plt.title(\"Uniform distribution over int64 numbers in [{:d} ... {:d}]\".format(\n", + " np.amin(sample), np.amax(sample)), size=12)\n", + "plt.grid(True)\n", + "# plt.savefig(\"uniform_distrib_int.png\", bbox_inches=\"tight\")\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Normal distribution\n", + "\n", + "To generate random variates with a standard normal distribution using two independent \n", + "samples $u_1, u_2$ of the uniform distribution on the unit interval [0, 1], one can\n", + "consider the Box-Muller transform to obtain a 2-vector:\n", + "\n", + "\\begin{align}\n", + "\\begin{bmatrix}\n", + "%R\\cos(\\Theta )=\n", + "{\\sqrt {-2\\ln u_{1}}}\\cos(2\\pi u_{2}) \\\\\n", + "% R\\sin(\\Theta )=\n", + "{\\sqrt {-2\\ln u_{1}}}\\sin(2\\pi u_{2})\n", + "\\end{bmatrix},\n", + "\\end{align}\n", + "\n", + "wherein we have two independent samples of the standard normal distribution.\n", + "In IBM Q, this is implemented as follows: " + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [], + "source": [ + "def normal_rand_float64(circuit: QuantumCircuit, num_target_qubits: int,\n", + " size: int, mu: float, sigma: float) -> np.ndarray:\n", + " \"\"\"\n", + " Draws a sample vector from the normal distribution given the mean and standard\n", + " deviation, using the Box-Muller method. \n", + " \"\"\"\n", + " TINY = np.sqrt(np.finfo(np.float64).tiny)\n", + " assert isinstance(size, int) and size > 0\n", + " rand_vec = np.zeros((size,), dtype=np.float64)\n", + "\n", + " # Generate array of uniformly distributed samples, factor 1.5 longer that\n", + " # actually needed.\n", + " n = (3 * size) // 2\n", + " x = np.reshape(uniform_rand_float64(circuit, num_target_qubits,\n", + " 2*n, 0.0, 1.0), (-1, 2))\n", + "\n", + " x1 = 0.0 # first sample in a pair\n", + " c = 0 # counter\n", + " for d in range(size):\n", + " r2 = 2.0\n", + " while r2 >= 1.0 or r2 < TINY:\n", + " # Regenerate array of uniformly distributed samples upon shortage.\n", + " if c >= n:\n", + " c = 0\n", + " n = max(size // 10, 1)\n", + " x = np.reshape(uniform_rand_float64(circuit, num_target_qubits,\n", + " 2*n, 0.0, 1.0), (-1, 2))\n", + "\n", + " x1 = 2.0 * x[c, 0] - 1.0 # first sample in a pair\n", + " x2 = 2.0 * x[c, 1] - 1.0 # second sample in a pair\n", + " r2 = x1 * x1 + x2 * x2\n", + " c += 1\n", + "\n", + " f = np.sqrt(np.abs(-2.0 * np.log(r2) / r2))\n", + " rand_vec[d] = f * x1\n", + " \n", + " return (rand_vec * sigma + mu)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The following example demonstrates how to draw a random vector of normally distributed variates:" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Normal distribution (mu=2.400, sigma=5.100):\n", + " sample type: , element type: float64 , shape: (4321,)\n", + " sample min: -16.3332, max: 20.7365\n", + " sampling time: 1.69 secs\n" + ] + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "# Mean and standard deviation.\n", + "mu = 2.4\n", + "sigma = 5.1\n", + "\n", + "# Draw a sample from the normal distribution.\n", + "start_time = time.time()\n", + "sample = normal_rand_float64(circuit, glo_num_qubits, size=4321, mu=mu, sigma=sigma)\n", + "sampling_time = time.time() - start_time\n", + "\n", + "# Print out some details.\n", + "print(\"Normal distribution (mu={:.3f}, sigma={:.3f}):\".format(mu, sigma))\n", + "print(\" sample type:\", type(sample), \", element type:\", sample.dtype, \", shape:\", sample.shape)\n", + "print(\" sample min: {:.4f}, max: {:.4f}\".format(np.amin(sample), np.amax(sample)))\n", + "print(\" sampling time: {:.2f} secs\".format(sampling_time))\n", + "\n", + "# Plotting the distribution.\n", + "x = np.linspace(mu - 4.0 * sigma, mu + 4.0 * sigma, 1000)\n", + "analyt = np.exp(-0.5 * ((x - mu) / sigma)**2) / (sigma * math.sqrt(2.0 * math.pi))\n", + "plt.hist(sample.ravel(),\n", + " bins=min(int(np.ceil(np.sqrt(sample.size))), 100),\n", + " density=True, facecolor='r', alpha=0.75)\n", + "plt.plot(x, analyt, '-b', lw=1)\n", + "plt.xlabel(\"value\", size=12)\n", + "plt.ylabel(\"probability\", size=12)\n", + "plt.title(\"Normal distribution: empirical vs analytic\", size=12)\n", + "plt.grid(True)\n", + "# plt.savefig(\"normal_distrib.png\", bbox_inches=\"tight\")\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "There is a substantial amount of further work needed to either certify the quality of the source of random numbers (cf. NIST SP 800-90B, Recommendation for the Entropy Sources Used for Random Bit Generation) or to use random variates within quantum algorithms (cf. uncertainty_models within Qiskit Aqua)." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "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.2" + } + }, + "nbformat": 4, + "nbformat_minor": 1 +} diff --git a/qiskit/finance/data_providers/time_series.ipynb b/qiskit/finance/data_providers/time_series.ipynb new file mode 100644 index 000000000..8ef7b99a2 --- /dev/null +++ b/qiskit/finance/data_providers/time_series.ipynb @@ -0,0 +1,361 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\"Note: Trusted Notebook\" width=\"500 px\" align=\"left\">" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# _*Qiskit Finance: Loading and Processing Stock-Market Time-Series Data*_\n", + "\n", + "The latest version of this notebook is available on https://github.com/qiskit/qiskit-tutorial.\n", + "\n", + "***\n", + "### Contributors\n", + "Jakub Marecek[1]\n", + "\n", + "### Affiliation\n", + "- [1]IBMQ" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Introduction\n", + "Across many problems in finance, one starts with time series. Here, we showcase how to download the time series from a number of common providers." + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": { + "scrolled": true + }, + "outputs": [], + "source": [ + "%matplotlib inline\n", + "from qiskit.aqua.translators.data_providers import *\n", + "import warnings\n", + "warnings.filterwarnings(\"ignore\", category=DeprecationWarning)\n", + "import datetime\n", + "import matplotlib.pyplot as plt\n", + "from pandas.plotting import register_matplotlib_converters\n", + "register_matplotlib_converters()" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": {}, + "outputs": [], + "source": [ + "stocks = [\"GOOG\", \"AAPL\"]\n", + "from qiskit.aqua.translators.data_providers.wikipediadataprovider import StockMarket\n", + "wiki = WikipediaDataProvider(token = \"\",\n", + " tickers = stocks,\n", + " stockmarket = StockMarket.NASDAQ.value,\n", + " start = datetime.datetime(2016,1,1),\n", + " end = datetime.datetime(2016,1,30))\n", + "wiki.run()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Once the data are loaded, you can run a variety of algorithms on those to aggregate the data. Notably, you can compute the covariance matrix or a variant, which would consider alternative time-series similarity measures based on dynamic time warping (DTW). In DTW, changes that vary in speed, e.g., one stock's price following another stock's price with a small delay, can be accommodated." + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "A time-series similarity measure:\n", + "[[1.00000000e+00 8.44268222e-05]\n", + " [8.44268222e-05 1.00000000e+00]]\n" + ] + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "A covariance matrix:\n", + "[[269.60118129 25.42252332]\n", + " [ 25.42252332 7.86304499]]\n" + ] + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "if wiki._n <= 1: \n", + " raise Exception(\"Not enough data to plot covariance or time-series similarity. Please use at least two tickers.\")\n", + "\n", + "rho = wiki.get_similarity_matrix()\n", + "print(\"A time-series similarity measure:\")\n", + "print(rho)\n", + "#plt.subplot(211)\n", + "plt.imshow(rho)\n", + "plt.show()\n", + "\n", + "cov = wiki.get_covariance()\n", + "print(\"A covariance matrix:\")\n", + "print(cov)\n", + "#plt.subplot(212)\n", + "plt.imshow(cov)\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "If you wish, you can look into the internals using:" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "The underlying evolution of stock prices:\n" + ] + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "GOOG\n", + "Date\n", + "2016-01-04 741.84\n", + "2016-01-05 742.58\n", + "2016-01-06 743.62\n", + "2016-01-07 726.39\n", + "2016-01-08 714.47\n", + "2016-01-11 716.03\n", + "2016-01-12 726.07\n", + "2016-01-13 700.56\n", + "2016-01-14 714.72\n", + "2016-01-15 694.45\n", + "2016-01-19 701.79\n", + "2016-01-20 698.45\n", + "2016-01-21 706.59\n", + "2016-01-22 725.25\n", + "2016-01-25 711.67\n", + "2016-01-26 713.04\n", + "2016-01-27 699.99\n", + "2016-01-28 730.96\n", + "2016-01-29 742.95\n", + "Name: Adj. Close, dtype: float64\n", + "AAPL\n", + "Date\n", + "2016-01-04 101.783763\n", + "2016-01-05 99.233131\n", + "2016-01-06 97.291172\n", + "2016-01-07 93.185040\n", + "2016-01-08 93.677776\n", + "2016-01-11 95.194629\n", + "2016-01-12 96.576222\n", + "2016-01-13 94.093220\n", + "2016-01-14 96.151117\n", + "2016-01-15 93.842021\n", + "2016-01-19 93.387931\n", + "2016-01-20 93.513531\n", + "2016-01-21 93.040118\n", + "2016-01-22 97.986799\n", + "2016-01-25 96.073825\n", + "2016-01-26 96.605206\n", + "2016-01-27 90.257610\n", + "2016-01-28 90.904929\n", + "2016-01-29 94.044912\n", + "Name: Adj. Close, dtype: float64\n" + ] + } + ], + "source": [ + "print(\"The underlying evolution of stock prices:\")\n", + "for (cnt, s) in enumerate(stocks):\n", + " plt.plot(wiki._data[cnt], label=s)\n", + "plt.legend()\n", + "plt.xticks(rotation=90)\n", + "plt.show()\n", + "\n", + "for (cnt, s) in enumerate(stocks):\n", + " print(s)\n", + " print(wiki._data[cnt])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### [Optional] Setup token to access recent, fine-grained time-series\n", + "\n", + "If you would like to download professional data, you will have to set-up a token with one of the major providers. Let us now illustrate the data with NASDAQ Data on Demand, which can supply bid and ask prices in arbitrary resolution, as well as aggregates such as daily adjusted closing prices, for NASDAQ and NYSE issues.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "If you have access to NASDAQ Data on Demand you should have your own token, which you should use instead of REPLACE-ME below. \n", + "Also you should have your own means of validating NASDAQ's certificates.\n", + "If you don't you may want to run the cell below to disable the associated warnings. " + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [], + "source": [ + "import urllib3\n", + "urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "'Accessing NASDAQ Data on Demand failed.'\n", + "You need to replace REPLACE-ME with a valid token.\n" + ] + } + ], + "source": [ + "from qiskit.aqua.translators.data_providers.dataondemandprovider import StockMarket\n", + "try:\n", + " nasdaq = DataOnDemandProvider(token = \"REPLACE-ME\",\n", + " tickers = [\"GOOG\", \"AAPL\"],\n", + " stockmarket = StockMarket.NASDAQ.value,\n", + " start = datetime.datetime(2016,1,1),\n", + " end = datetime.datetime(2016,1,2))\n", + " nasdaq.run()\n", + " nasdaq.plot()\n", + "except QiskitFinanceError as e:\n", + " print(e)\n", + " print(\"You need to replace REPLACE-ME with a valid token.\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Another major vendor of stock market data is Exchange Data International (EDI), whose feeds can be used to query emerging and frontier markets that are Africa, Asia, Far East, Latin America and Middle East, as well as the more established ones. The access again requires a valid access token to replace REPLACE-ME below.\n", + "\n", + "In the following example, we look at the prices at London Stock Exchange. " + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "'Cannot retrieve Exchange Data data.'\n", + "You need to replace REPLACE-ME with a valid token.\n" + ] + } + ], + "source": [ + "from qiskit.aqua.translators.data_providers.exchangedataprovider import StockMarket\n", + "try:\n", + " lse = ExchangeDataProvider(token = \"REPLACE-ME\",\n", + " tickers = [\"AIBGl\", \"AVSTl\"],\n", + " stockmarket = StockMarket.LONDON.value,\n", + " start = datetime.datetime(2019,1,1),\n", + " end = datetime.datetime(2019,1,30))\n", + " lse.run()\n", + " lse.plot()\n", + "except QiskitFinanceError as e: \n", + " print(e)\n", + " print(\"You need to replace REPLACE-ME with a valid token.\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "For the actual use of the data, please see the portfolio_optimization or portfolio_diversification notebooks. " + ] + } + ], + "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.2" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/qiskit/finance/optimization/portfolio_diversification.ipynb b/qiskit/finance/optimization/portfolio_diversification.ipynb new file mode 100644 index 000000000..5b3a04b52 --- /dev/null +++ b/qiskit/finance/optimization/portfolio_diversification.ipynb @@ -0,0 +1,732 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# _*Qiskit Finance: Portfolio diversification*_\n", + "\n", + "The latest version of this notebook is available on https://github.com/qiskit/qiskit-tutorial.\n", + "\n", + "***\n", + "### Contributors\n", + "Andrea Simonetto[1], Jakub Marecek[1], Martin Mevissen[1]\n", + "\n", + "### Affiliation\n", + "- [1]IBMQ\n", + "\n", + "\n", + "## Introduction \n", + "\n", + "In asset management, there are broadly two approaches: active and passive investment management. Within passive investment management, there are index-tracking funds and there are approaches based on portfolio diversification, which aim at representing a portfolio with large number of assets by a smaller number of representative stocks.\n", + "This notebook illustrates a portfolio diversification problem, which has recently become popular for two reasons:\n", + "1. it makes it possible to mimick the performance of an index (or a similarly large set of assets) with a limited budget, at limited transaction costs. That is: traditional index-tracking may purchase all assets in the index, ideally with the same weights as in the index. This may be impractical for a number of reasons: the total of even a single round lot per asset may amount to more than the assets under management, the large scale of the index-tracking problem with integrality constraints may render the optimisation problem difficult, and the transaction costs of the frequent rebalancing to adjust the positions to the weights in the index may render the approach expensive. Thus, a popular approach is to select a portfolio of $q$ assets that represent the market with $n$ assets, where $q$ is significantly smaller than $n$, but where the portfolio replicates the behaviour of the underlying market. To determine how to group assets into $q$ clusters and how to determine which $q$ assets should represent the $q$ clusters amounts to solving a large-scale optimization problem. In the following we describe the mathematical model for the portfolio diversification problem as introduced in [Cornuejols & Tutuncu, 2006] \n", + "2. it allows for similarity measures between time-series beyond the covariance matrix. Notice that traditionally, modern portfolio theory considers the covariance matrix as measure of similarity between the assets. As such, however, covariance matrix is imperfect. Consider, for instance, a company listed both in London and New York. Although both listings should be very similar, only parts of the time series of the prices of the two listings will overlap, because of the partial overlap of the times the markets open. Instead of covariance, one can consider, for example, dynamic time warping of [Berndt and Clifford, 1994] as a measure of similarity between two time series, which allows for the fact that for some time periods, the data are captured by only one of the time series, while for others, both time series exhibit the similarity due to the parallel evolution of the stock price.\n", + "\n", + "The overall workflow we demonstrate comprises:\n", + "\n", + "1. pick the ground set of assets. In our case, this is a small number of US stocks.\n", + "\n", + "2. load the time series capturing the evolution of the prices of assets. In our case, this is an simplistic load of adjusted daily closing price data from Wikipedia or Nasdaq or LSE or EuroNext, whereas in a real asset management, a much higher frequency may be considered.\n", + "\n", + "3. compute the pair-wise similarity among the time series. In our case, we run a linear-time approximation of the dynamic time warping, still on the classical computer.\n", + "\n", + "4. compute the actual portfolio of $q$ representative assets, based on the similarity measure. This step is run twice, actually. First, we obtain a reference value by a run of an IBM solver (IBM ILOG CPLEX or the Exact Eigensolver) on the classical computer. Second, we run an alternative, hybrid algorithm partly on the quantum computer.\n", + "\n", + "5. visualisation of the results. In our case, this is again a simplistic plot.\n", + "\n", + "In the following, we first explain the model used in (4) above, before we proceed with the installation of the pre-requisites and the data loading.\n", + "\n", + "\n", + "## The Model\n", + "\n", + "As discussed in [Cornuejols & Tutuncu, 2006], we describe a mathematical model that clusters assets into groups of similar ones and selects one representative asset from each group to be included in the index fund portfolio. The model is based on the following data, which we will discuss in more detail later:\n", + "\n", + "$$\n", + "\\rho_{ij} = \\textrm{similarity}\\, \\textrm{between}\\, \\textrm{stock}\\, i \\, \\textrm{and}\\, \\textrm{stock}\\, j.\n", + "$$\n", + "\n", + "For example, $\\rho_{ii} = 1$, $\\rho_{ij} \\leq 1$ for $i \\neq j$ and $\\rho_{ij}$ is larger for more similar stocks. An example of this is the correlation between the returns of stocks $i$ and $j$. But one could choose other similarity indices $\\rho_{ij}$.\n", + "\n", + "The problem that we are interested in solving is:\n", + "\n", + "$$\n", + "(M) \\quad f = \\max_{x_{ij}, y_{j}} \\,\\, \\sum_{i=1}^n \\sum_{j=1}^n \\rho_{ij} x_{ij}\n", + "$$\n", + "\n", + "subject to the clustering constraint:\n", + "\n", + "$$\n", + "\\sum_{j=1}^n y_j = q,\n", + "$$\n", + "\n", + "to consistency constraints:\n", + "\n", + "$$\n", + "\\sum_{j=1}^n x_{ij} = 1, \\,\\textrm{ for }\\, i = 1,\\ldots, n,\n", + "\\quad x_{ij} \\leq y_j,\\,\\textrm{ for }\\, i = 1,\\ldots, n; \\, j = 1,\\ldots, n,\n", + "\\quad x_{jj} = y_j,\\,\\textrm{ for }\\, j = 1,\\ldots, n,\n", + "$$\n", + "\n", + "and integral constraints:\n", + "\n", + "$$\n", + "\\quad x_{ij}, y_j \\in\\{0,1\\}, \\,\\textrm{ for }\\, i = 1,\\ldots, n; \\, j = 1,\\ldots, n.\n", + "$$\n", + "\n", + "The variables $y_j$ describe which stocks $j$ are in the index fund ($y_j = 1$ if $j$ is selected in the fund, $0$ otherwise). For each stock $i = 1,\\dots,n$, the variable $x_{ij}$ indicates which stock $j$ in the index fund is most similar to $i$ ($x_{ij} = 1$ if $j$ is the most similar stock in the index fund, $0$ otherwise).\n", + "\n", + "The first constraint selects $q$ stocks in the fund. The second constraint imposes that each stock $i$ has exactly one representative stock $j$ in the fund. The third and fourth constraints guarantee that stock $i$ can be represented by stock $j$ only if $j$ is in the fund. The objective of the model maximizes the similarity between the $n$ stocks and their representatives in the fund. Different cost functions can also be considered. \n", + "\n", + "Let us concatenate the decision variables in one vector \n", + "\n", + "$$\n", + "{\\bf z} = [x_{11},x_{12},\\ldots,x_{11}, x_{22},\\ldots,x_{nn}, y_{1},\\ldots,y_{n}],\n", + "$$\n", + "\n", + "whose dimension is ${\\bf z} \\in \\{0,1\\}^N$, with $N = n (n+1)$ and denote the optimal solution with ${\\bf z}^*$, and the optimal cost $f^*$. \n", + "\n", + "\n", + "## A Hybrid Approach\n", + "\n", + "Here, we demonstrate an approach that combines classical and quantum computing steps, following the quantum approximate optimization approach of Farhi, Goldstone, and Gutman (2014). \n", + "\n", + "### Construct a binary polynomial optimization\n", + "\n", + "From $(M)$ one can construct a binary polynomial optimization with equality constraints only, by substituting the $x_{ij} \\leq y_j$ inequality constraints with the equivalent equality constraints $x_{ij} (1- y_j) = 0$. Then the problem becomes:\n", + "\n", + "$$\n", + "(BPO) \\quad f = \\max_{x_{ij}, y_{j}} \\,\\, \\sum_{i=1}^n \\sum_{j=1}^n \\rho_{ij} x_{ij}\n", + "$$\n", + "\n", + "subject to the clustering constrain, the integral constraints, and the following modified consistency constraints:\n", + "\n", + "$$\\sum_{j=1}^n x_{ij} = 1, \\,\\textrm{ for }\\, i = 1,\\ldots, n,$$\n", + "$$\\quad x_{ij} (1- y_j) = 0,\\,\\textrm{ for }\\, i = 1,\\ldots, n; \\, j = 1,\\ldots, n,$$\n", + "$$\\quad x_{jj} = y_j,\\,\\textrm{ for }\\, j = 1,\\ldots, n.$$\n", + "\n", + "### Construct the Ising Hamiltonian\n", + "\n", + "We can now construct the Ising Hamiltonian (QUBO) by penalty methods (introducting a penalty coefficient $A$ for each equality constraint) as\n", + "\n", + "$$\n", + "(IH) \\quad H = \\sum_{i=1}^n \\sum_{j=1}^n \\rho_{ij} x_{ij} + A\\Big( \\sum_{j=1}^n y_j - q\\Big)^2 + \\sum_{i=1}^n A\\Big( \\sum_{j=1}^n x_{ij} - 1\\Big)^2 + \\sum_{j=1}^n A (x_{jj}-y_j)^2 +\\sum_{i=1}^n \\sum_{j=1}^n A \\left(x_{ij} (1- y_j)\\right).\n", + "$$\n", + "\n", + "### From Hamiltonian to Quadratic Programming (QP) formulation \n", + "\n", + "In the vector ${\\bf z}$, the Ising Hamiltonian elements can be rewritten as follows,\n", + "\n", + "First term:\n", + "\n", + "$$\n", + "\\sum_{i=1}^n \\sum_{j=1}^n \\rho_{ij} x_{ij} = [\\rho_{11},\\rho_{12},\\ldots,\\rho_{11}, \\rho_{22},\\ldots,\\rho_{nn}|{\\bf 0}_n ]{\\bf z} =: {\\bf c}_0^T {\\bf z}\n", + "$$\n", + "\n", + "Second term:\n", + "\n", + "$$\n", + "A\\Big( \\sum_{j=1}^n y_j - q\\Big)^2 = A \\Big(\\sum_{j=1}^n y_j\\Big)^2 - 2 A \\sum_{j=1}^n y_j + A q^2 = A {\\bf z}^T \\left[\\begin{array}{c}{\\bf 0}_{n^2} \\\\ \\hline {\\bf 1}_n \\end{array}\\right]\\left[\\begin{array}{cc}{\\bf 0}_{n^2} | {\\bf 1}_n \\end{array}\\right]{\\bf z} - 2 A q [{\\bf 0}_{n^2}|{\\bf 1}_n]{\\bf z} + A q^2 =: {\\bf z}^T {\\bf Q}_0 {\\bf z} + {\\bf c}_1^T {\\bf z} + r_0\n", + "$$\n", + "\n", + "Third term:\n", + "\n", + "$$\n", + "\\sum_{i=1}^n A\\Big( \\sum_{j=1}^n x_{ij} - 1\\Big)^2 = A\\sum_{i=1}^n \\Big(\\sum_{j=1}^n x_{ij}\\Big)^2 - 2 A \\sum_{i=1}^n\\sum_{j=1}^n x_{ij} + n A = \\qquad\\qquad\\qquad\\qquad\\qquad\\qquad\\qquad $$\n", + "\n", + "which is equivalent to: \n", + "\n", + "$$\n", + "\\qquad\\qquad\\qquad\\qquad\\qquad\\qquad\\qquad = A {\\bf z}^T \\left(\\sum_{i=1}^n \\left[\\begin{array}{c}{\\bf 0}_{n(i-1)} \\\\ {\\bf 1}_n \\\\ {\\bf 0}_{n(n-i)} \\\\ \\hline {\\bf 0}_{n} \\end{array}\\right]\\left[\\begin{array}{cccc}{\\bf 0}_{n(i-1)} & {\\bf 1}_n & {\\bf 0}_{n(n-i)} & | {\\bf 0}_{n} \\end{array}\\right]\\right){\\bf z} - 2 A [{\\bf 1}_{n^2}|{\\bf 0}_n]{\\bf z} + n A =: {\\bf z}^T {\\bf Q}_1 {\\bf z} + {\\bf c}_2^T {\\bf z} + r_1\n", + "$$\n", + "\n", + "Fourth term:\n", + "\n", + "$$\n", + "A \\sum_{j=1}^n (x_{jj}-y_j)^2 = A {\\bf z}^T \\left(\\sum_{j=0}^{n-1} \\left[\\begin{array}{c}{\\bf 0}_{nj + j} \\\\ 1 \\\\ {\\bf 0}_{n^2-(nj+j+1)} \\\\ \\hline {\\bf 0}_{j} \\\\ -1 \\\\ {\\bf 0}_{n-j-1} \\end{array}\\right]\\left[\\begin{array}{cccccc}{\\bf 0}_{nj + j} & 1 & {\\bf 0}_{n^2-(nj+j+1)} & | {\\bf 0}_{j} & -1 & {\\bf 0}_{n-j-1} \\end{array}\\right]\\right){\\bf z} = A {\\bf z}^T {\\bf Q}_2 {\\bf z}\n", + "$$\n", + "\n", + "Fifth term:\n", + "\n", + "$$\n", + "\\sum_{i=1}^n \\sum_{j=1}^n A \\left(x_{ij} (1- y_j)\\right) = A [{\\bf 1}_{n^2}|{\\bf 0}_n]{\\bf z} + A {\\bf z}^T \\left( \\sum_{i=1}^n \\sum_{j=1}^n \\left[\\begin{array}{ccc|c} & & & \\\\ & {\\bf 0}_{n^2\\times n^2} & & -1/2_{(ij,j)} \\\\ & & & \\\\ \\hline & -1/2_{(j, ij)} & & {\\bf 0}_{n} \\end{array}\\right] \\right) {\\bf z} =: {\\bf z}^T {\\bf Q}_3 {\\bf z} + {\\bf c}_3^T {\\bf z}\n", + "$$\n", + "\n", + "Therefore, the formulation becomes,\n", + "\n", + "$$\n", + "(IH-QP)\\quad \\max_{{\\bf z}\\in\\{0,1\\}^{n(n+1)}} \\, {\\bf z}^T ({\\bf Q}_0+{\\bf Q}_1+ {\\bf Q}_2 + {\\bf Q}_3 ){\\bf z} + ({\\bf c}_0+{\\bf c}_1+{\\bf c}_2+{\\bf c}_3)^T {\\bf z} +r_0+r_1+r_2$$\n", + "\n", + "which can be passed to variational quantum eigensolver. \n", + "\n", + "\n", + "\n", + "## References\n", + "\n", + "[1] G. Cornuejols, M. L. Fisher, and G. L. Nemhauser, *Location of bank accounts to optimize float: an analytical study of exact and approximate algorithms*, Management Science, vol. 23(8), 1997\n", + "\n", + "[2] E. Farhi, J. Goldstone, S. Gutmann e-print arXiv 1411.4028, 2014\n", + "\n", + "[3] G. Cornuejols and R. Tutuncu, *Optimization methods in finance*, 2006\n", + "\n", + "[4] DJ. Berndt and J. Clifford, *Using dynamic time warping to find patterns in time series*. In KDD workshop 1994 (Vol. 10, No. 16, pp. 359-370).\n", + "\n", + "[5] https://github.com/Qiskit/qiskit-tutorial/blob/master/qiskit/aqua/optimization/maxcut_and_tsp.ipynb" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## The Implementation\n", + "\n", + "First, we import the requisite modules." + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [], + "source": [ + "# Import requisite modules\n", + "import math\n", + "import operator\n", + "import logging\n", + "import traceback\n", + "import datetime\n", + "import sys\n", + "import warnings\n", + "warnings.filterwarnings(\"error\") \n", + "warnings.filterwarnings(\"ignore\", category=DeprecationWarning)\n", + "import numpy as np\n", + "import matplotlib.pyplot as plt\n", + "%matplotlib inline\n", + "\n", + "# Import Qiskit packages\n", + "warnings.filterwarnings('ignore')\n", + "import qiskit \n", + "from qiskit import BasicAer\n", + "from qiskit.aqua import QuantumInstance\n", + "from qiskit.aqua import Operator, run_algorithm\n", + "from qiskit.aqua.input import EnergyInput\n", + "from qiskit.aqua.algorithms import VQE, QAOA, ExactEigensolver\n", + "from qiskit.aqua.components.optimizers import COBYLA\n", + "from qiskit.aqua.components.variational_forms import RY\n", + "# setup aqua logging\n", + "from qiskit.aqua._logging import set_logging_config, build_logging_config\n", + "# set_logging_config(build_logging_config(logging.DEBUG)) # choose INFO, DEBUG to see the log\n", + "\n", + "# The data providers of stock-market data\n", + "from qiskit.aqua.translators.data_providers import *\n", + "from qiskit.aqua.translators.data_providers.wikipediadataprovider import StockMarket\n", + "from qiskit.aqua.translators.ising import portfoliodiversification" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Next, we download price data for two stocks and compute their pair-wise similarity matrix (dynamic time warping distance normalised to (0,1] by taking the reciprocal). If this fails, e.g., due to your being offline or exeeding the daily limit for accesses to the stock-market data, we consider a constant matrix instead." + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "metadata": { + "scrolled": true + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Cannot load real data. This may happen with over 50 accesses per day, for instnace. Using a constant rho.\n" + ] + } + ], + "source": [ + "# Generate a pairwise time-series similarity matrix\n", + "stocks = [\"GOOG\", \"AAPL\"]\n", + "n = len(stocks)\n", + "rho = np.ones((n,n))\n", + "rho[0,1] = 0.8\n", + "rho[1,0] = 0.8\n", + "\n", + "try:\n", + " wiki = WikipediaDataProvider(token = \"\",\n", + " tickers = stocks,\n", + " stockmarket = StockMarket.NASDAQ.value,\n", + " start = datetime.datetime(2016,1,1),\n", + " end = datetime.datetime(2016,1,30))\n", + " wiki.run()\n", + " rho = wiki.get_similarity_matrix()\n", + "except Exception as e:\n", + " print(\"Cannot load real data. This may happen with over 50 accesses per day, for instnace. Using a constant rho.\")\n", + "\n", + "# Actually, we consider the additive inverse to invert the direction of optimisation. \n", + "rho = -1 * rho" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now we decide on the number of clusters. This has to be smaller than the number of stocks we have loaded." + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "metadata": {}, + "outputs": [], + "source": [ + "q = 1 # q less or equal than wiki._n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Classical solution using IBM ILOG CPLEX\n", + "\n", + "For a classical solution, we use IBM CPLEX. CPLEX is able to find the exact solution of this problem. We first define a ClassicalOptimizer class that encodes the problem in a way that CPLEX can solve, and then instantiate the class and solve it. \n" + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "metadata": {}, + "outputs": [], + "source": [ + "class ClassicalOptimizer:\n", + " def __init__(self, rho, n, q):\n", + "\n", + " self.rho = rho\n", + " self.n = n # number of inner variables\n", + " self.q = q # number of required selection\n", + "\n", + " def compute_allowed_combinations(self):\n", + " f = math.factorial\n", + " return int(f(self.n) / f(self.q) / f(self.n - self.q))\n", + "\n", + " def cplex_solution(self):\n", + "\n", + " # refactoring\n", + " rho = self.rho\n", + " n = self.n\n", + " q = self.q\n", + "\n", + " my_obj = list(rho.reshape(1, n ** 2)[0]) + [0. for x in range(0, n)]\n", + " my_ub = [1 for x in range(0, n ** 2 + n)]\n", + " my_lb = [0 for x in range(0, n ** 2 + n)]\n", + " my_ctype = \"\".join(['I' for x in range(0, n ** 2 + n)])\n", + "\n", + " my_rhs = [q] + [1 for x in range (0, n)] +[0 for x in range (0, n)] + [0.1 for x in range(0, n ** 2)]\n", + " my_sense = \"\".join(['E' for x in range(0, 1+n)]) + \"\".join(['E' for x in range(0, n)]) + \"\".join(\n", + " ['L' for x in range(0, n ** 2)])\n", + "\n", + " try:\n", + " my_prob = cplex.Cplex()\n", + " self.populatebyrow(my_prob, my_obj, my_ub, my_lb, my_ctype, my_sense, my_rhs)\n", + "\n", + " my_prob.solve()\n", + "\n", + " except CplexError as exc:\n", + " print(exc)\n", + " return\n", + "\n", + " x = my_prob.solution.get_values()\n", + " x = np.array(x)\n", + " cost = my_prob.solution.get_objective_value()\n", + "\n", + " return x, cost\n", + "\n", + " def populatebyrow(self, prob, my_obj, my_ub, my_lb, my_ctype, my_sense, my_rhs):\n", + "\n", + " n = self.n\n", + "\n", + " prob.objective.set_sense(prob.objective.sense.minimize)\n", + " prob.variables.add(obj=my_obj, lb=my_lb, ub=my_ub, types=my_ctype)\n", + "\n", + " prob.set_log_stream(None)\n", + " prob.set_error_stream(None)\n", + " prob.set_warning_stream(None)\n", + " prob.set_results_stream(None)\n", + "\n", + " rows = []\n", + " col = [x for x in range(n**2, n**2+n)]\n", + " coef = [1 for x in range(0, n)]\n", + " rows.append([col, coef])\n", + "\n", + " for ii in range(0, n):\n", + " col = [x for x in range(0+n*ii, n+n*ii)]\n", + " coef = [1 for x in range(0, n)]\n", + "\n", + " rows.append([col, coef])\n", + "\n", + " for ii in range(0, n):\n", + " col = [ii * n + ii, n ** 2 + ii]\n", + " coef = [1, -1]\n", + " rows.append([col, coef])\n", + "\n", + " for ii in range(0, n):\n", + " for jj in range(0, n):\n", + " col = [ii*n + jj, n ** 2 + jj]\n", + " coef = [1, -1]\n", + "\n", + " rows.append([col, coef])\n", + " \n", + " prob.linear_constraints.add(lin_expr=rows, senses=my_sense, rhs=my_rhs)" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Number of feasible combinations= 2\n", + "Total number of combinations= 64\n" + ] + } + ], + "source": [ + "# Instantiate the classical optimizer class\n", + "classical_optimizer = ClassicalOptimizer(rho, n, q)\n", + "\n", + "# Compute the number of feasible solutions:\n", + "print('Number of feasible combinations= ' + str(classical_optimizer.compute_allowed_combinations()))\n", + "\n", + "# Compute the total number of possible combinations (feasible + unfeasible)\n", + "print('Total number of combinations= ' + str(2 ** (n*(n+1))))" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "metadata": {}, + "outputs": [], + "source": [ + "# Visualize the solution\n", + "\n", + "def visualize_solution(xc, yc, x, C, n, K, title_str):\n", + " plt.figure()\n", + " plt.scatter(xc, yc, s=200)\n", + " for i in range(len(xc)):\n", + " plt.annotate(i, (xc[i] + 0.015, yc[i]), size=16, color='r')\n", + " \n", + " plt.grid()\n", + "\n", + " for ii in range(n ** 2, n **2 + n):\n", + "\n", + " if x[ii] > 0:\n", + " plt.plot(xc[ii-n**2], yc[ii-n**2], 'r*', ms=20)\n", + "\n", + " for ii in range(0, n ** 2):\n", + "\n", + " if x[ii] > 0:\n", + " iy = ii // n\n", + " ix = ii % n\n", + " plt.plot([xc[ix], xc[iy]], [yc[ix], yc[iy]], 'C2')\n", + "\n", + " plt.title(title_str +' cost = ' + str(int(C * 100) / 100.))\n", + " plt.show()\n", + " " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Solution shows the selected stocks via the stars and in green the links (via similarities) with other stocks that are represented in the fund by the linked stock. " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Quantum Computing with IBM Q\n", + "\n", + "For the quantum solution, we use Qiskit. We first define a class QuantumOptimizer that encodes the quantum approach to solve the problem and then we instantiate it and solve it. We define the following methods inside the class:\n", + "- `construct_hamiltonian` : constructs the Ising Hamiltonian in terms of the $Z$ basis using the Ising translator provided in Qiskit Aqua;\n", + "- `exact_solution` : to make sure that the Ising Hamiltonian is correctly encoded in the $Z$ basis, we can compute its eigendecomposition classicaly, i.e., considering a symmetric matrix of dimension $2^N \\times 2^N$. For the problem at hand $n=3$, that is $N = 12$ seems the limit for many laptops; \n", + "- `vqe_solution` : solves the problem $(M)$ via the variational quantum eigensolver (VQE);\n", + "- `qaoa_solution` : solves the problem $(M)$ via a Quantum Approximate Optimization Algorithm (QAOA)." + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "metadata": {}, + "outputs": [], + "source": [ + "class QuantumOptimizer:\n", + "\n", + " def __init__(self, rho, n, q):\n", + "\n", + " self.rho = rho\n", + " self.n = n\n", + " self.q = q\n", + "\n", + " def construct_hamiltonian(self):\n", + " return portfoliodiversification.get_portfoliodiversification_qubitops(self.rho, self.n, self.q)\n", + "\n", + " # Obtains the least eigenvalue of the Hamiltonian classically\n", + " def exact_solution(self):\n", + " qubitOp = self.construct_hamiltonian()\n", + " algo_input = EnergyInput(qubitOp)\n", + " algorithm_cfg = {\n", + " 'name': 'ExactEigensolver',\n", + " }\n", + " params = {\n", + " 'problem': {'name': 'ising'},\n", + " 'algorithm': algorithm_cfg\n", + " }\n", + " result = run_algorithm(params, algo_input)\n", + " return self.decode_result(result)\n", + "\n", + " def vqe_solution(self):\n", + " qubitOp = self.construct_hamiltonian()\n", + " backend = BasicAer.get_backend('statevector_simulator')\n", + " seed = 50\n", + " cobyla = COBYLA()\n", + " cobyla.set_options(maxiter=250)\n", + " ry = RY(qubitOp.num_qubits, depth=5, entanglement='full')\n", + " vqe = VQE(qubitOp, ry, cobyla, 'matrix')\n", + " vqe.random_seed = seed\n", + " quantum_instance = QuantumInstance(backend=backend, seed=seed, seed_mapper=seed)\n", + " result = vqe.run(quantum_instance)\n", + " return self.decode_result(result)\n", + " \n", + " def qaoa_solution(self):\n", + " qubitOp = self.construct_hamiltonian()\n", + " backend = BasicAer.get_backend('statevector_simulator')\n", + " seed = 50\n", + " cobyla = COBYLA()\n", + " cobyla.set_options(maxiter=250)\n", + " qaoa = QAOA(qubitOp, cobyla, 3, 'matrix')\n", + " qaoa.random_seed = seed\n", + " quantum_instance = QuantumInstance(backend=backend, seed=seed, seed_mapper=seed)\n", + " result = qaoa.run(quantum_instance)\n", + " return self.decode_result(result)\n", + "\n", + " def decode_result(self, result, offset = 0):\n", + " quantum_solution = portfoliodiversification.get_portfoliodiversification_solution(self.rho, self.n, self.q, result)\n", + " ground_level = portfoliodiversification.get_portfoliodiversification_value(self.rho, self.n, self.q, quantum_solution)\n", + " return quantum_solution, ground_level\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Step 1\n", + "\n", + "Instantiate the quantum optimizer class with parameters: \n", + "- the similarity matrix `rho`;\n", + "- the number of assets and clusters `n` and `q`;" + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "metadata": {}, + "outputs": [], + "source": [ + "# Instantiate the quantum optimizer class with parameters: \n", + "quantum_optimizer = QuantumOptimizer(rho, n, q)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Step 2\n", + "\n", + "Encode the problem as a binary formulation (IH-QP).\n", + "\n", + "Sanity check: make sure that the binary formulation in the quantum optimizer is correct (i.e., yields the same cost given the same solution)." + ] + }, + { + "cell_type": "code", + "execution_count": 28, + "metadata": {}, + "outputs": [], + "source": [ + "# Check if the binary representation is correct. This requires CPLEX\n", + "\n", + "try: \n", + " import cplex\n", + " warnings.filterwarnings('ignore')\n", + " quantum_solution, quantum_cost = quantum_optimizer.exact_solution()\n", + " classical_solution, classical_cost = classical_optimizer.cplex_solution()\n", + " print(quantum_cost, classical_cost)\n", + " if np.abs(quantum_cost - classical_cost) < 0.01:\n", + " print('Binary formulation is correct')\n", + " else: print('Error in the formulation of the Hamiltonian')\n", + "except: None" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Step 3\n", + "\n", + "Encode the problem as an Ising Hamiltonian in the Z basis. \n", + "\n", + "Sanity check: make sure that the formulation is correct (i.e., yields the same cost given the same solution)" + ] + }, + { + "cell_type": "code", + "execution_count": 29, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[0 1 0 1 0 1]\n" + ] + } + ], + "source": [ + "ground_state, ground_level = quantum_optimizer.exact_solution()\n", + "print(ground_state)\n", + "\n", + "try:\n", + " if np.abs(ground_level - classical_cost)<0.01:\n", + " print('Ising Hamiltonian in Z basis is correct')\n", + " else: print('Error in the Ising Hamiltonian formulation')\n", + "except: None" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Step 4\n", + "\n", + "Solve the problem via VQE. Notice that depending on the number of qubits, this can take a while: for 6 qubits it takes 15 minutes on a 2015 Macbook Pro, for 12 qubits it takes more than 12 hours. For longer runs, logging may be useful to observe the workings; otherwise, you just have to wait until the solution is printed." + ] + }, + { + "cell_type": "code", + "execution_count": 30, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[0 1 0 1 0 1]\n", + "VQE produces the same solution as the exact eigensolver.\n" + ] + } + ], + "source": [ + "warnings.filterwarnings('ignore')\n", + "vqe_state, vqe_level = quantum_optimizer.vqe_solution()\n", + "print(vqe_state)\n", + "\n", + "try:\n", + " if np.linalg.norm(ground_state - vqe_state)<0.01:\n", + " print('VQE produces the same solution as the exact eigensolver.')\n", + " else: print('VQE does not produce the same solution as the exact eigensolver, but that is to be expected.')\n", + "except: None" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Step 5\n", + "Visualize the solution" + ] + }, + { + "cell_type": "code", + "execution_count": 31, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "xc, yc = wiki.get_coordinates()\n", + "visualize_solution(xc, yc, ground_state, ground_level, n, q, 'Classical')\n", + "visualize_solution(xc, yc, vqe_state, vqe_level, n, q, 'VQE')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Solution shows the selected stocks via the stars and in green the links (via similarities) with other stocks that are represented in the fund by the linked stock. Keep in mind that VQE is an heuristic working on the QP formulation of the Ising Hamiltonian, though. For suitable choices of A, local optima of the QP formulation will be feasible solutions to the ILP. While for some small instances, as above, we can find optimal solutions of the QP formulation which coincide with optima of the ILP, finding optimal solutions of the ILP is harder than finding local optima of the QP formulation, in general. Even within the VQE, one may provide stronger guarantees, for specific variational forms (trial wave functions). " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "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.2" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +}