Монотонный код Грея — различия между версиями
Gpevnev (обсуждение | вклад) |
м (rollbackEdits.php mass rollback) |
||
(не показано 14 промежуточных версий 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> | ||
Строка 13: | Строка 13: | ||
<tex> | <tex> | ||
− | V_n(i) = \{ v \mid | + | V_n(i) = \{ v \mid v \text{ has weight } i \} |
</tex> | </tex> | ||
для <tex>0 \leqslant i \leqslant n</tex>. Для всех уровней выполняется соотношение <tex>|V_n(i)| = C_n^i</tex>. | для <tex>0 \leqslant i \leqslant n</tex>. Для всех уровней выполняется соотношение <tex>|V_n(i)| = C_n^i</tex>. | ||
− | Пусть <tex>Q_n(i)</tex> подграф <tex>Q_n</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> | ||
− | [[Файл:Monotonic_Gray_Code_Graph.png|center|4-ичный | + | [[Файл:Monotonic_Gray_Code_Graph.png|center|4-ичный монотонный код Грея]] |
− | Элегантная идея построения <tex>n</tex>-ичного монотонного кода Грея состоит в том, чтобы рекурсивно строить подпути <tex>P_{n,j}</tex> длинны <tex> | + | Элегантная идея построения <tex>n</tex>-ичного монотонного кода Грея состоит в том, чтобы рекурсивно строить подпути <tex>P_{n,j}</tex> длинны <tex>2C_n^j</tex> включающих вершины <tex>E_n(j)</tex>. |
− | Определим <tex>P_{1,0} = (0, 1)</tex> и <tex>P_{n,j} = \emptyset</tex>, когда <tex>j < 0</tex> или <tex>j \ | + | Определим <tex>P_{1,0} = (0, 1)</tex> и <tex>P_{n,j} = \emptyset</tex>, когда <tex>j < 0</tex> или <tex>j \geqslant n</tex> и |
<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>. | + | </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>. | ||
− | Существует два варианта построить | + | Существует два варианта построить монотонный код грея по путям <tex>P_{n, j}</tex>. |
Назовем их <tex>G_n^{(1)}</tex> и <tex>G_n^{(2)}</tex>. Будем строить их таким образом: | Назовем их <tex>G_n^{(1)}</tex> и <tex>G_n^{(2)}</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]
Содержание
Алгоритм построения
Для начала определим такое понятие, как вес двоичного кода, им будет являтся количество код Грея в котором бы вес всегда возрастал. Неплохим решением этой проблемы будет обход всех кодов со смежными с данным весами.
в данном двоичном коде. Очевидно, что нельзя построитьМы можем формализовать модель монотонных кодов Грея рассматривая разбиение гиперкуба
, вершины в котором являются двоичными кодами, на уровни с одинаковым весом вершин.
для
. Для всех уровней выполняется соотношение .Пусть Гамильтонов путь в , при котором любое множество вершин такие, что , то идет перед .
подграф , который является объединением двух смежных уровней, т. е. , и пусть множество граней . Тогда монотонным кодом Грея будет являтсяНиже на катринке Гамильтонов путь в гиперкубе [2]
для , построенный по алгоритму Саважа-Винклера (англ. Savage-Winkler).Элегантная идея построения
-ичного монотонного кода Грея состоит в том, чтобы рекурсивно строить подпути длинны включающих вершины .Определим
и , когда или и . То есть это объединение множеств с приписанной в начале и с приписанным в начале .Здесь
это определенная перестановка элементов множества к которому она применена, а это путь к котрому была применена пересатновка . Существует два варианта построить монотонный код грея по путям .Назовем их
и . Будем строить их таким образом:Выбор перестановки
обусловлен тем, чтобы получившиеся коды соответсвовали требованиям кода Грея и поэтому эта перестановка равна .Чтобы лучше разобратся в том, как сторится этот код и работает перестановка
следует рассмотреть таблицу ниже.Монотонный код Грея может быть эффективно сгенерирован по этому алгоритму за время
. Легче всего написать этот алгоритм используя генератор.Псевдокод
Перед тем как писать псевдокод необходимо объяснить что такое 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
|
Визуализация работы алгоритма
Для
Для