Участник:Full/Поиск автоморфизмов графов: различия между версиями

Материал из Алговики
Перейти к навигации Перейти к поиску
Строка 192: Строка 192:
При классификации по высоте ЯПФ, таким образом, алогоритм имеет сложностью <math> O(n) </math>.
При классификации по высоте ЯПФ, таким образом, алогоритм имеет сложностью <math> O(n) </math>.


При классификации по ширине ЯПФ его сложность <math> O(O(n(\frac{e}{2})^{\ln(n)^2} \ln(n))) </math>.
При классификации по ширине ЯПФ его сложность <math> O(n(\frac{e}{2})^{\ln(n)^2} \ln(n))) </math>.


== Входные и выходные данные алгоритма ==
== Входные и выходные данные алгоритма ==

Версия от 11:37, 10 декабря 2017

Алгоритм: Поиск автоморфизмов графов
Автор статьи: Ефремов С.С. (группа 419)

Свойства и структура алгоритмов

Данный алгоритм, описанный в статье Егорова В.Н.[1], предназначен для поиска автоморфизмов графов, которые можно представить в виде матриц смежности, а также для исследования изоморфности графов. Так как алгоритм работает с матрицами, можно решать эти же задачи и на других комбинаторных объектах, представимых матрицами смежности[2].

Общее описание алгоритма

На вход подается матрица смежности графа. При отображение вершины v1 в вершину v2 в соответсвующей графу матрице меняются местами строка и столбец v1 со строкой и столбцом v2. Автоморфизмом является отображение множества вершин графа на себя, сохраняющее смежность. Это есть такая перестановка строк и столбцов матрицы, после применения которой, матрица останется той же.

Математическое описание алгоритма

Определения и обозначения

[math]\displaystyle{ A = A^{n\times n} }[/math] - матрица смежности графа [math]\displaystyle{ G(V,E) }[/math] размера [math]\displaystyle{ n\times n }[/math]; [math]\displaystyle{ a_{ij} }[/math] - элементы матрицы ,[math]\displaystyle{ \ i,j = 1,\ldots,n=|V| }[/math].

Частичным отображением [math]\displaystyle{ g^s_k }[/math] ([math]\displaystyle{ s }[/math] - обозначает индекс элемента в множестве [math]\displaystyle{ M_k }[/math]) называется подстановка вида

[math]\displaystyle{ \begin{pmatrix} 1 & 2 & \ldots & k & k+1 &\ldots & n\cr r_1 & r_2 & \ldots & r_k & q_{k+1} & \ldots & q_n \end{pmatrix} }[/math]

, где [math]\displaystyle{ r_1,\ldots,r_k }[/math] - фиксированные (заданные) элементы, [math]\displaystyle{ q_{k+1},\ldots,q_n }[/math] - произвольные, причем последовательность [math]\displaystyle{ r_1,\ldots,r_k }[/math], [math]\displaystyle{ q_{k+1},\ldots,q_n }[/math] является перестановкой вершин заданного графа.

[math]\displaystyle{ M_k }[/math] - множество, состоящее из элементов [math]\displaystyle{ g^s_k }[/math], [math]\displaystyle{ \ s = 1,\ldots,n_k=|M_k| }[/math].

[math]\displaystyle{ |M_k| }[/math] - количество элементов [math]\displaystyle{ g^s_k }[/math] в множестве.

