Это не официальный сайт wikipedia.org 01.01.2023

Алгоритм Шрайера — Симса — Википедия

Алгоритм Шрайера — Симса

Алгоритм Шрайера — Симса — алгоритм из области вычислительной теории групп, позволяющий после однократного исполнения за линейное время находить порядок группы, порождённой перестановками, проверять принадлежность элемента такой группе и перечислять её элементы. Алгоритм был предложен Чарльзом Симсом в 1970 году для поиска примитивных групп перестановок[1] и основывается на лемме Шрайера о порождении подгрупп[2]. Представление группы перестановок, которое находит алгоритм, аналогично ступенчатому виду матрицы для её пространства строк[3]. Разработанные Симсом методы лежат в основе большинства современных алгоритмов для работы с группами перестановок[4], модификации алгоритма также используются в современных системах компьютерной алгебры, таких как GAP и Magma[en][5]. Одним из наиболее наглядных приложений алгоритма является то, что он может быть использован для решения кубика Рубика[6].

Алгоритм Шрайера — Симса
Граф Кэли группы '"`UNIQ--postMath-00000001-QINU`"'
Граф Кэли группы S 4
Назван в честь Чарльз Симс и Отто Шрайер
Автор Чарльз Симс
Предназначение Определение порядка группы перестановок
Структура данных Перестановки
Худшее время O ( n 3 m + n 6 )

ИсторияПравить

 
Чарльз Симс

Одной из основных задач в теории групп перестановок является поиск групп перестановок заданной степени (то есть минимального числа элементов множества, в группу перестановок которого вкладывается заданная группа перестановок). К 1970 году для степеней от 2 до 11 были найдены все группы перестановок, для степеней от 12 до 15 были найдены все транзитивные группы (то есть подгруппы, действующие на порождающем множестве транзитивно), а для степеней от 16 до 20 были найдены только примитивные группы перестановок[en]. Для поиска примитивных групп большей степени Чарльз Симс разработал программу, которая находит порядок и некоторую структуру в группе перестановок, заданной своим порождающим множеством[1].

Оригинальная программа, упомянутая в работе Симса, была написана для IBM 7040[en] в Ратгерском университете и поддерживала работу с любыми группами, чья степень не превосходила 50[7]. Точная оценка времени работы алгоритма была впервые проведена Фурстом, Хопкрофтом и Лаксом[en] в 1980 году[8]. Время работы было улучшено Джеррумом[en] в 1982[9] и Дональдом Кнутом в 1981 году[10]. В 1980 году была разработана эффективная вероятностная версия алгоритма[11]. Различные вариации алгоритма, включая те, которые используют вектор Шрайера[en] вместо дерева орбиты, были разобраны Шерешем[de] в 2003 году[12][13].

В вычислительной теории групп алгоритмы над группами перестановок — одна из наиболее развитых областей, и даже сегодня большинство из этих алгоритмов основываются на методах, разработанных Симсом[4].

Основная идеяПравить

Эффективность вычислений с группой перестановок существенно зависит от того, как она задана в программе[2]. Один из эффективных способов такого задания — выделить ряд её подгрупп и выбрать однозначных представителей смежных классов для каждой подгруппы в этом ряду относительно её предшественника. Предложенный Чарльзом Симсом алгоритм находит ряд подгрупп, в котором каждая следующая группа является стабилизатором предыдущей. Последовательность точек, для которых строятся стабилизаторы, называется базой[en], а множество, содержащее образующие элементы для каждой группы в ряду, — сильным порождающим множеством[en][2].

Алгоритм строит базу и сильное порождающее множество для подгруппы перестановок, заданной своим порождающим множеством, используя лемму Шрайера для нахождения порождающих множеств. Размер получаемых на промежуточных шагах множеств растёт экспоненциально, поэтому были разработаны вариации алгоритма, уменьшающие количество рассматриваемых порождающих элементов[2].

