Вы находитесь на странице: 1из 11

Математические основы алгоритмов, осень 2022 г.

Лекция 4. Поиск в графе с весами: алгоритм Дейкстры.


Пути между всеми парами вершин в графе, алгоритм
Варшалла, алгоритм Флойда–Варшалла. Использование
умножения матриц. Алгоритм Штрассена быстрого
умножения матриц. Умножение булевых матриц через
числовые∗
Александр Охотин

12 декабря 2022 г.

Содержание
1 Поиск в графе с весами: aлгоритм Дейкстры 1

2 Пути между всеми парами вершин 4

3 Быстрое умножение матриц 7

1 Поиск в графе с весами: aлгоритм Дейкстры


Алгоритм Дейкстры [1959] (Dijkstra) — другой алгоритм, находящий в данном графе с веса-
ми все пути наименьшего веса из данной вершины 𝑠, работающий быстрее, но требующий,
чтобы веса всех дуг были неотрицательными.
Как и алгоритм Беллмана–Форда, алгоритм Дейкстры (алгоритм 1) в каждый момент
времени помнит для каждой вершины 𝑣 вес 𝑑𝑣 лучшего из известных ему путей из 𝑠, а
также предпоследнюю вершину на этом пути, и пытается находить более короткие пути.
Главное отличие алгоритма Дейкстры в том, что он обрабатывает вершины в некотором
порядке, причём в момент обработки очередной вершины 𝑢 путь наименьшего веса в 𝑢 к
этому моменту уже известен. Тогда алгоритм рассматривает все дуги, исходящие из вер-
шины 𝑢, и с их помощью улучшает пути, ведущие на одну вершину дальше. Такой порядок
рассмотрения позволяет алгоритму просматривать каждую дугу графа лишь однажды.
На каждом шаге алгоритм помнит набор вершин 𝑄 ⊆ 𝑉 , пути наименьшего веса из кото-
рых ещё не продолжены. Изначально это все вершины, 𝑄 = 𝑉 . Далее алгоритм на каждом
шаге находит такую вершину 𝑢 из 𝑄, что известная длина 𝑑𝑢 кратчайшего пути в неё —
наименьшая, и перебирает исходящие из неё дуги, улучшая пути по ним. Утверждается,
что, действуя таким образом, алгоритм найдёт все пути наименьшего веса.

Краткое содержание лекций, прочитанных студентам 1-го курса факульте-
та МКН СПбГУ в осеннем семестре 2022–2023 учебного года. Страница курса:
http://users.math-cs.spbu.ru/~okhotin/teaching/algorithms1_2022/.

1
Рис. 1: Эдсгер Дейкстра (1930–2002).

Алгоритм 1 Алгоритм Дейкстры

1: 𝑑𝑠 = 0
2: 𝑑𝑣 = ∞ для всех 𝑣 ̸= 𝑠
3: 𝑄=𝑉
4: while 𝑄 ̸= ∅ do
5: пусть 𝑢 ∈ 𝑄 — вершина с минимальным значением 𝑑𝑢
6: 𝑄 = 𝑄 ∖ {𝑢}
7: for all 𝑣: (𝑢, 𝑣) ∈ 𝐸 do
8: if 𝑑𝑢 + 𝑤𝑢,𝑣 < 𝑑𝑣 then /* если путь из 𝑠 в 𝑣 можно улучшить этой дугой */
9: 𝑑𝑣 = 𝑑𝑢 + 𝑤𝑢,𝑣
10: 𝜋𝑣 = 𝑢

Теорема 1. Алгоритм Дейкстры работает правильно.

Доказательство. Пусть 𝐷𝑣 — наименьший вес путей из 𝑠 в 𝑣.


