Done puzzle 60
authorNeil Smith <neil.git@njae.me.uk>
Thu, 13 Apr 2017 13:26:29 +0000 (14:26 +0100)
committerNeil Smith <neil.git@njae.me.uk>
Thu, 13 Apr 2017 13:26:29 +0000 (14:26 +0100)
euler60.ipynb [new file with mode: 0644]

diff --git a/euler60.ipynb b/euler60.ipynb
new file mode 100644 (file)
index 0000000..a9b5200
--- /dev/null
@@ -0,0 +1,557 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "# Approach 1: generate and test\n",
+    "My first thought was to generate all tuples of five primes, up to some limit, and then test to see which of them had the concatenation property. That proved to be rather slow.\n",
+    "\n",
+    "# Approach 2: interleave generation and testing\n",
+    "The second approach was to interleave generation and testing. I maintain a list of groups that have the concatenation property, and try adding the next prime to each of the groups. Those that succeed are added to the list. Groups are never removed from the list, as a later prime may give a valid extension of the group."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 23,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "1229"
+      ]
+     },
+     "execution_count": 23,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "require_relative 'primes'\n",
+    "require_relative 'array-numbers'\n",
+    "$primes = Primes.instance\n",
+    "$primes.primes.length"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 3,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "1223"
+      ]
+     },
+     "execution_count": 3,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "candidates = $primes.take(200)\n",
+    "candidates.last"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 4,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]"
+      ]
+     },
+     "execution_count": 4,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "ds = (0..10).to_a"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 5,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       ":tuples"
+      ]
+     },
+     "execution_count": 5,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "def tuples(items, count)\n",
+    "  if count == 0\n",
+    "    [[]]\n",
+    "  elsif items.empty?\n",
+    "    []\n",
+    "  else\n",
+    "    tuples(items.drop(1), count) + tuples(items.drop(1), count-1).map {|t| [items.first] + t}\n",
+    "  end\n",
+    "end"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 23,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "19900"
+      ]
+     },
+     "execution_count": 23,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "tuples(candidates, 2).length"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 32,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "[[1201, 1213, 1217, 1223], [1193, 1213, 1217, 1223], [1193, 1201, 1217, 1223], [1193, 1201, 1213, 1223], [1193, 1201, 1213, 1217], [1187, 1213, 1217, 1223], [1187, 1201, 1217, 1223], [1187, 1201, 1213, 1223], [1187, 1201, 1213, 1217], [1187, 1193, 1217, 1223], [1187, 1193, 1213, 1223], [1187, 1193, 1213, 1217], [1187, 1193, 1201, 1223], [1187, 1193, 1201, 1217], [1187, 1193, 1201, 1213], [1181, 1213, 1217, 1223], [1181, 1201, 1217, 1223], [1181, 1201, 1213, 1223], [1181, 1201, 1213, 1217], [1181, 1193, 1217, 1223], [1181, 1193, 1213, 1223]]"
+      ]
+     },
+     "execution_count": 32,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "groups = tuples(candidates, 4)\n",
+    "groups[0..20]"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 26,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "[78, 79, 710, 87, 89, 810, 97, 98, 910, 107, 108, 109]"
+      ]
+     },
+     "execution_count": 26,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "[7, 8, 9, 10].permutation(2).map {|a, b| (a.to_digits + b.to_digits).to_i}"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 6,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       ":valid_group"
+      ]
+     },
+     "execution_count": 6,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "def valid_group(group)\n",
+    "  group.permutation(2).map {|a, b| (a.to_digits + b.to_digits).to_i}.all? {|n| $primes.is_prime? n}\n",
+    "end"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 7,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       ":valid_group2"
+      ]
+     },
+     "execution_count": 7,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "# No need to restest primality of combinations of numbers already in the group\n",
+    "def valid_group2(group, item)\n",
+    "  item_digits = item.to_digits\n",
+    "  group.flat_map {|a| [(a.to_digits + item_digits).to_i, \n",
+    "    (item_digits + a.to_digits).to_i]}.all? {|n| $primes.is_prime? n}\n",
+    "end"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "# groups.select {|g| valid_group g}"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 9,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       ":grow"
+      ]
+     },
+     "execution_count": 9,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "def grow(groups, item)\n",
+    "  new_groups = groups.map {|g| g + [item]}.select {|g| valid_group g}\n",
+    "  groups + [[item]] + new_groups\n",
+    "end"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 10,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       ":grow2"
+      ]
+     },
+     "execution_count": 10,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "def grow2(groups, item)\n",
+    "  new_groups = groups.select {|g| valid_group2 g, item}.map {|g| g + [item]}\n",
+    "  groups + [[item]] + new_groups\n",
+    "end"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 11,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "[[2], [3], [5], [7], [3, 7], [11], [3, 11], [13], [17], [3, 17], [19], [7, 19], [13, 19], [23], [11, 23], [29], [31], [3, 31], [19, 31], [37], [3, 37], [41], [43], [47], [23, 47], [53], [59], [3, 59], [61], [7, 61], [13, 61], [67], [3, 67], [37, 67], [3, 37, 67], [71], [29, 71]]"
+      ]
+     },
+     "execution_count": 11,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "pgroups = []\n",
+    "$primes.take(20).each do |p|\n",
+    "  pgroups = grow pgroups, p\n",
+    "end\n",
+    "pgroups"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 12,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       ":grow_to_size"
+      ]
+     },
+     "execution_count": 12,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "def grow_to_size(group_size = 5, debug = false)\n",
+    "  pgroups = []\n",
+    "  i = 0\n",
+    "  while !pgroups.any? {|g| g.length >= group_size}\n",
+    "    pgroups = grow pgroups, $primes[i]\n",
+    "    puts \"#{pgroups.length} groups, added #{$primes[i]}\" if debug && (i % 50 == 0)\n",
+    "    i += 1\n",
+    "  end\n",
+    "  \n",
+    "  pgroups.select {|g| g.length >= group_size}\n",
+    "end"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 13,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       ":grow_to_size2"
+      ]
+     },
+     "execution_count": 13,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "def grow_to_size2(group_size = 5, debug = false)\n",
+    "  pgroups = []\n",
+    "  i = 0\n",
+    "  while !pgroups.any? {|g| g.length >= group_size}\n",
+    "    pgroups = grow2 pgroups, $primes[i]\n",
+    "    puts \"#{pgroups.length} groups, added #{$primes[i]}\" if debug && (i % 50 == 0)\n",
+    "    i += 1\n",
+    "  end\n",
+    "  \n",
+    "  pgroups.select {|g| g.length >= group_size}\n",
+    "end"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 25,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "1 groups, added 2\n",
+      "142 groups, added 233\n",
+      "437 groups, added 547\n",
+      "Found [[3, 7, 109, 673]] in 2.166974642\n"
+     ]
+    }
+   ],
+   "source": [
+    "start = Time.now\n",
+    "found = grow_to_size 4, debug=true\n",
+    "finish = Time.now\n",
+    "puts \"Found #{found} in #{finish - start}\""
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 26,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "1 groups, added 2\n",
+      "142 groups, added 233\n",
+      "437 groups, added 547\n",
+      "Found [[3, 7, 109, 673]] in 1.012126927\n"
+     ]
+    }
+   ],
+   "source": [
+    "start = Time.now\n",
+    "found = grow_to_size2 4, debug=true\n",
+    "finish = Time.now\n",
+    "puts \"Found #{found} in #{finish - start}\""
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 15,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "1 groups, added 2\n",
+      "142 groups, added 233\n",
+      "437 groups, added 547\n"
+     ]
+    },
+    {
+     "data": {
+      "text/plain": [
+       "[[3, 7, 109, 673]]"
+      ]
+     },
+     "execution_count": 15,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "grow_to_size2 4, debug=true"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 33,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "1 groups, added 2\n",
+      "142 groups, added 233\n",
+      "437 groups, added 547\n",
+      "903 groups, added 877\n",
+      "1420 groups, added 1229\n",
+      "1926 groups, added 1597\n",
+      "2531 groups, added 1993\n",
+      "3201 groups, added 2371\n",
+      "3958 groups, added 2749\n",
+      "4678 groups, added 3187\n",
+      "5565 groups, added 3581\n",
+      "6455 groups, added 4001\n",
+      "7509 groups, added 4421\n",
+      "8594 groups, added 4861\n",
+      "9887 groups, added 5281\n",
+      "11260 groups, added 5701\n",
+      "12844 groups, added 6143\n",
+      "14344 groups, added 6577\n",
+      "16018 groups, added 7001\n",
+      "17704 groups, added 7507\n",
+      "19570 groups, added 7927\n",
+      "21743 groups, added 8389\n",
+      "Found [[13, 5197, 5701, 6733, 8389]], sum [26033], in 1095.055247849\n"
+     ]
+    }
+   ],
+   "source": [
+    "start = Time.now\n",
+    "found = grow_to_size 5, debug=true\n",
+    "finish = Time.now\n",
+    "puts \"Found #{found}, sum #{found.map {|f| f.sum}}, in #{finish - start}\""
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 34,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "1 groups, added 2\n",
+      "142 groups, added 233\n",
+      "437 groups, added 547\n",
+      "903 groups, added 877\n",
+      "1420 groups, added 1229\n",
+      "1926 groups, added 1597\n",
+      "2531 groups, added 1993\n",
+      "3201 groups, added 2371\n",
+      "3958 groups, added 2749\n",
+      "4678 groups, added 3187\n",
+      "5565 groups, added 3581\n",
+      "6455 groups, added 4001\n",
+      "7509 groups, added 4421\n",
+      "8594 groups, added 4861\n",
+      "9887 groups, added 5281\n",
+      "11260 groups, added 5701\n",
+      "12844 groups, added 6143\n",
+      "14344 groups, added 6577\n",
+      "16018 groups, added 7001\n",
+      "17704 groups, added 7507\n",
+      "19570 groups, added 7927\n",
+      "21743 groups, added 8389\n",
+      "Found [[13, 5197, 5701, 6733, 8389]], sum [26033], in 387.589197431\n"
+     ]
+    }
+   ],
+   "source": [
+    "start = Time.now\n",
+    "found = grow_to_size2 5, debug=true\n",
+    "finish = Time.now\n",
+    "puts \"Found #{found}, sum #{found.map {|f| f.sum}}, in #{finish - start}\""
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 35,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "26033"
+      ]
+     },
+     "execution_count": 35,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "[13, 5197, 5701, 6733, 8389].sum"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Ruby 2.4.0",
+   "language": "ruby",
+   "name": "ruby"
+  },
+  "language_info": {
+   "file_extension": ".rb",
+   "mimetype": "application/x-ruby",
+   "name": "ruby",
+   "version": "2.4.0"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 2
+}