Golf los pseudoprimes!

9

Introducción / antecedentes

En una discusión reciente en el chat de cifrado, tuve el desafío de discutir / ayudar con la prueba de primalidad de Fermat y los números de Carmichael. Esta prueba se basa en la premisa que a^(p-1) mod p==1siempre se mantendrá para los primos p, pero no siempre para los compuestos. Ahora, un número de Carmichael es esencialmente el peor enemigo de la prueba de Fermat: un número para el que tienes que elegir apara no ser primo ppara obtener a^(p-1) mod p!=1. Ahora, si ano es co-prime, esencialmente encontraste un factor no trivial depy como todos sabemos, factorizar puede ser bastante difícil. Especialmente si todos los factores son suficientemente grandes. Ahora puede darse cuenta de por qué la prueba de Fermat no se usa en la práctica con tanta frecuencia (bueno, hay mejores algoritmos), es porque hay números para los que usted como defensor (en términos de seguridad) tendría que hacer una cantidad similar de trabajo que un atacante (es decir, factorizar el número).

Entonces, ahora que sabemos por qué estos números son algo fascinantes, los generaremos de la manera más breve posible, ¡así que podemos memorizar el código de generación si alguna vez necesitamos alguno!

Los números de Carmichael también se conocen como A002997 en OEIS . Ya
existe un desafío relacionado , pero las entradas desde allí no son competitivas aquí porque están optimizadas para la velocidad en lugar del tamaño. El mismo argumento es válido para la dirección inversa, es probable que las entradas aquí hagan compensaciones contra la velocidad a favor del tamaño.

Especificación

Entrada

Este es un desafío de estándar , por lo que toma un entero positivo o no negativo ncomo entrada. npuede estar indexado 0 o 1 como prefiera (indíquelo).

Salida

Su salida será el nenésimo número carmichael o los primeros nnúmeros carmichael, como prefiera (indíquelo).

Especificación

Un entero xes un número de Carmichael si y solo si xes compuesto y para todos los enteros ycon gcd(x,y)=1, contiene quey^(x-1) mod x==1 .

¿Quién gana?

Este es el , por lo que gana el código más corto en bytes.
Se aplican las reglas estándar de E / S y lagunas.

Casos de prueba

Los primeros números de Carmichael son:

 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
SEJPM
fuente

Respuestas:

6

Python 2 , 92 bytes

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

Pruébalo en línea!

1 indexado y lento como la melaza.

En la comprensión de la lista, utilizo el método de Dennis para generar todos los números enteros coprimos an ( totativos de n ), y luego calculox**~-n%n para todos ellos. Llamemos a esta lista L.

Para detectar un número de Carmichael, comparo esta lista lexicográficamente con una lista que consta de n-1unos. ¿Por qué funciona esto?

Cada elemento de Les un número entero positivo: (k/n)es coprimo para n, (k/n)**~-ntambién lo es, así (k/n)**~-n%n > 0. Por lo tanto, los únicos valores posibles de Leso son lexicográficamente menores que [1]*(n-1) los que consisten enteramente en menos de n-1 unos. (¡ Lno puede contener más que n-1valores, ya nque no puede tener más que n-1totativos! Entonces las comparaciones como[1,1,1,1,3] < [1,1,1,1] están fuera).

Verificar que haya menos de n-1entradas Lasegura que nsea ​​compuesto. (Tener n-1totativos es una condición equivalente a la primalidad). Y luego, la condición para ser un número de Carmichael es exactamente que cada elemento de Ligual 1. Entonces, esta comparación lexicográfica detecta exactamente los correos electrónicos Lque nos interesan.

El Sr. Xcoder guardó un byte al cambiar a la forma recursiva lambda: jcuenta regresiva cada vez que tocamos un número de Carmichael y ncuenta cada vez que recurrimos. Entonces, una vez que jllega a cero, n-1es igual al original_value_of_jnúmero th de Carmichael.

Lynn
fuente
5

Jalea ,  12  11 bytes

-1 byte gracias a miles & Mr. Xcoder (uso del átomo de función Carmichael y un golf del mismo)

%Æc’=ÆP
⁹Ç#

Un enlace monádico que toma ny devuelve una lista de los primeros nnúmeros de Carmichael.

Pruébalo en línea!

¿Cómo?

Al igual que el anterior (a continuación), excepto que hay una función incorporada para la función Carmichael, que produce la potencia más pequeña de tal manera que la entrada elevada a esa potencia es congruente con un módulo que la potencia para todos los enteros co-prime a ese entero. Por lo tanto, podemos excluir los falsos positivos (primos) en menos bytes y tener un código más rápido.

%Æ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

Anteriores 12 bytes :

Ṗ*%⁼Ṗ_ÆP
⁹Ç#

Pruébalo en línea! (Sí, se agota el tiempo para n=3).

¿Cómo?

Un número, ces un número de Carmichael si es compuesto y es cierto que cualquier número entero x, elevado a ces congruente con el xmódulo c.

Tan sólo hay que comprobar esto de positivo xa x=csí mismo.

Tenga en cuenta también que en x=cla verificación se determina si xelevar a la potencia de xes congruente con el xmódulo x, lo cual es cierto, por lo que no necesitamos verificar esto (esto hace que el código sea más corto).