Утверждение о правильности: в начале каждой итерации внешнего цикла, для всякой
вершины 𝑣 ∈ / 𝑄, путь наименьшего веса в неё уже построен, то есть 𝑑𝑣 = 𝐷𝑣 .
Индукция по длине вычисления. В начале работы условие выполняется, поскольку вер-
шин не из 𝑄 нет. Пусть из 𝑄 удаляется вершина 𝑢, и при удалении всех предшествовавших
вершин условие выполнялось. Надо доказать, что значение 𝑑𝑢 в этот момент — это наи-
меньший вес пути из 𝑠 в 𝑢; иными словами, что 𝑑𝑢 = 𝐷𝑢 .
Какой-то путь наименьшего веса 𝐷𝑢 из 𝑠 в 𝑢 есть. Поскольку 𝑠 ∈
/ 𝑄 и 𝑢 ∈ 𝑄, на этом пути
есть пара последовательных вершин 𝑥 ∈ / 𝑄, 𝑦 ∈ 𝑄, соединённых ребром (𝑥, 𝑦) ∈ 𝐸 (ничто не
мешает вершине 𝑥 совпадать с 𝑠, а вершине 𝑦 — с 𝑢). Вершина 𝑥 была удалена из 𝑄 раньше,
чем 𝑢, и, по предположению индукции, в тот момент для неё уже был построен путь наи-
меньшего веса. Тогда же этот путь был продолжен до пути наименьшего веса до вершины
𝑦 (именно это продолжение даёт кратчайший путь в 𝑦, поскольку, по предположению, это
начальный участок пути наименьшего веса в 𝑢).
Тогда известно следующее. Во-первых, раз алгоритм выбрал вершину 𝑢 из 𝑄, то 𝑑𝑢 ⩽ 𝑑𝑦 .
Во-вторых, 𝑑𝑦 = 𝐷𝑦 , так как путь наименьшего веса в 𝑦 уже найден. В-третьих, 𝐷𝑦 ⩽ 𝐷𝑢 ,
поскольку эти две вершины находятся на одном пути. Из цепочки неравенств 𝑑𝑢 ⩽ 𝑑𝑦 =
𝐷𝑦 ⩽ 𝐷𝑢 следует, что 𝑑𝑢 = 𝐷𝑢 — стало быть, путь наименьшего веса в вершину 𝑢 к этому
моменту найден.

2
1.1 Очередь с приоритетами
Для представления множества 𝑄 алгоритм использует особую структуру данных: очередь с
приоритетами (priority queue). Каждый элемент 𝑄 находится там вместе со своим текущим
значением 𝑑𝑣 .
Операции:

• insert(𝑥): вставить новый элемент.

• min(): выдать минимальный элемент.

• extract_min(): выдать минимальный элемент и удалить его.

• decrease(𝑥, 𝑘): изменить значение элемента 𝑥 ∈ 𝑄 на 𝑘, коль скоро 𝑘 меньше текущего


значения 𝑥𝑖 .

Сложность алгоритма Дейкстры зависит от того, как реализована очередь с приорите-


тами. Наивная реализация: хранить массив 𝑥𝑣 , индексированный по 𝑣 ∈ 𝑉 . Тогда decrease
работает за время 𝑂(1), но extract_min требует время |𝑉 |. Отсюда общее время работы —
|𝑉 |2 + |𝐸| = 𝑂(|𝑉 |2 ).
Другая наивная реализация — хранить сортированный массив. Теперь extract_min ра-
ботает за время 𝑂(1), а для decrease нужно будет переставлять элемент в нужное место,
что потребует времени |𝑉 |. Выйдет время |𝐸| · |𝑉 | — ещё хуже.
Как эффективно реализовать очередь с приоритетами?

1.2 Реализация очереди с приоритетами с помощью кучи


Используется куча, в которой значение в каждой внутренней вершине не больше, чем зна-
чение в любом из её потомков (min-heap).

• insert(𝑥): добавить в конец кучи новый элемент (он становится листом), после чего
дать ему всплыть наверх до его законного места.

• min(): просто вернуть 𝑥1 .

• extract_min(): переместить 𝑥𝑛 в 𝑥1 , убрав его в конце; затем запустить исправление


кучи из корня, то есть, heapify(1).

• decrease(𝑖, 𝑘): изменить значение 𝑥𝑖 на 𝑘, после чего дать элементу 𝑥𝑖 всплыть наверх,
пока возможно.

