Skip to content

k5ta/floyd-warshall

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

7 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Алгоритм Флойда-Уоршелла

Предстваляет собой алгоритм нахождения длин кратчайших путей между всеми парами вершин во взвешенном ориентированном графе. Алгоритм работает за θ(n^3) времени и использует θ(n^2) памяти. Был разработан Робертом Флойдом и Стивеном Уоршеллом в 1962 году.

Решаемая задача

Дан взвешенный ориентированный граф G(V,E), в котором вершины пронумерованы от 1 до n.

Граф задан в виде матрицы, где на месте элемента (i,j) стоит расстояние между вершинами i и j в случае, если между ними есть ребро, и бесконечности в противном случае.

Требуется найти матрицу кратчайших расстояний, в которой элемент (i,j) либо равен длине кратчайшего пути из i в j, либо равен бесконечности, если вершина j не достижима из i.

Реализация

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

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

Формат данных

Путь к файлу с данными указывается в application.conf следующим образом (пример для файла matrix_data.txt):

input-data = "matrix_data.txt"

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

Пример файла для небольшой матрицы:

2.1 3

inf 11.02

Путь к файлу с выходными данными указывается в application.conf следующим образом (пример для файла matrix_result.txt):

output-data = "matrix_result.txt"

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

Требования к запуску

  • Scala 2.13.3 (см. файл build.sbt)
  • SBT 1.4.1 (см. файл build.properties)
  • Java 8+ (тестировалось на Java 11, AdoptOpenJDK)

Сборка и запуск

Сборка:

sbt assembly

Запуск:

java -Dconfig.file=application.conf -Dlog4j.configurationFile=log4j2.xml -jar FloydWarshall-assembly-1.0.jar

В файле application.conf указывается максимальное число потоков выполнения программы следующим образом (пример для двух потоков):

max-threads = 2

Также возможно указание флага для печати времени работы алгоритма:

print-time = true

К проекту приложены файлы application.conf, а также matrix_data.txt с примером входных данных и matrix_result.txt с примером правильного результата дла таких данных.

Скорость параллелизации

Поскольку для выполнения программы может быть поставлен флаг печати времени работы алгоритма, была осуществлена проверка и проведено дальнейшее сравнение результатов для различного числа потоков. Для облегчения тестирования был написан скрипт matrix_generator.py, позволяющий получить файл с матрицей нужного размера и случайных значений из нужного диапазона. Важный момент: для упрощения скрипта и множественного заполнения "бесконечностью", был выбран простой метод - положительные значения записываются в матрицу, а вместо отрицательных пишется ноль. Рекомендуемое количество отрицательных чисел в диапазоне - 40-50%.

Было проведено тестирование производительности для матриц разных размерностей. Тестирование осуществлялось на процессоре Intel Core i5-7200U, по заявлениям производителя, обладающий двумя физическими и четыремя логическими ядрами. Таким образом, наиболее разумным вариантом выглядит проверка исполнения программы в 1, 2, 4 и 8 потоках.

Данные для матриц размерности 1000x1000 и 2000x2000 вынесены в таблицу и представлены в секундах (среднее значение 5 измерений).

Число потоков/Размерность N = 1000 N = 2000
1 18 136
2 12.5 92
4 10.5 79
8 11.5 85

Некоторые выводы:

  • Несмотря на то, что операций для матрицы с N=2000 примерно в 8 раз больше, чем для матрицы с N=1000, соотношение времени выполнения меньше 8 - это связано с тем, что матрицы относительно небольшие и каждая строка обрабатывается достаточно быстро, а значит затраты связанные с многопоточностью (переключение контекста, синхронизация потоков и тд) вносят весомый вклад
  • Ожидаемо, наибольший скачек производительности происходит при использовании 2 потоков вместо 1. Для 4 рост по отношению к 2 незначителен, так как используются не разные физические ядра, а разные потоки в составе одного ядра, что обладает своими тонкостями
  • При использовании 8 потоков производительность падает - также ожидаемый вывод, поскольку при реальных 4 потоках использование 8 не даст выигрыша (реально используется 4 потока, остальные ждут, внося далее дополнительный вклад в общее время из-за синхронизацию и переключения)

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published