From ca690e495d0207a4c70b80962f87192afb06cb92 Mon Sep 17 00:00:00 2001 From: mabrell <122741469+mabrell@users.noreply.github.com> Date: Sun, 4 Feb 2024 09:54:55 -0500 Subject: [PATCH] Final submission --- moodys_challenge_yale-harvard.ipynb | 1464 +++++++++++++++++++++++++++ 1 file changed, 1464 insertions(+) create mode 100644 moodys_challenge_yale-harvard.ipynb diff --git a/moodys_challenge_yale-harvard.ipynb b/moodys_challenge_yale-harvard.ipynb new file mode 100644 index 0000000..3a1860c --- /dev/null +++ b/moodys_challenge_yale-harvard.ipynb @@ -0,0 +1,1464 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "de7fe4be-dd2d-4d8c-9358-5ab6a636496e", + "metadata": { + "id": "de7fe4be-dd2d-4d8c-9358-5ab6a636496e" + }, + "source": [ + "# The path to Quantum in production in the financial industry" + ] + }, + { + "cell_type": "markdown", + "id": "266aceea-015c-4c8b-a75e-7e9e74c47f33", + "metadata": { + "id": "266aceea-015c-4c8b-a75e-7e9e74c47f33" + }, + "source": [ + "## How could quantum avoid the drawbacks of classical optimization algorithms?\n" + ] + }, + { + "cell_type": "markdown", + "id": "6c89cba0-4047-4b23-b949-baa20f67fae5", + "metadata": { + "id": "6c89cba0-4047-4b23-b949-baa20f67fae5" + }, + "source": [ + "## Learning objectives of the challenge" + ] + }, + { + "cell_type": "markdown", + "id": "7fb51a43-6f42-4077-a894-38c874c61721", + "metadata": { + "id": "7fb51a43-6f42-4077-a894-38c874c61721" + }, + "source": [ + "**1.** Leverage quantum computing to try to avoid the drawbacks of classical optimization algorithms for portfolio optimization in the financial industry. What are the most promising problems and the corresponding techniques to solve them?
\n", + "**2.** What are the main bottlenecks/steps to solve financial optimization problems with quantum? What are the proposals in the literature to overcome them? Inclusion of equality and inequality constraints in optimization problems.
\n", + "**3.** Mapping a classical portfolio optimization problem to a quantum one.
\n", + "**4.** Think about resource estimation, can we do something useful with near term devices? How far are we from quantum advantage? How do we translate hardware roadmaps into utility timelines?
\n", + "**5.** Use of simulated annealing and other quantum computing techniques to find the solution of the problem." + ] + }, + { + "cell_type": "markdown", + "id": "85d339f8-0a2d-4c84-88d2-ae2f5d7e7597", + "metadata": { + "id": "85d339f8-0a2d-4c84-88d2-ae2f5d7e7597" + }, + "source": [ + "## The challenge" + ] + }, + { + "cell_type": "markdown", + "id": "ddf18fd5", + "metadata": { + "id": "ddf18fd5" + }, + "source": [ + "### Portfolio optimization in the financial industry\n", + "\n", + "\n", + "Portfolio optimization is a formal mathematical approach to making investment decisions across a collection of financial instruments or assets. In 1952, Harry Markowitz introduced Modern Portfolio Theory (MPT). MPT introduced the notion that the diversification of a portfolio can inherently decrease the risk of a portfolio. Simply put, this meant that investors could increase their returns while also reducing their risk. Markowitz’s work on MPT was groundbreaking in the world of asset allocation, eventually earning him a Nobel prize for his work in 1990.\n", + "\n", + "\n", + "The behaviour of a portfolio can be quite different from the behaviour of\n", + "individual components of the portfolio. The risk of a properly constructed\n", + "portfolio from equities in leading markets could be half the sum of the risks of\n", + "individual assets in the portfolio. This is due to complex correlation patterns\n", + "between individual assets or equities. A good optimizer can exploit the\n", + "correlations, the expected returns, the risk (variance) and user constraints\n", + "to obtain an optimized portfolio.\n", + "\n", + "Portfolio optimization is often called **mean-variance (MV)** optimization.\n", + "The term mean refers to the *mean or the expected return* of the investment\n", + "and the *variance* is the measure of the risk associated with the portfolio.\n", + "\n", + "![image](data:image/png;base64,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)\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "In this challenge, we consider an alternative Markowitz’s mean–variance model in which the variance is replaced with an industry standard risk measure, Value-at-Risk (VaR), in order to better assess market risk exposure associated with financial and commodity asset price fluctuations.\n", + "\n", + "\n", + " VaR is defined as the maximum dollar amount expected to be lost over a given time horizon, at a pre-defined confidence level. For example, if the 95% one-month VAR is 1 million dollars, there is 95% confidence that over the next month the portfolio will not lose more than 1 million dollars. Realistic portfolio optimization in the mean-VaR framework is a challenging problem since it leads to a *non-convex NP-hard problem* which is computationally intractable. In fact, minimizing a nonparametric VaR measure is a complex task due to the non-smooth objective function landscape with many local minima. When more dimensions and trading constraints are added to the problem, the complexity of the problem increases. Hence, a good candidate to becnhmark quantum optimization heuristics.\n", + "\n", + "In the MV model, risk is defined by a dispersion parameter and it is assumed that returns are normally or elliptically distributed. However, the distributions of returns are asymmetric and usually have excess kurtosis in practice. Variance as a risk measure has thus been widely criticized by practitioners due to its symmetrical measure which equally weights desirable positive returns and undesirable negative ones. In fact, Markowitz recognized the inefficiencies embedded in the mean–variance approach. As a result, several extensions\n", + "and modifications of the basic Markowitz model reflecting real-world constraints have been developed.\n", + "\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "id": "c898b22a-1ee3-4cf5-af66-0c9ff99ecaa8", + "metadata": { + "id": "c898b22a-1ee3-4cf5-af66-0c9ff99ecaa8" + }, + "source": [ + "### Problem Statement -- The Mean-Variance-VaR model" + ] + }, + { + "cell_type": "markdown", + "id": "cfe38b05-e39a-4d01-a1d6-b6fafcec3db3", + "metadata": { + "id": "cfe38b05-e39a-4d01-a1d6-b6fafcec3db3" + }, + "source": [ + "Note that here we closely follow reference\n", + "[Mean-Variance-VaR portfolios: MIQP formulation and performance analysis](https://arxiv.org/abs/2111.09773). One could read this reference for an overview on the topic." + ] + }, + { + "cell_type": "markdown", + "id": "98d58de7-4005-4836-9b30-55a6ce04df2f", + "metadata": { + "id": "98d58de7-4005-4836-9b30-55a6ce04df2f" + }, + "source": [ + "Consider n assets with the following portfolio:" + ] + }, + { + "cell_type": "markdown", + "id": "5bf58d94-2e32-4a34-9289-8be19473ec46", + "metadata": { + "id": "5bf58d94-2e32-4a34-9289-8be19473ec46" + }, + "source": [ + "$$x \\epsilon \\Delta = \\{ x \\epsilon \\mathbb{R}^{n} : \\sum_{k=1}^{n} x_{k}=1, x_{k} \\ge 0, k=1, \\dots, n \\}$$" + ] + }, + { + "cell_type": "markdown", + "id": "be7a6796-0b53-499d-8579-c710fc40975e", + "metadata": { + "id": "be7a6796-0b53-499d-8579-c710fc40975e" + }, + "source": [ + "with $x_{k}$ the percentage of the total portfolio invested in asset $k$ (let's call this $\\textit{Asset}_{k}$) and $n$ the total number of assets. The equality $\\sum_{k=1}^{n} x_{k}=1$ that 100% of the total portfolio is invested and $x_{k}\\ge 0$ indicates that all the percentages are positive (no-short sellings constraint).\n", + "\n", + "By having in mind that the investment decision at a particular point in time is made considering **T** equally likely scenarios, the portfolio return is given by:" + ] + }, + { + "cell_type": "markdown", + "id": "55deece6-9c98-45ff-9b73-1bceb783f2d0", + "metadata": { + "id": "55deece6-9c98-45ff-9b73-1bceb783f2d0" + }, + "source": [ + "$$R_{Pt}(x)=\\sum_{k=1}^{n}x_{k}r_{kt}$$" + ] + }, + { + "cell_type": "markdown", + "id": "74a4485c-36d8-4257-a19b-e6b330d07a7b", + "metadata": { + "id": "74a4485c-36d8-4257-a19b-e6b330d07a7b" + }, + "source": [ + "with the variables $r_{kt}$ corresponding to the return of each asset $k$ for the scenario $t \\epsilon \\{ 1, \\dots, T \\}$." + ] + }, + { + "cell_type": "markdown", + "id": "42f4e7c4-404c-4f06-bc29-448c3360127f", + "metadata": { + "id": "42f4e7c4-404c-4f06-bc29-448c3360127f" + }, + "source": [ + "The classical **Mean-Variance** portfolio optimization problem focuses on minimizing the variance (risk), while at the same time making sure that the expected return is above a specific value $\\eta$. It has the following convex form:" + ] + }, + { + "cell_type": "markdown", + "id": "81769ffb-ef50-4d4f-ba67-aea1d2a2a64d", + "metadata": { + "id": "81769ffb-ef50-4d4f-ba67-aea1d2a2a64d" + }, + "source": [ + "$$\\min \\sum_{k=1}^{n}\\sum_{j=1}^{n} x_{k}x_{j}\\sigma_{kj}$$" + ] + }, + { + "cell_type": "markdown", + "id": "7953dade-e77f-4ca0-a6b7-15e9d7704489", + "metadata": { + "id": "7953dade-e77f-4ca0-a6b7-15e9d7704489" + }, + "source": [ + "$$\\text{s.t.}$$" + ] + }, + { + "cell_type": "markdown", + "id": "227a6a97-f5af-4b37-aec9-14c6abdb8297", + "metadata": { + "id": "227a6a97-f5af-4b37-aec9-14c6abdb8297" + }, + "source": [ + "$$\\sum_{k=1}^{n} \\mu_{k}x_{k} \\ge \\eta$$\n", + "\n", + "\n", + "$$\\sum_{k=1}^{n} x_{k}=1$$\n", + "\n", + "\n", + "$$x_{k}\\ge 0 \\ \\text{for}\\ k=1,\\dots,n $$" + ] + }, + { + "cell_type": "markdown", + "id": "78d223bd-40f9-4191-821b-1a782b1b157e", + "metadata": { + "id": "78d223bd-40f9-4191-821b-1a782b1b157e" + }, + "source": [ + "with $\\sigma^{2}_{P}(x)=\\sum_{k=1}^{n}\\sum_{j=1}^{n} x_{k}x_{j}\\sigma_{kj}$ the portfolio variance ($\\sigma_{kj}$ the covariance between the assets $k$ and $j$), $\\mu_{P}(x)=\\sum_{k=1}^{n} \\mu_{k}x_{k}$ the expected total return ($\\mu_{k}=\\frac{1}{T}\\sum_{t=1}^{T}r_{kt}$ is the expected return of asset k).\n", + "\\\n", + "\\\n", + "The inequality $\\sum_{k=1}^{n} \\mu_{k}x_{k} \\ge \\eta$ indicates that the expected total returns should be above or equal a specific target value ($\\eta$).\n", + "\\\n", + "\\\n", + "By solving the optimization problem above, one gets the **best distribution of assets**, or differently the optimal set of percentages $\\{x_{k}\\}$ of the total portfolio that should be invested in each one of the assets $k$. For example consider $\\textit{Asset}_1$, with the corresponding optimal percentage $x_{1}$. If the solution of the problem is $x_{1}=0.1$ that means that 10% of the total portfolio should be invested in $\\textit{Asset}_1$." + ] + }, + { + "cell_type": "markdown", + "id": "6843ae65-192a-4d62-aa96-79f615af7614", + "metadata": { + "id": "6843ae65-192a-4d62-aa96-79f615af7614" + }, + "source": [ + "The above optimization problem does not include the Value-at-Risk (VaR), which is an additional risk measure. $VaR_{\\epsilon}$ is defined as the **maximum loss** for scenarios $\\{1, \\dots, T\\}$ with $(1-\\epsilon)$ the given confidence level. $\\epsilon$ typically takes the values $\\epsilon=0.01, 0.05, 0.10$.\n", + "\n", + "To further understand what VaR is, first consider that for a given portfolio $x$, the portfolio loss is given by $L_{P}(x)=-\\sum_{k=1}^{n}x_{k}R_{k}$, with $R_{k}$ the return of asset $k$. $VaR_{\\epsilon}(x)$ is the value such that the portfolio loss $L_{P}(x)$ is above $VaR_{\\epsilon}(x)$ with probability $\\epsilon \\times 100 \\%$. If we include $VaR_{\\epsilon}$ in the **Mean-Variance** portfolio optimization problem we have the **Mean-Variance-VaR** approach. In this approach, a portfolio return $R_{P}(x)$ is preferred to $R_{P}(y)$ iff $\\mu_{P}(x)\\ge \\mu_{P}(y)$, $\\sigma^{2}_{P}(x)\\le \\sigma^{2}_{P}(y)$ and $VaR_{\\epsilon}(x)\\le VaR_{\\epsilon}(y)$." + ] + }, + { + "cell_type": "markdown", + "id": "eee858f6-43ec-4872-a014-21ef86e4ee0b", + "metadata": { + "id": "eee858f6-43ec-4872-a014-21ef86e4ee0b" + }, + "source": [ + "By following [Mean-Variance-VaR portfolios: MIQP formulation and performance analysis](https://arxiv.org/abs/2111.09773) the **Mean-Variance-VaR** problem is written as a **Mixed-Integer Quadratic Programming (MIQP)** problem:" + ] + }, + { + "cell_type": "markdown", + "id": "cb3d5b16-9150-49af-84dc-5f89bcd08bf3", + "metadata": { + "id": "cb3d5b16-9150-49af-84dc-5f89bcd08bf3" + }, + "source": [ + "$$min_{(x, r_{\\epsilon}, y)}\\sum_{k=1}^{n}\\sum_{j=1}^{n}x_{k}x_{j}\\sigma_{kj}$$" + ] + }, + { + "cell_type": "markdown", + "id": "431b0e46-0516-46f6-9c52-258f0704697b", + "metadata": { + "id": "431b0e46-0516-46f6-9c52-258f0704697b" + }, + "source": [ + "$$\\text s.t.$$\n", + "$$\\sum_{k=1}^{n}\\mu_{k}x_{k}\\ge \\eta$$\n", + "$$-r_{\\epsilon} \\le z$$\n", + "$$r_{\\epsilon}\\le \\sum_{k=1}^{n}r_{kt}x_{k}+M(1-y_{t})\\ \\text{for}\\ t=1, \\dots, T$$\n", + "$$\\sum_{t=1}^{T} y_{t} \\ge (1-\\epsilon)T$$\n", + "$$\\sum_{k=1}^{n}x_{k}=1$$\n", + "$$x_{k} \\ge 0\\ \\text{for}\\ k=1, \\dots, n$$\n", + "$$y_{t}\\epsilon \\{ 0,1 \\} \\ \\text{for}\\ t=1, \\dots, T$$" + ] + }, + { + "cell_type": "markdown", + "id": "87424257-51ce-4280-ab5a-c5c12d8ef307", + "metadata": { + "id": "87424257-51ce-4280-ab5a-c5c12d8ef307" + }, + "source": [ + "with $VaR_{\\epsilon}(x)=-r_{\\epsilon}$, $r_{\\epsilon}$ a real and positive variable. Therefore $-r_{\\epsilon}$ represents the VaR of the portfolio and is bounded above by $z$ (which is real and positive, $z\\gt 0$), which is actually the target VaR. This is expressed as $-r_{\\epsilon} \\le z$ above.\n", + "\\\n", + "\\\n", + "$M$ is a large positive number that has to be fine-tuned in the optimization procedure. Find the optimal $M$ value here: [Mean-Variance-VaR portfolios: MIQP formulation and performance analysis](https://link.springer.com/article/10.1007/s00291-023-00719-x) and use it in the exercises below. $y_{t}$ (for $t=1,\\dots,T$) are boolean variables.\n", + "\\\n", + "\\\n", + "The inequalities $r_{\\epsilon}\\le \\sum_{k=1}^{n}r_{kt}x_{k}+M(1-y_{t})$ (one for each event $t$) indicate the following: if the **portfolio loss** $-\\sum_{k=1}^{n}r_{kt}x_{k}$ is above the VaR $-r_{\\epsilon}$ that means that $y_{t}$ must be 0 (for sufficiently big $M$). That practically means that if the portfolio loss is above the VaR, the event $t$ should **not** happen ($y_{t}=0$).\n", + "\\\n", + "\\\n", + "For the challenge, we simplify the problem as follows:\n", + "\n", + "$$ \\textbf{Mean-Variance-VaR Simplified Version}$$" + ] + }, + { + "cell_type": "markdown", + "id": "ef016e31-eaad-4c39-a47f-dbaa522d4d1e", + "metadata": { + "id": "ef016e31-eaad-4c39-a47f-dbaa522d4d1e" + }, + "source": [ + "$$min_{(x, r_{\\epsilon}, y)}\\sum_{k=1}^{n}\\sum_{j=1}^{n}x_{k}x_{j}\\sigma_{kj}-\\sum_{k=1}^{n}\\mu_{k}x_{k}$$" + ] + }, + { + "cell_type": "markdown", + "id": "408985e0-8c1d-4c12-9640-c117a68a0cc5", + "metadata": { + "id": "408985e0-8c1d-4c12-9640-c117a68a0cc5" + }, + "source": [ + "$$\\text s.t.$$\n", + "$$-r_{\\epsilon} \\le z$$\n", + "$$r_{\\epsilon}\\le \\sum_{k=1}^{n}r_{kt}x_{k}+M(1-y_{t})\\ \\text{for}\\ t=1, \\dots, T$$\n", + "$$\\sum_{t=1}^{T} y_{t} \\ge (1-\\epsilon)T$$\n", + "$$\\sum_{k=1}^{n}x_{k}=1$$\n", + "$$x_{k} \\ge 0\\ \\text{for}\\ k=1, \\dots, n$$\n", + "$$y_{t}\\epsilon \\{ 0,1 \\} \\ \\text{for}\\ t=1, \\dots, T$$" + ] + }, + { + "cell_type": "markdown", + "id": "6d1e1ae4-fb34-43fe-a9a7-7fcf9497efa6", + "metadata": { + "id": "6d1e1ae4-fb34-43fe-a9a7-7fcf9497efa6" + }, + "source": [ + "Specifically, we include the expected total returns, $\\sum_{k=1}^{n}\\mu_{k}x_{k}$, in the objective fuction $f(x)=\\sum_{k=1}^{n}\\sum_{j=1}^{n}x_{k}x_{j}\\sigma_{kj}-\\sum_{k=1}^{n}\\mu_{k}x_{k}$ that is minimized. Now, by minimizing the objective function we select the **best distribution of assets** that maximize the return and minimize the variance (risk), while making sure that the equality/inequality constraints written above are also satisfied." + ] + }, + { + "cell_type": "markdown", + "id": "e8cc901b", + "metadata": { + "id": "e8cc901b" + }, + "source": [ + "In the next sections you will learn how one can solve the **Mean-Variance-VaR Simplified Version** problem with quantum or quantum-inspired techniques.\n" + ] + }, + { + "cell_type": "markdown", + "id": "effe5813-0118-46ce-bd2a-560cb74e6a70", + "metadata": { + "id": "effe5813-0118-46ce-bd2a-560cb74e6a70" + }, + "source": [ + "
\n", + " \n", + "**STEPS:**\n", + " \n", + "1. Learn how to incorporate the equality/inequality constraints of the **Mean-Variance-VaR Simplified Version** problem in the objective function that is minimized.\n", + "2. Cast the problem into the QUBO formulation, by choosing an **encoding** for all the variables of step 1. The QUBO formulation can be used for finding the solution of the problem **classically** or with **quantum** or **quantum-inspired** methods.\n", + "3. Use Simulated Annealing to solve the problem. This is a specific algorithm used for **optimization problems**.\n", + "4. Evaluate the solutions of step 3.\n", + "5. Move to **quantum** optimization techniques such as Quantum Annealing or QAOA to solve the problem.\n", + "
" + ] + }, + { + "cell_type": "markdown", + "id": "19a0a45f", + "metadata": { + "id": "19a0a45f" + }, + "source": [ + "### Reading in financial data\n", + "\n", + "\n", + "To examine the practical applicability of the mean-VaR model with quantum techniques, we will use a small dataset that compromises the weekly linear returns for Eurostoxx50 Market Index from 01-22-2007 to 05-06-2013 and contains up to 32 assets. You may find the associated file: *returns_data.txt*" + ] + }, + { + "cell_type": "code", + "source": [ + "%pip install pyqubo -q\n", + "%pip install dimod -q\n", + "%pip install dwave-neal -q\n", + "\n", + "import numpy as np\n", + "import pandas as pd\n", + "import scipy\n", + "import matplotlib as plt" + ], + "metadata": { + "id": "smNCXcwLZT1_" + }, + "id": "smNCXcwLZT1_", + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a78f8aea", + "metadata": { + "id": "a78f8aea" + }, + "outputs": [], + "source": [ + "# You may choose to select different parameters/values\n", + "number_assets = 3\n", + "T = 3\n", + "\n", + "# Read returns\n", + "df = pd.read_csv('returns_data.txt',delim_whitespace=True)\n", + "\n", + "df.head()\n", + "\n", + "Rraw = df.values.T\n", + "\n", + "# Select the first N,T assets and scenarios, you may choose a different strategy if you would like to do so.\n", + "R = Rraw[:number_assets,:T]\n", + "\n", + "# Expected return of each asset\n", + "expected_returns = np.mean(R, axis = 1)\n", + "\n", + "# Covariance matrix of asset returns\n", + "covariance_matrix = np.cov(R)" + ] + }, + { + "cell_type": "markdown", + "id": "736c3eea-e219-4d6c-8457-3a4f21e9f6fc", + "metadata": { + "id": "736c3eea-e219-4d6c-8457-3a4f21e9f6fc" + }, + "source": [ + "### Section 1: Incorporating equality/inequality constraints" + ] + }, + { + "cell_type": "markdown", + "id": "8a6ce336-2cfc-4a5a-80a4-6616b280adaf", + "metadata": { + "id": "8a6ce336-2cfc-4a5a-80a4-6616b280adaf" + }, + "source": [ + "- Convert the inequalities of the **Mean-Variance-VaR Simplified Version** problem into equalities, with the use of slack variables and the penalty method approach. For reference one could read [A real world test of Portfolio Optimization with Quantum Annealing](https://arxiv.org/abs/2303.12601) (page 10).\n", + "Specifically, re-write the objective function above as a new objective function called L that includes the inequality constraints. To do that usually one introduces new variables, called **slack variables**, that transform an inequality constraint into an equality constraint. If you do that for each inequality of the optimization problem, what are the total number of variables to be optimized including the slack variables?\n", + "- In a similar way and by following the same reference, try to incorporate the one equality constraint, $\\sum_{k=1}^{n}x_{k}=1$ as a penalty term in the objective function L. Notice that now slack variables are not needed." + ] + }, + { + "cell_type": "markdown", + "id": "ec015dad-7449-433c-bd44-593e5fecb4ec", + "metadata": { + "id": "ec015dad-7449-433c-bd44-593e5fecb4ec" + }, + "source": [ + "
NOTE:\n", + "L has the following form: $L=\\sum_{k=1}^{n}\\sum_{j=1}^{n}x_{k}x_{j}\\sigma_{kj}-\\sum_{k=1}^{n}\\mu_{k}x_{k}+\\textit{penalty terms}$, with the penalty terms to be found in this section (and include all the equalities and inequalities of the problem). This will need to be mapped to a quantum Hamiltonian in the following section. Each penalty term will correspond to one lagrange multiplier that will need to be fine-tuned in the next sections, so that the constraints are imposed.\n", + "
" + ] + }, + { + "cell_type": "markdown", + "source": [ + "Current L Hypothesis: $L=\\sum_{k=1}^{n}\\sum_{j=1}^{n}x_{k}x_{j}\\sigma_{kj}-\\sum_{k=1}^{n}\\mu_{k}x_{k}+\\textit{penalty terms}$\n", + "\n" + ], + "metadata": { + "id": "HJiZ6n58EzK6" + }, + "id": "HJiZ6n58EzK6" + }, + { + "cell_type": "markdown", + "id": "23645c2f-0916-477e-9cf8-2ecb6ed114d1", + "metadata": { + "id": "23645c2f-0916-477e-9cf8-2ecb6ed114d1" + }, + "source": [ + "**Answer:**" + ] + }, + { + "cell_type": "markdown", + "source": [ + "We use $T+2$ nonzero slack variables ($s_{T+3}=0$ for the $\\sum (x)=0$ equality).\n", + "\n", + "---\n", + "\n", + "\n", + "$$L=\\sum_{k=1}^{n}\\sum_{j=1}^{n}x_{k}x_{j}\\sigma_{kj}-\\sum_{k=1}^{n}\\mu_{k}x_{k}+\\sum_{j = 1}^{T+3}\\lambda_j\\left(\\sum_{i = 1}^{n+T+1}(A_{ji} x_i) - b_j+ s_j\\right)^2$$" + ], + "metadata": { + "id": "RvNlISSZGocT" + }, + "id": "RvNlISSZGocT" + }, + { + "cell_type": "markdown", + "source": [ + "\n", + "$\\vec{x}\\in\\mathbb{R}^{(n+T+1)}$\n", + "\n", + "$\\vec{s},\\vec{b}\\in\\mathbb{R}^{(T+3)}$\n", + "\n", + "$A\\in\\mathbb{R}^{(T+3)\\times (n + T+1)}$" + ], + "metadata": { + "id": "NMKP-WtcMwwS" + }, + "id": "NMKP-WtcMwwS" + }, + { + "cell_type": "markdown", + "source": [ + "$\\vec{x} = \\begin{pmatrix}x_1\\\\ x_2\\\\ \\vdots\\\\ x_n\\\\ y_1\\\\ y_2\\\\ \\vdots\\\\ y_T\\\\ r_\\epsilon\\end{pmatrix}$" + ], + "metadata": { + "id": "xcW4e-GMyKyD" + }, + "id": "xcW4e-GMyKyD" + }, + { + "cell_type": "markdown", + "source": [ + "$A = \\begin{pmatrix}-r_{11}& -r_{21}& \\dots& -r_{n1}& M& 0& \\dots& 0& 1\\\\ -r_{12}& -r_{22}& \\dots& -r_{n2}& 0& M& \\dots& 0& 1\\\\ \\vdots& \\vdots& \\vdots& \\vdots& \\vdots& \\vdots& \\ddots& \\vdots& \\vdots\\\\\n", + "-r_{1t}& -r_{2t}& \\dots& -r_{nt}& 0& 0& \\dots& M& 1\\\\\n", + "0&0&\\dots& 0& -1& -1& \\dots& -1& 0\\\\\n", + "0&0&\\dots& 0& -1& -1& \\dots& -1& -1\\\\\n", + "1&1&\\dots& 1& 0& 0& \\dots& 0& 0\\\\\\end{pmatrix}$" + ], + "metadata": { + "id": "yA1V9qKLJEqS" + }, + "id": "yA1V9qKLJEqS" + }, + { + "cell_type": "markdown", + "source": [ + "In block matrices, with $R\\in\\mathbb{R}^{t\\times n}$ and $I$ the identity matrix," + ], + "metadata": { + "id": "IcoZor6_7xpF" + }, + "id": "IcoZor6_7xpF" + }, + { + "cell_type": "markdown", + "source": [ + "![Screenshot 2024-02-03 154603.png](data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAA1wAAAGQCAYAAAC6UGEiAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAAEnQAABJ0Ad5mH3gAAFEmSURBVHhe7d0HmFRF9vDhg+CQdckgWYkqAhIlSFiURRBkFUUBFzGAoH6LugZU9A+KC7suuyooRiSJiCIqKEgUUEmSJEuSnGWAIQj0N6e6eqanaZiemb7dt3t+7/P0Q9XtnsTMvX1P1alTOTzJBAAAAAAQdpfYfwEAAAAAYUbABQAAAAAOIeACAAAAAIcQcAEAAACAQwi4AAAAAMAhBFwAAAAA4BACLgAAAABwCAEXAAAAADiEgAsAAAAAHELABQAAAAAOIeACAAAAAIcQcAEAAACAQwi4AAAAAMAhBFwAAAAA4BACLgAAAABwCAEXAAAAADiEgAsAAAAAHELABQAAAAAOIeACAAAAAIcQcAEAAACAQ3J4ktk2AABht337dvniiy8kISFBevbsaY8CQPQNHz5czp49K7fffrtcccUV9igQXgRcAABHzZw5U1q1aiUFCxaUxMREexQAoi937txy+vRpmTdvnjRp0sQeBcKLlEIAAAAAcAgBFwAAAAA4hIALMW/u3LlSoUIFkwqwdetWexQAAABucurUKXniiSfksssuk3/9619y5swZ+0x8I+BCTFu7dq08/fTTsm3bNunUqZOUL1/ePgMAAACl90n9+vWTFStW2CPRoWvm2rdvL4ULF5aBAwfKhAkTJDuUkyDgQszau3evPPvss7Jw4UK599575b777pMcOXLYZwEAAKDmz58vr776qkydOtUeiZ7GjRvLww8/LEePHpWXX35ZVq1aZZ+JXwRciEk6Bf3uu+/K5MmTpXr16inT0wAAAAjODSl8uXLlkh49ekjHjh1NplL//v3NIHo8I+BCzNGpZ52CHjJkiOn37dtXatSoYdoAAABwt2LFipkUR10KooPnup5L13fFKwIuxJx169aZYEunojWV8K677iKVEAAAIIbUrl1b+vTpY9rvvPOOfPbZZ3G7nouACzFFN0395z//aRZ96qjIo48+SiohAABAjMmZM6d0797dpBbqILoOpuugejwi4ELM0FGPDz/8UEaNGmX6PXv2NKMjAAAAiD2aWtirVy8pWLCgGUzXQXUdXI83BFyIGUuXLpWhQ4eadosWLUw6oY6OAAAAIDY1a9ZMHnroIdPWQfVPPvkk7lILCbgQEw4fPmymmnUfCXX//fdL6dKlTRsAAACxSffm0vu6mjVrmr4OrsdbqXgCLriejnJMnDhRPv30U9PXma1bb73VtAEAABDbqlWrZvZTVVoq/s0335Tjx4+bfjwg4ILr6QLKYcOGmbbm+Hbp0oVCGQAAAHFCq03fcccdZsmIGj9+vHz11VemHQ8IuOBquifD+++/bxZSqnvuuUeaNm1q2gAAAIgPulREB9WVVi3UUvE7d+40/VhHwAVXmzt3rjnhVKlSpczO5Hnz5jV9AAAAxA9dMtK+fXvTnj17towbN07Onj1r+rGMgAuupYUy3nvvPTPKoTp16pSyoBIAAADxpXjx4nLnnXfanpjtgFavXm17sYuAC641derUlEIZOrul08xayQYAAADx6aabbkqZ5dICGloqXpeYxDICLrjSvn37ZMKECbYn5sSrUaOG7QEAACAe6SyXL+BSWqk61svEE3DBlbQyzZdffmnaWplQ0wlZuwUAABD/brnlFmnVqpVp6x6susTkxIkTph+LCLjgOrt37zblQH1uv/12adiwoe0BAAAgnpUsWVLatGlje2IG4RcvXmx7sYeAC64za9YsmTFjhu15K9bkz5/f9gAAABDPdF+utm3bphRL08H4zz77LGbXchFwwVW0MqGeUD46nXzDDTfYHgAAALKDSpUqpVnLpYXUfPuyxhoCLriK7rkwadIk2xMznazTygAAAMg+cubMKe3atTOVqpXOcmlBtVic5SLggmscP37cFMvwqV69urRu3dpMKwMAACB70XtBX/EMpVsG/frrr7YXOwi44Bq6sd20adNsz7sPg04nAwAAIPvRStXNmjWzPe++XHqv6PF47JHYQMAFVzh79qx8/fXXZrrY589//jMbHQMAAGRjLVu2lAYNGtieyDfffCN79uyxvdhAwAVX+O2332T69Om25y2WUa9ePdsDAABAdnTFFVekCbi0kvWPP/5oe7GBgAuuoKXgFy5caHtiKhPqTuMAAADIvjTbSYtn+NM1/7r2P1YQcCHqtBT8lClTbM+br6vFMrQ6DQAAALK3a665Rpo3b257YtZx6dr/WEHAhahbs2ZNmo2OGzduLFWrVrU9AAAAZGclSpSQpk2b2p63RLwuRYmV4hkEXIgqLZahoxRHjx61R7wB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uOAK1157rRmt8NFRDB3NAABkH5oC6L+nTkbTyzUN0adx48YEXMgW9O9c/959MlIkTGeR9+/fb3veQhRuC7h0s2NfURCly1C0OEgsFSQi4IIr6CiF/yyXjmLoyZXRaXEAQOzS9VY333yz7XlvHENdj6I3jtu2bbM9MXs6XX755bYHxC+tSOi/NGPz5s22lb6kpKQ0AZruH6r7iLqJViX0X7+lP2usDaYQcMEVdJSiffv2ZmTF57vvvsvwtDgAILbdcMMNKRkPy5cvl71795p2ejQtavHixaatKVa33HKLaQPxTu+hdMbHV4Ds559/NtvuhEJnkX3r5vU+rGHDhqbtFjqQ8vXXX6fMXmvqpH6fsVIsw4eAC65Rrly5NCObui+Eby8VAED2oOlM3bt3N+0ffvjBrN0IxaJFi1IW1d93330UzEC2Uq1aNenWrZtph3r/pFlEumZes4o0kOnRo4cUL17cPusOGhBOnz7d9rzFMq6//nrbix0EXHANrbSjG9r5RmiOHj0qX375pdkkFrFLN7r99ddfbc+b6uCf9gMAgW677Taz+ap6//33zWa8F6OzYB9++KF53+jUqZPce++9bDiNbEXvoTRg6tChg5kN0vMmvY3m161bZzYOVg899JD85S9/MW03mTVrVprqhF27do3JjcxzJEe3LJKBa2hw9dxzz5kdzpUGX59++qlcc801pg/30p36P/vsszSL3LU9c+ZMWb9+vT3ipSNpusBX11j454r/9a9/lcqVK9se4oX+DeiopP7e07sBAHx0If8TTzwho0ePlgcffFD++c9/SuHChe2zqTTIevrpp+Wtt94yN5vDhg0zxTeAUGhqmr5/zZs3z+wLGut0vdMjjzxiZoVeeukleeqpp4LuRaeDGH369JHJkyfLww8/LIMHD06pdOgWWizj/vvvl0mTJpm+vo+MGjXKlVUU00PABdfRXGKd6fLNggwaNMhcMHT0Bu514sQJ6du3rwmQdf3EpZdeap9Jn95YLVu2zKQO+VdaQnwg4EJm6XXl7bfflpdfftnsDfTiiy+am2IthqHPaerUK6+8IkuXLjUzYvpeESwoAy4k3gIudejQIRkyZIgMHz5cmjVrJv/4xz/MnlUaeOnaLi1KpvdWuu3C888/L7169XLlBuH63tGxY0czqKLee+89E4DFIgIuuE7gLJcW0tApb92fBUDsIeBCVuls+fjx4+Xzzz9Pk15Uu3Ztadu2rVmzpe8RpBEio+Ix4FJ6e68pg+PGjTMDof6ZJhqE3XrrrXLPPfe4drbIN4g7YsQI04/l2S1FwAVXCpzleuedd+SBBx7gzRSIQQRcCDe9QXZb6WrEpngNuALp7f6ZM2cylH0STVoER9dy+qoTxvp9IEUz4Eq1atWSLl262J6YGa5du3bZHgAgOyPYAjJGA5VYCbY002nChAkpwZYO2OlerbE86E7ABVfKlSuX3HXXXSkVC2fPni3ffvutaQMAACA+rVq1SiZOnGh7YraJiNVUQh8CLriWVib07Smhxo4dm25pYAAAAMQmnd3S9Zq+JSW6zUM8bGJOwAXX0qqEupdKixYtTF9nuaZOnWrykAEAABBf/Ge3dFZLS9zH4r5bgQi44Gq6l4puxufbG+Kjjz5i01wAAIA4o5UJtfS77z5Pqyhqpep4QMAF19PSpZ07dzZt3XNFC2icPXvW9AEAABD7fvjhB1PGXmmg1bNnT1NFMh4QcMH18ufPb6aUfQU0Ro8eLatXrzZtAAAAxLbDhw+bPbd8mxzrfV+lSpVMOx4QcCEm1KhRw4x0qLVr18q7775rpp4BAAAQ23SNvm7QrB588EHp2LFjXO29SsCFmKAnnRbQ0Go1Stdy6SaFAAAAiF1bt26Vt956y7Rr1qwpffv2NdlN8YSACzFDq9Q89dRTUr58eTPl/Prrr8uePXvsswAAAIglZ86ckTFjxpg1+urJJ5+UatWqmXY8IeBCTKlTp44899xzpj1lyhSznosCGgAAALFHAy2tTKh69+4dd6mEPgRciCl6EmqZUD0p1bBhw2TZsmWmDQAAgNiwf/9++d///mfKwGtVwr///e9xl0roQ8CFmKMno56UenLqSTpkyBBT3QYAAADup9lJI0eOlEmTJpmlIoMHD5bKlSvbZ+MPARdikp6UenLqSapVbXQ6mtRCAAAA95s/f77JUlIPP/ywNG7c2LTjFQEXYtaNN94ogwYNkoIFC5qTVk9eAAAAuNfevXtl6NChJktJl4jonlu5cuWyz8YnAi7ELF3P1aFDB+nRo4c5aTUPWPOBAQAA4D6ajTRq1CiZPHmyuYfr379/3K7b8pfDk8y2gZikGyAvX77ctGvVqiV58+Y1bQDuMHPmTGnVqpWZjU5MTLRHASD6cufOLadPnzZ7ezZp0sQehVM07Fi9erUcOHBAqlevLiVKlLDPxDcCLgCAoxYvXiyPPfaY5MuXzwRfAOAWTZs2NXtBvf3222bTXcAJBFwAAAAA4BDWcAEAAACAQwi4AAAAAMAhBFwAAAAA4BACLgAAAABwCAEXAAAAADiEgAsAAAAAHELABQAAAAAOIeACAAAAAIcQcAEAAACAQwi4AAAAAMAhBFwAAAAA4AiR/w/Rtak1zwv6pQAAAABJRU5ErkJggg==)" + ], + "metadata": { + "id": "NdTPrf2pzeac" + }, + "id": "NdTPrf2pzeac" + }, + { + "cell_type": "markdown", + "source": [ + "$b_i = M$ for $i: 1\\rightarrow T$. $b_{T+1} = -T(1-\\epsilon)$. $b_{T+2} = z$. $b_{T+3} = 1$. So: $\\vec{b} = \\begin{pmatrix}M\\\\M\\\\\\vdots\\\\M\\\\-T(1-\\epsilon)\\\\z\\\\1\\end{pmatrix}$" + ], + "metadata": { + "id": "js85Cz6pH8uM" + }, + "id": "js85Cz6pH8uM" + }, + { + "cell_type": "markdown", + "source": [ + "$\\vec{s} = \\begin{pmatrix}s_1\\\\ s_2\\\\ \\vdots\\\\ s_{T+2}\\\\0 \\end{pmatrix}$" + ], + "metadata": { + "id": "qW5py9VfyRrl" + }, + "id": "qW5py9VfyRrl" + }, + { + "cell_type": "markdown", + "source": [ + "Note, following [Mean-Variance-VaR portfolios: MIQP formulation and performance analysis](https://arxiv.org/abs/2111.09773), $\\tilde{M}_{ideal} = -z-\\min_{\\forall i,t}{r_{i, t}}$\n", + "\n", + "\n" + ], + "metadata": { + "id": "O_VQdB2T87gV" + }, + "id": "O_VQdB2T87gV" + }, + { + "cell_type": "markdown", + "id": "bb2982bd-fbb9-49de-8dbc-370e9390173b", + "metadata": { + "id": "bb2982bd-fbb9-49de-8dbc-370e9390173b" + }, + "source": [ + "### Section 2: Encoding/Casting the problem into a QUBO formulation" + ] + }, + { + "cell_type": "markdown", + "id": "1282b39d-ec53-46b8-a149-b353c624c533", + "metadata": { + "id": "1282b39d-ec53-46b8-a149-b353c624c533" + }, + "source": [ + "Many discrete optimization problems that are NP hard can be mapped to quadratically unconstrained binary optimization (QUBO) problems. A QUBO can be expressed in the following form:" + ] + }, + { + "cell_type": "markdown", + "id": "557fd82b-e680-4819-8c41-d8381a5a3fe9", + "metadata": { + "id": "557fd82b-e680-4819-8c41-d8381a5a3fe9" + }, + "source": [ + " $$\\text{min} \\quad z^{T}Qz$$" + ] + }, + { + "cell_type": "markdown", + "id": "4c50b9c4-bf08-4f63-8e9a-d9ad5e55e0d4", + "metadata": { + "id": "4c50b9c4-bf08-4f63-8e9a-d9ad5e55e0d4" + }, + "source": [ + "with $z \\epsilon \\{ 0,1\\}^{N}$ the bit vector and $Q \\epsilon \\mathbb{R}^{N \\times N}$ the corresponding QUBO matrix. The aim of this exercise is to write the objective function L you found in **Section 1** in the QUBO form, with $z$ a vector that includes all the variables $\\{x_{i}\\}$ ($i \\in \\{1, \\dots n\\}$), $r_{\\epsilon}$, $\\{ y_{t} \\}$ ($t \\in \\{1, \\dots, T \\}$) and the slack variables introduced in **Section 1**." + ] + }, + { + "cell_type": "markdown", + "id": "f0f0847a-f9a6-4a03-9921-ea8b5bf0acb8", + "metadata": { + "id": "f0f0847a-f9a6-4a03-9921-ea8b5bf0acb8" + }, + "source": [ + "Map the classical objective function of **Section 1** to a quantum Hamiltonian. Follow the steps:\n", + "- Map all the variables $\\{x_{i}\\}$, $r_{\\epsilon}$, $\\{ y_{t} \\}$ and the slack variables of **Section 1** into different binary variables. Reference [Approaching Collateral Optimization for NISQ and Quantum-Inspired Computing](https://arxiv.org/pdf/2305.16395.pdf) indicates how to map the slack variables into binary ones, with the use of the \"log-encoding\" in pages 4-5. However, reference [Solving the Optimal Trading Trajectory Problem Using a Quantum Annealer](https://arxiv.org/abs/1508.06182) presents different encodings.\n", + "\n", + "The encodings can be writen as a linear function of binary variables. For example, for the variable $x_{i}$ we have:\n", + "$$x_{i}=\\sum_{d=1}^{D}f(d)z_{di}$$\n", + "with $z_{di} \\epsilon \\{ 0,1\\}$ and $f(d)$ the function you are looking for (particular for each encoding). Notice that you will need to introduce $D$ new binary variables, for each variable $x_{i}$.\n", + "\n", + "- Which encoding did you use for each of the variables $\\{x_{i}\\}$, $r_{\\epsilon}$, $\\{y_{t}\\}$, which for the slack variables and why?\n", + "\n", + "\n", + "\n", + "We used log-binary encoding for all of the variables (including slack variables). For most of the variables, we used log-binary encoding as it is the most variable-efficienty encoding method out of the options of log-binary encoding, unitary, and sequential. In addition, since we are ignoring the potential effects of quantum noise, many of the largest drawbacks of log-binary are ignored.\n", + "\n", + "- As you can see, the total number of variables increase after the encoding. What is the total number of binary variables that you have after the mapping?\n", + "\n", + "\n", + "- One could cast the problem into a QUBO form, by finding $Q$. Then one can map it to a Hamiltonian by promoting all the binary variables (for example $z_{di}$) to binary operators ($z_{di} \\rightarrow \\hat{z}_{di}$). The Hamiltonian will then have the following form $\\hat{H}=\\hat{z}^{T}Q\\hat{z}$ with $Q \\epsilon \\mathbb{R}^{N \\times N}$ the corresponding QUBO matrix. You do **not** need to find the explicit QUBO form of the Hamiltonian $\\hat{H}$. Instead, substitute the encoding you found in this section to the Langrange formulation of **Section 1** (let's call it $L_{fin}$). Then, use $L_{fin}$ and with the help of [pyqubo](https://pyqubo.readthedocs.io/en/latest/getting_started.html#) find the QUBO formulation of the problem, by finding the matrix $Q$. One could then promote all the variables to operators, to find the quantum version of $L_{fin}$ (let's call it $\\hat{H}$). $L_{fin}$ and $\\hat{H}$ will be used in the following sections." + ] + }, + { + "cell_type": "markdown", + "id": "f1aefa04-e56e-4826-9be5-3eaf66ebb17e", + "metadata": { + "id": "f1aefa04-e56e-4826-9be5-3eaf66ebb17e" + }, + "source": [ + "
NOTE 1:\n", + " \n", + "Notice that the above optimization problem can be translated to an Ising Hamiltonian with the following change of variables $x_{i}=\\frac{1-\\sigma_{i}}{2}$ as:\n", + " $$H(s)=-\\sum_{j}h_{j}\\sigma_{j}-\\sum_{j" + ] + }, + { + "cell_type": "markdown", + "id": "f7f83e50-386f-4a6b-a137-fd3cbbb82a47", + "metadata": { + "id": "f7f83e50-386f-4a6b-a137-fd3cbbb82a47" + }, + "source": [ + "
NOTE 2 (Hint):\n", + " \n", + "Encoding requires finding the minimum and maximum values for each one of the variables of the problem. You will need to find them.\n", + "Notice that $-z \\le r_{\\epsilon} \\le 0$, with $z$ a positive, real number. Are the variables needed to be normalized and why?\n", + "\n", + "
" + ] + }, + { + "cell_type": "markdown", + "id": "9cabd342-4061-488b-9b3d-5d93d96344ec", + "metadata": { + "id": "9cabd342-4061-488b-9b3d-5d93d96344ec" + }, + "source": [ + "
NOTE 3 (Hint):\n", + "\n", + "Ignore how the choice of encoding might affect the noise level of a quantum device and only consider how it affects the granularity of the problem as well as the number of binary variables needed for the encoding of each variable of the problem. One could also read\n", + "[A real world test of Portfolio Optimization with Quantum Annealing](https://arxiv.org/abs/2303.12601).\n", + "
" + ] + }, + { + "cell_type": "markdown", + "id": "897a8e15-2da5-4ae2-9108-31aa005d6057", + "metadata": { + "id": "897a8e15-2da5-4ae2-9108-31aa005d6057" + }, + "source": [ + "**Answer:**" + ] + }, + { + "cell_type": "markdown", + "source": [ + "We use binary encoding due to its efficiency in representing the most number of values with the given bits. Additionally, all of our variables are normalized to $[0,1)$, so the variables represent fractions of constants or inputs (such as $z$).\n", + "\n", + "Assuming that we are using an p qubit quantum computer, where p is the number of qubits and is sufficiently large, the total number of binary variables we use is dependent on the level of granularity we want. This is because we can map each qubit 1 to 1 to the number of binary variables that our system has to keep track of.\n", + "\n", + "So, allocating our qubits (with an explanation of each variable afterwards):\n", + "\n", + "$x_n$: $n * [log_2 (n) + g]$\n", + "\n", + "- bits derived from investment granularity, where g is a variable denoting how fine we want the granularity, with $log_2 (n)$ being the minimum.\n", + "\n", + "$y_n$: $T$\n", + "\n", + "- bits dedicated to keeping track of current time\n", + "\n", + "$-r_ϵ$: $Φ$\n", + "\n", + "- bits dedicated to varying VaR\n", + "\n", + "\n", + "$S_{yt}$: $log_2(T)$\n", + "\n", + "- bits dedicated to y's slack variables\n", + "\n", + "$S_r: Φ$\n", + "\n", + "- bits dedicated to $r_ϵ$'s slack variable\n", + "\n", + "$S_{...}$: $Φ * T$\n", + "\n", + "- bits dedicated to slack variables for the second equality\n", + "\n", + "So, assuming p = 80, which is what we will be assuming for the rest of the challenge, so we end up using the binary variable distribution:\n", + "\n", + "$x_n$: $n * [log_2 (n) + g] = 18$\n", + "\n", + "\n", + "$y_n$: $T = 10$\n", + "\n", + "\n", + "$-r_ϵ$: $Φ = 4$\n", + "\n", + "\n", + "$S_{yt}$: $log_2(T) = 4$\n", + "\n", + "\n", + "$S_r$ : $Φ = 4$\n", + "\n", + "\n", + "$S_{...}$: $Φ * T = 40$\n", + "\n", + "\n", + "\n", + "Therefore the total binary variables used is 80.\n", + "\n" + ], + "metadata": { + "id": "rNa9yosXoxAV" + }, + "id": "rNa9yosXoxAV" + }, + { + "cell_type": "code", + "execution_count": null, + "id": "553d8b31", + "metadata": { + "id": "553d8b31" + }, + "outputs": [], + "source": [ + "# write your code here\n", + "from pyqubo import Array, Binary, LogEncInteger, Placeholder, Constraint\n", + "\n", + "# Number of qubits we have\n", + "QUBIT_COUNT = 80\n", + "\n", + "# Number of binary variables per variable\n", + "g = 4\n", + "x_size = int(np.ceil(np.log2(number_assets)) + g)\n", + "y_size = 1\n", + "s_3_size = int(np.ceil(np.log2(T)))\n", + "phi = (QUBIT_COUNT - (x_size * number_assets + y_size * T + s_3_size)) // (T+2)\n", + "r_size = phi\n", + "s_1_size = phi\n", + "s_2_size = phi\n", + "\n", + "# Set up the variables\n", + "x = [1/(2**x_size - 1) * LogEncInteger(f\"x{i}\", (0, 2**x_size - 1)) for i in range(number_assets)]\n", + "y = Array.create('y', shape = T, vartype = 'BINARY')\n", + "# Note r is range of -1 to 0, instead of -z to 0\n", + "r = -1/(2**r_size - 1)*LogEncInteger(f\"r\", (0, 2**r_size - 1))\n", + "s_1 = 1/(2**s_1_size - 1)*LogEncInteger(f\"s_1\", (0, 2**s_1_size - 1))\n", + "s_2 = [1/(2**s_2_size - 1)*LogEncInteger(f\"s_2{i}\", (0, 2**s_2_size - 1)) for i in range(T)]\n", + "s_3 = 1/(2**s_3_size - 1)*LogEncInteger(f\"s_3\", (0, 2**s_3_size - 1))\n", + "\n", + "lambda_1 = Placeholder(\"lmd1\")\n", + "lambda_2 = [Placeholder(f\"lmbd2{i}\") for i in range(T)]\n", + "lambda_3 = Placeholder(\"lmd3\")\n", + "lambda_4 = Placeholder(\"lmd4\")\n", + "# Temporary values for lambdas\n", + "feed_dict = {\n", + " 'lmd1': 1,\n", + " 'lmd3': 1,\n", + " 'lmd4': 1\n", + "}\n", + "for i in range(T):\n", + " feed_dict[f\"lmbd2{i}\"] = 1\n", + "\n", + "z = 0.04238\n", + "M = -z-np.min(np.min(R))\n", + "e = 0.01\n", + "\n", + "H1 = 0 # The first term\n", + "for k in range(number_assets):\n", + " for j in range(number_assets):\n", + " H1 += x[k] * x[j] * covariance_matrix[k][j]\n", + "\n", + "H2 = 0 # The second term\n", + "for k in range(number_assets):\n", + " H2 += -expected_returns[k] * x[k]\n", + "\n", + "# The constraints\n", + "soft_constraint = lambda x: abs(x) < 1e-3\n", + "\n", + "H3 = lambda_1 * Constraint((-r * z + s_1 - z) ** 2, \"First Constraint\", soft_constraint)\n", + "\n", + "for t in range(T):\n", + " H3 += lambda_2[t] * Constraint((sum([R[i][t] * x[i] for i in range(number_assets)]) + M * y[t] + r + s_2[t] - M) ** 2, f\"Second Constraint{t}\", soft_constraint)\n", + "\n", + "H3 += lambda_3 * Constraint((-sum(y) + s_3 + T * (1-e)) ** 2, \"Third Constraint\", soft_constraint)\n", + "H3 += lambda_4 * Constraint((sum(x) - 1) ** 2, \"Fourth Constraint\", soft_constraint)\n", + "\n", + "H = H1 + H2 + H3\n", + "model = H.compile()\n", + "qubo, offset = model.to_qubo(feed_dict = feed_dict)" + ] + }, + { + "cell_type": "markdown", + "id": "ed9d5b11-b2f3-4c79-bdf9-000cd7685f85", + "metadata": { + "id": "ed9d5b11-b2f3-4c79-bdf9-000cd7685f85" + }, + "source": [ + "
\n", + " \n", + "BONUS EXERCISE:\n", + "As you notice the number of binary operators one has to use scales with the number of variables. Introducing the slack variables is therefore very costly. Try to suggest a new way of implementing the inequalities, without a lot of details. You can use the help of reference [Unbalanced penalization: A new approach to encode inequality constraints of combinatorial problems for quantum optimization algorithms](https://arxiv.org/abs/2211.13914).\n", + "\n", + "
" + ] + }, + { + "cell_type": "markdown", + "id": "51466cca-e371-4f55-bdee-7b2eea6159d8", + "metadata": { + "id": "51466cca-e371-4f55-bdee-7b2eea6159d8" + }, + "source": [ + "**Answer:**\n", + "\n", + "Our current penalty terms for the constraints looks like\n", + "\n", + "$$\\sum_{j = 1}^{T+3}\\lambda_j\\left(\\sum_{i = 1}^{n+T+1}(A_{ji} x_i) - b_j+ s_j \\right)^2$$\n", + "or if we write out the digits of $s_j$,\n", + "$$\\sum_{j = 1}^{T+3}\\lambda_{j} \\left(\\sum_{i=1}^{n+T+1} (A_{ji}x_{i}) - b_j + \\beta_t\\sum_{k=1}^{D} 2^{-k} s_{jk}\\right)^2$$\n", + "where $s_{jk}$ are the digits of the slack variables of slack variable $s_j$. This means we have to use $D(T+3)$ extra binary digits for the slack variables.\n", + "\n", + "Instead, we implement the inequalities as unbalanced penalization functions, specifically an exponential decay. For QUBO to work, we need to approximate the exponential as\n", + "$$e^{-h(x)}-1 = -h(x)+\\frac{1}{2} h(x)^2$$\n", + "where we are trying to constrain $h(t)\\leq 0$, and the penalty to go to $0$ as $h$ goes to $0$. The constant term can be ignored in the minimization. So our new penalty would be\n", + "\n", + "$$\\sum_{j = 1}^{T+3}\\left[-\\lambda_{j,1}\\left(\\sum_{i = 1}^{n+T+1}(A_{ji} x_i) - b_j\\right)+\\lambda_{j,2}\\left(\\sum_{i = 1}^{n+T+1}(A_{ji} x_i) - b_j\\right)^2\\right]$$\n", + "\n", + "We have effectively traded $D(T+3)$ slack variable digits (so less qubits required) for more penalty term coefficients that we need to tune." + ] + }, + { + "cell_type": "markdown", + "id": "9344d008-0e1a-45fd-9aa3-1399e56b859c", + "metadata": { + "id": "9344d008-0e1a-45fd-9aa3-1399e56b859c" + }, + "source": [ + "### Section 3: Simulated Annealing" + ] + }, + { + "cell_type": "markdown", + "id": "1a9abb2c-9062-451e-9b4b-8009bd455e3c", + "metadata": { + "id": "1a9abb2c-9062-451e-9b4b-8009bd455e3c" + }, + "source": [ + "Optimization problems, like the one above, can be solved with the use of simulated annealing. It is one of the most preferred heuristic methods to solve optimization problems, since it avoids local minima." + ] + }, + { + "cell_type": "markdown", + "id": "49533860-07ce-4bea-a2b8-c1a8cd3d2670", + "metadata": { + "id": "49533860-07ce-4bea-a2b8-c1a8cd3d2670" + }, + "source": [ + "- Using simulated annealing and the **data** calculate the ground state and find the best solution of the QUBO problem, $L_{fin}$, found in **Section 2**. Note that the lagrange multipliers in front of the penalty terms/constraints will need to be fine-tuned so that the equalities/inequalities of the problem are all satisfied. The output of the algorithm will give you the optimal values of the binary variables of the encoding of $\\{x_{i}\\}$, $r_{\\epsilon}$, $\\{y_{t}\\}$ and the slack variables so that the return is maximized, the risk is minimized while at the same time the inequality/equality constraints of the problem are all satisfied. In the next section you will learn how to evaluate your solutions." + ] + }, + { + "cell_type": "markdown", + "id": "9a897de7-1efd-414e-bf16-a3f2353c9f6b", + "metadata": { + "id": "9a897de7-1efd-414e-bf16-a3f2353c9f6b" + }, + "source": [ + "
NOTE 1 (Hint):\n", + "\n", + "\n", + "Feel free to first read any references provided online for Simulated Annealing like [Optimization Simulated Annealing](https://www.science.org/doi/10.1126/science.220.4598.671). You do not need to write your own code for this Section. Instead try [pyqubo](https://pyqubo.readthedocs.io/en/latest/getting_started.html#) and [D-Wave neal](https://docs.ocean.dwavesys.com/projects/neal/en/latest/).\n", + "
" + ] + }, + { + "cell_type": "markdown", + "id": "54c2a1b7-feda-4461-bd63-b5e183e0b8f7", + "metadata": { + "id": "54c2a1b7-feda-4461-bd63-b5e183e0b8f7" + }, + "source": [ + "
NOTE 2 (Hint):\n", + "\n", + " [pyqubo](https://pyqubo.readthedocs.io/en/latest/getting_started.html#) offers an easy way to evaluate whether the constraints are satisfied or not. Use it so that you are able to fine-tune the lagrange multipliers and get your solution to be as close as possible in satisfying the constraints.\n", + " \n", + " The lagrange multipliers act as relative weights between the different terms of the QUBO problem. Fine-tuning them so that the constraints of the problem are satisfied is **not** trivial. The fine-tuning process goes as following:\n", + " \n", + " Consider the following constraint optimization problem:\n", + " $$\\text{min} f(\\textbf{x})$$\n", + " subject to the constraint:\n", + " $$c(\\textbf{x})=0.$$\n", + "We can find a solution to this problem with the use of the **penalty method** approach, where we define a new objective function that includes the constraint as an added penalty term in the objective fuction. The $k^{th}$ step of the now unconstraint optimization problem is the following:\n", + "$$\\text{min}\\Psi_{k}(\\textbf{x})=f(\\textbf{x})+\\mu_{k}c(\\textbf{x})^{2}$$\n", + " with $\\mu_{k}$ the lagrange multiplier of this step (or else the penalty term coefficient). In order to fine-tune the langrange multiplier you start with a large-enough value of $\\mu_{1}$ (in comparison to the coefficients of the non-penalty terms of the QUBO problem). In the next steps of the iteration you increase the value of the coefficient until the constraints are satisfied.\n", + " \n", + " Specifically take a look at [pyqubo--validation of the constraints](https://pyqubo.readthedocs.io/en/latest/getting_started.html#validation-of-constraints). One could check whether the constraints are satisfied by making sure the energy contribution of each penalty term is 0. [pyqubo--validation of the constraints](https://pyqubo.readthedocs.io/en/latest/getting_started.html#validation-of-constraints) outputs the energy contribution of each penalty term. If you do not manage to get the energy contribution of the penalty terms to exactly 0, make sure they are as close as possible to that.\n", + "
" + ] + }, + { + "cell_type": "markdown", + "id": "ce724e8f-cc21-49fb-89b6-7e2b1e93296f", + "metadata": { + "id": "ce724e8f-cc21-49fb-89b6-7e2b1e93296f" + }, + "source": [ + "
NOTE 3 (Hint):\n", + "The binary variables used for the encoding of $\\{x_{i}\\}$, $r_{\\epsilon}$, $\\{y_{t}\\}$ and all the slack variables affect the granularity of the problem. Choose the number of binary variables you use for the encoding of each one of the variables $\\{x_{i}\\}$, $r_{\\epsilon}$ and the slack variables. Why do you think that's a reasonable number of binary variables? How many binary variables do you need to use for the variables $\\{y_{t}\\}$?\n", + "
" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a359a291-bbb0-4f4f-97fd-acd5f90d8eb6", + "metadata": { + "id": "a359a291-bbb0-4f4f-97fd-acd5f90d8eb6", + "colab": { + "base_uri": "https://localhost:8080/" + }, + "outputId": "bf9e1174-ada9-49cb-a635-cd40b2f248c7" + }, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "{'Fourth Constraint': (True, -1.8041124150158794e-16), 'First Constraint': (True, 3.246334309293835e-08), 'Second Constraint2': (True, 1.5039738098141906e-07), 'Third Constraint': (True, 0.0008999999999996788), 'Second Constraint0': (True, 7.690880993535025e-09), 'Second Constraint1': (True, 2.8736800918583425e-08)}\n", + "[DecodedSolution({x2[5]:0, x2[1]:1, x2[0]:0, x1[4]:0, x1[3]:0, x1[1]:0, x1[0]:1, x0[5]:1, x0[2]:1, s_20[3]:0, s_22[10]:0, s_20[2]:0, s_20[9]:0, s_1[7]:0, s_20[1]:1, s_22[1]:0, x0[0]:0, s_1[6]:1, s_21[6]:1, s_21[8]:0, s_1[4]:0, s_20[0]:1, s_21[2]:1, s_3[1]:0, y[0]:1, s_1[1]:1, s_1[2]:0, y[2]:1, r[3]:1, y[1]:1, s_1[3]:1, s_20[4]:0, x2[3]:1, s_21[0]:0, s_22[5]:0, x2[2]:0, s_1[8]:0, s_22[6]:0, r[10]:0, s_1[5]:0, r[1]:1, r[5]:0, x1[2]:0, s_20[6]:0, s_21[10]:0, s_22[7]:0, r[7]:0, r[9]:0, r[8]:1, s_22[3]:1, r[0]:0, x2[4]:0, s_22[0]:0, r[2]:1, r[6]:0, x0[3]:0, s_21[9]:0, s_22[2]:1, r[4]:1, s_1[0]:1, s_1[10]:0, s_3[0]:0, s_20[7]:0, s_20[8]:1, s_21[1]:1, s_21[3]:1, x1[5]:0, s_21[4]:0, x0[4]:1, s_21[5]:0, s_21[7]:1, s_22[4]:0, s_22[8]:1, s_20[5]:1, s_22[9]:0, s_1[9]:0, s_20[10]:0, x0[1]:0}, energy=0.075229)]\n" + ] + } + ], + "source": [ + "# write your code here\n", + "import neal\n", + "from itertools import product\n", + "\n", + "# Ranges for lambda\n", + "a, b = 100,102\n", + "ranges = {\n", + " 'lmd1':list(range(a, b)),\n", + " 'lmd3': list(range(a, b)),\n", + " 'lmd4': list(range(a, b))\n", + "}\n", + "for i in range(T):\n", + " ranges[f\"lmbd2{i}\"] = list(range(a, b))\n", + "\n", + "possibilities = list(product(*ranges.values()))\n", + "\n", + "sampler = neal.SimulatedAnnealingSampler()\n", + "feasible_sols =[]\n", + "for p in possibilities:\n", + " feed_dict = {key: value for key, value in zip(ranges.keys(), p)}\n", + " # qubo, offset = model.to_qubo(feed_dict = feed_dict)\n", + " bqm = model.to_bqm(feed_dict = feed_dict)\n", + " bqm.normalize()\n", + " sampleset = sampler.sample(bqm, num_reads = 10)#, sweeps = 1000, beta_schedule_type = 'custom', beta_schedule = [0, 1, 2, 3])\n", + " #sampleset = sampler.sample_qubo(qubo)\n", + " dec_samples = model.decode_sampleset(sampleset, feed_dict = feed_dict)\n", + " best = min(dec_samples, key = lambda x: x.energy)\n", + "\n", + " print(best.constraints())\n", + "\n", + " if not best.constraints(only_broken = True):\n", + " feasible_sols.append(best)\n", + "\n", + "print(feasible_sols)\n", + "best_feasible = min(feasible_sols,key=lambda x: x.energy)" + ] + }, + { + "cell_type": "markdown", + "id": "5e4786ea-1db6-46a6-b9f8-d1bfcdb88b20", + "metadata": { + "id": "5e4786ea-1db6-46a6-b9f8-d1bfcdb88b20" + }, + "source": [ + "### Section 4: Simulated Annealing--Verifying your solutions" + ] + }, + { + "cell_type": "markdown", + "id": "37e4d030-3484-4fe2-b2de-7c2d374e58af", + "metadata": { + "id": "37e4d030-3484-4fe2-b2de-7c2d374e58af" + }, + "source": [ + "In the previous section you solved the **Mean-Variance-VaR** problem with Simulated Annealing, making sure that the penalty terms are imposed properly, so that the equalities/inequalities of the problem are satisfied. In this section, you will further test your solutions.\n", + "- From the output of **Section 3** you get the optimal values of the binary variables of the encoding. For example, for the variable $x_{i}$ we have:\n", + "$$x_{i}=\\sum_{d=1}^{D}f(d)z_{di}$$\n", + "with $\\{ z_{di} \\}$ the output of **Section 3** and $f(d)$ the function you have chosen for the encoding. Use this output in order to calculate the optimal percentages of the total portfolio invested in each one of the assets, $\\{x_{i}\\}$.\n", + "- After obtaining $\\{ x_{i} \\}$ use them to calculate the **expected total returns**: $$\\mu_{P}(x):=\\sum_{k=1}^{n}\\mu_{k}x_{k}$$\n", + " and **variance**: $$V(x):=\\sum_{k=1}^{n}\\sum_{j=1}^{n}x_{k}x_{j}\\sigma_{kj}$$\n", + "- In a similar way, from the output of **Section 3** calculate the $VaR_{\\epsilon}=-r_{\\epsilon}$.\n", + "- Run the code of **Section 3** multiple times. Each time calculate the expected returns, the variance and $VaR_{\\epsilon}$. Peak the best result and justify your answer.\n", + "- Calculate the historical VaR with the use of the following function:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "95761549", + "metadata": { + "id": "95761549" + }, + "outputs": [], + "source": [ + "def calculate_historical_VaR(weights, mu_R, confidence_level=0.95):\n", + "\n", + " portfolio_returns = np.dot(mu_R, np.transpose(np.array(weights)))\n", + "\n", + " VaR = np.percentile(portfolio_returns, 100 * (1 - confidence_level))\n", + "\n", + " return -VaR" + ] + }, + { + "cell_type": "markdown", + "id": "09d0c42b", + "metadata": { + "id": "09d0c42b" + }, + "source": [ + "with $\\textit{weights}$ being a list that includes the optimal values (your solution) for the variables $\\{x_{i}\\}$ and $\\textit{mu_R}$ the expected returns of the assets (given by the data). Compare the return value got from this function to $VaR_{\\epsilon}$ calculated above." + ] + }, + { + "cell_type": "markdown", + "id": "e32da760-2d7c-44cc-b541-0fd576eaedf2", + "metadata": { + "id": "e32da760-2d7c-44cc-b541-0fd576eaedf2" + }, + "source": [ + "**Answer:**" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7c6d5972", + "metadata": { + "id": "7c6d5972" + }, + "outputs": [], + "source": [ + "x_value = []\n", + "for i in range(len(x)):\n", + " x_str = ''.join([str(best_feasible.sample[f\"x{i}[{pos}]\"]) for pos in range(x_size - 1, -1, -1)])\n", + " x_value.append(1/(2**x_size - 1) * int(x_str, base = 2))\n", + "print(x_value)\n", + "\n", + "mu_P = sum([expected_returns[k]*x_value[k] for k in range(number_assets)])\n", + "print(mu_P)\n", + "\n", + "V = 0\n", + "for k in range(number_assets):\n", + " for j in range(number_assets):\n", + " V += x_value[k] * x_value[j] * covariance_matrix[k][j]\n", + "print(V)\n", + "\n", + "r_value = None\n", + "r_str = ''.join([str(best_feasible.sample[f\"r[{pos}]\"]) for pos in range(r_size - 1, -1, -1)])\n", + "r_value = -1/(2**r_size - 1) * int(r_str, base = 2) * z\n", + "print(r_value)\n", + "\n", + "print(calculate_historical_VaR(x_value, expected_returns, confidence_level = 1 - e))" + ] + }, + { + "cell_type": "markdown", + "id": "9acc19d6-5b85-4ef4-aef4-7cdfe709b566", + "metadata": { + "id": "9acc19d6-5b85-4ef4-aef4-7cdfe709b566" + }, + "source": [ + "### Section 5: Quantum optimization (Quantum Annealing and/or QAOA)" + ] + }, + { + "cell_type": "markdown", + "id": "ac6a4eab-e29a-470d-ba29-a3995c8eac10", + "metadata": { + "id": "ac6a4eab-e29a-470d-ba29-a3995c8eac10" + }, + "source": [ + "\n", + "**Note**: For the exercises below use the $\\hat{H}$ you found in **Section 2**, with the same encoding you used in that exercise and with the use of the **data** provided in the beginning of the challenge.\n", + "\n", + "**STEP 1:** Study the **Mean-Variance-VaR Simplified Version** problem with QAOA and Quantum Annealing.\n", + "\n", + "The Quantum Approximate Optimization Algorithm (QAOA) was first introduced in [A Quantum Approximate Optimization Algorithm](https://arxiv.org/abs/1411.4028). QAOA is a popular method to solve combinatorial optimization problems in noisy intermediate-scale quantum (NISQ) devices.\n", + "\n", + "Useful tutorials on implementing QAOA can be found here:\n", + "- [Pulser tutorial QAOA](https://pulser.readthedocs.io/en/latest/tutorials/qubo.html)\n", + "- [Qiskit QAOA](https://docs.quantum.ibm.com/api/qiskit/qiskit.algorithms.minimum_eigensolvers.QAOA), [Qiskit tutorial QAOA](https://qiskit.org/documentation/stable/0.40/tutorials/algorithms/05_qaoa.html)\n", + "- [pyQAOA tutorial QAOA](https://grove-docs.readthedocs.io/en/latest/qaoa.html)\n", + "- [PennyLane tutorial QAOA](https://pennylane.ai/qml/demos/tutorial_qaoa_intro/)\n", + "- [OpenQAOA-EntropicaLabs](https://openqaoa.entropicalabs.com/)\n", + "\n", + "For Quantum Annealing, you may read this reference [D-Wave, Quantum Annealing](https://docs.dwavesys.com/docs/latest/c_gs_2.html#getting-started-qa) and follow [D-Wave Ocean Software documentation](https://docs.ocean.dwavesys.com/en/stable/index.html) for the implementation.\n", + "In [Solving the Optimal Trading Trajectory Problem Using a Quantum Annealer](https://arxiv.org/abs/1508.06182), the authors explain how the choice of encoding might differ when considering solving an optimization problem with quantum annealing instead of simulated annealing.\n", + " \n", + "Do not implement anything at the moment. This step is for introducing you to different quantum or quantum-inspired algorithms one could utilize for this problem.\n", + "\n", + "**STEP 2:** In **Section 3** you used [D-Wave neal](https://docs.ocean.dwavesys.com/projects/neal/en/latest/) to solve the problem with Simulated Annealing. As also seen in the previous step, [D-Wave Ocean](https://docs.ocean.dwavesys.com/en/stable/getting_started.html) gives you immediate, secure access to D-Wave quantum and hybrid solvers. Study the capabilities of [D-Wave Ocean](https://docs.ocean.dwavesys.com/en/stable/getting_started.html) and answer the following questions:\n", + "\n", + "- For reasonable granularity (i.e. number of qubits per encoded variable) how many assets $n$ and events $T$ you can study with a quantum device and D-Wave? For that you will need to find the total number of qubits that you can explore with [D-Wave Ocean](https://docs.ocean.dwavesys.com/en/stable/getting_started.html) for the algorithm of your choice. Notice that the resources available to the public are much less than the capabilities of these devices.\n", + "\n", + "**STEP 3:** After exploring the capabilities of [D-Wave Ocean Software documentation](https://docs.ocean.dwavesys.com/en/stable/index.html), you are encouraged to use a **quantum simulator/backend** to study the **Mean-Variance-VaR Simplified Version** problem with the **data** provided in the beginning of the challenge (feel free to change $T$ and $n$ if needed) and any method of your choice. For this, you can use your qBraid account. Explore the options below:\n", + "\n", + "- [Qiskit](https://docs.quantum.ibm.com/api/qiskit)\n", + "- [Amazon Braket](https://docs.aws.amazon.com/braket/latest/developerguide/what-is-braket.html)\n", + "\n", + "Or even more, you may also opt to explore the usage of GPUs for simulating quantum algorithms. For example, see a recent [work](https://www.jpmorgan.com/technology/technology-blog/quantum-optimization-research) that studies QAOA scaling performance on a fast GPU-specific QAOA simulator.\n", + "\n", + "No matter what algorithm you choose, **you are encouraged to run small-scale simulations of the problems on quantum backends and simulators, always keeping in mind the resources that you are utilizing and their cost**. What problems/limitations do you encounter in comparison with simulated annealing?" + ] + }, + { + "cell_type": "markdown", + "id": "dbc17d65-627d-4805-ac9f-3a3803bfc70d", + "metadata": { + "id": "dbc17d65-627d-4805-ac9f-3a3803bfc70d" + }, + "source": [ + "
Note 1 (Hint):\n", + " \n", + " One could read the following references:\n", + "\n", + "- [Quantum Optimization: Potential, Challenges, and the Path Forward](https://arxiv.org/abs/2312.02279) and references within.\n", + " \n", + "
" + ] + }, + { + "cell_type": "markdown", + "id": "8b4a5f08-14de-4d26-8031-8c1b2cd4f003", + "metadata": { + "id": "8b4a5f08-14de-4d26-8031-8c1b2cd4f003" + }, + "source": [ + "
Note 2 (Hint):\n", + " \n", + "One can take a look at the [IBM Quantum Development Roadmap to 2033](https://newsroom.ibm.com/2023-12-04-IBM-Debuts-Next-Generation-Quantum-Processor-IBM-Quantum-System-Two,-Extends-Roadmap-to-Advance-Era-of-Quantum-Utility) and [QuEra's Quantum Computing Roadmap](https://www.quera.com/press-releases/quera-computing-releases-a-groundbreaking-roadmap-for-advanced-error-corrected-quantum-computers-pioneering-the-next-frontier-in-quantum-innovation) for an idea about the current and predicted quantum capabilities.\n", + " \n", + "
" + ] + }, + { + "cell_type": "markdown", + "id": "990a82c7-6ccc-4552-8b86-97a95fece3cd", + "metadata": { + "id": "990a82c7-6ccc-4552-8b86-97a95fece3cd" + }, + "source": [ + "**Answer:**" + ] + }, + { + "cell_type": "markdown", + "source": [ + "Physically, the D-Wave quantum annealer is implemented as an array of superconducting loops for qubits, with current circulating clockwise or counterclockwise in order to represent +1s and -1s. In order to program a specific Hamiltonian function into the quantum annealer, bias terms can be applied to each qubit using external magnetic fields, and qubits can also be coupled together, which acts as a tuneable correlation weight between them. With the bias and correlation terms, any Hamiltonian of interest can be programmed, which is written as a quadratic function of the spins of each qubit. By making the change of variables x = (s+1)/2, the spins become 0s and 1s and the system has been recast as a quadratic unconstrained binary optimization (QUBO) problem. However, not every qubit can be correlated with every other qubit. There is a very specific network topology, so in order to represent the Hamiltonian as an arbitrary graph and embed it into the qubit network, some qubits need to be chained together, effectively acting as a single variable by highly correlating with each other.\n", + "\n", + "Quantum annealing with many variables is therefore harder than simulated annealing because of hardware limitations and noise. We have a much smaller set of qubits that we can use to run the simulation, and DWave chains multiple qubits together in order to make a single 'logical' qubit. There is also the issue of how the qubits are physically connected. Since not every qubit has a correlation with every other qubit (it is only connected to the ~10 nearest neighbors), not every possible graph can be represented without some kind of embedding, which could possibly take many more qubits. The upside is that because it is a physical process, it is much faster: even though it is an adiabatic process, which sounds like it should be slow, the timescale depends mainly on the temperature and scales like exp(sqrt(N)) rather than exp(N) because of quantum tunneling.\n", + "\n", + "Given that D-wave allows us to use 80 qubits, and at the reasonable granularity of 1/64 of total assets, we can simulate 3 assets for 6 weeks. This is an answer backed by data and will be covered briefly in the presentation." + ], + "metadata": { + "id": "ikLFsJ3FmbVW" + }, + "id": "ikLFsJ3FmbVW" + }, + { + "cell_type": "markdown", + "source": [ + "The below code is our above code adapted for the dwave quantum annealer. This code accesses the DwaveSampler and performs the previous quantum annealment. We then convert from binary to readable data using the code from Problem 4." + ], + "metadata": { + "id": "VStBngFVkARt" + }, + "id": "VStBngFVkARt" + }, + { + "cell_type": "code", + "execution_count": null, + "id": "aa60be68", + "metadata": { + "id": "aa60be68" + }, + "outputs": [], + "source": [ + "# write your code here\n", + "import neal\n", + "from itertools import product\n", + "from dwave.system import DWaveSampler, EmbeddingComposite\n", + "\n", + "# Ranges for lambda\n", + "a, b = 100,102\n", + "ranges = {\n", + " 'lmd1':list(range(a, b)),\n", + " 'lmd3': list(range(a, b)),\n", + " 'lmd4': list(range(a, b))\n", + "}\n", + "for i in range(T):\n", + " ranges[f\"lmbd2{i}\"] = list(range(a, b))\n", + "\n", + "possibilities = list(product(*ranges.values()))\n", + "\n", + "sampler = EmbeddingComposite(DWaveSampler())\n", + "feasible_sols =[]\n", + "for p in possibilities:\n", + " feed_dict = {key: value for key, value in zip(ranges.keys(), p)}\n", + " # qubo, offset = model.to_qubo(feed_dict = feed_dict)\n", + " bqm = model.to_bqm(feed_dict = feed_dict)\n", + " bqm.normalize()\n", + " sampleset = sampler.sample(bqm, num_reads = 10)#, sweeps = 1000, beta_schedule_type = 'custom', beta_schedule = [0, 1, 2, 3])\n", + " #sampleset = sampler.sample_qubo(qubo)\n", + " dec_samples = model.decode_sampleset(sampleset, feed_dict = feed_dict)\n", + " best = min(dec_samples, key = lambda x: x.energy)\n", + "\n", + " print(best.constraints())\n", + "\n", + " if not best.constraints(only_broken = True):\n", + " feasible_sols.append(best)\n", + "\n", + " if len(feasible_sols) > 0:\n", + " break\n", + "print(feasible_sols)\n", + "best_feasible = min(feasible_sols,key=lambda x: x.energy)" + ] + }, + { + "cell_type": "markdown", + "id": "95e10967", + "metadata": { + "id": "95e10967" + }, + "source": [ + "### Section 6 (BONUS):\n", + "\n", + "Above you followed specific steps and used simulated annealing as well as quantum or quantum-inspired methods to solve the problem of interest. To do this, you were instructed to incorporate the constraints of the problem (equalities/inequalities) in the objective function and then to find the QUBO formulation of the problem in question. In this exercise you are asked to think of another way to solve the **Mean-Variance-VaR Simplified Version** problem with quantum, quantum-inspired or hybrid methods, without following any of the steps mentioned in this challenge." + ] + }, + { + "cell_type": "markdown", + "id": "d57153d6", + "metadata": { + "id": "d57153d6" + }, + "source": [ + "**Answer:**" + ] + }, + { + "cell_type": "markdown", + "source": [ + "**Hybrid HHL**\n", + "\n", + "Portfolio optimization can be reformulated as convex quadratic program. This is equivalent to solving a linear system Ax=b using the method of Lagrange multipliers (so A is an augmented covariance matrix). Note that this is NOT encoded using binary variables yet. While we turned this into a QUBO problem for sections 1-5 so that we could use simulated and quantum annealing solvers, we do not necessarily have to do this.\n", + "\n", + "Instead, we propose an alternative way to solve this problem using a quantum/classical hybrid linear solvers. Quantum state representing the solution can be obtained by solving the corresponding QLSP using the HHL algorithm. This can be done because the covariance matrix is Hermitian. The resulting quantum state allows us to recover the optimal portfolio.\n", + "\n", + "HHL is a method of solving linear systems of equations using quantum computers, taking advantage of the speedup of the quantum Fourier transform. Noteably, HHL on its own is hard to implement on NISQ hardware because of the need for lots of connections between different qubits compared to the limited topology of the computers. In order to limit the number of swap (and other) gates in the implementation of the HHL algorithm, a hybrid approach can make it more efficient.\n", + "\n", + "Classical methods are used to determine how to scale the matrix A. In the foundational HHL article, the eigenvalues are restricted to [1/k, 1] to\n", + "account for the periodicity of the imaginary exponential and ensure well-conditioning. We need A to have a spectrum in this range, but it is more efficient to estimate λmax first so we don't waste bits for encoding unnecessarily and then scaling A by γ = 1/λmax, so that the maximum eigenvalue of γA is 1. We also use classical methods to guess a scaling parameter and then determine by how much it overestimates.\n", + "\n", + "Sources:\n", + "- \"Hybrid HHL with Dynamic Quantum Circuits on Real Hardware\" (https://arxiv.org/abs/2110.15958)\n", + "- Qiskit Documentation (https://docs.quantum.ibm.com/api/qiskit/0.35/qiskit.algorithms.linear_solvers.HHL)" + ], + "metadata": { + "id": "djc0kzxLe-rq" + }, + "id": "djc0kzxLe-rq" + }, + { + "cell_type": "markdown", + "source": [ + "**QRNNs**\n", + "\n", + "Recurrent Neural Network (RNN) are a type of deep learning models in which the subcomponent, NN, contains state data that remembers information over time and is stacked together with other subcomponents, which is ideal for predicting sequences and time series. QRNN are the quantum version of RNNs: the component stacking is staggered to improve coherent time (the staggering removes the need for some qubits to have long term persistent states). It is a fully quantum ML model: input and output requires minor prior and post processing. QRNN performance on classical data has been confirmed on weather data, natural language, and stock data. It shows theoretical better performance than RNNs and other QNN with needing under 10 quantum tunable parameters and even fewer qubits.\n", + "\n", + "Source:\n", + "- Quantum Recurrent Neural Networks for Sequential Learning: https://arxiv.org/pdf/2302.03244.pdf" + ], + "metadata": { + "id": "eKHj_nxGjLfV" + }, + "id": "eKHj_nxGjLfV" + }, + { + "cell_type": "code", + "execution_count": null, + "id": "067cea0c", + "metadata": { + "id": "067cea0c" + }, + "outputs": [], + "source": [ + "# write your code here" + ] + }, + { + "cell_type": "markdown", + "id": "71ae8d5b-93a8-4305-95a1-0cebf1f29cf6", + "metadata": { + "id": "71ae8d5b-93a8-4305-95a1-0cebf1f29cf6" + }, + "source": [ + "### Section 7: Pitch your quantum strategy to a client" + ] + }, + { + "cell_type": "markdown", + "id": "ecb9a766-b6df-4b91-b0ff-13ced8fc5b52", + "metadata": { + "id": "ecb9a766-b6df-4b91-b0ff-13ced8fc5b52" + }, + "source": [ + "Imagine that you are part of the Quantum team at Moody's. You are meeting the board of stakeholders of an important company in the US. Given what you now know about the current quantum hardware capabilities, in which quantum algorithms should the stakeholders invest and why? Prepare your pitch focusing only on portfolio optimization problems. How do you think quantum could potentially avoid the drawbacks of classical optimization algorithms and why should a company invest in quantum today?" + ] + }, + { + "cell_type": "markdown", + "id": "a440d8cd-2ed2-45e9-8a89-895847db823c", + "metadata": { + "id": "a440d8cd-2ed2-45e9-8a89-895847db823c" + }, + "source": [ + "
Hint:\n", + " \n", + " One could read the following references:\n", + "\n", + "- [Quantum Optimization: Potential, Challenges, and the Path Forward](https://arxiv.org/abs/2312.02279)\n", + "- [QAOA with N⋅p≥200](https://arxiv.org/abs/2303.02064)\n", + "- [Evidence of Scaling Advantage for the Quantum Approximate Optimization Algorithm on a Classically Intractable Problem](https://arxiv.org/pdf/2308.02342.pdf)\n", + "- [Towards optimization under uncertainty for fundamental models in energy markets using quantum computers](https://arxiv.org/abs/2301.01108)\n", + " \n", + "
" + ] + }, + { + "cell_type": "markdown", + "source": [ + "Citations:\n", + "\n" + ], + "metadata": { + "id": "-NtU1rdF-92P" + }, + "id": "-NtU1rdF-92P" + }, + { + "cell_type": "markdown", + "id": "550f2bc1-7726-417e-88b5-8253ac12baeb", + "metadata": { + "id": "550f2bc1-7726-417e-88b5-8253ac12baeb" + }, + "source": [ + "**Answer:**\n", + "\n", + "After carefully reviewing the quantum algorithms suited to solving the problem of portfolio optimization and thoroughly testing the implementations of several of them, we would recommend that stakeholders invest in both Quantum Annealment and Hybrid HHL (Harrow-Hassidim-Lloyd). We recommend Quantum Annealment due to its reliability, existing infrastructure, and highly noise-resistant processes. Furthermore, our personal testing has confirmed the speed and reliability of popular Quantum Annealing processes. Next, Hybrid HHL manages to take advantage of quantum advantage for portfolio optimization while still using classical computing to dramatically increase the speed of several subroutines.\n", + "\n", + "Quantum manages to avoid many of the drawbacks of classical optimization algorithms by relying on physical processes that scale linearly with size of input, while classical processes scale exponentially. A company should invest in quantum in order to stay ahead in terms of computing power and take advantage of differences in the market.\n" + ] + }, + { + "cell_type": "markdown", + "id": "c098599c-7ab0-48b1-9e33-51d22502310d", + "metadata": { + "id": "c098599c-7ab0-48b1-9e33-51d22502310d" + }, + "source": [ + "# This is the end of the challenge. Good luck!" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "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.11.5" + }, + "colab": { + "provenance": [] + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} \ No newline at end of file