eulerbooks/notebooks/problem0027.ipynb

159 lines
29 KiB
Plaintext
Raw Permalink Normal View History

2025-04-13 01:19:18 +00:00
{
"cells": [
{
"cell_type": "markdown",
"id": "e4ea692f",
"metadata": {},
"source": [
"# [Quadratic Primes](https://projecteuler.net/problem=27)\n",
"\n",
2025-07-20 02:55:27 +00:00
"We can easily write a function to test how many consecutive primes $n^2 + an + b$ generates."
2025-04-13 01:19:18 +00:00
]
},
{
"cell_type": "code",
"execution_count": 1,
"id": "a9751bc6",
"metadata": {},
2025-07-20 02:55:27 +00:00
"outputs": [],
2025-04-13 01:19:18 +00:00
"source": [
"from itertools import count\n",
"\n",
"def consecutive_primes(a, b):\n",
" f = lambda x: x^2 + a*x + b\n",
" for n in count(0):\n",
" if not is_prime(f(n)):\n",
2025-07-20 02:55:27 +00:00
" return n"
]
},
{
"cell_type": "markdown",
"id": "ce6a48ba",
"metadata": {},
"source": [
"Couple of observations to speed up iterating through values of $a$ and $b$:\n",
"1. $0^2 + 0a + b = b$ must be prime. Additionally, since $|b| \\leq 1000$, the largest possible value for $b$ is 997.\n",
"2. $1^2 + 1a + b = 1 + a + b$ must be prime. Therefore $a = p - b - 1$ for some prime $p$. Furthermore, since $|a| < 1000$, it follows that $-1000 < p - b - 1 < 1000 \\implies b - 999 < p < b + 1001$, so $p$ must be less than $997 + 1001 = 1998$ in the most extreme case.\n",
2025-04-13 01:19:18 +00:00
"\n",
2025-07-20 02:55:27 +00:00
"These facts allows us to iterate over just prime numbers instead of the larger range of integers."
]
},
{
"cell_type": "code",
"execution_count": 2,
"id": "03a9f808",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"(-61, 971)"
]
},
"execution_count": 2,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
2025-04-13 01:19:18 +00:00
"coeffs = dict()\n",
"primes = prime_range(2000)\n",
"for b in primes:\n",
" if b > 1000:\n",
" break\n",
" \n",
" for p in primes:\n",
" a = p - b - 1\n",
" if not (abs(a) < 1000):\n",
" break\n",
" \n",
" coeffs[(a, b)] = consecutive_primes(a, b)\n",
"\n",
"a, b = max(coeffs, key=coeffs.get)\n",
2025-07-20 02:55:27 +00:00
"a, b"
2025-04-13 01:19:18 +00:00
]
},
{
"cell_type": "markdown",
"id": "cbd83361",
"metadata": {},
"source": [
2025-07-20 02:55:27 +00:00
"Their product is -59231.\n",
"\n",
"If you iterate through $n=0,1,2,\\ldots$ for the resulting quadratic and the other formula given, $n^2 - 79n + 1601$, you'll see that these polynomials don't actually generate any new prime numbers compared to Euler's formula - they just repeat primes that Euler's formula already gives.\n",
2025-04-13 01:19:18 +00:00
"\n",
"Furthermore, both of these polynomials are actually just shifts of Euler's formula:\n",
"$$n^2 - 61n + 971 = (n-31)^2 + (n-31) + 41$$\n",
"$$n^2 - 79n + 1601 = (n-40)^2 + (n-40) + 41$$\n",
"\n",
"What's going on? Let $f(n) = n^2 + n + 41$. An interesting property of [prime-generating functions](https://mathworld.wolfram.com/Prime-GeneratingPolynomial.html) is if $p(n)$ generates primes for $0 \\leq n \\leq u$, then $p(u - n)$ also will. To understand why, try evaluating $p(u-n)$ at $n=0,1,2,\\ldots,u$; you get $p(u),p(u-1),p(u-2),\\ldots,p(0)$, which are the same values given by $p(n)$, just in reverse.\n",
"\n",
"However, that property alone doesn't explain why shifting $f$ right generates *more* (non-distinct) primes than $f(n)$. To understand that aspect, let's look at a plot of $f(n)$."
]
},
{
"cell_type": "code",
2025-07-20 02:55:27 +00:00
"execution_count": 3,
2025-04-13 01:19:18 +00:00
"id": "93c85dea",
"metadata": {},
"outputs": [
{
"data": {
2025-07-25 03:08:19 +00:00
"image/png": "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
2025-04-13 01:19:18 +00:00
"text/plain": [
"Graphics object consisting of 1 graphics primitive"
]
},
2025-07-20 02:55:27 +00:00
"execution_count": 3,
2025-04-13 01:19:18 +00:00
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"f(n) = n^2 + n + 41\n",
"plot(f, (-5, 5))"
]
},
{
"cell_type": "markdown",
"id": "af51cf45",
"metadata": {},
"source": [
"This quadratic is symmetric across $x=-0.5$. Because of this, $f(-1) = f(0)$, $f(-2) = f(1)$, and so on; in general, $f(n) = f(-1-n)$. However, since the axis of symmetry is just to the left of the $y$-axis, when we iterate through $n=0,1,2,\\ldots$, we only output values on one side of the axis, so we don't output any duplicated values.\n",
"\n",
"But when we transform this function by shifting it $k$ units to the right, $f(n - k)$, we cause the part of the function that's left of the axis of symmetry to *also* be output when we iterate through $n=0,1,2,\\ldots$. Since these values are all equal to values we were already outputting, they'll also be prime, but they won't be *new* primes. Since $f$ outputs primes from $n=0$ to $39$ (40 distinct values), we can shift it up to 40 units to the right and have every value from $n=0$ to $79$ be prime.\n",
"\n",
"Because of the symmetry of $f$, the transformation $f(u-n)$ is actually the *same* as shifting $f$ to the right $u+1$ units (this can be shown algebraically); then, after outputting the primes in reverse, the vertex is reached and the function starts increasing again, repeating the primes that were already output.\n",
"\n",
"## Relevant sequences\n",
2025-07-25 03:08:19 +00:00
"* Primes generated by Euler's formula: [A005846](https://oeis.org/A005846)\n",
"\n",
"#### Copyright (C) 2025 filifa\n",
"\n",
"This work is licensed under the [Creative Commons Attribution-ShareAlike 4.0 International license](https://creativecommons.org/licenses/by-sa/4.0/) and the [BSD Zero Clause license](https://spdx.org/licenses/0BSD.html)."
2025-04-13 01:19:18 +00:00
]
}
],
"metadata": {
"kernelspec": {
"display_name": "SageMath 9.5",
"language": "sage",
"name": "sagemath"
},
"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.11.2"
}
},
"nbformat": 4,
"nbformat_minor": 5
}