Существуют ли алгоритмы сжатия случайных данных с конечным алфавитом?

Итак, есть случайная строка заданной длины и с заданным алфавитом. Длину и алфавит исходной строки можно задавать как угодно. Нужно сократить количество символов не изменяя алфавит. Т.е. если на входе была строка из 256 цифр от 0 до 9, то и на выходе должна получиться строка состоящая только из цифр, но короче.

Я пробовал применять классику, вроде RLE, LZ и Хаффмана. Пробовал реализовывать сам, пробовал брать готовое, пробовал менять параметры строки, но в лучшем случае получал ту же длину, обычно размер только увеличивался. Либо я чего-то не понимаю, либо у входных данных слишком высокая энтропия.

1) Такие алгоритмы вообще существуют?
2) Если да, то хотелось бы пример реализации, на любом языке.
3) И пару книжек по теме для совсем тупеньких :)
  • Вопрос задан
  • 771 просмотр
Решения вопроса 2
Rsa97
@Rsa97
Для правильного вопроса надо знать половину ответа
Случайные данные - это наихудший вариант для сжатия. Практически все алгоритмы сжатия данных без потерь основаны на поиске закономерностей и повторяющихся последовательностей. В случайной последовательности нет ни того, ни другого.
Ответ написан
Adamos
@Adamos
Сжатие - это замена части информации логикой, позволяющей восстановить эту часть.
В случайных данных логики нет, и любые алгоритмы сжатия без потерь с одинаковой вероятностью могут либо уменьшить объем данных, случайно найдя закономерность, либо увеличить, если таковой не нашлось.
Ответ написан
Комментировать
Пригласить эксперта
Ответы на вопрос 3
Griboks
@Griboks
Хотелось бы уведомить гениев наподобие Rsa97 и Adamos.
Для примера возьмём исходную случайную последовательность: 3333221 (всего 7 цифр).
Теперь используем известный алгоритм кодирования длин серий: 432211 (всего 6 цифр). Ура, нам удалось сжать "несжимаемое".
Остался вопрос: а когда этот алгоритм будет эффективным? Когда коэффициент асимметрии распределения значителен по модулю.

p.s.
Некоторые могут сказать, что моя последовательность неслучайна. Если так, то предлагаю этим умельцам продолжить её до 20 цифр. В противном случае последовательность является случайной по определению.

p.s.s
Некоторые люди подразумевают под случайностью равномерно распределённую случайную величину. В таком случае предлагаю использовать архиватор бабушкина - для 256 цифр он будет работать довольно быстро. Ну или просто перебрать все строки длины 256 и записать номер исходной.
Ответ написан
wataru
@wataru Куратор тега Алгоритмы
Разработчик на С++, экс-олимпиадник.
Очень мешает ограничение на фиксированный выходной алфавит, если в этом алфавите не степень двойки символов (как для цифр от 0 до 9). Так-то многие алгоритмы сжатия пользуются тем, что можно записать минимально возможную единицу информации - один бит. Иначе неэффективно сжимается. А на случайных данных без какой-то структуры и с большой энтропией и так все хреново работает.

Советую посмотреть в сторону Burrows-Wheeler transform и потом попробовать RLE или LZ присобачить сверху. Может, ваши данные будут им хорошо сжиматься.

Еще вам тут сильно помогло бы что-то вроде Base64 encode/decode. Допустим у вас k символов в алфавите. Значит каждый символ несет log_2(k) бит. И если у вас символов N, то ваша входная строка содержит N*log_2(k) бит информации. Округлите это число вверх и сгенерируйте столько битов. Это фактически преобразование из k-ичной системы счисления в двоичную. На больших строках будет тормозить, потому что пока мне не очевидно, как для произвольного k делать преобразование быстро, а не делить большое число на 2 с остатком. Если только у вас k не степень двойки, тогда как в base64 можно быстро преобразовывать по блокам.

Потом можно эту битовую строку сжать каким угодно алгоритмом (разбить на блоки, скажем, 8 бит и хоть хаффманом, хоть lz). Потом надо сжатую битовую строку преобразовать назад в k-ичную систему счисления.

Можно комбинировать сжатие на исходном тексте и запись произвольной битовой строки в вашем алфавите. Например после BW-transform вы гоните LZ на тексте из цифр. LZ для эффективности надо уметь писать произвольные битовые строки. Вот вы где-то в памяти отдельно собираете новые символы, которые замыкают новые строки-эталоны (цифры в вашем примере), и отдельно битовую строку. Потом эту строку переведите в k-ичную систему счисления и запишите перед просто символами (как-то закодировав ее длину в скольки-то первых символах заголовка).
Ответ написан
Комментировать
@ComodoHacker
Универсальные алгоритмы сжатия не смогут сжать случайные данные (см. ответ Rsa97). Но если знать специфику данных, откуда они поступают, может что-то и получится. Например, все же выявить какие-то закономерности.
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы