¿Cómo se elige el anillo interno en el algoritmo Schönhage – Strassen?


9

He estado tratando de implementar el algoritmo de multiplicación de enteros de Schönhage-Strassen, pero me topé con un obstáculo en el paso recursivo.

Tengo un valor con bits y quiero calcular x ^ 2 \ pmod {2 ^ n + 1} . Originalmente pensé que la idea era elegir una k tal que 4 ^ k \ geq 2n , dividir x en 2 ^ k piezas cada una con 2 ^ {k-1} bits, aplicar la convolución de SSA mientras se trabaja el módulo 2 ^ {2 ^ k} +1 , un anillo con 2 ^ k bits de capacidad por valor, luego vuelve a juntar las piezas. Sin embargo, la salida de la convolución tiene un poco más de 2n bits (es decir, > 2 ^ knxnx2(mod2n+1)4 k2 n x 2 k 2 k - 1 2 2 k + 1 2 k 2 n > 2 kk4k2nx2k2k122k+12k2norte>2kbits por valor de salida, que es más que la capacidad del anillo, debido a que cada valor de salida es una suma de varios productos), por lo que esto no funciona. Tuve que agregar un factor adicional de 2 de relleno.

Ese factor adicional de 2 en el relleno arruina la complejidad. Hace que mi paso recursivo sea demasiado caro. En lugar de un algoritmo F(norte)=nortelgnorte+norteF(2norte)=Θ(nortelgnortelglgnorte) , termino con un algoritmo F(norte)=nortelgnorte+norteF(4 4norte)=Θ(nortelg2norte) .

Leí algunas referencias vinculadas desde wikipedia, pero todas parecen pasar por alto los detalles de cómo se resuelve este problema. Por ejemplo, podría evitar la sobrecarga de relleno adicional trabajando el módulo 2pags2k+1 para un pags que no es una potencia de 2 ... pero luego las cosas se rompen más tarde, cuando solo tengo no poder- de-2 factores restantes y no se puede aplicar Cooley-Tukey sin duplicar el número de piezas. Además, pags puede no tener un módulo inverso multiplicativo 2pags+1 . Entonces todavía hay factores forzados de 2 introducidos.

¿Cómo elijo el anillo para usar durante el paso recursivo, sin soplar la complejidad asintótica?

O, en forma de pseudocódigo:

multiply_in_ring(a, b, n):
  ...
  // vvv                          vvv //
  // vvv HOW DOES THIS PART WORK? vvv //
  // vvv                          vvv //
  let inner_ring = convolution_ring_for_values_of_size(n);
  // ^^^                          ^^^ //
  // ^^^ HOW DOES THIS PART WORK? ^^^ //
  // ^^^                          ^^^ //

  let input_bits_per_piece = ceil(n / inner_ring.order);
  let piecesA = a.splitIntoNPiecesOfSize(inner_ring.order, input_bits_per_piece);
  let piecesB = b.splitIntoNPiecesOfSize(inner_ring.order, input_bits_per_piece);

  let piecesC = inner_ring.negacyclic_convolution(piecesA, piecesB);
  ...

Por favor, no publicar la misma pregunta en varios sitios . Cada comunidad debe tener una oportunidad honesta de responder sin perder el tiempo de nadie. Le sugiero que elimine una de las dos copias.
DW

@DW Hecho. Hice una publicación cruzada después de que cs no dio ninguna respuesta durante una semana, pensando que era demasiado difícil para ese sitio. Iba a vincular cualquier respuesta obviamente.
Craig Gidney

Entiendo. Si aparece en el futuro, siempre puede marcar su publicación para atención del moderador y solicitar que se migre, y podemos moverla por usted a CSTheory. ¡Gracias por su comprensión!
DW

3
Existe una versión del algoritmo que funciona con números de módulo de la forma : A. Schönhage. Algoritmos asintóticamente rápidos para la multiplicación numérica y la división de polinomios con coeficientes complejos. En EUROCAM '82: European Computer Algebra Conference, Lect. Notas Comp. Sci. 144, 3-15. iai.uni-bonn.de/~schoe/publi39.dvi2ν2norte
Markus Bläser

IIRC usted tuvo una respuesta parcial en la pregunta CS ahora eliminada. Parece una pena perder eso. ¿Podría incluirlo aquí (en la pregunta, para que la pregunta no esté marcada como ya respondida)?
Peter Taylor

Respuestas:


4

Esta respuesta está tomada del documento "Algoritmos asintóticamente rápidos para la muitiplicación numérica y la división de polinomios con coeficientes complejos" que Markus vinculó en los comentarios.


Desea elevar al cuadrado un número de bits, módulo . Esto es lo que haces:2 n + 1norte2norte+1

  • Encuentra y que satisfacen y .s n = ( p - 1 ) 2 s s p 2 spagssnorte=(pags-1)2sspags2s

  • Elija el número de piezas para dividir los bits y los parámetros correspondientes para los tamaños de pieza: n2metronorte

    metro=s/ /2+1s2=s/ /2+1pags2=pags/ /2+1

    Tenga en cuenta que y continúan satisfaciendo la invariante . También tenga en cuenta que está satisfecho, por lo que la entrada se ajusta con espacio para acarreos.p 2s2pags22 m 2 s 2 p 22 n + m + 1s2pags22s22metro2s2pags22norte+metro+1

  • Realice la convolución negacyclic basada en FFT en las piezas y el resto, como de costumbre.

Esa es la idea general: un factor de relleno logarítmico . Ahora para el análisis de complejidad. La FFT se llevará trabajo por hacer, y estamos recursividad en piezas de tamaño , por lo que ahora podemos hacer operaciones matemáticas muy duro con la recurrencia relación WRT :n m 2 m ( p 2 - 1 ) 2 s 2 spagsnortemetro2metro(pags2-1)2s2s

F(s)()(pags-1)2smetro+2metroF(s/ /2+1)()2s2s(s/ /2+1)+2s/ /2+1F(s/ /2+1)()s22s+22s/ /2F(s/ /2+1)()s22s+4 4(s/ /2)22s+dieciséis(s/ /4 4)22s+...()2ss2lg(s)()nortelgnorte(lgnortelgnorte)2lglgnortelgnorte()nortelgnorte(lg2norte)lglgnorte()norte(lgnorte)lglgnorte

Lo cual parece correcto, aunque hice trampa en esos pasos.

El 'truco' parece ser el hecho de que terminamos con lugar de en el costo base. Todavía hay dos multiplicaciones por dos por nivel recursivo, como me estaba quejando en la pregunta, pero ahora la reducción a la mitad de está pagando dividendos dobles, por lo que todo funciona. Luego, al final, cancelamos el factor adicional de (que en realidad es un factor de ) gracias a que inicialmente logarítmicamente es grande en relación con .s2sssIniciar sesiónnortepagss

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.