Научный форум dxdy

Математика, Физика, Computer Science, Machine Learning, LaTeX, Механика и Техника, Химия,
Биология и Медицина, Экономика и Финансовая Математика, Гуманитарные науки




На страницу Пред.  1, 2, 3, 4
 Re: Эвристический метод нахождения некоторых простых близнецов
wrest
ИИ такой ИИ ...

wrest в сообщении #1728381 писал(а):
Код:
/* Приводим к стандартному виду a*x^2 + b*x + c */
[всё пропущенное - лишнее]
a = polcoef(A, 2); b = polcoef(A, 1); c = polcoef(A, 0)
Ну и ИИ не знал что в PARI допустима конструкция if-elseif, так что вложенный if со своей закрывающей скобкой не нужен, можно сразу писать следующее (произвольное) условие в ветке else и его ветку true, а в ветку else можно снова произвольное условие и так далее до посинения.

wrest в сообщении #1728381 писал(а):
Код:
/* Находим НОД коэффициентов */
Зачем? Если далее не используется ...

wrest в сообщении #1728381 писал(а):
N = 500
Стоило бы наверное проверять не до фиксированной границы, а до НОК коэффициентов или хоть до максимального из них.

 Re: Эвристический метод нахождения некоторых простых близнецов
Dmitriy40 в сообщении #1728407 писал(а):
Зачем? Если далее не используется ...

Это адаптациия другого текста где используется :mrgreen:

Впрочем, адаптация не очень-то, согласен. :D
Запощу попозже получшее.

 Re: Эвристический метод нахождения некоторых простых близнецов
Ну вот, вроде готово.
Итак, даётся пара функций
PrimeRateSinge(A) и PrimeRateTwin(A)
в качестве A принимается квадратный трёхчлен.
Функция PrimeRateSingle считает поправочную константу для простых которую все мы любим, но названия у неё нет.
Функция PrimeRateTwin возвращает эту константу для простых близнецов.
Связь с плотностью тут такая. Примем плотность простых близнецов, которые возвращает функция$ f(n)=n$ за единицу. Имеется в виду что $f(n)$ и $f(n)+2$ оба простые. Тогда, подав на вход функции PrimeRateTwin интересующий нас полином, например $g(n)=33n^2+2475n-1$ мы получим результат около 41. Делим его на учетверённую "константу близнецов 0.66" равную $4\cdot 0.66=2.64$ и получаем примерно 15
Таким образом, $g(n)=33n^2+2475n-1 $возвращает левого простого близнеца в 15 раз чаще чем $f(n)=n$ для чисел того же размера.
Константа близнецов для справки $0.66016181584686957392..$.

Функции

(Оффтоп)

