Added explanations of DP, note about better test cases
[ou-summer-of-code-2017.git] / 09-resolving-the-bill / resolving-the-bill-solution.ipynb
index 3643807022dbde7f6e593940e8571f66b3fa171b..ed427e6b9a64f08d7e3c66085a448cb1e58cbddd 100644 (file)
@@ -78,7 +78,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 1,
+   "execution_count": 104,
    "metadata": {},
    "outputs": [
     {
@@ -87,7 +87,7 @@
        "148"
       ]
      },
-     "execution_count": 1,
+     "execution_count": 104,
      "metadata": {},
      "output_type": "execute_result"
     }
   },
   {
    "cell_type": "code",
-   "execution_count": 2,
+   "execution_count": 105,
    "metadata": {
     "collapsed": true
    },
   },
   {
    "cell_type": "code",
-   "execution_count": 3,
+   "execution_count": 106,
    "metadata": {
     "collapsed": true
    },
   },
   {
    "cell_type": "code",
-   "execution_count": 4,
+   "execution_count": 107,
    "metadata": {
     "collapsed": true
    },
   },
   {
    "cell_type": "code",
-   "execution_count": 5,
+   "execution_count": 108,
    "metadata": {
     "collapsed": true
    },
   },
   {
    "cell_type": "code",
-   "execution_count": 6,
+   "execution_count": 109,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "def is_subseq_greedy(s1, s2):\n",
+    "    i = j = 0\n",
+    "    while i < len(s1) and j < len(s2):\n",
+    "        if s1[i] == s2[j]:\n",
+    "            i += 1\n",
+    "        j += 1\n",
+    "    return i == len(s1)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 110,
    "metadata": {
     "collapsed": true
    },
   },
   {
    "cell_type": "code",
-   "execution_count": 35,
+   "execution_count": 111,
    "metadata": {
     "collapsed": true
    },
   },
   {
    "cell_type": "code",
-   "execution_count": 7,
+   "execution_count": 112,
    "metadata": {},
    "outputs": [
     {
        "22"
       ]
      },
-     "execution_count": 7,
+     "execution_count": 112,
      "metadata": {},
      "output_type": "execute_result"
     }
   },
   {
    "cell_type": "code",
-   "execution_count": 36,
+   "execution_count": 113,
    "metadata": {},
    "outputs": [
     {
        "22"
       ]
      },
-     "execution_count": 36,
+     "execution_count": 113,
      "metadata": {},
      "output_type": "execute_result"
     }
   },
   {
    "cell_type": "code",
-   "execution_count": 8,
+   "execution_count": 114,
    "metadata": {},
    "outputs": [
     {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      "1 loop, best of 3: 8.02 s per loop\n"
-     ]
+     "data": {
+      "text/plain": [
+       "22"
+      ]
+     },
+     "execution_count": 114,
+     "metadata": {},
+     "output_type": "execute_result"
     }
    ],
    "source": [
-    "%%timeit\n",
     "sum(1 for s in bills\n",
     "   if s != 0\n",
-    "   if is_subseq(bills[0], bills[s]))"
+    "   if is_subseq_greedy(bills[0], bills[s]))"
    ]
   },
   {
    "cell_type": "code",
-   "execution_count": 37,
+   "execution_count": 12,
    "metadata": {},
    "outputs": [
     {
      "name": "stdout",
      "output_type": "stream",
      "text": [
-      "1 loop, best of 3: 3.04 s per loop\n"
+      "1 loop, best of 3: 7.07 s per loop\n"
      ]
     }
    ],
     "%%timeit\n",
     "sum(1 for s in bills\n",
     "   if s != 0\n",
-    "   if is_subseq_rows(bills[0], bills[s]))"
+    "   if is_subseq(bills[0], bills[s]))"
    ]
   },
   {
    "cell_type": "code",
-   "execution_count": 9,
+   "execution_count": 14,
    "metadata": {
     "scrolled": true
    },
        " 146]"
       ]
      },
