This shows you the differences between two versions of the page.
|
pp:26:teme:haskell-graphs [2026/03/22 13:16] mihnea.muraru [Etapa 1] |
pp:26:teme:haskell-graphs [2026/04/27 15:55] (current) mihnea.muraru |
||
|---|---|---|---|
| Line 1: | Line 1: | ||
| - | ====== Haskell: Graph Zoo ====== | + | ====== Haskell: Grafuri funcționale ====== |
| - | * Data publicării: TODO | + | * Data publicării: 27.04.2026 |
| - | * Data ultimei modificări: TODO | + | * Data ultimei modificări: 27.04.2026 |
| * Deadline hard: ziua laboratorului 12 | * Deadline hard: ziua laboratorului 12 | ||
| - | * Forum temă | + | * [[https://curs.upb.ro/2025/mod/forum/view.php?id=169983|Forum temă]] |
| * [[https://vmchecker.cs.pub.ro/ui/#PP|vmchecker]] | * [[https://vmchecker.cs.pub.ro/ui/#PP|vmchecker]] | ||
| Line 23: | Line 23: | ||
| * una pe care o veți rezolva după laboratorul 11, cu deadline în ziua laboratorului 12, la ora 08:00. | * una pe care o veți rezolva după laboratorul 11, cu deadline în ziua laboratorului 12, la ora 08:00. | ||
| - | Așa cum se poate observa, **ziua deadline-ului variază în funcție de semigrupa în care sunteți repartizați**. **Restanțierii care refac tema și nu refac laboratorul beneficiază de ultimul deadline** (deci vor avea deadline-uri în zilele de TODO). | + | Așa cum se poate observa, **ziua deadline-ului variază în funcție de semigrupa în care sunteți repartizați**. **Restanțierii care refac tema și nu refac laboratorul beneficiază de ultimul deadline** (deci vor avea deadline-uri în zilele de 08.05, 15.05, 22.05 și 29.05). |
| **Rezolvările tuturor etapelor pot fi trimise până la ora 08:00 în ziua laboratorului 12** (**deadline hard pentru toate etapele**). Orice exercițiu trimis după un **deadline soft**, dar înainte de cel hard, se punctează cu **jumătate** din punctaj. Orice exercițiu trimis după deadline-ul hard nu se mai punctează deloc. Nota finală pe etapă se calculează conform formulei: **n = (n1 + n2) / 2** (n1 = nota obținută înainte de deadline; n2 = nota obținută după deadline). Când toate submisiile sunt înainte de deadline-ul soft, nota pe ultima submisie este și nota finală (întrucât n1 = n2). | **Rezolvările tuturor etapelor pot fi trimise până la ora 08:00 în ziua laboratorului 12** (**deadline hard pentru toate etapele**). Orice exercițiu trimis după un **deadline soft**, dar înainte de cel hard, se punctează cu **jumătate** din punctaj. Orice exercițiu trimis după deadline-ul hard nu se mai punctează deloc. Nota finală pe etapă se calculează conform formulei: **n = (n1 + n2) / 2** (n1 = nota obținută înainte de deadline; n2 = nota obținută după deadline). Când toate submisiile sunt înainte de deadline-ul soft, nota pe ultima submisie este și nota finală (întrucât n1 = n2). | ||
| Line 56: | Line 56: | ||
| * Funcția ''%%splitNode%%'' **sparge** un nod în mai multe noduri, ținând cond de arcele nodului inițial. | * Funcția ''%%splitNode%%'' **sparge** un nod în mai multe noduri, ținând cond de arcele nodului inițial. | ||
| * Funcția ''%%mergeNodes%%'' **îmbină** mai multe noduri într-unul singur, ținând cont de arcele nodurilor inițiale. | * Funcția ''%%mergeNodes%%'' **îmbină** mai multe noduri într-unul singur, ținând cont de arcele nodurilor inițiale. | ||
| - | * ''%%Algorithms%%'': conține algoritmii standard de **căutare**, BFS și DFS: | + | * ''%%Algorithms%%'': conține algoritmii standard de **căutare**, BFS și DFS, **restricționați** pentru simplitate la grafuri pentru care nu există mai multe căi între două noduri și nici cicluri. |
| - | * Funcțiile ''%%bfs%%'' și ''%%dfs%%'' întorc lista de noduri parcurse în ordinea aferentă **căutării în lățime**, respectiv **în adâncime**, pornind de la un anumit nod, ținând cont și de posibilele cicluri. Aceste funcții vor fi **derivate** dintr-o funcție mai generală, menționată în continuare. | + | * Funcțiile ''%%bfs%%'' și ''%%dfs%%'' întorc lista de noduri parcurse în ordinea aferentă **căutării în lățime**, respectiv **în adâncime**, pornind de la un anumit nod. |
| - | * Funcția ''%%search%%'' **generalizează** cele două strategii de căutare de mai sus, plecând de la observația că singura diferență dintre ele este modul în care se **combină** la un moment dat nodurile deja existente în structura de date utilizată (stivă/coadă, ambele reprezentate ca liste standard) cu vecinii proaspăt expandați ai nodului curent. Funcția **nu este testată direct**. | + | |
| * Funcția ''%%countIntermediate%%'' verifică **existența unei căi** între două noduri din graf, și calculează **numărul nodurilor intermediare** pe care le expandează cele două strategii de mai sus pentru acest scop. | * Funcția ''%%countIntermediate%%'' verifică **existența unei căi** între două noduri din graf, și calculează **numărul nodurilor intermediare** pe care le expandează cele două strategii de mai sus pentru acest scop. | ||
| Line 75: | Line 74: | ||
| Găsiți detalii despre **funcționalitate** și **implementare**, precum și **exemple**, direct în codul sursă. Aveți de completat definițiile care încep cu **''%%*** TODO ***%%''**. | Găsiți detalii despre **funcționalitate** și **implementare**, precum și **exemple**, direct în codul sursă. Aveți de completat definițiile care încep cu **''%%*** TODO ***%%''**. | ||
| - | Se impun următoarele **constrângeri** de implementare: | + | Se impun următoarele **constrângeri** de implementare asupra funcțiilor din modulul ''StandardGraph'': |
| - | * Toate funcțiile din această etapă, cu excepția ''%%search%%'', trebuie implementate **FĂRĂ recursivitate explicită**. | + | * Toate trebuie implementate **FĂRĂ recursivitate explicită**. |
| - | * Funcțiile trebuie să opereze **direct pe mulțimile** de noduri și arce, utilizând funcțiile specifice acestei reprezentări, **FĂRĂ conversii** redundante la liste și înapoi la mulțimi. | + | * Ele trebuie să opereze **direct pe mulțimile** de noduri și arce, utilizând funcțiile specifice acestei reprezentări, **FĂRĂ conversii** redundante la liste și înapoi la mulțimi. |
| Este suficient ca arhiva pentru **vmchecker** să conțină modulele ''%%StandardGraph%%'' și ''%%Algorithms%%''. | Este suficient ca arhiva pentru **vmchecker** să conțină modulele ''%%StandardGraph%%'' și ''%%Algorithms%%''. | ||
| + | |||
| + | **ATENȚIE!** După ce experimentați în modulul ''Algorithms'' cu funcțiile de **debug** din schelet, ''appendDebug'' și ''concatMapDebug'', așa cum se precizează în comentarii, **reveniți** la versiunile obișnuite ale acestora, ''(++)'' și ''concatMap'', pentru a evita generarea mesajelor stufoase pe vmchecker. | ||
| ==== Depunctări ==== | ==== Depunctări ==== | ||
| - | O funcție care nu respectă cele două constrângeri de mai sus va fi **depunctată total**. | + | * Funcțiile din modulul ''StandardGraph'' care nu respectă cele două constrângeri de mai sus vor fi **depunctate total**. |
| + | * Funcțiile din modulul ''Algorithms'' care nu respectă constrângerile din schelet vor fi **depunctate total**. | ||
| ===== Etapa 2 ===== | ===== Etapa 2 ===== | ||
| În această etapă: | În această etapă: | ||
| - | * veți lucra cu o altă reprezentare a grafurilor orientate, pe care o vom denumi //**constructivă**//, sau //**algebrică**// (explicațiile urmează) | + | * veți lucra cu o altă reprezentare a grafurilor orientate, pe care o vom denumi //**constructivă**// sau //**algebrică**// (explicațiile urmează) |
| * veți **redefini** funcțiile de acces și manipulare din etapa 1 (din modulul ''%%StandardGraph%%''), pentru a opera pe noua reprezentare | * veți **redefini** funcțiile de acces și manipulare din etapa 1 (din modulul ''%%StandardGraph%%''), pentru a opera pe noua reprezentare | ||
| * pentru bonus, veți începe să implementați o funcționalitate de **compactare** a reprezentării unui graf, continuată în etapa 3. | * pentru bonus, veți începe să implementați o funcționalitate de **compactare** a reprezentării unui graf, continuată în etapa 3. | ||
| Line 110: | Line 112: | ||
| Ideile de mai sus se pot traduce direct într-un **tip de date utilizator**, unde ''%%a%%'' este tipul **etichetelor** nodurilor: | Ideile de mai sus se pot traduce direct într-un **tip de date utilizator**, unde ''%%a%%'' este tipul **etichetelor** nodurilor: | ||
| - | <code> | + | <code haskell> |
| data AlgebraicGraph a | data AlgebraicGraph a | ||
| = Empty | = Empty | ||
| Line 120: | Line 122: | ||
| Mai jos, sunt **exemplificate** mai multe grafuri care utilizează această reprezentare, pentru o înțelegere mai bună: | Mai jos, sunt **exemplificate** mai multe grafuri care utilizează această reprezentare, pentru o înțelegere mai bună: | ||
| - | * ''%%Overlay (Node 2) (Node 3)%%'' este un graf foarte simplu, care conține doar nodurile 2 și 3, fără niciun arc. | + | * ''%%Overlay (Node 2) (Node 3)%%'' este un graf foarte simplu, care conține doar nodurile 2 și 3, fără arce. |
| * ''%%Connect (Node 2) (Node 3)%%'' conține nodurile 2 și 3, precum și arcul (2, 3). | * ''%%Connect (Node 2) (Node 3)%%'' conține nodurile 2 și 3, precum și arcul (2, 3). | ||
| * ''%%Connect (Node 1) (Overlay (Node 2) (Node 3))%%'' conține nodurile 1, 2 și 3, și arcele (1, 2) și (1, 3), pentru că nodul 1 trebuie conectat cu fiecare dintre nodurile 2 și 3. | * ''%%Connect (Node 1) (Overlay (Node 2) (Node 3))%%'' conține nodurile 1, 2 și 3, și arcele (1, 2) și (1, 3), pentru că nodul 1 trebuie conectat cu fiecare dintre nodurile 2 și 3. | ||
| Line 146: | Line 148: | ||
| * Mulțimea [1, 3] **nu** ar putea constitui un modul, pentru că există arcul (1, 2), dar nu și arcul (3, 2). | * Mulțimea [1, 3] **nu** ar putea constitui un modul, pentru că există arcul (1, 2), dar nu și arcul (3, 2). | ||
| - | {{ :pp:22:teme:haskell:graph.png }} | + | {{ :pp:26:teme:haskell:graph.png }} |
| Orice graf are două descompuneri modulare **banale**: | Orice graf are două descompuneri modulare **banale**: | ||
| Line 163: | Line 165: | ||
| Veți implementa aspecte legate de descompunerea modulară parțial ca bonus, în cadrul etapelor 2 și 3. Deși există [[https://www.sciencedirect.com/science/article/pii/S0166218X04002458|algoritmi eficienți (liniari)]] pentru determinarea descompunerii modulare, aceștia sunt destul de complicați, astfel că vom utiliza o abordare mai simplă bazată pe forță brută. Cu alte cuvinte, vom genera **toate partițiile** mulțimii de noduri, și apoi le vom filtra pentru a obține modulele. | Veți implementa aspecte legate de descompunerea modulară parțial ca bonus, în cadrul etapelor 2 și 3. Deși există [[https://www.sciencedirect.com/science/article/pii/S0166218X04002458|algoritmi eficienți (liniari)]] pentru determinarea descompunerii modulare, aceștia sunt destul de complicați, astfel că vom utiliza o abordare mai simplă bazată pe forță brută. Cu alte cuvinte, vom genera **toate partițiile** mulțimii de noduri, și apoi le vom filtra pentru a obține modulele. | ||
| - | În etapa 2, **scheletul** conține următoarele module: | + | Ca încălzire: |
| + | * Gândiți-vă cum se poate **redefini** tipul ''%%StandardGraph%%'' din etapa 1 ca **tip de date utilizator** (''%%data%%''), în locul sinonimului de tip pereche. | ||
| + | * Funcțiile ''%%nodes%%'' și ''%%edges%%'' pot fi definite direct drept **câmpuri** în cadrul tipului. | ||
| + | * Funcția ''%%fromComponents%%'' trebuie și ea redefinită. | ||
| + | * Schițați în comentarii redefinirea celor patru entități de mai sus. Această parte nu este testată automat, dar o veți **prezenta**. | ||
| + | * Nu este necesar să reimplementați celelalte funcții din acest modul. | ||
| - | * ''%%StandardGraph%%'': implementat în etapa 1. Reprezentarea originală este de **pereche** de mulțimi de noduri, respectiv arce. Ca încălzire: | + | În etapa 2, **scheletul** conține următoarele module: |
| - | * Gândiți-vă cum se poate **redefini** tipul ''%%StandardGraph%%'' ca **tip de date utilizator** (''%%data%%''), în locul sinonimului de tip pereche. | + | |
| - | * Funcțiile ''%%nodes%%'' și ''%%edges%%'' pot fi definite direct drept **câmpuri** în cadrul tipului. | + | |
| - | * Funcția ''%%fromComponents%%'' trebuie și ea redefinită. | + | |
| - | * Schițați în comentarii redefinirea celor patru entități de mai sus. Această parte nu este testată automat, dar o veți **prezenta**. | + | |
| - | * Nu este necesar să reimplementați celelalte funcții din acest modul. | + | |
| * ''%%AlgebraicGraph%%'': conține **reprezentarea algebrică** a grafurilor, descrisă mai sus | * ''%%AlgebraicGraph%%'': conține **reprezentarea algebrică** a grafurilor, descrisă mai sus | ||
| * Tipul ''%%AlgebraicGraph%%'' este cel prezentat mai sus. | * Tipul ''%%AlgebraicGraph%%'' este cel prezentat mai sus. | ||
| * Mai departe, veți implementa **aceleași funcții** ca în modulul ''%%StandardGraph%%'', cu excepția ''%%fromComponents%%'', dar de data aceasta vor opera pe reprezentarea algebrică. | * Mai departe, veți implementa **aceleași funcții** ca în modulul ''%%StandardGraph%%'', cu excepția ''%%fromComponents%%'', dar de data aceasta vor opera pe reprezentarea algebrică. | ||
| - | * Toate funcțiile vor fi implementate **CU recursivitate explicită**. | ||
| * Veți observa că implementările funcțiilor ''%%removeNode%%'', ''%%splitNode%%'' și ''%%mergeNodes%%'' respectă un **tipar similar**, pe care vom căuta să îl generalizăm în etapa 3. | * Veți observa că implementările funcțiilor ''%%removeNode%%'', ''%%splitNode%%'' și ''%%mergeNodes%%'' respectă un **tipar similar**, pe care vom căuta să îl generalizăm în etapa 3. | ||
| - | * **ATENȚIE!** Funcțiile de mai sus trebuie să opereze **direct pe reprezentarea algebrică** din această etapă. **NU este permisă** convertirea în reprezentarea din etapa 1 și utilizarea funcțiilor de acolo. | ||
| * ''%%Modular%%'': conține momentan doar câteva funcții pentru determinarea **descompunerii modulare** a grafului, dar va fi îmbogățit în etapa 3: | * ''%%Modular%%'': conține momentan doar câteva funcții pentru determinarea **descompunerii modulare** a grafului, dar va fi îmbogățit în etapa 3: | ||
| * Funcția ''%%mapSingle%%'' este asemănătoare cu ''%%map%%'', în sensul că aplică o funcție asupra fiecărui element al unei liste, dar aplicarea se face asupra unui **singur element** din listă la un moment dat, celelalte rămânând nemodificate. | * Funcția ''%%mapSingle%%'' este asemănătoare cu ''%%map%%'', în sensul că aplică o funcție asupra fiecărui element al unei liste, dar aplicarea se face asupra unui **singur element** din listă la un moment dat, celelalte rămânând nemodificate. | ||
| * Funcția ''%%partitions%%'' generează toate partițiile unei liste. | * Funcția ''%%partitions%%'' generează toate partițiile unei liste. | ||
| + | |||
| + | Se impun următoarele **constrângeri** de implementare asupra funcțiilor din modulul ''AlgebraicGraph'': | ||
| + | |||
| + | * Toate trebuie implementate **CU recursivitate explicită**. | ||
| + | * Toate trebuie să opereze **direct pe reprezentarea algebrică** din această etapă. **NU este permisă** convertirea în reprezentarea din etapa 1 și utilizarea funcțiilor de acolo. | ||
| + | |||
| + | Este suficient ca arhiva pentru **vmchecker** să conțină modulele ''%%AlgebraicGraph%%'' și ''%%Modular%%''. | ||
| + | |||
| + | ==== Depunctări ==== | ||
| + | |||
| + | Funcțiile care nu respectă constrângerile de mai sus sau pe cele din schelet vor fi **depunctate total**. | ||
| ===== Etapa 3 ===== | ===== Etapa 3 ===== | ||
| Line 221: | Line 232: | ||
| * Funcția ''%%maximalModularPartition%%'' determină cea mai acoperitoare partiție, pornind de la lista tuturor partițiilor mulțimii de noduri (vedeți explicațiile din comentarii). | * Funcția ''%%maximalModularPartition%%'' determină cea mai acoperitoare partiție, pornind de la lista tuturor partițiilor mulțimii de noduri (vedeți explicațiile din comentarii). | ||
| * Funcția ''%%modularlyDecompose%%'' este **deja implementată**, și vă permite să puneți cap la cap funcțiile de mai sus. | * Funcția ''%%modularlyDecompose%%'' este **deja implementată**, și vă permite să puneți cap la cap funcțiile de mai sus. | ||
| + | |||
| + | Este suficient ca arhiva pentru **vmchecker** să conțină modulele ''%%AlgebraicGraph%%'' și ''%%Modular%%''. | ||
| + | |||
| + | ==== Depunctări ==== | ||
| + | |||
| + | Funcțiile care nu respectă constrângerile din schelet vor fi **depunctate total**. | ||
| + | |||
| ===== Precizări ===== | ===== Precizări ===== | ||
| - | * Încercați să folosiți pe cât posibil funcții **predefinite** din modulele [[https://hackage.haskell.org/package/base-4.16.1.0/docs/Data-List.html|Data.List]] și [[https://hackage.haskell.org/package/containers-0.6.5.1/docs/Data-Set.html|Data.Set]]. Este foarte posibil ca o funcție de prelucrare de care aveți nevoie să fie deja definită aici. | ||
| - | * Ca sugestie, exploatați cu încredere //**pattern matching**//, **''%%case%%''** și **gărzi**, în locul //if//-urilor imbricate. | ||
| * Pentru **rularea testelor**, încărcați în interpretor modulul ''%%TestGraph%%'' și evaluați ''%%checkAll%%''. | * Pentru **rularea testelor**, încărcați în interpretor modulul ''%%TestGraph%%'' și evaluați ''%%checkAll%%''. | ||
| + | * Încercați să folosiți pe cât posibil funcții **predefinite** din modulele ''[[https://hackage-content.haskell.org/package/base-4.22.0.0/docs/Data-List.html|Data.List]]'' și ''[[https://hackage.haskell.org/package/containers-0.6.7/docs/Data-Set.html|Data.Set]]''. Este foarte posibil ca o funcție de prelucrare de care aveți nevoie să fie deja definită aici. | ||
| + | * Ca sugestie, exploatați cu încredere //**pattern matching**//, **''%%case%%''** și **gărzi**, în locul //if//-urilor imbricate. | ||
| ===== Resurse ===== | ===== Resurse ===== | ||
| - | * [[https://ocw.cs.pub.ro/courses/_media/pp/22/teme/haskell/etapa1.zip|Schelet etapa 1]] | + | * [[https://ocw.cs.pub.ro/courses/_media/pp/26/teme/haskell/etapa1.zip|Schelet etapa 1]] |
| - | * [[https://ocw.cs.pub.ro/courses/_media/pp/22/teme/haskell/etapa2.zip|Schelet etapa 2]] | + | * [[https://ocw.cs.pub.ro/courses/_media/pp/26/teme/haskell/etapa2.zip|Schelet etapa 2]] |
| - | * [[https://ocw.cs.pub.ro/courses/_media/pp/22/teme/haskell/etapa3.zip|Schelet etapa 3]] | + | * [[https://ocw.cs.pub.ro/courses/_media/pp/26/teme/haskell/etapa3.zip|Schelet etapa 3]] |
| ===== Referințe ===== | ===== Referințe ===== | ||