diff --git a/examples/quantum_annealing/price_optimization/QUBO-Pricing.ipynb b/examples/quantum_annealing/price_optimization/QUBO-Pricing.ipynb new file mode 100644 index 000000000..cfd35fd0a --- /dev/null +++ b/examples/quantum_annealing/price_optimization/QUBO-Pricing.ipynb @@ -0,0 +1,2855 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "2c5219f3", + "metadata": {}, + "source": [ + "# Using quantum annealing on Amazon Braket for price optimization\n", + "\n", + "Combinatorial Optimization is one of the most important fields in optimization. Practical applications can be found in virtually every industry. Prominent examples include supply chain optimization in transport and logistics, portfolio management in finance, and the optimization of clinical trials in healthcare, among many others. It is also one of the most active research topics in operation research and computer science. However, many practical combinatorial optimization problems are NP-hard and require massive computation costs to find solution of good quality. \n", + "\n", + "In this notebook, we demonstrate how a quantum annealer on Amazon Braket can be used for price optimization taking into consideration the trade-off between maximizing revenue and minimizing risk. We show how to formulate this problem as a quadratic unconstrained binary optimization problem (QUBO) and use the D-Wave Advantage quantum annealer on Amazon Braket to find close-to-optimal solutions. Overall, this notebook demonstrates that customers can easily leverage quantum computing through Amazon Braket to solve difficult combinatorial optimization challenges in their daily decision-making process." + ] + }, + { + "cell_type": "markdown", + "id": "10f29dc7", + "metadata": {}, + "source": [ + "# Table of contents\n", + "### 1. Demand model\n", + " 1. Create demand dataset\n", + " 2. Fit demand model through linear regression\n", + "### 2. Price optimization with QUBO\n", + " 1. Construct revenue objective\n", + " 2. Add penalty for prediction uncertainty\n", + " 3. Add equality constraints\n", + "### 3. Solve QUBO with Amazon Braket\n", + " 1. Evaluate results\n", + "### 4. Trade-off between revenue expectation and prediction uncertainty\n", + "### 5. Conclusion\n", + "### 6. Literature review\n", + "-----------------" + ] + }, + { + "cell_type": "markdown", + "id": "aed8d388", + "metadata": {}, + "source": [ + "We start by importing Amazon braket SDK and Dwave SDK to be used for quantum annealing in this use case. In addition, we import sklearn to fit the demand estimation model." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "1f31ea86", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Requirement already satisfied: sklearn in /home/ec2-user/anaconda3/envs/Braket/lib/python3.7/site-packages (0.0)\n", + "Requirement already satisfied: scikit-learn in /home/ec2-user/anaconda3/envs/Braket/lib/python3.7/site-packages (from sklearn) (1.0.1)\n", + "Requirement already satisfied: scipy>=1.1.0 in /home/ec2-user/anaconda3/envs/Braket/lib/python3.7/site-packages (from scikit-learn->sklearn) (1.5.2)\n", + "Requirement already satisfied: numpy>=1.14.6 in /home/ec2-user/anaconda3/envs/Braket/lib/python3.7/site-packages (from scikit-learn->sklearn) (1.19.2)\n", + "Requirement already satisfied: threadpoolctl>=2.0.0 in /home/ec2-user/anaconda3/envs/Braket/lib/python3.7/site-packages (from scikit-learn->sklearn) (3.0.0)\n", + "Requirement already satisfied: joblib>=0.11 in /home/ec2-user/anaconda3/envs/Braket/lib/python3.7/site-packages (from scikit-learn->sklearn) (1.1.0)\n" + ] + } + ], + "source": [ + "!pip install sklearn" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "6718da7a", + "metadata": {}, + "outputs": [], + "source": [ + "from braket.aws import AwsDevice\n", + "from braket.ocean_plugin import BraketSampler, BraketDWaveSampler\n", + "from pyqubo import Binary\n", + "# magic word for producing visualizations in notebook\n", + "%matplotlib inline\n", + "import time\n", + "import reprlib\n", + "from collections import defaultdict\n", + "from itertools import combinations\n", + "import math\n", + "import networkx as nx\n", + "import dwave_networkx as dnx\n", + "import minorminer\n", + "import dimod\n", + "from dimod.binary_quadratic_model import BinaryQuadraticModel\n", + "from dwave.system.composites import EmbeddingComposite\n", + "import numpy as np\n", + "from sklearn.linear_model import LinearRegression\n", + "import matplotlib.pyplot as plt\n", + "\n", + "from qubo_dynamic_pricing import optimize\n", + "\n", + "np.random.seed(0)\n", + "repr_compact = reprlib.Repr()\n", + "repr_compact.maxother=200" + ] + }, + { + "cell_type": "markdown", + "id": "61be0cc9", + "metadata": {}, + "source": [ + "__NOTE__: Enter your S3 bucket and key below. " + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "ce15ec79", + "metadata": {}, + "outputs": [], + "source": [ + "# Enter the S3 bucket you created during onboarding in the code below\n", + "my_bucket = \"amazon-braket-Your-Bucket-Name\" # the name of the bucket\n", + "my_prefix = \"Your-Folder-Name\" # the name of the folder in the bucket\n", + "s3_folder = (my_bucket, my_prefix)" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "c2fc5e7e", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Device: Device('name': Advantage_system4.1, 'arn': arn:aws:braket:::device/qpu/d-wave/Advantage_system4)\n" + ] + } + ], + "source": [ + "# session and device\n", + "device = AwsDevice(\"arn:aws:braket:::device/qpu/d-wave/Advantage_system4\")\n", + "print('Device:', device)" + ] + }, + { + "cell_type": "markdown", + "id": "173be395", + "metadata": {}, + "source": [ + "# 1. Demand model" + ] + }, + { + "cell_type": "markdown", + "id": "5c05da56", + "metadata": {}, + "source": [ + "The usual goal of price optimization is to maximize the revenue in the next certain period with respect to the corresponding prices, where the revenue can usually be represented by a function of demand and price: \n", + "\n", + "$$\\max_{{\\mathbf{p}}} R(\\mathbf{p}) = \\sum_{t=T}^{T+n-1}d_tp_t$$\n", + "\n", + "where $p_t$ and $d_t$ are the price and demand at day $t$.\n", + "\n", + "In order to do price optimization, we need to create a demand model to estimate demand by a function of price: $d_t=f(\\mathbf{p}_t)$, where $\\mathbf{p}$ is a vector of latest prices. In such a way, the revenue objective can be transformed as a function solely depending on price to do optimization $R=\\sum_{t=T}^{T+n-1}f(\\mathbf{p_t})p_t$." + ] + }, + { + "cell_type": "markdown", + "id": "e7de211f", + "metadata": {}, + "source": [ + "## 1.1 Create training dataset" + ] + }, + { + "cell_type": "markdown", + "id": "21fe8119", + "metadata": {}, + "source": [ + "For simplicity, we create a dummy dataset on historical demand and price observations so that a demand estimation model can be trained. \n", + "\n", + "Here we assume the true demand at day $d_t$ follows a linear model of the latest $n$ days' prices $p_i, i\\in [t-n+1, t-n+2, \\ldots, t]$ plus a noise following normal distribution $\\varepsilon\\sim N(0,\\sigma) $.\n", + "\n", + "Thus the demand at day $t$ would be\n", + "$$d_t = \\sum_{i=t-n+1}^{t}a_{i+n-1-t}p_{i} + b + \\varepsilon $$\n", + "where $a_j, j\\in [0, 1, \\ldots, n-1]$ is the elasiticity between the price at day $j+t-n+1$ and demand at day $t$, and\n", + "$b$ is a constant.\n", + "\n", + "We use these assumptions to create our dummy training dataset." + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "438e6d85", + "metadata": { + "scrolled": true + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "dataset x first 10 samples:\n", + "[[ 8 10 10 8 8 10 8]\n", + " [10 10 8 8 10 8 13]\n", + " [10 8 8 10 8 13 19]\n", + " [ 8 8 10 8 13 19 8]\n", + " [ 8 10 8 13 19 8 10]\n", + " [10 8 13 19 8 10 8]\n", + " [ 8 13 19 8 10 8 8]\n", + " [13 19 8 10 8 8 16]\n", + " [19 8 10 8 8 16 5]\n", + " [ 8 10 8 8 16 5 5]]\n", + "dataset y first 10 samples:\n", + "[176.60983362005817, 166.3135122384355, 122.40886555130055, 139.82753849065216, 136.5494478345374, 139.08672451958816, 171.1141344886614, 149.02456906069798, 153.67576697932017, 185.92865845385478]\n" + ] + } + ], + "source": [ + "a0=[-0.3, -0.5, -1.0, -2.0, -3.0, -3.3, -3.5] # elasticities in linear demand model\n", + "b0=300 # constants in the linear demand model \n", + "sigma=10. # the standard deviation of the noise\n", + "price_levels=[5, 8, 10, 12, 13, 16, 19] # predefined possible prices for each day\n", + "probabilities=[0.3, 0.3, 0.2, 0.05, 0.05, 0.05, 0.05] # the probabilities of taking a price choice at a day\n", + "n_samples=1000 # the number of sample we want to create\n", + "\n", + "def create_data_point(p, a, b, sigma):\n", + " \"\"\"\n", + " estimate the demand\n", + " :param p: np.array, (T,)\n", + " :param a: np.array, (T,)\n", + " :param b: float, the constants\n", + " :return: v\n", + " \"\"\"\n", + " v = np.dot(p,a) + b + np.random.normal(loc=0.0, scale=sigma)\n", + " return v\n", + "\n", + "def create_dataset(a, b, N, price_levels, probabilities, sigma):\n", + " \"\"\"\n", + " create a dataset for training the demand model\n", + " :param a: np.array, (T,)\n", + " :param b: float\n", + " :param N: int number of samples\n", + " :param price_levels: list, price levels\n", + " :param probabilities: list, probabilities distribution of the prices\n", + " :return:\n", + " \"\"\"\n", + " t = len(a)\n", + " prices = np.random.choice(price_levels, N+t-1, p=probabilities)\n", + " data_x = []\n", + " data_y = []\n", + " for i in range(N):\n", + " p = prices[i:i+t]\n", + " v = create_data_point(p, a, b, sigma)\n", + " data_x.append(\n", + " np.expand_dims(p, axis=0)\n", + " )\n", + " data_y.append(v)\n", + "\n", + " data_x = np.concatenate(data_x,axis=0)\n", + " return data_x, data_y\n", + "\n", + "data_x, data_y = create_dataset(a0, b0, n_samples, price_levels, probabilities, sigma)\n", + "\n", + "print(\"dataset x first 10 samples:\")\n", + "print(data_x[:10])\n", + "print(\"dataset y first 10 samples:\")\n", + "print(data_y[:10])" + ] + }, + { + "cell_type": "markdown", + "id": "8f68105b", + "metadata": {}, + "source": [ + "## 1.2. Fit the demand model" + ] + }, + { + "cell_type": "markdown", + "id": "31302cb4", + "metadata": {}, + "source": [ + "We use `sklearn` to fit a linear demand model to the training set. This fitted linear demand model will be used for the following price optimization problem." + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "08cdb86d", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "fitted elasticities: [-0.3779074420638822, -0.5723441150118157, -0.8832936349398142, -2.044653528191526, -2.9861902495686956, -3.2337479564086022, -3.6095730899274248]\n", + "fitted constant: 301.2623906306577\n" + ] + } + ], + "source": [ + "def linear_regression(data_x, data_y):\n", + " reg = LinearRegression().fit(data_x, data_y)\n", + " a = reg.coef_\n", + " b = reg.intercept_\n", + " return a, b\n", + "\n", + "\n", + "a, b = linear_regression(data_x, data_y)\n", + "a = [i for i in a]\n", + "b = b\n", + "\n", + "print(f'fitted elasticities: {a}')\n", + "print(f'fitted constant: {b}')" + ] + }, + { + "cell_type": "markdown", + "id": "694b5278", + "metadata": {}, + "source": [ + "# 2. Price optimization with QUBO" + ] + }, + { + "cell_type": "markdown", + "id": "c67da567", + "metadata": {}, + "source": [ + "In this notebook, we leverage a general-purpose mathematical framework: Quadratic Unconstrained Binary Optimization (QUBO), which has been recently proposed as an effective framework that is able to generalize across a large variety of combinatorial optimization use cases in industries [2, 3]. We take this price optimization as an example and showcase how to formulate it into QUBO framework considering prediction uncertainties as well as equality constraints." + ] + }, + { + "cell_type": "markdown", + "id": "2f6135bd", + "metadata": {}, + "source": [ + "The formal definition of QUBO is expressed as an optimization problem, Minimize:\n", + "$$H=x^TQx$$" + ] + }, + { + "cell_type": "markdown", + "id": "277ac4cc", + "metadata": {}, + "source": [ + "where $x$ is a vector of binary variables representing the decision variables of the combinatorial optimization. $Q$ is a squared matrix of constants inherently encoding the context and constraints of the optimization problems. $Q$ is commonly assumed to be symmetric or upper triangular without loss of generality. The goal is to find the optimal values of the binary decision variables $x$ that minimize the objective $H$.\n", + "\n", + "As shown above, the format of QUBO is strikingly simple, providing a general-purpose framework for a large class of combinatorial optimization problems. Below we show how to transform the objective function together with the constraints into this QUBO format. " + ] + }, + { + "cell_type": "markdown", + "id": "b4ce1392", + "metadata": {}, + "source": [ + "## 2.1 Construct objective function" + ] + }, + { + "cell_type": "markdown", + "id": "4e5a61db", + "metadata": {}, + "source": [ + "Assuming tomorrow is day $T$, then the goal of our price optimization is to find the optimal prices $p_t, t\\in[T, T+1, \\ldots, T+n-1]$ in the next $n$ days in order to maximize the revenue in next $n$ days. Based on the demand model we showed above where the demand at a day is correlated with the latest $n$ days' price, we can construct objective function as below:\n", + "\n", + "$$\\max_{{\\mathbf{p}}}R(\\mathbf{p})=\\sum_{t=T}^{T+n-1}d_tp_t$$\n", + "\n", + "where $d_t$ is represented by our fitted model above: $d_t = \\sum_{i=t-n+1}^{t}a_{i+n-1-t}p_{i} + b $\n", + "\n", + "Therefore, we need at least the most recent n days historical prices. Here we randomly choose a historical range of $n$ days' prices as the most recent price data. " + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "8ab0bc6b", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[10, 8, 8, 5, 5, 8, 8]" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "p_data = data_x[np.random.randint(0,n_samples)].tolist()\n", + "\n", + "p_data" + ] + }, + { + "cell_type": "markdown", + "id": "8ced72f4", + "metadata": {}, + "source": [ + "Now, let's construct the objective function, i.e. the total revenue $R$, for the next $n$ days.\n", + "\n", + "First, we need to define the price variable $p_t$. According to certain business requirements, the possible prices are usually defined to be a set of discrete price values (e.g. \\\\$5.99, \\\\$9.99, \\\\$14.99). This means the price at each day only has a set of fixed available $m$ options $c_k, k \\in [0, 1, \\ldots, m-1]$, we can represent the price $p_t$ at day $t$ as: $$p_t=\\sum_{k=0}^{m-1}c_{k}x_{t,k}, \\textrm{ subject to } \\sum_{k=0}^{m-1}x_{t,k}=1$$ \n", + "\n", + "where $x_{t,k}$ is a binary variable with $1$ meaning the price at day $t$ takes option $c_k$, and $0$ meaning otherwise. Therefore, we can use binary variables $x_{t,k}$ to represent the price variables $p_t$." + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "a668a23a", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[10,\n", + " 8,\n", + " 8,\n", + " 5,\n", + " 5,\n", + " 8,\n", + " 8,\n", + " (Binary(X_006)*Num(19.000000)+Binary(X_005)*Num(16.000000)+Binary(X_004)*Num(13.000000)+Binary(X_003)*Num(12.000000)+Binary(X_002)*Num(10.000000)+Binary(X_000)*Num(5.000000)+Binary(X_001)*Num(8.000000)),\n", + " (Binary(X_013)*Num(19.000000)+Binary(X_012)*Num(16.000000)+Binary(X_011)*Num(13.000000)+Binary(X_010)*Num(12.000000)+Binary(X_009)*Num(10.000000)+Binary(X_007)*Num(5.000000)+Binary(X_008)*Num(8.000000)),\n", + " (Binary(X_020)*Num(19.000000)+Binary(X_019)*Num(16.000000)+Binary(X_018)*Num(13.000000)+Binary(X_017)*Num(12.000000)+Binary(X_016)*Num(10.000000)+Binary(X_014)*Num(5.000000)+Binary(X_015)*Num(8.000000)),\n", + " (Binary(X_027)*Num(19.000000)+Binary(X_026)*Num(16.000000)+Binary(X_025)*Num(13.000000)+Binary(X_024)*Num(12.000000)+Binary(X_023)*Num(10.000000)+Binary(X_021)*Num(5.000000)+Binary(X_022)*Num(8.000000)),\n", + " (Binary(X_034)*Num(19.000000)+Binary(X_033)*Num(16.000000)+Binary(X_032)*Num(13.000000)+Binary(X_031)*Num(12.000000)+Binary(X_030)*Num(10.000000)+Binary(X_028)*Num(5.000000)+Binary(X_029)*Num(8.000000)),\n", + " (Binary(X_041)*Num(19.000000)+Binary(X_040)*Num(16.000000)+Binary(X_039)*Num(13.000000)+Binary(X_038)*Num(12.000000)+Binary(X_037)*Num(10.000000)+Binary(X_035)*Num(5.000000)+Binary(X_036)*Num(8.000000)),\n", + " (Binary(X_048)*Num(19.000000)+Binary(X_047)*Num(16.000000)+Binary(X_046)*Num(13.000000)+Binary(X_045)*Num(12.000000)+Binary(X_044)*Num(10.000000)+Binary(X_042)*Num(5.000000)+Binary(X_043)*Num(8.000000))]" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# here, we use a list to represent the sequence of prices from day T-n to day T+n-1.\n", + "\n", + "t = len(a) # next number of days to optimize\n", + "n_level = len(price_levels) # number of price options\n", + "\n", + "x = []\n", + "p = []\n", + "\n", + "# get p\n", + "for i in range(t):\n", + " p_i = 0\n", + " for j in range(n_level):\n", + " x_ij = Binary(f\"X_{i*n_level+j:03d}\")\n", + " x.append(x_ij)\n", + " p_i += x_ij*price_levels[j]\n", + " p.append(p_i)\n", + " \n", + "# plus historical prices\n", + "all_p = p_data + p\n", + "\n", + "all_p" + ] + }, + { + "cell_type": "markdown", + "id": "437d5378", + "metadata": {}, + "source": [ + "Next, we can input the price variables into our fitted model to estimate the demand, and then use the demand together with the price to represent the revenue $R$." + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "71dde625", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Revenue:\n" + ] + }, + { + "data": { + "text/plain": [ + "'(((Binary(X_048)*Num(19.000000)+Binary(X_047)*Num(16.000000)+Binary(X_046)*Num(13.000000)+Binary(X...m(12.000000)+Binary(X_009)*Num(10.000000)+Binary(X_007)*Num(5.000000)+Binary(X_008)*Num(8.000000)))'" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "def get_demand(coeff, b, prices):\n", + " assert len(coeff) == len(prices)\n", + " d = b\n", + " for i in range(len(coeff)):\n", + " d += coeff[i]*prices[i]\n", + "\n", + " return d\n", + "\n", + "# get d, rev\n", + "def get_demands_rev(a,b,hist_p, p):\n", + " \"\"\" represent the next n days demands and total revenue, based on:\n", + " 1. the fitted coefficients a,b\n", + " 2. the historical price hist_p\n", + " 3. and the future price decisions represented by binary variable x\n", + " \"\"\"\n", + " all_p = hist_p + p\n", + " t = len(a)\n", + " d = [get_demand(\n", + " coeff=a,\n", + " b=b,\n", + " prices=all_p[i+1:i+1+t]\n", + " ) for i in range(t)]\n", + " rev = np.dot(d, p)\n", + " return d, rev\n", + "\n", + "d, rev = get_demands_rev(a,b,p_data, p)\n", + "\n", + "print('Revenue:')\n", + "repr_compact.repr(rev)" + ] + }, + { + "cell_type": "markdown", + "id": "88ec1a39", + "metadata": {}, + "source": [ + "## 2.2 Add penalty for prediction uncertainty" + ] + }, + { + "cell_type": "markdown", + "id": "05742984", + "metadata": {}, + "source": [ + "In optimization, we usually desire to reduce the risk while maximizing the reward, which means we want to reduce the estimated uncertainty/variance of the predicted demands. Therefore, we add a penalty term in the objective function to represent the uncertainty of the predicted demand. The uncertainty of the predicted demand $d_t$ can be represented by its estimated variance,\n", + "\n", + "$$H=Revenue-\\beta\\sum_{t=T}^{T+n-1}var(d_t)$$\n", + "\n", + "where $\\beta$ is the regularization parameter to control the effect of risk estimation. The variance of the demand predictions can be estimated as [10]: $$var(d_t)=\\sigma^2(1+\\vec{p}_t'(\\vec{X}'\\vec{X})^{-1}\\vec{p}_t)$$\n", + "\n", + "where $\\vec{p}_t'=[1, p_{t-n+1},p_{t-n+2}, \\ldots,p_{t}]$ is the price vector to estimate demand $d_t$. $\\vec{X}$ are the observations in the training dataset used to fit the demand model, where each row is an observation in the training set.\n", + "\n", + "$$\\vec{X} = \\left[\n", + " \\begin{matrix}\n", + " 1 & p_{0,1} & p_{1,1} & \\dots & p_{n-1,1}\\\\\n", + " 1 & p_{0,2} & p_{1,2} & \\dots & p_{n-1,2}\\\\\n", + " \\vdots& \\vdots& \\vdots&& \\vdots\\\\\n", + " 1 & p_{0,N}& p_{1,N}& \\dots& p_{n-1,N}\n", + " \\end{matrix}\\right].$$" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "id": "6c3d500e", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Objective with expected revenue and prediction variance:\n" + ] + }, + { + "data": { + "text/plain": [ + "'((((Binary(X_048)*Num(19.000000)+Binary(X_047)*Num(16.000000)+Binary(X_046)*Num(13.000000)+Binary(...X_001)*Num(8.000000))*Num(-0.000535)+Num(0.016381))+Num(1.000000))*Num(100.000000))*Num(-1.000000))'" + ] + }, + "execution_count": 10, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "beta=1.\n", + "\n", + "def get_variance(data_x, p, sigma):\n", + " \"\"\"\n", + " :param data_x (np.array): [n_samples, n_days]\n", + " :param p (list): [n_days]\n", + " :return: variance\n", + " \"\"\"\n", + " n_samples, t = data_x.shape\n", + " ones = np.ones((n_samples, 1), dtype=np.float)\n", + " x_mat = np.concatenate([ones, data_x], axis=1) # [n_samples, n_days+1]\n", + " x_mat = np.linalg.inv(\n", + " np.dot(x_mat.T, x_mat)\n", + " )\n", + " p = np.array([1.]+p)\n", + " variance = (sigma**2) * (1. + p.dot(x_mat).dot(p))\n", + " return variance\n", + "\n", + "def get_overall_variance(data_x, hist_p, p, sigma):\n", + " all_p = hist_p + p\n", + " t = len(p)\n", + " var = 0\n", + " for i in range(t):\n", + " var += get_variance(data_x, all_p[i+1:i+1+t], sigma)\n", + "\n", + " return var\n", + "\n", + "objective = rev - beta * get_overall_variance(data_x, p_data, p, sigma)\n", + "\n", + "print('Objective with expected revenue and prediction variance:')\n", + "repr_compact.repr(objective)" + ] + }, + { + "cell_type": "markdown", + "id": "52a8d37f", + "metadata": {}, + "source": [ + "## 2.3 Add penalty for equality constraints" + ] + }, + { + "cell_type": "markdown", + "id": "0a92e9af", + "metadata": {}, + "source": [ + "Since the price can only take one value per day, exactly one of the binary variables in a day must be $1$, and the others must be $0$. Formallly, we have equality constraints:\n", + "$$\\sum_{k=0}^{m-1}x_{t,k}=1, \\;t\\in[T, T+1, \\cdots, T+n-1]$$\n", + "\n", + "We can easily incorporate this equality constraint into the objective function by substracting a penalty term $H_p$ with large enough coefficient $L_p$. If the solution satisfies these constraints, the penalty term will be 0, otherwise a large penalty will be imposed.\n", + "\n", + "$$H_p=L_p\\sum_{t=T}^{t=T+n-1}[(\\sum_{k=0}^{m-1}x_{t,k})-1]^{2}$$" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "id": "96c8c9be", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Objective with additional equality constraints:\n" + ] + }, + { + "data": { + "text/plain": [ + "'(((((((((((Binary(X_048)*Num(19.000000)+Binary(X_047)*Num(16.000000)+Binary(X_046)*Num(13.000000)+...nary(X_044)+Binary(X_042)+Binary(X_043))+Num(-1.000000))*Num(10000000000000.000000)*Num(-1.000000))'" + ] + }, + "execution_count": 11, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# add equalty constraints\n", + "Lp=1e13\n", + "\n", + "for i in range(t):\n", + " penalty_i = ((sum(x[i*n_level:(i+1)*n_level]) - 1)**2)*Lp\n", + " objective -= penalty_i\n", + " \n", + "print('Objective with additional equality constraints:')\n", + "repr_compact.repr(objective)" + ] + }, + { + "cell_type": "markdown", + "id": "6fbf2237", + "metadata": {}, + "source": [ + "# 3. Solve QUBO with Braket" + ] + }, + { + "cell_type": "markdown", + "id": "9edaa67f", + "metadata": {}, + "source": [ + "Now we have transformed to the total objective function which:\n", + "- maximizes the revenue \n", + "- minimizes the prediction uncertainty \n", + "- incorporates equality constraints, $\\sum_{k=0}^{m-1}x_{t,k}=1, \\;t\\in[T, T+1, \\cdots, T+n-1]$ \n", + "\n", + "$$H=Revenue-\\beta\\sum_{t=T}^{T+n-1}var(d_t) - H_p $$\n", + "where $H_p=L_p\\sum_{t=T}^{t=T+n-1}[(\\sum_{k=0}^{m-1}x_{t,k})-1]^{2} $ is the penalty term for price equality constraints, and $L_p$ is a constant.\n", + "\n", + "We can transform this objective function to binary quadratic model, and solve it using Amazon Braket." + ] + }, + { + "cell_type": "markdown", + "id": "2547ec98", + "metadata": {}, + "source": [ + "Amazon Braket provides access to quantum annealers from D-Wave Systems Inc. which are specifically designed to solve QUBO problems. A quantum annealer is a hardware implementation of Quantum Annealing (QA) which is a generic algorithm to solve combinatorial optimization problems by taking advantage of quantum fluctuations to escape local minima in complex energy landscapes by effect of tunnelling through barriers separating local minima [5]. Through a simple Amazon Braket API call, the formatted QUBO problem can be embedded to the hardwired topology of the machine and submitted to machine. In turn, the quantum annealer performs an annealing process and obtains a result. However, because of the sparsity of the underlying chip, one typically faces a certain overhead in embedding the original QUBO problem to the D-Wave hardware, because (typically) one logical binary variable maps onto several physical qubits, in order to effectively distill the connectivity of the original QUBO problem. For more details, we refer to the Amazon Braket tutorial notebook available here (https://github.com/aws/amazon-braket-examples/blob/main/examples/quantum_annealing/Dwave_Anatomy.ipynb)." + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "id": "fdfe3dce", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "\"BinaryQuadraticModel({X_005: -10000000002744.719, X_030: -10000000002576.855, X_036: -100000000021...', 'X_026'): 572.3665512211251, ('X_026', 'X_013'): 906.2470394334479}, 70000000000715.1, 'BINARY')\"" + ] + }, + "execution_count": 12, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "model = (-objective).compile().to_bqm()\n", + "\n", + "repr_compact.repr(model)" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "id": "54a70c81", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "49" + ] + }, + "execution_count": 13, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "len(model)" + ] + }, + { + "cell_type": "markdown", + "id": "f149c413", + "metadata": {}, + "source": [ + "We embed and submit the QUBO task to be solved by a quantum annealer at D-wave backend. Similar to classical simulated annealing, we take several independent shots in order to increase our chances for success in finding a high-quality solution to the QUBO problem. The response contains a number of rows. Each row represents the optimization result of a single shot, including the binary decision variables $[x_T,\\cdots,x_{T+n-1}]$, and corresponding energy which is the negative value of objective function, i.e. $H$. Below we show how to submit a QUBO problem to D-Wave and provide a sample response. Here, the key figure of merit is listed in the column labelled with energy, representing the value for the objective function . We can then easily read off the best bit string found.\n", + "\n", + "Each row represents an optimized solution. The columns starting with `X_` show the value of the binary decision variables $x_{t,k}$ and the `energy` column shows the negative value of the objective function, i.e. $-H$" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "id": "b762f1e9", + "metadata": { + "scrolled": true + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
X_000X_001X_002X_003X_004X_005X_006X_007X_008X_009...X_040X_041X_042X_043X_044X_045X_046X_047X_048energy
760000100000...010000001-12752.164062
9140010000001...010000001-12602.234375
13310000100000...000000001-12597.156250
770000100000...000000001-12589.992188
780000100000...000000001-12555.671875
\n", + "

5 rows × 50 columns

\n", + "
" + ], + "text/plain": [ + " X_000 X_001 X_002 X_003 X_004 X_005 X_006 X_007 X_008 X_009 \\\n", + "76 0 0 0 0 1 0 0 0 0 0 \n", + "914 0 0 1 0 0 0 0 0 0 1 \n", + "1331 0 0 0 0 1 0 0 0 0 0 \n", + "77 0 0 0 0 1 0 0 0 0 0 \n", + "78 0 0 0 0 1 0 0 0 0 0 \n", + "\n", + " ... X_040 X_041 X_042 X_043 X_044 X_045 X_046 X_047 X_048 \\\n", + "76 ... 0 1 0 0 0 0 0 0 1 \n", + "914 ... 0 1 0 0 0 0 0 0 1 \n", + "1331 ... 0 0 0 0 0 0 0 0 1 \n", + "77 ... 0 0 0 0 0 0 0 0 1 \n", + "78 ... 0 0 0 0 0 0 0 0 1 \n", + "\n", + " energy \n", + "76 -12752.164062 \n", + "914 -12602.234375 \n", + "1331 -12597.156250 \n", + "77 -12589.992188 \n", + "78 -12555.671875 \n", + "\n", + "[5 rows x 50 columns]" + ] + }, + "execution_count": 15, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "## run dwave quantum annealing\n", + "num_shots = 10000\n", + "\n", + "sampler = BraketDWaveSampler(s3_folder,'arn:aws:braket:::device/qpu/d-wave/Advantage_system4')\n", + "sampler = EmbeddingComposite(sampler)\n", + "response = sampler.sample(model, num_reads=num_shots)\n", + "\n", + "# print results\n", + "results_df = response.to_pandas_dataframe()\n", + "results_columns = results_df.columns[results_df.columns.str.startswith('X_')].tolist()\n", + "results_columns += ['energy']\n", + "\n", + "results_df[results_columns].sort_values('energy').head()" + ] + }, + { + "cell_type": "markdown", + "id": "ec86a64d", + "metadata": {}, + "source": [ + "## 3.1 Evaluate the results" + ] + }, + { + "cell_type": "markdown", + "id": "0fb4bbfb", + "metadata": {}, + "source": [ + "With the response, we can decode the binary array results into the optimal price results" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "id": "43d94f12", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "([13, 13, 12, 5, 10, 19, 19],\n", + " array([0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1,\n", + " 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0,\n", + " 0, 0, 0, 0, 1], dtype=int8),\n", + " -12752.1640625)" + ] + }, + "execution_count": 16, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "def decoder_price_response(response, n_days, price_options):\n", + " opt_price, energy = response.record.sample[response.record.energy.argmin()], response.record.energy.min()\n", + " prices = []\n", + " for i in range(n_days):\n", + " price_i = opt_price[i*len(price_options): (i+1)*len(price_options)]\n", + " assert price_i.sum()==1\n", + " prices.append(price_options[price_i.argmax()])\n", + " return prices, opt_price, energy\n", + "\n", + "opt_decoded_prices, opt_prices, energy =decoder_price_response(response, len(a), price_levels)\n", + "\n", + "opt_decoded_prices, opt_prices, energy" + ] + }, + { + "cell_type": "markdown", + "id": "43a86a5e", + "metadata": {}, + "source": [ + "The optimized price path and corresponding demand curve are plotted below, respectively. The optimal price level is higher than the past 7 days, which results in the demand decreasing." + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "id": "efa123fb", + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "plt.rcParams.update({'font.size': 18})\n", + "plt.figure(figsize=(10,8))\n", + "plt.plot(range(1,8),opt_decoded_prices)\n", + "plt.xlabel('Day')\n", + "plt.ylabel('Price ($)')\n", + "plt.savefig('price_path.png')" + ] + }, + { + "cell_type": "markdown", + "id": "6342fa6d", + "metadata": {}, + "source": [ + "Let's also calculate the total revenue, and plot the demand of each day." + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "id": "ce8ec494", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "([182.33668654152052,\n", + " 161.75101851993844,\n", + " 148.9134817833946,\n", + " 165.47394138330202,\n", + " 167.4983113772031,\n", + " 138.92967848592662,\n", + " 108.20132675236677],\n", + " 13457.943867415815)" + ] + }, + "execution_count": 18, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "opt_d, max_rev = get_demands_rev(a,b,p_data, opt_decoded_prices)\n", + "\n", + "opt_d, max_rev" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "id": "0e621ea0", + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "plt.rcParams.update({'font.size': 18})\n", + "plt.figure(figsize=(10,8))\n", + "plt.plot(range(1,8),opt_d)\n", + "plt.xlabel('Day')\n", + "plt.ylabel('Demand')\n", + "plt.savefig('demand_path.png')" + ] + }, + { + "cell_type": "markdown", + "id": "fa79da19", + "metadata": {}, + "source": [ + "Finally, let's get the overall uncertainty of the demand predictions. Here we simply use the estimated demand variance to indicate the uncertainty." + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "id": "169d083b", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "705.7816180128258" + ] + }, + "execution_count": 20, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "overall_variance = get_overall_variance(data_x, p_data, opt_decoded_prices, sigma)\n", + "\n", + "overall_variance" + ] + }, + { + "cell_type": "markdown", + "id": "0fb60623", + "metadata": {}, + "source": [ + "__We can also derive the standard deviation of the revenue based on the variance of demand__\n", + "\n", + "$$std(R)=\\sqrt{(\\sum_{t=T}^{T+n-1}var(\\hat{d}_t)*p_t^2) + \\sum_{t_1, t_2\\in [T,\\ldots,T+n-1] \\\\ t_1!=t_2}2p_{t_1}p_{t_2}cov(\\hat{d}_{t_1} \\hat{d}_{t_2}) }$$" + ] + }, + { + "cell_type": "markdown", + "id": "ea9d6a49", + "metadata": {}, + "source": [ + "where $cov(\\hat{d}_{t_1} \\hat{d}_{t_2}) = \\sigma^2(1+\\vec{p}_{t_1}'(\\vec{X}'\\vec{X})^{-1}\\vec{p}_{t_2})$" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "id": "b916ae54", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "911.7464747275401" + ] + }, + "execution_count": 21, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "def get_covariance(data_x, p1, p2, sigma):\n", + " \"\"\"\n", + " :param data_x (np.array): [n_samples, n_days]\n", + " :param p1, p2 (list): [n_days]\n", + " :return: variance\n", + " \"\"\"\n", + " n_samples, t = data_x.shape\n", + " ones = np.ones((n_samples, 1), dtype=np.float)\n", + " x_mat = np.concatenate([ones, data_x], axis=1) # [n_samples, n_days+1]\n", + " x_mat = np.linalg.inv(\n", + " np.dot(x_mat.T, x_mat)\n", + " )\n", + " p1 = np.array([1.] + p1)\n", + " p2 = np.array([1.] + p2)\n", + " variance = (sigma**2) * (1. + p1.dot(x_mat).dot(p2))\n", + " return variance\n", + "\n", + "def get_overall_revenue_variance(data_x, hist_p, p, sigma):\n", + " all_p = hist_p + p\n", + " t = len(p)\n", + " var = sum([get_variance(data_x, all_p[i+1:i+1+t], sigma) * (p[i]**2) for i in range(t)])\n", + " \n", + " # add covariance\n", + " var += sum([\n", + " get_covariance(\n", + " data_x,\n", + " all_p[i + 1:i + 1 + t],\n", + " all_p[j + 1:j + 1 + t],\n", + " sigma\n", + " ) * 2 * p[i] * p[j] for i, j in combinations(list(range(t)), 2) \n", + " ])\n", + "\n", + " return var\n", + "\n", + "revenue_variance = get_overall_revenue_variance(data_x, p_data, opt_decoded_prices, sigma)\n", + "\n", + "np.sqrt(revenue_variance)" + ] + }, + { + "cell_type": "markdown", + "id": "c2340e8b", + "metadata": {}, + "source": [ + "We can investigate the value of the penality terms to see if any equality constraints are violated. The penalty is close to zero showing that all the constraints are satisfied. This small but non-zero value is due to floating point precision." + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "id": "8cc64429", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "-0.0018130970111087663" + ] + }, + "execution_count": 22, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "penalty = max_rev - beta*overall_variance + energy\n", + "\n", + "penalty" + ] + }, + { + "cell_type": "markdown", + "id": "f8ca8c97", + "metadata": {}, + "source": [ + "For comparison, to assess the quality of this optimized result, we also iterate (by brute-force search) through all the $7^7=823,543$ possible price solutions to obtain the energy for each one, which takes more than 5 minutes to run on a standard ml.m5.2xlarge AWS instance. We plot the distribution of the energies of all the 823,543 possible solutions as shown below, where the red line represents our optimized result obtained from the quantum annealer. We can see that although the optimized result from the quantum annealer is not the global optimum with minimum cost, it is close-to-optimal and of good quality. " + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "id": "0bed907a", + "metadata": { + "scrolled": true + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "0\n", + "1000\n", + "2000\n", + "3000\n", + "4000\n", + "5000\n", + "6000\n", + "7000\n", + "8000\n", + "9000\n", + "10000\n", + "11000\n", + "12000\n", + "13000\n", + "14000\n", + "15000\n", + "16000\n", + "17000\n", + "18000\n", + "19000\n", + "20000\n", + "21000\n", + "22000\n", + "23000\n", + "24000\n", + "25000\n", + "26000\n", + "27000\n", + "28000\n", + "29000\n", + "30000\n", + "31000\n", + "32000\n", + "33000\n", + "34000\n", + "35000\n", + "36000\n", + "37000\n", + "38000\n", + "39000\n", + "40000\n", + "41000\n", + "42000\n", + "43000\n", + "44000\n", + "45000\n", + "46000\n", + "47000\n", + "48000\n", + "49000\n", + "50000\n", + "51000\n", + "52000\n", + "53000\n", + "54000\n", + "55000\n", + "56000\n", + "57000\n", + "58000\n", + "59000\n", + "60000\n", + "61000\n", + "62000\n", + "63000\n", + "64000\n", + "65000\n", + "66000\n", + "67000\n", + "68000\n", + "69000\n", + "70000\n", + "71000\n", + "72000\n", + "73000\n", + "74000\n", + "75000\n", + "76000\n", + "77000\n", + "78000\n", + "79000\n", + "80000\n", + "81000\n", + "82000\n", + "83000\n", + "84000\n", + "85000\n", + "86000\n", + "87000\n", + "88000\n", + "89000\n", + "90000\n", + "91000\n", + "92000\n", + "93000\n", + "94000\n", + "95000\n", + "96000\n", + "97000\n", + "98000\n", + "99000\n", + "100000\n", + "101000\n", + "102000\n", + "103000\n", + "104000\n", + "105000\n", + "106000\n", + "107000\n", + "108000\n", + "109000\n", + "110000\n", + "111000\n", + "112000\n", + "113000\n", + "114000\n", + "115000\n", + "116000\n", + "117000\n", + "118000\n", + "119000\n", + "120000\n", + "121000\n", + "122000\n", + "123000\n", + "124000\n", + "125000\n", + "126000\n", + "127000\n", + "128000\n", + "129000\n", + "130000\n", + "131000\n", + "132000\n", + "133000\n", + "134000\n", + "135000\n", + "136000\n", + "137000\n", + "138000\n", + "139000\n", + "140000\n", + "141000\n", + "142000\n", + "143000\n", + "144000\n", + "145000\n", + "146000\n", + "147000\n", + "148000\n", + "149000\n", + "150000\n", + "151000\n", + "152000\n", + "153000\n", + "154000\n", + "155000\n", + "156000\n", + "157000\n", + "158000\n", + "159000\n", + "160000\n", + "161000\n", + "162000\n", + "163000\n", + "164000\n", + "165000\n", + "166000\n", + "167000\n", + "168000\n", + "169000\n", + "170000\n", + "171000\n", + "172000\n", + "173000\n", + "174000\n", + "175000\n", + "176000\n", + "177000\n", + "178000\n", + "179000\n", + "180000\n", + "181000\n", + "182000\n", + "183000\n", + "184000\n", + "185000\n", + "186000\n", + "187000\n", + "188000\n", + "189000\n", + "190000\n", + "191000\n", + "192000\n", + "193000\n", + "194000\n", + "195000\n", + "196000\n", + "197000\n", + "198000\n", + "199000\n", + "200000\n", + "201000\n", + "202000\n", + "203000\n", + "204000\n", + "205000\n", + "206000\n", + "207000\n", + "208000\n", + "209000\n", + "210000\n", + "211000\n", + "212000\n", + "213000\n", + "214000\n", + "215000\n", + "216000\n", + "217000\n", + "218000\n", + "219000\n", + "220000\n", + "221000\n", + "222000\n", + "223000\n", + "224000\n", + "225000\n", + "226000\n", + "227000\n", + "228000\n", + "229000\n", + "230000\n", + "231000\n", + "232000\n", + "233000\n", + "234000\n", + "235000\n", + "236000\n", + "237000\n", + "238000\n", + "239000\n", + "240000\n", + "241000\n", + "242000\n", + "243000\n", + "244000\n", + "245000\n", + "246000\n", + "247000\n", + "248000\n", + "249000\n", + "250000\n", + "251000\n", + "252000\n", + "253000\n", + "254000\n", + "255000\n", + "256000\n", + "257000\n", + "258000\n", + "259000\n", + "260000\n", + "261000\n", + "262000\n", + "263000\n", + "264000\n", + "265000\n", + "266000\n", + "267000\n", + "268000\n", + "269000\n", + "270000\n", + "271000\n", + "272000\n", + "273000\n", + "274000\n", + "275000\n", + "276000\n", + "277000\n", + "278000\n", + "279000\n", + "280000\n", + "281000\n", + "282000\n", + "283000\n", + "284000\n", + "285000\n", + "286000\n", + "287000\n", + "288000\n", + "289000\n", + "290000\n", + "291000\n", + "292000\n", + "293000\n", + "294000\n", + "295000\n", + "296000\n", + "297000\n", + "298000\n", + "299000\n", + "300000\n", + "301000\n", + "302000\n", + "303000\n", + "304000\n", + "305000\n", + "306000\n", + "307000\n", + "308000\n", + "309000\n", + "310000\n", + "311000\n", + "312000\n", + "313000\n", + "314000\n", + "315000\n", + "316000\n", + "317000\n", + "318000\n", + "319000\n", + "320000\n", + "321000\n", + "322000\n", + "323000\n", + "324000\n", + "325000\n", + "326000\n", + "327000\n", + "328000\n", + "329000\n", + "330000\n", + "331000\n", + "332000\n", + "333000\n", + "334000\n", + "335000\n", + "336000\n", + "337000\n", + "338000\n", + "339000\n", + "340000\n", + "341000\n", + "342000\n", + "343000\n", + "344000\n", + "345000\n", + "346000\n", + "347000\n", + "348000\n", + "349000\n", + "350000\n", + "351000\n", + "352000\n", + "353000\n", + "354000\n", + "355000\n", + "356000\n", + "357000\n", + "358000\n", + "359000\n", + "360000\n", + "361000\n", + "362000\n", + "363000\n", + "364000\n", + "365000\n", + "366000\n", + "367000\n", + "368000\n", + "369000\n", + "370000\n", + "371000\n", + "372000\n", + "373000\n", + "374000\n", + "375000\n", + "376000\n", + "377000\n", + "378000\n", + "379000\n", + "380000\n", + "381000\n", + "382000\n", + "383000\n", + "384000\n", + "385000\n", + "386000\n", + "387000\n", + "388000\n", + "389000\n", + "390000\n", + "391000\n", + "392000\n", + "393000\n", + "394000\n", + "395000\n", + "396000\n", + "397000\n", + "398000\n", + "399000\n", + "400000\n", + "401000\n", + "402000\n", + "403000\n", + "404000\n", + "405000\n", + "406000\n", + "407000\n", + "408000\n", + "409000\n", + "410000\n", + "411000\n", + "412000\n", + "413000\n", + "414000\n", + "415000\n", + "416000\n", + "417000\n", + "418000\n", + "419000\n", + "420000\n", + "421000\n", + "422000\n", + "423000\n", + "424000\n", + "425000\n", + "426000\n", + "427000\n", + "428000\n", + "429000\n", + "430000\n", + "431000\n", + "432000\n", + "433000\n", + "434000\n", + "435000\n", + "436000\n", + "437000\n", + "438000\n", + "439000\n", + "440000\n", + "441000\n", + "442000\n", + "443000\n", + "444000\n", + "445000\n", + "446000\n", + "447000\n", + "448000\n", + "449000\n", + "450000\n", + "451000\n", + "452000\n", + "453000\n", + "454000\n", + "455000\n", + "456000\n", + "457000\n", + "458000\n", + "459000\n", + "460000\n", + "461000\n", + "462000\n", + "463000\n", + "464000\n", + "465000\n", + "466000\n", + "467000\n", + "468000\n", + "469000\n", + "470000\n", + "471000\n", + "472000\n", + "473000\n", + "474000\n", + "475000\n", + "476000\n", + "477000\n", + "478000\n", + "479000\n", + "480000\n", + "481000\n", + "482000\n", + "483000\n", + "484000\n", + "485000\n", + "486000\n", + "487000\n", + "488000\n", + "489000\n", + "490000\n", + "491000\n", + "492000\n", + "493000\n", + "494000\n", + "495000\n", + "496000\n", + "497000\n", + "498000\n", + "499000\n", + "500000\n", + "501000\n", + "502000\n", + "503000\n", + "504000\n", + "505000\n", + "506000\n", + "507000\n", + "508000\n", + "509000\n", + "510000\n", + "511000\n", + "512000\n", + "513000\n", + "514000\n", + "515000\n", + "516000\n", + "517000\n", + "518000\n", + "519000\n", + "520000\n", + "521000\n", + "522000\n", + "523000\n", + "524000\n", + "525000\n", + "526000\n", + "527000\n", + "528000\n", + "529000\n", + "530000\n", + "531000\n", + "532000\n", + "533000\n", + "534000\n", + "535000\n", + "536000\n", + "537000\n", + "538000\n", + "539000\n", + "540000\n", + "541000\n", + "542000\n", + "543000\n", + "544000\n", + "545000\n", + "546000\n", + "547000\n", + "548000\n", + "549000\n", + "550000\n", + "551000\n", + "552000\n", + "553000\n", + "554000\n", + "555000\n", + "556000\n", + "557000\n", + "558000\n", + "559000\n", + "560000\n", + "561000\n", + "562000\n", + "563000\n", + "564000\n", + "565000\n", + "566000\n", + "567000\n", + "568000\n", + "569000\n", + "570000\n", + "571000\n", + "572000\n", + "573000\n", + "574000\n", + "575000\n", + "576000\n", + "577000\n", + "578000\n", + "579000\n", + "580000\n", + "581000\n", + "582000\n", + "583000\n", + "584000\n", + "585000\n", + "586000\n", + "587000\n", + "588000\n", + "589000\n", + "590000\n", + "591000\n", + "592000\n", + "593000\n", + "594000\n", + "595000\n", + "596000\n", + "597000\n", + "598000\n", + "599000\n", + "600000\n", + "601000\n", + "602000\n", + "603000\n", + "604000\n", + "605000\n", + "606000\n", + "607000\n", + "608000\n", + "609000\n", + "610000\n", + "611000\n", + "612000\n", + "613000\n", + "614000\n", + "615000\n", + "616000\n", + "617000\n", + "618000\n", + "619000\n", + "620000\n", + "621000\n", + "622000\n", + "623000\n", + "624000\n", + "625000\n", + "626000\n", + "627000\n", + "628000\n", + "629000\n", + "630000\n", + "631000\n", + "632000\n", + "633000\n", + "634000\n", + "635000\n", + "636000\n", + "637000\n", + "638000\n", + "639000\n", + "640000\n", + "641000\n", + "642000\n", + "643000\n", + "644000\n", + "645000\n", + "646000\n", + "647000\n", + "648000\n", + "649000\n", + "650000\n", + "651000\n", + "652000\n", + "653000\n", + "654000\n", + "655000\n", + "656000\n", + "657000\n", + "658000\n", + "659000\n", + "660000\n", + "661000\n", + "662000\n", + "663000\n", + "664000\n", + "665000\n", + "666000\n", + "667000\n", + "668000\n", + "669000\n", + "670000\n", + "671000\n", + "672000\n", + "673000\n", + "674000\n", + "675000\n", + "676000\n", + "677000\n", + "678000\n", + "679000\n", + "680000\n", + "681000\n", + "682000\n", + "683000\n", + "684000\n", + "685000\n", + "686000\n", + "687000\n", + "688000\n", + "689000\n", + "690000\n", + "691000\n", + "692000\n", + "693000\n", + "694000\n", + "695000\n", + "696000\n", + "697000\n", + "698000\n", + "699000\n", + "700000\n", + "701000\n", + "702000\n", + "703000\n", + "704000\n", + "705000\n", + "706000\n", + "707000\n", + "708000\n", + "709000\n", + "710000\n", + "711000\n", + "712000\n", + "713000\n", + "714000\n", + "715000\n", + "716000\n", + "717000\n", + "718000\n", + "719000\n", + "720000\n", + "721000\n", + "722000\n", + "723000\n", + "724000\n", + "725000\n", + "726000\n", + "727000\n", + "728000\n", + "729000\n", + "730000\n", + "731000\n", + "732000\n", + "733000\n", + "734000\n", + "735000\n", + "736000\n", + "737000\n", + "738000\n", + "739000\n", + "740000\n", + "741000\n", + "742000\n", + "743000\n", + "744000\n", + "745000\n", + "746000\n", + "747000\n", + "748000\n", + "749000\n", + "750000\n", + "751000\n", + "752000\n", + "753000\n", + "754000\n", + "755000\n", + "756000\n", + "757000\n", + "758000\n", + "759000\n", + "760000\n", + "761000\n", + "762000\n", + "763000\n", + "764000\n", + "765000\n", + "766000\n", + "767000\n", + "768000\n", + "769000\n", + "770000\n", + "771000\n", + "772000\n", + "773000\n", + "774000\n", + "775000\n", + "776000\n", + "777000\n", + "778000\n", + "779000\n", + "780000\n", + "781000\n", + "782000\n", + "783000\n", + "784000\n", + "785000\n", + "786000\n", + "787000\n", + "788000\n", + "789000\n", + "790000\n", + "791000\n", + "792000\n", + "793000\n", + "794000\n", + "795000\n", + "796000\n", + "797000\n", + "798000\n", + "799000\n", + "800000\n", + "801000\n", + "802000\n", + "803000\n", + "804000\n", + "805000\n", + "806000\n", + "807000\n", + "808000\n", + "809000\n", + "810000\n", + "811000\n", + "812000\n", + "813000\n", + "814000\n", + "815000\n", + "816000\n", + "817000\n", + "818000\n", + "819000\n", + "820000\n", + "821000\n", + "822000\n", + "823000\n" + ] + } + ], + "source": [ + "all_rev=[]\n", + "all_var=[]\n", + "all_energy=[]\n", + "i=0\n", + "\n", + "for p_t1 in price_levels:\n", + " for p_t2 in price_levels:\n", + " for p_t3 in price_levels:\n", + " for p_t4 in price_levels:\n", + " for p_t5 in price_levels:\n", + " for p_t6 in price_levels:\n", + " for p_t7 in price_levels:\n", + " if i%1000==0:\n", + " print(i)\n", + " \n", + " _, sample_rev = get_demands_rev(a,b,p_data, [p_t1,p_t2,p_t3,p_t4,p_t5,p_t6,p_t7])\n", + " sample_overall_variance = get_overall_variance(data_x, p_data, [p_t1,p_t2,p_t3,p_t4,p_t5,p_t6,p_t7], sigma)\n", + " all_rev.append(sample_rev)\n", + " all_var.append(sample_overall_variance)\n", + " all_energy.append(-(sample_rev-beta*sample_overall_variance))\n", + " i+=1" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "id": "c218c92f", + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "plt.rcParams.update({'font.size': 18})\n", + "plt.figure(figsize=(10,8))\n", + "plt.vlines(energy,0,125000, 'r')\n", + "plt.hist(all_energy,20)\n", + "plt.xlabel('Energy distribution of all possible solutions')\n", + "plt.ylabel('Frequency')\n", + "plt.savefig('result_quality.png')" + ] + }, + { + "cell_type": "markdown", + "id": "f5089d50", + "metadata": {}, + "source": [ + "# 4. Trade-off between expected revenue and prediction uncertainty." + ] + }, + { + "cell_type": "markdown", + "id": "85862da0", + "metadata": {}, + "source": [ + "Let's first wrap the above price optimization into a single optimize function for convenience." + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "id": "36b838f3", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "(13362.364731002446,\n", + " 706.7208258596746,\n", + " -12655.6484375,\n", + " [185.94625963144793,\n", + " 154.15604720656478,\n", + " 167.46543979322945,\n", + " 155.9292482281557,\n", + " 160.514740479689,\n", + " 130.2613846464788,\n", + " 98.73268259663321],\n", + " [12, 16, 5, 12, 10, 19, 19],\n", + " 931.8876101527734)" + ] + }, + "execution_count": 25, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "Ld=1e6\n", + "\n", + "max_revenue, prediction_variance, energy, opt_demand, opt_prices, rev_std = optimize(\n", + " a = a,\n", + " b = b,\n", + " data_x = data_x,\n", + " selected_hist_prices = p_data,\n", + " price_levels = price_levels,\n", + " Lp = Lp,\n", + " Ld = Ld,\n", + " sigma = sigma ,\n", + " beta=beta,\n", + " vol_bound=None,\n", + " s3_folder=s3_folder\n", + ")\n", + "\n", + "max_revenue, prediction_variance, energy, opt_demand, opt_prices, rev_std" + ] + }, + { + "cell_type": "markdown", + "id": "5b8efe22", + "metadata": {}, + "source": [ + "In order to investigate the trade-off between the expected revenue and prediction uncertainties, we vary the hyperparameter $\\beta$ within a large range of $[1e2,1e9]$ and run multiple experiments on D-Wave with different $\\beta$ values. The scatter plot is shown below, where each dot represents the optimized result of an experiment with x-axis representing its expected revenue and y-axis representing the estimated standard deviation of revenue $std(R)$." + ] + }, + { + "cell_type": "markdown", + "id": "1e11af8f", + "metadata": {}, + "source": [ + "
\n", + "Caution: Running the following cell will run a substantial amount of tasks for various senarios taking about 30 minutes. Only uncomment it if you are happy to wait.\n", + "
" + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "id": "a047a433", + "metadata": { + "scrolled": true + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "---\n", + "beta_sample:100.0\n", + "max_revenue:13142.782268581876\n", + "prediction_variance:703.5502036738326\n", + "energy:57212.2421875\n", + "opt_demand:[182.33668654152052, 179.79888396957557, 165.08222156543758, 155.1378810016535, 155.08534332330055, 154.92897272299166, 125.8542042377626]\n", + "opt_prices:[13, 8, 12, 12, 10, 10, 19]\n", + "rev_std: 840.9865848076566\n", + "penalty_term: 0.004088698617124464\n", + "---\n", + "beta_sample:1000.0\n", + "max_revenue:13198.22244328534\n", + "prediction_variance:702.9415585415351\n", + "energy:689743.3359375\n", + "opt_demand:[193.16540581130278, 182.28098165894653, 163.96372331139906, 159.28485931053694, 157.1272228349854, 151.58799858923842, 122.5817558425566]\n", + "opt_prices:[10, 10, 13, 10, 10, 12, 19]\n", + "rev_std: 841.0012457923974\n", + "penalty_term: -0.0001607497688382864\n", + "---\n", + "beta_sample:10000.0\n", + "max_revenue:11976.233040996605\n", + "prediction_variance:702.6893930180825\n", + "energy:7014917.6953125\n", + "opt_demand:[185.94625963144793, 183.03263192598416, 182.506704174716, 195.38453798497142, 183.33048747152048, 185.3349129647881, 166.23041487017076]\n", + "opt_prices:[12, 8, 8, 5, 12, 8, 13]\n", + "rev_std: 660.4930504735115\n", + "penalty_term: -0.0018273275345563889\n", + "---\n", + "beta_sample:100000.0\n", + "max_revenue:11515.07074768842\n", + "prediction_variance:701.8849560662594\n", + "energy:70176980.5390625\n", + "opt_demand:[193.16540581130278, 182.28098165894653, 182.0115887610362, 175.45359909257996, 172.05817408282888, 161.81126623019608, 177.53224727623964]\n", + "opt_prices:[10, 10, 8, 10, 10, 12, 5]\n", + "rev_std: 650.464648418367\n", + "penalty_term: 0.0031842440366744995\n", + "---\n", + "beta_sample:1000000.0\n", + "max_revenue:11984.699124804318\n", + "prediction_variance:701.8939938693518\n", + "energy:701882009.171875\n", + "opt_demand:[193.16540581130278, 189.5001278388014, 181.2599384939985, 167.73933749904532, 170.9267509071122, 167.20280803722733, 167.21305214231802]\n", + "opt_prices:[10, 8, 10, 12, 8, 10, 10]\n", + "rev_std: 680.4924545774593\n", + "penalty_term: 0.0016480684280395508\n", + "---\n", + "beta_sample:10000000.0\n", + "max_revenue:12282.115767083424\n", + "prediction_variance:702.0784098201561\n", + "energy:7020771816.0859375\n", + "opt_demand:[193.16540581130278, 189.5001278388014, 188.47908467385338, 181.42597959171735, 165.3187618694297, 153.8766096308499, 151.67049930792007]\n", + "opt_prices:[10, 8, 8, 10, 13, 12, 10]\n", + "rev_std: 710.5669426766799\n", + "penalty_term: 0.00014400482177734375\n", + "---\n", + "beta_sample:100000000.0\n", + "max_revenue:12241.871304610453\n", + "prediction_variance:702.0141973826334\n", + "energy:70201407496.40625\n", + "opt_demand:[200.38455199115765, 188.74847757176371, 180.7648230803187, 173.07541023614584, 157.0236615837889, 163.60369589432054, 155.23088433792412]\n", + "opt_prices:[8, 10, 10, 10, 13, 8, 12]\n", + "rev_std: 710.5717716766972\n", + "penalty_term: 0.01422119140625\n", + "---\n", + "beta_sample:1000000000.0\n", + "max_revenue:11607.35132521147\n", + "prediction_variance:702.3039204704776\n", + "energy:702303908863.1328\n", + "opt_demand:[193.16540581130278, 189.5001278388014, 174.04079231414366, 168.49098776608298, 153.37400087115492, 152.91714169793863, 172.6526861306151]\n", + "opt_prices:[10, 8, 12, 10, 13, 10, 5]\n", + "rev_std: 680.5670317172533\n", + "penalty_term: 0.006591796875\n", + "---\n", + "beta_sample:100.0\n", + "max_revenue:13308.789275999401\n", + "prediction_variance:704.4245606588714\n", + "energy:57133.6640625\n", + "opt_demand:[182.33668654152052, 165.36059160986585, 148.53765664987577, 136.3497989570427, 147.90593718441198, 142.00373104850712, 116.90801724449558]\n", + "opt_prices:[13, 12, 13, 13, 8, 13, 19]\n", + "rev_std: 911.440627188109\n", + "penalty_term: -0.0027273877494735643\n", + "---\n", + "beta_sample:1000.0\n", + "max_revenue:12670.478721092995\n", + "prediction_variance:702.6378450712685\n", + "energy:689967.3671875\n", + "opt_demand:[185.94625963144793, 183.03263192598416, 175.28755799486112, 178.08832280237198, 164.04729001322988, 169.05328720329032, 144.51495749636558]\n", + "opt_prices:[12, 8, 10, 8, 13, 8, 16]\n", + "rev_std: 750.6271669208057\n", + "penalty_term: 0.0008373245364055037\n", + "---\n", + "beta_sample:10000.0\n", + "max_revenue:11817.559866927473\n", + "prediction_variance:702.2867319690542\n", + "energy:7011049.7578125\n", + "opt_demand:[193.16540581130278, 189.5001278388014, 170.43121922421625, 165.25723980967433, 153.9973837115136, 161.32538230601057, 170.39435938827893]\n", + "opt_prices:[10, 8, 13, 10, 12, 8, 8]\n", + "rev_std: 690.5524395782304\n", + "penalty_term: -0.0020111147314310074\n", + "---\n", + "beta_sample:100000.0\n", + "max_revenue:11730.90327753302\n", + "prediction_variance:702.6054633102096\n", + "energy:70248815.4296875\n", + "opt_demand:[200.38455199115765, 188.74847757176371, 173.54567690046386, 159.38876814347378, 173.4603698912537, 164.9736996303592, 174.76781254228632]\n", + "opt_prices:[8, 10, 12, 12, 5, 12, 8]\n", + "rev_std: 670.5375896992824\n", + "penalty_term: 0.0019440650939941406\n", + "---\n", + "beta_sample:1000000.0\n", + "max_revenue:11366.13708846887\n", + "prediction_variance:701.9254561595391\n", + "energy:701914090.0234375\n", + "opt_demand:[200.38455199115765, 195.9676237516186, 180.01317281328105, 179.79944100232086, 172.43680332363402, 176.95460047618036, 182.095155462867]\n", + "opt_prices:[8, 8, 12, 8, 10, 8, 8]\n", + "rev_std: 620.4867422821079\n", + "penalty_term: 0.0009868144989013672\n", + "---\n", + "beta_sample:10000000.0\n", + "max_revenue:12059.244435137061\n", + "prediction_variance:702.1589543897425\n", + "energy:7021577484.65625\n", + "opt_demand:[185.94625963144793, 175.81348574612934, 168.82006208204393, 172.1159423032346, 170.78670222662907, 162.54965144292677, 168.27043290883302]\n", + "opt_prices:[12, 10, 10, 8, 10, 12, 8]\n", + "rev_std: 700.4770822738305\n", + "penalty_term: 0.0032606124877929688\n", + "---\n", + "beta_sample:100000000.0\n", + "max_revenue:12586.848019820494\n", + "prediction_variance:702.2588263689306\n", + "energy:70225870050.04688\n", + "opt_demand:[193.16540581130278, 189.5001278388014, 174.04079231414366, 168.49098776608298, 171.42186632079205, 158.2571622101994, 149.0058087898134]\n", + "opt_prices:[10, 8, 12, 10, 8, 13, 13]\n", + "rev_std: 740.5999324626732\n", + "penalty_term: 0.0018310546875\n", + "---\n", + "beta_sample:1000000000.0\n", + "max_revenue:11513.084463226094\n", + "prediction_variance:701.9673403893491\n", + "energy:701967328876.2656\n", + "opt_demand:[193.16540581130278, 182.28098165894653, 182.0115887610362, 182.67274527243484, 185.74481617550094, 199.51815427164263, 181.35358580720091]\n", + "opt_prices:[10, 10, 8, 8, 8, 5, 13]\n", + "rev_std: 620.4493819300103\n", + "penalty_term: 0.0009765625\n", + "---\n", + "beta_sample:100.0\n", + "max_revenue:13220.837666382635\n", + "prediction_variance:703.2708579595874\n", + "energy:57106.2421875\n", + "opt_demand:[193.16540581130278, 175.06183547909168, 168.32494666836413, 155.79457650077055, 148.30984443463637, 129.07720313226912, 111.91898840597983]\n", + "opt_prices:[10, 12, 10, 12, 12, 16, 16]\n", + "rev_std: 881.2620851851485\n", + "penalty_term: -0.005942076095379889\n", + "---\n", + "beta_sample:1000.0\n", + "max_revenue:12295.011741408678\n", + "prediction_variance:702.0143363129322\n", + "energy:689719.3203125\n", + "opt_demand:[193.16540581130278, 182.28098165894653, 182.0115887610362, 168.23445291272512, 165.5906781700117, 170.27717809076842, 157.5013473260716]\n", + "opt_prices:[10, 10, 8, 12, 10, 8, 13]\n", + "rev_std: 710.5194469295551\n", + "penalty_term: -0.004259023466147482\n", + "---\n", + "beta_sample:10000.0\n", + "max_revenue:12137.958959707696\n", + "prediction_variance:701.7035451887735\n", + "energy:7004897.5\n", + "opt_demand:[200.38455199115765, 195.9676237516186, 187.2323189931359, 179.04779073528323, 171.94168790995423, 167.85238085357116, 158.86664740383665]\n", + "opt_prices:[8, 8, 10, 10, 10, 10, 12]\n", + "rev_std: 680.5356666395476\n", + "penalty_term: 0.0070719728246331215\n", + "---\n", + "beta_sample:100000.0\n", + "max_revenue:12662.168821110694\n", + "prediction_variance:702.0474353071147\n", + "energy:70192081.359375\n", + "opt_demand:[193.16540581130278, 182.28098165894653, 182.0115887610362, 175.45359909257996, 164.83902790297404, 155.34377031737887, 142.68328205768287]\n", + "opt_prices:[10, 10, 8, 10, 12, 12, 13]\n", + "rev_std: 750.6086003087909\n", + "penalty_term: -0.002515360713005066\n", + "---\n", + "beta_sample:1000000.0\n", + "max_revenue:11584.987162273512\n", + "prediction_variance:701.6265137028367\n", + "energy:701614928.7265625\n", + "opt_demand:[200.38455199115765, 195.9676237516186, 194.45146517299077, 185.5152866481004, 185.1332145889465, 178.4091838227714, 173.82476135270855]\n", + "opt_prices:[8, 8, 8, 10, 8, 10, 10]\n", + "rev_std: 620.5051819276027\n", + "penalty_term: 0.010887980461120605\n", + "---\n", + "beta_sample:10000000.0\n", + "max_revenue:11875.017901773796\n", + "prediction_variance:702.7108889577102\n", + "energy:7027097014.5546875\n", + "opt_demand:[185.94625963144793, 183.03263192598416, 193.33542344449825, 194.25706258441494, 189.80696053085563, 174.5395063537641, 166.61244313370094]\n", + "opt_prices:[12, 8, 5, 8, 10, 12, 10]\n", + "rev_std: 650.489008200234\n", + "penalty_term: -0.004512786865234375\n", + "---\n", + "beta_sample:100000000.0\n", + "max_revenue:11823.25581739232\n", + "prediction_variance:701.7629736877091\n", + "energy:70176285545.53125\n", + "opt_demand:[200.38455199115765, 188.74847757176371, 187.98396926017358, 179.54290614896303, 173.82476135270855, 162.95595446021971, 167.45934289058516]\n", + "opt_prices:[8, 10, 8, 10, 10, 12, 8]\n", + "rev_std: 660.5028248731621\n", + "penalty_term: 0.0161590576171875\n", + "---\n", + "beta_sample:1000000000.0\n", + "max_revenue:12167.489725816766\n", + "prediction_variance:702.2176753704937\n", + "energy:702217663203.0078\n", + "opt_demand:[185.94625963144793, 175.81348574612934, 168.82006208204393, 164.89679612337972, 157.10006013395704, 164.54806739068187, 163.92459099909212]\n", + "opt_prices:[12, 10, 10, 10, 12, 8, 10]\n", + "rev_std: 720.5240801141839\n", + "penalty_term: 0.00390625\n", + "---\n", + "beta_sample:100.0\n", + "max_revenue:13094.765089274155\n", + "prediction_variance:703.662012789634\n", + "energy:57271.4375\n", + "opt_demand:[193.16540581130278, 182.28098165894653, 182.0115887610362, 164.6248798227977, 169.57607639345792, 134.05317976481524, 115.02912750674054]\n", + "opt_prices:[10, 10, 8, 13, 8, 19, 16]\n", + "rev_std: 841.1476642973098\n", + "penalty_term: 0.0013103107485221699\n", + "---\n", + "beta_sample:1000.0\n", + "max_revenue:12603.56403338578\n", + "prediction_variance:702.1242685672336\n", + "energy:689520.6953125\n", + "opt_demand:[193.16540581130278, 182.28098165894653, 182.0115887610362, 168.23445291272512, 165.5906781700117, 152.2293126411313, 144.94218063395599]\n", + "opt_prices:[10, 10, 8, 12, 10, 13, 12]\n", + "rev_std: 750.6158788184107\n", + "penalty_term: -0.0092213477473706\n", + "---\n", + "beta_sample:10000.0\n", + "max_revenue:12157.321498711704\n", + "prediction_variance:702.2691817581286\n", + "energy:7010534.4921875\n", + "opt_demand:[185.94625963144793, 175.81348574612934, 176.0392082618988, 178.58343821605177, 183.97822890562134, 169.4968813221996, 165.5565065415866]\n", + "opt_prices:[12, 10, 8, 8, 8, 13, 10]\n", + "rev_std: 690.4600457482996\n", + "penalty_term: -0.003895075060427189\n", + "---\n", + "beta_sample:100000.0\n", + "max_revenue:12774.905484494411\n", + "prediction_variance:702.2596528682677\n", + "energy:70213190.3828125\n", + "opt_demand:[193.16540581130278, 182.28098165894653, 167.57329640132647, 169.7377534468004, 166.5809089973713, 166.8241787964222, 144.85057171647898]\n", + "opt_prices:[10, 10, 12, 8, 10, 10, 16]\n", + "rev_std: 760.6239136631048\n", + "penalty_term: 0.001470223069190979\n", + "---\n", + "beta_sample:1000000.0\n", + "max_revenue:11667.308525800716\n", + "prediction_variance:702.412810625621\n", + "energy:702401143.3203125\n", + "opt_demand:[185.94625963144793, 168.59433956627447, 169.57171234908157, 172.6110577169144, 179.88892184923827, 178.55901332210226, 181.33220836064368]\n", + "opt_prices:[12, 12, 8, 8, 8, 10, 8]\n", + "rev_std: 660.4122866959771\n", + "penalty_term: 0.003217339515686035\n", + "---\n", + "beta_sample:10000000.0\n", + "max_revenue:10547.842565002704\n", + "prediction_variance:701.9551138790306\n", + "energy:7019540590.9375\n", + "opt_demand:[193.16540581130278, 182.28098165894653, 174.79244258118132, 168.98610317976278, 173.30493976354637, 189.45646671612218, 204.37427620035757]\n", + "opt_prices:[10, 10, 10, 10, 8, 5, 5]\n", + "rev_std: 580.4321159096354\n", + "penalty_term: -0.010241508483886719\n", + "---\n", + "beta_sample:100000000.0\n", + "max_revenue:10999.322306622127\n", + "prediction_variance:701.8825186390502\n", + "energy:70188240864.57812\n", + "opt_demand:[193.16540581130278, 189.5001278388014, 188.47908467385338, 181.42597959171735, 176.14748113921195, 188.84486512956772, 190.4844519313412]\n", + "opt_prices:[10, 8, 8, 10, 10, 5, 8]\n", + "rev_std: 590.4418148595013\n", + "penalty_term: -0.00457763671875\n", + "---\n", + "beta_sample:1000000000.0\n", + "max_revenue:11671.62338254227\n", + "prediction_variance:702.2254866319277\n", + "energy:702225474960.3047\n", + "opt_demand:[200.38455199115765, 195.9676237516186, 187.2323189931359, 171.82864455542838, 172.69333817699186, 186.3953617168881, 173.30888753870656]\n", + "opt_prices:[8, 8, 10, 12, 8, 5, 13]\n", + "rev_std: 640.5219703820226\n", + "penalty_term: 0.00048828125\n", + "---\n", + "beta_sample:100.0\n", + "max_revenue:13236.730899961218\n", + "prediction_variance:703.7806798074442\n", + "energy:57141.3359375\n", + "opt_demand:[200.38455199115765, 177.91975830198146, 171.06357921109287, 156.8976933075849, 162.4700705360342, 142.27358955298732, 113.21850090358835]\n", + "opt_prices:[8, 13, 10, 12, 8, 16, 19]\n", + "rev_std: 861.2398056717766\n", + "penalty_term: -0.0011432832106947899\n", + "---\n", + "beta_sample:1000.0\n", + "max_revenue:12112.4296039292\n", + "prediction_variance:702.0797161052823\n", + "energy:689967.2890625\n", + "opt_demand:[193.16540581130278, 175.06183547909168, 175.54409284821895, 176.70036477329745, 181.65550911911788, 179.7037015521259, 167.6497308850617]\n", + "opt_prices:[10, 12, 8, 8, 8, 10, 12]\n", + "rev_std: 680.4481890220659\n", + "penalty_term: 0.0025611468590795994\n", + "---\n", + "beta_sample:10000.0\n", + "max_revenue:11792.924595157247\n", + "prediction_variance:702.3924264432308\n", + "energy:7012131.34375\n", + "opt_demand:[193.16540581130278, 175.06183547909168, 168.32494666836413, 155.79457650077055, 155.52899061449125, 149.98299140479602, 170.53166471995328]\n", + "opt_prices:[10, 12, 10, 12, 10, 12, 5]\n", + "rev_std: 710.6152086362777\n", + "penalty_term: 0.0039128502830863\n", + "---\n", + "beta_sample:100000.0\n", + "max_revenue:12194.85761350477\n", + "prediction_variance:701.8919743058643\n", + "energy:70177002.578125\n", + "opt_demand:[193.16540581130278, 182.28098165894653, 182.0115887610362, 182.67274527243484, 178.52566999564607, 164.17407363940606, 160.33994092657696]\n", + "opt_prices:[10, 10, 8, 8, 10, 13, 10]\n", + "rev_std: 690.4910630253685\n", + "penalty_term: 0.005152076482772827\n", + "---\n", + "beta_sample:1000000.0\n", + "max_revenue:11242.602046086131\n", + "prediction_variance:702.4748933885294\n", + "energy:702463650.78125\n", + "opt_demand:[185.94625963144793, 175.81348574612934, 176.0392082618988, 189.41215748583403, 186.4603265949923, 190.03582160772567, 189.1059725889217]\n", + "opt_prices:[12, 10, 8, 5, 10, 8, 8]\n", + "rev_std: 610.3991271613321\n", + "penalty_term: -0.005233287811279297\n", + "---\n", + "beta_sample:10000000.0\n", + "max_revenue:10704.831049213793\n", + "prediction_variance:702.4259815510339\n", + "energy:7024249110.6796875\n", + "opt_demand:[200.38455199115765, 195.9676237516186, 194.45146517299077, 203.56315209773754, 212.13067364077173, 195.82223275998587, 193.75825000940995]\n", + "opt_prices:[8, 8, 8, 5, 5, 12, 8]\n", + "rev_std: 540.5693089280617\n", + "penalty_term: 0.000396728515625\n", + "---\n", + "beta_sample:100000000.0\n", + "max_revenue:12118.204399688242\n", + "prediction_variance:702.0775739077151\n", + "energy:70207745272.57031\n", + "opt_demand:[200.38455199115765, 195.9676237516186, 180.01317281328105, 172.58029482246604, 158.750161230962, 157.2955778843709, 158.3468258146745]\n", + "opt_prices:[8, 8, 12, 10, 12, 10, 10]\n", + "rev_std: 700.5863093976069\n", + "penalty_term: 0.003204345703125\n", + "---\n", + "beta_sample:1000000000.0\n", + "max_revenue:10350.06038481572\n", + "prediction_variance:702.4846362905347\n", + "energy:702484625940.4688\n", + "opt_demand:[211.2132712609399, 205.66886762084437, 203.41003592169682, 198.86839341252983, 187.03144522672824, 197.67896620376422, 196.46329619804368]\n", + "opt_prices:[5, 8, 8, 8, 10, 5, 8]\n", + "rev_std: 520.6166233702603\n", + "penalty_term: -0.0054931640625\n", + "---\n", + "beta_sample:100.0\n", + "max_revenue:13101.089112842521\n", + "prediction_variance:703.2120045508508\n", + "energy:57220.109375\n", + "opt_demand:[200.38455199115765, 177.91975830198146, 178.28272539094775, 170.58433540025698, 160.4716545882791, 153.83857764258306, 120.0646260572107]\n", + "opt_prices:[8, 13, 8, 10, 12, 12, 19]\n", + "rev_std: 820.959265376438\n", + "penalty_term: -0.001967242562386673\n", + "---\n", + "beta_sample:1000.0\n", + "max_revenue:12799.39306175473\n", + "prediction_variance:702.7497978139801\n", + "energy:689950.3984375\n", + "opt_demand:[200.38455199115765, 188.74847757176371, 173.54567690046386, 155.77919505354637, 144.9596103053531, 135.7417005960029, 130.53821386106824]\n", + "opt_prices:[8, 10, 12, 13, 12, 13, 13]\n", + "rev_std: 810.9564396486212\n", + "penalty_term: -0.006314725265838206\n", + "---\n", + "beta_sample:10000.0\n", + "max_revenue:11668.057902789285\n", + "prediction_variance:702.114905983479\n", + "energy:7009481.0\n", + "opt_demand:[193.16540581130278, 189.5001278388014, 188.47908467385338, 199.47384504135448, 192.31622092125497, 192.94709710762896, 172.9586102534359]\n", + "opt_prices:[10, 8, 8, 5, 10, 8, 13]\n", + "rev_std: 620.5042342568443\n", + "penalty_term: -0.0019320007413625717\n", + "---\n", + "beta_sample:100000.0\n", + "max_revenue:12133.533110080407\n", + "prediction_variance:702.0571376283112\n", + "energy:70193580.234375\n", + "opt_demand:[193.16540581130278, 175.06183547909168, 168.32494666836413, 163.0137226806254, 169.2156327071633, 176.86116017646032, 168.26133247161616]\n", + "opt_prices:[10, 12, 10, 10, 8, 8, 12]\n", + "rev_std: 700.4772829770868\n", + "penalty_term: 0.004653960466384888\n", + "---\n", + "beta_sample:1000000.0\n", + "max_revenue:10843.245671844892\n", + "prediction_variance:701.7569277253392\n", + "energy:701746084.4921875\n", + "opt_demand:[193.16540581130278, 182.28098165894653, 182.0115887610362, 175.45359909257996, 179.27732026268376, 182.717054502723, 196.43961960101143]\n", + "opt_prices:[10, 10, 8, 10, 8, 8, 5]\n", + "rev_std: 590.4245277513222\n", + "penalty_term: 0.012520194053649902\n", + "---\n", + "beta_sample:10000000.0\n", + "max_revenue:11696.71176176828\n", + "prediction_variance:702.2911264607972\n", + "energy:7022899567.890625\n", + "opt_demand:[200.38455199115765, 188.74847757176371, 173.54567690046386, 166.60791432332866, 154.66085417457893, 173.57685606412835, 173.3708773666939]\n", + "opt_prices:[8, 10, 12, 10, 12, 5, 10]\n", + "rev_std: 670.533082027326\n", + "penalty_term: -0.005584716796875\n", + "---\n", + "beta_sample:100000000.0\n", + "max_revenue:11259.819536849312\n", + "prediction_variance:701.8711813398561\n", + "energy:70187106874.17188\n", + "opt_demand:[193.16540581130278, 189.5001278388014, 181.2599384939985, 174.95848367890017, 177.39424681992944, 191.22305398600184, 187.4710989807441]\n", + "opt_prices:[10, 8, 10, 10, 8, 5, 10]\n", + "rev_std: 610.443345015263\n", + "penalty_term: 0.00579833984375\n", + "---\n", + "beta_sample:1000000000.0\n", + "max_revenue:12094.573836154155\n", + "prediction_variance:702.2972898129863\n", + "energy:702297277718.4141\n", + "opt_demand:[193.16540581130278, 189.5001278388014, 170.43121922421625, 172.4763859895292, 174.9031719840405, 165.79446227107266, 166.27428943744752]\n", + "opt_prices:[10, 8, 13, 8, 8, 12, 10]\n", + "rev_std: 690.5026388893243\n", + "penalty_term: 0.001708984375\n" + ] + } + ], + "source": [ + "#beta_options=[1e2,1e3,1e4,1e5,1e6,1e7,1e8,1e9]\n", + "#results = {beta_option:[] for beta_option in beta_options}\n", + "#beta_samples = beta_options*6\n", + "\n", + "#for beta_i in beta_samples:\n", + "# max_revenue, prediction_variance, energy, opt_demand, opt_prices, rev_std = optimize(\n", + "# a = a,\n", + "# b = b,\n", + "# data_x = data_x,\n", + "# selected_hist_prices = p_data,\n", + "# price_levels = price_levels,\n", + "# Lp = Lp,\n", + "# Ld = Ld,\n", + "# sigma = sigma ,\n", + "# beta=beta_i,\n", + "# vol_bound=None,\n", + "# s3_folder=s3_folder\n", + "# )\n", + "# print('---')\n", + "# print(f\"beta_sample:{beta_i}\")\n", + "# print(f\"max_revenue:{max_revenue}\")\n", + "# print(f\"prediction_variance:{prediction_variance}\")\n", + "# print(f\"energy:{energy}\")\n", + "# print(f\"opt_demand:{opt_demand}\")\n", + "# print(f\"opt_prices:{opt_prices}\")\n", + "# print(f\"rev_std: {rev_std}\")\n", + "# print(f\"penalty_term: {max_revenue-beta_i*prediction_variance+energy}\")\n", + "# results[beta_i].append([energy, max_revenue, prediction_variance, rev_std])" + ] + }, + { + "cell_type": "markdown", + "id": "d853f336", + "metadata": {}, + "source": [ + "We can see from the plot below that there is a Pareto front [11] where the expected revenue cannot be increased without increasing the standard deviation (i.e. uncertainties), and the other way around.\n", + "\n", + "We can see that the expected revenue can vary significantly between 10000 and 13500, while the estimated standard deviation of the revenue (i.e. uncertainty) can change in a large range $[550,900]$ as well. The figure shows that as the expected revenue increases, the estimated standard deviation of the revenue will also increase. This means that if we select a price solution for higher expected revenue, the uncertainties will increase at the same time indicating that the demand estimation model will become less confident about its predictions. This illustrates there is a trade-off between maximizing the revenue and minimizing the uncertainty. High revenue and rewards usually accompany with high uncertainties and risk. In practice, according to different business strategies and needs, we usually need to find an appropriate $\\beta$ to maximize the revenue under an acceptable level of uncertainty." + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "id": "b6db5e4c", + "metadata": {}, + "outputs": [], + "source": [ + "beta_x=[]\n", + "revenue_y=[]\n", + "variance_y=[]\n", + "rev_std_y=[]\n", + "\n", + "for beta_i in beta_options:\n", + " for result in results[beta_i]:\n", + " beta_x.append(beta_i)\n", + " revenue_y.append(result[1])\n", + " variance_y.append(result[2])\n", + " rev_std_y.append(result[3])" + ] + }, + { + "cell_type": "code", + "execution_count": 28, + "id": "719f9fce", + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "plt.rcParams.update({'font.size': 18})\n", + "plt.figure(figsize=(10,8))\n", + "plt.scatter(revenue_y, rev_std_y)\n", + "plt.xlabel('Revenue')\n", + "plt.ylabel('Revenue standard deviation')\n", + "plt.savefig('tradoff_sigma=10_b=300.png')" + ] + }, + { + "cell_type": "markdown", + "id": "f2667f41", + "metadata": {}, + "source": [ + "# 5. Conclusion" + ] + }, + { + "cell_type": "markdown", + "id": "febb3839", + "metadata": {}, + "source": [ + "In this notebook, we demonstrate how to leverage a quantum annealer on Amazon Braket to solve a price optimization use case. We showed how to mathematically formulate the problem within the (quantum-ready) QUBO framework, and then subsequently solve the optimization problem on a D-Wave quantum annealer. Our results are promising in terms of both close-to-optimal quality and computational efficiency. Since the QUBO formalism is a generalized framework that can embrace a variety of combinatorial optimization use cases (e.g. scheduling/planning, routing, portfolio management), the proposed solution can be arguably adapted and recycled by customers across other multiple industries. Already today our customers can get quantum-ready, and easily leverage Amazon Braket to help solve their daily combinatorial optimization challenges, and make better business and operation decisions." + ] + }, + { + "cell_type": "markdown", + "id": "9c00a940", + "metadata": {}, + "source": [ + "# 6. References:\n", + "1. Glover, F., Kochenberger, G. and Du, Y., 2019. Quantum Bridge Analytics I: a tutorial on formulating and using QUBO models. 4OR, 17(4), pp.335-371.\n", + "2. Kochenberger, G., Hao, J.K., Glover, F., Lewis, M., Lü, Z., Wang, H. and Wang, Y., 2014. The unconstrained binary quadratic programming problem: a survey. Journal of combinatorial optimization, 28(1), pp.58-81.\n", + "3. Anthony, M., Boros, E., Crama, Y. and Gruber, A., 2017. Quadratic reformulations of nonlinear binary optimization problems. Mathematical Programming, 162(1), pp.115-144.\n", + "4. Amazon Web Services. Amazon Braket – Amazon Web Services, 2021. Available at: https://aws.amazon.com/braket/ (Accessed: 15 July, 2021)\n", + "5. Cruz-Santos, W., Venegas-Andraca, S.E. and Lanzagorta, M., 2019. A QUBo formulation of Minimum Multicut problem instances in trees for D-Wave Quantum Annealers. Scientific reports, 9(1), pp.1-12.\n", + "6. Amazon Web Services. A python SDK for interacting with quantum devices via AWS, 2021. Available at: https://github.com/aws/amazon-braket-sdk-python (Accessed: 16 July, 2021) \n", + "7. Amazon Web Services. Amazon SageMaker – Machine Learning – Amazon Web Services, 2021. Available at: https://aws.amazon.com/sagemaker/ (Accessed: 20 July, 2021)\n", + "8. Ben-Tal, A. and Nemirovski, A., 2002. Robust optimization–methodology and applications. Mathematical programming, 92(3), pp.453-480.\n", + "9. Fabozzi, F.J., Kolm, P.N., Pachamanova, D.A. and Focardi, S.M., 2007. Robust portfolio optimization and management. John Wiley & Sons.\n", + "10. Hyndman, R.J. and Athanasopoulos, G., 2018. Forecasting: principles and practice. OTexts. Available at: https://otexts.com/fpp2/regression-matrices.html (Accessed: 20 July, 2021)\n", + "11. Wikipedia. Pareto front - Wikipedia, 2021. Available at: https://en.wikipedia.org/wiki/Pareto_front (Accessed: 21 Dec, 2021)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5a26a9dc", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "conda_braket", + "language": "python", + "name": "conda_braket" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.7.11" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/examples/quantum_annealing/price_optimization/qubo_dynamic_pricing.py b/examples/quantum_annealing/price_optimization/qubo_dynamic_pricing.py new file mode 100644 index 000000000..fffbc2137 --- /dev/null +++ b/examples/quantum_annealing/price_optimization/qubo_dynamic_pricing.py @@ -0,0 +1,288 @@ +from pyqubo import Binary +import numpy as np +import dimod +from braket.ocean_plugin import BraketDWaveSampler +from dwave.system.composites import EmbeddingComposite +from itertools import combinations + +np.random.seed(0) + +def get_coeffient(expr, mode): + coeffs, consts = expr.compile().to_qubo() + if mode == 'linear': + new_coeffs = {} + for k, v in coeffs.items(): + assert k[0] == k[1] + new_coeffs[k[0]] = v + elif mode == 'quadratic': + new_coeffs = coeffs + else: + raise TypeError(f"unknown mode: {mode}") + + return new_coeffs, consts + + +def get_demand(coeff, b, prices): + assert len(coeff) == len(prices) + d = b + for i in range(len(coeff)): + d += coeff[i]*prices[i] + + return d + + +def get_variance(data_x, p, sigma): + """ + :param data_x (np.array): [n_samples, n_days] + :param p (list): [n_days] + :return: variance + """ + n_samples, t = data_x.shape + ones = np.ones((n_samples, 1), dtype=np.float) + x_mat = np.concatenate([ones, data_x], axis=1) # [n_samples, n_days+1] + x_mat = np.linalg.inv( + np.dot(x_mat.T, x_mat) + ) + p = np.array([1.]+p) + variance = (sigma**2) * (1. + p.dot(x_mat).dot(p)) + return variance + + +def get_covariance(data_x, p1, p2, sigma): + """ + :param data_x (np.array): [n_samples, n_days] + :param p1, p2 (list): [n_days] + :return: variance + """ + n_samples, t = data_x.shape + ones = np.ones((n_samples, 1), dtype=np.float) + x_mat = np.concatenate([ones, data_x], axis=1) # [n_samples, n_days+1] + x_mat = np.linalg.inv( + np.dot(x_mat.T, x_mat) + ) + p1 = np.array([1.] + p1) + p2 = np.array([1.] + p2) + variance = (sigma**2) * (1. + p1.dot(x_mat).dot(p2)) + return variance + + +def create_program(a,b, p_data, price_levels, data_x, Lp, Ld, sigma, beta, vol_bound): + """ + + :param a (list of int): [7], coefficient + :param b (int): + :param p_data (list of int): [7], past 7 days prices + :param price_levels (list of int): number of price levels + :param data_x (np.array): [nsamples, n_days] + :param L (float): coeff of constraints penalty + :param sigma (float): standard deviation of noise + :param beta (float): coeff of variance + :return: + """ + assert type(a) is list + #assert type(b) is int + assert type(p_data) is list + assert type(price_levels) is list + + t = len(a) + n_level = len(price_levels) + + # variables + x = [] + p = [] + d = [] + + # get p + for i in range(t): + p_i = 0 + for j in range(n_level): + x_ij = Binary(f"X_{i*n_level+j:03d}") + x.append(x_ij) + p_i += x_ij*price_levels[j] + p.append(p_i) + + all_p = p_data + p + + # get d, rev + rev = 0 + for i in range(t): + d_i = get_demand( + coeff=a, + b=b, + prices=all_p[i+1:i+1+t] + ) + d.append(d_i) + rev += d_i * p[i] + # minus variance + rev -= beta * get_variance(data_x, all_p[i+1:i+1+t], sigma) + # add inequaliry constraints + if vol_bound: + _, d_const = get_coeffient(d_i, 'linear') + rev -= inequality_penalty( + demand=d_i, + demand_name=f'demand{i}', + vol_bounday=vol_bound, + d_const=d_const, + Ld=Ld + ) + + # add equalty constraints + for i in range(t): + penalty = x[i*n_level] + for j in range(1, n_level): + penalty += x[i*n_level+j] + penalty = ((penalty-1)**2)*Lp + rev -= penalty + + return rev, d + + +def construct_slack(n, name): + e = 0 + slack = 0 + while n >= 2**e: + n -= 2**e + slack += (2**e) * Binary(f"{name}_{e}") + e += 1 + + slack += n * Binary(f"{name}_{e}") + return slack + + +def inequality_penalty(demand, demand_name, vol_bounday, d_const, Ld): + rhs = vol_bounday - d_const + assert rhs <= 0 + n = -rhs + slack = construct_slack(n, demand_name) + return ((demand-vol_bounday-slack)**2)*Ld + + +def optimize( + a, + b, + data_x, + selected_hist_prices, + price_levels, + Lp, + Ld, + sigma, + beta, + vol_bound, + s3_folder=None, + dwave=True +): + """ + + :param a: list of int, coeff + :param b: int, const + :param data_x: training set of x + :param selected_hist_prices: list, last n days prices + :param price_levels: list of int, options of prices + :param Lp: int, coeff of price constraints penalty + :param Ld: int, coeff of demand constraints penalty + :param sigma: float, stand deviation of noise + :param beta: float, coeff of variance penalty + :param vol_bound: float, boundary of demand + :return: + """ + obj, demands = create_program( + a=a, + b=b, + p_data=selected_hist_prices, + price_levels=price_levels, + data_x=data_x, + Lp=Lp, + Ld=Ld, + sigma=sigma, + beta=beta, + vol_bound=vol_bound + ) + + # qubo solver + response = dwave_solver(obj, s3_folder) if dwave else qubo_solver(obj) + + # get optimal prices + opt_prices, _, energy = decoder_price_response(response, len(a), price_levels) + opt_demand, max_revenue = get_demands_rev(a, b, selected_hist_prices, opt_prices) + prediction_variance = get_overall_variance(data_x, selected_hist_prices, opt_prices, sigma) + revenue_variance = get_overall_revenue_variance(data_x, selected_hist_prices, opt_prices, sigma) + + return max_revenue, prediction_variance, energy, opt_demand, opt_prices, np.sqrt(revenue_variance) + + +def qubo_solver(obj): + model = (-obj).compile().to_bqm() + num_shots = 100 + + sampler = dimod.SimulatedAnnealingSampler() + response = sampler.sample(model, num_reads=num_shots) + return response + + +def dwave_solver(obj, s3_folder): + model = (-obj).compile().to_bqm() + num_shots = 10000 + + device_arn = 'arn:aws:braket:::device/qpu/d-wave/Advantage_system4' + if s3_folder: + sampler = BraketDWaveSampler(s3_folder, device_arn=device_arn) + else: + sampler = BraketDWaveSampler(device_arn=device_arn) + + sampler = EmbeddingComposite(sampler) + response = sampler.sample(model, num_reads=num_shots) + return response + + +def decoder_price_response(response, n_days, price_options): + opt_price, energy = response.record.sample[response.record.energy.argmin()], response.record.energy.min() + prices = [] + for i in range(n_days): + price_i = opt_price[i*len(price_options): (i+1)*len(price_options)] + assert price_i.sum()==1 + prices.append(price_options[price_i.argmax()]) + return prices, opt_price, energy + + +def get_demands_rev(a, b, hist_p, p): + all_p = hist_p + p + t = len(a) + d = [] + revenue = 0 + for i in range(t): + d_i = get_demand( + coeff=a, + b=b, + prices=all_p[i+1:i+1+t] + ) + d.append(d_i) + revenue += d_i * p[i] + return d, revenue + + +def get_overall_variance(data_x, hist_p, p, sigma): + all_p = hist_p + p + t = len(p) + var = 0 + for i in range(t): + var += get_variance(data_x, all_p[i+1:i+1+t], sigma) + + return var + + +def get_overall_revenue_variance(data_x, hist_p, p, sigma): + all_p = hist_p + p + t = len(p) + var = 0 + for i in range(t): + var += get_variance(data_x, all_p[i+1:i+1+t], sigma) * (p[i]**2) + + for i, j in combinations(list(range(t)), 2): + var += get_covariance( + data_x, + all_p[i + 1:i + 1 + t], + all_p[j + 1:j + 1 + t], + sigma + ) * 2 * p[i] * p[j] + + return var