Кіріспе

Жоқтайтын деректерді қысу алгоритмі

Lempel–Ziv–Markov тізбегі алгоритмі (LZMA) – деректерді жоғалтпай қысу үшін қолданылатын алгоритм. Оны 1996 немесе 1998 жылдан бастап Игорь Павлов әзірлеген және алғаш рет 7-Zip архивтеушісінің 7z форматында пайдаланылған. Бұл алгоритм 1977 жылы Абрахам Лемпель мен Джейкоб Зив жариялаған LZ77 алгоритміне ұқсас сөздік негізіндегі қысу схемасын қолданады және жоғары қысу қатынасына (әдетте bzip2-ден жоғары) және өзгермелі қысу сөздігінің көлеміне (4 ГБ-қа дейін) ие, сонымен бірге басқа көп қолданылатын қысу алгоритмдерімен салыстырылатын қысу жылдамдығын сақтайды. LZMA2 – бұл қарапайым контейнер форматы, ол қысылмаған деректерді де, LZMA деректерін де, тіпті бірнеше түрлі LZMA кодтау параметрлерін де қамтуы мүмкін. LZMA2 кез келген деңгейде масштабталатын көп өрісті қысу және ашуды, сондай-ақ ішінара қысылмайтын деректерді тиімді қысуды қолдайды.

Декомпрессия алгоритмінің егжей-тегжейі

Қысылған форматтың толыққанды табиғи тілдегі сипаттамасы, осы мәтінде жасалғаннан басқа, көрінеді жоқ. Төмендегі сипаттама Linux ядросының бастапқы кодында қамтылған Лассе Коллиннің ықшам XZ Embedded декодеріне негізделген, одан LZMA және LZMA2 алгоритмдерінің толық мәліметтерін салыстырмалы түрде оңай табуға болады: демек, кодты сілтеме ретінде пайдалану идеалды болмаса да, кез келген бағдарламашы төмендегі мәлімдемелерді бірнеше сағат жұмыс істеу арқылы тексеруге мүмкіндік алады.

Бүкіл сандардың ауқымын кодтау

Диапазондық декодер сонымен қатар біт ағашын, кері біт ағашын және бүтін сандарды декодтау мүмкіндіктерін, сондай-ақ жоғарыда сипатталған бір биттік декодтауды жалпылау үшін пайдаланылатын тұрақты ықтималдықпен бүтін сандарды декодтау құралдарын ұсынады. Лимиттен кіші қолтаңбасыз бүтін сандарды декодтау үшін (лимит - 1) 11 биттік ықтималдық айнымалысынан тұратын массив ұсынылады, олар тұжырымдамалық тұрғыдан лимит жапырақтары бар толық бинарлық ағаштың ішкі түйіндері ретінде орналасқан. Кері емес біт ағашын декодтау, айнымалылар ағашына көрсеткішті сақтап жұмыс істейді, ол түбірден басталады. Көрсеткіш жапыраққа бағытталмағанда, көрсеткіш көрсеткен айнымалыны пайдаланып бит декодталады, содан кейін бит 0 немесе 1 болған жағдайда көрсеткіш солға немесе оңға жылжытылады; көрсеткіш жапыраққа бағытталғанда, жапыраққа сәйкес келетін сан қайтарылады. Осылайша, кері емес біт ағашын декодтау ең маңызды биттен ең аз маңызды битке қарай жүзеге асырылады, тек жарамды диапазон ішінде бір ғана мән болғанда тоқтатылады (бұл концептуалды түрде диапазон өлшемдерінің екінің дәрежесі болмауына мүмкіндік береді, бірақ LZMA мұны пайдаланбайды). Кері біт ағашын декодтау, керісінше, ең аз маңызды биттен ең маңызды битке қарай декодтайды, сондықтан тек екінің дәрежесіндегі диапазонды ғана қолдайды және әрқашан бірдей бит санын декодтайды. Бұл екінің дәрежесі лимитімен кері емес біт ағашын декодтауды орындаумен және нәтиженің соңғы биттерін кері қайтарумен тең. Linux ядросындағы функцияда бүтін сандар шындығында [limit, 2 × limit) диапазонында қайтарылады (концептуалды мәнге лимит қосылады), массивтегі 0 индексіндегі айнымалы пайдаланылмайды, ал 1 индексіндегісі түбір болып табылады, ал сол және оң балалардың индекстері 2i және 2i + 1 ретінде есептеледі. Функцияның өзі [0, limit) диапазонындағы бүтін сандарды шақырушы ұсынған айнымалыға қосады, мұнда лимит оның логарифмі арқылы жасырылған, және тиімділік үшін өзінің тәуелсіз іске асырылуына ие. Тұрақты ықтималдықпен бүтін санды декодтау, ең маңыздыдан ең аз маңыздыға қарай биттерді оқып, тұрақты ықтималдықпен биттік декодтауды қайталап орындайды.

Сығу алгоритмінің егжей-тегжейі

