Параллельный алгоритм кратчайшего пути для всех пар - Parallel all-pairs shortest path algorithm - Wikipedia

Центральная проблема алгоритмической теория графов это проблема кратчайшего пути. Таким образом, проблема поиска кратчайшего пути между каждой парой узлов известна как все пары кратчайших путей (APSP) проблема. В качестве последовательные алгоритмы поскольку эта проблема часто приводит к длительному времени выполнения, параллелизм оказался полезным в этой области. В данной статье представлены два эффективных алгоритма решения этой проблемы.

Другой вариант проблемы - это задача с одним источником кратчайших путей (SSSP), которая также имеет параллельные подходы: Параллельный алгоритм кратчайшего пути с одним источником.

Определение проблемы

Позволять ориентированный граф с множеством узлов и набор ребер . Каждый край имеет вес назначенный. Задача задачи кратчайших путей всех пар - найти кратчайший путь между все пары узлов графа. Для того, чтобы этот путь был уникальным, необходимо, чтобы в графе не было циклов с отрицательным весом.

В оставшейся части статьи предполагается, что граф представлен с использованием матрица смежности. Мы ожидаем, что на выходе алгоритма будет матрица расстояний . В , каждая запись вес кратчайшего пути в из узла узел .

В Алгоритм Флойда представленный позже может обрабатывать отрицательные веса ребер, тогда как Алгоритм Дейкстры требует, чтобы все ребра имели положительный вес.

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

В Алгоритм Дейкстры первоначально был предложен как средство решения проблемы кратчайших путей с одним источником. Однако алгоритм можно легко использовать для решения проблемы кратчайших путей для всех пар, выполнив вариант с одним источником с каждым узлом в роли корневого узла.