Описанное выше представление разбивает группу в произведение вложенных в неё подмножеств аналогично тому, как ступенчатое представление разбивает векторное пространство в прямую сумму вложенных в него подпространств[3].

Постановка задачиПравить

Симметрической группой S n   называют группу, элементами которой являются перестановки элементов некоторого множества Ω  . Обычно в качестве такого множества берётся Ω = { 1 , 2 , , n }  . В таких обозначениях элементы группы можно рассматривать как отображения σ : Ω Ω  , переводящие множество Ω   в себя, то есть его автоморфизмы. Групповой операцией в таких обозначениях является композиция перестановок, для перестановок σ 1   и σ 2   определяемая как σ = σ 1 σ 2  , где σ ( ω ) = σ 1 ( σ 2 ( ω ) )   для ω Ω  . Соответственно, единичной перестановкой будет перестановка σ   такая, что σ ( ω ) = ω  , а обратная перестановка может быть задана как σ 1 ( σ ( ω ) ) = ω  [14].

Пусть S = { g 1 , , g m } S n   — множество перестановок длины n  . Порождённой подгруппой множества S   называют наименьшую по включению подгруппу S  , которая содержит S   как подмножество или, что эквивалентно, подгруппу всех элементов S n  , которые могут быть представлены в виде конечного произведения элементов S   и обратных к ним. Порядком группы перестановок S   называют число элементов в ней | S |  , а её степенью — мощность множества | Ω |  , на котором она действует. В таких обозначениях алгоритм должен уметь[7]:

  • Получать порядок | S |   подгруппы, порождённой данными перестановками,
  • По перестановке g   проверять, лежит ли она в порождённой подгруппе S  ,
  • Последовательно перечислять элементы порождённой подгруппы без повторений.

ПримененияПравить

Модификации алгоритма реализованы в двух наиболее популярных специализированных на вычислительной теории групп системах компьютерной алгебры — GAP и Magma[en][5]. Инструменты для работы с группами перестановок, включая алгоритмы перечисления смежных классов и алгоритм Шрайера — Симса также представлены в популярных системах более широкого профиля Maple и Mathematica[15]. Изначально алгоритм был разработан для поиска примитивных групп перестановок заданной степени[1], однако впоследствии область его применения многократно выросла — например, с помощью данного алгоритма можно находить решения к заданной конфигурации кубика Рубика, так как его вращения образуют группу[6]. Также алгоритм хорошо показал себя при работе с группами матриц[en][16].

АлгоритмПравить

Факторизация группыПравить

Пусть H   — подгруппа некоторой конечной группы G  , через G / H   обозначим трансверсаль семейства левых смежных классов { g H : g G }  . Любой элемент g G   может быть единственным образом представлен как g = t h  , где t G / H   и h H  . Последовательно применяя этот результат к H   и её подгруппам, его можно обобщить в следующем виде[3][17]:

Пусть G = G ( 0 ) G ( 1 ) G ( k ) = { e }   — ряд подгрупп G  . Тогда любой элемент g G   может быть единственным образом представлен как g = g 1 g 2 g k  , где g 1 G ( 0 ) / G ( 1 ) , g 2 G ( 1 ) / G ( 2 ) , , g k G ( k 1 ) / G ( k )  .

Вычисление порядка и перечисление элементовПравить

Описанное выше представление обладает такими свойствами:

  • По теореме Лагранжа порядок группы может быть вычислен по формуле | G | = | G ( 0 ) / G ( 1 ) | × | G ( 1 ) / G ( 2 ) | × × | G ( k 1 ) / G ( k ) |  [3],
  • Элементы группы можно перечислить, перебирая все возможные представления g = g 1 g 2 g k  [7].

Чтобы также иметь возможность проверять элементы на принадлежность порождённой подгруппе, нужно рассматривать ряды подгрупп особого вида, а именно — составленные из стабилизаторов[7].

Орбиты и стабилизаторыПравить

