ГоловнаСтаттіПеретворення Бёрроуза-Вілера: Зворотне Перемішування, Що Стоїть За bzip2 та Пошуком Геномів

Перетворення Бёрроуза-Вілера: Зворотне Перемішування, Що Стоїть За bzip2 та Пошуком Геномів

Уявіть собі перестановку літер тексту так, щоб ідентичні літери розташовувалися поруч один з одним, але ви могли б все ще відновити точний оригінальний текст, символ за символом, лише з переставленого варіанту. Це саме те, що виконує перетворення Бёрроуза-Вілера, або BWT, створене у 1994 році Майклом Бёрроузом та Девідом Віллером під час роботи в DEC Systems Research Center. Цей обманливо простий алгоритм бере рядок, генерує всі його циклічні обертання, сортує ці обертання за алфавітним порядком і потім читає останній символ кожного відсортованого обертання. Результат на перший погляд виглядає перекрученим, але це ні в чому не випадково: оскільки обертання, які мають однакову наступну контекст, схильні знаходитися поруч один з одним після сортування, послідовності однакових символів з'являються набагато частіше, ніж у вихідному тексті. Це кластерування є золотом для стиснення, оскільки проста конвеєрна обробка, включаючи кодування «рух вперед», кодування довжиною та ентропійне кодування, може сильно стиснути ці послідовності, що є точною манією, яка живить bzip2. Та саме властивість кластеризації, поєднана зі спритними структурами індексування, такими як FM-індекс, також дозволяє біологам шукати короткі запитові послідовності в ряду мільярдів базових одиниць ДНК майже миттєво, тому вирівнювачі, такі як BWA та Bowtie, покладаються на неї. Важливо зазначити, що перетворення не є одностороннім перекручуванням. Використовуючи лише трансформований рядок і одне додаткове число, індекс оригінального рядка серед відсортованих обертань, точний оригінал можна відновити за допомогою елегантного алгоритму, який ніколи не потребує зберігання або генерації всіх цих обертань. Ця лабораторія розглядає процес створення обертів, сортування їх, вилучення перетворення та зворотного процесу крок за кроком.

mysimulator teamОновлено — червень 2026≈ 8 хв читання▶ Відкрити симуляцію

Будівництво Трансформації: Повороти та Сортування

Трансформація Буроу-Вілера починається з одного трюку, запозиченого з теорії рядків: циклічне обертання. Враховуючи рядок, додайте унікальний розділовий символ, який гарантовано менший за будь-який інший символ алфавіту, часто позначається спеціальним символом. Цей розділовий символ позначає справжнє закінчення рядка і, що важливо, гарантує, що жодне обертання ніколи не є таким самим, як інше, що робить етап сортування добре визначеним. З цього розділового символу, позначеного рядка, згенеруйте всі циклічні оберти: візьміть рядок, перемістіть його перший символ в кінець і повторіть цей процес до тих пір, поки не буде створено стільки обертів, скільки є символів у рядку, включаючи розділовий символ. Після того, як згенеруються всі оберти, розташуйте їх у матриці та відсортуйте рядки лексикографічно, тобто за допомогою правил порівняння символів алфавіту в словнику. Ця відсортована структура часто називається Матрицею Буроу-Вілера. Оскільки розділовий символ визначено як менший за будь-який інший символ, він завжди сортується так, щоб займати перший рядок, коли з'являється на початку обертання, що закріплює всю структуру та робить її можливим реверсуванням пізніше. Трансформація сама по собі є останньою колонкою цієї відсортованої матриці, прочитано зверху вниз. Ця одна колонка є повним виходом Трансформації Буроу-Вілера. Зверніть увагу на те, що сталося структурно: перший стовпець відсортованої матриці - це просто символи оригінального рядка, відсортовані за алфавітним порядком, а останній стовпець – це перестановка, визначена тим, який символ відбувся перед контекстом кожного оберту. Оскільки сортування групує всі оберти, які починаються з одного й того ж підрядка, символи, що знаходяться безпосередньо перед цими спільними підрядками, які опиняються в останньому стовпці, часто повторюються. Це єдина механічна причина виникнення кластеризації: подібні контексти сортуються поруч, і символ, що слідує за кожним з цих подібних контекстів, має тенденцію бути одним і тим же символом, який повторюється. Трансформація обмінює рядок із розкиданими повторами на рядок із кластеризованими повторами без втрати жодної інформації, необхідної для скасування процесу.

