This shows you the differences between two versions of the page.
sd-ca:teme:tema2-2020 [2020/03/26 19:42] gabriel_danut.matei |
sd-ca:teme:tema2-2020 [2020/04/11 12:07] (current) gabriel_danut.matei |
||
---|---|---|---|
Line 1: | Line 1: | ||
- | {{:../figures/out/hash1.png| Adaugare}} | + | ====== Tema 2 - Count-distinct problem ====== |
+ | |||
+ | ** Responsabili: ** | ||
+ | *[[lucaistrate@gmail.com|Luca Istrate]] | ||
+ | *[[matei.danut.dm@gmail.com|Dănuţ Matei]] | ||
+ | |||
+ | ** Data publicării : 26 martie, ora: 21:00 ** | ||
+ | |||
+ | ** Deadline: 17 aprilie, ora 23:55 ** | ||
+ | |||
+ | == Modificări şi actualizări == | ||
+ | * **27 martie, ora 01:30** - adăugat clarificari in sectiunea **Introducere** | ||
+ | * **27 martie, ora 21:05** - adăugat **checker** in **enunt** si pe **vmchecker** | ||
+ | * **27 martie, ora 23:40** - modificat fisier **Makefile** din **checker** | ||
+ | * **29 martie, ora 16:00** - adăugat precizari in **cerinta II** legate de **dimensiunea Hashtable-ului** | ||
+ | * **29 martie, ora 18:40** - adăugat corectare in **cerinta III** legata de **definitia lui m** | ||
+ | * **29 martie, ora 19:30** - modificat fisier **check.sh** din **checker**; acum partea de **valgrind** are comportamentul corect pentru toate cerintele | ||
+ | * **3 aprilie, ora 19:10** - reformulat **cerinta III** pentru a o face mai usor de inteles | ||
+ | * **11 aprilie, ora 12:05** - actualizat **deadline** | ||
+ | |||
<hidden> | <hidden> | ||
- | ====== Count-distinct problem ====== | + | * **26 martie, ora 21:00** - adăugat **checker** |
+ | </hidden> | ||
+ | ===== Obiective ===== | ||
+ | |||
+ | În urma realizării acestei teme: | ||
+ | * veţi învăţa să lucraţi cu Dictionare | ||
+ | * vă veţi familiariza cu rezolvarea unei probleme reale prin structuri de date din ce in ce mai eficiente | ||
===== Introducere ===== | ===== Introducere ===== | ||
**Problema estimarii cardinalitatii** (a numararii elementelor distincte) este, in esenta, gasirea numarului de elemente unice dintr-o colectie de elemente care se pot repeta. | **Problema estimarii cardinalitatii** (a numararii elementelor distincte) este, in esenta, gasirea numarului de elemente unice dintr-o colectie de elemente care se pot repeta. | ||
+ | <note important> | ||
+ | Pentru cerintele **I** si **II**, vom rezolva o problema si mai restrictiva: gasirea **numarului de aparitii** pentru fiecare element. Pentru cerinta **III**, vom vedea ca acest lucru e mai greu realizabil cand vine vorba de volume mari de date si, de aceea, ne vom rezuma la **gasirea numarului de elemente distincte**.</note> | ||
+ | |||
+ | |||
+ | **Conceptual, ne referim la:** | ||
+ | |||
+ | INPUT: | ||
+ | |||
+ | ''1, 34, 2, 2, 2, 3'' | ||
+ | |||
+ | OUTPUT: | ||
+ | |||
+ | **Pentru cerintele I si II:** | ||
+ | |||
+ | ''1 - 1'' | ||
+ | |||
+ | ''2 - 3'' | ||
+ | |||
+ | ''3 - 1'' | ||
+ | |||
+ | ''34 - 1'' | ||
+ | |||
+ | **Pentru cerinta III:** | ||
+ | |||
+ | ''Exista 4 elemente distincte'' | ||
- | Pentru primele doua subpuncte, vom rezolva o problema si mai restrictiva: gasirea **numarului de aparitii** pentru fiecare element. Pentru restul, vom vedea ca acest lucru e mai greu realizabil cand vine vorba de volume mari de date si, de aceea, ne vom rezuma la gasirea numarului de elemente distincte. | + | <note warning>**Fiecare** dintre cele **3** cerinte se va implementa intr-un **fisier separat**.</note> |
- | ===== I. Vector de frecventa ===== | + | ===== I. Vector de frecventa - 25p ===== |
La intrare se dau numere intre **0** si **2000000**. Gasiti numarul de aparitii ale fiecarui element, utilizand un **vector de frecventa**. | La intrare se dau numere intre **0** si **2000000**. Gasiti numarul de aparitii ale fiecarui element, utilizand un **vector de frecventa**. | ||
Line 15: | Line 66: | ||
Un vector de frecventa este un vector care are pe pozitia **i** //numarul de aparitii// ale elementului **i**. | Un vector de frecventa este un vector care are pe pozitia **i** //numarul de aparitii// ale elementului **i**. | ||
- | {{:../figures/out/freq.png| Vector de frecventa}} | + | {{:sd-ca:teme:freq.png|}} |
//Se garanteaza ca numarul de aparitii ale oricarui element este mai mic decat **256**.// | //Se garanteaza ca numarul de aparitii ale oricarui element este mai mic decat **256**.// | ||
- | ===== II. Hashtable cu open addressing ===== | + | ===== II. Hashtable cu open addressing - 25p ===== |
La intrare se dau siruri de caractere. Gasiti numarul de aparitii ale fiecarui sir folosind un Hashtable cu politica de rezolvare a conflictelor de tip **open addressing** prin **linear probing**. | La intrare se dau siruri de caractere. Gasiti numarul de aparitii ale fiecarui sir folosind un Hashtable cu politica de rezolvare a conflictelor de tip **open addressing** prin **linear probing**. | ||
Line 25: | Line 76: | ||
Aceasta politica presupune ca, in momentul in care bucketul unde trebuie realizata insertia este deja ocupat, //se va cauta secvential o pozitie libera incepand cu bucketul urmator//. | Aceasta politica presupune ca, in momentul in care bucketul unde trebuie realizata insertia este deja ocupat, //se va cauta secvential o pozitie libera incepand cu bucketul urmator//. | ||
- | {{:../figures/out/hash1.png| Adaugare}} | + | {{:sd-ca:teme:hash1.png|}} |
Evident, daca si aceasta pozitie este ocupata, vom cauta prima pozitie libera in continuare. | Evident, daca si aceasta pozitie este ocupata, vom cauta prima pozitie libera in continuare. | ||
- | {{:../figures/out/hash2.png| Adaugare cu cautare de loc liber}} | + | {{:sd-ca:teme:hash2.png|}} |
Daca se va ajunge la finalul listei de bucketuri, se va continua de la inceput. | Daca se va ajunge la finalul listei de bucketuri, se va continua de la inceput. | ||
- | {{:../figures/out/hash3.png| Cautarea continua circular}} | + | {{:sd-ca:teme:hash3.png|}} |
- | //Se garanteaza existenta a cel putin unui bucket liber in momentul fiecarei operatii de insertie.// | + | //Se garanteaza existenta a cel putin unui bucket liber in momentul fiecarei operatii de insertie.// **Pentru a satisface aceasta conditie, o idee ar fi ca dimensiunea Hashtable-ului sa fie egala cu numarul de siruri existente in fisierul de intrare.** |
Evident, daca in momentul unei operatii de selectie nu gasim cheia in bucketul in care ne-am astepta, vom continua cautarea secvential, aplicand un procedeu similar cu cel din momentul insertiei. | Evident, daca in momentul unei operatii de selectie nu gasim cheia in bucketul in care ne-am astepta, vom continua cautarea secvential, aplicand un procedeu similar cu cel din momentul insertiei. | ||
- | //Se garanteaza ca lungimea maxima a oricarui este maxim **100** de caractere.// | + | //Se garanteaza ca lungimea maxima a oricarui sir este maxim **100** de caractere.// |
//Se garanteaza ca numarul de aparitii ale oricarui element este mai mic decat **256**.// | //Se garanteaza ca numarul de aparitii ale oricarui element este mai mic decat **256**.// | ||
- | ===== III. Estimatori probabilistici ===== | + | ===== III. Estimatori probabilistici - 30p ===== |
In cerintele anterioare am observat ca putem calcula cu exactitate numarul de elemente distincte (si numarul lor de aparitii) retinand, intr-un fel sau altul, fiecare element unic (ca pozitie intr-un vector, respectiv ca cheie intr-un hashtable). Din pacate, in aplicatiile din lumea reala, //aceasta strategie nu este sustenabila//. | In cerintele anterioare am observat ca putem calcula cu exactitate numarul de elemente distincte (si numarul lor de aparitii) retinand, intr-un fel sau altul, fiecare element unic (ca pozitie intr-un vector, respectiv ca cheie intr-un hashtable). Din pacate, in aplicatiile din lumea reala, //aceasta strategie nu este sustenabila//. | ||
Line 60: | Line 111: | ||
In ilustrarea functionarii algoritmului **HyperLogLog**, vom incepe de la o serie de principii simple pe care le vom pune cap la cap, ajungand la descrierea algoritmului final. | In ilustrarea functionarii algoritmului **HyperLogLog**, vom incepe de la o serie de principii simple pe care le vom pune cap la cap, ajungand la descrierea algoritmului final. | ||
+ | |||
+ | <note important>Sectiunile 1 si 2 sunt prezentate pentru a intelege de ce functioneaza HyperLogLog. Pentru a rezolva tema, trebuie sa implementati **doar algoritmul final (descris in sectiunea 3)**.</note> | ||
==== 1. Probabilistic counting ==== | ==== 1. Probabilistic counting ==== | ||
Line 71: | Line 124: | ||
Similar, probabilitatea ca numarul sa inceapa cu **3** biti **0** este **1/8**. Astfel, pentru a intalni un numar care sa inceapa cu **3** biti **0**, //va trebui sa generam, in medie, **8** numere//. | Similar, probabilitatea ca numarul sa inceapa cu **3** biti **0** este **1/8**. Astfel, pentru a intalni un numar care sa inceapa cu **3** biti **0**, //va trebui sa generam, in medie, **8** numere//. | ||
- | {{:../figures/out/probcount1.png| Probabilitatea de a generea 3 0 consecutivi}} | + | {{:sd-ca:teme:probcount1.png|}} |
- | Privind aceasta observatie in sens invers, daca am generat numere aleatoare si secventa cea mai lunga de **0** de la inceputul oricarui numar a fost de lungime **3**, atunci avem urmatoarele posibilitati: - am generat //cel putin **8** numere// - am avut noroc si a trebuit sa generam //mai putin de 8 numere// | + | Privind aceasta observatie in sens invers, daca am generat numere aleatoare si secventa cea mai lunga de **0** de la inceputul oricarui numar a fost de lungime **3**, atunci avem doua posibilitati: |
+ | |||
+ | - am generat //cel putin **8** numere// | ||
+ | |||
+ | - am avut noroc si a trebuit sa generam //mai putin de 8 numere// | ||
Evident, pentru valori mici precum **2** sau **3** biti consecutivi, exista o sansa semnificativa sa generam numarul mai rapid (chiar din prima incercare), dar cu cat valorile devin mai mari, cu atat scade aceasta sansa. | Evident, pentru valori mici precum **2** sau **3** biti consecutivi, exista o sansa semnificativa sa generam numarul mai rapid (chiar din prima incercare), dar cu cat valorile devin mai mari, cu atat scade aceasta sansa. | ||
Line 83: | Line 140: | ||
==== 2. LogLog ==== | ==== 2. LogLog ==== | ||
- | Daca vrem sa imbunatatim performanta algoritmului nostru va trebui sa: - Atenuam efectul negativ al generarii rapide unui numar cu multi biti de **0** initiali - Oferim estimari //mai granulare// decat **puterile lui 2** | + | Daca vrem sa imbunatatim performanta algoritmului nostru va trebui sa: |
- | {{:../figures/from_internet/2n_table.png| Pentru puteri mari intervalul estimarii devine prea lat}} | + | - Atenuam efectul negativ al generarii rapide unui numar cu multi biti de **0** initiali |
+ | |||
+ | - Oferim estimari //mai granulare// decat **puterile lui 2** | ||
+ | |||
+ | {{:sd-ca:teme:2n_table.png|}} | ||
O idee de rezolvare a primei probleme este sa impartim numerele in mai multe **bucketuri**. Cea mai usoara modalitate de a face acest lucru este sa impartim fiecare numar in 2 parti: //prima parte// va fi folosita pentru a determina bucketul, iar //a doua// va fi folosita ca pana acum. | O idee de rezolvare a primei probleme este sa impartim numerele in mai multe **bucketuri**. Cea mai usoara modalitate de a face acest lucru este sa impartim fiecare numar in 2 parti: //prima parte// va fi folosita pentru a determina bucketul, iar //a doua// va fi folosita ca pana acum. | ||
- | {{:../figures/from_internet/buckets.png| Calculare bucket-urilor}} | + | {{:sd-ca:teme:buckets.png|}} |
Singura diferenta fata de metoda precedenta este ca acum vom face maximul de zerouri consecutive //pentru fiecare bucket// si nu pentru toate numerele. | Singura diferenta fata de metoda precedenta este ca acum vom face maximul de zerouri consecutive //pentru fiecare bucket// si nu pentru toate numerele. | ||
Line 97: | Line 158: | ||
==== 3. HyperLogLog ==== | ==== 3. HyperLogLog ==== | ||
- | Pentru a aduce algoritmul in forma finala, va trebui sa mai facem cateva ajustari matematice la procedeul descris anterior. | + | Recapituland ce am prezentat in sectiunile precedente, in cadrul algoritmului HyperLogLog avem 3 etape: |
- | In primul rand, vom folosi o medie similara cu **media armonica** in loc de cea geometrica. | + | **1)** stabilim numarul total de bucketuri **m**, apoi initializam cu 0 un vector **M** de dimensiune **m**. |
+ | <note important>Alegerea lui m este diferita de la caz la caz. In contextul problemei curente, puteti sa folositi valoarea m = $2^{11}$, insa exista si alte variante posibile.</note> | ||
- | In al doilea rand, vom utiliza un **factor de atenuare** alfa, pentru a imbunatati eroarea de aproximare. | + | **2)** pentru fiecare numar citit de la intrare: |
- | {{:../figures/from_internet/estimare.png| Estimarea finala}} | + | - ii calculam hash-ul cu o functie de hash pentru numere intregi |
- | **E** reprezinta //estimarea finala// | + | - pe baza primilor $\log_2(m)$ biti din hash determinam bucketul in care se afla (din cele $m$ bucketuri posibile); notam numarul bucketului cu **j** |
- | **m** reprezinta //numarul total de bucketuri// | + | - calculam numarul de biti 0 initiali din restul hash-ului; notam acest numar cu **x** |
- | **Z** reprezinta //media//, calculata dupa urmatoarea formula: | + | - M[j] = max(M[j], x) |
- | {{:../figures/from_internet/media.png| Media}} | + | **3)** agregam valorile din toate bucketurile |
- | **alfa_m** reprezinta //factorul de atenuare//, calculat in functie de **m** dupa urmatoarea formula: | ||
- | {{:../figures/from_internet/alfa.png| Factorul de atenuare}} | + | In sectiunea precedenta, am mentionat ca pentru a agrega valorile din fiecare bucket, folosim media geometrica. Pentru a implementa HyperLogLog, vom folosi in locul ei urmatorea medie: |
- | ==== Referinte ==== | + | {{:sd-ca:teme:media.png|}} |
- | * https:%%//%%en.wikipedia.org/wiki/Count-distinct_problem | + | Ca exemplu, pentru bucketul evidentiat cu verde, **j = 6**, iar **M[j] = 2** |
- | * https:%%//%%www.omnicoreagency.com/youtube-statistics | + | |
- | * https:%%//%%en.wikipedia.org/wiki/HyperLogLog | + | |
- | * https:%%//%%en.wikipedia.org/wiki/Linear_probing | + | |
- | * https:%%//%%stackoverflow.com/questions/12327004/how-does-the-hyperloglog-algorithm-work | + | |
+ | {{:sd-ca:teme:buckets.png|}} | ||
- | </hidden> | + | Avand aceasta medie **Z**, raspunsul final **E** (numarul de elemente distincte intalnite) va fi dat de urmatorea formula: |
+ | |||
+ | {{:sd-ca:teme:estimare.png|}} | ||
+ | |||
+ | Explicatie: | ||
+ | |||
+ | **m**, ca si pana acum, este numarul total de bucketuri folosite | ||
+ | |||
+ | **$\alpha_m$** reprezinta //factorul de atenuare//, calculat in functie de **m** dupa urmatoarea formula: | ||
+ | |||
+ | {{:sd-ca:teme:alfa.png|}} | ||
+ | |||
+ | |||
+ | //Pentru ultima cerinta, citirea se va face dintr-un fisier al carui nume este primit ca parametru.// | ||
+ | |||
+ | === Precizări === | ||
+ | <note warning>Rezolvati cerintele I si II utilizand structura de date ceruta. Nerespectarea acestui lucru va aduce la anularea punctajului pentru cerinta respectiva.</note> | ||
+ | |||
+ | <note important>Având în vedere ca a 3-a parte a temei presupune implementarea unei structuri de date probabilistice, checkerul ofera punctajul daca raspunsul vostru se incadreaza intr-o marja de eroare de 10% fata de raspunsul corect.</note> | ||
+ | |||
+ | === Checker === | ||
+ | {{:sd-ca:teme:2-distinct-count.zip|CHECKER}} | ||
+ | |||
+ | Temele vor fi trimise pe [[https://elf.cs.pub.ro/vmchecker/ui/#SD|vmchecker]]. | ||
+ | **Atenție!** Temele trebuie trimise în secțiunea **Structuri de Date (CA)**. | ||
+ | |||
+ | Arhiva trebuie să conțină: | ||
+ | * surse | ||
+ | * fișierul Makefile **din arhiva cu checkerul** | ||
+ | * fișier **README** care să conțină detalii despre implementarea temei | ||
+ | |||
+ | === Punctaj === | ||
+ | |||
+ | <note warning>**Atentie!** O temă care nu compilează va primi 0 puncte.</note> | ||
+ | |||
+ | - 80p teste | ||
+ | - **Fiecare** test este verificat cu valgrind. Dacă un test are memory leaks, nu va fi punctat. | ||
+ | - 20p README + comentarii/claritate cod (ATENȚIE! Fișierul README trebuie făcut explicit, cât să se înțeleagă ce ați făcut în sursă, dar fără comentarii inutile și detalii inutile). | ||
+ | - Se acordă 20% din punctajul obținut pe teste, ca bonus pentru coding style. De exemplu, pentru o temă care obține maxim pe teste, se pot obține 20p bonus dacă nu aveți erori de coding style. Pentru o temă ce trece 18 teste din 20, se pot obține 18p dacă nu aveți erori de coding style. | ||
+ | - O temă care obține 0p pe vmchecker este punctată cu 0. | ||
+ | - Temele au deadline hard. Prin urmare, o temă trimisă dupa deadline este punctată cu 0. | ||
+ | <note warning>**Nu copiați!** Toate soluțiile vor fi verificate folosind o unealtă de detectare a plagiatului. În cazul detectării unui astfel de caz, atât plagiatorul cât și autorul original (nu contează cine e) vor primi punctaj 0 pe **toate temele**! | ||
+ | |||
+ | De aceea, vă sfătuim să nu vă lăsați rezolvări ale temelor pe calculatoare partajate (la laborator etc), pe mail/liste de discuții/grupuri etc.</note> | ||
+ | |||
+ | ===FAQ=== | ||
+ | **Q:** Ce functii de hashing trebuie sa folosesc in tema, la cerintele II si III? \\ \\ | ||
+ | **A:** Puteti folosi orice functii doriti. Un exemplu ar fi cele din laborator. | ||
+ | |||
+ | **Q:** La cerinta II functia mea de hashing nu imi genereaza deloc coliziuni. E ok? \\ \\ | ||
+ | **A:** E in regula, insa codul care trateaza posibilitatea coliziunilor **trebuie sa existe**. | ||
+ | |||
+ | **Q:** In enuntul cerintei III sunt mentionate functiile matematice log si pow, insa checkerul nu permite folosirea functiilor matematice. Cum rezolvam problema asta \\ \\ | ||
+ | **A:** Pentru a-l calcula pe **m** care e de forma $2^k$, puteti folosi shiftarea pe biti, adica <code>int m = 1 << k;</code> Din moment ce k se stabileste in prealabil, $\log_2{m} = k$. | ||
+ | |||
+ | |||
+ | ===Link-uri utile=== | ||
+ | |||
+ | [[https://en.wikipedia.org/wiki/Count-distinct_problem]] | ||
+ | |||
+ | [[https://www.omnicoreagency.com/youtube-statistics]] | ||
+ | |||
+ | [[https://en.wikipedia.org/wiki/HyperLogLog]] | ||
+ | |||
+ | [[https://en.wikipedia.org/wiki/Linear_probing]] | ||
+ | |||
+ | [[https://stackoverflow.com/questions/12327004/how-does-the-hyperloglog-algorithm-work]] |