Fattorizzatore intero tweet più veloce


17

Il compito è trovare un fattore non banale di un numero composto.

Scrivi il codice che trova il fattore non banale di un numero composto il più rapidamente possibile, a condizione che il tuo codice non sia lungo più di 140 byte. L'output dovrebbe essere solo il fattore che hai trovato.

Il codice può prendere input e fornire output in qualsiasi modo sia conveniente, incluso ad esempio come argomenti di una funzione.

Casi di prova che elencano tutti i fattori (è necessario solo emetterne uno)

187: 11 17
1679: 23 73
14369648346682547857: 1500450271 9576890767
34747575467581863011: 3628273133 9576890767
52634041113150420921061348357: 2860486313 5463458053 3367900313
82312263010898855308580978867: 264575131106459 311111111111113
205255454905325730631914319249: 2860486313 71755440315342536873 
1233457775854251160763811229216063007: 1110111110111 1000000000063 1111111999999
1751952685614616185916001760791655006749: 36413321723440003717 48112959837082048697

Non segnerò la tua risposta sul seguente caso di test difficile che potrebbe essere di interesse per il test:

513231721363284898797712130584280850383: 40206835204840513073 12764787846358441471

Punto

Il tuo punteggio è il tempo combinato per fattorizzare tutti i casi di test sopra con una penalità di 10 minuti per ogni fattorizzazione fallita (tutto arrotondato al secondo più vicino). Il tuo codice dovrebbe funzionare anche per altri numeri interi, cioè non dovrebbe solo codificare queste risposte.

Smetterò il tuo codice dopo 10 minuti.

Se due persone ottengono lo stesso punteggio, vince la prima risposta.

restrizioni

Il codice non può utilizzare alcuna funzione incorporata o libreria che esegue la fattorizzazione a numeri interi. Si può presumere che l'input impieghi meno di 256 bit. Tutti i numeri di input saranno composti.

Come farò?

Eseguirò letteralmente time ./myprogsul mio sistema Ubuntu per fare i tempi, quindi per favore forniscimi anche un programma completo che includa qualsiasi funzione che hai definito.

Una nota per le lingue compilate

Il tempo di compilazione non deve richiedere più di 1 minuto sulla mia macchina.

È davvero possibile?

Se ignori i vincoli di spazio, ognuno può essere preso in considerazione in meno di 2 secondi sul mio computer usando puro codice Python + pypy.

Quindi cos'è un algoritmo di factoring non banale?

L'algoritmo rho di Pollard è veloce e adatto per il golf. Ovviamente ci sono molti altri modi per fattorizzare anche un numero intero .

Ancora più veloce è il setaccio quadratico . Sembra una seria sfida comprimerlo in 140 byte.

Punteggi principali

  • SEJPM , penalità di 10 minuti per l'ultimo caso di prova + 16 secondi in Haskell

Quindi, ci potrebbe essere dato un numero come 2 ** 1024?
Conor O'Brien,

@ ConorO'Brien Non ti verrà dato nulla con più cifre rispetto ai casi di test.

Quindi, in termini di precisione, niente più di 256 bit.
Conor O'Brien,

Per un input come 4, l'output dovrebbe essere 2o 2, 2?
Mr. Xcoder,

1
@AndersKaseorg Ho aggiornato la domanda seguendo il tuo suggerimento. Grazie.

Risposte:


9

Haskell, 100 97 91 89 87 72 67 byte

Provalo online!

-3 byte grazie a @flawr
-6 byte grazie a @flawr di nuovo
-2 byte grazie a @flawr di nuovo
-2 byte grazie a un set ottimizzato di parametri
-1 byte grazie a @flawrs ancora un altro tempo
-14 byte grazie al requisito a dover solo generare un fattore di
-5 byte grazie a @AndersKaseorg

f n|let s x=mod(x*x+7)n;a#b|d<-gcd(b-a)n,d>1=d|c<-s b=s a#s c=5#s 5

Funziona per i primi 5 casi di test in tempi impercettibili.
Probabilmente si verificherà un timeout sul più grande caso di test.

In generale, questo di solito restituisce un fattore non banale nel tempo proporzionale alla radice quadrata del fattore più piccolo.
Non funzionerà su tutti gli input perché non varia il polinomio e il rilevamento del caso eccezionale è difficile da eseguire in 140 byte.
Inoltre non produrrà la piena fattorizzazione, ma piuttosto un fattore non banale e la divisione dell'input per questo fattore.
Inoltre non ordinerà i fattori per dimensione.

Il metodo utilizzato è Pollard-Rho-Factoring con il valore iniziale standard di 2 (con il x^2+1polinomio standard applicato una volta) e il fattore costante polinomiale non standard di 7 (perché 1non ha funzionato con il 1679) per tutte le ulteriori valutazioni.

Programma completo ( factor.hs):

import System.Environment(getArgs)

f n|let s x=mod(x*x+7)n;a#b|d<-gcd(b-a)n,d>1=d|c<-s b=s a#s c=5#s 5

