Редактирование: Метод четырёх русских для умножения матриц
Внимание! Вы не авторизовались на сайте. Ваш IP-адрес будет публично видимым, если вы будете вносить любые правки. Если вы войдёте или создадите учётную запись, правки вместо этого будут связаны с вашим именем пользователя, а также у вас появятся другие преимущества.
Правка может быть отменена. Пожалуйста, просмотрите сравнение версий, чтобы убедиться, что это именно те изменения, которые вас интересуют, и нажмите «Записать страницу», чтобы изменения вступили в силу.
Текущая версия | Ваш текст | ||
Строка 1: | Строка 1: | ||
− | + | Рассмотрим следующую задачу: «Дано две квадратных матрицы <tex>A_{[n \times n]}</tex> и <tex>B_{[n \times n]}</tex>, | |
− | + | состоящие из нулей и единиц. Нужно найти их произведение. При этом, все операции выполняются по модулю <tex>2</tex>.» | |
− | состоящие из нулей и единиц. Нужно найти их произведение. При этом, все операции выполняются по модулю <tex>2</tex>. | + | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
== Простое решение == | == Простое решение == | ||
− | Если мы будем считать произведение матриц <tex>C = A \cdot B</tex> по определению <tex dpi= | + | Если мы будем считать произведение матриц <tex>C = A \cdot B</tex> по определению(<tex dpi=140>c_{i, j} = \sum\limits_{k = 1}^n a_{i,k}b_{k,j}</tex>), то трудоёмкость алгоритма составит <tex>O(n^3)</tex> {{---}} каждый из <tex>n^2</tex> элементов результирующей матрицы <tex>C</tex> вычисляется за время, пропорциональное <tex>n</tex>. |
Сейчас будет показано, как немного уменьшить это время. | Сейчас будет показано, как немного уменьшить это время. | ||
Строка 28: | Строка 16: | ||
Аналогично поступим с матрицей <tex>B</tex>, вместо строк деля столбцы. Получим матрицу <tex dpi=140>B'_{\lceil\frac nk\rceil\times n}</tex>. | Аналогично поступим с матрицей <tex>B</tex>, вместо строк деля столбцы. Получим матрицу <tex dpi=140>B'_{\lceil\frac nk\rceil\times n}</tex>. | ||
− | Теперь, если вместо произведения матриц <tex>A</tex> и <tex>B</tex> считать произведение новых матриц <tex>A'</tex> и <tex>B'</tex>, воспользовавшись посчитанными скалярными произведениями, то каждый элемент матрицы <tex>C</tex> будет получаться уже за время, пропорциональное <tex>\lceil \ | + | Теперь, если вместо произведения матриц <tex>A</tex> и <tex>B</tex> считать произведение новых матриц <tex>A'</tex> и <tex>B'</tex>, воспользовавшись посчитанными скалярными произведениями, то каждый элемент матрицы <tex>C</tex> будет получаться уже за время, пропорциональное <tex>\lceil \frac nk \rceil</tex> вместо <tex>n</tex>, и время произведения матриц сократится с <tex>O(n^3)</tex> до <tex dpi=140>O(n^2 \cdot\frac nk) = O(\frac{n^3}{k}) </tex>. |
− | == Оценка | + | == Оценка трудоёмкости и выбор k == |
− | |||
− | Оценим | + | Оценим трудоёмкость данного алгоритма. |
* Предподсчёт скалярных произведений работает за <tex>O(2^{2k}k)</tex>. | * Предподсчёт скалярных произведений работает за <tex>O(2^{2k}k)</tex>. | ||
− | * Создание матриц <tex>A'</tex> и <tex>B'</tex> {{---}} <tex>O(n^2)</tex> | + | * Создание матриц <tex>A'</tex> и <tex>B'</tex> {{---}} <tex>O(n^2)</tex> |
− | * Перемножение полученных матриц {{---}} <tex>O(\ | + | * Перемножение полученных матриц {{---}} <tex dpi=140>O(\frac{n^3}{k})</tex> |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | <tex> | + | Итого: <tex>O(2^{2k}k) + O(\frac{n^3}{k})</tex>. |
− | + | Приведем анализ выбора числа <tex>k</tex> для получения оптимальной сложности алгоритма. | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | </tex> | ||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | </tex> | ||
− | <tex> k = \ | + | В силу возрастания функции <tex>f(k) = 2^{2k}k</tex> и убывания функции <tex>g(k) = \frac{n^3}{k}</tex> имеем, что сложность будет оптимальна при таком значении <tex>k</tex>, что <tex>f(k) = g(k)</tex>. Прологарифмируем обе части этого равенства: |
− | + | <tex>k \ln 4 + \ln k= 3 \ln n - \ln k</tex> | |
− | <tex> | + | <tex>k = \frac{3 \ln n - 2 \ln k}{\ln 4} </tex> |
− | \ | ||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | </tex> | ||
− | + | <tex> k = 3 \log_4 n - 2 \log_4 k </tex> | |
− | <tex> | + | В силу того, что <tex> \log_4 k </tex> пренебрежительно мал по сравнению с <tex> k </tex> имеем, что <tex> k </tex> с точностью до константы равен <tex> \log n </tex> |
− | <tex> | ||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | </tex> | ||
− | , | ||
− | <tex> | ||
− | <tex> | ||
− | |||
− | |||
− | |||
− | |||
− | </tex> | ||
− | + | Таким образом, при подстановке <tex>k = \log n</tex>, получаем итоговую трудоёмкость <tex dpi=140>O(n^2 \log n) + O(\frac{n^3}{\log n}) = O(\frac{n^3}{\log n})</tex> | |
+ | == Код алгоритма == | ||
+ | <code> | ||
− | < | + | // Предподсчёт скалярных произведений |
− | < | + | // Пусть precalc[i][j] - "скалярное произведение для битовых представлений" чисел i и j |
− | + | // "&" - битовый and; "<<" - битовый сдвиг влево. | |
− | + | int k = ceil(log n); //округление вверх | |
− | + | for i := 0 to (1 << k) - 1 | |
− | + | for j := 0 to (1 << k) - 1 { | |
− | + | int scalmul = 0; | |
− | + | for pos := 0 to k - 1 | |
− | + | if (((1 << pos) & i) != 0 and ((1 << pos) & j) != 0) { | |
+ | scalmul = (scalmul + 1) mod 2; | ||
+ | } | ||
+ | precalc[i][j] = scalmul; | ||
+ | } | ||
+ | |||
+ | // Создание сжатых матриц anew, bnew | ||
+ | for i := 0 to n - 1 { | ||
+ | while (start < n) { | ||
+ | int cursuma = 0, cursumb = 0, curpos = start, deg = (1 << (k - 1)); | ||
+ | while (curpos < start + k and curpos < n) { | ||
+ | cursuma += a[i][curpos] * deg; | ||
+ | cursumb += b[curpos][i] * deg; | ||
+ | deg /= 2; | ||
+ | curpos++; | ||
+ | } | ||
+ | anew[i][start div k](cursuma); | ||
+ | bnew[start div k][i](cursumb); | ||
+ | start = start + k; | ||
+ | } | ||
+ | } | ||
+ | |||
+ | //Перемножение полученных матриц | ||
+ | for i := 0 to n - 1 | ||
+ | for j := 0 to n - 1 { | ||
+ | int curans = 0; | ||
+ | for pos := 0 to m - 1 { | ||
+ | curans = (curans + precalc[anew[i][pos]][bnew[pos][j]]) % 2; | ||
+ | } | ||
+ | ans[i][j] = curans; | ||
+ | } | ||
− | |||
− | == | + | </code> |
− | * ''Gregory V. Bard'' — ''Accelerating Cryptanalysis with the Method of Four Russians'' | + | == Литература == |
+ | * ''Gregory V. Bard'' — '''Accelerating Cryptanalysis with the Method of Four Russians''' | ||
[[Категория: Дискретная математика и алгоритмы]] | [[Категория: Дискретная математика и алгоритмы]] | ||
[[Категория: Динамическое программирование]] | [[Категория: Динамическое программирование]] | ||
− |