Ṗ*%⁼Ṗ_Æ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
Jonathan Allan
fuente
También tiene 12 bytes, pero calcula los primeros 33 en menos de un minuto utilizando el átomo de Carmichael.
millas
11 bytes utilizando la función incorporada de Carmichael.
Sr. Xcoder
@ Mr.Xcoder Iba a sugerir millas publicadas por separado, luego vi la suya, luego vi su comentario y lo borré. El dv puede deberse a que alguien piensa que es demasiado similar a millas 'comentó uno en lugar de este, pero creo que incluso eso es una razón extraña ya que no hay razón para pensar que no encontraste lo mismo de forma independiente (sé que' he hecho ese tipo de cosas muchas veces). Publicaré sus 11 si lo desea, pero soy de la opinión de que usted o sus millas deben tomar algo de crédito.
Jonathan Allan
@miles también ... ^
Jonathan Allan
@ JonathanAllan Solo publícalo tú mismo. Mencione millas y mi contribución, y tampoco creo que miles de mentes :-) (Por cierto, ni siquiera vi el comentario de millas: - / antes de publicar mi respuesta)
Sr. Xcoder
2

ECMAScript Regex, 86 89 bytes

Advertencia: no leas esto si no quieres que te estropeen un poco de magia regex unaria. Si desea intentar descubrir esta magia usted mismo, le recomiendo comenzar resolviendo algunos problemas en la expresión regular ECMAScript: consulte esta publicación anterior para obtener una lista de problemas recomendados etiquetados consecutivamente con spoilers para resolver uno por uno.

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

Pruébalo en línea!

# 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 principal de esta expresión regular está en la parte que afirma que todos los factores primos de N son de multiplicidad exactamente única. Es el mismo truco utilizado por mis cadenas Match, cuya longitud es una cuarta potencia y expresiones regulares de Find the Smoothest Number : división implícita repetida por el factor primo más pequeño.

También es posible probar directamente que N no tiene factores de cuadrado perfecto (es decir, que N no tiene cuadrado). Utiliza una variante del algoritmo de multiplicación que se describe brevemente en un párrafo de mi publicación de expresiones regulares abundantes para probar si un número es un cuadrado perfecto. Este es un spoiler . Así que no sigas leyendo si no quieres que se te estropee un poco de magia regex unaria avanzada . Si desea intentar descubrir esta magia usted mismo, le recomiendo comenzar resolviendo algunos problemas en la lista de problemas recomendados etiquetados consecutivamente con spoilers en esta publicación anterior , e intentando encontrar las ideas matemáticas de forma independiente.

Sin embargo, el uso de ese algoritmo en este problema no proporciona ningún beneficio. Resulta en una expresión regular más lenta, con un tamaño mayor de 97 bytes. Sin la prueba de multiplicidad primaria (que en un bucle afirma que hay al menos 2 factores primos y que cada uno es de multiplicidad única), tenemos que afirmar por separado que N es compuesto.

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

Pruébalo en línea!


 ^
 (?!
     # 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
 

Código muerto
fuente
2
(Hablando estrictamente, esta es una decision-problemrespuesta, pero el desafío es un sequencedesafío.) ¿Presumiblemente en una variante de expresión regular más poderosa habría una prueba más directa para los divisores cuadrados disponibles?
Neil
@Neil Tienes razón, puedo jugar golf probando directamente los divisores cuadrados. En ECMA, no se necesitan funciones adicionales. Pero eso lo hará mucho más lento (y también querré ocultarlo debajo de una etiqueta de spoiler). Creo que quiero incluir ambas versiones.
Código muerto el
Sí, es muy molesto encontrar preguntas para expresiones regulares que ya he escrito, que no son el tipo correcto de desafío. ¿Debo eliminar mi respuesta?
Código muerto el
@Neil Aquí tienes. Implementé el algoritmo usando tu idea. Sin embargo, esta es probablemente la razón por la que no pensé en perseguirlo por mi cuenta; en realidad resulta en una expresión regular más larga, porque se necesita una prueba compuesta.
Código muerto el
(Según las reglas del sitio, debería eliminar su respuesta, sí.) Mi idea era que usando características adicionales de, por ejemplo, expresiones regulares de Retina, podría reducirlo a golf ^(?!(x(x+))(?!\2*$)\1*(?=\1$)(?!(xx+)\3+$)|((^x|xx\5){2,})\4*$)(xx+)\6+$, o tal vez incluso menos de 72 bytes.
Neil
1

Retina , 94 bytes

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

Pruébalo en línea!1 indexado. No es rápido, por lo que se n>5agotará el tiempo en TIO. Explicación:

\d*$
x

Incrementar el valor actual. En la primera pasada, esto también eliminan del búfer de salida (pero $+aún puede acceder a él).

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

Pruebe si el valor actual es un número de Carmichael. Esto utiliza el algoritmo alternativo de @ Deadcode, ya que la detección de cuadrados es más corta cuando se escribe usando .NET / Perl / PCRE regex.

^+`

Repita hasta que el valor actual sea un número Carmichael.

$
x

Incrementar el valor actual.

"$+"}

Repita el incremento inicial y el bucle anterior n tiempos de .

x

Convierte el resultado a decimal.

Neil
fuente
0

Haskell , 95 bytes

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

Pruébalo en línea!

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
Max Yekhlakov
fuente