Пусть G   действует на множестве Ω  . Выберем набор элементов ω 1 , , ω k Ω   и построим ряд подгрупп так, чтобы выполнялось G ( i ) = G ω i ( i 1 )  , где G ω = { g : g ω = ω }   — стабилизатор элемента ω  . Другими словами, G ( i )   — это подгруппа элементов G  , которые переводят каждый из элементов ω 1 , , ω i   в себя[7]. При таком подходе на каждом следующем шаге часть множества Ω  , на которую нетривиально действует очередная подгруппа G  , будет уменьшаться на один элемент, а порядок подгруппы, с которой ведётся работа, — хотя бы в два раза. Из этого следует, что понадобится min ( | Ω | , log | G | )   итераций алгоритма, прежде чем будет найдено искомое разбиение[18].

Для построения смежных классов нужно воспользоваться тем, что существует взаимно-однозначное соответствие (биекция) между элементами орбиты G ω   и левыми смежными классами G / G ω   стабилизатора G ω  [19].

Из доказательства следует, что в качестве представителей смежных классов можно брать элементы, реализующие различные точки орбиты G ω  [19].

Проверка принадлежностиПравить

Обозначим через u ¯   такой элемент G / G ω  , что u ¯ ω = u  . Разбиение в ряд стабилизаторов позволит проверять элемент на принадлежность группе[7]:

  • Если g G ( i 1 )  , то найдётся элемент t i G ( i 1 ) / G ( i )   такой, что g t i G ( i )  , то есть t i 1 g G ( i )  ,
  • В силу биекции между элементами смежного класса и точками орбиты, можно однозначно определить, что t i = g ( ω i ) ¯  .

Эти свойства позволяют сделать переход от G ( i 1 )   к G ( i )  , что в итоге приведёт к тому, что текущий элемент должен лежать в G ( k ) = { e }  . Если это действительно так, то e = t k 1 t 2 1 t 1 1 g  , откуда можно выразить g = t 1 t 2 t k  [7].

Вычисление орбитыПравить

Пусть у группы G   есть порождающее множество S  . Орбиту любого элемента α   под действием группы G = S   можно организовать в дерево следующего вида[17]:

  • В корне дерева записан некоторый элемент α Ω  ,
  • В каждой вершине дерева записан некоторый элемент β G ( α )   из орбиты элемента α  ,
  • На ребре, ведущем из вершины с элементом u   в вершину с элементом v  , записан элемент s S   такой, что s ( u ) = v  .

Описанное дерево можно построить обходом в глубину, для этого нужно в каждой вершине u   перебирать элемент s S  , пока не окажется, что для s ( u )   ещё не была выделена вершина[17]. Пример реализации на языке Python:

# Строит дерево орбиты по заданному элементу w и порождающему множеству S
def build_schreier_tree(w, S, orbit):
    for g in S:
        if g[w] not in orbit:
            orbit[g[w]] = apply(g, orbit[w])
            build_schreier_tree(g[w], S, orbit)

Здесь функция a p p l y ( a , b )   возвращает результат применения групповой операции к элементам a   и b   в качестве первого и второго аргумента, а в o r b i t [ α ]   хранится элемент α ¯  .

Лемма ШрайераПравить

Из леммы Шрайера следует, что стабилизатор G α   порождается множеством генераторов Шрайера: G ω = { ( s u ¯ ) 1 s u ¯ u G ω , s S }  . Этот результат позволяет по порождающему множеству для G ( w 1 )   и орбите элемента ω   построить порождающее множество для G ( ω )  . Возможная реализация для функции, возвращающей новое порождающее множество[20]:

# Принимает порождающее множество для G_{w-1} и орбиту элемента w
# Возвращает порождающее множество для G_w
def make_gen(S, orbit):
    n = len(next(iter(S)))
    newS = set()
    for s in S:
        for u in orbit:
            newS.add(reduce(apply, [inverse(orbit[s[u]]), s, orbit[u]]))
    return newS

