Як вибрано внутрішнє кільце в алгоритмі Шенгаге-Страссена?


9

Я намагався реалізувати алгоритм множення цілих чисел Шенгаге-Страссена, але потрапив на камеру спотикання на етапі рекурсивності.

Я маю цінність x з nбіт, і я хочу обчислити . Спочатку я вважав, що ідея полягає в тому, щоб вибрати , щоб 4 ^ k \ geq 2n , розділили х на 2 ^ k шматки, кожен з 2 ^ {k-1} бітами, застосувавши згортку SSA під час роботи модуля 2 ^ {2 ^ k} +1 , кільце ємністю 2 ^ k на значення, а потім складіть шматки назад. Тим не менш, вихід згортки має трохи більше 2n біт (тобто > 2 ^ k біт на вихідне значення, що перевищує ємність кільця, оскільки кожне вихідне значення є сумою декількох продуктів), тому це не працює . Мені довелося додати додатковий коефіцієнт 2 прокладки.x2(mod2n+1)k4k2nx2k2k122k+12k2n>2k

Цей додатковий коефіцієнт 2 у прокладці руйнує складність. Це робить мій рекурсивний крок занадто дорогим. Замість алгоритму F(n)=nlgn+nF(2n)=Θ(nlgnlglgn) , я закінчую з алгоритмом F(n)=nlgn+nF(4n)=Θ(nlg2n) .

Я прочитав кілька посилань, пов’язаних із вікіпедії, але всі вони, здається, змальовують деталі того, як вирішується це питання. Наприклад, я міг би уникнути додаткових накладних накладних витрат, працюючи за модулем 2p2k+1 для p що не є потужністю 2 ... але потім речі просто ламаються пізніше, коли у мене є лише неенерго- Залишилося 2 чинника, і не можна застосувати Cooley-Tukey, не подвоївши кількість штук. Також p може не мати мультипликативного зворотного модуля 2p+1 . Отже, все ще вводяться примусові фактори 2.

Як вибрати кільце для використання під час рекурсивного кроку, не роздуваючи асимптотичну складність?

Або у формі псевдокоду:

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

Будь ласка , не ставте один і той же питання на кількох сайтах . Кожна громада повинна чесно реагувати на відповіді, не витрачаючи ні на кого часу. Я пропоную вам видалити один із двох примірників.
DW

@DW Готово. Я перекреслив після того, як cs протягом тижня не давав відповідей, вважаючи, що це занадто важко для цього сайту. Очевидно, збирався зв’язати будь-які відповіді.
Крейг Гідні

Я розумію. Якщо вона з’явиться в майбутньому, ви завжди можете позначати свою публікацію для уваги модератора і просити її перенести, і ми можемо перенести її для вас на CSTheory. Дякую за розуміння!
DW

3
Існує версія алгоритму, яка працює за модульними номерами форми : A. Schönhage. Асимптотично швидкі алгоритми чисельного множення та ділення многочленів зі складними коефіцієнтами. В EUROCAM '82: Європейська конференція з комп'ютерної алгебри, лект. Примітки Comp. Наук. 144, 3-15. iai.uni-bonn.de/~schoe/publi39.dvi2ν2n
Маркус Блясер

IIRC, у вас був частковий відповідь на видалене CS-питання. Дуже прикро втратити це. Чи можете ви включити його сюди (у запитання, щоб питання не було позначене як уже відповіді)?
Пітер Тейлор

Відповіді:


4

Ця відповідь взята з статті "Асимптотично швидкі алгоритми чисельного ослаблення та поділу многочленів зі складними коефіцієнтами", які Маркус пов'язував у коментарях.


Ви хочете скласти бітове число, модуль . Ось що ви робите:n2n+1

  • Знайдіть і які задовольняють і .psn=(p1)2ssp2s

  • Виберіть кількість шматочків щоб розділити біт і відповідні параметри для розмірів шматка:2mn

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

    Зауважте, що і продовжують задовольняти інваріант . Також зауважте, що задоволено, тому вхід відповідає простору для проведення.s2p2s2p22s22m2s2p22n+m+1

  • Виконайте негативні згортання на основі FFT на шматках, а решта, як зазвичай.

Отже, це всеохоплююча ідея: логарифмічний коефіцієнт прокладки . Тепер для аналізу складності. FFT займе роботу, і ми повторюємо шматок розміру , тож тепер ми можемо робити надзвичайно грубу математику із відношенням рецидиву wrt :pnm2m(p21)2s2s

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

Що здається правильним, хоча я досить сильно обдурив на тих кроках.

«Трюк», здається, полягає в тому, що ми закінчуємо замість в базовій вартості. Є ще два множення на два на рекурсивний рівень, як я скаржився у питанні, але зараз половина виплачує подвійні дивіденди, щоб все вийшло. Тоді, наприкінці, ми скасовуємо додатковий коефіцієнт (який насправді є коефіцієнтом ) завдяки зростанню логарифмічно великого відносно .s2ssslognps

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.