325 lines
13 KiB
Python
325 lines
13 KiB
Python
"""
|
||
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
|
||
|
||
# ══════════════════════════════════════════════════════════════════
|
||
# A MATRIZ SAGRADA — 12 BRAÇOS (MOD 42)
|
||
# ══════════════════════════════════════════════════════════════════
|
||
ARMS = [1, 5, 11, 13, 17, 19, 23, 25, 29, 31, 37, 41]
|
||
PILARES = [2, 3, 5, 7]
|
||
|
||
# ══════════════════════════════════════════════════════════════════
|
||
# POLLARD-RHO HELICOIDAL — Becker-GPT
|
||
#
|
||
# Sementes x₀ e c ancoradas nos 12 braços mod 42.
|
||
# Preserva O(n^1/4) + geometria helicoidal determinística.
|
||
# ══════════════════════════════════════════════════════════════════
|
||
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
|
||
|
||
|
||
# ══════════════════════════════════════════════════════════════════
|
||
# FATORAÇÃO PRINCIPAL — APENAS POLLARD-RHO HELICOIDAL
|
||
# ══════════════════════════════════════════════════════════════════
|
||
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()
|
||
|
||
# ── Fase 1: Pilares ──
|
||
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")
|
||
|
||
# ── Fase 2: SOMENTE Pollard-Rho Helicoidal (sem linear) ──
|
||
while n > 1:
|
||
fator = -1
|
||
metodo = ""
|
||
paralelo = False
|
||
|
||
# Pollard-Rho Helicoidal (sempre executado)
|
||
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"),
|
||
}
|
||
|
||
|
||
# ══════════════════════════════════════════════════════════════════
|
||
# RELATÓRIO TXT (formato 100% idêntico ao original)
|
||
# ══════════════════════════════════════════════════════════════════
|
||
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")
|
||
|
||
|
||
# ══════════════════════════════════════════════════════════════════
|
||
# INTERFACE PRINCIPAL (100% igual)
|
||
# ══════════════════════════════════════════════════════════════════
|
||
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()
|