Кодування набору індексів діапазону

Нам потрібно закодувати інформацію про присутність чи відсутність елементів у списку трикутників.

Ми наближаємося до цього, зосереджуючись на еквівалентній проблемі кодування набору (оболонка, яка зберігає неповторюючі елементи, оптимізовані для виявлення присутності або відсутності певних елементів), яка може містити лише елементи, що належать до діапазону цілих чисел: [0, кількість трикутників - 1), тобто діапазон індексу списку трикутників.


Мета: закодувати цей набір за допомогою мінімальної кількості бітів.

Опис

Давайте поглянемо на дрібний підхід, який у багатьох випадках може бути оптимальним:

Вона складала:

  • Кількість елементів у діапазоні (з 31 бітами, оскільки списки у Java обмежено 2^31 - 1) елементів.
  • Слідує за 1 бітом для кожного покажчика, вказуючи чи присутній елемент у наборі, чи ні.

Це реалізація, яку мала перша версія компресора фрактального зображення для збереження даних з дроблення і об'єднання триангуляцій.

Хоча вона не була оптимальною, оскільки ітерації дроблень прогресували, кількість елементів, які зберігатимуться, зменшилася, а це стало дуже малим відсотоком від загальної кількості, у цьому випадку можна значно покращити дріб'язкове кодування.


Тепер мета полягає у тому, щоб покращити це незначне кодування, щоб побачити, чи можна отримати більш стиснуте кодування з точки зору кількості використаних бітів.


Перший підхід : Коли кількість елементів у множині набагато менша за розмір діапазону, ми можемо взяти до уваги наявність індексів.

В цьому випадку, використання таке:

  • 31 біта для кількості елементів у діапазоні.
  • 31 біта для кількості елементів, що є у множині.
  • 31 біт * кількість елементів у множині.


Другий підхід . Ми покращуємо кількість бітів на збережений елемент:

  • 31 бітів для кількості елементів у діапазоні. Кількість бітів найбільшого елемента у діапазоні ( NumBits Elem ) було б підраховано.
  • 5 бітів для збереження NumBits Elem .Отже, якщо кількість елементів у діапазоні дорівнює 1023, то 10 буде зберігатися в цих 5 бітах.
  • NumBits Elem біти, які слід зберегти у наборі.
  • NumBits Elem біти * кількість елементів у наборі.

Ну, помаленьку ми наближаємося до кращого кодування...


Третя наближення . Ми розуміємо, що, якщо ми впорядковуємо набір у порядку зростання, дельти (розбіжності між послідовними елементами) можуть бути закодовані з меншою кількістю бітів, ніж абсолютний елемент діапазону:

  • 31 біта для кількості елементів у діапазоні.
  • Ми підраховуємо найменший NumBits Elem для кодування елементу.Ми також підраховуємо список дельтів (список відмінностей між послідовними елементами впорядкованого списку елементів у множині).І, нарешті, ми також підрахуємо NumBitsDelta
  • 5 бітів для збереження NumBits Elem .
  • 5 бітів для збереження NumBitsDelta .
  • NumBits Elem біти, які слід зберегти у наборі.
  • NumBitsDelta біти * кількість елементів у наборі.


Здається, ми вже досягли оптимального кодування, чи не так?

Продовжимо...

Четверте наближення Ми зосереджуємося на тому факті, що може бути набагато більше число менших дельтів, і, можливо, лише кілька набагато більших, які розбивають NumBitsDelta теперь.

Під цими обставинами, можна знайти · nonOptimumBitsDelta ⇩ менше, ніж максимальна ⇩ NumMaxBitsDelta ♫ Що у свою чергу є меншим або рівним до ♫ NumBits Elem теперь.

Але як ми закодовуємо дельта елемент, який йде nonOptimumBitsDelta А?

Ну... оскільки дельта ніколи не буде 0 (у множині немає повторюваних елементів), ми можемо використати значення 0, щоб позначити, що це особливе значення.

