Вы находитесь на странице: 1из 1

Парное укрупнение Alexander

МАИ • May 10, 2019 EDIT


Алгоритм.

Парное укрупнение символов текста производится по следующему алгоритму:

. Находим пару соседних символов, с наибольшим количеством вхождений в


текст.

. Заменяем всюду в тексте эту пару на новый символ. Заменяемую пару, а


также новый символ добавляем в таблицу замен.

. Повторяем шаги 1 и 2 достаточное количество раз.

При неограниченном повторении шагов 1-2 процесс естественным образом


заканчивается, когда частоты всех символьных пар становятся = 1. В процессе
укрупнения новые символы сами вовлекаются в процесс замен и могут даже
вовсе исчезнуть из текста. Укрупненный текст с использованием таблицы замен
всегда можно развернуть в исходный текст.

Примечание: возможны и иные правила для определения пары, которая


должна заменяться на новый символ.

Очевидно, на каждой итерации размер текста в символах уменьшается на


количество замен. На Рис. 1 показан график изменения количества символов в
тексте в процессе укрупнения (голубая часть графика соответствует матричному
методу счета, а красная - подсчету пар на одномерном массиве - подробнее см.
ниже). В скобках показан начальный размер текста - 2 Гб. График начинается
после первой итерации, поэтому верхняя точка немного ниже отметки в 2 Гб.

Рис. 1. Уменьшение количества символов в тексте в процессе укрупнения

Видно, что текст может сократиться в 4 раза и более.

Что же касается количества разных пар, то оно наоборот растет в процессе


укрупнения. В пределе, когда все пары становятся уникальными, количество
пар должно сравняться с размером текста.

На Рис. 2 показан пример изменения количества пар в процессе укрупнения


текста с первоначальной длиной 300 Мб.

Рис. 2. Изменения количества пар в процессе укрупнения

Как следует из графика, после тысячи итераций рост становится практически


линейным.

Плотность.

Локальная плотность - это количество символьных пар в тексте, начинающихся


на заданный символ. Средняя плотность - это отношение количества разных
символьных пар в тексте к количеству разных символов. Если текст
преобразовать в граф (сеть), то локальная плотность будет равна количеству
узлов, в которые можно перейти из заданного узла. Средняя же плотность будет
равна количеству таких переходов, в среднем приходящихся на один узел. Если
проводить аналогию с нейронной сетью, то локальная плотность - это
количество синапсов у данного нейрона, а средняя плотность - это среднее
количество синапсов, приходящихся на один нейрон.

Рис. 3. Начальная средняя плотность в зависимости от размера текста

В русскоязычных текстах средняя плотность до укрупнения составляет


несколько десятков (Рис. 3). Например, на тексте размером 50 Мб средняя
плотность = 35. 

Зависимости плотности.

На Рис. 4 показано изменение средней плотности в процессе укрупнения текста


размером 400 Мб.

Рис. 4. Изменение средней плотности в процессе итераций


на тексте размером 400 Мб

Видно, что плотность быстро нарастает в начале процесса укрупнения,


достигает максимума в 850 единиц на 8000-й итерации и далее медленно
снижается. Голубой и красный цвета графика соответствуют двум методам
подсчета пар - на матрице и на линейном массиве (см. ниже).

С увеличение размера текста средняя плотность сети растет, то есть количество


связей растет быстрее количества узлов. На Рис. 5 показаны графики роста
плотности с увеличением количества итераций на текстах разного размера.

Рис. 5. Изменение средней плотности в процессе итераций на текстах разного размера.

Видно, что с увеличением длины текста растет как максимально достижимая


плотность, так и необходимое для этого количество итераций.

Средняя плотность в пике укрупнения показана на Рис. 6 для различных


размеров текста.

Рис. 6. Максимальная средняя плотность в зависимости от размера текста

Пиковая средняя плотность хорошо аппроксимируется степенной функцией


(показана на рисунке). При размере текста в 12 Гб эта аппроксимация дает
прогноз максимальной средней плотности более 8000 единиц.

Рис. 7 дает представление о количестве итераций, необходимых для достижения


максимума средней плотности.

Рис. 7. Количество итераций, необходимых для достижения максимума плотности

Степенная зависимость от размера текста позволяет оценить количество


требуемых итераций при размере текста 12 Гб - более 40000.

Помимо средней плотности полезно выяснить распределение плотности по


