From: Neil Smith Date: Mon, 22 May 2017 13:59:24 +0000 (+0100) Subject: Updated word chain problem X-Git-Url: https://git.njae.me.uk/?a=commitdiff_plain;h=4c5672cbef4ef0df1d6964c55a42fe80634766a9;hp=736040348711b246f04e606e18eb85b54d1c475d;p=ou-summer-of-code-2017.git Updated word chain problem --- diff --git a/word-chains/explore-word-chain-4.ipynb b/word-chains/explore-word-chain-4.ipynb index 6e230ed..5f624fd 100644 --- a/word-chains/explore-word-chain-4.ipynb +++ b/word-chains/explore-word-chain-4.ipynb @@ -189,8 +189,12 @@ }, "outputs": [], "source": [ - "def extend(chain):\n", - " return [chain + [s] for s in neighbours[chain[-1]]\n", + "def extend(chain, closed=None):\n", + " if closed:\n", + " nbrs = set(neighbours[chain[-1]]) - closed\n", + " else:\n", + " nbrs = neighbours[chain[-1]]\n", + " return [chain + [s] for s in nbrs\n", " if s not in chain]" ] }, @@ -262,8 +266,22 @@ }, "outputs": [], "source": [ - "def bfs_search(start, target, debug=False):\n", - " return bfs([[start]], target, debug=debug)" + "def bfs_search(start, goal, debug=False):\n", + " agenda = [[start]]\n", + " finished = False\n", + " while not finished and agenda:\n", + " current = agenda[0]\n", + " if debug:\n", + " print(current)\n", + " if current[-1] == goal:\n", + " finished = True\n", + " else:\n", + " successors = extend(current)\n", + " agenda = agenda[1:] + successors\n", + " if agenda:\n", + " return current\n", + " else:\n", + " return None " ] }, { @@ -274,7 +292,9 @@ }, "outputs": [], "source": [ - "def bfs(agenda, goal, debug=False):\n", + "def bfs_search_closed(start, goal, debug=False):\n", + " agenda = [[start]]\n", + " closed = set()\n", " finished = False\n", " while not finished and agenda:\n", " current = agenda[0]\n", @@ -283,7 +303,8 @@ " if current[-1] == goal:\n", " finished = True\n", " else:\n", - " successors = extend(current)\n", + " closed.add(current[-1])\n", + " successors = extend(current, closed)\n", " agenda = agenda[1:] + successors\n", " if agenda:\n", " return current\n", @@ -330,19 +351,8 @@ }, "outputs": [], "source": [ - "def dfs_search(start, target, debug=False):\n", - " return dfs([[start]], target, debug=debug)" - ] - }, - { - "cell_type": "code", - "execution_count": 19, - "metadata": { - "collapsed": true - }, - "outputs": [], - "source": [ - "def dfs(agenda, goal, debug=False):\n", + "def dfs_search(start, goal, debug=False):\n", + " agenda = [[start]]\n", " finished = False\n", " while not finished and agenda:\n", " current = agenda[0]\n", @@ -361,7 +371,7 @@ }, { "cell_type": "code", - "execution_count": 20, + "execution_count": 19, "metadata": {}, "outputs": [ { @@ -381,7 +391,7 @@ "['abbe', 'able', 'ably', 'ally']" ] }, - "execution_count": 20, + "execution_count": 19, "metadata": {}, "output_type": "execute_result" } @@ -392,7 +402,7 @@ }, { "cell_type": "code", - "execution_count": 21, + "execution_count": 20, "metadata": {}, "outputs": [ { @@ -847,7 +857,13 @@ "['cart', 'mart', 'tart', 'wart']\n", "['cart', 'mart', 'tart', 'tort']\n", "['cart', 'mart', 'tart', 'tact']\n", - "['cart', 'mart', 'tart', 'taut']\n", + "['cart', 'mart', 'tart', 'taut']\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ "['cart', 'mart', 'tart', 'tare']\n", "['cart', 'mart', 'tart', 'taro']\n", "['cart', 'mart', 'tart', 'tarp']\n", @@ -859,13 +875,7 @@ "['cart', 'mart', 'wart', 'waft']\n", "['cart', 'mart', 'wart', 'wait']\n", "['cart', 'mart', 'wart', 'want']\n", - "['cart', 'mart', 'wart', 'watt']\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ + "['cart', 'mart', 'wart', 'watt']\n", "['cart', 'mart', 'wart', 'ward']\n", "['cart', 'mart', 'wart', 'ware']\n", "['cart', 'mart', 'wart', 'warm']\n", @@ -1338,7 +1348,13 @@ "['cart', 'wart', 'ware', 'wire']\n", "['cart', 'wart', 'ware', 'wore']\n", "['cart', 'wart', 'ware', 'wade']\n", - "['cart', 'wart', 'ware', 'wage']\n", + "['cart', 'wart', 'ware', 'wage']\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ "['cart', 'wart', 'ware', 'wake']\n", "['cart', 'wart', 'ware', 'wale']\n", "['cart', 'wart', 'ware', 'wane']\n", @@ -1541,7 +1557,7 @@ "['cart', 'cant', 'cans', 'vans']" ] }, - "execution_count": 21, + "execution_count": 20, "metadata": {}, "output_type": "execute_result" } @@ -1552,7 +1568,7 @@ }, { "cell_type": "code", - "execution_count": 22, + "execution_count": 21, "metadata": {}, "outputs": [ { @@ -1561,7 +1577,7 @@ "['cart', 'cant', 'cane', 'vane']" ] }, - "execution_count": 22, + "execution_count": 21, "metadata": {}, "output_type": "execute_result" } @@ -1572,7 +1588,7 @@ }, { "cell_type": "code", - "execution_count": 23, + "execution_count": 22, "metadata": {}, "outputs": [ { @@ -2158,7 +2174,7 @@ " 'vane']" ] }, - "execution_count": 23, + "execution_count": 22, "metadata": {}, "output_type": "execute_result" } @@ -2169,14 +2185,60 @@ }, { "cell_type": "code", - "execution_count": 24, + "execution_count": 23, "metadata": { "collapsed": true }, "outputs": [], "source": [ - "def astar_search(start, target, debug=False):\n", - " return astar([(distance(start, target), [start])], target, debug=debug)" + "def astar_search(start, goal, debug=False):\n", + " agenda = [(distance(start, goal), [start])]\n", + " heapq.heapify(agenda)\n", + " finished = False\n", + " while not finished and agenda:\n", + " _, current = heapq.heappop(agenda)\n", + " if debug:\n", + " print(current)\n", + " if current[-1] == goal:\n", + " finished = True\n", + " else:\n", + " successors = extend(current)\n", + " for s in successors:\n", + " heapq.heappush(agenda, (len(current) + distance(s[-1], goal) - 1, s))\n", + " if agenda:\n", + " return current\n", + " else:\n", + " return None " + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "['cart']\n", + "['cart', 'cant']\n", + "['cart', 'cant', 'cane']\n", + "['cart', 'cant', 'cane', 'vane']\n" + ] + }, + { + "data": { + "text/plain": [ + "['cart', 'cant', 'cane', 'vane']" + ] + }, + "execution_count": 24, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "astar_search('cart', 'vane', debug=True)" ] }, { @@ -2187,7 +2249,10 @@ }, "outputs": [], "source": [ - "def astar(agenda, goal, debug=False):\n", + "def astar_search_closed(start, goal, debug=False):\n", + " agenda = [(distance(start, goal), [start])]\n", + " heapq.heapify(agenda)\n", + " closed = set()\n", " finished = False\n", " while not finished and agenda:\n", " _, current = heapq.heappop(agenda)\n", @@ -2196,7 +2261,8 @@ " if current[-1] == goal:\n", " finished = True\n", " else:\n", - " successors = extend(current)\n", + " closed.add(current[-1])\n", + " successors = extend(current, closed)\n", " for s in successors:\n", " heapq.heappush(agenda, (len(current) + distance(s[-1], goal) - 1, s))\n", " if agenda:\n", @@ -2232,7 +2298,7 @@ } ], "source": [ - "astar_search('cart', 'vane', debug=True)" + "astar_search_closed('cart', 'vane', debug=True)" ] }, { @@ -2246,7 +2312,7 @@ }, { "cell_type": "code", - "execution_count": 27, + "execution_count": 77, "metadata": {}, "outputs": [ { @@ -2255,7 +2321,7 @@ "94" ] }, - "execution_count": 27, + "execution_count": 77, "metadata": {}, "output_type": "execute_result" } @@ -2281,7 +2347,7 @@ }, { "cell_type": "code", - "execution_count": 28, + "execution_count": 78, "metadata": {}, "outputs": [ { @@ -2290,7 +2356,7 @@ "2204" ] }, - "execution_count": 28, + "execution_count": 78, "metadata": {}, "output_type": "execute_result" } @@ -2301,7 +2367,7 @@ }, { "cell_type": "code", - "execution_count": 29, + "execution_count": 79, "metadata": {}, "outputs": [ { @@ -2310,7 +2376,7 @@ "1" ] }, - "execution_count": 29, + "execution_count": 79, "metadata": {}, "output_type": "execute_result" } @@ -2321,7 +2387,7 @@ }, { "cell_type": "code", - "execution_count": 30, + "execution_count": 80, "metadata": { "scrolled": true }, @@ -2332,7 +2398,7 @@ "Counter({1: 75, 2: 6, 3: 7, 4: 2, 5: 2, 6: 1, 2204: 1})" ] }, - "execution_count": 30, + "execution_count": 80, "metadata": {}, "output_type": "execute_result" } @@ -2343,7 +2409,7 @@ }, { "cell_type": "code", - "execution_count": 31, + "execution_count": 81, "metadata": {}, "outputs": [ { @@ -2352,7 +2418,7 @@ "[5]" ] }, - "execution_count": 31, + "execution_count": 81, "metadata": {}, "output_type": "execute_result" } @@ -2363,7 +2429,7 @@ }, { "cell_type": "code", - "execution_count": 32, + "execution_count": 82, "metadata": {}, "outputs": [ { @@ -2372,7 +2438,7 @@ "[{'abbe', 'able', 'ably', 'ally', 'axle'}]" ] }, - "execution_count": 32, + "execution_count": 82, "metadata": {}, "output_type": "execute_result" } @@ -2383,7 +2449,7 @@ }, { "cell_type": "code", - "execution_count": 33, + "execution_count": 83, "metadata": {}, "outputs": [ { @@ -2392,7 +2458,7 @@ "['buns', 'bunk', 'punk']" ] }, - "execution_count": 33, + "execution_count": 83, "metadata": {}, "output_type": "execute_result" } @@ -2403,8 +2469,10 @@ }, { "cell_type": "code", - "execution_count": 34, - "metadata": {}, + "execution_count": 84, + "metadata": { + "collapsed": true + }, "outputs": [], "source": [ "for a in reachables:\n", @@ -2416,8 +2484,10 @@ }, { "cell_type": "code", - "execution_count": 35, - "metadata": {}, + "execution_count": 85, + "metadata": { + "collapsed": true + }, "outputs": [], "source": [ "# longest_chain = []\n", @@ -2437,7 +2507,7 @@ }, { "cell_type": "code", - "execution_count": 36, + "execution_count": 86, "metadata": { "collapsed": true }, @@ -2448,40 +2518,40 @@ }, { "cell_type": "code", - "execution_count": 37, + "execution_count": 87, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "['over', 'ever', 'eves', 'eyes', 'dyes', 'does', 'toes', 'tors', 'tars', 'taro', 'tyro']\n", - "['aide', 'aids', 'bids', 'bits', 'bats', 'mats']\n", - "['miff', 'riff', 'rife', 'rise', 'risk', 'rusk']\n", - "['hims', 'hems', 'hens', 'lens', 'lent']\n", - "['tipi', 'tips', 'tits', 'tots', 'cots', 'cote']\n", - "['apex', 'aped', 'sped', 'sued', 'sues', 'subs', 'tubs', 'tabs', 'tabu']\n", - "['wino', 'wind', 'wild', 'gild', 'gilt']\n", - "['rasp', 'ramp', 'lamp', 'limp', 'limn']\n", - "['paps', 'caps', 'cars', 'card', 'cord', 'lord', 'loud']\n", - "['lava', 'lama', 'lamp', 'ramp']\n", - "['ways', 'bays', 'boys', 'boos', 'coos', 'coop', 'coup']\n", - "['boob', 'boor', 'boar', 'bear', 'beer', 'jeer', 'jeez']\n", - "['troy', 'trod', 'prod', 'plod', 'pled', 'pied', 'died', 'diet']\n", - "['vest', 'lest', 'less', 'loss', 'lows', 'rows']\n", - "['shop', 'shot', 'soot', 'sort', 'sore', 'sire', 'dire', 'dike']\n", - "['sing', 'zing']\n", - "['beak', 'beat', 'belt', 'welt', 'wilt', 'wily', 'oily', 'only']\n", - "['spry', 'spay', 'spas', 'seas', 'secs', 'sics', 'sirs', 'sire', 'tire', 'tiro']\n", - "['gosh', 'bosh', 'boss', 'bogs', 'begs', 'bees', 'byes']\n", - "['racy', 'race', 'rape', 'raps', 'saps', 'sops']\n" + "['late', 'lats', 'lets', 'leas', 'seas', 'seam', 'swam', 'sway']\n", + "['leap', 'heap', 'hear', 'dear', 'deer']\n", + "['peel', 'peek', 'perk', 'park', 'nark']\n", + "['sing', 'sang', 'sand', 'said', 'sail', 'hail', 'haul']\n", + "['vats', 'bats', 'bets', 'bees', 'been', 'teen', 'then', 'thin', 'this', 'thus', 'thud']\n", + "['sues', 'sees', 'seen', 'sewn', 'hewn']\n", + "['rash', 'bash', 'bast', 'bait', 'bail', 'hail', 'hair', 'heir']\n", + "['apex', 'aped', 'sped', 'seed', 'deed', 'dead', 'deal', 'veal']\n", + "['gulf', 'golf', 'gold', 'bold', 'bond', 'bony', 'tony']\n", + "['snag', 'shag', 'shat', 'seat', 'peat', 'pent', 'pint', 'mint']\n", + "['rife', 'rime', 'rims', 'rums', 'cums', 'cuss']\n", + "['diss', 'kiss', 'kits']\n", + "['gyps', 'gaps', 'gads', 'wads', 'wade', 'wide', 'tide']\n", + "['bilk', 'bill', 'bell', 'tell', 'teal', 'tear', 'tzar']\n", + "['logo', 'loge', 'lode', 'lade', 'jade', 'jape']\n", + "['hunt', 'bunt', 'buns', 'nuns', 'nubs']\n", + "['glow', 'glop', 'plop', 'prop', 'prep', 'peep', 'keep']\n", + "['iamb', 'lamb', 'lams', 'laps', 'lips', 'pips']\n", + "['pain', 'lain', 'laid', 'land', 'lend', 'vend', 'veld']\n", + "['fake', 'bake', 'bare', 'bars', 'ears', 'errs', 'ergs', 'eggs', 'egos']\n" ] } ], "source": [ "for _ in range(20):\n", " start, goal = random.sample(bigset, 2)\n", - " print(astar_search(start, goal))" + " print(astar_search_closed(start, goal))" ] }, { @@ -2564,6 +2634,146 @@ "astar_search('wars', 'love')" ] }, + { + "cell_type": "code", + "execution_count": 61, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "CPU times: user 0 ns, sys: 0 ns, total: 0 ns\n", + "Wall time: 210 µs\n" + ] + }, + { + "data": { + "text/plain": [ + "5" + ] + }, + "execution_count": 61, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "%time len(astar_search('wars', 'love'))" + ] + }, + { + "cell_type": "code", + "execution_count": 62, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "CPU times: user 0 ns, sys: 0 ns, total: 0 ns\n", + "Wall time: 252 µs\n" + ] + }, + { + "data": { + "text/plain": [ + "5" + ] + }, + "execution_count": 62, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "%time len(astar_search_closed('wars', 'love'))" + ] + }, + { + "cell_type": "code", + "execution_count": 63, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "CPU times: user 24 ms, sys: 0 ns, total: 24 ms\n", + "Wall time: 24.2 ms\n" + ] + }, + { + "data": { + "text/plain": [ + "404" + ] + }, + "execution_count": 63, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "%time len(dfs_search('wars', 'love'))" + ] + }, + { + "cell_type": "code", + "execution_count": 64, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "CPU times: user 5min 20s, sys: 76 ms, total: 5min 20s\n", + "Wall time: 5min 20s\n" + ] + }, + { + "data": { + "text/plain": [ + "5" + ] + }, + "execution_count": 64, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "%time len(bfs_search('wars', 'love'))" + ] + }, + { + "cell_type": "code", + "execution_count": 65, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "CPU times: user 1.44 s, sys: 0 ns, total: 1.44 s\n", + "Wall time: 1.43 s\n" + ] + }, + { + "data": { + "text/plain": [ + "5" + ] + }, + "execution_count": 65, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "%time len(bfs_search_closed('wars', 'love'))" + ] + }, { "cell_type": "code", "execution_count": 42, @@ -2727,6 +2937,346 @@ "[len(r) for r in reachables if 'star' in r if 'born' in r]" ] }, + { + "cell_type": "code", + "execution_count": 49, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "1 loop, best of 3: 7.9 s per loop\n" + ] + } + ], + "source": [ + "%%timeit\n", + "astar_search('bats', 'exit')" + ] + }, + { + "cell_type": "code", + "execution_count": 50, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "10 loops, best of 3: 141 ms per loop\n" + ] + } + ], + "source": [ + "%%timeit\n", + "astar_search_closed('bats', 'exit')" + ] + }, + { + "cell_type": "code", + "execution_count": 51, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "['bats',\n", + " 'bans',\n", + " 'band',\n", + " 'sand',\n", + " 'said',\n", + " 'skid',\n", + " 'skit',\n", + " 'smit',\n", + " 'emit',\n", + " 'exit']" + ] + }, + "execution_count": 51, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "astar_search_closed('bats', 'exit')" + ] + }, + { + "cell_type": "code", + "execution_count": 88, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{2: [['heel', 'keel'], ['wane', 'wave'], ['cell', 'sell'], ['cons', 'cobs']],\n", + " 3: [['hank', 'haws'], ['bars', 'bets'], ['rats', 'paws'], ['lock', 'hack']],\n", + " 4: [['rule', 'sore'], ['wavy', 'rape'], ['peas', 'ping'], ['bond', 'toll']],\n", + " 5: [['cope', 'yowl'], ['lose', 'loci'], ['rump', 'dash'], ['four', 'dyes']],\n", + " 6: [['boon', 'sell'], ['lots', 'pomp'], ['cola', 'turn'], ['boos', 'laid']],\n", + " 7: [['eave', 'inns'], ['meek', 'mere'], ['keys', 'wily'], ['slam', 'yore']],\n", + " 8: [['hack', 'flip'], ['crag', 'huge'], ['flux', 'gill'], ['play', 'busy']],\n", + " 9: [['lacy', 'whey'], ['wren', 'rook'], ['lire', 'drip'], ['grab', 'lame']],\n", + " 10: [['over', 'turn'], ['worn', 'anew'], ['stow', 'elks'], ['ergo', 'rich']],\n", + " 11: [['bask', 'idea'], ['gabs', 'thud'], ['idea', 'clod'], ['mark', 'ibis']],\n", + " 12: [['umps', 'torn'], ['futz', 'shun'], ['abut', 'face'], ['slug', 'open']],\n", + " 13: [['umps', 'skin'], ['chum', 'rats'], ['fury', 'chum'], ['omen', 'zany']],\n", + " 14: [['chug', 'gaff'], ['atom', 'fizz']],\n", + " 15: [['chug', 'oxen']]}" + ] + }, + "execution_count": 88, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "solutions = {}\n", + "for _ in range(10000):\n", + " start, goal = random.sample(bigset, 2)\n", + " solution = astar_search_closed(start, goal)\n", + " sl = len(solution)\n", + " if sl not in solutions:\n", + " solutions[sl] = []\n", + " if len(solutions[sl]) < 4:\n", + " solutions[sl].append([start, goal])\n", + " \n", + "# if len(solution) >= 10:\n", + "# solutions += [solution]\n", + " \n", + "solutions" + ] + }, + { + "cell_type": "code", + "execution_count": 91, + "metadata": {}, + "outputs": [], + "source": [ + "solutions = {2: [['heel', 'keel'], ['wane', 'wave'], ['cell', 'sell'], ['cons', 'cobs']],\n", + " 3: [['hank', 'haws'], ['bars', 'bets'], ['rats', 'paws'], ['lock', 'hack']],\n", + " 4: [['rule', 'sore'], ['wavy', 'rape'], ['peas', 'ping'], ['bond', 'toll']],\n", + " 5: [['cope', 'yowl'], ['lose', 'loci'], ['rump', 'dash'], ['four', 'dyes']],\n", + " 6: [['boon', 'sell'], ['lots', 'pomp'], ['cola', 'turn'], ['boos', 'laid']],\n", + " 7: [['eave', 'inns'], ['meek', 'mere'], ['keys', 'wily'], ['slam', 'yore']],\n", + " 8: [['hack', 'flip'], ['crag', 'huge'], ['flux', 'gill'], ['play', 'busy']],\n", + " 9: [['lacy', 'whey'], ['wren', 'rook'], ['lire', 'drip'], ['grab', 'lame']],\n", + " 10: [['over', 'turn'], ['worn', 'anew'], ['stow', 'elks'], ['ergo', 'rich']],\n", + " 11: [['bask', 'idea'], ['gabs', 'thud'], ['idea', 'clod'], ['mark', 'ibis']],\n", + " 12: [['umps', 'torn'], ['futz', 'shun'], ['abut', 'face'], ['slug', 'open']],\n", + " 13: [['umps', 'skin'], ['chum', 'rats'], ['fury', 'chum'], ['omen', 'zany']],\n", + " 14: [['chug', 'gaff'], ['atom', 'fizz'], ['chug', 'jinn'], ['amen', 'flog'],\n", + " ['buzz', 'grog'], ['imps', 'pros']],\n", + " 15: [['chug', 'oxen'], ['amen', 'doff']]}" + ] + }, + { + "cell_type": "code", + "execution_count": 54, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[('amen', 'doff', 15), ('chug', 'jinn', 14), ('amen', 'flog', 14)]" + ] + }, + "execution_count": 54, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "[(s[0], s[-1], len(s)) for s in solutions if len(s) >= 14]" + ] + }, + { + "cell_type": "code", + "execution_count": 55, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "1 loop, best of 3: 360 ms per loop\n" + ] + } + ], + "source": [ + "%%timeit\n", + "astar_search_closed('blab', 'amen')" + ] + }, + { + "cell_type": "code", + "execution_count": 56, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "CPU times: user 384 ms, sys: 0 ns, total: 384 ms\n", + "Wall time: 385 ms\n" + ] + }, + { + "data": { + "text/plain": [ + "14" + ] + }, + "execution_count": 56, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "%time len(astar_search_closed('blab', 'amen'))" + ] + }, + { + "cell_type": "code", + "execution_count": 57, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "CPU times: user 124 ms, sys: 0 ns, total: 124 ms\n", + "Wall time: 121 ms\n" + ] + }, + { + "data": { + "text/plain": [ + "15" + ] + }, + "execution_count": 57, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "%time len(astar_search_closed('amen', 'doff'))" + ] + }, + { + "cell_type": "code", + "execution_count": 58, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "CPU times: user 32 ms, sys: 0 ns, total: 32 ms\n", + "Wall time: 32.4 ms\n" + ] + }, + { + "data": { + "text/plain": [ + "14" + ] + }, + "execution_count": 58, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "%time len(astar_search_closed('chug', 'jinn'))" + ] + }, + { + "cell_type": "code", + "execution_count": 59, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "CPU times: user 16 ms, sys: 0 ns, total: 16 ms\n", + "Wall time: 17.1 ms\n" + ] + }, + { + "data": { + "text/plain": [ + "14" + ] + }, + "execution_count": 59, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "%time len(astar_search_closed('amen', 'flog'))" + ] + }, + { + "cell_type": "code", + "execution_count": 73, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "CPU times: user 268 ms, sys: 4 ms, total: 272 ms\n", + "Wall time: 272 ms\n" + ] + }, + { + "data": { + "text/plain": [ + "14" + ] + }, + "execution_count": 73, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "%time len(astar_search_closed('buzz', 'grog'))" + ] + }, + { + "cell_type": "code", + "execution_count": 74, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "CPU times: user 64 ms, sys: 0 ns, total: 64 ms\n", + "Wall time: 64.1 ms\n" + ] + }, + { + "data": { + "text/plain": [ + "14" + ] + }, + "execution_count": 74, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "%time len(astar_search_closed('imps', 'pros'))" + ] + }, { "cell_type": "code", "execution_count": null, diff --git a/word-chains/word-chain-solution.ipynb b/word-chains/word-chain-solution.ipynb index e90caca..8a87922 100644 --- a/word-chains/word-chain-solution.ipynb +++ b/word-chains/word-chain-solution.ipynb @@ -106,9 +106,9 @@ }, "outputs": [], "source": [ - "def extend(chain):\n", - " return [chain + [s] for s in neighbours[chain[-1]]\n", - " if s not in chain]" + "# def extend(chain):\n", + "# return [chain + [s] for s in neighbours[chain[-1]]\n", + "# if s not in chain]" ] }, { @@ -119,8 +119,11 @@ }, "outputs": [], "source": [ - "def extend_raw(chain):\n", - " nbrs = [w for w in adjacents(chain[-1]) if w in words]\n", + "def extend(chain, closed=None):\n", + " if closed:\n", + " nbrs = set(neighbours[chain[-1]]) - closed\n", + " else:\n", + " nbrs = neighbours[chain[-1]]\n", " return [chain + [s] for s in nbrs\n", " if s not in chain]" ] @@ -133,8 +136,10 @@ }, "outputs": [], "source": [ - "def bfs_search(start, target, debug=False):\n", - " return bfs([[start]], target, debug=debug)" + "def extend_raw(chain):\n", + " nbrs = [w for w in adjacents(chain[-1]) if w in words]\n", + " return [chain + [s] for s in nbrs\n", + " if s not in chain]" ] }, { @@ -145,7 +150,8 @@ }, "outputs": [], "source": [ - "def bfs(agenda, goal, debug=False):\n", + "def bfs_search(start, goal, debug=False):\n", + " agenda = [[start]]\n", " finished = False\n", " while not finished and agenda:\n", " current = agenda[0]\n", @@ -164,25 +170,42 @@ }, { "cell_type": "code", - "execution_count": 10, + "execution_count": 19, "metadata": { "collapsed": true }, "outputs": [], "source": [ - "def dfs_search(start, target, debug=False):\n", - " return dfs([[start]], target, debug=debug)" + "def bfs_search_closed(start, goal, debug=False):\n", + " agenda = [[start]]\n", + " closed = set()\n", + " finished = False\n", + " while not finished and agenda:\n", + " current = agenda[0]\n", + " if debug:\n", + " print(current)\n", + " if current[-1] == goal:\n", + " finished = True\n", + " else:\n", + " closed.add(current[-1])\n", + " successors = extend(current, closed)\n", + " agenda = agenda[1:] + successors\n", + " if agenda:\n", + " return current\n", + " else:\n", + " return None " ] }, { "cell_type": "code", - "execution_count": 11, + "execution_count": 10, "metadata": { "collapsed": true }, "outputs": [], "source": [ - "def dfs(agenda, goal, debug=False):\n", + "def dfs_search(start, goal, debug=False):\n", + " agenda = [[start]]\n", " finished = False\n", " while not finished and agenda:\n", " current = agenda[0]\n", @@ -201,27 +224,15 @@ }, { "cell_type": "code", - "execution_count": 12, + "execution_count": 11, "metadata": { "collapsed": true }, "outputs": [], "source": [ - "def astar_search(start, target, debug=False):\n", - " agenda = [(distance(start, target), [start])]\n", + "def astar_search(start, goal, debug=False):\n", + " agenda = [(distance(start, goal), [start])]\n", " heapq.heapify(agenda)\n", - " return astar(agenda, target, debug=debug)" - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "metadata": { - "collapsed": true - }, - "outputs": [], - "source": [ - "def astar(agenda, goal, debug=False):\n", " finished = False\n", " while not finished and agenda:\n", " _, current = heapq.heappop(agenda)\n", @@ -241,27 +252,45 @@ }, { "cell_type": "code", - "execution_count": 14, + "execution_count": 12, "metadata": { "collapsed": true }, "outputs": [], "source": [ - "def astar_search_raw(start, target, debug=False):\n", - " agenda = [(distance(start, target), [start])]\n", + "# Uses direct lookup of successors, rather than using cached neighbours in the dict\n", + "def astar_search_raw(start, goal, debug=False):\n", + " agenda = [(distance(start, goal), [start])]\n", " heapq.heapify(agenda)\n", - " return astar_raw(agenda, target, debug=debug)" + " finished = False\n", + " while not finished and agenda:\n", + " _, current = heapq.heappop(agenda)\n", + " if debug:\n", + " print(current)\n", + " if current[-1] == goal:\n", + " finished = True\n", + " else:\n", + " successors = extend_raw(current) # Difference here\n", + " for s in successors:\n", + " heapq.heappush(agenda, (len(current) + distance(s[-1], goal) - 1, s))\n", + " if agenda:\n", + " return current\n", + " else:\n", + " return None " ] }, { "cell_type": "code", - "execution_count": 15, + "execution_count": 13, "metadata": { "collapsed": true }, "outputs": [], "source": [ - "def astar_raw(agenda, goal, debug=False):\n", + "def astar_search_closed(start, goal, debug=False):\n", + " agenda = [(distance(start, goal), [start])]\n", + " heapq.heapify(agenda)\n", + " closed = set()\n", " finished = False\n", " while not finished and agenda:\n", " _, current = heapq.heappop(agenda)\n", @@ -270,18 +299,19 @@ " if current[-1] == goal:\n", " finished = True\n", " else:\n", - " successors = extend_raw(current)\n", + " closed.add(current[-1])\n", + " successors = extend(current, closed)\n", " for s in successors:\n", " heapq.heappush(agenda, (len(current) + distance(s[-1], goal) - 1, s))\n", " if agenda:\n", " return current\n", " else:\n", - " return None " + " return None " ] }, { "cell_type": "code", - "execution_count": 16, + "execution_count": 14, "metadata": {}, "outputs": [ { @@ -290,7 +320,7 @@ "['vice', 'dice', 'dire', 'dare', 'ware', 'wars']" ] }, - "execution_count": 16, + "execution_count": 14, "metadata": {}, "output_type": "execute_result" } @@ -301,7 +331,7 @@ }, { "cell_type": "code", - "execution_count": 17, + "execution_count": 15, "metadata": {}, "outputs": [ { @@ -310,7 +340,7 @@ "['vice', 'dice', 'dire', 'dare', 'ware', 'wars']" ] }, - "execution_count": 17, + "execution_count": 15, "metadata": {}, "output_type": "execute_result" } @@ -321,7 +351,7 @@ }, { "cell_type": "code", - "execution_count": 18, + "execution_count": 16, "metadata": {}, "outputs": [ { @@ -330,7 +360,7 @@ "6" ] }, - "execution_count": 18, + "execution_count": 16, "metadata": {}, "output_type": "execute_result" } @@ -341,7 +371,7 @@ }, { "cell_type": "code", - "execution_count": 19, + "execution_count": 17, "metadata": {}, "outputs": [ { @@ -350,7 +380,7 @@ "6" ] }, - "execution_count": 19, + "execution_count": 17, "metadata": {}, "output_type": "execute_result" } @@ -367,7 +397,7 @@ { "data": { "text/plain": [ - "793" + "6" ] }, "execution_count": 20, @@ -376,19 +406,39 @@ } ], "source": [ - "len(dfs_search('vice', 'wars'))" + "len(bfs_search_closed('vice', 'wars'))" ] }, { "cell_type": "code", "execution_count": 21, "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "793" + ] + }, + "execution_count": 21, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "len(dfs_search('vice', 'wars'))" + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "10000 loops, best of 3: 153 µs per loop\n" + "10000 loops, best of 3: 158 µs per loop\n" ] } ], @@ -399,14 +449,14 @@ }, { "cell_type": "code", - "execution_count": 22, + "execution_count": 23, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "100 loops, best of 3: 15.8 ms per loop\n" + "100 loops, best of 3: 15.6 ms per loop\n" ] } ], @@ -417,14 +467,32 @@ }, { "cell_type": "code", - "execution_count": 23, + "execution_count": 24, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "10000 loops, best of 3: 168 µs per loop\n" + ] + } + ], + "source": [ + "%%timeit\n", + "astar_search_closed('vice', 'wars')" + ] + }, + { + "cell_type": "code", + "execution_count": 25, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "1 loop, best of 3: 1min 42s per loop\n" + "1 loop, best of 3: 1min 40s per loop\n" ] } ], @@ -435,14 +503,32 @@ }, { "cell_type": "code", - "execution_count": 24, + "execution_count": 26, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "1 loop, best of 3: 597 ms per loop\n" + ] + } + ], + "source": [ + "%%timeit\n", + "bfs_search_closed('vice', 'wars')" + ] + }, + { + "cell_type": "code", + "execution_count": 27, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "10 loops, best of 3: 88 ms per loop\n" + "10 loops, best of 3: 85.5 ms per loop\n" ] } ], @@ -469,7 +555,7 @@ }, { "cell_type": "code", - "execution_count": 25, + "execution_count": 28, "metadata": { "collapsed": true }, @@ -491,7 +577,7 @@ }, { "cell_type": "code", - "execution_count": 26, + "execution_count": 29, "metadata": { "scrolled": true }, @@ -503,7 +589,7 @@ " '`bash`, `cash`, `dash`, `gash`, `hash`, `lash`, `mash`, `rasp`, `rush`, `sash`, `wash`')" ] }, - "execution_count": 26, + "execution_count": 29, "metadata": {}, "output_type": "execute_result" } @@ -514,7 +600,7 @@ }, { "cell_type": "code", - "execution_count": 27, + "execution_count": 30, "metadata": { "scrolled": true }, @@ -526,7 +612,7 @@ " '`base`, `bash`, `bask`, `bass`, `bast`, `bath`, `bosh`, `bush`, `case`, `cash`, `cask`, `cast`, `dash`, `dish`, `gash`, `gasp`, `gosh`, `gush`, `hash`, `hasp`, `hath`, `hush`, `lash`, `lass`, `last`, `lath`, `lush`, `mash`, `mask`, `mass`, `mast`, `math`, `mesh`, `mush`, `push`, `ramp`, `rasp`, `ruse`, `rush`, `rusk`, `rust`, `sash`, `sass`, `tush`, `wash`, `wasp`, `wish`')" ] }, - "execution_count": 27, + "execution_count": 30, "metadata": {}, "output_type": "execute_result" } @@ -537,7 +623,7 @@ }, { "cell_type": "code", - "execution_count": 28, + "execution_count": 31, "metadata": { "scrolled": true }, @@ -548,7 +634,7 @@ "180" ] }, - "execution_count": 28, + "execution_count": 31, "metadata": {}, "output_type": "execute_result" } @@ -559,7 +645,7 @@ }, { "cell_type": "code", - "execution_count": 29, + "execution_count": 32, "metadata": { "scrolled": true }, @@ -570,7 +656,7 @@ "2195" ] }, - "execution_count": 29, + "execution_count": 32, "metadata": {}, "output_type": "execute_result" } @@ -581,7 +667,7 @@ }, { "cell_type": "code", - "execution_count": 30, + "execution_count": 33, "metadata": { "scrolled": true }, @@ -592,7 +678,7 @@ "2192" ] }, - "execution_count": 30, + "execution_count": 33, "metadata": {}, "output_type": "execute_result" } @@ -603,7 +689,7 @@ }, { "cell_type": "code", - "execution_count": 31, + "execution_count": 34, "metadata": { "scrolled": true }, @@ -612,7 +698,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "100 loops, best of 3: 5.96 ms per loop\n" + "100 loops, best of 3: 5.82 ms per loop\n" ] } ], @@ -623,7 +709,7 @@ }, { "cell_type": "code", - "execution_count": 32, + "execution_count": 35, "metadata": { "scrolled": true },