-     "execution_count": 9,
+     "execution_count": 14,
      "metadata": {},
      "output_type": "execute_result"
     }
   },
   {
    "cell_type": "code",
-   "execution_count": 65,
+   "execution_count": 15,
    "metadata": {},
    "outputs": [
     {
      "name": "stdout",
      "output_type": "stream",
      "text": [
-      "CPU times: user 168 ms, sys: 0 ns, total: 168 ms\n",
-      "Wall time: 166 ms\n"
+      "CPU times: user 148 ms, sys: 0 ns, total: 148 ms\n",
+      "Wall time: 148 ms\n"
      ]
     },
     {
        "(True, False)"
       ]
      },
-     "execution_count": 65,
+     "execution_count": 15,
      "metadata": {},
      "output_type": "execute_result"
     }
   },
   {
    "cell_type": "code",
-   "execution_count": 73,
+   "execution_count": 16,
    "metadata": {
     "collapsed": true
    },
   },
   {
    "cell_type": "code",
-   "execution_count": 39,
+   "execution_count": 17,
    "metadata": {},
    "outputs": [
     {
   },
   {
    "cell_type": "code",
-   "execution_count": 47,
+   "execution_count": 18,
    "metadata": {
     "collapsed": true
    },
   },
   {
    "cell_type": "code",
-   "execution_count": 40,
+   "execution_count": 19,
    "metadata": {
     "collapsed": true
    },
   },
   {
    "cell_type": "code",
-   "execution_count": 40,
+   "execution_count": 20,
    "metadata": {
     "collapsed": true
    },
   },
   {
    "cell_type": "code",
-   "execution_count": 46,
+   "execution_count": 21,
    "metadata": {
     "collapsed": true
    },
   },
   {
    "cell_type": "code",
-   "execution_count": 41,
+   "execution_count": 22,
    "metadata": {
     "collapsed": true
    },
   },
   {
    "cell_type": "code",
-   "execution_count": 44,
+   "execution_count": 23,
    "metadata": {},
    "outputs": [
     {
        "[30]"
       ]
      },
-     "execution_count": 44,
+     "execution_count": 23,
      "metadata": {},
      "output_type": "execute_result"
     }
   },
   {
    "cell_type": "code",
-   "execution_count": 41,
+   "execution_count": 24,
    "metadata": {},
    "outputs": [
     {
        "[30]"
       ]
      },
-     "execution_count": 41,
+     "execution_count": 24,
      "metadata": {},
      "output_type": "execute_result"
     }
   },
   {
    "cell_type": "code",
-   "execution_count": 48,
+   "execution_count": 25,
    "metadata": {},
    "outputs": [
     {
        "[30]"
       ]
      },
-     "execution_count": 48,
+     "execution_count": 25,
      "metadata": {},
      "output_type": "execute_result"
     }
   },
   {
    "cell_type": "code",
-   "execution_count": 45,
+   "execution_count": 102,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "[30]"
+      ]
+     },
+     "execution_count": 102,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "[s for s in bills\n",
+    "   if is_subseq(bills[0], bills[s])\n",
+    "   if is_subseq(bills[1], bills[s])]"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 26,
    "metadata": {},
    "outputs": [
     {
        "True"
       ]
      },
