diff --git a/docs/source/tutorial.rst b/docs/source/tutorial.rst index 0fbf075d..e5697960 100644 --- a/docs/source/tutorial.rst +++ b/docs/source/tutorial.rst @@ -23,7 +23,8 @@ Jupyter Tutorials tutorials/vqex_mbl.ipynb tutorials/dqas.ipynb tutorials/barren_plateaus.ipynb - tutorials/qaoa_portfolio_optimization.ipynb + tutorials/qubo_problem.ipynb + tutorials/portfolio_optimization.ipynb tutorials/imag_time_evo.ipynb tutorials/classical_shadows.ipynb tutorials/sklearn_svc.ipynb diff --git a/docs/source/tutorials/portfolio_optimization.ipynb b/docs/source/tutorials/portfolio_optimization.ipynb new file mode 100644 index 00000000..7ec25888 --- /dev/null +++ b/docs/source/tutorials/portfolio_optimization.ipynb @@ -0,0 +1,499 @@ +{ + "cells": [ + { + "attachments": {}, + "cell_type": "markdown", + "id": "6ddb8a88-779a-43f7-ae14-115463bd87f5", + "metadata": {}, + "source": [ + "# Portfolio Optimization\n", + "\n", + "In this tutorial, we demonstrate the transformation of financial portfolio optimization into a quadratic unconstrained binary optimization (QUBO) problem. Subsequently, we employ the Quantum Approximate Optimization Algorithm (QAOA) to solve it. We will conduct a comparative analysis between the outcomes obtained through QAOA and those derived from classical brute force searching. Additionally, we explore the potential for enhancing results by customizing the QAOA 'mixer' component.\n", + "\n", + "## Introduction\n", + "\n", + "Consider the following scenario: Xiaoming, an astute individual, possesses a sum of money represented by $B$ and is contemplating investing it in the stock market. The market contains $n$ shares, each having an identical price. Xiaoming's objective is to maximize returns while minimizing risk, taking into account the varying levels of risk tolerance among individuals. Xiaoming's personal risk tolerance is represented by $q$. In light of these considerations, the question arises: Which shares should Xiaoming choose to construct an optimal portfolio?\n", + "\n", + "Xiaoming's predicament falls under the purview of portfolio optimization problems. These problems are classified as Quadratic Unconstrained Binary Optimization (QUBO) problems, wherein binary numbers are utilized to represent decisions. In this case, \"1\" signifies selection, while \"0\" denotes the opposite. To address the challenge of portfolio optimization, the Quantum Approximate Optimization Algorithm (QAOA) is employed.\n", + "\n", + "## Solving portfolio optimization problems with QAOA\n", + "\n", + "In a simple boolean Markowitz portfolio optimization problem, we wish to solve \n", + "\n", + "$$\n", + "\\min_{x\\in\\{0,1\\}^n}\\quad q x^T \\Sigma x - \\mu^T x\n", + "$$\n", + "\n", + "subject to a constraint\n", + "\n", + "$$\n", + "1^T x = B\n", + "$$\n", + "\n", + "where \n", + "* $n$: number of assets under consideration\n", + "* $q > 0 $: risk-appetite\n", + "* $\\Sigma \\in \\mathbb{R}^{n\\times n}$: covariance matrix of the assets\n", + "* $\\mu\\in\\mathbb{R}^n$: mean return of the assets\n", + "* $B$: budget (i.e., the total number of assets out of $n$ that can be selected)\n", + "\n", + "Our first step is to convert this constrained quadratic programming problem into a QUBO. We do this by adding a penalty factor $t$ and considering the alternative problem:\n", + "\n", + "$$\n", + "\\min_{x\\in\\{0,1\\}^n}\\quad q x^T \\Sigma x - \\mu^Tx + t(1^Tx-B)^2\n", + "$$\n", + "\n", + "The linear terms $\\mu^Tx = \\mu_1 x_1 + \\mu_2 x_2+\\ldots$ can all be transformed into squared forms, exploiting the properties of boolean variables where $0^2=0$ and $1^2=1$. The same trick is applied to the middle term of $t(1^Tx-B)^2$. Then the function is written as\n", + "\n", + "$$\n", + "\\min_{x\\in\\{0,1\\}^n}\\quad q x^T \\Sigma x - \\sum_{i=1}^n\\mu_i x_i^2 + t(1^Tx-B)^2\n", + "$$\n", + "\n", + "which is a QUBO problem\n", + "\n", + "$$\n", + "\\min_{x\\in\\{0,1\\}^n}\\quad x^T Q x + tB^2\n", + "$$\n", + "\n", + "where matrix $Q$ is\n", + "\n", + "$$\n", + "Q = q\\Sigma -\\mu\\begin{pmatrix}1 & \\\\ & 1\\\\ & & \\ddots\\end{pmatrix} + t\\begin{pmatrix}1 -2B & 1 & \\ldots & 1 \\\\\n", + "1 & 1-2B & 1 & \\ldots \\\\1 & 1 & 1-2B \\\\\n", + "\\vdots\\end{pmatrix}\n", + "$$\n", + "\n", + "and we ignore the constant term $t B^2$. We can now solve this by QAOA.\n", + "\n", + "## Set up" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "4f4feab6", + "metadata": {}, + "outputs": [], + "source": [ + "import tensorcircuit as tc\n", + "import numpy as np\n", + "import tensorflow as tf\n", + "import matplotlib.pyplot as plt\n", + "\n", + "from tensorcircuit.templates.ansatz import QAOA_ansatz_for_Ising\n", + "from tensorcircuit.templates.conversions import QUBO_to_Ising\n", + "from tensorcircuit.applications.optimization import QUBO_QAOA, QAOA_loss\n", + "from tensorcircuit.applications.finance.portfolio import StockData, QUBO_from_portfolio\n", + "\n", + "K = tc.set_backend(\"tensorflow\")\n", + "tf.compat.v1.logging.set_verbosity(tf.compat.v1.logging.ERROR)" + ] + }, + { + "cell_type": "markdown", + "id": "55659298", + "metadata": {}, + "source": [ + "## Import data\n", + "\n", + "To optimize a portfolio, it is essential to utilize historical data from various stocks within the same time frame. Websites such as [Nasdaq](Nasdaq.com) and [Yahoo Finance](https://finance.yahoo.com/) provide access to such data. The next step involves transforming this data into an annualized return ($\\mu$) and covariance matrix ($\\sigma$), which can be recognized by the Quantum Approximate Optimization Algorithm (QAOA). To simplify this process, we can utilize the `StockData` class. This class performs the necessary calculations for annualized return and covariance, as outlined in this [paper](https://doi.org/10.1007/s11128-022-03766-5). They are:\n", + "\n", + "$$\n", + "\\mu = \\left[\\prod ^m_{k=1}\\left(1+r_k^{(i)}\\right)\\right]^{\\frac{252}{m}}\\\\\n", + "\\sigma_{ij}=\\frac{252}{m}\\sum^m_{k=1}\\left(r_k^{(i)}-\\overline{r^{(i)}}\\right)\\left(r_k^{(j)}-\\overline{r^{(j)}}\\right)\n", + "$$\n", + "\n", + "Here is a demonstration of how to use this class:" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "id": "62bf0673", + "metadata": {}, + "outputs": [], + "source": [ + "import random\n", + "\n", + "# randomly generate historical data of 6 stocks in 1000 days\n", + "data = [[random.random() for i in range(1000)] for j in range(6)]\n", + "stock_data = StockData(data) # Create an instance\n", + "\n", + "# calculate the annualized return and covariance matrix\n", + "mu = stock_data.get_return()\n", + "sigma = stock_data.get_covariance()\n", + "\n", + "# some other information can also be obtained from this class\n", + "n_stocks = stock_data.n_stocks # number of stocks\n", + "n_days = stock_data.n_days # length of the time span\n", + "daily_change = stock_data.daily_change # relative change of each day" + ] + }, + { + "cell_type": "markdown", + "id": "0fb1d227", + "metadata": {}, + "source": [ + "In this analysis, we have carefully chosen six prominent stocks: Apple Inc. (AAPL), Microsoft Corporation (MSFT), NVIDIA Corporation (NVDA), Pfizer Inc. (PFE), Levi Strauss & Co. (LEVI), and Cisco Systems, Inc. (CSCO). We acquired their historical data spanning from 09/07/2022 to 09/07/2023 from Yahoo Finance. Here are the return and covariance associated with this dataset" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "a7eb3a74", + "metadata": {}, + "outputs": [], + "source": [ + "# real-world stock data, calculated using the class above\n", + "# stock name: aapl, msft, nvda, pfe, levi, csco\n", + "# from 09/07/2022 to 09/07/2023\n", + "mu = [1.21141, 1.15325, 2.06457, 0.63539, 0.63827, 1.12224]\n", + "\n", + "sigma = np.array(\n", + " [\n", + " [0.08488, 0.06738, 0.09963, 0.02124, 0.05516, 0.04059],\n", + " [0.06738, 0.10196, 0.11912, 0.02163, 0.0498, 0.04049],\n", + " [0.09963, 0.11912, 0.31026, 0.01977, 0.10415, 0.06179],\n", + " [0.02124, 0.02163, 0.01977, 0.05175, 0.01792, 0.02137],\n", + " [0.05516, 0.0498, 0.10415, 0.01792, 0.19366, 0.0432],\n", + " [0.04059, 0.04049, 0.06179, 0.02137, 0.0432, 0.05052],\n", + " ]\n", + ")" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "f6dc53d4-7ed0-436d-aa1f-8674c56e756e", + "metadata": {}, + "source": [ + "Using this mean and covariance data, we can now define our portfolio optimization problem, convert it to a QUBO matrix, and then extract the Pauli terms and weights, which is similar to what we do in the [QUBO tutorial](https://tensorcircuit.readthedocs.io/en/latest/tutorials/qubo_problem.html)." + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "3f6edcd5-3c10-49fc-86ea-160fc6d3187e", + "metadata": {}, + "outputs": [], + "source": [ + "q = 0.5 # the risk preference of investor\n", + "budget = 4 # Note that in this example, there are 6 assets, but a budget of only 4\n", + "penalty = 1.2\n", + "\n", + "Q = QUBO_from_portfolio(sigma, mu, q, budget, penalty)\n", + "portfolio_pauli_terms, portfolio_weights, portfolio_offset = QUBO_to_Ising(Q)" + ] + }, + { + "cell_type": "markdown", + "id": "730da712", + "metadata": {}, + "source": [ + "## Classical method\n", + "\n", + "We first use brute force to calculate the cost of each combination, which is the expectation value $x^TQx$ for each $x\\in\\{0, 1\\}^n$ ($n$ is the number of stocks). It will give us a clue about the performance of QAOA." + ] + }, + { + "cell_type": "code", + "execution_count": 31, + "id": "168f7c36", + "metadata": {}, + "outputs": [], + "source": [ + "def print_Q_cost(Q, wrap=False, reverse=False):\n", + " n_stocks = len(Q)\n", + " states = []\n", + " for i in range(2**n_stocks):\n", + " a = f\"{bin(i)[2:]:0>{n_stocks}}\"\n", + " n_ones = 0\n", + " for j in a:\n", + " if j == \"1\":\n", + " n_ones += 1\n", + " states.append(a)\n", + "\n", + " cost_dict = {}\n", + " for selection in states:\n", + " x = np.array([int(bit) for bit in selection])\n", + " cost_dict[selection] = np.dot(x, np.dot(Q, x))\n", + " cost_sorted = dict(sorted(cost_dict.items(), key=lambda item: item[1]))\n", + " if reverse == True:\n", + " cost_sorted = dict(\n", + " sorted(cost_dict.items(), key=lambda item: item[1], reverse=True)\n", + " )\n", + " num = 0\n", + " print(\"\\n-------------------------------------\")\n", + " print(\" selection\\t |\\t cost\")\n", + " print(\"-------------------------------------\")\n", + " for k, v in cost_sorted.items():\n", + " print(\"%10s\\t |\\t%.4f\" % (k, v))\n", + " num += 1\n", + " if (num >= 8) & (wrap == True):\n", + " break\n", + " print(\" ...\\t |\\t ...\")\n", + " print(\"-------------------------------------\")" + ] + }, + { + "cell_type": "code", + "execution_count": 32, + "id": "6a9d41c9", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "-------------------------------------\n", + " selection\t |\t cost\n", + "-------------------------------------\n", + " 111001\t |\t-24.0487\n", + " 101101\t |\t-23.7205\n", + " 111100\t |\t-23.6414\n", + " 011101\t |\t-23.6340\n", + " 101011\t |\t-23.5123\n", + " 011011\t |\t-23.4316\n", + " 111010\t |\t-23.4269\n", + " 111101\t |\t-23.3742\n", + " ...\t |\t ...\n", + "-------------------------------------\n" + ] + } + ], + "source": [ + "print_Q_cost(Q, wrap=True)" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "c34f3398", + "metadata": {}, + "source": [ + "### Use QAOA\n", + "\n", + "Here, a standard QAOA ansatz with 12 layers is used. This circuit will be trained for 1000 iterations." + ] + }, + { + "cell_type": "code", + "execution_count": 33, + "id": "9249ea96", + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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xowZY2bOnGkSiYT5zne+Q10fxHbhhReau+++21x22WXGGGMuvfTSks8Hok7j8bjZsmWLefzxx81JJ51kZs+ebdrb2803v/nNgfgN9iuxnNurr75q5s+f770PBALmww8/NLfeeqv1sh2q27Bhw4wxxnzuc58zkkxdXZ1JJpNm5syZ3jEnnniiMcaY008/3Uj5/+FkMhlz1FFHecdce+21Zvfu3SYSiVj/TZW0xWIx895775np06ebpUuXekGEeh6Ybe7cuebFF1/c5zGbN2823/3ud733dXV1prOz08yePdtIMhMmTDDGGDN16lTvmAsuuMBks1lz9NFHW/+NlbL9+te/Ng8//HDJvl/+8pfm8ccfp64HaOsriAxEnV533XVmx44dJf9uzJ0716xdu/agy+zU0EwkEtHUqVO1ZMkSb58xRkuWLNGZZ55psWSHtsGDB0uSdu7cKUmaOnWqqqqqSur5vffe08aNG716PvPMM/Xmm29q27Zt3jHPPfecBg8erE996lNlLH3la2xs1OLFi/XCCy+U7KeeB8Yll1yiFStW6KmnnlJzc7NWrVqla665xvv8+OOP19FHH11Sz4lEQsuXLy+p5127dmnlypXeMUuWLFEul9Ppp59evh9T4V5++WVNnz5d48aNkySdfPLJOuuss/Tb3/5WEnXth4Gq0zPPPFMvvvii0um0d8xzzz2nCRMmaMiQIQdVxop/6N1AGjZsmMLhsJqbm0v2Nzc3a8KECZZKdWgLBAJ64IEH9NJLL+ntt9+WJI0YMULJZFJ79uwpOba5uVkjRozwjunrv0PxM+TNnj1bU6ZM6XMeE/U8ME444QRdf/31uv/++/X9739f06ZN049//GOlUik99thjXj31VY8967ln2JOkbDarnTt3Us893HPPPaqrq9O7776rbDarUCik22+/XU8++aQkUdc+GKg6HTFihNavX7/XdxQ/271798cuo1NBBAOvsbFREydO1FlnnWW7KIedY445Rj/60Y80Y8YMlrn2UTAY1IoVK3T77bdLklavXq2JEyfquuuu02OPPWa5dIeXWbNm6aqrrtKVV16pt99+W5MnT9YDDzygzZs3U9cOc2popqWlRZlMRvX19SX76+vrtXXrVkulOnTNnz9fX/rSl3TeeeepqanJ279161ZFo1FvyKaoZz1v3bq1z/8Oxc+QH3qpr6/XqlWrlE6nlU6nde655+of/uEflE6n1dzcTD0PgC1btuidd94p2bd27Vode+yxkrrraV//bmzdunWvu5VCoZCOOOII6rmH++67T/fcc49+/vOf66233tITTzyhefPmqaGhQRJ17YeBqlM//y1xKoik02mtXLlS06dP9/YFAgFNnz5dr7zyisWSHXrmz5+vyy+/XJ///Oe1YcOGks9WrlypVCpVUs/jx4/XmDFjvHp+5ZVXNGnSJA0fPtw7ZsaMGdqzZ89ejYKrXnjhBU2cOFGTJ0/2tj//+c9atGiRJk+erBUrVlDPA2DZsmU68cQTS/aNHz9eGzdulCStX79eW7ZsKanneDyu008/vaSehw4dqilTpnjHfP7zn1cwGNTy5cvL8CsODbW1tcrlciX7stmsgsF8U0RdD7yBqtNXXnlFZ599tsLh7oGUGTNm6N133z2oYZki67N8y7nNmjXLdHZ2mq9+9atmwoQJ5ic/+YnZuXNnyV0FbPveGhsbza5du8zZZ59t6uvrva26uto75qGHHjIbNmww5557rpkyZYpZtmyZWbZsmfd58bbS3/3ud+bkk082559/vmlubua20v1sPe+aoZ4HZjv11FNNKpUyDQ0NZuzYseaKK64wbW1t5sorr/SOueWWW8zOnTvNxRdfbCZOnGieeeaZPm9/XLlypZk2bZr5zGc+Y9577z2nbynta1u4cKHZtGmTd/vuZZddZrZt22buuece6vogtlgsZk455RRzyimnGGOMufHGG80pp5xiRo8ePWB1WldXZ7Zs2WIeffRRc9JJJ5lZs2aZtrY2bt/9uNvf//3fmw0bNpiuri7z6quvmtNOO816mQ6l7aN87Wtf846JRqPmwQcfNDt27DBtbW3m6aefNvX19SXfc+yxx5rFixeb9vZ2s23bNnPfffeZUChk/fdV8tY7iFDPA7N98YtfNGvWrDGdnZ3mnXfeMddcc81ex9x5551my5YtprOz0/z+978348aNK/l86NChZtGiRSaRSJjdu3eb//zP/zSxWMz6b6ukbdCgQWbevHlmw4YNpqOjw7z//vvm7rvv3utWcur6wLZzzjmnz3+TFy5cOKB1OmnSJPPiiy+azs5Os2nTJnPLLbcMSPkDhRcAAABl59QcEQAAUFkIIgAAwBqCCAAAsIYgAgAArCGIAAAAawgiAADAGoIIAACwhiACAACsIYgAAABrCCIAAMAagggAALCGIAIAAKz5/+r+so8y6PhtAAAAAElFTkSuQmCC", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "iterations = 1000\n", + "nlayers = 12\n", + "loss_list = []\n", + "\n", + "\n", + "# define a callback function to recode the loss\n", + "def record_loss(loss, params):\n", + " loss_list.append(loss)\n", + "\n", + "\n", + "# apply QAOA on this portfolio optimization problem\n", + "final_params = QUBO_QAOA(Q, nlayers, iterations, callback=record_loss)\n", + "\n", + "p = plt.plot(loss_list)" + ] + }, + { + "cell_type": "markdown", + "id": "9126333d", + "metadata": {}, + "source": [ + "Create a function to visualize the results, listing all combinations in descending order of probability." + ] + }, + { + "cell_type": "code", + "execution_count": 34, + "id": "4a2c60e4", + "metadata": {}, + "outputs": [], + "source": [ + "def print_result_prob(c, wrap=False, reverse=False):\n", + " states = []\n", + " n_qubits = c._nqubits\n", + " for i in range(2**n_qubits):\n", + " a = f\"{bin(i)[2:]:0>{n_qubits}}\"\n", + " states.append(a)\n", + " # Generate all possible binary states for the given number of qubits\n", + "\n", + " probs = K.numpy(c.probability()).round(decimals=4)\n", + " # Calculate the probabilities of each state using the circuit's probability method\n", + "\n", + " sorted_indices = np.argsort(probs)[::-1]\n", + " if reverse == True:\n", + " sorted_indices = sorted_indices[::-1]\n", + " state_sorted = np.array(states)[sorted_indices]\n", + " prob_sorted = np.array(probs)[sorted_indices]\n", + " # Sort the states and probabilities in descending order based on the probabilities\n", + "\n", + " print(\"\\n-------------------------------------\")\n", + " print(\" selection\\t |\\tprobability\")\n", + " print(\"-------------------------------------\")\n", + " if wrap == False:\n", + " for i in range(len(states)):\n", + " print(\"%10s\\t |\\t %.4f\" % (state_sorted[i], prob_sorted[i]))\n", + " # Print the sorted states and their corresponding probabilities\n", + " elif wrap == True:\n", + " for i in range(4):\n", + " print(\"%10s\\t |\\t %.4f\" % (state_sorted[i], prob_sorted[i]))\n", + " print(\" ... ...\")\n", + " for i in range(-5, -1):\n", + " print(\"%10s\\t |\\t %.4f\" % (state_sorted[i], prob_sorted[i]))\n", + " print(\"-------------------------------------\")" + ] + }, + { + "cell_type": "code", + "execution_count": 35, + "id": "680f52d2", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "-------------------------------------\n", + " selection\t |\tprobability\n", + "-------------------------------------\n", + " 111001\t |\t 0.1169\n", + " 101101\t |\t 0.0872\n", + " 111100\t |\t 0.0823\n", + " 101011\t |\t 0.0809\n", + " ... ...\n", + " 000100\t |\t 0.0000\n", + " 010000\t |\t 0.0000\n", + " 000010\t |\t 0.0000\n", + " 000001\t |\t 0.0000\n", + "-------------------------------------\n" + ] + } + ], + "source": [ + "c_final = QAOA_ansatz_for_Ising(\n", + " final_params, nlayers, portfolio_pauli_terms, portfolio_weights\n", + ")\n", + "print_result_prob(c_final, wrap=True)" + ] + }, + { + "cell_type": "markdown", + "id": "71c7a0e0", + "metadata": {}, + "source": [ + "The highest probability corresponds to the best combination, which is consistent with what we found with classical brute force search.\n", + "\n", + "## Use XY mixer to improve the performance\n", + "\n", + "In the context of QAOA, XY mixers serve as a specific type of quantum gate to augment the optimization process. XY mixers, which are quantum gates introducing qubit interactions through controlled rotations, enable modification of the quantum system's state. The utilization of XY mixers in QAOA provides several advantages. They facilitate more efficient exploration of the solution space, thereby potentially improving the algorithm's overall performance. Moreover, XY mixers can amplify gradients of the objective function during optimization and enhance quantum circuit depth. Notably, in scenarios like portfolio optimization (covered in another tutorial), where constraints exist, XY mixers preserve the constraints associated with individual combinations while allowing for smooth transitions between them.\n", + "\n", + "It is crucial to consider that the choice of mixers relies on the specific problem under consideration, its unique characteristics, and the quantum hardware available." + ] + }, + { + "cell_type": "code", + "execution_count": 38, + "id": "3d558b9f", + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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VqxYoY6ODrtLGdY4zvHBcY4fjnV8cJzjYygc52E5YRcAAAxfjLwAAICEQngBAAAJhfACAAASCuEFAAAkFMJLP33lK1/RgQMH1NbWpl27dqmwsNDukhLKt771Lf3lL3+Rz+dTbW2tfvvb32rGjBk9+qSkpGj16tWqr69Xc3OzfvOb32jChAk9+kyaNEm///3v1dLSotraWn3/+9+Xy+WK51dJKA888ICMMXr00UcjyzjOsTNx4kQ9/fTTqq+vV2trq958803Nnz+/R58HH3xQR48eVWtrq/7whz9o+vTpPdZnZmZqw4YNampqktfr1bp165Senh7PrzGkOZ1OPfTQQ6qsrFRra6v279+v73znOx/px3GOzic+8Qk999xzqqqqkjFG11577Uf6xOKYzp49Wzt27FBbW5s++OADffOb34zZdzC0vttNN91k2tvbzW233WbOP/988/jjj5uGhgYzfvx422tLlLZlyxbzuc99zlxwwQVmzpw55ve//705ePCgSUtLi/T52c9+Zg4dOmSuuOIKU1BQYF577TWzc+fOyHqn02nefPNNs3XrVjN37lxz5ZVXmrq6OvMf//Eftn+/odguuugiU1lZafbs2WMeffRRjnOM29ixY82BAwfMf/7nf5rCwkJz7rnnmuLiYjN16tRIn/vvv994vV5zzTXXmNmzZ5vf/e535v333zcpKSmRPps3bzZ//etfzcUXX2wuvfRS8+6775qNGzfa/v2GSlu+fLk5duyY+dSnPmUmT55srr/+euPz+cxXv/pVjvMg2pVXXmm++93vmuuuu84YY8y1117bY30sjqnH4zHV1dXm6aefNhdccIG5+eabTUtLi/niF78Yi+9g/0Ec6m3Xrl3msccei7x3OBzmyJEj5oEHHrC9tkRt48aNM8YY84lPfMJIMhkZGaajo8Ncf/31kT4zZ840xhizYMECI3X+xxYMBs2ECRMifb70pS+ZxsZG43a7bf9OQ6mlp6ebd955xyxZssS8/PLLkfDCcY5dW7lypdmxY0effY4ePWr+5V/+JfI+IyPDtLW1mZtvvtlIMvn5+cYYY+bPnx/ps3TpUhMKhUxubq7t33EotOeff96sW7eux7Lf/OY35umnn+Y4x6j1Fl5icUzvuusuc/z48R7/bqxcudLs27dv0DVz2ugM3G635s+fr23btkWWGWO0bds2FRUV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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "loss_list = []\n", + "final_params = QUBO_QAOA(Q, nlayers, iterations, mixer=\"XY\", callback=record_loss)\n", + "\n", + "p = plt.plot(loss_list)" + ] + }, + { + "cell_type": "code", + "execution_count": 39, + "id": "d83fc94c", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "-------------------------------------\n", + " selection\t |\tprobability\n", + "-------------------------------------\n", + " 111001\t |\t 0.1553\n", + " 001001\t |\t 0.1260\n", + " 101001\t |\t 0.1180\n", + " 111000\t |\t 0.0934\n", + " ... ...\n", + " 100110\t |\t 0.0000\n", + " 000111\t |\t 0.0000\n", + " 000101\t |\t 0.0000\n", + " 000100\t |\t 0.0000\n", + "-------------------------------------\n" + ] + } + ], + "source": [ + "c_final = QAOA_ansatz_for_Ising(\n", + " final_params, nlayers, portfolio_pauli_terms, portfolio_weights, mixer=\"XY\"\n", + ")\n", + "print_result_prob(c_final, wrap=True)" + ] + }, + { + "cell_type": "markdown", + "id": "917c9415", + "metadata": {}, + "source": [ + "Compared with the standard X mixer, the XY mixer gives a higher probability of measuring the best result." + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "tc_dev", + "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.4" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/docs/source/tutorials/qaoa_portfolio_optimization.ipynb b/docs/source/tutorials/qaoa_portfolio_optimization.ipynb deleted file mode 100644 index 7f390853..00000000 --- a/docs/source/tutorials/qaoa_portfolio_optimization.ipynb +++ /dev/null @@ -1,602 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "id": "6ddb8a88-779a-43f7-ae14-115463bd87f5", - "metadata": {}, - "source": [ - "# Solving QUBO problems using QAOA\n", - "\n", - "## Overview\n", - "\n", - "Here we show how to solve a quadratic unconstrained binary optimization (QUBO) problem using QAOA. Later on below we will extend this to show how to solve binary Markowitz portfolio optimization problems.\n", - "\n", - "Consider minimizing the following 2x2 QUBO objective function:\n", - "\n", - "$\\begin{pmatrix}x_1 & x_2\\end{pmatrix}\\begin{pmatrix}-5& -2 \\\\-2 & 6\\end{pmatrix}\\begin{pmatrix}x_1\\\\x_2\\end{pmatrix} = -5x_1^2 -4x_1x_2 +6x_2^2$\n", - "\n", - "Clearly this is minimized at $(x_1,x_2) = (1,0)$, with corresponding objective function value of $-5$\n", - "\n", - "We first convert this to an Ising Hamiltonian by mapping $x_i\\rightarrow \\frac{I-Z_i}{2}$\n", - "\n", - "This gives\n", - "\n", - "$$-\\frac{5}{4}(I-Z_1)^2 -\\frac{4}{4}(I-Z_1)(I-Z_2) + \\frac{6}{4}(I-Z_2)^2 $$\n", - "\n", - "which simplifies to\n", - "\n", - "$$-\\frac{1}{2}I +\\frac{7}{2}Z_1 -2Z_2 -Z_1Z_2$$ \n", - "\n", - "The $-I/2$ term is simply a constant offset, so we can solve the problem by finding the minimum of \n", - "\n", - "$$\\langle \\psi | \\frac{7}{2}Z_1 -2Z_2 -Z_1Z_2 |\\psi\\rangle$$ \n", - "\n", - "Note that the minimum should correspond to the computational basis state $|10\\rangle$, and the corresponding true objective function value should be $-4.5$ (ignoring the offset value of $-1/2$)" - ] - }, - { - "cell_type": "markdown", - "id": "8176aa81", - "metadata": {}, - "source": [ - "## Setup" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "45964c1f", - "metadata": {}, - "outputs": [], - "source": [ - "import tensorcircuit as tc\n", - "import numpy as np\n", - "import tensorflow as tf\n", - "import matplotlib.pyplot as plt\n", - "from functools import partial" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "id": "4006848a-1a2f-407a-9f80-63e75ea0d3a4", - "metadata": {}, - "outputs": [], - "source": [ - "# we first manually encode the terms (-7/2) Z_1 - 2 Z_2 - Z_1Z_2 as:\n", - "pauli_terms = [\n", - " [1, 0],\n", - " [0, 1],\n", - " [1, 1],\n", - "] # see the TensorCircuit whitepaper for 'pauli structures'\n", - "weights = [7 / 2, -2, -1]\n", - "\n", - "# see below for a function to generate the pauli terms and weights from the QUBO matrix" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "id": "d197cf4a-1bad-4470-a846-998bfe68ba3c", - "metadata": {}, - "outputs": [], - "source": [ - "# Now we define the QAOA ansatz of depth nlayers\n", - "def QAOA_from_Ising(params, nlayers, pauli_terms, weights):\n", - " nqubits = len(pauli_terms[0])\n", - " c = tc.Circuit(nqubits)\n", - " for i in range(nqubits):\n", - " c.h(i)\n", - " for j in range(nlayers):\n", - " for k in range(len(pauli_terms)):\n", - " term = pauli_terms[k]\n", - " index_of_ones = []\n", - " for l in range(len(term)):\n", - " if term[l] == 1:\n", - " index_of_ones.append(l)\n", - " if len(index_of_ones) == 1:\n", - " c.rz(index_of_ones[0], theta=2 * weights[k] * params[2 * j])\n", - " elif len(index_of_ones) == 2:\n", - " c.exp1(\n", - " index_of_ones[0],\n", - " index_of_ones[1],\n", - " unitary=tc.gates._zz_matrix,\n", - " theta=weights[k] * params[2 * j],\n", - " )\n", - " else:\n", - " raise ValueError(\"Invalid number of Z terms\")\n", - "\n", - " for i in range(nqubits):\n", - " c.rx(i, theta=params[2 * j + 1]) # mixing terms\n", - " return c" - ] - }, - { - "cell_type": "markdown", - "id": "cb38c120-500a-44cc-96ec-fb5ceb11032d", - "metadata": {}, - "source": [ - "For a general state that is the output of a quantum circuit c, we first define the corresponding loss with respect to the Ising Hamiltonian." - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "id": "88cec9cf-3ab6-4a4c-b743-ed95ee8c3817", - "metadata": {}, - "outputs": [], - "source": [ - "def Ising_loss(c, pauli_terms, weights):\n", - " loss = 0.0\n", - " for k in range(len(pauli_terms)):\n", - " term = pauli_terms[k]\n", - " index_of_ones = []\n", - "\n", - " for l in range(len(term)):\n", - " if term[l] == 1:\n", - " index_of_ones.append(l)\n", - "\n", - " if len(index_of_ones) == 1:\n", - " delta_loss = weights[k] * c.expectation_ps(z=[index_of_ones[0]])\n", - "\n", - " else:\n", - " delta_loss = weights[k] * c.expectation_ps(\n", - " z=[index_of_ones[0], index_of_ones[1]]\n", - " )\n", - "\n", - " loss += delta_loss\n", - "\n", - " return K.real(loss)" - ] - }, - { - "cell_type": "markdown", - "id": "30a3aa96-7823-4337-9b2f-5170502bb893", - "metadata": {}, - "source": [ - "For the particular case of a circuit corresponding to a QAOA ansatz this is:" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "id": "26e4bec2-ce5b-4d0d-9e06-c80fda20619f", - "metadata": {}, - "outputs": [], - "source": [ - "def QAOA_loss(nlayers, pauli_terms, weights, params):\n", - " c = QAOA_from_Ising(params, nlayers, pauli_terms, weights)\n", - " return Ising_loss(c, pauli_terms, weights)" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "id": "ca8b7a76-5c4f-4ad8-9173-90126b8bb93b", - "metadata": {}, - "outputs": [], - "source": [ - "K = tc.set_backend(\"tensorflow\")" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "id": "d5b1897f-cd77-4cd3-bd3b-ece64e6004fc", - "metadata": {}, - "outputs": [], - "source": [ - "def QAOA_solve(pauli_terms, weights, nlayers, iterations):\n", - " print_every = 100\n", - " learning_rate = 1e-2\n", - "\n", - " loss_val_grad = K.value_and_grad(partial(QAOA_loss, nlayers, pauli_terms, weights))\n", - " loss_val_grad_jit = K.jit(loss_val_grad)\n", - "\n", - " opt = K.optimizer(tf.keras.optimizers.Adam(learning_rate))\n", - "\n", - " params = K.implicit_randn(shape=[2 * nlayers], stddev=0.5)\n", - " print(f\"initial params: {params}\")\n", - " for i in range(iterations):\n", - " loss, grads = loss_val_grad_jit(params)\n", - " if i % print_every == 0:\n", - " print(K.numpy(loss))\n", - " params = opt.update(grads, params)\n", - "\n", - " return params" - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "id": "2bc533da-b4f2-4ffb-b486-c65880a30a6d", - "metadata": { - "tags": [] - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "initial params: [ 0.39931756 -0.49578992 -0.22545011 -0.40585193]\n", - "-2.1728685\n", - "-4.177884\n", - "-4.2291102\n", - "-4.2291365\n", - "-4.229136\n" - ] - } - ], - "source": [ - "iterations = 500\n", - "nlayers = 2\n", - "final_params = QAOA_solve(pauli_terms, weights, nlayers, iterations)" - ] - }, - { - "cell_type": "markdown", - "id": "e93d8cbe-2884-4f0a-80f8-3b600194927b", - "metadata": {}, - "source": [ - "We note that for nlayers=2 and 500 iterations, the objective function does not in this case (although it depends on the initial parameters)converge to the true value of $-4.5$. However, the we see below that the final wavefunction does have large overlap with the desired state $|10\\rangle$, so measuring the output of the QAOA algorithm will, with high probability, output the correct answer." - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "id": "294ea9ce-5064-4176-94d0-8dbb7d1707f8", - "metadata": {}, - "outputs": [], - "source": [ - "def print_output(c):\n", - " n = c._nqubits\n", - " N = 2**n\n", - " x_label = r\"$\\left|{0:0\" + str(n) + r\"b}\\right>$\"\n", - " labels = [x_label.format(i) for i in range(N)]\n", - " plt.bar(range(N), c.probability())\n", - " plt.xticks(range(N), labels, rotation=70);" - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "id": "fc1353ab-7a7a-4cdc-931c-3b90417c4961", - "metadata": { - "tags": [] - }, - "outputs": [ - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAiMAAAGwCAYAAAB7MGXBAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjYuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8o6BhiAAAACXBIWXMAAA9hAAAPYQGoP6dpAAAdrklEQVR4nO3df3DX9X3A8VcSIAEx0UpJhKamFVv1kGChpqCt/SMVN0bLRk/OUqGs02urzhrdlVgkqB3RbuXoTVqunuy6cx70x3Q/YNQay7UrdMzgDp2KqxaJ2oSgZxLiSJZ8v/ujIy4jKF8E33y/PB53+YNPPp/knXvlQ575fD/fb4qy2Ww2AAASKU69AADg1CZGAICkxAgAkJQYAQCSEiMAQFJiBABISowAAEmJEQAgqVGpF3A0MplMvPLKK3H66adHUVFR6uUAAEchm81GT09PTJo0KYqLj3z9Iy9i5JVXXonq6urUywAAjkFbW1u8733vO+L78yJGTj/99Ij43RdTXl6eeDUAwNHo7u6O6urqoZ/jR5IXMXLooZny8nIxAgB55u1usXADKwCQlBgBAJISIwBAUmIEAEhKjAAASYkRACApMQIAJCVGAICkxAgAkJQYAQCSEiMAQFJiBABISowAAEmJEQAgqVGpFwCQq5plm1Iv4ZS15+65qZdAAXJlBABISowAAEmJEQAgKTECACQlRgCApMQIAJCUGAEAkhIjAEBSYgQASEqMAABJiREAICkxAgAkJUYAgKTECACQlBgBAJISIwBAUmIEAEhKjAAASYkRACApMQIAJCVGAICkxAgAkJQYAQCSEiMAQFLHFCNr166NmpqaKCsri7q6utixY8db7r9mzZr48Ic/HGPHjo3q6uq4+eab4+DBg8e0YACgsOQcIxs3boyGhoZoamqKnTt3Rm1tbcyZMyf27ds34v4PPvhgLFu2LJqamuKZZ56J+++/PzZu3Bi33XbbO148AJD/co6R1atXx7XXXhtLly6NCy+8MNatWxfjxo2L9evXj7j/tm3b4tJLL43Pfe5zUVNTE1dccUVcffXVb3s1BQA4NeQUI/39/dHa2hr19fVvfoDi4qivr4/t27ePeMzs2bOjtbV1KD5eeOGF2Lx5c/z+7//+ET9PX19fdHd3D3sDAArTqFx23r9/fwwODkZlZeWw7ZWVlfHss8+OeMznPve52L9/f1x22WWRzWZjYGAgvvSlL73lwzTNzc1xxx135LI0ACBPnfBn02zdujVWrVoV3/nOd2Lnzp3xd3/3d7Fp06a46667jnhMY2NjdHV1Db21tbWd6GUCAInkdGVkwoQJUVJSEh0dHcO2d3R0RFVV1YjH3H777XHNNdfEn/zJn0RExEUXXRS9vb1x3XXXxde//vUoLj68h0pLS6O0tDSXpQEAeSqnKyNjxoyJGTNmREtLy9C2TCYTLS0tMWvWrBGPeeONNw4LjpKSkoiIyGazua4XACgwOV0ZiYhoaGiIJUuWxMyZM+OSSy6JNWvWRG9vbyxdujQiIhYvXhyTJ0+O5ubmiIiYN29erF69Oi6++OKoq6uLX//613H77bfHvHnzhqIEADh15RwjCxcujM7OzlixYkW0t7fH9OnTY8uWLUM3te7du3fYlZDly5dHUVFRLF++PF5++eV473vfG/PmzYs///M/P35fBQCQt4qyefBYSXd3d1RUVERXV1eUl5enXg6QWM2yTamXcMrac/fc1Esgjxztz29/mwYASEqMAABJiREAICkxAgAkJUYAgKTECACQlBgBAJISIwBAUmIEAEhKjAAASYkRACApMQIAJCVGAICkxAgAkJQYAQCSEiMAQFJiBABISowAAEmJEQAgKTECACQlRgCApMQIAJCUGAEAkhIjAEBSYgQASEqMAABJiREAICkxAgAkJUYAgKTECACQlBgBAJISIwBAUmIEAEhKjAAASYkRACApMQIAJCVGAICkxAgAkJQYAQCSEiMAQFJiBABISowAAEmJEQAgKTECACQlRgCApMQIAJCUGAEAkhIjAEBSYgQASEqMAABJiREAICkxAgAkJUYAgKTECACQlBgBAJISIwBAUmIEAEhKjAAASYkRACApMQIAJCVGAICkxAgAkJQYAQCSEiMAQFJiBABISowAAEmJEQAgKTECACQlRgCApMQIAJDUMcXI2rVro6amJsrKyqKuri527Njxlvu//vrrcf3118fZZ58dpaWl8aEPfSg2b958TAsGAArLqFwP2LhxYzQ0NMS6deuirq4u1qxZE3PmzIndu3fHxIkTD9u/v78/PvWpT8XEiRPjRz/6UUyePDlefPHFOOOMM47H+gGAPJdzjKxevTquvfbaWLp0aURErFu3LjZt2hTr16+PZcuWHbb/+vXr47XXXott27bF6NGjIyKipqbmna0aACgYOT1M09/fH62trVFfX//mBygujvr6+ti+ffuIx/zDP/xDzJo1K66//vqorKyMqVOnxqpVq2JwcPCIn6evry+6u7uHvQEAhSmnGNm/f38MDg5GZWXlsO2VlZXR3t4+4jEvvPBC/OhHP4rBwcHYvHlz3H777fGtb30rvvGNbxzx8zQ3N0dFRcXQW3V1dS7LBADyyAl/Nk0mk4mJEyfG9773vZgxY0YsXLgwvv71r8e6deuOeExjY2N0dXUNvbW1tZ3oZQIAieR0z8iECROipKQkOjo6hm3v6OiIqqqqEY85++yzY/To0VFSUjK07YILLoj29vbo7++PMWPGHHZMaWlplJaW5rI0ACBP5XRlZMyYMTFjxoxoaWkZ2pbJZKKlpSVmzZo14jGXXnpp/PrXv45MJjO07bnnnouzzz57xBABAE4tOT9M09DQEPfdd198//vfj2eeeSa+/OUvR29v79CzaxYvXhyNjY1D+3/5y1+O1157LW666aZ47rnnYtOmTbFq1aq4/vrrj99XAQDkrZyf2rtw4cLo7OyMFStWRHt7e0yfPj22bNkydFPr3r17o7j4zcaprq6On/zkJ3HzzTfHtGnTYvLkyXHTTTfF1772teP3VQAAeasom81mUy/i7XR3d0dFRUV0dXVFeXl56uUAidUs25R6CaesPXfPTb0E8sjR/vz2t2kAgKTECACQlBgBAJISIwBAUmIEAEhKjAAASYkRACApMQIAJCVGAICkxAgAkJQYAQCSEiMAQFJiBABISowAAEmJEQAgKTECACQlRgCApMQIAJCUGAEAkhIjAEBSYgQASEqMAABJiREAICkxAgAkJUYAgKTECACQlBgBAJISIwBAUmIEAEhKjAAASYkRACApMQIAJCVGAICkxAgAkJQYAQCSEiMAQFJiBABISowAAEmJEQAgKTECACQlRgCApMQIAJCUGAEAkhIjAEBSYgQASEqMAABJiREAICkxAgAkJUYAgKTECACQlBgBAJISIwBAUmIEAEhKjAAASYkRACApMQIAJCVGAICkxAgAkJQYAQCSEiMAQFJiBABISowAAEmJEQAgKTECACQlRgCApMQIAJCUGAEAkhIjAEBSYgQASOqYYmTt2rVRU1MTZWVlUVdXFzt27Diq4zZs2BBFRUUxf/78Y/m0AEAByjlGNm7cGA0NDdHU1BQ7d+6M2tramDNnTuzbt+8tj9uzZ0/ceuut8fGPf/yYFwsAFJ6cY2T16tVx7bXXxtKlS+PCCy+MdevWxbhx42L9+vVHPGZwcDAWLVoUd9xxR3zwgx98RwsGAApLTjHS398fra2tUV9f/+YHKC6O+vr62L59+xGPu/POO2PixInxxS9+8dhXCgAUpFG57Lx///4YHByMysrKYdsrKyvj2WefHfGYf/mXf4n7778//v3f//2oP09fX1/09fUN/bu7uzuXZQIAeeSEPpump6cnrrnmmrjvvvtiwoQJR31cc3NzVFRUDL1VV1efwFUCACnldGVkwoQJUVJSEh0dHcO2d3R0RFVV1WH7P//887Fnz56YN2/e0LZMJvO7TzxqVOzevTvOPffcw45rbGyMhoaGoX93d3cLEgAoUDnFyJgxY2LGjBnR0tIy9PTcTCYTLS0tccMNNxy2//nnnx9PPvnksG3Lly+Pnp6e+Pa3v33EwCgtLY3S0tJclgYA5KmcYiQioqGhIZYsWRIzZ86MSy65JNasWRO9vb2xdOnSiIhYvHhxTJ48OZqbm6OsrCymTp067PgzzjgjIuKw7QDAqSnnGFm4cGF0dnbGihUror29PaZPnx5btmwZuql17969UVzshV0BgKNTlM1ms6kX8Xa6u7ujoqIiurq6ory8PPVygMRqlm1KvYRT1p6756ZeAnnkaH9+u4QBACQlRgCApMQIAJCUGAEAkhIjAEBSYgQASEqMAABJiREAICkxAgAkJUYAgKTECACQlBgBAJISIwBAUmIEAEhKjAAASYkRACApMQIAJCVGAICkxAgAkJQYAQCSEiMAQFJiBABISowAAEmJEQAgKTECACQlRgCApMQIAJCUGAEAkhIjAEBSYgQASEqMAABJiREAICkxAgAkJUYAgKTECACQlBgBAJISIwBAUmIEAEhKjAAASYkRACApMQIAJCVGAICkxAgAkJQYAQCSEiMAQFJiBABISowAAEmJEQAgKTECACQlRgCApMQIAJCUGAEAkhIjAEBSYgQASEqMAABJiREAICkxAgAkJUYAgKTECACQlBgBAJISIwBAUmIEAEhKjAAASYkRACApMQIAJCVGAICkxAgAkJQYAQCSEiMAQFJiBABI6phiZO3atVFTUxNlZWVRV1cXO3bsOOK+9913X3z84x+PM888M84888yor69/y/0BgFNLzjGycePGaGhoiKampti5c2fU1tbGnDlzYt++fSPuv3Xr1rj66qvjZz/7WWzfvj2qq6vjiiuuiJdffvkdLx4AyH9F2Ww2m8sBdXV18dGPfjTuvffeiIjIZDJRXV0dN954Yyxbtuxtjx8cHIwzzzwz7r333li8ePFRfc7u7u6oqKiIrq6uKC8vz2W5QAGqWbYp9RJOWXvunpt6CeSRo/35ndOVkf7+/mhtbY36+vo3P0BxcdTX18f27duP6mO88cYb8d///d/xnve854j79PX1RXd397A3AKAw5RQj+/fvj8HBwaisrBy2vbKyMtrb24/qY3zta1+LSZMmDQua/6+5uTkqKiqG3qqrq3NZJgCQR97VZ9PcfffdsWHDhnjooYeirKzsiPs1NjZGV1fX0FtbW9u7uEoA4N00KpedJ0yYECUlJdHR0TFse0dHR1RVVb3lsX/5l38Zd999dzz66KMxbdq0t9y3tLQ0SktLc1kaAJCncroyMmbMmJgxY0a0tLQMbctkMtHS0hKzZs064nHf/OY346677ootW7bEzJkzj321AEDByenKSEREQ0NDLFmyJGbOnBmXXHJJrFmzJnp7e2Pp0qUREbF48eKYPHlyNDc3R0TEPffcEytWrIgHH3wwampqhu4tGT9+fIwfP/44fikAQD7KOUYWLlwYnZ2dsWLFimhvb4/p06fHli1bhm5q3bt3bxQXv3nB5bvf/W709/fHZz/72WEfp6mpKVauXPnOVg8A5L2cX2ckBa8zAvxfXmckHa8zQi5OyOuMAAAcb2IEAEhKjAAASYkRACApMQIAJCVGAICkxAgAkJQYAQCSEiMAQFJiBABISowAAEmJEQAgKTECACQlRgCApMQIAJCUGAEAkhIjAEBSYgQASEqMAABJiREAICkxAgAkJUYAgKTECACQlBgBAJIalXoBABARUbNsU+olnLL23D036ed3ZQQASEqMAABJiREAICkxAgAkJUYAgKTECACQlBgBAJISIwBAUmIEAEhKjAAASYkRACApMQIAJCVGAICkxAgAkJQYAQCSEiMAQFJiBABISowAAEmJEQAgKTECACQlRgCApMQIAJCUGAEAkhIjAEBSYgQASEqMAABJiREAICkxAgAkJUYAgKTECACQlBgBAJISIwBAUmIEAEhKjAAASYkRACApMQIAJCVGAICk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mUwmRo363ZPdqqqq4p577oklS5aYbR762c9+FitXroxf/OIXztsC5Zx958RIHvqP//iP+Nu//dvYvHlzlJeXxznnnBOLFy+OT33qU6mXxnHwf//zevLJJ2PBggWxe/duv13luaeffjo2bNgQ//RP/xTjx4933uap7NvcjOqcPTZi5CT3+uuvxxNPPBG//e1vo7+/P2bPnh0f+tCHht7f09MT48eP902fhw7Ntr29PTKZTHzsYx+Lc889d9g+fX190dnZGe973/v8fYs8NTAwECUlJcPO0Z6enhg3bpzfmAvQf/3Xf8X+/fujurraOZsDMXISOvQN/Nhjj8Xq1atj8+bN8f73vz+qqqriwIEDcf7558fChQtj7ty5MW7cON/weeStZtvb2xvnn39+LFq0KH7v934vSktLUy+XHBz6jbmzszMGBwdj4sSJw87LbDYbg4ODUVxc7HzNI283V44PMXISOvQD6yMf+UhMnz49Vq5cGaWlpdHa2hq7du2Kf/3Xf42XX345vvCFL8RXvvKV1MslB2ZbuA7N9g//8A+jq6srFi5cGJdddlmcc845MX78+GH7Pv300zEwMDDsab+cnHKZ6zPPPBP9/f1RW1ubaLV5LMEzeDgKr7zySvaMM87I/uY3vznsfc8991y2sbExW1RUlH3ggQfe/cXxjpht4XrppZeyo0ePzs6ePTtbWlqaraioyF511VXZH/zgB9nnn38+e/DgwWwmk8nOnz8/+41vfCObzXraZz4w1xPPtaaT1MGDB+ODH/xg/PjHPz7sfeedd16sWrUqrrvuunjkkUeiv78/wQo5VmZbeLL/e4F527ZtMWvWrHj44Yfj4MGDce+998ZLL70UCxcujE9+8pNx6623xt/8zd/E3//938dnPvOZxKvm7Zjru0eMnIQymUx84AMfiCuvvDK+//3vx49//OM4cODAYftNmTIldu3adcS/AsrJx2wL06GbU2tqauLKK68cmunnP//5+OUvfxn79++PG2+8MR599NFYunRp1NbWxtSpU71M+EnOXN897hk5ibW1tcUtt9wSDz30UMyePTuuueaa+OhHPxqjR4+O3bt3x5133hlXXXVVNDY2Dv0RJvKD2RamgYGB2LdvX0yaNGno30VFRcOeNTNlypS44YYb4qtf/arZ5glzfRekfIyIw23cuDH79NNPD9v2y1/+MrtgwYLsaaedlj3ttNOyF198cfb000/P3nTTTdkDBw5ks1mPT+YDsy1cI812cHAwOzAwkM1mfzfDgYGB7L/9279li4qKsvv27RvazsnLXN89roycRLLZbCxYsCAef/zxOOecc2LBggWxaNGieO973zu0z2OPPRa//e1vY+bMmTFlyhSvU5AnzLZw/f/ZXnXVVbFo0aJ4z3veM7TPoZcEb2tri61bt3plzjxgru8uMXKSee211+I3v/lNPPLII7Fly5Z48cUXY9q0afH5z38+PvvZzx72/Hbf+PnDbAvXSLOtra2Na665JhYsWDDs/oH+/n73AuUJc333iJGT1MDAQLz66qvx1FNPxebNm6OlpSUOHDgQn/jEJ+KP//iP47LLLhva99AI3TCVH8y2cP3/2T722GNx4MCB+OQnPxlf+MIX4tJLLx3a12zzh7meeGIkD/T19UV7e3s8/vjj8Y//+I+xffv2KCsri3nz5sXixYuHvTw8+cVsC5fZFiZzPTHESJ7p7e2NvXv3xs9//vP453/+5/jVr34VCxYsiJUrVw67/4D8Y7aFy2wLk7keP2IkT2Uymeju7o7//M//jK6urrjsssuirKws9bI4Dsy2cJltYTLXd06MAABJeQVWACApMQIAJCVGAICkxAgAkJQYAQCSEiMAQFJiBABISowAAEmJEQAgKTECACQlRgCApP4H157oSnD133MAAAAASUVORK5CYII=\n", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "c = QAOA_from_Ising(final_params, nlayers, pauli_terms, weights)\n", - "\n", - "print_output(c)" - ] - }, - { - "cell_type": "markdown", - "id": "d155c5e5-5843-4bba-9edc-595a18cb0c9a", - "metadata": {}, - "source": [ - "## General Case\n", - "\n", - "For the general QUBO case, we wish to minimize\n", - "\n", - "$$ x^T Q x$$\n", - "\n", - "where $x\\in\\{0,1\\}^n$ and $Q\\in\\mathbb{R}^{n\\times n}$ is a real symmetric matrix.\n", - "\n", - "This maps to an Ising Hamiltonian \n", - "\n", - "$$\\frac{1}{2}\\left(\\sum_{i=1}^n C_{ii} + \\sum_{i 0 $: risk-appetite\n", - "* $\\Sigma \\in \\mathbb{R}^{n\\times n}$: covariance matrix of the assets\n", - "* $\\mu\\in\\mathbb{R}^n$: mean return of the assets\n", - "* $B$: budget (i.e., total number of assets out of $n$ that can be selected)\n", - "\n", - "Our first step is to convert this constrained quadratic programming problem into a QUBO. We do this by adding a penalty factor $t$ and consider the alternative problem:\n", - "\n", - "$$ \\min_{x\\in\\{0,1\\}^n}\\quad q x^T \\Sigma x - \\mu^Tx + t(1^Tx-B)^2$$\n", - "\n", - "The variables in the linear terms $\\mu^Tx = \\mu_1 x_1 + \\mu_2 x_2+\\ldots$ can all be squared (since they are boolean variables), i.e. we can consider\n", - "\n", - "$$\\min_{x\\in\\{0,1\\}^n}\\quad q x^T \\Sigma x - \\sum_{i=1}^n\\mu_i x_i^2 + t(1^Tx-B)^2$$\n", - "\n", - "which is a QUBO defined by the matrix $Q$ \n", - "\n", - "$$ Q = q\\Sigma -\\mu\\begin{pmatrix}1 & \\\\ & 1\\\\ & & \\ddots\\end{pmatrix} + t\\begin{pmatrix}1 -2B & 1 & \\ldots & 1 \\\\\n", - "1 & 1-2B & 1 & \\ldots \\\\1 & 1 & 1-2B \\\\\n", - "\\vdots\\end{pmatrix}$$\n", - "\n", - "i.e., we wish to mimimize\n", - "\n", - "$$ x^T Q X + tB$$\n", - "\n", - "and we ignore the constant term $t B$.\n", - "We can now solve this by QAOA as above.\n", - "\n", - "Let us first define a function to convert portfolio data into a QUBO matrix:" - ] - }, - { - "cell_type": "code", - "execution_count": 16, - "id": "3080b901-fb6c-4bda-8348-c96540cbc39a", - "metadata": {}, - "outputs": [], - "source": [ - "def QUBO_from_portfolio(cov, mean, q, B, t):\n", - " # cov: n x n covariance numpy array\n", - " # mean: numpy array of means\n", - " n = cov.shape[0]\n", - " R = np.diag(mean)\n", - " S = np.ones((n, n)) - 2 * B * np.diag(np.ones(n))\n", - "\n", - " Q = q * cov - R + t * S\n", - " return Q" - ] - }, - { - "cell_type": "markdown", - "id": "b4cdcb0e-15a2-461c-b487-084488486c67", - "metadata": {}, - "source": [ - "We can test this using the qiskit_finance package to generate some stock covariance and mean data:\n", - "\n", - "*Note that this was tested with qiskit version 0.39.3 and qiskit-finance version 0.3.4.*" - ] - }, - { - "cell_type": "code", - "execution_count": 17, - "id": "2168c69e-73ce-4306-8a39-4ddc475acc8f", - "metadata": {}, - "outputs": [], - "source": [ - "import datetime\n", - "from qiskit_finance.data_providers import RandomDataProvider" - ] - }, - { - "cell_type": "code", - "execution_count": 18, - "id": "6a7bc671-a496-4cd8-b954-50a280b5dd85", - "metadata": {}, - "outputs": [], - "source": [ - "num_assets = 4\n", - "seed = 123\n", - "\n", - "# Generate expected return and covariance matrix from (random) time-series\n", - "stocks = [(\"TICKER%s\" % i) for i in range(num_assets)]\n", - "data = RandomDataProvider(\n", - " tickers=stocks,\n", - " start=datetime.datetime(2016, 1, 1),\n", - " end=datetime.datetime(2016, 1, 30),\n", - " seed=seed,\n", - ")\n", - "data.run()\n", - "\n", - "mu = data.get_period_return_mean_vector()\n", - "sigma = data.get_period_return_covariance_matrix()" - ] - }, - { - "cell_type": "markdown", - "id": "f6dc53d4-7ed0-436d-aa1f-8674c56e756e", - "metadata": {}, - "source": [ - "Using this mean and covariance data, we can now define our portfolio optimization problem, convert it to a QUBO matrix, and then extract the pauli terms and weights" - ] - }, - { - "cell_type": "code", - "execution_count": 19, - "id": "3f6edcd5-3c10-49fc-86ea-160fc6d3187e", - "metadata": {}, - "outputs": [], - "source": [ - "q = 0.5\n", - "budget = 3 # Note that in this example, there are 4 assets, but a budget of only 3\n", - "penalty = 3\n", - "\n", - "Q = QUBO_from_portfolio(sigma, mu, q, budget, penalty)\n", - "portfolio_pauli_terms, portfolio_weights, portfolio_offset = QUBO_to_Ising(Q)" - ] - }, - { - "cell_type": "code", - "execution_count": 20, - "id": "809b90fa-7047-4c88-b862-355da4f58a50", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "0000: 21.006979417669037\n", - "0001: 6.006208358124514\n", - "0010: 6.006857249462996\n", - "0011: -2.994037697463167\n", - "0100: 6.007889613170697\n", - "0101: -2.992836964752989\n", - "0110: -2.992179512275861\n", - "0111: -5.9930299775811875\n", - "1000: 5.992965725313347\n", - "1001: -3.007905195444355\n", - "1010: -3.0070278423618397\n", - "1011: -6.008022650501182\n", - "1100: -3.0060506769683\n", - "1101: -6.006877116105166\n", - "1110: -6.005991201884008\n", - "1111: -3.006941528402507\n" - ] - } - ], - "source": [ - "# Brute force search over classical results for comparison before we run QAOA\n", - "for i in range(2):\n", - " for j in range(2):\n", - " for k in range(2):\n", - " for l in range(2):\n", - " x = np.array([i, j, k, l])\n", - " print(f\"{i}{j}{k}{l}: {np.dot(x,np.dot(Q,x))- portfolio_offset}\")" - ] - }, - { - "cell_type": "markdown", - "id": "b5e69a34-87dc-47b4-aeb2-3b9a03fd0974", - "metadata": {}, - "source": [ - "We see that, due to the penalty, the lowest energy solutions correspond to 0111, 1011, 1101, 1110, i.e. the portfolios with only 3 assets." - ] - }, - { - "cell_type": "code", - "execution_count": 21, - "id": "80c1de6c-d3a4-4ea5-922a-bffb59dd1ea3", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "initial params: [ 0.13778198 -0.75357753 -0.01271329 -0.5461785 -0.1501883 0.36323363]\n", - "-4.204754\n", - "-5.681799\n", - "-5.6837077\n", - "-5.6837044\n", - "-5.6837053\n", - "-5.683704\n", - "-5.6837063\n", - "-5.683709\n", - "-5.6837063\n", - "-5.683705\n" - ] - } - ], - "source": [ - "iterations = 1000\n", - "nlayers = 3\n", - "final_params = QAOA_solve(portfolio_pauli_terms, portfolio_weights, nlayers, iterations)" - ] - }, - { - "cell_type": "code", - "execution_count": 22, - "id": "8a9064e3-0c61-4d2d-baf9-bdf120c0331d", - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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\n", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "c_final = QAOA_from_Ising(\n", - " final_params, nlayers, portfolio_pauli_terms, portfolio_weights\n", - ")\n", - "print_output(c_final)" - ] - } - ], - "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.8.0" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/docs/source/tutorials/qubo_problem.ipynb b/docs/source/tutorials/qubo_problem.ipynb new file mode 100644 index 00000000..a4779366 --- /dev/null +++ b/docs/source/tutorials/qubo_problem.ipynb @@ -0,0 +1,580 @@ +{ + "cells": [ + { + "attachments": {}, + "cell_type": "markdown", + "id": "6ddb8a88-779a-43f7-ae14-115463bd87f5", + "metadata": {}, + "source": [ + "# Solving QUBO Problem using QAOA\n", + "\n", + "## Overview\n", + "\n", + "In this tutorial, we will demonstrate how to solve quadratic unconstrained binary optimization (QUBO) problems using QAOA. There is a specific application for portfolio optimization and we will introduce it in another [tutorial](https://tensorcircuit.readthedocs.io/en/latest/tutorials/portfolio_optimization.html).\n", + "\n", + "## QUBO problem\n", + "\n", + "### What is QUBO?\n", + "\n", + "Quadratic unconstrained binary optimization (QUBO) is a type of problem that aims to optimize a quadratic objective function using binary variables. The primary goal of a QUBO problem is to determine the assignments of binary variables that minimize or maximize the quadratic objective function. These variables represent choices or decision variables that can be either selected (1) or not selected (0). The objective function captures the associated costs, benefits, or constraints related to these decisions.\n", + "\n", + "From a computational perspective, solving a QUBO problem is NP-hard. This classification implies that solving the optimal solution to a QUBO instance is believed to be computationally challenging, and no known polynomial-time algorithm that can efficiently solve all QUBO problems.\n", + "\n", + "However, a promising approach called Quantum Approximate Optimization Algorithm (QAOA), introduced in [this tutorial](https://tensorcircuit.readthedocs.io/en/latest/tutorials/qaoa.html), has the potential to offer significant advantages when applied to QUBO problem-solving. QAOA leverages inherent quantum parallelism and interference effects to explore the solution space more efficiently compared to classical methods. This efficiency can lead to faster and more optimal solutions. In QAOA, each qubit represents a binary variable, and the objective function is calculated as the expected value of a quantum state generated by the ansatz (a quantum circuit with parameters to be decided). The parameters in the ansatz are iteratively optimized by a classical algorithm to improve the solution quality.\n", + "\n", + "### General Case\n", + "\n", + "For the general QUBO case, we wish to minimize a cost function of the form\n", + "\n", + "$$ \n", + "x^T Q x\n", + "$$\n", + "\n", + "where $x\\in\\{0,1\\}^n$ and $Q\\in\\mathbb{R}^{n\\times n}$ is a real symmetric matrix.\n", + "\n", + "This function maps to an Ising Hamiltonian \n", + "\n", + "$$\n", + "\\frac{1}{2}\\left(\\sum_{i=1}^n C_{ii} + \\sum_{i{n_qubits}}\"\n", + " states.append(a)\n", + "\n", + " # Calculate the probabilities of each state using the circuit's probability method\n", + " probs = K.numpy(c.probability()).round(decimals=4)\n", + "\n", + " # Sort the states and probabilities in descending order based on the probabilities\n", + " sorted_indices = np.argsort(probs)[::-1]\n", + " if reverse == True:\n", + " sorted_indices = sorted_indices[::-1]\n", + " state_sorted = np.array(states)[sorted_indices]\n", + " prob_sorted = np.array(probs)[sorted_indices]\n", + "\n", + " print(\"\\n-------------------------------------\")\n", + " print(\" selection\\t |\\tprobability\")\n", + " print(\"-------------------------------------\")\n", + " if wrap == False:\n", + " for i in range(len(states)):\n", + " print(\"%10s\\t |\\t %.4f\" % (state_sorted[i], prob_sorted[i]))\n", + " # Print the sorted states and their corresponding probabilities\n", + " elif wrap == True:\n", + " for i in range(4):\n", + " print(\"%10s\\t |\\t %.4f\" % (state_sorted[i], prob_sorted[i]))\n", + " print(\" ... ...\")\n", + " for i in range(-4, -1):\n", + " print(\"%10s\\t |\\t %.4f\" % (state_sorted[i], prob_sorted[i]))\n", + " print(\"-------------------------------------\")" + ] + }, + { + "cell_type": "code", + "execution_count": 83, + "id": "da315228", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "-------------------------------------\n", + " selection\t |\tprobability\n", + "-------------------------------------\n", + " 10\t |\t 0.8848\n", + " 11\t |\t 0.1051\n", + " 01\t |\t 0.0093\n", + " 00\t |\t 0.0008\n", + "-------------------------------------\n" + ] + } + ], + "source": [ + "c = QAOA_ansatz_for_Ising(final_params, nlayers, pauli_terms, weights)\n", + "\n", + "print_result_prob(c)" + ] + }, + { + "cell_type": "code", + "execution_count": 84, + "id": "294ea9ce-5064-4176-94d0-8dbb7d1707f8", + "metadata": {}, + "outputs": [], + "source": [ + "def print_output(c):\n", + " n = c._nqubits\n", + " N = 2**n\n", + "\n", + " # Generate labels for the x-axis representing the binary states\n", + " x_label = r\"$\\left|{0:0\" + str(n) + r\"b}\\right>$\"\n", + " labels = [x_label.format(i) for i in range(N)]\n", + "\n", + " # Create a bar plot with the probabilities of each state\n", + " plt.bar(range(N), c.probability())\n", + "\n", + " # Set the x-axis ticks to the generated labels and rotate them for better visibility\n", + " plt.xticks(range(N), labels, rotation=70)" + ] + }, + { + "cell_type": "code", + "execution_count": 85, + "id": "fc1353ab-7a7a-4cdc-931c-3b90417c4961", + "metadata": { + "tags": [] + }, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAiMAAAGuCAYAAABC7AYqAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjcuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8pXeV/AAAACXBIWXMAAA9hAAAPYQGoP6dpAAAcuklEQVR4nO3dcXDW9X3A8U8iwRMIOgQTiYK2KrjWlcLBTLde1XQb1XU3rwy33rW7Ye0YtS3F0RbKVECl9DQ7Z3t2cx0y3dFxenO6tmOmerPagIKDoUXXVqg2KQGKDlbAQPjuj9bcMgLmAemHhNfr7nOlv/x+PF/49jne/T1PnlRFRAkAgCTV2QsAAE5uYgQASCVGAIBUYgQASCVGAIBUYgQASCVGAIBUYgQASDUoewF9NXr06Ni9e3f2MgCACtTW1kZ7e/sRz+kXMTJ69Ohoa2vLXgYAcBQaGhqOGCT9IkbeuCPS0NDg7ggA9BO1tbXR1tb2pv9294sYecPu3bvFCAAMMN7ACgCkEiMAQCoxAgCkEiMAQCoxAgCkEiMAQCoxAgCkEiMAQCoxAgCkEiMAQCoxAgCkEiMAQCoxAgCkEiMAQKpB2QsAqNQdG1uzl3DSuuGSxuwlMAC5MwIApBIjAEAqMQIApBIjAEAqMQIApBIjAEAqMQIApBIjAEAqMQIApBIjAEAqMQIApBIjAEAqMQIApBIjAEAqMQIApBIjAEAqMQIApBIjAEAqMQIApBIjAEAqMQIApBIjAEAqMQIApBIjAEAqMQIApBIjAEAqMQIApBIjAEAqMQIApDqqGJk1a1Zs3rw59u7dG6tXr47Jkycf8fxPf/rT8cILL8SePXvi5Zdfjubm5jj11FOPasEAwMBScYxMnz49mpubY+HChTFx4sTYsGFDrFq1KkaNGtXr+X/0R38UX/ziF2PhwoVx8cUXx7XXXhvXXHNN3Hbbbce8eACg/6s4RubMmRP33HNP3HvvvbFp06aYOXNm7NmzJ2bMmNHr+e95z3viqaeeihUrVsSPfvSjePTRR2PFihUxZcqUY148AND/VRQjNTU1MWnSpGhpaek+VkqJlpaWaGxs7PWa7373uzFp0qTul3LOP//8uPLKK+Ob3/zmYR9n8ODBUVtb22MAgIFpUCUnjxw5MgYNGhQdHR09jnd0dMT48eN7vWbFihUxcuTIePLJJ6Oqqipqamri7rvvjiVLlhz2cebNmxc333xzJUsDAPqp4/7dNO973/ti/vz5MWvWrJg4cWJcffXVcdVVV8WCBQsOe82SJUti+PDh3dPQ0HC8lwkAJKnozsiOHTviwIEDUVdX1+N4XV1dbN26tddrFi9eHPfdd1987Wtfi4iI5557LoYOHRp/8zd/E7feemuUUg65prOzMzo7OytZGgDQT1V0Z2T//v2xbt26aGpq6j5WVVUVTU1N0dra2us1Q4YMiYMHD/Y41tXV1X0tAHByq+jOSEREc3NzLF++PNauXRtPP/10zJ49O4YOHRrLli2LiIjly5dHW1tbzJ8/PyIiHnnkkZgzZ078x3/8R6xZsyYuuOCCWLx4cTzyyCOHRAoAcPKpOEZWrlwZo0aNikWLFkV9fX2sX78+pk6dGtu2bYuIiDFjxvSIjFtuuSVKKXHLLbdEQ0NDbN++PR555JH4whe+8Nb9KQCAfqsqIg5908YJpra2Nnbt2hXDhw+P3bt3Zy8HSHbHxt5fFub4u+GS3j/GAXrT13+//WwaACCVGAEAUokRACCVGAEAUokRACCVGAEAUokRACCVGAEAUokRACCVGAEAUokRACCVGAEAUokRACCVGAEAUokRACCVGAEAUokRACCVGAEAUokRACCVGAEAUokRACCVGAEAUokRACCVGAEAUokRACCVGAEAUokRACCVGAEAUokRACCVGAEAUokRACCVGAEAUokRACCVGAEAUokRACCVGAEAUokRACCVGAEAUokRACCVGAEAUokRACCVGAEAUokRACCVGAEAUokRACCVGAEAUokRACCVGAEAUokRACCVGAEAUokRACCVGAEAUokRACCVGAEAUokRACCVGAEAUokRACCVGAEAUokRACCVGAEAUokRACCVGAEAUokRACCVGAEAUokRACCVGAEAUokRACCVGAEAUh1VjMyaNSs2b94ce/fujdWrV8fkyZOPeP7pp58eX/7yl6O9vT327dsXL774YnzgAx84qgUDAAPLoEovmD59ejQ3N8fMmTNjzZo1MXv27Fi1alWMGzcutm/ffsj5NTU18eijj8a2bdti2rRp0dbWFmPHjo3XXnvtrVg/ANDPVRwjc+bMiXvuuSfuvffeiIiYOXNmXHXVVTFjxoxYunTpIefPmDEjRowYEe95z3viwIEDERHxox/96NhWDQAMGBW9TFNTUxOTJk2KlpaW7mOllGhpaYnGxsZer/m93/u9aG1tja985SuxdevW2LhxY8ybNy+qqw//0IMHD47a2toeAwAMTBXFyMiRI2PQoEHR0dHR43hHR0fU19f3es3b3va2mDZtWpxyyilx5ZVXxuLFi+OGG26IBQsWHPZx5s2bF7t27eqetra2SpYJAPQjx/27aaqrq2Pbtm3x8Y9/PJ599tlYuXJl3HrrrTFz5szDXrNkyZIYPnx49zQ0NBzvZQIASSp6z8iOHTviwIEDUVdX1+N4XV1dbN26tddrfvKTn8T+/fvj4MGD3cc2bdoUZ599dtTU1MT+/fsPuaazszM6OzsrWRoA0E9VdGdk//79sW7dumhqauo+VlVVFU1NTdHa2trrNU899VRccMEFUVVV1X3soosuivb29l5DBAA4uVT8Mk1zc3Ncd9118dGPfjTGjx8fd999dwwdOjSWLVsWERHLly+P2267rfv8u+++O0aMGBF33nlnXHjhhXHllVfG/Pnz4ytf+cpb96cAAPqtir+1d+XKlTFq1KhYtGhR1NfXx/r162Pq1Kmxbdu2iIgYM2ZMj5dkfvzjH8fv/M7vxF/+5V/Gf/7nf0ZbW1vceeedvX4bMABw8qmKiJK9iDdTW1sbu3btiuHDh8fu3buzlwMku2Nj7y8Lc/zdcEnvH+MAvenrv99+Ng0AkEqMAACpxAgAkEqMAACpxAgAkEqMAACpxAgAkEqMAACpxAgAkEqMAACpxAgAkEqMAACpxAgAkEqMAACpxAgAkEqMAACpxAgAkEqMAACpxAgAkEqMAACpxAgAkEqMAACpxAgAkEqMAACpxAgAkEqMAACpxAgAkEqMAACpxAgAkEqMAACpxAgAkEqMAACpxAgAkEqMAACpxAgAkEqMAACpxAgAkEqMAACpxAgAkEqMAACpxAgAkEqMAACpxAgAkEqMAACpxAgAkEqMAACpxAgAkEqMAACpxAgAkEqMAACpxAgAkEqMAACpxAgAkEqMAACpxAgAkEqMAACpxAgAkEqMAACpxAgAkEqMAACpxAgAkEqMAACpxAgAkEqMAACpxAgAkEqMAACpxAgAkEqMAACpxAgAkOqoYmTWrFmxefPm2Lt3b6xevTomT57cp+uuueaaKKXEP/3TPx3NwwIAA1DFMTJ9+vRobm6OhQsXxsSJE2PDhg2xatWqGDVq1BGvGzt2bNx+++3xxBNPHPViAYCBp+IYmTNnTtxzzz1x7733xqZNm2LmzJmxZ8+emDFjxuEfpLo6/uEf/iFuuummeOmll45pwQDAwFJRjNTU1MSkSZOipaWl+1gpJVpaWqKxsfGw1914442xbdu2+Lu/+7s+Pc7gwYOjtra2xwAAA1NFMTJy5MgYNGhQdHR09Dje0dER9fX1vV7zG7/xG3HttdfGdddd1+fHmTdvXuzatat72traKlkmANCPHNfvphk2bFjcd999cd1118VPf/rTPl+3ZMmSGD58ePc0NDQcx1UCAJkGVXLyjh074sCBA1FXV9fjeF1dXWzduvWQ89/+9rfH+eefH4888kj3serqn/fP/v37Y9y4cb2+h6SzszM6OzsrWRoA0E9VdGdk//79sW7dumhqauo+VlVVFU1NTdHa2nrI+S+88EK8853vjAkTJnTPww8/HI8//nhMmDAhXnnllWP/EwAA/VpFd0YiIpqbm2P58uWxdu3aePrpp2P27NkxdOjQWLZsWURELF++PNra2mL+/Pnx+uuvx/PPP9/j+tdeey0i4pDjAMDJqeIYWblyZYwaNSoWLVoU9fX1sX79+pg6dWps27YtIiLGjBkTBw8efMsXCgAMTFURUbIX8WZqa2tj165dMXz48Ni9e3f2coBkd2w89GVhfjluuOTwH+MA/19f//32s2kAgFRiBABIJUYAgFRiBABIJUYAgFRiBABIJUYAgFRiBABIJUYAgFRiBABIJUYAgFRiBABIJUYAgFRiBABIJUYAgFRiBABIJUYAgFRiBABIJUYAgFRiBABIJUYAgFRiBABIJUYAgFRiBABIJUYAgFRiBABIJUYAgFRiBABIJUYAgFRiBABIJUYAgFRiBABIJUYAgFRiBABIJUYAgFRiBABIJUYAgFRiBABIJUYAgFRiBABIJUYAgFRiBABIJUYAgFRiBABIJUYAgFRiBABIJUYAgFRiBABIJUYAgFRiBABIJUYAgFRiBABIJUYAgFRiBABIJUYAgFRiBABIJUYAgFRiBABIJUYAgFRiBABIJUYAgFRiBABIJUYAgFRiBABIJUYAgFRiBABIJUYAgFRiBABIJUYAgFRHFSOzZs2KzZs3x969e2P16tUxefLkw577sY99LJ544onYuXNn7Ny5Mx599NEjng8AnFwqjpHp06dHc3NzLFy4MCZOnBgbNmyIVatWxahRo3o9/7LLLosVK1bE5ZdfHo2NjfHKK6/Ev/3bv8Xo0aOPefEAQP9XFRGlkgtWr14dzzzzTHzyk5/8+W9QVRWvvPJK3HXXXbF06dI3vb66ujpeffXVuP766+O+++7r02PW1tbGrl27Yvjw4bF79+5KlgsMQHdsbM1ewknrhksas5dAP9LXf78rujNSU1MTkyZNipaWlu5jpZRoaWmJxsa+/Q90yJAhUVNTEzt37jzsOYMHD47a2toeAwAMTBXFyMiRI2PQoEHR0dHR43hHR0fU19f36fdYunRptLe39wia/2/evHmxa9eu7mlra6tkmQBAP/JL/W6az33uc/GHf/iHcfXVV8frr79+2POWLFkSw4cP756GhoZf4ioBgF+mQZWcvGPHjjhw4EDU1dX1OF5XVxdbt2494rU33HBDfP7zn4/3v//9sXHjxiOe29nZGZ2dnZUsDQDopyq6M7J///5Yt25dNDU1dR+rqqqKpqamaG09/BvK5s6dG3/xF38RU6dOjXXr1h39agGAAaeiOyMREc3NzbF8+fJYu3ZtPP300zF79uwYOnRoLFu2LCIili9fHm1tbTF//vyIiPjsZz8bixYtig9/+MOxZcuW7rsq//M//xM/+9nP3sI/CgDQH1UcIytXroxRo0bFokWLor6+PtavXx9Tp06Nbdu2RUTEmDFj4uDBg93n/9mf/Vmceuqp8eCDD/b4fW6++eZYuHDhMS4fAOjvKv6ckQw+ZwT4v3zOSB6fM0IljsvnjAAAvNXECACQSowAAKnECACQSowAAKnECACQSowAAKnECACQSowAAKnECACQSowAAKnECACQSowAAKnECACQSowAAKnECACQSowAAKnECACQSowAAKnECACQSowAAKnECACQSowAAKnECACQSowAAKnECACQSowAAKnECACQSowAAKnECACQalD2AgAgIuKOja3ZSzhp3XBJY+rjuzMCAKQSIwBAKjECAKQSIwBAKjECAKQSIwBAKjECAKQSIwBAKjECAKQSIwBAKjECAKQSIwBAKjECAKQSIwBAKjECAKQSIwBAKjECAKQSIwBAKjECAKQSIwBAKjECAKQSIwBAKjECAKQSIwBAKjECAKQSIwBAKjECAKQSIwBAKjECAKQSIwBAKjECAKQSIwBAKjECAKQSIwBAKjECAKQSIwBAKjECAKQadDQXzZo1K+bOnRv19fWxYcOG+OQnPxnPPPPMYc+fNm1aLF68OM4777z4/ve/H5/73OfiW9/61lEvGvrijo2t2Us4ad1wSWP2EoB+pOI7I9OnT4/m5uZYuHBhTJw4MTZs2BCrVq2KUaNG9Xp+Y2NjrFixIr72ta/Fu9/97njooYfioYceine84x3HvHgAoP+rOEbmzJkT99xzT9x7772xadOmmDlzZuzZsydmzJjR6/mf/vSn41//9V/j9ttvjxdeeCFuvPHGePbZZ+P6668/5sUDAP1fRS/T1NTUxKRJk2LJkiXdx0op0dLSEo2Nvd+WbWxsjObm5h7HVq1aFb//+79/2McZPHhwnHrqqd3/vba2tsd/Ql8Mrj4lewknreP9XLW3eY7n3trXPMdrX/v6+1YUIyNHjoxBgwZFR0dHj+MdHR0xfvz4Xq+pr6/v9fz6+vrDPs68efPi5ptvPuR4W1tbJcsFkly/a1f2EjhO7O3AdLz3tba2Nnbv3n3Yrx/VG1iPtyVLlhxyN2XEiBGxc+fOpBWdmGpra6OtrS0aGhqOuMn0L/Z14LK3A5e9Pbza2tpob28/4jkVxciOHTviwIEDUVdX1+N4XV1dbN26tddrtm7dWtH5ERGdnZ3R2dnZ45jNPbzdu3f7+xmA7OvAZW8HLnt7qL78fVT0Btb9+/fHunXroqmpqftYVVVVNDU1RWtr799G2dra2uP8iIjf+q3fOuz5AMDJp1Qy06dPL3v37i0f/ehHy/jx48tXv/rVsnPnznLWWWeViCjLly8vt912W/f5jY2NpbOzs8yZM6eMGzeu3HTTTeX1118v73jHOyp6XHPo1NbWllJKqa2tTV+Lsa/G3p7MY2+PeSq/6BOf+ETZsmVL2bdvX1m9enWZMmVK99cef/zxsmzZsh7nT5s2rbzwwgtl3759ZePGjeUDH/hA9h96QMzgwYPLTTfdVAYPHpy+FmNfjb09mcfeHttU/eIXAAAp/GwaACCVGAEAUokRACCVGAEAUokRACCVGAEAUokRACDVCfmD8ji8c889Ny688MLYsmVLtLe3xznnnBOvvfZa7NixI3tpHCN7OzDZ14HL3r51xEg/Mnr06Pj4xz8ekydPjne+851RSok1a9bEeeedF2eddVbcddddcdddd8W+ffuyl0qF7O3AZF8HLnv71vIJrP3MmDFj4qyzzorvf//7MW7cuGhoaIiXX3453vWud8XHPvaxePbZZ+NLX/pSvPzyy9lLpUL2dmCyrwOXvX1rpX8mvXlr5tJLLy3//M//XJ544oly+eWXp6/H2FtjX0/WsbcVT/oCzFs4tbW15Y477ijPPPNMmTNnThkyZEj6mkzfpqqqyt6ehGNf++94zr6Ff5e/+AX9wBlnnBF/8id/EmeeeWacdtppsXnz5vjmN78ZL7300iHnXnvttfHhD384mpqaElbK8WRv+w/PWSLsbV+IkX7i3HPPjfvvvz/Gjh0b27dvjx07dsSIESNiyJAh0draGn/7t38bTz/9dFRVVUUpP9/ShoaGaGtr63GME8+wYcNiwoQJ8b3vfS9effXVPu2VvT3xec4OXJ6zx0f67RlzhFtXv7gNeOedd5bHH3+8nH322SUiyujRo8sVV1xRvvCFL5THHnusPPbYY+Vtb3tb+npN36e6urpERLn11ltLV1dX+cY3vlH+9E//tFx88cVl6NChPc6tr68v119/fTn11FPT122OPJ6zA3c8Z4/rpC/A9GG+853vlOuvv77Xr1188cVl7dq15dvf/nb3k8X0n3n22WfLsmXLyoMPPlj27dtXdu7cWVasWFGmTZtWxo4dW0455ZSyYMGC8swzz6Sv1fR9PGcH7njOHpdJX4B5k6muri5f/OIXy/PPP1/Gjh3b6zmNjY3l+eefL7/2a7+Wvl7T92loaCiPPvpomTZtWvexj3zkI+W73/1u6erqKlu2bCl33nln6ejoKHPnzi0RUU455ZT0dZsjj+fswB3P2eM26QswfZhx48aV1atXl/vvv79MmTKl1NTU9Pj6r/7qr5Y9e/aUYcOGpa/V9H3OOOOM8qEPfag0NjYe8rURI0aUz372s+XHP/5x6erqOuQ2sDmxZ9y4caW1tbX8/d//vefsAJo3nrO//uu/fsjXPGePfryBtZ+oqqqKK664IpYuXRrvfve744knnogHH3wwXnrppZgwYUK8973vjQMHDsQHP/jBqK6ujoMHD2YvmT465ZRToqurKyIiqquro6amJrq6uuLAgQMREXHHHXfExIkT4/LLL7e3/cxVV10VS5cujYsuuij+/d//PR566KHYvHmz52w/V1398x/r9saeVVdXR1VVVffz2HP26KQXkTnynHbaaWXIkCHlnHPOKTU1NWXSpEnly1/+ctm6dWvZsmVLee6558rtt9/efTvYa9D9Z4YMGVKGDRtWJk2aVM4888weX6uuri6nn356+cEPflD++I//2N7243n/+99fvv71r5ef/vSn5Yc//KHn7ACe008/vfzwhz/0nK180hdgepk33pH/27/926WlpaX893//d1m/fn1pbW0tf/3Xf13e+973logo559/fqmvr09frzn6vX311VfL2rVry1NPPVWWL19ePvjBD3bf0h88eHCZMmVK+ppN3+fNXnYZP378IeFp+sf09SW1yZMnp6+1v42XaU5gp59+erz44ovx4IMPxje+8Y0455xzYuzYsTFhwoQYPXp0PPXUUzF37tzYu3dv9lKpUG97O2bMmJgwYULU1dXFmjVr4sYbb4ydO3dmL5UKDBkyJP7qr/4qHnvssVi9enW0t7f3+oPSRo8eHe3t7Qkr5Gj1dW/r6+tj69atCSvs/9KLyPQ+n/nMZ8ratWsPuc130UUXldmzZ5eXX365/Mu//Is3SfXD6cvePvzww97c2E/mjbtdn/rUp0pXV1fZu3dvaW9vL1/96lfL1KlTy+jRo8ugQYNKRJSRI0eWlpYWnzHST6aSvT3zzDPLt7/9bXt7dJO+AHOY+fM///OyatWqctppp/X69UsvvbT84Ac/KJdeemn6Wo29NVG+/vWvlyVLlpRRo0aVT3ziE+W5554rXV1d5fnnny+LFy8uU6ZMKXPnzi2vvvpq+lqNvT3BJn0B5jBzySWXlB07dpSbb765jBw58pCvV1dXl3Xr1pVPfepT6Ws19vZkn8GDB5fPf/7zZcGCBT2On3feeWXp0qWlvb297Nmzp3R1dZXbbrutRPj8if4y9vaXMukLMEeYWbNmlfb29rJq1aryoQ99qJx99tmltra2nHbaaWXKlCllz5495e1vf3v6Oo29NVHOOeeccsEFF5SIKDU1NYf8VNdrrrmmdHV1lXPPPTd9rcbenmCTvgDzJvObv/mb5Vvf+lbZt29f2b59e3n44YfL6tWry5YtW8pdd91VIt78R1mbE3Ps7cCdN/atqqqq+71BCxYsKD/5yU/saz8fe3sc/k5/8QtOMHV1dXHFFVfEAw88EPv374+IiLPOOiuuuuqquOyyy+LFF1+MNWvWRGtra+zZs8dPguxH7O3AVF9fH5dddlk88MAD3R9YFxE9PvTqM5/5TGzfvj3uv//+Hh92x4nN3h5/YuQEdeGFF8Ytt9wSZ5xxRvzXf/1XrFy5Mr7zne90f90/UP2XvR2Y/u++btq0KR544IF48skne5wzdOjQ+NnPfpa0Qo6WvT3+xMgJbtiwYXH11VfH7/7u78av/MqvRGtra/zjP/5jfO9738teGsfI3g5M/3dfzzjjjHjyySdj5cqV8eKLL2YvjWNkb48fMXIC+///D3nMmDHxB3/wB/G+970vhg8fHh/5yEfilVdeSVwhR8veDkz2deCyt8df+htXTOXzrne9K30Nxt4a+2rs7Vsx7owAAKmqsxcAAJzcxAgAkEqMAACpxAgAkEqMAACpxAgAkEqMAACpxAgAkEqMAACpxAgAkEqMAACp/hfD9CqCsTZO9wAAAABJRU5ErkJggg==", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "print_output(c)" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "c48e4a38", + "metadata": {}, + "source": [ + "## Improve the performance with CVaR\n", + "\n", + "Conditional Value-at-Risk (CVaR) is a risk measure that quantifies the potential loss beyond a certain threshold (alpha), considering the tail end of the distribution. As proposed by [Barkoutsos et al. (2020)](https://arxiv.org/abs/1907.04769), incorporating CVaR as an objective function in QAOA allows for addressing risk-averse optimization problems effectively. By optimizing for CVaR, the algorithm focuses on minimizing the expected value of the worst-case scenario, rather than solely optimizing for the mean or expected value, which usually leads to faster convergence to a more accurate result.\n", + "\n", + "To showcase the performance of CVaR, a more complicated QUBO problem is used. This QUBO problem is described as a randomly generated symmetric Q matrix. The Q matrix is:" + ] + }, + { + "cell_type": "code", + "execution_count": 86, + "id": "02ec55b6", + "metadata": {}, + "outputs": [], + "source": [ + "Q = np.array(\n", + " [\n", + " [-60.3657, 11.68835, 12.23445, 11.7274, 11.9959, 11.80955],\n", + " [11.68835, -59.7527, 11.6231, 13.23295, 11.96335, 12.44725],\n", + " [12.23445, 11.6231, -59.69535, 11.29525, 12.00035, 11.78495],\n", + " [11.7274, 13.23295, 11.29525, -59.12165, 12.1006, 12.5461],\n", + " [11.9959, 11.96335, 12.00035, 12.1006, -60.45515, 12.07545],\n", + " [11.80955, 12.44725, 11.78495, 12.5461, 12.07545, -59.9126],\n", + " ]\n", + ")\n", + "pauli_terms, weights, offset = QUBO_to_Ising(Q)" + ] + }, + { + "cell_type": "markdown", + "id": "76879a55", + "metadata": {}, + "source": [ + "Then let's define a function to classically brute-force calculate all feasible combinations of stocks and their associated cost. The results are printed below." + ] + }, + { + "cell_type": "code", + "execution_count": 87, + "id": "46e9cbd9", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "-------------------------------------\n", + " selection\t |\t cost\n", + "-------------------------------------\n", + " 110010\t |\t-109.2784\n", + " 100011\t |\t-108.9717\n", + " 011010\t |\t-108.7296\n", + " 111000\t |\t-108.7219\n", + " 101100\t |\t-108.6685\n", + " 001110\t |\t-108.4798\n", + " 001011\t |\t-108.3416\n", + " 101001\t |\t-108.3157\n", + " ...\t |\t ...\n", + "-------------------------------------\n" + ] + } + ], + "source": [ + "def print_Q_cost(Q, wrap=False, reverse=False):\n", + " n_stocks = len(Q)\n", + " states = []\n", + " for i in range(2**n_stocks):\n", + " a = f\"{bin(i)[2:]:0>{n_stocks}}\"\n", + " n_ones = 0\n", + " for j in a:\n", + " if j == \"1\":\n", + " n_ones += 1\n", + " states.append(a)\n", + "\n", + " cost_dict = {}\n", + " for selection in states:\n", + " x = np.array([int(bit) for bit in selection])\n", + " cost_dict[selection] = np.dot(x, np.dot(Q, x))\n", + " cost_sorted = dict(sorted(cost_dict.items(), key=lambda item: item[1]))\n", + " if reverse == True:\n", + " cost_sorted = dict(\n", + " sorted(cost_dict.items(), key=lambda item: item[1], reverse=True)\n", + " )\n", + " num = 0\n", + " print(\"\\n-------------------------------------\")\n", + " print(\" selection\\t |\\t cost\")\n", + " print(\"-------------------------------------\")\n", + " for k, v in cost_sorted.items():\n", + " print(\"%10s\\t |\\t%.4f\" % (k, v))\n", + " num += 1\n", + " if (num >= 8) & (wrap == True):\n", + " break\n", + " print(\" ...\\t |\\t ...\")\n", + " print(\"-------------------------------------\")\n", + "\n", + "\n", + "print_Q_cost(Q, wrap=True)" + ] + }, + { + "cell_type": "markdown", + "id": "04d4ea38", + "metadata": {}, + "source": [ + "The QAOA with CVaR and three different alpha (1, 0.25, 0.1) will be run and a callback function will be used to record the parameters during the solving procedure. When alpha is $1$, the complete measurement results are accepted and the model changes to the standard QAOA." + ] + }, + { + "cell_type": "code", + "execution_count": 88, + "id": "d3b386d6", + "metadata": {}, + "outputs": [], + "source": [ + "# Set the number of layers to 2\n", + "nlayers = 2\n", + "\n", + "# Define a list of alpha values\n", + "alpha_list = [0.1, 0.25, 1]\n", + "\n", + "\n", + "# Define the callback function to record parameter values\n", + "def record_param(xk):\n", + " xk_list.append(xk)\n", + "\n", + "\n", + "# Generate initial parameters randomly for all alpha\n", + "init_params = K.implicit_randn(shape=[2 * nlayers], stddev=0.5)\n", + "\n", + "# Create an empty list to store parameter values for each alpha\n", + "params_list = []\n", + "\n", + "# Iterate over each alpha value\n", + "for alpha in alpha_list:\n", + " # Create a new empty list for callback function\n", + " xk_list = []\n", + "\n", + " # Run the QUBO_QAOA_cvar function with the specified parameters\n", + " final_params = QUBO_QAOA_cvar(\n", + " Q,\n", + " nlayers,\n", + " alpha=alpha,\n", + " callback=record_param,\n", + " maxiter=100,\n", + " init_params=init_params,\n", + " )\n", + "\n", + " # Append the parameter values for the current alpha to the params_list\n", + " params_list.append(xk_list)" + ] + }, + { + "cell_type": "code", + "execution_count": 89, + "id": "b3da7c48", + "metadata": {}, + "outputs": [], + "source": [ + "best = 50 # Represents the binary number 110010\n", + "prob_list = [] # Create an empty list to store probabilities\n", + "loss_list = [] # Create an empty list to store loss values\n", + "\n", + "# Iterate three times\n", + "for i in range(3):\n", + " c = QAOA_ansatz_for_Ising(init_params, nlayers, pauli_terms, weights)\n", + " loss = [cvar_loss(nlayers, Q, 1000, alpha_list[i], True, init_params)]\n", + " prob = [c.probability()[best].numpy()]\n", + "\n", + " # Iterate 100 times\n", + " for j in range(100):\n", + " if j < len(params_list[i]) - 1:\n", + " params = params_list[i][j]\n", + " else:\n", + " pass\n", + " c = QAOA_ansatz_for_Ising(params, nlayers, pauli_terms, weights)\n", + " loss.append(cvar_loss(nlayers, Q, 1000, alpha_list[i], True, params))\n", + " prob.append(c.probability()[best].numpy())\n", + "\n", + " loss_list.append(loss) # Append the loss values to the loss_list\n", + " prob_list.append(prob) # Append the probability values to the prob_list" + ] + }, + { + "cell_type": "code", + "execution_count": 92, + "id": "d1f375ce", + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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u3dvceLECfHNN99UVpu9/9Ju9LJr1y7x0UcfyZ8VCoW4ePGiePnll73etupSateuLYQQ4uabbxYARGhoqCgsLBT33nuvXKdly5ZCCCF69Ojh9fb6WwkODhaJiYli0KBBYuvWrXJwxPdccWX27Nli27ZtLutcvnxZTJo0Sf4cGhoqDAaDeOCBB7zefn8pq1evFl988YXdsZ9++kksW7aM77mCiqPgqLR32qpVKyGEEF26dJHr3HrrrcJsNou6detWeBvZreZlGo0GXbp0webNm+VjQghs3rwZcXFxXmxZ9RIWFgYAuHr1KgCgS5cu0Gq1du89MTERSUlJfO9lsHDhQqxduxZbtmyxO873XHHuuusu7NmzBz/88ANSUlKwb98+PPHEE/L5m266CXXr1rV719nZ2di9ezfftQf++usvDBo0CM2bNwcAdOjQAX369MG6desA8D1XBnfeaVxcHDIyMrB37165zubNm2GxWNCjR48KbxM3nvWy2rVrQ61WIyUlxe54SkoKWrVq5aVWVS8KhQIffPABduzYgSNHjgAAoqOjUVhYiKysLLu6KSkpiI6O9kYz/dYDDzyAzp07Oxwnx/dccZo0aYKnnnoK8+bNw9tvv41u3brhww8/hNFoxNKlS+X36ei/JXzX7nvnnXcQGhqK48ePw2w2Q6VS4dVXX8W3334LAHzPlcCddxodHY3U1FS782azGVevXq2U987giKq9hQsXol27dujTp4+3m1LtNGjQAAsWLMDgwYO5pUIlUyqV2LNnD1599VUAwIEDB9CuXTtMnDgRS5cu9XLrqo+RI0dizJgxGD16NI4cOYKOHTvigw8+wOXLl/mebyDsVvMyvV6PoqIiREVF2R2PiopCcnKyl1pVfXz00UcYNmwYBgwYgEuXLsnHk5OTERAQIHe3SfjePdOlSxdERUVh3759MJlMMJlM6N+/P5577jmYTCakpKTwPVeQK1eu4OjRo3bHjh07hpiYGACQ3yf/W1I+c+bMwTvvvIPvv/8e//77L5YvX4758+dj6tSpAPieK4M77zQ5ObnELFeVSoWaNWtWyntncORlJpMJe/fuxaBBg+RjCoUCgwYNQkJCghdb5v8++ugjjBgxAgMHDsS5c+fszu3duxdGo9Huvbdo0QKNGjXie/fAli1b0K5dO3Ts2FEu//zzD7755ht07NgRe/bs4XuuIDt37kTLli3tjrVo0QJJSUkAgLNnz+LKlSt271qn06FHjx581x4ICgqCxWKxO2Y2m6FUWn9d8j1XPHfeaUJCAiIiItC5c2e5zsCBA6FUKrF79+5KaZfXR67f6GXkyJHCYDCIhx9+WLRq1Up89tln4urVq6JOnTpeb5u/loULF4qMjAzRt29fERUVJZcaNWrIdT755BNx7tw50b9/f9G5c2exc+dOsXPnTq+33d+L7Ww1vueKK127dhVGo1FMnTpVNG3aVDz44IMiNzdXjB49Wq7z0ksviatXr4o777xTtGvXTqxcuZJTzD0sX331lbhw4YI8lf/uu+8Wqamp4p133uF7LkcJDg4WsbGxIjY2VgghxPPPPy9iY2NFw4YN3X6nv/32m9i7d6/o1q2b6NWrl0hMTORU/upennnmGXHu3DlRUFAgdu3aJbp37+71NvlzcWbcuHFynYCAAPHxxx+L9PR0kZubK37++WcRFRXl9bb7e7k+OOJ7rrhyxx13iEOHDgmDwSCOHj0qnnjiiRJ1ZsyYIa5cuSIMBoPYtGmTaN68udfb7U8lJCREzJ8/X5w7d07k5+eLU6dOiTfffFNoNBq+53KUfv36Ofxv8ldffeX2O42IiBDffPONyM7OFpmZmWLx4sUiODi4UtqruPYDEREREYFjjoiIiIjsMDgiIiIissHgiIiIiMgGgyMiIiIiGwyOiIiIiGwwOCIiIiKyweCIiIiIyAaDIyIiIiIbDI6IyOds3boV8+fP93Yz7AghMHz4cG83g4iqiNeXFWdhYWGxLRERESIkJEQAEGfPnhXx8fFV9uw33nhD7N+/v8TxqKgoodVqvf5uWFhYKr+oQUTkYzIyMir8nhqNBiaTqczXp6SkVGBriMjXeT1CY2FhYbEt0ua1W7duLbFRpVSnd+/eYtu2bSI/P1+cP39eLFiwQAQFBcnnz549K1577TWxZMkSkZWVJW9w+c4774jExESRl5cnTp8+LWbOnCnUarUAIMaNG+d0s2IhhBg+fLh8/3bt2oktW7aI/Px8odfrxaJFi+w2wfzqq6/EypUrxaRJk8Tly5eFXq8XH3/8sfwsAOKpp54SJ06cEAaDQSQnJ4sff/zR6++ehYUFAj7QABYWFha7IgVHERER4vz58+K1114TUVFRIioqSgAQTZo0ETk5OSI+Pl40a9ZMxMXFib1794ovv/xSvsfZs2dFZmameOGFF0STJk1EkyZNBADx6quviri4ONGoUSMxbNgwceXKFTF58mQBQNSoUUPMmTNHHD58WH5ejRo1BGAfHAUFBYlLly6Jn376SbRt21YMGDBAnD592m6H8a+++kpkZmaKTz75RLRs2VLccccdIjc3VzzxxBMCgOjSpYswmUxi1KhRIiYmRnTs2FE8++yzXn/3LCwsEPCBBrCwsLDYFSk4AhyPOfr888/FZ599Znesd+/eoqioSAQEBMjX/fLLL6U+a9KkSeKff/6RPzsbc2QbHD3xxBMiPT3dLlN12223iaKiIlGnTh0BWIOjs2fPCqVSKdf5/vvvxYoVKwQAMWLECJGZmSmPrWJhYfGdwjFHROR3YmNj0aFDB4wZM0Y+plAooFKpcNNNN+H48eMAgD179pS4duTIkXjuuefQtGlThISEQK1WIzs726Pnt27dGgcPHkR+fr58bOfOnVCpVGjZsiVSU1MBAEeOHIHFYpHrXLlyBe3btwcAbNq0CUlJSThz5gzWr1+P9evXY+XKlTAYDB61hYgqHqfyE5HfCQkJwaJFi9CxY0e5xMbGolmzZjh9+rRcLy8vz+66nj174ptvvsFvv/2GYcOGoVOnTpg1axa0Wm2ltPP6AeBCCCiV1v/s5ubmonPnznjwwQdx5coVzJw5EwcPHkRYWFiltIWI3MfMERH5NKPRCJVKZXds3759aNOmjV0g5I5evXohKSkJb7/9tnysUaNGpT7veseOHcMjjzyCoKAgOXvUu3dvmM1mJCYmut0es9mMLVu2YMuWLZgxYwYyMzMxcOBArFy50oNvRUQVjZkjIvJp586dQ9++fVGvXj3UqlULAPDuu++iV69e+Oijj+SM0V133YWPPvrI5b1OnjyJmJgYPPDAA2jSpAmeffZZjBgxosTzbrrpJsTGxqJWrVoOs0rffPMNCgoKsGTJErRt2xb9+/fHRx99hGXLlsldaqW544478OyzzyI2NhYxMTF4+OGHoVQqPQquiKhyMDgiIp82bdo0NG7cGKdPn4ZerwcAHD58GP369UOLFi2wfft27N+/HzNnzsTly5dd3mv16tWYP38+Pv74Yxw4cAC9evXCm2++aVfn559/xvr167F161bo9Xo8+OCDJe5jMBhw6623ombNmvjnn3/w008/YcuWLfi///s/t79XZmYm7rnnHvz+++84duwYJk6ciAcffBBHjx51+x5EVDkUsI7MJiIiIiIwc0RERERkh8ERERERkQ0GR0REREQ2GBwRERER2WBwRERERGSDwRERERGRDQZHRERERDYYHBERERHZYHBEREREZIPBEREREZENBkdERERENv4flMrniyoj9T4AAAAASUVORK5CYII=", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "for loss in loss_list:\n", + " plt.plot(loss)\n", + "plt.legend([\"alpha = 0.1\", \"alpha = 0.25\", \"alpha = 1\"])\n", + "plt.xlabel(\"iterations\")\n", + "p = plt.ylabel(\"cost\")" + ] + }, + { + "cell_type": "markdown", + "id": "6a88dda3", + "metadata": {}, + "source": [ + "The depicted figure illustrates that utilizing CVaR results in quicker convergence towards a lower loss." + ] + }, + { + "cell_type": "code", + "execution_count": 93, + "id": "f81fdeae", + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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/vSnP8He3h5//vOfMWjQIJw7dw4zZ87sF88uISIiop6hejf3rAXPADEYDIbpQqvVSnJysnh5eameC+PZDy8vL0lOThatVtvhte78/lb9m6CJiMi8VVZWAgB8fHxUzoT6gof/TvR6/VPtR/VLYEREZN4aGhpw5swZREZGAgBu3LihPBWd6CFra2v4+PggMjISZ86ceeIXPz5xfz2UFxER0Y+WmJgIAIiKilI5E3rWnTlzRvn38jQs8OBaGH2PRqNBbW0tHB0d+Z1AREQmZGdnB2dn5371hXvUM0QEer2+0zM/3fn9zTNARET0zGhsbMSdO3fUToPMABdBExERkdlhA0RERERmhw0QERERmR2uAeqERqNROwUiIiLqou783mYD9AgPC1haWqpyJkRERNRdGo3miXeB8Tb4x3B3d++VW+A1Gg1KS0vxwgsv8Bb7XsQ6mwbrbBqss2mwzqbR23XWaDQoKyt74jyeAXqMrhTvadTV1fE/mAmwzqbBOpsG62warLNp9Fadu7pPLoImIiIis8MGiIiIiMwOGyATa25uxh/+8Ac0NzernUq/xjqbButsGqyzabDOpvGs1JmLoImIiMjs8AwQERERmR02QERERGR22AARERGR2WEDRERERGaHDZAJrVixAkVFRTAYDDh//jyCgoLUTqlPe/vtt/H111+jtrYWOp0OqampGDVqlNEcW1tb7Nq1C3q9HnV1dTh8+DBcXFxUyrh/WL9+PUQE8fHxyhjr3DPc3d1x4MAB6PV6NDY24ptvvkFgYKDRnJiYGJSVlaGxsRGnTp3CiBEjVMq2b7K0tERsbCxu376NxsZG3Lp1C5s2beowj3XuvpdffhmfffYZSktLISKIiIjoMOdJdXVycsInn3yCe/fuobq6Gvv374e9vX2v5SyM3o/IyEhpamqSt956S0aPHi379u2TqqoqGTJkiOq59dU4fvy4LF68WMaMGSPjx4+Xf/3rX1JcXCx2dnbKnD179khJSYlMnTpVAgIC5KuvvpJz586pnntfjZdeeklu374teXl5Eh8fzzr3YAwaNEiKiork448/lqCgIBk2bJhMnz5dPD09lTnr1q2T6upqmTt3rowbN06OHj0qhYWFYmtrq3r+fSU2bNgg//nPf+S1114TDw8Pef3116W2tlaio6NZ56eMmTNnyubNm2XevHkiIhIREWH0elfqeuzYMbl06ZJMnDhRwsLC5ObNm5KSktJbOatfNHOI8+fPS0JCgrJtYWEh3333naxfv1713PpLODs7i4jIyy+/LADE0dFRmpub5fXXX1fmeHt7i4hIcHCw6vn2tbC3t5f8/HwJDw+XjIwMpQFinXsmtm3bJmfPnu10TllZmaxZs0bZdnR0FIPBIFFRUarn31ciLS1N9u/fbzR2+PBhOXDgAOvcg/GoBuhJdfXx8RERkcDAQGXOjBkzpK2tTYYOHdrjOfISmAnY2NggMDAQp0+fVsZEBKdPn0ZISIiKmfUvzz33HACgqqoKABAYGIgBAwYY1T0/Px8lJSWs+4+we/dufP7550hPTzcaZ517xty5c5GTk4NDhw5Bp9Ph4sWLWLJkifL68OHDMXToUKM619bW4sKFC6xzN3z11VcIDw/HyJEjAQDjx4/HpEmTcPz4cQCsc2/pSl1DQkJQXV2N3NxcZc7p06fR3t6O4ODgHs+JD0M1AWdnZ1hbW0On0xmN63Q6+Pj4qJRV/2JhYYH3338f586dw9WrVwEAbm5uaG5uxr1794zm6nQ6uLm5qZFmnxUVFYWAgIBHrltjnXuGp6cnli9fjh07dmDr1q0ICgrCBx98gJaWFiQnJyu1fNTPEda56+Li4uDo6IgbN26gra0NVlZW2LhxI/76178CAOvcS7pSVzc3N9y9e9fo9ba2NlRVVfVK7dkAUb+we/du+Pr6YtKkSWqn0u+8+OKL2LlzJ6ZPn676V9f3Z5aWlsjJycHGjRsBAHl5efD19cWyZcuQnJyscnb9R2RkJN58800sXLgQV69ehb+/P95//32UlZWxzmaGl8BMQK/X4/79+3B1dTUad3V1RUVFhUpZ9R8JCQmYPXs2pk6ditLSUmW8oqICtra2yqWxh1j37gkMDISrqysuXryI1tZWtLa2YsqUKVi5ciVaW1uh0+lY5x5QXl6Oa9euGY1dv34dWq0WAJRa8ufI09m+fTvi4uJw8OBBXLlyBZ988gni4+OxYcMGAKxzb+lKXSsqKjrcPWplZYXBgwf3Su3ZAJlAa2srcnNzER4eroxZWFggPDwcWVlZKmbW9yUkJGD+/PmYNm0aiouLjV7Lzc1FS0uLUd1HjRoFDw8P1r0b0tPT4evrC39/fyWys7ORkpICf39/5OTksM49IDMzE97e3kZjo0aNQklJCQCgqKgI5eXlRnXWaDQIDg5mnbvBzs4O7e3tRmNtbW2wtHzw65B17h1dqWtWVhacnJwQEBCgzJk2bRosLS1x4cKFXslL9dXi5hCRkZFiMBhk0aJF4uPjI3v37pWqqipxcXFRPbe+Grt375bq6mp55ZVXxNXVVYmBAwcqc/bs2SPFxcUyZcoUCQgIkMzMTMnMzFQ9974e378LjHXumXjppZekpaVFNmzYIF5eXrJgwQKpr6+XhQsXKnPWrVsnVVVVMmfOHPH19ZXU1FTent3NSExMlH//+9/KbfDz5s2Tu3fvSlxcHOv8lGFvby9+fn7i5+cnIiK///3vxc/PT37yk590ua7Hjh2T3NxcCQoKktDQUMnPz+dt8P0hfvvb30pxcbE0NTXJ+fPnZeLEiarn1JfjcRYvXqzMsbW1lV27dkllZaXU19fLkSNHxNXVVfXc+3r8sAFinXsmZs2aJd98840YDAa5du2aLFmypMOcmJgYKS8vF4PBIKdOnZKRI0eqnndfCgcHB4mPj5fi4mJpbGyUW7duyebNm8XGxoZ1fsqYPHnyI38mJyYmdrmuTk5OkpKSIrW1tVJTUyMfffSR2Nvb90q+Fv//FyIiIiKzwTVAREREZHbYABEREZHZYQNEREREZocNEBEREZkdNkBERERkdtgAERERkdlhA0RERERmhw0QERERmR02QERkchkZGYiPj1c7DSMigoiICLXTICITUv3rsxkMhnmFk5OTODg4CAApKiqSVatWmezY7777rly6dKnDuKurqwwYMED12jAYDNOENYiITKy6urrH92ljY4PW1tYf/X6dTteD2RBRX6B6F8ZgMMwrHj5MNSMjo8ODEx/OCQsLk7Nnz0pjY6PcuXNHdu7cKXZ2dsrrRUVFsmnTJklKSpJ79+4pD1yMi4uT/Px8aWhokMLCQomNjRVra2sBIIsXL37sw3NFRCIiIpT9+/r6Snp6ujQ2Noper5d9+/YZPZQxMTFRUlNTZc2aNVJWViZ6vV527dqlHAuALF++XG7evCkGg0EqKirk73//u+q1ZzAYSqieAIPBMLN42AA5OTnJnTt3ZNOmTeLq6qo8Qd7T01Pq6upk1apVMmLECAkJCZHc3Fz5+OOPlX0UFRVJTU2NrF69Wjw9PcXT01MAyMaNGyUkJEQ8PDxk9uzZUl5eLmvXrhUAMnDgQNm+fbt8++23yvEGDhwogHEDZGdnJ6WlpXL48GEZO3asTJ06VQoLC42eap2YmCg1NTWyZ88e8fb2llmzZkl9fb3yBPfAwEBpbW2VN954Q7Rarfj7+0t0dLTqtWcwGEqongCDwTCzeNgAAY9eA/SXv/xF9u7dazQWFhYm9+/fF1tbW+V9//jHP554rDVr1kh2dray/bg1QN9vgJYsWSKVlZVGZ5xeffVVuX//vri4uAjwoAEqKioSS0tLZc7Bgwfl008/FQAyf/58qampUdY6MRiMZyu4BoiInjl+fn4YP3483nzzTWXMwsICVlZWGD58OG7cuAEAyMnJ6fDeyMhIrFy5El5eXnBwcIC1tTVqa2u7dfzRo0fj8uXLaGxsVMYyMzNhZWUFb29v3L17FwBw9epVtLe3K3PKy8sxbtw4AMCpU6dQUlKC27dv48SJEzhx4gRSU1NhMBi6lQsR9Q7eBk9EzxwHBwfs27cP/v7+Svj5+WHEiBEoLCxU5jU0NBi976c//SlSUlJw7NgxzJ49GxMmTMB7772HAQMG9EqeP1x0LSKwtHzwY7W+vh4BAQFYsGABysvLERsbi8uXL+O5557rlVyIqHt4BoiIVNXS0gIrKyujsYsXL2LMmDFGzU5XhIaGoqSkBFu3blXGPDw8nni8H7p+/Treeust2NnZKWeBwsLC0NbWhvz8/C7n09bWhvT0dKSnpyMmJgY1NTWYNm0aUlNTu/GpiKg38AwQEamquLgYr7zyCtzd3fH8888DAP74xz8iNDQUCQkJypmfuXPnIiEhodN9FRQUQKvVIioqCp6enoiOjsb8+fM7HG/48OHw8/PD888//8izQykpKWhqakJSUhLGjh2LKVOmICEhAQcOHFAufz3JrFmzEB0dDT8/P2i1WixatAiWlpbdaqCIqPewASIiVb3zzjsYNmwYCgsLodfrAQDffvstJk+ejFGjRuHLL7/EpUuXEBsbi7Kysk73lZaWhvj4eOzatQt5eXkIDQ3F5s2bjeYcOXIEJ06cQEZGBvR6PRYsWNBhPwaDATNmzMDgwYORnZ2Nw4cPIz09Hb/73e+6/Llqamrws5/9DF988QWuX7+OZcuWYcGCBbh27VqX90FEvccCD1ZDExEREZkNngEiIiIis8MGiIiIiMwOGyAiIiIyO2yAiIiIyOywASIiIiKzwwaIiIiIzA4bICIiIjI7bICIiIjI7LABIiIiIrPDBoiIiIjMDhsgIiIiMjv/ByyWoR/vyUHjAAAAAElFTkSuQmCC", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "for prob in prob_list:\n", + " plt.plot(prob)\n", + "plt.legend([\"alpha = 0.1\", \"alpha = 0.25\", \"alpha = 1\"])\n", + "plt.xlabel(\"iterations\")\n", + "p = plt.ylabel(\"probability of the best answer\")" + ] + }, + { + "cell_type": "markdown", + "id": "0ae45348", + "metadata": {}, + "source": [ + "The data presented in this figure indicates that QAOA with CVaR typically shows a higher probability of obtaining the correct measurement outcome." + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "tc_dev", + "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.4" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/tensorcircuit/applications/optimization.py b/tensorcircuit/applications/optimization.py index bf0cc1c5..28c5c81a 100644 --- a/tensorcircuit/applications/optimization.py +++ b/tensorcircuit/applications/optimization.py @@ -5,7 +5,6 @@ from typing import List, Callable, Any, Optional, Tuple from functools import partial -import numpy as np import tensorflow as tf import scipy.optimize as optimize @@ -161,43 +160,41 @@ def QUBO_QAOA( # Return the optimized parameters for the ansatz circuit. -def cvar_value(r: List[float], p: List[float], percent: float) -> float: +def cvar_value(r: List[float], p: List[float], percent: float) -> Any: """ - Calculate the Conditional Value at Risk (CVaR) according to the measurement results. + Compute the Conditional Value at Risk (CVaR) based on the measurement results. - :param r: The results showing after measurements. - :param p: Probabilities corresponding to each result. - :param percent: The cut-off percentage of CVaR. + :param r: The observed outcomes after measurements. + :param p: Probabilities associated with each observed outcome. + :param percent: The cut-off percentage for CVaR computation. :return: The calculated CVaR value. """ - sorted_indices = np.argsort(r) - p = np.array(p)[sorted_indices] # type: ignore - r = np.array(r)[sorted_indices] # type: ignore - - sump = 0.0 # The sum of probabilities. - count = 0 - cvar_result = 0.0 - - # Iterate over the sorted results and calculate CVaR. - while sump < percent: - if round(sump + p[count], 6) >= percent: - # Add the remaining portion of the last result that exceeds the cut-off percentage. - cvar_result += r[count] * (percent - sump) - count += 1 - break - else: - # Add the entire result to the CVaR calculation. - sump += p[count] - cvar_result += r[count] * p[count] - count += 1 + sorted_indices = tf.argsort(r) + p_sorted = tf.cast(tf.gather(p, sorted_indices), dtype=tf.float32) + r_sorted = tf.cast(tf.gather(r, sorted_indices), dtype=tf.float32) + + # Calculate the cumulative sum of sorted probabilities. + cumsum_p = tf.math.cumsum(p_sorted) + + # Create a tensor that evaluates to 1 if the condition is met, otherwise 0. + mask = tf.cast(tf.math.less(cumsum_p, percent), dtype=tf.float32) + + # Use mask to filter and sum the required elements for CVaR. + cvar_numerator = tf.reduce_sum(mask * p_sorted * r_sorted) + + # Compute the last remaining portion that exceeds the cut-off percentage. + last_portion_index = tf.math.argmax(tf.math.greater_equal(cumsum_p, percent)) + last_portion = (percent - cumsum_p[last_portion_index - 1]) * r_sorted[ + last_portion_index + ] + + # Calculate the final CVaR. + cvar_result = (cvar_numerator + last_portion) / percent - cvar_result /= percent return cvar_result -def cvar_from_circuit( - circuit: Circuit, nsamples: int, Q: Tensor, alpha: float -) -> float: +def cvar_from_circuit(circuit: Circuit, nsamples: int, Q: Tensor, alpha: float) -> Any: """ Directly calculate the Conditional Value at Risk (CVaR) from a circuit. The CVaR depends on a bunch of measurements. @@ -208,27 +205,43 @@ def cvar_from_circuit( :param alpha: The cut-off percentage for CVaR. :return: The calculated CVaR value. """ - s = circuit.state() + # Obtain and normalize measurement results + measurement_data = circuit.state() results = measurement_results( - s, counts=nsamples, format="count_dict_bin" - ) # Get readouts from the measurements. - results = {k: v / nsamples for k, v in results.items()} # Normalize the results. - values = [] # List to store the measurement values. - probabilities = [] # List to store the corresponding probabilities. - - # Iterate over the measurement results and calculate the values and probabilities. - for k, v in results.items(): - x = np.array([int(bit) for bit in k]) - values.append(np.dot(x, np.dot(Q, x))) - probabilities.append(v) + measurement_data, counts=nsamples, format="sample_int", jittable=True + ) + n_counts = tf.shape(results)[0] + + # Determine the number of qubits in the circuit and generate all possible states + n_qubits = len(Q) + all_states = tf.constant([format(i, f"0{n_qubits}b") for i in range(2**n_qubits)]) + all_binary = tf.reshape( + tf.strings.to_number(tf.strings.bytes_split(all_states), tf.float32), + (2**n_qubits, n_qubits), + ) + all_decimal = tf.range(2**n_qubits, dtype=tf.int32) + + # Convert the Q matrix to a TensorFlow tensor + Q_tensor = tf.convert_to_tensor(Q, dtype=tf.float32) + + # calculate cost values + values = tf.reduce_sum(all_binary * tf.matmul(all_binary, Q_tensor), axis=1) + # Count the occurrences of each state and calculate probabilities + state_counts = tf.reduce_sum( + tf.cast(tf.equal(tf.reshape(results, [-1, 1]), all_decimal), tf.int32), axis=0 + ) + probabilities = tf.cast(state_counts, dtype=tf.float32) / tf.cast( + n_counts, dtype=tf.float32 + ) + + # Calculate CVaR cvar_result = cvar_value(values, probabilities, alpha) - # Calculate the CVaR using the cvar_value function. return cvar_result -def cvar_from_expectation(circuit: Circuit, Q: Tensor, alpha: float) -> float: +def cvar_from_expectation(circuit: Circuit, Q: Tensor, alpha: float) -> Any: """ Calculate the Conditional Value at Risk (CVaR) from the expectation values of a quantum circuit. @@ -237,23 +250,29 @@ def cvar_from_expectation(circuit: Circuit, Q: Tensor, alpha: float) -> float: :param alpha: The cut-off percentage for CVaR. :return: The calculated CVaR value. """ - prob = circuit.probability() # Get the probabilities of the circuit states. - prob /= np.sum(prob) - states = [] - # Generate all possible binary states based on the length of Q. - for i in range(2 ** len(Q)): - a = f"{bin(i)[2:]:0>{len(Q)}}" - states.append(a) + # Calculate the probability amplitudes for quantum circuit outcomes. + prob = tf.convert_to_tensor(circuit.probability(), dtype=tf.float32) - values = [] - for state in states: - x = np.array([int(bit) for bit in state]) - values.append(np.dot(x, np.dot(Q, x))) - # Calculate the values by taking the dot product of each state with the Q-matrix. + # Generate all possible binary states for the given Q-matrix. + n_qubits = len(Q) + all_states = tf.constant( + [format(i, "0" + str(n_qubits) + "b") for i in range(2 ** len(Q))] + ) + all_binary = tf.reshape( + tf.strings.to_number(tf.strings.bytes_split(all_states), tf.float32), + (2**n_qubits, n_qubits), + ) + # Convert the Q-matrix to a TensorFlow tensor. + Q_tensor = tf.convert_to_tensor(Q, dtype=tf.float32) + + # calculate cost values + elementwise_product = tf.multiply(all_binary, tf.matmul(all_binary, Q_tensor)) + values = tf.reduce_sum(elementwise_product, axis=1) + + # Calculate the CVaR value using the computed values and the probability distribution. cvar_result = cvar_value(values, prob, alpha) - # Calculate the CVaR using the cvar_value function. return cvar_result @@ -265,7 +284,7 @@ def cvar_loss( alpha: float, expectation_based: bool, params: List[float], -) -> float: +) -> Any: """ Calculate the CVaR loss for a given QUBO problem using the QAOA ansatz. @@ -297,7 +316,7 @@ def cvar_loss( def QUBO_QAOA_cvar( Q: Tensor, nlayers: int, - alpha: int, + alpha: float, nsamples: int = 1000, callback: Optional[Callable[[List[float], float], None]] = None, expectation_based: bool = False, @@ -320,7 +339,7 @@ def QUBO_QAOA_cvar( """ loss = partial(cvar_loss, nlayers, Q, nsamples, alpha, expectation_based) - f_scipy = scipy_interface(loss, shape=(2 * nlayers,), jit=False, gradient=False) + f_scipy = scipy_interface(loss, shape=(2 * nlayers,), jit=True, gradient=False) if init_params is None: params = backend.implicit_randn(shape=[2 * nlayers], stddev=0.5) @@ -338,7 +357,6 @@ def QUBO_QAOA_cvar( method="COBYLA", callback=callback, options={"maxiter": maxiter}, - # bounds=[(0, (2 - np.mod(i, 2))*np.pi) for i in range(2*nlayers)] ) # Perform the optimization using the COBYLA method from scipy.optimize.