Этим алгоритм не исчерпывается, так как хотя размер нового порождающего множества и зависит полиномиально от размера орбиты и старого порождающего множества для одного отдельного вызова, в совокупности по всем вызовам данной функции размер порождающего множества растёт экспоненциально[2].

Просеивание генераторовПравить

Чтобы избежать неконтролируемого роста порождающих множеств, необходимо применять процедуру просеивания. Для этого потребуется следующее утверждение[3][20]:

Пусть S G  . Тогда можно построить набор S   из не более чем | Ω | 2   элементов такой, что S = S  .

Описанная в доказательстве процедура называется фильтром Симса и работает за O ( | S | Ω 2 )  [21]. Её реализация может выглядеть так:

# Принимает порождающее множество S
# Возвращает прореженное порождающее множество S'
def normalize(S):
    n = len(next(iter(S)))
    newS = set()
    base = [{} for i in range(n)]
    for s in S:
        for x in range(0, n):
            if s[x] != x:
                if s[x] in base[x]:
                    s = apply(inverse(s), base[x][s[x]])
                else:
                    base[x][s[x]] = s
                    newS.add(s)
                    break
    return newS

Помимо фильтра Симса для поиска небольшого набора S   может использоваться фильтр Джеррума[22]. В отличие от фильтра Симса, который находит набор из не более, чем | Ω | 2   элементов, фильтр Джеррума находит набор из не более чем | Ω |   элементов. В то же время фильтр Джеррума работает за O ( | S | | Ω | 4 )  , поэтому в случае алгоритма Шрайера — Симса предпочтительнее использовать именно фильтр Симса[21].

АлгоритмПравить

Всё вышенаписанное вместе даёт алгоритм, который может быть лаконично реализован следующим образом[20]:

# Принимает порождающее множество S = s1, ..., sk
# Возвращает трансверсали смежных классов U1, ..., Uk
def schreier_sims(S):
    n = len(next(iter(S)))
    ans = []
    w = 0
    while S:
        orbit = {}
        orbit[w] = tuple(range(n))
        
        build_schreier_tree(w, S, orbit)
        ans += [[orbit[i] for i in orbit]]
        
        S = normalize(make_gen(S, orbit))
        w += 1
    return ans

По шагам его действия имеют следующий смысл:

  1. Строится орбита элемента ω i   поиском в глубину,
  2. Вычисляются все генераторы Шрайера для G ( i + 1 )  ,
  3. Множество генераторов прореживается, чтобы избежать их экспоненциального роста.

На выходе алгоритм вернёт список, элементами которого являются трансверсали смежных классов G ( 0 ) / G ( 1 ) , G ( 1 ) / G ( 2 ) , , G ( k 1 ) / G ( k )  .

Время работы алгоритмаПравить

Всего алгоритм требует не больше | Ω |   итераций. Каждая итерация состоит из:

  1. Построения дерева орбиты, которое занимает O ( | S | | Ω | )   элементарных операций,
  2. Построения генераторов Шрайера, которое занимает O ( | S | | Ω | 2 )   элементарных операций и возвращает | S | | Ω |   генераторов,
  3. Нормализации порождающего множества, которое занимает O ( | S | | Ω | 2 )   элементарных операций, где S   — множество, полученное на прошлом шаге.

Величина | Ω |   в случае, когда дан набор S = { g 1 , , g m } S n  , на протяжении алгоритма не меняется и равна n  . Размер порождающего множество изначально равен m  , а на каждом последующем шаге не превышает | Ω | 2 = n 2  . Таким образом, общее время работы алгоритма в приведённой реализации можно оценить как O ( n 3 m + n 6 )  [8][12][13].

Вариации алгоритмаПравить

Псевдо-линейные версииПравить