-     "execution_count": 45,
+     "execution_count": 26,
      "metadata": {},
      "output_type": "execute_result"
     }
   },
   {
    "cell_type": "code",
-   "execution_count": 48,
+   "execution_count": 27,
    "metadata": {},
    "outputs": [
     {
        "[30]"
       ]
      },
-     "execution_count": 48,
+     "execution_count": 27,
      "metadata": {},
      "output_type": "execute_result"
     }
   },
   {
    "cell_type": "code",
-   "execution_count": 70,
+   "execution_count": 28,
    "metadata": {},
    "outputs": [
     {
      "name": "stdout",
      "output_type": "stream",
      "text": [
-      "1 loop, best of 3: 2.68 s per loop\n"
+      "1 loop, best of 3: 2.81 s per loop\n"
      ]
     }
    ],
   },
   {
    "cell_type": "code",
-   "execution_count": 42,
+   "execution_count": 29,
    "metadata": {},
    "outputs": [
     {
      "name": "stdout",
      "output_type": "stream",
      "text": [
-      "1 loop, best of 3: 1.06 s per loop\n"
+      "1 loop, best of 3: 916 ms per loop\n"
      ]
     }
    ],
   },
   {
    "cell_type": "code",
-   "execution_count": 49,
+   "execution_count": 30,
    "metadata": {},
    "outputs": [
     {
      "name": "stdout",
      "output_type": "stream",
      "text": [
-      "1 loop, best of 3: 1.56 s per loop\n"
+      "1 loop, best of 3: 1.45 s per loop\n"
      ]
     }
    ],
   },
   {
    "cell_type": "code",
-   "execution_count": 71,
+   "execution_count": 31,
    "metadata": {},
    "outputs": [
     {
      "name": "stdout",
      "output_type": "stream",
      "text": [
-      "1 loop, best of 3: 660 ms per loop\n"
+      "1 loop, best of 3: 705 ms per loop\n"
      ]
     }
    ],
    "source": [
     "# Sense solution\n",
     "Took \n",
-    "* 22.9 seconds to load file\n",
-    "* 14906.8 seconds to find subsequences (4.14 hours; 4 hours, 8 minutes, 26.8 seconds)\n",
-    "* 41726.9 seconds to check all interleavings (11.59 hours; 11 hours, 35 minutes, 26.9 seconds)\n",
+    "* 25.8 seconds to load file\n",
+    "* 15203.9 seconds to find subsequences (4.22 hours; 4 hours, 13 minutes, 23.9 seconds)\n",
+    "* 40083.8 seconds to check all interleavings (11.13 hours; 11 hours, 8 minutes, 3.8 seconds)\n",
     "\n",
-    "Total of 15 hours 44 minutes 16.6 seconds."
+    "Total of 15 hours 21 minutes 53.5 seconds."
    ]
   },
   {
    "cell_type": "code",
-   "execution_count": 19,
+   "execution_count": 32,
    "metadata": {},
    "outputs": [
     {
      "data": {
       "text/plain": [
-       "(4.140777777777777, 4, 8, 26.799999999999272)"
+       "(4.223305555555555, 4, 13, 23.899999999999636)"
       ]
      },
-     "execution_count": 19,
+     "execution_count": 32,
      "metadata": {},
      "output_type": "execute_result"
     }
    ],
    "source": [
-    "rtime = 14906.8\n",
+    "rtime = 15203.9\n",
     "(rtime / 3600,\n",
     " int(rtime / 3600), \n",
     " int(rtime / 60 - int(rtime / 3600) * 60), \n",
   },
   {
    "cell_type": "code",
-   "execution_count": 20,
+   "execution_count": 33,
    "metadata": {},
    "outputs": [
     {
      "data": {
       "text/plain": [
-       "(11.590805555555557, 11, 35, 26.900000000001455)"
+       "(11.13438888888889, 11, 8, 3.8000000000029104)"
       ]
      },
-     "execution_count": 20,
+     "execution_count": 33,
      "metadata": {},
      "output_type": "execute_result"
     }
    ],
    "source": [
-    "rtime = 41726.9 \n",
+    "rtime = 40083.8\n",
     "(rtime / 3600,\n",
     " int(rtime / 3600), \n",
     " int(rtime / 60 - int(rtime / 3600) * 60), \n",
   },
   {
    "cell_type": "code",
-   "execution_count": 21,
+   "execution_count": 34,
    "metadata": {},
    "outputs": [
     {
      "data": {
       "text/plain": [
-       "(15.737944444444445, 15, 44, 16.599999999998545)"
+       "(15.36486111111111, 15, 21, 53.5)"
       ]
      },
-     "execution_count": 21,
+     "execution_count": 34,
      "metadata": {},
      "output_type": "execute_result"
     }
    ],
    "source": [
-    "rtime = 22.9 + 14906.8 + 41726.9 \n",
+    "rtime = 25.8 + 15203.9 +40083.8\n",
     "(rtime / 3600,\n",
     " int(rtime / 3600), \n",
     " int(rtime / 60 - int(rtime / 3600) * 60), \n",
     ")"
    ]
   },
+  {
+   "cell_type": "markdown",
+   "metadata": {
+    "collapsed": true
+   },
+   "source": [
+    "# Explanations"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 95,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "starget = 'acba'\n",
+    "swrong = 'cdabcaca'\n",
+    "sinterleave = 'abcacbba'\n",
+    "ssubseq = 'aaccabab'"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 84,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "def show_subseq_md_table(short, long, table):\n",
+    "    header = '|   |' + '|'.join('{}<br />{}'.format('<br />'.join(str(long[:i])), i) for i in range(len(long) + 1)) + '|'\n",
+    "    separator = '|:---:' * (len(long) + 2) + '|'\n",
+    "    rows = []\n",
+    "    columns = sorted(set(k[1] for k in table))\n",
+    "    for r in range(len(short) + 1):\n",
+    "        row = '|{}<br />{}|'.format(r, short[:r])\n",
+    "        row += '|'.join('T' if table[r, c] else '.' for c in columns)\n",
+    "        row += '|'\n",
+    "        rows += [row]\n",
+    "    return '\\n'.join([header] + [separator] + rows)\n",
+    "#     return '\\n'.join(\n",
+    "#         ' '.join('T' if table[i, j] else '.' for j in sorted(set([k[1] for k in table])))\n",
+    "#         for i in sorted(set([k[0] for k in table])))        "
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 82,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      ". . . . . . . . .\n",
+      ". a a c c a b a b\n",
+      ". . . c c a b a b\n",
+      ". . . . . . b a b\n",
+      ". . . . . . . a b\n",
+      "AcCaBAb\n"
+     ]
+    }
+   ],
+   "source": [
+    "v, bp, t = is_subseq(starget, ssubseq, return_backpointers=True, return_table=True)\n",
+    "print(show_annotated_table(t, bp))\n",
+    "print(show_backtrace_s(bp))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 83,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "T T T T T T T T T\n",
+      ". T T T T T T T T\n",
+      ". . . T T T T T T\n",
+      ". . . . . . T T T\n",
+      ". . . . . . . T T\n"
+     ]
+    }
+   ],
+   "source": [
+    "print(show_table(t))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 85,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "|   |<br />0|a<br />1|a<br />a<br />2|a<br />a<br />c<br />3|a<br />a<br />c<br />c<br />4|a<br />a<br />c<br />c<br />a<br />5|a<br />a<br />c<br />c<br />a<br />b<br />6|a<br />a<br />c<br />c<br />a<br />b<br />a<br />7|a<br />a<br />c<br />c<br />a<br />b<br />a<br />b<br />8|\n",
+      "|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|\n",
+      "|0<br />|T|T|T|T|T|T|T|T|T|\n",
+      "|1<br />a|.|T|T|T|T|T|T|T|T|\n",
+      "|2<br />ac|.|.|.|T|T|T|T|T|T|\n",
+      "|3<br />acb|.|.|.|.|.|.|T|T|T|\n",
+      "|4<br />acba|.|.|.|.|.|.|.|T|T|\n"
+     ]
+    }
+   ],
+   "source": [
+    "print(show_subseq_md_table(starget, ssubseq, t))"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "|   |<br />0|a<br />1|a<br />a<br />2|a<br />a<br />c<br />3|a<br />a<br />c<br />c<br />4|a<br />a<br />c<br />c<br />a<br />5|a<br />a<br />c<br />c<br />a<br />b<br />6|a<br />a<br />c<br />c<br />a<br />b<br />a<br />7|a<br />a<br />c<br />c<br />a<br />b<br />a<br />b<br />8|\n",
+    "|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|\n",
+    "|0<br />|T|T|T|T|T|T|T|T|T|\n",
+    "|1<br />a|.|T|T|T|T|T|T|T|T|\n",
+    "|2<br />ac|.|.|.|T|T|T|T|T|T|\n",
+    "|3<br />acb|.|.|.|.|.|.|T|T|T|\n",
+    "|4<br />acba|.|.|.|.|.|.|.|T|T|"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 99,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      ". . . . . . . . .\n",
+      ". . . a b c a c a\n",
+      ". . . . . c a c a\n",
+      ". . . . . . . . .\n",
+      ". . . . . . . . .\n",
+      "ACa\n"
+     ]
+    }
+   ],
+   "source": [
+    "v, bp, t = is_subseq(starget, swrong, return_backpointers=True, return_table=True)\n",
+    "print(show_annotated_table(t, bp))\n",
+    "print(show_backtrace_s(bp))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 100,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "|   |<br />0|c<br />1|c<br />d<br />2|c<br />d<br />a<br />3|c<br />d<br />a<br />b<br />4|c<br />d<br />a<br />b<br />c<br />5|c<br />d<br />a<br />b<br />c<br />a<br />6|c<br />d<br />a<br />b<br />c<br />a<br />c<br />7|c<br />d<br />a<br />b<br />c<br />a<br />c<br />a<br />8|\n",
+      "|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|\n",
+      "|0<br />|T|T|T|T|T|T|T|T|T|\n",
+      "|1<br />a|.|.|.|T|T|T|T|T|T|\n",
+      "|2<br />ac|.|.|.|.|.|T|T|T|T|\n",
+      "|3<br />acb|.|.|.|.|.|.|.|.|.|\n",
+      "|4<br />acba|.|.|.|.|.|.|.|.|.|\n"
+     ]
+    }
+   ],
+   "source": [
+    "print(show_subseq_md_table(starget, swrong, t))"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "|   |<br />0|c<br />1|c<br />d<br />2|c<br />d<br />a<br />3|c<br />d<br />a<br />b<br />4|c<br />d<br />a<br />b<br />c<br />5|c<br />d<br />a<br />b<br />c<br />a<br />6|c<br />d<br />a<br />b<br />c<br />a<br />c<br />7|c<br />d<br />a<br />b<br />c<br />a<br />c<br />a<br />8|\n",
+    "|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|\n",
+    "|0<br />|T|T|T|T|T|T|T|T|T|\n",
+    "|1<br />a|.|.|.|T|T|T|T|T|T|\n",
+    "|2<br />ac|.|.|.|.|.|T|T|T|T|\n",
+    "|3<br />acb|.|.|.|.|.|.|.|.|.|\n",
+    "|4<br />acba|.|.|.|.|.|.|.|.|.|"
+   ]
+  },
   {
    "cell_type": "code",
    "execution_count": null,