Skip to content
Snippets Groups Projects
Ladislav_Zemek_BP_UTF-8.tex 41.8 KiB
Newer Older
Ladislav Zemek's avatar
Ladislav Zemek committed
% arara: pdflatex
% arara: pdflatex
% arara: pdflatex

% options:
% thesis=B bachelor's thesis
% thesis=M master's thesis
% czech thesis in Czech language
% slovak thesis in Slovak language
% english thesis in English language
% hidelinks remove colour boxes around hyperlinks

\documentclass[thesis=B,czech]{FITthesis}[2012/06/26]

\usepackage[utf8]{inputenc} % LaTeX source encoded as UTF-8

\usepackage{graphicx} %graphics files inclusion
Ladislav Zemek's avatar
Ladislav Zemek committed
\usepackage[]{algorithm2e}
Ladislav Zemek's avatar
Ladislav Zemek committed
\usepackage{listings}
Ladislav Zemek's avatar
Ladislav Zemek committed
% \usepackage{amsmath} %advanced maths
% \usepackage{amssymb} %additional math symbols

\usepackage{dirtree} %directory tree visualisation

% % list of acronyms
% \usepackage[acronym,nonumberlist,toc,numberedsection=autolabel]{glossaries}
% \iflanguage{czech}{\renewcommand*{\acronymname}{Seznam pou{\v z}it{\' y}ch zkratek}}{}
% \makeglossaries

\newcommand{\tg}{\mathop{\mathrm{tg}}} %cesky tangens
\newcommand{\cotg}{\mathop{\mathrm{cotg}}} %cesky cotangens
Ladislav Zemek's avatar
Ladislav Zemek committed
\newcommand{\classname}[1]{\texttt{#1}}
Ladislav Zemek's avatar
Ladislav Zemek committed
% % % % % % % % % % % % % % % % % % % % % % % % % % % % % % 
% ODTUD DAL VSE ZMENTE
% % % % % % % % % % % % % % % % % % % % % % % % % % % % % % 

\department{Katedra softwarového inženýrství}
\title{Implementace kompresních metod LZ77, LZ78 a~LZW v~jazyce Java}
\authorGN{Ladislav} %(křestní) jméno (jména) autora
\authorFN{Zemek} %příjmení autora
\authorWithDegrees{Ladislav Zemek} %jméno autora včetně současných akademických titulů
\author{Ladislav Zemek} %jméno autora bez akademických titulů
\supervisor{Ing. Radomír Polách}
\acknowledgements{Rád bych poděkoval Ing. Radomírovi Poláchovi za odborné vedení, pomoc a vstřícnost při vedení bakalařské práce.}
\abstractCS{Tato bakalářská práce se~zabývá návrhem, analýzou, implementací a~testováním tří kompresních metod LZ77, LZ78 a~LZW do~knihovny SCT. Knihovna je koncipována tak, aby v~budoucnu nabídla uživatelům velkou škálu kompresních metod a~tak usnadnila výběr vhodné metody pro jejich projekt.  Uvnitř této práce se zabývám vhodným návrhem a~popisem daných algoritmů. U~všech metod se mi podařilo při vhodně zvolených parametrech dosáhnout zmenšení testovaných korpusů vždy alespoň o~30~\%. Přínosem této práce je přispění do knihovny, která může v budoucnu usnadnit některým vývojářům práci.}
Ladislav Zemek's avatar
Ladislav Zemek committed
\abstractEN{This bachelor thesis deals with the design, analysis, implementation and~testing of~three compression methods LZ77, LZ78 and~LZW in~the~SCT library. The~library is designed to~offer users a~wide range of~compression methods in~the~future to~facilitate the~choice of~the~right method for their project. Inside this thesis I deal with suitable design and~description of~given algorithms. For all methods, I managed to~reduce the tested corpuses with~appropriately selected parameters at~least by~30~\%. The benefit of~this work is contributing to a~library that can make it easier for some developers to work in the~future.}
\placeForDeclarationOfAuthenticity{V~Praze}
\declarationOfAuthenticityOption{4} %volba Prohlášení (číslo 1-6)
Ladislav Zemek's avatar
Ladislav Zemek committed
\keywordsCS{Komprese dat, dekomprese dat, chaining, Java, LZ77, LZ78, LZW, SCT}
Ladislav Zemek's avatar
Ladislav Zemek committed
\keywordsEN{Compression, decompression, chaining, LZ77, LZ78, LZW, SCT}
%\website{https://gitlab.fit.cvut.cz/zemeklad/BP} %volitelná URL práce, objeví se v tiráži - úplně odstraňte, nemáte-li URL práce

\begin{document}

%\newacronym{CVUT}{{\v C}VUT}{{\v C}esk{\' e} vysok{\' e} u{\v c}en{\' i} technick{\' e} v Praze}
%\newacronym{FIT}{FIT}{Fakulta informa{\v c}n{\' i}ch technologi{\' i}}

\begin{introduction}
	V~době, kdy se začali počítače rozšiřovat do~běžného života, vznikla potřeba ukládat čím dál větší objem dat. Z~dnešního pohledu to nevypadá jako problém, jednoduše si uložíte několika gigabytový soubor na svůj pevný disk s~kapacitou stovek gigabytů. Ovšem tehdy měli pevné disky jen desítky megabytů, což je téměř sto tisíckrát méně než dnes, paměti tedy rozhodně nebylo nazbyt. Proto bylo potřeba data nějakým způsobem zmenšit, za~předpokladu, že nedojde ke~ztrátě informací.
Ladislav Zemek's avatar
Ladislav Zemek committed
	  
	Právě za tímto účelem vznikla bezztrátová komprese dat, která zakóduje data pomocí důmyslných algoritmů. Nová data pak mají výrazně menší velikost než ta původní.\cite{komprese} Jsou tedy vhodnější pro uložení na~disk nebo k~odeslání přes internet. Data je následně možné dekódovat pomocí dekomprese, což je inverzní operace ke kompresi. Výstupem dekomprese jsou původní data.
	
	Jelikož v knihovně SCT nejsou naimplementovány zmíněné algoritmy, rozhodl jsem se je do knihovny doplnit.
	
	\section{Pojmy}
	V této kapitole bych rád vysvětlil a definoval některé pojmy.
	\begin{itemize}
		\item \textbf{Komprese/komprimace dat} -- Zmenšování objemu dat.
		\item \textbf{Bezztrátová komprese dat} -- Komprese dat, při které nedochází ke ztrátě informace.
		\item \textbf{Dekomprese/dekomprimace dat} -- Inverzní operace ke kompresi. Ze zmenšených dat obnovím ty původní.
		\item \textbf{Triplet} -- V této bakalářské práci je tripletem myšlena jakákoliv n-tice. Je tomu tak proto, že v knihovně SCT je každá n-tice zpracovávána pomocí třídy TripletProcessor. Neznamená to tedy vždy trojici (LZ77). V závislosti na metodě může jít i o dvojici (LZ78) nebo jednici (LZW).
		\item \textbf{Adaptivní kompresní metoda} -- Tyto metody si vytváří struktůry za běhu programu v závislosti na vstupních datech. Vytvořené struktůry pak používá ke komprimaci. Není potřeba tyto struktůry ukládat společně s komprimovanými daty. 
		\item \textbf{Slovníkové kompresní metody} -- Tyto metody používají pro komprimaci slovník, který v průběhu komprimace i dekomprimace roste přidáváním nových frází. Proto patří slovníkové metody mezi adaptivní kompresní metody. Komprimovaná data poté obsahují indexy frází ve vytvářeném slovníku.
		\item \textbf{Symetrická kompresní metoda} -- Komprimace i dekomprimace těchto metod má stejnou složitost.
		\item \textbf{Asymetrická kompresní metoda} -- Komprimace i dekomprimace těchto metod má odlišnou složitost.
		\item \textbf{Entropie} -- míra neurčitosti systému
	\end{itemize}	

Ladislav Zemek's avatar
Ladislav Zemek committed
\end{introduction}
Ladislav Zemek's avatar
Ladislav Zemek committed
	
Ladislav Zemek's avatar
Ladislav Zemek committed
\chapter{Cíl práce}
Ladislav Zemek's avatar
Ladislav Zemek committed
Cílem této bakalářské práce je seznámení se s~kompresními algoritmy LZ77, LZ78, LZW a~jejich následná implementace do knihovny SCT (Small Compression Toolkit). Součástí této práce je také jejich následné otestování z~hlediska časové a~paměťové náročnosti, případně porovnání efektivity se stávajícími kompresními algoritmy v~knihovně. Tato knihovna by pak měla ušetřit spoustu práce programátorům, kteří díky ní nebudou muset vymýšlet vlastní implementaci těchto algoritmů.

\section{Existující řešení}
Jedná se o~poměrně zastaralé metody, které vznikli v~80.~letech 20.~století a~dnes je již v~efektivitě překonávají jiné. Nicméně metodu LZ77 je možné použít například v programu CRUSH.\cite{crush} Z LZ77 bylo odvozeno mnoho dalších kompresních algoritmů, které jsou velmi často používány. LZ78 byla taktéž předlohou pro jiné algoritmy například LZW nebo BTLZ. \cite{inspire} Samotná se příliš nevyužívá, protože nedosahuje tak dobrého komprimačního poměru. Naopak metoda LZW bývala poměrně hojně využívá při komprimaci monochromatických obrázků a~obecně je velmi efektivní tam, kde se opakuje velké množství dat. LZW se používala v~dřívějších verzích formátu PDF, později byla nahrazená efektivnějším algoritmem.\cite{lzwEN} Tyto algoritmy patří mezi základní kompresní metody a~jelikož je hlavním cílem SCT poskytnout co největší spektrum kompresních algoritmů, rozhodl jsem se je do knihovny doimplementovat.

Ladislav Zemek's avatar
Ladislav Zemek committed

Ladislav Zemek's avatar
Ladislav Zemek committed
\section{Analýza požadavků}
V této části bych se rád věnoval požadavkům, které mi zadal vedoucí práce a jejich analýze. Každý softwarový projekt by měl začínat analýzou toho, co si zákazník přeje, aby program dělal nebo dodržoval. Požadavek musí být proveditelný, testovatelný a také musí byt definovaný dostatečné detailně pro účely návrhu.\cite{req} Obvykle se požadavky dělí na funkční a nefunkční.

\subsection{Funkční požadavky}
 Funkční požadavky objasňují, jaké má mít požadovaný software funkce, co má umět a jak se má chovat v daných situacích. Podle zadání a diskuse s vedoucím práce jsem určil tyto požadavky jako funkční:
 
\begin{itemize}
Ladislav Zemek's avatar
Ladislav Zemek committed
	\item \textbf{Dekomprese} -- Kromě výchozí funkce komprese bude možné program spustit v režimu dekomprese.
	\item \textbf{Parametry} -- Algoritmům bude možné změnit jejich parametry, jako je například veliskost bufferů, počet prvků ve slovníku nebo jak velké části souboru se budou komprimovat najednou. Parametry bude možné měnit při spoštění přes příkazovou řádku pomocí parametrů a nebo
Ladislav Zemek's avatar
Ladislav Zemek committed
	\item \textbf{Komprimace po částech} -- Algoritmy budou schopné rozdělit soubor na menší části a ty pak komprimovat. Dekomprimace bude probíhat nad celým souborem ne po častech, nicméně algoritmy budou schopny dekomprimovat i soubor, který byl předtím zakomprimován po částech. Velikost částí si určí uživatel pomocí parametru, případně využije výchozích nastavených hodnot.
	\item \textbf{Spustitelnost} -- Program bude možné pustit se zvolenými parametry z příkazové řadky. Nepůjde tedy pouze o implementaci metod do knihovny, ale i o jejich inteface, který bude možné prakticky využít.
Ladislav Zemek's avatar
Ladislav Zemek committed
	
 		
\end{itemize}		
 
\subsection{Nefunkční požadavky}
Ladislav Zemek's avatar
Ladislav Zemek committed
Nefunkční požadavky, jsou takové požadavky, které přímo neříkají, co má program umět. Jedná se převážně o omezující nebo zpřesňující podmínky, kterými se má návrh řídit. Tyto požadavky jsem určil jako nefunkční:
Ladislav Zemek's avatar
Ladislav Zemek committed
\begin{itemize}
	\item \textbf{Triplety} -- Program bude pro ukládání dat do souboru využívat již naimplementované metody třídy TripletProcesor a pro definování jednotlivých složek v tripletu třídu TripletFieldId.
	\item \textbf{Velikostí slovníků a bufferů} -- Aby nedocházelo k nekontrolovatelnému růstu slovníku a tím i k zvyšování pamětové i časové náročnosti, budou mít algorytmy LZ78 a LZW parametr, který zhora omezí počet prvků ve slovníku. U metody LZ77 bude pomocí dvou parametrů omezen vyhledávací buffer i tzv. look ahead buffer.
	\item \textbf{Velikosti prvků v tripletu} -- Toto omezení vychází z implementace třídy TripletProcessor, která dokáže zpracovávat pouze čísla, která je možné zapsat pomocí 28 bitů, tedy maximálně číslo 134 217 728.
	\item \textbf{Jazyk Java} -- Program bude napsán v jave, protože celá knihovna SCT je v tomto jazyce napsána.
	\item \textbf{Řetězení} -- Implementace metody bude dodržovat myšlenku řetězení, tedy že různé kompresní metody bude možné za sebe zapojovat a docílit tak několikanásobné komprese.  
	
\end{itemize}

\subsection{Výjimky} ??

\chapter{Analýza algoritmů}
V této kapitole pojednávám přímo o jednotlivých metodách. Na jakém principu fungují a v čem se liší. Také zde určím jejich asymptotickou složitost, náročnost na pamět, výhody a nevýhody.
Ladislav Zemek's avatar
Ladislav Zemek committed
\section{LZ77}
\subsection{Popis}
Tento kompresní algoritmus vynalezli v roce 1977 pánové Abraham Lempel a Jakob Ziv. Jedná se o slovníkovou, jednoprůchodovou, adaptivní a bezztrátovou metodu. Je založena na principu klouzavého okénka (floating window), které si lze představit jako vyříznutou část dat. Při běhu programu se okénko posouvá v datech pouze jedním směrem a to od začátku do konce. Je rozděleno na dvě části - prohlížecí okénko (search buffer) a aktuální okénko (look-ahead buffer). Jejich velikost je velmi zásadní pro efektivitu celého algoritmu. V zásadě se dá řict, že velikost prohlížecího okénka musí být vždy větší nebo rovna velikosti aktuálního okénka, nicméně v praxi je prohlížecí okénko obvykle tisíci násobně větší než aktuální.\cite{vohoLZ77}
\subsection{Komprese}
Hlavní myšlenka tohoto algoritmu spočívá v nalenzení co nejdelšího prefixu z nezakódovaných dat, který je zároveň obsažený i v prohlížecím okénku. Tato metoda umožňuje menší vylepšení efektivity, pokud se při vyhledávání neomezím pouze na prohlížecí okénko, ale jen na podmínku, že prefix v něm musí začínat. V některých případech je možné nalezt nejdelší prefix, který přesahuje do aktualního okénka. Je tedy možné zakódovat větší část dat. Slovník této metody je tvořen všemi podřetězci, které začínají v prohlížecím okénku.
Ladislav Zemek's avatar
Ladislav Zemek committed

Zde je jednoduchý pseudokód, který popisuje tuto metodu:

\IncMargin{1em}
Ladislav Zemek's avatar
Ladislav Zemek committed
\begin{algorithm}[H]
Ladislav Zemek's avatar
Ladislav Zemek committed
	prohlížecí a aktualní okénko jsou prázdná\;
Ladislav Zemek's avatar
Ladislav Zemek committed
	\While{na vstupu jsou data}{
	přidej na konec aktualního okénka symbol ze vstupu\;
	najdi prefix $p$ z aktualního okénka, který začíná v prohlížecím okénku\;
	\eIf{$p$ bylo nalezeno}{
		zapiš trojici $(i, j, k)$, kde $i$ je vzdálenost prvního znaku nalezeného $p$ od začátku aktualního okénka, $j$ je délka $p$ a $k$ je první nasledující symbol po $p$\;
		posun klouzavé okénko o $j+1$\;
Ladislav Zemek's avatar
Ladislav Zemek committed
	}{
		zapiš triplet $(0, 0, m)$, kde $m$ je první symbol v aktualním okénku\;
		posuň klouzavé okénko o $1$\;
Ladislav Zemek's avatar
Ladislav Zemek committed
	}
	}
\caption{Pseudokód komprese metody LZ77}
Ladislav Zemek's avatar
Ladislav Zemek committed
\end{algorithm}\DecMargin{1em}

\subsection{Složitost komprese}
Dle mého názoru je složitost tohoto algoritmu $O(nm)$, kde $ n $ je délka vstupních dat a $ m $ je velikost prohlížecího okénka.
Na první pohled není uplně zřejmé, jak jsem k tomuto závěru došel. Rozhodl jsem se tedy své tvrzení dokázat pomocí matematického důkazu. 

Mějme asymptotickou složitost znázorněnou sumou, která vyjadřuje nejvyšší možný počet operací potřebných pro komprimaci souboru:
$$O(\sum_{i=1}^{|P|} m p_{i})$$
kde $P$ je množina všech prefixů nalezených v datech, $m$ je velikost prohlížecího okénka a $p_{i}$ velikost $i$-tého prefixu z $P$.
Ladislav Zemek's avatar
Ladislav Zemek committed

Protože součet sumy nezáleží na $ m $, mohu ho vytknout před sumu:

$$O(m\sum_{i=1}^{|P|}p_{i})$$
Ladislav Zemek's avatar
Ladislav Zemek committed

Součet sumy je vždy rovný velikosti dat, protože procházím celá vstupní data a rozděluji je na podřetězce, které najdu v prohlížecím okénku. Nezáleží tedy na délce jednotlivých podřetězců, jejich součet velikostí bude vždy roven velikosti vstupních dat, tedy $ n $. Proto:

$$O(\sum_{i=1}^{|P|} m p_{i}) = O(mn)$$
Ladislav Zemek's avatar
Ladislav Zemek committed

Je třeba říci, že na vyhledání prefixu nebude vždy potřeba stejný počet operací, proto jsem se rozhodl použít tzv. omikron $ O $, který složitost omezuje shora.

\subsection{Dekomprese}

Algoritmus je poměrně jednoduchý. Nejdříve načte ze vstupu triplet, který v sobě obsahuje informaci o tom, odkud a jak dlouhou část prohlížecího okénka je potřeba zapsat na výstup. Poslední část tripletu je jeden byte, který je taktéž potřeba zapsat. Následně zapsaná data rovněž přidáme na konec prohlížecího okénka. Zde je jednoduchý pseudokód:\newline

\begin{algorithm}[H]
	prohlížecí okénko je prázdné\;
	\While{na vstupu jsou data}{
		ze vstupu načti triplet $ (i, j, k) $, kde $i$ je vzdálenost prvního znaku hledaného podřetězce $p$ od konce prohlížecího okénka, $j$ je délka $p$ a $k$ je první nasledující symbol po $p$\;
		
		\eIf{$i$ se rovná 0}{
			zapiš $k$\;
			pridej na konec prohlížecího okénka $k$\;
		}{
			$v:=$ aktuální velikost prohlížecího okénka\; 
			$z:= v - i$\;
			$p:=$ podřetězec prohlížecího okénka od indexu $z$ az do $z + j$\;
			$p:= p + k$\;
			zapiš $p$\;
			do prohlížecího okénka přidej $p$\;
		}
	}
	\caption{Pseudokód dekomprese metody LZ77}
\end{algorithm}

\subsection{Složitost dekomprese}
Oproti kompresi je složitost dekomprese vcelku trivialní. Řekněme, že $ t $ je počet tripletů, pro každý triplet bude potřeba $ p_{i} $ operací, při čtení podřetězce z prohlížecího okénka. To znamená, že celkový počet operací bude roven sumě všech délek podřetězců. Tato suma se však rovná velikosti puvodního nekomprimovaného souboru, tedy $ n $. Čímž dostáváme:  $$\sum_{i=1}^{t} p_{i} = n$$ z čehož plyne, že složitost dekomprese je $ \Theta(n) $. 

Složitosti komprese i dekomprese jsou rozdílné, jedná se tedy o asymetrickou metodu.


Ladislav Zemek's avatar
Ladislav Zemek committed
\subsection{Výhody}
\begin{itemize}
	\item \textbf{Paměť} -- Díky posuvnému okénu se zpracovává vždy pouze poměrně malá čast dat, proto neroste paměťová náročnost s velikost vstupu.  
	\item \textbf{Rychlost dekomprese} -- Při vhodně zvolené implementaci je algoritmus dekomprese lineárně závislý pouze na velikosti dat. Jeho složitost je tedy $\Theta(n)$, kde n je velikost původních dat. 
Ladislav Zemek's avatar
Ladislav Zemek committed
	
\end{itemize}
\subsection{Nevýhody}
Ladislav Zemek's avatar
Ladislav Zemek committed
\begin{itemize}
	\item \textbf{Náhodná data} -- Pokud mají data příliš velkou entropii, algoritmus dosahuje velmi špatných výsledků, často i komprimovaný soubor zvětší. To se týká například některých formátů obrázku (jpeg).   
	\item \textbf{Rychlost komprese} -- Složitost $O(nm)$ je oproti dekompresi $ m $ krát větší. To znamená, že algoritmus bude pomalejší, protože $ m $ je obvykle velké číslo v řádech tisíců až desetitisíců.
Ladislav Zemek's avatar
Ladislav Zemek committed
\end{itemize}

\section{LZ78}
\subsection{Popis}
Metoda byla vynalezena stejnými autory jako LZ77 v roce 1978. Z počátku se jednalo o velmi oblíbenou komprimační metodu až do doby než byly některé její časti patentovány.
Jedná se o paměťově velmi náročnou metodu. Je tomu tak hlavně kvůli obvykle velkému slovníku. Metoda totiž v původní verzi přidává do slovníku položku vždy, když zapisuje triplet, což se děje velmi často. Existuje mnoho způsobu, jak tento problém vyřešit. Například v případě vyčerpání paměti tzv. zamrazit slovník nebo smazat a vytvořit nový. Nejznámější modifikací je LZW, kterou se také zabývám v této práci.\cite{stringologyLZ78}

\subsection{Komprese}

Prvním krokem tohoto algoritmu je inicializace slovníku. Tento krok je velmi důležitý pro správný průběh dekomprese. Do slovníku se přidá slovo délky jedna za každé písmeno abecedy souboru. Abeceda je množina všech znaků, které se mohou v souboru objevit. Obvykle se používá množina všech bytů (0--255), pokud komprese kóduje po bytech. Dále nastaví řetězec $ str $ jako prázdný.
 Následující krok se opakuje pro každý byte ze vstupu. Pokud spojení řetězce $ str $ a načtený byte  $ b $ nejsou ve slovníku, na výstup se přidá triplet obsahující index $ str $ ve slovníku a $ b $. V opačném případě se na konec řetězce $ str $ přidá byte $ b $. Výstupem teto metody je posloupnost dvojic -- číslo, byte.
Zde je jednoduchý pseudokód, popisující kompresi:\newline

\begin{algorithm}[H]
	inicializace $slovníku$\;
	$str :=$ prázdný řetězec\;
	\While{na vstupu jsou data}{
		ze vstupu načti byte $ b $\;
		\eIf{$str + b$ není ve $slovníku$}{
			zapiš triplet $(i, b)$, kde $i$ je index $str$ ve $slovníku$\;
			přidej na konec $slovníku$ slovo $str + b$ \;
			$str :=$ prázdný řetězec\;
		}{
			$str = str + b$\;
		}
	}
	\caption{Pseudokód komprese metody LZ78}
\end{algorithm}


\subsection{Složitost komprese}
Tento algoritmus velmi ovlivňuje zvolená implementace. Pokud se slovník representuje pomocí datové struktůry strom, složitost je $ \Theta(n) $, kde n je velikost vstupních dat v bytech. Protože dokáže v konstantní složitosti $ \Theta(1) $ říci, jestli slovník již obsahuje daný řetězec či nikoliv. Pro každy vstupní symbol vykoná $ \Theta(1) $ operací. Pro uplnost doplním jednoduchou rovnici, která ukazuje, že v asymptotické složitosti se konstantní složitost neprojeví: $$ \Theta(1 * n ) = \Theta(n) $$


\subsection{Dekomprese}

Jak je vidět na pseudokódu níže, algoritmus je velmi jednoduchý. Prvním a zásadním krokem je inicializace slovníku přesně stejnou abecedou jako v kompresi. Následně se načte triplet ze vstupu, podle něj se najde slovo ve slovníku a zapiše do souboru společně s následujícím bytem. Tento zapsaný řetězec je přidán do slovníku na konec (přiřadí se mu nejvyšší index).\newline

\begin{algorithm}[H]
	inicializace $slovníku$\;
	\While{na vstupu jsou data}{
		ze vstupu načti triplet $ (i, b) $, kde $ i $ je index do $slovníku$ a $ b $ je následující byte\;
		$str := slovník[i]$ + $ b $\;
		zapiš $ str $\;
		přidej na konec $slovníku$ slovo $str$ \;
	}
	\caption{Pseudokód dekomprese metody LZ78}
\end{algorithm}

\subsection{Složitost dekomprese}
Jak bylo řečeno v popisu, jedná se o symetrickou metodu. Složitost je tedy stejná jako u komprese a tedy $ \Theta(n) $, kde $ n $ je velikost původních dat. Podobně jako u metody LZ77, máme sice menší vstup, nicméně je potřeba přičíst i režiji slovníku na zrekonstruováná slova. Jedná se o strom, to znamená, že metoda pro rekonstrukci slova udělá počet operací rovný délce slova. Pokud tedy všechny délky posčítáme, dostaneme $ n $.

\subsection{Výhody}
\begin{itemize}  
	\item \textbf{Rychlost komprese i dekomprese} -- Při vhodně zvolené implementaci je algoritmus komprese i dekomprese lineárně závislý pouze na velikosti dat. Jejich složitost je $\Theta(n)$, kde n je velikost původních dat.
	\item \textbf{Implementace} -- Metoda je poměrně jednoduchá na implementaci, především pak dekomprese.
	\item \textbf{Velikost tripletů} -- Do souboru se ukládají pouze dvojice -- číslo, byte.
\end{itemize}
\subsection{Nevýhody}
\begin{itemize}
	\item \textbf{Paměť} -- Paměťová náročnost roste s velikostí vstupu. Proto se při implementaci musí počítat s tím, že metoda vyčerpá přidělenou pamět a podle toho se zachovat.
	\item \textbf{Náhodná data} -- Podobně jako u metody LZ77, při velké entropii dat dochází k horší kompresi, někdy muže dojít až k zvětšení souboru.
	
	
\end{itemize}

\section{LZW}
Tuto slovníkovou, symetrickou, adaptivní a jednoprůchodovou metodu vytvořili Abraham Lempel, Jacob Ziv a Terry Welch v roce 1984. Jedná se o modifikaci metody LZ78. Hlavním rozdílem je, že algoritmu pro dekomprimaci dat stačí pouze indexy ve slovníku. Již tedy nepotřebuje následující byte jako jeho předchůdce. To má ale také za následek rychlejší růst počtu frází ve slovníku. Slovník tedy typicky bývá větší než u LZ78 a spotřebovává rychleji paměť. Je tedy potřeba s tím počítat při implementaci a tento problém vhodně vyřešit. Obecně platí, že čím větší slovník, tím lepší kompresní poměr. Algoritmus je navržen tak aby byl rychlý, nicméně ne vždy je optimální, protože neprovádí žádnou analýzu dat během komprese.\cite{stringologyLZW}

Metoda se stala velmi oblíbenou kolem roku 1987, protože poskytovala nejlepší kompresní poměr. Byla využita například ve formátu GIF, později například ve formátu PDF nebo v unixovém nástroji $ compress $. Stala se první široce využívanou kompresní metodou na počítačích.


\subsection{Komprese}

Ladislav Zemek's avatar
Ladislav Zemek committed
První krok algoritmu je inicializace, která probíhá totožně jako v metodě LZ78. Následně se načte byte $ b $ ze vstupu. Pokud je řetězec $ str + b $ ve slovníku, nastaví se jako $ str $. Pokud není, do souboru se zapíše triplet $ (i) $, kde $ i $ je index fráze $ str $. Do slovníku se pak přidá fráze $ str + b $ a jako nové $ str $ se nastaví $ b $. To je hlaní změna oproti metodě LZ78, která umožnuje právě vynechání nasledujícího bytu v tripletu. Tento postup se opakuje dokud jsou na vstupu data.\newline

\begin{algorithm}[H]
	inicializace $slovníku$\;
	$str :=$ prázdný řetězec\;
	\While{na vstupu jsou data}{
		ze vstupu načti byte $ b $\;
		\eIf{slovo $str + b$ není ve $slovníku$}{
			zapiš triplet $(i)$, kde $i$ je index $str$ ve $slovníku$\;
			přidej na konec $slovníku$ slovo $str + b$ \;
			$str := b$ \;
		}{
			$str = str + b$\;
		}
	}
	\caption{Pseudokód komprese metody LZW}
Ladislav Zemek's avatar
Ladislav Zemek committed
\subsection{Složitost komprese}
Metoda obsahuje pouze drobné změny oproti LZ78, které nemají vliv na asymptotickou složitost. Je totožná se složitostí komprese LZ78, tedy $\Theta(n)$. Proto si dovolím vynechat její odvození.

\subsection{Dekomprese}

Princip dekomprese není na první pohle pochopitelný, protože nepřidávám do slovníku slovo tvořené právě zapisovaným řetězcem, ale tím který byl zapsaný v minulém běhu a pouze prvním znakem zapisovaného řetězce. Tato skutečnost je dána tím, že komprimace přidává do slovníku slovo délky $ n $, končící právě načteným bytem, ale do souboru zapisuje index předchozího slova délky $ n - 1  $, tedy bez načteného bytu. Dekomprimační algoritmus pak vždy ví, že do slovníku je potřeba přidat slovo z minulého běhu zakončené prvním znakem z fráze nalezené ve slovníku. 

Specialní případ nastane, pokud algoritmus ze vstupu načte triplet s indexem, který není ve slovníku. Toto číslo však může být pouze o jedna větší než nejvyšší obsazený index, jinak se jedná o chybu kompresního algoritmu. V tomto případě do slovníku vloží slovo, které bylo vloženo v předchozím kroku zakončené jeho prvním znakem.

K tomuto případu dochází, pokud bylo pro komprimaci použito slovo na posledním indexu (naposledy přidaná fráze do slovníku).

Zde je pseudokód, popisující tento algoritmus:\newline

\begin{algorithm}[H]
	inicializace $slovníku$\;
	$str :=$ prázdný řetězec\;
	\While{na vstupu jsou data}{
		ze vstupu načti triplet $ (i) $\;
		\eIf{$slovník$ obsahuje slovo s indexem $ i $}{
			$ fráze :=  slovník[i]$\;
			zapiš $fráze$\;
			přidej na konec $slovníku$ slovo $str $ + první znak $ fráze $ \;
		}{
			$fráze = str $ + první znak ze $str$\;
			zapiš $str$\;
			přidej na konec $slovníku$ slovo $fráze$\; 
		}
	$str := fráze$
	}
	\caption{Pseudokód komprese metody LZW}
\end{algorithm}

\subsection{Složitost dekomprese}
V závislosti na implementaci se muže složitost tohoto algoritmu lišit. Nicméně pokud struktůru slovníku representuje strom je možné dosáhnout složitosti $ \Theta(n) $, kde $ n $ je velikost původních dat před kompresí. Metoda LZW je navíc symetrická, takže složitost je stejná jako u komprese. Důvod proč jsem došel k této složitosti je analogický s určením složitosti dekomprese u LZ78. Nejvice kroků bude potreba udělat tam, kde se ze slovníku rekonstruuje řetězec, což odpovídá celkové velikosti dat. Ostatní operace mají zanedbatelnou režii a při určování asymptotické složitosti se zanedbávají. 

\subsection{Výhody}
\begin{itemize}  
	\item \textbf{Rychlost komprese i dekomprese} -- Stejně jako u LZ78 je hlavní výhodou rychlost. Při správné implementaci $ \Theta(n) $.
	\item \textbf{Velikost tripletů} -- Do souboru se ukládají pouze číslo. Na jeden triplet je tedy potřeba uložit nejmeně dat z metod kterými se zabývá tato práce.
	\item \textbf{Kompresní poměr} -- Na běžném anglickém textu dosahuje metoda velmi dobrých výsledků, typicky zmenší soubor zhruba o 50 %.
\end{itemize}
\subsection{Nevýhody}
\begin{itemize}
	\item \textbf{Paměť} -- Paměťová náročnost roste s velikostí vstupu. Roste dokonce rychleji než u LZ78. Proto se při implementaci musí počítat s tím, že metoda vyčerpá přidělenou pamět.
	\item \textbf{Náhodná data} -- Podobně jako u předchozích metod, dochází při velké entropii dat k horší kompresi. Může dojít až k zvětšení souboru.
	
	
\end{itemize}

\section{Závěr analýzy}
Ladislav Zemek's avatar
Ladislav Zemek committed
Hlavním přínosem těchto metod je samotný princip na jakém fungují. Především pak LZ77 z které vznikla řada algoritmů, které se dnes využívají v praxi. Největší nevýhodou těchto algoritmů je špatný kompresní poměr na datech, ve kterých se neopakují delší řetězce znaků. Další nevýhodou LZ78 a LZW je velká náročnost na paměť. Jejich kompresní poměr je obvykle závislí na velikosti slovníku. Nicméně i přes tyto nevýhody se LZW v některých programech používá dodnes, protože je velmi rychlá a vhodná na klasický text.


\chapter{Implementace}
V této kapitole popisuji realizaci metod přímo v knihovně SCT. Zásadní věcí v implementaci těchto metod je reprezentace slovníků, ať už u komprese nebo dekomprese. Efektivní přidávání a hledání ve slovníku je zásadní pro efektivitu techto metod. Vysvětluji jaké parametry bude moci nastavit uživatel a jak ovlivní efektivitu nebo paměťovou náročnost. Jakým způsobem metody načítají data ze vstupu a jak zapisují triplety do souboru.  

\section{Řetězení}
V knihovně se používá princip řetězení (chaining). To znamená, že některé metody se dají zapojovat za sebe. Zde je ukázka kódu:
\begin{lstlisting}
ChainBuilder.create(io::openParse)
.chain(lz77::compress)
.chain(t2b)
.end(bytes -> io.saveObject(bytes, f2.toPath()))
.accept(f1.toPath());
\end{lstlisting}

Význam kódu není zatím relevantní, nicméně představuje použití komprese. Důležitý je princip, podle kterého je naimplementovaná metoda \classname{compress}. Hlavní podmínkou pro chainování jsou dva parametry metody. První je vstupní parametr a druhý výstupní. Respektive druhým parametrem je objekt consumer, který má za parametr datový typ výstupu. Ukázka kódu:
\begin{lstlisting}
public void compress(ByteBuffer byteBuffer,
Consumer<TripletSupplier> tripletSupplierConsumer) {...}
\end{lstlisting}

\newpage

Další možností je implementovat celý objekt tak, aby mohl být řetězený, pomocí implementace rozhraní \classname{Chainable<x, y>}, kde x je datový typ vstupního parametru a y datový typ pro výstup. Zde je hlavička třídy, kterou je možné řetězit:

\begin{lstlisting}
public abstract class TripletToByteConverter<T> 
   implements Chainable<TripletSupplier, List<byte[]>>
	{...}
\end{lstlisting}

Zde je vstupní parametr typu \classname{ByteBuffer}, to znamená že předchozí metoda v řetězci musela mít druhý parametr typu \classname{Consumer<ByteBuffer>}. Vystupním parametrem je \classname{TripletSuplier}, následující metoda tedy musí mít první parametr \classname{TripletSuplier}. V tomto připadě je to objekt \classname{t2b}, který je instancí třídy \classname{TripletToByteConverter}, která implementuje rozhraní \newline \classname{Chainable<TripletSupplier, List<byte[]>>}.

Uvnitř metody se pak volá třídní metoda consumera \classname{accept}, která posílá data do další metody. Objekt musí mít vždy implementovanou metodu \classname{setConsumer}, která nastavý consumera. Ten funguje stejne jako u metody.

\section{Načítání a zápis do souboru}
Načítání ze souboru se u komprese a dekomprese liší. Zatím co v prvním případě, načítám ze souboru  byty u dekomprese se jedná o načtení celého objektu ze souboru. Je tomu tak proto, že po kompresi se ukládá celé pole bytů jako objekt, aby bylo možné načítat uložené triplety. Dekomprese ukládá data do souboru po bytech, aby byl soubor stejný jako před komprimací.

Ladislav Zemek's avatar
Ladislav Zemek committed
O vše se stará třída \classname{FileIO}, která má jako parametr velikost, podle které rozděluje načítaný soubor na menší části a ty se následně zkomprimují a v podobě tripletů uloží do souboru. Zkomprimované soubory se načítají i dekomprimují jako celek, aby nedocházelo k narušení slovníků. Mohlo by se stát, že načteme menší nebo větší část tripletů než jaká byla vytvořena z jedné části pri kompresi. Takový případ by pak vedl k sestavení špatného slovníku, což by vedlo k chybám v dekompresi.

Ladislav Zemek's avatar
Ladislav Zemek committed
\section{Triplety}

Ladislav Zemek's avatar
Ladislav Zemek committed
Nedílnou součástí všech implementovaných kompresních metod jsou triplety. Jejich spracování a následný zápis je sprostředkován pomocí rozhraní\newline \classname{TripletSupplier}, které se vždy používá jen pro vytvoření anonymní vnitřní trídy, která implementuje metodu visit, jejímž parametrem je \classname{TripletProcessor}. Ten dokáže pomocí metody \classname{write} zapsat jednotlivé části tripletu do souboru.\newpage Zde je ukázka kódu:

Ladislav Zemek's avatar
Ladislav Zemek committed


\begin{lstlisting}
output.accept((TripletSupplier) new TripletSupplier() {
	@Override
	public void visit(TripletProcessor visitor) {
	visitor.write(nodeFieldId, num);
	visitor.write(characterFieldId, b);
	}
});
\end{lstlisting}
Ladislav Zemek's avatar
Ladislav Zemek committed
Metoda \classname{write} má dva parametry. Druhým parametrem je je hodnota zapisované složky tripletu. Prvním je objekt reprezentovaný třídou \classname{TripletFieldId}, který popisuje, kolik bitů má zapisovaná hodnota. \classname{TripletProcessor} se postará o správný zápis bitů. To je velká výhoda, protože u všech metod vždy dopředu vím, jaké největší číslo může být zapsáno.

 Například, pokud metoda pracuje se slovníkem, jehož maximálně počet frází je $ 2^{10}$. Není potřeba zapisovat indexy jako integer, který má 32 bitů. Pro zapsání jakéhokoliv indexu je potřeba nejvýše 11 bitů, zbytek jsou redundantní data. Tento postup v tomto případě ušetří na každém tripletu 22 bitů, což je velká úspora paměti, která výrazně zlepší kompresní poměr. Samotná implementace třídy \classname{TripletFieldId} umožnuje zapsat pouze číslo o velikosti 28 bitů. Tato skutečnost ale není omezující, protože slovník s takovým počtem frází ($ 2^{29} $ a více) by byl velmi neefektivní.
Ladislav Zemek's avatar
Ladislav Zemek committed
\section{Realizace LZ77}
\section{Realizace LZ78}
\section{Realizace LZW}
Ladislav Zemek's avatar
Ladislav Zemek committed

Ladislav Zemek's avatar
Ladislav Zemek committed
\chapter{Testovaní}

Ladislav Zemek's avatar
Ladislav Zemek committed
\begin{conclusion}
	%sem napište závěr Vaší práce
\end{conclusion}

\bibliographystyle{csn690}
Ladislav Zemek's avatar
Ladislav Zemek committed
\begin{thebibliography}{1}

\bibitem{komprese}
\textit{Komprese dat} [online]. [cit. 2018-04-22]. Wikipedie. Dostupné z:  \url{https://cs.wikipedia.org/wiki/Komprese_dat}

\bibitem{crush}
\textit{Crush} [online]. [cit. 2018-04-23]. Dostupné z: \url{https://sourceforge.net/projects/crush}

\bibitem{inspire}
\textit{LZ77 and LZ78} [online]. [cit. 2018-04-23]. Wikipedie. Dostupné z: \url{https://en.wikipedia.org/wiki/LZ77_and_LZ78}

\bibitem{lzwEN}
\textit{LZW} [online]. [cit. 2018-04-23]. Dostupné z: \url{https://www.prepressure.com/library/compression-algorithm/lzw}

\bibitem{req}
\textit{Analýza požadavků} [online]. [cit. 2018-04-23]. Wikipedie. Dostupné z: \url{https://cs.wikipedia.org/wiki/Anal\%C3\%BDza_po\%C5\%BEadavk\%C5\%AF}

Ladislav Zemek's avatar
Ladislav Zemek committed
\bibitem{vohoLZ77}
\textit{Algoritmus LZ77} [online]. [cit. 2018-04-25]. Dostupné z: \url{http://voho.eu/wiki/algoritmus-lz77/}

\bibitem{stringologyLZ78}
\textit{Algoritmus LZ78} [online]. [cit. 2018-04-28]. Dostupné z: \url{http://stringology.org/DataCompression/lz78/index_cs.html}

\bibitem{stringologyLZW}
\textit{Algoritmus LZW} [online]. [cit. 2018-04-28]. Dostupné z: \url{http://www.stringology.org/DataCompression/lzw-e/index_cs.html}

Ladislav Zemek's avatar
Ladislav Zemek committed
\end{thebibliography}
Ladislav Zemek's avatar
Ladislav Zemek committed

\appendix

\chapter{Seznam použitých zkratek}
% \printglossaries
\begin{description}
Ladislav Zemek's avatar
Ladislav Zemek committed
	\item[SCT] Small compression toolkit
	\item[LZ] Lempel-ziv
Ladislav Zemek's avatar
Ladislav Zemek committed
\end{description}


% % % % % % % % % % % % % % % % % % % % % % % % % % % % 
% % Tuto kapitolu z výsledné práce ODSTRAŇTE.
% % % % % % % % % % % % % % % % % % % % % % % % % % % % 
% 
% \chapter{Návod k~použití této šablony}
% 
% Tento dokument slouží jako základ pro napsání závěrečné práce na Fakultě informačních technologií ČVUT v~Praze.
% 
% \section{Výběr základu}
% 
% Vyberte si šablonu podle druhu práce (bakalářská, diplomová), jazyka (čeština, angličtina) a kódování (ASCII, \mbox{UTF-8}, \mbox{ISO-8859-2} neboli latin2 a nebo \mbox{Windows-1250}). 
% 
% V~české variantě naleznete šablony v~souborech pojmenovaných ve formátu práce\_kódování.tex. Typ může být:
% \begin{description}
% 	\item[BP] bakalářská práce,
% 	\item[DP] diplomová (magisterská) práce.
% \end{description}
% Kódování, ve kterém chcete psát, může být:
% \begin{description}
% 	\item[UTF-8] kódování Unicode,
% 	\item[ISO-8859-2] latin2,
% 	\item[Windows-1250] znaková sada 1250 Windows.
% \end{description}
% V~případě nejistoty ohledně kódování doporučujeme následující postup:
% \begin{enumerate}
% 	\item Otevřete šablony pro kódování UTF-8 v~editoru prostého textu, který chcete pro psaní práce použít -- pokud můžete texty s~diakritikou normálně přečíst, použijte tuto šablonu.
% 	\item V~opačném případě postupujte dále podle toho, jaký operační systém používáte:
% 	\begin{itemize}
% 		\item v~případě Windows použijte šablonu pro kódování \mbox{Windows-1250},
% 		\item jinak zkuste použít šablonu pro kódování \mbox{ISO-8859-2}.
% 	\end{itemize}
% \end{enumerate}
% 
% 
% V~anglické variantě jsou šablony pojmenované podle typu práce, možnosti jsou:
% \begin{description}
% 	\item[bachelors] bakalářská práce,
% 	\item[masters] diplomová (magisterská) práce.
% \end{description}
% 
% \section{Použití šablony}
% 
% Šablona je určena pro zpracování systémem \LaTeXe{}. Text je možné psát v~textovém editoru jako prostý text, lze však také využít specializovaný editor pro \LaTeX{}, např. Kile.
% 
% Pro získání tisknutelného výstupu z~takto vytvořeného souboru použijte příkaz \verb|pdflatex|, kterému předáte cestu k~souboru jako parametr. Vhodný editor pro \LaTeX{} toto udělá za Vás. \verb|pdfcslatex| ani \verb|cslatex| \emph{nebudou} s~těmito šablonami fungovat.
% 
% Více informací o~použití systému \LaTeX{} najdete např. v~\cite{wikilatex}.
% 
% \subsection{Typografie}
% 
% Při psaní dodržujte typografické konvence zvoleného jazyka. České \uv{uvozovky} zapisujte použitím příkazu \verb|\uv|, kterému v~parametru předáte text, jenž má být v~uvozovkách. Anglické otevírací uvozovky se v~\LaTeX{}u zadávají jako dva zpětné apostrofy, uzavírací uvozovky jako dva apostrofy. Často chybně uváděný symbol "{} (palce) nemá s~uvozovkami nic společného.
% 
% Dále je třeba zabránit zalomení řádky mezi některými slovy, v~češtině např. za jednopísmennými předložkami a spojkami (vyjma \uv{a}). To docílíte vložením pružné nezalomitelné mezery -- znakem \texttt{\textasciitilde}. V~tomto případě to není třeba dělat ručně, lze použít program \verb|vlna|.
% 
% Více o~typografii viz \cite{kobltypo}.
% 
% \subsection{Obrázky}
% 
% Pro umožnění vkládání obrázků je vhodné použít balíček \verb|graphicx|, samotné vložení se provede příkazem \verb|\includegraphics|. Takto je možné vkládat obrázky ve formátu PDF, PNG a JPEG jestliže používáte pdf\LaTeX{} nebo ve formátu EPS jestliže používáte \LaTeX{}. Doporučujeme preferovat vektorové obrázky před rastrovými (vyjma fotografií).
% 
% \subsubsection{Získání vhodného formátu}
% 
% Pro získání vektorových formátů PDF nebo EPS z~jiných lze použít některý z~vektorových grafických editorů. Pro převod rastrového obrázku na vektorový lze použít rasterizaci, kterou mnohé editory zvládají (např. Inkscape). Pro konverze lze použít též nástroje pro dávkové zpracování běžně dodávané s~\LaTeX{}em, např. \verb|epstopdf|.
% 
% \subsubsection{Plovoucí prostředí}
% 
% Příkazem \verb|\includegraphics| lze obrázky vkládat přímo, doporučujeme však použít plovoucí prostředí, konkrétně \verb|figure|. Například obrázek \ref{fig:float} byl vložen tímto způsobem. Vůbec přitom nevadí, když je obrázek umístěn jinde, než bylo původně zamýšleno -- je tomu tak hlavně kvůli dodržení typografických konvencí. Namísto vynucování konkrétní pozice obrázku doporučujeme používat odkazování z~textu (dvojice příkazů \verb|\label| a \verb|\ref|).
% 
% \begin{figure}\centering
% 	\includegraphics[width=0.5\textwidth, angle=30]{cvut-logo-bw}
% 	\caption[Příklad obrázku]{Ukázkový obrázek v~plovoucím prostředí}\label{fig:float}
% \end{figure}
% 
% \subsubsection{Verze obrázků}
% 
% % Gnuplot BW i barevně
% Může se hodit mít více verzí stejného obrázku, např. pro barevný či černobílý tisk a nebo pro prezentaci. S~pomocí některých nástrojů na generování grafiky je to snadné.
% 
% Máte-li například graf vytvořený v programu Gnuplot, můžete jeho černobílou variantu (viz obr. \ref{fig:gnuplot-bw}) vytvořit parametrem \verb|monochrome dashed| příkazu \verb|set term|. Barevnou variantu (viz obr. \ref{fig:gnuplot-col}) vhodnou na prezentace lze vytvořit parametrem \verb|colour solid|.
% 
% \begin{figure}\centering
% 	\includegraphics{gnuplot-bw}
% 	\caption{Černobílá varianta obrázku generovaného programem Gnuplot}\label{fig:gnuplot-bw}
% \end{figure}
% 
% \begin{figure}\centering
% 	\includegraphics{gnuplot-col}
% 	\caption{Barevná varianta obrázku generovaného programem Gnuplot}\label{fig:gnuplot-col}
% \end{figure}
% 
% 
% \subsection{Tabulky}
% 
% Tabulky lze zadávat různě, např. v~prostředí \verb|tabular|, avšak pro jejich vkládání platí to samé, co pro obrázky -- použijte plovoucí prostředí, v~tomto případě \verb|table|. Například tabulka \ref{tab:matematika} byla vložena tímto způsobem.
% 
% \begin{table}\centering
% 	\caption[Příklad tabulky]{Zadávání matematiky}\label{tab:matematika}
% 	\begin{tabular}{|l|l|c|c|}\hline
% 		Typ		& Prostředí		& \LaTeX{}ovská zkratka	& \TeX{}ovská zkratka	\tabularnewline \hline \hline
% 		Text		& \verb|math|		& \verb|\(...\)|	& \verb|$...$|		\tabularnewline \hline
% 		Displayed	& \verb|displaymath|	& \verb|\[...\]|	& \verb|$$...$$|	\tabularnewline \hline
% 	\end{tabular}
% \end{table}
% 
% % % % % % % % % % % % % % % % % % % % % % % % % % % % 

\chapter{Obsah přiloženého CD}

%upravte podle skutecnosti

\begin{figure}
	\dirtree{%
		.1 readme.txt\DTcomment{stručný popis obsahu CD}.
		.1 exe\DTcomment{adresář se spustitelnou formou implementace}.
		.1 src.
		.2 impl\DTcomment{zdrojové kódy implementace}.
		.2 thesis\DTcomment{zdrojová forma práce ve formátu \LaTeX{}}.
		.1 text\DTcomment{text práce}.
		.2 thesis.pdf\DTcomment{text práce ve formátu PDF}.
		.2 thesis.ps\DTcomment{text práce ve formátu PS}.
	}
\end{figure}

\end{document}