Чому кластеризація полегшує стиснення

Перетворення Брунова-Вейлера не стискає дані само по собі; воно переставляє дані таким чином, щоб інші, простіші алгоритми могли значно легше їх стиснути. Це розрізнення має значення. Трансформація завжди супроводжується невеликою ланцюжком подальших кроків, і розуміння того, чому кожен крок виграє від перестановки, пояснює весь дизайн. Першим таким кроком зазвичай є кодування «переміщення вгору». Ця техніка підтримує список усіх можливих символів і, щоразу коли символ з’являється у вхідних даних, видає його поточну позицію в списку та переміщує цей символ на початок. Коли вхідні дані містять довгі послідовності однакових або подібних символів, як це часто буває у вихідних даних перетворення Брунова-Вейлера, кодування «переміщення вгору» виробляє довгі послідовності малих чисел, особливо нулів, оскільки нещодавно з’явлений символ, ймовірно, знову з’явиться і вже буде біля початку списку. Другий крок — це кодування довжини послідовностей, яке використовує саме ці довгі послідовності повторюваних малих чисел, замінюючи їх одним значенням плюс лічильник. Послідовність із двадцяти нулів стає лише двома числами замість двадцяти. Цей крок сам по собі може досягти величезних зменшень розміру при тому, що вихідні дані кодування «переміщення вгору» переважно складаються з довгих послідовностей, що є точно тим становищем, яке створює перетворення Брунова-Вейлера. Остаточний крок зазвичай — це ентропійний кодер, такий як кодування Хаффмана або арифметичне кодування, застосований до потоку, закодованого довжиною послідовностей. Ентропійні кодери призначають коротші коди більш частим символам. Оскільки попередні кроки вже концентрували статистичну структуру даних у невеликий набір часто повторюваних малих значень, ентропійний кодер має менше роботи для досягнення сильного стиснення, ніж він би зробив над вихідними даними без змін. Це повна ланцюжок, що використовується в bzip2: перетворення Брунова-Вейлера, кодування «переміщення вгору», кодування довжиною послідовностей і потім кодування Хаффмана, і кожен етап існує конкретно тому, щоб попередня стадія пристосувала дані для полегшення наступної стадії її роботи.

Зворотне перетворення: Перша колонка, Остання колонка

