Golf gli pseudoprimi!


9

Introduzione / Contesto

In una recente discussione nella chat crittografica sono stato sfidato a discutere / aiutare con il test di primalità di Fermat e i numeri di Carmichael. Questo test si basa sulla premessa che a^(p-1) mod p==1sarà sempre valida per i numeri primi p, ma non sempre per i composti. Ora un numero di Carmichael è essenzialmente prova il peggior nemico di Fermat: numero A per il quale si deve scegliere adi non essere co-prime con pper ottenere a^(p-1) mod p!=1. Ora, se anon è co-prime, hai essenzialmente trovato un fattore non banale dipe come tutti sappiamo il factoring può essere piuttosto difficile. Soprattutto se tutti i fattori sono sufficientemente grandi. Ora puoi capire perché il test di Fermat non viene utilizzato nella pratica spesso (bene ci sono algoritmi migliori), è perché ci sono numeri per i quali tu come difensore (in termini di sicurezza) dovresti fare un lavoro simile come un attaccante (ovvero fattore il numero).

Quindi ora che sappiamo perché questi numeri sono in qualche modo affascinanti, li genereremo nel modo più breve possibile, quindi possiamo semplicemente memorizzare il codice di generazione se mai ne avremo bisogno!

I numeri di Carmichael sono anche conosciuti come A002997 su OEIS .
Esiste già una sfida correlata , ma qui le voci non sono competitive perché sono ottimizzate per la velocità rispetto alle dimensioni. Lo stesso argomento vale per la direzione inversa, le voci qui sono suscettibili di compromettere la velocità a favore delle dimensioni.

specificazione

Ingresso

Questa è una sfida di standard , quindi prendi un intero positivo o non negativo ncome input. npuò essere indicizzato 0 o 1 come preferisci (si prega di indicare).

Produzione

Il tuo output sarà il n-th numero di carmichael o il primo nnumero di carmichael, come preferisci (per favore indica).

specificazione

Un numero intero xè un numero di Carmichael se e solo se xè composto e per tutti i numeri interi ycon gcd(x,y)=1, lo detiene y^(x-1) mod x==1.

Chi vince?

Questo è , quindi vince il codice più corto in byte!
Si applicano le regole IO e scappatoie standard.

Casi test

I primi pochi numeri di Carmichael sono:

 561,1105,1729,2465,2821,6601,8911,10585,15841,
 29341,41041,46657,52633,62745,63973,75361,101101,
 115921,126217,162401,172081,188461,252601,278545,
 294409,314821,334153,340561,399001,410041,449065,
 488881,512461

Risposte:



6

Python 2 , 92 byte

f=lambda j,n=1:j and f(j-([(k/n)**~-n%n for k in range(n*n)if k/n*k%n==1]<[1]*~-n),n+1)or~-n

Provalo online!

1-indicizzato e lento come melassa.

Nella comprensione della lista, uso il metodo di Dennis per generare tutti i interi interi inn (i totali di n ), e quindi calcolo x**~-n%nper tutti loro. Chiamiamo questo elenco L.

Per rilevare un numero di Carmichael, confronto questo elenco lessicograficamente con un elenco costituito da n-1quelli. Perché funziona?

Ogni elemento di Lè un numero intero positivo: (k/n)è coprime a n, quindi (k/n)**~-nlo è anche (k/n)**~-n%n > 0. Pertanto, gli unici valori possibili di Lciò sono lessicograficamente inferiori a [1]*(n-1) quelli costituiti interamente da meno di n-1 quelli. ( Lnon può contenere più di n-1valori, in quanto nnon può avere più di n-1totali! Quindi confronti come [1,1,1,1,3] < [1,1,1,1]sono fuori.)

Controllare che ci siano meno di n-1voci in Lassicura che nsia composito. (Avere i n-1totali è una condizione equivalente alla primalità.) E quindi, la condizione per essere un numero di Carmichael è esattamente che ogni elemento è Luguale 1. Quindi questo confronto lessicografico rileva esattamente le Ls che ci interessano.

