This shows you the differences between two versions of the page.
sd-ca:teme:teme-04 [2015/04/29 13:26] cosmin.boaca |
sd-ca:teme:teme-04 [2015/05/26 09:25] (current) alexandru.farcasanu [Tema 4] |
||
---|---|---|---|
Line 1: | Line 1: | ||
- | ===== Tema 4 ===== | + | ====== Tema 4 ====== |
- | **Responsabili:** | + | Termen de predare: **Luni, 25 Mai 2015, ora 23:55** |
- | *[[cosmin.boaca1994@gmail.com| Cosmin Boacă]] | + | Deadline hard: **Joi, 28 Mai, ora 23:55** |
- | *[[ciprianfarcasanu@gmail.com| Alex Fărcășanu]] | + | |
- | <hidden> | + | <note important> |
+ | **1 Mai** Adaugat precizare legata de reprezentantul unui nod. Actualizat arhiva de teste. | ||
- | ==== Obiective ==== | + | **23 Mai** Modificare deadline: 25 Mai. |
+ | |||
+ | **24 Mai** Update script testare: limita de timp a fost marita la 100 de secunde. | ||
+ | </note> | ||
+ | ===== Obiective ===== | ||
În urma realizării acestei teme, studentul va fi capabil: | În urma realizării acestei teme, studentul va fi capabil: | ||
Line 15: | Line 19: | ||
* să folosească algoritmii de compresie pentru reprezentarea compactă a imaginilor în format bitmap | * să folosească algoritmii de compresie pentru reprezentarea compactă a imaginilor în format bitmap | ||
- | ==== Cunoştinţe necesare ==== | + | ===== Cunoştinţe necesare ===== |
Pentru a putea rezolva această temă, studentul trebuie să fie familiar cu următoarele noţiuni: | Pentru a putea rezolva această temă, studentul trebuie să fie familiar cu următoarele noţiuni: | ||
Line 22: | Line 26: | ||
* codificarea Huffman - o documentaţie accesibilă poate fi găsită [[sd-ca:teme:doc-tema04|aici]]. | * codificarea Huffman - o documentaţie accesibilă poate fi găsită [[sd-ca:teme:doc-tema04|aici]]. | ||
- | ==== Cerinţă ==== | + | ===== Cerinţă ===== |
- | === Enunt === | + | ==== Enunt ==== |
Sarcina voastră este să implementaţi un program care să comprime / decomprime un fişier arbitrar, aplicând algoritmul Huffman. [[sd-ca:teme:doc-tema04|Aici]] este descris, pe scurt, algoritmul şi aveţi şi un exemplu pentru compresia unui şir de caractere (fişier text). Algoritmul funcţionează pentru orice tip de fişier (nu neapărat text): se consideră fişierul ca un şir de octeţi. | Sarcina voastră este să implementaţi un program care să comprime / decomprime un fişier arbitrar, aplicând algoritmul Huffman. [[sd-ca:teme:doc-tema04|Aici]] este descris, pe scurt, algoritmul şi aveţi şi un exemplu pentru compresia unui şir de caractere (fişier text). Algoritmul funcţionează pentru orice tip de fişier (nu neapărat text): se consideră fişierul ca un şir de octeţi. | ||
- | === Executabil === | + | ==== Executabil ==== |
Programul vostru va trebui să primească la intrare numele unui fişier şi o serie de opţiuni, în felul următor: | Programul vostru va trebui să primească la intrare numele unui fişier şi o serie de opţiuni, în felul următor: | ||
Line 48: | Line 52: | ||
Astfel, daca numele fişierului este ''poza.bmp'', fişierul comprimat se va numi ''poza.bmp.cmp'', iar fişierul decomprimat ''decompressed_poza.bmp'' | Astfel, daca numele fişierului este ''poza.bmp'', fişierul comprimat se va numi ''poza.bmp.cmp'', iar fişierul decomprimat ''decompressed_poza.bmp'' | ||
- | === Compresie === | + | ==== Compresie ==== |
Se va considera şirul de octeti din fişier ca pe un şir de simboluri. Acestui şir de simboluri va trebui să-i aplicaţi o codificare Huffman, (a se vedea documentaţia pusă la dispoziţie) asociind fiecărui simbol o probabilitate de apariţie egală cu frecvenţa simbolului în fişier (deci va trebui să parcurgeţi la început întregul fişier pentru a determina aceste probabilităţi). Pentru reprezentarea cozii prioritare din care veţi extrage nodurile cu costul cel mai mic, veţi folosi o structură de heap. Pentru heap, veţi avea nevoie de o funcţie care compară două noduri între ele, şi veţi folosi următoarele reguli (presupunem ca prioritatea este maximă în vârful cozii): | Se va considera şirul de octeti din fişier ca pe un şir de simboluri. Acestui şir de simboluri va trebui să-i aplicaţi o codificare Huffman, (a se vedea documentaţia pusă la dispoziţie) asociind fiecărui simbol o probabilitate de apariţie egală cu frecvenţa simbolului în fişier (deci va trebui să parcurgeţi la început întregul fişier pentru a determina aceste probabilităţi). Pentru reprezentarea cozii prioritare din care veţi extrage nodurile cu costul cel mai mic, veţi folosi o structură de heap. Pentru heap, veţi avea nevoie de o funcţie care compară două noduri între ele, şi veţi folosi următoarele reguli (presupunem ca prioritatea este maximă în vârful cozii): | ||
* dacă probabilitate(Nod1) < probabilitate(Nod2), atunci Nod1 > Nod2 (ordinea se inversează), şi viceversa. | * dacă probabilitate(Nod1) < probabilitate(Nod2), atunci Nod1 > Nod2 (ordinea se inversează), şi viceversa. | ||
* dacă probabilitate(Nod1) = probabilitate(Nod2), atunci ne uităm la înălţimea nodului în arbore, şi dacă înălţime(Nod1) < înălţime(Nod2), atunci Nod1 > Nod2 (ordinea se inversează), şi viceversa. | * dacă probabilitate(Nod1) = probabilitate(Nod2), atunci ne uităm la înălţimea nodului în arbore, şi dacă înălţime(Nod1) < înălţime(Nod2), atunci Nod1 > Nod2 (ordinea se inversează), şi viceversa. | ||
- | * dacă probabilitate(Nod1) = probabilitate(Nod2), şi înălţime(Nod1) = înălţime(Nod2), atunci Nod1 = Nod2. | + | * dacă probabilitate(Nod1) = probabilitate(Nod2), şi înălţime(Nod1) = înălţime(Nod2), atunci ne uitam la reprezentantii nodurilor (vezi definitie mai jos). Daca reprezentant(Nod1) < reprezentant(Nod2) atunci Nod1 > Nod2 (ordinea se inversează), si viceversa. |
- | Practic, aceste reguli specifică ordinea în care se vor scoate elementele din coadă: se preferă cele cu probabilitate mică, iar dacă sunt mai multe cu aceeaşi probabilitate, le vom lua pe cele de pe nivelurile cele mai mici, pentru a păstra echilibrat arborele Huffman. | + | Practic, aceste reguli specifică ordinea în care se vor scoate elementele din coadă: se preferă cele cu probabilitate mică, iar dacă sunt mai multe cu aceeaşi probabilitate, le vom lua pe cele de pe nivelurile cele mai mici, pentru a păstra echilibrat arborele. Daca si inaltimile sunt egale, luam in considerare reprezentantul. Astfel vom avem un mod unic de a scoate elementele din coada prioritara. |
- | === Serializare === | + | **Reprezentantul** unui nod se defineste in felul urmator: |
+ | * daca nodul este frunza, reprezentantul este caracterul(octetul) asociat frunzei respective (In exemplul de [[sd-ca:teme:doc-tema04|aici]] reprezentantii tuturor frunzelor sunt 'a', 'n', ' ', 'r', 'e', 'm'). | ||
+ | * altfel, reprezentant(Nod) = minim {reprezentant(Nod_stanga), reprezentant(Nod_dreapta)} unde Nod_stanga si Nod_dreapta sunt fii nodului Nod. | ||
+ | |||
+ | ==== Serializare ==== | ||
Arborele Huffman construit va fi necesar şi in pasul de decompresie, astfel că este nevoie sa fie salvat in fişier. Reprezentarea arborelui în fişier trebuie să fie cel de vector de structuri de forma: | Arborele Huffman construit va fi necesar şi in pasul de decompresie, astfel că este nevoie sa fie salvat in fişier. Reprezentarea arborelui în fişier trebuie să fie cel de vector de structuri de forma: | ||
Line 77: | Line 85: | ||
* ''value'' reprezintă valorea simbolului (valoarea octetului) din frunza arborelui; | * ''value'' reprezintă valorea simbolului (valoarea octetului) din frunza arborelui; | ||
* ''childData'' reprezintă informaţii despre descendenţi, în cazul nodurilor neterminale; leftChild şi rightChild reprezintă indecşi în vectorul de structuri (indexarea porneşte de la 0), şi indică structurile ce codifică descendenţii stâng, respectiv drept, ai nodului. Trebuie remarcat faptul că într-un arbore Huffman, un nod fie este terminal, fie are exact doi descendenţi, deci cele două câmpuri vor fi valide simultan. De asemenea, structura de pe poziţia 0 din vector va fi rădăcina arborelui Huffman. | * ''childData'' reprezintă informaţii despre descendenţi, în cazul nodurilor neterminale; leftChild şi rightChild reprezintă indecşi în vectorul de structuri (indexarea porneşte de la 0), şi indică structurile ce codifică descendenţii stâng, respectiv drept, ai nodului. Trebuie remarcat faptul că într-un arbore Huffman, un nod fie este terminal, fie are exact doi descendenţi, deci cele două câmpuri vor fi valide simultan. De asemenea, structura de pe poziţia 0 din vector va fi rădăcina arborelui Huffman. | ||
+ | |||
+ | <note tip> | ||
+ | Observam ca reprezentantul unui nod nu este salvat in fisier deoarece nu mai avem nevoie de el. Acesta a fost folosit pentru a garanta o secventa unica de extragere a nodurilor din coada prioritara. | ||
+ | </note> | ||
După ce este scris arborele Huffman se scrie şi dimensiunea fişierului de intrare ca un element de tip întreg fara semn(necesar la decomprimare pentru a şti câte simboluri trebuie decodificate). Urmează simbolurile scrise codificat în ordinea în care au fost citite din fişierul original. În urma aplicării arborelui Huffman asupra simbolurilor, se obţine un şir de biţi. | După ce este scris arborele Huffman se scrie şi dimensiunea fişierului de intrare ca un element de tip întreg fara semn(necesar la decomprimare pentru a şti câte simboluri trebuie decodificate). Urmează simbolurile scrise codificat în ordinea în care au fost citite din fişierul original. În urma aplicării arborelui Huffman asupra simbolurilor, se obţine un şir de biţi. | ||
Line 95: | Line 107: | ||
* 10010111<sub>(2)</sub> = 151<sub>(10)</sub> | * 10010111<sub>(2)</sub> = 151<sub>(10)</sub> | ||
* 10111110<sub>(2)</sub> = 190<sub>(10)</sub> | * 10111110<sub>(2)</sub> = 190<sub>(10)</sub> | ||
- | * **00**010001<sub>(2)</sub> = 17<sub>(10)</sub>. **Atentie:** in cazul in care numarul total de biti nu este multiplu de 8, se vor adauga biti de **0** ca padding. | + | * **00**010001<sub>(2)</sub> = 17<sub>(10)</sub>. |
- | TODO: atentionare - folosire doar unsigned vars. | + | <note warning> |
- | === Format fisier comprimat === | + | **Atentie:** in cazul in care numarul total de biti nu este multiplu de 8, se vor adauga biti de **0** ca padding. |
+ | |||
+ | Pentru operaţiile pe biţi folosiţi **DOAR variabile unsigned**. | ||
+ | |||
+ | Recomandarea noastră este să folosiţi tipurile de date **uint8_t** / **uint16_t** / **uint32_t** după caz. | ||
+ | |||
+ | </note> | ||
+ | |||
+ | ==== Format fisier comprimat ==== | ||
Conform celor spuse mai sus, formatul unui fisier comprimat trebuie sa arate astfel (in aceasta ordine): | Conform celor spuse mai sus, formatul unui fisier comprimat trebuie sa arate astfel (in aceasta ordine): | ||
Line 105: | Line 125: | ||
^Camp|**K**| **V** | **N** | **L**| | ^Camp|**K**| **V** | **N** | **L**| | ||
^Semnificatie|numarul de noduri din arbore| arborele serializat | dimensiunea fisierului original | fisier comprimat| | ^Semnificatie|numarul de noduri din arbore| arborele serializat | dimensiunea fisierului original | fisier comprimat| | ||
- | ^Tip/Dimensiune | 1 * uint16_t | K * HuffmanSerializedNode | 1 * uint32_t | sir de biti de lungime variabila | | + | ^Tip/Dimensiune | 1 * uint16_t | K * HuffmanSerializedNode | 1 * uint32_t | sir de biti ce reprezinta fisierul comprimat | |
- | ==== Testare ==== | + | ===== Testare ===== |
Testarea temei se va face folosind [[https://vmchecker.cs.pub.ro/ui/#SD|vmchecker]]. | Testarea temei se va face folosind [[https://vmchecker.cs.pub.ro/ui/#SD|vmchecker]]. | ||
Line 118: | Line 138: | ||
Puteţi descărca checker-ul pentru testare locală sub linux de [[http://ocw.cs.pub.ro/courses/_media/sd-ca/teme/checker.zip|aici]]. | Puteţi descărca checker-ul pentru testare locală sub linux de [[http://ocw.cs.pub.ro/courses/_media/sd-ca/teme/checker.zip|aici]]. | ||
+ | |||
+ | <note> | ||
+ | Folositi flag-ul de optimizare -O2 la compilare. | ||
+ | </note> | ||
- | ==== Alte precizari ==== | + | ===== Alte precizari ===== |
+ | * Atunci cand se construieste un nod nou, nodul cel mai prioritar din coada va deveni fiul **stang** al noului nod. | ||
+ | * Serializarea arborelui se va face printr-o parcurgere in **preordine**. | ||
* Se recomanda ca atat citirea cat si scrierea sa se realizeze cu functiile fread si fwrite. | * Se recomanda ca atat citirea cat si scrierea sa se realizeze cu functiile fread si fwrite. | ||
* Se recomanda folosirea tipurile de date uint8_t, uint16_t si uint32_t in cazul citirii si scrierii din fisiere. | * Se recomanda folosirea tipurile de date uint8_t, uint16_t si uint32_t in cazul citirii si scrierii din fisiere. | ||
Line 130: | Line 156: | ||
* Puteți folosi funcționalități ale C++, cu excepția claselor care implementeaza direct funcționalitatea cerută (cum ar fi priority_queue din STL). | * Puteți folosi funcționalități ale C++, cu excepția claselor care implementeaza direct funcționalitatea cerută (cum ar fi priority_queue din STL). | ||
- | </hidden> |