Re-Pair (сокращение от Recursive Pairing) - это алгоритм сжатия на основе грамматики, который по входному тексту строит прямолинейную программу, то есть контекстно-свободную грамматику, генерирующую одну строку : вводимый текст. Грамматика строится путем рекурсивной замены пары символов, наиболее часто встречающейся в тексте. Если нет пары символов, встречающейся дважды, полученная строка используется как аксиома грамматики. Следовательно, грамматика вывода такова, что все правила, кроме аксиомы, имеют два символа в правой части.
Re-Pair была впервые представлена NJ. Ларссон и А. Моффат в 1999 г.
В их статье алгоритм представлен вместе с подробным описанием структур данных, необходимых для его реализации с линейной временной и пространственной сложностью. Эксперименты показали, что Re-Pair достигает высоких степеней сжатия и предлагает хорошие характеристики для декомпрессии. Однако основным недостатком алгоритма является потребление памяти, которое примерно в 5 раз превышает размер входных данных. Такое использование памяти требуется для выполнения сжатия за линейное время, но делает алгоритм непрактичным для сжатия больших файлов.
На изображении справа показано, как работает алгоритм сжимает строку .
Во время первой итерации пара , который встречается трижды в , заменяется новым символом . На второй итерации самая частая пара в строке , то есть , заменяется новым символом . Таким образом, в конце второй итерации оставшаяся строка имеет вид . В следующих двух итерациях пары и заменяются символами и соответственно. Наконец, строка не содержит повторяющейся пары и поэтому используется как аксиома выходной грамматики.
Для достижения линейной временной сложности Re-Pair требует следующих структур данных
Поскольку хеш-таблица и приоритетная очередь относятся к одним и тем же элементам (парам), они могут быть реализованы с помощью общей структуры данных, называемой PAIR, с указателями на хэш таблица (h_next) и очередь приоритетов (p_next и p_prev). Кроме того, каждая PAIR указывает на начало первого (f_pos) и последнего (b_pos) вхожденийстроки, представленной PAIR в последовательности. На следующем рисунке показан обзор этой структуры данных.
На следующих двух рисунках показан пример того, как эти структуры данных выглядят после инициализации и после применения одного шага процесса сопряжения (указатели на NULL не отображаются):
Один раз грамматика была построена для данной входной строки, чтобы добиться эффективного сжатия, эта грамматика должна быть эффективно закодирована. Одним из простейших методов кодирования грамматики является неявное кодирование, которое заключается в последовательном вызове функции encodeCFG (X)
, описанной ниже, для всех символов аксиомы. Интуитивно правила кодируются при обращении к ним при обходе грамматики в глубину. При первом посещении правила его правая часть рекурсивно кодируется, и правилу присваивается новый код. С этого момента, когда правило достигается, записывается присвоенное значение.
num_rules_encoded = 256 // По умолчанию расширенная кодировка ASCII является терминалами грамматики. writeSymbol (символ s) {bitslen = log (num_rules_encoded); // Изначально 8, чтобы описать любой расширенный символ ASCII, записываем s в двоичном формате с использованием битовых битов} void encodeCFG_rec (symbol s) {if (s нетерминальный, и это первый раз, когда появляется символ s) {take rule s → X Y; encodeCFG_rec (X); encodeCFG_rec (Y); присвоить символу значение ++ num_rules_encoded; записать бит 1; } else {записываем бит 0; writeSymbol (терминал / присвоенное значение)}} void encodeCFG (symbol s) {encodeCFG_rec (s); записать бит 1; }
Другая возможность - разделить правила грамматики на поколения так, чтобы правило принадлежало поколению , если хотя бы один из или принадлежит к поколению , а другой принадлежит поколению с . Затем эти поколения кодируются последовательно, начиная с поколения . Этот метод был предложен изначально, когда впервые было введено Re-Pair . Однако в большинстве реализаций Re-Pair используется неявный метод кодирования из-за его простоты и хорошей производительности. Кроме того, он позволяет производить декомпрессию на лету.
Существует ряд различных реализаций Re-Pair . Каждая из этих версий направлена на улучшение одного конкретного аспекта алгоритма, такого как сокращение времени выполнения, уменьшение занимаемого места или увеличение степени сжатия.
Улучшение | Год | Реализация | Описание |
---|---|---|---|
Просмотр фраз | 2003 | [1] | Вместо того, чтобы манипулировать строка ввода как последовательность символов, этот инструмент сначала группирует символы в фразы (например, слова). Алгоритм сжатия работает как Re-Pair, но рассматривает идентифицированные фразы как терминалы грамматики. Инструмент принимает разные варианты, чтобы решить, какие фразы следует учитывать, и кодирует полученную грамматику в отдельные файлы: один содержит аксиому, а другой - остальные правила. |
Оригинал | 2011 | [2] | Это одна из самых популярных реализаций Re-Pair. Он использует описанные здесь структуры данных (те, что были предложены при первоначальной публикации) и кодирует полученную грамматику с использованием метода неявного кодирования. Большинство более поздних версий Re-Pair реализованы, начиная с этой. |
Encoding | 2013 | [3] | Вместо метода неявного кодирования в этой реализации используется метод переменной длины в метод фиксированной длины, в котором каждое правило (представлено со строкой переменной длины) кодируется с использованием кода фиксированной длины. |
Использование памяти | 2017 | [4] | Алгоритм выполняется в два этапа. На первом этапе он рассматривает высокочастотные пары, то есть те, которые встречаются более раз, а во втором - пары низких частот. Основное различие между двумя фазами - это реализация соответствующих очередей приоритетов. |
Сжатие | 2017 | [5] | Эта версия изменяет способ выбора следующей пары для замены. Вместо того, чтобы просто рассматривать наиболее часто встречающуюся пару, он использует эвристику, которая штрафует пары, которые не соответствуют факторизации Лемпеля-Зива входной строки. |
Compression | 2018 | [6] | Этот алгоритм уменьшает размер грамматики, сгенерированной Re-Pair, сначала заменяя максимальное количество повторов. Когда пара определяется как наиболее часто встречающаяся пара, то есть та, которая должна быть заменена на текущем шаге алгоритма, MR-repair расширяет пару, чтобы найти самую длинную строку, которая встречается такое же количество раз, как и пара, которую нужно заменить. Предоставленная реализация кодирует грамматику, просто перечисляя правила в тексте, поэтому этот инструмент предназначен исключительно для исследовательских целей и не может использоваться для сжатия как таковой. |