{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "![MOSEK ApS](https://www.mosek.com/static/images/branding/webgraphmoseklogocolor.png )" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Wasserstein Barycenters using Mosek" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Wasserstein Distance is a way to measure the distance between two probabilty distributions. It allows to summarize, compare, match and reduce the dimensionality of the emprical probability measures to carry out some machine learning fundamentals." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Wasserstein distance of order $p$ between two probabilty measures $\\mu$ and $\\upsilon$ in $P(\\Omega)$ is defined as:\n", "
\n", "
\n", "$$W_p(\\mu,\\upsilon) \\overset{\\underset{\\mathrm{def}}{}}{=} \\bigg( \\underset{\\pi \\in \\Pi{(\\mu, \\upsilon)}}{\\mbox{inf}} \\int_{\\Omega^2} D(X_i,Y_j)^p d\\pi(x,y)\\bigg)^{1/p}\n", "$$\n", "
\n", "where $\\Pi(\\mu, \\upsilon)$ is the set of all probability measures on $\\Omega^2$" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "If the distributions are discrete $W_p(\\mu,\\upsilon)$ is equilavent to the objective of the following LP model:\n", "
\n", "
\n", "$$ \\mbox{minimize} \\quad \\sum_{i=1}\\sum_{j=1} D(X_i,Y_j)^p\\pi_{ij}$$\n", "
\n", "$$ \\mbox{st.} \\quad \\sum_{j=1} \\pi_{ij} = \\mu_i , \\quad i = 1,2,..n $$\n", "
\n", "$$ \\quad \\sum_{i=1} \\pi_{ij} = \\upsilon_j, \\quad j = 1,2,..m $$\n", "
\n", "$$ \\pi_{ij} \\geq 0, \\quad \\forall_{i,j}$$\n", "
\n", "where $D(X_i,Y_j)$ is the distance function on $\\Omega$." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "There are more efficient ways to approximate this metric but LP approach will be applied in order to compare the performance and modeling structure of Fusion, Pyomo and CVXPY." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Wasserstein Barycenter" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Wasserstein barycenter problem involves all Wasserstein distances from one to many measures. Given measures $\\upsilon_1,\\ldots,\\upsilon_N$ we want to find the measure which minimizes the sum of distances to the given measures, that is solve the problem:\n", "$$ \\mbox{minimize}_\\mu\\sum_{i=1} \\lambda_i W_p(\\mu,\\upsilon_i) $$\n", "for some fixed system $\\lambda_i $ of weights of distances to specific distributions that satisfies $$\\sum_{i=1}\\lambda_i = 1.$$\n", "For simplicity uniform weights are used in this problem. Then the barycenters problem becomes:\n", "$$ \\mbox{minimize}_\\mu \\frac1N \\sum_{i=1}^{N} W_p(\\mu,\\upsilon_i). $$" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In this problem, Wasserstein Barycenter of One's are visualized using images with size $28x28$ using $20$ handwriten '1' digits from MNIST database http://yann.lecun.com/exdb/mnist/. Computations are carried out by Intel(R) Xeon(R) CPU E5-2687W v4 @ 3.00GHz processor. Similar experiments are performed by Cuturi and Doucet in http://proceedings.mlr.press/v32/cuturi14.pdf." ] }, { "cell_type": "code", "execution_count": 1, "metadata": { "scrolled": false }, "outputs": [ { "data": { "image/png": "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\n", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "import struct\n", "import numpy as np\n", "%matplotlib inline\n", "import matplotlib.pyplot as plt\n", "\n", "#Define the number of images for the barycenter calculation\n", "n=20\n", "\n", "#Read the images from the file\n", "def read_idx(filename):\n", " with open(filename, 'rb') as f:\n", " zero, data_type, dims = struct.unpack('>HBB', f.read(4))\n", " shape = tuple(struct.unpack('>I', f.read(4))[0] for d in range(dims))\n", " return np.frombuffer(f.read(), dtype=np.uint8).reshape(shape)\n", " \n", "data = read_idx('train-images.idx3-ubyte')\n", "labels = read_idx('train-labels.idx1-ubyte')\n", "#Select the images\n", "ones = data[labels == 1]\n", "train_1 = ones[:n]\n", "\n", "plt.figure(figsize=(20,10))\n", "for i in range(10):\n", " plt.subplot(2,5,i+1)\n", " plt.imshow(ones[np.random.randint(0,ones.shape[0])])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Barycenters using Mosek Fusion" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The final barycenter problem is as follows. We choose $p=2$.\n", "
\n", "
\n", "$$ \\mbox{minimize} \\quad \\frac1N \\sum_{i,j,k}^{N} D(X_i,Y_j)^2\\pi_{ij}^k$$\n", "
\n", "$$\\mbox{st.} \\quad \\sum_{j=1} \\pi_{ij}^{k} = \\mu_i, \\quad \\forall_{k,i} \\quad (1)$$\n", "
\n", "$$ \\quad \\sum_{i=1} \\pi_{ij}^{k} = \\upsilon_j^{k}, \\quad \\forall_{k,j} \\quad (2) $$\n", "
\n", "$$ \\pi_{ij}^{k} \\geq 0 \\quad \\forall_{k,i,j}$$\n", "
\n", "where $D(X_i,Y_j)$ is the Euclidean distance between pixels and $N$ is the number of samples." ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [], "source": [ "from mosek.fusion import *\n", "import time\n", "import sys\n", "class Wasserstein_Fusion:\n", " \n", " def __init__(self):\n", " self.time = 0.0\n", " self.M = Model('Wasserstein')\n", " self.result = None\n", " \n", " \n", " def single_pmf(self, data = None, img=False):\n", " \n", " ''' Takes a image or array of images and extracts the probabilty mass function'''\n", " \n", " if not img:\n", " v=[]\n", " for image in data:\n", " arr = np.asarray(image).ravel(order='K')\n", " v.append(arr/np.sum(arr))\n", " else:\n", " v = np.asarray(data).ravel(order='K')\n", " v = v/np.sum(v)\n", " return v\n", " \n", " def ms_distance(self, m ,n, constant=False):\n", " \n", " ''' Squared Euclidean distance calculation between the pixels '''\n", " \n", " if constant:\n", " d = np.ones((m,m))\n", " else:\n", " d = np.empty((m,m))\n", " coor = []\n", " for i in range(n):\n", " for j in range(n):\n", " coor.append(np.array([i,j]))\n", " for i in range(m):\n", " for j in range(m):\n", " d[i][j] = np.linalg.norm(coor[i]-coor[j])**2\n", " return d\n", " \n", " def Wasserstein_Distance(self, bc ,data, img = False):\n", " \n", " ''' Calculation of wasserstein distance between a barycenter and an image by solving the minimization problem '''\n", " \n", " v = np.array(self.single_pmf(data, img))\n", " n = v.shape[0]\n", " d = self.ms_distance(n,data.shape[1])\n", " with Model('Wasserstein') as M:\n", " #Add variable\n", " pi = M.variable('pi',[n,n], Domain.greaterThan(0.0))\n", " \n", " #Add constraints\n", " M.constraint('c1' , Expr.sum(pi,0), Domain.equalsTo(v))\n", " M.constraint('c2' , Expr.sum(pi,1), Domain.equalsTo(bc))\n", " \n", " M.objective('Obj.' , ObjectiveSense.Minimize, Expr.dot(d, pi))\n", " \n", " M.solve()\n", " objective = M.primalObjValue()\n", " \n", " return objective\n", " \n", " def Wasserstein_BaryCenter(self,data):\n", "\n", " M = self.M\n", " start_time = time.time()\n", " k = data.shape[0]\n", " v = np.array(self.single_pmf(data))\n", " n = v.shape[1]\n", " d = self.ms_distance(n,data.shape[1])\n", "\n", " #Add variables \n", " mu = M.variable('Mu', n, Domain.greaterThan(0.0)) \n", " pi = (M.variable('Pi', [k,n,n] , Domain.greaterThan(0.0)))\n", "\n", " #Add constraints \n", "\n", " #Constraint (1)\n", " M.constraint('B', Expr.sub(Expr.sum(pi,1) , Var.repeat(mu,1,k).transpose()), Domain.equalsTo(0.0))\n", " #Constraint (2)\n", " M.constraint('C', Expr.sum(pi,2), Domain.equalsTo(v))\n", "\n", " M.objective('Obj' , ObjectiveSense.Minimize, Expr.sum(Expr.mul(Expr.mul(Expr.reshape(pi.asExpr(), k, n*n) , d.ravel()), 1/k)))\n", "\n", " M.setLogHandler(sys.stdout)\n", " M.solve()\n", " self.result = mu.level()\n", " M.selectedSolution(SolutionType.Interior)\n", " self.objective = M.primalObjValue()\n", " self.time = time.time() - start_time\n", "\n", " return mu.level()\n", "\n", " def reset(self):\n", " self.M = Model('Wasserstein')\n", " " ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Problem\n", " Name : Wasserstein \n", " Objective sense : min \n", " Type : LO (linear optimization problem)\n", " Constraints : 31360 \n", " Cones : 0 \n", " Scalar variables : 12293905 \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.35 \n", "Lin. dep. - number : 19 \n", "Presolve terminated. Time: 5.70 \n", "GP based matrix reordering started.\n", "GP based matrix reordering terminated.\n", "Problem\n", " Name : Wasserstein \n", " Objective sense : min \n", " Type : LO (linear optimization problem)\n", " Constraints : 31360 \n", " Cones : 0 \n", " Scalar variables : 12293905 \n", " Matrix variables : 0 \n", " Integer variables : 0 \n", "\n", "Optimizer - threads : 24 \n", "Optimizer - solved problem : the primal \n", "Optimizer - Constraints : 17440\n", "Optimizer - Cones : 0\n", "Optimizer - Scalar variables : 1395520 conic : 0 \n", "Optimizer - Semi-definite variables: 0 scalarized : 0 \n", "Factor - setup time : 16.44 dense det. time : 0.21 \n", "Factor - ML order time : 0.04 GP order time : 14.45 \n", "Factor - nonzeros before factor : 1.55e+06 after factor : 1.44e+07 \n", "Factor - dense dim. : 0 flops : 1.64e+10 \n", "Factor - GP saved nzs : 1.75e+06 GP saved flops : 3.15e+09 \n", "ITE PFEAS DFEAS GFEAS PRSTATUS POBJ DOBJ MU TIME \n", "0 5.5e+03 3.2e+02 8.3e+07 0.00e+00 1.182613040e+07 0.000000000e+00 4.9e+01 23.93 \n", "1 6.8e-01 4.0e-02 1.0e+04 -1.00e+00 1.120231068e+07 -1.638527125e+05 6.1e-03 24.96 \n", "2 5.8e-02 3.4e-03 8.8e+02 2.61e+01 1.558624710e+04 -2.985003979e+03 5.2e-04 26.57 \n", "3 4.5e-02 2.6e-03 6.8e+02 1.08e+01 3.256531514e+03 -6.820367762e+02 4.0e-04 27.67 \n", "4 4.2e-02 2.5e-03 6.4e+02 5.25e+00 2.407863248e+03 -4.995626420e+02 3.8e-04 28.62 \n", "5 3.8e-02 2.2e-03 5.7e+02 4.40e+00 1.571023848e+03 -3.171235705e+02 3.4e-04 29.52 \n", "6 3.3e-02 1.9e-03 5.0e+02 3.48e+00 1.104555995e+03 -2.125212567e+02 3.0e-04 30.36 \n", "7 2.9e-02 1.7e-03 4.3e+02 2.91e+00 7.928892307e+02 -1.415543053e+02 2.6e-04 31.30 \n", "8 1.2e-02 7.1e-04 1.8e+02 2.47e+00 2.252271180e+02 -1.976502285e+01 1.1e-04 32.37 \n", "9 5.2e-03 3.1e-04 7.9e+01 1.44e+00 9.137862868e+01 -2.802278257e+00 4.7e-05 33.33 \n", "10 1.2e-03 6.9e-05 1.8e+01 1.16e+00 2.223917710e+01 2.047778184e+00 1.1e-05 34.94 \n", "11 7.7e-04 4.5e-05 1.2e+01 1.04e+00 1.552925437e+01 2.419701859e+00 6.9e-06 35.99 \n", "12 3.9e-04 2.3e-05 5.9e+00 1.02e+00 9.411514139e+00 2.769092362e+00 3.5e-06 37.12 \n", "13 1.3e-04 8.1e-06 2.0e+00 1.01e+00 5.275173812e+00 3.000408169e+00 1.2e-06 38.69 \n", "14 5.5e-05 3.3e-06 8.2e-01 1.00e+00 3.990965725e+00 3.070294675e+00 4.9e-07 39.91 \n", "15 2.5e-05 1.5e-06 3.8e-01 1.00e+00 3.515474345e+00 3.095350472e+00 2.2e-07 40.99 \n", "16 1.2e-05 7.0e-07 1.8e-01 1.00e+00 3.304309669e+00 3.106260800e+00 1.1e-07 42.22 \n", "17 7.1e-06 4.3e-07 1.1e-01 1.00e+00 3.229689796e+00 3.109866447e+00 6.4e-08 43.16 \n", "18 3.1e-06 2.4e-07 4.8e-02 1.00e+00 3.165660320e+00 3.112133382e+00 2.8e-08 44.08 \n", "19 1.2e-06 9.5e-08 1.9e-02 1.00e+00 3.135045283e+00 3.113923931e+00 1.1e-08 45.09 \n", "20 2.5e-07 1.9e-08 3.9e-03 1.00e+00 3.119054866e+00 3.114731758e+00 2.3e-09 46.13 \n", "21 1.2e-09 9.1e-11 1.8e-05 1.00e+00 3.114878927e+00 3.114858639e+00 1.1e-11 47.44 \n", "22 3.4e-12 2.5e-13 4.8e-08 1.00e+00 3.114858825e+00 3.114858771e+00 2.8e-14 48.27 \n", "23 3.7e-13 5.7e-14 3.3e-13 1.00e+00 3.114858772e+00 3.114858772e+00 2.9e-18 49.09 \n", "Basis identification started.\n", "Basis identification terminated. Time: 0.51\n", "Optimizer terminated. Time: 53.52 \n", "\n", "\n", "Interior-point solution summary\n", " Problem status : PRIMAL_AND_DUAL_FEASIBLE\n", " Solution status : OPTIMAL\n", " Primal. obj: 3.1148587718e+00 nrm: 1e+00 Viol. con: 4e-13 var: 0e+00 \n", " Dual. obj: 3.1148587718e+00 nrm: 2e+02 Viol. con: 0e+00 var: 6e-14 \n", "\n", "Basic solution summary\n", " Problem status : PRIMAL_AND_DUAL_FEASIBLE\n", " Solution status : OPTIMAL\n", " Primal. obj: 3.1148587718e+00 nrm: 1e+00 Viol. con: 4e-17 var: 1e-06 \n", " Dual. obj: 3.1148587718e+00 nrm: 2e+02 Viol. con: 0e+00 var: 2e-09 \n", "\n", "Time Spent to solve problem with Fusion: \n", " 74.02755951881409\n", "Time Spent in solver: \n", " 53.52407097816467\n", "The average Wasserstein distance between digits and the barycenter: \n", " 3.1148587717997467\n" ] } ], "source": [ "fusion_model = Wasserstein_Fusion()\n", "f_bc = fusion_model.Wasserstein_BaryCenter(train_1)\n", "print('\\nTime Spent to solve problem with Fusion: \\n {0}'.format(fusion_model.time))\n", "print('Time Spent in solver: \\n {0}'.format(fusion_model.M.getSolverDoubleInfo(\"optimizerTime\")))\n", "print('The average Wasserstein distance between digits and the barycenter: \\n {0}'.format(fusion_model.objective))" ] }, { "cell_type": "code", "execution_count": 4, "metadata": { "scrolled": true }, "outputs": [ { "data": { "image/png": "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\n", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "fus_bc = np.reshape(f_bc,(28,28))\n", "plt.imshow(fus_bc)\n", "plt.title('Barycenter')\n", "plt.show()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Modeling the same problem with Pyomo" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The same problem is formulated using Pyomo and solved using Mosek. Unlike Fusion Pyomo requires rules and summations to formulate the problem." ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [], "source": [ "import pyomo.environ as pyo\n", "import time\n", "class Wasserstein_Pyomo:\n", " \n", " def __init__(self):\n", " self.time = 0.0\n", " self.result = None\n", " self._solver = 'mosek'\n", " self.M = pyo.ConcreteModel()\n", " \n", " \n", " def single_pmf(self, data = None, img=False):\n", " \n", " ''' Takes a image or array of images and extracts the probabilty mass function'''\n", " \n", " if not img:\n", " v=[]\n", " for image in data:\n", " arr = np.asarray(image).ravel(order='K')\n", " v.append(arr/np.sum(arr))\n", " else:\n", " v = np.asarray(data).ravel(order='K')\n", " v = v/np.sum(v)\n", " return v\n", " \n", " def ms_distance(self, m ,n, constant=False):\n", " \n", " ''' Squared Euclidean distance calculation between the pixels '''\n", " \n", " if constant:\n", " d = np.ones((m,m))\n", " else:\n", " d = np.empty((m,m))\n", " coor = []\n", " for i in range(n):\n", " for j in range(n):\n", " coor.append(np.array([i,j]))\n", " for i in range(m):\n", " for j in range(m):\n", " d[i][j] = np.linalg.norm(coor[i]-coor[j])**2\n", " return d\n", " \n", " def Wasserstein_BaryCenter(self,data):\n", " \n", " ''' Calculation of wasserstein barycenter of given images by solving the minimization problem '''\n", " \n", " M = self.M\n", " k = data.shape[0]\n", " v = np.array(self.single_pmf(data))\n", " n = v.shape[1]\n", " d = self.ms_distance(n,data.shape[1])\n", " \n", " #Define indices\n", " M.i = range(n)\n", " M.j = range(n)\n", " M.k = range(k)\n", " \n", " #Add variables\n", " M.pi = pyo.Var(M.k, M.i, M.j, domain = pyo.NonNegativeReals)\n", " M.mu = pyo.Var(M.i, domain = pyo.NonNegativeReals)\n", " M.t = pyo.Var(M.k, domain = pyo.NonNegativeReals)\n", " \n", " M.obj = pyo.Objective(expr = sum(M.t[k] for k in M.k)/k, sense= pyo.minimize)\n", " \n", " #Define constraint rules\n", " def c3_rule(model, k, j): #Rule for Constraint (3)\n", " return sum(model.pi[k,i,j] for i in model.i) == v[k][j]\n", " def c2_rule(model, k, i): #Rule for Constraint (2)\n", " return sum(model.pi[k,i,j] for j in model.j) == model.mu[i]\n", " def c1_rule(model, k): #Rule for Constraint (1)\n", " return sum(d[i][j]*model.pi[k,i,j] for i in model.i for j in model.j) <= model.t[k]\n", " \n", " # Add Constraints\n", " M.c3 = pyo.Constraint(M.k, M.j , rule = c3_rule)\n", " M.c2 = pyo.Constraint(M.k, M.i , rule = c2_rule)\n", " M.c1 = pyo.Constraint(M.k, rule = c1_rule)\n", " \n", " return M\n", " \n", " def run(self,data):\n", " start_time = time.time()\n", " model = self.Wasserstein_BaryCenter(data)\n", " opt = pyo.SolverFactory(self._solver)\n", " self.result = opt.solve(model, tee = True)\n", " self.time = time.time() - start_time\n", " bc = []\n", " [bc.append(model.mu[i]()) for i in range(data.shape[1]*data.shape[2])]\n", " return np.array(bc)\n", " \n", " def reset(self):\n", " self.M = pyo.ConcreteModel()\n", " " ] }, { "cell_type": "code", "execution_count": 6, "metadata": { "scrolled": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Problem\n", " Name : \n", " Objective sense : min \n", " Type : LO (linear optimization problem)\n", " Constraints : 31380 \n", " Cones : 0 \n", " Scalar variables : 12293924 \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.39 \n", "Lin. dep. - number : 19 \n", "Presolve terminated. Time: 9.03 \n", "GP based matrix reordering started.\n", "GP based matrix reordering terminated.\n", "Problem\n", " Name : \n", " Objective sense : min \n", " Type : LO (linear optimization problem)\n", " Constraints : 31380 \n", " Cones : 0 \n", " Scalar variables : 12293924 \n", " Matrix variables : 0 \n", " Integer variables : 0 \n", "\n", "Optimizer - threads : 24 \n", "Optimizer - solved problem : the primal \n", "Optimizer - Constraints : 17440\n", "Optimizer - Cones : 0\n", "Optimizer - Scalar variables : 1395520 conic : 0 \n", "Optimizer - Semi-definite variables: 0 scalarized : 0 \n", "Factor - setup time : 16.13 dense det. time : 0.22 \n", "Factor - ML order time : 0.04 GP order time : 14.46 \n", "Factor - nonzeros before factor : 1.55e+06 after factor : 1.44e+07 \n", "Factor - dense dim. : 0 flops : 1.64e+10 \n", "Factor - GP saved nzs : 1.75e+06 GP saved flops : 3.15e+09 \n", "ITE PFEAS DFEAS GFEAS PRSTATUS POBJ DOBJ MU TIME \n", "0 5.5e+03 3.2e+02 8.3e+07 0.00e+00 1.182613040e+07 0.000000000e+00 4.9e+01 26.72 \n", "1 6.8e-01 4.0e-02 1.0e+04 -1.00e+00 1.120231111e+07 -1.638527136e+05 6.1e-03 27.80 \n", "2 5.8e-02 3.4e-03 8.8e+02 2.61e+01 1.558624799e+04 -2.985004062e+03 5.2e-04 29.37 \n", "3 4.5e-02 2.6e-03 6.8e+02 1.08e+01 3.256531589e+03 -6.820367758e+02 4.0e-04 30.39 \n", "4 4.2e-02 2.5e-03 6.4e+02 5.25e+00 2.407863322e+03 -4.995626462e+02 3.8e-04 31.33 \n", "5 3.8e-02 2.2e-03 5.7e+02 4.40e+00 1.571023931e+03 -3.171235815e+02 3.4e-04 32.18 \n", "6 3.3e-02 1.9e-03 5.0e+02 3.48e+00 1.104556065e+03 -2.125212675e+02 3.0e-04 33.06 \n", "7 2.9e-02 1.7e-03 4.3e+02 2.91e+00 7.928892926e+02 -1.415543160e+02 2.6e-04 34.05 \n", "8 1.2e-02 7.1e-04 1.8e+02 2.47e+00 2.252273003e+02 -1.976505585e+01 1.1e-04 35.13 \n", "9 5.2e-03 3.1e-04 7.9e+01 1.44e+00 9.137867985e+01 -2.802280352e+00 4.7e-05 36.09 \n", "10 1.2e-03 6.9e-05 1.8e+01 1.16e+00 2.223918431e+01 2.047776659e+00 1.1e-05 37.94 \n", "11 7.7e-04 4.5e-05 1.2e+01 1.04e+00 1.552926266e+01 2.419700435e+00 6.9e-06 38.99 \n", "12 3.9e-04 2.3e-05 5.9e+00 1.02e+00 9.413170641e+00 2.768991242e+00 3.5e-06 39.96 \n", "13 1.3e-04 8.1e-06 2.0e+00 1.01e+00 5.274879516e+00 3.000437008e+00 1.2e-06 41.68 \n", "14 5.5e-05 3.3e-06 8.2e-01 1.00e+00 3.991039163e+00 3.070294699e+00 4.9e-07 42.90 \n", "15 2.5e-05 1.5e-06 3.8e-01 1.00e+00 3.515553240e+00 3.095347848e+00 2.2e-07 44.03 \n", "16 1.2e-05 7.0e-07 1.8e-01 1.00e+00 3.304324846e+00 3.106260526e+00 1.1e-07 45.22 \n", "17 7.1e-06 4.3e-07 1.1e-01 1.00e+00 3.229734360e+00 3.109864486e+00 6.4e-08 46.19 \n", "18 3.1e-06 2.4e-07 4.8e-02 1.00e+00 3.165698228e+00 3.112133278e+00 2.8e-08 47.16 \n", "19 1.2e-06 9.4e-08 1.9e-02 1.00e+00 3.135045322e+00 3.113924772e+00 1.1e-08 48.29 \n", "20 2.5e-07 1.9e-08 3.9e-03 1.00e+00 3.119048189e+00 3.114732226e+00 2.3e-09 49.29 \n", "21 1.2e-09 9.1e-11 1.8e-05 1.00e+00 3.114878911e+00 3.114858640e+00 1.1e-11 50.64 \n", "22 3.6e-12 2.5e-13 4.7e-08 1.00e+00 3.114858824e+00 3.114858771e+00 2.8e-14 51.46 \n", "23 4.1e-13 7.1e-14 2.0e-12 1.00e+00 3.114858772e+00 3.114858772e+00 2.9e-18 52.27 \n", "Basis identification started.\n", "Basis identification terminated. Time: 0.42\n", "Optimizer terminated. Time: 58.87 \n", "\n", "\n", "Interior-point solution summary\n", " Problem status : PRIMAL_AND_DUAL_FEASIBLE\n", " Solution status : OPTIMAL\n", " Primal. obj: 3.1148587718e+00 nrm: 6e+00 Viol. con: 7e-13 var: 0e+00 \n", " Dual. obj: 3.1148587718e+00 nrm: 2e+02 Viol. con: 0e+00 var: 4e-14 \n", "\n", "Basic solution summary\n", " Problem status : PRIMAL_AND_DUAL_FEASIBLE\n", " Solution status : OPTIMAL\n", " Primal. obj: 3.1148587718e+00 nrm: 6e+00 Viol. con: 4e-17 var: 1e-06 \n", " Dual. obj: 3.1148587718e+00 nrm: 2e+02 Viol. con: 0e+00 var: 2e-09 \n", "\n", "Time spent to solve problem with Pyomo: \n", " 900.9914240837097\n", "Time spent in solver: \n", " 58.86694002151489\n", "The average Wasserstein distance between digits and the barycenter: \n", " 3.114858771795237\n" ] } ], "source": [ "pyomo_model = Wasserstein_Pyomo()\n", "p_bc = pyomo_model.run(train_1)\n", "print('\\nTime spent to solve problem with Pyomo: \\n {0}'.format(pyomo_model.time))\n", "print('Time spent in solver: \\n {0}'.format(pyomo_model.result.solver.wallclock_time))\n", "print('The average Wasserstein distance between digits and the barycenter: \\n {0}'.format(pyomo_model.M.obj()))" ] }, { "cell_type": "code", "execution_count": 7, "metadata": { "scrolled": false }, "outputs": [ { "data": { "image/png": "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\n", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "pyo_bc = np.reshape(p_bc, (28,28))\n", "#print('Visualization of the barycenter:')\n", "plt.imshow(pyo_bc)\n", "plt.title('Barycenter')\n", "plt.show()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Modeling the same problem with CVXPY" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [], "source": [ "import cvxpy as cp\n", "import time\n", "class Wasserstein_CVXPY:\n", " \n", " def __init__(self):\n", " self.time = 0.0\n", " self.result = None\n", " self.prob = None\n", "\n", " def single_pmf(self, data = None, img=False):\n", " \n", " ''' Takes a image or array of images and extracts the probabilty mass function'''\n", " \n", " if not img:\n", " v=[]\n", " for image in data:\n", " arr = np.asarray(image).ravel(order='K')\n", " v.append(arr/np.sum(arr))\n", " else:\n", " v = np.asarray(data).ravel(order='K')\n", " v = v/np.sum(v)\n", " return v\n", " \n", " def ms_distance(self, m ,n, constant=False):\n", " \n", " ''' Squared Euclidean distance calculation between the pixels '''\n", " \n", " if constant:\n", " d = np.ones((m,m))\n", " else:\n", " d = np.empty((m,m))\n", " coor = []\n", " for i in range(n):\n", " for j in range(n):\n", " coor.append(np.array([i,j]))\n", " for i in range(m):\n", " for j in range(m):\n", " d[i][j] = np.linalg.norm(coor[i]-coor[j])**2\n", " return d\n", " \n", " def Wasserstein_Distance(self, bc ,data, img = False):\n", " \n", " ''' Calculation of wasserstein distance between a barycenter and an image by solving \n", " the minimization problem '''\n", " \n", " v = np.array(self.single_pmf(data, img))\n", " n = v.shape[0]\n", " d = self.ms_distance(n,data.shape[1])\n", " \n", " pi = cp.Variable((n,n), nonneg=True)\n", " obj = cp.Minimize((np.ones(n).T @ cp.multiply(d,pi) @ np.ones(n)))\n", " \n", " Cons=[]\n", " Cons.append((np.ones(n) @ pi).T == bc)\n", " Cons.append((pi @ np.ones(n)) == v)\n", " \n", " prob = cp.Problem(obj, constraints= Cons)\n", " \n", " return prob.solve(solver=cp.MOSEK, verbose = True)\n", " \n", " def Wasserstein_BaryCenter(self,data):\n", " \n", " ''' Calculation of wasserstein barycenter of given images by solving the minimization problem '''\n", " \n", " start_time = time.time()\n", " k = data.shape[0]\n", " v = np.array(self.single_pmf(data))\n", " n = v.shape[1]\n", " d = self.ms_distance(n,data.shape[1])\n", " \n", " #Add variables\n", " pi= []\n", " t= []\n", " mu = cp.Variable(n, nonneg = True)\n", " for i in range(k):\n", " pi.append(cp.Variable((n,n), nonneg = True))\n", " t.append(cp.Variable(nonneg = True))\n", " \n", " obj = cp.Minimize(np.sum(t)/k)\n", " \n", " #Add constraints\n", " Cons=[]\n", " for i in range(k):\n", " Cons.append( t[i] >= np.ones(n).T @ cp.multiply(d,pi[i]) @ np.ones(n) ) #Constraint (1)\n", " Cons.append( (np.ones(n) @ pi[i]).T == mu) #Constraint (2)\n", " Cons.append( (pi[i] @ np.ones(n)) == v[i]) #Constraint (3)\n", " \n", " self.prob = cp.Problem(obj, constraints= Cons)\n", " self.result = self.prob.solve(solver=cp.MOSEK,verbose = True)\n", " self.time = time.time() - start_time\n", " \n", " return mu.value\n", " \n", " def reset(self):\n", " self.prob = None\n", " self.result = None\n" ] }, { "cell_type": "code", "execution_count": 9, "metadata": { "scrolled": true }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n", "\n", "Problem\n", " Name : \n", " Objective sense : min \n", " Type : LO (linear optimization problem)\n", " Constraints : 12325304 \n", " Cones : 0 \n", " Scalar variables : 12293924 \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 : 2.55 \n", "Lin. dep. - number : 19 \n", "Presolve terminated. Time: 15.54 \n", "GP based matrix reordering started.\n", "GP based matrix reordering terminated.\n", "Problem\n", " Name : \n", " Objective sense : min \n", " Type : LO (linear optimization problem)\n", " Constraints : 12325304 \n", " Cones : 0 \n", " Scalar variables : 12293924 \n", " Matrix variables : 0 \n", " Integer variables : 0 \n", "\n", "Optimizer - threads : 24 \n", "Optimizer - solved problem : the primal \n", "Optimizer - Constraints : 17440\n", "Optimizer - Cones : 0\n", "Optimizer - Scalar variables : 1395520 conic : 0 \n", "Optimizer - Semi-definite variables: 0 scalarized : 0 \n", "Factor - setup time : 16.43 dense det. time : 0.21 \n", "Factor - ML order time : 0.04 GP order time : 14.57 \n", "Factor - nonzeros before factor : 1.55e+06 after factor : 1.44e+07 \n", "Factor - dense dim. : 0 flops : 1.64e+10 \n", "Factor - GP saved nzs : 1.75e+06 GP saved flops : 3.15e+09 \n", "ITE PFEAS DFEAS GFEAS PRSTATUS POBJ DOBJ MU TIME \n", "0 5.5e+03 3.2e+02 8.3e+07 0.00e+00 1.182613040e+07 0.000000000e+00 4.9e+01 34.19 \n", "1 6.8e-01 4.0e-02 1.0e+04 -1.00e+00 1.120231112e+07 -1.638527133e+05 6.1e-03 35.19 \n", "2 5.8e-02 3.4e-03 8.8e+02 2.61e+01 1.558624808e+04 -2.985004070e+03 5.2e-04 36.64 \n", "3 4.5e-02 2.6e-03 6.8e+02 1.08e+01 3.256531589e+03 -6.820367740e+02 4.0e-04 37.60 \n", "4 4.2e-02 2.5e-03 6.4e+02 5.25e+00 2.407863324e+03 -4.995626454e+02 3.8e-04 38.57 \n", "5 3.8e-02 2.2e-03 5.7e+02 4.40e+00 1.571023937e+03 -3.171235819e+02 3.4e-04 39.50 \n", "6 3.3e-02 1.9e-03 5.0e+02 3.48e+00 1.104556071e+03 -2.125212684e+02 3.0e-04 40.49 \n", "7 2.9e-02 1.7e-03 4.3e+02 2.91e+00 7.928892985e+02 -1.415543170e+02 2.6e-04 41.34 \n", "8 1.2e-02 7.1e-04 1.8e+02 2.47e+00 2.252273014e+02 -1.976505604e+01 1.1e-04 42.35 \n", "9 5.2e-03 3.1e-04 7.9e+01 1.44e+00 9.137868017e+01 -2.802280320e+00 4.7e-05 43.28 \n", "10 1.2e-03 6.9e-05 1.8e+01 1.16e+00 2.223918434e+01 2.047776637e+00 1.1e-05 44.86 \n", "11 7.7e-04 4.5e-05 1.2e+01 1.04e+00 1.552926278e+01 2.419700413e+00 6.9e-06 45.89 \n", "12 3.9e-04 2.3e-05 5.9e+00 1.02e+00 9.413192190e+00 2.768989925e+00 3.5e-06 46.88 \n", "13 1.3e-04 8.1e-06 2.0e+00 1.01e+00 5.274875679e+00 3.000437376e+00 1.2e-06 48.55 \n", "14 5.5e-05 3.3e-06 8.2e-01 1.00e+00 3.991040086e+00 3.070294698e+00 4.9e-07 49.88 \n", "15 2.5e-05 1.5e-06 3.8e-01 1.00e+00 3.515554299e+00 3.095347811e+00 2.2e-07 50.96 \n", "16 1.2e-05 7.0e-07 1.8e-01 1.00e+00 3.304325086e+00 3.106260520e+00 1.1e-07 52.26 \n", "17 7.1e-06 4.3e-07 1.1e-01 1.00e+00 3.229734970e+00 3.109864458e+00 6.4e-08 53.26 \n", "18 3.1e-06 2.4e-07 4.8e-02 1.00e+00 3.165698749e+00 3.112133276e+00 2.8e-08 54.22 \n", "19 1.2e-06 9.4e-08 1.9e-02 1.00e+00 3.135045328e+00 3.113924783e+00 1.1e-08 55.44 \n", "20 2.5e-07 1.9e-08 3.9e-03 1.00e+00 3.119048079e+00 3.114732233e+00 2.3e-09 56.55 \n", "21 1.2e-09 9.1e-11 1.8e-05 1.00e+00 3.114878914e+00 3.114858640e+00 1.1e-11 57.87 \n", "22 3.5e-12 2.5e-13 4.7e-08 1.00e+00 3.114858824e+00 3.114858771e+00 2.8e-14 58.71 \n", "23 4.6e-13 5.7e-14 2.8e-14 1.00e+00 3.114858772e+00 3.114858772e+00 2.9e-18 59.58 \n", "Basis identification started.\n", "Basis identification terminated. Time: 0.40\n", "Optimizer terminated. Time: 68.77 \n", "\n", "\n", "Interior-point solution summary\n", " Problem status : PRIMAL_AND_DUAL_FEASIBLE\n", " Solution status : OPTIMAL\n", " Primal. obj: 3.1148587718e+00 nrm: 6e+00 Viol. con: 3e-12 var: 0e+00 \n", " Dual. obj: 3.1148587718e+00 nrm: 2e+02 Viol. con: 9e-16 var: 6e-14 \n", "\n", "Basic solution summary\n", " Problem status : PRIMAL_AND_DUAL_FEASIBLE\n", " Solution status : OPTIMAL\n", " Primal. obj: 3.1148587718e+00 nrm: 6e+00 Viol. con: 1e-06 var: 0e+00 \n", " Dual. obj: 3.1148587718e+00 nrm: 2e+02 Viol. con: 2e-09 var: 2e-09 \n", "\n", "Time Spent to solve problem with CVXPY: \n", " 122.6916720867157\n", "Time Spent in solver: \n", " 68.76518487930298\n", "The average Wasserstein distance between digits and the barycenter: \n", " 3.1148587717983913\n" ] } ], "source": [ "cvxpy_model = Wasserstein_CVXPY()\n", "result = cvxpy_model.Wasserstein_BaryCenter(train_1)\n", "print('\\nTime Spent to solve problem with CVXPY: \\n {0}'.format(cvxpy_model.time))\n", "print('Time Spent in solver: \\n {0}'.format(cvxpy_model.prob.solver_stats.solve_time))\n", "print('The average Wasserstein distance between digits and the barycenter: \\n {0}'.format(cvxpy_model.result))" ] }, { "cell_type": "code", "execution_count": 10, "metadata": { "scrolled": true }, "outputs": [ { "data": { "image/png": "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\n", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "plt.imshow(np.reshape(result.squeeze(), (28,28)))\n", "plt.title('Barycenter')\n", "plt.show()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Also, when the log data from Mosek is investigated the number of variables are same for each modeling language. However, while Pyomo and Fusion having same number of constraints CVXPY has a lot of extra constraints that resulted from nonnegativity of the variables." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Comparison of Modeling Languages" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Time to solve the problem" ] }, { "cell_type": "code", "execution_count": 11, "metadata": { "scrolled": true }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Total Time:\n", "Fusion: 74.02755951881409\n", "Pyomo : 900.9914240837097\n", "CVXPY : 122.6916720867157\n", "\n", "Time spent in the solver:\n", "Fusion: 53.52407097816467\n", "Pyomo : 58.86694002151489\n", "CVXPY : 68.76518487930298\n" ] } ], "source": [ "print('Total Time:')\n", "print('Fusion: {0}'.format(fusion_model.time))\n", "print('Pyomo : {0}'.format(pyomo_model.time))\n", "print('CVXPY : {0}'.format(cvxpy_model.time))\n", "print('\\nTime spent in the solver:')\n", "print('Fusion: {0}'.format(fusion_model.M.getSolverDoubleInfo(\"optimizerTime\")))\n", "print('Pyomo : {0}'.format(pyomo_model.result.solver.wallclock_time))\n", "print('CVXPY : {0}'.format(cvxpy_model.prob.solver_stats.solve_time))" ] }, { "cell_type": "code", "execution_count": 12, "metadata": { "scrolled": true }, "outputs": [ { "data": { "image/png": "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\n", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "plt.style.use('seaborn')\n", "plt.figure(figsize=(10,4))\n", "\n", "total_t = [fusion_model.time, pyomo_model.time, cvxpy_model.time]\n", "solver_t = [fusion_model.M.getSolverDoubleInfo(\"optimizerTime\"), pyomo_model.result.solver.wallclock_time, cvxpy_model.prob.solver_stats.solve_time]\n", "\n", "#Total time plot\n", "plt.subplot(1,2,1)\n", "plt.bar(['Fusion', 'Pyomo', 'CVXPY'], height= total_t,\n", " width=0.5, color=(0.3, 0.6, 0.2, 0.5))\n", "plt.ylabel(\"Total Time (s)\")\n", "plt.title(\"Comparison of Total Time\")\n", "\n", "#Solver time plot\n", "plt.subplot(1,2,2)\n", "plt.bar(['Fusion', 'Pyomo', 'CVXPY'], height=solver_t,\n", " width=0.5, color=(0.5, 0.6, 0.9, 0.8))\n", "plt.ylabel(\"Solver Time (s)\")\n", "plt.title(\"Comparison of Solver Time\")\n", "plt.show()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Discussion\n", "\n", "Apparently, **Fusion passes the model data to Mosek faster** than the other ones. CVXPY is close to Fusion but its solver time is longer, mainly due to presolve (for example CVXPY enters variable bounds as constraints). In terms of total time Pyomo is behind the others because all the transformations are made in Python, as opposed to Fusion and CVXPY which call a C library. However, this is a huge model with 31 thousand constraints and 12 million variables and the difference will not be that big for normal-sized models.\n", "\n", "On the other hand, Fusion and CVXPY allow you to express model in vectorized form (using **matrix, vector** notation). Pyomo is mainly based on **sum expressions** that can be defined by **rule functions** which makes modelling much easier. Therefore the **time and effort spent on constructing the model in Pyomo was much smaller** than with the other languages.\n", "\n", "The decision of which one to use depends on the problem and the preferences of the user." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## CVXPY and Fusion on huge models" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ " $\\quad$The plots above show the performance of the modeling languages for 20 images. It is also reasonable to test the behaivor of solving times as the model gets larger and larger. In order to make this test same problem is solved with 50 images by using CVXPY and Fusion." ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [], "source": [ "n = 50\n", "train_1 = ones[:n]\n", "cvxpy_model.reset()\n", "fusion_model.reset()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### CVXPY" ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n", "\n", "Problem\n", " Name : \n", " Objective sense : min \n", " Type : LO (linear optimization problem)\n", " Constraints : 30812084 \n", " Cones : 0 \n", " Scalar variables : 30733634 \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 : 6.01 \n", "Lin. dep. - number : 49 \n", "Presolve terminated. Time: 37.73 \n", "GP based matrix reordering started.\n", "GP based matrix reordering terminated.\n", "Problem\n", " Name : \n", " Objective sense : min \n", " Type : LO (linear optimization problem)\n", " Constraints : 30812084 \n", " Cones : 0 \n", " Scalar variables : 30733634 \n", " Matrix variables : 0 \n", " Integer variables : 0 \n", "\n", "Optimizer - threads : 24 \n", "Optimizer - solved problem : the primal \n", "Optimizer - Constraints : 43692\n", "Optimizer - Cones : 0\n", "Optimizer - Scalar variables : 3560928 conic : 0 \n", "Optimizer - Semi-definite variables: 0 scalarized : 0 \n", "Factor - setup time : 152.40 dense det. time : 0.58 \n", "Factor - ML order time : 77.89 GP order time : 70.64 \n", "Factor - nonzeros before factor : 4.53e+06 after factor : 9.72e+07 \n", "Factor - dense dim. : 0 flops : 3.04e+11 \n", "Factor - GP saved nzs : 3.57e+07 GP saved flops : 5.09e+11 \n", "ITE PFEAS DFEAS GFEAS PRSTATUS POBJ DOBJ MU TIME \n", "0 3.8e+03 1.0e+02 5.9e+07 0.00e+00 1.207747296e+07 0.000000000e+00 2.4e+01 195.47\n", "1 9.7e-01 2.6e-02 1.5e+04 -1.00e+00 1.138202629e+07 -1.932435859e+05 6.1e-03 199.68\n", "2 1.7e-01 4.7e-03 2.7e+03 4.69e+01 2.749170572e+04 -2.705073018e+03 1.1e-03 206.20\n", "3 1.2e-01 3.3e-03 1.9e+03 8.18e+00 4.793007222e+03 -5.773295566e+02 7.6e-04 211.01\n", "4 1.1e-01 3.1e-03 1.7e+03 3.34e+00 3.771396588e+03 -4.640287740e+02 7.1e-04 214.99\n", "5 1.1e-01 2.9e-03 1.6e+03 3.09e+00 3.173273039e+03 -3.951025274e+02 6.7e-04 219.11\n", "6 9.7e-02 2.6e-03 1.5e+03 2.94e+00 2.470985631e+03 -3.117937667e+02 6.1e-04 223.02\n", "7 6.5e-02 1.8e-03 1.0e+03 2.74e+00 1.021523834e+03 -1.260039800e+02 4.1e-04 227.61\n", "8 8.4e-03 2.3e-04 1.3e+02 2.13e+00 8.372742526e+01 -2.798064226e+00 5.2e-05 234.39\n", "9 4.0e-03 1.1e-04 6.1e+01 1.18e+00 3.888935256e+01 -6.475636806e-01 2.5e-05 240.88\n", "10 2.0e-03 5.4e-05 3.1e+01 1.09e+00 2.102550501e+01 1.461108737e+00 1.2e-05 245.43\n", "11 1.6e-03 4.5e-05 2.5e+01 1.04e+00 1.781785581e+01 1.824394084e+00 1.0e-05 249.44\n", "12 1.4e-03 4.0e-05 2.2e+01 1.03e+00 1.560289396e+01 1.976506458e+00 8.7e-06 253.43\n", "13 1.2e-03 3.1e-05 1.9e+01 1.03e+00 1.404619009e+01 2.298815530e+00 7.5e-06 257.53\n", "14 1.1e-03 2.8e-05 1.7e+01 1.02e+00 1.287129495e+01 2.405788065e+00 6.7e-06 261.85\n", "15 8.5e-04 2.2e-05 1.3e+01 1.02e+00 1.082240990e+01 2.583882531e+00 5.3e-06 267.28\n", "16 7.5e-04 1.9e-05 1.1e+01 1.01e+00 9.871522333e+00 2.665118594e+00 4.6e-06 271.43\n", "17 6.3e-04 1.6e-05 9.6e+00 1.01e+00 8.789904345e+00 2.753524954e+00 3.9e-06 275.72\n", "18 2.6e-04 6.0e-06 3.9e+00 1.01e+00 5.486142029e+00 3.037439240e+00 1.6e-06 280.57\n", "19 2.1e-04 4.8e-06 3.2e+00 1.00e+00 5.049911898e+00 3.067269696e+00 1.3e-06 285.09\n", "20 1.1e-04 2.8e-06 1.7e+00 1.00e+00 4.192997697e+00 3.120001209e+00 6.9e-07 289.72\n", "21 8.3e-05 2.1e-06 1.3e+00 1.00e+00 3.937217141e+00 3.136827758e+00 5.2e-07 293.98\n", "22 4.3e-05 1.4e-06 6.7e-01 1.00e+00 3.575235178e+00 3.153092018e+00 2.7e-07 298.06\n", "23 2.6e-05 8.4e-07 4.0e-01 1.00e+00 3.417790137e+00 3.165912215e+00 1.6e-07 302.48\n", "24 1.3e-05 4.4e-07 2.1e-01 1.00e+00 3.306492542e+00 3.174555301e+00 8.5e-08 306.79\n", "25 5.5e-06 1.8e-07 8.5e-02 1.00e+00 3.233672573e+00 3.179897390e+00 3.5e-08 311.42\n", "26 7.7e-07 1.9e-08 1.2e-02 1.00e+00 3.190109552e+00 3.182620943e+00 4.8e-09 316.45\n", "27 3.3e-07 8.2e-09 5.1e-03 1.00e+00 3.185934904e+00 3.182730244e+00 2.1e-09 320.91\n", "28 2.7e-08 6.7e-10 4.1e-04 1.00e+00 3.183064915e+00 3.182803646e+00 1.7e-10 326.93\n", "29 6.5e-10 1.5e-11 9.3e-06 1.00e+00 3.182810905e+00 3.182805007e+00 3.8e-12 331.90\n", "30 3.4e-11 1.4e-13 3.8e-08 1.00e+00 3.182805061e+00 3.182805037e+00 1.5e-14 335.98\n", "Basis identification started.\n", "Basis identification terminated. Time: 1.86\n", "Optimizer terminated. Time: 361.28 \n", "\n", "\n", "Interior-point solution summary\n", " Problem status : PRIMAL_AND_DUAL_FEASIBLE\n", " Solution status : OPTIMAL\n", " Primal. obj: 3.1828050614e+00 nrm: 2e+01 Viol. con: 1e-10 var: 0e+00 \n", " Dual. obj: 3.1828050373e+00 nrm: 2e+02 Viol. con: 4e-16 var: 9e-14 \n", "\n", "Basic solution summary\n", " Problem status : PRIMAL_AND_DUAL_FEASIBLE\n", " Solution status : OPTIMAL\n", " Primal. obj: 3.1828050375e+00 nrm: 2e+01 Viol. con: 8e-07 var: 0e+00 \n", " Dual. obj: 3.1828050375e+00 nrm: 2e+02 Viol. con: 7e-15 var: 9e-14 \n", "\n", "Time Spent to solve problem with CVXPY: \n", " 512.632221698761\n", "Time Spent in solver: \n", " 361.275288105011\n", "The average Wasserstein distance between digits and the barycenter: \n", " 3.182805061402046\n" ] } ], "source": [ "res_cvx = cvxpy_model.Wasserstein_BaryCenter(train_1)\n", "print('\\nTime Spent to solve problem with CVXPY: \\n {0}'.format(cvxpy_model.time))\n", "print('Time Spent in solver: \\n {0}'.format(cvxpy_model.prob.solver_stats.solve_time))\n", "print('The average Wasserstein distance between digits and the barycenter: \\n {0}'.format(cvxpy_model.result))" ] }, { "cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [ { "data": { "image/png": "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\n", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "plt.style.use(\"default\")\n", "plt.figure(figsize=(3.3,3.3))\n", "plt.imshow(np.reshape(res_cvx.squeeze(), (28,28)))\n", "plt.title('Barycenter')\n", "plt.show()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Fusion" ] }, { "cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Problem\n", " Name : Wasserstein \n", " Objective sense : min \n", " Type : LO (linear optimization problem)\n", " Constraints : 78400 \n", " Cones : 0 \n", " Scalar variables : 30733585 \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.89 \n", "Lin. dep. - number : 49 \n", "Presolve terminated. Time: 13.31 \n", "GP based matrix reordering started.\n", "GP based matrix reordering terminated.\n", "Problem\n", " Name : Wasserstein \n", " Objective sense : min \n", " Type : LO (linear optimization problem)\n", " Constraints : 78400 \n", " Cones : 0 \n", " Scalar variables : 30733585 \n", " Matrix variables : 0 \n", " Integer variables : 0 \n", "\n", "Optimizer - threads : 24 \n", "Optimizer - solved problem : the primal \n", "Optimizer - Constraints : 43692\n", "Optimizer - Cones : 0\n", "Optimizer - Scalar variables : 3560928 conic : 0 \n", "Optimizer - Semi-definite variables: 0 scalarized : 0 \n", "Factor - setup time : 148.91 dense det. time : 0.60 \n", "Factor - ML order time : 77.43 GP order time : 67.30 \n", "Factor - nonzeros before factor : 4.53e+06 after factor : 9.72e+07 \n", "Factor - dense dim. : 0 flops : 3.04e+11 \n", "Factor - GP saved nzs : 3.57e+07 GP saved flops : 5.09e+11 \n", "ITE PFEAS DFEAS GFEAS PRSTATUS POBJ DOBJ MU TIME \n", "0 3.8e+03 1.0e+02 5.9e+07 0.00e+00 1.207747296e+07 0.000000000e+00 2.4e+01 166.33\n", "1 9.7e-01 2.6e-02 1.5e+04 -1.00e+00 1.138202628e+07 -1.932435836e+05 6.1e-03 170.72\n", "2 1.7e-01 4.7e-03 2.7e+03 4.69e+01 2.749170586e+04 -2.705073033e+03 1.1e-03 176.96\n", "3 1.2e-01 3.3e-03 1.9e+03 8.18e+00 4.793007234e+03 -5.773295562e+02 7.6e-04 181.92\n", "4 1.1e-01 3.1e-03 1.7e+03 3.34e+00 3.771396617e+03 -4.640287759e+02 7.1e-04 186.01\n", "5 1.1e-01 2.9e-03 1.6e+03 3.09e+00 3.173273061e+03 -3.951025289e+02 6.7e-04 189.91\n", "6 9.7e-02 2.6e-03 1.5e+03 2.94e+00 2.470985651e+03 -3.117937685e+02 6.1e-04 193.88\n", "7 6.5e-02 1.8e-03 1.0e+03 2.74e+00 1.021523849e+03 -1.260039818e+02 4.1e-04 198.83\n", "8 8.4e-03 2.3e-04 1.3e+02 2.13e+00 8.372815147e+01 -2.798139621e+00 5.2e-05 205.42\n", "9 4.0e-03 1.1e-04 6.1e+01 1.18e+00 3.888892297e+01 -6.475319201e-01 2.5e-05 211.68\n", "10 2.0e-03 5.4e-05 3.1e+01 1.09e+00 2.102558681e+01 1.461095266e+00 1.2e-05 216.47\n", "11 1.6e-03 4.5e-05 2.5e+01 1.04e+00 1.781792814e+01 1.824383152e+00 1.0e-05 221.00\n", "12 1.4e-03 4.0e-05 2.2e+01 1.03e+00 1.560302313e+01 1.976495303e+00 8.7e-06 225.04\n", "13 1.2e-03 3.1e-05 1.9e+01 1.03e+00 1.404624228e+01 2.298817130e+00 7.5e-06 228.87\n", "14 1.1e-03 2.8e-05 1.7e+01 1.02e+00 1.287134161e+01 2.405789410e+00 6.7e-06 233.13\n", "15 8.5e-04 2.2e-05 1.3e+01 1.02e+00 1.082241807e+01 2.583885971e+00 5.3e-06 238.64\n", "16 7.5e-04 1.9e-05 1.1e+01 1.01e+00 9.871538265e+00 2.665120797e+00 4.6e-06 242.84\n", "17 6.3e-04 1.6e-05 9.6e+00 1.01e+00 8.789936046e+00 2.753525214e+00 3.9e-06 247.20\n", "18 2.6e-04 6.0e-06 3.9e+00 1.01e+00 5.486120490e+00 3.037438811e+00 1.6e-06 252.18\n", "19 2.1e-04 4.8e-06 3.2e+00 1.00e+00 5.049889518e+00 3.067269697e+00 1.3e-06 256.42\n", "20 1.1e-04 2.8e-06 1.7e+00 1.00e+00 4.193063274e+00 3.120006971e+00 6.9e-07 261.06\n", "21 8.3e-05 2.1e-06 1.3e+00 1.00e+00 3.937318985e+00 3.136828389e+00 5.2e-07 265.26\n", "22 4.3e-05 1.4e-06 6.7e-01 1.00e+00 3.575228557e+00 3.153094207e+00 2.7e-07 269.78\n", "23 2.6e-05 8.4e-07 4.0e-01 1.00e+00 3.417767887e+00 3.165915025e+00 1.6e-07 274.64\n", "24 1.3e-05 4.4e-07 2.1e-01 1.00e+00 3.306549094e+00 3.174551508e+00 8.5e-08 278.83\n", "25 5.5e-06 1.8e-07 8.5e-02 1.00e+00 3.233604776e+00 3.179902683e+00 3.5e-08 283.63\n", "26 7.7e-07 1.3e-08 1.2e-02 1.00e+00 3.190062404e+00 3.182728989e+00 4.7e-09 289.08\n", "27 3.4e-07 5.7e-09 5.1e-03 1.00e+00 3.186012714e+00 3.182772597e+00 2.1e-09 293.89\n", "28 2.9e-08 4.9e-10 4.4e-04 1.00e+00 3.183083026e+00 3.182803490e+00 1.8e-10 299.39\n", "29 1.1e-09 1.5e-11 1.6e-05 1.00e+00 3.182815207e+00 3.182804980e+00 6.6e-12 303.47\n", "30 1.9e-11 1.7e-13 2.4e-08 1.00e+00 3.182805053e+00 3.182805037e+00 1.0e-14 307.66\n", "31 4.4e-12 1.4e-13 2.1e-12 1.00e+00 3.182805038e+00 3.182805038e+00 1.3e-18 312.21\n", "Basis identification started.\n", "Basis identification terminated. Time: 1.87\n", "Optimizer terminated. Time: 323.71 \n", "\n", "\n", "Interior-point solution summary\n", " Problem status : PRIMAL_AND_DUAL_FEASIBLE\n", " Solution status : OPTIMAL\n", " Primal. obj: 3.1828050375e+00 nrm: 1e+00 Viol. con: 7e-12 var: 0e+00 \n", " Dual. obj: 3.1828050375e+00 nrm: 2e+02 Viol. con: 0e+00 var: 9e-14 \n", "\n", "Basic solution summary\n", " Problem status : PRIMAL_AND_DUAL_FEASIBLE\n", " Solution status : OPTIMAL\n", " Primal. obj: 3.1828050375e+00 nrm: 1e+00 Viol. con: 4e-17 var: 8e-07 \n", " Dual. obj: 3.1828050375e+00 nrm: 2e+02 Viol. con: 0e+00 var: 7e-12 \n", "\n", "Time Spent to solve problem with Fusion: \n", " 369.8690595626831\n", "Time Spent in solver: \n", " 323.7116389274597\n", "The average Wasserstein distance between digits and the barycenter: \n", " 3.182805037502097\n" ] } ], "source": [ "res_f = fusion_model.Wasserstein_BaryCenter(train_1)\n", "print('\\nTime Spent to solve problem with Fusion: \\n {0}'.format(fusion_model.time))\n", "print('Time Spent in solver: \\n {0}'.format(fusion_model.M.getSolverDoubleInfo(\"optimizerTime\")))\n", "print('The average Wasserstein distance between digits and the barycenter: \\n {0}'.format(fusion_model.objective))" ] }, { "cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [ { "data": { "image/png": "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\n", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "plt.figure(figsize=(3.3,3.3))\n", "plt.imshow(np.reshape(res_f,(28,28)))\n", "plt.title('Barycenter')\n", "plt.show()" ] }, { "cell_type": "code", "execution_count": 18, "metadata": {}, "outputs": [ { "data": { "image/png": "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ODs7w87ODpmZmYiMjMTp06dx6NAhAHxCRkTaT+Njdh9UVlaG8+fPw97eXmqcqxpkACgvL0diYiJ69+4NAFAqlSguLsZPP/0klTlx4gSKi4ulMkRE2s7FxQUZGRlITU3FlClTEBYWhqysLAD3x+v6+vrCzc0No0ePxtdff43Dhw/j1KlT0vl8QkZE2kyjPbsREREIDg5Gq1atUFBQgIULF6KkpARhYWGQyWSYNWsWFi9ejPbt26N9+/ZYvHgxjIyMEBISAgDo2LEj/P39MWnSJGnCxeTJkxEUFMRxZkT0zNDX18fzzz8PAOjRowfS0tKwevXqahPRAKB79+7Q09PDxYsX0b17dz4hIyKtp9FkNycnB6+88gr++ecfWFtbw8vLC6mpqWjdujUA4H//+x9u376NqVOnoqioCL169cLBgwdhamoq1bF161bMnDlTWrVh6NChWLNmjUbuh4ioKRBCoKysrMZj586dQ0VFhTQ87MEnZD179gTAJ2REpF1kQgih6SA0raSkBAqFAsXFxTAzM9N0OEQate1k9d5Aqi6kx6u1LtuQbcxbb72FgIAAODk54caNG4iLi8MHH3yAhIQEtG3bFlu3bsWQIUNgZWWFrKwshIeHw9DQEGlpadDR0QFwf7Jwbm6uyhOy1q1bY8+ePU3iHomao093/qPpEJq8ySOs6lRe3XamSU1QIyKiurly5QpCQ0ORl5cHhUKBzp07IyEhAYMGDUJ2dja+//57rF69Gjdv3oSTkxMCAwPx7rvvSokuwCdkRKTdmOwSETVjGzZseOQxJycnJCYmPrEOCwsLxMbG1mdYRERNRpNajYGIiIiIqD4x2SUiIiIircVkl4iIiIi0FpNdIiIiItJaTHaJiIiISGsx2SUiIiIircVkl4iIiIi0FpNdIiIiItJaTHaJiIiISGsx2SUiIiIircVkl4iIiIi0lq6mAyAiomfXpzv/0XQITd7kEVaaDoGoWWPPLhERERFpLSa7RERERKS1mOwSERERkdZisktEREREWovJLhERERFpLSa7RERERKS1mOwSERERkdZisktEREREWovJLhERERFpLSa7RERERKS1mOwSERERkdZisktEREREWovJLhFRMxYTE4POnTvDzMwMZmZmUCqV2L9/v3S8rKwMM2bMgJWVFYyNjTF06FDk5OSo1HH58mUEBwfD2NgYVlZWmDlzJsrLyxv7VoiIGgSTXSKiZszR0REffPABTp48iZMnT2LgwIEYNmwYzp07BwCYNWsWdu3ahbi4OCQlJeHmzZsICgpCZWUlAKCyshKBgYEoLS1FUlIS4uLi8M033yA8PFyTt0VEVG90NR0AERGpLzg4WGV70aJFiImJQWpqKhwdHbFhwwZs2bIFvr6+AIDY2Fg4OTnh8OHDGDx4MA4ePIisrCxkZ2fDwcEBALBixQqMHz8eixYtgpmZWaPfExFRfWLPLhGRlqisrERcXBxKS0uhVCqRnp6OiooK+Pn5SWUcHBzg5uaG5ORkAEBKSgrc3NykRBcABg8ejLKyMqSnpz/yWmVlZSgpKVH5EBE1RUx2iYiaubNnz8LExARyuRyvvfYadu3aBVdXV+Tn50NfXx/m5uYq5W1tbZGfnw8AyM/Ph62trcpxc3Nz6OvrS2VqEhUVBYVCIX2cnJzq/8aIiOoBk10iombOxcUFGRkZSE1NxZQpUxAWFoasrKxHlhdCQCaTSdsP/vOjyjwsMjISxcXF0ic7O/vpboKIqIFwzC4RUTOnr6+P559/HgDQo0cPpKWlYfXq1Xj55ZdRXl6OoqIild7dgoIC9O7dGwBgZ2eHEydOqNRXVFSEioqKaj2+D5LL5ZDL5Q1wN0RE9Ys9u0REWkYIgbKyMnh4eEBPTw+HDh2SjuXl5SEzM1NKdpVKJTIzM5GXlyeVOXjwIORyOTw8PBo9diKi+saeXSKiZuytt95CQEAAnJyccOPGDcTFxeHYsWNISEiAQqHAxIkTER4eDktLS1hYWCAiIgLu7u7S6gx+fn5wdXVFaGgoli1bhsLCQkRERGDSpElciYGItAKTXSKiZuzKlSsIDQ1FXl4eFAoFOnfujISEBAwaNAgAsGrVKujq6mLUqFG4ffs2fHx88MUXX0BHRwcAoKOjg/j4eEydOhV9+vSBoaEhQkJCsHz5ck3eFhFRvWGyS0TUjG3YsOGxxw0MDBAdHY3o6OhHlmnVqhX27t1b36ERETUJHLNLRERERFqLyS4RERERaa0mk+xGRUVBJpNh1qxZ0r6ysjLMmDEDVlZWMDY2xtChQ5GTk6Ny3uXLlxEcHAxjY2NYWVlh5syZKC8vb+zwiYiIiKgJahLJblpaGj799FN07txZZf+sWbOwa9cuxMXFISkpCTdv3kRQUBAqKysB3H81ZmBgIEpLS5GUlIS4uDh88803CA8P18RtEBEREVETo/Fk9+bNmxgzZgzWr1+vsuh5cXExNmzYgBUrVsDX1xfdunVDbGwszp49i8OHDwO4vxZkVlYWYmNj0a1bN/j6+mLFihVYv34939NORERERJpPdqdNm4bAwEBpzccq6enpqKiogJ+fn7TPwcEBbm5uSE5OBgCkpKTAzc0NDg4OUpnBgwejrKwM6enpj7xmWVkZSkpKVD5EREREpH00uvRYXFwcTp06hbS0tGrH8vPzoa+vr9LbCwC2trbIz8+Xyjz8Oktzc3Po6+tLZWoSFRWFBQsW1MP9Fu0wAAAgAElEQVQdEBEREVFTprGe3ezsbLz++uuIjY2FgYFBrc8TQkAmk0nbD/7zo8o8LDIyEsXFxdInOzu7bsETERERUbOgsWQ3PT0dBQUF8PDwgK6uLnR1dZGYmIiPPvoIurq6sLW1RXl5OYqKilTOKygokHpz7ezsqvXgFhUVoaKiolqP74PkcjnMzMxUPkRERESkfTSW7Pr4+ODs2bPIyMiQPj169MCYMWOkf9bT08OhQ4ekc/Ly8pCZmYnevXsDAJRKJTIzM5GXlyeVOXjwIORyOTw8PBr9noiIiIioadHYmF1TU1O4ubmp7DM2NoalpaW0f+LEiQgPD4elpSUsLCwQEREBd3d3aTKbn58fXF1dERoaimXLlqGwsBARERGYNGkSe2uJiIiISLMT1J5k1apV0NXVxahRo3D79m34+Pjgiy++gI6ODgBAR0cH8fHxmDp1Kvr06QNDQ0OEhIRg+fLlGo6ciIiIiJqCJpXsHjt2TGXbwMAA0dHRiI6OfuQ5rVq1wt69exs4MiIiIiJqjjS+zi4RERERUUNhsktEREREWovJLhERERFpLSa7RERERKS1mOwSERERkdZisktEREREWovJLhERERFpLSa7RERERKS1mtRLJZqTbSc/0XQIzUJIj1c1HQIRERE9w5jsEhE1MiEEEhMTcfz4cfz555+4desWrK2t0a1bN/j6+sLJyUnTIRIRaQ0OYyAiaiS3b9/G4sWL4eTkhICAAMTHx+P69evQ0dHBb7/9hnfffRfOzs4YMmQIUlNTNR0uEZFWYM8uEVEj8fDwgJeXF9atW4fBgwdDT0+vWpm//voL27Ztw8svv4x58+Zh0qRJGoiUiEh7qN2zK4TA1atX8ddff6G0tLQ+YyIi0kpff/01vv76awQFBdWY6AJA69atERkZiYsXL6J///5PrDMqKgqenp4wNTWFjY0Nhg8fjgsXLqiU6d+/P2Qymcpn9OjRKmWKiooQGhoKhUIBhUKB0NBQXL9+Xe17JSJqKuqU7N65cwebNm2Cv78/FAoF7Ozs0LZtW5iZmcHFxQUzZszAmTNnGipWIqJmzdXVtdZl9fX10b59+yeWS0xMxLRp05CamopDhw7h7t278PPzq9YJMWnSJOTl5UmfTz5RnWQbEhKCjIwMJCQkICEhARkZGQgNDa11vERETVWthzHExMRgwYIFsLKywtChQ/Haa6+hZcuWMDQ0RGFhITIzM3H8+HH07t0bvr6+WLVqFZydnRsydiKiZishIQEmJibo27cvAODjjz/G+vXr4erqio8//hjm5ua1rudBGzduhI2NDdLT09GvXz9pv5GREezs7Gqs4/z580hISEBqaip69eoFAFi/fj2USiUuXLgAFxcXdW6RiKhJqHXP7r59+7Bnzx5kZmZi8eLFGD58ODw9PeHm5oZ+/fph6tSp2L59O/Lz89GvXz8cOHCgIeMmImrW/vvf/6KkpAQAcPbsWYSHh2PIkCH4448/MHv2bLXrLS4uBgBYWFio7N+6dSusrKzQqVMnRERE4MaNG9KxlJQUKBQKKdEFAC8vLygUCiQnJ9d4nbKyMpSUlKh8iIiaolr37O7Zs6dW5UxMTJ6qoSYiehZcunRJGtbwzTffICgoCIsXL8apU6cwZMgQteoUQmD27Nno27cv3NzcpP1jxoyBs7Mz7OzskJmZicjISJw+fRqHDh0CAOTn58PGxqZafTY2NsjPz6/xWlFRUViwYIFacRIRNaZ6WY2htLQUx48fR/v27dGuXbv6qJKISKvp6+vj1q1bAIDDhw9j3LhxAO73yKrbSzp9+nScOXMGSUlJKvsfXNHBzc0N7du3R48ePXDq1Cl0794dACCTyarVJ4SocT8AREZGqnRslJSUcH1gImqS1FqNYezYsVi7di2A+4+yevbsicDAQHTs2BHfffddvQZIRKSN+vbti9mzZ+P999/HTz/9hMDAQADAr7/+CkdHxzrXN2PGDHz33Xc4evToE8/v3r079PT0cPHiRQCAnZ0drly5Uq3c1atXYWtrW2MdcrkcZmZmKh8ioqZIrWT38OHD6N27NwBg165duHPnDgoLC7F06VI+1iIiqoU1a9ZAV1cXX3/9NWJiYtCyZUsAwP79++Hv71/reoQQmD59Onbu3IkjR47UamLwuXPnUFFRAXt7ewCAUqlEcXExfvrpJ6nMiRMnUFxcLLX1RETNlVrDGK5fvw5LS0sA92cCv/TSS1AoFHjxxRcxb968eg2QiEgbtWrVCnv37q22f9WqVXWqZ9q0adi2bRu+/fZbmJqaSmNsFQoFDA0N8fvvv2Pr1q0YMmQIrKyskJWVhfDwcHTr1g19+vQBAHTs2BH+/v6YNGmStCTZ5MmTERQUxJUYiKjZU6tn19HREWlpabhz5w4SEhIwaNAgAPdnARsYGNRrgERE2qKuL+CpTfmYmBgUFxejf//+sLe3lz5ffvklgPtjg7///nsMHjwYLi4umDlzJvz8/HD48GHo6OhI9WzduhXu7u7w8/ODn58fOnfujC1bttTtBomImiC1enanT5+OV155BQqFAtbW1hg4cCAAICkpCZ06darXAImItEW3bt0wc+ZMjB8/Hg4ODjWWEULg8OHDWLlyJfr164fIyMjH1imEeOxxJycnJCYmPjE2CwsLxMbGPrEcEVFzo1ayO2vWLHh6euLy5csYMmSI1Dtgb2/PMbtERI8QHx+PDz74AAsWLEDXrl3Ro0cPODg4wMDAAEVFRcjKykJKSgr09PQQGRmJyZMnazpkIqJmT+2lx/r06SON96ry4osvPnVARETaqn379tixYwdycnKwY8cO/PDDD0hOTsbt27dhZWWFbt26Yf369RgyZAhatFBrlBkRET2k1snuhx9+iClTpkAulz+xbEZGBq5cuYLBgwc/VXBERNrI0dERb7zxBt544w1Nh0JEpPVq3XWQnJyM1q1b44033sDRo0dVXjUJ3F8b8vPPP8fAgQMRHBwMfX39eg+WiIiIiKguat2z+9VXXyEtLQ1r1qxBcHAwbt++DSMjIxgYGKC4uBiVlZXo2LEjJk+ejP/85z8wMjJqyLiJiIiIiJ6oTmN2PT09sWnTJmzYsAHp6en4888/VcaaVS2KTkRERETUFKg1QU1XVxe9evVCr1696jseIiIiIqJ6w+m+RERERKS1mOwSEWnI8ePHMXbsWCiVSvz9998AgC1btiApKUnDkRERaQ8mu0REGvDNN99g8ODBMDQ0xM8//4yysjIAwI0bN7B48WINR0dEpD2Y7BIRacDChQuxbt06rF+/Hnp6etL+3r1749SpUxqMjIhIuzxVspuTk4PExETcuXOnvuIhInomXLhwAf369au238zMDNevX9dARERE2kmtZPf69esICgpCq1atMHDgQOTm5gIAJk6ciDfffLNeAyQi0kb29vb47bffqu1PSkpC27ZtNRAREZF2UivZDQ8Px61bt/Drr7+qvDzi//2//4f4+Ph6C46ISFu9+uqreP3113HixAnIZDLk5uZi69atiIiIwNSpUzUdHhGR1lBrnd39+/cjPj4ezz//vMr+Dh064M8//6yPuIiItNr//vc/FBcXY8CAAbhz5w769esHuVyOiIgITJ8+XdPhERFpDbWS3ZKSEpiamlbbX1RUBH19/acOiojoWbBo0SLMnTsXWVlZuHfvHlxdXWFiYqLpsIiItIpawxj69u2L7du3S9symQwAsHLlSnh7e9e6npiYGHTu3BlmZmYwMzODUqnE/v37peNlZWWYMWMGrKysYGxsjKFDhyInJ0eljsuXLyM4OBjGxsawsrLCzJkzUV5ers5tERE1OiMjI/To0QM9e/ZkoktE1ADU6tldtmwZ+vfvj1OnTqG8vBxvv/02MjMzkZOTgx9//LHW9Tg6OuKDDz6QhkNs2rQJw4YNw88//4xOnTph1qxZ2LNnD+Li4mBpaYnw8HAEBQUhPT0dOjo6qKysRGBgIKytrZGUlIRr164hLCwMQghER0erc2tERI3izp07iI6OxtGjR1FQUIB79+6pHOfyY0RE9UOtZNfd3R2nT59GdHQ0bty4gdzcXPj6+uL111+Hk5NTresJDg5W2V60aBFiYmKQmpoKR0dHbNiwAVu2bIGvry8AIDY2Fk5OTjh8+DAGDx6MgwcPIisrC9nZ2XBwcAAArFixAuPHj8eiRYtgZmamzu0RETW4f//73zh06BBGjhyJnj17Sk/IiIiofqmV7AL3e2WXLFlSb4FUVlZix44dKC0thVKpRHp6OioqKuDn5yeVcXBwgJubG5KTkzF48GCkpKTAzc1NSnQBYPDgwSgrK0N6ejoGDBhQ47XKysqktxUB98cgExE1pvj4eOzbtw99+vTRdChERFpN7WS3oqIC58+fr/Hx24MJ6pOcPXsWSqUSd+7cgYmJCXbt2gVXV1dkZGRAX18f5ubmKuVtbW2Rn58PAMjPz4etra3KcXNzc+jr60tlahIVFYUFCxbUOkYiovrWsmXLGif6EhFR/VIr2f3+++8RGhpaY0Ipk8lQWVlZ67pcXFyQkZGB69ev45tvvkFYWBgSExMfWV4IofK4r6ZHfw+XeVhkZCRmz54tbZeUlNRp+AUR0dNasWIF3nzzTaxbtw6tW7fWdDhERFpLrWR3ypQpCAwMxLx582Bra/tUY8309fWlCWo9evRAWloaVq9ejZdffhnl5eUoKipS6d0tKChA7969AQB2dnY4ceKESn1FRUWoqKio1uP7ILlcDrlcrnbMRERPq0ePHrhz5w7atm0LIyMj6OnpqRwvLCzUUGRERNpFrWQ3Pz8fc+bMaZDeCCEEysrK4OHhAT09PRw6dAijRo0CAOTl5SEzMxNLly4FACiVSixatAh5eXmwt7cHABw8eBByuRweHh71HhsRUX155ZVX8Pfff2Px4sVP3WlARESPplayO2zYMCQlJaFdu3ZPdfG33noLAQEBcHJywo0bNxAXF4djx44hISEBCoUCEydORHh4OCwtLWFhYYGIiAi4u7tLqzP4+fnB1dUVoaGhWLZsGQoLCxEREYFJkyZxJQYiatKSk5ORkpKCLl26PFU9UVFR2LlzJ3755RcYGhqid+/eWLJkCVxcXKQyZWVliIiIwPbt23H79m34+Phg7dq1cHR0lMpcvnwZ06ZNw5EjR2BoaIiQkBAsX76cLwoiomZPrWQ3JiYGo0ePRkpKCtzd3as9fps8eXKt6rly5QpCQ0ORl5cHhUKBzp07IyEhAYMGDQIArFq1Crq6uhg1apTUQH/xxRfQ0dEBAOjo6CA+Ph5Tp05Fnz59VBpoIqKm7IUXXsDt27efup7ExERMmzYNnp6euHv3LubOnQs/Pz9kZWXB2NgYALhmORE902RCCFHXkzZv3oz//Oc/kMlkMDc3rzZhLDc3t16DbGglJSVQKBQoLi6udY/wtpOfNHBU2iGkx6uaDoHqiL/t2qnLb7umNubgwYNYsGABFi1aVGOngbpPp65evQobGxskJiaiX79+KC4uhrW1NbZs2YKXX34ZAJCbmwsnJyfs27cPgwcPxv79+xEUFKSyZnlcXBzGjx+PgoKCWsWiTjsKAJ/u/Eet+3yWTB5hpekQSA38bT9ZXX/b6rYzavXszpkzB5GRkXj77behq6v26mVERM8sf39/AICPj4/K/qrVZOqyqs2DiouLAQAWFhYA0GBrlnO9ciJqLtTKVG/duoVx48Yx0SUiUtPRo0frvU4hBGbPno2+ffvCzc0NwP0JxQ2xZjnXKyei5kKtbDU0NBS7d+9GeHh4fcdDRPRM8Pb2rvc6p0+fjjNnziApKemJZZ92zXKuV05EzYVaya5cLsfChQtx8OBBdO7cudpYs8WLF9dLcERE2iQzMxNeXl5o0aIFzpw589iynTt3rlPdM2bMwHfffYcffvhBZZUFOzu7BlmznOuVE1FzoVay++OPP+KFF15ASUlJtR4ErhVJRFSzvn37Ij8/HzY2NujatStkMhlqmiNclzG7QgjMmDEDu3btwrFjx+Ds7KxynGuWE9GzTq1kNyUlpb7jICLSemfOnIG1tTUA4NKlS/VS57Rp07Bt2zZ8++23MDU1lcbYKhQKGBoacs1yInrmcYYZEVEjadWqFSZOnIjVq1fX2xsoY2JiAAD9+/dX2b9x40aMHz8eANcsJ6JnW62T3ZCQEHzyyScwNTVFSEjIY8tu27btqQMjItJGmzZtwgcffABTU9N6qa82S6UbGBggOjr6sS+IaNWqFfbu3VsvMRERNSW1TnYfbFDVeA8FERGB7ScRUWOrdbK7fft2FBQUwNTUFNu3b2/ImIiItBon8hIRNZ46jdm1t7dHXl4ebGxsGioeIiKt16FDhycmvIWFhY0UDRGRdqtTssvHb0RET2/BggVQKBSaDoOI6JnA1RiIiBrZ6NGj+YSMiKiR1DnZ3bJlyxNnEU+ePFntgIiItBnH6xIRNa46J7tLly5FixYtHnlcJpMx2SUiegQOByMialx1TnbPnj3Lx29ERGq6d++epkMgInqmPLqLtgZ8/EZEREREzUmdkl0+fiMiIiKi5qROye6bb74JExOThoqFiIiIiKhe1SnZjYqKgpGRUUPFQkT0TKioqMCECRPwxx9/aDoUIiKtV6dkl4iInp6enh527dql6TCIiJ4JTHaJiDTgxRdfxO7duzUdBhGR1uMb1IiINOD555/H+++/j+TkZHh4eMDY2Fjl+MyZMzUUGRGRdmGyS0SkAZ999hmee+45pKenIz09XeWYTCZjsktEVE9qnewqlcpar7ObnJysdkBERM+CS5cuaToEIqJnQq2T3f79+zdgGEREz6by8nJcunQJ7dq1g64uH7YREdW3WresUVFRDRkHEdEz5datW5gxYwY2bdoEAPj111/Rtm1bzJw5Ew4ODpgzZ46GIyQi0g5cjYGISAMiIyNx+vRpHDt2DAYGBtJ+X19ffPnllxqMjIhIu6j1zOzevXtYu3YtvvrqK1y+fBnl5eUqx3Nzc+slOCIibbV79258+eWX8PLyUpkP4erqit9//12DkRERaRe1enYXLVqE9957D35+frhy5QomTpyIgQMH4s6dO5g9e3Z9x0hEpHWuXr0KGxubavtLS0trPRmYiIieTK1kd9OmTfjss88wb9486OrqYvz48YiNjcXcuXNx5syZ+o6RiEjreHp6Ij4+XtquSnDXr18PpVKpqbCIiLSOWsMYcnNz0bVrVwCAsbExSkpKANx/I9D7779ff9EREWmpqKgo+Pv7IysrC3fv3sXq1atx7tw5pKSkIDExUdPhERFpDbV6dh0dHZGfnw8AaNeuHY4cOQIAyMjIgJ6eXv1FR0SkpXr37o0ff/wRt27dQrt27XDw4EHY2toiJSUFHh4emg6PiEhrqJXsBgUF4cCBAwCA6dOnIzIyEu7u7hgzZgxCQ0PrNUAiIm3l7u6OTZs2ITMzE1lZWYiNjYW7u3ud6vjhhx8QHBwMBwcHyGQy7N69W+X4+PHjIZPJVD5eXl4qZcrKyjBjxgxYWVnB2NgYQ4cORU5OzlPfHxFRU6DWMIaVK1dK//zKK6/AwcEBP/74I55//nmMGjWq3oIjItJWAwYMwNixYzFy5EgoFAq16yktLUWXLl0wYcIEvPTSSzWW8ff3x8aNG6VtfX19leOzZs3Cnj17EBcXB0tLS4SHhyMoKAjp6enQ0dFROzYioqZArWT3p59+goeHh9QIent7w9vbG5WVlfjpp5/Qs2fPeg2SiEjbuLu7Y968eZg+fTqGDBmC0NBQDBkypFoi+iQBAQEICAh4bBm5XA47O7sajxUXF2PDhg3YsmULfH19AQCxsbFwcnLC4cOHMXjw4DrFQ0TU1Kg1jEGpVOLatWvV9l+/fp2ziImIauGjjz7C33//jW+//RampqYICwuDnZ0dJk+eXO8T1I4dOwYbGxt06NABkyZNQkFBgXQsPT0dFRUV8PPzk/Y5ODjAzc0NycnJj6yzrKwMJSUlKh8ioqZIrWRXCFHjOpBFRUUwMjJ66qCIiJ4FLVq0gJ+fH7744gtcuXIFn3zyCX766ScMHDiw3q4REBCArVu34siRI1ixYgXS0tIwcOBAlJWVAQDy8/Ohr68Pc3NzlfNsbW2licg1iYqKgkKhkD5OTk71FjMRUX2q0zCGkJAQAPfXg3z11VdVXnFZWVmJjIyMahMfiIjo8fLz8xEXF4fY2FicOXMGnp6e9Vb3yy+/LP2zm5sbevTogdatWyM+Ph4jRox45HmP6tSoEhkZqfISoZKSEia8RNQk1alnVwjxyI+BgQFGjx6NLVu21Lq+qKgoeHp6wtTUFDY2Nhg+fDguXLigUqY2s4QvX76M4OBgGBsbw8rKCjNnzqz2CmMioqakpKQEGzduxKBBg+Dk5ISYmBgEBwfj119/xYkTJxrsuvb29mjdujUuXrwIALCzs0N5eTmKiopUyhUUFMDW1vaR9cjlcpiZmal8iIiaojr17G7fvh0A0KZNG8ybNw/GxsZPdfHExERMmzYNnp6euHv3LubOnQs/Pz9kZWVJdT9plnBlZSUCAwNhbW2NpKQkXLt2DWFhYRBCIDo6+qniIyJqKLa2tjA3N8eoUaOwePHieu3NfZxr164hOzsb9vb2AAAPDw/o6enh0KFD0mo6eXl5yMzMxNKlSxslJiKihqTWagxRUVEA7s/ivXjxImQyGdq3b1/n/7NPSEhQ2d64cSNsbGyQnp6Ofv361WqW8MGDB5GVlYXs7Gw4ODgAAFasWIHx48dj0aJF7G0goibp22+/ha+vL1q0UGvqhOTmzZv47bffpO1Lly4hIyMDFhYWsLCwwPz58/HSSy/B3t4ef/75J9566y1YWVnhxRdfBAAoFApMnDgR4eHhsLS0hIWFBSIiIuDu7i61u0REzZlarWxZWRmmTp0Ka2tr9OzZE56enrC2tsa0adOkSQ/qKC4uBgBYWFgAqN0s4ZSUFLi5uUmJLgAMHjwYZWVlSE9Pf2T8nEVMRJrk5+f31IkuAJw8eRLdunVDt27dAACzZ89Gt27d8M4770BHRwdnz57FsGHD0KFDB4SFhaFDhw5ISUmBqampVMeqVaswfPhwjBo1Cn369IGRkRH27NnDNXaJSCuo1bM7e/Zs7Nu3D19++SX69OkDIQR+/PFHzJ49Gy1atFBr+IAQArNnz0bfvn3h5uYGoHazhPPz86uNKzM3N4e+vv4jZxJHRUVhwYIFdY6RiOhp9O3bF7q6tWt2T506Vaty/fv3hxDikcer3nb5OAYGBoiOjubQLyLSSmoluzt27MD27dvh4+Mj7RsxYgRMTU0xZswYtRrM6dOn48yZM0hKSnpi2YdnCdc0Y/hxM4k5i5iINCEoKAhyuVzTYRARPVPUSnZv3LiBli1bVtvfsmVL3Lx5s871zZgxA9999x1++OEHODo6SvsfnCX8YO9uQUEBevfuLZV5eOZyUVERKioqHjmTWC6X8z84RNTo5syZw3kERESNTK0BY7169cLChQtVlvcqLy/H4sWL0atXr1rXI4TA9OnTsXPnThw5cgTOzs4qxx+cJVylapZwVbKrVCqRmZmJvLw8qczBgwchl8vh4eGhzu0RETWa9PR0xMbGYuvWrfj55581HQ4RkdZRq2d31apV8Pf3R6tWreDh4QGZTIaTJ08CqL7CwuNMmzYN27Ztk16XWTXGVqFQwNDQsFazhP38/ODq6orQ0FAsW7YMhYWFiIiIwKRJk9iDQkRNVkFBAUaPHo1jx47hueeegxACxcXFGDBgAOLi4mBtba3pEImItIJaPbvdunXDb7/9hrlz56JNmzZo1aoV5s2bh4sXL6Jr1661ricmJgbFxcXo378/7O3tpc+XX34plXnSLGEdHR3Ex8fDwMAAffr0wahRozB8+HAsX75cnVsjImoUM2bMQElJCc6dO4fCwkIUFRUhMzMTJSUlmDlzpqbDIyLSGnXq2f33v/+N1atXw9TUFKamppgxY8ZTXfxxM4ir1GaWcKtWrbB3796nioWIqDElJCTg8OHD6Nixo7TP1dUVH3/8scpyi0RE9HTq1LO7adMm3L59u6FiISJ6Zty7dw96enrV9uvp6eHevXsaiIiISDvVKdmtTU8sERE92cCBA/H6668jNzdX2vf333/jjTfeUFnWkYiInk6dx+w+au1aIiKqvTVr1uDGjRto06YN2rVrh+effx7Ozs64ceMGX+5ARFSP6rwaQ4cOHZ6Y8BYWFqodEBHRs8DJyQmnTp3CoUOH8Msvv0AIAVdXV2mlGSIiqh91TnYXLFgAhULRELEQET1zBg0ahEGDBmk6DCIirVXnZHf06NGwsbFpiFiIiLTeiRMnUFhYiICAAGnf5s2b8e6776K0tBTDhw9HdHQ03/JIRFRP6jRml+N1iYiezvz583HmzBlp++zZs5g4cSJ8fX0xZ84c7NmzB1FRURqMkIhIu3A1BiKiRpSRkaGy2kJcXBx69eqF9evXY/bs2fjoo4/w1VdfaTBCIiLtUqdhDFz7kYjo6RQVFcHW1lbaTkxMhL+/v7Tt6emJ7OxsTYRGRKSV1HpdMBERqcfW1haXLl0CAJSXl+PUqVNQKpXS8Rs3btT4sgkiIlIPk10iokbk7++POXPm4Pjx44iMjISRkRH+9a9/ScfPnDmDdu3aaTBCIiLtUufVGIiISH0LFy7EiBEj4O3tDRMTE2zatAn6+vrS8c8//xx+fn4ajJCISLsw2SUiakTW1tY4fvw4iouLYWJiAh0dHZXjO3bsgImJiYaiIyLSPkx2iYg04FEv57GwsGjkSIiItBvH7BIRERGR1mKyS0RERERai8kuEREREWktJrtEREREpLWY7BIRNWM//PADgoOD4eDgAJlMht27d6scF0Jg/vz5cHBwgKGhIfr3749z586plCkqKkJoaCgUCgUUCgVCQ0Nx/fr1xrwNIqIGw2SXiGlvs4kAABKXSURBVKgZKy0tRZcuXbBmzZoajy9duhQrV67EmjVrkJaWBjs7OwwaNAg3btyQyoSEhCAjIwMJCQlISEhARkYGQkNDG+sWiIgaFJceIyJqxgICAhAQEFDjMSEEPvzwQ8ydOxcjRowAAGzatAm2trbYtm0bXn31VZw/fx4JCQlITU1Fr169AADr16+HUqnEhQsX4OLi0mj3QkTUENizS0SkpS5duoT8/HyVN7LJ5XJ4e3sjOTkZAJCSkgKFQiElugDg5eUFhUIhlalJWVkZSkpKVD5ERE0Rk10iIi2Vn58PALC1tVXZb2trKx3Lz8+HjY1NtXNtbGykMjWJioqSxvgqFAo4OTnVY+RERPWHyS4RkZaTyWQq20IIlX0PH6+pzMMiIyNRXFwsfbKzs+svYCKiesQxu0REWsrOzg7A/d5be3t7aX9BQYHU22tnZ4crV65UO/fq1avVeoQfJJfLIZfL6zliIqL6x55dIiIt5ezsDDs7Oxw6dEjaV15e/v/bu/uYKuv/j+OvoyghcRPecNMOiHpWKmmbKUILsLSkqbXKUhvRVLyhLL6WJmHzdAfNlTqnNXMlZjmdNW3ZMslNbFneVORNzEkxtY0TmXiAIlD5/P7w57VOQDcKHs7F87Fdq+vz+VyX78tdvvfy4vIclZaWKjU1VZKUkpIir9er/fv3W2v27dsnr9drrQGAQMaTXQAIYPX19aqoqLD2KysrVVZWpqioKMXHxysvL0+FhYVyuVxyuVwqLCxUr169NG3aNEnS4MGDNX78eOXk5GjNmjWSpFmzZmnChAl8EgMAWyDsAkAAO3jwoMaMGWPtz58/X5KUnZ2t4uJiLVy4UA0NDcrNzVVNTY2Sk5O1c+dOhYWFWce89957euKJJ6xPbZg0aVKbn9sLAIGGsAsAASwjI0PGmDbnHQ6H3G633G53m2uioqL07rvvdkB1AOB/vLMLAAAA2yLsAgAAwLYIuwAAALAtwi4AAABsi7ALAAAA2yLsAgAAwLYIuwAAALAtwi4AAABsi7ALAAAA2yLsAgAAwLb8Gnb37NmjiRMnKi4uTg6HQ9u2bfOZN8bI7XYrLi5OISEhysjI0NGjR33W1NTUKCsrSxEREYqIiFBWVpbOnj17NS8DAAAAnZRfw+5vv/2m4cOHa9WqVa3OL126VMuWLdOqVat04MABxcTEaNy4caqrq7PWTJs2TWVlZdqxY4d27NihsrIyZWVlXa1LAAAAQCcW5M9fPDMzU5mZma3OGWO0YsUKFRQU6L777pMkrV+/XtHR0dq4caNmz56t8vJy7dixQ1999ZWSk5MlSWvXrlVKSoqOHTumG2644apdCwAAADqfTvvObmVlpTwej+68805rLDg4WOnp6dq7d68k6csvv1RERIQVdCVp9OjRioiIsNa0prGxUbW1tT4bAAAA7KfThl2PxyNJio6O9hmPjo625jwej/r169fi2H79+llrWlNUVGS94xsRESGn09mOlQMAAKCz6LRh9xKHw+Gzb4zxGfvrfGtr/io/P19er9faTp061X4FAwAAoNPw6zu7fycmJkbSxae3sbGx1nh1dbX1tDcmJkY///xzi2N/+eWXFk+E/yw4OFjBwcHtXDEAAAA6m077ZDcxMVExMTEqKSmxxpqamlRaWqrU1FRJUkpKirxer/bv32+t2bdvn7xer7UGAAAAXZdfn+zW19eroqLC2q+srFRZWZmioqIUHx+vvLw8FRYWyuVyyeVyqbCwUL169dK0adMkSYMHD9b48eOVk5OjNWvWSJJmzZqlCRMm8EkMAAAA8G/YPXjwoMaMGWPtz58/X5KUnZ2t4uJiLVy4UA0NDcrNzVVNTY2Sk5O1c+dOhYWFWce89957euKJJ6xPbZg0aVKbn9sLAACArsWvYTcjI0PGmDbnHQ6H3G633G53m2uioqL07rvvdkB1AAAACHSd9p1dAAAA4EoRdgEAAGBbhF0AAADYFmEXAAAAtkXYBQCbc7vdcjgcPtulL+6RLn7rpNvtVlxcnEJCQpSRkaGjR4/6sWIAaD+EXQDoAoYOHaqqqiprO3z4sDW3dOlSLVu2TKtWrdKBAwcUExOjcePGqa6uzo8VA0D7IOwCQBcQFBSkmJgYa+vbt6+ki091V6xYoYKCAt13331KSkrS+vXr9fvvv2vjxo1+rhoArhxhFwC6gOPHjysuLk6JiYmaMmWKfvzxR0kXv7nS4/FYX8wjScHBwUpPT9fevXvbPF9jY6Nqa2t9NgDojAi7AGBzycnJeuedd/Tpp59q7dq18ng8Sk1N1a+//iqPxyNJio6O9jkmOjrammtNUVGRIiIirM3pdHboNQDA5SLsAoDNZWZm6v7779dNN92ksWPH6uOPP5YkrV+/3lrjcDh8jjHGtBj7s/z8fHm9Xms7depUxxQPAFeIsAsAXUxoaKhuuukmHT9+3PpUhr8+xa2urm7xtPfPgoODFR4e7rMBQGdE2AWALqaxsVHl5eWKjY1VYmKiYmJiVFJSYs03NTWptLRUqampfqwSANpHkL8LAAB0rKeffloTJ05UfHy8qqur9dJLL6m2tlbZ2dlyOBzKy8tTYWGhXC6XXC6XCgsL1atXL02bNs3fpQPAFSPsAoDN/fTTT5o6dapOnz6tvn37avTo0frqq6+UkJAgSVq4cKEaGhqUm5urmpoaJScna+fOnQoLC/Nz5QBw5Qi7AGBzmzZt+tt5h8Mht9stt9t9dQoCgKuId3YBAABgW4RdAAAA2BZhFwAAALZF2AUAAIBtEXYBAABgW4RdAAAA2BZhFwAAALZF2AUAAIBtEXYBAABgW4RdAAAA2BZhFwAAALZF2AUAAIBtEXYBAABgW4RdAAAA2BZhFwAAALZF2AUAAIBtEXYBAABgW4RdAAAA2BZhFwAAALZF2AUAAIBtEXYBAABgW4RdAAAA2BZhFwAAALZF2AUAAIBt2Sbsvv7660pMTNQ111yjESNG6PPPP/d3SQAQUOijAOzIFmF38+bNysvLU0FBgb799lvddtttyszM1MmTJ/1dGgAEBPooALuyRdhdtmyZZsyYoZkzZ2rw4MFasWKFnE6n3njjDX+XBgABgT4KwK6C/F3AlWpqatLXX3+tRYsW+Yzfeeed2rt3b6vHNDY2qrGx0dr3er2SpNra2n/96/5e33AZ1XY9/+X3FJ0D9/a/81/u7UtrjTEdVc4V8VcflaSG3+v+Y7VdT21tT3+XgMvAvf3P/uu9fbm9NODD7unTp3XhwgVFR0f7jEdHR8vj8bR6TFFRkZ5//vkW406ns0Nq7Mpy9D9/lwB0iMu5t+vq6hQREdEB1VwZ+mjnlufvAoAOcrn39n/tpQEfdi9xOBw++8aYFmOX5Ofna/78+dZ+c3Ozzpw5o969e7d5TGdXW1srp9OpU6dOKTw83N/lAO3GDve2MUZ1dXWKi4vzdyl/iz4a+Pca0Bq73NuX20sDPuz26dNH3bt3b/H0obq6usVTikuCg4MVHBzsMxYZGdlhNV5N4eHhAX0jA20J9Hu7Mz7RvYQ+6ivQ7zWgLXa4ty+nlwb8P1Dr2bOnRowYoZKSEp/xkpISpaam+qkqAAgc9FEAdhbwT3Ylaf78+crKytItt9yilJQUvfnmmzp58qTmzJnj79IAICDQRwHYVXe32+32dxFXKikpSb1791ZhYaFeffVVNTQ0aMOGDRo+fLi/S7uqunfvroyMDAUF2eLvMICFe7vj0Ucv4l6DXXXle9thOutn4QAAAABXKODf2QUAAADaQtgFAACAbRF2AQAAYFuEXQAAANgWYdeG+vfvrxUrVvi7DAAIWPRRwD4Iu37y6KOPyuFwtNgqKiqu+NwHDhzQrFmz2qFK4PJ4PB7NmzdPAwYMUHBwsJxOpyZOnKhPP/1Uffr00UsvvdTqcUVFRerTp4+ampq0cOFC9e/fX3V1dT5rJk6cqLS0NDU3N0u6GEou/fnp1auXkpKStGbNGknSiy++qNjYWJ05c8bnHN9995169uypDz/8sAOuHlcLfRR2Rh9tRwZ+kZ2dbcaPH2+qqqp8tvPnz/u7NOCKVFZWmri4ODNkyBCzZcsWc+zYMXPkyBHz2muvmRtuuME8+eSTZuDAgaa5ubnFsS6Xy+Tl5RljjPnjjz/M0KFDzcyZM635t956y4SGhpqKigprLCEhwbzwwgumqqrKHD9+3BQUFBhJZtOmTebcuXNm5MiRZsqUKdb6pqYmc/PNN5vs7OyO+03AVUEfhV3RR9sXYddPsrOzzT333NPqXEJCglm+fLnP2PDhw82SJUus/SVLlhin02l69uxpYmNjzbx589o8/sSJE2bSpEkmNDTUhIWFmcmTJxuPx+NzruHDh5t33nnHJCQkmPDwcPPQQw+Z2tradrpadCWZmZnm+uuvN/X19S3mampqzKFDh4wks3v3bp+5PXv2GEnm8OHD1tjBgwdNjx49zCeffGJOnDhhwsPDzerVq32Oa+3Pi8vlshpzeXm5CQkJMVu2bDHGXLzf4+PjjdfrbZfrhf/QR2FX9NH21fW+RsMG3n//fS1fvlybNm3S0KFD5fF49N1337W61hije++9V6GhoSotLdX58+eVm5urhx56SLt377bW/fDDD9q2bZu2b9+umpoaPfjgg3rllVf08ssvX6Wrgh2cOXNGO3bs0Msvv6zQ0NAW85GRkYqMjNTIkSO1bt06paenW3Nvv/22Ro0apaSkJGtsxIgRys/P18yZMzVw4ECNHDlSc+fO/cc6rrnmGp07d06SdOONN6qwsFBz585VWFiYioqK9Mknnyg8PLwdrhiBij6Kzoo+2v54Z9ePtm/frmuvvdbaJk+e/K+OO3nypGJiYjR27FjFx8dr1KhRysnJaXXtZ599pkOHDmnjxo0aMWKEkpOTtWHDBpWWlurAgQPWuubmZhUXFyspKUm33XabsrKytGvXrna5TnQdFRUVMsboxhtv/Nt106dP1/vvv6/6+npJUn19vbZs2aIZM2a0WLt48WJ169ZN+/bt09tvvy2Hw9Hmec+fP6/i4mIdPnxYd9xxhzX+5JNPKikpSXfffbfmzp2r22+//TKvEJ0NfRR2Qx9tf4RdPxozZozKysqsbeXKlf/quMmTJ6uhoUEDBgxQTk6Otm7dqvPnz7e6try8XE6nU06n0xobMmSIIiMjVV5ebo31799fYWFh1n5sbKyqq6sv88rQVZn///bxv2ukkjR16lQ1Nzdr8+bNkqTNmzfLGKMpU6a0WFtSUqKqqioZY3yCxZ8988wzuvbaaxUSEqLHHntMCxYs0OzZs615h8OhgoICNTc3a/HixZd7eeiE6KOwG/po+yPs+lFoaKgGDRpkbbGxsZKkbt26WTf7JZd+lCBJTqdTx44d0+rVqxUSEqLc3FylpaX5rLnEGNPqH5i/jvfo0cNn3uFwWP9KE/i3XC6XHA6HTwBoTUREhB544AGtW7dOkrRu3To98MADLX4kVlNTo5ycHD377LN67rnnlJubq9OnT7c434IFC1RWVqYTJ06ovr5eS5cuVbduvu0tKCjI57+wB/oo7IY+2v4Iu51Q3759VVVVZe3X1taqsrLSZ01ISIgmTZqklStXavfu3fryyy91+PDhFucaMmSITp48qVOnTllj33//vbxerwYPHtxxF4EuKSoqSnfddZdWr16t3377rcX82bNnrf+fMWOGvvjiC23fvl1ffPFFqz96mzdvnvr166fFixdr0aJFcjqdevzxx1us69OnjwYNGqS4uLh/fBqCroE+ikBFH21/hN1O6Pbbb9eGDRv0+eef68iRI8rOzlb37t2t+eLiYr311ls6cuSIfvzxR23YsEEhISFKSEhoca6xY8dq2LBhevjhh/XNN99o//79euSRR5Senq5bbrnlal4WuojXX39dFy5c0KhRo/TBBx/o+PHjKi8v18qVK5WSkmKtS09P16BBg/TII49o0KBBSktL8znP1q1btWXLFq1fv149evRQUFCQiouLtXXrVn3wwQdX+7IQYOijCGT00fZF2O2E8vPzlZaWpgkTJujuu+/Wvffeq4EDB1rzkZGRWrt2rW699VYNGzZMu3bt0kcffaTevXu3OJfD4dC2bdt03XXXKS0tTWPHjtWAAQOsd3yA9paYmKhvvvlGY8aM0VNPPaWkpCSNGzdOu3bt0htvvOGzdvr06aqpqdH06dN9xk+fPq05c+ZoyZIlGjZsmDWelJSkJUuWtPljOOAS+igCGX20fTnMX19qAgAAAGyCJ7sAAACwLcIuAAAAbIuwCwAAANsi7AIAAMC2CLsAAACwLcIuAAAAbIuwCwAAANsi7AIAAMC2CLsAAACwLcIuAAAAbIuwCwAAANv6P0yjLQ92iQSsAAAAAElFTkSuQmCC\n", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "plt.figure(figsize=(8,3.5))\n", "\n", "total_t50 = [fusion_model.time, cvxpy_model.time]\n", "solver_t50 = [fusion_model.M.getSolverDoubleInfo(\"optimizerTime\"), cvxpy_model.prob.solver_stats.solve_time]\n", "\n", "#Total time plot\n", "plt.subplot(1,2,1)\n", "plt.bar(['Fusion', 'CVXPY'], height= total_t50,\n", " width=0.4, color=(0.3, 0.6, 0.2, 0.5))\n", "plt.ylabel(\"Total Time (s)\")\n", "plt.title(\"Comparison of Total Time\")\n", "\n", "#Solver time plot\n", "plt.subplot(1,2,2)\n", "plt.bar(['Fusion','CVXPY'], height=solver_t50,\n", " width=0.4, color=(0.5, 0.6, 0.9, 0.8))\n", "plt.ylabel(\"Solver Time (s)\")\n", "plt.title(\"Comparison of Solver Time\")\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 }