Il signor Xcoder ha salvato un byte passando alla forma lambda ricorsiva: fa il jconto alla rovescia ogni volta che colpiamo un numero di Carmichael e nconta ogni volta che ci reclutiamo. Quindi una volta che jarriva a zero, è n-1uguale al original_value_of_j'th numero Carmichael.


5

Gelatina ,  12  11 byte

-1 byte grazie a miglia e Mr. Xcoder (uso della funzione Atom di Carmichael e un suo golf)

%Æc’=ÆP
⁹Ç#

Un collegamento monadico che prende ne restituisce un elenco dei primi nnumeri di Carmichael.

Provalo online!

Come?

Proprio come il precedente (sotto) tranne per il fatto che esiste una funzione incorporata per la funzione Carmichael - che produce la più piccola potenza in modo tale che l'input elevato a quella potenza sia congruente a un modulo che la potenza di tutti gli interi coincide con quell'intero. Quindi possiamo escludere i falsi positivi (numeri primi) in meno byte e avere un codice più veloce!

%Æc’⁼ÆP - isCarmichael: number, n (any integer)
 Æc     - Carmicael function of n
%       - n modulo that
   ’    - decremented (0 for Carmichael numbers and primes)
     ÆP - is n prime? (1 for primes 0 otherwise)
    ⁼   - equal?

⁹Ç# - Main link: number, n
  # - count up finding the first n values satisfying:
 Ç  - ...condition: call the last link as a monad
⁹   - ...starting with a value of: literal 256

12 byte precedenti :

Ṗ*%⁼Ṗ_ÆP
⁹Ç#

Provalo online! (Sì, va in timeout per n=3).

Come?

Un numero, cè un numero di Carmichael se è composto ed è vero che qualsiasi numero intero x, elevato a cè congruente al xmodulo c.

Dobbiamo solo controllare questo per positivo xfino a x=cse stesso.

Si noti inoltre che al momento x=cdel controllo è se xil potere di xè congruente al xmodulo x, il che è vero, quindi non è necessario verificarlo (questo rende il codice più breve).

Ṗ*%⁼Ṗ_ÆP - Link 1, isCarmichaelNumber: integer c (greater than 1)
Ṗ        - pop c (uses the implicit range(c)) = [1, 2, 3, ..., c-1]
 *       - raise to the power of c (vectorises) = [1^c, 2^c, 3^c, ..., (c-1)^c]
  %      - modulo by c (vectorises) = [1^c%c, 2^c%c, 3^c%c, ..., (c-1)^c%c]
    Ṗ    - pop c = [1, 2, 3, ..., c-1]
   ⁼     - equal? (non-vectorising) = 1 if so, 0 if not
      ÆP - isPrime?(c) = 1 if so, 0 if not
     _   - subtract = 1 if Carmichael 0 if not
         -     (Note the caveat that c must be an integer greater than 1, this is because
         -      popping 1 yields [] thus the equality check will hold; same for 0,-1,...)

⁹Ç# - Main link: number, n
  # - count up finding the first n values satisfying:
 Ç  - ...condition: call the last link as a monad
⁹   - ...starting with a value of: literal 256

Anche 12 byte ma calcola i primi 33 in meno di un minuto usando l'atomo di Carmichael.
miglia

11 byte utilizzando la funzione integrata Carmichael.
Mr. Xcoder,

@ Mr.Xcoder Stavo per suggerire miglia postate separatamente, quindi ho visto le tue, poi ho visto il tuo commento ed eliminato. Il dv può essere dovuto al fatto che qualcuno pensa che sia troppo simile al commento di miglia piuttosto che a questo, ma penso che anche quello sia uno strano motivo poiché non c'è motivo di pensare che non hai trovato la stessa cosa in modo indipendente (lo so che ' ho fatto questo genere di cose molte volte). Pubblicherò i tuoi 11 se vuoi, ma sono dell'opinione che tu o miglia dovresti prenderti un po 'di credito.
Jonathan Allan,

