From 8951a919777ac283f4337fd5759e5395b669abc7 Mon Sep 17 00:00:00 2001 From: Omar Costa Hamido Date: Sat, 9 Mar 2019 14:04:15 -0800 Subject: [PATCH 01/22] slides typo corrections teach_me_quantum_2018/TeachMeQ/Week_0-Hello_Quantum_World/slides.pdf slides 9 and 12 --- .../TeachMeQ/Week_0-Hello_Quantum_World/latex/main.tex | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/community/awards/teach_me_quantum_2018/TeachMeQ/Week_0-Hello_Quantum_World/latex/main.tex b/community/awards/teach_me_quantum_2018/TeachMeQ/Week_0-Hello_Quantum_World/latex/main.tex index 51cf77a18..c22abb995 100755 --- a/community/awards/teach_me_quantum_2018/TeachMeQ/Week_0-Hello_Quantum_World/latex/main.tex +++ b/community/awards/teach_me_quantum_2018/TeachMeQ/Week_0-Hello_Quantum_World/latex/main.tex @@ -95,7 +95,7 @@ \section{\qp vs \cp} \begin{frame}{\qp} \begin{card} - \qp (also \qm) describes the world \textit{as we see it}, in its macro level. Some of its properties: + \qp (also \qm) describes the world \textit{as we see it}, in its micro level. Some of its properties: \begin{description} \item[size] objects with $size \lesssim 1nm$ \item[speed] objects of $speed \lesssim \speedoflight$ @@ -127,7 +127,7 @@ \subsubsection{\qsp} \cardImg{img/cat.png}{0.5\textwidth} \end{center} \begin{center} - To worlds, inside one. + Two worlds, inside one. \end{center} \pagenumber \end{frame} From 9c5bf570fe0a69b1210508e80bc8f204aeb70225 Mon Sep 17 00:00:00 2001 From: Omar Costa Hamido Date: Sat, 9 Mar 2019 20:08:19 -0800 Subject: [PATCH 02/22] typo correction small typos on the qiskit/basics/getting_started_with_qiskit.ipynb --- qiskit/basics/getting_started_with_qiskit.ipynb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qiskit/basics/getting_started_with_qiskit.ipynb b/qiskit/basics/getting_started_with_qiskit.ipynb index de3016282..88c121e68 100644 --- a/qiskit/basics/getting_started_with_qiskit.ipynb +++ b/qiskit/basics/getting_started_with_qiskit.ipynb @@ -205,7 +205,7 @@ "
\n", "\n", "\n", - "When representing the state of a multi-qubit system, the tensor order used in qiskit is different than that use in most physics textbooks. Suppose there are $n$ qubits, and qubit $j$ is labeled as $Q_{j}$. In most textbooks (such as Nielsen and Chuang's \"Quantum Computation and Information\"), the basis vectors for the $n$-qubit state space would be labeled as $Q_{0}\\otimes Q_{1} \\otimes \\cdots \\otimes Q_{n}$. **This is not the ordering used by qiskit!** Instead, qiskit uses an ordering in which the $n^{\\mathrm{th}}$ qubit is on the _left_ side of the tesnsor product, so that the basis vectors are labeled as $Q_n\\otimes \\cdots \\otimes Q_1\\otimes Q_0$.\n", + "When representing the state of a multi-qubit system, the tensor order used in qiskit is different than that use in most physics textbooks. Suppose there are $n$ qubits, and qubit $j$ is labeled as $Q_{j}$. In most textbooks (such as Nielsen and Chuang's \"Quantum Computation and Information\"), the basis vectors for the $n$-qubit state space would be labeled as $Q_{0}\\otimes Q_{1} \\otimes \\cdots \\otimes Q_{n}$. **This is not the ordering used by qiskit!** Instead, qiskit uses an ordering in which the $n^{\\mathrm{th}}$ qubit is on the **left** side of the tensor product, so that the basis vectors are labeled as $Q_n\\otimes \\cdots \\otimes Q_1\\otimes Q_0$.\n", "\n", "For example, if qubit zero is in state 0, qubit 1 is in state 0, and qubit 2 is in state 1, qiskit would represent this state as $|100\\rangle$, whereas most physics textbooks would represent it as $|001\\rangle$.\n", "\n", From 91b0d92a431169e8a0e09b91f127f7fc78a7485f Mon Sep 17 00:00:00 2001 From: Omar Costa Hamido Date: Sat, 9 Mar 2019 20:09:43 -0800 Subject: [PATCH 03/22] bold and italic correction bold and italic now correctly applied. --- qiskit/basics/getting_started_with_qiskit.ipynb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qiskit/basics/getting_started_with_qiskit.ipynb b/qiskit/basics/getting_started_with_qiskit.ipynb index 88c121e68..fadef5fd1 100644 --- a/qiskit/basics/getting_started_with_qiskit.ipynb +++ b/qiskit/basics/getting_started_with_qiskit.ipynb @@ -205,7 +205,7 @@ "
\n", "\n", "\n", - "When representing the state of a multi-qubit system, the tensor order used in qiskit is different than that use in most physics textbooks. Suppose there are $n$ qubits, and qubit $j$ is labeled as $Q_{j}$. In most textbooks (such as Nielsen and Chuang's \"Quantum Computation and Information\"), the basis vectors for the $n$-qubit state space would be labeled as $Q_{0}\\otimes Q_{1} \\otimes \\cdots \\otimes Q_{n}$. **This is not the ordering used by qiskit!** Instead, qiskit uses an ordering in which the $n^{\\mathrm{th}}$ qubit is on the **left** side of the tensor product, so that the basis vectors are labeled as $Q_n\\otimes \\cdots \\otimes Q_1\\otimes Q_0$.\n", + "When representing the state of a multi-qubit system, the tensor order used in qiskit is different than that use in most physics textbooks. Suppose there are $n$ qubits, and qubit $j$ is labeled as $Q_{j}$. In most textbooks (such as Nielsen and Chuang's \"Quantum Computation and Information\"), the basis vectors for the $n$-qubit state space would be labeled as $Q_{0}\\otimes Q_{1} \\otimes \\cdots \\otimes Q_{n}$. **This is not the ordering used by qiskit!** Instead, qiskit uses an ordering in which the $n^{\\mathrm{th}}$ qubit is on the left side of the tensor product, so that the basis vectors are labeled as $Q_n\\otimes \\cdots \\otimes Q_1\\otimes Q_0$.\n", "\n", "For example, if qubit zero is in state 0, qubit 1 is in state 0, and qubit 2 is in state 1, qiskit would represent this state as $|100\\rangle$, whereas most physics textbooks would represent it as $|001\\rangle$.\n", "\n", From aa29bec2837c1ef52a0cf0133a0e2caca427cd88 Mon Sep 17 00:00:00 2001 From: Omar Costa Hamido Date: Sun, 10 Mar 2019 10:48:04 -0700 Subject: [PATCH 04/22] punctuation comma to collon --- qiskit/basics/getting_started_with_qiskit.ipynb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qiskit/basics/getting_started_with_qiskit.ipynb b/qiskit/basics/getting_started_with_qiskit.ipynb index fadef5fd1..cb2d521b9 100644 --- a/qiskit/basics/getting_started_with_qiskit.ipynb +++ b/qiskit/basics/getting_started_with_qiskit.ipynb @@ -588,7 +588,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "After generating your API token, call, `IBMQ.save_account('MY_TOKEN')`. For Q Network users, you'll also need to include your access url: `IBMQ.save_account('MY_TOKEN', 'URL')`\n", + "After generating your API token, call: `IBMQ.save_account('MY_TOKEN')`. For Q Network users, you'll also need to include your access url: `IBMQ.save_account('MY_TOKEN', 'URL')`\n", "\n", "This will store your IBMQ credentials in a local file. Unless your registration information has changed, you only need to do this once. You may now load your accounts by calling," ] From a21c562accf88c1fd1066aeef34809b5254f2d45 Mon Sep 17 00:00:00 2001 From: Omar Costa Hamido Date: Sun, 10 Mar 2019 23:29:04 -0700 Subject: [PATCH 05/22] Update README.md trying to fix the binder notebooks --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 692fdfd6c..1b9cab408 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-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 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/omarcostahamido/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. Please refer to this [installation guide](INSTALL.md) for setting up Qiskit and the tutorials on your own machine (this is the recommended way). From ed3ca60941773dcf3966f12e148f3eacc6e499cd Mon Sep 17 00:00:00 2001 From: Omar Costa Hamido Date: Sun, 10 Mar 2019 23:29:48 -0700 Subject: [PATCH 06/22] binder fixes trying to fix the binder notebooks --- environment.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/environment.yml b/environment.yml index 526b5ccf8..9c89d07cc 100644 --- a/environment.yml +++ b/environment.yml @@ -1,6 +1,6 @@ name: Qiskitenv dependencies: -- python=3 +- python==3.6 - pip=18 - matplotlib - notebook From 3686ae3e894e8f7ab268c5aa61d63630230a5f6f Mon Sep 17 00:00:00 2001 From: Omar Costa Hamido Date: Mon, 11 Mar 2019 00:03:09 -0700 Subject: [PATCH 07/22] fixing binder i think i could fix the binder issues. simply by using lowercase on the username "qiskit" and correcting the the path to (...)tutorials instead of (...)tutorial forced it to rebuild the binder image. :) if this alone is not enough then we may try to specify python==3.6, because one guy here (https://gitter.im/jupyterhub/binder) was able to make it work just by doing so. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 1b9cab408..567160359 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/omarcostahamido/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-tutorial/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). From eda5a3b52a14d03285b64c02812666bcab232493 Mon Sep 17 00:00:00 2001 From: Omar Costa Hamido Date: Mon, 11 Mar 2019 20:54:47 -0700 Subject: [PATCH 08/22] fixing links weirdly enough they may still work as it is but I think it is best to keep everything consistent, and have them refer to the correct repo directory which is qiskit-tutorials and not qiskit-tutorial. --- index.ipynb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) 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." ] }, { From 0c05c54294d468fa8c3faa24aa4b7321f42d6fce Mon Sep 17 00:00:00 2001 From: Omar Costa Hamido Date: Mon, 11 Mar 2019 20:57:08 -0700 Subject: [PATCH 09/22] fixing links again, qiskit-tutorials instead of qikit-tutorial --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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). From 6b9bfd21f7acd4d19721f6a9c2937424de9dc9ab Mon Sep 17 00:00:00 2001 From: Matteo AC Rossi Date: Mon, 18 Mar 2019 19:39:36 +0200 Subject: [PATCH 10/22] qiskit.backends -> qiskit.providers --- community/terra/qis_intro/entanglement_testing.ipynb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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", From 9f4f8b8c2a0977f8fe7ec9a12a7062b81ac74c3b Mon Sep 17 00:00:00 2001 From: James Wootton Date: Wed, 20 Mar 2019 15:01:47 +0100 Subject: [PATCH 11/22] Random Terrain Generation (#568) * Add terrain generation notebook * Update README.md --- community/games/README.md | 4 +- .../games/random_terrain_generation.ipynb | 793 ++++++++++++++++++ 2 files changed, 796 insertions(+), 1 deletion(-) create mode 100644 community/games/random_terrain_generation.ipynb 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": "iVBORw0KGgoAAAANSUhEUgAAAXQAAAD8CAYAAABn919SAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADl0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uIDIuMi4zLCBodHRwOi8vbWF0cGxvdGxpYi5vcmcvIxREBQAABoBJREFUeJzt3N1x4koUhVHJdVMA8s8O4xiEbgKu4rRHf717rWcVmEb67HmYPa/rOgHQv6+zfwAAtiHoACEEHSCEoAOEEHSAEIIOEELQAUIIOkAIQQcI8d+RbzbP83Oapsen657P5/t+v5d+2Twej/fPz0/l2vdU/wVWvdZrnvOaaZ+nfO3393f52bjf71HPRvWzN3zu8ns3XLfLa67rOleum4/8r//zPJfe7P1+l1/z68s/MhhHy/M6z6UGdKP62dM+9zTVg66GACEEHSCEoAOEEHSAEIIOEELQAUIIOkAIQQcIIegAIQQdIISgA4QQdIAQRwe9tLr1fD7LL3i73f78w3At1VGlkQfZ9ng2Wsaszjz76mfvpQl7jIhdcm2RMVVXNlsehMTlva21rJtWz9O5f9bYXmuLACMRdIAQgg4QQtABQgg6QAhBBwgh6AAhBB0ghKADhBB0gBCCDhBC0AFCXHJtsYURoBzVNb1lWcqv2cvy3plaFhyrZ+/cP2s596ru1xarS3EjT64CfVvX1doiwEgEHSCEoAOEEHSAEIIOEELQAUIIOkAIQQcIIegAIQQdIISgA4S45DhXy+BWdeDGWFCOPQbZjLxtq+U87Sxt55LjXC0/kwdxPNVBtmmqx2KP1xxZyzNcvXbkczfOBTAYQQcIIegAIQQdIISgA4QQdIAQgg4QQtABQgg6QAhBBwgh6AAhBB0gxCXXFqsLitN07oqiYbBz7HF/nH3Ppd1LLee5LEvpOs/6Z5dcW+yFVUi2Ur2X3EfnOHuN09oiwGAEHSCEoAOEEHSAEIIOEELQAUIIOkAIQQcIIegAIQQdIISgA4S45DhXizO3Lc4edCJH9V5quY/svmynl2e9+3Euo0bwu+qg1B5jUmzLOBfAYAQdIISgA4QQdIAQgg4QQtABQgg6QAhBBwgh6AAhBB0ghKADhBB0gBDdry3usVIHCSw4XtseZ9n92iJwHAuO26me5TRN01ysv1MHCCHoACEEHSCEoAOEEHSAEIIOEELQAUIIOkAIQQcIIegAIQQdIET341yco2VYyK7HZ72MXvUwhtfLvVk9yxbGufiTPe6bXqK2B6NX22kZvao6+9zXdTXOBTASQQcIIegAIQQdIISgA4QQdIAQgg4QQtABQgg6QAhBBwgh6AAhBB0ghLVF/qRlKW5ZltJ1Zy70na2HFcMWZw6tjXxvWlsENtfSlZFXNqusLQIMRtABQgg6QAhBBwgh6AAhBB0ghKADhBB0gBCCDhBC0AFCCDpACEEHCGFt8RfGguDftCwe9rBk2NKEr6/z/k62tviL6pkIP4yhpZPVa1vCb20RYDCCDhBC0AFCCDpACEEHCCHoACEEHSCEoAOEEHSAEIIOEELQAUJccpzr7I2U6rBQD6NCwL9rGRtblqV03R79uOQ41/tdH2U8c9kM4AjGuQAGI+gAIQQdIISgA4QQdIAQgg4QQtABQgg6QAhBBwgh6AAhBB0ghKADhLjk2mLLspnFQ67q7NXQXmx9Ti2vlzbud8m1RUhgNbSmek7VM2o596qzvx9riwCDEXSAEIIOEELQAUIIOkAIQQcIIegAIQQdIISgA4QQdIAQgg4Q4pLjXCMbedAp7bMbmaupntPj8Shd93q9yu+9LEvpul6+H+NcF9PyfaQFcOuRJrLs0apeniHjXACDEXSAEIIOEELQAUIIOkAIQQcIIegAIQQdIISgA4QQdIAQgg4QQtABQhwa9NvtZm3xgz0W+noZIKqu5FVX99jeHvdS9TWrz0Z1QXGa+llRrDp0bXGaptKb9RKgXvSy4Djyml4vqt9Ry7lb2fzM2iLAYAQdIISgA4QQdIAQgg4QQtABQgg6QAhBBwgh6AAhBB0ghKADhBB0gBCHBv31epVWeFoW0IwvfbbHguMerOldX3URs+Xcq9+77/KzQ9cW53ne/M0stcFx9lhb5DNriwCDEXSAEIIOEELQAUIIOkAIQQcIIegAIQQdIISgA4QQdIAQgg4Q4uig14ZXGhj2gd/tsafiebu27se5gN8Z0sphnAtgMIIOEELQAUIIOkAIQQcIIegAIQQdIISgA4QQdIAQgg4QQtABQgg6QIhDx7kA2I+/0AFCCDpACEEHCCHoACEEHSCEoAOEEHSAEIIOEELQAUIIOkAIQQcIIegAIQQdIISgA4QQdIAQgg4QQtABQgg6QAhBBwgh6AAhBB0ghKADhBB0gBD/A58quWxRNrPLAAAAAElFTkSuQmCC\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": "iVBORw0KGgoAAAANSUhEUgAAAXQAAAD8CAYAAABn919SAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADl0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uIDIuMi4zLCBodHRwOi8vbWF0cGxvdGxpYi5vcmcvIxREBQAAEkBJREFUeJzt3EmPlAXXxvFTPVVP0PbIjEyCDIobiUPiRleuXLryy/iJXLslMUYiMRGUJjI20MjU9EQ31VX1LN64fMP/vG9X8Xjy/61Pzl33dFWlFlej2+2GJOnfb+BtfwBJ0u4w0CWpCANdkoow0CWpCANdkoow0CWpCANdkoow0CWpCANdkooY6ufBvv/+++WI2PemudOnT3eGhobQl83Kykqn2+2+cXZ0dLTTaDTQzl9//bWzs7PzxtmrV6+iuYiI9fV19DlPnTqFz31jY6MT4Ev5xo0bnXa7jXbOz893BgcH3zj76aefdkZGRtDOY8eOoXOamJjoDAwMvHFuz549aC4i4vr16+jcz507h6/75cuXO61W642zs7Oz+HN+9tln6HrOzMzgne12Gz0fy8vLnU6ng3ZeuHChMzw8/MbZV69eoWNH8Odz//796NlsNpv4XX/48CE6959++gnd84iItbU19K5//vnn+B368ssvG2Su37/Q3xjmERH0xYqIIBcuIoLe4IgIGtJ0LoJ/zsy5B7x/NMwjIsgLExFBH8QIfk40qOhcBD/3zHWnL3bmc9LrmdkZ8PmgYR4RQcI8c+wIfo/os5l51+m503sewd/1zDtE+ZeLJBVhoEtSEQa6JBVhoEtSEQa6JBVhoEtSEQa6JBVhoEtSEQa6JBVhoEtSEQa6JBVhoEtSEX0N9G632yFzOzs7eGejgUrIotvt4p1DQ6yEks5lZM6dGhwcxLPtdhvNvX79Gu+k50TvUaeDHqOI4Oeeue7Dw8NoLvM56fXM7KQyfV+tVmvXj0/vEX02M+86PXd6zyN4JmXeIaqv9bm0sWxhYQHv3LcPFTjGzZs38c7V1VU01+l08APx/PlzNLe1tYXmIviDOzQ0lPryIS9Os9nE++ixjx49iuZWVlZwsNEAmpqaQnMRETMzM2hubW0N79zZ2UFfKrOzs/i+3717F83R84mIGB8fR3OZ523v3r1o7s6dO2juww8/xMemz1G328XnNDc3h+ZmZ2fRXIZ/uUhSEQa6JBVhoEtSEQa6JBVhoEtSEQa6JBVhoEtSEQa6JBVhoEtSEQa6JBVhoEtSEQa6JBXR10AfGRlBTTiZFjJaVJRpHKQlPJmdvWj92+1jR/Cyosw9oi159Nxpm10Ev5eZ86E7M5+THp9eywjeJJhpcNzt5swI/nzS65l5h+g1ypSN0XP/17ctfvXVV+jq0da9CN7+9vjxY7yz2WyiNsHR0VG889tvv0VzL1++xDvpy33+/Hm88+rVq2huc3MzNjc30Sxtz6QtebS5MoK3cd67dw/vpC2Gmed4cnISzU1MTOCdy8vLaO7w4cN458rKCprL/IgYGxvb1WPTTMjszLyX9Avl0aNHeOelS5fQnH+5SFIRBrokFWGgS1IRBrokFWGgS1IRBrokFWGgS1IRBrokFWGgS1IRBrokFWGgS1IRfQ30breLWoAyBUS0CGd4eBjvpLOZvopWq4XmMoVOVKZ8iZYQZQqQtre30RwtK8pcIzpLS5oi+POReY7p85HZST8nPXYEf98y5VzU2yxay5RzUb0o4utrOVer1UJvTaZchz7gmZ3dbhfdQBpUEbwo6dixY3gnDWp67IiIqakpNDc9PY130hKzjY2N2NjYeOMcLbKKiLh9+zaay3zh04KszDNHZwcGBnBYnjlzBs11Oh38LNOitbW1NTQXwYPtxIkTeCcNdfoc0/cigpe3zc/P452Uf7lIUhEGuiQVYaBLUhEGuiQVYaBLUhEGuiQVYaBLUhEGuiQVYaBLUhEGuiQVYaBLUhEGuiQV0e9AR21SvWh/yzQj0qKmTAMbLdLKtOlRvWhw7EWTIJ3LtEdm7jtF73vmc/aibfFt3/e3pRfXKPOu0+bOTLkf1de2xcnJSXSmV65cwTtHRkbQ3OHDh/FO2k64f/9+vHNlZQXNZR4c+sWTqTKl7XOZitILFy6guQcPHqC5zAt78OBBNLe4uIh30nbAmZkZvJM+x81mE+98+vQpmjt69Cje+fLlSzSXqSMeGxtDcy9evEBzmS9xej0zbYt//PEHmnv9+nXqPSL8y0WSijDQJakIA12SijDQJakIA12SijDQJakIA12SijDQJakIA12SijDQJakIA12SiuhroHdgW1GmB4L2lGT6P2i3RC/QnpAIfu6Zkia6M9MPs7m5ieYy952i9z1zbNoVkrmXdDbzHNPP2YvCrczzQWfpPerF+WT6YWgf0273uET0uZxrc3MT3ZGzZ8/u+rGXlpZS8yTUaZlURMTff/+N5s6ePYtb+mhQ/v7772guIuLdd99Fc9niKRJY9Ni0lCyCl26trq7ind1uF4VLu93G4UKPnwkrWrT26NEjvPPcuXNojhbcRUTcvXsXzR05cgTN3b9/Hx97fX0dzW1tbeGdtEWRHjvDv1wkqQgDXZKKMNAlqQgDXZKKMNAlqQgDXZKKMNAlqQgDXZKKMNAlqQgDXZKKMNAlqQgDXZKK6Gugt9tt1DrVi8bBTJtes9nc9Z208bAnDWyw/S2Clz/RArEIXiJGd2aOTe9R5l72ovWvF9edzmbaOOm7+TavZ+Z8qMxOWh7XarX+rx/nf9XXtsWlpSV05y5fvox30ka5/fv3451DQ0MoBJ88eYJ3XrlyBc0dP34c76Th//PPP+OdU1NTaO7MmTN4J22avHbtGpqjXxARESdPnkRzBw8exDtpsMzNzeGdjUYDBfCBAwfwTvrMZcKXvm+jo6N45507d9DcrVu30NwXX3yBj02zJnON6Ltx+vRpvJPyLxdJKsJAl6QiDHRJKsJAl6QiDHRJKsJAl6QiDHRJKsJAl6QiDHRJKsJAl6QiDHRJKqKvgd5oNFBbUKY3oReFTrTMKlN6RWe3trbwToqWjUXwfphMsRCdHRwcxDsp2ruSKdKiRU2ZZ46WzGWK6+gzR48dEbG9vY1nKVpmRWUK7nb72BH8+cjcS6qv5Vxzc3MoqWlJU0TEyMgImsuUGtFQnZiYwDsbjQZ6eLa3t/FL8+6776K5hYUFNBcRsbq6iuYyL8Lhw4fR3G+//YbmMl/47733HprLtOktLi6iuaNHj+KdtFAq8xxHsFCfnJxM7STPZ+bHTgR7nui7nnkv33nnHTT38OFDvHNtbQ3NNRqN1A8Jwr9cJKkIA12SijDQJakIA12SijDQJakIA12SijDQJakIA12SijDQJakIA12SijDQJakIA12SiuhroHe7XVQ/lyl+oo12mXZA2k6YaQek55RpiqPFPrTUKIJfz0zrHp3tRfMdvZ6ZxkF6PTPFS/RzZnbS65lphaTvUeZ60s9Jd2bedfoOZwrh6Gzmc1J9bVvc3t5GZ9psNnGo0rnx8XE0988smd/c3MQ7x8bGYmxs7I1z+/btwztpq9vz58/xztOnT6O5TENfo9FAgTUwMIDuZ+bLZGdnB9WUjo2N4cAYHBxE95LM/IPeS9oe+Q8SlpkfJvScOp3Orof6kydP0K7R0VF83E6ng5o2X716hXfS5zNTa035l4skFWGgS1IRBrokFWGgS1IRBrokFWGgS1IRBrokFWGgS1IRBrokFWGgS1IRBrokFWGgS1IR/5Vti5myINoUl2kxpO1vmXZAek6Zz0ll2hZpA1zmc9LZoSHWFUfKlLLH7kU7YKYZkRSIRfTmOc6ce08aAnf5vmfK22xb/H9ot9voTDMn2m630Yuzvr6Od9IWRdr+FhGxvLyM5jqdTmxtbaFZ+iJ0u138cjcaDRQujUYD36dWq4VmNzY20L5M0yO975mdtBFz7969eOfdu3fR3NGjR/HOZ8+eobnMFyT9cZD5kqABTIOy3W7jd5i+lxMTE2guIuLQoUNoLtMKSfmXiyQVYaBLUhEGuiQVYaBLUhEGuiQVYaBLUhEGuiQVYaBLUhEGuiQVYaBLUhEGuiQV0ddAbzQaqEmLdpRE8M4IWn6UOX6m9IruzBQLUZkSsV6URNHZzOekaEEWLXnLyOykfSq9KOfKoD1DGbtdzpW5Rpk+pN2WKW+j+lrONT09jb5AvvvuO7yTXujbt2/jnY8fP0Zzc3NzeCct9zlw4ADeefz4cTRHC4giImZnZ9Hc8+fP8c49e/aguW+++QbNjY2N4WPTArXFxUW885dffkFzH3/8Md5J7+Xq6ire+f7776O5THHdvXv30FzmOe52u6j18Pz582jf06dP8bGHh4fRF9+dO3fwzr/++gvNZRocKf9ykaQiDHRJKsJAl6QiDHRJKsJAl6QiDHRJKsJAl6QiDHRJKsJAl6QiDHRJKsJAl6QiDHRJKuK/sm0x04xIy7kyRTjNZnPXd9KmuMy507a2TCskbQjMNAnShr5eNCPS607Kof5BG/parRbeSc890/rXi4ZAujPTJEivfS/aCenzkXnX6WzmXaf62ra4sLCAzjTTfLexsYHmTp06hXfSCtuDBw/inTdu3EBzhw4dwjt3dnbQQzE9PY13LiwsoLlMxfHJkyfRHG2py7zYFy9eRHP379/HO0dHR9Fc5vmgLZfz8/N459LSEprLPHNra2toLtPgSJ+PBw8eoDnaXBnB7+XKygreSX8QZt5Lyr9cJKkIA12SijDQJakIA12SijDQJakIA12SijDQJakIA12SijDQJakIA12SijDQJamIvgZ6u91GrUpvu/SK9jtkyo9oAVGm0IkeP1M81YuSqM3NTTSX+ZwUvZ6Zbho6+/r1a7yzF8Vk9D3qRelVL0rEenE+vShv68W7TvW1nOvJkyfojnzwwQd458uXL9HctWvX8E5aUPXjjz/inZOTk2huz549eCcNloGBAfwy3Lp1C8198sknaC4i4uHDh2juwoULaG58fBwf++rVq2huYmIC72w0GjE8PPzGuTt37uCdR44cQXOdTgeH+t69e9EcLbiLiJiamkJzmR9Q9Isv827QUKfnTovOIniRF72WGf7lIklFGOiSVISBLklFGOiSVISBLklFGOiSVISBLklFGOiSVISBLklFGOiSVISBLklFGOiSVES/Ax21CmWKfXrRlkaLrEhB0z9oo9zbbluk1zPzOeksve+ZxkFaYJZpB6T3PfM5aUFVZmcvvO3jE5nPSJ/3TBsnzY/t7W28k+pr22LAL5BWq4VDYH5+Hs0tLi7iC02b1dbX19FcRMSlS5fQ3L179/BO2j43MzODdy4vL6O5ra2t2NraQrO0HZEGZaYdkDYjPn36FO988OABmhsZGcE7V1dX0dzU1BT+8qENoxcvXkRzEYHvOW16jIh48uQJmqOtnceOHcPHfvToEZp7/Pgx3vnq1Ss8u9uh7l8uklSEgS5JRRjoklSEgS5JRRjoklSEgS5JRRjoklSEgS5JRRjoklSEgS5JRRjoklSEgS5JRfQ10Hd2dna9bZE2q2Xa0mhJVKbFkLbp0fa3CH7umSZBek6ZtkVaQETve+Z8aCFb5rrT0q12u4130ucj827QZz5zL6leNB7Se5m57vR5z+QHPZ9/fdvirVu30B3JtOmNjY2hucXFRbyTtig+e/YM7/zhhx/Q3IkTJ/DOZrOJ5u7evYt30rDMNNrRJkHa0EcbISMi/vzzTzT39ddf4503b95Ec5lgGR4eRtc+0+A4OjqK5l69eoUbAj/66CM09+LFCzQXwa8T/YwTExP42AMDA+iLYnJyEu+k131ubg7vpPzLRZKKMNAlqQgDXZKKMNAlqQgDXZKKMNAlqQgDXZKKMNAlqQgDXZKKMNAlqQgDXZKK6Gugd7td1NiT6cCgJUCZIi06S0u8MjLnTntXaKlRRqbQabeLpzJFWvReZoqSMn0qFL2emXIueu6ZIi36OTP3iD6fdC7zbNJrlMkPir4XGX0t5+p0OuiOTE9P4523bt1Cc/Pz83jnw4cPd30n/Zzj4+N4Jy0mo2VjERGzs7NojhZpRfzPi0iC6Pr162hf5ro3Gg3UlLe2thZra2to58rKCpqjJU0RvKhpamoK76TX6fnz53gnLfLKhNXS0hKaO3LkCJobHBzEX1K0dKsXPzJpuV6Gf7lIUhEGuiQVYaBLUhEGuiQVYaBLUhEGuiQVYaBLUhEGuiQVYaBLUhEGuiQVYaBLUhEGuiQV0aCNfZKk/27+QpekIgx0SSrCQJekIgx0SSrCQJekIgx0SSrCQJekIgx0SSrCQJekIgx0SSrCQJekIgx0SSrCQJekIgx0SSrCQJekIgx0SSrCQJekIgx0SSrCQJekIgx0SSrCQJekIgx0SSrCQJekIv4DUBiT/WNuZXIAAAAASUVORK5CYII=\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 +} From ba26c4e6cb1581286e05598dd46c96b2c505ab54 Mon Sep 17 00:00:00 2001 From: Albert Akhriev Date: Fri, 12 Apr 2019 13:26:06 +0100 Subject: [PATCH 12/22] random number generator notebook --- .../finance/generating_random_variates.ipynb | 285 ++++++++++++++++++ 1 file changed, 285 insertions(+) create mode 100644 qiskit/aqua/finance/generating_random_variates.ipynb diff --git a/qiskit/aqua/finance/generating_random_variates.ipynb b/qiskit/aqua/finance/generating_random_variates.ipynb new file mode 100644 index 000000000..d4e5236f3 --- /dev/null +++ b/qiskit/aqua/finance/generating_random_variates.ipynb @@ -0,0 +1,285 @@ +{ + "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], Stephen Wood[1], Marco Pistoia[1]\n", + "### Affliation\n", + "- [1]IBMQ" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Uniformly-distributed scalars and vectors\n", + "\n", + "Functions in the base class \\textbf{UnivariateDistribution}\n", + "\n", + "```python\n", + "def uniform_rand_float64(self, size: int, vmin: float, vmax: float) -> np.ndarray:\n", + " \"\"\"\n", + " Generates a vector of random float64 values in the range [vmin, vmax].\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 + self.num_target_qubits - 1) // self.num_target_qubits\n", + " job = execute(self.circuit, self.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", + "\n", + "```python\n", + "def uniform_rand_int64(self, size: int, vmin: int, vmax: int) -> np.ndarray:\n", + " \"\"\"\n", + " Generates a vector of random int64 values in the range [vmin, vmax].\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(self.uniform_rand_float64(size, float(vmin), float(vmax))).astype(np.int64)\n", + "```\n", + "\n", + "Function in the base class \\textbf{NormalDistribution}\n", + "\n", + "```python\n", + "def normal_rand_float64(self, size: int) -> np.ndarray:\n", + " \"\"\"\n", + " Draws a sample vector from standard normal distribution (mu=0, std=1)\n", + " using Box-Muller method.\n", + " \"\"\"\n", + " EPS = 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.\n", + " n = 2 * size\n", + " x = np.reshape(self.uniform_rand_float64(n, float(0.0), float(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 < EPS:\n", + " # Regenerate array of uniformly distributed samples upon shortage.\n", + " if c > n:\n", + " c = 0\n", + " n = max(((size // 10) // 2) * 2, 2)\n", + " x = np.reshape(self.uniform_rand_float64(n, float(0.0), float(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", + " return rand_vec\n", + "```" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import matplotlib.pyplot as plt\n", + "%matplotlib inline\n", + "import numpy as np\n", + "import time\n", + "from qiskit import BasicAer\n", + "from qiskit.aqua.algorithms import AmplitudeEstimation\n", + "from qiskit.aqua.components.random_distributions import MultivariateNormalDistribution\n", + "from qiskit.aqua.components.uncertainty_problems import FixedIncomeExpectedValue\n", + "from qiskit.aqua.components.random_distributions import *\n", + "from qiskit import QuantumCircuit, QuantumRegister, ClassicalRegister, execute\n", + "from qiskit.tools.visualization import plot_histogram, circuit_drawer\n", + "import scipy.stats as stats\n", + "\n", + "# In this example we use 'qasm_simulator' backend.\n", + "glo_backend = BasicAer.get_backend(\"qasm_simulator\")\n", + "\n", + "# Parameters.\n", + "glo_num_qubits = 5" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Uniform distribution of floating point numbers." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "scrolled": true + }, + "outputs": [], + "source": [ + "# Create uniform distribution sampler.\n", + "start_time = time.time()\n", + "uniform = UniformDistribution(glo_num_qubits, backend=glo_backend)\n", + "creation_time = time.time() - start_time\n", + "\n", + "# Draw a sample.\n", + "start_time = time.time()\n", + "sample = uniform.uniform_rand_float64(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 of 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(\"time: creation: {:.5f}, sampling: {:.2f}\".format(creation_time, 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(\"random variable\", size=12)\n", + "plt.ylabel(\"probability\", size=12)\n", + "plt.title(\"Uniform distribution of float64 numbers [{:.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 of integer numbers." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Draw a sample, reuse the previous instance of the sampler.\n", + "start_time = time.time()\n", + "sample = uniform.uniform_rand_int64(size=54321, vmin=37, vmax=841)\n", + "sampling_time = time.time() - start_time\n", + "\n", + "# Print out some details.\n", + "print(\"Uniform distribution of 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(\"time: sampling: {:.2f}\".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(\"random variable\", size=12)\n", + "plt.ylabel(\"probability\", size=12)\n", + "plt.title(\"Uniform distribution of int64 numbers [{: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": [ + "#### Standard normal distribution" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Create uniform distribution sampler.\n", + "start_time = time.time()\n", + "normal = NormalDistribution(glo_num_qubits, backend=glo_backend)\n", + "creation_time = time.time() - start_time\n", + "\n", + "# Draw a sample from the standard normal distribution.\n", + "start_time = time.time()\n", + "sample = normal.normal_rand_float64(size=4321)\n", + "sampling_time = time.time() - start_time\n", + "\n", + "# Print out some details.\n", + "print(\"Standard normal distribution:\")\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(\"time: creation: {:.5f}, sampling: {:.2f}\".format(creation_time, 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='r', alpha=0.75)\n", + "plt.xlabel(\"random variable\", size=12)\n", + "plt.ylabel(\"probability\", size=12)\n", + "plt.title(\"Standard normal distribution\", size=12)\n", + "plt.grid(True)\n", + "# plt.savefig(\"std_normal_distrib.png\", bbox_inches=\"tight\")\n", + "plt.show()" + ] + }, + { + "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.3" + } + }, + "nbformat": 4, + "nbformat_minor": 1 +} From 0f83aa0fdf764c25d173746a553d26bc7c436ef5 Mon Sep 17 00:00:00 2001 From: Albert Akhriev Date: Fri, 12 Apr 2019 16:11:41 +0100 Subject: [PATCH 13/22] new random generator --- qiskit/aqua/finance/generating_random_variates.ipynb | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/qiskit/aqua/finance/generating_random_variates.ipynb b/qiskit/aqua/finance/generating_random_variates.ipynb index d4e5236f3..cb7123ecd 100644 --- a/qiskit/aqua/finance/generating_random_variates.ipynb +++ b/qiskit/aqua/finance/generating_random_variates.ipynb @@ -114,7 +114,7 @@ "import matplotlib.pyplot as plt\n", "%matplotlib inline\n", "import numpy as np\n", - "import time\n", + "import sys, math, time\n", "from qiskit import BasicAer\n", "from qiskit.aqua.algorithms import AmplitudeEstimation\n", "from qiskit.aqua.components.random_distributions import MultivariateNormalDistribution\n", @@ -122,7 +122,6 @@ "from qiskit.aqua.components.random_distributions import *\n", "from qiskit import QuantumCircuit, QuantumRegister, ClassicalRegister, execute\n", "from qiskit.tools.visualization import plot_histogram, circuit_drawer\n", - "import scipy.stats as stats\n", "\n", "# In this example we use 'qasm_simulator' backend.\n", "glo_backend = BasicAer.get_backend(\"qasm_simulator\")\n", @@ -242,9 +241,12 @@ "print(\"time: creation: {:.5f}, sampling: {:.2f}\".format(creation_time, sampling_time))\n", "\n", "# Plotting the distribution.\n", + "x = np.linspace(-4.0, 4.0, 1000)\n", + "analyt = np.exp(-0.5 * x**2) / 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=2)\n", "plt.xlabel(\"random variable\", size=12)\n", "plt.ylabel(\"probability\", size=12)\n", "plt.title(\"Standard normal distribution\", size=12)\n", From 4f97244846702db7c1202b3a69cee13211f5b1d8 Mon Sep 17 00:00:00 2001 From: Albert Akhriev Date: Fri, 12 Apr 2019 16:38:43 +0100 Subject: [PATCH 14/22] minor improvements --- .../finance/generating_random_variates.ipynb | 22 ++++++++++--------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/qiskit/aqua/finance/generating_random_variates.ipynb b/qiskit/aqua/finance/generating_random_variates.ipynb index cb7123ecd..f6ba44fbf 100644 --- a/qiskit/aqua/finance/generating_random_variates.ipynb +++ b/qiskit/aqua/finance/generating_random_variates.ipynb @@ -215,7 +215,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "#### Standard normal distribution" + "#### Normal distribution" ] }, { @@ -224,34 +224,36 @@ "metadata": {}, "outputs": [], "source": [ - "# Create uniform distribution sampler.\n", + "# Create normal distribution sampler.\n", + "mu = 2.4\n", + "sigma = 5.1\n", "start_time = time.time()\n", - "normal = NormalDistribution(glo_num_qubits, backend=glo_backend)\n", + "normal = NormalDistribution(glo_num_qubits, mu=mu, sigma=sigma, backend=glo_backend)\n", "creation_time = time.time() - start_time\n", "\n", - "# Draw a sample from the standard normal distribution.\n", + "# Draw a sample from the normal distribution.\n", "start_time = time.time()\n", "sample = normal.normal_rand_float64(size=4321)\n", "sampling_time = time.time() - start_time\n", "\n", "# Print out some details.\n", - "print(\"Standard normal distribution:\")\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(\"time: creation: {:.5f}, sampling: {:.2f}\".format(creation_time, sampling_time))\n", "\n", "# Plotting the distribution.\n", - "x = np.linspace(-4.0, 4.0, 1000)\n", - "analyt = np.exp(-0.5 * x**2) / math.sqrt(2.0 * math.pi)\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=2)\n", + "plt.plot(x, analyt, '-b', lw=1)\n", "plt.xlabel(\"random variable\", size=12)\n", "plt.ylabel(\"probability\", size=12)\n", - "plt.title(\"Standard normal distribution\", size=12)\n", + "plt.title(\"Normal distribution: empirical vs analytic\", size=12)\n", "plt.grid(True)\n", - "# plt.savefig(\"std_normal_distrib.png\", bbox_inches=\"tight\")\n", + "# plt.savefig(\"normal_distrib.png\", bbox_inches=\"tight\")\n", "plt.show()" ] }, From 9907068ae81723dbe349524772be6ad7b09d7396 Mon Sep 17 00:00:00 2001 From: Jakub Marecek Date: Fri, 12 Apr 2019 16:43:50 +0100 Subject: [PATCH 15/22] Moving the drivers to tutorials --- qiskit/finance/data_providers/__init__.py | 20 + .../data_providers/drivers/__init__.py | 26 + .../data_providers/drivers/_basedriver.py | 154 ++++ .../data_providers/drivers/algorithminput.py | 67 ++ .../drivers/dataondemand/README.md | 14 + .../drivers/dataondemand/__init__.py | 21 + .../dataondemand/dataondemanddriver.py | 156 ++++ .../drivers/exchangedata/README.md | 22 + .../drivers/exchangedata/__init__.py | 21 + .../exchangedata/exchangedatadriver.py | 138 ++++ .../drivers/wikipedia/README.md | 11 + .../drivers/wikipedia/__init__.py | 21 + .../drivers/wikipedia/wikipediadriver.py | 136 ++++ .../finance/data_providers/time_series.ipynb | 112 +++ .../portfolio_diversification.ipynb | 731 ++++++++++++++++++ 15 files changed, 1650 insertions(+) create mode 100644 qiskit/finance/data_providers/__init__.py create mode 100644 qiskit/finance/data_providers/drivers/__init__.py create mode 100644 qiskit/finance/data_providers/drivers/_basedriver.py create mode 100644 qiskit/finance/data_providers/drivers/algorithminput.py create mode 100644 qiskit/finance/data_providers/drivers/dataondemand/README.md create mode 100644 qiskit/finance/data_providers/drivers/dataondemand/__init__.py create mode 100644 qiskit/finance/data_providers/drivers/dataondemand/dataondemanddriver.py create mode 100644 qiskit/finance/data_providers/drivers/exchangedata/README.md create mode 100644 qiskit/finance/data_providers/drivers/exchangedata/__init__.py create mode 100644 qiskit/finance/data_providers/drivers/exchangedata/exchangedatadriver.py create mode 100644 qiskit/finance/data_providers/drivers/wikipedia/README.md create mode 100644 qiskit/finance/data_providers/drivers/wikipedia/__init__.py create mode 100644 qiskit/finance/data_providers/drivers/wikipedia/wikipediadriver.py create mode 100644 qiskit/finance/data_providers/time_series.ipynb create mode 100644 qiskit/finance/optimization/portfolio_diversification.ipynb diff --git a/qiskit/finance/data_providers/__init__.py b/qiskit/finance/data_providers/__init__.py new file mode 100644 index 000000000..300002f49 --- /dev/null +++ b/qiskit/finance/data_providers/__init__.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- + +# Copyright 2018 IBM. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ============================================================================= + +from .drivers import * + +__all__ = ['drivers'] diff --git a/qiskit/finance/data_providers/drivers/__init__.py b/qiskit/finance/data_providers/drivers/__init__.py new file mode 100644 index 000000000..3c737a444 --- /dev/null +++ b/qiskit/finance/data_providers/drivers/__init__.py @@ -0,0 +1,26 @@ +# -*- coding: utf-8 -*- + +# Copyright 2018 IBM. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ============================================================================= + +from ._basedriver import BaseDriver, UnitsType +from .dataondemand import DataOnDemandDriver +from .exhangedata import ExchangeDataDriver +from .wikipedia import WikipediaDriver + +__all__ = ['BaseDriver', + 'DataOnDemandDriver', + 'ExchangeDataDriver', + 'WikipediaDriver'] diff --git a/qiskit/finance/data_providers/drivers/_basedriver.py b/qiskit/finance/data_providers/drivers/_basedriver.py new file mode 100644 index 000000000..1993d517a --- /dev/null +++ b/qiskit/finance/data_providers/drivers/_basedriver.py @@ -0,0 +1,154 @@ +# -*- coding: utf-8 -*- + +# Copyright 2018 IBM. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ============================================================================= + +""" +This module implements the abstract base class for driver modules +within Qiskit Finance. + +To create add-on driver modules subclass the BaseDriver class in this module. +Doing so requires that the required driver interface is implemented. +""" + +from abc import ABC, abstractmethod +import copy +from qiskit.aqua.parser import JSONSchema +from enum import Enum +import logging + +logger = logging.getLogger(__name__) + + +class DataType(Enum): + DAILYADJUSTED = 'Daily (adj)' + DAILY = 'Daily' + + +class BaseDriver(ABC): + """ + Base class for Drivers. + + This method should initialize the module and its configuration, and + use an exception if a component of the module is available. + + """ + @abstractmethod + def __init__(self): + self.check_driver_valid() + self._configuration = copy.deepcopy(self.CONFIGURATION) + self._work_path = None + + @property + def configuration(self): + """Return driver configuration.""" + return self._configuration + + @classmethod + def init_from_input(cls, section): + """ + Initialize via section dictionary. + + Args: + params (dict): section dictionary + + Returns: + Driver: Driver object + """ + pass + + @staticmethod + def check_driver_valid(): + """Checks if driver is ready for use. Throws an exception if not""" + pass + + def validate(self, args_dict): + schema_dict = self.CONFIGURATION.get('input_schema', None) + if schema_dict is None: + return + + jsonSchema = JSONSchema(schema_dict) + schema_property_names = jsonSchema.get_default_section_names() + json_dict = {} + for property_name in schema_property_names: + if property_name in args_dict: + json_dict[property_name] = args_dict[property_name] + + jsonSchema.validate(json_dict) + + @property + def work_path(self): + return self._work_path + + @work_path.setter + def work_path(self, new_work_path): + self._work_path = new_work_path + + @abstractmethod + def run(self): + pass + + # gets coordinates suitable for plotting + # it does not have to be overridden in non-abstract derived classes. + def get_coordinates(self): + # Coordinates for visualisation purposes + xc = np.zeros([self.n, 1]) + yc = np.zeros([self.n, 1]) + xc = (np.random.rand(self.n) - 0.5) * 1 + yc = (np.random.rand(self.n) - 0.5) * 1 + #for (cnt, s) in enumerate(self.tickers): + #xc[cnt, 1] = self.data[cnt][0] + # yc[cnt, 0] = self.data[cnt][-1] + return xc, yc + + # it does not have to be overridden in non-abstract derived classes. + def get_covariance(self): + if not self._data: return None + self.cov = np.cov(self._data, rowvar = True) + return self.cov + + # it does not have to be overridden in non-abstract derived classes. + def get_similarity_matrix(self): + if not self.data: return None + try: + import fastdtw + for ii in range(0, self._n): + self.rho[ii,ii] = 1. + for jj in range(ii + 1, self.n): + thisRho, path = fastdtw.fastdtw(self._data[ii], self._data[jj]) + self.rho[ii, jj] = thisRho + self.rho[jj, ii] = self.rho[ii, jj] + self.rho = self.rho / np.nanmax(self.rho) + for ii in range(0, self.n): + self.rho[ii,ii] = 1. + except ImportError: + print("This requires fastdtw package.") + return self.rho + + # it does not have to be overridden in non-abstract derived classes. + def plot(self): + #for (cnt, s) in enumerate(self.tickers): + # plot(self.data[cnt], grid = True, label=s) + #plt.legend() + #plt.title("Evolution of the adjusted closing price") + #plt.show() + self.get_covariance() + self.get_similarity_matrix() + print("Top: a similarity measure. Bottom: covariance matrix.") + plt.subplot(211) + plt.imshow(self.rho) + plt.subplot(212) + plt.imshow(self.cov) + plt.show() \ No newline at end of file diff --git a/qiskit/finance/data_providers/drivers/algorithminput.py b/qiskit/finance/data_providers/drivers/algorithminput.py new file mode 100644 index 000000000..b68d5e96b --- /dev/null +++ b/qiskit/finance/data_providers/drivers/algorithminput.py @@ -0,0 +1,67 @@ +# -*- coding: utf-8 -*- + +# Copyright 2018 IBM. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ============================================================================= + +from qiskit.aqua import Pluggable +from abc import abstractmethod +import copy +from qiskit.aqua import AquaError + + +class AlgorithmInput(Pluggable): + + _PROBLEM_SET = ['portfoliodiversification', 'portfoliooptimisation'] + + @abstractmethod + def __init__(self): + super().__init__() + if 'problems' not in self.configuration or len(self.configuration['problems']) <= 0: + raise AquaError('Algorithm Input missing or empty configuration problems') + + for problem in self.configuration['problems']: + if problem not in AlgorithmInput._PROBLEM_SET: + raise AquaError('Problem {} not in known problem set {}'.format(problem, AlgorithmInput._PROBLEM_SET)) + + @property + def all_problems(self): + return copy.deepcopy(self._PROBLEM_SET) + + @property + def problems(self): + """ + Gets the set of problems that this input form supports + """ + return self.configuration.problems + + @abstractmethod + def to_params(self): + """ + Convert the derived algorithminput class fields to a dictionary where the values are in a + form that can be saved to json + Returns: + Dictionary of input fields + """ + raise NotImplementedError() + + @abstractmethod + def from_params(self, params): + """ + Load the dictionary into the algorithminput class fields. This dictionary being that as + created by to_params() + Args: + params: A dictionary as originally created by to_params() + """ + raise NotImplementedError() diff --git a/qiskit/finance/data_providers/drivers/dataondemand/README.md b/qiskit/finance/data_providers/drivers/dataondemand/README.md new file mode 100644 index 000000000..836eb7f04 --- /dev/null +++ b/qiskit/finance/data_providers/drivers/dataondemand/README.md @@ -0,0 +1,14 @@ +# Qiskit Finance + +## Stock market data driver for NASDAQ Data on Demand + +NASDAQ is a major vendor of stock market data. It provides data not only for NASDAQ +issues, but also for NYSE etc. + +This driver requires Data on Demand API Token. + +## Example query + +The data are obtained by running a query through the REST API. +``` +``` diff --git a/qiskit/finance/data_providers/drivers/dataondemand/__init__.py b/qiskit/finance/data_providers/drivers/dataondemand/__init__.py new file mode 100644 index 000000000..682ce312d --- /dev/null +++ b/qiskit/finance/data_providers/drivers/dataondemand/__init__.py @@ -0,0 +1,21 @@ +# -*- coding: utf-8 -*- + +# Copyright 2018 IBM. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ============================================================================= + +from .dataondemanddriver import DataOnDemandDriver + +__all__ = ['DataOnDemandDriver', + 'StockMarket'] diff --git a/qiskit/finance/data_providers/drivers/dataondemand/dataondemanddriver.py b/qiskit/finance/data_providers/drivers/dataondemand/dataondemanddriver.py new file mode 100644 index 000000000..6ef8e50d0 --- /dev/null +++ b/qiskit/finance/data_providers/drivers/dataondemand/dataondemanddriver.py @@ -0,0 +1,156 @@ +# -*- coding: utf-8 -*- + +# Copyright 2018 IBM. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ============================================================================= + +from qiskit.aqua.drivers import BaseDriver, UnitsType +import importlib +from enum import Enum +import logging + +logger = logging.getLogger(__name__) + + +class StockMarket(Enum): + NASDAQ = 'NASDAQ' + NYSE = 'NYSE' + +class DataOnDemandDriver(BaseDriver): + """Python implementation of an NASDAQ Data on Demand driver.""" + + CONFIGURATION = { + "name": "DOD", + "description": "NASDAQ Data on Demand Driver", + "input_schema": { + "$schema": "http://json-schema.org/schema#", + "id": "dod_schema", + "type": "object", + "properties": { + STOCKMARKET: { + "type": "string", + "default": StockMarket.NASDAQ.value, + "oneOf": [ + {"enum": [ + StockMarket.NASDAQ.value, + StockMarket.NYSE.value, + ]} + ] + }, + DATATYPE: { + "type": "string", + "default": DataType.DAILYADJUSTED.value, + "oneOf": [ + {"enum": [ + DataType.DAILYADJUSTED.value, + DataType.DAILY.value, + DataType.BID.value, + DataType.ASK.value, + ]} + ] + }, + }, + } + } + + def __init__(self, + token, + tickers, + stockmarket = StockMarket.NASDAQ, + start = datetime.datetime(2016,1,1), + end = datetime.datetime(2016,1,30)): + """ + Initializer + Args: + token (str): quandl access token + tickers (str or list): tickers + stockmarket (StockMarket): LONDON, EURONEXT, or SINGAPORE + """ + if not isinstance(atoms, list) and not isinstance(atoms, str): + raise QiskitFinanceError("Invalid atom input for DOD Driver '{}'".format(atoms)) + + if isinstance(tickers, list): + self._tickers = ';'.join(tickers) + else: + self._tickers = tickers.replace('\n', ';') + self._n = len(self._tickers.split(";")) + + self.validate(locals()) + super().__init__() + self._stockmarket = stockmarket # .value? + self._token = token + self._start = start + self._end = end + + @staticmethod + def check_driver_valid(): + err_msg = 'quandl is not installed.' + try: + spec = importlib.util.find_spec('quandl') + if spec is not None: + return + except Exception as e: + logger.debug('quandl check error {}'.format(str(e))) + raise QiskitFinanceError(err_msg) from e + + raise QiskitFinanceError(err_msg) + + @classmethod + def init_from_input(cls, section): + """ + Initialize via section dictionary. + + Args: + params (dict): section dictionary + + Returns: + Driver: Driver object + """ + if section is None or not isinstance(section, dict): + raise QiskitFinanceError('Invalid or missing section {}'.format(section)) + + params = section + kwargs = {} + #for k, v in params.items(): + # if k == ExchangeDataDriver. ...: v = UnitsType(v) + # kwargs[k] = v + logger.debug('init_from_input: {}'.format(kwargs)) + return cls(**kwargs) + + def run(self): + import re + import urllib + import urllib2 + import json + url = 'https://dataondemand.nasdaq.com/api/v1/quotes' + self._data = [] + for ticker in self._tickers: + values = {'_Token' : self._token, + 'symbols' : [ticker] + 'start' : start.strftime("%Y-%m-%d'T'%H:%M:%S.%f'Z'") , + 'end' : end.strftime("%Y-%m-%d'T'%H:%M:%S.%f'Z'") , + 'next_cursor': 0 + #'start' : start.strftime("%m/%d/%Y %H:%M:%S.%f") , + #'end' : end.strftime("%m/%d/%Y %H:%M:%S.%f") , + } + request_parameters = urllib.urlencode(values) + req = urllib2.Request(url, request_parameters) + try: + response = urllib2.urlopen(req) + quotes = json.loads(response)["quotes"] + priceEvolution = [] + for q in quotes: priceEvolution.append(q["ask_price"]) + self._data.append(priceEvolution) + except: + raise QiskitFinanceError('Accessing Qiskit failed') diff --git a/qiskit/finance/data_providers/drivers/exchangedata/README.md b/qiskit/finance/data_providers/drivers/exchangedata/README.md new file mode 100644 index 000000000..31ec5e883 --- /dev/null +++ b/qiskit/finance/data_providers/drivers/exchangedata/README.md @@ -0,0 +1,22 @@ +# Qiskit Finance + +## Stock market data driver for Exchange Data International + +Exchange Data International is a major vendor of stock-market data. See +https://www.exchange-data.com/about_us.php#edi + +For samples of the data, please see: +https://www.quandl.com/data/XSES-Singapore-Exchange-Prices +https://www.quandl.com/data/XBER-Berlin-Stock-Exchange-Prices +https://www.quandl.com/data/XPAR-Euronext-Paris-Stock-Prices/documentation + +This driver requires Quandl API Token. + +## Example query + +The data are obtained by running a query through quandl. See: +https://docs.quandl.com/docs/parameters-2#section-times-series-parameters +for details. + +``` +``` diff --git a/qiskit/finance/data_providers/drivers/exchangedata/__init__.py b/qiskit/finance/data_providers/drivers/exchangedata/__init__.py new file mode 100644 index 000000000..26e0bf76f --- /dev/null +++ b/qiskit/finance/data_providers/drivers/exchangedata/__init__.py @@ -0,0 +1,21 @@ +# -*- coding: utf-8 -*- + +# Copyright 2018 IBM. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ============================================================================= + +from .exchangedatadriver import ExchangeDataDriver, StockMarket + +__all__ = ['ExchangeDataDriver', + 'StockMarket'] diff --git a/qiskit/finance/data_providers/drivers/exchangedata/exchangedatadriver.py b/qiskit/finance/data_providers/drivers/exchangedata/exchangedatadriver.py new file mode 100644 index 000000000..b2458b165 --- /dev/null +++ b/qiskit/finance/data_providers/drivers/exchangedata/exchangedatadriver.py @@ -0,0 +1,138 @@ +# -*- coding: utf-8 -*- + +# Copyright 2018 IBM. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ============================================================================= + +from qiskit.aqua.drivers import BaseDriver, UnitsType +import importlib +from enum import Enum +import logging + +logger = logging.getLogger(__name__) + + +class StockMarket(Enum): + LONDON = 'XLON' + EURONEXT = 'XPAR' + SINGAPORE = 'XSES' + +class ExchangeDataDriver(BaseDriver): + """Python implementation of an Exchange Data driver.""" + + CONFIGURATION = { + "name": "EDI", + "description": "Exchange Data International Driver", + "input_schema": { + "$schema": "http://json-schema.org/schema#", + "id": "edi_schema", + "type": "object", + "properties": { + STOCKMARKET: { + "type": "string", + "default": StockMarket.LONDON.value, + "oneOf": [ + {"enum": [ + StockMarket.LONDON.value, + StockMarket.EURONEXT.value, + StockMarket.SINGAPORE.value, + ]} + ] + }, + DATATYPE: { + "type": "string", + "default": DataType.LONDON.value, + "oneOf": [ + {"enum": [ + DataType.DAILYADJUSTED.value, + DataType.DAILY.value, + ]} + ] + }, + }, + } + } + + def __init__(self, + token, + tickers, + stockmarket = StockMarket.LONDON, + start = datetime.datetime(2016,1,1), + end = datetime.datetime(2016,1,30)): + """ + Initializer + Args: + token (str): quandl access token + tickers (str or list): tickers + stockmarket (StockMarket): LONDON, EURONEXT, or SINGAPORE + """ + if not isinstance(atoms, list) and not isinstance(atoms, str): + raise QiskitFinanceError("Invalid atom input for PYQUANTE Driver '{}'".format(atoms)) + + if isinstance(tickers, list): + tickers = ';'.join(tickers) + else: + tickers = tickers.replace('\n', ';') + self._n = len(self._tickers.split(";")) + + self.validate(locals()) + super().__init__() + self._stockmarket = stockmarket # .value? + self._token = token + self._tickers = tickers + self._start = start + self._end = end + + @staticmethod + def check_driver_valid(): + err_msg = 'quandl is not installed.' + try: + spec = importlib.util.find_spec('quandl') + if spec is not None: + return + except Exception as e: + logger.debug('quandl check error {}'.format(str(e))) + raise QiskitFinanceError(err_msg) from e + + raise QiskitFinanceError(err_msg) + + @classmethod + def init_from_input(cls, section): + """ + Initialize via section dictionary. + + Args: + params (dict): section dictionary + + Returns: + Driver: Driver object + """ + if section is None or not isinstance(section, dict): + raise QiskitFinanceError('Invalid or missing section {}'.format(section)) + + params = section + kwargs = {} + #for k, v in params.items(): + # if k == ExchangeDataDriver. ...: v = UnitsType(v) + # kwargs[k] = v + logger.debug('init_from_input: {}'.format(kwargs)) + return cls(**kwargs) + + def run(self): + import quandl + quandl.ApiConfig.api_key = self._token + quandl.ApiConfig.api_version = '2015-04-09' + for (cnt, s) in enumerate(self._tickers): + d = quandl.get(self._stockmarket + "/" + s, start_date=self._start, end_date=self._end) + self._data.append(d["close"]) diff --git a/qiskit/finance/data_providers/drivers/wikipedia/README.md b/qiskit/finance/data_providers/drivers/wikipedia/README.md new file mode 100644 index 000000000..f5dc77c2f --- /dev/null +++ b/qiskit/finance/data_providers/drivers/wikipedia/README.md @@ -0,0 +1,11 @@ +# Qiskit Finance + +## Stock market data driver for Wikipedia + +Wikipedia contains stockmarket data, that are rather reliable up until 2018. + +## Example query + +The data are obtained by running a query through quandl. +``` +``` diff --git a/qiskit/finance/data_providers/drivers/wikipedia/__init__.py b/qiskit/finance/data_providers/drivers/wikipedia/__init__.py new file mode 100644 index 000000000..7324d1dd5 --- /dev/null +++ b/qiskit/finance/data_providers/drivers/wikipedia/__init__.py @@ -0,0 +1,21 @@ +# -*- coding: utf-8 -*- + +# Copyright 2018 IBM. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ============================================================================= + +from .wikipediadriver import WikipediaDriver, StockMarket + +__all__ = ['WikipediaDriver', + 'StockMarket'] diff --git a/qiskit/finance/data_providers/drivers/wikipedia/wikipediadriver.py b/qiskit/finance/data_providers/drivers/wikipedia/wikipediadriver.py new file mode 100644 index 000000000..e3900cd20 --- /dev/null +++ b/qiskit/finance/data_providers/drivers/wikipedia/wikipediadriver.py @@ -0,0 +1,136 @@ +# -*- coding: utf-8 -*- + +# Copyright 2018 IBM. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ============================================================================= + +from qiskit.aqua.drivers import BaseDriver, UnitsType +import importlib +from enum import Enum +import logging + +logger = logging.getLogger(__name__) + + +class StockMarket(Enum): + NASDAQ = 'NASDAQ' + NYSE = 'NYSE' + +class WikipediaDriver(BaseDriver): + """Python implementation of a Wikipedia driver.""" + + CONFIGURATION = { + "name": "WIKI", + "description": "Wikipedia Driver", + "input_schema": { + "$schema": "http://json-schema.org/schema#", + "id": "edi_schema", + "type": "object", + "properties": { + STOCKMARKET: { + "type": "string", + "default": StockMarket.NASDAQ.value, + "oneOf": [ + {"enum": [ + StockMarket.NASDAQ.value, + StockMarket.NYSE.value, + ]} + ] + }, + DATATYPE: { + "type": "string", + "default": DataType.DAILYADJUSTED.value, + "oneOf": [ + {"enum": [ + DataType.DAILYADJUSTED.value, + DataType.DAILY.value, + ]} + ] + }, + }, + } + } + + def __init__(self, + token = "", + tickers, + stockmarket = StockMarket.LONDON, + start = datetime.datetime(2016,1,1), + end = datetime.datetime(2016,1,30)): + """ + Initializer + Args: + token (str): quandl access token, which is not needed, strictly speaking + tickers (str or list): tickers + stockmarket (StockMarket): NASDAQ, NYSE + """ + if not isinstance(atoms, list) and not isinstance(atoms, str): + raise QiskitFinanceError("Invalid atom input for Wikipedia Driver '{}'".format(atoms)) + + if isinstance(tickers, list): + tickers = ';'.join(tickers) + else: + tickers = tickers.replace('\n', ';') + self._n = len(self._tickers.split(";")) + + self.validate(locals()) + super().__init__() + self._stockmarket = stockmarket # .value? + self._token = token + self._tickers = tickers + self._start = start + self._end = end + + @staticmethod + def check_driver_valid(): + err_msg = 'quandl is not installed.' + try: + spec = importlib.util.find_spec('quandl') + if spec is not None: + return + except Exception as e: + logger.debug('quandl check error {}'.format(str(e))) + raise QiskitFinanceError(err_msg) from e + + raise QiskitFinanceError(err_msg) + + @classmethod + def init_from_input(cls, section): + """ + Initialize via section dictionary. + + Args: + params (dict): section dictionary + + Returns: + Driver: Driver object + """ + if section is None or not isinstance(section, dict): + raise QiskitFinanceError('Invalid or missing section {}'.format(section)) + + params = section + kwargs = {} + #for k, v in params.items(): + # if k == ExchangeDataDriver. ...: v = UnitsType(v) + # kwargs[k] = v + logger.debug('init_from_input: {}'.format(kwargs)) + return cls(**kwargs) + + def run(self): + import quandl + quandl.ApiConfig.api_key = self._token + quandl.ApiConfig.api_version = '2015-04-09' + for (cnt, s) in enumerate(self._tickers): + d = quandl.get("WIKI/" + s, start_date=self._start, end_date=self._end) + self._data.append(d["close"]) diff --git a/qiskit/finance/data_providers/time_series.ipynb b/qiskit/finance/data_providers/time_series.ipynb new file mode 100644 index 000000000..5938dcdb5 --- /dev/null +++ b/qiskit/finance/data_providers/time_series.ipynb @@ -0,0 +1,112 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\"Note: Trusted Notebook\" width=\"500 px\" align=\"left\">" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# _*Qiskit Finance: Loading 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": 9, + "metadata": { + "scrolled": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "['/Users/jmarecek/git/qiskit-tutorials/qiskit/aqua/artificial_intelligence', '/Users/jmarecek/anaconda3/envs/localqiskit/lib/python37.zip', '/Users/jmarecek/anaconda3/envs/localqiskit/lib/python3.7', '/Users/jmarecek/anaconda3/envs/localqiskit/lib/python3.7/lib-dynload', '', '/Users/jmarecek/anaconda3/envs/localqiskit/lib/python3.7/site-packages', '/Users/jmarecek/anaconda3/envs/localqiskit/lib/python3.7/site-packages/sympy-1.3-py3.7.egg', '/Users/jmarecek/anaconda3/envs/localqiskit/lib/python3.7/site-packages/scipy-1.2.1-py3.7-macosx-10.7-x86_64.egg', '/Users/jmarecek/anaconda3/envs/localqiskit/lib/python3.7/site-packages/psutil-5.6.1-py3.7-macosx-10.7-x86_64.egg', '/Users/jmarecek/anaconda3/envs/localqiskit/lib/python3.7/site-packages/ply-3.11-py3.7.egg', '/Users/jmarecek/anaconda3/envs/localqiskit/lib/python3.7/site-packages/Pillow-5.4.1-py3.7-macosx-10.7-x86_64.egg', '/Users/jmarecek/anaconda3/envs/localqiskit/lib/python3.7/site-packages/numpy-1.16.2-py3.7-macosx-10.7-x86_64.egg', '/Users/jmarecek/anaconda3/envs/localqiskit/lib/python3.7/site-packages/networkx-2.2-py3.7.egg', '/Users/jmarecek/anaconda3/envs/localqiskit/lib/python3.7/site-packages/marshmallow_polyfield-3.2-py3.7.egg', '/Users/jmarecek/anaconda3/envs/localqiskit/lib/python3.7/site-packages/marshmallow-2.19.1-py3.7.egg', '/Users/jmarecek/anaconda3/envs/localqiskit/lib/python3.7/site-packages/jsonschema-2.6.0-py3.7.egg', '/Users/jmarecek/anaconda3/envs/localqiskit/lib/python3.7/site-packages/mpmath-1.1.0-py3.7.egg', '/Users/jmarecek/anaconda3/envs/localqiskit/lib/python3.7/site-packages/decorator-4.4.0-py3.7.egg', '/Users/jmarecek/anaconda3/envs/localqiskit/lib/python3.7/site-packages/pyeda-0.28.0-py3.7-macosx-10.7-x86_64.egg', '/Users/jmarecek/anaconda3/envs/localqiskit/lib/python3.7/site-packages/dlx-1.0.4-py3.7.egg', '/Users/jmarecek/anaconda3/envs/localqiskit/lib/python3.7/site-packages/cvxopt-1.2.3-py3.7-macosx-10.7-x86_64.egg', '/Users/jmarecek/anaconda3/envs/localqiskit/lib/python3.7/site-packages/scikit_learn-0.20.3-py3.7-macosx-10.7-x86_64.egg', '/Users/jmarecek/git/qiskit-aer', '/Users/jmarecek/git/qiskit-ignis', '/Users/jmarecek/anaconda3/envs/localqiskit/lib/python3.7/site-packages/requests-2.21.0-py3.7.egg', '/Users/jmarecek/anaconda3/envs/localqiskit/lib/python3.7/site-packages/requests_ntlm-1.1.0-py3.7.egg', '/Users/jmarecek/anaconda3/envs/localqiskit/lib/python3.7/site-packages/urllib3-1.24.1-py3.7.egg', '/Users/jmarecek/anaconda3/envs/localqiskit/lib/python3.7/site-packages/idna-2.8-py3.7.egg', '/Users/jmarecek/anaconda3/envs/localqiskit/lib/python3.7/site-packages/chardet-3.0.4-py3.7.egg', '/Users/jmarecek/anaconda3/envs/localqiskit/lib/python3.7/site-packages/ntlm_auth-1.2.0-py3.7.egg', '/Users/jmarecek/anaconda3/envs/localqiskit/lib/python3.7/site-packages/cryptography-2.6.1-py3.7-macosx-10.7-x86_64.egg', '/Users/jmarecek/anaconda3/envs/localqiskit/lib/python3.7/site-packages/six-1.12.0-py3.7.egg', '/Users/jmarecek/anaconda3/envs/localqiskit/lib/python3.7/site-packages/cffi-1.12.2-py3.7-macosx-10.7-x86_64.egg', '/Users/jmarecek/anaconda3/envs/localqiskit/lib/python3.7/site-packages/asn1crypto-0.24.0-py3.7.egg', '/Users/jmarecek/anaconda3/envs/localqiskit/lib/python3.7/site-packages/pycparser-2.19-py3.7.egg', '/Users/jmarecek/git/qiskit-aqua', '/Users/jmarecek/git/qiskit', '/Users/jmarecek/git/qiskit-terra', '/Users/jmarecek/anaconda3/envs/localqiskit/lib/python3.7/site-packages/IPython/extensions', '/Users/jmarecek/.ipython', '/Users/jmarecek/git/qiskit-tutorials/qiskit/aqua/artificial_intelligence', '/Users/jmarecek/git/qiskit-tutorials/qiskit/aqua/artificial_intelligence', '/Users/jmarecek/git/qiskit-tutorials/qiskit/aqua/artificial_intelligence']\n" + ] + }, + { + "ename": "ModuleNotFoundError", + "evalue": "No module named 'drivers'", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mModuleNotFoundError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[1;32m 2\u001b[0m \u001b[0msys\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mpath\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mappend\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mos\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mgetcwd\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 3\u001b[0m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0msys\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mpath\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 4\u001b[0;31m \u001b[0;32mfrom\u001b[0m \u001b[0mdrivers\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0;34m*\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 5\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 6\u001b[0m \u001b[0;32mfrom\u001b[0m \u001b[0mqiskit\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mAer\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;31mModuleNotFoundError\u001b[0m: No module named 'drivers'" + ] + } + ], + "source": [ + "import os, sys\n", + "sys.path.append(os.getcwd())\n", + "print(sys.path)\n", + "from drivers import *\n", + "\n", + "from qiskit import Aer\n", + "from qiskit_aqua import run_algorithm, QuantumInstance\n", + "\n", + "# setup aqua logging\n", + "import logging\n", + "from qiskit_aqua import set_aqua_logging" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "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.\n" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python [conda env:localqiskit]", + "language": "python", + "name": "conda-env-localqiskit-py" + }, + "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/optimization/portfolio_diversification.ipynb b/qiskit/finance/optimization/portfolio_diversification.ipynb new file mode 100644 index 000000000..bcdcdca32 --- /dev/null +++ b/qiskit/finance/optimization/portfolio_diversification.ipynb @@ -0,0 +1,731 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Portfolio diversification: classical and quantum solutions\n", + "\n", + "## Contributors\n", + "Andrea Simonetto, Jakub Marecek, Martin Mevissen; IBM Research -- Ireland\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 ca 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 daily stock-price data from Wikipedia, whereas in a real asset management, this may come from a Reuters, Bloomberg, or similar at a much higher frequency.\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 (CPLEX) 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 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 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", + "If everything has been installed, the following should run without any errors. \n", + "If there are errors, please refer to Installation.ipynb for details." + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "localqiskit\n", + "/Users/jmarecek/anaconda3/envs/localqiskit/bin/python\n" + ] + } + ], + "source": [ + "import os\n", + "print(os.environ['CONDA_DEFAULT_ENV'])\n", + "#!source activate localqiskit\n", + "#!conda list\n", + "#help(\"modules\")\n", + "# If you get errors, you can install from here using:\n", + "#!conda install -y --name localqiskit quandl\n", + "#!conda install -y -c bioconda --name localqiskit fastdtw\n", + "print(sys.executable)\n", + "\n", + "# Import requisite modules\n", + "import math\n", + "import operator\n", + "import logging\n", + "import datetime\n", + "import sys\n", + "import warnings\n", + "warnings.filterwarnings(\"error\") \n", + "import numpy as np\n", + "import matplotlib.pyplot as plt\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.translators.ising import portfolio\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", + "from qiskit.aqua.translators.ising import portfoliodiv" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We then initialize the variables" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [], + "source": [ + "# Initialize the problem by defining the parameters\n", + "\n", + "n = 2 # Number of inner variables\n", + "q = 1 # Number of clusters, q less or equal than n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We define get data either by randomly placing the assets in a 2-D plane and computing the distance between them (the closer they are in this plane, the more similar they are), or by actually downloading stock-market price data and computing the dynamic time warping distance and normalising it to (0,1]. Either way, we obtain the `rho` matrix. " + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": {}, + "outputs": [], + "source": [ + "# The code for generating a random rho or obtain stock-market data\n", + "\n", + "from qiskit.aqua.input.portfoliodata import *" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": { + "scrolled": true + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[[-1. -0.83591861]\n", + " [-0.83591861 -1. ]]\n" + ] + } + ], + "source": [ + "# Initialize the problem by randomly generating the similarity matrix rho\n", + "\n", + "data = RandomData(n)\n", + "xc,yc,rho = data.generate_instance()\n", + "try:\n", + " data = RealData(n, plots=True)\n", + " #data = RealData(n, plots=False)\n", + "except:\n", + " print(\"Cannot load real data, possibly due to issues with pandas.\")\n", + "print(rho)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Classical solution using IBM 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": 39, + "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": 40, + "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": 41, + "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", + " \n", + "\n", + "# Eventually, you can runvisualize_solution(xc, yc, x, classical_cost, n, q, 'Classical')" + ] + }, + { + "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 solution using IBM-Q simulator\n", + "\n", + "For the quantum solution, we use Qskit. 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", + "- `binary_representation` : encodes the problem $(M)$ into a the Ising Hamiltonian QP (that's basically linear algebra);\n", + "- `construct_hamiltonian` : constructs the Ising Hamiltonian in terms of the $Z$ basis;\n", + "- `check_hamiltonian` : makes sure that the Ising Hamiltonian is correctly encoded in the $Z$ basis: to do this, it solves a eigenvalue-eigenvector problem for a symmetric matrix of dimension $2^N \\times 2^N$. For the problem at hand $n=3$, that is $N = 12$ seems the limit; \n", + "- `vqe_solution` : solves the problem $(M)$ via VQE by using the SPSA solver (with default parameters);\n", + "- `_q_solution` : internal routine to represent the solution in a usable format.\n" + ] + }, + { + "cell_type": "code", + "execution_count": 42, + "metadata": {}, + "outputs": [], + "source": [ + "class QuantumOptimizer:\n", + "\n", + " def __init__(self, rho,n,q,max_trials=1000):\n", + "\n", + " self.rho = rho\n", + " self.n = n\n", + " self.q = q\n", + " self.max_trials = max_trials\n", + "\n", + " def construct_hamiltonian(self):\n", + "\n", + " return portfoliodiv.get_portfoliodiversification_qubitops(self.rho, self.n, self.q, self.max_trials)\n", + "\n", + " def check_hamiltonian(self):\n", + "\n", + " Op = self.construct_hamiltonian()\n", + " qubitOp, offset = Op, 0\n", + " algo_input = EnergyInput(qubitOp)\n", + "\n", + " # Making the Hamiltonian in its full form and getting the lowest eigenvalue and eigenvector\n", + "\n", + " algorithm_cfg = {\n", + " 'name': 'ExactEigensolver',\n", + " }\n", + "\n", + " params = {\n", + " 'problem': {'name': 'ising'},\n", + " 'algorithm': algorithm_cfg\n", + " }\n", + " result = run_algorithm(params, algo_input)\n", + "\n", + " quantum_solution = self._q_solution(result['eigvecs'][0],self.n*(self.n+1))\n", + " ground_level = result['energy'] + offset\n", + "\n", + " return quantum_solution, ground_level\n", + "\n", + " def vqe_solution(self):\n", + "\n", + " qubitOp = self.construct_hamiltonian()\n", + " algo_input = EnergyInput(qubitOp)\n", + "\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=3, 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(algo_input)\n", + "\n", + " #quantum_solution = self._q_solution(result['eigvecs'][0], self.n * (self.n + 1))\n", + " quantum_solution_dict = result['eigvecs'][0]\n", + "\n", + " q_s = max(quantum_solution_dict.items(), key=operator.itemgetter(1))[0]\n", + " quantum_solution= [int(chars) for chars in q_s]\n", + " quantum_solution = np.flip(quantum_solution, axis=0)\n", + "\n", + " #_,_,_,level = self.binary_representation(x_sol=quantum_solution)\n", + " return quantum_solution_dict, quantum_solution\n", + "\n", + " def _q_solution(self, v, N):\n", + "\n", + " index_value = [x for x in range(len(v)) if v[x] == max(v)][0]\n", + " string_value = \"{0:b}\".format(index_value)\n", + "\n", + " while len(string_value)\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[0;31m# Check if the binary representation is correct\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 2\u001b[0;31m \u001b[0mQ\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0mg\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0mc\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0mquantum_cost\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mquantum_optimizer\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mvqe_solution\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 3\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 4\u001b[0m \u001b[0msol\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mclassical_cost\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mClassicalOptimizer\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mcplex_solution\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 5\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m\u001b[0m in \u001b[0;36mvqe_solution\u001b[0;34m(self)\u001b[0m\n\u001b[1;32m 48\u001b[0m \u001b[0mvqe\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mrandom_seed\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mseed\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 49\u001b[0m \u001b[0mquantum_instance\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mQuantumInstance\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mbackend\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mbackend\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mseed\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mseed\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mseed_mapper\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mseed\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 50\u001b[0;31m \u001b[0mresult\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mvqe\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mrun\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0malgo_input\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 51\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 52\u001b[0m \u001b[0;31m#quantum_solution = self._q_solution(result['eigvecs'][0], self.n * (self.n + 1))\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m~/anaconda3/lib/python3.7/site-packages/qiskit_aqua/algorithms/quantum_algorithm.py\u001b[0m in \u001b[0;36mrun\u001b[0;34m(self, quantum_instance, **kwargs)\u001b[0m\n\u001b[1;32m 101\u001b[0m \u001b[0mquantum_instance\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mset_config\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 102\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_quantum_instance\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mquantum_instance\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 103\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_run\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 104\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 105\u001b[0m \u001b[0;34m@\u001b[0m\u001b[0mabstractmethod\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m~/anaconda3/lib/python3.7/site-packages/qiskit_aqua/algorithms/adaptive/vqe/vqe.py\u001b[0m in \u001b[0;36m_run\u001b[0;34m(self)\u001b[0m\n\u001b[1;32m 266\u001b[0m \u001b[0mDictionary\u001b[0m \u001b[0mof\u001b[0m \u001b[0mresults\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 267\u001b[0m \"\"\"\n\u001b[0;32m--> 268\u001b[0;31m \u001b[0;32mif\u001b[0m \u001b[0;32mnot\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_quantum_instance\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mis_statevector\u001b[0m \u001b[0;32mand\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_operator_mode\u001b[0m \u001b[0;34m==\u001b[0m \u001b[0;34m'matrix'\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 269\u001b[0m logger.warning('Qasm simulation does not work on {} mode, changing '\n\u001b[1;32m 270\u001b[0m 'the operator_mode to \"paulis\"'.format(self._operator_mode))\n", + "\u001b[0;31mAttributeError\u001b[0m: 'EnergyInput' object has no attribute 'is_statevector'" + ] + } + ], + "source": [ + "# Check if the binary representation is correct\n", + "Q,g,c,quantum_cost = quantum_optimizer.vqe_solution()\n", + "\n", + "sol, classical_cost = ClassicalOptimizer.cplex_solution()\n", + "\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 binary formulation')" + ] + }, + { + "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": null, + "metadata": {}, + "outputs": [], + "source": [ + "ground_state, ground_level = quantum_optimizer.check_hamiltonian()\n", + "\n", + "print(ground_level,classical_cost)\n", + "print(ground_state)\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')" + ] + }, + { + "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": null, + "metadata": {}, + "outputs": [], + "source": [ + "quantum_dictionary, quantum_solution, quantum_cost = quantum_optimizer.vqe_solution()\n", + "\n", + "print(quantum_solution,quantum_cost)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Step 5\n", + "Visualize the solution" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "visualize_solution(xc, yc, quantum_solution, quantum_cost, n, q, 'Quantum')\n", + "visualize_solution(xc, yc, x, classical_cost, n, q, 'Classical')" + ] + }, + { + "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. Note that in this particular case, we can find the optimal solution of the QP formulation, which happens to coincide with the optimal solution of the ILP.\n", + "\n", + "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 +} From 1b69ff74ed670f74ebaa2d7f746a73fb7d38beb2 Mon Sep 17 00:00:00 2001 From: Jakub Marecek Date: Fri, 12 Apr 2019 16:59:44 +0100 Subject: [PATCH 16/22] Deprecation of warnings, addition of outputs --- .../finance/generating_random_variates.ipynb | 88 +++++++++++++++++-- 1 file changed, 80 insertions(+), 8 deletions(-) diff --git a/qiskit/aqua/finance/generating_random_variates.ipynb b/qiskit/aqua/finance/generating_random_variates.ipynb index f6ba44fbf..986d9edbb 100644 --- a/qiskit/aqua/finance/generating_random_variates.ipynb +++ b/qiskit/aqua/finance/generating_random_variates.ipynb @@ -107,7 +107,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 7, "metadata": {}, "outputs": [], "source": [ @@ -115,6 +115,9 @@ "%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.aqua.algorithms import AmplitudeEstimation\n", "from qiskit.aqua.components.random_distributions import MultivariateNormalDistribution\n", @@ -139,11 +142,34 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 8, "metadata": { "scrolled": true }, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Uniform distribution of floating point numbers:\n", + "sample type: , element type: float64 , shape: (54321,)\n", + "sample min: -7.6697, max: 19.5199\n", + "time: creation: 0.00043, sampling: 6.49\n" + ] + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], "source": [ "# Create uniform distribution sampler.\n", "start_time = time.time()\n", @@ -183,9 +209,32 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 9, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Uniform distribution of integer numbers:\n", + "sample type: , element type: int64 , shape: (54321,)\n", + "sample min: 37, max: 841\n", + "time: sampling: 6.36\n" + ] + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], "source": [ "# Draw a sample, reuse the previous instance of the sampler.\n", "start_time = time.time()\n", @@ -220,9 +269,32 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 10, "metadata": {}, - "outputs": [], + "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: -14.4205, max: 20.7960\n", + "time: creation: 0.01026, sampling: 1.60\n" + ] + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], "source": [ "# Create normal distribution sampler.\n", "mu = 2.4\n", @@ -281,7 +353,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.7.3" + "version": "3.7.2" } }, "nbformat": 4, From ab744319f5094868444e190c1fe5a41200d4b497 Mon Sep 17 00:00:00 2001 From: Jakub Marecek Date: Fri, 12 Apr 2019 19:58:22 +0100 Subject: [PATCH 17/22] A simple tutorial for the Qiskit Finance data loading --- .../finance/generating_random_variates.ipynb | 159 +++++++++--------- .../finance/data_providers/time_series.ipynb | 54 ++---- 2 files changed, 99 insertions(+), 114 deletions(-) diff --git a/qiskit/aqua/finance/generating_random_variates.ipynb b/qiskit/aqua/finance/generating_random_variates.ipynb index 986d9edbb..71f0f2faa 100644 --- a/qiskit/aqua/finance/generating_random_variates.ipynb +++ b/qiskit/aqua/finance/generating_random_variates.ipynb @@ -17,7 +17,8 @@ "\n", "***\n", "### Contributors\n", - "Albert Akhriev[1], Jakub Marecek[1], Stephen Wood[1], Marco Pistoia[1]\n", + "Albert Akhriev[1], Jakub Marecek[1], Marco Pistoia[1]\n", + "\n", "### Affliation\n", "- [1]IBMQ" ] @@ -26,83 +27,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "### Uniformly-distributed scalars and vectors\n", - "\n", - "Functions in the base class \\textbf{UnivariateDistribution}\n", - "\n", - "```python\n", - "def uniform_rand_float64(self, size: int, vmin: float, vmax: float) -> np.ndarray:\n", - " \"\"\"\n", - " Generates a vector of random float64 values in the range [vmin, vmax].\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 + self.num_target_qubits - 1) // self.num_target_qubits\n", - " job = execute(self.circuit, self.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", - "\n", - "```python\n", - "def uniform_rand_int64(self, size: int, vmin: int, vmax: int) -> np.ndarray:\n", - " \"\"\"\n", - " Generates a vector of random int64 values in the range [vmin, vmax].\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(self.uniform_rand_float64(size, float(vmin), float(vmax))).astype(np.int64)\n", - "```\n", - "\n", - "Function in the base class \\textbf{NormalDistribution}\n", - "\n", - "```python\n", - "def normal_rand_float64(self, size: int) -> np.ndarray:\n", - " \"\"\"\n", - " Draws a sample vector from standard normal distribution (mu=0, std=1)\n", - " using Box-Muller method.\n", - " \"\"\"\n", - " EPS = 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.\n", - " n = 2 * size\n", - " x = np.reshape(self.uniform_rand_float64(n, float(0.0), float(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 < EPS:\n", - " # Regenerate array of uniformly distributed samples upon shortage.\n", - " if c > n:\n", - " c = 0\n", - " n = max(((size // 10) // 2) * 2, 2)\n", - " x = np.reshape(self.uniform_rand_float64(n, float(0.0), float(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", - " return rand_vec\n", - "```" + "### Uniformly-distributed scalars and vectors\n" ] }, { @@ -329,6 +254,84 @@ "plt.show()" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Background\n", + "\n", + "In order to understand the implementation, it may be useful to see:\n", + "\n", + "Functions in the base class *UnivariateDistribution*\n", + "\n", + "```python\n", + "def uniform_rand_float64(self, size: int, vmin: float, vmax: float) -> np.ndarray:\n", + " \"\"\"\n", + " Generates a vector of random float64 values in the range [vmin, vmax].\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", + " nbits = 7 * 8 # nbits > mantissa of float64\n", + " bit_str_len = (nbits * size + self.num_target_qubits - 1) // self.num_target_qubits\n", + " job = execute(self.circuit, self.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", + "\n", + "```python\n", + "def uniform_rand_int64(self, size: int, vmin: int, vmax: int) -> np.ndarray:\n", + " \"\"\"\n", + " Generates a vector of random int64 values in the range [vmin, vmax].\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", + " return np.rint(self.uniform_rand_float64(size, float(vmin), float(vmax))).astype(np.int64)\n", + "```\n", + "\n", + "Function in the base class *NormalDistribution*:\n", + "\n", + "```python\n", + "def normal_rand_float64(self, size: int) -> np.ndarray:\n", + " \"\"\"\n", + " Draws a sample vector from standard normal distribution (mu=0, std=1)\n", + " using Box-Muller method.\n", + " \"\"\"\n", + " EPS = 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.\n", + " n = 2 * size\n", + " x = np.reshape(self.uniform_rand_float64(n, float(0.0), float(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 < EPS:\n", + " # Regenerate array of uniformly distributed samples upon shortage.\n", + " if c > n:\n", + " c = 0\n", + " n = max(((size // 10) // 2) * 2, 2)\n", + " x = np.reshape(self.uniform_rand_float64(n, float(0.0), float(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", + " return rand_vec\n", + "```" + ] + }, { "cell_type": "code", "execution_count": null, diff --git a/qiskit/finance/data_providers/time_series.ipynb b/qiskit/finance/data_providers/time_series.ipynb index 5938dcdb5..aed94d68d 100644 --- a/qiskit/finance/data_providers/time_series.ipynb +++ b/qiskit/finance/data_providers/time_series.ipynb @@ -33,42 +33,17 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": null, "metadata": { - "scrolled": false + "scrolled": true }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "['/Users/jmarecek/git/qiskit-tutorials/qiskit/aqua/artificial_intelligence', '/Users/jmarecek/anaconda3/envs/localqiskit/lib/python37.zip', '/Users/jmarecek/anaconda3/envs/localqiskit/lib/python3.7', '/Users/jmarecek/anaconda3/envs/localqiskit/lib/python3.7/lib-dynload', '', '/Users/jmarecek/anaconda3/envs/localqiskit/lib/python3.7/site-packages', '/Users/jmarecek/anaconda3/envs/localqiskit/lib/python3.7/site-packages/sympy-1.3-py3.7.egg', '/Users/jmarecek/anaconda3/envs/localqiskit/lib/python3.7/site-packages/scipy-1.2.1-py3.7-macosx-10.7-x86_64.egg', '/Users/jmarecek/anaconda3/envs/localqiskit/lib/python3.7/site-packages/psutil-5.6.1-py3.7-macosx-10.7-x86_64.egg', '/Users/jmarecek/anaconda3/envs/localqiskit/lib/python3.7/site-packages/ply-3.11-py3.7.egg', '/Users/jmarecek/anaconda3/envs/localqiskit/lib/python3.7/site-packages/Pillow-5.4.1-py3.7-macosx-10.7-x86_64.egg', '/Users/jmarecek/anaconda3/envs/localqiskit/lib/python3.7/site-packages/numpy-1.16.2-py3.7-macosx-10.7-x86_64.egg', '/Users/jmarecek/anaconda3/envs/localqiskit/lib/python3.7/site-packages/networkx-2.2-py3.7.egg', '/Users/jmarecek/anaconda3/envs/localqiskit/lib/python3.7/site-packages/marshmallow_polyfield-3.2-py3.7.egg', '/Users/jmarecek/anaconda3/envs/localqiskit/lib/python3.7/site-packages/marshmallow-2.19.1-py3.7.egg', '/Users/jmarecek/anaconda3/envs/localqiskit/lib/python3.7/site-packages/jsonschema-2.6.0-py3.7.egg', '/Users/jmarecek/anaconda3/envs/localqiskit/lib/python3.7/site-packages/mpmath-1.1.0-py3.7.egg', '/Users/jmarecek/anaconda3/envs/localqiskit/lib/python3.7/site-packages/decorator-4.4.0-py3.7.egg', '/Users/jmarecek/anaconda3/envs/localqiskit/lib/python3.7/site-packages/pyeda-0.28.0-py3.7-macosx-10.7-x86_64.egg', '/Users/jmarecek/anaconda3/envs/localqiskit/lib/python3.7/site-packages/dlx-1.0.4-py3.7.egg', '/Users/jmarecek/anaconda3/envs/localqiskit/lib/python3.7/site-packages/cvxopt-1.2.3-py3.7-macosx-10.7-x86_64.egg', '/Users/jmarecek/anaconda3/envs/localqiskit/lib/python3.7/site-packages/scikit_learn-0.20.3-py3.7-macosx-10.7-x86_64.egg', '/Users/jmarecek/git/qiskit-aer', '/Users/jmarecek/git/qiskit-ignis', '/Users/jmarecek/anaconda3/envs/localqiskit/lib/python3.7/site-packages/requests-2.21.0-py3.7.egg', '/Users/jmarecek/anaconda3/envs/localqiskit/lib/python3.7/site-packages/requests_ntlm-1.1.0-py3.7.egg', '/Users/jmarecek/anaconda3/envs/localqiskit/lib/python3.7/site-packages/urllib3-1.24.1-py3.7.egg', '/Users/jmarecek/anaconda3/envs/localqiskit/lib/python3.7/site-packages/idna-2.8-py3.7.egg', '/Users/jmarecek/anaconda3/envs/localqiskit/lib/python3.7/site-packages/chardet-3.0.4-py3.7.egg', '/Users/jmarecek/anaconda3/envs/localqiskit/lib/python3.7/site-packages/ntlm_auth-1.2.0-py3.7.egg', '/Users/jmarecek/anaconda3/envs/localqiskit/lib/python3.7/site-packages/cryptography-2.6.1-py3.7-macosx-10.7-x86_64.egg', '/Users/jmarecek/anaconda3/envs/localqiskit/lib/python3.7/site-packages/six-1.12.0-py3.7.egg', '/Users/jmarecek/anaconda3/envs/localqiskit/lib/python3.7/site-packages/cffi-1.12.2-py3.7-macosx-10.7-x86_64.egg', '/Users/jmarecek/anaconda3/envs/localqiskit/lib/python3.7/site-packages/asn1crypto-0.24.0-py3.7.egg', '/Users/jmarecek/anaconda3/envs/localqiskit/lib/python3.7/site-packages/pycparser-2.19-py3.7.egg', '/Users/jmarecek/git/qiskit-aqua', '/Users/jmarecek/git/qiskit', '/Users/jmarecek/git/qiskit-terra', '/Users/jmarecek/anaconda3/envs/localqiskit/lib/python3.7/site-packages/IPython/extensions', '/Users/jmarecek/.ipython', '/Users/jmarecek/git/qiskit-tutorials/qiskit/aqua/artificial_intelligence', '/Users/jmarecek/git/qiskit-tutorials/qiskit/aqua/artificial_intelligence', '/Users/jmarecek/git/qiskit-tutorials/qiskit/aqua/artificial_intelligence']\n" - ] - }, - { - "ename": "ModuleNotFoundError", - "evalue": "No module named 'drivers'", - "output_type": "error", - "traceback": [ - "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[0;31mModuleNotFoundError\u001b[0m Traceback (most recent call last)", - "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[1;32m 2\u001b[0m \u001b[0msys\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mpath\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mappend\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mos\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mgetcwd\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 3\u001b[0m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0msys\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mpath\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 4\u001b[0;31m \u001b[0;32mfrom\u001b[0m \u001b[0mdrivers\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0;34m*\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 5\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 6\u001b[0m \u001b[0;32mfrom\u001b[0m \u001b[0mqiskit\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mAer\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;31mModuleNotFoundError\u001b[0m: No module named 'drivers'" - ] - } - ], + "outputs": [], "source": [ - "import os, sys\n", - "sys.path.append(os.getcwd())\n", - "print(sys.path)\n", - "from drivers import *\n", - "\n", - "from qiskit import Aer\n", - "from qiskit_aqua import run_algorithm, QuantumInstance\n", - "\n", - "# setup aqua logging\n", - "import logging\n", - "from qiskit_aqua import set_aqua_logging" + "from qiskit.aqua.input.finance import *\n", + "from qiskit.aqua.input.finance.wikipedia import StockMarket\n", + "import warnings\n", + "warnings.filterwarnings(\"ignore\",category=DeprecationWarning)\n", + "import datetime" ] }, { @@ -76,7 +51,14 @@ "execution_count": null, "metadata": {}, "outputs": [], - "source": [] + "source": [ + "wiki = WikipediaDriver(token = \"\",\n", + " tickers = [\"GOOG\"],\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", @@ -90,9 +72,9 @@ ], "metadata": { "kernelspec": { - "display_name": "Python [conda env:localqiskit]", + "display_name": "Python 3", "language": "python", - "name": "conda-env-localqiskit-py" + "name": "python3" }, "language_info": { "codemirror_mode": { From 6bb134068f4fe1a1c756373deb613df5ffe1fdbf Mon Sep 17 00:00:00 2001 From: Jakub Marecek Date: Fri, 12 Apr 2019 20:29:33 +0100 Subject: [PATCH 18/22] Updates to the random variates notebook --- .../finance/generating_random_variates.ipynb | 66 +++++++++++++++++-- .../finance/data_providers/time_series.ipynb | 44 +++++++++++-- 2 files changed, 101 insertions(+), 9 deletions(-) diff --git a/qiskit/aqua/finance/generating_random_variates.ipynb b/qiskit/aqua/finance/generating_random_variates.ipynb index 71f0f2faa..f14f562b4 100644 --- a/qiskit/aqua/finance/generating_random_variates.ipynb +++ b/qiskit/aqua/finance/generating_random_variates.ipynb @@ -27,12 +27,46 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "### Uniformly-distributed scalars and vectors\n" + "## 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.\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 Bernoulli-distributed scalars (i.e. either 0 or 1). Starting from a simple circuit such as a Hadamard gate followed by measurement, one can progress to\n", + "Bernoulli-distributed vectors.\n", + "\n", + "By addition of such random variates, we could get binomial distributions. \n", + "By multiplication we could get geometric distributions.\n", + "Both may lead to unacceptable circuit depth, though.\n", + "\n", + "\n", + "## Uniformly-distributed scalars and vectors\n", + "\n", + "It is clear that there are many options for approximating uniformly-distributed scalars\n", + "by the choice of an integer from a finite range uniformly at random,\n", + "e.g., by a binary-code construction from the Bernoulli-distributed vectors.\n", + "In the following snippet, we generate random bits,\n", + "which we then convert using the binary-code construction, up to the \n", + "machine precision of a classical computer." ] }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 12, "metadata": {}, "outputs": [], "source": [ @@ -62,7 +96,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "#### Uniform distribution of floating point numbers." + "### Uniform distribution over floating point numbers." ] }, { @@ -129,7 +163,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "#### Uniform distribution of integer numbers." + "### Uniform distribution over integers." ] }, { @@ -189,7 +223,23 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "#### Normal distribution" + "## 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: " ] }, { @@ -258,6 +308,12 @@ "cell_type": "markdown", "metadata": {}, "source": [ + "Using basic linear algebra, we can correlate multivariate variables. Indeed, when $L$ is \n", + "the left Cholesky factor of the $n \\times n$ covariance matrix $\\Sigma= L L^T$,\n", + "and $\\mu$ is an $n$-vector,\n", + "and $x$ is an $n$-vector distributed according to the standard normal distribution,\n", + "then $\\mu + Lx$ is a random sample from $N(\\mu, \\Sigma)$.\n", + "\n", "## Background\n", "\n", "In order to understand the implementation, it may be useful to see:\n", diff --git a/qiskit/finance/data_providers/time_series.ipynb b/qiskit/finance/data_providers/time_series.ipynb index aed94d68d..95b7ea478 100644 --- a/qiskit/finance/data_providers/time_series.ipynb +++ b/qiskit/finance/data_providers/time_series.ipynb @@ -33,11 +33,20 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 2, "metadata": { "scrolled": true }, - "outputs": [], + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/Users/jmarecek/git/qiskit-terra/qiskit/tools/qcvv/__init__.py:13: DeprecationWarning: The qiskit.tools.qcvv package is deprecated. Please use qiskit-ignis available on PIP for similar functionality and more.\n", + " 'functionality and more.', DeprecationWarning)\n" + ] + } + ], "source": [ "from qiskit.aqua.input.finance import *\n", "from qiskit.aqua.input.finance.wikipedia import StockMarket\n", @@ -48,9 +57,36 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 3, "metadata": {}, - "outputs": [], + "outputs": [ + { + "ename": "KeyError", + "evalue": "'close'", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mKeyError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m~/anaconda3/envs/localqiskit/lib/python3.7/site-packages/pandas/core/indexes/base.py\u001b[0m in \u001b[0;36mget_loc\u001b[0;34m(self, key, method, tolerance)\u001b[0m\n\u001b[1;32m 2656\u001b[0m \u001b[0;32mtry\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m-> 2657\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_engine\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mget_loc\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mkey\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 2658\u001b[0m \u001b[0;32mexcept\u001b[0m \u001b[0mKeyError\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32mpandas/_libs/index.pyx\u001b[0m in \u001b[0;36mpandas._libs.index.IndexEngine.get_loc\u001b[0;34m()\u001b[0m\n", + "\u001b[0;32mpandas/_libs/index.pyx\u001b[0m in \u001b[0;36mpandas._libs.index.IndexEngine.get_loc\u001b[0;34m()\u001b[0m\n", + "\u001b[0;32mpandas/_libs/hashtable_class_helper.pxi\u001b[0m in \u001b[0;36mpandas._libs.hashtable.PyObjectHashTable.get_item\u001b[0;34m()\u001b[0m\n", + "\u001b[0;32mpandas/_libs/hashtable_class_helper.pxi\u001b[0m in \u001b[0;36mpandas._libs.hashtable.PyObjectHashTable.get_item\u001b[0;34m()\u001b[0m\n", + "\u001b[0;31mKeyError\u001b[0m: 'close'", + "\nDuring handling of the above exception, another exception occurred:\n", + "\u001b[0;31mKeyError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[1;32m 4\u001b[0m \u001b[0mstart\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mdatetime\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mdatetime\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m2016\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 5\u001b[0m end = datetime.datetime(2016,1,30))\n\u001b[0;32m----> 6\u001b[0;31m \u001b[0mwiki\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mrun\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;32m~/git/qiskit-aqua/qiskit/aqua/input/finance/wikipedia/wikipediadriver.py\u001b[0m in \u001b[0;36mrun\u001b[0;34m(self)\u001b[0m\n\u001b[1;32m 137\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0;34m(\u001b[0m\u001b[0mcnt\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0ms\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;32min\u001b[0m \u001b[0menumerate\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_tickers\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 138\u001b[0m \u001b[0md\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mquandl\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mget\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"WIKI/\"\u001b[0m \u001b[0;34m+\u001b[0m \u001b[0ms\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mstart_date\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_start\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mend_date\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_end\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 139\u001b[0;31m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_data\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mappend\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0md\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m\"close\"\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;32m~/anaconda3/envs/localqiskit/lib/python3.7/site-packages/pandas/core/frame.py\u001b[0m in \u001b[0;36m__getitem__\u001b[0;34m(self, key)\u001b[0m\n\u001b[1;32m 2925\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mcolumns\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mnlevels\u001b[0m \u001b[0;34m>\u001b[0m \u001b[0;36m1\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 2926\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_getitem_multilevel\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mkey\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m-> 2927\u001b[0;31m \u001b[0mindexer\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mcolumns\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mget_loc\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mkey\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 2928\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mis_integer\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mindexer\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 2929\u001b[0m \u001b[0mindexer\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0mindexer\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m~/anaconda3/envs/localqiskit/lib/python3.7/site-packages/pandas/core/indexes/base.py\u001b[0m in \u001b[0;36mget_loc\u001b[0;34m(self, key, method, tolerance)\u001b[0m\n\u001b[1;32m 2657\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_engine\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mget_loc\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mkey\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 2658\u001b[0m \u001b[0;32mexcept\u001b[0m \u001b[0mKeyError\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m-> 2659\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_engine\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mget_loc\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_maybe_cast_indexer\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mkey\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 2660\u001b[0m \u001b[0mindexer\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mget_indexer\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mkey\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mmethod\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mmethod\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mtolerance\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mtolerance\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 2661\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mindexer\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mndim\u001b[0m \u001b[0;34m>\u001b[0m \u001b[0;36m1\u001b[0m \u001b[0;32mor\u001b[0m \u001b[0mindexer\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0msize\u001b[0m \u001b[0;34m>\u001b[0m \u001b[0;36m1\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32mpandas/_libs/index.pyx\u001b[0m in \u001b[0;36mpandas._libs.index.IndexEngine.get_loc\u001b[0;34m()\u001b[0m\n", + "\u001b[0;32mpandas/_libs/index.pyx\u001b[0m in \u001b[0;36mpandas._libs.index.IndexEngine.get_loc\u001b[0;34m()\u001b[0m\n", + "\u001b[0;32mpandas/_libs/hashtable_class_helper.pxi\u001b[0m in \u001b[0;36mpandas._libs.hashtable.PyObjectHashTable.get_item\u001b[0;34m()\u001b[0m\n", + "\u001b[0;32mpandas/_libs/hashtable_class_helper.pxi\u001b[0m in \u001b[0;36mpandas._libs.hashtable.PyObjectHashTable.get_item\u001b[0;34m()\u001b[0m\n", + "\u001b[0;31mKeyError\u001b[0m: 'close'" + ] + } + ], "source": [ "wiki = WikipediaDriver(token = \"\",\n", " tickers = [\"GOOG\"],\n", From a8c8fef4777f4b8c0eb9d0f1aa23ac273cd0708e Mon Sep 17 00:00:00 2001 From: Jakub Marecek Date: Fri, 12 Apr 2019 20:35:15 +0100 Subject: [PATCH 19/22] A bugfix --- .../finance/data_providers/time_series.ipynb | 44 ++----------------- 1 file changed, 4 insertions(+), 40 deletions(-) diff --git a/qiskit/finance/data_providers/time_series.ipynb b/qiskit/finance/data_providers/time_series.ipynb index 95b7ea478..aed94d68d 100644 --- a/qiskit/finance/data_providers/time_series.ipynb +++ b/qiskit/finance/data_providers/time_series.ipynb @@ -33,20 +33,11 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": null, "metadata": { "scrolled": true }, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/Users/jmarecek/git/qiskit-terra/qiskit/tools/qcvv/__init__.py:13: DeprecationWarning: The qiskit.tools.qcvv package is deprecated. Please use qiskit-ignis available on PIP for similar functionality and more.\n", - " 'functionality and more.', DeprecationWarning)\n" - ] - } - ], + "outputs": [], "source": [ "from qiskit.aqua.input.finance import *\n", "from qiskit.aqua.input.finance.wikipedia import StockMarket\n", @@ -57,36 +48,9 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "ename": "KeyError", - "evalue": "'close'", - "output_type": "error", - "traceback": [ - "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[0;31mKeyError\u001b[0m Traceback (most recent call last)", - "\u001b[0;32m~/anaconda3/envs/localqiskit/lib/python3.7/site-packages/pandas/core/indexes/base.py\u001b[0m in \u001b[0;36mget_loc\u001b[0;34m(self, key, method, tolerance)\u001b[0m\n\u001b[1;32m 2656\u001b[0m \u001b[0;32mtry\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m-> 2657\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_engine\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mget_loc\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mkey\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 2658\u001b[0m \u001b[0;32mexcept\u001b[0m \u001b[0mKeyError\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;32mpandas/_libs/index.pyx\u001b[0m in \u001b[0;36mpandas._libs.index.IndexEngine.get_loc\u001b[0;34m()\u001b[0m\n", - "\u001b[0;32mpandas/_libs/index.pyx\u001b[0m in \u001b[0;36mpandas._libs.index.IndexEngine.get_loc\u001b[0;34m()\u001b[0m\n", - "\u001b[0;32mpandas/_libs/hashtable_class_helper.pxi\u001b[0m in \u001b[0;36mpandas._libs.hashtable.PyObjectHashTable.get_item\u001b[0;34m()\u001b[0m\n", - "\u001b[0;32mpandas/_libs/hashtable_class_helper.pxi\u001b[0m in \u001b[0;36mpandas._libs.hashtable.PyObjectHashTable.get_item\u001b[0;34m()\u001b[0m\n", - "\u001b[0;31mKeyError\u001b[0m: 'close'", - "\nDuring handling of the above exception, another exception occurred:\n", - "\u001b[0;31mKeyError\u001b[0m Traceback (most recent call last)", - "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[1;32m 4\u001b[0m \u001b[0mstart\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mdatetime\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mdatetime\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m2016\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 5\u001b[0m end = datetime.datetime(2016,1,30))\n\u001b[0;32m----> 6\u001b[0;31m \u001b[0mwiki\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mrun\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", - "\u001b[0;32m~/git/qiskit-aqua/qiskit/aqua/input/finance/wikipedia/wikipediadriver.py\u001b[0m in \u001b[0;36mrun\u001b[0;34m(self)\u001b[0m\n\u001b[1;32m 137\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0;34m(\u001b[0m\u001b[0mcnt\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0ms\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;32min\u001b[0m \u001b[0menumerate\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_tickers\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 138\u001b[0m \u001b[0md\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mquandl\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mget\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"WIKI/\"\u001b[0m \u001b[0;34m+\u001b[0m \u001b[0ms\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mstart_date\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_start\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mend_date\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_end\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 139\u001b[0;31m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_data\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mappend\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0md\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m\"close\"\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", - "\u001b[0;32m~/anaconda3/envs/localqiskit/lib/python3.7/site-packages/pandas/core/frame.py\u001b[0m in \u001b[0;36m__getitem__\u001b[0;34m(self, key)\u001b[0m\n\u001b[1;32m 2925\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mcolumns\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mnlevels\u001b[0m \u001b[0;34m>\u001b[0m \u001b[0;36m1\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 2926\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_getitem_multilevel\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mkey\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m-> 2927\u001b[0;31m \u001b[0mindexer\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mcolumns\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mget_loc\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mkey\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 2928\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mis_integer\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mindexer\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 2929\u001b[0m \u001b[0mindexer\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0mindexer\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;32m~/anaconda3/envs/localqiskit/lib/python3.7/site-packages/pandas/core/indexes/base.py\u001b[0m in \u001b[0;36mget_loc\u001b[0;34m(self, key, method, tolerance)\u001b[0m\n\u001b[1;32m 2657\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_engine\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mget_loc\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mkey\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 2658\u001b[0m \u001b[0;32mexcept\u001b[0m \u001b[0mKeyError\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m-> 2659\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_engine\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mget_loc\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_maybe_cast_indexer\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mkey\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 2660\u001b[0m \u001b[0mindexer\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mget_indexer\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mkey\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mmethod\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mmethod\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mtolerance\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mtolerance\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 2661\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mindexer\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mndim\u001b[0m \u001b[0;34m>\u001b[0m \u001b[0;36m1\u001b[0m \u001b[0;32mor\u001b[0m \u001b[0mindexer\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0msize\u001b[0m \u001b[0;34m>\u001b[0m \u001b[0;36m1\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;32mpandas/_libs/index.pyx\u001b[0m in \u001b[0;36mpandas._libs.index.IndexEngine.get_loc\u001b[0;34m()\u001b[0m\n", - "\u001b[0;32mpandas/_libs/index.pyx\u001b[0m in \u001b[0;36mpandas._libs.index.IndexEngine.get_loc\u001b[0;34m()\u001b[0m\n", - "\u001b[0;32mpandas/_libs/hashtable_class_helper.pxi\u001b[0m in \u001b[0;36mpandas._libs.hashtable.PyObjectHashTable.get_item\u001b[0;34m()\u001b[0m\n", - "\u001b[0;32mpandas/_libs/hashtable_class_helper.pxi\u001b[0m in \u001b[0;36mpandas._libs.hashtable.PyObjectHashTable.get_item\u001b[0;34m()\u001b[0m\n", - "\u001b[0;31mKeyError\u001b[0m: 'close'" - ] - } - ], + "outputs": [], "source": [ "wiki = WikipediaDriver(token = \"\",\n", " tickers = [\"GOOG\"],\n", From acb2a7886dbd1530f600caa12196129c57304e1b Mon Sep 17 00:00:00 2001 From: Jakub Marecek Date: Tue, 16 Apr 2019 18:44:56 +0100 Subject: [PATCH 20/22] Time series tutorial --- .../finance/data_providers/time_series.ipynb | 198 +++++++++++++++++- 1 file changed, 188 insertions(+), 10 deletions(-) diff --git a/qiskit/finance/data_providers/time_series.ipynb b/qiskit/finance/data_providers/time_series.ipynb index aed94d68d..a3c423018 100644 --- a/qiskit/finance/data_providers/time_series.ipynb +++ b/qiskit/finance/data_providers/time_series.ipynb @@ -33,31 +33,121 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 1, "metadata": { "scrolled": true }, "outputs": [], "source": [ - "from qiskit.aqua.input.finance import *\n", - "from qiskit.aqua.input.finance.wikipedia import StockMarket\n", + "%matplotlib inline\n", + "from qiskit.aqua.translators.data_providers import *\n", + "from qiskit.aqua.translators.data_providers.wikipediadataprovider import StockMarket\n", "import warnings\n", - "warnings.filterwarnings(\"ignore\",category=DeprecationWarning)\n", + "warnings.filterwarnings(\"ignore\", category=DeprecationWarning)\n", "import datetime" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 2, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Evolution of the stock price:\n", + "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" + ] + }, + { + "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 time-series similarity measure:\n", + "[[1.00000000e+00 8.44268222e-05]\n", + " [8.44268222e-05 1.00000000e+00]]\n", + "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": [ - "wiki = WikipediaDriver(token = \"\",\n", - " tickers = [\"GOOG\"],\n", + "wiki = WikipediaDataProvider(token = \"\",\n", + " tickers = [\"GOOG\", \"AAPL\"],\n", " stockmarket = StockMarket.NASDAQ.value,\n", " start = datetime.datetime(2016,1,1),\n", " end = datetime.datetime(2016,1,30))\n", - "wiki.run()" + "wiki.run()\n", + "wiki.plot()" ] }, { @@ -68,6 +158,94 @@ "\n", "If you would like to download professional data, you will have to set-up a token with one of the major providers.\n" ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "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,30))\n", + " nasdaq.run()\n", + " nasdaq.plot()\n", + "except QiskitFinanceError: \n", + " print(\"You need to replace REPLACE-ME with a valid token.\")" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "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,30))\n", + " nasdaq.run()\n", + " nasdaq.plot()\n", + "except QiskitFinanceError: \n", + " print(\"You need to replace REPLACE-ME with a valid token.\")" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "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: \n", + " print(\"You need to replace REPLACE-ME with a valid token.\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] } ], "metadata": { @@ -90,5 +268,5 @@ } }, "nbformat": 4, - "nbformat_minor": 1 + "nbformat_minor": 2 } From f8408aa5384869e8e9a37cb879069a6b8cc39a84 Mon Sep 17 00:00:00 2001 From: Jakub Marecek Date: Tue, 16 Apr 2019 19:15:07 +0100 Subject: [PATCH 21/22] Minor improvements --- .../finance/data_providers/time_series.ipynb | 49 ++++++------------- 1 file changed, 16 insertions(+), 33 deletions(-) diff --git a/qiskit/finance/data_providers/time_series.ipynb b/qiskit/finance/data_providers/time_series.ipynb index a3c423018..bb6641b93 100644 --- a/qiskit/finance/data_providers/time_series.ipynb +++ b/qiskit/finance/data_providers/time_series.ipynb @@ -161,40 +161,22 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 3, "metadata": {}, "outputs": [ { - "name": "stdout", + "name": "stderr", "output_type": "stream", "text": [ - "You need to replace REPLACE-ME with a valid token.\n" + "/Users/jmarecek/anaconda3/envs/localqiskit/lib/python3.7/site-packages/urllib3/connectionpool.py:847: InsecureRequestWarning: Unverified HTTPS request is being made. Adding certificate verification is strongly advised. See: https://urllib3.readthedocs.io/en/latest/advanced-usage.html#ssl-warnings\n", + " InsecureRequestWarning)\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,30))\n", - " nasdaq.run()\n", - " nasdaq.plot()\n", - "except QiskitFinanceError: \n", - " print(\"You need to replace REPLACE-ME with a valid token.\")" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "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" ] } @@ -202,20 +184,21 @@ "source": [ "from qiskit.aqua.translators.data_providers.dataondemandprovider import StockMarket\n", "try:\n", - " nasdaq = DataOnDemandProvider(token = \"REPLACE-ME\",\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,30))\n", - " nasdaq.run()\n", - " nasdaq.plot()\n", - "except QiskitFinanceError: \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": "code", - "execution_count": 7, + "execution_count": 4, "metadata": {}, "outputs": [ { @@ -229,13 +212,13 @@ "source": [ "from qiskit.aqua.translators.data_providers.exchangedataprovider import StockMarket\n", "try:\n", - " lse = ExchangeDataProvider(token = \"REPLACE-ME\",\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", + " lse.run()\n", + " lse.plot()\n", "except QiskitFinanceError: \n", " print(\"You need to replace REPLACE-ME with a valid token.\")" ] From c5627ab9aa5c115bf0532f8675b044ac72b8f3bc Mon Sep 17 00:00:00 2001 From: Jakub Marecek Date: Tue, 23 Apr 2019 10:58:12 +0200 Subject: [PATCH 22/22] Contributing the time_series, portfolio_diversification, and generating_random_variates notebooks. --- .../finance/generating_random_variates.ipynb | 420 ---------------- .../general/generating_random_variates.ipynb | 473 ++++++++++++++++++ qiskit/finance/data_providers/__init__.py | 20 - .../data_providers/drivers/__init__.py | 26 - .../data_providers/drivers/_basedriver.py | 154 ------ .../data_providers/drivers/algorithminput.py | 67 --- .../drivers/dataondemand/README.md | 14 - .../drivers/dataondemand/__init__.py | 21 - .../dataondemand/dataondemanddriver.py | 156 ------ .../drivers/exchangedata/README.md | 22 - .../drivers/exchangedata/__init__.py | 21 - .../exchangedata/exchangedatadriver.py | 138 ----- .../drivers/wikipedia/README.md | 11 - .../drivers/wikipedia/__init__.py | 21 - .../drivers/wikipedia/wikipediadriver.py | 136 ----- .../finance/data_providers/time_series.ipynb | 236 ++++++--- .../portfolio_diversification.ipynb | 381 +++++++------- 17 files changed, 835 insertions(+), 1482 deletions(-) delete mode 100644 qiskit/aqua/finance/generating_random_variates.ipynb create mode 100644 qiskit/aqua/general/generating_random_variates.ipynb delete mode 100644 qiskit/finance/data_providers/__init__.py delete mode 100644 qiskit/finance/data_providers/drivers/__init__.py delete mode 100644 qiskit/finance/data_providers/drivers/_basedriver.py delete mode 100644 qiskit/finance/data_providers/drivers/algorithminput.py delete mode 100644 qiskit/finance/data_providers/drivers/dataondemand/README.md delete mode 100644 qiskit/finance/data_providers/drivers/dataondemand/__init__.py delete mode 100644 qiskit/finance/data_providers/drivers/dataondemand/dataondemanddriver.py delete mode 100644 qiskit/finance/data_providers/drivers/exchangedata/README.md delete mode 100644 qiskit/finance/data_providers/drivers/exchangedata/__init__.py delete mode 100644 qiskit/finance/data_providers/drivers/exchangedata/exchangedatadriver.py delete mode 100644 qiskit/finance/data_providers/drivers/wikipedia/README.md delete mode 100644 qiskit/finance/data_providers/drivers/wikipedia/__init__.py delete mode 100644 qiskit/finance/data_providers/drivers/wikipedia/wikipediadriver.py diff --git a/qiskit/aqua/finance/generating_random_variates.ipynb b/qiskit/aqua/finance/generating_random_variates.ipynb deleted file mode 100644 index f14f562b4..000000000 --- a/qiskit/aqua/finance/generating_random_variates.ipynb +++ /dev/null @@ -1,420 +0,0 @@ -{ - "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], Marco Pistoia[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.\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 Bernoulli-distributed scalars (i.e. either 0 or 1). Starting from a simple circuit such as a Hadamard gate followed by measurement, one can progress to\n", - "Bernoulli-distributed vectors.\n", - "\n", - "By addition of such random variates, we could get binomial distributions. \n", - "By multiplication we could get geometric distributions.\n", - "Both may lead to unacceptable circuit depth, though.\n", - "\n", - "\n", - "## Uniformly-distributed scalars and vectors\n", - "\n", - "It is clear that there are many options for approximating uniformly-distributed scalars\n", - "by the choice of an integer from a finite range uniformly at random,\n", - "e.g., by a binary-code construction from the Bernoulli-distributed vectors.\n", - "In the following snippet, we generate random bits,\n", - "which we then convert using the binary-code construction, up to the \n", - "machine precision of a classical computer." - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "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.aqua.algorithms import AmplitudeEstimation\n", - "from qiskit.aqua.components.random_distributions import MultivariateNormalDistribution\n", - "from qiskit.aqua.components.uncertainty_problems import FixedIncomeExpectedValue\n", - "from qiskit.aqua.components.random_distributions import *\n", - "from qiskit import QuantumCircuit, QuantumRegister, ClassicalRegister, execute\n", - "from qiskit.tools.visualization import plot_histogram, circuit_drawer\n", - "\n", - "# In this example we use 'qasm_simulator' backend.\n", - "glo_backend = BasicAer.get_backend(\"qasm_simulator\")\n", - "\n", - "# Parameters.\n", - "glo_num_qubits = 5" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Uniform distribution over floating point numbers." - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": { - "scrolled": true - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Uniform distribution of floating point numbers:\n", - "sample type: , element type: float64 , shape: (54321,)\n", - "sample min: -7.6697, max: 19.5199\n", - "time: creation: 0.00043, sampling: 6.49\n" - ] - }, - { - "data": { - "image/png": "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\n", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], - "source": [ - "# Create uniform distribution sampler.\n", - "start_time = time.time()\n", - "uniform = UniformDistribution(glo_num_qubits, backend=glo_backend)\n", - "creation_time = time.time() - start_time\n", - "\n", - "# Draw a sample.\n", - "start_time = time.time()\n", - "sample = uniform.uniform_rand_float64(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 of 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(\"time: creation: {:.5f}, sampling: {:.2f}\".format(creation_time, 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(\"random variable\", size=12)\n", - "plt.ylabel(\"probability\", size=12)\n", - "plt.title(\"Uniform distribution of float64 numbers [{:.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." - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Uniform distribution of integer numbers:\n", - "sample type: , element type: int64 , shape: (54321,)\n", - "sample min: 37, max: 841\n", - "time: sampling: 6.36\n" - ] - }, - { - "data": { - "image/png": "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\n", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], - "source": [ - "# Draw a sample, reuse the previous instance of the sampler.\n", - "start_time = time.time()\n", - "sample = uniform.uniform_rand_int64(size=54321, vmin=37, vmax=841)\n", - "sampling_time = time.time() - start_time\n", - "\n", - "# Print out some details.\n", - "print(\"Uniform distribution of 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(\"time: sampling: {:.2f}\".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(\"random variable\", size=12)\n", - "plt.ylabel(\"probability\", size=12)\n", - "plt.title(\"Uniform distribution of int64 numbers [{: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": 10, - "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: -14.4205, max: 20.7960\n", - "time: creation: 0.01026, sampling: 1.60\n" - ] - }, - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAY4AAAEZCAYAAACAZ8KHAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADl0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uIDMuMC4zLCBodHRwOi8vbWF0cGxvdGxpYi5vcmcvnQurowAAIABJREFUeJzt3Xd4FOXax/HvnYTQQgslNJGugh3sjaA0RbGAEKSoIKKix67gexQ89nLEig2VIiBwLCCgoBQbKEVRAUV6B+kQapL7/WMmsiwpu8nuzmZzf65rr+zOzO78drLZO/M8M8+IqmKMMcYEKs7rAMYYY4oWKxzGGGOCYoXDGGNMUKxwGGOMCYoVDmOMMUGxwmGMMSYoVjhMvkRkoIiMDGJ5FZGG7v03ReTfIcpRR0T2iki8+3imiPQOxWu7rzdFRHqG6vWigYgsEpEWecwfICLvFnIddd3feUJhXscrIrJKRC4r4HND9vkuSorkLzrWiMgqoDRQX1XT3Wm9gW6q2sLDaIWmqn0DWc7dBr1V9as8XmsNkBSKXCIyEGioqt18Xr9dKF47mqhq03zmPxWpLEWdiNyI8xm9MHtaoJ/vWGN7HNEjAfhXYV9EHDH3ey2q/81GM9umpqBi7gumCHseuF9EKuY0U0TOF5G5IrLL/Xm+z7yZIvKkiHwP7APqu9OeEJEf3OadiSJSWUQ+FJHd7mvU9XmNl0VkrTtvvohcFGhwEXlARDaKyAYRudlv3gci8oR7v4qIfC4iO0Vku4h8KyJxIjICqANMdLM+6NP80UtE1gDTc2kSaSAiP7nb5TMRSXbX1UJE1vllWSUil4lIW2AA0Nld30Kf7djbvR8nIv8nIqtFZIuIDBeRCu687Bw9RWSNiGwVkUeC2F4lReQF97mb3eaO0r653W2wxd2uV4vI5SKy1N1uA3xea6CIjBeRj0Rkj4gsEJHT/N+z37IjRWQ3cKP4NUOKyIXuZ2an+3m40Z1+hYj87H4+1rp7bIG814dFZLzftJdF5BX3/o0issLNvlJEbsjldc4Wkdluro0i8pqIJPrMVxHpKyJ/icgOEXldRMSd10BEpovINvd39aHk8HcmItVFZJ+IVPaZ1kxE/haRU4A3gfPcz8xOd/4/n2/3cQcR+cXdTsvdz1rMscIRPeYBM4H7/We4X4aTgFeAysB/gUm+H3CgO9AHKAesdqd1cafXAhoAs4H3gWRgCfCYz/PnAqe780YB40SkVH6h3T+M+4FWQCMgr7bi+4B1QFUgBefLW1W1O7AGuFJVk1T1OZ/nXAKcBLTJ5TV7ADcDNYEMnG2UJ1X9AngK+Mhd32k5LHaje0sF6uM0kb3mt8yFwAnApcCjInIS/PPluzOPCM8CjXG2d0Oc38+jPvOrA6V8pr8DdAOaARe566rvs3wHYBxHfnefikiJXNbdARgPVAQ+9J0hInWAKcCrOL+j04Ff3NnpONu6InAFcJuIXJ3He8w2GrhcRMq764gHrgdGiUhZnN9XO1UtB5zvsz5/mcA9QBXgPJxtfrvfMu2Bs4DT3HVkf2YEeBrnM3IScBww0H8FqroJ52/wep/J3YAxqvob0BeY7X5mcio8ZwPDgQdwttPFwKpc3k+RZoUjujwK3CkiVf2mXwH8paojVDVDVUcDfwBX+izzgaoucucfdqe9r6rLVXUXzhfCclX9SlUzcL5ozsh+sqqOVNVt7vNfBErifCnm53p3Pb+7/TMD81j2MFADOF5VD6vqt5r/YGkDVTVdVffnMn+Ez7r/DVzvfjkV1g3Af1V1haruBfoDXfz2dgap6n5VXQgsxPnCQlW/y+mLBZymROAW4B5V3a6qe3CKWBefxQ4DT7q/xzE4X5Yvq+oeVV0ELAJO9Vl+vqqOd5f/L07ROTeX9zVbVT9V1awctukNwFeqOtr9/WxT1V/c9zRTVX9zn/crTkG4JPfN51DV1cACILvItAT2qeoc93EWcLKIlFbVje77y+l15qvqHPfzuQp4K4f1P6OqO92+sBk4hQ9VXaaq01T1oKr+7W6j3LIPwykW2UUuDRiR3/t09QLec9eVparrVfWPAJ9bpFjhiCKq+jvwOfCw36yaHNmLyLYa5z/SbGtzeMnNPvf35/D4n45mEblPRJaI0+SzE6iA84WVn5p+6/bP6et5YBkw1W2e8H+fOcnpfeU2fzVQgsBy58d/m6/G6YdK8Zm2yef+PgLruK8KlAHmu80uO4Ev3OnZtqlqpns/+8s9198dPttAVbNw9upq5rL+vLbnccDynGaIyDkiMsNtttmF8993oNt5FM4XMEBX9zFuse/svtZGEZkkIifmsv7G4jRzbnKb2Z7KYf05/j5EpJqIjBGR9e5zR+aR/TOgibtH1wrYpao/Bfg+c91+scYKR/R5DOc/Ut+isAE43m+5OsB6n8cFHuZYnP6Mh3D2Hiq5/y3vwtnFz89GnD8Y31w5cv9jvk9V6+PsLd0rIpdmz87tafms33/dh4GtOE0rZbJnuP89+n455/e6/tu8Dk5T2OacFw/YVpwv/qaqWtG9VVDVwhwt9s82EOfAiNo4+XOS1/tei9OkmZNRwATgOFWtgNPeH8jnA5y92xYiUhu4xn0tJ4zql6raCmdP9A+cZrmcDHHnN1LV8jjNnIGu/2mc932q+9xuuT1XVQ8AY3H2vrpz9N5Gfp+ZvLZfTLHCEWVUdRnwEXCXz+TJQGMR6SoiCSLSGWiCs3cSCuVwvhT/BhJE5FGgfIDPHYvTydpERMpwdL/JUUSkvYg0dJtrduO0W2f/Z70Zpy8hWN181v04MN79b30pUMrt1C0B/B9O81u2zUBdyf0ItNHAPSJST0SSONInklGAjP9w9wjeAV4SkWoAIlJLRHLrwwlEMxG51m1Guxs4CMzJ5zk5+RC4TESudz9nlUXkdHdeOWC7qh5w2/K7BvqibvPQTJz+tZWqugRARFJE5Cq3r+MgsJcjnwd/5XA+M3vdvZLbgnhf5dzX3ikitXD6IPIyHKd/6yqcvZNsm4Havp3yfoYCN4nIpeIcXFErtz2oos4KR3R6HCib/UBVt+F0/N0HbAMeBNqr6tYQre9LnD6QpThNMgfIv4koO9sUYDAwHacZanoeizcCvsL5I54NvKGqM915TwP/5zbfHHOAQB5GAB/gNFOUwi24br/O7cC7OHtm6ThNONnGuT+3iciCHF73Pfe1vwFW4myTOwMJJCIXicjePBZ5CGdbzXGbTr4isP6k3HyG0+SzA+e/5Gt9+rkC5vYNXI7zOduO01GdfeDA7cDjIrIHpy9ubJAvPwrnwIlRPtPi3HVtcNd3Ccd2eGe7H6dY7cEpvB8Fse5BwJk4e9GTgI/zWlhVv8fpe1ng9qdkm47Tv7RJRI7523ObtG4CXnLXNYtjWwpiguTfN2mMiVaSw4mMpvBEZDowSlULdVZ9rLITgIwxxoeInIWzh9LB6yzRypqqjDHGJSLDcJoO73YPlTY5sKYqY4wxQbE9DmOMMUGJyT6OKlWqaNWqVSlbtmz+C0dQenq6ZQpQNOayTIGJxkwQnbmiLdP8+fO3qqr/yBXHUtWYuzVr1kxnzJih0cYyBS4ac1mmwERjJtXozBVtmYB5GsB3rDVVGWOMCYoVDmOMMUGxwmGMMSYoVjiMMcYExQqHMcaYoFjhMMYYExQrHMYYY4JihcMYY0xQrHAYY4wJSkwOOWJMVEpNPfrxjBne5DCmkGyPwxhjTFCscBhjjAmKFQ5jjDFBscJhjDEmKFY4jDHGBMUKhzHGmKBY4TDGGBMUKxzGGGOCYoXDGGNMUKxwGGOMCYoVDmOMMUGxwmGMMSYoVjiMMcYExQqHMcaYoESscIhIWxH5U0SWicjDOcwvKSIfufN/FJG67vQSIjJMRH4TkSUi0j9SmY0xxhwrIoVDROKB14F2QBMgTUSa+C3WC9ihqg2Bl4Bn3emdgJKqegrQDLg1u6gYY4yJvEjtcZwNLFPVFap6CBgDdPBbpgMwzL0/HrhURARQoKyIJAClgUPA7sjENsYY4y9ShaMWsNbn8Tp3Wo7LqGoGsAuojFNE0oGNwBrgBVXdHu7AxhhjciaqGv6ViHQC2qhqb/dxd+BsVb3TZ5lF7jLr3MfLcfZUTgRuB24EKgHfAu1UdYXfOvoAfQBSUlKavfvuuyQlJYX7rQVl7969lilA0Zir0JmWLj36cePGhQtEjG6nMInGXNGWKTU1db6qNs9vuUhdc3wdcJzP49rAhlyWWec2S1UAtgNdgS9U9TCwRUS+B5oDRxUOVX0beBugefPmmpSURIsWLcLwVgpu5syZlilA0Zir0JkGDTr6cX7XHA/gGuUxuZ3CJBpzRWOmQESqqWou0EhE6olIItAFmOC3zASgp3u/IzBdnd2hNUBLcZQFzgX+iFBuY4wxfiKyx6GqGSLSD/gSiAfeU9VFIvI4ME9VJwBDgREisgxnT6OL+/TXgfeB3wEB3lfVXyOR25hQ2L4dJk2Cn/66k82HkikVd4gTyqyhzTxo1gxEvE5oTHAi1VSFqk4GJvtNe9Tn/gGcQ2/9n7c3p+nGRLsNG+DJJ2HUKLjkErik1EYurPA7+zJL8nt6PdLSoFw5ePxxaN/e67TGBC5ihcOY4mTMGLjrLujRw+kTr1oVSB1/1DLPf309EybA/ffDyJHwxhuQnOxNXmOCYYXDmBDKyoL+/eGTT2DyZGiex/EpcXFw9dXQpg089BCcey5MmQINGuTyhAA6y42JBBurypgQycqC3r3hu+9g9uy8i4av0qXhlVfg3nvhootgyZLw5jSmsGyPw5gQUIX77oM//oBp06Bs2eBfo29f53mtW8M330C90Mc0JiSscBgTAoMHw9dfw6xZPkXDv2kpAN27w86dTmf5nOTSlEvYH9qgxoSAFQ5jCsotDN/sPJVnFz3Gj81up9K1mwv9sv36wa+/wo2fPsz4po/Z4bom6lgfhzGFsPlQJdIW/x/DT3qa40sVvmiAc17Ha6/B+oNVGLyuY0he05hQsj0OYwpIFfouvYee1afSOnle4V/Qp2mrJDCqSQ3OWfAGbZLn0qTs6sK/vjEhYnscxhTQmC0t+WtfbR6rOyz/hQugfumNPFXvXbovGcDhrPiwrMOYgrDCYUwBbN4Mdy+7gw9OfIaScYfDtp7eNSZRtcROXl53XdjWYUywrHAYUwAPPQQ9qk+lefml+S9cCCLwWqOXeWZNV9YdqBLWdRkTKCscxgTpxx9h6lR49PjhEVlfwzIbuK3WZ9y//LaIrM+Y/FjhMCYIWVnwr3/BU08R0XMs+tcZxY97TmLGjtMjtk5jcmNHVRkThFGjnOLRowdQ2D7xIE4QLBN/kKfqvctDK/rw45m327kdxlO2x2FMgDIyhEcfheefdwYojLTO1WZwWBP4eOvFkV+5MT6scBgToClTqtOggXNtDS/EifJ0vXd4ZEUvMrLsT9d4xz59xgTgwAEYOfJ4/vMfb3O0SZ5LjZLbGLa5rbdBTLFmhcOYALzzDtSvn86553qbQwQG1f2Ap1d3JSPD2yym+LLCYUw+Dh6EZ56Bm25a6XUUAC6u+Cs1Sm5j7Fivk5jiygqHMfkYORJOOw0aN97rdZR/PFJnJE895RzhZUykWeEwJg9ZWc5RVA8+iHPx8NTUIzcPtUmeS6lS8MMPdja5iTwrHMbkYeJEKFfOuyOpciMCAwbAhx/WQdXrNKa4scJhTB6ee87Z24jGE+6uvhr27Enghx+8TmKKGztz3BRf/s1NM2Yc9fD7M+9k05KHufb1HvBGFqSlRTBc/uLi4Npr1zN4cCMuuIB8348xoWJ7HMbk4sW1nbjvuHHES/T2QLdtu4np02G1XefJRJAVDmNysGYNzNp5Gj1SvvQ6Sp7KlMmkZ094/XWvk5jixAqHMTl46y3olvIVSQkHvI6SrzvvhPfeg/TMUl5HMcWEFQ5j/Bw8CEOHwu21PvM6SkDq1YOLLoJhm9p4HcUUE1Y4jPEzfjyccgqcUGat11ECdtddMGTDVXZorokIKxzG+Hn9dbjjDq9TBKdFCziYVYLZu5t6HcUUA1Y4jPHx88+wbh20b+91kuCIQJ8an/PWhiu9jmKKASscxvh44w3o2xcSisIZTqmpRw2DcmP1L/hs6wXsOJzkdTIT46xwGOPas8fp37j5Zq+TFEyVxN1cXvlHRmxu7XUUE+OscBjjGjsWLr4Yqlf3OknB9akxkbc2XGmd5CasrHAY4xo6FHr18jpF4VxScSGZGsf3u072OoqJYVY4jAGWpNdh5Uq4/HKvkxSOCPSp+Tlvb7ROchM+VjiMAd7b1I6ePYtIp3g+uqVMY8LW89mzx+skJlZZ4TDF3uGseEZsal1kO8X9VUvcySUVFzJ+vNdJTKyywmGKvc+3nUfjMmtp3NjrJKFzY/Uv+OADr1OYWBWxwiEibUXkTxFZJiIP5zC/pIh85M7/UUTq+sw7VURmi8giEflNRGw0NxMy721qx83Vp3gdI6SuqDyHxYthxQqvk5hYFJHCISLxwOtAO6AJkCYiTfwW6wXsUNWGwEvAs+5zE4CRQF9VbQq0AA5HIreJfZsPVeK7XafQqdosr6OEVGJcBmlpMHy410lMLIrUHsfZwDJVXaGqh4AxQAe/ZToAw9z744FLRUSA1sCvqroQQFW3qWpmhHKbGDd2SwuurDybsvHRP3x6sG680SkcWdF7HSpTRIlG4EwhEekItFXV3u7j7sA5qtrPZ5nf3WXWuY+XA+cA3YBmQDWgKjBGVZ/LYR19gD4AKSkpzd59912SkqJr6IW9e/dapgBFJNfSpdzxTAd6tF/AOSev5ZhOjqVLj86UnEzS9u3hzRSkvDJpo8b06tWcu+76i9NP3xW5TMX5MxWkaMuUmpo6X1Wb57dcpA4+lBym+Ves3JZJAC4EzgL2AV+LyHxV/fqoBVXfBt4GaN68uSYlJdGiRYvC5g6pmTNnWqYARSLXyoffYsu667l34YuU+C3z2Gt0Dxp0dKa0NFqMHh3WTMHKM9OMGdxxB/z66xncfXcEMxXjz1SwojFTICLVVLUOOM7ncW1gQ27LuP0aFYDt7vRZqrpVVfcBk4Ezw57YxLwxW1rSseosSsTFbsvnDTfAJ59AerrXSUwsCbhwiEjlQqxnLtBIROqJSCLQBZjgt8wEoKd7vyMwXZ12tC+BU0WkjFtQLgEWFyKLMQCM3tKSrtW+zn/BIqx6dbjgAqd4GBMqwexxrBWRz0Sko/vlHzBVzQD64RSBJcBYVV0kIo+LyFXuYkOByiKyDLgXeNh97g7gvzjF5xdggapOCmb9xvhbtAh2ZJTjggq/ex0l7G64AUaN8jqFiSXB9HEcD6QBDwFvi8h4YLiqfhfIk1V1Mk4zk++0R33uHwA65fLckTiH5BoTEqNHQ5dq04mT2B9G9qqr4LbbYMsWqFbN6zQmFgS8x6Gqf6vqK6p6FnAesAUYISIr3D2H48OW0pgQUnUKR1q16V5HiYiyZZ0rGo4b53USEysK2jle3b2VB5YDtYCfczoj3Jho89NPzmCGZyT95XWUiOnaFT780OsUJlYE0zneVESeFpE1wBDgL+BUVW2lqr1wjnQaEKacxoTM6NGQluYMQR7T3EvKkppKq1awbJkNQWJCI5g9jm+AckBHVW2iqs+q6vrsmaq6Chgc4nzGhFRmpnOlv7Q0r5NEVokS0KkTjBnjdRITC4IpHNeoaj9V/cl3ooicnX3ft7PbmGg0axbUqAEnnOB1ksjLbq6yy8qawgqmcHyey/QvQhHEmEjIbqYqjs47zzkR8NdfvU5iirp8D8cVkTic4UDEHXTQt2W4AZARpmzGhNTBg/Dxx/DLL14n8UZcnLPXMWoUnHaa12lMURbIeRwZHBlXyr9IZAFPhjSRMWHy5ZfQtCkcd1wuC6SmRjSPF7p2da6r/vTTTiExpiACKRz1cPYyZgEX+0xX4G9V3R+OYMaEWnFupsp28slQsSJ89x1cfHH+yxuTk3wLh6qudu/aCX6myEpPhylT4NVXvU7ivexOciscpqDyLBwi8raq9nHv53otMVXtEepgxoTShAlw/vlQpYrXSbyXlgbNmjlFNDGoUeeMceS3x7HS5/7ycAYxJpyKfTOVT//N8cAJJ8xg6lRnKBJjgpVn4VDVp33uD8prWWOi1fbtzvkbNuTGEV27OsXUCocpiPyaqloG8iKqWjxGizNF0v/+B61bQ7lyXieJHp06wSOPwL59UKaM12lMUZNfU9XQAF5DgfohyGJMWIweDf365b9ccVKtGpxzDkycCJ07e53GFDX5NVXVi1QQY8Jhwwb4+Wfn3AXjIzWVtI1tGH3HhXR+89/HXm/dmDzYKUAmpo0dC1dfDaVKeZ0k+lxT9Ttm7DydnYfLeh3FFDF5Fg4RWeJzf62IrMnpFv6YxhRMsT+aKg8VEtK5tNICPt5qJ3SY4OTXx3GLz/1u4QxiTKgtXw6rVkHLgA7xKJ7Sqk3n7Y3tudnrIKZIya+P4zuf+7PCH8eY0Bk92jl6KCH7U14MxqIKVvvKs7nlz/vZtAmqV/c6jSkqgrkCYKJ7bfG/RCTd/fkfEbHWYxN1/rmuuDVT5al0/CGurPIDY8d6ncQUJcF0jg8BWgJ3AWe5Py8B3ghDLmMK5bffYO9e5xoUJm9p1aYzerTXKUxREsjouNmuBhqo6k738WIR+RFYBtZEaqJL9t6GDR2ev1aV5tFzMaxcCfXsAHwTgGAKxyagDLDTZ1ppYGNIExlTSKrOtbU/rdIbUm2ItfyUiMukY0dnm/Xv73UaUxTkdzhuy+wbMAL4QkRuEZF2ItIHmAzkOmquMV6YMwdKl4ZTy1rRCFRaGtZcZQJWkCFHBvg9vhV4NjRxjCm8UaOcL0KxEdQCduGFsGMHLFrkXCXRmLzYkCMmpmRkwLhxzhXusMIRsLg4Z8yq0aPhiSe8TmOinXUdmpgyY4ZzTfGGDb1OUvRkN1epep3ERLtgzuMoLyL/FZH5IrLahhwx0Wj0aOdaEyZ4Z54J8fEwd67XSUy0C2aP4w3gTOBxIBm4E1gDvBSGXMYE7eBB+PRTGya8oESsk9wEJpjC0Rq4TlU/AzLdn52B7mFJZkyQpkyB006DmjW9TlJ0paXBRx9BZqbXSUw0C6ZwxAG73Pt7RaQizjkc1ppsooINMVJ4J54IKSnwzTdeJzHRLJgTABfiDDHyNfAt8DqwF1gahlzGBGXPHvjiC3jDBsApGJ8BINN2d2H06FttTEiTq2D2OG4BVrn37wIOABWBHiHOZEzQPvsMLroIKlf2OknR16XadD7+GA4d8jqJiVYB73Go6gqf+38DvcKSyJgCsKOpQqdOqS2ceCJMnQrt23udxkSjoM7jEJGbRWSaiCxyf/YSEQlXOGMCsW0bfP89dOjgdZLY0XXLYEb1+tppwrI2K+MnmPM4ngMeAj4GHnB/3o8NN2I8Nn48tG0LSUleJ4kdnarOZPK2c0jPtMvtmGMFs8dxI3Cpqg5R1cmqOgTnEN2bwpLMmABlj01lQqdq4i7OLb+YiVvtgibmWMEUjj3uzX/a7kCeLCJtReRPEVkmIg/nML+kiHzkzv9RROr6za8jIntF5P4gMpsYt3Yt/P47tGvndZLYk5YyndFbLvU6holC+Q2rXj/7BgwGPhaRViJykoi0BsYRwJnjIhKPc/huO6AJkCYiTfwW6wXsUNWG7mv6N4G9BEwJ5E2Z4mP0aLjuOkhM9DpJ7LmmyrfM3HkaOw5bG6A5Wn5HVS0DFPDtAPfvKWsJvJbP65wNLMs+MktExgAdgMU+y3QABrr3xwOviYioqorI1cAKID2f9ZhiZtQoePllr1PEpvIJ+7is0gI+3nqxHUJpjiIagaEwRaQj0FZVe7uPuwPnqGo/n2V+d5dZ5z5eDpwD7Ae+AlrhdMbvVdUXclhHH6APQEpKSrN3332XpCjrLd27d69lClAguVauLMODD57GRx/NzvkSsUtDe27q3uRkkrZvD+lrFla4M82aX48J35zEi0OWBZ6pCH+mIi3aMqWmps5X1eb5LRfMmeOA09cA1ALWqeraQJ+WwzT/ipXbMoOAl1R1b15H/qrq28DbAM2bN9ekpCRatGgRYLzImDlzpmUKUCC5pk2DG2+Eli1zWW7QoNBmSkujRZSNABjuTOdkJjJ42XhOPLEF1asHmKkIf6YiLRozBSKYw3FriMgsnOarj4HlIvKNiAQypNw64Difx7WBDbktIyIJQAVgO85ex3Misgq4GxggIv0wxZqq00x1ww1eJ4ltpeMPcWXl2Ywd63USE02COapqCM54VZVUtQZQCfgZeDOA584FGolIPRFJBLoAE/yWmQD0dO93BKar4yJVrauqdXE66J9S1fz6VEyMmz3bua74aad5nST2pVX72oZaN0cJpqnqQqCGqh4GUNV0EXkQWJ/fE1U1w91L+BKIB95T1UUi8jgwT1Un4FzffISILMPZ0+gS5HsxxcioUc4QIzZuQfhdVmk+PRbDypVQzy4mbQiucOzAOZR2oc+0E4CdgTxZVScDk/2mPepz/wDQKZ/XGBhgVhPDDh+GsWNhzhyvkxQPJeIy6dQJxoyB/v29TmOiQTCF4zngKxEZCqwGjsc5a/zf4QhmTG6++goaNID6vfyODJ8xw5tAxUBaGtxxhxUO4whmdNx33ENkuwKn4nRup6nq9HCFM+Yo7mB7o5b0p2u5P5xDLExEXHAB7NgBixZB06ZepzFeC6hzXETiRWQY8L2q9lbVy92fVjRMRKVnlmLi1vO5vtpMr6MUK3Fx0KWLXY/cOAIqHKqaiTOgYVZ44xiTt4lbz+Pc8otJSdzhdZTiJTWVtBl9GP3ierSFDbNe3AVzOO5LwCARKRGuMMbkZ/jm1nRLmeZ1jGLpjKS/SJBMftpzktdRjMeCKRx34lyHY4+IrBWRNdk/w5TNmKNsOFiZ2bubck3V77yOUiyJQFq16Yze3NLrKMZjwRxV1S1sKYwJwIebL+PaKt9SNv6A11GKrbSU6aT+8l9ezIT4eK/TGK8EUzhmA/8HpAE1cY6qGgM8GYZcxhxFFYZtasMbjQfnvpBd4jTsTiizluqJ25k1qwotbcej2Ap2yJGWwF3AWe7PS4A3wpDLmKMsWAD7skpyYYV3V2ovAAAY2UlEQVTfvI5S7HVL+Yrhw71OYbwUzB7H1UADVc0+U3yxiPyIM+jhzSFPZoyPYcOgR8pU4iT8lwEwebsh5Sv+82F39izvTLmE/c5EO/myWAlmj2MTUMZvWmlgY+jiGHOsQ4ec8wd6VJ/qdRQDpCTu4JIKCxn3dwuvoxiPBFM4RgBfiMgtItLOvXDSZGC4iLTMvoUnpinOJk+Gk06C+qXtf5RocVONL3hvo13ovbgKpqnqVvfnAL/pfd0bOBdeql/YUMYA/3R2D/v9cXpWngM1PM5j/nF58hxu/fNelu6rTeMy67yOYyIs4D0OVa0XwM2Khgmpvw9VYMaOM+hUdabXUYyPEnGZdEuZxgeb2nodxXggmKYqYyJu1JbLaF95NuUT9nkdxfi5qcYXDNvUmky1r5Hixn7jJmqpwjsbrqBXjcn5L2wirmnZVdQuuZWp25t7HcVEmBUOE7Xm7G7CQS1Bi4q/eB3F5OKm6lN4f5N1khc3wXSOGxNevmd+p6Xxzsb23FJjkl0eNop1qTadh1f0Yds2qFzZ6zQmUmyPw0Sl9P0l+GTrhfSs/qXXUUweKpZI54rKcxg50uskJpKscJio9PVPDbm04gK77kYRcGvNibz1ltMnZYoHKxwmKn3+3YncUnOS1zFMAC6q8CsA337rcRATMdbHYaLO/D2N2Z1eilb15nkdxQRABPr2hSFD4OKL3Yn+IxXbWFYxxfY4TNR5Z8MVXHHBHzagYRHSvTtMmQJbtnidxESCFQ4TVfZmlGLs3y1oe/6fXkcxQahUCa69Ft5/3+skJhKscJioMnJzKy6puJCqlexM8aKmb1946y3IyvI6iQk3KxwmaqjCa+uv4c5an3gdxRTAWWc5ex7z5lXyOooJMyscJmrM3Hk6ipBa8Wevo5gCyO4knzixptdRTJjZUVXGO35H3ry6fhD9an1iZ4oXRe7vMi2jFPct+IQ1p1ajTinrKY9VtsdhosLqAynM2nka3VPsKn9FWVLCAdqc9xevr7/a6ygmjKxwmKjw5oYr6Z4yjaSEA15HMYV0bcvfGbrxcvZmlPI6igkTKxzGc/szExm68XLuqPWp11FMCNSosoeLKy5k+OY2XkcxYWKFw3huzJaWNCu3lEZl1nsdxYTI3bX/x8vrriVLrcMqFlnhMJ5ShRfXXs89tcd7HcWE0EUVfqVs/AG+2H6211FMGFjhMJ6asv0cEiSTVpVsXKpYIgL31B7P4HXXeR3FhIEVDuOp59d25v7jPrJDcGPQ9dVm8nt6PX7fW9frKCbErHAYz8zb3Zjl+2vSuZqNnBqLSsYd5o5an/LC2s5eRzEhZoXDeOb5tV24u/b/KBGX6XUUEyZ31PyUidvOY9Uqr5OYULLCYTyxciV8veNMbqnxuddRTBhVLJHOLTUm8cILXicxoRSxwiEibUXkTxFZJiIP5zC/pIh85M7/UUTqutNbich8EfnN/dkyUplN+LzwAtxS83PKJez3OooJs3uOG8+oUbB5s9dJTKhEpHCISDzwOtAOaAKkiUgTv8V6ATtUtSHwEvCsO30rcKWqngL0BEZEIrMJn3XrYMwYuLf2OK+jmAhISdxBWhoMHux1EhMqkdrjOBtYpqorVPUQMAbo4LdMB2CYe388cKmIiKr+rKob3OmLgFIiUjIiqU1YPPss3HwzVE3c5XUUEyEPPADvvAM7d3qdxISCqIb/8pwi0hFoq6q93cfdgXNUtZ/PMr+7y6xzHy93l9nq9zp9VfWyHNbRB+gDkJKS0uzdd98lKSkpnG8raHv37i3emZYuZevOMtw8qCMfDBpHcvncm6n2JieTtH17ZHIFyDIFJsdMjRvz9NMnUqvWfnr0WO1NruL+9xeA1NTU+araPL/lIjWsek5H6ftXrDyXEZGmOM1XrXNagaq+DbwN0Lx5c01KSqJFixYFChsuM2fOLN6ZBg3i7r/uoHfyRK6d9F7eudLSaDF6dGRyBcgyBSbHTDNmUKsWnHcevPhiPSp5cK2nYv/3F0KRaqpaBxzn87g2sCG3ZUQkAagAbHcf1wY+AXqo6vKwpzVhsfFgMsM3t+bB46Lri85ERqNGcPXV2BFWMSBShWMu0EhE6olIItAFmOC3zASczm+AjsB0VVURqQhMAvqr6vcRymvC4Nk1afRImUr1kju8jmIiLTUVUlN5dFFn3nxuF1vsGk9FWkQKh6pmAP2AL4ElwFhVXSQij4vIVe5iQ4HKIrIMuBfIPmS3H9AQ+LeI/OLeqkUitwmdlSth5OZWDDj+Q6+jGA/VKbWFrilf8+yz+S9rolfELh2rqpOByX7THvW5fwDolMPzngCeCHtAE1aPPgr9an1CtUQ7rKa4G1DnQ07+4FruvRdq1fI6jSkIO3PchN0vv8C0aXDfcWO9jmKiQI2S2+nVCwYO9DqJKaiI7XGY4qt/f/i//4Ny/7OzxI1jwAA44QS480449VScPhBfM2zgy2hmexwmrL7+GpYuhT59vE5ioknFivDvf8O99zoX8zJFixUOEzaHD8O//gUvvgiJiV6nMdHm1lth/XqYNMnrJCZYVjhM2LzR5DVqbphLh8GpxzZFmGKvRAnnn4r774fDWfFexzFBsMJhwmLLFnhidTdebviaXd3PHMs9r6Pdc6nU3fITg9d19DqRCYIVDhMWjzwC3VOmcVLZNV5HMVFMBF5t9ArPrEljzQE7PauosMJhQsf9L/L7M+9k0vCtPFZ3WP7PMcVeozLr+Vftj7nrrzu9jmICZIXDhNSBzBL0/vN+Xm30KhUS0r2OY4qIh+qMZsm+Ony29QKvo5gAWOEwIfXkmm6cVGY111X9xusopggpGXeYNxu/xF1/9WN3Rhmv45h8WOEwIfPr3vq8teFKXmv0itdRTBGUWukX2iTP495lt3sdxeTDCocJiUOH4KY/HuKpeu9Ss+Q2r+OYIurFBm/w9c4z7dyOKGeFw4TEo49CrZJ/06vG5PwXNiYX5RL288GJz9KnD2yz/z+ilo1VZQrOPalvxo7TGbFkAL80f97O2TCFdknFhXROhb59YexY7DMVhWyPwxTKtsPl6fFHf94/8TmqJu7yOo6JEU/Na82yL/5iyAmDbdSBKGSFwxRYlgo3/vEQnarOonXyPK/jmBhSKv4w45oMZOCqnszb3djrOMaPFQ5TYI+v6sGujLI8W/8tr6OYGNSwzAbeaDSY6xc/xg672nBUscJhCmTCBBi66XLGNhlEibhMr+OYGNWx2jdcVfkH0tIgI8PrNCabFQ4TtCVLoHdvGNdkINVL2r+CJrxeaDAEVbjnHq+TmGxWOExQNmyAdu3ghRfg3ApLvI5jioGEuCzGjoXp0+G113JZyB0n7Z+bCSsrHCZgu3Y5RePWW6FHD6/TmOKkQgWYOBGefBI+/dTrNMbO4zABOXAArr0WLrwQHn7Y6zSmOKpfHz7/3PnnpWxZaNXK60TFl+1xmHzt3w8dOkC1avDKK3ZClvFOs2bw8cfQtSt8953XaYov2+MwecouGlWqwPDhEG9X+DRe8Om3uBAYNWoG114L48bBJZd4F6u4sj0Ok6tdu6B9e6ha1SkaCfZvhokSrZ5KZUzNe+nUagcTTxngdZxix74KTI7WrYPLL4eLL4aXX3b3NOxoFRNFWlb6mc9PGcBVvz3Jcxlv0aP6VK8jFRu2x2GOsXAhnH8+dO8Or75qzVMmep1d/g+mn34vA1f15KHlfchU+0qLBNvK5igffACXXeacp/HAA9YRbqJfk7Kr+enM25i75wSu/O1Jdh4u63WkmGdNVQaAffvgXw0/59udpzLz5MdoOmQVDPE6lTGBqZK4my9PfZD7lt/OGfPfYeT3cIFdvjxsbI/D8P33cPrpsC+zFHOb9aVp2VVeRzImaCXiMnml0asMbvg6110Hjz0Ghw97nSo2WeEoxvZcdDmvP5FMx5bbeCbxUT5s8iTlEvZ7HcuYQulQ5Xt+/hnmzoUzz3T+MTKhZYWjGMrKgmHD4MSfhrE7vRS/Nu/FtVW/9TqWMSFTowZMmuRc0rhzZ+jVC7ZuTfQ6VsywPo5iRNUZ72fQIOecjP81fYwDN51O1dF25T4TY1JTEaAT0KZeGZ6oPImbbz6LuXPhoYcgOdnrgEWb7XHEMnek0IxLLmV808c480znP7BHHoHZs210W1M8lE/Yx3NzUxn6yEfsHDGRxim7eOABWLPG62RFlxWOGLbxYDL/WdWdunPGMHhdRwYOhJ9/dgYrjLPfvClmqlbax1sn/Jd5zW4lKwvOOAO6dIFp0yDTrkUWFGuqKsr8z+SeMYNt25xB4MaMgQVzP6Bz1RlMOrU/pyUthw4zvMlpTBSpW3ozL77oHHU1bBj07w8bN0K3btCpk9OhHnfpsX9b5ggrHEVcpsaxYE8jvtx+FlMvds76btMG7rgD2h3uSOn4Q0cWtiFDjHGkplIeuBO4sxwsiqvLiNGtuOHVC9mbWZr2le+lXfKPXFTxNyqX2O112qhjhaMIUYXNm2HePPjxR/hp4XP8tOdEaiZuo3XyXAYMcMaWKlPGfcKrh/J8PWOMo2nZVTzT4B2eafAOS/fVZuK28xiyoQM9/uhPnZJbuOg2OOss53ynJk2gVCmvE3srYoVDRNoCLwPxwLuq+ozf/JLAcKAZsA3orKqr3Hn9gV5AJnCXqn4ZqdyRlpUFW7bA2rXOQIMrVjjX+F6yBJb85Pzn06zcUs4pt4Q7av3B8PJLSEl0r/vdtpOHyY2JDY3LrOO+MuO477hxZGTF8cvehnzb+C2mT4eXXoJly6BB3Eqall1Fg9IbqF9qA/WHPED9+lC7di6jSOfQrFyURaRwiEg88DrQClgHzBWRCaq62GexXsAOVW0oIl2AZ4HOItIE6AI0BWoCX4lIY1WNyu6sw4ed4Tv273d++t7/8cdkNm+G7duPvm3b5tw2LNjIhoOVqZCQznEl/6Z2y8bUrQvNmzsDDp40oCdVS+y08aOMiZCEuCyal19K8wnuF38VOJhcgsXpx7N4X11W7q/OD7tPZuTjsHw5bNoEFStCyr6VpCTucG/bqRDfkwoJ6VRISKd8fDoVpjmXw121qgwrVjh7MCVLHvkZ7ZcwiFS8s4FlqroCQETGAB0A38LRARjo3h8PvCYi4k4fo6oHgZUissx9vdnhCHrZZZCeDhkZzpEWOf3Mbd6hQ05zUpkyR26lSx+5v39/bY4/HipXdo4jr/HpEE4usZvkEntITthNzdO2USvxb0rFu+Mk7AZ+dW8A+Z2/ZH0YxoRdybjDnFFuGWeUW3Zk4ox2gPM9sG0bbLriCTYfqsSmQ8lsOVyRXRlJrD6Qwq7MsuzOKMuuZ2H3bti8uSnx8XBg/VYOZpXgQFYi+7NKEhcf908RSUx0RqjO6ZaQcOy0Bx6Aq68O7zYQVQ3vGgAR6Qi0VdXe7uPuwDmq2s9nmd/dZda5j5cD5+AUkzmqOtKdPhSYoqrj/dbRB+jjPjwBp7lrazjfVwFUwTIFKhpzWabARGMmiM5c0ZbpeFWtmt9CkdrjyKlxxb9i5bZMIM9FVd8G3v7nxUTmqWrzYEKGm2UKXDTmskyBicZMEJ25ojFTICJ1Gtg64Difx7WBDbktIyIJQAVge4DPNcYYEyGRKhxzgUYiUk9EEnE6uyf4LTMB6One7whMV6cdbQLQRURKikg9oBHwU4RyG2OM8RORpipVzRCRfsCXOIfjvqeqi0TkcWCeqk4AhgIj3M7v7TjFBXe5sTgd6RnAHQEeUfV2/otEnGUKXDTmskyBicZMEJ25ojFTviLSOW6MMSZ22FB3xhhjgmKFwxhjTFBiqnCIyPMi8oeI/Coin4hIRZ95/UVkmYj8KSJtIpipk4gsEpEsEWnuM72uiOwXkV/c25uRypRXLneeJ9vKL8NAEVnvs30u9yKHm6Wtuy2WicjDXuXwJyKrROQ3d/vM8yjDeyKyxT0PK3tasohME5G/3J+VoiCTp58nETlORGaIyBL37+5f7nRPt1WBqWrM3IDWQIJ7/1ngWfd+E2AhUBKoBywH4iOU6SScExJnAs19ptcFfvdwW+WWy7Nt5ZdvIHB/FHym4t1tUB/n3P2FQBOvc7nZVgFVPM5wMXCm72cZeA542L3/cPbfoceZPP08ATWAM9375YCl7t+ap9uqoLeY2uNQ1amqmuE+nINzzgf4DFuiqiuB7GFLIpFpiar+GYl1BSOPXJ5tqyj1z3A5qnoIyB4uxwCq+g3OUZC+OgDD3PvDgDAPgBFQJk+p6kZVXeDe3wMsAWrh8bYqqJgqHH5uBqa492sBa33mrXOnea2eiPwsIrNE5CKvw7iiaVv1c5sd3/NwFz6atoc/BaaKyHx3yJ1okaKqG8H5wgSqeZwnWzR8nhCRusAZwI9E77bKU5SPwXgsEfkKqJ7DrEdU9TN3mUdwzvn4MPtpOSwfsuOQA8mUg41AHVXdJiLNgE9FpKmqhuyqMQXMFdZtddSK8sgHDAH+4677P8CLOP8MRFrEtkcBXKCqG0SkGjBNRP5w/9s2x4qKz5OIJAH/A+5W1d1SRIe6LnKFQ1Uvy2u+iPQE2gOXqttwSJiHLckvUy7POQgcdO/Pdwd1bAyErJOzILmI4BAvgeYTkXeAz8ORIQBRO+SNqm5wf24RkU9wmtWioXBsFpEaqrpRRGoAW7wOpKqbs+979XkSkRI4ReNDVf3YnRx12yoQMdVUJc7Foh4CrlLVfT6zom7YEhGpKs51ShCR+m6mFV5mckXFtnL/iLJdA/ye27JhFshwOREnImVFpFz2fZwDQ7zaRv58hw/qCeS2dxsxXn+exNm1GAosUdX/+syKum0VEK9750N5w+nIXQv84t7e9Jn3CM7RMX8C7SKY6Rqc/1oPApuBL93p1wGLcI7SWQBcGeFtlWMuL7eVX74RwG84VyOZANTw8HN1Oc5RMMtxmvk8yeGXqb772Vnofo48yQWMxml2Pex+nnoBlYGvgb/cn8lRkMnTzxNwIU4z2a8+30+Xe72tCnqzIUeMMcYEJaaaqowxxoSfFQ5jjDFBscJhjDEmKFY4jDHGBMUKhzHGmKBY4TDGhzuK6kivcwRLRN4UkX8HuOxMEemdy7y6IqIiUuRODjaRYx8OY2KAqvb1OoMpPmyPwxRZ9l+xI3sEAmMixQqHKVLcixc9JCK/AukikiAiD4vIchHZIyKLReQan+VvFJHvROQFEdkhIitFpJ3P/Hru6MR7RGQaUMVvfVe5F97Z6TbxnOSX5QF3xNV0ERkqIikiMsV9va9yG4XVvaBPe5/HCSKyVUTOdB+PE5FNIrJLRL4RkaY+y34gIkNEZLKIpAOp7rQn3PmVRORzEfnbfc+fi0htvwgNROQn9/U/E5HkXHJWcN/XRnEuhPSEFSpjhcMURWnAFUBFda6/shy4CKgADAJG+o1NdA7O8ClVcC6cM1SODEs6CpjvzvsPR8YNQkQa4wxfcTdQFZgMTHTHrMp2HdAKZ4DKK3GG8h/gvl4ccFcu72G0+z6ytQG2qnvNBvd1GuEMs72AIyM9Z+sKPIlzUaDv/ObFAe8DxwN1gP3Aa37L9MAZHbYmzkjSr+SSc5g7vyHOUOCtgRz7R0wx4vWYJ3azWzA3nKve3ZzPMr8AHdz7N+JciCl7XhmcMYOq43ypZgBlfeaPAka69/8NjPWZFwesB1r4ZLnBZ/7/gCE+j+8EPs0lY0NgD1DGffwh8Gguy1Z0M1dwH38ADPdb5gPgiVyefzqww+fxTOAZn8dNgEM4Vzus664rAUjBGcustM+yacAMrz8HdvP2Zm3EpijyvbASItIDuBfnSw8giaObnDZl31HVfe7ORvYyO1Q13WfZ1RwZRr2m+zj7uVkispajL+S02ef+/hweJ+X0BlR1mYgsAa4UkYnAVTj/0Wf3WTwJdMLZ08lyn1YF2JXTNvAlImWAl4C2QHZTWTkRiVfVzByevxoogV8zHc4eSwlgo891I+LyWrcpHqxwmKLon5E5ReR44B3gUmC2qmaKyC/kfAEmfxuBSiJS1qd41PF5/Q3AKT7rEpyisr7wbwE40lwVByxW1WXu9K44lxS9DGevpgKwg6PfU16jk96Hcz35c1R1k4icDvzs93zfa4zUwRlJdqvf9LU4exxV9MglmY2xPg5T5JXF+RL9G0BEbgJODuSJqroa58JZg0QkUUQuxOmnyDYWuEJELnUvwnMfzhfpDyHKPganz+A2nCaybOXc9WzDaVp7KsjXLYezt7PT7fR+LIdluolIE3fv5HFgvM/eCPDPpUynAi+KSHkRiRORBiJySZB5TIyxwmGKNFVdjHMZ0Nk4zUSnAN8H8RJdcTrPt+N8wQ73ee0/gW7Aqzj/jV+Jc92UQyHKvtHNfT7wkc+s4TjNR+uBxcCcIF96MFAaJ/Mc4IsclhmB0y+yCShF7p34PYBEN8cOYDxQI5dlTTFh1+MwxhgTFNvjMMYYExQrHMYYY4JihcMYY0xQrHAYY4wJihUOY4wxQbHCYYwxJihWOIwxxgTFCocxxpig/D+FYfv0wtPuogAAAABJRU5ErkJggg==\n", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], - "source": [ - "# Create normal distribution sampler.\n", - "mu = 2.4\n", - "sigma = 5.1\n", - "start_time = time.time()\n", - "normal = NormalDistribution(glo_num_qubits, mu=mu, sigma=sigma, backend=glo_backend)\n", - "creation_time = time.time() - start_time\n", - "\n", - "# Draw a sample from the normal distribution.\n", - "start_time = time.time()\n", - "sample = normal.normal_rand_float64(size=4321)\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(\"time: creation: {:.5f}, sampling: {:.2f}\".format(creation_time, 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(\"random variable\", 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": [ - "Using basic linear algebra, we can correlate multivariate variables. Indeed, when $L$ is \n", - "the left Cholesky factor of the $n \\times n$ covariance matrix $\\Sigma= L L^T$,\n", - "and $\\mu$ is an $n$-vector,\n", - "and $x$ is an $n$-vector distributed according to the standard normal distribution,\n", - "then $\\mu + Lx$ is a random sample from $N(\\mu, \\Sigma)$.\n", - "\n", - "## Background\n", - "\n", - "In order to understand the implementation, it may be useful to see:\n", - "\n", - "Functions in the base class *UnivariateDistribution*\n", - "\n", - "```python\n", - "def uniform_rand_float64(self, size: int, vmin: float, vmax: float) -> np.ndarray:\n", - " \"\"\"\n", - " Generates a vector of random float64 values in the range [vmin, vmax].\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", - " nbits = 7 * 8 # nbits > mantissa of float64\n", - " bit_str_len = (nbits * size + self.num_target_qubits - 1) // self.num_target_qubits\n", - " job = execute(self.circuit, self.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", - "\n", - "```python\n", - "def uniform_rand_int64(self, size: int, vmin: int, vmax: int) -> np.ndarray:\n", - " \"\"\"\n", - " Generates a vector of random int64 values in the range [vmin, vmax].\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", - " return np.rint(self.uniform_rand_float64(size, float(vmin), float(vmax))).astype(np.int64)\n", - "```\n", - "\n", - "Function in the base class *NormalDistribution*:\n", - "\n", - "```python\n", - "def normal_rand_float64(self, size: int) -> np.ndarray:\n", - " \"\"\"\n", - " Draws a sample vector from standard normal distribution (mu=0, std=1)\n", - " using Box-Muller method.\n", - " \"\"\"\n", - " EPS = 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.\n", - " n = 2 * size\n", - " x = np.reshape(self.uniform_rand_float64(n, float(0.0), float(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 < EPS:\n", - " # Regenerate array of uniformly distributed samples upon shortage.\n", - " if c > n:\n", - " c = 0\n", - " n = max(((size // 10) // 2) * 2, 2)\n", - " x = np.reshape(self.uniform_rand_float64(n, float(0.0), float(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", - " return rand_vec\n", - "```" - ] - }, - { - "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/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": "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\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/__init__.py b/qiskit/finance/data_providers/__init__.py deleted file mode 100644 index 300002f49..000000000 --- a/qiskit/finance/data_providers/__init__.py +++ /dev/null @@ -1,20 +0,0 @@ -# -*- coding: utf-8 -*- - -# Copyright 2018 IBM. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# ============================================================================= - -from .drivers import * - -__all__ = ['drivers'] diff --git a/qiskit/finance/data_providers/drivers/__init__.py b/qiskit/finance/data_providers/drivers/__init__.py deleted file mode 100644 index 3c737a444..000000000 --- a/qiskit/finance/data_providers/drivers/__init__.py +++ /dev/null @@ -1,26 +0,0 @@ -# -*- coding: utf-8 -*- - -# Copyright 2018 IBM. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# ============================================================================= - -from ._basedriver import BaseDriver, UnitsType -from .dataondemand import DataOnDemandDriver -from .exhangedata import ExchangeDataDriver -from .wikipedia import WikipediaDriver - -__all__ = ['BaseDriver', - 'DataOnDemandDriver', - 'ExchangeDataDriver', - 'WikipediaDriver'] diff --git a/qiskit/finance/data_providers/drivers/_basedriver.py b/qiskit/finance/data_providers/drivers/_basedriver.py deleted file mode 100644 index 1993d517a..000000000 --- a/qiskit/finance/data_providers/drivers/_basedriver.py +++ /dev/null @@ -1,154 +0,0 @@ -# -*- coding: utf-8 -*- - -# Copyright 2018 IBM. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# ============================================================================= - -""" -This module implements the abstract base class for driver modules -within Qiskit Finance. - -To create add-on driver modules subclass the BaseDriver class in this module. -Doing so requires that the required driver interface is implemented. -""" - -from abc import ABC, abstractmethod -import copy -from qiskit.aqua.parser import JSONSchema -from enum import Enum -import logging - -logger = logging.getLogger(__name__) - - -class DataType(Enum): - DAILYADJUSTED = 'Daily (adj)' - DAILY = 'Daily' - - -class BaseDriver(ABC): - """ - Base class for Drivers. - - This method should initialize the module and its configuration, and - use an exception if a component of the module is available. - - """ - @abstractmethod - def __init__(self): - self.check_driver_valid() - self._configuration = copy.deepcopy(self.CONFIGURATION) - self._work_path = None - - @property - def configuration(self): - """Return driver configuration.""" - return self._configuration - - @classmethod - def init_from_input(cls, section): - """ - Initialize via section dictionary. - - Args: - params (dict): section dictionary - - Returns: - Driver: Driver object - """ - pass - - @staticmethod - def check_driver_valid(): - """Checks if driver is ready for use. Throws an exception if not""" - pass - - def validate(self, args_dict): - schema_dict = self.CONFIGURATION.get('input_schema', None) - if schema_dict is None: - return - - jsonSchema = JSONSchema(schema_dict) - schema_property_names = jsonSchema.get_default_section_names() - json_dict = {} - for property_name in schema_property_names: - if property_name in args_dict: - json_dict[property_name] = args_dict[property_name] - - jsonSchema.validate(json_dict) - - @property - def work_path(self): - return self._work_path - - @work_path.setter - def work_path(self, new_work_path): - self._work_path = new_work_path - - @abstractmethod - def run(self): - pass - - # gets coordinates suitable for plotting - # it does not have to be overridden in non-abstract derived classes. - def get_coordinates(self): - # Coordinates for visualisation purposes - xc = np.zeros([self.n, 1]) - yc = np.zeros([self.n, 1]) - xc = (np.random.rand(self.n) - 0.5) * 1 - yc = (np.random.rand(self.n) - 0.5) * 1 - #for (cnt, s) in enumerate(self.tickers): - #xc[cnt, 1] = self.data[cnt][0] - # yc[cnt, 0] = self.data[cnt][-1] - return xc, yc - - # it does not have to be overridden in non-abstract derived classes. - def get_covariance(self): - if not self._data: return None - self.cov = np.cov(self._data, rowvar = True) - return self.cov - - # it does not have to be overridden in non-abstract derived classes. - def get_similarity_matrix(self): - if not self.data: return None - try: - import fastdtw - for ii in range(0, self._n): - self.rho[ii,ii] = 1. - for jj in range(ii + 1, self.n): - thisRho, path = fastdtw.fastdtw(self._data[ii], self._data[jj]) - self.rho[ii, jj] = thisRho - self.rho[jj, ii] = self.rho[ii, jj] - self.rho = self.rho / np.nanmax(self.rho) - for ii in range(0, self.n): - self.rho[ii,ii] = 1. - except ImportError: - print("This requires fastdtw package.") - return self.rho - - # it does not have to be overridden in non-abstract derived classes. - def plot(self): - #for (cnt, s) in enumerate(self.tickers): - # plot(self.data[cnt], grid = True, label=s) - #plt.legend() - #plt.title("Evolution of the adjusted closing price") - #plt.show() - self.get_covariance() - self.get_similarity_matrix() - print("Top: a similarity measure. Bottom: covariance matrix.") - plt.subplot(211) - plt.imshow(self.rho) - plt.subplot(212) - plt.imshow(self.cov) - plt.show() \ No newline at end of file diff --git a/qiskit/finance/data_providers/drivers/algorithminput.py b/qiskit/finance/data_providers/drivers/algorithminput.py deleted file mode 100644 index b68d5e96b..000000000 --- a/qiskit/finance/data_providers/drivers/algorithminput.py +++ /dev/null @@ -1,67 +0,0 @@ -# -*- coding: utf-8 -*- - -# Copyright 2018 IBM. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# ============================================================================= - -from qiskit.aqua import Pluggable -from abc import abstractmethod -import copy -from qiskit.aqua import AquaError - - -class AlgorithmInput(Pluggable): - - _PROBLEM_SET = ['portfoliodiversification', 'portfoliooptimisation'] - - @abstractmethod - def __init__(self): - super().__init__() - if 'problems' not in self.configuration or len(self.configuration['problems']) <= 0: - raise AquaError('Algorithm Input missing or empty configuration problems') - - for problem in self.configuration['problems']: - if problem not in AlgorithmInput._PROBLEM_SET: - raise AquaError('Problem {} not in known problem set {}'.format(problem, AlgorithmInput._PROBLEM_SET)) - - @property - def all_problems(self): - return copy.deepcopy(self._PROBLEM_SET) - - @property - def problems(self): - """ - Gets the set of problems that this input form supports - """ - return self.configuration.problems - - @abstractmethod - def to_params(self): - """ - Convert the derived algorithminput class fields to a dictionary where the values are in a - form that can be saved to json - Returns: - Dictionary of input fields - """ - raise NotImplementedError() - - @abstractmethod - def from_params(self, params): - """ - Load the dictionary into the algorithminput class fields. This dictionary being that as - created by to_params() - Args: - params: A dictionary as originally created by to_params() - """ - raise NotImplementedError() diff --git a/qiskit/finance/data_providers/drivers/dataondemand/README.md b/qiskit/finance/data_providers/drivers/dataondemand/README.md deleted file mode 100644 index 836eb7f04..000000000 --- a/qiskit/finance/data_providers/drivers/dataondemand/README.md +++ /dev/null @@ -1,14 +0,0 @@ -# Qiskit Finance - -## Stock market data driver for NASDAQ Data on Demand - -NASDAQ is a major vendor of stock market data. It provides data not only for NASDAQ -issues, but also for NYSE etc. - -This driver requires Data on Demand API Token. - -## Example query - -The data are obtained by running a query through the REST API. -``` -``` diff --git a/qiskit/finance/data_providers/drivers/dataondemand/__init__.py b/qiskit/finance/data_providers/drivers/dataondemand/__init__.py deleted file mode 100644 index 682ce312d..000000000 --- a/qiskit/finance/data_providers/drivers/dataondemand/__init__.py +++ /dev/null @@ -1,21 +0,0 @@ -# -*- coding: utf-8 -*- - -# Copyright 2018 IBM. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# ============================================================================= - -from .dataondemanddriver import DataOnDemandDriver - -__all__ = ['DataOnDemandDriver', - 'StockMarket'] diff --git a/qiskit/finance/data_providers/drivers/dataondemand/dataondemanddriver.py b/qiskit/finance/data_providers/drivers/dataondemand/dataondemanddriver.py deleted file mode 100644 index 6ef8e50d0..000000000 --- a/qiskit/finance/data_providers/drivers/dataondemand/dataondemanddriver.py +++ /dev/null @@ -1,156 +0,0 @@ -# -*- coding: utf-8 -*- - -# Copyright 2018 IBM. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# ============================================================================= - -from qiskit.aqua.drivers import BaseDriver, UnitsType -import importlib -from enum import Enum -import logging - -logger = logging.getLogger(__name__) - - -class StockMarket(Enum): - NASDAQ = 'NASDAQ' - NYSE = 'NYSE' - -class DataOnDemandDriver(BaseDriver): - """Python implementation of an NASDAQ Data on Demand driver.""" - - CONFIGURATION = { - "name": "DOD", - "description": "NASDAQ Data on Demand Driver", - "input_schema": { - "$schema": "http://json-schema.org/schema#", - "id": "dod_schema", - "type": "object", - "properties": { - STOCKMARKET: { - "type": "string", - "default": StockMarket.NASDAQ.value, - "oneOf": [ - {"enum": [ - StockMarket.NASDAQ.value, - StockMarket.NYSE.value, - ]} - ] - }, - DATATYPE: { - "type": "string", - "default": DataType.DAILYADJUSTED.value, - "oneOf": [ - {"enum": [ - DataType.DAILYADJUSTED.value, - DataType.DAILY.value, - DataType.BID.value, - DataType.ASK.value, - ]} - ] - }, - }, - } - } - - def __init__(self, - token, - tickers, - stockmarket = StockMarket.NASDAQ, - start = datetime.datetime(2016,1,1), - end = datetime.datetime(2016,1,30)): - """ - Initializer - Args: - token (str): quandl access token - tickers (str or list): tickers - stockmarket (StockMarket): LONDON, EURONEXT, or SINGAPORE - """ - if not isinstance(atoms, list) and not isinstance(atoms, str): - raise QiskitFinanceError("Invalid atom input for DOD Driver '{}'".format(atoms)) - - if isinstance(tickers, list): - self._tickers = ';'.join(tickers) - else: - self._tickers = tickers.replace('\n', ';') - self._n = len(self._tickers.split(";")) - - self.validate(locals()) - super().__init__() - self._stockmarket = stockmarket # .value? - self._token = token - self._start = start - self._end = end - - @staticmethod - def check_driver_valid(): - err_msg = 'quandl is not installed.' - try: - spec = importlib.util.find_spec('quandl') - if spec is not None: - return - except Exception as e: - logger.debug('quandl check error {}'.format(str(e))) - raise QiskitFinanceError(err_msg) from e - - raise QiskitFinanceError(err_msg) - - @classmethod - def init_from_input(cls, section): - """ - Initialize via section dictionary. - - Args: - params (dict): section dictionary - - Returns: - Driver: Driver object - """ - if section is None or not isinstance(section, dict): - raise QiskitFinanceError('Invalid or missing section {}'.format(section)) - - params = section - kwargs = {} - #for k, v in params.items(): - # if k == ExchangeDataDriver. ...: v = UnitsType(v) - # kwargs[k] = v - logger.debug('init_from_input: {}'.format(kwargs)) - return cls(**kwargs) - - def run(self): - import re - import urllib - import urllib2 - import json - url = 'https://dataondemand.nasdaq.com/api/v1/quotes' - self._data = [] - for ticker in self._tickers: - values = {'_Token' : self._token, - 'symbols' : [ticker] - 'start' : start.strftime("%Y-%m-%d'T'%H:%M:%S.%f'Z'") , - 'end' : end.strftime("%Y-%m-%d'T'%H:%M:%S.%f'Z'") , - 'next_cursor': 0 - #'start' : start.strftime("%m/%d/%Y %H:%M:%S.%f") , - #'end' : end.strftime("%m/%d/%Y %H:%M:%S.%f") , - } - request_parameters = urllib.urlencode(values) - req = urllib2.Request(url, request_parameters) - try: - response = urllib2.urlopen(req) - quotes = json.loads(response)["quotes"] - priceEvolution = [] - for q in quotes: priceEvolution.append(q["ask_price"]) - self._data.append(priceEvolution) - except: - raise QiskitFinanceError('Accessing Qiskit failed') diff --git a/qiskit/finance/data_providers/drivers/exchangedata/README.md b/qiskit/finance/data_providers/drivers/exchangedata/README.md deleted file mode 100644 index 31ec5e883..000000000 --- a/qiskit/finance/data_providers/drivers/exchangedata/README.md +++ /dev/null @@ -1,22 +0,0 @@ -# Qiskit Finance - -## Stock market data driver for Exchange Data International - -Exchange Data International is a major vendor of stock-market data. See -https://www.exchange-data.com/about_us.php#edi - -For samples of the data, please see: -https://www.quandl.com/data/XSES-Singapore-Exchange-Prices -https://www.quandl.com/data/XBER-Berlin-Stock-Exchange-Prices -https://www.quandl.com/data/XPAR-Euronext-Paris-Stock-Prices/documentation - -This driver requires Quandl API Token. - -## Example query - -The data are obtained by running a query through quandl. See: -https://docs.quandl.com/docs/parameters-2#section-times-series-parameters -for details. - -``` -``` diff --git a/qiskit/finance/data_providers/drivers/exchangedata/__init__.py b/qiskit/finance/data_providers/drivers/exchangedata/__init__.py deleted file mode 100644 index 26e0bf76f..000000000 --- a/qiskit/finance/data_providers/drivers/exchangedata/__init__.py +++ /dev/null @@ -1,21 +0,0 @@ -# -*- coding: utf-8 -*- - -# Copyright 2018 IBM. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# ============================================================================= - -from .exchangedatadriver import ExchangeDataDriver, StockMarket - -__all__ = ['ExchangeDataDriver', - 'StockMarket'] diff --git a/qiskit/finance/data_providers/drivers/exchangedata/exchangedatadriver.py b/qiskit/finance/data_providers/drivers/exchangedata/exchangedatadriver.py deleted file mode 100644 index b2458b165..000000000 --- a/qiskit/finance/data_providers/drivers/exchangedata/exchangedatadriver.py +++ /dev/null @@ -1,138 +0,0 @@ -# -*- coding: utf-8 -*- - -# Copyright 2018 IBM. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# ============================================================================= - -from qiskit.aqua.drivers import BaseDriver, UnitsType -import importlib -from enum import Enum -import logging - -logger = logging.getLogger(__name__) - - -class StockMarket(Enum): - LONDON = 'XLON' - EURONEXT = 'XPAR' - SINGAPORE = 'XSES' - -class ExchangeDataDriver(BaseDriver): - """Python implementation of an Exchange Data driver.""" - - CONFIGURATION = { - "name": "EDI", - "description": "Exchange Data International Driver", - "input_schema": { - "$schema": "http://json-schema.org/schema#", - "id": "edi_schema", - "type": "object", - "properties": { - STOCKMARKET: { - "type": "string", - "default": StockMarket.LONDON.value, - "oneOf": [ - {"enum": [ - StockMarket.LONDON.value, - StockMarket.EURONEXT.value, - StockMarket.SINGAPORE.value, - ]} - ] - }, - DATATYPE: { - "type": "string", - "default": DataType.LONDON.value, - "oneOf": [ - {"enum": [ - DataType.DAILYADJUSTED.value, - DataType.DAILY.value, - ]} - ] - }, - }, - } - } - - def __init__(self, - token, - tickers, - stockmarket = StockMarket.LONDON, - start = datetime.datetime(2016,1,1), - end = datetime.datetime(2016,1,30)): - """ - Initializer - Args: - token (str): quandl access token - tickers (str or list): tickers - stockmarket (StockMarket): LONDON, EURONEXT, or SINGAPORE - """ - if not isinstance(atoms, list) and not isinstance(atoms, str): - raise QiskitFinanceError("Invalid atom input for PYQUANTE Driver '{}'".format(atoms)) - - if isinstance(tickers, list): - tickers = ';'.join(tickers) - else: - tickers = tickers.replace('\n', ';') - self._n = len(self._tickers.split(";")) - - self.validate(locals()) - super().__init__() - self._stockmarket = stockmarket # .value? - self._token = token - self._tickers = tickers - self._start = start - self._end = end - - @staticmethod - def check_driver_valid(): - err_msg = 'quandl is not installed.' - try: - spec = importlib.util.find_spec('quandl') - if spec is not None: - return - except Exception as e: - logger.debug('quandl check error {}'.format(str(e))) - raise QiskitFinanceError(err_msg) from e - - raise QiskitFinanceError(err_msg) - - @classmethod - def init_from_input(cls, section): - """ - Initialize via section dictionary. - - Args: - params (dict): section dictionary - - Returns: - Driver: Driver object - """ - if section is None or not isinstance(section, dict): - raise QiskitFinanceError('Invalid or missing section {}'.format(section)) - - params = section - kwargs = {} - #for k, v in params.items(): - # if k == ExchangeDataDriver. ...: v = UnitsType(v) - # kwargs[k] = v - logger.debug('init_from_input: {}'.format(kwargs)) - return cls(**kwargs) - - def run(self): - import quandl - quandl.ApiConfig.api_key = self._token - quandl.ApiConfig.api_version = '2015-04-09' - for (cnt, s) in enumerate(self._tickers): - d = quandl.get(self._stockmarket + "/" + s, start_date=self._start, end_date=self._end) - self._data.append(d["close"]) diff --git a/qiskit/finance/data_providers/drivers/wikipedia/README.md b/qiskit/finance/data_providers/drivers/wikipedia/README.md deleted file mode 100644 index f5dc77c2f..000000000 --- a/qiskit/finance/data_providers/drivers/wikipedia/README.md +++ /dev/null @@ -1,11 +0,0 @@ -# Qiskit Finance - -## Stock market data driver for Wikipedia - -Wikipedia contains stockmarket data, that are rather reliable up until 2018. - -## Example query - -The data are obtained by running a query through quandl. -``` -``` diff --git a/qiskit/finance/data_providers/drivers/wikipedia/__init__.py b/qiskit/finance/data_providers/drivers/wikipedia/__init__.py deleted file mode 100644 index 7324d1dd5..000000000 --- a/qiskit/finance/data_providers/drivers/wikipedia/__init__.py +++ /dev/null @@ -1,21 +0,0 @@ -# -*- coding: utf-8 -*- - -# Copyright 2018 IBM. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# ============================================================================= - -from .wikipediadriver import WikipediaDriver, StockMarket - -__all__ = ['WikipediaDriver', - 'StockMarket'] diff --git a/qiskit/finance/data_providers/drivers/wikipedia/wikipediadriver.py b/qiskit/finance/data_providers/drivers/wikipedia/wikipediadriver.py deleted file mode 100644 index e3900cd20..000000000 --- a/qiskit/finance/data_providers/drivers/wikipedia/wikipediadriver.py +++ /dev/null @@ -1,136 +0,0 @@ -# -*- coding: utf-8 -*- - -# Copyright 2018 IBM. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# ============================================================================= - -from qiskit.aqua.drivers import BaseDriver, UnitsType -import importlib -from enum import Enum -import logging - -logger = logging.getLogger(__name__) - - -class StockMarket(Enum): - NASDAQ = 'NASDAQ' - NYSE = 'NYSE' - -class WikipediaDriver(BaseDriver): - """Python implementation of a Wikipedia driver.""" - - CONFIGURATION = { - "name": "WIKI", - "description": "Wikipedia Driver", - "input_schema": { - "$schema": "http://json-schema.org/schema#", - "id": "edi_schema", - "type": "object", - "properties": { - STOCKMARKET: { - "type": "string", - "default": StockMarket.NASDAQ.value, - "oneOf": [ - {"enum": [ - StockMarket.NASDAQ.value, - StockMarket.NYSE.value, - ]} - ] - }, - DATATYPE: { - "type": "string", - "default": DataType.DAILYADJUSTED.value, - "oneOf": [ - {"enum": [ - DataType.DAILYADJUSTED.value, - DataType.DAILY.value, - ]} - ] - }, - }, - } - } - - def __init__(self, - token = "", - tickers, - stockmarket = StockMarket.LONDON, - start = datetime.datetime(2016,1,1), - end = datetime.datetime(2016,1,30)): - """ - Initializer - Args: - token (str): quandl access token, which is not needed, strictly speaking - tickers (str or list): tickers - stockmarket (StockMarket): NASDAQ, NYSE - """ - if not isinstance(atoms, list) and not isinstance(atoms, str): - raise QiskitFinanceError("Invalid atom input for Wikipedia Driver '{}'".format(atoms)) - - if isinstance(tickers, list): - tickers = ';'.join(tickers) - else: - tickers = tickers.replace('\n', ';') - self._n = len(self._tickers.split(";")) - - self.validate(locals()) - super().__init__() - self._stockmarket = stockmarket # .value? - self._token = token - self._tickers = tickers - self._start = start - self._end = end - - @staticmethod - def check_driver_valid(): - err_msg = 'quandl is not installed.' - try: - spec = importlib.util.find_spec('quandl') - if spec is not None: - return - except Exception as e: - logger.debug('quandl check error {}'.format(str(e))) - raise QiskitFinanceError(err_msg) from e - - raise QiskitFinanceError(err_msg) - - @classmethod - def init_from_input(cls, section): - """ - Initialize via section dictionary. - - Args: - params (dict): section dictionary - - Returns: - Driver: Driver object - """ - if section is None or not isinstance(section, dict): - raise QiskitFinanceError('Invalid or missing section {}'.format(section)) - - params = section - kwargs = {} - #for k, v in params.items(): - # if k == ExchangeDataDriver. ...: v = UnitsType(v) - # kwargs[k] = v - logger.debug('init_from_input: {}'.format(kwargs)) - return cls(**kwargs) - - def run(self): - import quandl - quandl.ApiConfig.api_key = self._token - quandl.ApiConfig.api_version = '2015-04-09' - for (cnt, s) in enumerate(self._tickers): - d = quandl.get("WIKI/" + s, start_date=self._start, end_date=self._end) - self._data.append(d["close"]) diff --git a/qiskit/finance/data_providers/time_series.ipynb b/qiskit/finance/data_providers/time_series.ipynb index bb6641b93..8ef7b99a2 100644 --- a/qiskit/finance/data_providers/time_series.ipynb +++ b/qiskit/finance/data_providers/time_series.ipynb @@ -11,7 +11,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "# _*Qiskit Finance: Loading Time Series Data*_\n", + "# _*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", @@ -33,7 +33,7 @@ }, { "cell_type": "code", - "execution_count": 1, + "execution_count": 17, "metadata": { "scrolled": true }, @@ -41,22 +41,139 @@ "source": [ "%matplotlib inline\n", "from qiskit.aqua.translators.data_providers import *\n", - "from qiskit.aqua.translators.data_providers.wikipediadataprovider import StockMarket\n", "import warnings\n", "warnings.filterwarnings(\"ignore\", category=DeprecationWarning)\n", - "import datetime" + "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": 2, + "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": [ - "Evolution of the stock price:\n", + "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", @@ -102,52 +219,19 @@ "2016-01-29 94.044912\n", "Name: Adj. Close, dtype: float64\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 time-series similarity measure:\n", - "[[1.00000000e+00 8.44268222e-05]\n", - " [8.44268222e-05 1.00000000e+00]]\n", - "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": [ - "wiki = WikipediaDataProvider(token = \"\",\n", - " tickers = [\"GOOG\", \"AAPL\"],\n", - " stockmarket = StockMarket.NASDAQ.value,\n", - " start = datetime.datetime(2016,1,1),\n", - " end = datetime.datetime(2016,1,30))\n", - "wiki.run()\n", - "wiki.plot()" + "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])" ] }, { @@ -156,22 +240,33 @@ "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.\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": 3, + "execution_count": 13, "metadata": {}, "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/Users/jmarecek/anaconda3/envs/localqiskit/lib/python3.7/site-packages/urllib3/connectionpool.py:847: InsecureRequestWarning: Unverified HTTPS request is being made. Adding certificate verification is strongly advised. See: https://urllib3.readthedocs.io/en/latest/advanced-usage.html#ssl-warnings\n", - " InsecureRequestWarning)\n" - ] - }, { "name": "stdout", "output_type": "stream", @@ -196,15 +291,25 @@ " 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": 4, + "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" ] } @@ -219,16 +324,17 @@ " end = datetime.datetime(2019,1,30))\n", " lse.run()\n", " lse.plot()\n", - "except QiskitFinanceError: \n", + "except QiskitFinanceError as e: \n", + " print(e)\n", " print(\"You need to replace REPLACE-ME with a valid token.\")" ] }, { - "cell_type": "code", - "execution_count": null, + "cell_type": "markdown", "metadata": {}, - "outputs": [], - "source": [] + "source": [ + "For the actual use of the data, please see the portfolio_optimization or portfolio_diversification notebooks. " + ] } ], "metadata": { diff --git a/qiskit/finance/optimization/portfolio_diversification.ipynb b/qiskit/finance/optimization/portfolio_diversification.ipynb index bcdcdca32..5b3a04b52 100644 --- a/qiskit/finance/optimization/portfolio_diversification.ipynb +++ b/qiskit/finance/optimization/portfolio_diversification.ipynb @@ -4,27 +4,41 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "# Portfolio diversification: classical and quantum solutions\n", + "" + ] + }, + { + "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", - "## Contributors\n", - "Andrea Simonetto, Jakub Marecek, Martin Mevissen; IBM Research -- Ireland\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 ca 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", + "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 daily stock-price data from Wikipedia, whereas in a real asset management, this may come from a Reuters, Bloomberg, or similar at a much higher frequency.\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 (CPLEX) on the classical computer. Second, we run an alternative, hybrid algorithm partly on the quantum computer.\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", @@ -100,13 +114,13 @@ "\n", "### Construct the Ising Hamiltonian\n", "\n", - "We can now construct the Ising Hamiltonian by penalty methods (introducting a penalty coefficient $A$ for each equality constraint) as\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 QP formulation \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", @@ -173,45 +187,28 @@ "source": [ "## The Implementation\n", "\n", - "If everything has been installed, the following should run without any errors. \n", - "If there are errors, please refer to Installation.ipynb for details." + "First, we import the requisite modules." ] }, { "cell_type": "code", - "execution_count": 14, + "execution_count": 7, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "localqiskit\n", - "/Users/jmarecek/anaconda3/envs/localqiskit/bin/python\n" - ] - } - ], + "outputs": [], "source": [ - "import os\n", - "print(os.environ['CONDA_DEFAULT_ENV'])\n", - "#!source activate localqiskit\n", - "#!conda list\n", - "#help(\"modules\")\n", - "# If you get errors, you can install from here using:\n", - "#!conda install -y --name localqiskit quandl\n", - "#!conda install -y -c bioconda --name localqiskit fastdtw\n", - "print(sys.executable)\n", - "\n", "# 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", @@ -220,7 +217,6 @@ "from qiskit.aqua import QuantumInstance\n", "from qiskit.aqua import Operator, run_algorithm\n", "from qiskit.aqua.input import EnergyInput\n", - "from qiskit.aqua.translators.ising import portfolio\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", @@ -228,87 +224,85 @@ "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", - "from qiskit.aqua.translators.ising import portfoliodiv" + "# 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": [ - "We then initialize the variables" + "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": 15, - "metadata": {}, - "outputs": [], + "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": [ - "# Initialize the problem by defining the parameters\n", + "# 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", - "n = 2 # Number of inner variables\n", - "q = 1 # Number of clusters, q less or equal than 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": [ - "We define get data either by randomly placing the assets in a 2-D plane and computing the distance between them (the closer they are in this plane, the more similar they are), or by actually downloading stock-market price data and computing the dynamic time warping distance and normalising it to (0,1]. Either way, we obtain the `rho` matrix. " + "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": 16, + "execution_count": 22, "metadata": {}, "outputs": [], "source": [ - "# The code for generating a random rho or obtain stock-market data\n", - "\n", - "from qiskit.aqua.input.portfoliodata import *" - ] - }, - { - "cell_type": "code", - "execution_count": 17, - "metadata": { - "scrolled": true - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[[-1. -0.83591861]\n", - " [-0.83591861 -1. ]]\n" - ] - } - ], - "source": [ - "# Initialize the problem by randomly generating the similarity matrix rho\n", - "\n", - "data = RandomData(n)\n", - "xc,yc,rho = data.generate_instance()\n", - "try:\n", - " data = RealData(n, plots=True)\n", - " #data = RealData(n, plots=False)\n", - "except:\n", - " print(\"Cannot load real data, possibly due to issues with pandas.\")\n", - "print(rho)" + "q = 1 # q less or equal than wiki._n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "## Classical solution using IBM CPLEX\n", + "## 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": 39, + "execution_count": 23, "metadata": {}, "outputs": [], "source": [ @@ -395,7 +389,7 @@ }, { "cell_type": "code", - "execution_count": 40, + "execution_count": 24, "metadata": {}, "outputs": [ { @@ -409,7 +403,7 @@ ], "source": [ "# Instantiate the classical optimizer class\n", - "classical_optimizer = ClassicalOptimizer(rho,n,q)\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", @@ -420,7 +414,7 @@ }, { "cell_type": "code", - "execution_count": 41, + "execution_count": 25, "metadata": {}, "outputs": [], "source": [ @@ -446,11 +440,9 @@ " 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.title(title_str +' cost = ' + str(int(C * 100) / 100.))\n", " plt.show()\n", - " \n", - "\n", - "# Eventually, you can runvisualize_solution(xc, yc, x, classical_cost, n, q, 'Classical')" + " " ] }, { @@ -464,101 +456,75 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "## Quantum solution using IBM-Q simulator\n", - "\n", - "For the quantum solution, we use Qskit. 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", - "- `binary_representation` : encodes the problem $(M)$ into a the Ising Hamiltonian QP (that's basically linear algebra);\n", - "- `construct_hamiltonian` : constructs the Ising Hamiltonian in terms of the $Z$ basis;\n", - "- `check_hamiltonian` : makes sure that the Ising Hamiltonian is correctly encoded in the $Z$ basis: to do this, it solves a eigenvalue-eigenvector problem for a symmetric matrix of dimension $2^N \\times 2^N$. For the problem at hand $n=3$, that is $N = 12$ seems the limit; \n", - "- `vqe_solution` : solves the problem $(M)$ via VQE by using the SPSA solver (with default parameters);\n", - "- `_q_solution` : internal routine to represent the solution in a usable format.\n" + "## 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": 42, + "execution_count": 26, "metadata": {}, "outputs": [], "source": [ "class QuantumOptimizer:\n", "\n", - " def __init__(self, rho,n,q,max_trials=1000):\n", + " def __init__(self, rho, n, q):\n", "\n", " self.rho = rho\n", " self.n = n\n", " self.q = q\n", - " self.max_trials = max_trials\n", "\n", " def construct_hamiltonian(self):\n", + " return portfoliodiversification.get_portfoliodiversification_qubitops(self.rho, self.n, self.q)\n", "\n", - " return portfoliodiv.get_portfoliodiversification_qubitops(self.rho, self.n, self.q, self.max_trials)\n", - "\n", - " def check_hamiltonian(self):\n", - "\n", - " Op = self.construct_hamiltonian()\n", - " qubitOp, offset = Op, 0\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", - "\n", - " # Making the Hamiltonian in its full form and getting the lowest eigenvalue and eigenvector\n", - "\n", " algorithm_cfg = {\n", " 'name': 'ExactEigensolver',\n", " }\n", - "\n", " params = {\n", " 'problem': {'name': 'ising'},\n", " 'algorithm': algorithm_cfg\n", " }\n", " result = run_algorithm(params, algo_input)\n", - "\n", - " quantum_solution = self._q_solution(result['eigvecs'][0],self.n*(self.n+1))\n", - " ground_level = result['energy'] + offset\n", - "\n", - " return quantum_solution, ground_level\n", + " return self.decode_result(result)\n", "\n", " def vqe_solution(self):\n", - "\n", " qubitOp = self.construct_hamiltonian()\n", - " algo_input = EnergyInput(qubitOp)\n", - "\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=3, entanglement='full')\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(algo_input)\n", - "\n", - " #quantum_solution = self._q_solution(result['eigvecs'][0], self.n * (self.n + 1))\n", - " quantum_solution_dict = result['eigvecs'][0]\n", - "\n", - " q_s = max(quantum_solution_dict.items(), key=operator.itemgetter(1))[0]\n", - " quantum_solution= [int(chars) for chars in q_s]\n", - " quantum_solution = np.flip(quantum_solution, axis=0)\n", - "\n", - " #_,_,_,level = self.binary_representation(x_sol=quantum_solution)\n", - " return quantum_solution_dict, quantum_solution\n", - "\n", - " def _q_solution(self, v, N):\n", - "\n", - " index_value = [x for x in range(len(v)) if v[x] == max(v)][0]\n", - " string_value = \"{0:b}\".format(index_value)\n", - "\n", - " while len(string_value)\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[0;31m# Check if the binary representation is correct\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 2\u001b[0;31m \u001b[0mQ\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0mg\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0mc\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0mquantum_cost\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mquantum_optimizer\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mvqe_solution\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 3\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 4\u001b[0m \u001b[0msol\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mclassical_cost\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mClassicalOptimizer\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mcplex_solution\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 5\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;32m\u001b[0m in \u001b[0;36mvqe_solution\u001b[0;34m(self)\u001b[0m\n\u001b[1;32m 48\u001b[0m \u001b[0mvqe\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mrandom_seed\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mseed\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 49\u001b[0m \u001b[0mquantum_instance\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mQuantumInstance\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mbackend\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mbackend\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mseed\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mseed\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mseed_mapper\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mseed\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 50\u001b[0;31m \u001b[0mresult\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mvqe\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mrun\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0malgo_input\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 51\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 52\u001b[0m \u001b[0;31m#quantum_solution = self._q_solution(result['eigvecs'][0], self.n * (self.n + 1))\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;32m~/anaconda3/lib/python3.7/site-packages/qiskit_aqua/algorithms/quantum_algorithm.py\u001b[0m in \u001b[0;36mrun\u001b[0;34m(self, quantum_instance, **kwargs)\u001b[0m\n\u001b[1;32m 101\u001b[0m \u001b[0mquantum_instance\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mset_config\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 102\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_quantum_instance\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mquantum_instance\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 103\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_run\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 104\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 105\u001b[0m \u001b[0;34m@\u001b[0m\u001b[0mabstractmethod\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;32m~/anaconda3/lib/python3.7/site-packages/qiskit_aqua/algorithms/adaptive/vqe/vqe.py\u001b[0m in \u001b[0;36m_run\u001b[0;34m(self)\u001b[0m\n\u001b[1;32m 266\u001b[0m \u001b[0mDictionary\u001b[0m \u001b[0mof\u001b[0m \u001b[0mresults\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 267\u001b[0m \"\"\"\n\u001b[0;32m--> 268\u001b[0;31m \u001b[0;32mif\u001b[0m \u001b[0;32mnot\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_quantum_instance\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mis_statevector\u001b[0m \u001b[0;32mand\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_operator_mode\u001b[0m \u001b[0;34m==\u001b[0m \u001b[0;34m'matrix'\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 269\u001b[0m logger.warning('Qasm simulation does not work on {} mode, changing '\n\u001b[1;32m 270\u001b[0m 'the operator_mode to \"paulis\"'.format(self._operator_mode))\n", - "\u001b[0;31mAttributeError\u001b[0m: 'EnergyInput' object has no attribute 'is_statevector'" - ] - } - ], + "outputs": [], "source": [ - "# Check if the binary representation is correct\n", - "Q,g,c,quantum_cost = quantum_optimizer.vqe_solution()\n", - "\n", - "sol, classical_cost = ClassicalOptimizer.cplex_solution()\n", - "\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 binary formulation')" + "# 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" ] }, { @@ -639,17 +592,26 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 29, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[0 1 0 1 0 1]\n" + ] + } + ], "source": [ - "ground_state, ground_level = quantum_optimizer.check_hamiltonian()\n", - "\n", - "print(ground_level,classical_cost)\n", + "ground_state, ground_level = quantum_optimizer.exact_solution()\n", "print(ground_state)\n", - "if np.abs(ground_level - classical_cost)<0.01:\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')" + " else: print('Error in the Ising Hamiltonian formulation')\n", + "except: None" ] }, { @@ -663,13 +625,28 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 30, "metadata": {}, - "outputs": [], + "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": [ - "quantum_dictionary, quantum_solution, quantum_cost = quantum_optimizer.vqe_solution()\n", + "warnings.filterwarnings('ignore')\n", + "vqe_state, vqe_level = quantum_optimizer.vqe_solution()\n", + "print(vqe_state)\n", "\n", - "print(quantum_solution,quantum_cost)" + "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" ] }, { @@ -682,21 +659,45 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 31, "metadata": {}, - "outputs": [], + "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": [ - "visualize_solution(xc, yc, quantum_solution, quantum_cost, n, q, 'Quantum')\n", - "visualize_solution(xc, yc, x, classical_cost, n, q, 'Classical')" + "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. Note that in this particular case, we can find the optimal solution of the QP formulation, which happens to coincide with the optimal solution of the ILP.\n", - "\n", - "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). " + "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). " ] }, {