В псевдокоде такая реализация могла бы выглядеть так:

 1    func ДейкстраСССП (грамм,v) { 2        ... // здесь стандартная SSSP-реализация 3 возврат dv; 4    } 5     6    func DijkstraAPSP (грамм) { 7        D := |V| x |V| -Матрица 8 за я из 1 к |V| { 9           //D [v] обозначает v-ю строку D 10          D[v]: = DijkstraSSP (грамм,я) 11       } 12   }

В этом примере мы предполагаем, что DisjktraSSSP берет график и корневой узел в качестве входных данных. Результатом выполнения, в свою очередь, является список расстояний. . В , то -й элемент хранит расстояние от корневого узла к узлу .Поэтому список точно соответствует -я строка матрицы расстояний APSP .По этой причине, DijkstraAPSP перебирает все узлы графа и выполняет DisjktraSSSP с каждым в качестве корневого узла, сохраняя результаты в .

Время выполнения DijkstraSSSP является поскольку мы ожидаем, что график будет представлен с использованием матрица смежности.Следовательно DijkstraAPSP имеет общее время последовательной работы .

Распараллеливание до |V| процессоры

Тривиальное распараллеливание может быть получено распараллеливанием цикла DijkstraAPSP в соответствии8Однако при использовании последовательного DijkstraSSSP это ограничивает количество используемых процессоров числом итераций, выполняемых в цикле. Следовательно, для этого тривиального распараллеливания - это верхняя граница количества процессоров.

Например, пусть количество процессоров быть равным количеству узлов . В результате каждый процессор выполняет DijkstraSSSP ровно один раз параллельно. Однако когда есть только, например, доступных процессоров, каждый процессор должен выполнять DijkstraSSSP дважды.

В целом это дает время выполнения , когда кратно Следовательно, эффективность этого распараллеливания идеальна: процессоры сокращают время выполнения в раз .

Еще одно преимущество этого распараллеливания состоит в том, что не требуется связи между процессорами. Однако требуется, чтобы у каждого процессора было достаточно локальной памяти для хранения всей матрицы смежности графа.

Распараллеливание более чем |V| процессоры

Apsp dijkstra graph.png
Apsp dijkstra distancelist.png

Если больше чем процессоры должны использоваться для распараллеливания, требуется, чтобы несколько процессоров участвовали в DijkstraSSSP вычисление. По этой причине распараллеливание разделено на два уровня.

На первом уровне процессоры разделены на разделов - каждый раздел отвечает за вычисление одной строки матрицы расстояний . Это означает, что каждый раздел должен оценивать один DijkstraSSSP выполнение с фиксированным корневым узлом. с этим определением каждый раздел имеет размер процессоры. Разделы могут выполнять свои вычисления параллельно, поскольку результаты каждого из них не зависят друг от друга. Следовательно, распараллеливание, представленное в предыдущем разделе, соответствует размеру раздела 1 с процессоры.

Основная трудность заключается в распараллеливании нескольких процессоров, выполняющих DijkstraSSSP для одного корневого узла. Идея этого распараллеливания состоит в распределении управления списком расстояний. в ДейкстраСССП внутри раздела. Таким образом, каждый процессор в разделе несет исключительную ответственность за элементы . Например, рассмотрим и : это дает размер раздела . В этом случае первый процессор каждого раздела отвечает за , а второй процессор отвечает за и . Таким образом, общие списки расстояний составляют .

В DijkstraSSSP алгоритм в основном состоит из повторения двух шагов: во-первых, ближайший узел в списке расстояний нужно найти. Для этого узла уже найден кратчайший путь, после чего расстояние до всех соседей должен быть скорректирован в .

Эти шаги необходимо изменить следующим образом, поскольку для распараллеливания был распределен по разделу:

  1. Найдите узел с кратчайшим расстоянием в .
    • Каждому процессору принадлежит часть : Каждый процессор ищет локальный минимум со своей стороны, например, используя линейный поиск.
    • Вычислить глобальный минимум в путем выполнения сокращение операции по всему .
    • Трансляция глобального минимума ко всем узлам в разделе.
  2. Отрегулируйте расстояние до всех соседей в
    • Теперь каждый процессор знает ближайший глобальный узел и его расстояние. На основе этой информации настройте соседей в которые управляются соответствующим процессором.

Общее время выполнения такой итерации DijkstraSSSP выполняется разделом размера можно вывести на основе выполненных подзадач:

  • Линейный поиск :
  • Операции широковещательной передачи и сокращения: они могут быть эффективно реализованы, например, с использованием бинонмиальных деревьев. Это дает накладные расходы на связь в размере .

За -iterations это приводит к общему времени выполнения .После подстановки определения это дает общее время выполнения для DijkstraAPSP: .

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

Пример

Граф, используемый в этом примере, представлен на изображении с четырьмя узлами.

Цель состоит в том, чтобы вычислить матрицу расстояний с По этой причине процессоры разделены на четыре раздела по два процессора в каждом. Для иллюстрации мы сфокусируемся на разделе, который отвечает за вычисление кратчайших путей от узла А ко всем остальным узлам. Назовем процессоры этого раздела p1 и p2.

Вычисление списка расстояний для различных итераций визуализировано на втором изображении.

Верхний ряд на изображении соответствует после инициализации нижний на после завершения алгоритма. Узлы распределяются таким образом, что p1 отвечает за узлы А и B, пока p2 Ответственный за C и D.Дистанционный список распределяется в соответствии с этим. Для второй итерации выполняемые подзадачи явно показаны на изображении:

  1. Вычисление узла локального минимума в
  2. Вычисление узла глобального минимума в через операцию уменьшения
  3. Трансляция узла глобального минимума в
  4. Пометка ближайшего глобального узла как завершенного и корректировка расстояния до его соседей

Алгоритм Флойда

Алгоритм Флойда решает проблему кратчайших путей для всех пар для ориентированных графов. С матрица смежности графа в качестве входных данных, он вычисляет более короткие пути итеративно. После |V| итераций матрица расстояний содержит все кратчайшие пути. Ниже описана последовательная версия алгоритма в псевдокоде:

 1    func Флойд_Все_Пары_SP (А) { 2         = А; 3        за k := 1 к п делать 4            за я := 1 к п делать 5                за j := 1 к п делать 6                     7     }
разбиение матрицы с двумерным блочным отображением

Где А это матрица смежности, п = |V| количество узлов и D матрица расстояний. Для более подробного описания последовательного алгоритма ищите Алгоритм Флойда-Уоршолла.

Распараллеливание

Основная идея распараллеливания алгоритма - разделить матрицу и разделить вычисления между процессами. Каждому процессу назначена определенная часть матрицы. Обычный способ добиться этого - 2-D блочное отображение. Здесь матрица разбивается на квадраты одинакового размера, и каждый квадрат назначается процессу. Для -матрица и п обрабатывает каждый процесс вычисляет размерная часть матрицы расстояний. За каждому процессу будет назначен ровно один элемент матрицы. Из-за этого распараллеливание масштабируется только до максимума процессы. В дальнейшем мы будем ссылаться на процессу, который назначен квадрату в i-й строке и j-м столбце.

Поскольку вычисление частей матрицы расстояний зависит от результатов других частей, процессы должны взаимодействовать друг с другом и обмениваться данными. В дальнейшем мы будем ссылаться на элементу i-й строки и j-го столбца матрицы расстояний после k-й итерации. Вычислять нам нужны элементы , и как указано в строке 6 алгоритма. доступен каждому процессу, поскольку он был рассчитан сам по себе на предыдущей итерации.

Кроме того, каждому процессу требуется часть k-й строки и k-го столбца таблицы. матрица. В элемент содержит процесс в той же строке, а element содержит процесс в том же столбце, что и процесс, который хочет вычислить . Каждый процесс, который вычислил часть k-й строки в матрица должна отправить эту часть всем процессам в своем столбце. Каждый процесс, который вычислил часть k-го столбца в матрица должна отправить эту часть всем процессам в своей строке. Все эти процессы должны выполнять операцию широковещательной рассылки по строке или столбцу. Зависимости данных показаны на изображении ниже.

Для двумерного блочного отображения мы должны изменить алгоритм следующим образом:

 1    func Floyd_All_Pairs_Parallel () { 2      за k := 1 к п делать{3 Каждый процесс  имеющий отрезок k-й строки , передает его  процессы; 4 Каждый процесс  имеющий сегмент k-го столбца , передает его  процессы; 5 Каждый процесс ожидает получения необходимых сегментов; 6 Каждый процесс вычисляет свою часть  матрица; 7} 8}
зависимости данных в алгоритме Флойда

В строке 5 алгоритма у нас есть этап синхронизации, чтобы гарантировать, что все процессы имеют данные, необходимые для вычисления следующей итерации. Чтобы улучшить время выполнения алгоритма, мы можем удалить шаг синхронизации, не влияя на корректность алгоритма. Для этого каждый процесс начинает вычисление, как только у него есть данные, необходимые для вычисления его части матрицы. Эта версия алгоритма называется конвейерное отображение двухмерных блоков.

Время выполнения

Время выполнения последовательного алгоритма определяется тройным вложенным циклом for. Вычисление в строке 6 может быть выполнено за постоянное время (). Следовательно, время выполнения последовательного алгоритма равно .

2-D блочное отображение

Время выполнения распараллеленного алгоритма состоит из двух частей. Время на вычисления и часть на связь и передачу данных между процессами.

Поскольку в алгоритме нет дополнительных вычислений, и вычисление делится поровну между п процессов, у нас есть время выполнения для вычислительной части.

На каждой итерации алгоритма выполняется операция широковещательной рассылки «один ко всем» по строке и столбцу процессов. Есть элементы трансляции. После этого выполняется этап синхронизации. Сколько времени займут эти операции, сильно зависит от архитектуры используемой параллельной системы. Следовательно, время, необходимое для связи и передачи данных в алгоритме, равно .

Для всего алгоритма у нас есть следующая среда выполнения:

Конвейерное двухмерное отображение блоков

Во время выполнения передачи данных между процессами в конвейерной версии алгоритма мы предполагаем, что процесс может передавать k элементы к соседнему процессу в время. На каждом шагу есть элементы строки или столбца отправляются в соседний процесс. Такой шаг требует время. После шаги соответствующие данные первой строки и столбца поступают в процесс время).

Значения последовательных строк и столбцов следуют после времени в конвейерном режиме. Процесс завершает свое последнее вычисление после O () + O () время. Следовательно, дополнительное время, необходимое для обмена данными в конвейерной версии, равно .

Общее время выполнения конвейерной версии алгоритма составляет:

Рекомендации

Библиография