Дать элементу 𝑥𝑖 всплыть — это значит, что если 𝑥𝑖 меньше своего родителя, то он
обменивается со своим родителем местами, после чего та же операция применяется к вер-
шине на уровень выше, где теперь находится 𝑥𝑖 . И так проделывается до тех пор, пока 𝑥𝑖
не доедет до положенного ему места.
Важно, что процедура decrease получает на входе номер ячейки 𝑖, в которой лежит эле-
мент, а любая операция над кучей может перемещать элементы между ячейками. Поэтому
необходимо поддерживать дополнительную структуру данных — отображение номеров вер-
шин исходного массива в номера ячеек.

3
2 Пути между всеми парами вершин
Дан ориентированный граф 𝐺 = (𝑉, 𝐸), где 𝑉 = {1, . . . , 𝑛}, а 𝐸 ⊆ 𝑉 × 𝑉 . Ставится задача
проверить существование пути из каждой вершины в каждую — то есть для каждой пары
вершин (𝑖, 𝑗) определить, есть ли путь из 𝑖 в 𝑗.
Эти сведения составляют новый граф с тем же множеством вершин, называемый тран-
зитивным замыканием графа 𝐺: это граф 𝐺* = (𝑉, 𝐸 * ), где (𝑖, 𝑗) ∈ 𝐸 * , если в 𝐺 есть путь
из 𝑖 в 𝑗.

2.1 Очевидный алгоритм для транзитивного замыкания


Очевидный алгоритм (алгоритм 2) будет перебирать все пары вершин (𝑖, 𝑗), а для каждой
пары — все промежуточные вершины 𝑘, для которых есть дуги (𝑖, 𝑘) и (𝑘, 𝑗). Если при этом
дуги (𝑖, 𝑗) ещё нет, она будет добавляться. Перебор всех пар (𝑖, 𝑗) будет продолжаться, пока
можно добавить новые дуги.

Алгоритм 2 Очевидный алгоритм для транзитивного замыкания

1: while можно добавить дуги do


2: for 𝑖 = 1 to 𝑛 do
3: for 𝑗 = 1 to 𝑛 do
4: for 𝑘 = 1 to 𝑛 do
5: if (𝑖, 𝑘) ∈ 𝐸 ∧ (𝑘, 𝑗) ∈ 𝐸 then
6: добавить дугу (𝑖, 𝑗) к 𝐸

Утверждение о правильности алгоритма — следующий инвариант внешнего цикла.

Лемма 1. После каждой 𝑡-й итерации внешнего цикла будут просчитаны все пути длины
не более 2𝑡 , и для каждого из них в граф будет добавлена дуга.

Это утверждение доказывается индукцией по 𝑡.


Отсюда следует, что время работы алгоритма — не более, чем 𝑛3 log2 𝑛 шагов.

2.2 Алгоритм Варшалла


Оказывается, что можно построить транзитивное замыкание за время 𝑛3 , обойдясь без
внешнего цикла («пока можно добавить дуги»). Для этого достаточно — внезапно — поме-
нять циклы местами, сделав цикл по промежуточной вершины 𝑘 внешним.

Алгоритм 3 Алгоритм Варшалла для транзитивного замыкания

1: for 𝑘 = 1 to 𝑛 do
2: for 𝑖 = 1 to 𝑛 do
3: for 𝑗 = 1 to 𝑛 do
4: if (𝑖, 𝑘) ∈ 𝐸 ∧ (𝑘, 𝑗) ∈ 𝐸 then
5: добавить дугу (𝑖, 𝑗) в 𝐸

Время работы очевидно — ведь каждая тройка (𝑖, 𝑘, 𝑗) рассматривается лишь однажды.
Но почему алгоритм 3 работает правильно, то есть действительно строит транзитивное
замыкание графа?

4
k

i j i j

1..k 1..k–1

Рис. 2: (слева) Условие правильности алгоритма Варшалла; (справа) индукционный переход