узлам. На Рис. 8 показан ранжир плотности в начале процесса укрупнения и по
достижении максимума при размере текста 50 Мб.

Рис. 8. Упорядоченное распределение плотности в начале и в максимуме процесса


укрупнения.

Точками показаны средние значения плотности; динамика этого среднего


значения и отражена на Рис. 5.

Как видно из Рис. 9, с увеличением размера текста ранжир локальной


плотности, измеренный в момент достижения пика, изменяется подобным
образом.

Рис. 9. Ранжиры локальной плотности в максимуме

Распределения.

Как было сказано, сжатый текст может быть развернут к исходному виду. При
этом укрупненным символам будут соответствовать текстовые фрагменты,
которые мы будем называть словами. Распределение количества разных слов по
их длине для текстов разного размера показано на Рис. 10. Распределения
получены на итерации № 40000.

Рис. 10. Сравнение распределений слов по длине для разных текстов

Примечательно, что несмотря на то что длины текстов различаются в 40 раз,


распределения практически совпадают. Это указывает на то, что уже на 50 Мб
статистические свойства текста достаточно хорошо оформлены.

Количество замен.

По мере укрупнения количество разных символьных пар с частотой > 1, из


которых и выбираются пары для замены, сокращается. На Рис. 11 показан
график изменения количества таких пар для текста с начальным размером 400
Мб.

Рис. 11. Изменение количества неукрупненных пар с частотой > 1

Синяя линия, обозначенная как остаток, это размер пула, из которого


выбираются пары для замен. Как видно, после итерации примерно в 70 тысяч
этот остаток, то есть количество пар, пригодных для замены, начинает
сокращаться в абсолютном выражении. Красная линия отражает долю остатка в
общем количество пар в тексте. Очевидно, что в пределе обе линии стремятся к
нулю.

Параллельно с уменьшением резерва пар, пригодных для замен, уменьшается и


их частота, то есть количество замен в каждой итерации. Этот эффект показан
на Рис. 12 для текста 50 Мб.

Рис. 12. Количество замен в одной итерации

Спад количества замен происходит по степенному закону. В формуле


аппроксимации x соответствует номеру итерации в тысячах. К концу процесса
график приобретает ступенчатый характер; последняя ступенька соответствует
количеству замен = 2. Замечание: график не окончен, последняя ступенька в
действительности простирается за отметку 800 тысяч.

Количество замен, очевидно, растет с увеличением длины текста. На Рис. 13


показаны графики количество замен для разных текстов.

Рис.13. Сравнение количества замен для разных текстов

Обращает на себя внимание хорошее подобие и даже параллельность кривых.


При нормировании количества замен на длину текста кривые полностью
совпадают. На Рис. 14. показан тот же график после нормировки. По вертикали
отложено количество замен, приходящихся на 1 Гб длины текста.

Рис. 14. Количество замен в расчете на 1 Гб исходного текста

В формуле аппроксимации x означает номер итерации, выраженный в тысячах.

Совпадение кривых можно интерпретировать следующим образом: если


разбить текст на части и произвести укрупнение независимо в каждой из них, то
суммарное количество замен будет таким же, как и при укрупнении всего текста
как целого. И это - несмотря на то, что объединенный алфавит получившихся
сжатых частей будет отличаться от алфавита целого текста.

График на Рис 14 дает возможность оценки количества итераций, необходимых


для достижения заданного количества замен:

I = 9520* T / (C^0.8095)

Здесь, I - количество итераций в тысячах, T - длина текста в Гб, C - требуемое


количество замен.

Технология укрупнения.

Одна итерация укрупнения состоит из трех действий:

. Сканируется текст и подсчитывается количество разных пар, другими


словами, составляется частотная таблица пар.

. Полученная таблица просматривается и определяется пара с наибольшим


количеством вхождений в текст.

. Снова сканируется текст, при этом встречающиеся пары, определенные в


п.2, заменяются на один новый символ.

Так как при заменах появляются новые коды, кодировка символов текста
должна быть достаточно емкой. Если выделить на каждый знак два байта, то
ограничение на количество итераций составит 65 тысяч. С учетом сказанного
понятно, что под текст потребуется удвоенный объем памяти по сравнению с
исходным количеством знаков в ASCII формате.

Самым простым способом подсчета пар является счет на матрице, в которой