Декомпрессиялық форматтарға ұқсас түрде, 7-Zip немесе xz кодилеу техникаларының толыққанды табиғи тілдегі сипаттамасы, төменде келтірілгеннен басқа, көрінетіндей емес. Төмендегі сипаттама Лассе Коллин жасаған Java үшін XZ кодилегішіне негізделген, ол бірдей алгоритмдерді қолдана отырып, түпнұсқа 7-Zip-тің бірнеше қайта жазылуының арасында ең түсінікті болып көрінеді: қайтадан айта кетейік, бастапқы кодты сілтеме ретінде келтіру – идеалды шешім емес, бірақ кез келген бағдарламашы төмендегі мәлімдемелерді бірнеше сағат жұмыс істеу арқылы тексеруге мүмкіндік алады.

Сөздіктердегі іздеу деректерінің құрылымдары

Кодтаушы сөздікте сәйкестіктерді жылдам табуға қабілетті болуы керек. LZMA қысуды жақсарту үшін өте үлкен сөздіктерді (потенциалды түрде гигабайттармен өлшенетін) пайдаланатындықтан, егер бүкіл сөздікті қарап шығу керек болса, кодтаушы тым баяу болып, пайдалануға жарамсыз болып қалады. Сондықтан жылдам сәйкестіктерді іздеуге қолдау көрсету үшін күрделі дерек құрылымдары қажет.

Хаш тізбектері

Ең қарапайым тәсіл, "хаш-тізбектер" деп аталады, және ол 2, 3 немесе 4 болатын N тұрақтысымен параметрленеді, бұл тұрақты әдетте сөздіктің көлемінен үлкен немесе оған тең етіп таңдалады. Ол әр k-ның N-ге тең немесе кіші мәні үшін k байттық тізімдермен индексиленген хаш-кесте құрудан тұрады, мұнда әрбір ұяшықта осы хаш-кесте ұяшығымен байланысты хаш-мәніне хэштелген бірінші k байттың соңғы орны сақталады. Тізбектеу, әрбір сөздік орны үшін соңғы рет көрінген және алғашқы N байты аталған орның алғашқы N байтымен бірдей хэштелген алдыңғы орнды сақтайтын қосымша массив арқылы жүзеге асырылады. N немесе одан жоғары ұзындықтағы сәйкестіктерді табу үшін іздеу N өлшемді хаш-кестесінен басталып, хаш-тізбек массиві арқылы жалғастырылады; іздеу, хаш-тізбек тораптарының алдын ала анықталған санынан өткесімен немесе хаш-тізбектер "айналып келгенде" тоқтатылады, бұл сөздікте қайта жазылған кірістің бөлігіне жеткенін көрсетеді. N-ден кіші өлшемдегі сәйкестіктер тек тиісті хаш-кестені қарау арқылы табылады, ол соңғы сәйкестікті (бар болса) немесе бірдей мәнге хэштелген тізбекті қамтиды; соңғы жағдайда кодер сәйкестікті таба алмайды. Бұл мәселе алыс қысқа сәйкестіктер үшін бірнеше литеральдарды пайдалану аз биттерді қажет етуімен және жақын тізбектерде хаш-қақтығыстардың болу ықтималдығының төмендігімен азайтылады; үлкен хаш-кестелерді немесе тікелей іздеу кестелерін пайдалану жоғары кэштен қашу деңгейі және төмен өнімділік есебінен проблеманы азайтуға болады. Барлық сәйкестіктерді растау қажет, себебі хаш-механизмі тек өткен уақытта хаш-кесте ұяшығы индексіне кейбір таңбалардың хэштелгенін кепілдік береді (кейбір іске асырулар тіпті оны кепілдік бермейді, өйткені олар дерек құрылымдарын инициализацияламайды).

Екілік ағаштар

Бинарлық ағаш әдісі хештік тізбек әдісін ұстанады, бірақ тізбелеу үшін байланысты тізімнің орнына бинарлық ағашты логикалық түрде пайдаланады. Бинарлық ағаш әрқашан жұрнақтың лексикографиялық ретіне қатысты іздеу ағашы және сөздік позициясы бойынша максималды үйірме болып сақталады (яғни, түбірі әрқашан ең соңғы тізбек болады, ал баласы ата-анасынан кейінірек қосылған болмайды): егер барлық тізбектер лексикографиялық ретпен орналасса, онда бұл шарттар бинарлық ағашты бірегей түрде анықтайды (бұл ағаштың көлемі бойынша индукция арқылы оңай дәлелдеуге болады). Іздеуге және енгізуге арналған тізбек бірдей болғандықтан, сөздік бойынша іздеу және енгізуді (ағашты бұруды талап ететін) бір ағашты аралау арқылы жүзеге асыруға болады.

LZMA2 кодтаушысы