Ранее было показано, что алгоритм требует min ( | Ω | , log | G | )   итераций. В общем случае размер группы может быть порядка n !  , и в таком случае по формуле Стирлинга log | G | n log n  , что заведомо больше | Ω | = n  . Но в некоторых случаях порядок группы небольшой, в связи с чем выгоднее иметь алгоритм, который зависит от log | G |  , а не n   — например, когда речь идёт о какой-то известной группе, которая задана как группа перестановок[12].

По теореме Кэли любая конечная группа изоморфна некоторой группе перестановок. Степень такой группы n   может быть большой, но для многих групп их порядок | G |   таков, что log | G | < n  . Например, диэдральная группа D n   изоморфна группе перестановок, порождённой циклическим сдвигом r = ( 1     2         n )   и отражением s = ( 1     n ) ( 2     n 1 ) ( 3     n 2 )  . То есть степень данной группы равна n  , а порядок — 2 n  , и log | G | log n  . Для таких групп можно рассматривать алгоритмы со временем работы O ( n m log c | G | )  , которые называются псевдо-линейными[12].

В попытке приблизить алгоритм к псевдо-линейному и снизить степень n  , входящую в его время работы, Шереш пришёл к версиям алгоритма, требующим[18]:

  1. O ( n 2 log 3 | G | + m n 2 log | G | )   времени и O ( n 2 log | G | + m n )   памяти,
  2. O ( n 3 log 3 | G | + m n 3 log | G | )   времени и O ( n log 2 | G | + m n )   памяти.

Вероятностная версияПравить

Первая рабочая вероятностная версия алгоритма была разработана Джефри Леоном в 1980 году[11]. Обычно именно её имеют в виду, когда говорят про вероятностный метод Шрайера — Симса. В нём при прореживании генераторов Шрайера данная процедура досрочно прекращалась, если 20 генераторов подряд оказывались разложенными на множители. Шереш показал, что в совокупности с некоторыми оптимизациями эта процедура даёт следующее утверждение[5]:

Для любой константы d   существует алгоритм типа Монте-Карло, который с вероятностью ошибки не больше n d   построит сильное порождающее множество для группы перестановок G = S  , используя O ( n log n log 4 | G | + m n log | G | )   времени и O ( n log | G | + m n )   памяти.

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

ПримечанияПравить

  1. 1 2 3 Симс, 1970, p. 169—170.
  2. 1 2 3 4 5 Мюррей, 2003, p. 1—3.
  3. 1 2 3 4 5 Холт, Эйк, О'Брайен, 2005, p. 87—90.
  4. 1 2 Шереш, 2003, p. 1—4.
  5. 1 2 3 4 Шереш, 2003, p. 62—64.
  6. 1 2 Брауэр, 2016, p. 4.
  7. 1 2 3 4 5 6 7 Симс, 1970, p. 176—177.
  8. 1 2 Фурст, Хопкрофт, Лакс, 1980.
  9. Джеррум, 1986.
  10. Кнут, 1991.
  11. 1 2 Леон, 1980.
  12. 1 2 3 4 Шереш, 2003, p. 48—54.
  13. 1 2 Холт, Эйк, О'Брайен, 2005, p. 93—94.
  14. Журавлёв, Флёров, Вялый, 2019, Перестановки, с. 31—36.
  15. Холт, Эйк, О'Брайен, 2005, p. 1—7.
  16. Мюррей, О'Брайен, 1995.
  17. 1 2 3 Мюррей, 2003, p. 9—24.
  18. 1 2 Шереш, 2003, p. 59—62.
  19. 1 2 Журавлёв, Флёров, Вялый, 2019, Орбиты и стабилизаторы, с. 140—145.
  20. 1 2 3 Мюррей, 2003, p. 25—33.
  21. 1 2 Vipul Naik. Sims filter (англ.). Groupprops, The Group Properties Wiki. Дата обращения: 23 сентября 2019. Архивировано 1 сентября 2019 года.
  22. Vipul Naik. Jerrum's filter (англ.). Groupprops, The Group Properties Wiki. Дата обращения: 23-09-19. Архивировано 1 сентября 2019 года.

ЛитератураПравить