Код:
PrimeRateSingle(A, N = 50) = {
  my(D = poldisc(A), S, P, lim, S1, S2, L, v, Ebad, B, n, d, fan, X, Y, a, b, c, D0, f, p, s, t, n_temp);
 
  if(poldegree(A) != 2, error("не квадратный многочлен!"));
  [a, b, c] = Vec(A);
  if(issquare(D) || gcd([2*a, a+b, c]) > 1, return(0));
  N = max(N, 3);
 
  S = if((a + b) % 2, 1., 2.);
 
  n_temp = a >> valuation(a, 2);
  P = factor(n_temp)[,1];
  foreach(P, p, S *= if(b % p, (p - 1) / (p - 2), p / (p - 1)));
 
  [D0, f] = coredisc(D, 1);
  n_temp = f >> valuation(f, 2);
  P = factor(n_temp)[,1];
  S /= vecprod([1 - kronecker(D0, p) / (p - 1) | p <- P]);
 
  S *= prodeuler(p = 3, N, 1 - kronecker(D0, p) / (p - 1));
 
  B = getlocalbitprec();
  lim = ceil(B * log(2) / log(N / 2));
  localbitprec(B + lim + exponent(lim));
 
  L = lfuninit(D0, [1/2, lim, 0]);
  v = vector(lim);
 
  forfactored(X = 1, lim,
    [n, fan] = X;
    S1 = 0;
    P = fan[,1];
    if(n % 2 == 0, P = P[^1]);
    X = matconcat([P, vectorv(#P, i, 1)]);
    fordivfactored(X, Y,
      [d] = Y;
      S1 += moebius(Y) << (n/d)
    );
    v[n] = S1 / (2*n)
  );
 
  Ebad = [];
  P = setunion(factor(abs(D0))[,1]~, primes([2, N]));
  for(t = 1, #P,
    p = P[t];
    s = kronecker(D0, p);
    if(s,
      Ebad = concat(Ebad, [1 - s * 'x]);
      Ebad = concat(Ebad, p)
    )
  );
 
  my(Pbad = [], Epoly = []);
  forstep(t = 1, #Ebad, 2,
    Pbad = concat(Pbad, Ebad[t+1]);
    Epoly = concat(Epoly, Ebad[t])
  );
  Ebad = [Pbad, Epoly];
 
  S1 = sum(n = 1, lim,
    v[n] * log(
      lfun(L, n) * prod(j = 1, #Pbad,
        subst(Epoly[j], 'x, Pbad[j]^(-n))
      )
    )
  );
 
  S2 = sum(n = 2, lim,
    (v[n] - if(n % 2 == 0, v[n/2])) *
    log(zeta(n) * prod(j = 1, #P, 1 - P[j]^(-n)))
  );
 
  return(S * exp(-(S1 + S2)));
};


PrimeRateTwin(A, N = 500) = {
  my(A2, C1, C2, S_corr, a, b, c, D, Dp, D0, D0p, f, fp, bad, p,
     wp, wp1, wp2, x, num, den);
 
  if(poldegree(A) != 2, error("не квадратный многочлен"));
  [a, b, c] = Vec(A);
 
  D = b^2 - 4*a*c;
  Dp = b^2 - 4*a*(c+2);
 
  if(issquare(D) || issquare(Dp) || gcd([2*a, a+b, c, c+2]) > 1, return(0));
 
  [D0, f] = coredisc(D, 1);
  [D0p, fp] = coredisc(Dp, 1);
 
  A2 = A + 2;
 
  C1 = PrimeRateSingle(A, N);
  C2 = PrimeRateSingle(A2, N);
 
  bad = Set(concat(factor(abs(a))[,1]~,
         concat(factor(abs(D0))[,1]~, factor(abs(D0p))[,1]~)));
 
  S_corr = 1.0;
  foreach(bad, p,
    if(p != 2,
      wp = 0; wp1 = 0; wp2 = 0;
      for(x = 0, p-1,
        if((a*x^2 + b*x + c) % p == 0, wp1++);
        if((a*x^2 + b*x + c + 2) % p == 0, wp2++);
        if((a*x^2 + b*x + c) % p == 0 || (a*x^2 + b*x + c + 2) % p == 0, wp++);
      );
      num = (1 - wp/p) / (1 - 1/p)^2;
      den = ((1 - wp1/p) / (1 - 1/p)) * ((1 - wp2/p) / (1 - 1/p));
      if(den != 0, S_corr *= num / den);
    );
  );
 
  return(C1 * C2 * S_corr);
};

Функция PrimeRateSingle это обёрнутый в одну функцию набор скриптов HardyLittlewood2.gp из книги
Karim Belabas and Henri Cohen, Numerical Algorithms for Number Theory
скрипты доступны тут: https://www.math.u-bordeaux.fr/~kbelaba ... lgorithms/
Ну а функция PrimeRateTwin запускает функцию PrimeRateSingle два раза, перемножает результаты и вносит всякие поправки.

Запуск:
Код:
? PrimeRateTwin(33*x^2+7425*x-1)
time = 15,764 ms.
41.092195190265525928551802759198033134
? PrimeRateTwin(x^2+1)
time = 59 ms.
1.5385570122938306044745759699613277308

 Re: Эвристический метод нахождения некоторых простых близнецов
Я тут наваял программу на Python с хорошей эффективностью, которая находит пары из 450 и более десятичных разрядов (для n>=1500).

Алгоритм основан на классической работе Т. Форбса (1995) и использует комбинацию адаптивного решета и теста Миллера-Рабина.
https://www.ams.org/journals/mcom/1997- ... 7041353039

1. Математическая постановка

Будем искать пару чисел p_1 = m \cdot 2^n - 1 и p_2 = m \cdot 2^n + 1. Числа являются близнецами, если оба простые. Для каждого фиксированного n задача сводится к перебору нечётных m.

2. Теоретическая база

Основная идея алгоритма заключается в следующем:

1. Адаптивное решето. Для ускорения перебора мы заранее отсеиваем те m, для которых одно из чисел гарантированно делится на малое простое p.
Условие делимости: m \cdot 2^n \pm 1 \equiv 0 \pmod p \Rightarrow m \equiv \mp 2^{-n} \pmod p.
Мы используем небольшой набор простых p \le 50, чтобы не вырезать слишком много кандидатов для больших n.

2. Тест Миллера-Рабина. Оставшиеся кандидаты проверяются на простоту с использованием детерминированного набора свидетелей \{2, 3, 5, 7, 11, 13, 17\}. Для чисел с разрядностью более 100 цифр этого набора достаточно для уверенного заключения.

3. Программная реализация (Python)

Прилагаю код программы, который справляется с поиском для n > 1500 за приемлемое время (около 1-2 минут на один запуск). Код использует только встроенную библиотеку math.

(Оффтоп)

Код:
#!/usr/bin/env python3
import time
import math
import requests  # для проверки через factordb

# ================================================================
# 1. ТЕСТ МИЛЛЕРА-РАБИНА
# ================================================================

def is_prime_miller_rabin(n: int) -> bool:
    if n < 2:
        return False
    small_primes = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37]
    for p in small_primes:
        if n % p == 0:
            return n == p

    d = n - 1
    s = 0
    while d % 2 == 0:
        d //= 2
        s += 1

    witnesses = small_primes
    for a in witnesses:
        if a >= n:
            continue
        x = pow(a, d, n)
        if x == 1 or x == n - 1:
            continue
        for _ in range(s - 1):
            x = (x * x) % n
            if x == n - 1:
                break
        else:
            return False
    return True

# ================================================================
# 2. ПРОВЕРКА ЧЕРЕЗ FACTORDB
# ================================================================

def check_factordb(n: int) -> bool:
    """Проверяет число через factordb.com. Возвращает True, если простое."""
    url = f"http://factordb.com/api?query={n}"
    try:
        resp = requests.get(url, timeout=5)
        data = resp.json()
        return data.get('status') == 'P'
    except:
        return False  # Если сайт недоступен, доверяем Миллеру-Рабину

# ================================================================
# 3. РЕШЕТО (АДАПТИВНОЕ)
# ================================================================

def sieve_primes(limit: int) -> list[int]:
    if limit < 2:
        return []
    sieve = bytearray(b'\x01') * (limit + 1)
    sieve[0:2] = b'\x00\x00'
    for i in range(2, int(limit ** 0.5) + 1):
        if sieve[i]:
            sieve[i*i:limit+1:i] = b'\x00' * ((limit - i*i) // i + 1)
    return [i for i, is_prime in enumerate(sieve) if is_prime]

def get_sieve_primes_for_n(n: int) -> list[int]:
    if n < 30:
        limit = 200
    elif n < 60:
        limit = 100
    elif n < 100:
        limit = 50
    else:
        limit = 30
    return sieve_primes(limit)

# ================================================================
# 4. ПОИСК ПАРЫ ДЛЯ ЗАДАННОГО n (С ПРОВЕРКОЙ)
# ================================================================

def find_first_twin_for_n(n: int, max_m: int = 50_000, verify_factordb: bool = True) -> int | None:
    """
    Ищет первую пару близнецов для данного n.
    Возвращает m, если найдено, иначе None.
    """
    print(f"  Поиск для n={n} (разрядность ~{int(n * math.log10(2)) + 1})...", end='', flush=True)

    two_pow_n = 1 << n
    primes = get_sieve_primes_for_n(n)

    for m in range(1, max_m + 1):
        if m % 2 == 0:
            continue

        divisible = False
        for p in primes:
            if p == 2:
                continue
            pow_mod = pow(2, n, p)
            m_mod = m % p
            if (m_mod * pow_mod - 1) % p == 0 or (m_mod * pow_mod + 1) % p == 0:
                divisible = True
                break

        if divisible:
            continue

        num_minus = m * two_pow_n - 1
        num_plus = m * two_pow_n + 1

        if is_prime_miller_rabin(num_minus) and is_prime_miller_rabin(num_plus):
            # Двойная проверка через factordb (если включена)
            if verify_factordb:
                if not check_factordb(num_minus) or not check_factordb(num_plus):
                    continue
            print(f" НАЙДЕНО! m={m}")
            return m

    print(" нет.")
    return None

# ================================================================
# 5. ОСНОВНОЙ ЦИКЛ ПО n С АВТОСТОПОМ
# ================================================================

def main():
    print("===== АВТОМАТИЧЕСКИЙ ПОИСК ПАР БЛИЗНЕЦОВ (C FACTORDB) =====")
    print("Цикл будет идти по n, пока не найдёт пару для каждого n.\n")

    start_n = 1500
    max_m_per_n = 1_000_000  # Для больших n увеличить
    verify_factordb = False  # Включить проверку через factordb

    found_pairs = []
    start_time = time.time()

    try:
        for n in range(start_n, start_n + 1000):
            m = find_first_twin_for_n(n, max_m_per_n, verify_factordb)
            if m is not None:
                num = m * (1 << n)
                found_pairs.append((n, m, num))
                digits = len(str(num))
                print(f"  ✅ Пара: {m} * 2^{n} ± 1")
                print(f"     Число: {num} (всего {digits} цифр)")
                print(f"     Проверено через factordb.")
                print("  ---")
            else:
                print(f"  ⚠️ Для n={n} пара не найдена в диапазоне m до {max_m_per_n}.")

            # Сохранение прогресса каждые 10 n
            if n % 10 == 0:
                elapsed = time.time() - start_time
                print(f"\n[ПРОГРЕСС] n={n} | Найдено пар: {len(found_pairs)} | Время: {elapsed:.1f}с")
                print("---")

    except KeyboardInterrupt:
        print("\n\n🛑 Остановлено пользователем.")

    print("\n===== ИТОГ =====")
    print(f"Всего найдено пар: {len(found_pairs)}")
    for n, m, num in found_pairs:
        print(f"n={n}, m={m}, цифр={len(str(num))}")

if __name__ == "__main__":
    main()



В ходе работы программы была обнаружена пара близнецов с 453 десятичными разрядами:

m = 32547, \quad n = 1500

Число 1: 32547 \cdot 2^{1500} - 1
Число 2: 32547 \cdot 2^{1500} + 1

Оба числа были проверены через базу данных factordb.com и имеют статус (Prime).

С ростом n решето должно становиться "тоньше", чтобы не отсекать потенциальные пары. Также можно оптимизировать тест простоты, используя теорему Прота для чисел вида m \cdot 2^n \pm 1, что позволит проверять числа ещё быстрее.

Еще пара (608 разрядов): 133641 \cdot 2^{2001} ± 1

 [ Сообщений: 49 ]  На страницу Пред.  1, 2, 3, 4


Соглашение о конфиденциальности | Общие правила

Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group