@miles too ... ^
Jonathan Allan,

@JonathanAllan Pubblicalo tu stesso. Cita le miglia e il mio contributo, e non penso neanche alle menti delle miglia :-) (A proposito non ho nemmeno visto il commento delle miglia: - / prima di pubblicare la mia risposta)
Mr. Xcoder

2

ECMAScript Regex, 86 89 byte

Avvertenza: non leggerlo se non vuoi che qualche magia regex unaria venga rovinata per te. Se vuoi provare a capire da solo questa magia, ti consiglio vivamente di iniziare risolvendo alcuni problemi nella regex di ECMAScript: vedi questo post precedente per un elenco di problemi consecutivi contrassegnati con spoiler per risolvere uno per uno.

^(?!(x(x+))(?!\2*$)\1*(?=\1$)(?!(xx+)\3+$))((?=(xx+?)\5*$)(?=(x+)(\6+$))\7(?!\5*$)){2,}x$

Provalo online!

# Match Carmichael numbers in the domain ^x*$ using Korselt's criterion
# N = input number (initial value of tail)
^
(?!
    # Iterate through factors \1, with \2 = \1-1, for which \2 does not divide into N-1
    (x(x+))
    (?!\2*$)           # Assert N-1 is not divisible by \2
    \1*(?=\1$)         # Assert N is divisible by \1; tail = \1
    # If the factor \1, which already passed the aboved tests, is prime, then fail the
    # outside negative lookahead, because N is not a Carmichael number.
    (?!(xx+)\3+$)
)
# Assert that N has at least 2 unique prime factors, and that all of its prime factors
# are of exactly single multiplicity (i.e. that N is square-free).
(
    (?=(xx+?)\5*$)     # \5 = smallest prime factor of tail
    (?=(x+)(\6+$))     # \6 = tail / \5 (implicitly); \7 = tool to make tail = \6
    \7                 # tail = \6
    (?!\5*$)           # Assert that tail is no longer divisible by \5, i.e. that that
                       # prime factor was of exactly single multiplicity.
){2,}
x$

La magia principale di questa regex sta nella parte che afferma che tutti i fattori primi di N sono di una molteplicità esattamente singola. È lo stesso trucco usato dalle mie stringhe Match la cui lunghezza è una quarta potenza e regex Trova il numero più regolare: ripetuta divisione implicita per il fattore primo più piccolo.

È anche possibile testare direttamente che N non ha fattori del quadrato perfetto (cioè che N è privo di quadrati). Questo utilizza una variante dell'algoritmo di moltiplicazione brevemente descritto in un paragrafo dei miei post abbondanti di regex per verificare se un numero è un quadrato perfetto. Questo è uno spoiler . Quindi non leggere oltre se non vuoi che qualche magia regex unaria avanzata venga viziata per te . Se vuoi provare a capire da solo questa magia, ti consiglio vivamente di risolvere alcuni problemi nell'elenco di problemi consecutivamente contrassegnati con spoiler in questo post precedente e di provare a elaborare le intuizioni matematiche in modo indipendente.

L'uso di questo algoritmo su questo problema non offre tuttavia alcun vantaggio. Il risultato è una regex più lenta, con una dimensione maggiore di 97 byte. Senza il test di molteplicità primo (che in un ciclo afferma sia che ci sono almeno 2 fattori primi sia che sono ciascuno di singola molteplicità), dobbiamo affermare separatamente che N è composito.

^(?!(x(x+))(?!\2*$)\1*(?=\1$)(?!(xx+)\3+$)|((xx+)\5*(?=\5$))?(x(x*))(?=(\6*)\7+$)\6*$\8)(xx+)\9+$

