Jak wybiera się pierścień wewnętrzny w algorytmie Schönhage – Strassen?


9

Próbowałem zaimplementować algorytm mnożenia liczb całkowitych Schönhage-Strassen, ale natknąłem się na przeszkodę w kroku rekurencyjnym.

I mają wartość o bitów i Aby obliczyć . Początkowo myślałem, że pomysł takiego, że , podziel na kawałki każdy za pomocą bitów, zastosuj splot SSA podczas pracy modulo , pierścień z bitami pojemności na wartość, a następnie złóż kawałki z powrotem. Jednak wyjście splotu ma nieco więcej niż bitów (tj.xnx2(mod2n+1)k4k2nx2k2k122k+12k2n>2kbitów na wartość wyjściową, która jest większa niż pojemność pierścienia, ponieważ każda wartość wyjściowa jest sumą kilku produktów), więc to nie działa. Musiałem dodać dodatkowy współczynnik 2 wypełnień.

Ten dodatkowy współczynnik 2 w wypełnieniu psuje złożoność. To sprawia, że ​​mój krok rekurencyjny jest zbyt drogi. Zamiast algorytmu kończę z algorytmem F (n) = n \ lg n + \ sqrt {n} F (4 \ sqrt {n}) = \ Theta (n \ lg ^ 2 n) .F(n)=nlgn+nF(2n)=Θ(nlgnlglgn)F(n)=nlgn+nF(4n)=Θ(nlg2n)

Przeczytałem kilka odnośników z wikipedii, ale wszystkie wydają się rozmyślać o szczegółach rozwiązania tego problemu. Na przykład, mógłbym uniknąć dodatkowego narzutu, pracując modulo 2p2k+1 dla p który nie jest potęgą 2 ... ale potem wszystko się psuje później, kiedy mam tylko brak mocy z 2 pozostałych czynników i nie można zastosować Cooleya-Tukeya bez podwojenia liczby elementów. Ponadto p może nie mieć multiplikatywnego odwrotnego modułu 2p+1 . Wciąż wprowadzane są czynniki wymuszone 2.

Jak wybrać pierścień do użycia podczas etapu rekurencyjnego, nie powodując asymptotycznej złożoności?

Lub w formie pseudokodu:

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);
  ...

Proszę nie pisać to samo pytanie na wielu stronach . Każda społeczność powinna rzetelnie odpowiedzieć na pytanie bez marnowania czasu. Sugeruję usunięcie jednej z dwóch kopii.
DW

@DW Gotowe. Przesłałem po tym, jak cs nie dał żadnych odpowiedzi przez tydzień, stwierdzając, że to było zbyt trudne dla tej strony. Najwyraźniej zamierzał odsyłać wszelkie odpowiedzi.
Craig Gidney

Rozumiem. Jeśli pojawi się w przyszłości, zawsze możesz oflagować swój post dla uwagi moderatora i poprosić o migrację, a my możemy przenieść go dla Ciebie do CSTheory. Dziękuję za zrozumienie!
DW

3
Istnieje wersja algorytmu, która działa na liczbach modulo formularza 2ν2n: A. Schönhage. Asymptotycznie szybkie algorytmy do numerycznego mnożenia i dzielenia wielomianów o złożonych współczynnikach. W EUROCAM '82: European Conference Algebra Conference, Lect. Notes Comp. Sci. 144, 3-15. iai.uni-bonn.de/~schoe/publi39.dvi
Markus Bläser

IIRC miałeś częściową odpowiedź na już usunięte pytanie CS. Szkoda tego stracić. Czy możesz podać to tutaj (w pytaniu, aby pytanie nie było oznaczone jako już udzielone)?
Peter Taylor

Odpowiedzi:


4

Ta odpowiedź pochodzi z artykułu „Asymptotycznie szybkie algorytmy mnożenia i dzielenia liczbowego wielomianów o złożonych współczynnikach”, które Markus połączył w komentarzach.


Chcesz wyrównać n-bit liczba, modulo 2n+1. Oto co robisz:

  • Odnaleźć p i s które spełniają n=(p1)2s i sp2s.

  • Wybierz liczbę sztuk 2m podzielić n bitów w i odpowiednie parametry dla rozmiarów sztuk:

    m=s/2+1s2=s/2+1p2=p/2+1

    Zauważ, że s2 i p2 nadal spełnia s2p22s2niezmienny. Zauważ też, że2m2s2p22n+m+1 jest spełniony, więc dane wejściowe pasują do miejsca do przenoszenia.

  • Wykonaj negacykliczny splot oparty na FFT na kawałkach, a resztę, jak zwykle.

Oto nadrzędny pomysł: logarytmiczny współczynnik wypełnienia p. Teraz do analizy złożoności. FFT zajmienm pracować do zrobienia, a my się powtarzamy 2m kawałki wielkości (p21)2s2, więc teraz możemy zrobić wyjątkowo szorstką matematykę z wrt Relation Relt s:

F(s)()(p1)2sm+2mF(s/2+1)()2s2s(s/2+1)+2s/2+1F(s/2+1)()s22s+22s/2F(s/2+1)()s22s+4(s/2)22s+16(s/4)22s+...()2ss2lg(s)()nlgn(lgnlgn)2lglgnlgn()nlgn(lg2n)lglgn()n(lgn)lglgn

Co wydaje się słuszne, chociaż na tych etapach sporo zdradzałem.

„Sztuczka” wydaje się polegać na tym, że na tym kończymy s2 zamiast sw koszcie podstawowym. Wciąż są dwa pomnożenia przez dwa na poziom rekurencyjny, tak jak narzekałem w pytaniu, ale teraz o połowęspłaci podwójne dywidendy, więc wszystko się udaje. Następnie na koniec anulujemy dodatkowy czynniks (co w rzeczywistości jest czynnikiem logn) dzięki tworzeniu p logarytmicznie duży w stosunku do s początkowo.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.