Upload problem_solvers/ktuple_constants.py
Browse files
problem_solvers/ktuple_constants.py
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
PROBLEM 5: Hardy-Littlewood k-Tuple Constants
|
| 3 |
+
===============================================
|
| 4 |
+
Verify the density of prime k-tuples against Hardy-Littlewood predictions.
|
| 5 |
+
"""
|
| 6 |
+
|
| 7 |
+
import numpy as np
|
| 8 |
+
from typing import Dict, List
|
| 9 |
+
|
| 10 |
+
|
| 11 |
+
class KTupleAnalyzer:
|
| 12 |
+
def __init__(self):
|
| 13 |
+
self.results = {}
|
| 14 |
+
|
| 15 |
+
def sieve_primes(self, limit: int) -> List[int]:
|
| 16 |
+
sieve = np.ones(limit + 1, dtype=bool)
|
| 17 |
+
sieve[:2] = False
|
| 18 |
+
for i in range(2, int(limit ** 0.5) + 1):
|
| 19 |
+
if sieve[i]:
|
| 20 |
+
sieve[i * i::i] = False
|
| 21 |
+
return np.where(sieve)[0].tolist()
|
| 22 |
+
|
| 23 |
+
def count_patterns(self, primes: List[int], pattern: List[int]) -> int:
|
| 24 |
+
"""Count occurrences of a k-tuple pattern."""
|
| 25 |
+
prime_set = set(primes)
|
| 26 |
+
count = 0
|
| 27 |
+
for p in primes:
|
| 28 |
+
if all((p + d) in prime_set for d in pattern):
|
| 29 |
+
count += 1
|
| 30 |
+
return count
|
| 31 |
+
|
| 32 |
+
def hardy_littlewood_constant(self, pattern: List[int]) -> float:
|
| 33 |
+
"""
|
| 34 |
+
Compute the Hardy-Littlewood constant 𝔖(H) for pattern H.
|
| 35 |
+
𝔖(H) = ∏_p (1 - 1/p)^{-k} * (1 - ν_H(p)/p)
|
| 36 |
+
where ν_H(p) is number of distinct residues mod p occupied by H.
|
| 37 |
+
Approximate for small p.
|
| 38 |
+
"""
|
| 39 |
+
from sympy import primerange, Rational
|
| 40 |
+
k = len(pattern)
|
| 41 |
+
product = 1.0
|
| 42 |
+
for p in primerange(2, 100):
|
| 43 |
+
residues = set((d % p) for d in pattern)
|
| 44 |
+
nu_H = len(residues)
|
| 45 |
+
if nu_H == p:
|
| 46 |
+
continue # Pattern impossible mod p
|
| 47 |
+
term = (1.0 - 1.0 / p) ** (-k) * (1.0 - nu_H / p)
|
| 48 |
+
product *= term
|
| 49 |
+
return product
|
| 50 |
+
|
| 51 |
+
def analyze(self, limit: int = 2_000_000) -> Dict:
|
| 52 |
+
primes = self.sieve_primes(limit)
|
| 53 |
+
prime_set = set(primes)
|
| 54 |
+
n_primes = len(primes)
|
| 55 |
+
x = limit
|
| 56 |
+
|
| 57 |
+
patterns = {
|
| 58 |
+
'twin': [0, 2],
|
| 59 |
+
'cousin': [0, 4],
|
| 60 |
+
'sexy': [0, 6],
|
| 61 |
+
'triplet1': [0, 2, 6],
|
| 62 |
+
'triplet2': [0, 4, 6],
|
| 63 |
+
'quadruplet': [0, 2, 6, 8],
|
| 64 |
+
}
|
| 65 |
+
|
| 66 |
+
results = {}
|
| 67 |
+
for name, pat in patterns.items():
|
| 68 |
+
count = self.count_patterns(primes, pat)
|
| 69 |
+
k = len(pat)
|
| 70 |
+
hl_const = self.hardy_littlewood_constant(pat)
|
| 71 |
+
# Predicted: count ~ 𝔖(H) · x / (log x)^k
|
| 72 |
+
predicted = hl_const * x / (np.log(x) ** k)
|
| 73 |
+
error = abs(count - predicted) / max(predicted, 1)
|
| 74 |
+
|
| 75 |
+
results[name] = {
|
| 76 |
+
'pattern': pat,
|
| 77 |
+
'count': count,
|
| 78 |
+
'predicted': float(predicted),
|
| 79 |
+
'hardy_littlewood_constant': float(hl_const),
|
| 80 |
+
'relative_error': float(error),
|
| 81 |
+
'k': k,
|
| 82 |
+
}
|
| 83 |
+
|
| 84 |
+
self.results = {
|
| 85 |
+
'limit': limit,
|
| 86 |
+
'n_primes': n_primes,
|
| 87 |
+
'patterns': results,
|
| 88 |
+
}
|
| 89 |
+
return self.results
|
| 90 |
+
|
| 91 |
+
def summary(self) -> str:
|
| 92 |
+
r = self.results
|
| 93 |
+
s = f"Hardy-Littlewood k-Tuple Analysis (up to {r['limit']:,})\n{'='*50}\n"
|
| 94 |
+
for name, pat in r['patterns'].items():
|
| 95 |
+
s += f" {name:12s}: count={pat['count']:,}, predicted={pat['predicted']:.1f}, "
|
| 96 |
+
s += f"𝔖={pat['hardy_littlewood_constant']:.6f}, rel_err={pat['relative_error']:.4f}\n"
|
| 97 |
+
return s
|