{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "![MOSEK ApS](https://www.mosek.com/static/images/branding/webgraphmoseklogocolor.png )" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Optimization for multiuser communications" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We consider a multiple-input multiple-output (MIMO) communication system \n", "with $n$ transmitters and $n$ receivers. Each transmitter transmits with power $p_j$ and the \n", "gain from transmitter $j$ to receiver $i$ is $G_{ij}$. The signal power from transmitter $i$ to receiver $i$ is then\n", "\n", "$$ S_i = G_{ii} p_i $$\n", "\n", "and the interference is\n", "\n", "$$ I_i = \\sum_{j\\neq i} G_{ij} p_j + \\sigma_i $$\n", "\n", "where $\\sigma_i$ is an additive noise component. In this notebook we consider different strategies for optimizing the signal-to-inference-plus-noise ratio (SINR)\n", "\n", "$$ s_i = \\frac{G_{ii} p_i}{\\sum_{j\\neq i} G_{ij} p_j + \\sigma_i} $$\n", "\n", "with a bound on the total transmitted power $ \\sum_i p_i \\leq P $." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Minimizing total power for given SINRs\n", "Suppose we are given lower bounds $s_i \\geq \\gamma_i$. We can then minimize the required power\n", "$$ \n", "\\begin{array}{ll}\n", "\\text{minimize} & \\sum_i p_i \\\\\n", "\\text{subject to} & s_i \\geq \\gamma_i \\\\\n", " & \\sum_i p_i \\leq P,\n", "\\end{array}\n", "$$\n", "which is equivalent to a linear optimization problem\n", "$$ \n", "\\begin{array}{ll}\n", "\\text{minimize} & \\sum_i p_i \\\\\n", "\\text{subject to} & G_{ii} p_i \\geq \\gamma_i\\left ( \\sum_{j\\neq i} G_{ij} p_j + \\sigma_i \\right ) \\\\\n", " & \\sum_i p_i \\leq P.\n", "\\end{array}\n", "$$" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Maximizing the worst SINR\n", "Alternatively we can maximize the smallest $s_i$,\n", "\n", "$$\n", "\\begin{array}{ll}\n", "\\text{maximize} & t \\\\\n", "\\text{subject to} & s_i \\geq t \\\\\n", " & \\sum_i p_i \\leq P.\n", "\\end{array}\n", "$$\n", "\n", "Equivalently we can minimize the inverse, \n", "\n", "$$\n", "\\begin{array}{ll}\n", "\\text{minimize} & t^{-1} \\\\\n", "\\text{subject to} & t \\left ( \\sum_{j\\neq i} G_{ij} p_j + \\sigma_i \\right ) G_{ii}^{-1} p_i^{-1} \\leq 1 \\\\\n", " & \\sum_i p_i \\leq P,\n", "\\end{array}\n", "$$\n", "\n", "which can be rewritten as a geometric programming problem\n", "\n", "$$\n", "\\begin{array}{ll}\n", "\\text{minimize} & -z\\\\\n", "\\text{subject to} &\n", "\\log \\left ( \\sum_{j\\neq i}e^{z + q_j - q_i + \\log(G_{ij}/G_{ii})} + e^{z - q_i + \\log(\\sigma_i/G_{ii})} \\right ) \\leq 0\\\\\n", "& \\log \\left ( \\sum_i e^{q_i-\\log P}\\right) \\leq 0\n", "\\end{array}\n", "$$\n", "\n", "with $p_i := e^{q_i}$ and $t := e^z$. To rewrite the geometric program into conic form, we note that\n", "\n", "$$ \n", "\\log \\left( \\sum_{i=1}^n e^{a_i^T x + b_i}\\right) \\leq 0 \\qquad \\Longleftrightarrow \\qquad \n", "\\sum_i u_i\\leq 1, \\quad (u_i, 1, a_i^Tx + b_i)\\in K_\\text{exp}, \\: i=1,\\dots n.\n", "$$" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "import sys\n", "import numpy as np\n", "from mosek.fusion import *\n", "import matplotlib.pyplot as plt" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [], "source": [ "def logsumexp(M, A, x, b): \n", " u = M.variable(A.shape[0])\n", " M.constraint( Expr.sum(u), Domain.lessThan(1.0))\n", " M.constraint( Expr.hstack(u,\n", " Expr.constTerm(A.shape[0], 1.0),\n", " Expr.add(Expr.mul(A, x), b)), Domain.inPExpCone())" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [], "source": [ "def max_worst_sinr(G, P, sigma):\n", " n = G.shape[0]\n", " with Model('MAX_WORST_SINR') as M:\n", " qz = M.variable('qz', n+1) # concatenation of q and z\n", " M.objective('Objective',ObjectiveSense.Minimize,Expr.neg(qz.index(n)))\n", " for i in range(n):\n", " A = np.zeros((n,n+1))\n", " b = np.zeros(n)\n", " for j in [k for k in range(n) if k!=i]:\n", " A[j,[i,j,n]] = [-1, 1, 1]\n", " b[j] = G[i,j]/G[i,i]\n", " A[i, [i, n]] = [-1, 1]\n", " b[i] = sigma[i]/G[i,i]\n", " # If any Gij == 0, then we filter out row j\n", " idx = np.nonzero(b)[0] \n", " logsumexp(M, A[idx,:], qz, np.log(b[idx]))\n", " \n", " logsumexp(M, np.eye(n), qz.slice(0,n), -np.log(P)*np.ones(n))\n", " M.setLogHandler(sys.stdout)\n", "\n", " M.solve()\n", " pt = np.exp(qz.level())\n", " return (pt[0:n], pt[n])" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [], "source": [ "P = 0.5\n", "\n", "G = np.array([[1.0,0.1,0.2,0.1,0.0],\n", " [0.1,1.0,0.1,0.1,0.0],\n", " [0.2,0.1,2.0,0.2,0.2],\n", " [0.1,0.1,0.2,1.0,0.1],\n", " [0.0,0.0,0.2,0.1,1.0]])\n", "\n", "sigma = 0.01*np.ones(G.shape[0])" ] }, { "cell_type": "code", "execution_count": 5, "metadata": { "scrolled": true }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Problem\n", " Name : MAX_WORST_SINR \n", " Objective sense : min \n", " Type : CONIC (conic optimization problem)\n", " Constraints : 84 \n", " Cones : 26 \n", " Scalar variables : 110 \n", " Matrix variables : 0 \n", " Integer variables : 0 \n", "\n", "Optimizer started.\n", "Presolve started.\n", "Linear dependency checker started.\n", "Linear dependency checker terminated.\n", "Eliminator started.\n", "Freed constraints in eliminator : 1\n", "Eliminator terminated.\n", "Eliminator - tries : 1 time : 0.00 \n", "Lin. dep. - tries : 1 time : 0.00 \n", "Lin. dep. - number : 0 \n", "Presolve terminated. Time: 0.01 \n", "Problem\n", " Name : MAX_WORST_SINR \n", " Objective sense : min \n", " Type : CONIC (conic optimization problem)\n", " Constraints : 84 \n", " Cones : 26 \n", " Scalar variables : 110 \n", " Matrix variables : 0 \n", " Integer variables : 0 \n", "\n", "Optimizer - threads : 20 \n", "Optimizer - solved problem : the primal \n", "Optimizer - Constraints : 26\n", "Optimizer - Cones : 26\n", "Optimizer - Scalar variables : 84 conic : 78 \n", "Optimizer - Semi-definite variables: 0 scalarized : 0 \n", "Factor - setup time : 0.00 dense det. time : 0.00 \n", "Factor - ML order time : 0.00 GP order time : 0.00 \n", "Factor - nonzeros before factor : 273 after factor : 274 \n", "Factor - dense dim. : 0 flops : 6.44e+03 \n", "ITE PFEAS DFEAS GFEAS PRSTATUS POBJ DOBJ MU TIME \n", "0 8.3e+00 2.0e+00 3.6e+01 0.00e+00 -2.256346207e+00 -2.484467505e+01 2.3e+00 0.03 \n", "1 9.8e-01 2.3e-01 2.5e+00 2.84e-01 -1.209531123e-01 -3.870013357e+00 2.7e-01 0.05 \n", "2 2.0e-01 4.8e-02 9.5e-02 1.53e+00 -1.990579522e-01 -7.785188954e-01 5.6e-02 0.05 \n", "3 4.9e-02 1.2e-02 1.1e-02 1.43e+00 -6.685338326e-01 -7.871072260e-01 1.4e-02 0.05 \n", "4 9.1e-03 2.1e-03 9.3e-04 1.10e+00 -7.570036183e-01 -7.776695214e-01 2.5e-03 0.05 \n", "5 6.7e-04 1.6e-04 1.9e-05 1.02e+00 -7.751417794e-01 -7.766579413e-01 1.9e-04 0.06 \n", "6 1.5e-05 3.6e-06 6.4e-08 1.00e+00 -7.765076649e-01 -7.765421638e-01 4.3e-06 0.06 \n", "7 2.3e-06 5.3e-07 3.7e-09 1.00e+00 -7.765307842e-01 -7.765358682e-01 6.3e-07 0.06 \n", "8 1.6e-07 3.8e-08 7.0e-11 1.00e+00 -7.765341634e-01 -7.765345269e-01 4.5e-08 0.06 \n", "9 2.1e-08 5.0e-09 3.3e-12 1.00e+00 -7.765343712e-01 -7.765344185e-01 5.8e-09 0.06 \n", "10 1.8e-08 4.1e-09 2.5e-12 1.00e+00 -7.765343736e-01 -7.765344130e-01 4.7e-09 0.06 \n", "Optimizer terminated. Time: 0.07 \n", "\n", "\n", "Interior-point solution summary\n", " Problem status : PRIMAL_AND_DUAL_FEASIBLE\n", " Solution status : OPTIMAL\n", " Primal. obj: -7.7653437363e-01 nrm: 5e+00 Viol. con: 1e-08 var: 0e+00 cones: 0e+00 \n", " Dual. obj: -7.7653441298e-01 nrm: 3e-01 Viol. con: 3e-17 var: 1e-09 cones: 0e+00 \n" ] } ], "source": [ "p1, t1 = max_worst_sinr(G, P, sigma)" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(array([0.10756629, 0.09148653, 0.09004626, 0.12322311, 0.0876778 ]),\n", " 2.173925182931828)" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "p1, t1" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([2.17392523, 2.17392526, 2.17392523, 2.17392522, 2.17392524])" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "SINR1 = (np.diagonal(G)*p1)/(np.dot(G,p1) - np.diagonal(G)*p1 + sigma)\n", "SINR1" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Maximizing the best SINR\n", "The solution to\n", "$$\n", "\\begin{array}{ll}\n", "\\text{maximize} & t_i \\\\\n", "\\text{subject to} & s_i \\leq t_i \\\\\n", " & \\sum_i p_i \\leq P\n", "\\end{array}\n", "$$\n", "is trivial; we choose the index $k$ maximizing $P_{ii}/\\sigma_i$ and take $p_k=P$ and $p_j=0,\\: j\\neq k$." ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [], "source": [ "def max_best_SINR(G,P,sigma):\n", " GSD = [G[i][i]/sigma[i] for i in range(G.shape[0])]\n", " P_max = max(GSD)\n", " #Thus, maximum of the best SINR is equal to...\n", " return(P_max*P)" ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "100.0" ] }, "execution_count": 9, "metadata": {}, "output_type": "execute_result" } ], "source": [ "max_best_SINR(G,P,sigma)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Maximizing average SINR\n", "We can maximize the average SINR as\n", "$$\n", "\\begin{array}{ll}\n", "\\text{maximize} & \\sum_i t_i \\\\\n", "\\text{subject to} & s_i \\geq t_i \\\\\n", " & 0 \\leq p_i \\leq P_i \\\\\n", " & \\sum_i p_i \\leq P,\n", "\\end{array}\n", "$$\n", "which corresponds to an intractable non-convex bilinear optimization problem. However, in the low-SINR regime, we can approximate the above problem by maximizing $\\sum_i \\log t_i$, or equivalently minimizing $\\prod_i t_i^{-1}$:\n", "$$\n", "\\begin{array}{ll}\n", "\\text{minimize} & \\prod_i t_i^{-1} \\\\\n", "\\text{subject to} & t_i \\left ( \\sum_{j\\neq i} G_{ij} p_j + \\sigma_i \\right ) G_{ii}^{-1} p_i^{-1} \\leq 1 \\\\\n", " & 0 \\leq p_i \\leq P_i \\\\\n", " & \\sum_i p_i \\leq P,\n", "\\end{array}\n", "$$\n", "which again corresponds to a geometric programming problem." ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [], "source": [ "def min_Geo_mean(G,P,sigma):\n", " n = G.shape[0]\n", " with Model('MIN_GEO_MEAN') as M:\n", " t = M.variable('t',n)\n", " x = M.variable('x',n)\n", " q = M.variable('q',n)\n", " \n", " logsumexp(M,np.eye(n),q,-np.log(P)*np.ones(n))\n", " \n", " M.constraint(Expr.hstack(x,Expr.constTerm(n, 1.0),Expr.neg(t)),Domain.inPExpCone())\n", " M.objective('Objective',ObjectiveSense.Minimize,Expr.sum(x))\n", " \n", " for i in range(n):\n", " A = np.zeros((n,n+1))\n", " b = np.zeros(n)\n", " for j in [k for k in range(n) if k!=i]:\n", " A[j,[i,j,n]] = [-1,1,1]\n", " b[j] = G[i,j]/G[i,i]\n", " A[i,[i,n]] = [-1,1]\n", " b[i] = sigma[i]/G[i,i]\n", " idx = np.nonzero(b)[0]\n", " logsumexp(M,A[idx,:],Expr.vstack(q,t.index(i)),np.log(b[idx]))\n", " \n", " M.setLogHandler(sys.stdout)\n", "\n", " M.solve()\n", " T = t.level()\n", " p = np.exp(q.level())\n", " return(T,p)" ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Problem\n", " Name : MIN_GEO_MEAN \n", " Objective sense : min \n", " Type : CONIC (conic optimization problem)\n", " Constraints : 99 \n", " Cones : 31 \n", " Scalar variables : 134 \n", " Matrix variables : 0 \n", " Integer variables : 0 \n", "\n", "Optimizer started.\n", "Presolve started.\n", "Linear dependency checker started.\n", "Linear dependency checker terminated.\n", "Eliminator started.\n", "Freed constraints in eliminator : 0\n", "Eliminator terminated.\n", "Eliminator - tries : 1 time : 0.00 \n", "Lin. dep. - tries : 1 time : 0.00 \n", "Lin. dep. - number : 0 \n", "Presolve terminated. Time: 0.00 \n", "Problem\n", " Name : MIN_GEO_MEAN \n", " Objective sense : min \n", " Type : CONIC (conic optimization problem)\n", " Constraints : 99 \n", " Cones : 31 \n", " Scalar variables : 134 \n", " Matrix variables : 0 \n", " Integer variables : 0 \n", "\n", "Optimizer - threads : 20 \n", "Optimizer - solved problem : the primal \n", "Optimizer - Constraints : 27\n", "Optimizer - Cones : 31\n", "Optimizer - Scalar variables : 99 conic : 93 \n", "Optimizer - Semi-definite variables: 0 scalarized : 0 \n", "Factor - setup time : 0.00 dense det. time : 0.00 \n", "Factor - ML order time : 0.00 GP order time : 0.00 \n", "Factor - nonzeros before factor : 185 after factor : 201 \n", "Factor - dense dim. : 0 flops : 3.06e+03 \n", "ITE PFEAS DFEAS GFEAS PRSTATUS POBJ DOBJ MU TIME \n", "0 1.2e+01 2.8e+00 7.0e+01 0.00e+00 6.454638549e+00 -2.495816205e+01 4.6e+00 0.01 \n", "1 1.3e+00 3.1e-01 3.5e+00 4.75e-01 4.463773399e+00 6.636911219e-02 5.1e-01 0.02 \n", "2 2.6e-01 6.2e-02 2.3e-01 1.32e+00 2.810914833e+00 2.070129028e+00 1.0e-01 0.02 \n", "3 4.0e-02 9.4e-03 1.3e-02 1.21e+00 2.324042616e+00 2.222420496e+00 1.6e-02 0.02 \n", "4 4.6e-03 1.1e-03 4.8e-04 1.04e+00 2.242616061e+00 2.231211157e+00 1.8e-03 0.02 \n", "5 2.0e-04 4.8e-05 4.5e-06 1.01e+00 2.233464306e+00 2.232960386e+00 8.0e-05 0.02 \n", "6 1.5e-05 3.5e-06 8.7e-08 1.00e+00 2.233112252e+00 2.233075749e+00 5.8e-06 0.02 \n", "7 1.8e-06 4.3e-07 3.7e-09 1.00e+00 2.233089609e+00 2.233085129e+00 7.1e-07 0.02 \n", "8 1.5e-07 3.6e-08 9.3e-11 1.00e+00 2.233086826e+00 2.233086444e+00 6.0e-08 0.03 \n", "9 4.1e-08 9.5e-09 1.3e-11 1.00e+00 2.233086648e+00 2.233086548e+00 1.5e-08 0.03 \n", "10 4.3e-08 9.3e-09 1.2e-11 1.00e+00 2.233086650e+00 2.233086552e+00 1.5e-08 0.03 \n", "11 3.6e-08 8.3e-09 1.0e-11 1.00e+00 2.233086644e+00 2.233086557e+00 1.3e-08 0.03 \n", "12 3.6e-08 8.3e-09 1.0e-11 1.00e+00 2.233086644e+00 2.233086557e+00 1.3e-08 0.03 \n", "13 3.6e-08 8.3e-09 1.0e-11 1.00e+00 2.233086644e+00 2.233086557e+00 1.3e-08 0.03 \n", "14 7.6e-09 1.8e-09 1.0e-12 1.00e+00 2.233086591e+00 2.233086572e+00 2.8e-09 0.03 \n", "Optimizer terminated. Time: 0.04 \n", "\n", "\n", "Interior-point solution summary\n", " Problem status : PRIMAL_AND_DUAL_FEASIBLE\n", " Solution status : OPTIMAL\n", " Primal. obj: 2.2330865908e+00 nrm: 5e+00 Viol. con: 3e-09 var: 0e+00 cones: 0e+00 \n", " Dual. obj: 2.2330865723e+00 nrm: 1e+00 Viol. con: 2e-16 var: 5e-10 cones: 0e+00 \n" ] } ], "source": [ "t2,p2 = min_Geo_mean(G, P, sigma)" ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(array([0.10622214, 0.1062226 , 0.07511098, 0.10622196, 0.10622232]),\n", " array([0.83111115, 1.00826399, 0.57707338, 0.62443057, 1.09194245]))" ] }, "execution_count": 12, "metadata": {}, "output_type": "execute_result" } ], "source": [ "p2,t2" ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([2.29586837, 2.74083876, 1.78081902, 1.86718244, 2.98005707])" ] }, "execution_count": 13, "metadata": {}, "output_type": "execute_result" } ], "source": [ "SINR2 = (np.diagonal(G)*p2)/(np.dot(G,p2) - np.diagonal(G)*p2 + sigma)\n", "SINR2" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Comparing the SINR for the cases above..." ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [ { "data": { "image/png": "iVBORw0KGgoAAAANSUhEUgAAAwwAAAJQCAYAAAAjRONDAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADl0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uIDIuMS4yLCBodHRwOi8vbWF0cGxvdGxpYi5vcmcvNQv5yAAAIABJREFUeJzt3X20XXV57+3vTYLyKra8SCTUaBG0xAgY3hWBtljQB3RQG/AISHRgi0qIilpaEBlAdegD1toWUGpEBXkapGLkoFChKFA0wRBApKSaSirSNJ5EKCIEfs8f2eSEZP8SAlnskFzXGHuw1pxzz3WzM0eST+aca1VrLQAAAMPZaKQHAAAA1l2CAQAA6BIMAABAl2AAAAC6BAMAANAlGAAAgC7BAAAAdAkGAACgSzAAAABdo0d6gDW1zTbbtHHjxo30GAAA8Jw2a9as/26tbbu67Z5zwTBu3LjMnDlzpMcAAIDntKr6j6eynUuSAACALsEAAAB0CQYAAKDrOXcPw3AeffTRzJ8/Pw8//PBIj8KzbJNNNsnYsWOz8cYbj/QoAADrpfUiGObPn58tt9wy48aNS1WN9Dg8S1prWbhwYebPn5+XvvSlIz0OAMB6ab24JOnhhx/O1ltvLRY2MFWVrbfe2pklAIABWi+CIYlY2ED5dQcAGKz1JhgAAIC1b724h2FF4z7yzbW6v3kff+Nqt6mqvP3tb8+XvvSlJMmSJUsyZsyY7L333pkxY8Yzev3dd989X/jCF7LbbrtlyZIl2WqrrXLBBRfk7W9/e5LkNa95TT73uc9ljz32eNqvsWjRolxyySU58cQTh11/9tln55JLLsmoUaOy0UYb5YILLsjee++dAw88MJ/61KcyceLEjBs3Lq95zWty+eWXJ0mmT5+eGTNmZNq0aZk2bVpOOeWU7LDDDnn44Yfz7ne/O1OnTn3a8wIA8OxwhmEt2XzzzXPHHXfk17/+dZLkmmuuyQ477LBW9r3ffvvlpptuSpLcdttt2WWXXZY9/5//+Z/85Cc/yatf/eqntK8lS5YMu3zRokX5u7/7u2HX3XzzzZkxY0ZuvfXWzJkzJ9dee2123HHHYbedOXNm7rzzzmHXTZo0KbNnz86NN96Ys88+O/fee+9TmhkAgJEjGNaiQw89NN/85tKzG5deemmOPvroZeu+//3vZ7/99svuu++e/fbbL3fffXeS5Nxzz83kyZOTJLfffnvGjx+fhx566En73X///ZcFwk033ZQ//dM/zezZs5ftd4899sioUaPyy1/+Mm9+85szYcKE7LPPPpkzZ06S5IwzzsgJJ5yQQw45JMcee2zuvPPO7LXXXtltt90yYcKE3HPPPfnIRz6Sf//3f89uu+2WU0455Umvf99992WbbbbJ85///CTJNttskxe/+MXD/gw++MEP5pxzzlnlz2nrrbfOTjvtlPvuu2/1P1QAAEaUYFiLjjrqqHz1q1/Nww8/nDlz5mTvvfdetu4Vr3hFbrjhhvzwhz/MmWeemVNPPTVJcvLJJ2fu3Lm54oorcvzxx+eCCy7IZptt9qT9Ln+G4aabbsoBBxyQ5z//+XnggQdy0003Zf/990+SfPSjH83uu++eOXPm5Jxzzsmxxx67bB+zZs3K17/+9VxyySU5//zzM2XKlMyePTszZ87M2LFj8/GPfzy/+7u/m9mzZ+eTn/zkk17/kEMOyb333pudd945J554Yv7lX/6l+zP4kz/5k9x6662ZO3dud5uf/exnefjhhzNhwoSn+JMFAGCkCIa1aMKECZk3b14uvfTSHHbYYU9at3jx4rz1rW/N+PHjM3Xq1GWX7Wy00UaZNm1ajjnmmLz+9a9f9pf/5Y0bNy6PPPJIfvGLX+THP/5xdtlll+y555655ZZbctNNN2W//fZLknzve9/LMccckyQ5+OCDs3DhwixevDhJcvjhh2fTTTdNkuy7774555xz8olPfCL/8R//sWx5zxZbbJFZs2blwgsvzLbbbptJkyZl2rRpw247atSonHLKKfmrv/qrldZddtll2XXXXfOyl70sU6ZMySabbLLK1wUAYOQJhrXs8MMPzwc/+MEnXY6UJKeddloOOuig3HHHHfnGN77xpM8OuOeee7LFFlvk5z//eXe/++67b6ZPn54xY8akqrLPPvvkxhtvzPe///3ss88+SZZ+kNmKnnjb0c0333zZsre97W258sors+mmm+YNb3hDvvOd76z2/2vUqFE58MAD87GPfSyf/exnl93YPJxjjjkmN9xwQ372s589afmkSZNy55135rvf/W4+8IEP5Be/+MVqXxcAgJElGNayyZMn5/TTT8+rXvWqJy1fvHjxspugl//X+cWLF2fKlCm54YYbsnDhwkyfPn3Y/e6///4577zzsu+++yZZGhAXX3xxtt9++7zwhS9MkhxwwAH5yle+kiS5/vrrs8022+QFL3jBSvv6yU9+kpe97GU56aSTcvjhh2fOnDnZcsst88ADDwz72nfffXfuueeeZc9nz56dl7zkJd2fwcYbb5ypU6fm05/+9LDr99133xxzzDH567/+6+4+AABYN6yXb6v6VN4GdVDGjh2bKVOmrLT8Qx/6UI477rice+65Ofjgg5ctnzp1ak488cTsvPPOueiii3LQQQflgAMOyHbbbfek799///0zderUZcEwZsyYPPbYY8suR0qW3tx8/PHHZ8KECdlss83yxS9+cdgZL7vssnz5y1/OxhtvnO233z6nn356fvu3fzv7779/xo8fn0MPPfRJ9zE8+OCDed/73pdFixZl9OjR2WmnnXLhhReu8ufwzne+M2eddVZ3/Yc//OHsscceOfXUU7Pllluucl8AAIycGu4ylnXZxIkT28yZM5+07K677sorX/nKEZqIkebXHwBgzVXVrNbaxNVtN7BLkqpqk6r6flXdVlV3VtXHhtnm+VV1WVXNrapbqmrcoOYBAADW3CDvYfhNkoNba69OsluSP6qqfVbY5p1J/k9rback5yX5xADnAQAA1tDAgqEt9eDQ042Hvla8/umIJE9caD89ye/XE2/rAwAAjLiBvktSVY2qqtlJ/ivJNa21W1bYZIck9yZJa21JksVJth7kTAAAwFM30GBorT3WWtstydgke1XV+BU2Ge5swkp3YVfVCVU1s6pmLliwYBCjAgAAw3hWPoehtbYoyfVJ/miFVfOT7JgkVTU6yVZJfjnM91/YWpvYWpu47bbbDnhaAADgCQP7HIaq2jbJo621RVW1aZI/yMo3NV+Z5LgkNyf54yTfaWvjfV7P2OoZ7+LJ+1u82k2qKm9/+9vzpS99KUmyZMmSjBkzJnvvvXdmzJixVsaYMmVKpk+fnnvvvTcbbbRuf+be3XffnXe/+91ZtGhRfvOb3+R1r3tdLrzwwlx//fX51Kc+lRkzZmTatGmZPHlyZs+enQkTJiRJxo8fnxkzZmTcuHEZN25cttxyy1RVfuu3fisXX3zxKj8wDgCAtW+QH9w2JskXq2pUlp7J+P9aazOq6swkM1trVya5KMmXqmpulp5ZOGqA8wzU5ptvnjvuuCO//vWvs+mmm+aaa65Z9snOa8Pjjz+eK664IjvuuGNuuOGGHHjggc94n0uWLMno0YM5BE466aRMnTo1RxxxRJLk9ttvH3a7sWPH5uyzz85ll1027Prrrrsu22yzTT760Y/mrLPOyuc+97mBzAsAPIes7X8cHglP4R+k1xWDfJekOa213VtrE1pr41trZw4tP30oFtJae7i19tbW2k6ttb1aaz8Z1DzPhkMPPTTf/OY3kySXXnppjj766GXrvv/972e//fbL7rvvnv322y933313kuTcc8/N5MmTkyz9S/X48ePz0EMPrbTv6667LuPHj8+f/dmf5dJLL02yNCLGjRuXRYsWLdtup512yv33358FCxbkyCOPzJ577pk999wzN954Y5KlnwZ9wgkn5JBDDsmxxx6befPm5XWve1322GOP7LHHHrnpppuW7fvEE0/Mrrvumje96U057LDDMn369CTJrFmz8vrXvz6vec1r8oY3vCH33XffSvPed999GTt27LLnr3rVq4b9mb3pTW/KnXfeuezn0bPvvvvmP//zP1e5DQAAa9+6fV3Lc8xRRx2Vr371q3n44YczZ86c7L333svWveIVr8gNN9yQH/7whznzzDNz6qmnJklOPvnkzJ07N1dccUWOP/74XHDBBdlss81W2vcTAfKWt7wlM2bMyKOPPpqNNtooRxxxRK644ookyS233JJx48blRS96UaZMmZKpU6fmBz/4QS6//PK8613vWravWbNm5etf/3ouueSSbLfddrnmmmty66235rLLLstJJ52UJPna176WefPm5fbbb8/nP//53HzzzUmSRx99NO973/syffr0zJo1K5MnT85f/MVfrDTv1KlTc/DBB+fQQw/Neeed96SoWd5GG22UD33oQznnnHNW+bO9+uqr8+Y3v3mV2wAAsPYN8pKkDc6ECRMyb968XHrppTnssMOetG7x4sU57rjjcs8996Sq8uijjyZZ+hfmadOmZcKECXn3u9+d/ffff6X9PvLII7nqqqty3nnnZcstt8zee++db3/723njG9+YSZMm5cwzz8zxxx+fr371q5k0aVKS5Nprr82PfvSjZfv41a9+lQceeCBJcvjhh2fTTTdNsjQA3vve92b27NkZNWpU/u3f/i1J8r3vfS9vfetbs9FGG2X77bfPQQcdlGTpvQl33HFH/vAP/zBJ8thjj2XMmDErzXz88cfnDW94Q66++up8/etfzwUXXJDbbrtt2J/b2972tpx99tn56U9/utK6gw46KPfff3+22267nHXWWav46QMAMAiCYS07/PDD88EPfjDXX399Fi5cuGz5aaedloMOOihXXHFF5s2b96R7EO65555sscUW+fnPfz7sPq+++uosXrx42WU9Dz30UDbbbLO88Y1vzL777pu5c+dmwYIF+ad/+qf85V/+ZZKllxTdfPPNy8JgeZtvvvmyx+edd15e9KIX5bbbbsvjjz+eTTbZJEnSu/e8tZZdd9112RmHVXnxi1+cyZMnZ/LkyRk/fnzuuOOOYbcbPXp0PvCBD+QTn1j5g76vu+66bL755nnHO96R008/Peeee+5qXxcAgLXHJUlr2eTJk3P66aevdM3+4sWLl90EPW3atCctnzJlSm644YYsXLhw2X0Cy7v00kvz+c9/PvPmzcu8efPy05/+NN/+9rfz0EMPparylre8Je9///vzyle+MltvvfRz7w455JB89rOfXbaP2bNnDzvv4sWLM2bMmGy00Ub50pe+lMceeyxJ8trXvjaXX355Hn/88dx///25/vrrkyS77LJLFixY8KRLlO68886V9nv11VcvO4vyi1/8IgsXLlzlTeDveMc7cu2112a4z9nYdNNN8+lPfzoXX3xxfvnLld51FwCAAVo/zzCM4F3nY8eOzZQpU1Za/qEPfSjHHXdczj333Bx88MHLlk+dOjUnnnhidt5551x00UU56KCDcsABB2S77bZLsvRswre+9a1ccMEFy75n8803z2tf+9p84xvfyKRJkzJp0qTsueeeTwqRz3zmM3nPe96TCRMmZMmSJTnggANy/vnnrzTXiSeemCOPPDL/+I//mIMOOmjZ2Ycjjzwy//zP/5zx48dn5513zt57752tttoqz3ve8zJ9+vScdNJJWbx4cZYsWZKTTz45u+6665P2++1vfztTpkxZdsbik5/8ZLbffvv8+Mc/Hvbn9rznPS8nnXTSsD+7JBkzZkyOPvro/O3f/m1OO+20YbcBAGDtq7XxsQfPpokTJ7aZM2c+adldd92VV77ylSM00frrwQcfzBZbbJGFCxdmr732yo033pjtt99+pMdaiV9/ANjAeFvVtaKqZrXWJq5uu/XzDANrxZve9KYsWrQojzzySE477bR1MhYAABgswUDXE/ctAACw4Vpvbnp+rl1a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\n", "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "fig,ax = plt.subplots(figsize = (13,10))\n", "bar_width = 0.35\n", "p_num = np.arange(1,G.shape[0]+1)\n", "\n", "B1 = ax.bar(p_num,SINR1,bar_width,label = 'Max Worst SINR')\n", "B2 = ax.bar(p_num+bar_width,SINR2,bar_width,label = 'Max Average SINR')\n", "\n", "ax.set_ylabel('SINR')\n", "ax.set_xticks(p_num + bar_width/2)\n", "x_tiK = ['p{}'.format(i+1) for i in range(G.shape[0])]\n", "ax.set_xticklabels(x_tiK)\n", "ax.set_xlabel('Transmitter')\n", "ax.legend()\n", "plt.show()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\"Creative
This work is licensed under a Creative Commons Attribution 4.0 International License. The **MOSEK** logo and name are trademarks of Mosek ApS. The code is provided as-is. Compatibility with future release of **MOSEK** or the `Fusion API` are not guaranteed. For more information contact our [support](mailto:support@mosek.com). " ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.6.4" } }, "nbformat": 4, "nbformat_minor": 2 }