І після цього 0 буде значення дельти, але закодовано цього разу з ♫ NumMaxBitsDelta теперь.Загальна кількість бітів може бути обчислена таким чином:

  • 31 біт для кількості елементів у діапазоні. NumBits Elem щоб мати змогу шифрувати один елемент. Ми також обчислюємо список дельтів (список відмінностей між послідовними елементами впорядкованого списку елементів у наборі).
  • 31 біт, щоб зберегти кількість елементів у Сеті.
  • 5 бітів для збереження nonOptimumBitsDelta .
  • 5 бітів для збереження NumMaxBitsDelta .
  • nonOptimumBitsDelta біти * кількість елементів у наборі.
  • NumMaxBitsDelta біт * кількість дельтів, що перевищує nonOptimumBitsDelta .


Чи ми вже досягли оптимального кодування?

П' ять наближення Ну... так как мы уже все запрограммировали...Ми можемо подумати про додаткову ситуацію...Чи може бути, що кодування доповнення множини з тим самим алгоритмом призведе до створення більш стиснутих результатів?

Доповнення множини сприймається як ще одна множина, що не співвідноситься з початковою множиною, чий зв'язок з початковою множиною є цілим діапазоном.

Тобто, доповнююча множина буде мати всі елементи діапазону відсутні у початковій множині, і жодного з них не знайдено у початковій множині.

Краса в тому, що з множини легко отримати доповнюючий набір, і тому ми могли б отримати оригінальний набір, закодувавши доповнюючий набір.

Очевидною програмою є набір елементів діапазону, окрім одного або декількох...

Ну... якщо ми зберігаємо лише відсутні (доповнювальні множини), вони можуть зберігатися в значно менших розмірах, чи не так?

Кодування у цьому випадку може бути таким:

  • 31 біт для кількості елементів у діапазоні. NumBits Elem для кодування елемента. Ми також обчислюємо список дельтів (список відмінностей між послідовними елементами впорядкованого списку елементів у наборі).
  • 1 біт, щоб зберегти, чи ми зберігаємо оригінальну множину, чи доповнення.Це зайвий біт.
  • 31 біт, щоб зберегти кількість елементів у Сеті.
  • 5 бітів для збереження nonOptimumBitsDelta .
  • 5 бітів для збереження NumMaxBitsDelta .
  • nonOptimumBitsDelta біти * кількість елементів у наборі.
  • NumMaxBitsDelta біт * кількість дельтів, що перевищує nonOptimumBitsDelta На місцях, де вони з'являються.

Ну... сейчас мы говорим.

Отже, це місце, де я застрягла... але я знаю, що якщо всі ці дива можна було б зробити, що не могло бути зроблено пошуком інших візерунків, або просто використовуючи компресор без втрат, наприклад, "застібку" або 7z...


Придется подождать, в следующий раз на заднем пальнике...

Опис коду

Декодер тривіальний... Вам просто потрібно прочитати параметри bitstream і застосувати потрібні дії для отримання початкового набору.


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

Ідея полягає в тому, щоб заздалегідь підрахувати кількість бітів, які б він заповнив будь-яким типом кодування і зберегти оптимальну кількість.

Оскільки немає сенсу використовувати кодування дельти, якщо воно займає більше, ніж просте кодування.

Тож... ми підрахуємо, що зайняло незначне кодування.

І також... ми обчислюємо оптимальні параметри більш вишуканого кодування дельти, яке ми пояснювали в попередньому розділі.


Це можна зробити під час обчислення кількості бітів кодування, які буде використано для комбінацій параметрів:

  • nonOptimumBitsDelta
  • NumMaxBitsDelta Все полагоджено.
  • Використовувати початковий або доповнюючий набір.


Щоб уникнути надмірної складності під час пошуків оптимальних параметрів (які можуть бути покарані великими діапазонами значень), ми робимо наступне:

Доповнювальна множина обчислюється лише один раз і зберігається.

Дельта списку початкового набору і доповнювального набору обчислюються лише один раз і зберігаються.

Щоб обчислити кількість бітів, створених різними варіантами, виконайте команду:

Ми обчислюємо гістограму кількості бітів у дельті лише один раз. Заснована на цій гістограмі, обчислювати загальну кількість бітів дуже просто і обчислювальна складність цих розрахунків набагато нижча, ніж якщо ми "засвоюємо" кодування елемента за елементом.


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

Звантаження