python: разложить ГИГАНТСКОЕ число на простые множители

Подскажите как можно быстро разложить гигантское число на простые множители?

Я использую Ро-алгоритм Полларда

import math
import random
from collections import Counter


# === АЛГОРИТМ РАЗЛОЖЕНИЯ ЧИСЛА НА ПРОСТЫЕ МНОЖИТЕЛИ ===
def rabinMiller(n, trials=5):
    s = n - 1
    t = 0
    while s % 2 == 0:
        # keep halving s while it is even (and use t
        # to count how many times we halve s)
        s = s // 2
        t += 1

    for trial in range(trials):
        a = random.randrange(2, n - 1)
        v = pow(a, s, n)
        if v != 1: # this test does not apply if v is 1.
            i = 0
            while v != n - 1:
                if i == t - 1:
                    return False
                else:
                    i += 1
                    v = (v * v) % n
    return True


def is_prime(n):
    # return sympy.isprime(n)

    if n < 2:
        return False

    # Примерно в 1/3 случаев простоту числа можно быстро определить путем деления на первые несколько десятков простых чисел
    lowPrimes = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509, 521, 523, 541, 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, 607, 613, 617, 619, 631, 641, 643, 647, 653, 659, 661, 673, 677, 683, 691, 701, 709, 719, 727, 733, 739, 743, 751, 757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, 829, 839, 853, 857, 859, 863, 877, 881, 883, 887, 907, 911, 919, 929, 937, 941, 947, 953, 967, 971, 977, 983, 991, 997]

    if n in lowPrimes:
        return True

    for prime in lowPrimes:
        if n % prime == 0:
            return False

    return rabinMiller(n)


def pollard_rho(n):
    f = lambda x: (x * x + c) % n

    while True:
        x, c = random.randrange(1, n), random.randrange(1, n)

        y = f(x)
        while (d := math.gcd(abs(x - y), n)) == 1:
            x, y = f(x), f(f(y))

        if d != n:
            return d


def get_factors(n):
    if is_prime(n) or n == 1:
        return Counter([n])

    r = pollard_rho(n)

    return get_factors(r) + get_factors(n // r)

Но на числах порядка 10^50 алгоритм работает уже очень медленно а нужно факторизовать числа порядка 10^300 - 10^1000

Подскажите в какую сторону смотреть или как ускорить текущий алгоритм

Например 26991040568646557637808265097422436096502138577315 = {5: 1, 23: 1, 4003: 1, 4543543: 1, 1305356177: 1, 3216951057821: 1, 3073039005199217: 1}

раскладывается за 6 сек, а 269910405686465576378082650974224360965021385773159370777487992681182736359902834804413489558103002563789087645685105748017635407131725619949388418611135969801154294953222769257225627541110077328183793 не раскладывается никогда :(


Ответы (1 шт):

Автор решения: Matvj

Используйте метод факторизации с помощью эллиптических кривых.

Его вычислительная сложность составляет: Ln[1/2;1].

Он является субэкспоненциальным, что значит, что он быстрее любого экспоненциального алгоритма (в том числе Полларда).

Правда за такую быстро действенность придётся платить сложностью реализации.

Вы можете узнать реализацию алгоритма на этом GitHub.

→ Ссылка