Монотонный код Грея — различия между версиями
Gpevnev (обсуждение | вклад) м  | 
				м (rollbackEdits.php mass rollback)  | 
				||
| (не показано 11 промежуточных версий 5 участников) | |||
| Строка 1: | Строка 1: | ||
{{Определение  | {{Определение  | ||
|definition =  | |definition =  | ||
| − | '''Монотонный код Грея''' (англ. ''Monotonic Gray Code'') {{---}} способ построения кода Грея, при котором <tex>\  | + | '''Монотонный код Грея''' (англ. ''Monotonic Gray Code'') {{---}} способ построения кода Грея, при котором <tex>\forall i < j</tex> <tex>\nexists g_i, g_j</tex>, что <tex>g_i</tex> содержит на <tex>2</tex> или больше единиц, чем <tex>g_j</tex>.  | 
}}  | }}  | ||
Монотонный код Грея преимущественно используется в теории связанных сетей, например для минимизации ожидания линейным массивом процессоров.<ref>[http://www.sciencedirect.com/science/article/pii/0097316595900918 C. D Savage and P. Winkler (1995). "Monotone Gray codes and the middle levels problem"page 7]</ref>  | Монотонный код Грея преимущественно используется в теории связанных сетей, например для минимизации ожидания линейным массивом процессоров.<ref>[http://www.sciencedirect.com/science/article/pii/0097316595900918 C. D Savage and P. Winkler (1995). "Monotone Gray codes and the middle levels problem"page 7]</ref>  | ||
| Строка 19: | Строка 19: | ||
Пусть <tex>Q_n(i)</tex> подграф <tex>Q_n</tex>, который является объединением двух смежных уровней, т. е. <tex>V_n(i) \cup V_n(i+1)</tex>, и пусть <tex>E_n(i)</tex> множество граней <tex>Q_n(i)</tex>.  | Пусть <tex>Q_n(i)</tex> подграф <tex>Q_n</tex>, который является объединением двух смежных уровней, т. е. <tex>V_n(i) \cup V_n(i+1)</tex>, и пусть <tex>E_n(i)</tex> множество граней <tex>Q_n(i)</tex>.  | ||
| − | Тогда монотонным кодом Грея будет являтся [[:Гамильтоновы_графы|Гамильтонов путь]] в <tex>Q_n</tex>, при котором любое множество вершин <tex>\delta_1 , \delta_2</tex> такие, что <tex>\forall i, j : i \leqslant j</tex>, то <tex>\delta_1 \in E_n(i)</tex> идет перед <tex>\delta_2 \in E_n(j)</tex>.  | + | Тогда монотонным кодом Грея будет являтся [[:Гамильтоновы_графы#.D0.9E.D1.81.D0.BD.D0.BE.D0.B2.D0.BD.D1.8B.D0.B5_.D0.BE.D0.BF.D1.80.D0.B5.D0.B4.D0.B5.D0.BB.D0.B5.D0.BD.D0.B8.D1.8F|Гамильтонов путь]] в <tex>Q_n</tex>, при котором любое множество вершин <tex>\delta_1 , \delta_2</tex> такие, что <tex>\forall i, j : i \leqslant j</tex>, то <tex>\delta_1 \in E_n(i)</tex> идет перед <tex>\delta_2 \in E_n(j)</tex>.  | 
Ниже на катринке Гамильтонов путь в гиперкубе <tex>Q_4</tex> для <tex>n = 4</tex>, построенный по алгоритму Саважа-Винклера (англ. ''Savage-Winkler'').<ref>[http://www.sciencedirect.com/science/article/pii/0097316595900918 C. D Savage and P. Winkler (1995). "Monotone Gray codes and the middle levels problem"page 14]</ref>  | Ниже на катринке Гамильтонов путь в гиперкубе <tex>Q_4</tex> для <tex>n = 4</tex>, построенный по алгоритму Саважа-Винклера (англ. ''Savage-Winkler'').<ref>[http://www.sciencedirect.com/science/article/pii/0097316595900918 C. D Savage and P. Winkler (1995). "Monotone Gray codes and the middle levels problem"page 14]</ref>  | ||
| Строка 30: | Строка 30: | ||
<tex>  | <tex>  | ||
P_{n+1,j} = 1P^{\pi_n}_{n,j-1}, 0P_{n,j}  | P_{n+1,j} = 1P^{\pi_n}_{n,j-1}, 0P_{n,j}  | ||
| − | </tex>. То есть P_{n+1, j} это объединение множеств P^{\pi_n}_{n,j-1} с приписанной в начале 1 и P_{n,j} с   | + | </tex>. То есть <tex>P_{n+1, j}</tex> это объединение множеств <tex>P^{\pi_n}_{n,j-1}</tex> с приписанной в начале <tex>1</tex> и <tex>P_{n,j}</tex> с приписанным в начале <tex>0</tex>.  | 
Здесь <tex>\pi_n</tex> это определенная перестановка элементов множества к которому она применена, а <tex>P^{\pi}</tex> это путь <tex>P</tex> к котрому была применена пересатновка  <tex>\pi</tex>.  | Здесь <tex>\pi_n</tex> это определенная перестановка элементов множества к которому она применена, а <tex>P^{\pi}</tex> это путь <tex>P</tex> к котрому была применена пересатновка  <tex>\pi</tex>.  | ||
| Строка 70: | Строка 70: | ||
</center>  | </center>  | ||
| − | Монотонный код Грея может быть эффективно сгенерирован по этому алгоритму за время <tex>O(n)</tex>. Легче всего написать этот алгоритм используя   | + | Монотонный код Грея может быть эффективно сгенерирован по этому алгоритму за время <tex>O(n)</tex>. Легче всего написать этот алгоритм используя генератор.  | 
=== Псевдокод ===  | === Псевдокод ===  | ||
| + | Перед тем как писать псевдокод необходимо объяснить что такое <code>'''yield'''</code> и что понимать под выражениями типа <code>(0,)</code> или <code>(1,)</code>.  | ||
| + | |||
| + | <code>'''yield'''</code> {{---}} аналог <code>'''return'''</code> только для функций-генераторов. То есть генераторы это тоже итерируемые объекты, но прочитать их можно лишь один раз. Это связано с тем, что они не хранят значения в памяти, а генерируют их на лету.   | ||
| + | |||
| + | С конструкциями типа <code>(0,)</code> или <code>(1,)</code> все проще. Используя ее совместно с <code>'''yield'''</code> мы можем изменять наш генерируемый объект. Например, <code>'''yield''' (0,)</code> допишет к генерируемому объекту (в нашем случае кортежу (англ. ''tuple'')) <tex>0</tex> в начало.   | ||
{| border="0"    | {| border="0"    | ||
|align="left" colspan="4"|  | |align="left" colspan="4"|  | ||
| + | Вспомогательная функция для генерации перестановки, циклически сдвигает битовый вектор направо <tex>n</tex> раз.   | ||
| + | Принимает и возвращает кортеж. Кортеж аналог списка, но в кортеже нельзя менять элементы, можно только добавлять.  | ||
| + | <code>[i:]</code> {{---}} возвращает подсписок, начиная с индекса <tex>i</tex> (аналогично <code>[:i]</code>), а отрицательный знак позволяет индексироваться с конца (полагая, что -1 — последний элемент списка).  | ||
<code>  | <code>  | ||
| − |   rotateRight(x  | + |   '''function''' rotateRight(x: '''int[n]'''): '''int[n]'''  | 
     '''return''' x[-n:] + x[:-n]  |      '''return''' x[-n:] + x[:-n]  | ||
| − | + | </code>  | |
| − |      '''if''' n <= 1  | + | Рекурсивная генерация <tex>n</tex>-ой перестановки.    | 
| + | Возвращает перестановку в виде кортежа.    | ||
| + | Если <tex>n</tex> становится меньше <tex>2</tex> дописывает в начало кортежа <tex>0</tex> и возвращает его.  | ||
| + | <code>  | ||
| + |  '''function''' pi('''int''' n): '''int[n]'''  | ||
| + |      '''if''' n <= 1  | ||
         '''return''' (0,)  |          '''return''' (0,)  | ||
     x = pi(n - 1) + (n - 1,)  |      x = pi(n - 1) + (n - 1,)  | ||
| − |      '''return'''   | + |      '''return''' rotateRight('''tuple'''(x[k] '''for''' k '''in''' x), 1)  | 
| − | + | </code>  | |
| − |      if n == 1 and j == 0  | + | Рекурсивная генерация пути <tex>P_{n, j}</tex>.    | 
| − |          '''if''' '''not''' reverse  | + | Принимает <tex>n, j</tex>, а так же дополнительный параметр определяющий надо-ли переворачивать кортеж.  | 
| + | <code>  | ||
| + |  '''function''' p('''int''' n, '''int''' j, '''bool''' reverse = ''false''): '''list<int[n]>'''  | ||
| + |      '''if''' n == 1 and j == 0  | ||
| + |          '''if''' '''not''' reverse  | ||
             '''yield''' (0,)  |              '''yield''' (0,)  | ||
             '''yield''' (1,)  |              '''yield''' (1,)  | ||
| − |          '''else'''  | + |          '''else'''  | 
             '''yield''' (1,)  |              '''yield''' (1,)  | ||
             '''yield''' (0,)  |              '''yield''' (0,)  | ||
| − |      '''  | + |      '''else if''' j >= 0 '''and''' j < n  | 
         perm = pi(n - 1)  |          perm = pi(n - 1)  | ||
| − |          '''if''' '''not''' reverse  | + |          '''if''' '''not''' reverse  | 
| − |              '''for''' x '''in''' p(n - 1, j - 1)  | + |              '''for''' x '''in''' p(n - 1, j - 1)  | 
                 '''yield''' (1,) + '''tuple'''(x[k] '''for''' k '''in''' perm)  |                  '''yield''' (1,) + '''tuple'''(x[k] '''for''' k '''in''' perm)  | ||
| − |              '''for''' x '''in''' p(n - 1, j)  | + |              '''for''' x '''in''' p(n - 1, j)  | 
                 '''yield''' (0,) + x  |                  '''yield''' (0,) + x  | ||
| − |          '''else'''  | + |          '''else'''  | 
| − |              '''for''' x '''in''' p(n - 1, j, reverse=  | + |              '''for''' x '''in''' p(n - 1, j, reverse=''true'')  | 
                 '''yield''' (0,) + x  |                  '''yield''' (0,) + x  | ||
| − |              '''for''' x '''in''' p(n - 1, j - 1, reverse=  | + |              '''for''' x '''in''' p(n - 1, j - 1, reverse=''true'')  | 
| − |                  '''yield''' (1,) + '''tuple'''(x[k] '''for''' k '''in''' perm)    | + |                  '''yield''' (1,) + '''tuple'''(x[k] '''for''' k '''in''' perm)  | 
| − | + | </code>  | |
| − |      '''for''' i '''in''' range(n)  | + | Генерация монотонного кода Грея при помощи уже написанного генератора <tex>p</tex>.  | 
| − |          '''for''' x '''in''' (p(n, i) '''if''' i % 2 == 0 '''else''' p(n, i, reverse=  | + | <code>   | 
| + |  '''function''' monotonic('''int''' n): '''list<int[n]>'''  | ||
| + |      '''for''' i '''in''' range(n)  | ||
| + |          '''for''' x '''in''' (p(n, i) '''if''' i % 2 == 0 '''else''' p(n, i, reverse=''true''))  | ||
             '''yield''' x  |              '''yield''' x  | ||
</code>  | </code>  | ||
| Строка 141: | Строка 161: | ||
[[Категория: Дискретная математика и алгоритмы]]  | [[Категория: Дискретная математика и алгоритмы]]  | ||
[[Категория: Комбинаторика]]  | [[Категория: Комбинаторика]]  | ||
| + | [[Категория: Комбинаторные объекты ]]  | ||
Текущая версия на 19:23, 4 сентября 2022
| Определение: | 
| Монотонный код Грея (англ. Monotonic Gray Code) — способ построения кода Грея, при котором , что содержит на или больше единиц, чем . | 
Монотонный код Грея преимущественно используется в теории связанных сетей, например для минимизации ожидания линейным массивом процессоров.[1]
Содержание
Алгоритм построения
Для начала определим такое понятие, как вес двоичного кода, им будет являтся количество в данном двоичном коде. Очевидно, что нельзя построить код Грея в котором бы вес всегда возрастал. Неплохим решением этой проблемы будет обход всех кодов со смежными с данным весами.
Мы можем формализовать модель монотонных кодов Грея рассматривая разбиение гиперкуба , вершины в котором являются двоичными кодами, на уровни с одинаковым весом вершин.
для . Для всех уровней выполняется соотношение .
Пусть подграф , который является объединением двух смежных уровней, т. е. , и пусть множество граней . Тогда монотонным кодом Грея будет являтся Гамильтонов путь в , при котором любое множество вершин такие, что , то идет перед .
Ниже на катринке Гамильтонов путь в гиперкубе для , построенный по алгоритму Саважа-Винклера (англ. Savage-Winkler).[2]
Элегантная идея построения -ичного монотонного кода Грея состоит в том, чтобы рекурсивно строить подпути длинны включающих вершины .
Определим и , когда или и . То есть это объединение множеств с приписанной в начале и с приписанным в начале .
Здесь это определенная перестановка элементов множества к которому она применена, а это путь к котрому была применена пересатновка . Существует два варианта построить монотонный код грея по путям .
Назовем их и . Будем строить их таким образом:
Выбор перестановки обусловлен тем, чтобы получившиеся коды соответсвовали требованиям кода Грея и поэтому эта перестановка равна .
Чтобы лучше разобратся в том, как сторится этот код и работает перестановка следует рассмотреть таблицу ниже.
Монотонный код Грея может быть эффективно сгенерирован по этому алгоритму за время . Легче всего написать этот алгоритм используя генератор.
Псевдокод
Перед тем как писать псевдокод необходимо объяснить что такое yield и что понимать под выражениями типа (0,) или (1,).
yield — аналог return только для функций-генераторов. То есть генераторы это тоже итерируемые объекты, но прочитать их можно лишь один раз. Это связано с тем, что они не хранят значения в памяти, а генерируют их на лету. 
С конструкциями типа (0,) или (1,) все проще. Используя ее совместно с yield мы можем изменять наш генерируемый объект. Например, yield (0,) допишет к генерируемому объекту (в нашем случае кортежу (англ. tuple))  в начало. 
| 
 Вспомогательная функция для генерации перестановки, циклически сдвигает битовый вектор направо  раз. 
Принимает и возвращает кортеж. Кортеж аналог списка, но в кортеже нельзя менять элементы, можно только добавлять.
 function rotateRight(x: int[n]): int[n] return x[-n:] + x[:-n] 
Рекурсивная генерация -ой перестановки. 
Возвращает перестановку в виде кортежа. 
Если  становится меньше  дописывает в начало кортежа  и возвращает его.
 function pi(int n): int[n]
   if n <= 1
       return (0,)
   x = pi(n - 1) + (n - 1,)
   return rotateRight(tuple(x[k] for k in x), 1)
Рекурсивная генерация пути . 
Принимает , а так же дополнительный параметр определяющий надо-ли переворачивать кортеж.
 function p(int n, int j, bool reverse = false): list<int[n]>
   if n == 1 and j == 0
       if not reverse
           yield (0,)
           yield (1,)
       else
           yield (1,)
           yield (0,)
   else if j >= 0 and j < n
       perm = pi(n - 1)
       if not reverse
           for x in p(n - 1, j - 1)
               yield (1,) + tuple(x[k] for k in perm)
           for x in p(n - 1, j)
               yield (0,) + x
       else
           for x in p(n - 1, j, reverse=true)
               yield (0,) + x
           for x in p(n - 1, j - 1, reverse=true)
               yield (1,) + tuple(x[k] for k in perm)
Генерация монотонного кода Грея при помощи уже написанного генератора .
 function monotonic(int n): list<int[n]>
   for i in range(n)
       for x in (p(n, i) if i % 2 == 0 else p(n, i, reverse=true))
           yield x
  | 
Визуализация работы алгоритма
Для
Для


