{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# PuLPを使ってみる"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "特に実装すべきアルゴリズムはなかったが、せっかくなのでpythonで線形計画問題を解くためのパッケージ(?)である**PuLP**を使って実際に線形計画問題を解く方法を調べてみた。\n",
    "\n",
    "[参考にしたサイト](http://qiita.com/Tsutomu-KKE@github/items/070ca9cb37c6b2b492f0)\n",
    "\n",
    "インストール方法は、\n",
    "```\n",
    "sudo pip install pulp\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "from pulp import *"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "$$\\max 100x + 100y$$\n",
    "\n",
    "$$ s.t. \\\\ x + 2y \\leq 16 $$\n",
    "\n",
    "$$ x + y \\leq 18 $$"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "4.0 6.0\n"
     ]
    }
   ],
   "source": [
    "m = LpProblem(sense=LpMaximize) # 数理モデル\n",
    "x = LpVariable('x', lowBound=0) # 変数\n",
    "y = LpVariable('y', lowBound=0)\n",
    "m += 100 * x + 100 * y # 目的関数\n",
    "m += x + 2 * y <= 16 #制約1\n",
    "m += 3 * x + y <= 18 # 制約2\n",
    "m.solve() # ソルバー実行\n",
    "print(value(x), value(y))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "100*x + 100*y\n"
     ]
    }
   ],
   "source": [
    "print(m.objective)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {
    "collapsed": false,
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1000.0\n"
     ]
    }
   ],
   "source": [
    "print(value(m.objective))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "status = m.solve()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Optimal\n"
     ]
    }
   ],
   "source": [
    "print (LpStatus[status])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# PuLP with pandas"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "輸送最適化問題を解く(参考サイトに問題の詳細あり)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "import numpy as np, pandas as pd\n",
    "from itertools import product\n",
    "from pulp import *\n",
    "\n",
    "np.random.seed(1)\n",
    "nw, nf = 3, 4\n",
    "pr = list(product(range(nw),range(nf)))\n",
    "supply = np.random.randint(30, 50, nw)\n",
    "demand = np.random.randint(20, 40, nf)\n",
    "cost = np.random.randint(10, 20, (nw,nf))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{(0, 0): 28.0,\n",
       " (0, 1): 7.0,\n",
       " (1, 2): 31.0,\n",
       " (1, 3): 5.0,\n",
       " (2, 1): 22.0,\n",
       " (2, 3): 20.0}"
      ]
     },
     "execution_count": 13,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# pandasを使わずにモデリングすると\n",
    "\n",
    "m1 = LpProblem() # minimizing\n",
    "v1 = {(i,j):LpVariable('v%d_%d'%(i,j), lowBound=0) for i,j in pr}\n",
    "m1 += lpSum(cost[i][j] * v1[i,j] for i,j in pr) # objective function\n",
    "for i in range(nw):\n",
    "    m1 += lpSum(v1[i,j] for j in range(nf)) <= supply[i]\n",
    "for j in range(nf):\n",
    "    m1 += lpSum(v1[i,j] for i in range(nw)) >= demand[j]\n",
    "m1.solve()\n",
    "{k:value(x) for k,x in v1.items() if value(x) > 0}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{(0, 0): v0_0,\n",
       " (0, 1): v0_1,\n",
       " (0, 2): v0_2,\n",
       " (0, 3): v0_3,\n",
       " (1, 0): v1_0,\n",
       " (1, 1): v1_1,\n",
       " (1, 2): v1_2,\n",
       " (1, 3): v1_3,\n",
       " (2, 0): v2_0,\n",
       " (2, 1): v2_1,\n",
       " (2, 2): v2_2,\n",
       " (2, 3): v2_3}"
      ]
     },
     "execution_count": 14,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "v1"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "v1_1"
      ]
     },
     "execution_count": 16,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "v1[1,1]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "dict_items([((0, 1), v0_1), ((1, 2), v1_2), ((0, 0), v0_0), ((1, 1), v1_1), ((2, 1), v2_1), ((0, 2), v0_2), ((2, 0), v2_0), ((1, 3), v1_3), ((2, 3), v2_3), ((2, 2), v2_2), ((1, 0), v1_0), ((0, 3), v0_3)])"
      ]
     },
     "execution_count": 17,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "v1.items()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "0.0"
      ]
     },
     "execution_count": 18,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "value(v1[1,1])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>warehouse</th>\n",
       "      <th>factory</th>\n",
       "      <th>cost</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>10</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>0</td>\n",
       "      <td>1</td>\n",
       "      <td>10</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>0</td>\n",
       "      <td>2</td>\n",
       "      <td>11</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "   warehouse  factory  cost\n",
       "0          0        0    10\n",
       "1          0        1    10\n",
       "2          0        2    11"
      ]
     },
     "execution_count": 20,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# pandasを使ってモデリング\n",
    "a = pd.DataFrame([(i,j) for i, j in pr], columns=['warehouse', 'factory'])\n",
    "a['cost'] = cost.flatten()\n",
    "a[:3]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>warehouse</th>\n",
       "      <th>factory</th>\n",
       "      <th>cost</th>\n",
       "      <th>Var</th>\n",
       "      <th>Val</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>10</td>\n",
       "      <td>v0</td>\n",
       "      <td>28.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>0</td>\n",
       "      <td>1</td>\n",
       "      <td>10</td>\n",
       "      <td>v1</td>\n",
       "      <td>7.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>6</th>\n",
       "      <td>1</td>\n",
       "      <td>2</td>\n",
       "      <td>12</td>\n",
       "      <td>v6</td>\n",
       "      <td>31.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>7</th>\n",
       "      <td>1</td>\n",
       "      <td>3</td>\n",
       "      <td>14</td>\n",
       "      <td>v7</td>\n",
       "      <td>5.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>9</th>\n",
       "      <td>2</td>\n",
       "      <td>1</td>\n",
       "      <td>12</td>\n",
       "      <td>v9</td>\n",
       "      <td>22.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>11</th>\n",
       "      <td>2</td>\n",
       "      <td>3</td>\n",
       "      <td>12</td>\n",
       "      <td>v11</td>\n",
       "      <td>20.0</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "    warehouse  factory  cost  Var   Val\n",
       "0           0        0    10   v0  28.0\n",
       "1           0        1    10   v1   7.0\n",
       "6           1        2    12   v6  31.0\n",
       "7           1        3    14   v7   5.0\n",
       "9           2        1    12   v9  22.0\n",
       "11          2        3    12  v11  20.0"
      ]
     },
     "execution_count": 31,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "m2 = LpProblem()\n",
    "a['Var'] = [LpVariable('v%d'%i, lowBound=0) for i in a.index]\n",
    "m2 += lpDot(a.cost, a.Var)\n",
    "for k, v in a.groupby('warehouse'):\n",
    "    m2 += lpSum(v.Var) <= supply[k]\n",
    "for k, v in a.groupby('factory'):\n",
    "    m2 += lpSum(v.Var) >= demand[k]\n",
    "m2.solve()\n",
    "a['Val'] = a.Var.apply(value)\n",
    "a[a.Val > 0]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {
    "collapsed": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0\n",
      "1\n",
      "2\n",
      "3\n",
      "4\n",
      "5\n",
      "6\n",
      "7\n",
      "8\n",
      "9\n",
      "10\n",
      "11\n"
     ]
    }
   ],
   "source": [
    "for i in a.index:\n",
    "    print (i)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0\n",
      "0    v0\n",
      "1    v1\n",
      "2    v2\n",
      "3    v3\n",
      "Name: Var, dtype: object\n",
      "1\n",
      "4    v4\n",
      "5    v5\n",
      "6    v6\n",
      "7    v7\n",
      "Name: Var, dtype: object\n",
      "2\n",
      "8      v8\n",
      "9      v9\n",
      "10    v10\n",
      "11    v11\n",
      "Name: Var, dtype: object\n"
     ]
    }
   ],
   "source": [
    "for k, v in a.groupby('warehouse'):\n",
    "    print (k)\n",
    "    print (v.Var)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "anaconda-cloud": {},
  "kernelspec": {
   "display_name": "Python [conda root]",
   "language": "python",
   "name": "conda-root-py"
  },
  "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"
  },
  "toc": {
   "nav_menu": {
    "height": "48px",
    "width": "252px"
   },
   "navigate_menu": true,
   "number_sections": true,
   "sideBar": true,
   "threshold": 4,
   "toc_cell": false,
   "toc_section_display": "block",
   "toc_window_display": false
  }
 },
 "nbformat": 4,
 "nbformat_minor": 1
}