XZ LZMA2 кодтаушысы кіріс деректерді бөліктерге бөліп өңдейді (созылмаған көлемі 2 МБ-қа дейін немесе 64 КБ-қа дейін, ең кішісін таңдайды), әр бөлікті LZMA кодтаушысына жібереді, содан кейін кодталған деректерді қамтитын LZMA2 LZMA бөлігін шығаруға немесе LZMA2 сығылмаған бөлігін шығаруға шешім қабылдайды, қайсысы қысқа болса, соны таңдайды (LZMA, кез келген басқа сығымдағыш сияқты, кейбір деректерді сығымдаудың орнына кеңейтуі мүмкін). LZMA жай-күйі тек бірінші бөлікте, шақырушы қасиеттерді өзгертуді сұраса және сығылған бөлік шығарылған сайын қалпына келтіріледі. LZMA қасиеттері тек бірінші бөлікте немесе шақырушы қасиеттерді өзгертуді сұраса ғана өзгертіледі. Сөздік тек бірінші бөлікте қалпына келтіріледі.

Жоғарғы кодтау қабаттары

LZMA2 кодтаудан бұрын, берілген опцияларға байланысты, xz BCJ сүзгісін қолдана алады, ол орындалатын кодты салыстырмалы офсеттерді көбірек қайталанатын абсолютті мәндермен алмастыру үшін сүзгілейді, немесе дельта сүзгісін қолданады, ол әр байтты одан бұрынғы байттың мәні мен арасындағы айырмамен алмастырады. Параллель кодтау файлды бөліктерге бөліп, оларды жіптерге (thread) таратады, содан кейін әр бөлік жеке кодталады (мысалы, xz блокты кодтау арқылы), нәтижесінде шығыс файлдағы бөліктер арасында сөздік жаңадан басталады.

7-Zip эталондық іске асыру

7 Zip-тен алынған LZMA іске асырылуы LZMA SDK ретінде қолжетімді. Бастапқыда GNU LGPL және Common Public License екі лицензиясы бойынша, байланыстырылған бинарлық файлдарға арналған қосымша ерекшелікпен берілген, бірақ 2008 жылдың 2 желтоқсанында Игорь Павлов 4.62 нұсқасымен бірге оны қоғамдық доменге өткізді. Қазіргі таңда .7z форматы үшін стандартты сығылу әдісі болып табылады, 2012 жылдың 26 қазанындағы 9.30 нұсқасынан бастап. Ашық кодты LZMA сығылу кітапханасы бастапқыда C++ тілінде жазылған, бірақ ANSI C, C# және Java тілдеріне аударылды. 7 Zip іске асырылуы сөздік іздеу алгоритмінің негізі ретінде хэш-тізбектердің, бинарлық ағаштардың және Патрисия ағаштарының бірнеше түрлерін пайдаланады. LZMA-дан басқа, SDK және 7 Zip сығылуды жақсартуға арналған бірнеше алдын ала өңдеу сүзгілерін де іске асырады, олар қарапайым дельта кодтаудан (суреттер үшін) бастап, орындалатын код үшін BCJ-ге дейін жетеді. Ол сондай-ақ 7z форматында қолданылатын басқа да сығылу алгоритмдерін ұсынады. LZMA үшін тек сығылмайтын кодты компиляциялау көбінесе 5 КБ шамасында болады, ал сығылу кезінде қажетті RAM мөлшері негізінен сығылу кезінде қолданылатын жылжымалы терезенің мөлшерімен анықталады. Шағын код мөлшері, салыстырмалы түрде аз жадты қажет етуі, әсіресе кішкентай сөздік ұзындығында, және ашық бастапқы код LZMA сығылу алгоритмін кіріктірілген жүйелерге өте қолайлы етеді.

Басқа іске асырулар

7-Zip эталондық нұсқасына қосымша, LZMA форматын келесілер қолдайды. xz: xz файл пішімінде LZMA және LZMA2 қолдайтын, gzip сияқты командалық жол құралы бар ағынды іске асыру. Ол жоғары өнімділігімен (bzip2-мен салыстырғанда) және шағын көлемімен (gzip-бен салыстырғанда) Unix сияқты жүйелердегі көптеген бағдарламалық қамтамасыздарға енді. Fedora қазір өз шығарылымдарын қысу үшін xz-ді пайдаланады. lzip: Unix сияқты жүйелер үшін xz-бен тікелей бәсекелесуге арналған тағы бір LZMA нұсқасы. Ол негізінен қарапайым файл пішімімен және осылайша қателерді оңай қалпына келтіру мүмкіндігімен ерекшеленеді. ZIPX: WinZip 12.1 нұсқасынан бастап құрылған ZIP қысылу форматының кеңейтімі. Ол BZip және PPMd сияқты басқа да қысу әдістерін де қолдана алады.

LZHAM

LZHAM (LZ, Huffman, Arithmetic, Markov) — LZMA сияқты, компрессия жылдамдығын өте жоғары сығылу коэффициенттері мен жоғары декомпрессия жылдамдығы үшін құрбан ететін әдіс. Авторы 2020 жылдың 15 қыркүйегінде оны жалпы қолданысқа қойды.