в доказательстве.

Лемма 2 (Варшалл [1962]). После 𝑘-й итерации внешнего цикла переменная 𝐸 содержит
все пары вершин (𝑖, 𝑗), для которых в исходном графе существует путь из 𝑖 в 𝑗, прохо-
дящий только через промежуточные вершины из множества {1, . . . , 𝑘} (как показано на
рис. 2(левом)).

Доказательство. Доказывается индукцией по числу итераций.

Базис 𝑘 = 0: перед началом работы алгоритма переменная 𝐸 содержит все рёбра графа,
то есть все пути, проходящие через промежуточные вершины из пустого множества.

Переход. К началу 𝑘-й итерации все пути, проходящие через промежуточные вершины из
{1, . . . , 𝑘 −1} уже найдены. Пусть кратчайший путь из 𝑖 в 𝑗 проходит только через вершины
из {1, . . . , 𝑘}. Если через 𝑘 он не проходит, то он уже построен. Если же он проходит через 𝑘,
как изображено на рис. 2(правом), то он когда-то приходит в неё впервые — и, стало быть,
есть путь из 𝑖 в 𝑘, проходящий только через промежуточные вершины из {1, . . . , 𝑘 − 1} — и
когда-то в последний раз её покидает, так что есть путь из 𝑘 и 𝑗, тоже проходящий только
через {1, . . . , 𝑘 − 1}. Эти два пути уже построены по предположению индукции, и тогда на
𝑘-й итерации находится и искомый путь.

Рис. 3: Стивен Варшалл (1935–2006); Роберт Флойд (1936–2001).

Из леммы сразу следует правильность алгоритма: действительно, после 𝑛-й итера-


ции внешнего цикла будут найдены все пути, проходящие через промежуточные вершины
{1, . . . , 𝑛}, то есть совсем все пути.

5
2.3 Кратчайшие пути с весами
Что делать, если нужно не только определить существование путей между всеми парами
вершин, но и длины кратчайших путей между ними? Это частный случай более общей
задачи. Пусть граф теперь взвешенный, то есть для каждой дуги задан её вес 𝑤𝑖,𝑗 . Если
дуги нет, можно положить 𝑤𝑖,𝑗 = ∞. Нужно найти пути наименьшего веса между всеми
парами вершин.
Можно запустить алгоритм Дейкстры из каждой вершины, но это будет |𝑉 | раз
|𝐸| log |𝑉 |, так что если рёбер много, то время работы достигнет |𝑉 |3 log |𝑉 |.
Алгоритм Флойда–Варшалла (алгоритм 4): время 𝑂(𝑛3 ).

Алгоритм 4 Алгоритм Флойда–Варшалла для нахождения всех кратчайших путей


если 𝑖 = 𝑗

⎨0,

Массив 𝑑𝑖,𝑗 , начальные значения: 𝑑𝑖,𝑗 = 𝑤𝑖,𝑗 , если (𝑖, 𝑗) ∈ 𝐸 .
в противном случае

∞,

1: for 𝑘 = 1 to 𝑛 do
2: for 𝑖 = 1 to 𝑛 do
3: for 𝑗 = 1 to 𝑛 do
4: if 𝑑𝑖,𝑗 > 𝑑𝑖,𝑘 + 𝑑𝑘,𝑗 then
5: 𝑑𝑖,𝑗 = 𝑑𝑖,𝑘 + 𝑑𝑘,𝑗

Инвариант внешнего цикла подобен инварианту для алгоритма Варшалла.

Лемма 3. После 𝑘-й итерации для каждой пары вершин (𝑖, 𝑗) найден путь из 𝑖 в 𝑗 наи-
меньшего веса среди путей, проходящих только через промежуточные вершины из мно-
жества {1, . . . , 𝑘}.

Чтобы построить сами кратчайшие пути, для каждой пары вершин запоминается вер-
шина 𝜋𝑖,𝑗 — следующая после 𝑖 вершина на кратчайшем пути из 𝑖 в 𝑗. Она будет обновляться
одновременно с улучшением дуги.

