From 23eefc32ff2a14f527658597dbc85287496c464e Mon Sep 17 00:00:00 2001 From: Peter Norvig Date: Tue, 6 Jan 2026 23:03:29 -0800 Subject: [PATCH] Add files via upload --- ipynb/TruncatablePrimes.ipynb | 552 ++++++++++++++++++++++------------ 1 file changed, 358 insertions(+), 194 deletions(-) diff --git a/ipynb/TruncatablePrimes.ipynb b/ipynb/TruncatablePrimes.ipynb index 9133eab..4397e19 100644 --- a/ipynb/TruncatablePrimes.ipynb +++ b/ipynb/TruncatablePrimes.ipynb @@ -13,7 +13,7 @@ "\n", "[![](https://community.wolfram.com//c/portal/getImageAttachment?filename=IMG_20181212_120939.jpg&userId=143131)](https://community.wolfram.com/groups/-/m/t/1569707)\n", "\n", - "The number printed on it is a prime, and as you sharpen the pencil and remove digits one at a time from the left, the resulting numbers are all primes:\n", + "The 24-digit number printed on it is a prime, and as you sharpen the pencil and remove digits one at a time from the left, the resulting numbers are all primes:\n", "\n", " 357686312646216567629137 is prime\n", " 57686312646216567629137 is prime\n", @@ -25,7 +25,7 @@ "\n", "Numbers like this are called [**truncatable primes**](https://en.wikipedia.org/wiki/Truncatable_prime). I thought I would write a program to find other truncatable primes.\n", "\n", - "My function `left_truncatable_primes` below starts with the list of one-digit primes: [2, 3, 5, 7]. Then it tries placing each possible digit 1–9 to the left of each of the one-digit primes, giving a list of two-digit candidates. From the candidates it filters out just the primes and recursively tries to add digits to them, giving us three-digit primes, then four-digit primes, and so on, stopping when none of the candidates are primes. It gathers up all the truncatable primes and returns them in sorted order." + "My function `left_truncatable_primes` below starts with the list of one-digit primes: [2, 3, 5, 7]. Then it places each possible digit 1–9 to the left of each of the one-digit primes, giving a list of two-digit candidates. From the candidates it filters out just the primes. If there are any new primes, it recursively adds digits to them, giving us three-digit primes, then four-digit primes, and so on, stopping when there are no more new primes. In the end, the function gathers up all the truncatable primes and returns them in sorted order." ] }, { @@ -39,11 +39,9 @@ "\n", "def left_truncatable_primes(starting_primes=[2, 3, 5, 7]) -> list[int]:\n", " \"\"\"All left-truncatable primes, in ascending order.\"\"\"\n", - " if not starting_primes:\n", - " return []\n", - " else:\n", - " candidates = [int(d + str(p)) for d in \"123456789\" for p in starting_primes]\n", - " return starting_primes + left_truncatable_primes(list(filter(isprime, candidates)))" + " candidates = [int(d + str(p)) for d in \"123456789\" for p in starting_primes]\n", + " new_primes = list(filter(isprime, candidates))\n", + " return starting_primes + (left_truncatable_primes(new_primes) if new_primes else [])" ] }, { @@ -82,7 +80,7 @@ "id": "a32b56c4-587b-48d5-91ec-1abcef2e909f", "metadata": {}, "source": [ - "There are 4260 left-truncatable primes. Here are the smallest and largest ones:" + "There are 4260 left-truncatable primes. Here are the smallest and largest of them:" ] }, { @@ -147,7 +145,7 @@ "id": "853d5a6c-936e-4ab4-afc3-2082641063fc", "metadata": {}, "source": [ - "Below is the count for each digit-size, with a bar chart. We see there is only one 24-digit left-truncatable prime, the one on the pencil, and that the most common number of digits is 9.\n" + "Below is the count for each digit-length, with a bar chart. We see there is only one 24-digit left-truncatable prime, the one on the pencil, and that the most common number of digits is 9.\n" ] }, { @@ -191,7 +189,7 @@ }, { "data": { - "image/png": "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AQUAKI6AAgAUR0ABAIojoAAAxRFQAIDiCCgAQHEEFACgOAIKAFAcAQUAKE6HWhcA4J0wZPaqZj/25YUTWrQswNtTgwIAFEdAAQCKI6AAAK07oCxYsCA+8pGPxKmnnhp9+/aNq6++OjZv3txkn71798a0adOiT58+0b1795g0aVLs2LGjyT5btmyJCRMmRNeuXfPzzJo1Kw4ePNgy7wgAaFsBZe3atTl8bNiwIVavXh0HDhyIsWPHxuuvv17dZ8aMGfHII4/EihUr8v7btm2LiRMnVrcfOnQoh5P9+/fHunXr4r777otly5bFvHnzWvadAQBtYxTPY4891mQ5BYtUA7Jx48a45JJLYvfu3XHvvffG8uXL47LLLsv7LF26NM4+++wcakaNGhWPP/54PP/88/HEE09Ev379YsSIEXHbbbfFjTfeGLfcckt06tSpZd8hANC2+qCkQJL07t07z1NQSbUqY8aMqe4zdOjQGDRoUKxfvz4vp/mwYcNyOKkYN25c7NmzJzZt2nTM19m3b1/efuQEANSvZgeUw4cPxw033BAf/ehH49xzz83rtm/fnmtAevXq1WTfFEbStso+R4aTyvbKtrfq+9KzZ8/qNHDgwOYWGwCo54CS+qL86U9/igcffDBOtjlz5uTamsq0devWk/6aAEAru5Ls9ddfHytXroynn346zjjjjOr6/v37586vu3btalKLkkbxpG2VfX772982eb7KKJ/KPkfr3LlzngCAtuG4alAaGxtzOHn44YfjySefjDPPPLPJ9pEjR0bHjh1jzZo11XVpGHIaVjx69Oi8nObPPfdc7Ny5s7pPGhHUo0ePOOecc078HQEAbasGJTXrpBE6P//5z/O1UCp9RlK/kFNOOSXPp0yZEjNnzswdZ1PomD59eg4laQRPkoYlpyBy7bXXxqJFi/JzzJ07Nz+3WhIA4LgDyt13353nl156aZP1aSjxF77whfzz4sWLo6GhIV+gLY2+SSN07rrrruq+7du3z81DU6dOzcGlW7duMXny5Jg/f75PpI3dgC1xEzYATjigpCaet9OlS5dYsmRJnt7K4MGD49FHHz2elwYA2hD34gEAiiOgAADFEVAAgOIIKABAcQQUAKA4AgoAUBwBBQAojoACABRHQAEAiiOgAADFEVAAgOIIKABAcQQUAKA4AgoAUBwBBQAojoACABRHQAEA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", + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAjsAAAGwCAYAAABPSaTdAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjgsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvwVt1zgAAAAlwSFlzAAAPYQAAD2EBqD+naQAAKBhJREFUeJzt3QlU1WX+x/EvyKKiuKWgiWi57+ZKpZkSpObo6JmpxjEqszI1l8mUyS2tMCs1HcypY+qcySxnsnLJxH1KXMLMNUY7eqQUKE1RS0W4//N9/v97/1wFQ7xwLw/v1zm/c/kt997n93CBD8/y+/k5HA6HAAAAWMrf2wUAAAAoToQdAABgNcIOAACwGmEHAABYjbADAACsRtgBAABWI+wAAACrBXi7AL4gNzdXTpw4IZUrVxY/Pz9vFwcAABSCXirw3LlzUqdOHfH3L7j9hrAjYoJOREREYeoVAAD4mLS0NKlbt26B+wk7IqZFx1lZoaGhJffdAQAARZaVlWUaK5x/xwtC2BFxdV1p0CHsAABQuvzWEBQGKAMAAKsRdgAAgNUIOwAAwGqEHQAAYDXCDgAAsBphBwAAWI2wAwAArEbYAQAAViPsAAAAqxF2AACA1Qg7AADAaoQdAABgNcIOAACwGmEHAABYjbADAACsFuDtAgAouvoTVhf5ucdm9KHqAZQJtOwAAACrEXYAAIDVCDsAAMBqhB0AAGA1wg4AALAaYQcAAFiNsAMAAKxG2AEAAFYj7AAAAKsRdgAAgNUIOwAAwGqEHQAAYDXCDgAAsBphBwAAWC3A2wUAypr6E1YX+bnHZvTxaFkAoCygZQcAAFiNsAMAAKxGNxYAg+41ALaiZQcAAFiNsAMAAKxG2AEAAFYj7AAAAKsRdgAAgNUIOwAAwGpeDTtTp04VPz8/t6Vp06au/RcvXpThw4dLjRo1pFKlSjJw4EDJyMhwe43jx49Lnz59pGLFilKrVi0ZN26cXLlyxQtnAwAAfJHXr7PTokULWb9+vWs9IOD/izRmzBhZvXq1LF++XKpUqSIjRoyQAQMGyJdffmn25+TkmKATHh4u27Ztk5MnT8ojjzwigYGB8sorr3jlfAAAgG/xetjRcKNh5Wpnz56VhQsXytKlS6VHjx5m26JFi6RZs2ayfft26dKli6xbt04OHjxowlJYWJi0bdtWpk+fLuPHjzetRkFBQV44IwAA4Eu8Pmbn8OHDUqdOHbnttttk0KBBpltKpaSkSHZ2tkRHR7uO1S6uevXqSXJyslnXx1atWpmg4xQbGytZWVly4MCBAt/z0qVL5pi8CwAAsJNXw07nzp1l8eLFsnbtWnnrrbfk6NGj0rVrVzl37pykp6eblpmqVau6PUeDje5T+pg36Dj3O/cVJCEhwXSLOZeIiIhiOT8AAFDGu7F69erl+rp169Ym/ERGRsqHH34oFSpUKLb3jY+Pl7Fjx7rWtWWHwAMAgJ283o2Vl7biNG7cWI4cOWLG8Vy+fFnOnDnjdozOxnKO8dHHq2dnOdfzGwfkFBwcLKGhoW4LAACwk0+FnfPnz8t3330ntWvXlvbt25tZVRs2bHDtT01NNWN6oqKizLo+7tu3TzIzM13HJCUlmfDSvHlzr5wDAADwLV7txnruueekb9++puvqxIkTMmXKFClXrpw8/PDDZizNkCFDTHdT9erVTYAZOXKkCTg6E0vFxMSYUDN48GCZOXOmGaczceJEc20ebb0BAADwatj5/vvvTbA5deqU1KxZU+6++24zrVy/VrNnzxZ/f39zMUGdQaUzrebPn+96vgajVatWybBhw0wICgkJkbi4OJk2bZoXzwoAAPgSr4adZcuWXXd/+fLlJTEx0SwF0VahNWvWFEPpAACADXxqzA4AAICnEXYAAIDVCDsAAMBqhB0AAGA1wg4AALAaYQcAAFiNsAMAAKxG2AEAAFYj7AAAAKsRdgAAgNUIOwAAwGqEHQAAYDXCDgAAsBphBwAAWI2wAwAArEbYAQAAViPsAAAAqxF2AACA1Qg7AADAaoQdAABgNcIOAACwGmEHAABYjbADAACsRtgBAABWI+wAAACrEXYAAIDVArxdAAD2qT9hdZGfe2xGH4+WBQBo2QEAAFYj7AAAAKsRdgAAgNUIOwAAwGqEHQAAYDXCDgAAsBphBwAAWI2wAwAArEbYAQAAViPsAAAAqxF2AACA1Qg7AADAatwIFCgEbmwJAKUXLTsAAMBqhB0AAGA1wg4AALAaYQcAAFiNsAMAAKxG2AEAAFYj7AAAAKsRdgAAgNUIOwAAwGqEHQAAYDXCDgAAsBphBwAAWI2wAwAArEbYAQAAVvOZsDNjxgzx8/OT0aNHu7ZdvHhRhg8fLjVq1JBKlSrJwIEDJSMjw+15x48flz59+kjFihWlVq1aMm7cOLly5YoXzgAAAPginwg7u3btkr///e/SunVrt+1jxoyRlStXyvLly2XLli1y4sQJGTBggGt/Tk6OCTqXL1+Wbdu2yZIlS2Tx4sUyefJkL5wFAADwRV4PO+fPn5dBgwbJO++8I9WqVXNtP3v2rCxcuFBmzZolPXr0kPbt28uiRYtMqNm+fbs5Zt26dXLw4EH55z//KW3btpVevXrJ9OnTJTEx0QSggly6dEmysrLcFgAAYCevhx3tptLWmejoaLftKSkpkp2d7ba9adOmUq9ePUlOTjbr+tiqVSsJCwtzHRMbG2vCy4EDBwp8z4SEBKlSpYpriYiIKJZzAwAAZTzsLFu2THbv3m3Cx9XS09MlKChIqlat6rZdg43ucx6TN+g49zv3FSQ+Pt60HDmXtLQ0D50RAADwNQHeemMNGKNGjZKkpCQpX758ib53cHCwWQAAgP281rKj3VSZmZlyxx13SEBAgFl0EPLcuXPN19pCo+Nuzpw54/Y8nY0VHh5uvtbHq2dnOdedxwAAgLLNa2GnZ8+esm/fPtmzZ49r6dChgxms7Pw6MDBQNmzY4HpOamqqmWoeFRVl1vVRX0NDk5O2FIWGhkrz5s29cl4AAMC3eK0bq3LlytKyZUu3bSEhIeaaOs7tQ4YMkbFjx0r16tVNgBk5cqQJOF26dDH7Y2JiTKgZPHiwzJw504zTmThxohn0TDcVAADwatgpjNmzZ4u/v7+5mKBOF9eZVvPnz3ftL1eunKxatUqGDRtmQpCGpbi4OJk2bZpXyw0AAHyHT4WdzZs3u63rwGW9Zo4uBYmMjJQ1a9aUQOkAAEBp5PXr7AAAABQnwg4AALAaYQcAAFiNsAMAAKxG2AEAAFYj7AAAAKsRdgAAgNUIOwAAwGqEHQAAYDXCDgAAsBphBwAAWI2wAwAArEbYAQAAViPsAAAAqxF2AACA1Qg7AADAaoQdAABgNcIOAACwGmEHAABYjbADAACsRtgBAABWI+wAAACrBXi7AABwPfUnrC5yBR2b0YfKBUDLDgAAsBvdWAAAwGqEHQAAYDXCDgAAsBphBwAAWI2wAwAArEbYAQAAViPsAAAAqxF2AACA1Qg7AADAaoQdAABgNcIOAACwGmEHAABYjbADAACsRtgBAABWI+wAAACrEXYAAIDVArxdAKC41J+wusjPPTajj0fLAgDwHlp2AACA1Qg7AADAaoQdAABgNcIOAACwGmEHAABYjbADAACsRtgBAABWK1LYue222+TUqVPXbD9z5ozZBwAAUKrDzrFjxyQnJ+ea7ZcuXZIffvjBE+UCAAAo+Ssof/rpp66vP//8c6lSpYprXcPPhg0bpH79+p4pGQAAQEmHnf79+5tHPz8/iYuLc9sXGBhogs4bb7zhiXIBAACUfNjJzc01jw0aNJBdu3bJLbfc4plSAAAA+NKYnaNHj3ok6Lz11lvSunVrCQ0NNUtUVJR89tlnrv0XL16U4cOHS40aNaRSpUoycOBAycjIcHuN48ePS58+faRixYpSq1YtGTdunFy5cuWmywYAAMr4Xc91fI4umZmZrhYfp3fffbdQr1G3bl2ZMWOGNGrUSBwOhyxZskT69esnX3/9tbRo0ULGjBkjq1evluXLl5vxQSNGjJABAwbIl19+6RonpEEnPDxctm3bJidPnpRHHnnEdKm98sorRT01AABQ1sPOiy++KNOmTZMOHTpI7dq1zRieoujbt6/b+ssvv2xae7Zv326C0MKFC2Xp0qXSo0cPs3/RokXSrFkzs79Lly6ybt06OXjwoKxfv17CwsKkbdu2Mn36dBk/frxMnTpVgoKCilQuAABQxsPOggULZPHixTJ48GCPFURbabQF58KFC6Y7KyUlRbKzsyU6Otp1TNOmTaVevXqSnJxswo4+tmrVygQdp9jYWBk2bJgcOHBA2rVrl+976RR5XZyysrI8dh4AAMCCMTuXL1+WO++80yMF2LdvnxmPExwcLE8//bSsWLFCmjdvLunp6aZlpmrVqm7Ha7DRfUof8wYd537nvoIkJCSYbjHnEhER4ZFzAQAAloSdJ554wnQveUKTJk1kz549smPHDtMio1PatWuqOMXHx8vZs2ddS1paWrG+HwAAKGXdWDpL6u233zZjZXQ2lQ4IzmvWrFmFfi1tvWnYsKH5un379mZK+5tvvikPPvigaUHSW1Dkbd3R2Vg6IFnp486dO91ezzlby3lMfrQVSRcAAGC/IoWdvXv3msHAav/+/W77ijpY2Ulndul4Gg0+GqJ0xpdOOVepqalmqrmO6VH6qIOadUaYTjtXSUlJZhq7doUBAAAUKexs2rTJY91JvXr1MoOOz507Z7rGNm/e7LoVxZAhQ2Ts2LFSvXp1E2BGjhxpAo4OTlYxMTEm1OhA6ZkzZ5pxOhMnTjTX5qHlBgAA3NR1djxBW2T0ujh6fRwNN9olpkHnvvvuM/tnz54t/v7+pmVHW3t0ptX8+fNdzy9XrpysWrXKjPXREBQSEmLG/Oi0eAAAgCKHnXvvvfe63VUbN24s1OvodXSup3z58pKYmGiWgkRGRsqaNWsK9X4AAKDsKVLYcY7XcdLr4eiMKh2/c/UNQgEAAEpd2NHupfzoVYvPnz9/s2UCAADw7nV2CvLnP/+50PfFAgAAKHVhR2/foONsAAAASnU3lt55PC+9Y7nOqPrqq69k0qRJniobAACAd8KOThPPS6eH620fdMq3XvsGAACgVIedRYsWeb4kAAAAvnZRwZSUFDl06JD5ukWLFtKuXTtPlQsAAMB7YUevfPzQQw+ZWzs4b9KpN+zUiw0uW7ZMatas6ZnSAYAH1Z+wusjPPTajD98LoCzNxtJ7VOm9rA4cOCCnT582i15QMCsrS5599lnPlxIAAKAkW3bWrl0r69evl2bNmrm26Q059bYODFAGAAClvmUnNzdXAgMDr9mu23QfAABAqQ47PXr0kFGjRsmJEydc23744QcZM2aM9OzZ05PlAwAAKPmw87e//c2Mz6lfv77cfvvtZmnQoIHZNm/evJsrEQAAgLfH7ERERMju3bvNuJ1vv/3WbNPxO9HR0Z4sGwAAQMm27GzcuNEMRNYWHD8/P7nvvvvMzCxdOnbsaK6185///OfmSwUAAOCNsDNnzhwZOnSohIaG5nsLiaeeekpmzZrlqbIBAACUbNj55ptv5P777y9wv04716sqAwAAlMqwk5GRke+Uc6eAgAD58ccfPVEuAACAkg87t956q7lSckH27t0rtWvX9kS5AAAASj7s9O7dWyZNmiQXL168Zt+vv/4qU6ZMkQceeMAzJQMAACjpqecTJ06Ujz76SBo3biwjRoyQJk2amO06/VxvFZGTkyMvvPCCJ8oFAABQ8mEnLCxMtm3bJsOGDZP4+HhxOBxmu05Dj42NNYFHjwEAAPAVN3xRwcjISFmzZo38/PPPcuTIERN4GjVqJNWqVSueEgIAAJT0FZSVhhu9kCAAAIB198YCAAAoLQg7AADAaoQdAABgNcIOAACwGmEHAABYjbADAACsRtgBAABWI+wAAACrEXYAAIDVCDsAAMBqhB0AAGA1wg4AALAaYQcAAFiNsAMAAKxG2AEAAFYj7AAAAKsRdgAAgNUIOwAAwGqEHQAAYDXCDgAAsBphBwAAWI2wAwAArEbYAQAAViPsAAAAqxF2AACA1QK8XQAAKG3qT1h9U88/NqOPx8oC4LfRsgMAAKxG2AEAAFYj7AAAAKt5NewkJCRIx44dpXLlylKrVi3p37+/pKamuh1z8eJFGT58uNSoUUMqVaokAwcOlIyMDLdjjh8/Ln369JGKFSua1xk3bpxcuXKlhM8GAAD4Iq+GnS1btpggs337dklKSpLs7GyJiYmRCxcuuI4ZM2aMrFy5UpYvX26OP3HihAwYMMC1PycnxwSdy5cvy7Zt22TJkiWyePFimTx5spfOCgAA+BKvzsZau3at27qGFG2ZSUlJkW7dusnZs2dl4cKFsnTpUunRo4c5ZtGiRdKsWTMTkLp06SLr1q2TgwcPyvr16yUsLEzatm0r06dPl/Hjx8vUqVMlKCjIS2cHAAB8gU+N2dFwo6pXr24eNfRoa090dLTrmKZNm0q9evUkOTnZrOtjq1atTNBxio2NlaysLDlw4EC+73Pp0iWzP+8CAADs5DNhJzc3V0aPHi133XWXtGzZ0mxLT083LTNVq1Z1O1aDje5zHpM36Dj3O/cVNFaoSpUqriUiIqKYzgoAAHibz4QdHbuzf/9+WbZsWbG/V3x8vGlFci5paWnF/p4AAKAMX0F5xIgRsmrVKtm6davUrVvXtT08PNwMPD5z5oxb647OxtJ9zmN27tzp9nrO2VrOY64WHBxsFgAAYD+vtuw4HA4TdFasWCEbN26UBg0auO1v3769BAYGyoYNG1zbdGq6TjWPiooy6/q4b98+yczMdB2jM7tCQ0OlefPmJXg2AADAFwV4u+tKZ1p98skn5lo7zjE2Oo6mQoUK5nHIkCEyduxYM2hZA8zIkSNNwNGZWEqnqmuoGTx4sMycOdO8xsSJE81r03oDAAC8Gnbeeust89i9e3e37Tq9/NFHHzVfz549W/z9/c3FBHUWlc60mj9/vuvYcuXKmS6wYcOGmRAUEhIicXFxMm3atBI+G3j7BovcXBEA4HNhR7uxfkv58uUlMTHRLAWJjIyUNWvWeLh0AADABj4zGwsAAKA4EHYAAIDVCDsAAMBqhB0AAGA1wg4AALAaYQcAAFiNsAMAAKxG2AEAAFYj7AAAAKsRdgAAgNUIOwAAwGqEHQAAYDXCDgAAsBphBwAAWI2wAwAArEbYAQAAViPsAAAAqxF2AACA1Qg7AADAaoQdAABgNcIOAACwGmEHAABYjbADAACsRtgBAABWI+wAAACrEXYAAIDVCDsAAMBqhB0AAGA1wg4AALAaYQcAAFiNsAMAAKxG2AEAAFYj7AAAAKsRdgAAgNUIOwAAwGqEHQAAYDXCDgAAsBphBwAAWI2wAwAArEbYAQAAViPsAAAAqxF2AACA1Qg7AADAaoQdAABgNcIOAACwGmEHAABYLcDbBQCAsqz+hNU39fxjM/p4rCyArWjZAQAAViPsAAAAqxF2AACA1Qg7AADAaoQdAABgNcIOAACwGmEHAABYzathZ+vWrdK3b1+pU6eO+Pn5yccff+y23+FwyOTJk6V27dpSoUIFiY6OlsOHD7sdc/r0aRk0aJCEhoZK1apVZciQIXL+/PkSPhMAAOCrvBp2Lly4IG3atJHExMR898+cOVPmzp0rCxYskB07dkhISIjExsbKxYsXXcdo0Dlw4IAkJSXJqlWrTIB68sknS/AsAACAL/PqFZR79epllvxoq86cOXNk4sSJ0q9fP7PtH//4h4SFhZkWoIceekgOHToka9eulV27dkmHDh3MMfPmzZPevXvL66+/blqM8nPp0iWzOGVlZRXL+QEAAO/z2TE7R48elfT0dNN15VSlShXp3LmzJCcnm3V91K4rZ9BRery/v79pCSpIQkKCeS3nEhERUcxnAwAAvMVn742lQUdpS05euu7cp4+1atVy2x8QECDVq1d3HZOf+Ph4GTt2rFvLDoHHO/f24b4+AIAyG3aKU3BwsFkAAID9fLYbKzw83DxmZGS4bdd15z59zMzMdNt/5coVM0PLeQwAACjbfDbsNGjQwASWDRs2uHU36VicqKgos66PZ86ckZSUFNcxGzdulNzcXDO2BwAAwKvdWHo9nCNHjrgNSt6zZ48Zc1OvXj0ZPXq0vPTSS9KoUSMTfiZNmmRmWPXv398c36xZM7n//vtl6NChZnp6dna2jBgxwszUKmgmFgAAKFu8Gna++uoruffee13rzkHDcXFxsnjxYnn++efNtXj0ujnagnP33Xebqebly5d3Pee9994zAadnz55mFtbAgQPNtXkAAAC8Hna6d+9urqdTEL2q8rRp08xSEG0FWrp0aTGVEAAAlHY+O2YHAADAEwg7AADAaoQdAABgNcIOAACwGmEHAABYjbADAACsRtgBAABWI+wAAACrEXYAAIDVCDsAAMBqXr1dBADAc+pPWH1Tzz82o4/HygL4Elp2AACA1Qg7AADAaoQdAABgNcIOAACwGmEHAABYjbADAACsRtgBAABWI+wAAACrEXYAAIDVCDsAAMBqhB0AAGA1wg4AALAaYQcAAFiNsAMAAKxG2AEAAFYj7AAAAKsRdgAAgNUIOwAAwGqEHQAAYLUAbxcAAOB76k9YXeTnHpvRx6NlAW4WLTsAAMBqtOyUUfzXBgAoK2jZAQAAViPsAAAAqxF2AACA1Qg7AADAaoQdAABgNcIOAACwGmEHAABYjbADAACsxkUFAQDFiouYwtto2QEAAFYj7AAAAKsRdgAAgNUIOwAAwGqEHQAAYDXCDgAAsBpTzwEApQbT2FEUtOwAAACr0bJTivAfDQAAN46WHQAAYDXCDgAAsJo13ViJiYny2muvSXp6urRp00bmzZsnnTp18naxAABlYGgAwwx8mxVh54MPPpCxY8fKggULpHPnzjJnzhyJjY2V1NRUqVWrllfLxg8AAIC/G95lRdiZNWuWDB06VB577DGzrqFn9erV8u6778qECRO8XTwAALyCf7gtCTuXL1+WlJQUiY+Pd23z9/eX6OhoSU5Ozvc5ly5dMovT2bNnzWNWVpbHy5d76ZciP/fq8vBa1BefCd/4GbqZ1ykLr8Xn1M76ajnl8yK/1v4XY6U4OMvocDiuf6CjlPvhhx/0DB3btm1z2z5u3DhHp06d8n3OlClTzHNYqAM+A3wG+AzwGeAzIKW+DtLS0q6bFUp9y05RaCuQjvFxys3NldOnT0uNGjXEz8/vN1NkRESEpKWlSWhoaAmUFtS9d/GZp+7LIj73paPetUXn3LlzUqdOneseV+rDzi233CLlypWTjIwMt+26Hh4enu9zgoODzZJX1apVb+h99ZtA2PEO6p56L2v4zFP3ZU3oDfyNrVKliv3X2QkKCpL27dvLhg0b3FpqdD0qKsqrZQMAAN5X6lt2lHZJxcXFSYcOHcy1dXTq+YULF1yzswAAQNllRdh58MEH5ccff5TJkyebiwq2bdtW1q5dK2FhYR5/L+3+mjJlyjXdYCh+1L13UO/eQ91T92VNcDH9jfXTUcoefUUAAAAfUurH7AAAAFwPYQcAAFiNsAMAAKxG2AEAAFYj7NyAxMREqV+/vpQvX97cXX3nzp3F952BMXXqVHNV67xL06ZNqZ1isHXrVunbt6+5EqnW88cff+y2X+cy6IzH2rVrS4UKFcz95w4fPsz3ogTq/tFHH73m5+D++++n7m9SQkKCdOzYUSpXriy1atWS/v37S2pqqtsxFy9elOHDh5sr7FeqVEkGDhx4zUVsUTx1371792s+908//XQR3o2wU2gffPCBuZ6PTonbvXu3tGnTRmJjYyUzM7NIFY/Ca9GihZw8edK1fPHFF1RfMdBrU+nnWkN9fmbOnClz586VBQsWyI4dOyQkJMT8DOgfAxRv3SsNN3l/Dt5//32q/SZt2bLFBJnt27dLUlKSZGdnS0xMjPl+OI0ZM0ZWrlwpy5cvN8efOHFCBgwYQN2XQN2roUOHun3u9fdQkXjyppw205uKDh8+3LWek5PjqFOnjiMhIcGr5bKd3rS1TZs23i5GmaO/GlasWOFaz83NdYSHhztee+0117YzZ844goODHe+//76XSlk26l7FxcU5+vXr57UylRWZmZmm/rds2eL6jAcGBjqWL1/uOubQoUPmmOTkZC+W1P66V/fcc49j1KhRDk+gG6sQLl++LCkpKabZ3snf39+sJycnFy1lotC0q0Sb92+77TYZNGiQHD9+nNorYUePHjUX7Mz7M6D3o9HuXH4GSsbmzZtNc3+TJk1k2LBhcurUqRJ657Lj7Nmz5rF69ermUX/va4tD3s+9dqPXq1ePz30x173Te++9Z+6B2bJlS3MT719++aXsXkG5uP3000+Sk5NzzRWZdf3bb7/1WrnKAv1junjxYvMLXpswX3zxRenatavs37/f9PWiZGjQUfn9DDj3ofhoF5Z2nTRo0EC+++47+etf/yq9evUyf3D1Rsi4eXpPxdGjR8tdd91l/rAq/Wzr/RevvlE0n/vir3v1pz/9SSIjI80/u3v37pXx48ebcT0fffTRDb8HYQc+TX+hO7Vu3dqEH/3wf/jhhzJkyBCvlg0oKQ899JDr61atWpmfhdtvv9209vTs2ZNvhAfo+BH9J4oxgb5T908++aTb514nR+jnXQO/fv5vBN1YhaBNaPrf09Uj8HU9PDz8hiocN0f/w2rcuLEcOXKEqixBzs85PwO+Qbt09fcSPweeMWLECFm1apVs2rRJ6tat6/a512EMZ86ccTue3/3FX/f50X92VVE+94SdQtBmzPbt28uGDRvcmt10PSoq6oYrHUV3/vx5k+o14aPkaPeJ/uLP+zOQlZVlZmXxM1Dyvv/+ezNmh5+Dm6PjwfWP7YoVK2Tjxo3mc56X/t4PDAx0+9xrN4qOG+RzX7x1n589e/aYx6J87unGKiSddh4XFycdOnSQTp06yZw5c8wUuccee+yGKx2F99xzz5nrj2jXlU751Kn/2sr28MMPU43FECTz/sekg5L1l4sOGNQBmdqn/tJLL0mjRo3ML6ZJkyaZvnS9PgaKr+510bFqen0XDZwa9p9//nlp2LChmfqPm+s+Wbp0qXzyySdmDKBz/JkOvtdrSemjdpfr73/9PoSGhsrIkSNN0OnSpQtVX4x1r59z3d+7d29zjSMds6OXAejWrZvpxr1hHpnTVUbMmzfPUa9ePUdQUJCZir59+3ZvF8l6Dz74oKN27dqmzm+99VazfuTIEW8Xy0qbNm0yUz+vXnTas3P6+aRJkxxhYWFmynnPnj0dqamp3i629XX/yy+/OGJiYhw1a9Y006AjIyMdQ4cOdaSnp3u72KVefnWuy6JFi1zH/Prrr45nnnnGUa1aNUfFihUdv//97x0nT570arnLQt0fP37c0a1bN0f16tXN75uGDRs6xo0b5zh79myR3s/v/94UAADASozZAQAAViPsAAAAqxF2AACA1Qg7AADAaoQdAABgNcIOAACwGmEHAABYjbADAACsRtgB4FXHjh0TPz8/131vfMG3335rbgdQvnx5adu2baGf1717d3NbDaf69eubW8uU5roAbEDYAcq4Rx991PyBnTFjhtv2jz/+2Gwvi/QebCEhIeamj3lvAnmjdu3aJU8++WShj4+IiJCTJ09Ky5YtzfrmzZvN9+Dqu24DuDGEHQCmBePVV1+Vn3/+2ZrauHz5cpGfqzchvPvuu80NaPUmhEVVs2ZNqVixYqGP15vc6s0+AwK4RzPgSYQdABIdHW3+yCYkJBRYG1OnTr2mS0e7aLSrJm8rkd4F/ZVXXpGwsDCpWrWqTJs2Ta5cuSLjxo0zd46uW7euLFq0KN+uozvvvNMEL23Z2LJli9v+/fv3S69evaRSpUrmtQcPHiw//fSTWxfSiBEjTDfSLbfcUuAdwXNzc02ZtBzBwcHmnNauXevary0pKSkp5hj9Ws87PxcuXJBHHnnElKd27dryxhtvXHPM1d1Yeo4aovQcmzdvLuvXrzfvoa1oV3dj6df33nuv2V6tWjWzXetX/etf/5JWrVqZu0NrGNPvn5YHQP4IOwBMi4IGlHnz5sn3339/UzWyceNGOXHihGzdulVmzZpluoQeeOAB8wd7x44d8vTTT8tTTz11zftoGPrLX/4iX3/9tURFRUnfvn3l1KlTZp924/To0UPatWsnX331lQknGRkZ8sc//tHtNZYsWSJBQUHy5ZdfyoIFC/It35tvvmmCyeuvvy579+41oeh3v/udHD582OzXbqQWLVqYsujXzz33XL6vo+XVQPbJJ5/IunXrTJfT7t27C6yXnJwcEwS1pUfr4e2335YXXnjhul1a//73v83X2p2mZdGy6+PDDz8sjz/+uBw6dMi874ABA4R7OgPX4dmbtgMobeLi4hz9+vUzX3fp0sXx+OOPm69XrFjhyPsrYsqUKY42bdq4PXf27NmOyMhIt9fS9ZycHNe2Jk2aOLp27epav3LliiMkJMTx/vvvm/WjR4+a95kxY4brmOzsbEfdunUdr776qlmfPn26IyYmxu2909LSzPNSU1PN+j333ONo167db55vnTp1HC+//LLbto4dOzqeeeYZ17qep55vQc6dO+cICgpyfPjhh65tp06dclSoUMExatQo1zatC60j9dlnnzkCAgIcJ0+edO1PSkoy56B1nbcuvv76a7O+adMms/7zzz+7npOSkmK2HTt27DfPFcD/omUHgIuO29HWEW0xKCptFfH3//9fLdrlpF0ueVuRtOslMzPT7XnamuOkY1Y6dOjgKsc333wjmzZtMl1GzqVp06au8TVO7du3v27ZsrKyTKvTXXfd5bZd12/knPU9dUxQ586dXdu0i65JkyYFPkdbZ7S1RrsLnTp16iQ3qk2bNtKzZ09Tp3/4wx/knXfesWqsFVAcCDsAXLp162a6deLj46/9ZeHvf01XSXZ29jXHBQYGuq3rWJP8tunYmcI6f/686dbSsSx5F+160jI76Qwq22lYTEpKks8++8yM+9GuRw1ZR48e9XbRAJ9F2AHgRqegr1y5UpKTk6+ZWZSenu4WeDx5PZjt27e7vtYBzTpIuFmzZmb9jjvukAMHDpgBvw0bNnRbbiTghIaGSp06dcyYnrx0XYNDYd1+++0mwOnYGydtXfnvf/9b4HM0kKSlpZmxRnmnpl+Pjj9yjve5Oixqa9SLL75oxjjpcStWrCh0+YGyhrADwI12jwwaNEjmzp3rtl1nO/34448yc+ZM042TmJhoWhc8RV9P/2DrjKXhw4eb8KCDcJWunz592gzM1YCg7//555/LY489dk0Q+C06sFi76z744APTtTRhwgQT2kaNGlXo19ButCFDhpjX0gHZOlNMZ0rl7b672n333WdCUlxcnBkYrQFr4sSJZl9B1zPSqe+6b9WqVabutYVLA5YOJteB2sePH5ePPvrI7HMGQwDXIuwAuIZOu766m0n/mM6fP9+EEh03snPnzgJnKhW1RUkXfe0vvvhCPv30UzOFXDlbYzTYxMTEmECmU8x1avv1AkZ+nn32WRk7dqyZbaWvozO79L0aNWp0Q6/z2muvSdeuXU33mk791inl1xszpN1POsVcA0vHjh3liSeecM3G0qno+bn11ltN640GMh37pFPrtXVKZ7r17t1bGjdubAKTzi7TafkA8ueno5QL2AcAKEYa4DQkHTlyxLT6ACgehB0AKCHaTaddYNqKpAFHu870+kPakgWg+HBNcgAoIefOnZPx48ebsTbaRafdX/ldeRmAZ9GyAwAArMYAZQAAYDXCDgAAsBphBwAAWI2wAwAArEbYAQAAViPsAAAAqxF2AACA1Qg7AABAbPY/SY5kJ5KwxVUAAAAASUVORK5CYII=", "text/plain": [ "
" ] @@ -204,10 +202,14 @@ "import matplotlib.pyplot as plt\n", "from collections import Counter\n", "\n", - "digits = Counter(len(str(p)) for p in P)\n", + "def digit_lengths(primes) -> Counter:\n", + " \"\"\"Plot a bar chart and return a Counter of the number of digits in these primes.\"\"\"\n", + " digits = Counter(len(str(p)) for p in primes)\n", + " plt.bar(list(digits), list(digits.values()))\n", + " plt.xlabel('Number of digits'); plt.ylabel('Count')\n", + " return digits\n", "\n", - "plt.bar(list(digits), list(digits.values()))\n", - "dict(digits)" + "dict(digit_lengths(P))" ] }, { @@ -229,11 +231,9 @@ "source": [ "def right_truncatable_primes(starting_primes=[2, 3, 5, 7]) -> list[int]:\n", " \"\"\"All right-truncatable primes, in ascending order.\"\"\"\n", - " if not starting_primes:\n", - " return []\n", - " else:\n", - " candidates = [10 * p + d for p in starting_primes for d in (1, 3, 7, 9)]\n", - " return starting_primes + right_truncatable_primes(list(filter(isprime, candidates)))" + " candidates = [10 * p + d for p in starting_primes for d in (1, 3, 7, 9)]\n", + " new_primes = list(filter(isprime, candidates))\n", + " return starting_primes + (right_truncatable_primes(new_primes) if new_primes else [])" ] }, { @@ -300,7 +300,7 @@ "id": "d4abc561-5a2d-4e93-a18e-b78b104f7b7c", "metadata": {}, "source": [ - "Here is the count of digit sizes:" + "Here is the count of digit lengths:" ] }, { @@ -312,7 +312,7 @@ { "data": { "text/plain": [ - "{1: 4, 2: 9, 3: 14, 4: 16, 5: 15, 6: 12, 7: 8, 8: 5}" + "Counter({4: 16, 5: 15, 3: 14, 6: 12, 2: 9, 7: 8, 8: 5, 1: 4})" ] }, "execution_count": 9, @@ -321,7 +321,7 @@ }, { "data": { - "image/png": "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DTfckI96XHjhhXHBBRfEvHnzdrh+TU1NNDQ0NC/19fXl3iUAoMjx0aNHjxgwYECL6w477LDYuHHjDtevrq6Ozp07t1gAgOIqe3xkr3RZvXp1i+vWrFkTffr0KfemAIAKVPb4uOKKK2L58uX5YZd169bFggUL4tZbb42LL7643JsCACpQ2eNjyJAhsWjRoli4cGEMHDgwrr322pg9e3aMHz++3JsCACpQ2c/zkTn99NPzBQDg47y3CwCQlPgAAJISHwBAUuIDAEhKfAAASYkPACAp8QEAJCU+AICkxAcAkJT4AACSEh8AQFLiAwBISnwAAEmJDwAgKfEBACTVLu3mAKA4+k57OCrRazNH7dLtG/kAAJISHwBAUuIDAEhKfAAASYkPACAp8QEAJCU+AICkxAcAkJT4AACSEh8AQFLiAwBISnwAAEmJDwAgKfEBACQlPgCApMQHAJCU+AAAihUfM2fOjKqqqrj88stbe1MAQFuPj+eeey5uueWWOOKII1pzMwBABWm1+NiyZUuMHz8+brvttth7771bazMAQIVptfi4+OKLY9SoUTF8+PD/uF5TU1M0Nja2WACA4mrXGt/07rvvjpUrV+aHXT5LbW1tzJgxI1LpO+3hqESvzRy1q3cBAL6YIx/19fVx2WWXxV133RXt27f/zPVramqioaGhecm+HgAorrKPfKxYsSI2b94cRx99dPN1H374YSxbtixuvvnm/DDL7rvv3vy56urqfAEA2oayx8epp54aL730UovrJk6cGP37948rr7yyRXgAAG1P2eOjU6dOMXDgwBbXdezYMbp16/aJ6wGAtscZTgGAyn+1y8ctXbo0xWYAgApg5AMASEp8AABJiQ8AICnxAQAkJT4AgKTEBwCQlPgAAJISHwBAUuIDAEhKfAAASYkPACAp8QEAJCU+AICkxAcAkJT4AACSEh8AQFLiAwBISnwAAEmJDwAgKfEBACQlPgCApMQHAJCU+AAAkhIfAEBS4gMASEp8AABJiQ8AICnxAQAkJT4AgKTEBwCQlPgAAJISHwBAUuIDAKjs+KitrY0hQ4ZEp06donv37jF27NhYvXp1uTcDAFSossfHk08+GRdffHEsX748Hnvssfjggw/itNNOi61bt5Z7UwBABWpX7m+4ZMmSFpfnz5+fj4CsWLEiTj755HJvDgBo6/HxcQ0NDfnHrl27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dsoll1wSDz30UP4qn2yCZtFkzxa/+tWv5v+fvTtz9izypptuyidlFkU2T2fz5s1x9NFHN1+XPcPK7tObb745mpqa8mddRbPXXnvFIYccEuvWrYsi6dGjxydG5w477LC49957o4g2bNiQTyK+7777omimTp2aj36MGzcuv5y9aim7vdmrDYs2iiU++FyygZ1LL700PwyxdOnSQk5o+7RDTNkf4yI59dRT88NLH5XNqM+Geq+88spChsf2CbavvPJKnH/++VEk2eHPj7/sPZsz0KdPnyiibGJtNrdl+6TMInn33Xdjt91aTsXM/j1mv4eKRnyU4RfaR59JrV+/PlatWpVPxOzdu3cUaXLiggUL4v7778+Pl2fvVpzJXgKWvR69CGpqavKJXdn99s477+S3NwutRx99NIoku/8+Plcne7l0do6IIs3h+eEPf5i/gin7I/zGG2/k7xCa/SI/99xzo0iuuOKKfKLiDTfcEGeffXb+yohbb701X4om+yOcxUc2ClDEl02PHj06n+OR/Q7KXmGXvcz/xhtvzCfWFs6uPu5T6Z544ol8rsfHlwkTJpSKZEe3MVtuv/32UlFMmjQpn8uy5557lvbdd9/SqaeeWvrDH/5QaguKOOfjnHPOKfXo0SO/P7/yla/kl9etW1cqogcffLA0cODAUnV1dal///6lW2+9tVREjz76aP57Z/Xq1aUiamxszP8d9u7du9S+ffvSgQceWPrJT36Sz0UrmqrsP7s6gACAtsN5PgCApMQHAJCU+AAAkhIfAEBS4gMASEp8AABJiQ8AICnxAQAkJT4AgKTEBwCQlPgAAJISHwBApPT/ABTjgt70nMKKAAAAAElFTkSuQmCC", + "image/png": "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s2ZSv359efHFF+W3336TqVOn6pndW7RooWciLqtrR83GrIKVapn4/PPPPbbv379fzzB+3XXX6fseNWqU/Pe///Xo4hk3bpzu5mncuLEMGDCg3JmQVZ1UPXx9ffUxrV+/3r1dtYSkp6fr26jf1XGXpaCgQB566CFdn8DAQHnttdcuus2F3UzqGFVIUsfYvn172bRpk/4bqhXswm4m9XtkZKRe36BBA71ePb7KRx99JJ06ddIzyKuwpZ4/VR8A5SPMAA6nWgRUAHnrrbfkP//5z++6ry1btsixY8ckNTVV5s6dq7tsBg8erD+Qv/zyS3nyySfliSeeuOjvqLDzzDPPyJ49e+S2226T6Oho+fnnn/U21c1y5513SpcuXSQtLU2Hj5MnT8p9993ncR9Lly4VHx8f+de//iXJycll1u+NN97QwePVV1+Vffv26dAzZMgQOXjwoN6uunk6dOig66J+f/bZZ8u8H1VfFbg++eQT+eyzz3SX0O7du8t9XIqKinTQUy016nFYuHChPPfcc5fscvr444/176q7S9VF1V39fOCBB2TMmDHy3Xff6b87fPhwYT5g4DKsnrYbwNUTExPjGjp0qP791ltvdY0ZM0b/npKS4ir933/mzJmu8PBwj31ff/11V8uWLT3uSy0XFRW514WFhbl69erlXv7tt99cdevWdX3wwQd6OSsrS/+dhIQE923Onz/vatGihSsxMVEvz54929W/f3+Pv52dna33y8jI0Mt9+vRxdenS5bLHGxQU5HrppZc81kVERLiefvpp97I6TnW85Tlz5ozLx8fHtWLFCve6n3/+2VWnTh3XxIkT3evUY6EeI2XdunUub29v1/Hjx93bN27cqI9BPdalH4s9e/bo5a1bt+rlU6dOufdJT0/X6w4dOnTZYwXwf2iZAWoINW5GtW6ob/yVpVo1atX6v7cN1SWkukRKtwKprpGcnByP/VRrTAk1ZqRbt27uenz99deydetW3aVTUtq2bese31LilltuuWTd8vLydKtRz549Pdar5Ss5ZvU31ZicHj16uNepLrSwsLBy91GtK6q1RXXnlejevbtcqfDwcOnXr59+TO+9915ZtGiRo8Y6AVcLYQaoIXr37q27XWJjYy/apgLKhV0Z58+fv+h2tWvX9lhWYz3KWqfGrlRUfn6+7nZSY0lKF9U1pOpcQp2B5HQqDG7cuFHWrVunx92orkEVorKysqyuGmBrhBmgBlGnaH/66aeyY8eOi87MOXHihEegqcrroezcudP9uxowrAbhtmvXTi937dpVvv32Wz2g9qabbvIoVxJg/P39JSgoSI+pKU0tq2BQUTfeeKMOaGrsSwnVOnLgwIFy91GBIzs7W4/1KX3q9qWo8T8l420uDIOqNSkuLk6PMVK3S0lJqXD9gZqIMAPUIKr7YuTIkfLmm296rFdnC/3000/yyiuv6G6WpKQk3TpQVdT9qQ9kdcbP2LFjdThQg1wVtfzLL7/oga8qAKi/v2HDBhk9evRFH/SXowbuqu60Dz/8UHf9TJ8+XYeyiRMnVvg+VDfXI488ou9LDXhWZ1qpM41Kd69d6K677tIhKCYmRg88VgHq+eef19vKu56POjVcbVuzZo1+7FULlQpQarC2Ggh95MgRWblypd5WEvwAlI0wA9Qw6rTkC7uB1Ifl22+/rUOHGrexa9eucs/0qWyLkCrqvrdv3y6rV6/Wp1grJa0pKrj0799fBy51CrY69ftSAaIsEyZMkClTpuizldT9qDOj1N9q3br1Fd3PX/7yF+nVq5fu/lKnRqtTri81Zkd1D6lTsFUgiYiIkEcffdR9NpM6Vbss119/vW59UYFLjT1Sp56r1iV1ptjdd98tbdq00YFInZ2lTlsHUD4vNQr4EtsBAJWgApoKQZmZmbrVBsDVQ5gBgCqgutFUF5VqBVIBRnVtqevvqJYoAFcX19UGgCpw5swZmTZtmh7rorrQVPdUWVcOBlD1aJkBAABGYwAwAAAwGmEGAAAYjTADAACMRpgBAABGI8wAAACjEWYAAIDRCDMAAMBohBkAACAm+3/Xo/rsP3eszwAAAABJRU5ErkJggg==", "text/plain": [ "
" ] @@ -331,15 +331,12 @@ } ], "source": [ - "digits = dict(Counter(len(str(p)) for p in Q))\n", - "\n", - "plt.bar(list(digits), list(digits.values()));\n", - "digits" + "digit_lengths(Q)" ] }, { "cell_type": "markdown", - "id": "6b307b24-a93e-4353-9bee-fba739072bd1", + "id": "f2323985-2518-41d1-8a3b-6e21e40d27be", "metadata": {}, "source": [ "# Summary of Truncatable Primes\n", @@ -357,65 +354,68 @@ "\n", "# Note on Primality Checking\n", "\n", - "A prime number can be defined as *\"an integer greater than 1 that cannot be evenly divided by any whole number other than 1 and itself.\"* Here's a naive function to test whether a number is prime:" + "I was very impressed by the speed of `sympy.isprime`, so I wanted to look more deeply into the topic of primality checking. I'm going to write some prime-checking functions, so the first thing I will do is define a function to test that a prime checker correctly returns True when passed a prime and False when passed a composite number, for some given test cases." ] }, { "cell_type": "code", "execution_count": 10, - "id": "1d460931-3d70-485d-807f-8fb360ef4ef2", + "id": "4f377075-e352-46f9-a716-f1de673a7086", "metadata": {}, "outputs": [], "source": [ - "def isprime_naive(n: int) -> bool:\n", - " \"\"\"Simple primality checker.\"\"\"\n", - " divisors = range(2, n)\n", - " return n > 1 and not any(n % d == 0 for d in divisors)" + "from typing import Callable, Iterable\n", + "\n", + "def test_prime_checker(checker: Callable, \n", + " primes=(2, 3, 5, 7, 11, 37, 73, 101, 11939, 65537, 117223, 7629137),\n", + " composites=(0, 1, 4, 6, 8, 9, 10, 256, 11939*11939, 11939*117223)) -> Callable:\n", + " \"\"\"Test that a primality checking function correctly handles some primes and composites.\"\"\"\n", + " for n in primes:\n", + " assert checker(n) == True, f'{n} should be prime'\n", + " for n in composites:\n", + " assert checker(n) == False, f'{n} should be composite'\n", + " return checker # This allows us to use @test_prime_checker as a @decorator" ] }, { "cell_type": "markdown", - "id": "f30802c2-2e39-4cdd-8e33-fc74ad50977f", + "id": "c08ed813-2942-42da-aed3-d5044b0b403a", "metadata": {}, "source": [ - "And here's a function to test it. By default we test some easy cases, along with one 8-digit prime and a couple of 8-digit composites." + "Here's how we would use this to check the `isprime` function:" ] }, { "cell_type": "code", "execution_count": 11, - "id": "4f377075-e352-46f9-a716-f1de673a7086", + "id": "008cd6fd-86eb-4b45-bea9-c030273c4eb1", "metadata": {}, "outputs": [], "source": [ - "tests = {True: [2, 3, 5, 7, 37, 73, 101, 11939, 117223, 73939133],\n", - " False: [0, 1, 4, 6, 8, 9, 10, 256, 123456, 7333*7393, 7393**2]}\n", - "\n", - "def prime_test(predicate, tests=tests) -> None:\n", - " \"\"\"Test that a primality checking predicate gets the right answers on all the test cases.\n", - " `tests` is a dict of {True: [primes,...], False: [composites,...]}.\"\"\"\n", - " for result in tests:\n", - " for n in tests[result]:\n", - " assert predicate(n) == result, f'isprime({n}) should be {result}'" + "assert test_prime_checker(isprime)" + ] + }, + { + "cell_type": "markdown", + "id": "6b307b24-a93e-4353-9bee-fba739072bd1", + "metadata": {}, + "source": [ + "But I can also use `@test_prime_checker` as a decorator to test the function right where it is defined; I'll do that for `isprime_simple`, which follows the definition of a prime number almost verbatim:" ] }, { "cell_type": "code", "execution_count": 12, - "id": "328285d6-9d5c-44ef-8f84-7dbf2b6fe6bc", + "id": "1d460931-3d70-485d-807f-8fb360ef4ef2", "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "CPU times: user 2.1 s, sys: 18.7 ms, total: 2.12 s\n", - "Wall time: 2.12 s\n" - ] - } - ], + "outputs": [], "source": [ - "%time prime_test(isprime_naive)" + "@test_prime_checker\n", + "def isprime_simple(n: int) -> bool:\n", + " \"\"\"Simple primality checker. A prime number is defined as an integer greater than 1 \n", + " that cannot be evenly divided by any whole number other than 1 and itself.\"\"\"\n", + " divisors = range(2, n)\n", + " return n > 1 and not any(n % d == 0 for d in divisors)" ] }, { @@ -423,9 +423,9 @@ "id": "1834f8f0-3712-4302-ac56-79972f85d0db", "metadata": {}, "source": [ - "We see that `isprime_naive` passes the tests, but it takes 2 seconds, and we're only up to 8-digit numbers. That's too slow!\n", + "To test a *d*-digit prime we have to iterate through nearly 10d divisors, which will be noticeably slow for anything larger than about 7-digit numbers.\n", "\n", - "We can make it faster with two ideas. First, we don't have to check divisors all the way up to *n*. If *p* is composite, then *p* is the product of two numbers, and one of them must be less than or equal to the square root of *n*, so that's as far as we need to go. Second, once we check to see if *n* is divisible by 2, we don't have to check whether it is divisible by any other even number. " + "We can speed things up a bit with two ideas, one small and one big. The small idea is to cut the run time in half by only checking the odd divisors. Once we determine that 2 is a prime and all other even numbers are composite, we only need to check odd divisors. The big idea is that we only need to check divisors up to √*n*, not up to *n*. If *n* is composite, then *n* is the product of two numbers, and one of them must be less than or equal to √*n*, so we can stop there." ] }, { @@ -437,126 +437,64 @@ "source": [ "from math import sqrt\n", "\n", + "@test_prime_checker\n", "def isprime_faster(n: int) -> bool:\n", - " \"\"\"More sophisticated primality checker: go to square root, checking odd numbers only.\"\"\"\n", - " if n <= 10:\n", + " \"\"\"More sophisticated primality checker: go to square root, checking odd divisors only.\"\"\"\n", + " if n <= 10: # Handle small numbers up to 10\n", " return n in (2, 3, 5, 7)\n", - " elif n % 2 == 0:\n", + " elif n % 2 == 0: # Even numbers other than 2 are composite\n", " return False\n", - " else:\n", - " divisors = range(3, int(sqrt(n)) + 1, 2) # Check odd divisors up to sqrt(n)\n", + " else: # Check odd divisors up to sqrt(n)\n", + " divisors = range(11, int(sqrt(n)) + 1, 2) \n", " return not any(n % d == 0 for d in divisors)" ] }, - { - "cell_type": "code", - "execution_count": 14, - "id": "3bad2a74-49a2-43ce-aaf5-96112ae3c8d9", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "CPU times: user 405 μs, sys: 1 μs, total: 406 μs\n", - "Wall time: 407 μs\n" - ] - } - ], - "source": [ - "%time prime_test(isprime_faster)" - ] - }, - { - "cell_type": "markdown", - "id": "462fbfea-19ca-487e-b104-96eea821c001", - "metadata": {}, - "source": [ - "We see that this function is roughly a 5,000 times faster than the naive function on our specific test cases. But it would be wrong to conclude that it is always 5,000 times faster; more importantly it is *O*(√*n*) whereas the naive version is *O*(*n*). \n", - "\n", - "Let's try some tougher test cases, a pair of 16-digit numbers:" - ] - }, - { - "cell_type": "code", - "execution_count": 15, - "id": "b8664d7a-2033-47a1-b94a-d1e1ad77e31f", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "CPU times: user 2.51 s, sys: 21.2 ms, total: 2.53 s\n", - "Wall time: 2.53 s\n" - ] - } - ], - "source": [ - "test16 = {True: [8637267627626947], False: [73939133**2]}\n", - "\n", - "%time prime_test(isprime_faster, test16)" - ] - }, - { - "cell_type": "markdown", - "id": "251e2b35-91b1-40cf-a57e-a9b86947feef", - "metadata": {}, - "source": [ - "As expected, `isprime_faster` can handle 16-digit numbers in about the same time `isprime_naive` handles 8-digit numbers. \n", - "\n", - "What about `sympy.isprime`?" - ] - }, - { - "cell_type": "code", - "execution_count": 16, - "id": "e71701b0-6ad3-4a5d-b871-c433712ee99c", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "CPU times: user 56 μs, sys: 0 ns, total: 56 μs\n", - "Wall time: 57.2 μs\n" - ] - } - ], - "source": [ - "%time prime_test(isprime, test16)" - ] - }, { "cell_type": "markdown", "id": "05b8cbf7-ea10-4047-bcdb-a5ac7981384b", "metadata": {}, "source": [ - "That's about 40,000 times faster than `isprime_faster`! What makes `sympy.isprime` so fast? The answer is: [Number theory](https://en.wikipedia.org/wiki/Number_theory).\n", + "That's a noticeable improvement, but handling 24-digit numbers is still completely infeasible. We need a big breakthrough. \n", "\n", - "The big breakthrough came in 1640, when Pierre de Fermat [showed](https://en.wikipedia.org/wiki/Fermat_primality_test) that if *n* is prime and *a* is not divisible by *n*, then *a*(*n* - 1) ≡ 1 (mod *n*). \n", + "Fortunately, [Pierre de Fermat](https://en.wikipedia.org/wiki/Pierre_de_Fermat) provided that breakthrough in 1640, [showing](https://en.wikipedia.org/wiki/Fermat_primality_test) that if *n* is prime and *a* is not divisible by *n*, then *a*(*n* - 1) ≡ 1 (mod *n*). \n", "\n", - "That means we can check if *n* is prime by choosing a random *a* and testing if *a*(*n* - 1) ≡ 1 (mod *n*). If the test is false then *n* is definitely composite. If the test is true, then we're not sure: *n* might be prime, might be composite. But if we repeat the test multiple times with different values of *a*, and they are all true, then that is stronger evidence that *n* is prime. This is called a [Monte Carlo algorithm](https://en.wikipedia.org/wiki/Monte_Carlo_algorithm); an algorithm that uses randomization, and can sometimes be wrong.\n", + "That means we can check if *n* is prime by choosing a random *a* and testing if *a*(*n* - 1) ≡ 1 (mod *n*). If the test is false then *n* is definitely composite. If the test is true, then we're not sure: *n* might be prime, might be composite. But if we choose multiple values of *a* and they all give a remainder of 1 (mod *n*), then that is stronger evidence that *n* is probably prime. This is called a [Monte Carlo algorithm](https://en.wikipedia.org/wiki/Monte_Carlo_algorithm); an algorithm that uses randomization, and can sometimes be wrong.\n", + "Some examples:\n", "\n", - "Here is an implementation. (The optional third argument to the built-in `pow` function is the modulus.) " + "\n", + "|*n*|*a*|*a*(*n* - 1) (mod *n*)|Conclusion|\n", + "|--:|--:|:--:|:--|\n", + "|12|5|5|*12 is definitely composite*|\n", + "|221|18|1|*221 could be prime or composite*|\n", + "|221|2|16|*221 is definitely composite*|\n", + "|5|2|1|*5 could be prime or composite*|\n", + "|5|3|1|*5 could be prime or composite*|\n", + "|5|4|1|*5 could be prime or composite, but we have a lot of evidence that it is prime*|\n", + "\n", + "\n", + "Here is an implementation:" ] }, { "cell_type": "code", - "execution_count": 17, + "execution_count": 14, "id": "476282dd-a48a-4eb5-8fed-8495d4878ec2", "metadata": {}, "outputs": [], "source": [ "import random\n", "\n", + "def sample(lo: int, hi: int, k: int) -> Iterable[int]:\n", + " \"\"\"Randomly sample k integers from range(lo, hi), one by one.\"\"\"\n", + " return (random.randrange(lo, hi) for _ in range(k))\n", + " \n", + "@test_prime_checker\n", "def isprime_fermat(n: int, k=20) -> bool:\n", " \"\"\"n is probably a prime if this returns True; definitely composite if it returns False.\"\"\"\n", " if n <= 10:\n", " return n in (2, 3, 5, 7)\n", " else:\n", - " a_values = (random.randint(2, n - 1) for _ in range(k))\n", - " return any(pow(a, n - 1, n) == 1 for a in a_values)" + " return all(pow(a, n - 1, n) == 1 for a in sample(2, n, k))" ] }, { @@ -564,50 +502,180 @@ "id": "1ec7bba6-ea89-4255-a73c-bc25a32da883", "metadata": {}, "source": [ - "Let's test it out:" - ] - }, - { - "cell_type": "code", - "execution_count": 18, - "id": "ef715472-cacf-4af0-a8e9-c54039d9013c", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "CPU times: user 99 μs, sys: 2 μs, total: 101 μs\n", - "Wall time: 102 μs\n" - ] - } - ], - "source": [ - "prime_test(isprime_fermat)\n", - "\n", - "%time prime_test(isprime_fermat, test16)" + "Note that the built-in [modular exponentiation](https://en.wikipedia.org/wiki/Modular_exponentiation) function `pow(b, e, m)` computes *b**e* (mod *m*), and does it in an efficient way that doesn't have to multiply *b* by itself *e* times, and doesn't have to deal with any numbers larger than *m*." ] }, { "cell_type": "markdown", - "id": "b0b64505-706b-4b09-8f41-c8bfcda9b0c9", + "id": "15ef6884-253d-4a3a-b58f-397ac73f552d", "metadata": {}, "source": [ - "That's pretty good! Only a few lines of code, it passes the tests, and it is almost as fast as the highly-tuned (and highly complex) `sympy.isprime`. \n", + "**The problem** is that there are some composite numbers *n* for which *a*(*n* - 1) ≡ 1 (mod *n*) for some values of *a*, and thus `isprime_fermat` can lie: it can incorrectly report a **false prime** for a composite number *n*. \n", "\n", - "The problem is that `isprime_fermat` can lie:" + "How common are these false primes? Here's a function to estimate the percentage of false primes in the range `lo` to `hi` when `isprime_fermat` is allowed `k` choices of the `a` parameter:" ] }, { "cell_type": "code", - "execution_count": 19, - "id": "a6834bd8-b904-47ed-84d1-dae2c7227cd2", + "execution_count": 15, + "id": "45a11a93-9ef3-48d1-80fa-e0113041346e", + "metadata": {}, + "outputs": [], + "source": [ + "def false_prime_percent(lo: int, hi: int, k: int, repeat=100_000) -> float:\n", + " \"\"\"The estimated probability of a false prime from isprime_fermat(n, k) for n in range(lo, hi).\"\"\"\n", + " composites = (n for n in sample(lo, hi, repeat) if not isprime(n))\n", + " counts = Counter(isprime_fermat(n, k) for n in composites) \n", + " return 100 * counts[True] / (counts[True] + counts[False])" + ] + }, + { + "cell_type": "markdown", + "id": "778c3a9b-dcc7-4ad2-9092-d66aecd1d93c", + "metadata": {}, + "source": [ + "We'll choose ranges that represent digit-lengths, and for now use 1 for the value of `k`:" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "id": "9eba96df-c298-4d71-b68a-3bf36bf15095", "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "True" + "{3: 1.4553237025147137,\n", + " 4: 0.5076430372271561,\n", + " 5: 0.1345167870334638,\n", + " 6: 0.04226359478965734,\n", + " 7: 0.00642047704144418,\n", + " 8: 0.003178908998431738,\n", + " 9: 0.0,\n", + " 10: 0.0,\n", + " 11: 0.0,\n", + " 12: 0.0}" + ] + }, + "execution_count": 16, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "{d: false_prime_percent(10**(d-1), 10**d, k=1) for d in range(3, 13)}" + ] + }, + { + "cell_type": "markdown", + "id": "f3fe25d6-5f0a-478b-90d0-6c89e092e92e", + "metadata": {}, + "source": [ + "We see that 3-digit composites are falsely called prime about 1.5% of the time, but onnce we get to 10-digit composites, false primes are very rare indeed. Let's see how we reduce false primes by allowing up to 30 choices of `a`:" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "id": "8880c588-32f5-46e8-b59c-f9b49d492d3b", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{3: 0.0,\n", + " 4: 0.0,\n", + " 5: 0.0,\n", + " 6: 0.0,\n", + " 7: 0.0010682505261133842,\n", + " 8: 0.0,\n", + " 9: 0.0,\n", + " 10: 0.0,\n", + " 11: 0.0,\n", + " 12: 0.0}" + ] + }, + "execution_count": 17, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "{d: false_prime_percent(10**(d-1), 10**d, k=30) for d in range(3, 13)}" + ] + }, + { + "cell_type": "markdown", + "id": "61ee44c3-f963-4fb1-ac20-4a27adc90f83", + "metadata": {}, + "source": [ + "In some runs this produces no false primes; in some runs a few get through. \n", + "\n", + "There are a few numbers, called [**Carmichael numbers**](https://en.wikipedia.org/wiki/Carmichael_number), that have a particularly high false prime percentage. We can test some of them:" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "id": "7871aaa7-af1c-462b-85bb-d46818ccabea", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{561: 58.6,\n", + " 1105: 68.8,\n", + " 1729: 74.4,\n", + " 2465: 72.7,\n", + " 2821: 77.9,\n", + " 6601: 81.2,\n", + " 8911: 80.6,\n", + " 41041: 71.3,\n", + " 101101: 71.3,\n", + " 825265: 61.4,\n", + " 321197185: 66.5}" + ] + }, + "execution_count": 18, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "carmichael_numbers = (561, 1105, 1729, 2465, 2821, 6601, 8911, 41041, 101101, 825265, 321197185)\n", + "\n", + "{n: false_prime_percent(n, n + 1, k=1, repeat=1000) for n in carmichael_numbers}" + ] + }, + { + "cell_type": "markdown", + "id": "4ecd2289-66d5-4b0f-ac00-5db0ad92dde9", + "metadata": {}, + "source": [ + "That seems seriously bad; they all are above 50% error rate. But if we set `k=100`, we eliminate most (and on some runs all) of the errors:" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "id": "de492047-77b6-46a3-8a77-46308f219efd", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{561: 0.0,\n", + " 1105: 0.0,\n", + " 1729: 0.0,\n", + " 2465: 0.0,\n", + " 2821: 0.0,\n", + " 6601: 0.0,\n", + " 8911: 0.0,\n", + " 41041: 0.0,\n", + " 101101: 0.0,\n", + " 825265: 0.0,\n", + " 321197185: 0.0}" ] }, "execution_count": 19, @@ -616,52 +684,148 @@ } ], "source": [ - "assert 561 == 3 * 11 * 17\n", - "\n", - "isprime_fermat(561)" + "{n: false_prime_percent(n, n + 1, k=100, repeat=10_000) for n in carmichael_numbers}" ] }, { "cell_type": "markdown", - "id": "53980370-73e9-49c4-8d14-3d1e38e21e33", + "id": "bfd71dc7-7f6d-4c98-9886-5c242d9b297a", "metadata": {}, "source": [ - "We see that 561 is composite, but `isprime_fermat` claims it is a prime. We can increase the number of samples; that doesn't help:" + "So our Fermat test is mostly reliable, but it will on rare occasion let a false prime slip through.\n", + "\n", + "Fortunately there are variations on Fermat's idea that always give the right answer. `sympy.isprime` ([source code here](https://github.com/sympy/sympy/blob/master/sympy/ntheory/primetest.py)) uses the [Miller-Rabin test](https://en.wikipedia.org/wiki/Miller%E2%80%93Rabin_primality_test) (sometimes called Rabin-Miller, but I give Gary Miller precedence because he is my former colleague). The algorithm is guaranteed to give the right answer, but it does start to get slow for very large numbers. `sympy.isprime` gains efficiency by breaking the range of *n* values into subranges and cleverly precomputing a list of *a* values that work for every *n* in a subrange. For numbers greater than 264, `sympy.isprime` falls back on the [Baillie–PSW test](https://en.wikipedia.org/wiki/Baillie%E2%80%93PSW_primality_test), which is faster than Miller-Rabin, but is probabilistic. There are no known counterexamples found so far (no equivalent of the Carmichael numbers for the Baillie-PSW test), but no proof that such numbers don't exist.\n", + "\n", + "# Speed of Primality Checking\n", + "\n", + "**The great thing** about `isprime_fermat` and `sympy.isprime` is that they are **very fast**, handling 32-digit primes in well under a millisecond. Let's make a chart:" ] }, { "cell_type": "code", "execution_count": 20, - "id": "cf7a60d0-0b03-4b89-bd53-fdd182743e96", + "id": "8109d9fc-bbae-4ef0-a75c-908d9746a557", + "metadata": {}, + "outputs": [], + "source": [ + "import timeit\n", + "\n", + "big_primes = ([int('357686312646216567629137'[-i:]) for i in range(5, 25)] +\n", + " # The following primes sourced from t5k.org/curios/\n", + " [1000000000000000035000061, 59999999999899999999999999, 100000109999990000011000001,\n", + " 2728487949505050529272727777, 24444666666888888889999999991, 100003100019100043100057100069,\n", + " 9999999999999999777777775555331, 55555555555555555555555555555559])\n", + "\n", + "def plot_run_times(functions=(isprime_simple, isprime_faster, isprime_fermat, isprime), primes=big_primes):\n", + " \"\"\"For each primality-checking function, plot its run time on primes of different digit-lengths.\"\"\"\n", + " plt.figure(figsize=(9, 6))\n", + " for function in functions:\n", + " plt.plot(*time_test(function, primes), 'o-', label=function.__name__)\n", + " plt.grid(True, axis='y', which=\"major\", ls=':', color='gray')\n", + " plt.xticks(range(len(str(min(primes))), len(str(max(primes))) + 1))\n", + " plt.yscale('log')\n", + " plt.xlabel('Number of digits in prime')\n", + " plt.ylabel('Run time in seconds (log scale)')\n", + " plt.legend()\n", + "\n", + "def time_test(function, primes) -> tuple[list[int], list[float]]:\n", + " \"\"\"Time the function on each of the primes, stopping when one exceeds a second.\n", + " Return a list of the digit sizes and a list of the corresponding run times.\"\"\"\n", + " D, T = [], [] # D is length of primes in digits; T is time in seconds\n", + " repeat = 100 # Start with 100 repeats, but reduce when times get longer\n", + " for p in primes:\n", + " time = timeit.timeit(lambda: function(p), number=repeat) / repeat\n", + " D.append(len(str(p)))\n", + " T.append(time)\n", + " if time > 1:\n", + " break\n", + " if time > 1/1000:\n", + " repeat = 1\n", + " return D, T" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "id": "b1ab0f3d-6ce6-4b8c-9d4d-bb78bb1ac432", "metadata": {}, "outputs": [ { "data": { + "image/png": "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1+u3337TJvv69euqcuXKKnHixNJh//77bzVx4kSZnDkFk2v3cq9du1bON2/e3LHssWPHitJNnTpVJk44HjdunJoyZYrSxTvvvCNlnjt3rvrrr79k0o0JKwysQLl7964qUaKEmjZtms/3UfZPP/1UJk6YEGNgrlevngx6TmXj/SpVqkgdBUN08u/du6d2794txhv+wjjBQwETWaeyQYECBaSNUf/o9zBC0Q5XrlzRIt9k0aJF6o8//pBJpl3syMZk1V0H5s2bp0U2HrRoUxhTmzZtUvv375c2SJYsmRb57mXG66uvvpIHIx66TmX3799frVq1Sn377beiuzDKYUAsXbrUcdkxmcTE5OTJk2rJkiVqz549YvBDb/E5f2zevFkmGegL0H0YxOhv7p9999131bJly2RChuthHDdr1kyLbOgT+sz7779vqy4CkY9y4jVhwgR14MABNWfOHGmHTp06aSl76dKl1ezZs6VNV69eLW2Ba+Dc0SHfBAY9+qKuejHp3LmzR5/HmKxLPowFtCvO79ixQ56N6PMJEyZ0JDt37txRdHX48OEyQYZRpaPscABhTId+YhxGX8fEHrrlRDb+4hhtuWHDBrV161b16NEjcQZERkb6LTscDmFhYWrXrl3i4IQxBiP14MGDjvTUjux7DvTUn3wnehqrGCTOERoaapQoUSLG5A8ePNioUqWKERv07dvXyJ8/vxEZGelY1muvvWZ07NjR41yzZs2M1q1bGzq4d++ekShRImP58uUe50uVKmV88MEHjmRD1RYtWuQ6Rn1ky5bNGD9+vOvcjRs3jKRJkxrz5s1zJNudU6dOyft79uzRVnZf7NixQ677559/tMu+efOmXLdu3bqAZEcn/9y5c0bOnDmNAwcOGHny5DEmT56sRXb79u2Nxo0bByzLjuw333zTaNOmjWPZVvK9wX3UrFlTi+wiRYoYI0aM0KJX3vKPHDki59CWJhEREUbmzJmNWbNmBSz/8uXLIm/z5s0uvUycOLHx448/uq45dOiQXLNt2zZHst3ZuHGjvHf9+vWAy2xHvskPP/xgJEmSxHj8+LF22fv27ZNrjh8/HpDs6ORj7IKuhoeH2+q3dmVXr15dnk868CW/fPnyxocffhgjsr15+eWXozwbnchPmTKl8c0333hclyFDhoD1yVv26tWrjYQJE8qYbgL9SpAggbF27dqgyp8+fXrjiy++0Kqn3rJ162l08p3qaUzCCEMcBeF0eD6ff/551bp1a9tpB3aA16BMmTLi9UfYsGTJkmrWrFlKN/AcwKPYsWPHgLxDViA9aP369ero0aNyvG/fPvFA2/Gq2OHJkyfiGfP22CJEqDPCA06dOiVhX3hBTZBmUr58efFMxTcQOkUbp0uXTnsfQigYdQMPsw7gyUK4fdCgQRLJ0w28/9ArhJe7d++url69qqXMK1askOgLolCQj75iJz0jGBDGx/fp8nBBdzHuIFKHOf/GjRtFj+FtdMrDhw/lr7vewouLH7kKRm/NNIAMGTLIX3gE4Sl111VEeZA2EKiuesvWjR35uAYpESEhIVplw3uMaANSRuEFDxRf8uHVbdWqlUSWkB4TLFZl/+6771SmTJlU0aJF1dChQ+X7dMi/fPmyRI2hp+j7WbNmVdWrV9fSH71B/0TKabC66ks+yrxgwQJJlcHYM3/+fIl8IyXHiWzoKp4T7j9qB72FvgZaN3hWo1zod0jv0amn3rJ1E2FDfrB6GqM8bYuFROWXX34R6xLemlWrVhkVK1Y0nnvuOePWrVtaqgtebLyGDh1q7N692/j888+NZMmSGXPmzNHaHAsWLBCP/fnz57XIg9cQ0RF4I0JCQuTv6NGjDZ2gruF5QpmfPHlizJ07VzwiBQoUcCTX2zO2detWOXfhwgWP65o3b260aNHCkezYjjDcv39fvMWtWrXSJnvZsmXi5UIb58iRQyIYweBLPvpMnTp1XFEvnREGRIeWLFli7N+/X9576aWXjLJly0pfciLb9K6mSJHCmDRpkrTnmDFjpH42bdqkpezujB07VrxfaFsdsh88eGC0a9dO3oPuwnP29ddfByzbl/xHjx7J+AjduXbtmvHw4UMjLCxMrqtbt27AYwwimZUrV3ad++6776S83qBd33vvPUeydXou/ckHV65ckbp6//33tcmeNm2a6CrKXrBgwaCiC1byu3TpYnTq1Ml1HEyEwUo2nnt4vkJXv/32W4liNG3aVEvZ4dFGWeGV/+qrr+Q5269fP+lHR48edVx2d7p37y7jTDBYyUcfhO6Y+pomTRqJDjiVjYgDZCGyc/fuXePOnTtGr1695HvQ1nZAe6G/YW6RNm1aY8WKFdr01Eq2Lj3db0O+Ez2NaWgwxAPQMaFkVqGrQEHYDhNjd3r37m1UqFDB0AkGnNdff12bPEzGcuXKJX+heAiZYkDWaejgYVetWjUZEKDUGGyQ8lSoUCFHcp9VgwGTtYYNGxolS5b0CDM7lY0HybFjx+TBi1B73rx5jUuXLjmWv3PnTiNr1qweRqxOg8GbEydOBJVO5S0b5cW5li1belyHun/rrbe0lx0TPzzIg8GXbKTeweheunSpOEKmTJlipEqVKqg0BF/y0a5I4zT1tl69ekaDBg2M+vXrByS7W7du0h/Onj2r3WDwJVunweBPPvSzXLlyUifQW12ykQqCSTDSTtAf4TwI1ND0JR+G9wsvvGDcvn3bkcHgr15M1q9fH1Q6lS/55vgOp5w7xYoVM4YMGaKt7EijxcRzwoQJAZXZn3zoPvoKxq29e/caw4YNk+/Bc9epbBgezz//vDg7oKtIs0SfwfV2gEMAzwboPOoyU6ZMxsGDB7XoqZVsXXr60IZ8J3oa09BgiCeUKVMmoIEmOmC5unttwPTp08WTq4vTp0+LZ37x4sXaZMJYmDp1qse5kSNHyuRGN5iwmpN5TOBfffVVR/K8H3TmRNJ7Ig9jpU+fPo5kx5bBgMGsSZMmRvHixY1///1Xq2xvMHEIJprkLR+GgfmgMl+4Bn0VD7eYKDseCjNmzHAkGw8aePrQ393Bg7BSpUoByfYl350tW7bI+5goBIO3bExq4KTwXhuEMQgTe6fyvSev8GICPHR79OhhW27Pnj1ljDl58qTPiaT3BAHjKKI9TmTrmoj4k4/oNJxEtWrVCngyb6fs7v0UUbDvv//esXx4oa10FVFg3WXHmA/5iDo4LTuOIQsRanfwLLEbibVTdjjNoFtmnw8EK/kwmLzXBAH0na5du2orO7zoZl+HE2fcuHEB34NZLkQndOipleyYWsNQy0u+Ez2NDbiGIR6ALQmxQwq239QBdkjy3uoM+cTYWUQXyGVF/uZrr72mTSbyS713mEiUKJGt3RUCBTsWob6xoxR2/8BuBjpBni9ycrEmw+TWrVuS9xoTOZO6Qa4ods3AWpt169bJNnYxCdrYzFV3AtYuYHch5PyaL6wVwnoGtLNuzp07J2sYnOpukiRJZLvCmNZb8OWXX8ruN7rWjKCv4BUbuou1LtiuEf0SO5HY0VvYINi9BrtmYecW6KY7qAvsKOeuq2gHrCvzp6v+ZDvFjnyMK1grgj6EdSR2d9UKpuz/dULa0lV/8ocMGRJFV8HkyZPl+aK77KZ8O7rqTz52dsO4Eoy+BlJ26Cp2p0Oft4s/+eY6jmD0NZCyY+0I1rzhOqz5sLvLntWzwYme+pMdU0S6yQ9WT2OVp22xkKgMGDBA8pLhHUZos3bt2uKlDMaL4Avkg8NbOWrUKAmPIZQHrxDyOHWA3EVY9VhvoBPsQIM8U3gqUTcLFy6UegkkLcAf8C6tXLlSPCNr1qyRNAfsdhFMaBChdHj28YKqmbnn5k5CyLNOly6dK+cdu9Lky5fPlmfBn+yrV6/KMXIk8f78+fPlGLnwTsuOumjUqJF4kOCFhkzzBQ+jE9nw8iGMj1QkRKkQun377bdlzY23xyvYuvEmkJSk6GTjvYEDB0rZ0T8Rzkeo/cUXX5QcfqflRn+HN3HmzJmit0jrgdf1119/1VYvCIdjLPjss89sybQrGx5h7JQE7xx0a/bs2bJuCpFNHfKx5guyEblDVBNtih3U7IAccKRbYMx178uIjJggXQJj2oYNG6RPwgvondYZrGwc416wAw3uDREeHEOHncpHe2L8QioMPMfu1/hbV+NPNuoaUT/UB9oBzyqkJCFN1E76oJ26CTaq50826gK7dqHs0FWMwUiTQYTXDnbKjjEFqcTYtQf6ih2T0Of9pTzZrRfIRAQGz6tA8Ccf4zsiulWrVjW2b98u5UXKE77LKuc+kLJjTQfGSMhFBAb9pX///rbKjiwLpL6hzfDMxDHKhWe1Ez21IzvcgZ76k+9ET2MTGgxxEGyfmD17dsnHwwQZx8EsJIsOLCotWrSoTMSQn49JiC6QowiFwnaHOkG4DmFqDAgYeDHAY1tGO5PUQBZqQy7qHtueIrSKNIdgMEOX3i8YPgCLbj/66CMJx6IdEIa0W2f+ZGNC5ut9bNnrVL6Z5uTrhc85kQ1jCQsPkR6HNoAewDgJZNGzv7pxYjBEJxsPRazbwXaemNhDbufOnY2LFy9qK/eXX34pD3P0fxizgaT82ZGPhaDJkycPuM/7k40HX4cOHaRdUXakEU6cONH2dsv+5H/yySdiwKLeMT5gcmZ3XLDqy9AhE/RLpDdhITgMKvRRO8a3HdnQSX/XBCvfqt7wgh47kY11NVgnkiVLFql31D/SbQ4fPuy33HbrJliDwZ/sM2fOiHGAySrGXujUoEGDbK/Dslt2bEyAekGfwcTVjnFvVzYcK7lz5xYHXSDYkY81KTC40bYoO9JOvbdZDVY2HIl45qHPwJkSyDiA9WwYV/FswDiLZ6Y5oXeip3ZkhzrQU3/ynehpbJIA/zztKAchhBBCCCEkbsI1DIQQQgghhBBLaDAQQgghhBBCLKHBQAghhBBCCLGEBgMhhBBCCCHEEhoMhBBCCCGEEEtoMBBCCCGEEEIsocFACCGEEEIIsYQGAyGExDNOnz6tEiRIoPbu3aviCocPH1YVKlRQyZIlUy+//LLtz9WoUUP169fPdZw3b1718ccfP9W62LRpk8i8ceOGehp06NBBNWnS5Kl8NyGE+IIGAyGEBDGhw4QyLCzM4/zixYvl/P8ioaGhKmXKlOrIkSNq/fr1Qcv5888/VZcuXWxfnzt3bhUeHq6KFi2qbbJfqVIlkZk2bVr1NPjkk0/UnDlznsp3E0KIL2gwEEJIEMCTPnbsWHX9+vVnpv4ePXoU9GdPnDihqlSpovLkyaMyZswYtJzMmTOrFClS2L4+UaJEKlu2bCokJETpIkmSJCIzto2/iIgIFRkZKYZKunTpYvW7CSEkOmgwEEJIENSuXVsmlWPGjLG8ZtiwYVHSc5Bug7Qb7/ST0aNHq6xZs8pEccSIEerJkydq0KBBKkOGDCpXrlxq9uzZPtOA4A2H8QIP++bNmz3eP3DggGrQoIFKlSqVyG7btq36999/PdKBevXqJSlBmTJlUvXq1fN5H5jEokwoR9KkSeWeVq1a5XofE+tdu3bJNfg/7tsXd+/eVe3atZPyZM+eXU2cODHKNd4pSbhHGCK4x8KFC6t169bJdyCa452ShP+/8sorcj59+vRyHvULfvrpJ1WsWDGVPHlyMWjQfiiPL7yjFPD2o11Wr16tXnrpJSl//fr1JQphhSljxYoVqnjx4lJ+pGyhTUxMuUuXLpV7Q92eOXMmSkoS2ql3797STrgvtOWsWbOk/G+//bZKnTq1euGFF9TKlSsDan9CCLELDQZCCAkCeLYxyZ8yZYo6d+6cozrcsGGDunDhgtqyZYuaNGmSpPe8/vrrMjncvn276tatm+ratWuU74FBMWDAALVnzx5VsWJF1bBhQ3X16lV5D5PdmjVrqpIlS6qdO3fKBP/SpUuqRYsWHjK+/vpr8ahv3bpVzZgxwzJFBpP7CRMmqP3794th0ahRI3Xs2DF5HxPnIkWKSFnw/4EDB/qUg/LCqFmyZIlas2aNTKp3794drccdE2dEHFAPM2fOVB988EG06Uk///yz/B+pUSgLyo6/LVu2VB07dlSHDh2S723WrJkyDEPZ5d69e3L/c+fOlXbCxN7qPr3vGXWHVCtET9BGjx8/9pCLSNUXX3yhDh48qLJkyeJTDtoJRt2OHTvEeOjevbtq3ry5GIyow7p164pBAHmBtD8hhNjCIIQQEhDt27c3GjduLP+vUKGC0bFjR/n/okWLMAN1XRcaGmqUKFHC47OTJ0828uTJ4yELxxEREa5zBQsWNKpWreo6fvLkiZEyZUpj3rx5cnzq1Cn5nrCwMNc1jx8/NnLlymWMHTtWjkeOHGnUrVvX47vPnj0rnzty5IgcV69e3ShZsqTf+82RI4cxatQoj3Nly5Y1evTo4TrGfeJ+rbh9+7aRJEkS44cffnCdu3r1qpE8eXKjb9++rnOoC9QRWLlypRESEmKEh4e73l+7dq3cA+ravS727Nkjxxs3bpTj69evuz6za9cuOXf69Gm/9+pLxuzZs+X4+PHjrmumTZtmZM2a1a+M+fPnR7nfBQsWeMjdu3evZf8y26lKlSpR+kPbtm1d51BHkLVt2zbb7U8IIXZhhIEQQhwA7zC8v/BcBwu88wkT/v9wjPQRpM+4RzOQRnP58mWPzyGqYIIc/jJlyrjKsW/fPrVx40ZJRzFfhQoVcq03MCldunS0Zbt165ZEPypXruxxHseB3DO+E2skypcv7zqHdKuCBQtafgZRAkQNkPplUq5cORUoJUqUULVq1ZI6hVce6TyBrj1BlCN//vyuY6RUebeHL9zbyLxf93pDdAcpS/5wv8bsD+59BH0GmGWy2/6EEGIHfavECCHkf5Bq1apJis7QoUNd+fImMAK8017c01FMEidO7HGM3Hdf57CWwC537tyR9BcYNN5gsmuCnY2edTDBXrt2rfr9998lFQppZEhtQppTvnz5bMnw1R6BpDRZgTUVdhZX++sjpgyzj9htf0IIsQMjDIQQ4hBsr7ps2TK1bds2j/PIWb948aLHxFLn7wX88ccfrv9jkTQWHmNRLihVqpTkxGMRMRbEur8CMRLSpEmjcuTIIWsc3MExFuraBd55THAxSTeBl//o0aOWn4E3/uzZs5J7b4K1ANEBj725/sEdTKgRFRk+fLis+cB1ixYtUjGNexuZ92u2UUyiq/0JIQTQYCCEEIcgNaR169bq008/9TiP3W2uXLmixo0bJ2kg06ZNi7KTjRMgD5Ne7CTUs2dPmZBiYS/A8bVr12SxLybZ+H7s8oNddbwn03YW7sJTvWDBAkkTGjJkiBg+ffv2tS0DKTGdOnUSWVjkjR18EJFxT8Xypk6dOmJotG/fXhZbw0j58MMP5T0rrzy2dcV7y5cvl7qHpx1GChaoY/EvFisvXLhQ3ouNiTt2jsLvUpj3i4XLsfGjbDrbnxBCaDAQQoimiaF3yhAmpNOnT5eJPfLoscONnZ11Aols4AXZv/32m2zPiQkpMKMCmBxiBx0YNdiWE9t4RjdJ90WfPn1U//79ZRckyMGOO/iuF198MSA548ePV1WrVpVUGWxriu1So1tDgVQibJ+KSX/ZsmXVO++849olCduU+iJnzpwSRYBRg7x+bBuLKAl2Nnr11VdVgQIFxOjAzkXYcjSmQfvAsMJ9ItqESJQZBYlJdLY/IYQkwMpnVgMhhJD4ACbBMDSOHz/usQg5roGtW/GbEIj68EfYCCHxHS56JoQQEmdByhXSmRDNgJEAbz3WIsRlY4EQQp41aDAQQgiJs9y+fVsNHjxY1h4g3QqpTL5+IZoQQkjMwZQkQgghhBBCiCVc+UQIIYQQQgixhAYDIYQQQgghxBIaDIQQQgghhBBLaDAQQgghhBBCLKHBQAghhBBCCLGEBgMhhBBCCCHEEhoMhBBCCCGEEEtoMBBCCCGEEEIsocFACCGEEEIIUVb8H/2egl/OaLTaAAAAAElFTkSuQmCC", "text/plain": [ - "True" + "
" ] }, - "execution_count": 20, "metadata": {}, - "output_type": "execute_result" + "output_type": "display_data" } ], "source": [ - "isprime_fermat(561, k=500)" + "plot_run_times()" ] }, { "cell_type": "markdown", - "id": "83f69e44-4f3b-43b8-985c-0db82e983156", + "id": "408ba0fc-9bd9-4929-8ff3-1f9582ffa483", "metadata": {}, "source": [ - "561 is a [Carmichael number](https://en.wikipedia.org/wiki/Carmichael_number), a number that is resistant to the Fermat test.\n", + "We can test that our two Fermat functions work on the big primes and on the carmichael numbers, and get some more timing data:" + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "id": "7eacb754-e6ee-482e-82fd-8725845aad7e", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "CPU times: user 1.2 ms, sys: 1 μs, total: 1.2 ms\n", + "Wall time: 1.2 ms\n" + ] + } + ], + "source": [ + "%time test_prime_checker(isprime, primes=big_primes, composites=carmichael_numbers);" + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "id": "389cc455-6b9c-40f6-9fc2-2ae129159761", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "CPU times: user 3.43 ms, sys: 0 ns, total: 3.43 ms\n", + "Wall time: 3.43 ms\n" + ] + } + ], + "source": [ + "%time test_prime_checker(isprime_fermat, primes=big_primes, composites=carmichael_numbers);" + ] + }, + { + "cell_type": "markdown", + "id": "1347399a-24f2-4d5f-aa7f-822951126bf5", + "metadata": {}, + "source": [ + "What have we learned about timing?\n", + "- `isprime_simple` has a run time of *O*(*n*)\n", + "- `isprime_faster` has a run time of *O*(√*n*); we see its slope is half as steep on the log-log graph\n", + "- `isprime_fermat` and `isprime` ([according to Wikipedia](https://en.wikipedia.org/wiki/Fermat_primality_test)) have a run time of *O*(*k* log2*n*), where *k* is the number of repeats \n", + "- `isprime_faster` is more than 10,000 times faster than `isprime_simple` on 8-digit primes\n", + "- `isprime_fermat` is more than 10,000 times faster than `isprime_faster` on 17 digit primes\n", + "- `isprime` is about twice as fast as `isprime_fermat`; but that's quite good for `isprime_fermat` considering how simple it is\n", + "- `isprime` produces no known incorrect answers; `isprime_fermat` will on rare occasion produce a false prime\n", "\n", - "Fortunately there are variations on Fermat's idea that always give the right answer. `sympy.isprime` ([source code here](https://github.com/sympy/sympy/blob/master/sympy/ntheory/primetest.py)) uses the [Miller-Rabin test](https://en.wikipedia.org/wiki/Miller%E2%80%93Rabin_primality_test) (sometimes called Rabin-Miller, but I give Gary Miller precedence because he is my former colleague). The algorithm is guaranteed to give the right answer, but it does start to get slow for very large numbers.\n", - "\n", - "For numbers greater than 264 (20 digits), `sympy.isprime` falls back on the [Baillie–PSW test](https://en.wikipedia.org/wiki/Baillie%E2%80%93PSW_primality_test), which is faster than Miller-Rabin, but is probabilistic. There are no known counterexamples found so far (no equivalent of the Carmichael numbers for the Baillie-PSW test), but no proof that such numbers don't exist.\n", - "\n", - "I hope you have enjoyed this excursion into the land of prime numbers!" + "I hope you have enjoyed this excursion into the land of prime numbers.\n" ] } ],