{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Second-order cone program"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "A second-order cone program (SOCP) is an optimization problem of the form\n",
    "$$  \n",
    "    \\begin{array}{ll}\n",
    "    \\mbox{minimize}   & f^Tx\\\\\n",
    "    \\mbox{subject to} & \\|A_ix + b_i\\|_2 \\leq c_i^Tx + d_i, \\quad i=1,\\ldots,m \\\\\n",
    "                      & Fx = g,\n",
    "    \\end{array}\n",
    "$$\n",
    "where $x \\in \\mathcal{R}^{n}$ is the optimization variable and $f \\in \\mathcal{R}^n$, $A_i \\in \\mathcal{R}^{n_i \\times n}$, $b_i \\in \\mathcal{R}^{n_i}$, $c_i \\in \\mathcal{R}^n$, $d_i \\in \\mathcal{R}$, $F \\in \\mathcal{R}^{p \\times n}$, and $g \\in \\mathcal{R}^p$ are problem data.\n",
    "\n",
    "An example of an SOCP is the robust linear program\n",
    "$$  \n",
    "    \\begin{array}{ll}\n",
    "    \\mbox{minimize}   & c^Tx\\\\\n",
    "    \\mbox{subject to} & (a_i + u_i)^Tx \\leq b_i \\textrm{ for all } \\|u_i\\|_2 \\leq 1, \\quad i=1,\\ldots,m,\n",
    "    \\end{array}\n",
    "$$\n",
    "where the problem data $a_i$ are known within an $\\ell_2$-norm ball of radius one. The robust linear program can be rewritten as the SOCP\n",
    "$$  \n",
    "    \\begin{array}{ll}\n",
    "    \\mbox{minimize}   & c^Tx\\\\\n",
    "    \\mbox{subject to} & a_i^Tx + \\|x\\|_2 \\leq b_i, \\quad i=1,\\ldots,m,\n",
    "    \\end{array}\n",
    "$$\n",
    "\n",
    "When we solve a SOCP, in addition to a solution $x^\\star$, we obtain a dual solution $\\lambda_i^\\star$ corresponding to each second-order cone constraint. A non-zero $\\lambda_i^\\star$ indicates that the constraint $ \\|A_ix + b_i\\|_2 \\leq c_i^Tx + d_i$ holds with equality for $x^\\star$ and suggests that changing $d_i$ would change the optimal value."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Example"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "In the following code, we solve an SOCP with CVXPY."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "The optimal value is -9.582695716265503\n",
      "A solution x is\n",
      "[ 1.40303325  2.4194569   1.69146656 -0.26922215  1.30825472 -0.70834842\n",
      "  0.19313706  1.64153496  0.47698583  0.66581033]\n",
      "SOC constraint 0 dual variable solution\n",
      "[ 0.61662526  0.35370661 -0.02327185  0.04253095  0.06243588  0.49886837]\n",
      "SOC constraint 1 dual variable solution\n",
      "[ 0.35283078 -0.14301082  0.16539699 -0.22027817  0.15440264  0.06571645]\n",
      "SOC constraint 2 dual variable solution\n",
      "[ 0.86510445 -0.114638   -0.449291    0.37810251 -0.6144058  -0.11377797]\n"
     ]
    }
   ],
   "source": [
    "# Import packages.\n",
    "import cvxpy as cp\n",
    "import numpy as np\n",
    "\n",
    "# Generate a random feasible SOCP.\n",
    "m = 3\n",
    "n = 10\n",
    "p = 5\n",
    "n_i = 5\n",
    "np.random.seed(2)\n",
    "f = np.random.randn(n)\n",
    "A = []\n",
    "b = []\n",
    "c = []\n",
    "d = []\n",
    "x0 = np.random.randn(n)\n",
    "for i in range(m):\n",
    "    A.append(np.random.randn(n_i, n))\n",
    "    b.append(np.random.randn(n_i))\n",
    "    c.append(np.random.randn(n))\n",
    "    d.append(np.linalg.norm(A[i]@x0 + b, 2) - c[i].T@x0)\n",
    "F = np.random.randn(p, n)\n",
    "g = F@x0\n",
    "\n",
    "# Define and solve the CVXPY problem.\n",
    "x = cp.Variable(n)\n",
    "# We use cp.SOC(t, x) to create the SOC constraint ||x||_2 <= t.\n",
    "soc_constraints = [\n",
    "    cp.SOC(c[i].T@x + d[i], A[i]@x + b[i]) for i in range(m)\n",
    "]\n",
    "prob = cp.Problem(cp.Minimize(f.T@x),\n",
    "                  soc_constraints + [F@x == g])\n",
    "prob.solve()\n",
    "\n",
    "# Print result.\n",
    "print(\"The optimal value is\", prob.value)\n",
    "print(\"A solution x is\")\n",
    "print(x.value)\n",
    "for i in range(m):\n",
    "    print(\"SOC constraint %i dual variable solution\" % i)\n",
    "    print(soc_constraints[i].dual_value)"
   ]
  }
 ],
 "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.5.2"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 0
}