main= do
      args <- getArgs
      print$f (read $ head args :: Integer)

Compila come $ ghc factor.hs(necessita di ghcinstallazione).
Esegui come $ ./factor <number>.

Esempio di esecuzione:

$ ./factor 187
11

Codice non golfato:

f n=g 5 (s 5)
   where s x=mod(x*x+7)n
         g a b = if d>1 then d else g(s a)(s(s b))
               where d=gcd(b-a)n

Calcola il fattore non banale chiamando gcon i valori iniziali. Il polinomio viene pre-applicato su 2 qui e riapplicato sul risultato (5) in modo che l'input a g(in una clausola "where" ) possa sempre essere facilmente utilizzato per il test gcd. g(la versione golfata utilizza infix #) quindi tenta di calcolare un fattore non banale d(nella clausola where nella versione non golfata, in linea in quella golfizzata) come differenza tra i due input g, se riesce restituisce detto fattore , altri tentativi. Qui può generare ncome output se a==be quindi restituisce solo un fattore banale, l'approccio corretto per gestirlo sarebbe quello di variare i valori iniziali su questo evento o modificare il polinomio.


|1<2=s a#(s$s b)potrebbe essere sostituito con |c<-s b=s a#s ccredo :) (anche: perché non
pubblichi

Ho aggiornato la domanda seguendo i suggerimenti di commento. Ora devi solo generare un fattore e i numeri sono garantiti come composti.

3
PS: perché stiamo giocando a golf, questo non è nemmeno code-golf
flawr

4
Ora hai 53 byte in cui implementare un algoritmo di factoring ancora più sofisticato :)

1
Inoltre puoi eliminarlo abs , poiché bè sempre non negativo. (Forse intendevi abs$b-a, ma gcdaccetta argomenti negativi e produce sempre un risultato non negativo.) Ciò riduce questo a meno di mezzo tweet!
Anders Kaseorg,

6

Pari / GP , 137 byte, ~ 5 secondi

Utilizzando le operazioni integrate della curva ellittica di GP (e alcune ottimizzazioni parametriche subdole) :

ecm(n)=iferr(if(n%2==0,2,n%3==0,3,for(a=1,n,ellmul(ellinit(Mod([a,a^2-a-1],n)),[1,a],lcm([1..ceil(4^a^0.5)])))),e,gcd(n,lift(Vec(e)[3])))

ecmè una funzione che (dovrebbe) restituire un fattore. Provalo online!

Test:

ecm(n)=iferr(if(n%2==0,2,n%3==0,3,for(a=1,n,ellmul(ellinit(Mod([a,a^2-a-1],n)),[1,a],lcm([1..ceil(4^a^0.5)])))),e,gcd(n,lift(Vec(e)[3])))

{
ns = [
  187,
  1679,
  14369648346682547857,
  34747575467581863011,
  52634041113150420921061348357,
  82312263010898855308580978867,
  205255454905325730631914319249,
  1233457775854251160763811229216063007,
  1751952685614616185916001760791655006749
  ]
}

test(n) = {
    d = ecm(n);
    if (!(1<d && d<n && n%d==0), error(d));
    print(n, ": ", d)
}

apply(test, ns)

quit

Ungolfed:

ecm(n) = {
  iferr(if(n%2 == 0, 2,
           n%3 == 0, 3,
           for(a = 1, n,
               /* x^3 + A*x + B = y^2 */
               E = ellinit(Mod([a, a^2-a-1], n)); /* [A, B] */
               x0 = [1, a]; /* [x, y] */
               B = ceil(4^a^0.5); /* ~ exp(sqrt(log(p))), p ~= exp(a) */
               print("a=", a, ", B=", B);
               ellmul(E, x0, lcm([1..B]))
              )
          ),
         ERR, gcd(n, lift(Vec(ERR)[3] /* = Mod(d, n) */)),
         errname(ERR)=="e_INV")
}

Purtroppo, la gestione dei fattori 2 e 3 utilizza molti byte. Byte che avrebbero potuto essere utilizzati per aggiungere uno stadio 2:

ecm(n)=iferr(for(a=1,n,Y=X=ellmul(E=ellinit(Mod([a,1],n)),[0,1],(B=ceil(4^a^0.5))!);for(z=0,9*B,Y=elladd(E,Y,X))),e,gcd(n,lift(Vec(e)[3])))

1

Assioma, 137 byte 9 minuti

p(n:PI):PI==(j:=1;a:=3;s:=n^.2;repeat(b:=j:=nextPrime(j);repeat(b<s=>(b:=b*j);break);a:=powmod(a,b,n);d:=gcd(a-1,n);d>1 or j>n=>break);d)

sopra la funzione p () che implementerebbe l'algo p-1 per il factoring sotto cosa copiare in un file per la funzione test su p ()