Найбільш вражаюча властивість Burrows-Wheeler Transform полягає в тому, що її можна точно інвертувати, відновлюючи вихідний рядок символ за символом, використовуючи лише трансформований рядок, який часто називають останньою колонкою, плюс одне ціле число, яке позначає відповідну відсортовану ротацію, яка відповідає вихідному рядку. Не потрібно зберігати чи генерувати жодних ротацій під час інвертування, що забезпечує ефективність процесу навіть для дуже довгих рядків, таких як цілі хромосоми. Інвертування ґрунтується на зв’язку між першою колонкою та останньою колонкою відсортованої матриці обертань, описаної раніше. Пам'ятайте, що перша колонка просто символи трансформованого рядка, відсортовані в алфавітному порядку, оскільки вона перераховує початковий символ кожної відсортованої ротації. Важливий структурний факт, який іноді називають відображенням «останній-перший», полягає в тому, що відносний порядок появи будь-якого заданого символу зберігається між останньою колонкою та першою колонкою. Іншими словами, якщо ви подивитесь на третє місце появи літери, скажімо, літери «а», в останній колонці, воно відповідає третьому місцю появи тієї ж самої літери в першій колонці, оскільки обертання відбувається рівномірно у всіх рядках, а сортування зберігає відносний порядок зв’язків у стабільний спосіб. Цей факт дозволяє здійснити зворотний хід через вихідний рядок. Починаючи з рядка, який відомий як відповідний кінцю рядка, або еквівалентно використовуючи збережений індекс початкової ротації, алгоритм повторювано використовує відображення «останній-перший», щоб переміщатися від положення символу в останній колонці до його відповідного положення в першій колонці, витягуючи символи та рухаючись назад на одну позицію за раз. Оскільки першу колонку можна отримати просто сортувавши останню колонку, а відображення між місцями появи однакових символів можна обчислити простим підрахунком, весь вихідний рядок може бути відновлено за час, пропорційний його довжині, використовуючи лише масиви та лічильники, а не повну матрицю обертань. Ця ефективність як у прямому напрямку з використанням технік сортування суфіксів, так і в цьому уважному зворотньому ході, робить перетворення практичним для файлів і геномів величезних розмірів, а не просто теоретичною цікавістю.

Від текстового стиснення до вирівнювання геномів

Перетворення Брунова-Візерса спочатку знайшло основне застосування в загальнокористувацькому стисненні даних, зокрема у виконанні утиліти bzip2, де воно послідовно перевершує старіші методи, засновані на алгоритмі Лемпель-Зіва, на багатьох типах тексту та структурованих даних, завдяки тому, що воно виявляє локальні статистичні регулярності, які ті методи не безпосередньо використовують. Однак, десятиліття після винаходу, перетворення знайшло зовсім інше і, можливо, навіть більш значуще застосування: пошук величезних послідовностей ДНК. Людський геном містить приблизно три мільярди базових пар ДНК, а сучасні технології секвенування виробляють сотні мільйонів коротких фрагментів ДНК, які називаються «читами», і кожна з них потребує відповідного узгодження з її правильним розташуванням у цьому геномі. Розрахунок цього наочно, шляхом сканування геному для кожної чита, був би надто повільним. Інструменти, такі як BWA (Burrows-Wheeler Aligner) та Bowtie, замість цього будують перетворення Брунова-Візерса всього опорного геному заздалегідь, разом із супутньою індексною структурою під назвою FM-індекс, названу на честь її розробників Паоло Феррагіна та Джованні Манзіні. FM-індекс використовує ту ж взаємно зворотну відображення, яка живить реверсією, щоб підтримувати надзвичайно швидкий пошук підрядків. Починаючи з повного діапазону рядків відсортованої обертальної матриці, алгоритм пошуку звужує цей діапазон на один символ за раз, працюючи назад через послідовність запиту, використовуючи попередньо обчислені рахунки того, скільки разів з'являється кожен символ і де. Після обробки всього запиту будь-який залишок діапазону рядків відповідає точно кожній позиції у геномі, де зустрічається ця послідовність запиту. Цей пошук займає час пропорційний довжині чита запиту, а не довжині геному, що робить його здійсненним для вирівнювання сотень мільйонів чітків проти геному з багатьма мільярдами базових пар у розумний термін. Приваблива властивість стиснення, яка сприяє кластеризації, перетворення дивовижно така сама структурна особливість, що робить цей швидкий геномний пошук можливим.

Практичні міркування та обмеження

