thedeemon: (office)
[personal profile] thedeemon
Периодически встречаю словосочетание "декларативное программирование", которое противопоставляют императивному, сопровождая формулой "описывается, что должно быть получено, а не как оно должно быть получено". Известный пример декларативного языка - SQL. Еще к декларативщине частенько относят хаскель и другие ФЯ, но вот с ними проблема: сколько кода я на них видел, (практически) везде было явное описание процесса вычисления, т.е. код был все же императивным по сути (создать список такой-то, свернуть его так-то, построить дерево такое-то и т.д. - это все про "как"). Вопрос к залу: покажите максимально декларативное решение (на любом языке, в том числе еще не существующем и чисто гипотетическом) следующей задачи.

Есть последовательность байтов (фиксированный массив/список или потенциально бесконечный поток - на ваш выбор), нужно их сжать RLE методом по мотивам формата PCX: в выходном потоке байт Х <= 192 обозначает сам себя, а байт Х > 192 означает Х-192 повторений следующего за ним байта. Т.е. последовательность
1, 1, 2, 3, 2, 2, 2, 200, 0, 200, 200, 200, 200
должна превращаться в
194, 1, 2, 3, 195, 2, 193, 200, 0, 196, 200

Date: 2013-01-04 10:22 am (UTC)
From: [identity profile] raindog-2.livejournal.com
Неэффективную имплементацию сделать было бы нетрудно, мне кажется. Можно использовать что-то вроде beam search. Держать не более N лучших решений, на каждом шаге попробовать к каждому из них добавить в хвост один байт (от 0 до 255), отсеять те решения, которые не дают следующего байта (следующих байт) исходного потока. Если нужно - то отсеять худшие решения, чтобы оставить не более N. В тот момент, когда первый байт у всех N решений один и тот же - вывести его и удалить из всех решений. И так до конца.
Неэффективно, но должно работать, вроде бы. Можно для незваисимых тестов использовать.
Будет время - набросаю в коде, на словах не очень понятно, наверное.
Edited Date: 2013-01-04 10:24 am (UTC)

Date: 2013-01-04 02:19 pm (UTC)
From: [identity profile] sassa-nf.livejournal.com
А зачем здесь ещё beam search с N лучших решений?

Сжатие касается только цепочек одинаковых байт. Значит, можно рассматривать цепочки одинаковых байт по отдельности. Цепочка 2..63 байта минимально записывается 2 байтами; если ваш алгоритм так и делает, значит, он генерирует минимальное представление.

Цепочка 65..126 байт всегда записывается 4 байтами. Главное, не делать глупостей, вроде записывать любые 64 байта с помощью 4 байт: если ваш алгоритм умеет записывать 64 байта X <= 192 с помощью 3 байт, значит, он генерирует минимальное представление.

Далее по индукции показываем, что представление 63+n байт равно 2+(представление n байт). Отсюда вытекает рекурсия и одно минимальное представление. Поскольку оно уже минимально, незачем хранить N решений в надежде найти ещё лучшее.

Date: 2013-01-04 03:57 pm (UTC)
From: [identity profile] thedeemon.livejournal.com
Осталось научить компутер рассуждать в таком стиле. Интересен сам алгоритм построения обратной функции не только для rle, но для целого класса подобных трансформаций. Т.е. функция типа "код -> код".

Date: 2013-01-04 07:39 pm (UTC)
From: [identity profile] raindog-2.livejournal.com
Да, конкретно для rle все просто. Но этот метод более общий, он подходит для любого преобразования последовательностей байт. Дело в том, что для некоторых преобразований greedy solution будет неоптимальным.
Пусть нам нужно найти Y <- f(X), если у нас есть функция g, такая что x <- g(Y). Здесь X и Y - последовательнсти байт.
Предположим что X = '0123456789'.
Предположим, что g('a') = '0123', g('0') = '0'.
Если бы рассматривать только greedy solutions, мы должны однозначно выбрать 'a' как первый байт выхода. Но может оказаться, что единственным решением, которое начинается с 'a', будет 'a456789'. В то время как другим решением может быть '0c' (то есть 'c' преодбразуется в '123456789'). Более того, решения, которое начинается с 'a', может вообще не существовать.
То есть нужен какой-то backtracking, или какой-то другой поиск решения.
Beam search не универсален, но удобен при работе с потоками - например, не нем так имплементированы многие известные алгоритмы OCR и speech recognition.
Edited Date: 2013-01-04 07:41 pm (UTC)

Date: 2013-01-04 03:55 pm (UTC)
From: [identity profile] thedeemon.livejournal.com
Пока не очень ясно, как получаются те решения, из которых мы что-то выбираем и отсекаем.

Date: 2013-01-04 07:44 pm (UTC)
From: [identity profile] raindog-2.livejournal.com
Решения получаются путем добавления по одному байтику. Начальное решение - пустая последовательность. Кроме последовательности, в каждом решении хранится state обратной функции (в нашем случае - state декомпрессора). Я позже сегодня напишу код, так будет проще.

Profile

thedeemon: (Default)
Dmitry Popov

December 2025

S M T W T F S
 12 3456
789101112 13
14151617181920
21222324252627
28293031   

Most Popular Tags

Style Credit

Expand Cut Tags

No cut tags
Page generated Jan. 29th, 2026 03:25 am
Powered by Dreamwidth Studios