[math]\displaystyle{ M'_k }[/math] - множество элементов, которые содержатся в [math]\displaystyle{ M_k }[/math] и удовлетворяют критерию [math]\displaystyle{ h }[/math].

h - критерий (описанный далее).

[math]\displaystyle{ \{M'_k\} }[/math] - последовательность множеств [math]\displaystyle{ M'_k }[/math], [math]\displaystyle{ k = 1,\ldots,n }[/math].


Проверка по критерию

Критерием [math]\displaystyle{ h }[/math] является проверка подматриц на равенство. Предположим, требуется определить, удовлетворяет ли элемент [math]\displaystyle{ g^s_k }[/math] критерию h. Для этого необходимо, чтобы элементы [math]\displaystyle{ a_{ij} }[/math], для всех [math]\displaystyle{ i,j \leq k }[/math], были равны соответствующим элементам [math]\displaystyle{ a_{r_ir_j} }[/math]. Подматрица [math]\displaystyle{ g^s_k }[/math] выглядит так:

[math]\displaystyle{ \begin{matrix} & r_1 & r_2 & \dots & r_k \cr r_1 & a_{r_1r_1} & a_{r_1r_2} & \dots & a_{r_1r_k} \cr r_2 & a_{r_2r_1} & a'_{r_2r_2} & \dots & a_{r_2r_k} \cr \vdots & \vdots & \vdots & \ddots & \vdots \cr r_k & a_{r_kr_1} & a_{r_kr_2} & \dots & a_{r_kr_k} \cr \end{matrix} }[/math]

Если хотя бы одно из равенств не выполнено, это означает, что по данной частичной подстановке хотя бы одна вершина отобразилась в другую так, что структура графа изменилась. А так как частичная перестановка [math]\displaystyle{ g^s_k }[/math] фиксирует [math]\displaystyle{ r_1, \ldots r_k }[/math], то структура останется измененой, что означает отображение не будет являться автоморфизмом.


Построение множеств частичных отображений

Описание построения [math]\displaystyle{ M'_n }[/math].

На первом этапе рассматриваются все [math]\displaystyle{ g^s_1 }[/math], образующие множество [math]\displaystyle{ M_1 }[/math]. Каждый элемент [math]\displaystyle{ g^s_1 }[/math] проверяется по критерию h. Элементы, удовлетворяющие h, образуют [math]\displaystyle{ M'_1 }[/math]. В каждый элемент из [math]\displaystyle{ M'_1 }[/math] добавляется еще одно отображение (2 [math]\displaystyle{ \to }[/math] [math]\displaystyle{ r_2 }[/math]), т.е. происходит переход от [math]\displaystyle{ g^s_1 }[/math] к [math]\displaystyle{ g^s_2 }[/math]. Из каждого [math]\displaystyle{ g^s_1 }[/math] получается разных [math]\displaystyle{ (n-1) }[/math] элементов [math]\displaystyle{ g^s_2 }[/math]. Всевозможные элементы [math]\displaystyle{ g^s_2 }[/math] образуют [math]\displaystyle{ M_2 }[/math]. Далее строится [math]\displaystyle{ M'_2 }[/math], добавляя в него только те элементы из [math]\displaystyle{ M_2 }[/math], которые удовлетворяют критерию. Аналогично получаются множества [math]\displaystyle{ M_3,\ M'_3,\ M_4,\ldots, M_n,\ M'_n }[/math].


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

[math]\displaystyle{ \{M'_k\} }[/math]: [math]\displaystyle{ M'_1 \subseteq M'_2 \subseteq \ldots \subseteq M'_n }[/math].

Множество [math]\displaystyle{ M'_n }[/math] является множеством всех возможных автоморфизмов (или пустое, если их нет).

Вычислительное ядро алгоритма

Вычислительным ядром алгоритма является последовательность множеств [math]\displaystyle{ M'_1 \ldots M'_n }[/math]. Вычисляется на основе соответствующих [math]\displaystyle{ M_1 \ldots M_n }[/math]. Построение [math]\displaystyle{ M_1 \ldots M_n }[/math] занимает несущественную часть времени.

Макроструктура алгоритма

Каждое множество [math]\displaystyle{ M_i (i = 2 \ldots n) }[/math] вычисляется из [math]\displaystyle{ M'_{i-1} }[/math] путем добавления в каждый элемент (частичная перестановка, представленная вектором целых чисел) из [math]\displaystyle{ M'_{i-1} }[/math] всех возможных оставшихся чисел, которых нет в соответствующем элементе.

Для этого удобно использовать 2 не фиксированных по количеству строк двумерных массива размера t на n (t может увеличиваться), хранящих частичные отображения, такого вида:

[math]\displaystyle{ \begin{pmatrix} a_{11} & a_{12} & \ldots &a_{1i} & ? & \ldots & ? \cr a_{21} & a_{22} & \ldots &a_{2i} & ? & \ldots & ? \cr \ldots \cr a_{k1} & a_{k2} & \ldots &a_{ki} & ? & \ldots & ? \cr ? & ? & \ldots &  ? & ? & \ldots & ? \cr \ldots \cr ? & ? & \ldots &  ? & ? & \ldots & ? \cr \end{pmatrix} }[/math]

? - эти значения не известны и заполняются постепенно.

Один массив для [math]\displaystyle{ M'_{i-1} }[/math], другой для вычисления из предыдущего [math]\displaystyle{ M_i }[/math]. Из каждой строки множества [math]\displaystyle{ M'_{i-1} }[/math] (первый массив), в соответствие с алгоритмом, получается [math]\displaystyle{ n }[/math] новых строк длины i, которые записываются во второй массив (расширяется, если нужно).

После этого, второй массив копируется в первый и запускается цикл по всем векторам. Вектор исключается из массива, если [math]\displaystyle{ a_{ji} }[/math] равен какому-либо числу в данном векторе или вектор с [math]\displaystyle{ a_{ji} }[/math] является частичной перестановкой, не удовлетворяющей критерию;

Схема реализации последовательного алгоритма

Схема реализации представлена на языке C++

#define GRAPH_SIZE 300
#define ROW_ARR_SIZE 10000 
#define COL_ARR_SIZE GRAPH_SIZE

const int N = GRAPH_SIZE;

vector<array<unsigned short,COL_ARR_SIZE>> Mi(ROW_ARR_SIZE, COL_ARR_SIZE);
vector<array<unsigned short,COL_ARR_SIZE>> M'i(ROW_ARR_SIZE, COL_ARR_SIZE);
unsigned char **matrix;

struct_M'i make_M'i(Mi) {
    struct_M'i M'i;
    for (auto x: Mi) {
        for (int i = 0; i < n; ++i) {
            if (check_h(x) && !eq(x, i)) {
                M'i.push_back(x.add(i));
            }
        }
    }
    return M'i;
}

struct_Mi make_Mi(M'i) {
    struct_Mi Mi;
    for (auto x: M'i) {
        for (int i = 0; i < n; ++i) {
           Mi.push_back(x.add(i));
        }
    }
    return Mi;
}

int main() {

    //заполнение матрицы смежности
    init_automorphisms(matrix);

    //распараллеливание
    switch(process) {
    case 0:
        begin = 0;
        end = stop_0;
    case 1:
        begin = start_1;
        end = stop_1;
    ...
    case N:
        begin = start_n;
        end = M_0.size();

    //основной цикл
    for (i = begin; i < end; ++i) {
        Mi = make_Mi(M'i-1);
        M'i = make_M'i(Mi);
    }

    //сохранение результата (вывод автоморфизмов)
    final_automorphism(M'i);
}

Последовательная сложность алгоритма

Сложность всего алгоритма представляет собой сумму сложностей вычисления [math]\displaystyle{ M'_1 \ldots M'_n }[/math].

Количество элементов в каждом множестве (с вероятностью близкой к единице):

[math]\displaystyle{ |M'_{k}| \thickapprox \frac{n!}{(n-k-2)!~2^{(k)^2}} \thickapprox \frac{1}{e^{k}} \frac{n^{n+1/2}}{(n-k-2)^{(n-k-3/2)}~2^{(k)^2}} }[/math]

Можно оценить: [math]\displaystyle{ |M'_k| = \frac{n(n-1)\ldots(n-k-1)}{2^{(k)^2}} \le \frac{n^{k}}{2^{(k)^2}} }[/math]

Количество операций сравнения для подсчета всех множеств:

[math]\displaystyle{ \sum_{k = 1}^{n} \frac{1}{e^{k}} \frac{n^{n+1/2}}{(n-k-2)^{(n-k-3/2)}~2^{(k)^2}} \times (n - k)(2k + 1) }[/math]

Оценка (были учтены точка стабилизации и точка максимума последовательности множеств):

[math]\displaystyle{ n \times \frac{n^{(5/7) \ln(n)}}{2^{((5/7)\ln(n))^2}}\times n(2(\frac{5}{7}\ln(n)) + 1)\times \log_2(n) = O(n^2(\frac{e}{2})^{\ln(n)^2} \ln(n)) }[/math]

Сложность экспоненциальная.

Информационный граф

Граф алгоритма[3][4][5] при [math]\displaystyle{ n = 5 }[/math]:

Ресурс параллелизма алгоритма

Для поиска автоморфизмов матрицы порядка [math]\displaystyle{ n }[/math] итерационным алгоритмом в параллельном варианте требуется выполнить:

  • [math]\displaystyle{ n }[/math] ярусов сравнений (количество сравнений [math]\displaystyle{ }[/math])

При классификации по высоте ЯПФ, таким образом, алогоритм имеет сложностью [math]\displaystyle{ O(n) }[/math].

При классификации по ширине ЯПФ его сложность [math]\displaystyle{ O(n(\frac{e}{2})^{\ln(n)^2} \ln(n))) }[/math].

Входные и выходные данные алгоритма

Свойства алгоритма

Программная реализация алгоритма

Особенности реализации последовательного алгоритма

Локальность данных и вычислений

Возможные способы и особенности параллельной реализации алгоритма

Масштабируемость алгоритма и его реализации

Масштабируемость реализации алгоритма

Исследование проводилось на суперкомпьютере "Ломоносов"[6] Суперкомпьютерного комплекса Московского университета.

Набор и границы значений изменяемых параметров запуска реализации алгоритма:

  • число процессоров [4 : 128] с шагом [math]\displaystyle{ 2^n }[/math] (точки отображены с шагом 4, усреднив результаты);
  • размер матрицы [300 : 1000].

В результате проведённых экспериментов был получен следующий диапазон алгоритма:

  • минимальная эффективность реализации 0,11%;
  • максимальная эффективность реализации 2,65%.

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

Файл:.png
Рисунок 1. Параллельная реализация алгоритма поиска автоморфизмов. Изменение производительности в зависимости от числа процессоров и размера матрицы.
Файл:.png
Рисунок 2. Параллельная реализация алгоритма поиска автоморфизмов. Изменение эффективности в зависимости от числа процессоров и размера матрицы.

Оценки масштабируемости выбранной реализации:

  • По числу процессов: -0,000593. При увеличении числа процессов эффективность на рассмотренной области изменений параметров запуска уменьшается, однако в целом уменьшение не очень быстрое. Малая интенсивность изменения объясняется крайне низкой общей эффективностью работы приложения с максимумом в 2,65%, и значение эффективности на рассмотренной области значений быстро доходит до десятых долей процента. Это свидетельствует о том, что на большей части области значений нет интенсивного снижения эффективности. Это объясняется также тем, что с ростом вычислительной сложности падение эффективности становится не таким быстрым. Уменьшение эффективности на рассмотренной области работы параллельной программы объясняется быстрым ростом накладных расходов на организацию параллельного выполнения. С ростом вычислительной сложности задачи эффективность снижается так же быстро, но при больших значениях числа процессов. Это подтверждает предположение о том, что накладные расходы начинают сильно превалировать над вычислениями.
  • По размеру задачи: 0,06017. При увеличении размера задачи эффективность возрастает. Эффективность возрастает тем быстрее, чем большее число процессов используется для выполнения. Это подтверждает предположение о том, что размер задачи сильно влияет на эффективность выполнения приложения. Оценка показывает, что с ростом размера задачи эффективность на рассмотренной области значений параметров запуска сильно увеличивается. Также, учитывая разницу максимальной и минимальной эффективности в 2,5%, можно сделать вывод, что рост эффективности при увеличении размера задачи наблюдается на большей части рассмотренной области значений.
  • По двум направлениям: 0,000403. При рассмотрении увеличения как вычислительной сложности, так и числа процессов на всей рассмотренной области значений эффективность увеличивается, однако скорость увеличения эффективности небольшая. В совокупности с тем фактом, что разница между максимальной и минимальной эффективностью на рассмотренной области значений параметров небольшая, эффективность с увеличением масштабов возрастает, но медленно и с небольшими перепадами.

Динамические характеристики и эффективность реализации алгоритма

Выводы для классов архитектур

Существующие реализации алгоритма

Информация о реализациях данного алгоритма не найдена. При анализе алгоритма было разработано 2 программы:

1) приложение с графическим интерфейсом, написанное на Qt
  • не поддерживает распараллеливание
  • справляется с графами размера до 500 вершин
  • удобный анализ графов
  • помимо нахождения автоморфизмов, решает задачи изоморфизма и гомоморфизма графов
2) программа на языки C++ с поддержкой OpenMPI
  • поддерживает распараллеливание средствами OpenMPI
  • помимо нахождения автоморфизмов, сохраняет много информации для анализа графов с большим количеством вершин

Литература

  1. ↑ Группы автоморфизмов и изоморфизм комбинаторных объектов и алгебраических структур. Егоров В.Н., Егоров А.В. (Ломоносовские чтения, Научная конференция, Москва, факультет ВМК МГУ имени М.В.Ломоносова).
  2. ↑ О группах автоморфизмов матриц. Егоров В.Н. (журнал "Прикладная дискретная математика").
  3. ↑ Воеводин В.В. Математические основы параллельных вычислений// М.: Изд. Моск. ун-та, 1991. 345 с.
  4. ↑ Воеводин В.В., Воеводин Вл.В. Параллельные вычисления. – СПб.: БХВ - Петербург, 2002. – 608 с.
  5. ↑ Фролов А.В.. Принципы построения и описание языка Сигма. Препринт ОВМ АН N 236. М.: ОВМ АН СССР, 1989.
  6. ↑ Воеводин Вл., Жуматий С., Соболев С., Антонов А., Брызгалов П., Никитенко Д., Стефанов К., Воеводин Вад. Практика суперкомпьютера «Ломоносов» // Открытые системы, 2012, N 7, С. 36-39.