Вычислительные технологии
Том 20, № 3, 2015
Алгоритмы сжатия без потерь разностных целочисленных последовательностей при помощи оптимизации их разбиения на интервалы с постоянной
f* U f* u u
битовой глубиной значений
А. Е. Хмельнов
Институт динамики систем и теории управления СО РАН, Иркутск, Россия Контактный e-mail: [email protected]
Рассмотрен алгоритм сжатия без потери информации целочисленных данных, значения которых распределены преимущественно вблизи нуля. Такие данные получаются, например, при разностном кодировании целочисленных последовательностей, представляющих постепенно изменяющиеся величины (величины, принимающие близкие значения в соседних точках). По степени сжатия для этого вида данных алгоритм сравним с ZLib или превосходит его в режиме Z_BEST_COMP-RESSION. Он требует значительно меньше времени как при сжатии, так и при распаковке, поскольку характеризуется линейной вычислительной сложностью.
Предложенный алгоритм является разновидностью алгоритма VSEncoding, расширяющей его возможности: рассмотрено кодирование знаковых чисел и применение алгоритма для произвольных разностных последовательностей, учтён более общий способ кодирования заголовков интервалов. Предложен критерий остановки поиска, позволяющий находить точный минимум длины кодовой последовательности, а также способ достижения точного минимума при работе с буфером ограниченного размера, в который не помещается вся кодируемая последовательность. Проведено сравнение работы рассматриваемых алгоритмов при сжатии растров большого объёма.
Ключевые слова: сжатие без потери информации, специализированный алгоритм сжатия, динамическое программирование.
Введение
Несмотря на постоянный рост аппаратных возможностей вычислительной техники, потребность в компактном хранении информации сохраняется и продолжает увеличиваться, поскольку параллельно растут объёмы собираемых и обрабатываемых цифровых данных. Область сжатия данных очень хорошо исследована, и даже при принятии решения об использовании некоторого готового алгоритма сжатия разработчики сталкиваются с достаточно непростым выбором. Если учесть особенности конкретных данных, то можно предложить специализированные алгоритмы их сжатия, которые будут превосходить готовые универсальные алгоритмы по различным характеристикам, существенным для разрабатываемого приложения.
© ИВТ СО РАН, 2015
В работе рассмотрен принцип построения алгоритмов быстрого сжатия без потери информации целочисленных данных, значения которых распределены преимущественно вблизи нуля. Такие данные получаются, например, при разностном кодировании целочисленных последовательностей, представляющих постепенно изменяющиеся величины (принимающие близкие значения в соседних точках). Для этого вида данных алгоритм, построенный по рассматриваемому принципу, по степени сжатия сравним с ZLib [1] или превосходит его в режиме Z_BEST_COMPRESSION, но он требует значительно меньше времени как при сжатии, так и при распаковке, поскольку характеризуется линейной вычислительной сложностью. Начальная стадия работы рассматриваемых алгоритмов сжатия состоит в разделении мантиссы и порядка целочисленных значений и аналогична работе алгоритма UNIC (Universal Coding of Integers) вида SEM (Separate Exponents and Mantissas) [2], однако, в отличие от UNIC, для представления порядка используется разбиение последовательности на интервалы постоянной битовой глубины. Для оптимизации разбиения последовательности на интервалы с целью минимизации объёма памяти, используемой для её представления, применяется метод динамического программирования.
Первоначально в работе использовалась оригинальная схема применения метода динамического программирования и соответствующий алгоритм назывался BCRL (Bit Count Run-Length encoding). Этот алгоритм был упомянут в работах, посвящённых форматам данных, использующим сжатие разностных последовательностей [3]. Последующее знакомство с алгоритмом VSEncoding [4], его реализация и практическое тестирование показали, что предложенная в нем схема более проста, но достаточно эффективна для задачи сжатия разностных целочисленных последовательностей. Кроме того, сделанные доработки алгоритма позволили находить точный минимум объёма сжатых данных. В результате в качестве основного алгоритма, применяемого для сжатия разностных последовательностей, был использован доработанный алгоритм VSEncoding — алгоритм VSEopt.
Таким образом, основными результатами данной работы являются: адаптация алгоритма VSEncoding к задаче сжатия разностных целочисленных последовательностей; вывод критерия прекращения поиска, позволяющего находить точный минимум объёма сжатых данных; способ поиска начального фрагмента данных, которые можно записать в поток без ущерба для нахождения оптимального разбиения последовательности на интервалы при использовании для сжатия данных буфера ограниченного размера, а также результаты тестирования рассматриваемых алгоритмов на конкретных примерах данных.
1. Разностные последовательности
Любую конечную целочисленную последовательность можно охарактеризовать
диапазоном значений, принимаемых её элементами [^m, ¿"max]:
5min = mm(Sj) < Si < Smax = шах(^-).
3 3
Такой диапазон не всегда полностью использует все возможные значения п-байтных знаковых [— 28"-1 , 28"-1 — 1] или беззнаковых ([0 , 28га — 1]) целых чисел. Ещё в большей степени неполным использованием диапазона значений n-байтных целых чисел,
служащих для представления элементов последовательности, могут характеризоваться отдельные её подпоследовательности.
Часто целочисленные последовательности являются результатом измерения и дискретизации некоторой постепенно изменяющейся величины. Примеры таких величин: яркость пикселя на растровом изображении; высота рельефа, представленного на регулярной сетке; серия измерений, поступающих с внешнего аналогово-цифрового датчика; и т. д. Несмотря на то что элементы такой последовательности могут быть распределены на достаточно широком интервале, модуль разности соседних элементов, как правило, оказывается значительно меньше их абсолютных величин. Поэтому, если рассмотреть разностную последовательность {Di = S+i — ¿¿}, то, хотя потенциально диапазон значений её элементов может даже увеличиться: S^m — Smax < Dmin, Dmax < Smax — S^m , появляется большое количество подпоследовательностей, для которых диапазон значений существенно сокращается. Кроме наиболее простых (разностных) последовательностей, подобными характеристиками обладают последовательности, получающиеся, например, после применения целочисленных вейвлет-преобразований (лифтинг [5]). Далее для простоты будем называть все подобные последовательности разностными.
2. Применимость алгоритмов сжатия к разностным последовательностям
В литературе, посвящённой алгоритмам сжатия данных [2, 6, 7], большое внимание уделяется статистическим и словарным методам. Статистические методы позволяют более компактно кодировать часто встречающиеся значения, стремясь добиться степени сжатия, определяемой энтропией сигнала. При этом, если метод Хаффмана даёт возможность достичь этого результата только для вероятностей символов, являющихся степенями 1/2, то арифметическое и интервальное кодирование позволяет практически достичь задаваемого энтропией порога. При применении более сложных вероятностных методов, например PPM, используемых в архиваторе RAR, сжимаемые данные рассматриваются как результат работы марковского случайного процесса. При этом вероятность появления символа оценивается с учётом его предшественников. Словарные методы позволяют кодировать повторяющиеся подпоследовательности с использованием ссылок на уже обработанные данные. Также описываются блочные методы, при использовании которых последовательность разбивается на блоки некоторого заранее заданного и не зависящего от данных размера, после чего к ним применяется преобразование, облегчающее дальнейшее кодирование, например дискретное косинусное преобразование, или преобразование Барроуза —Уилера (BWT).
Рассмотрим применимость упомянутых методов для сжатия разностных последовательностей. Поскольку такие последовательности оказываются практически случайными, вероятность встретить в них повторяющиеся подпоследовательности достаточно низка. Это существенно снижает эффективность словарных методов, поэтому, например, в литературе по сжатию целочисленных последовательностей [4, 8] возможность использования таких методов не рассматривается. Слабая корреляция между соседними элементами не позволяет рассчитывать на эффективность при применении марковских моделей. Блочные методы могут быть применимы, однако часть из них, как, например, дискретное косинусное преобразование, преобразуют целые числа в действительные и поэтому ориентированы на сжатие с потерями. Преобразование BWT по су-
ти является конкурентом словарных методов и также не сможет дать более простую последовательность при отсутствии явных повторений. Таким образом, в нашем распоряжении остаются вероятностные методы, работа которых может быть улучшена путем учёта близости распределения сигнала к нормальному.
3. Методы сжатия целочисленных последовательностей
В литературе по общим методам сжатия данных задача кодирования последовательностей целых чисел не рассматривается, описываются только способы кодирования отдельных целочисленных значений (см., например, [2, 7]). При этом алгоритмы сжатия последовательностей натуральных чисел активно используются в поисковых системах для хранения, например, списков индексов использованных в документе слов [4, 8]. Поскольку такие списки по сути представляют множества, в них отсутствуют повторения и их элементы можно упорядочить для ускорения поиска и облегчения сжатия. Таким образом, при этом рассматривается задача компактного представления возрастающей последовательности целых чисел. Для сокращения диапазона значений элементов такой последовательности вместо исходной кодируется последовательность разностей значений соседних элементов. В силу отсутствия повторений и возрастания исходной последовательности последовательность разностей индексов содержит положительные целые числа. Другая задача, которая требует сжатия подобных последовательностей, — это компактное хранение индексов значений в гиперкубе в ОЬАР-системе [9]. Здесь также кодируются разности между упорядоченными целыми числами, представляющими кортежи — координаты точек в гиперкубе.
Использование специализированных алгоритмов, предназначенных для кодирования последовательностей целых чисел, позволяет получить более высокое сжатие, чем это могут сделать универсальные алгоритмы. Интересно, что, согласно приведённым в работе [4] результатам тестирования алгоритма УБЕпсо^^, рассматриваемые алгоритмы могут "победить энтропию", т. е. сжать последовательность сильнее, чем теоретический предел для методов, выполняющих независимое кодирование значений, ^ ^• log2битов на значение, где р^ — вероятность значения % для источника инг
формации, генерирующего последовательность независимых случайных величин. Это происходит потому, что теоретический предел получен для кодирования значений по отдельности, а алгоритмы сжатия последовательностей могут обнаруживать и использовать для лучшего сжатия общие свойства соседних значений.
Необходимо отметить, что в работах по сжатию индексов для поисковых систем рассматривается сценарий использования алгоритмов декомпрессии, который существенно отличается от применяемого в данной работе: предполагается, что индексы документов уже находятся в оперативной памяти, но в сжатом виде, при этом требуется максимально быстро их распаковывать для использования. Такая постановка задачи существенно смещает оценку качества алгоритмов в сторону быстродействия, например, иногда выполняется выравнивание сохраняемых данных в памяти (что требует записи нескольких лишних неиспользуемых битов) ради ускорения их чтения.
Основным сценарием использования алгоритмов декомпрессии в данной работе является распаковка считанных с диска данных сразу после чтения. В этом случае сокращение объёма передаваемых из медленной памяти (читаемых с диска) данных может оправдать работу более совершенного алгоритма сжатия иногда и по времени, посколь-
ку за то время, которое не было потрачено на чтение лишних данных с диска, может быть выполнен более медленный, но использующий более хорошее сжатие алгоритм. Таким образом, основным критерием качества алгоритма далее будем считать достигаемую степень сжатия.
4. Минимальная длина представления целого числа (битовая глубина)
В и-битном беззнаковом целом числе могут быть представлены значения в диапазоне [0, 2П — 1], а в знаковом (в дополнительном коде) — [— 2П-1, 2"-1 — 1]. Отсюда, рассуждая в обратном направлении, получим, что для представления беззнакового числа и минимально необходимое количество битов равно
п = |_1о§2)] + 1 при и > 0, |0 при и = 0,
т. е. для значения 0 будем считать, что оно помещается в 0 битов. Действительно, при кодировании последовательности, про которую известно, что она состоит только из нулевых значений, достаточно указать её длину — сами значения сохранять не требуется.
В литературе обычно употребляется другая форма записи Ьи (эквивалентная рассмотренной), позволяющая обойтись без вариантов:
Ьи(и )
Ш1П п
и<2"
Ьи(и )
Ш1П п
и+1<2"
Ш1П П = Г1°ё2(^ + 1)1:
+1)<га
но для рассмотрения всех случаев кодирования знаковых чисел удобнее будет воспользоваться первым способом.
Аналогично для представления знакового числа I минимально необходимое количество битов
)
Ш1П п,
-2П-1<1<2П-1
)
Ш1П/<2эт 0
-1 п = Ьи (I) + 1
при I > 0, при I = 0,
ш1п-/-1<2«-1 п = Ьи(—1 — 1) + 1 при I < 0,
и после подстановки выражения для Ьи получаем
)] +2 при 1> 0,
ад)
0 при I = 0,
1 при I = — 1, Ц^2(-1 — 1)] +2 при 1< —1.
Для значения 0, как и для беззнаковых чисел, считаем, что оно помещается в 0 битов. Представление значения 0 в 0 битах позволяет очень компактно кодировать однородные подпоследовательности, разностный образ которых состоит из одних нулей. Для представления значения — 1 требуется 1 бит, поэтому, если некоторый интервал состоит только из разностей 0 и —1, то его можно закодировать, расходуя 1 бит на значение. Для знакового представления положительных чисел требуется не менее чем 2 бита. Будем называть количество битов, используемых для записи целого числа, битовой глубиной представления целого числа.
5. Сокращение длины кодовой последовательности за счет сокращения битовой глубины значений
Элементы разностных последовательностей необходимо рассматривать как знаковые целые числа, поэтому для вычисления минимального количества битов, требующихся для представления их значений, следует использовать функцию Ь3. При работе с разностной последовательностью можно было бы существенно сэкономить используемую для её представления память, если бы удалось закодировать каждое значение минимально необходимым для его представления количеством битов, поскольку большинство этих значений находится вблизи нуля и для их представления требуется не слишком много битов. Величина
позволяет оценить снизу возможный объём упакованных данных, связанный с таким способом сжатия. Однако в общем случае невозможно достичь эту нижнюю границу, поскольку ещё необходимо потратить память на запоминание информации о битовой глубине, используемой для представления значения каждого из элементов последовательности.
В работе [10] с учётом особенности нормального распределения гауссова белого шума предложен алгоритм сжатия rdc (Random Data Encoder), основанный на оптимальном (для кодируемой последовательности) выборе порога, разделяющего короткие и длинные значения, после чего вся последовательность разбивается на блоки, состоящие из ряда коротких и, может быть, одного длинного значения. Каждый блок начинается с заголовка, в котором задается количество коротких элементов, а также содержится признак наличия длинного элемента. Для выбора порога битовой глубины достаточно проанализировать гистограмму битовых глубин значений элементов последовательности. Несмотря на использование столь простой схемы сжатия, при её применении к данным, полученным в результате декорреляции исходной последовательности посредством применения вейвлет-преобразования, степень сжатия оказывается лучше, чем у gzip-9 (то же, что и ZLib в режиме Z_BEST_COMPRESSION).
6. Представление информации о битовой глубине посредством разбиения на интервалы
Основной принцип работы рассматриваемых в данной работе алгоритмов состоит в том, что для хранения информации об используемых для представления значений количествах битов последовательность можно разбить на интервалы постоянной глубины. Для каждого интервала запоминается заголовок с информацией о его битовой глубине D и количестве значений L, после чего следуют сами значения, занимающие D ■ L битов. При этом каждое значение Si не обязательно должно быть представлено с глубиной Ls(Si), главное, чтобы выполнялось условие D > Ls(Si) для того интервала, которому принадлежит значение. На увеличение битовой глубины, используемой для представления некоторых значений, стоит пойти для того, чтобы сократить общее количество интервалов, на которые разбивается последовательность, и тем самым суммарные накладные расходы, связанные с запоминанием заголовков интервалов.
Для рассматриваемого представления упакованных данных алгоритм распаковки выглядит чрезвычайно просто.
1: Прочитано_значений ^ 0
2: while Прочитано_значений < Упаковано_значений do
3: (Глубина, Количество) ^ ПрочитатьЗаголовокИнтервала()
4: for i ^ 1, Количество do
5: ДобавитьЗначение(ПрочитатьЦелое(Глубина))
6: end for
7: Прочитано_значений ^ Прочитано_значений + Количество
8: end while
Таким образом, декодирование значения алгоритмом распаковки выражается в простом считывании из битового потока знакового целого числа некоторой глубины. Декодирование отдельного значения выполняется за постоянное время, а общее время распаковки линейно по объёму данных.
7. Поиск оптимального разбиения при сжатии
Информацию о глубине значений также можно рассматривать как последовательность. Идея рассматриваемого алгоритма основана на том, что последовательность значений и последовательность глубин не независимы и в некоторых случаях можно увеличить глубину значения сверх необходимой ради того, чтобы последовательность глубин стала проще (рис. 1). Алгоритмы сжатия целочисленных последовательностей находят близкое к оптимальному разбиение последовательности на интервалы, минимизирующее общий объём упакованных данных: накладные расходы (объём заголовков интервалов) плюс объём данных, используемых для представления в интервалах самих значений элементов последовательности.
Для поиска оптимального разбиения алгоритм сжатия использует метод динамического программирования. Для построения схемы применения динамического программирования необходимо выделить такую информацию, при наличии которой для предыдущего элемента последовательности аналогичную информацию можно найти и для следующего элемента, а по информации для последнего элемента — и само оптимальное разбиение.
Обозначим:
• Р($) — разбиение последовательности Б на интервалы;
• Ь(Р($)) — стоимость разбиения Р($) (объём упакованных данных при разбиении
Р (5));
• в<г — начальная подпоследовательность в, заканчивающаяся элементом
Рис. 1. Выигрыш от увеличения глубины интервала для объединения с соседними
Алгоритмы сжатия, которые строятся по рассматриваемому в данной работе принципу, могут различаться способом кодирования заголовка интервала. Пусть h(d, I) означает стоимость записи заголовка интервала с глубиной d и количеством элементов I при выбранном способе кодирования заголовка (т. е. количество битов, необходимое для его представления).
При реализации алгоритма сжатия более эффективно запоминать информацию не об отдельных значениях, а об интервалах значений с постоянной минимальной глубиной (Lg(Si) = const). Для хранения промежуточной информации о таких интервалах (длина, минимальная глубина, стоимость наилучшего разбиения, начало последнего интервала при наилучшем разбиении) используется вспомогательный буфер интервалов.
При выделении памяти сразу под весь буфер интервалов, достаточный для хранения информации обо всей последовательности, его объём может в несколько раз превысить объём сжимаемых данных. Если такие требования по памяти неприемлемы, то в случае переполнения буфера может выполняться сброс буфера: принудительное разбиение последовательности по границе последнего обработанного интервала, запись уже обработанной части согласно оптимальному к этому моменту разбиению, очистка буфера интервалов и обработка оставшейся части последовательности. Сброс буфера интервалов означает нарушение условия полной оптимальности найденного разбиения (если только не принять дополнительных мер для поиска безопасного места деления буфера при сбросе — см. далее).
8. Алгоритм У8Епсо^^
Рассмотрим алгоритм УБЕпсо^^, предложенный в работе [4]. Поскольку для дальнейшего изложения необходимо знакомство читателя с этим алгоритмом, приведём его псевдокод с использованием применяемых в данной работе обозначений.
1 2
3
4
5
6
7
8 9
10 11 12
13
14
15
16
17
18
С [0] ^ 0 for i ^ 1,п do
len ^ 1 > Длина интервала
D ^ L(S[г]) > Глубина интервала
С* ^ С [г — 1] + h(D, 1) + D > Минимальная найденная стоимость
Р* ^ г — 1 > Соответствующее разбиение начальной части
for j ^ г — 1,тах(0,г — тахК) step —1 do L ^ L + 1
D ^ max(D, L(S[j])) > Пересчёт глубины интервала
С cur ^ С [j — 1] + h(D, len) + D * len > Стоимость проверяемого разбиения if Ccur < С* then > Найден более хороший вариант
С * ^ Ссиг > Запомним его стоимость
Р* ^ j > и место начала последнего интервала
end if end for
С [г] ^ С * > Запомним в буфер стоимость наилучшего разбиения
р[г] ^ Р* > и место начала его последнего интервала
end for
Алгоритм УВЕпсо^^ выполняет поиск близкого к оптимальному разбиения Р(Б) исходной последовательности целых чисел в методом динамического программирования. Помимо в параметрами алгоритма являются способ кодирования заголовков интервалов и целое число тахК. Способ кодирования заголовков характеризуется функцией Н(й, I) стоимости записи заголовка интервала с глубиной й и количеством элементов I (т.е. его размером в битах). Число тахК ограничивает глубину поиска. Пусть п — длина последовательности Б. При работе алгоритма будем использовать два массива длины п +1: С[0..п] — стоимостей оптимальных разбиений и р[0..п] — номеров предыдущих элементов разбиения. При этом С [г] содержит стоимость наилучшего разбиения в<г, а р[г] — номер элемента, после которого начинается последний интервал этого наилучшего разбиения, дающего стоимость С [г].
Таким образом, чтобы найти лучшее разбиение последовательности на интервалы, на каждом шаге метода динамического программирования выполняется сравнение стоимостей разбиений с разными длинами последнего интервала и наилучшим разбиением оставшейся начальной части последовательности (которое уже к этому моменту известно). При поиске длина последнего интервала ограничена значением параметра тахК.
В оригинальном алгоритме VSEncoding рассматривалась функция Н(й, I) вида Н(й,1) = М1(Ь) + М2(1), т.е. с независимым кодированием глубины и длины интервала. В данной работе мы избавимся от таких ограничений, что позволяет, например, выбирать разные кодировки длины для интервалов разной глубины, чтобы учесть то, что большие по модулю значения встречаются в разностных последовательностях реже и образуют более короткие интервалы.
9. Поиск оптимального разбиения последовательности
Использование параметра тахК в алгоритме VSEncoding позволяет так ограничить поиск, чтобы он мог быть выполнен за разумное время. При длине последовательности п >> тахК вычислительная сложность такого алгоритма составит 0(п • тахК). Если же взять тахК > п, то получим сложность 0(п2), что вряд ли будет приемлемо при больших п. Сами авторы алгоритма VSEncoding используют тахК, не превосходящий 64, а также кодировку длины интервала М2, позволяющую представить интервалы с длиной не более 64. Однако в разностных последовательностях могут появляться интервалы, например из нулевых значений, гораздо большей длины, поэтому искусственное ограничение длины интервала может ухудшить сжатие.
С другой стороны, попытка рассмотреть интервал слишком большой длины в качестве окончания оптимального разбиения в подавляющем большинстве случаев обречена на неудачу, поскольку высока вероятность того, что на таком интервале встретится достаточно большое значение, появление которого существенно повысит стоимость кодирования всех значений длинного интервала.
Для того чтобы найти истинно (а не приближённо) оптимальное разбиение последовательности, необходимо предложить критерий остановки поиска, который должен позволить определить, что дальнейшая проверка интервалов большей длины уже не имеет смысла, поскольку она может дать только худшие результаты. Так, если количество битов в кодировке значений последнего интервала МахИ • I превзойдет стоимость наилучшего найденного варианта разбиения С', то можно прекращать поиск, поскольку любое дальнейшее увеличение длины интервала увеличит стоимость его кодирования не менее чем на МахИ битов. Конечно, приведённый пример критерия остановки по-
иска слишком грубый, но он показывает, что такие критерии в принципе существуют, поэтому попытаемся найти более точную оценку. Обозначим
Lmax(j,i) = max L(S(к)).
j<k<i
Заметим, что для j < к < j
Lmax(j,i) = max L(S(/)) = max(max L(S(I)), max L(S(/))) = j<l<i j<l<k k<l<i
= max(Lmax(j, k),Lmax(k, i)), (1)
также отсюда следует, что для j < к < j ¿max(j, i) > L
max (j, к) и L
max (j,i) > Lmax(k,i). (2)
Стоимость оптимального разбиения S< можно выразить следующим образом:
Ci = min Cj + h(Lmax(j, г), г — j) + (г - j) ■ Lmax(j, г). 0<j<i
Пусть в процессе поиска Ci найдено приближение С'. При этом уже пройдена точка разбиения к, поэтому С' < Ск + h(Lmax(k, i),i — к) + (г — к) ■ Lmax(k, г).
Рассмотрим некоторую следующую за к (в порядке уменьшения индекса) точку разбиения j, т. е. 0 < j < к. Поскольку Ck соответствует оптимальному разбиению S<k, при его поиске был рассмотрен вариант с прохождением разбиения через j, поэтому
Ск < Cj + h(Lmax(j, к), к — j) + (к — j) ■ Lmax(j, к).
Отсюда можно получить оценку варианта разбиения с интервалом от j до г
Ск + (i — к) ■ Lmax(k,i) <
< Cj + h(Lmax(j, к), к — j) + (к — j) ■ Lmax(j, к) + (l — к) ■ Lmax(k, l).
С учётом неравенств (2) для Lmax получаем
Ск + (i — к) ■ Lmax(k, i) < Cj + h(Lmax(i, к),к — j) + (г — j) ■ Lmax (j, i). (3)
Сначала для упрощения изложения сделаем достаточно обоснованное предположение, что функция h(d, l) является неубывающей по обоим аргументам, т. е. размер заголовка не может уменьшаться с ростом как длины /, так и глубины d (далее будет рассмотрен случай произвольной функции h). При монотонности h(d, I) можно заменить в правой части (3) с сохранением неравенства h(Lmax(j, к), к — j) на h(Lmax(j, i),i — j):
Cj + h(Lmax(j, к), к — j) + (г — j) ■ Lmax(j, l) <
< Cj + h(Lmax(i, i),i — j) + (i — j) ■ Lmax(i, i).
Сравнивая полученное неравенство с (3), находим оценку снизу для стоимостей всех разбиений, заканчивающихся интервалом j + 1..i при 0 < j < к:
ск + (г — к) ■ Lmax(k, i) < Cj + h(Lmax(i, i),i — j) + (« — j) ■ Lmax(j, i).
Таким образом, если эта величина окажется больше С', то поиск можно заканчивать. Искомый критерий бессмысленности продолжения дальнейшего поиска после проверки варианта к имеет вид
(4)
Заметим, что проверяемое выражение отличается от выражения для стоимости варианта к
Ск + Ь(Ьтах(к, ъ),ъ — к) + (г — к) • 1тах(к, г)
одним слагаемым — стоимостью заголовка, поэтому, чтобы искать оптимальное разбиение, требуется сделать минимальные изменения в коде алгоритма.
Вернемся к рассмотрению произвольной функции к(й,1), которая может оказаться немонотонной. В этом случае по к найдем вспомогательную величину
¿Н = тах к(в,,1) — к(в,1,11). (5)
ё,, I, 11 >1, ё,1>(1
Для неубывающей к выполняется ¿Н = 0, поскольку все разности неположительные (0 достигается при й = и I = /1). В общем случае для используемого в правой части (3) подвыражения получим
к(Ьт&х(з, к), к — 3) < к(Ьт&х(з, г), г — 3) + <Ш.
Отсюда для самой правой части (3)
Су + к(1тах(3, к), к — з) + (г — ]) • Ьтах(з, г) <
С' < Ск + ^ — к) • Ьтах(к, г)
< Су + к(Ьтах(з, г), г — 3) + dH + (г — 3) • Ьтах(], г).
В результате находим оценку снизу для стоимостей всех разбиений, заканчивающихся интервалом 3 + 1..г при 0 < 3 < к,
Су + к(Ьтах(з, г), г — 3) + (« — 3) • Ртах(з, г) > Ск + (г — к) • Ьтах(к, г) — dH и критерий остановки поиска после проверки варианта к
(6)
Таким образом, при немонотонной к приходится компенсировать эту немонотонность в оценке, прибавляя к порогу стоимости некоторую зависящую от к неотрицательную величину ¿Н. При этом в ходе поиска придется зайти немного дальше, чтобы убедиться в бесперспективности его продолжения, поскольку появляется шанс, что с увеличением длины или глубины интервала размер его заголовка уменьшится. Однако размер, занимаемый значениями интервала, всё равно увеличится, поэтому поиск не продлится слишком долго.
С' + ¿Н < Ск + (г — к) • Ьтах(к, г)
Приведём результирующий алгоритм поиска оптимального разбиения (далее будем его называть УБЕор^.
1: С [0] 4 0
2: for г 4 1,п do
3: len 4 1 > Длина интервала
4: D 4 L(S[г]) > Глубина интервала
5: С * 4 С [г — -1] + h(D, 1) + D > Минимальная найденная стоимость
6: р * 4 i — 1 > Соответствующее разбиение начальной части
7: for j 4 i — 1, 0 step —1 do
8: len 4 len + 1
9: D 4 max(D, L(S[j])) > Пересчёт глубины интервала
10: С cur 4 с [J - - 1] + D * len > Значение для критерия остановки
11 if с 11 Kycur > С * + dH then
12 break > Выход по критерию остановки поиска
13 end if
14: С cur 4 С сиг +h(D,len) > Стоимость проверяемого разбиения
15: if Ccur < С * then > Найден более хороший вариант
16: С * 4 С сиг > Запомним его стоимость
17: P * 4 J > и место начала последнего интервала
18: end ¡Г
19: end for
20: С [г] 4 С * > Запомним в буфер стоимость наилучшего разбиения
21: p[i] 4 Р* > и место начала его последнего интервала
22: end for
Измененные по сравнению с алгоритмом поиска при ограничении тахК фрагменты показаны на сером фоне.
10. Поиск оптимального разбиения при ограничении на размер буфера
При сжатии разностных последовательностей используется буфер, в котором для каждого значения запоминается информация о необходимом для его представления количестве битов [г]), стоимости найденного оптимального разбиения С [г] и точке начала последнего интервала р[г]. При выделении памяти сразу под весь буфер интервалов, достаточный для хранения информации обо всей последовательности, его объём может в несколько раз превысить объём сжимаемых данных. Если такие требования по памяти неприемлемы, то в случае переполнения буфера может выполняться его сброс. Понятно, что сброс буфера интервалов может означать нарушение полной оптимальности найденного разбиения.
Для сохранения оптимальности получаемого разбиения при ограниченном буфере можно попытаться найти обязательный префикс всех оптимальных разбиений — точку согласования разбиений, т. е. максимальный из таких индексов элементов последовательности, что все разбиения, которые могут быть выбраны в качестве оптимальных для любых возможных продолжений последовательности, будут содержать деление на
интервалы в этом месте. В качестве такой точки согласования может, например, выступать "выброс" — значение, кодируемое существенно большим числом битов, чем его соседи: любое оптимальное разбиение должно учитывать такой выброс, выделив его в отдельный интервал.
Для поиска точки согласования ксоп требуется сначала найти минимальную точку остановки перебора к* — такой индекс, за который критерий остановки поиска (6) не должен пропустить цикл поиска оптимального разбиения для любого продолжения последовательности. Будем использовать следующие индексы: г — номер элемента последовательности, на котором был достигнут конец буфера; I > г — номер произвольного следующего элемента последовательности.
Поиск оптимального разбиения для большинства I > г (достаточно далеких от г) может закончиться ещё до г, но для не слишком больших I будет сделана попытка использовать разбиение с последним интервалом, начинающимся перед г. В первом случае (для больших /) префиксом оптимального разбиения будет одно из разбиений, полученных для меньших /, поэтому достаточно рассмотреть второй случай, для которого согласно найденному в предыдущей главе критерию остановки (6) при достижении к* должно выполняться условие
С{ + dH < Ск* + {1 - к*) • Lmax{k*,l) VI > г. (7)
Здесь С[ — стоимость наилучшего известного к рассматриваемому моменту разбиения
P<L
При поиске оптимального разбиения для I должно быть рассмотрено и разбиение, проходящее через г, поэтому
С[ < Сг + h(Lmax(t, l),l - i) + (l - г) • Lmax(t, I). (8)
Для выполнения (7) достаточно, чтобы выполнялось условие
сг + h(Lm*x(i,l),l - i) + {l - г) • Lmax(i,l) + dH < Ск* + {l - к*) • Lmax(k*,l) VI >i. (9)
С учётом неравенств (2) для Lmax можно оценить снизу правую часть (9), разбив последний интервал к*..I на две части в точке г:
Ск* + {1 - к*) • Lmax(k*,l) > Ск* + (г - к*) • Lmax{k*, l) + {I - i) • Lmax(l,i).
Поэтому неравенство (9) будет выполнено при
Сг + h(Lmax(t, I), I - l) + dH < Ск* + {г - к*) • Lmax{k*,t) VI > г (10)
(подчеркнутые фрагменты сокращаются).
Обозначим через Hmax максимальный размер заголовка интервала. Эту вспомогательную величину так же, как и dH, можно найти по функции h:
Hmax = max h{d,l). (11)
d,l
Заменяя в (10) h{Lmax{i,l),1 - г) на Hmax, слегка усиливаем неравенство, избавляемся от зависимости условия от I и получаем окончательное условие на к*:
(12)
Сг + Hmax + dH < Ск* + {г - к*) • Lmax{k*,l)
Полученное условие отличается от критерия остановки поиска (6) для г слагаемым Нтах в левой части, поэтому поиск к* может зайти несколько дальше, чем поиск оптимального разбиения для .
Приведём алгоритм поиска минимальной точки остановки перебора к*.
1 к* ^ 0 > Искомая точка остановки перебора (пока не найдена)
2 len ^ 1 > Длина интервала
3 D ^ 0 > Глубина интервала
4 Lim ^ Ci + Hmax + dH > Предел — стоимость, которую надо превзойти
5 for j ^ i, i/2 step —1 do > Ограничиваем поиск последней половиной буфера
6 len ^ 1 en + 1
7 D ^ max(D,L(S[?])) > Пересчёт глубины интервала
8 if C[j — 1] + D * 1 en > Lim then > Предельная стоимость достигнута
9 к* > Точка остановки перебора найдена
10 break
11 end if
12 end for
В данном алгоритме используется эвристика для определения возможного предела поиска точки остановки перебора: здесь поиск ограничивается последней половиной буфера. В случае неудачи поиска к* придётся отказаться от мысли о нахождении истинно оптимального разбиения, сбросить весь буфер и ограничиться нахождением лишь близкого к оптимальному результата. Уменьшение предельного индекса точки остановки перебора может повысить шансы её нахождения. Однако в случае, если такая точка будет найдена где-то в начале буфера, придётся сбросить лишь малую его часть, а частое повторение такой ситуации может привести к существенному замедлению работы алгоритма. Впрочем, вычислительный эксперимент на реальных данных большого объёма показывает, что к* обычно находится совсем не далеко от конца буфера.
Если минимальную точку остановки перебора к* > 0 удаётся найти, то поиск оптимального разбиения VI > г закончится до к*. Поэтому оптимальное разбиение VI > г пройдёт через одну из точек к* + 1 .. г. Отсюда следует, что точка ксоп согласования всех оптимальных разбиений VI > г на самом деле является точкой согласования конечного числа оптимальных разбиений, соответствующих С[]} и р[]] V] : к* < ] < г. Для поиска точки согласования добавим вспомогательный флаг ивей^] в элементы буфера. Если флаг установлен, это означает, что по границе ] проходит одно из потенциально используемых разбиений. Если же флаг ивеЗ^)] не будет установлен к моменту рассмотрения позиции ], то на данную границу не вышло ни одно из ранее рассмотренных используемых разбиений, поэтому точку ] можно пропустить. Перед началом поиска задаем нижнюю границу к* и устанавливаем флаг ивей^] у всех элементов буфера в интервале к* + 1..г — все они могут быть использованы при построении оптимальных разбиений VI > %. Далее при обнаружении р[]] < к* уменьшаем границу поиска, устанавливая флаг изеЗ[р[]]] и сбрасывая его для остальных элементов в диапазоне р[]] + 1..к*.
Из приведённого ниже алгоритма поиска точки согласования ксоп видно, что работа алгоритма заканчивается в случае достижения циклом поиска точки согласования ксоп, поскольку это означает, что ни одна из рассмотренных последовательностей интервалов не "перепрыгнула" через неё.
1 2
3
4
5
6 7:
8:
9 10 11
12:
13
14
15
16
17
18
k ■(— k*
for j ^ k* + 1,i do Used[j] ^ true end for
for j ^ i, l step — l do if Used[j] then if j = kcm then
break
end if
if p[j] < kcm then for k ^ p[j] + l, kca,
Used[k] ^ false
end for
kcon ^ p[j]
end if
Used[p[j]] ^ true end if end for
> Устанавливаем начальное значение точки согласования > Устанавливаем флаги использования для разбиений до к*
> Поиск точки согласования
Найдена точка согласования, через которую прошли все разбиения
> Используется разбиение за пределами зоны поиска do > Флаги для этой части не были заданы
Пометим как пока не используемые все добавляемые в рассмотрение точки
> Расширим зону поиска
При обнаружении точки согласования выполняется сохранение начального фрагмента буфера до этой точки включительно со сдвигом в начало оставшейся части буфера. Экспериментальная проверка предложенного алгоритма на реальных данных показала, что он действительно позволяет найти оптимальное разбиение при использовании ограниченного буфера (выполнялось сравнение с оптимальными результатами, полученными без ограничения объёма). При этом размеры перемещаемых в начало буфера фрагментов оказываются небольшими (в среднем менее 100 элементов).
11. Конкретизация способа кодирования заголовков интервалов
Рассмотренный в данной работе метод сжатия определяет схему построения алгоритмов. Конкретный алгоритм будет получен при задании определённого способа кодирования заголовков интервалов. При выборе способа кодирования заголовков интервалов должны учитываться битовая глубина сжимаемой последовательности и распределение длин интервалов постоянной глубины. Так, в большинстве выполненных вычислительных экспериментах было использовано кодирование длины интервала блоками по к = 3 битов с дополнительным 1 битом — признаком продолжения, при котором
V* {(1,1) = 4 +{к + 1) ■
где первые 4 бита расходуются на глубину интервала, а далее на каждые 3 бита в представлении длины интервала тратится ещё по 4 бита (далее будем называть такое кодирование ярШ-п). Выбор разбиения на группы по 3 бита основан на результатах вычислительного эксперимента с конкретными данными, в котором для такого размера групп битов длины получен лучший результат.
Однако впоследствии был принят во внимание тот факт, что при этом допускается избыточность вариантов кодирования одного и того же значения длины. Поскольку
для кодирования длины потребовалось несколько интервалов, это значение не может быть представлено меньшим количеством интервалов. В результате для кодирования длины интервалов были использованы старт-шаг-стоп-коды [2] (с совпадением длин начальной и последующих групп битов — далее будем называть такое кодирование Б1ер-п). При использовании з1ер-п значения, кодируемые п интервалами, начинаются сразу после всех значений, представимых меньшим числом интервалов. В этом случае при использовании групп по к битов получаем немного меньший размер заголовка:
Нвк(¿, I) = 4 + (к + 1) ■ * (1 - 1/2к) + 1)/к].
Несмотря на незначительное сокращение длины интервала при использовании старт-шаг-стоп-кодов, вычислительный эксперимент показал, что для них лучшее сжатие получается при к = 2. Именно этот вариант кодирования заголовков будет далее использоваться в большинстве вычислительных экспериментов.
Другой проверенный экспериментально способ кодирования заголовков интервалов основан на использовании статических кодов Хаффмана для кодирования длины и/или глубины интервала. При этом дерево Хаффмана строится на основе статистики разбиения на интервалы, полученной при предварительно выполненном сжатии данных с помощью другого способа кодирования заголовков, не требующего знания статистики. Здесь возникает циклическая зависимость: статистика частоты использования интервалов с различными значениями длины и глубины определяет способ кодирования заголовков интервалов, а способ кодирования заголовков — статистику использования интервалов. Выполнение нескольких итераций сжатия для уточнения статистики позволяет ещё сократить размер файла.
Исследованы три варианта кодирования заголовков с использованием кодов Хафф-мана:
• Ь — общая кодировка длин интервалов независимо от глубины, глубина кодируется фиксированным числом битов;
• Ь^ — отдельная кодировка длин интервалов для каждого значения глубины, глубина кодируется фиксированным числом битов;
• Ь^О — отдельная кодировка длин интервалов для каждого значения глубины, глубина также кодируется по Хаффману.
Во всех вариантах коды Хаффмана использовались для кодирования количества битов длины, т. е. величины п = Ьи(Ь — 1) (кодируем Ь — 1, поскольку интервалов длины 0 не бывает), за этим кодом при Ь > 2 необходимо ещё записать п — 1 младший бит в двоичном представлении самого числа Ь — 1; старший бит всегда является единицей для ненулевых значений, поэтому его не храним. В варианте Ь^И коды Хаффмана используются непосредственно для представления глубины интервала. Во всех случаях деревья кодов Хаффмана строились для всего файла и записывались в его заголовок.
Все многообразие возможных способов кодирования заголовков интервалов не исчерпывается выполненными экспериментами и нуждается в дальнейших исследованиях.
12. Тестирование алгоритмов сжатия разностных последовательностей
Алгоритм БСКЬ разработан при реализации иерархического растрового формата МИС, позволяющего эффективно работать с растрами большого объёма (впоследствии в этом
качестве применялись алгоритмы семейства VSEopt). Первоначальной целью создания формата MRG было получение слитного иерархического растра высот земной поверхности по данным SRTM (Shuttle Radar Topography Mission [11]), которые распространяются блоками 1° по широте х1° по долготе с шагом 3''. При представлении пирамиды разрешений в формате MRG для более детальных блоков сохраняются разности между реальными значениями и результатами интерполяции этих значений по данным менее детальных блоков, кроме того, могут использоваться алгоритмы декорреляции значений. Таким образом, сохраняемые в формате MRG данные представляют собой разностные последовательности в том смысле, в каком они рассматриваются в этой статье. Впоследствии формат MRG был доработан для хранения произвольных растров высот, а также многоканальных растровых изображений большого объёма.
Первоначально разностные данные сжимались при помощи ZLib, но в дальнейшем возникла идея использовать алгоритм, способный получить более высокую степень сжатия путем учёта природы разностных данных, а также ускорить чтение блоков за счёт использования простого формата хранения упакованных значений.
Для оценки производительности алгоритмов сжатия разностных последовательностей при кодировании разностных растров выполнено их тестирование на 110 блоках SRTM, описывающих территорию вокруг Байкала. Для сравнения была использована упаковка тех же разностных последовательностей средствами библиотеки ZLib с различными значениями уровня сжатия.
Используемый фрагмент данных, с одной стороны, не слишком велик по сравнению со всем массивом данных SRTM, что позволяет выполнить над ним достаточно большое число вычислительных экспериментов. С другой стороны, объём обрабатываемых при этом данных достаточно велик (300 МБ в неупакованном виде, более 150 миллионов значений), поэтому получаемые для него результаты являются представительными и применимыми к другим данным.
В табл. 1 содержатся основные результаты проведённого тестирования алгоритмов. В первых двух строках приведена информация об исходных данных, остальные строки относятся к файлам MRG, полученным из этих данных с использованием различных алгоритмов сжатия (ZLib и VSEopt c различными вариантами кодирования заголовков интервалов). Отметим, что файлы SRTM распространяются в архивах ZIP, которые созданы со степенью сжатия, превышающей максимальную для имеющейся у автора
Таблица 1. Результаты тестирования алгоритмов сжатия на 110 блоках SRTM(50-60° с.ш.) х (100-109° в.д.)
Способ сжатия Размер, Коэф. % от Время, с Время,
байт сжатия, % ZLib max мин
Исходные данные без сжатия 317328 220 100.00 — — —
Исходные данные в Zip 113427015 35.74 — — —
MRG с ZLib fastest 88 752112 27.97 — 13.29 0:00:13
MRG с ZLib default 78 999 264 24.90 — 50.065 0:00:50
MRG с ZLib max 76 738 672 24.18 100 541.79 0:09:01
MRG с VSEopt, split-3 66 662 320 21.01 86.87 22.97 0:00:22
MRG с VSEopt, step-2 66 409 088 20.93 86.54 22.509 0:00:22
MRG с VSEopt, HT LdD 64 207328 20.23 83.67 36.676 0:00:36
MRG с VSEopt, HT LdD I5 63 905 280 20.14 83.28 40.081 0:00:40
версии архиватора PKZIP. Например, архив N50E100.hgt.zip имеет размер 1 376 212 Б, а после упаковки его содержимого при помощи архиватора PKZIPC получаем 1 418 255 Б. Этот же файл после максимального сжатия средствами библиотеки ZLib, используемой для сравнения, занимает 1430 423 Б. Таким образом, исходные данные были сжаты очень хорошей версией архиватора ZIP.
Тем не менее при помощи разностного кодирования блоков эти результаты превосходит даже ZLib с минимальным для библиотеки уровнем сжатия Fastest. Также видно, что алгоритм сжатия разностных последовательностей смог улучшить результаты ZLib с максимальным уровнем сжатия ещё на 13-16% от объёма после сжатия при помощи ZLib. Конкретные цифры определяются способом кодирования заголовков интервалов — далее будут более подробно рассмотрены результаты сравнения различных представлений заголовков.
По времени работы алгоритм VSEopt уступает только результатам ZLib с уровнем сжатия fastest, однако по степени сжатия BCRL существенно превосходит ZLib в этом режиме (на 25-28% от объёма упакованных ZLib данных).
Теперь выполним сравнение различных способов кодирования заголовка. В табл. 2 приведены результаты тестирования на тех же данных SRTM представлений заголовков split-n и step-n при различных значениях п, которые обосновывают выбор split-3 и step-2 для проведения тестов. Во всех тестах использовался алгоритм сжатия VSEopt. Видно, что метод step-2 дает наилучшее сжатие среди рассмотренных, не зависящих от конкретных данных методов, поэтому он использован для проведения большинства тестов.
Рассмотрим, какое преимущество может быть получено за счёт использования VSEopt по сравнению с VSEncoding при различных значениях параметра тахК, ограничивающего глубину перебора. В табл. 3 приведены результаты тестирования на тех же данных SRTM при кодировке заголовков step-2. Из таблицы видно, что при тахК = 64, действительно, достигается неплохое сжатие. С другой стороны, даже при тахК = 1024 оптимальное разбиение не находится. При этом по времени работы на рассматриваемых данных с кодировкой заголовка step-2 алгоритм VSEopt сравним с VSEncoding при тахК =16. Таким образом, использование критерия остановки поиска оказывается очень выгодным: оно позволяет не только найти оптимальное разбиение, но и сократить время работы даже по сравнению с достаточно небольшими значениями тахК.
Сжатие может быть улучшено за счёт применения методов кодирования заголовков интервалов, учитывающих особенности конкретных данных. Для этих целей реализованы три варианта представления заголовков с использованием кодов Хаффмана: L, Lp,
Таблица 2. Сравнение методов кодирования заголовков split-n и step-n по результатам работы на 110 блоках SRTM
п split-n step-n
Размер, байт Коэф. сжатия, % Размер, байт Коэф. сжатия, %
1 66 557008 20.97 67 744 096 21.35
2 66 409104 20.93 66 690 512 21.02
3 66 630 368 21.00 66 662 336 21.01
4 66 780 672 21.04 66 781 264 21.04
5 66 832 272 21.06 66 832 304 21.06
Таблица 3. Сравнение методов сжатия VSEopt и УВЕпеоё^ по результатам работы на 110 блоках SRTM
тахК Размер, байт Коэф. сжатия, % Время, с Время, мин
8 70 798 896 22.31 17.598 0:00:17
16 67913120 21.40 22.290 0:00:22
24 67273 056 21.20 26.540 0:00:26
32 66 890 384 21.08 31.010 0:00:31
40 66 683 360 21.01 35.354 0:00:35
48 66 567 520 20.98 40.128 0:00:40
56 66 505184 20.96 44.056 0:00:44
64 66 476 416 20.95 48.640 0:00:48
72 66 462 960 20,94 53.074 0:00:53
80 66 451952 20.94 57.659 0:00:57
88 66 443 296 20.94 62.667 0:01:02
96 66 436 432 20.94 66.024 0:01:06
128 66 420 320 20.93 84.077 0:01:24
256 66 410 096 20.93 154.367 0:02:34
512 66 409 744 20.93 292.853 0:04:52
1024 66 409 696 20.93 561.020 0:09:21
opt 66 409 088 20.93 22.509 0:00:22
Таблица 4. Сравнение методов кодирования заголовков с использованием кодов Хаффмана по результатам работы на 110 блоках SRTM
Кодировка Размер, байт Коэф. сжатия, % Время, с Время, мин
step-2 66 409 088 20.93 22.509 0:00:22
Ь 65910416 20.77 28.909 0:00:28
Ьо 65 779152 20.73 35.241 0:00:35
Ьв И 64 207328 20.23 36.676 0:00:36
Ь^О. Результаты применения этих методов приведены в табл. 4. Сжатие выполнялось с помощью алгоритма УБЕор! и статистики, полученной при использовании алгоритма УБЕор! и кодировки заголовка я1ер-2. По результатам тестирования видно, что наибольший выигрыш (0.7% от объёма исходных данных по сравнению с кодировкой я1ер-2) достигается при использовании кодировки Ь^О.
Для наиболее эффективного варианта кодирования заголовков Ь^И исследуем возможность улучшения сжатия за счёт поиска кодов Хаффмана, соответствующих статистике получаемого при их использовании распределения интервалов. Для этого выполним несколько итераций, начиная со статистики для я1ер-2 и продолжая использованием статистики для разбиений, полученных на предыдущей итерации, для выбора кодов, используемых на следующей. В табл. 5 показана динамика изменения размера файла по итерациям. Видно, что в ходе поиска размер файла монотонно уменьшается. Судя по совпадению размеров, можно предположить, что на 5-й итерации процесс сошелся. Это предположение подтверждается тем, что файлы статистики, полученные на 4-й и 5-й итерациях, совпадают.
Таблица 5. Динамика изменения размера файла в ходе улучшения статистики распределения интервалов методом итераций при сжатии 110 блоков БИТЫ
№ итера- Размер, Коэф. сжа- Время, с Время, мин
ции байт тия, %
0 (по step-2) 64 207328 20.23 36.676 0:00:36
1 63 968 688 20.16 39.605 0:00:39
2 63 928 768 20.15 39.963 0:00:39
3 63 910 992 20.14 40.228 0:00:40
4 63 905 280 20.14 40.097 0:00:40
5 63 905 280 20.14 40.081 0:00:40
Не ясно, насколько типичен этот случай, т. е. насколько часто процесс поиска согласованного со статистикой представления заголовков методом итераций будет сходиться, — этот вопрос требует дальнейшего исследования. Сам метод поиска наилучших параметров сжатия посредством генерации нескольких вспомогательных вариантов файла также выглядит не бесспорно — необходимо еще предложить сценарий его применения, обосновывающий целесообразность таких трудозатрат (например, оптимальную для фрагмента данных статистику можно использовать при сжатии всех данных). Тем не менее именно этот метод позволил найти наиболее компактное представление рассматриваемых в работе данных, которое приводится в последней строке табл. 1.
Рассмотренные ранее представления заголовков эрШ-п и я1ер-п являются монотонными, чего нельзя сказать о представлениях с помощью кодов Хаффмана: здесь реже встречающимся меньшим значениям могут быть присвоены более длинные коды. Поэтому на примере представлений заголовков с использованием кодов Хаффмана можно проверить необходимость введения поправки ¿Н в критерии остановки поиска (6). В табл. 6 приведены результаты такого тестирования. При этом вместо значения ¿Н, вычисленного по формуле (5) (здесь будем обозначать его ¿Н*), в условии остановки поиска (6) использованы альтернативные значения. Во всех тестах применялась статистика для кодировки заголовков э1ер-2, при этом получены ненулевые значения поправок для всех рассматриваемых вариантов кодирования заголовка, приведённые в столбце ¿Н*.
Тестирование показало, что поправка ¿Н действительно необходима в (6) для достижения оптимального результата, поскольку при ¿Н = 0 для всех вариантов получается результат хуже оптимального. Однако найденная по формуле (5) поправка либо оказывается слишком грубой, либо учитывает маловероятное сочетание интервалов, которое не реализуется на используемых для тестирования данных, поэтому уже при ¿Н = 1 для кодировок Ь и Ь^ и при ¿Н = 2 для кодировки Ь^ О находится оптимальное разбиение. Дополнительно проведено тестирование с ¿Н = ¿Н* + 1, которое показало, что
Таблица 6. Результаты тестирования алгоритма VSEopt с заменой вычисленного значения
* на альтернативные при сжатии 110 блоков БИТЫ с использованием статистики для step-2
Кодировка (Ш * Размер, байт
(1Н = 0 (Ш = 1 (Ш = 2.ЛН * + 1
Ь 2 65 912 560 65 910 416
8 65 781184 65 779152
Ьв И 10 64 212 688 64 207344 64 207 328
Таблица 7. Результаты тестирования работы алгоритма VSEopt с ограничениями на размер буфера при сжатии 110 блоков SRTM с кодировкой заголовков step-2
Размер Число Число г — к* г ксоп Увеличение г, с
буфера делений ошибок средн. а тах средн. а тах размера буфера
256 513639 18407 49.09566 29.56092 192 66.39054 36.06395 255 17872 22.409
512 223039 1745 54.09093 44.03588 384 71.23359 49.63309 511 1680 22.345
768 141332 295 55.45633 51.03141 576 72.7885 56.38411 762 272 22.422
1024 103181 50 55.99229 54.35135 768 73.48568 59.57874 1002 32 22.328
1536 66823 2 55.9353 55.42749 1017 73.24717 60.78797 1041 16 22.507
2048 49343 — 55.7629 55.519 1523 73.35563 60.85825 1553 0 22.329
4096 23890 — 55.37472 53.15844 907 72.56769 58.95732 1181 0 22.307
16384 5359 — 54.3357 51.40663 763 72.57772 56.65134 772 0 22.327
65536 1137 — 77.14776 82.33685 758 96.97186 85.8242 758 0 22.209
262144 — — — — — — — — 0 22.328
при этом не происходит дальнейшего улучшения, поскольку поправки ¿Н* достаточно для нахождения минимума.
Проверим работу алгоритма УБЕор! при ограничении размера буфера с использованием алгоритма поиска точки согласования разбиений. Во всех ранее приводившихся тестах использован буфер достаточного для представления всех кодируемых данных размера (поскольку в файлах МИД изображение разбивается на блоки 400 х 400, требуется, чтобы размер буфера был не меньше 160 000 элементов).
В табл. 7 приведён размер буфера, который был использован при сжатии, число выполненных делений буфера (в связи с его переполнением), число ошибок — для какого числа из этих делений не удалось найти точку согласования разбиений ксоп (в результате был сброшен весь буфер и получено неоптимальное разбиение). Приводятся статистические характеристики двух величин: г — к* (расстояние от конца буфера до точки разбиения) и г — ксоп (расстояние от конца буфера до точки согласования). Для каждой из величин показаны ее среднее значение, стандартное отклонение а и максимальное значение (столбец "тах"). Отображено увеличение размера буфера (в байтах), вызванное ошибками поиска точки согласования, относительно оптимального размера (66 409 088 байтов для используемой кодировки заголовка) и приводится время работы алгоритма сжатия.
По результатам выполненного тестирования видно, что использование буфера ограниченного размера не вызывает статистически значимого замедления работы алгоритма (время работы при разных размерах буфера колеблется в диапазоне погрешности измерений) и позволяет получить оптимальное разбиение в том случае, когда размер буфера превышает шах(г — ксап). Для рассматриваемого примера достаточный для нахождения оптимального разбиения размер буфера составил 2048 элементов.
Заключение
Рассмотренный принцип построения алгоритмов сжатия данных без потери информации ориентирован на работу с последовательностями целочисленных значений, распределённых преимущественно вблизи нуля. Для получения конкретного алгоритма сжа-
тия необходимо задать способ кодирования заголовков интервалов. Работа алгоритма направлена на снижение избыточности количества битов, используемых для представления целочисленных значений.
Особенностью алгоритмов сжатия разностных последовательностей является асимметрия по времени работы между этапами кодирования и декодирования: при всех вариантах алгоритма декодирование выполняется значительно быстрее и не вызывает существенного расхода памяти. Таким образом, потратив некоторое время на сжатие данных, мы получаем выигрыш по времени при каждом их чтении.
Основными результатами работы являются: алгоритм VSEopt (разработанный на основе алгоритма VSEncoding), позволяющий находить оптимальное сжатие разностных последовательностей; алгоритм поиска точки согласования разбиений, позволяющий находить оптимальное разбиение при использовании для хранения вспомогательной информации буфера ограниченного размера; тестирование конкретных алгоритмов сжатия, получаемых при выборе способа кодирования заголовков интервалов и, в частности, алгоритмов с использованием кодов Хаффмана, учитывающих статистические особенности обрабатываемых данных.
Имеется опыт использования рассматриваемых алгоритмов для сжатия без потерь растровых изображений и звуковых файлов, который показывает, что в сочетании с подходящим методом вычисления разностных значений алгоритм позволяет повысить степень сжатия по сравнению с популярными универсальными архиваторами.
Список литературы / References
[1] Gailly, J.-L., Adler, M. ZLib home site. Available at: http://www.zlib.net (accessed: 13.05.2015).
[2] Методы сжатия данных. Устройство архиваторов, сжатие изображений и видео / Д. Ва-толин, А. Ратушняк, М. Смирнов, В. Юкин. М.: ДИАЛОГ-МИФИ, 2003. 384 с.
Data compression methods. Construction of archivers, image and video compression / D. Vatolin, A. Ratushnyak, M. Smirnov, V. Yukin. Moscow: DIALOG-MIFI, 2003. 384 p. (in Russ.)
[3] Хмельнов А.Е. Формат файлов MRG для компактного представления и высокоскоростной декомпрессии матриц высот большого объёма // Вычисл. технологии. 2015. Т. 20, № 1. С. 63-74.
Hmelnov, A.E. The MRG file format for compact representation and fast decompression of large digital elevation models // Computational Technologies. 2015. Vol. 20, No. 1. P. 63-74. (in Russ.)
[4] Silvestri, F., Venturini, R. VSEncoding: efficient coding and fast decoding of integer lists via dynamic programming // Proceeding CIKM '10 Proceedings of the 19th ACM International Conference on Information and Knowledge Management. USA, New York, 2010. P. 1219-1228.
[5] Calderbank, A.R., Daubechies, I., Sweldens, W., Yeo, B.-L. Wavelet transforms that map integers to integers. Technical report, Department of Mathematics. USA: Princeton University, 1996. Available at:
ftp://ftp.ldv.ei.tum.de/pub/lossless/wavelet_transf_integers.pdf
[6] Ватолин Д. Все о сжатии данных, изображений и видео. Адрес доступа: http://www.compression.ru (дата обращения: 13.05.2015).
Vatolin, D. All about data, image and video compression. Available at: http://www.compression.ru (accessed: 13.05.2015). (in Russ.)
[7] Сэломон Д. Сжатие данных, изображений и звука. М.: Техносфера, 2004. Salomon, D. A Guide to data compression methods. New York: Springer-Verlag, 2002.
[8] Lemire, D., Boytsov, L. Decoding billions of integers per second through vectorization // Software: Practice and Experience. 2015. Vol. 45, iss. 1. P. 1-29.
[9] Deveaux, J.-P., Rau-Chaplin, A., Zeh, N. Adaptive tuple differential coding // Database and Expert Systems Applications. Lecture Notes in Computer Science. 2007. Vol. 4653. P. 109-119.
[10] Klimenko, S., Mitselmakher, G., Sazonov, A. Losless compression of LIGO data. Technical Note LIG0-T000076- 00- D, MIT 07.08.2000. Available at: http://www.phys.ufl.edu/~klimenko/wavelets/lossless.pdf
[11] Дубинин М. Описание и получение данных SRTM. Адрес доступа: http://gis-lab.info/qa/srtm.html (дата обращения 13.05.2015). Dubinin, M. The SRTM data description and sources. Available at: http://gis-lab.info/qa/srtm.html (accessed 13.05.2015). (in Russ.)
Поступила в 'редакцию 29 сентября 2014 г., с доработки — 25 мая 2015 г.
A lossless compression algorithm for integer difference sequences by optimization of their division into intervals of constant bit depth values
hmelnov, alexei e.
Institute for System Dynamics and Control Theory SB RAS, Irkutsk, 664033, Russia Corresponding author: Hmelnov, Alexei E., e-mail: [email protected]
Purpose. A principle for construction of algorithms for fast lossless compression of integer data values, which are distributed mainly near zero, is considered. Such data come from, e.g., differential encoding of integer sequences, which represent gradually varying quantities (the quantities, which take similar values in neighboring points). According to the degree of compression for the given kind of data, the algorithms considered are of superior performance compared to ZLib [1] in its strongest compression mode Z_BEST_COMPRESSION, but they take considerably less time for both compression and unpacking, since the proposed compression algorithm is characterized by a linear computational complexity in terms of the processed data size.
Design/methodology/approach. To find the best (most compact) representation of an integer sequence by series of intervals for values of constant bit depth we use the dynamic programming approach. The dynamic programming scheme used is of the VSEncoding algorithm [4] type. A concrete compression algorithm is defined by specifying a particular method for the interval header representation.
Findings. The VSEopt algorithm — an optimized version of VSEncoding algorithm is proposed, which allows to find the true minimum of compressed size without limiting the depth of the interval length search by the maxK parameter. A theoretical justification of the VSEopt algorithm is presented. The performed tests have demonstrated that VSEopt works as fast as VSEncoding with impractically small maxK = 16, but even with maxK = 1024 (and a lot of time spent) the VSEncoding algorithm can't achieve the optimal compression found by VSEopt.
© ICT SB RAS, 2015
98
A. Е. XMenbHOB
Another theoretical inference allows to use for the VSEopt compression the buffer of limited size without losing the capability of finding the true optimal solution. The performed tests show that the algorithm still be capable to find the best solution even when the buffer may be as small as 2000 items (when compressing much larger blocks of 160 000 values). Some particular methods of interval header encoding were considered and tested. The best results were obtained for encodings, which use the static Huffman codes obtained with the help of statistics for interval depths and lengths distribution. For the test performed, the process of finding the header encoding which matches the statistics resulting from its usage have converged to the smallest of all the tests executed compressed data size.
Originality/value. The VSEncoding algorithm is the well known tool for compression of document indexes. The optimized version of the algorithm — VSEopt is a new result. Our formulation and solution addresses the problem how to use a buffer of limited capacity but still find the best compression. The methods used for the algorithms of compression of differential integer sequences are also new and extend the field of the algorithm usage.
Keywords: lossless compression, specialized data compression algorithm, dynamic programming.
Received 29 September 2014 Received in revised form 25 May 2015