2.4 Достижимость в графe и умножение матриц


Достижимость в графе можно выразить через степени матрицы смежности графа. Матрица
смежности — булева матрица 𝐴 ∈ B𝑛×𝑛 , в которой элемент 𝑎𝑖,𝑗 равен 1, если в графе есть
дуга (𝑖, 𝑗), и равен 0, если дуги нет.
Произведение булевых матриц определяется в булевом полукольце. Иными словами,
произведение булевых матриц 𝐴 ∈ B𝑚×ℓ и 𝐵 ∈ Bℓ×𝑛 — это булева матрица 𝐴 × 𝐵 = 𝐶 ∈
B𝑚×𝑛 , со следующими значениями элементов.

⋁︁
𝑐𝑖,𝑗 = 𝑎𝑖,𝑘 ∧ 𝑏𝑘,𝑗
𝑘=1

Если 𝐴 ∈ B𝑛×𝑛 — матрица смежности графа, то 𝐴ℓ — матрица достижимости по путям


длины ровно ℓ. Пусть 𝐼 ∈ B𝑛×𝑛 — единичная матрица. Тогда (𝐴 ∨ 𝐼)ℓ — матрица дости-
жимости по путям длины не более чем ℓ, а 𝐴𝑛−1 — матрица достижимости. Обозначение:
𝐴* = (𝐴 ∨ 𝐼)𝑛−1 — рефлексивно-транзитивное замыкание.
Вычисляется возведением в квадрат log 𝑛 раз. Если умножать матрицы напрямую, полу-
чится время 𝑛3 log 𝑛 — медленней, чем Варшалл. Но, во-первых, здесь векторные операции,

6
их компьютеру выполнять удобнее, чем произвольный поиск по матрице смежности. Во-
вторых, матрицы можно умножать существенно быстрее, чем за кубическое время!

3 Быстрое умножение матриц


Произведение двух матриц размера 𝑛 × 𝑛 по определению вычисляется за 𝑛3 умножений и
𝑛2 (𝑛 − 1) сложений. Однако существуют алгоритмы умножения матриц, работающие быст-
рее, чем по определению, быстрее очевидного — и уже сама такая возможность удивительна.

3.1 Алгоритм Штрассена


Пусть ℛ — кольцо, то есть множество с заданными на нём ассоциативными операциями
сложения и умножения, причём сложение коммутативно, сложение и умножение дистрибу-
тивные, есть нейтральные элементы по сложению и умножению, а также у каждого элемен-
та есть противоположный элемент относительно сложения (без противоположного элемента
— полукольцо).
Сумма матриц 𝐴 ∈ ℛ𝑚×𝑛 , 𝐵 ∈ ℛ𝑚×𝑛 — матрица 𝐴 + 𝐵 = 𝐶 ∈ ℛ𝑛×𝑛 .

𝑐𝑖,𝑗 = 𝑎𝑖,𝑗 + 𝑏𝑖,𝑗

Сложение матриц ассоциативно, коммутативно, есть нейтральный и противоположный эле-


менты.
Произведение матриц 𝐴 ∈ ℛ𝑚×ℓ , 𝐵 ∈ ℛℓ×𝑛 — матрица 𝐴 × 𝐵 = 𝐶 ∈ ℛ𝑚×𝑛 .

∑︁
𝑐𝑖,𝑗 = 𝑎𝑖,𝑘 · 𝑏𝑘,𝑗
𝑘=1

Умножение матриц ассоциативно, есть нейтральный элемент.

Утверждение 1. Квадратные матрицы размера 𝑛×𝑛 над кольцом сами образуют кольцо.

Произведение двух матриц 2 × 2, согласно определению, выражается за 8 умножений и


4 сложения.
(︂ )︂ (︂ )︂ (︂ )︂
𝑎11 𝑎12 𝑏11 𝑏12 𝑎11 𝑏11 + 𝑎12 𝑏21 𝑎11 𝑏12 + 𝑎12 𝑏22
× =
𝑎21 𝑎22 𝑏21 𝑏22 𝑎21 𝑏11 + 𝑎22 𝑏21 𝑎21 𝑏12 + 𝑎22 𝑏22

