{ "cells": [ { "cell_type": "markdown", "id": "8812d495-6014-4669-97ae-003be4f54605", "metadata": {}, "source": [ "
Peter Norvig
Jan 2026
\n", "\n", "# Truncatable Primes\n", "\n", "What's special about [this pencil](https://mathsgear.co.uk/products/truncatable-prime-pencil)?\n", "\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 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", " 7686312646216567629137 is prime|\n", " ...\n", " 137 is prime\n", " 37 is prime\n", " 7 is prime\n", "\n", "Numbers like this are called [**truncatable primes**](https://en.wikipedia.org/wiki/Truncatable_prime). \n", "\n", "I thought I would write a program to find all the truncatable primes. (It is not immediately obvious that there is a finite number of them, but it turns out to be true.) My function `truncatable_primes` below starts with the list of one-digit primes, [2, 3, 5, 7], and on each iteration creates a list of new numbers that are one digit longer by placing each possible digit 1–9 to the left of each prime. Then out of those numbers we find just the new primes. If there are any new primes, the function 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 returns all the truncatable primes in sorted order." ] }, { "cell_type": "code", "execution_count": 1, "id": "8ab95f58-0d60-4516-b19c-5f55614abb54", "metadata": {}, "outputs": [], "source": [ "from sympy import isprime # isprime(n) returns True if n is a prime\n", "\n", "def truncatable_primes(primes=[2, 3, 5, 7]) -> list[int]:\n", " \"\"\"Truncatable primes, in ascending order.\"\"\"\n", " new_numbers = (int(d + str(p)) for d in \"123456789\" for p in primes)\n", " new_primes = [n for n in new_numbers if isprime(n)]\n", " if new_primes:\n", " return primes + truncatable_primes(new_primes)\n", " else:\n", " return primes" ] }, { "cell_type": "markdown", "id": "90d8f036-da26-4975-a0da-ab637694a679", "metadata": {}, "source": [ "Let's see how many truncatable primes there are:" ] }, { "cell_type": "code", "execution_count": 2, "id": "4c9a569c-af7f-4335-b10b-785e5709862b", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "4260" ] }, "execution_count": 2, "metadata": {}, "output_type": "execute_result" } ], "source": [ "TP = truncatable_primes()\n", "\n", "len(TP)" ] }, { "cell_type": "markdown", "id": "a32b56c4-587b-48d5-91ec-1abcef2e909f", "metadata": {}, "source": [ "There are **4260** of these truncatable primes. Here are the smallest and largest of them:" ] }, { "cell_type": "code", "execution_count": 3, "id": "e937655d-16eb-44ce-8698-0a0c09c9f6a9", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[2, 3, 5, 7, 13, 17, 23, 37, 43, 47, 53, 67, 73, 83, 97, 113]" ] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "TP[:16]" ] }, { "cell_type": "code", "execution_count": 4, "id": "502be81c-fb57-431a-855a-21184a1aeb0d", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[66276812967623946997,\n", " 67986315421273233617,\n", " 86312646216567629137,\n", " 315396334245663786197,\n", " 367986315421273233617,\n", " 666276812967623946997,\n", " 686312646216567629137,\n", " 918918997653319693967,\n", " 5918918997653319693967,\n", " 6686312646216567629137,\n", " 7686312646216567629137,\n", " 9918918997653319693967,\n", " 57686312646216567629137,\n", " 95918918997653319693967,\n", " 96686312646216567629137,\n", " 357686312646216567629137]" ] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ "TP[-16:]" ] }, { "cell_type": "markdown", "id": "e82700e8-8fb2-45cf-bcf0-7805e46174bb", "metadata": {}, "source": [ "## Right-Truncatable Primes\n", "\n", "What if you sharpen the pencil from the other end? The primes we found so far are called **left-truncatable primes**; there are also **right-trunctable primes**:" ] }, { "cell_type": "code", "execution_count": 5, "id": "3870bc47-5833-4879-b622-2094b4247239", "metadata": {}, "outputs": [], "source": [ "def right_truncatable_primes(primes=[2, 3, 5, 7]) -> list[int]:\n", " \"\"\"All right-truncatable primes, in ascending order.\"\"\"\n", " # Only consider (1, 3, 7, 9) as the digit on the right; placing any other digit forms a composite number\n", " new_numbers = (10 * p + d for p in primes for d in (1, 3, 7, 9))\n", " new_primes = [n for n in new_numbers if isprime(n)]\n", " if new_primes:\n", " return primes + right_truncatable_primes(new_primes)\n", " else:\n", " return primes" ] }, { "cell_type": "code", "execution_count": 6, "id": "7b39ffb5-ba52-42e6-a270-79bc10b26c2c", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "83" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "TPr = right_truncatable_primes()\n", "\n", "len(TPr)" ] }, { "cell_type": "markdown", "id": "5323ae60-285d-49d6-a133-5c476eb4c5e5", "metadata": {}, "source": [ "There are only 83 right-truncatable primes. Here they are:" ] }, { "cell_type": "code", "execution_count": 7, "id": "e3780212-2b86-469f-9df0-81bd6fcc9c94", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[2, 3, 5, 7, 23, 29, 31, 37, 53, 59, 71, 73, 79, 233, 239, 293, 311, 313, 317, 373, 379, 593, 599, 719, 733, 739, 797, 2333, 2339, 2393, 2399, 2939, 3119, 3137, 3733, 3739, 3793, 3797, 5939, 7193, 7331, 7333, 7393, 23333, 23339, 23399, 23993, 29399, 31193, 31379, 37337, 37339, 37397, 59393, 59399, 71933, 73331, 73939, 233993, 239933, 293999, 373379, 373393, 593933, 593993, 719333, 739391, 739393, 739397, 739399, 2339933, 2399333, 2939999, 3733799, 5939333, 7393913, 7393931, 7393933, 23399339, 29399999, 37337999, 59393339, 73939133]\n" ] } ], "source": [ "print(TPr)" ] }, { "cell_type": "markdown", "id": "976c7f1f-79c5-48c3-8909-62b809993057", "metadata": {}, "source": [ "We can also find the **two-sided truncatable primes**, which are both right- and left-truncatable. It turns out there are only 15 of them:" ] }, { "cell_type": "code", "execution_count": 8, "id": "b87ae26e-0dee-4c95-914f-c897fda17508", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{2, 3, 5, 7, 23, 37, 53, 73, 313, 317, 373, 797, 3137, 3797, 739397}" ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "set(TP) & set(TPr)" ] }, { "cell_type": "markdown", "id": "82fc3133-4a17-47ec-b742-7a37f78421a8", "metadata": {}, "source": [ "There isn't an official name for a truncatable prime that remains prime for all possible choices of truncating either the rightmost or leftmost digit at each step. I'll call them **omni-truncatable primes**. I can compute them like this:" ] }, { "cell_type": "code", "execution_count": 9, "id": "28f12184-b247-4cea-86d4-6b0e07e2a63f", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[2, 3, 5, 7, 23, 37, 53, 73, 373]" ] }, "execution_count": 9, "metadata": {}, "output_type": "execute_result" } ], "source": [ "def is_omni_truncatable_prime(n: int) -> bool:\n", " \"\"\"Is n a truncatable prime for all possible choices of truncating digits from left or right?\"\"\"\n", " return (isprime(n) and\n", " (n < 10 or (is_omni_truncatable_prime(int(str(n)[1:])) and\n", " is_omni_truncatable_prime(int(str(n)[:-1])))))\n", "\n", "[p for p in TP if is_omni_truncatable_prime(p)]" ] }, { "cell_type": "markdown", "id": "7b316527-f437-439f-ac64-ef7980ecf6ff", "metadata": {}, "source": [ "There are only 9 of them, with 373 the largest.\n", "\n", "## Palindromic Primes\n", "\n", "What about primes that are both truncatable and [**palindromic**](https://en.wikipedia.org/wiki/Palindromic_prime) (the same when you reverse the digits)?" ] }, { "cell_type": "code", "execution_count": 10, "id": "5a705ef4-b2b7-4006-b518-6e030de8fd30", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{2, 3, 5, 7, 313, 353, 373, 383, 797, 76367, 79397, 7693967, 799636997}" ] }, "execution_count": 10, "metadata": {}, "output_type": "execute_result" } ], "source": [ "{p for p in TP + TPr if str(p) == str(p)[::-1]}" ] }, { "cell_type": "markdown", "id": "cd0da3ad-54c0-47dc-979c-4eecc935425c", "metadata": {}, "source": [ "There are 13 **palindromic truncatable primes**, with only 4 of them longer than 3 digits.\n", "\n", "**Aside**: Now I'm curious about [**palindromic primes**](https://en.wikipedia.org/wiki/Palindromic_prime) in general. There are probably an infinite number of them, so I'll define `palindromic_primes(d)` to list all the palindromic primes up to `d` digits. To find them, I'll enumerate the \"first half\" of numbers, and then concatenate the reverse of the first half, forming both odd- and even-length numbers, e.g. when the first half is 123, `palindromes(123)` produces (12321, 123321). Then all we have to do is check each palindrome for primality." ] }, { "cell_type": "code", "execution_count": 11, "id": "fc208a86-c3f4-4426-913d-62ec0a639576", "metadata": {}, "outputs": [], "source": [ "def palindromic_primes(digit_length: int) -> list[int]:\n", " \"\"\"Generate all palindromic primes of up to `digit_length` digits.\"\"\"\n", " end = 10 ** ((digit_length + 1) // 2)\n", " return [n for half in range(1, end)\n", " for n in palindromes(half)\n", " if isprime(n)]\n", "\n", "def palindromes(half: int) -> tuple[int]:\n", " \"\"\"Given the left half of a palindrome, make two full palindromes,\n", " one without the middle digit repeated, one with.\"\"\"\n", " left = str(half)\n", " right = left[::-1]\n", " return int(left + right[1:]), int(left + right)\n", "\n", "assert palindromes(123) == (12321, 123321)" ] }, { "cell_type": "markdown", "id": "ec5f9d5a-c89e-4dc9-812b-232437e4801e", "metadata": {}, "source": [ "Let's count the palindromic primes of up to 11 digits, and peek at some of them:" ] }, { "cell_type": "code", "execution_count": 12, "id": "3f9c6d25-8d40-4267-a45f-c0284b910c86", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "47995" ] }, "execution_count": 12, "metadata": {}, "output_type": "execute_result" } ], "source": [ "PP = palindromic_primes(11)\n", "\n", "len(PP)" ] }, { "cell_type": "code", "execution_count": 13, "id": "69149eb4-d79d-4cfa-8e48-40946e54c48f", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[11,\n", " 2,\n", " 3,\n", " 5,\n", " 7,\n", " 101,\n", " 131,\n", " 151,\n", " 181,\n", " 191,\n", " 313,\n", " 353,\n", " 373,\n", " 383,\n", " 727,\n", " 757,\n", " 787,\n", " 797,\n", " 919,\n", " 929,\n", " 10301,\n", " 10501,\n", " 10601,\n", " 11311,\n", " 11411]" ] }, "execution_count": 13, "metadata": {}, "output_type": "execute_result" } ], "source": [ "PP[:25]" ] }, { "cell_type": "code", "execution_count": 14, "id": "3bebaad1-8fb2-4892-87f8-8846062d92d4", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[99985958999,\n", " 99986068999,\n", " 99988688999,\n", " 99988988999,\n", " 99991819999,\n", " 99994349999,\n", " 99995759999,\n", " 99998189999,\n", " 99998989999,\n", " 99999199999]" ] }, "execution_count": 14, "metadata": {}, "output_type": "execute_result" } ], "source": [ "PP[-10:]" ] }, { "cell_type": "markdown", "id": "853d5a6c-936e-4ab4-afc3-2082641063fc", "metadata": {}, "source": [ "# Digit Lengths\n", "\n", "How many digits are in the primes in all these lists? The function `digit_lengths` returns a {number_of_digits: count_of_primes_with_that_many_digits} dict, and plots a bar chart for that data:" ] }, { "cell_type": "code", "execution_count": 15, "id": "28b0bc97-1b22-449f-b33a-6f8c84fd890d", "metadata": {}, "outputs": [], "source": [ "import matplotlib.pyplot as plt\n", "from collections import Counter\n", "\n", "def digit_lengths(primes) -> dict[int, int]:\n", " \"\"\"Plot a bar chart and return a dict 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')\n", " plt.ylabel('Count')\n", " return dict(digits)" ] }, { "cell_type": "markdown", "id": "09bc98cf-2f43-4f58-b414-f3eff2d834b3", "metadata": {}, "source": [ "First for the **left-truncatable primes**:" ] }, { "cell_type": "code", "execution_count": 16, "id": "defd769e-9f92-4e4f-a12b-88a653b6efee", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{1: 4,\n", " 2: 11,\n", " 3: 39,\n", " 4: 99,\n", " 5: 192,\n", " 6: 326,\n", " 7: 429,\n", " 8: 521,\n", " 9: 545,\n", " 10: 517,\n", " 11: 448,\n", " 12: 354,\n", " 13: 276,\n", " 14: 212,\n", " 15: 117,\n", " 16: 72,\n", " 17: 42,\n", " 18: 24,\n", " 19: 13,\n", " 20: 6,\n", " 21: 5,\n", " 22: 4,\n", " 23: 3,\n", " 24: 1}" ] }, "execution_count": 16, "metadata": {}, "output_type": "execute_result" }, { "data": { "image/png": "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eo4aovQcmzdvLuvXrzfvoa1oV3dj6df33nuv2V6tWjWzXetX/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": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "digit_lengths(TP)" ] }, { "cell_type": "markdown", "id": "ec4c6f1d-d298-48de-884a-efee0b81fd19", "metadata": {}, "source": [ "And for the **right-truncatable** primes:" ] }, { "cell_type": "code", "execution_count": 17, "id": "09f29951-d8f2-47a3-b666-bfa6fd5d1c87", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{1: 4, 2: 9, 3: 14, 4: 16, 5: 15, 6: 12, 7: 8, 8: 5}" ] }, "execution_count": 17, "metadata": {}, "output_type": "execute_result" }, { "data": { "image/png": "iVBORw0KGgoAAAANSUhEUgAAAjMAAAGwCAYAAABcnuQpAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjgsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvwVt1zgAAAAlwSFlzAAAPYQAAD2EBqD+naQAAJSxJREFUeJzt3Q1UVVX+//EvhoCZ4LNCglgpPoaaaGU+kKRjijquHmyZkfacz5ajTJmSFtCUWUmSrkmdKTNXiZmOmo8xTpqBmtkUSqEyPtGUgtCIBve/9v4v7o+roEjIOfvwfq21hXPOPZd97r3e+7l773O2l8vlcgkAAIChalldAQAAgN+DMAMAAIxGmAEAAEYjzAAAAKMRZgAAgNEIMwAAwGiEGQAAYDRvcbji4mI5duyY1KtXT7y8vKyuDgAAqAB1GbwzZ85IUFCQ1KpVq2aHGRVkgoODra4GAACohOzsbGnRokXNDjOqRabkwfD397e6OgAAoALy8vJ0Y0TJ53iNDjMlXUsqyBBmAAAwS0WGiDAAGAAAGI0wAwAAjEaYAQAARiPMAAAAoxFmAACA0QgzAADAaIQZAABgNMIMAAAwGmEGAAAYjTADAACMRpgBAABGszTMpKamSnR0tJ7eW829sGrVqotu891338mQIUMkICBA6tatKxEREXLkyBFL6gsAAOzH0jBTUFAg4eHhkpSUVOb2H374Qe644w5p27atbNu2Tfbt2yczZswQPz+/aq8rAACwJy+Xy+USG1AtMykpKTJs2DD3uhEjRkjt2rXl73//+++aQly16uTm5jJrNgAAhriSz2/bjpkpLi6WtWvXSps2bWTAgAHStGlT6dGjR5ldUaUVFhbqB6B0AQAAzuUtNpWTkyP5+fmSkJAgc+bMkcTERFm/fr0MHz5ctm7dKn369Clzv/j4eImLi6v2+gKmCJ2+Vkx0KGGQ1VUAYFO2bplRhg4dKpMnT5bOnTvL9OnTZfDgwZKcnFzufrGxsbpJqqRkZ2dXY60BAEB1s23LTOPGjcXb21vat2/vsb5du3ayffv2cvfz9fXVBQAA1Ay2bZnx8fHRp2FnZGR4rD9w4IC0bNnSsnoBAAB7sbRlRo2JyczMdC9nZWXJ3r17pWHDhhISEiJTp06V+++/X3r37i2RkZF6zMynn36qT9MGAACwPMykpaXpkFJiypQp+mdMTIwsWbJE/vjHP+rxMWpQ74QJEyQsLEw+/vhjfe0ZAAAAy8NM37595XKXuRkzZowuAAAARo2ZAQAAqAjCDAAAMBphBgAAGI0wAwAAjEaYAQAARiPMAAAAoxFmAACA0QgzAADAaIQZAABgNMIMAAAwGmEGAAAYjTADAACMRpgBAABGI8wAAACjEWYAAIDRvK2uAABcDaHT1xr5wB5KGGR1FQDj0DIDAACMRpgBAABGI8wAAACjEWYAAIDRCDMAAMBohBkAAGA0wgwAADAaYQYAABiNMAMAAIxGmAEAAEYjzAAAAKMRZgAAgNEIMwAAwGiEGQAAYDTCDAAAMBphBgAAGI0wAwAAjGZpmElNTZXo6GgJCgoSLy8vWbVqVbm3ffLJJ/Vt5s2bV611BAAA9mZpmCkoKJDw8HBJSkq65O1SUlJk586dOvQAAACU5i0WGjhwoC6XcvToURk/frxs2LBBBg0aVG11AwAAZrA0zFxOcXGxjBo1SqZOnSodOnSo0D6FhYW6lMjLy7uKNQQAAFazdZhJTEwUb29vmTBhQoX3iY+Pl7i4uKtaLzhT6PS1YqJDCbRYAqjZbHs2U3p6urzxxhuyZMkSPfC3omJjYyU3N9ddsrOzr2o9AQCAtWwbZv75z39KTk6OhISE6NYZVQ4fPizPPPOMhIaGlrufr6+v+Pv7exQAAOBctu1mUmNloqKiPNYNGDBArx89erRl9QIAAPZiaZjJz8+XzMxM93JWVpbs3btXGjZsqFtkGjVq5HH72rVrS/PmzSUsLMyC2gIAADuyNMykpaVJZGSke3nKlCn6Z0xMjB4rAwAAYOsw07dvX3G5XBW+/aFDh65qfQAAgHlsOwAYAACgIggzAADAaIQZAABgNMIMAAAwGmEGAAAYjTADAACMRpgBAABGI8wAAACjEWYAAIDRCDMAAMBohBkAAGA0wgwAADAaYQYAABiNMAMAAIxGmAEAAEYjzAAAAKMRZgAAgNEIMwAAwGiEGQAAYDTCDAAAMBphBgAAGI0wAwAAjEaYAQAARiPMAAAAoxFmAACA0QgzAADAaIQZAABgNMIMAAAwGmEGAAAYjTADAACMRpgBAABGI8wAAACjEWYAAIDRLA0zqampEh0dLUFBQeLl5SWrVq1ybzt//rxMmzZNOnXqJHXr1tW3eeihh+TYsWNWVhkAANiMpWGmoKBAwsPDJSkp6aJtv/76q+zevVtmzJihf65cuVIyMjJkyJAhltQVAADYk7eVf3zgwIG6lCUgIEA2btzosW7+/PnSvXt3OXLkiISEhFRTLQEAgJ1ZGmauVG5uru6Oql+/frm3KSws1KVEXl5eNdUOAABYwZgwc/bsWT2G5oEHHhB/f/9ybxcfHy9xcXHVWjcAsEro9LVGPviHEgZZXQU4iBFnM6nBwPfdd5+4XC5ZsGDBJW8bGxurW3BKSnZ2drXVEwAAVD9vU4LM4cOHZcuWLZdslVF8fX11AQAANYO3CUHm4MGDsnXrVmnUqJHVVQIAADZjaZjJz8+XzMxM93JWVpbs3btXGjZsKIGBgXLPPffo07LXrFkjRUVFcuLECX07td3Hx8fCmgMAALuwNMykpaVJZGSke3nKlCn6Z0xMjMyaNUtWr16tlzt37uyxn2ql6du3bzXXFgAA2JGlYUYFEjWotzyX2gYAAGDM2UwAAADlIcwAAACjEWYAAIDRCDMAAMBohBkAAGA0wgwAADAaYQYAABiNMAMAAIxGmAEAAEYjzAAAAKMRZgAAgNEIMwAAwGiEGQAAYDTCDAAAMBphBgAAGI0wAwAAjEaYAQAARiPMAAAAoxFmAACA0QgzAADAaIQZAABgNMIMAAAwGmEGAAAYjTADAACMRpgBAABGI8wAAACjEWYAAIDRCDMAAMBohBkAAGA0wgwAADAaYQYAABiNMAMAAIxGmAEAAEazNMykpqZKdHS0BAUFiZeXl6xatcpju8vlkhdeeEECAwOlTp06EhUVJQcPHrSsvgAAwH4sDTMFBQUSHh4uSUlJZW5/5ZVX5M0335Tk5GT58ssvpW7dujJgwAA5e/ZstdcVAADYk7eVf3zgwIG6lEW1ysybN0+ef/55GTp0qF73t7/9TZo1a6ZbcEaMGFHNtQUAAHZk2zEzWVlZcuLECd21VCIgIEB69OghO3bsKHe/wsJCycvL8ygAAMC5bBtmVJBRVEtMaWq5ZFtZ4uPjdegpKcHBwVe9rgAAwDq2DTOVFRsbK7m5ue6SnZ1tdZUAAEBNDDPNmzfXP0+ePOmxXi2XbCuLr6+v+Pv7exQAAOBctg0zrVq10qFl8+bN7nVq/Is6q+m2226ztG4AAMA+LD2bKT8/XzIzMz0G/e7du1caNmwoISEhMmnSJJkzZ460bt1ah5sZM2boa9IMGzbMymoDAAAbsTTMpKWlSWRkpHt5ypQp+mdMTIwsWbJE/vSnP+lr0Tz++ONy+vRpueOOO2T9+vXi5+dnYa0BAICdWBpm+vbtq68nUx51VeAXX3xRFwAAAKPGzAAAAFQEYQYAABiNMAMAAIxGmAEAAEYjzAAAAKMRZgAAgNEIMwAAwGiEGQAAYDTCDAAAMBphBgAA1Lwwc8MNN8jPP/980Xo1f5LaBgAAYOswc+jQISkqKrpofWFhoRw9erQq6gUAAFD1E02uXr3a/fuGDRskICDAvazCzebNmyU0NPRK7hIAAKD6wsywYcPcs1nHxMR4bKtdu7YOMq+99trvqxEAAMDVCjPFxcX6Z6tWreSrr76Sxo0bX8nuAAAA1oaZEllZWVVfE9hW6PS1YqpDCYOsrgIAwI5hRlHjY1TJyclxt9iUePfdd6uibgAAAFcnzMTFxcmLL74o3bp1k8DAQD2GBgAAwJgwk5ycLEuWLJFRo0ZVfY0AAACu9nVmzp07J7fffntldgUAALA+zDz66KOybNmyqq0JAABAdXUznT17VhYuXCibNm2Sm2++WV9jprS5c+dW5m4BAACqJ8zs27dPOnfurH/fv3+/xzYGAwMAgOpUqTCzdevWqq8JAABAdY2ZAQAAMLplJjIy8pLdSVu2bPk9dQIAALi6YaZkvEyJ8+fPy969e/X4mQsnoAQAALBdmHn99dfLXD9r1izJz8//vXUCAACwZszMgw8+yLxMAADA3DCzY8cO8fPzq8q7BAAAqPpupuHDh3ssu1wuOX78uKSlpcmMGTMqc5cAAADVF2YCAgI8lmvVqiVhYWF6Ju3+/ftXriYAAADVFWYWL15cmd0AAADsNWYmPT1d3nvvPV327NkjVa2oqEh3W7Vq1Urq1KkjN954o8yePVt3awEAAFS6ZSYnJ0dGjBgh27Ztk/r16+t1p0+f1hfTW758uTRp0qRKHt3ExERZsGCBLF26VDp06KDH5IwePVp3c02YMIFnEAAAVK5lZvz48XLmzBn59ttv5ZdfftFFXTAvLy+vSkPGF198IUOHDpVBgwZJaGio3HPPPXpMzq5du3jqAABA5cPM+vXr5e2335Z27dq517Vv316SkpJk3bp1UlVuv/122bx5sxw4cEAvf/3117J9+3YZOHBgufsUFhbqUFW6AAAA56pUN1NxcbHUrl37ovVqndpWVaZPn67DSNu2beWaa67RY2heeuklGTlyZLn7xMfHS1xcXJXVAQBgrdDpa419Cg4lDLK6CjVCpVpm7rzzTpk4caIcO3bMve7o0aMyefJk6devX5VVbsWKFfL+++/LsmXLZPfu3XrszKuvvqp/lic2NlZyc3PdJTs7u8rqAwAAHNIyM3/+fBkyZIgexxIcHKzXqdDQsWNHfWZTVZk6dapunVGDjZVOnTrJ4cOHdetLeRNa+vr66gIAAGqGSoUZFWBUS8mmTZvk+++/1+vU+JmoqKgqrdyvv/6qL8hXmupuqsquLAAAUIPCzJYtW2TcuHGyc+dO8ff3l7vuuksXRXXpqNOnk5OTpVevXlVSuejoaD1GJiQkRN+3upbN3LlzZcyYMVVy/wAAoIaFmXnz5sljjz2mg8yF1LVfnnjiCR02qirMvPXWW/qieU8//bS+tk1QUJD+Gy+88EKV3D8AAKhhA4DVqdF/+MMfyt2urgGjrgpcVerVq6cDlBon87///U9++OEHmTNnjvj4+FTZ3wAAADUozJw8ebLMU7JLeHt7y08//VQV9QIAAKj6MHP99dfrK/2WZ9++fRIYGHgldwkAAFB9Yebuu+/WY1jOnj170TbVDTRz5kwZPHjw76sRAADA1RoA/Pzzz8vKlSulTZs2+qymsLAwvV6dnq2mMlBX6H3uueeu5C4BAACqL8w0a9ZMT/741FNP6Svtulwuvd7Ly0sGDBigA426DQAAgG0vmteyZUv5xz/+IadOnZLMzEwdaFq3bi0NGjS4OjUEAACo6isAKyq8REREVHZ3AAAA6yaaBAAAsAvCDAAAMBphBgAAGI0wAwAAjEaYAQAARiPMAAAAoxFmAACA0QgzAADAaIQZAABgNMIMAAAwGmEGAAAYjTADAACMRpgBAABGI8wAAACjEWYAAIDRCDMAAMBohBkAAGA0wgwAADAaYQYAABiNMAMAAIxGmAEAAEYjzAAAAKMRZgAAgNEIMwAAwGiEGQAAYDTCDAAAMJrtw8zRo0flwQcflEaNGkmdOnWkU6dOkpaWZnW1AACATXiLjZ06dUp69uwpkZGRsm7dOmnSpIkcPHhQGjRoYHXVAACATdg6zCQmJkpwcLAsXrzYva5Vq1aW1gkAANiLrbuZVq9eLd26dZN7771XmjZtKl26dJFFixZdcp/CwkLJy8vzKAAAwLlsHWZ+/PFHWbBggbRu3Vo2bNggTz31lEyYMEGWLl1a7j7x8fESEBDgLqplBwAAOJetw0xxcbF07dpVXn75Zd0q8/jjj8tjjz0mycnJ5e4TGxsrubm57pKdnV2tdQYAANXL1mEmMDBQ2rdv77GuXbt2cuTIkXL38fX1FX9/f48CAACcy9ZhRp3JlJGR4bHuwIED0rJlS8vqBAAA7MXWYWby5Mmyc+dO3c2UmZkpy5Ytk4ULF8rYsWOtrhoAALAJW4eZiIgISUlJkQ8++EA6duwos2fPlnnz5snIkSOtrhoAALAJW19nRhk8eLAuAAAAxrXMAAAAXA5hBgAAGI0wAwAAjEaYAQAARiPMAAAAoxFmAACA0QgzAADAaIQZAABgNMIMAAAwGmEGAAAYjTADAACMRpgBAABGI8wAAACjEWYAAIDRCDMAAMBo3lZXAAAAiIROX2vkw3AoYZDVVaBlBgAAmI1uJgAAYDTCDAAAMBphBgAAGI0wAwAAjEaYAQAARiPMAAAAoxFmAACA0QgzAADAaIQZAABgNMIMAAAwGmEGAAAYjTADAACMRpgBAABGI8wAAACjEWYAAIDRCDMAAMBoRoWZhIQE8fLykkmTJlldFQAAYBPGhJmvvvpK3nnnHbn55putrgoAALARI8JMfn6+jBw5UhYtWiQNGjSwujoAAMBGjAgzY8eOlUGDBklUVNRlb1tYWCh5eXkeBQAAOJe32Nzy5ctl9+7dupupIuLj4yUuLk6qS+j0tWKiQwmDrK4CAADOb5nJzs6WiRMnyvvvvy9+fn4V2ic2NlZyc3PdRd0HAABwLlu3zKSnp0tOTo507drVva6oqEhSU1Nl/vz5ukvpmmuu8djH19dXFwAAUDPYOsz069dPvvnmG491o0ePlrZt28q0adMuCjIAAKDmsXWYqVevnnTs2NFjXd26daVRo0YXrQcAADWTrcfMAAAAGN0yU5Zt27ZZXQUAAGAjtMwAAACjEWYAAIDRCDMAAMBohBkAAGA0wgwAADAaYQYAABiNMAMAAIxGmAEAAEYjzAAAAKMRZgAAgNEIMwAAwGiEGQAAYDTCDAAAMBphBgAAGI0wAwAAjEaYAQAARiPMAAAAoxFmAACA0QgzAADAaIQZAABgNMIMAAAwGmEGAAAYjTADAACMRpgBAABGI8wAAACjEWYAAIDRCDMAAMBohBkAAGA0wgwAADAaYQYAABiNMAMAAIxGmAEAAEYjzAAAAKPZPszEx8dLRESE1KtXT5o2bSrDhg2TjIwMq6sFAABswvZh5vPPP5exY8fKzp07ZePGjXL+/Hnp37+/FBQUWF01AABgA95ic+vXr/dYXrJkiW6hSU9Pl969e1tWLwAAYA+2DzMXys3N1T8bNmxY5vbCwkJdSuTl5VVb3QAAQPWzfTdTacXFxTJp0iTp2bOndOzYsdwxNgEBAe4SHBxc7fUEAADVx6gwo8bO7N+/X5YvX17ubWJjY3XrTUnJzs6u1joCAIDqZUw307hx42TNmjWSmpoqLVq0KPd2vr6+ugAAgJrB9mHG5XLJ+PHjJSUlRbZt2yatWrWyukoAAMBGvE3oWlq2bJl88skn+lozJ06c0OvVeJg6depYXT0AAGAx24+ZWbBggR770rdvXwkMDHSXDz/80OqqAQAAGzCimwkAAMDYlhkAAIBLIcwAAACjEWYAAIDRCDMAAMBohBkAAGA0wgwAADAaYQYAABiNMAMAAIxGmAEAAEYjzAAAAKMRZgAAgNEIMwAAwGiEGQAAYDTCDAAAMBphBgAAGI0wAwAAjEaYAQAARiPMAAAAoxFmAACA0QgzAADAaIQZAABgNMIMAAAwGmEGAAAYjTADAACMRpgBAABGI8wAAACjEWYAAIDRCDMAAMBohBkAAGA0wgwAADAaYQYAABiNMAMAAIxGmAEAAEYzIswkJSVJaGio+Pn5SY8ePWTXrl1WVwkAANiE7cPMhx9+KFOmTJGZM2fK7t27JTw8XAYMGCA5OTlWVw0AANiA7cPM3Llz5bHHHpPRo0dL+/btJTk5Wa699lp59913ra4aAACwAW+rK3Ap586dk/T0dImNjXWvq1WrlkRFRcmOHTvK3KewsFCXErm5ufpnXl7eValjceGvYqIreTxMPcaacpxX+trmOO2N59M5r1mF96Df/9i5XK7L39hlY0ePHlVH4Priiy881k+dOtXVvXv3MveZOXOm3ofCY8BrgNcArwFeA7wGxPjHIDs7+7J5wdYtM5WhWnHUGJsSxcXF8ssvv0ijRo3Ey8tLTKESaXBwsGRnZ4u/v784VU04zppwjArH6Sw8n86RZ+h7kGqROXPmjAQFBV32trYOM40bN5ZrrrlGTp486bFeLTdv3rzMfXx9fXUprX79+mIq9cIz6cVXWTXhOGvCMSocp7PwfDqHv4HvQQEBAeYPAPbx8ZFbbrlFNm/e7NHSopZvu+02S+sGAADswdYtM4rqMoqJiZFu3bpJ9+7dZd68eVJQUKDPbgIAALB9mLn//vvlp59+khdeeEFOnDghnTt3lvXr10uzZs3EyVRXmbq2zoVdZk5TE46zJhyjwnE6C8+nc/jWgPcgLzUK2OpKAAAAVJatx8wAAABcDmEGAAAYjTADAACMRpgBAABGI8zYTGpqqkRHR+srHqorFq9atUqcJj4+XiIiIqRevXrStGlTGTZsmGRkZIjTLFiwQG6++Wb3harUtZHWrVsnTpaQkKBft5MmTRKnmTVrlj620qVt27biNEePHpUHH3xQXzW9Tp060qlTJ0lLSxMnCQ0Nvei5VGXs2LHiJEVFRTJjxgxp1aqVfi5vvPFGmT17dsXmOjKM7U/NrmnUNXTCw8NlzJgxMnz4cHGizz//XL9pqEDz22+/yZ///Gfp37+//Pvf/5a6deuKU7Ro0UJ/uLdu3Vq/eSxdulSGDh0qe/bskQ4dOojTfPXVV/LOO+/oAOdU6nnbtGmTe9nb21lvoadOnZKePXtKZGSkDt5NmjSRgwcPSoMGDcRpr1X1QV9i//79ctddd8m9994rTpKYmKi/VKn3HvXaVaFUXaNNXVV3woQJ4iTO+p/oAAMHDtTFydR1gkpbsmSJbqFRM6T37t1bnEK1sJX20ksv6TeWnTt3Oi7M5Ofny8iRI2XRokUyZ84ccSoVXsqbSsUpH35qDp/Fixe716lv9U6jQlpp6kuHarXo06ePOMkXX3yhv0ANGjTI3SL1wQcfyK5du8Rp6GaC5XJzc/XPhg0bilOpb4HLly/XLW9OnIpDtbSpN8yoqChxMtVKobqAb7jhBh3ejhw5Ik6yevVqfbV11UKhvmB06dJFB1QnO3funLz33nu6NdykyYgr4vbbb9fT/xw4cEAvf/3117J9+3ZHfmGmZQaWUnNtqfEVqmm7Y8eOjns2vvnmGx1ezp49K9ddd52kpKRI+/btxUlUSNu9e7duuneyHj166FbEsLAwOX78uMTFxUmvXr10F4Ua/+UEP/74o249VNPIqO5f9Zyq7gg1T56aVsaJ1LjE06dPy8MPPyxOM336dD1jthrbpSZtVl+qVAuxCuJOQ5iB5d/o1YeB+rbgROqDb+/evbr16aOPPtIfCGrMkFMCTXZ2tkycOFE2btwofn5+4mSlv82qcUEq3LRs2VJWrFghjzzyiDjly4VqmXn55Zf1smqZUf8/k5OTHRtm/vrXv+rnVrW4Oc2KFSvk/fffl2XLlumubfVepL48qmN12vNJmIFlxo0bJ2vWrNFncKnBsk6kvtHedNNN+nc1A7z6pvvGG2/ogbJOoMY55eTkSNeuXd3r1Lc/9ZzOnz9fCgsL9TdCJ6pfv760adNGMjMzxSkCAwMvCtrt2rWTjz/+WJzo8OHDekD3ypUrxYmmTp2qW2dGjBihl9WZaeqY1RmlhBngd1Jn9owfP153uWzbts2RAwwv9c1XfcA7Rb9+/XRXWmnqbAnVrD1t2jTHBpmSQc8//PCDjBo1SpxCdfdeeJkENd5CtUA5kRrorMYGlQyQdZpff/1VatXyHBqr/k+q9yGnoWXGhm+Qpb/pZWVl6aZBNTg2JCREnNK1pJo9P/nkEz3WQM2GrqjTBdW1EJwiNjZWN1+r5+3MmTP6mFV427BhgziFev4uHOukTq9X1yhx2hioZ599Vp+hpj7Yjx07pmchVh8MDzzwgDjF5MmT9aBR1c1033336bNeFi5cqIvTqA90FWZUC4XTTrEvoV6vaoyMeg9S3UzqshBz587Vg50dR82aDfvYunWruprRRSUmJsblFGUdnyqLFy92OcmYMWNcLVu2dPn4+LiaNGni6tevn+uzzz5zOV2fPn1cEydOdDnN/fff7woMDNTP5/XXX6+XMzMzXU7z6aefujp27Ojy9fV1tW3b1rVw4UKXE23YsEG/72RkZLicKi8vT/9fDAkJcfn5+bluuOEG13PPPecqLCx0OY2X+sfqQAUAAFBZXGcGAAAYjTADAACMRpgBAABGI8wAAACjEWYAAIDRCDMAAMBohBkAAGA0wgwAADAaYQbAVXPo0CHx8vLSU3LYxffffy+33nqrnuW7c+fOFd6vb9++esbhEqGhoTJv3jyjHwvAKQgzgIM9/PDD+gM0ISHBY/2qVav0+ppIzamk5o9SEypu3ry50vejZkB//PHHK3z74OBgOX78uHvOKjVPl3oOTp8+Xek6APj/CDOAw6kWiMTERDl16pQ4xblz5yq9r5rp+o477tATRqoJMSurSZMmcu2111b49mpSyubNmzt2UkPASoQZwOGioqL0h2h8fHy5t5k1a9ZFXS6qC0V1pZRu5Rk2bJieUblZs2ZSv359efHFF+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": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "digit_lengths(TPr)" ] }, { "cell_type": "markdown", "id": "8618e5bc-ea92-4116-aa74-2380fbfd0dc3", "metadata": {}, "source": [ "Finally, for the **palindromic primes**, we find that \"11\" is the only even-digit-length palindromic prime. (It turns out that any even-digit-length palindromic number is [divisible by 11](https://www.geeksforgeeks.org/dsa/g-fact-all-palindromes-with-an-even-number-of-digits-are-divisible-by-11/).) The counts of primes grow so quickly that it is better to use a log scale on the y axis: " ] }, { "cell_type": "code", "execution_count": 18, "id": "ed392e12-7480-4d96-994f-96cdb786f8f9", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{2: 1, 1: 4, 3: 15, 5: 93, 7: 668, 9: 5172, 11: 42042}" ] }, "execution_count": 18, "metadata": {}, "output_type": "execute_result" }, { "data": { "image/png": "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pKfWtGnT4kjYMDAdeyuqBgAqeNXVLbfcEpdcckkRdDZu3BhvvPFGveNIYMNAAMhfg0Z0pk6dGtOnT4+rr7666VsEAFDKEZ0dO3bEhRde2FRtAAAon6DzxS9+Me69996mbw0AQKmnrt5+++2466674vHHH4/zzjuv2EPnnSZNmtRU7QMAOLxB54UXXohevXoVj1988cV6z6XNBAEAjtigM3fu3KZvCQBAOdToAABkO6IzcODA/U5RPfHEE41pEwBA6YJObX1OrZ07d8bSpUuLep133+wTAOCICjrf//7393r9W9/6VmzdurWxbQIAKL8anc9//vNHxH2uAIDK0KRBZ/78+dG6des4EqQbevbo0SP69u1b6qYAAOU0dXXllVfWO6+pqYnXXnstFi1aFDfffHMcKTf1TMfmzZujbdu2pW4OAFAuQefdwaBZs2bRvXv3+Pa3v13c1RwA4IgNOvfcc0/TtwQAoByCTq3FixfHSy+9VDw+++yz4/zzz2+qdgEAlCborF+/Pj772c/Gz3/+8zj++OOLa2+++WaxkeB9990X73//+xvfMgCAUqy6+spXvhJbtmyJX/3qV/G73/2uONJmgamw9/rrr29smwAASjeiM3v27Hj88cfjrLPOqruWlmqnJduKkQGAI3pEp7q6Oo466qg9rqdr6TkAgCM26Hz84x+PUaNGxZo1a+quvfrqq/G1r30tLr744qZsHwDA4Q06P/zhD4t6nG7dusVpp51WHKeeempx7c4772x4awAASl2j06VLl1iyZElRp7N8+fLiWqrXGTRoUFO2DQDg8I3oPPHEE0XRcRq5qaqqik984hPFCqx0pHtGpb10nnzyyca1CACgFEFn8uTJcd1110WbNm32eluIL3/5yzFp0qSmahsAwOELOs8//3z8wR/8wT6fT0vL027JAABHXNBZt27dXpeV12rRokVs2LChKdoFAHB4g87JJ59c7IC8Ly+88EKcdNJJcTitXr06LrrooqJ26Lzzzov777//sH5/ACCToPPJT34ybr755nj77bf3eO5///d/Y/z48XHZZZfF4ZRGkVLt0LJly+LRRx+Nr371q7Ft27bD2gYAIIPl5d/85jfjJz/5SZxxxhkxcuTI6N69e3E9LTFPt3/YvXt33HTTTXE4pRGk2lGkjh07Rvv27Yt7bx177LGHtR0AwBE+otOhQ4f4z//8zzjnnHNi7NixccUVVxTHN77xjeLaU089VbzmYMybNy+GDh0anTp1Kpasz5w5c4/XpBCVNids3bp19O/fPxYsWLDX90qF0ClspX1+AAAOemfkU045Jf7jP/4jNm7cGM8++2w888wzxeN0Le2OfLDSNFPPnj2LMLM3M2bMiNGjRxfTYmmTwvTawYMHx/r16+u9Lo3ifOELX4i77rrLf1UAoOE7IycnnHBCsUlgYw0ZMqQ49iXty5P27hk+fHhxPnXq1Jg1a1ZMmzYtxowZU1zbvn17XH755cX5hRdeuN/vl16bjlpp80MAIE8NutfV4bJjx45iOuqdt5Zo1qxZcT5//vzivKamJq655priRqNXX331e77nhAkTis0Naw/TXACQr7IOOmlKLNXcvLvuJ52vXbu2ePz0008X01uptqdXr17F8ctf/nKf75lqizZt2lR3pOXpAECeGjx1VS4+/OEPR3V19QG/vlWrVsUBlazbmFlRDlZNvLTUTQAyV9YjOmmpePPmzYsdmd8pnael5I2Rip/TJoNNUWcEAJSnsg46LVu2jN69e8ecOXPqrqXRm3Q+YMCARr33iBEjik0GFy5c2AQtBQDKUcmnrrZu3RorVqyoO1+5cmUsXbo02rVrF127di2Wlg8bNiz69OkT/fr1K3ZBTkvSa1dhAQCUbdBZtGhRDBw4sO48BZskhZvp06fHVVddVdwodNy4cUUBcio2nj179kFvTAgAVJ6SB510Q860RHx/0u0m0tGUUo1O7W0rAIA8lXWNzqGkRgcA8lexQQcAyJ+gAwBkq2KDjn10ACB/FRt01OgAQP4qNugAAPkTdACAbAk6AEC2KjboKEYGgPxVbNBRjAwA+avYoAMA5E/QAQCyJegAANmq2KCjGBkA8lexQUcxMgDkr2KDDgCQP0EHAMiWoAMAZEvQAQCyJegAANkSdACAbFVs0LGPDgDkr2KDjn10ACB/FRt0AID8CToAQLYEHQAgW4IOAJAtQQcAyJagAwBkS9ABALJVsUHHhoEAkL+KDTo2DASA/FVs0AEA8ifoAADZEnQAgGwJOgBAtgQdACBbgg4AkC1BBwDIlqADAGRL0AEAsiXoAADZqtig415XAJC/ig067nUFAPmr2KADAORP0AEAsiXoAADZEnQAgGwJOgBAtgQdACBbgg4AkK0WpW4AHKhuY2aVvLNWTby01E0A4CAY0QEAsiXoAADZEnQAgGwJOgBAtgQdACBbgg4AkC1BBwDIVhZB54orrogTTjgh/viP/7jUTQEAykgWQWfUqFHxT//0T6VuBgBQZrIIOhdddFEcd9xxpW4GAFBmSh505s2bF0OHDo1OnTpFVVVVzJw5c4/XTJkyJbp16xatW7eO/v37x4IFC0rSVgDgyFLyoLNt27bo2bNnEWb2ZsaMGTF69OgYP358LFmypHjt4MGDY/369Q36ftu3b4/NmzfXOwCAPJU86AwZMiRuvfXWoqB4byZNmhTXXXddDB8+PHr06BFTp06NY445JqZNm9ag7zdhwoRo27Zt3dGlS5dGfgIAoFyVPOjsz44dO2Lx4sUxaNCgumvNmjUrzufPn9+g9xw7dmxs2rSp7li9enUTthgAKCctooxt3Lgxdu/eHR06dKh3PZ0vX7687jwFn+eff76YBuvcuXPcf//9MWDAgL2+Z6tWrYoDAMhfWQedA/X444+XugkAQBkq66mr9u3bR/PmzWPdunX1rqfzjh07Nuq9U/Fzqvnp27dvI1sJAJSrsg46LVu2jN69e8ecOXPqrlVXVxfn+5qaOlAjRoyIZcuWxcKFC5ugpQBAOSr51NXWrVtjxYoVdecrV66MpUuXRrt27aJr167F0vJhw4ZFnz59ol+/fjF58uSiFietwgIAKOugs2jRohg4cGDdeQo2SQo306dPj6uuuio2bNgQ48aNi7Vr10avXr1i9uzZexQoN2TqKh2p2BkAyFOLcrh9Q01NzX5fM3LkyOJoSmnqKh1pw8C0nw4AkJ+yrtEBAGgMQQcAyJagAwBkq2KDjn10ACB/FRt07KMDAPmr2KADAORP0AEAslWxQUeNDgDkr2KDjhodAMhfxQYdACB/gg4AkC1BBwDIlqADAGSrYoOOVVcAkL+KDTpWXQFA/io26AAA+RN0AIBsCToAQLYEHQAgW4IOAJCtFlHBy8vTsXv37kP2PbqNmRXlYNXES0vdBAAoiYod0bG8HADyV7FBBwDIn6ADAGRL0AEAsiXoAADZEnQAgGwJOgBAtgQdACBbFRt00maBPXr0iL59+5a6KQDAIVKxQceGgQCQv4oNOgBA/gQdACBbgg4AkC1BBwDIlqADAGRL0AEAsiXoAADZEnQAgGwJOgBAtgQdACBbgg4AkK2KDTpu6gkA+avYoOOmngCQv4oNOgBA/gQdACBbgg4AkC1BBwDIlqADAGRL0AEAsiXoAADZEnQAgGwJOgBAtgQdACBbgg4AkC1BBwDIlqADAGRL0AEAsiXoAADZyiLoPPzww9G9e/c4/fTT4+///u9L3RwAoEy0iCPcrl27YvTo0TF37txo27Zt9O7dO6644oo48cQTS900AKDEjvgRnQULFsTZZ58dJ598crzvfe+LIUOGxKOPPlrqZgEAZaDkQWfevHkxdOjQ6NSpU1RVVcXMmTP3eM2UKVOiW7du0bp16+jfv38RbmqtWbOmCDm10uNXX331sLUfAChfJQ8627Zti549exZhZm9mzJhRTE2NHz8+lixZUrx28ODBsX79+gZ9v+3bt8fmzZvrHQBAnkpeo5OmmtKxL5MmTYrrrrsuhg8fXpxPnTo1Zs2aFdOmTYsxY8YUI0HvHMFJj/v167fP95swYULccsstTfwpjmzdxswqdRNi1cRLS90EADJU8hGd/dmxY0csXrw4Bg0aVHetWbNmxfn8+fOL8xRqXnzxxSLgbN26NR555JFixGdfxo4dG5s2bao7Vq9efVg+CwBQgSM6+7Nx48bYvXt3dOjQod71dL58+fLicYsWLeKOO+6IgQMHRnV1dfzFX/zFfldctWrVqjgAgPyVddA5UJ/61KeK42CkmqB0pCAFAOSprKeu2rdvH82bN49169bVu57OO3bs2Kj3HjFiRCxbtiwWLlzYyFYCAOWqrINOy5Ytiw0A58yZU3ctTU+l8wEDBpS0bQBA+Sv51FUqIF6xYkXd+cqVK2Pp0qXRrl276Nq1a7G0fNiwYdGnT5+i8Hjy5MnFkvTaVVgAAGUbdBYtWlQUEtdKwSZJ4Wb69Olx1VVXxYYNG2LcuHGxdu3a6NWrV8yePXuPAuWDpUYHAPJX8qBz0UUXRU1NzX5fM3LkyOJoSqlGJx1pw8B0jywAID9lXaMDANAYgg4AkK2KDTqpRqdHjx7Rt2/fUjcFADhEKjbo2EcHAPJXsUEHAMifoAMAZEvQAQCyVfJ9dEqldsPAXbt2FedpP52mVr39rSgH7/XZyqGdB9L/R0o7jwTl0JeJ/tSX7+ZnM7/+3HyI/t6sfd/32ouvqua9XpG53/72t9GlS5dSNwMAaIDVq1dH586d9/l8xQeddJPQNWvWxHHHHRdVVVUN6eOKl1J1Covph61NmzYV3x+NoS+blv7Ul+XKz2bjpXGaLVu2RKdOnaJZs31X4lTs1FWt1Dn7S4IcuBRyBJ2moS+blv7Ul+XKz2bjHMgtnBQjAwDZEnQAgGwJOjRaq1atYvz48cWf6Mty4mdTX5YrP5uHT8UXIwMA+TKiAwBkS9ABALIl6AAA2RJ0AIBsCTo0yIQJE6Jv377FjtK/93u/F5dffnm8/PLLerMJTJw4sdil+6tf/ar+bKBXX301Pv/5z8eJJ54YRx99dJx77rmxaNEi/dkAu3fvjptvvjlOPfXUoi9PO+20+M53vvOe9xciYt68eTF06NBi5970//TMmTPrdUvqw3HjxsVJJ51U9O2gQYPilVde0XVNTNChQX7xi1/EiBEj4plnnonHHnssdu7cGZdcckls27ZNjzbCwoUL4+/+7u/ivPPO048N9MYbb8SHPvShOOqoo+KRRx6JZcuWxR133BEnnHCCPm2A22+/Pf72b/82fvjDH8ZLL71UnH/3u9+NO++8U3++h/T3Yc+ePYsbSO9N6scf/OAHMXXq1Hj22Wfj2GOPjcGDB8fbb7+tb5uQ5eU0iQ0bNhQjOykAffSjH9WrDbB169b44Ac/GD/60Y/i1ltvjV69esXkyZP15UEaM2ZMPP300/Hkk0/quyZw2WWXRYcOHeIf/uEf6q790R/9UTEC8c///M/6+AClEZ0HHnigGP2uHc1JIz1f//rX44Ybbiiubdq0qejr6dOnx2c/+1l920SM6NAk0v+gSbt27fRoA6URsksvvbQYvqbhHnrooejTp098+tOfLsL3+eefH3fffbcubaALL7ww5syZE7/+9a+L8+effz6eeuqpGDJkiD5thJUrV8batWvr/f+e7tvUv3//mD9/vr5tQhV/U0+a5g7wqZ4kTRecc845urQB7rvvvliyZEkxdUXj/Pd//3cx1TJ69Oj4xje+UfTp9ddfHy1btoxhw4bp3gaMkKU7bZ955pnRvHnzombntttui8997nP6shFSyEnSCM47pfPa52gagg5NMhLx4osvFv/K4+CtXr06Ro0aVdQ6tW7dWhc2QfBOIzp/9Vd/VZynEZ3085nqIASdg/fjH/84/uVf/iXuvffeOPvss2Pp0qXFP2zStIv+5Ehg6opGGTlyZDz88MMxd+7c6Ny5s95sgMWLF8f69euL+pwWLVoUR6p1SkWK6XH6FzQHLq1g6dGjR71rZ511VvzmN7/RjQ1w4403FqM6qWYkrV67+uqr42tf+1qx8pKG69ixY/HnunXr6l1P57XP0TQEHRokFdKlkJOK65544oli6SkNc/HFF8cvf/nL4l/KtUcakUhTA+lxmi7gwKUp1HdvdZDqS0455RTd2ABvvfVWNGtW/1dF+plMI2c0XPo7MwWaVP9UK00RptVXAwYM0LVNyNQVDZ6uSkPZDz74YLGXTu2cciqmS6sxOHCp/95d25SWmaY9YNQ8Hbw02pAKaNPU1Wc+85lYsGBB3HXXXcXBwUv7wKSanK5duxZTV88991xMmjQprr32Wt15ACspV6xYUa8AOf3jJS3aSP2ZpgDTCsvTTz+9CD5pv6I0JVi7MosmUgMNkH509nbcc889+rMJfOxjH6sZNWqUvmygn/70pzXnnHNOTatWrWrOPPPMmrvuuktfNtDmzZuLn8WuXbvWtG7duuYDH/hAzU033VSzfft2ffoe5s6du9e/J4cNG1Y8X11dXXPzzTfXdOjQofhZvfjii2tefvll/drE7KMDAGRLjQ4AkC1BBwDIlqADAGRL0AEAsiXoAADZEnQAgGwJOgBAtgQdACBbgg5QMqtWrYqqqqpiW/xysXz58rjggguKO8n36tXrgL/uoosuKrb0r9WtW7eYPHnyEd0XkANBByrYNddcU/xynThxYr3rM2fOLK5XovHjxxf3Gks3Bn3nDRcP1sKFC+NLX/rSAb++S5cu8dprr9Xd3+znP/958d/gzTffbHAbAEEHKl4aubj99tvjjTfeyKYvduzY0eCv/a//+q/48Ic/XNztPN1YtaHe//73xzHHHHPAr093BE93s27Rwr2WoSkZ0YEKN2jQoOIX7IQJE/b5mm9961t7TOOkaZk0PfPO0aF01+V01/AOHTrE8ccfH9/+9rdj165dceONNxZ3bO7cuXPcc889e50uSnccT6ErjWj84he/qPf8iy++GEOGDIn3ve99xXtfffXVsXHjxnrTRiNHjiymjtq3bx+DBw/e6+eorq4u2pTa0apVq+IzzZ49u+75NIKyePHi4jXpcfrce7Nt27b4whe+ULTnpJNOijvuuGOP17x76ip9xhSg0mfs0aNHPP7448X3SKNn7566So8HDhxYXD/hhBOK66l/k3/7t3+Lc889N44++ugiiKX/fqk9wN4JOlDh0khCCid33nln/Pa3v23Uez3xxBOxZs2amDdvXkyaNKmYBrrsssuKX9bPPvts/Nmf/Vl8+ctf3uP7pCD09a9/PZ577rkYMGBADB06NF5//fXiuTR18/GPfzzOP//8WLRoURFM1q1bF5/5zGfqvcc//uM/RsuWLePpp5+OqVOn7rV9f/M3f1OEku9973vxwgsvFIHoU5/6VLzyyivF82nq6Oyzzy7akh7fcMMNe32f1N4Uxh588MF49NFHi2mmJUuW7LNfdu/eXYTANMKT+uGuu+6Km266ab/TWP/+7/9ePE5TaKktqe3pzz/5kz+Ja6+9Nl566aXi+1555ZVRU5Nuig3sVVPfDh04cgwbNqzmD//wD4vHF1xwQc21115bPH7ggQfSb866140fP76mZ8+e9b72+9//fs0pp5xS773S+e7du+uude/eveYjH/lI3fmuXbtqjj322Jp//dd/Lc5XrlxZfJ+JEyfWvWbnzp01nTt3rrn99tuL8+985zs1l1xySb3vvXr16uLrXn755eL8Yx/7WM3555//np+3U6dONbfddlu9a3379q358z//87rz9DnT592XLVu21LRs2bLmxz/+cd21119/veboo4+uGTVqVN211Bepj5JHHnmkpkWLFjWvvfZa3fOPPfZY8RlSX7+zL5577rnifO7cucX5G2+8Ufc1ixcvLq6tWrXqPT8r8H+M6ACFVKeTRkXSSEFDpdGQZs3+/18raZopTbO8c/QoTbesX7++3telUZxaqUalT58+de14/vnnY+7cucU0Ue1x5pln1tXT1Ordu/d+27Z58+ZitOlDH/pQvevp/GA+c/qeqQaof//+ddfStFz37t33+TVpVCaN0qQpwlr9+vWLg9WzZ8+4+OKLiz799Kc/HXfffXdWtVVwKAg6QOGjH/1oMZUzduzYPf+iaNZsj+mRnTt37vG6o446qt55qi3Z27VUK3Ogtm7dWkxlpdqVdx5puim1uVZaKZW7FBQfe+yxeOSRR4o6nzTdmALWypUrS900KFuCDlAnLTP/6U9/GvPnz99jBdHatWvrhZ2m3O/lmWeeqXucipdTQfBZZ51VnH/wgx+MX/3qV0Vx7+///u/XOw4m3LRp0yY6depU1PC8UzpPoeFAnXbaaUV4S7U2tdKoyq9//et9fk0KI6tXry5qi965/Hx/Ur1RbX3Pu4NiGoW65ZZbipqm9LoHHnjggNsPlUbQAeqkKZHPfe5z8YMf/KBer6RVTRs2bIjvfve7xdTNlClTilGFppLeL/2yTiuTRowYUQSHVHCbpPPf/e53RRFuCgfp+//sZz+L4cOH7xEC3ksqIk5TdDNmzCimk8aMGVMEtlGjRh3we6Spsz/90z8t3isVX6cVYWlF1Dun7N7tE5/4RBGQhg0bVhRBp3D1zW9+s3huX/sVpeXt6bmHH3646Ps0spXCVSocT0XZv/nNb+InP/lJ8VxtKAT2JOgA9aSl1e+eWkq/SH/0ox8VgSTViSxYsGCfK5IaOpKUjvTeTz31VDz00EPFMvGkdhQmhZpLLrmkCGNpGXlavr6/cLE3119/fYwePbpYVZXeJ63gSt/r9NNPP6j3+eu//uv4yEc+UkyppeXdadn4/mqE0pRTWkaewkrfvn3ji1/8Yt2qq7TcfG9OPvnkYtQmhbFU65SWz6dRqbSi7ZOf/GScccYZRVhKq8jS0ntg76pSRfI+ngPgEEnhLQWkFStWFKM9wKEh6AAcBmlqLk17pdGjFG7SdFnaXyiNYAGHjr3GAQ6DLVu2xF/+5V8WtTVpWi5Nee1tR2WgaRnRAQCypRgZAMiWoAMAZEvQAQCyJegAANkSdACAbAk6AEC2BB0AIFuCDgAQufp/J8tcqtiNRx8AAAAASUVORK5CYII=", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "plt.yscale('log')\n", "digit_lengths(PP)" ] }, { "cell_type": "markdown", "id": "f2323985-2518-41d1-8a3b-6e21e40d27be", "metadata": {}, "source": [ "# Summary \n", "\n", "Here's what we learned:\n", "\n", "- Left-trunctable primes:\n", " - Count: 4260\n", " - Largest: 357686312646216567629137 (24 digits)\n", " - The plurality have 9 digits; only 13 have more than 20 digits\n", "- Right-truncatable primes:\n", " - Count: 83\n", " - Largest: 73939133 (8 digits)\n", " - The plurality have 4 digits\n", "- Two-sided truncatable primes:\n", " - Count: 15\n", " - Largest: 739397 (6 digits)\n", "- Omni-truncatable primes:\n", " - Count: 9\n", " - Largest: 373\n", "- Palindromic truncatable primes:\n", " - Count: 13\n", " - Largest: 799636997 (9 digits)\n", "- Palindromic primes:\n", " - Count: probably infinite; 47995 of them up to 11 digits\n", " - All except \"11\" have an odd number of digits\n", "\n", "\n", "# Primality Testing\n", "\n", "I was very impressed with the speed of the function [`sympy.isprime`](https://github.com/sympy/sympy/blob/master/sympy/ntheory/primetest.py), and I wanted to investigate the topic of primality testing. I'll start by defining `isprime_simple`, which follows the definition of a prime number almost verbatim:" ] }, { "cell_type": "code", "execution_count": 19, "id": "1d460931-3d70-485d-807f-8fb360ef4ef2", "metadata": {}, "outputs": [], "source": [ "def isprime_simple(n: int) -> bool:\n", " \"\"\"Simple primality tester. 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)" ] }, { "cell_type": "markdown", "id": "1834f8f0-3712-4302-ac56-79972f85d0db", "metadata": {}, "source": [ "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 speed things up a bit with two ideas, one small and one bigger. The small idea is to cut the run time in half by only testing the odd divisors (after determining that 2 is a prime and all other even numbers are composite). The bigger idea is that we only need to test 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." ] }, { "cell_type": "code", "execution_count": 20, "id": "647fb66b-32ae-494a-8945-cf7358c2f958", "metadata": {}, "outputs": [], "source": [ "from math import sqrt\n", "\n", "def isprime_faster(n: int) -> bool:\n", " \"\"\"More sophisticated primality tester: test only odd divisors up to √n.\"\"\"\n", " if n <= 10: # Handle small numbers up to 10\n", " return n in (2, 3, 5, 7)\n", " elif n % 2 == 0: # Even numbers other than 2 are composite\n", " return False\n", " else: # test 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": "markdown", "id": "05b8cbf7-ea10-4047-bcdb-a5ac7981384b", "metadata": {}, "source": [ "For a 24-digit prime, `isprime_simple` would need to test septillions of divisors, while `isprime_faster` would \"only\" need to test trillions. That's the difference between never completing versus taking a few hours. But we would like to get the time down from hours to milliseconds. We need a massive breakthrough. \n", "\n", "# Probabilistic Primality Testing\n", "\n", "**Fortunately**, [Pierre de Fermat](https://en.wikipedia.org/wiki/Pierre_de_Fermat) provided the big breakthrough in 1640! \n", "\n", "[Fermat's little theorem](https://en.wikipedia.org/wiki/Fermat%27s_little_theorem) states that if *n* is prime and *a* is not divisible by *n*, then:\n", "\n", "        *a*(*n* - 1) ≡ 1 (mod *n*). \n", "\n", "We can use the theorem to create a [Fermat primality test](https://en.wikipedia.org/wiki/Fermat_primality_test): given an integer *n*, choose a random *a* and test 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 not. 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. \n", "For example:\n", "\n", "\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|*try again with new **a** value: 221 is definitely composite*|\n", "|5|2|1|*5 could be prime or composite*|\n", "|5|3|1|*try again: 5 could still be prime or composite*|\n", "|5|4|1|*try again: 5 could still be prime or composite, but a lot of evidence that it is prime*|\n", "\n", "\n", "This is called a [Monte Carlo algorithm](https://en.wikipedia.org/wiki/Monte_Carlo_algorithm); an algorithm that uses [randomization](https://en.wikipedia.org/wiki/Randomized_algorithm), and can sometimes be wrong. Here is a simple implementation:" ] }, { "cell_type": "code", "execution_count": 21, "id": "c8a59c5e-a01c-49be-a931-c1547c4ac712", "metadata": {}, "outputs": [], "source": [ "def isprime_fermat(n: int, k=20) -> bool:\n", " \"\"\"If isprime_fermat(n) is False then n is definitely composite; if True then n is probably prime.\n", " Increase `k` to decrease the probability of false primes.\"\"\"\n", " if n <= 10:\n", " return n in (2, 3, 5, 7)\n", " else:\n", " return all(pow(a, n - 1, n) == 1 for a in sample(2, n, k))" ] }, { "cell_type": "markdown", "id": "6746894c-00e7-41df-b4a3-d5c85862cc94", "metadata": {}, "source": [ "(*Note* that `pow(a, n - 1, n)` computes *a*(*n* - 1) (mod *n*) very efficiently; see the last section of this notebook.)\n", "\n", "We need a way to sample *k* random integers from a range, one at a time:" ] }, { "cell_type": "code", "execution_count": 22, "id": "476282dd-a48a-4eb5-8fed-8495d4878ec2", "metadata": {}, "outputs": [], "source": [ "import random\n", "from typing import Iterable\n", " \n", "def sample(start: int, stop: int, k: int) -> Iterable[int]:\n", " \"\"\"Randomly sample `k` integers from range(start, stop), one by one.\"\"\"\n", " return (random.randrange(start, stop) for _ in range(k))" ] }, { "cell_type": "markdown", "id": "15ef6884-253d-4a3a-b58f-397ac73f552d", "metadata": {}, "source": [ "**Unfortunately**, `isprime_fermat` can lie: it can incorrectly report a **false prime** for a composite number *n*. \n", "\n", "How common are these false primes? Here's a function to test a sample of numbers and report the the percentage of false primes when `isprime_fermat` is allowed `k` choices of the `a` parameter:" ] }, { "cell_type": "code", "execution_count": 23, "id": "45a11a93-9ef3-48d1-80fa-e0113041346e", "metadata": {}, "outputs": [], "source": [ "from statistics import mean\n", "\n", "def false_prime_percent(samples: Iterable[int], k: int) -> float:\n", " \"\"\"The percentage of false primes from isprime_fermat(n, k) for n across the samples.\"\"\"\n", " composites = (n for n in samples if not isprime(n))\n", " return mean(100 * isprime_fermat(n, k) for n in composites)" ] }, { "cell_type": "markdown", "id": "778c3a9b-dcc7-4ad2-9092-d66aecd1d93c", "metadata": {}, "source": [ "We'll choose sample ranges that represent digit-lengths, sample 200,000 times for each digit-length, and for now look at `k=1` values of *a*:" ] }, { "cell_type": "code", "execution_count": 24, "id": "9eba96df-c298-4d71-b68a-3bf36bf15095", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{3: 1.408066267526657,\n", " 4: 0.4848670443525749,\n", " 5: 0.1327436065501534,\n", " 6: 0.03568377685744872,\n", " 7: 0.011224724326115657,\n", " 8: 0.0015893702914905115,\n", " 9: 0,\n", " 10: 0,\n", " 11: 0,\n", " 12: 0}" ] }, "execution_count": 24, "metadata": {}, "output_type": "execute_result" } ], "source": [ "{d: false_prime_percent(sample(10**(d-1), 10**d, 200_000), 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.4% of the time, and 4-digit comnposites about 0.5%, but once we get to 9- or 10-digit composites, false primes are very rare indeed. Remember these are percents, not probabilities, so 0.001% is one in a hundred thousand.\n", "\n", "Let's see how we reduce false primes by allowing `k=25` choices of `a`:" ] }, { "cell_type": "code", "execution_count": 25, "id": "8880c588-32f5-46e8-b59c-f9b49d492d3b", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{3: 0,\n", " 4: 0,\n", " 5: 0.00036752274965820385,\n", " 6: 0.0007220216606498195,\n", " 7: 0,\n", " 8: 0,\n", " 9: 0,\n", " 10: 0,\n", " 11: 0,\n", " 12: 0}" ] }, "execution_count": 25, "metadata": {}, "output_type": "execute_result" } ], "source": [ "{d: false_prime_percent(sample(10**(d-1), 10**d, 300_000), k=25) for d in range(3, 13)}" ] }, { "cell_type": "markdown", "id": "61ee44c3-f963-4fb1-ac20-4a27adc90f83", "metadata": {}, "source": [ "The results are randomized, and in some runs this produces no false primes; in some runs a few get through. \n", "\n", "The so-called [**Carmichael numbers**](https://en.wikipedia.org/wiki/Carmichael_number) are composite numbers with a very high false prime percentage. [Some Carmichael numbers](https://oeis.org/A033502) are worse than others. \n", "\n", "We can test some of them:" ] }, { "cell_type": "code", "execution_count": 26, "id": "7871aaa7-af1c-462b-85bb-d46818ccabea", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{561: 57.14,\n", " 1105: 69.55,\n", " 1729: 74.87,\n", " 2465: 72.6,\n", " 2821: 76.78,\n", " 6601: 80.01,\n", " 8911: 79.49,\n", " 41041: 70.78,\n", " 101101: 71.57,\n", " 294409: 95.12,\n", " 340561: 82.24,\n", " 825265: 60.79,\n", " 56052361: 99.04,\n", " 118901521: 99.29,\n", " 172947529: 99.32,\n", " 216821881: 99.31,\n", " 1299963601: 99.58,\n", " 2301745249: 99.88,\n", " 9624742921: 99.8}" ] }, "execution_count": 26, "metadata": {}, "output_type": "execute_result" } ], "source": [ "carmichael_numbers = (561, 1105, 1729, 2465, 2821, 6601, 8911, 41041, 101101, 294409, 340561, 825265, \n", " 56052361, 118901521, 172947529, 216821881, 1299963601, 2301745249, 9624742921)\n", "\n", "{n: false_prime_percent([n] * 10_000, k=1) for n in carmichael_numbers}" ] }, { "cell_type": "markdown", "id": "4ecd2289-66d5-4b0f-ac00-5db0ad92dde9", "metadata": {}, "source": [ "This is bad; some error rates are above 99%. Increasing `k` can fix the numbers with a 60% or 70% error rate, but not the ones with a 99% error rate. Below we increase `k` to 50, and some Carmichael numbers still claim to be prime most of the time:" ] }, { "cell_type": "code", "execution_count": 27, "id": "de492047-77b6-46a3-8a77-46308f219efd", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{561: 0,\n", " 1105: 0,\n", " 1729: 0,\n", " 2465: 0,\n", " 2821: 0,\n", " 6601: 0,\n", " 8911: 0,\n", " 41041: 0,\n", " 101101: 0,\n", " 294409: 9,\n", " 340561: 0,\n", " 825265: 0,\n", " 56052361: 61,\n", " 118901521: 64,\n", " 172947529: 80,\n", " 216821881: 77,\n", " 1299963601: 85,\n", " 2301745249: 85,\n", " 9624742921: 96}" ] }, "execution_count": 27, "metadata": {}, "output_type": "execute_result" } ], "source": [ "{n: false_prime_percent([n] * 100, k=50) for n in carmichael_numbers}" ] }, { "cell_type": "markdown", "id": "bfd71dc7-7f6d-4c98-9886-5c242d9b297a", "metadata": {}, "source": [ "So our Fermat test is mostly reliable, but a few composite numbers will consistently be identified as false primes.\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 testing\n", "\n", "**The great thing** about `isprime_fermat` and `sympy.isprime` is that they are **very fast**, handling even 32-digit primes in well under a millisecond. Let's create a list of big primes in ascending order of digit-length from 5 to 32:" ] }, { "cell_type": "code", "execution_count": 28, "id": "be5f2fe7-b1e0-4a02-b7f0-7903e865c4b8", "metadata": {}, "outputs": [], "source": [ "big_primes = [*[int('357686312646216567629137'[-i:]) for i in range(5, 25)], # left-truncated primes\n", " # The following primes sourced from t5k.org/curios/\n", " 1000000000000000035000061, 59999999999899999999999999, 100000109999990000011000001,\n", " 2728487949505050529272727777, 24444666666888888889999999991, 100003100019100043100057100069,\n", " 9999999999999999777777775555331, 55555555555555555555555555555559]" ] }, { "cell_type": "markdown", "id": "6b2cbdc7-e8a9-4b83-aa0d-1e7cc83de071", "metadata": {}, "source": [ "Now let's make a chart of all the primality checking functions running on the big primes:" ] }, { "cell_type": "code", "execution_count": 29, "id": "8109d9fc-bbae-4ef0-a75c-908d9746a557", "metadata": {}, "outputs": [], "source": [ "import timeit\n", "\n", "prime_tests = (isprime_simple, isprime_faster, isprime_fermat, isprime)\n", "\n", "def plot_run_times(primes, functions=prime_tests):\n", " \"\"\"For each primality-testing 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 = (1 if function == isprime_simple else 200)\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 # Stop tsting a function once it takes over a second of run time\n", " elif time > 1e-3:\n", " repeat = 1\n", " return D, T" ] }, { "cell_type": "code", "execution_count": 30, "id": "b1ab0f3d-6ce6-4b8c-9d4d-bb78bb1ac432", "metadata": {}, "outputs": [ { "data": { "image/png": "iVBORw0KGgoAAAANSUhEUgAAAwwAAAINCAYAAACTVPhqAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjgsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvwVt1zgAAAAlwSFlzAAAPYQAAD2EBqD+naQAAvs5JREFUeJzs3Qd8U1X7B/BfunfphpayUdkbBERkCcgQRMHJcL/iK0MF9VXcDEUEFf+4cOBEFBVkgzJkT0Fk70JbCnTvJP/Pc9KUtnQkbdKs39fPNTfJzc3JTVvuc89znqPR6/V6EBERERERlcKttAeJiIiIiIgYMBARERERUbnYw0BERERERGViwEBERERERGViwEBERERERGViwEBERERERGViwEBERERERGViwEBERERERGXyKPspEjqdDufPn0dgYCA0Gg0PChERERE5PJm7OS0tDdHR0XBzK78PgQFDGebOnauW3NxcHD9+3BrfExERERGRTZ09exa1a9cudxuNXsILKlNKSgpq1KihDmZQUBCPFBERERE5vNTUVMTGxiI5ORnBwcHlbssehgoY05AkWGDAQERERETOxJSUew56JiIiIiKiMjFgICIiIiKiMjFgICIiIiKiMnEMAxEREZENSN2Z/Px8aLVaHn+yCk9PT7i7u1d5PwwYiIiIiKqZlG2/cOECMjMzeezJqgOapWRqQEBAlfbDgKGCeRgY9RMREZGlJ4U9efKkuvIrk2Z5eXlxcliySg/WxYsXce7cOTRu3LhKPQ2ch8GEGrVSm1bmY2BZVSIiIqqq7OxsFTDUrVsXfn5+PKBkNVlZWTh16hTq168PHx+fSp/jctAzERERkQ24ufE0jGw/x4Ip+JNKRERERERlYsBARERERERlYsBARERE5KC0Oj22HL+EX/fGqVu5b0233HILxo8fb7X9S769pNHs3bsX9uhUNbavXr16mD17NuwBqyQREREROaAVBy7g1SUHcSElu/CxWsE+eHlQU/RrXssq7/nzzz+r2v7WEhsbq8rNhoeHwx7F2nn7rIU9DEREREQOGCz85+vdxYIFEZ+SrR6X560hNDQUgYGBVpubQkp/1qxZEx4e9nlN293O22ctDBjI4VR39ysREVF11MzPzM03aUnLzsPLv/2D0v71Mz72ym8H1Xam7E/euzIpSR9++KGq7y/lOqOionDnnXcW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", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "plot_run_times(big_primes)" ] }, { "cell_type": "markdown", "id": "159833b0-afaf-486f-9c8e-1c8d2a11d9bf", "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`\n", " - (but that's quite good for `isprime_fermat` considering how much simpler it is: 10 lines versus 800)\n", "- `isprime` produces no known incorrect answers; `isprime_fermat` will on rare occasion produce a false prime" ] }, { "cell_type": "markdown", "id": "4c76de9d-4803-4db5-b6c5-811a6a1c6da1", "metadata": {}, "source": [ "It is good to get the timing results, but I should also run some test cases to demonstrate correctness:" ] }, { "cell_type": "code", "execution_count": 31, "id": "4f377075-e352-46f9-a716-f1de673a7086", "metadata": {}, "outputs": [], "source": [ "for fn in prime_tests:\n", " assert all(fn(p) for p in (2, 3, 5, 7, 11, 37, 73, 101, 11939, 65537, 117223, 7629137)) # primes\n", " assert all(fn(n) is False for n in (0, 1, 4, 6, 8, 9, 10, 256, 11939*11939, 11939*65537)) # composites" ] }, { "cell_type": "markdown", "id": "1347399a-24f2-4d5f-aa7f-822951126bf5", "metadata": {}, "source": [ "This was fun for me! I remember being amazed by Fermat's Little Theorem when I learned about it in [Prof. Michael Rosen's](https://mathematics.brown.edu/people/michael-rosen) number theory class in college, but I never worked through the details of how often the test gives a false prime result until now. \n", "\n", "That number theory class was important for me in several ways. First, it was hard fun. Second, it was the first class that felt like actually *doing* math, rather than being taught some techniques to prepare you to do math some time in the future. And third, I learned a valuable lesson: there was a take-home final exam, handed out Friday and due Monday. I worked on it all day Saturday, and couldn't answer a single one of the ten problems. At that point, I thought to myself \"This never happens on my computer science assignments; I guess I'm more cut out for CS than math.\" On Sunday I came back to it and eventually got answers to most of the problems. (I remember that on one problem, Prof. Rosen said \"You had a very elegant solution for that one, better than the answer I expected. But then I realized it was so good, it could be extended to be a trivial solution to this known difficult problem, and so I looked more closely and noticed a flaw in your argument. Too bad.\")\n", "\n", "# Note on Modular Exponentiation\n", "\n", "Just one more thing: none of this would work unless we can efficiently compute *a*(*n* - 1) (mod *n*). How does the `pow` builtin function do it? When *a* and *n* are 24-digit numbers, if we naively tried to compute `a ** (n - 1)`, we'd have two problems: we'd need nearly a billion petabytes to store the result, and we'd need centuries to compute it. The way around these problems is to use [modular exponentiation](https://en.wikipedia.org/wiki/Modular_exponentiation) where we apply the modulus to each intermediate result, and cut the exponent in half each iteration, so we need only do *O*(log *n*) multiplications, not *O*(*n*). That's a big difference: 1024 is a trillion trillion, and log2(1024) is only 80. \n", "\n", "There are two key ides that make this work:\n", "1) *b*2*e* = (*b* × *b*)*e*\n", "2) *b*2 (mod *m*) = (*b* (mod *m*))2 (mod *m*)\n", " - Proof: let *r* = *b* (mod *m*); then *b* = (*km* + *r*) for some integer value of *k*, and:\n", " - *b*2 (mod *m*) = (*km* + *r*)2 (mod *m*) = ((*km*)2 + 2*kmr* + *r*2) (mod *m*) = *r*2 (mod *m*)\n", "\n", "Here is an implementation:" ] }, { "cell_type": "code", "execution_count": 32, "id": "e71eb140-7e1a-4146-87a7-8c4eebf61486", "metadata": {}, "outputs": [], "source": [ "def modpow(b: int, e: int, m: int) -> int:\n", " \"\"\"Compute b**e mod m, efficiently.\"\"\"\n", " return (1 if e == 0 else\n", " b if e == 1 else\n", " modpow((b * b) % m, e // 2, m) if e % 2 == 0 else\n", " modpow((b * b) % m, e // 2, m) * b % m)" ] }, { "cell_type": "markdown", "id": "6baf40c3-db36-40ba-b2d7-45afa21f811f", "metadata": {}, "source": [ "We can see this function is fast and that it correctly computes the remainder of 1 for the following:" ] }, { "cell_type": "code", "execution_count": 33, "id": "01838139-52dd-48a0-8f62-bcdef351345e", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "CPU times: user 27 μs, sys: 0 ns, total: 27 μs\n", "Wall time: 28.8 μs\n" ] }, { "data": { "text/plain": [ "1" ] }, "execution_count": 33, "metadata": {}, "output_type": "execute_result" } ], "source": [ "a = 123456789012345678901234\n", "n = 357686312646216567629137\n", "\n", "%time modpow(a, n - 1, n)" ] }, { "cell_type": "markdown", "id": "4be033d1-93a0-4ef5-853e-81da0782ed20", "metadata": {}, "source": [ "I hope you have enjoyed this excursion into the world of primes!" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.13.3" } }, "nbformat": 4, "nbformat_minor": 5 }