| """ |
| Explicit Formula Engine (from v3, enhanced for v_mix) |
| Uses the von Mangoldt explicit formula with 100,000 zeros. |
| """ |
|
|
| import numpy as np |
| from typing import List, Dict |
| from dataclasses import dataclass |
|
|
|
|
| @dataclass |
| class PrimePrediction: |
| predicted_value: int |
| confidence: float |
| actual_is_prime: bool = False |
| error: int = 0 |
| method: str = "" |
|
|
|
|
| class ExplicitFormulaEngine: |
| def __init__(self, zeros: List[float]): |
| self.zeros = np.array(zeros, dtype=np.float64) |
| self._log = [] |
|
|
| def log(self, msg: str): |
| self._log.append(msg) |
| print(f" [ExplicitFormula] {msg}") |
|
|
| def compute_psi(self, x: float, n_zeros: int = None) -> float: |
| if n_zeros is None: |
| n_zeros = len(self.zeros) |
| n_zeros = min(n_zeros, len(self.zeros)) |
| if x <= 1: |
| return 0.0 |
| log_x = np.log(x) |
| sqrt_x = np.sqrt(x) |
| psi = x |
| gamma_subset = self.zeros[:n_zeros] |
| denom = 0.25 + gamma_subset ** 2 |
| cos_term = np.cos(gamma_subset * log_x) * 0.5 |
| sin_term = np.sin(gamma_subset * log_x) * gamma_subset |
| psi -= np.sum(2 * sqrt_x * (cos_term + sin_term) / denom) |
| psi -= np.log(2 * np.pi) |
| if x > 1.01: |
| psi -= 0.5 * np.log(1 - 1 / (x * x)) |
| return psi |
|
|
| def compute_psi_vectorized(self, x_values: np.ndarray, n_zeros: int = None) -> np.ndarray: |
| if n_zeros is None: |
| n_zeros = min(10000, len(self.zeros)) |
| n_zeros = min(n_zeros, len(self.zeros)) |
| x_values = np.asarray(x_values, dtype=np.float64) |
| log_x = np.log(np.maximum(x_values, 1.01)) |
| sqrt_x = np.sqrt(np.maximum(x_values, 0)) |
| psi = x_values.copy() |
| gamma_arr = self.zeros[:n_zeros] |
| for gamma in gamma_arr: |
| denom = 0.25 + gamma * gamma |
| cos_terms = np.cos(gamma * log_x) * 0.5 |
| sin_terms = np.sin(gamma * log_x) * gamma |
| psi -= 2 * sqrt_x * (cos_terms + sin_terms) / denom |
| psi -= np.log(2 * np.pi) |
| mask = x_values > 1.01 |
| psi[mask] -= 0.5 * np.log(1 - 1 / (x_values[mask] ** 2)) |
| return psi |
|
|
| def count_predicted_primes(self, x_max: int, n_zeros: int = None) -> int: |
| if n_zeros is None: |
| n_zeros = min(5000, len(self.zeros)) |
| x_range = np.arange(2, x_max + 1, dtype=np.float64) |
| psi_prev = self.compute_psi_vectorized(x_range - 0.5, n_zeros=n_zeros) |
| psi_next = self.compute_psi_vectorized(x_range + 0.5, n_zeros=n_zeros) |
| jumps = psi_next - psi_prev |
| expected = np.log(x_range) |
| predicted = np.sum(jumps > expected * 0.5) |
| return int(predicted) |
|
|
| def minimum_zeros_for_primes(self, x_max: int, max_zeros: int = 100000) -> Dict: |
| sieve = np.ones(x_max + 1, dtype=bool) |
| sieve[:2] = False |
| for i in range(2, int(x_max ** 0.5) + 1): |
| if sieve[i]: |
| sieve[i * i::i] = False |
| actual_primes = np.sum(sieve) |
|
|
| N_tests = [10, 50, 100, 200, 500, 1000, 2000, 5000, |
| 10000, 20000, 50000, 100000] |
| N_tests = [n for n in N_tests if n <= max_zeros] |
|
|
| results = [] |
| for N in N_tests: |
| predicted = self.count_predicted_primes(x_max, n_zeros=N) |
| results.append({ |
| 'N': N, |
| 'predicted_primes': predicted, |
| 'actual_primes': int(actual_primes), |
| 'accuracy': predicted / actual_primes if actual_primes > 0 else 0, |
| 'correct': predicted == actual_primes, |
| }) |
| if predicted == actual_primes: |
| break |
|
|
| return { |
| 'x_max': x_max, |
| 'results': results, |
| 'minimum_N': next((r['N'] for r in results if r['correct']), None), |
| } |
|
|
| def prime_oscillation_contributions(self, x: float, n_zeros: int = 1000) -> Dict: |
| n_zeros = min(n_zeros, len(self.zeros)) |
| log_x = np.log(x) |
| sqrt_x = np.sqrt(x) |
| contributions = [] |
| cumulative = 0.0 |
| for i in range(n_zeros): |
| gamma = self.zeros[i] |
| denom = 0.25 + gamma * gamma |
| cos_term = np.cos(gamma * log_x) * 0.5 |
| sin_term = np.sin(gamma * log_x) * gamma |
| actual = -2 * sqrt_x * (cos_term + sin_term) / denom |
| cumulative += actual |
| contributions.append({ |
| 'index': i + 1, |
| 'gamma': gamma, |
| 'contribution': float(actual), |
| 'cumulative': float(cumulative), |
| }) |
| return { |
| 'x': x, |
| 'total_contribution': float(cumulative), |
| 'contributions': contributions, |
| } |
|
|
| def get_log(self): |
| return self._log |
|
|