номера строк и столбцов определяются кодами символов в паре. Но этот способ
приемлем при сравнительно небольшом количестве итераций. Например, если
количество итераций составляет 40 тысяч, то количество кодов будет тоже
порядка 40 тысяч. Это значит, что матрица из int-элементов займет в памяти
40000*40000*4 = 6.4 Гб. Если учесть, что этот объем растет как квадрат
количества итерации, то нетрудно видеть, что уже при количестве итераций в
несколько десятков тысяч метод становится неприемлемым. Кроме того, время
просмотра матрицы с целью определения пары с максимальной частотой также
растет как квадрат числа итераций и может сильно увеличить время цикла. На
Рис. 13 показан пример измерений времени цикла для текста с начальным
размером 50 Мб и подсчетом пар на матрице. После итерации № 5000
отчетливо виден квадратичный рост времени цикла. Пики на графике связаны с
тем, что процессор иногда "отвлекается" на другие задачи.

Рис. 13. Время цикла в процессе укрупнения

Альтернативный способ подсчета пар, не требующий больших объемов памяти


и обеспечивающий стабильно высокую производительность, заключается в
следующем:

• Символьным парам присваиваются коды. Кодом пары может служить,


например, ее порядковый номер в описанной выше матрице счета.

• Текст представляется в виде последовательности кодов пар. Так, вместо


первого символа подставляется код пары (1, 2). Вместо второго символа - код
пары (2, 3) и т.д.

• При сканировании получившейся последовательности, символьные пары


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

• При сканировании с целью замены целевая высокочастотная пара из


последовательности удаляется, а ее соседи в каждой точке вхождения -
модифицируются. При этом генерируются новые пары с присвоением им
новых кодов.

Но у данного метода есть свой недостаток: в исходном тексте каждый знак


представлен двумя байтами, а в случае перехода на "парное" представление на
каждый код формата Int32 придется тратить 4 байта. То есть под текст придется
сразу выделять четырехкратный объем по сравнению с числом знаков.

Оптимальным оказался гибридный вариант: начинаем укрупнение по методу


№ 1, а после достаточного сокращения длины текста переходим на метод № 2.
Анализ показал, что смену метода укрупнения лучше всего производить на
итерации № 6000.

На Рис. 1 в начале статьи показана динамика размера текста (в символах) при


гибридном методе укрупнения. Голубым цветом показан участок укрупнения
методом 1. Красным - методом 2. Стрелка указывает на момент переключения
после итерации № 6000. К моменту переключения размер текста сокращается
почти в 4 раза, поэтому переход на четырехбайтовые коды пар не является
критическим.

Пример, демонстрирующий затраты памяти при гибридном методе укрупнения


при размере текста 200 Мб, представлен на Рис. 14. По вертикали отложена
суммарная память под текст и под массив для подсчета частот. На участке 0 -
6000 показаны требования к памяти для матричного счета. График начинается
с удвоенного размера текста. Пунктиром отмечен квадратичный рост затрат,
если продолжить счет матричным методом после итерации № 6000. Но
фактически на отметке #6000 происходит переключение на второй метод счета,
при котором память выделяется порциями, а ее потребление растет
сравнительно медленно.

Рис. 14. Затраты памяти при гибридном методе укрупнения

Степенная функция, показанная на фоне ступенек, подчеркивает, что рост


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

Рис. 15 показывает, как меняется время одной итерации при укрупнении текста
с начальным размером 1 Гб. Голубым цветом показана стадия укрупнения с
подсчетом пар на матрице. Красным - стадия парного представления текста и
подсчета пар на векторе.

Рис. 15. Время одной итерации при комбинированном укрупнении

По сравнению с Рис. 13 гибридный метод на стадии 2 демонстрирует слабый и


почти линейный, а не квадратичный рост длительности цикла, причем сам
уровень в начале меньше, чем лучшее время метода 1.

Оптимизация.

Для ускорения работы программы были использованы некоторые приемы


оптимизации.

. В процессе укрупнения, то есть замены символьных пар на новый символ,


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

. В таблице частот производился поиск не одной, а двух разных пар с


наибольшей частотой. В процессе замен первой пары составлялась таблица
адресов вхождений второй пары. На следующем проходе вместо сплошного
сканирования осуществлялась точечная замена второй пары по известным
адресам их присутствия. В результате время цикла замен второй пары
уменьшилось почти в два раза.

13.11.2019 г.