-- one has to copy this below text in a file name for example file.input
-- in one window where there is Axiom one could write 
-- )read C:\absolutepathwherethereisthatfile\file
-- and call the function test()
-- test()
-- the first character of all function and array must be afther a new line "\n"
)cl all
)time on
vA:=[187,1679,14369648346682547857,34747575467581863011,52634041113150420921061348357,82312263010898855308580978867,205255454905325730631914319249,1233457775854251160763811229216063007, 1751952685614616185916001760791655006749]

p(n:PI):PI==(j:=1;a:=3;s:=n^.2;repeat(b:=j:=nextPrime(j);repeat(b<s=>(b:=b*j);break);a:=powmod(a,b,n);d:=gcd(a-1,n);d>1 or j>n=>break);d)

-- this would try to factor n with p-1 Pollard method
pm1(n:PI):PI==
   j:=1;a:=3;s:=n^.2
   repeat
      b:=j:=nextPrime(j)
      repeat(b<s=>(b:=b*j);break)
      a:=powmod(a,b,n)
      d:=gcd(a-1,n);d>1 or j>n=>break
   d

test()==(for i in 1..#vA repeat output [vA.i, p(vA.i)])

risultati qui:

(5) -> test()
   [187,11]
   [1679,73]
   [14369648346682547857,9576890767]
   [34747575467581863011,9576890767]
   [52634041113150420921061348357,2860486313]
   [82312263010898855308580978867,311111111111113]
   [205255454905325730631914319249,2860486313]
   [1233457775854251160763811229216063007,1111111999999]
   [1751952685614616185916001760791655006749,36413321723440003717]
                                                               Type: Void
                              Time: 496.78 (EV) + 53.05 (GC) = 549.83 sec

Potresti precisare esattamente come eseguire questo codice dalla riga di comando in Ubuntu per favore? Ho installato axiom e creato un file chiamato foo.ax con il tuo codice non golfato.

@Lembik 1) rinomina fop.ax in foo.input 2) esegui Axiom in un terminale o xterm 3) scrivi in ​​quel terminale Axiom il seguente comando ") leggi C: absolutepath \ foo" 4) scrivi nel terminale di Axiom la chiamata test funzionale (). Ecco come fare in Windows, mi sembra che apra una sessione di Axiom e carichi il file con il comando ") read"
RosLuP

@Lembik se ci sono problemi con i file penso che sarebbe anche ok: 1) esegui Axiom 2) scrivi) tempo su <return> nel programma Axiom 3) copia incolla e premi Invio in ogni "copia incolla" nel programma Axiom: il array vA, la funzione p () e test () 4) nel programma Axiom write test () <return>
RosLuP

@Lembik quindi che tempo ci vuole?
RosLuP,

1

Assioma, 10 minuti + 31 secondi

A(a)==>a:=(a*a+7)rem n;z(n)==(p:=a:=b:=101;for i in 1..repeat(A(a);A(b);A(b);p:=mulmod(p,a-b,n);i rem 999<9=>(p:=gcd(p,n);p>1=>break));p)

z () è la funzione rho, una funzione di 137 byte; ungolfed z () e chiamarlo come rho (). Supponiamo che gcd (0, n) = n, quindi il ciclo si arresti e ritorni per errore n.

)time on    
rho(n)==
  p:=a:=b:=101
  for i in 1..repeat
          A(a);A(b);A(b)
          p:=mulmod(p,a-b,n)
          i rem 999<9=>(p:=gcd(p,n);p>1=>break)
  p

va1:=[187,1679,14369648346682547857,34747575467581863011,52634041113150420921061348357,82312263010898855308580978867,205255454905325730631914319249,1233457775854251160763811229216063007, 1751952685614616185916001760791655006749]
p1()==(for i in 1..#va1-1 repeat output [va1.i,z(va1.i)]) 

risultati (z () è ok per tutti ma l'ultimo numero 1751952685614616185916001760791655006749 non viene considerato (10 minuti))

(6) -> p1()
   [187,17]
   [1679,23]
   [14369648346682547857,1500450271]
   [34747575467581863011,3628273133]
   [52634041113150420921061348357,2860486313]
   [82312263010898855308580978867,264575131106459]
   [205255454905325730631914319249,2860486313]
   [1233457775854251160763811229216063007,1111111999999]
                                                               Type: Void
                                 Time: 30.38 (EV) + 1.38 (GC) = 31.77 sec

(8) -> z(1679)
   (8)  23
                                                    Type: PositiveInteger
                                                              Time: 0 sec

0

Python 3 , 100 99 byte, 45 40 39 secondi + 10 minuti di penalità

import math
def f(n):
 x=y=2;d=1
 while d<2:y=y*y+1;x,y=1+x*x%n,y*y%n+1;d=math.gcd(x-y,n)
 return d

Provalo online!

Usa Pollard-Rho con valore iniziale 2 e polinomio x ^ 2 + 1.


È possibile utilizzare pow(con il terzo argomento) per migliorare la velocità di esecuzione.
mbomb007,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.