Незважаючи на свою елегантність, перетворення Бёрроуза-Вілера має практичні витрати та обмеження, які важливо розуміти. Обчислення перетворення наївним способом, шляхом генерації всіх обертань і сортування їх, займає час пропорційний квадрату довжини рядка або гірше, оскільки кожне з багатьох обертань може потребувати порівняння символів символ за символом з багатьма іншими. Для коротких рядків це не має значення, але для файлів, які мають мегабайти або гігабайти, або геномів із мільярдами основ, цей наївний підхід надто повільний. У практиці перетворення обчислюється за допомогою алгоритмів побудови суфіксних масивів, які будують пов’язану відсортовану структуру в часі, який росте лише пропорційно, або майже так, із довжиною вхідних даних, використовуючи техніки під назвою DC3 або SA-IS. Перетворення Бёрроуза-Вілера потім може бути отримане безпосередньо з завершеного суфіксного масиву без необхідності матеріалізації повної матриці обертань, що робить реальні інструменти практичними на рівні геному. Ще одна практична увага – розмір блоку. Збійні програми, такі як bzip2, не застосовують перетворення до всього файлу одночасно; замість цього вони розділяють вхідні дані на блоки, часто кілька сотень кілобайт кожен, і обробляють кожен блок незалежно. Більші блоки зазвичай забезпечують краще стиснення, оскільки є більше контексту для згрупування символів, але вони також вимагають більше пам’яті та часу обчислень, тому реальні впровадження балансують розмір блоку проти цих витрат. Нарешті, важливо бути точним щодо того, що перетворення робить і не гарантує. Це беззбитне, повністю зворотне перестановки символів вхідного рядка; воно само по собі не відсікає або не наближає жодної інформації та не досягає самостійно будь-якого стиснення. Його цінність полягає у реорганізації даних таким чином, щоб прості, швидкі та добре відомі алгоритми, незалежно від того, чи це move-to-front і run-length encoding для стиснення або FM-індекс для пошуку, могли працювати набагато ефективніше, ніж вони б це зробили над початковим неперетвореним рядком.

Frequently asked questions

Чи самостійно здійснює стиснення Burrows-Wheeler Transform?

Ні. Трансформація — це безвтратне переупорядкування символів рядка; вихід має таку ж довжину, як і вхід, але з іншим порядком. Її цінність полягає в тому, що переупорядкований вихід має значно більше кластерів повторюваних символів, ніж оригінальний текст, що дозволяє простим подальшим методам, таким як кодування «перемістити уперед», кодування довгих послідовностей та кодування за допомогою ентропії, більш ефективно стискати його, ніж вони могли б стиснути оригінальний текст безпосередньо.

Чому трансформації потрібен sentinel-символ?

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

Яку інформацію потрібно для зворотного Burrows-Wheeler Transform?

Потрібно лише дві речі: трансформований рядок, який є останньою колонкою відсортованої матриці обертань, та одне ціле число, яке записує, яка рядка цієї відсортованої матриці відповідає оригінальному, незміненому рядку. Використовуючи взаємозв'язок між першою та останньою колонками, оригінальний рядок можна відновити символ за символом без збереження або повторного обчислення повної матриці обертань.

Як Burrows-Wheeler Transform використовується в інструментах для вирівнювання геномів, таких як BWA та Bowtie?

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

Чи обчислення Burrows-Wheeler Transform повільне для великих файлів або геномів?

Генерація кожного обертання та сортування їх безпосередньо було б надто повільно для великих вхідних даних. У практиці трансформація обчислюється за допомогою ефективних алгоритмів побудови суфіксного масиву, які працюють у часі, що приблизно лінійно залежить від довжини вхідних даних, без створення повної матриці обертань. Це робить трансформацію практичною для стиснення великих файлів у таких інструментах, як bzip2, і для індексації цілих геномів у біоінформатичному програмному забезпеченні.

Спробуйте наживо

Усе, що вище, працює прямо у вашому браузері — відкрийте Burrows-Wheeler Transform: The Reversible Shuffle Behind bzip2 and Genome Search і змінюйте параметри під час роботи. Нічого не встановлюється, нічого не завантажується на сервер, уся модель живе в одній вкладці.

▶ Відкрити симуляцію Burrows-Wheeler Transform: The Reversible Shuffle Behind bzip2 and Genome Search

Що ви знайшли?

Додати кроки відтворення (опційно)