Но есть удивительный способ вычисления этого же произведения за 7 умножений и 18


сложений.

(︂ )︂ (︂ )︂
𝑎11 𝑎12 𝑏11 𝑏12
Лемма 4 (Штрассен [1969]). Пусть 𝐴 = и𝐵= — две матрицы
𝑎21 𝑎22 𝑏21 𝑏22
(︂ )︂
𝑐11 𝑐12
размера 2×2 над кольцом ℛ. Тогда их произведение 𝐴×𝐵 = можно вычислить
𝑐21 𝑐22
за 7 умножений и 18 сложений в ℛ.

7
Рис. 4: Фолькер Штрассен (род. 1936).

b11 b21 b12 b22 b11 b21 b12 b22


a11 a11 d3
c11 c21 d1 d6 d5
a12 a12

a21 a21
c12 c22 d2
d4 d7
a22 a22

Рис. 5: (слева) Восемь произведений при умножении матриц 2 × 2 по определению; (справа)


семь произведений при умножении по Штрассену.

Доказательство. Восемь произведений, соответствующие определению произведения мат-


риц, отмечены на рис. 5(левом), где горизонтальные пунктирные линии соответствуют че-
тырём элементам 𝐴, вертикальные — четырём элементам 𝐵, а пересечение линий соответ-
ствует произведению элементов. Произведения разбиваются на 4 пары — суммы, соответ-
ствующие элементам искомой матрицы 𝐴 × 𝐵.
Чтобы вычислить эти же 4 суммы иначе, сперва вычисляются следующие 7 произведе-
ний.

𝑑1 = (𝑎11 + 𝑎22 )(𝑏11 + 𝑏22 ),


𝑑2 = (𝑎21 + 𝑎22 )𝑏11 ,
𝑑3 = 𝑎11 (𝑏12 − 𝑏22 ),
𝑑4 = 𝑎22 (𝑏21 − 𝑏11 ),
𝑑5 = (𝑎11 + 𝑎12 )𝑏22 ,
𝑑6 = (𝑎21 − 𝑎11 )(𝑏11 + 𝑏12 ),
𝑑7 = (𝑎12 − 𝑎22 )(𝑏21 + 𝑏22 ).

Они изображены на рис. 5(правом), где каждый заполненный круг соответствует произве-
дению со знаком «плюс», а пустой — произведению, умноженному на −1. Тогда искомое

8
произведение 𝐶 = 𝐴𝐵 выражается так.

𝑐11 = 𝑑1 + 𝑑4 + 𝑑7 − 𝑑5
𝑐12 = 𝑑3 + 𝑑5
𝑐21 = 𝑑2 + 𝑑4
𝑐22 = 𝑑1 + 𝑑3 + 𝑑6 − 𝑑2

Если умножать надо числовые матрицы размера 2 × 2, то такой способ вычисления их


произведения окажется медленней, чем если считать согласно определению: действительно,
легче проделать одно лишнее умножение, чем 14 лишних сложений. Смысл умножения
матриц 2 × 2 за 7 умножений и много сложений в том, что эту формулу для произведения
матриц можно применять рекурсивно, сводя умножение матриц размера 𝑛×𝑛 к умножению
семи пар матриц вдвое меньшего размера — семи, а не восьми.
Сперва матрицы 𝑛 × 𝑛 представляются в виде блочных матриц, состоящих из четырёх
подматриц размера 𝑛2 × 𝑛2 каждая.
(︂ )︂ (︂ )︂ (︂ )︂
𝐴11 𝐴12 𝐵11 𝐵12 𝐴11 × 𝐵11 + 𝐴12 × 𝐵21 𝐴11 × 𝐵12 + 𝐴12 × 𝐵22
× =
𝐴21 𝐴22 𝐵21 𝐵22 𝐴21 × 𝐵11 + 𝐴22 × 𝐵21 𝐴21 × 𝐵12 + 𝐴22 × 𝐵22

