| """ |
| OFFELLIA FATORADOR v2 — Decomposição Primo-Modal Helicoidal |
| ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ |
| Teoria : Roda mod 42 — Crivo Becker-GPT |
| Autor : Bruno Becker | Zenodo DOI:10.5281/zenodo.18772809 |
| |
| Hierarquia de métodos: |
| 1. Pilares de Origem {2, 3, 5, 7} — serial, O(1) |
| 2. Pollard-Rho Helicoidal — O(n^1/4), sementes nos braços |
| """ |
|
|
| import time |
| import math |
| import multiprocessing |
| from concurrent.futures import ProcessPoolExecutor |
| from typing import Tuple, Dict |
| from datetime import datetime |
| from random import randint |
|
|
| |
| |
| |
| ARMS = [1, 5, 11, 13, 17, 19, 23, 25, 29, 31, 37, 41] |
| PILARES = [2, 3, 5, 7] |
|
|
| |
| |
| |
| |
| |
| |
| def pollard_rho_helicoidal(n: int, tentativas: int = 5) -> Tuple[int, int]: |
| if n % 2 == 0: return 2, 1 |
|
|
| for t in range(tentativas): |
| arm_x = ARMS[t % 12] |
| k_x = randint(1, max(1, int(n ** 0.25) // 42 + 10)) |
| x = (42 * k_x + arm_x) % n or arm_x |
| arm_c = ARMS[(t + 5) % 12] |
| k_c = randint(0, 256) |
| c = (42 * k_c + arm_c) % n or arm_c |
|
|
| y, d, r, q, ys, x_save = x, 1, 1, 1, x, x |
|
|
| while d == 1: |
| x_save = y |
| for _ in range(r): |
| y = (y * y + c) % n |
| k = 0 |
| while k < r and d == 1: |
| ys = y |
| for _ in range(min(128, r - k)): |
| y = (y * y + c) % n |
| q = (q * abs(x_save - y)) % n |
| k += 128 |
| d = math.gcd(q, n) |
| r *= 2 |
| if r > 2: break |
|
|
| if d == n: |
| d = 1 |
| while d == 1: |
| ys = (ys * ys + c) % n |
| d = math.gcd(abs(x_save - ys), n) |
|
|
| if 1 < d < n: return d, t + 1 |
|
|
| return -1, tentativas |
|
|
|
|
| def pollard_rho_worker(args: Tuple[int, int, int]) -> int: |
| """Worker paralelo com braços-semente distintos.""" |
| n, seed_offset, tentativas = args |
| for t in range(tentativas): |
| arm_idx = (t + seed_offset) % 12 |
| x = (42 * randint(1, max(1, int(n ** 0.25) // 42 + 10)) + ARMS[arm_idx]) % n or ARMS[arm_idx] |
| c = (42 * randint(0, 256) + ARMS[(arm_idx + 5) % 12]) % n or ARMS[(arm_idx + 5) % 12] |
|
|
| y, d, r, q, ys, x_save = x, 1, 1, 1, x, x |
|
|
| while d == 1: |
| x_save = y |
| for _ in range(r): |
| y = (y * y + c) % n |
| k = 0 |
| while k < r and d == 1: |
| ys = y |
| for _ in range(min(128, r - k)): |
| y = (y * y + c) % n |
| q = (q * abs(x_save - y)) % n |
| k += 128 |
| d = math.gcd(q, n) |
| r *= 2 |
| if r > 9_999_999_999_999_999_999_999_999_999_999_999_999_999_999_999_999_999_999_999_999_999_999_999_999_999_999_999_999_999_999_999: break |
|
|
| if d == n: |
| d = 1 |
| while d == 1: |
| ys = (ys * ys + c) % n |
| d = math.gcd(abs(x_save - ys), n) |
|
|
| if 1 < d < n: return d |
| return -1 |
|
|
|
|
| |
| |
| |
| def fatorar_v2(n: int, num_cores: int) -> Dict: |
| original, fatores, passos = n, [], [] |
| total_div = workers_usados = 0 |
| metodos_usados = set() |
| t_inicio = time.perf_counter() |
|
|
| |
| for pilar in PILARES: |
| while n % pilar == 0: |
| fatores.append(pilar) |
| passos.append({"etapa": "Pilar de Origem", "metodo": "Pilares", |
| "divisor": pilar, "quociente": n // pilar, "paralelo": False}) |
| n //= pilar |
| total_div += 1 |
| metodos_usados.add("Pilares") |
|
|
| |
| while n > 1: |
| fator = -1 |
| metodo = "" |
| paralelo = False |
|
|
| |
| metodos_usados.add("Pollard-Rho Helicoidal") |
| if num_cores > 1: |
| n_workers = min(num_cores, 12) |
| workers_usados = max(workers_usados, n_workers) |
| try: |
| with ProcessPoolExecutor(max_workers=n_workers) as ex: |
| for res in ex.map(pollard_rho_worker, [(n, i*2, 15) for i in range(n_workers)]): |
| if res != -1: |
| fator = res |
| paralelo = True |
| break |
| except Exception: |
| fator, _ = pollard_rho_helicoidal(n, 256) |
| else: |
| fator, _ = pollard_rho_helicoidal(n, 256) |
| metodo = "Pollard-Rho Helicoidal" |
|
|
| if fator == -1: |
| fatores.append(n) |
| passos.append({"etapa": "Primo Residual (Exaustivo)", "metodo": "Exaustivo", |
| "divisor": n, "quociente": 1, "paralelo": False}) |
| n = 1 |
| break |
|
|
| fatores.append(fator) |
| passos.append({"etapa": f"Braço mod 42 (d ≡ {fator % 42} mod 42)", "metodo": metodo, |
| "divisor": fator, "quociente": n // fator, "paralelo": paralelo}) |
| n //= fator |
| total_div += 1 |
|
|
| t_fim = time.perf_counter() |
| fatores_exp = {} |
| for f in fatores: |
| fatores_exp[f] = fatores_exp.get(f, 0) + 1 |
|
|
| return { |
| "original": original, "fatores": sorted(fatores), |
| "fatores_exp": dict(sorted(fatores_exp.items())), "passos": passos, |
| "total_divisoes": total_div, "tempo_segundos": t_fim - t_inicio, |
| "num_cores": num_cores, "workers_usados": workers_usados, |
| "metodos_usados": sorted(metodos_usados), |
| "timestamp": datetime.now().strftime("%Y-%m-%d %H:%M:%S"), |
| } |
|
|
|
|
| |
| |
| |
| def gerar_relatorio(resultado: Dict, filename: str): |
| n = resultado["original"] |
| fatores = resultado["fatores"] |
| fat_exp = resultado["fatores_exp"] |
| passos = resultado["passos"] |
| tempo = resultado["tempo_segundos"] |
| cores = resultado["num_cores"] |
| workers = resultado["workers_usados"] |
| ts = resultado["timestamp"] |
| metodos = resultado["metodos_usados"] |
|
|
| notacao = " × ".join(f"{p}^{e}" if e > 1 else str(p) for p, e in fat_exp.items()) |
| produto = 1 |
| for f in fatores: produto *= f |
| verificacao = "CORRETO" if produto == n else f"ERRO (produto={produto})" |
|
|
| sep = "=" * 76 |
| sep2 = "-" * 76 |
| L = [] |
|
|
| L.append(sep) |
| L.append(" OFFELLIA FATORADOR v2 — Decomposição Primo-Modal Helicoidal") |
| L.append(" Teoria : Roda mod 42 (Crivo Becker-GPT)") |
| L.append(" Métodos: Pollard-Rho Helicoidal") |
| L.append(" Autor : Bruno Becker | Zenodo DOI:10.5281/zenodo.18772809") |
| L.append(sep) |
| L.append(f" Data/Hora : {ts}") |
| L.append(f" Núcleos disponíveis : {cores}") |
| L.append(f" Workers paralelos : {workers if workers > 0 else 'Não utilizados (serial)'}") |
| L.append(f" Métodos utilizados : {' | '.join(metodos)}") |
| L.append(sep) |
|
|
| L.append("") |
| L.append("[ NÚMERO ANALISADO ]") |
| L.append(f" N : {n:,}") |
| L.append(f" Dígitos : {len(str(n))}") |
| L.append(f" Bits : {n.bit_length()}") |
| L.append(f" É primo? : {'Sim' if len(fat_exp)==1 and list(fat_exp.values())[0]==1 else 'Não'}") |
|
|
| L.append("") |
| L.append("[ RESULTADO DA FATORAÇÃO ]") |
| L.append(f" Notação de potência : {notacao}") |
| L.append(f" Fatores (lista) : {fatores}") |
| L.append(f" Fatores únicos : {sorted(fat_exp.keys())}") |
| L.append(f" Verificação : {n:,} = {notacao} → {verificacao}") |
|
|
| L.append("") |
| L.append("[ MÉTRICAS DE EXECUÇÃO ]") |
| L.append(f" Tempo total : {tempo:.6f} segundos") |
| L.append(f" Divisões realizadas : {resultado['total_divisoes']}") |
| L.append(f" Fatores encontrados : {len(fatores)}") |
| L.append(f" Fatores distintos : {len(fat_exp)}") |
| if tempo > 0: |
| L.append(f" Fatores/segundo : {len(fatores)/tempo:.2f}") |
|
|
| L.append("") |
| L.append("[ DETALHAMENTO DOS FATORES ]") |
| L.append(f" {'Fator':>22} {'Exp':>4} {'Bits':>6} {'Origem'}") |
| L.append(" " + sep2) |
| for p, e in fat_exp.items(): |
| origem = "Pilar de Origem" if p in PILARES else f"Braço {p % 42} (mod 42)" |
| L.append(f" {p:>22,} {e:>4} {p.bit_length():>6} {origem}") |
|
|
| L.append("") |
| L.append("[ PASSO A PASSO DA DECOMPOSIÇÃO ]") |
| L.append(f" {'#':<5} {'Método':<24} {'Etapa':<256} {'Divisor':>16} {'Quociente':>20} {'Par':>4}") |
| L.append(" " + sep2) |
| for i, p in enumerate(passos, 1): |
| L.append(f" {i:<5} {p['metodo']:<24} {p['etapa']:<256} " |
| f"{p['divisor']:>16,} {p['quociente']:>20,} {'S' if p['paralelo'] else 'N':>4}") |
|
|
| L.append("") |
| L.append("[ TEORIA APLICADA — HIERARQUIA DE MÉTODOS ]") |
| L.append("") |
| L.append(" 1. PILARES DE ORIGEM {2, 3, 5, 7} — O(1), serial") |
| L.append(" 2. MILLER-RABIN — O(k·log²n), determinístico até 3.3×10²⁴") |
| L.append(" 3. POLLARD-RHO HELICOIDAL (inovação Becker-GPT)") |
| L.append(" x₀ = 42k + a (a ∈ ARMS) — semente no braço") |
| L.append(" c = 42k + a (a ∈ ARMS) — parâmetro helicoidal") |
| L.append(" Complexidade: O(n^1/4)") |
| L.append(" 3. BUSCA LINEAR NOS BRAÇOS — fallback garantido, 28.6% candidatos") |
| L.append("") |
| L.append(" Todo primo p > 7: p ≡ a (mod 42),") |
| L.append(" a ∈ {1, 5, 11, 13, 17, 19, 23, 25, 29, 31, 37, 41}") |
|
|
| bracos = sorted(set(p["divisor"] % 42 for p in passos if p["divisor"] not in PILARES)) |
| if bracos: |
| L.append(f" Braços utilizados : {bracos}") |
|
|
| L.append("") |
| L.append(sep) |
| L.append(" Fim do Relatório — OFFELLIA Fatorador v2") |
| L.append(" Zenodo: https://zenodo.org/records/18772809") |
| L.append(sep) |
|
|
| with open(filename, "w", encoding="utf-8") as f: |
| f.write("\n".join(L)) |
| f.write("\n") |
|
|
|
|
| |
| |
| |
| def run_fatorador(): |
| print("=" * 64) |
| print(" OFFELLIA FATORADOR v2 — Pollard-Rho Helicoidal") |
| print(" Roda mod 42 | Pollard-Rho Helicoidal") |
| print("=" * 64) |
|
|
| try: |
| n = int(input("\nInsira o número a fatorar: ")) |
| if n < 2: |
| print("Número deve ser >= 2.") |
| return |
| except ValueError: |
| print("Entrada inválida.") |
| return |
|
|
| num_cores = min(12, multiprocessing.cpu_count()) |
| print(f"\nNúcleos ativos : {num_cores}") |
| print(f"Número analisado : {n:,} ({len(str(n))} dígitos | {n.bit_length()} bits)") |
| print("\nIniciando decomposição...\n") |
|
|
| resultado = fatorar_v2(n, num_cores) |
|
|
| fat_exp = resultado["fatores_exp"] |
| notacao = " × ".join(f"{p}^{e}" if e > 1 else str(p) for p, e in fat_exp.items()) |
| tempo = resultado["tempo_segundos"] |
|
|
| print("─" * 64) |
| print(f" ✓ Fatoração concluída em {tempo:.6f} segundos") |
| print(f" {n:,} = {notacao}") |
| print(f" Divisões realizadas : {resultado['total_divisoes']}") |
| print(f" Fatores distintos : {len(fat_exp)}") |
| print(f" Métodos usados : {' | '.join(resultado['metodos_usados'])}") |
| print("─" * 64) |
|
|
| filename = f"offellia_v2_{n}.txt" |
| gerar_relatorio(resultado, filename) |
| print(f"\n Relatório salvo: '{filename}'") |
| print(" Operação finalizada.\n") |
|
|
|
|
| if __name__ == "__main__": |
| run_fatorador() |
|
|