| 31.10.2011 12:00 | |
Задача о максимальной подматрице(Maximum Subarray Problem):
Мы рассматриваем двумерный массив a[1...m, 1...n] в качестве входных данных. Задачей нахождения максимальной подматрицы (далее MSP) является максимизация части массива a[k...i, l...j], то есть, получения соответствующих индексов (K, L) и (I, J). Мы предполагаем, что верхний левый угол имеет координаты (1, 1).
Решение MSP было впервые предложено Бентли. Затем оно было усовершенствовано Тамаки и Токуяма. Бентли было достигнуто кубическое время для этого алгоритма. Тамаки и Токуяма далее получили суб-кубическое время для почти квадратный матрицы. Этот алгоритм является рекурсивным и чрезвычайно сложным. Тадао Такаока далее упростил алгоритм Тамаки и Токуяма, с помощью разделяй-и-властвуй метода достигнув суб-кубического времени для любой прямоугольный матрицы.
Допустим, что m ≤ n без ограничения общности. Алгоритм Бентли решает MSP за время O(m^2*n), он использует алгоритм Каданэ для одномерного случая, который работает за линейное время.
Алгоритм Каданэ /* максимальный подмассив a[k..l] массива a[1..n] */
(k, l) := (0, 0); s := −∞; t := 0; j := 1;
for i:=1 to n do begin
t := t + a[i];
if t > s then begin (k, l) := (j, i); s := t end;
if t < 0 then begin t := 0; j := i + 1 end
end
К сожалению, идея Каданэ не работает для двумерного случая.
Алгоритм Тамаки и Токуяма решает данную задачу за суб-кубическое время, где данная матрица пракчтически квадратная: m = O(n).
Разобьем матрицу на четыре части центральной вертикальной и горизонтальной линиями. Мы назовём верхнюю-левую, верхнюю-правую, нижнюю-левую и нижнюю-правую части NW (северо-запад), NE, SW и SE частями соответственно. Определим три условных решения задачи. Первое: максимальную подматрицу, пересекающую центр, назовём как A_center. Эта задача называется центральной задачей. Второе: максимальная подматрица, пересекающая горизонтальную линию, - A_row. Эта задача называется row-centered. И третья подматрица, пересекающая вертикальную линию, обозначается A_column. Эта задача называется column-centered. Алгоритм схематически представлен в рекурсивной форме ниже:
Основной алгоритм
- Если матрица становится одномерной, горизонтальной или вертикальной, - решать задачу алгоритмом Каданэ за линейное время. Иначе:
- пусть A_NW будет решением для NW-части,
- A_NE - решение для NE-части,
- A_SW - решение для SW-части,
- A_SE - для SE-части.
- A_row - решение для row-centered задачи.
- A_column - решение для column-centered задачи.
Решением всей задачи будет максимум из этих шести.
Алгоритм для решения row-centered задачи:
- Делим матрицу на две части вертикальной линией.
- Пусть A_left - решение для левой row-centered задачи.
- A_right - решение для right row-centered задачи.
- A_center - решение для центральной задачи.
Алгоритм для column-centered задачи
- Делим матрицу на две части горизонтальной линией.
- Пусть A_upper будет решением для верхней column-centered задачи.
- A_lower - решение для нижней column-centered задачи.
- A_center - решение центральной задачи.
max(i=1:m/2,j=1:n/2,k=m/2+1:m,l=n/2+1:n) {S_NW [i, j] + S_SW [k, j] + S_NE [i, l] + S_SE [k, l]}
Если мы зафиксируем i и k, то поиск такого максимума может быть сведен к решению задач DMM(distance matrix multiplication) для первых двух слагаемых и последних двух. Заметим также, что нам необходимо транспонировать S_SW и S_SE, что бы привести к решению DMM. Таким образом задача может быть решена за O(M (m, n)), где M (m, n) - время работы для "перемножения" матриц расстояний размером (m, n) и (n, m). В конечном итоге этот алгоритм решается за время:
T (m, n) = O(m^2*n(log(log(m))/ log( m))^0.5*log(n/m)).
Для начала нам необходимо посчитать все префиксные суммы s[i, j] для таких матриц, как a[1..i, 1..j], для всех i и j с ограничением s[i, 0] = s[0, j] = 0. Очевидно, это делается за время O(mn). Покажем, что column-centered задача может быть решена без рекурсий. Схема алгоритма представлена ниже. Отметим также, что нам нет необходимости решать одномерную задачу здесь, и префиксные суммы требуют подсчёта только один раз.
Основной алгоритм
- Если матрица оказывается одним элементом - возвращаем его значение.
- если m > n, поворачиваем матрицу на 90 градусов.
- Пусть A_left - решение для левой половины.
- A_right - решение для правой половины.
- A_column - решение для column-centered задачи.
Теперь column-centered задача может быть решена следующим образом.
A_column = max(k=1:i-1,l=0:n/2-1,i=1:m,j=n/2+1:n) {s[i, j] − s[i, l] − s[k, j] + s[k, l]}.
Мы фиксируем i и k, и максимизируем оставшееся выражение изменением l и j. Тогда это эквивалентно следующему выражению:
i = 1, ..., m и k = 1, ..., i − 1.
A_column [i, k] = max(l=0:n/2-1,j=n/2+1:n) {−s[i, l] + s[k, l] + s[i, j] − s[k, j]}
Пусть s∗[i, j] = −s[j, i]. Тогда данное выражение может быть сведено к:
A_column [i, k] = −min(l=0:n/2-1) {s[i, l] + s∗ [l, k]} + max(j=n/2+1:n) {s[i, j] + s ∗[j, k]}
Целью DMM является вычисление произведения расстояний(distance product) C = AB для двух n-мерных матрицA = а[i, j] and B = b[i,j], чьи элементы - вещественные числа.
c[i,j] = min(k=1:n) { ai,k + bk,j }
Суть c[i,j] - наименьшее расстояние из вершины i из первого слоя до вершины j в третьем слое в ациклическом ориентрированном графе, состоящем из трёх слоёв вершин. Эти вершины пронумерованы 1, ...,n в каждом слое, и расстояние от i в первом слое до j во втором слое - a[i,j] и из i во втором слое до j в третьем слое - b[i,j]. Очевидно, что это выражение можно легко привести для подсчёта максимума вместо минимума - это будет задача о нахождении наибольших путей.
Пожалуйста, обратитесь к странице Уведомление об оптимизации для более подробной информации относительно производительности и оптимизации в программных продуктах компании Intel.
Комментарии (4) 
| 19.11.2011 08:15
azilli
|
Да, это частичный перевод статьи Тадао Такаока, так как хотелось представить все алгоритмы в наиболее объективном виде. Однако этот алгоритм таки был реализован автором, спустя долгие часы и даже дни, проведенные над расшифровкой того, что же всё-таки имелось ввиду в той самой статье (= Настолько в подробности о сложности алгоритма я не вникала, однако могу сказать, что по анализу различных алгоритмов преимущество данного действительно заметно только при больших матрицах (о террабайтах ничего не знаю (= ). Тем более, что сравнивать Кадане и Такаоку ИМХО не очень корректно, так как Кадане работает для одномерного массива, а Такаока - для двумерного (и это естественно, что на одномерный массив не выгодно применять Такаоку). Но если вы имеете ввиду алгоритм Бентли, который фактически сводится к Кадане, то да - Такаоку в сравнении с ним выгодно применять только на больших данных. Про поворот на 90 градусов: фактически необязательно поворачивать матрицу, как показала практика, транспонирование также допустимо. Во избежание затрат на дополнительную память я реализовывала сложный доступ к элементам префиксной матрицы, который имитировал это самое транспонирование и прочие операции. И, на самом деле, если вы копнёте глубже и попробуете разобраться в алгоритме Такаока для Distance Matrix Multiplication, то увидите, что проблем с этим алгоритмом гораздо больше (= Спасибо за комментарий, рада что хоть кто-то заинтересовался статьёй, и мои титанические усилия по реализации алгоритма не прошли даром! (= |
| 19.11.2011 11:38
pawnbot
|
> Такаоку в сравнении с ним выгодно применять только на больших данных. Т.е. вы смогли найти тест на котором Такаока быстрее Бентли. Если не секрет, то можете сказать сколько ваша реализация алгоритма Такаока работает на матрице 10000х10000 на 1-м процессоре, или 40, или хотя бы какое соотношение времен алгоритма Такаока к алгоритму Бентли на 1-м или 40-ка процессорах. |
| 19.11.2011 12:23
azilli
|
Я говорю про большие тесты исключительно в теории (= Если вы хотите более углублённой теории, то это лучше искать в непосредственных источниках. Там есть и анализ и доказательство и иллюстрация сравнений в виде графиков. Сама же я не пробовала сравнивать на больших матрицах по причине, описанной ниже. Если бы вы вникли в алгоритм Distance Matrix Multiplication, то увидели б, что даже на средних матрицах эта реализация "жрёт" при распараллеливании огромное количество памяти. Так что нет, я не пробовала, и вряд ли мои скромные ресурсы позволят мне это (= Хочу отметить, что в этой статье я всего лишь описала алгоритм, но не утверждала его эффективности при распараллеливании (= |
Обратная ссылка (0)
Оставить комментарий 
Daniil Bondarev
| ||
azilli
|



pawnbot
1,977
Просто если это не так, то есть пара вопросов:
> Что же касается алгоритма Тадао Такаока для MSP - по всей видимости это наиболее быстрый алгоритм из всех
> известных на данный момент. Он работает за время O(n^3*log(log(n))/log(n)).
Правильно ли я понимаю, что константа при n^3*log(log(n))/log(n) - 12, в то время как у алгоритма Кадане - 0.5, т.е.
вообще говоря выгода может быть достигнута только на матрицах, которые и на терабайтовые жесткие диски не поместятся.
> Если m > n, поворачиваем матрицу на 90 градусов
Если не заводить дополнительной памяти, то это не такая простая задача и обращение к элементам матрицы будут идти не подряд, т.е. оперативная память при такой операции будет работать крайне неэффективно.