Поскольку матрицы размера 𝑛2 × 𝑛2 над кольцом сами образуют кольцо, здесь записано
произведение двух матриц размера 2 × 2 над этим кольцом. Согласно лемме 4, вычисление
этого произведения сводится к умножению семи пар матриц вдвое меньшего размера, а
также некоторому количеству сложений таких матриц. Наконец, для умножения матриц
размера 𝑛2 × 𝑛2 рекурсивно используется этот же алгоритм.
На каждом уровне рекурсии, кроме самого нижнего, полученный алгоритм занимает-
ся исключительно сложениями и вычитаниями блочных матриц некоторого размера. Семь
умножений — это только способ разбиения задачи на подзадачи методом «разделяй и власт-
вуй» — никакие числа при этом не умножаются. И лишь на самом нижнем уровне рекурсии
умножаются матрицы размера 1 × 1, то есть просто числа.
Глубина рекурсии — log2 𝑛. Задач размера 𝑛 — одна. Задач размера 𝑛2 — семь. Задач
каждого размера 2𝑛𝑖 — всего 7𝑖 . Для каждой задачи размера 2𝑛𝑖 на глубине 𝑖, время, затра-
ченное
(︀ 𝑛 2 процедурой на внутренние вычисления, без учёта рекурсивных вызовов, составляет
𝑂 ( 2𝑖 ) шагов — это константное число сложений и вычитаний матриц размера 2𝑛𝑖 × 2𝑛𝑖 .
)︀

Поэтому общее количество действий оценивается по следующей формуле.


log2 𝑛 log2 𝑛 (︁ (︀ 7 )︀1+log2 𝑛 (︁ 7log2 𝑛 )︁ (︁ 𝑛log2 7 )︁
∑︁
𝑖
(︁ 𝑛 )︁2
2
∑︁ 7 )︁𝑖 −1
= 𝑛2 4
= 𝑂 𝑛2 · log 𝑛 = 𝑂 𝑛2 · 2 = 𝑂 𝑛log2 7
(︀ )︀
7 =𝑛 7
2𝑖 4 4 −1 4 2 𝑛
𝑖=0 𝑖=0

Теорема 2 (Штрассен [1969]). Пусть ℛ — кольцо, пусть 𝑘 ⩾ 0, и пусть 𝐴 и 𝐵 — две


матрицы 2𝑘 × 2𝑘 над ℛ. Тогда произведение 𝐴𝐵 можно вычислить за 7𝑘 умножений и
Θ(7𝑘 ) сложений.

Если размер умножаемых матриц — не степень двойки, то их можно дополнить до


следующий степени двойки нулями, что ухудшит время работы лишь в константное число
раз. Поэтому матрицы любого размера 𝑛 × 𝑛 можно перемножить за время 𝑂(𝑛log2 7 ).
С помощью метода Штрассена можно умножать матрицы над любым кольцом — на-
пример, над целыми числами по любому модулю, в том числе для типа данных int.

9
Рис. 6: Самуил Виноград (1936–2019), Дональд Копперсмит (род. ок. 1950), Франсуа Ле
Галл.

Применяя метод Штрассена для умножения чисел с плавающей точкой, нужно иметь в
виду, что тип данных float не образует кольца, и потому алгоритм не обязан вычислять
правильные значения. На практике это может вылиться в накопление погрешности.
Позднее были получены разнообразные асимптотически более быстрые алгоритмы
умножения матриц. Теоретически самый быстрый известный алгоритм — это метод
Копперсмита–Винограда [1990] с улучшениями Ле Галла [2014], работающий за время
𝑂(𝑛2.373 ). Однако эти алгоритмы начинают работать быстрее Штрассена лишь для аст-
рономических значений 𝑛, а для матриц, которые есть надежда когда-нибудь умножить,
или хотя бы где-то записать, алгоритм Штрассена остаётся наилучшим.
Виноград [1971] показал методами линейной алгебры, что умножить матрицы размера
2 × 2 менее чем за 7 умножений нельзя, даже если использовать коммутативность умноже-
ния. Делались попытки улучшить алгоритм Штрассена, найдя способ умножить за малое
число шагов квадратные матрицы немного большего размера, чем 2 × 2, чтобы затем при-
менить эти формулы рекурсивно. Если бы матрицы размера 3 × 3 удалось умножить за 21
умножение, или матрицы размера 4 × 4 — за 48 умножений, то получилось бы практически
применимое улучшение алгоритма Штрассена. Однако найти такие формулы умножения по
сей день не удаётся. Например, для матриц размера 3×3 Ладерман [1976] изобрёл формулы
вычисления произведения за 23 умножения — но log3 23 > log2 7, и полученный алгоритм
всё равно работает медленнее алгоритма Штрассена.