Provalo online!


 ^
 (?!
     # Iterate through factors \1, with \2 = \1-1, for which \2 does not divide into N-1
     (x(x+))
     (?!\2*$)           # Assert N-1 is not divisible by \2
     \1*(?=\1$)         # Assert N is divisible by \1; tail = \1
     # If the factor \1, which already passed the aboved tests, is prime, then fail the
     # outside negative lookahead, because N is not a Carmichael number.
     (?!(xx+)\3+$)
 |
 # Assert that N is square-free, i.e. has no divisor >1 that is a perfect square.
     ((xx+)\5*(?=\5$))?  # cycle tail through all of the divisors of N, including N itself
     # Match iff tail is a perfect square
     (x(x*))             # \6 = potential square root; \7 = \6 - 1
     (?=
         (\6*)\7+$       # iff \6 * \6 == our number, then the first match here must result in \8 == 0
     )
     \6*$\8              # test for divisibility by \6 and for \8 == 0 simultaneously
 )
 (xx+)\9+$               # Assert that N is composite
 


2
(A rigor di termini, questa è una decision-problemrisposta, ma la sfida è una sequencesfida.) Presumibilmente in una variante regex più potente ci sarebbe un test più diretto per i divisori quadrati?
Neil,

@Neil Hai ragione, posso golf giù testando direttamente per i divisori quadrati. In ECMA, non sono necessarie funzionalità extra. Ma questo renderà molto più lento (e vorrò anche nasconderlo sotto un tag spoiler). Vorrei includere entrambe le versioni, credo.
Deadcode

Sì, è molto fastidioso trovare domande per le regex che ho già scritto, che non sono il giusto tipo di sfida. Devo cancellare la mia risposta?
Deadcode

@Neil Ecco qua. Ho implementato l'algoritmo usando la tua idea. Questo è probabilmente il motivo per cui non pensavo di perseguirlo da solo; si traduce in realtà in una regex più lunga, perché è necessario un test is-composite.
Deadcode

(In base alle regole del sito dovresti eliminare la tua risposta, sì.) La mia idea era che usando funzionalità extra, diciamo, regex Retina, si potesse golfare fino a ^(?!(x(x+))(?!\2*$)\1*(?=\1$)(?!(xx+)\3+$)|((^x|xx\5){2,})\4*$)(xx+)\6+$, o forse anche meno di 72 byte.
Neil,


1

Retina , 94 byte

\d*$
x
"$+"}/^(?!(x(x+))(?!\2*$)\1*(?=\1$)(?!(xx+)\3+$)|((^x|xx\5){2,})\4*$)(xx+)\6+$/^+`$
x
x

Provalo online! 1-indicizzati. Non veloce, quindi n>5scadrà per TIO. Spiegazione:

\d*$
x

Incrementa il valore corrente. Al primo passaggio, anche questo viene eliminato ndal buffer di output (ma $+può ancora accedervi).

/^(?!(x(x+))(?!\2*$)\1*(?=\1$)(?!(xx+)\3+$)|((^x|xx\5){2,})\4*$)(xx+)\6+$/

Verifica se il valore corrente è un numero di Carmichael. Questo utilizza l'algoritmo alternativo di @ Deadcode, poiché il rilevamento quadrato è più breve quando scritto usando regex .NET / Perl / PCRE.

^+`

Ripetere fino a quando il valore corrente è un numero di Carmichael.

$
x

Incrementa il valore corrente.

"$+"}

Ripeti l'incremento iniziale e i ntempi di ciclo sopra indicati .

x

Converti il ​​risultato in decimale.


0

Haskell , 95 byte

s=filter
c n=s(\x->let l=s((1==).gcd x)f;f=[1..x-1]in l/=f&&all(\y->y^(x-1)`mod`x==1)l)[1..]!!n

Provalo online!

Degolfed:

-- function to filter out Carmichael numbers
filterFunction x = 
    let coprimes = filter ((1 ==) . gcd x) lesserNumbers
        lesserNumbers = [1 .. x - 1]
    in
        -- the number x is Carmichael if it is not prime
        lesserNumbers /= coprimes && 
            -- and all of its coprimes satisfy the equation
            all (\y -> y ^ (x - 1) `mod` x == 1) coprimes

-- get n'th Carmichael number (zero-based)
c n = filter filterFunction [1..] !! n
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.