Задача 1. Рассмотреть формулы для умножения двух матриц размера 4 × 4 за 49 умно-


жений — они получаются двухуровневым применением метода Штрассена. Можно ли
что-то где-то переделать, чтобы обойтись 48 умножениями?

Нижних оценок времени умножения матриц произвольного размера нет, 𝑛2 действий


нужно просто для того, чтобы записать результат, и нельзя исключить, что матрицы на
самом деле можно умножать за время 𝑛2 (log 𝑛)𝑂(1) — просто мы не знаем, как. Показа-
тель степени при 𝑛 во времени работы асимптотически наилучшего алгоритма умножения
матриц обозначается через 𝜔 (омега), и известно лишь, что 2 ⩽ 𝜔 < 2.373.

3.2 Умножение булевых матриц через числовые


Булевы матрицы определены над булевым полукольцом, а не над кольцом, поскольку
нет противоположного элемента для сложения. Поэтому алгоритм Штрассена сам по себе

10
неприменим. Однако можно умножить булевы матрицы через числовые следующим обра-
зом.
Сперва булевы матрицы записываются как числовые матрицы с элементами 0 и 1, и
затем они перемножаются в кольце вычетов по модулю 𝑛 + 1 — или ⋁︀ по любому удобному
модулю, превосходящему 𝑛. Тогда вместо дизъюнкции конъюнкций ℓ𝑘=1 𝑎𝑖,𝑘 ∧𝑏𝑘,𝑗 будет вы-
числена сумма произведений ℓ𝑘=1 𝑎𝑖,𝑘 ·𝑏𝑘,𝑗 по модулю 𝑛+1. Сама по себе сумма ℓ𝑘=1 𝑎𝑖,𝑘 ·𝑏𝑘,𝑗
∑︀ ∑︀
в точности равна количеству истинных конъюнкций в дизъюнкции конъюнкций, и потому
она лежит в диапазоне от 0 до 𝑛 — откуда следует, что по модулю 𝑛 + 1 она вычислит-
ся точно. Чтобы узнать значение дизъюнкции конъюнкций, достаточно будет проверить
вычисленную сумму произведений на неравенство нулю.

Список литературы
[1990] D. Coppersmith, S. Winograd, “Matrix multiplication via arithmetic progressions”,
Journal of Symbolic Computation, 9:3 (1990), 251–280.

[1959] E. W. Dijkstra, “A note on two problems in connexion with graphs”, Numerische


Mathematik, 1 (1959), 269–271.

[1976] J. D. Laderman, “A noncommutative algorithm for multiplying 3 × 3 matrices using 23


multiplications”, Bulletin of the AMS, 82:1 (1976), 126–128.

[2014] F. Le Gall, “Powers of tensors and fast matrix multiplication”, ISSAC 2014, 296–303.

[1969] V. Strassen, “Gaussian elimination is not optimal”, Numerische Mathematik, 13 (1969),


354–356.

[1962] S. Warshall, “A theorem on Boolean matrices”, Journal of the ACM, 9:1 (1962), 11–12.

[1971] S. Winograd, “On multiplication of 2 × 2 matrices”, Linear Аlgebra and its Аpplications,
4:4 (1971), 381–388.

11

Вам также может понравиться