This shows you the differences between two versions of the page.
pp:22:teme:racket-smp [2022/12/20 20:41] mihaela.balint [Etapa 4] |
pp:22:teme:racket-smp [2023/02/28 23:30] (current) mihaela.balint |
||
---|---|---|---|
Line 1: | Line 1: | ||
- | ====== Problema mariajelor stabile ====== | + | ====== Racket: Problema mariajelor stabile ====== |
* Data publicării: 28.02.2023 | * Data publicării: 28.02.2023 | ||
Line 24: | Line 24: | ||
În această etapă vă veți familiariza cu problema mariajelor stabile (SMP) și felul în care modelăm datele sale de intrare in Racket, apoi veți implementa câteva funcții de manipulare a acestor date. | În această etapă vă veți familiariza cu problema mariajelor stabile (SMP) și felul în care modelăm datele sale de intrare in Racket, apoi veți implementa câteva funcții de manipulare a acestor date. | ||
- | În SMP se dau un număr egal de bărbați și femei și, pentru fiecare dintre aceștia, un "clasament" al persoanelor de sex opus, și se cere să se căsătorească fiecare bărbat cu câte o femeie astfel încât să nu existe un bărbat și o femeie în căsătorii diferite care s-ar prefera unul pe altul în detrimentul soților lor. Dacă ar exista o asemenea pereche, cei doi ar fi motivați să își părăsească partenerii pentru a fi împreună, așadar căsătoriile lor nu ar fi stabile (de aici numele problemei). | + | În SMP se dau un număr egal de bărbați și femei și, pentru fiecare dintre aceștia, un "clasament" al tuturor persoanelor de sex opus, și se cere să se căsătorească fiecare bărbat cu câte o femeie astfel încât să nu existe un bărbat și o femeie în căsătorii diferite care s-ar prefera unul pe altul în detrimentul soților lor. Dacă ar exista o asemenea pereche, cei doi ar fi motivați să își părăsească partenerii pentru a fi împreună, așadar căsătoriile lor nu ar fi stabile (de aici numele problemei). |
Vom modela o instanță SMP în Racket ca pe două liste (egale ca lungime) de preferințe masculine, respectiv feminine, ca în exemplul următor: | Vom modela o instanță SMP în Racket ca pe două liste (egale ca lungime) de preferințe masculine, respectiv feminine, ca în exemplul următor: | ||
Line 37: | Line 37: | ||
[cora bobo cos adi ])) | [cora bobo cos adi ])) | ||
</file> | </file> | ||
- | Astfel, lista de preferințe masculine/feminine este o listă de liste, fiecare listă interioară având pe prima poziție un bărbat/o femeie, iar pe următoarele poziții persoanele de sex opus în ordinea preferințelor acestui bărbat/acestei femei. Deși în exemplu bărbații/femeile apar în ordine alfabetică, nu presupuneți că acest lucru este necesar să se întâmple. | + | Astfel, lista de preferințe masculine/feminine este o listă de liste, fiecare listă interioară având pe prima poziție un bărbat/o femeie, iar pe următoarele poziții persoanele de sex opus în ordinea preferințelor acestui bărbat/acestei femei. De-a lungul întregii teme, o listă de preferințe masculine/feminine se va referi la o listă cu acest format. Când, în schimb, ne vom referi la lista preferințelor unei persoane p, ne vom referi la felul în care p a clasat persoanele de sex opus, așadar o listă care conține doar persoane de sex opus, nu și pe p pe prima poziție. Deși în exemplu bărbații/femeile apar în ordine alfabetică, nu presupuneți că acest lucru este necesar să se întâmple. |
Aceste liste vor fi definite în checker, însă este necesar să le înțelegeți structura pentru a putea implementa funcțiile din cerință. | Aceste liste vor fi definite în checker, însă este necesar să le înțelegeți structura pentru a putea implementa funcțiile din cerință. | ||
Line 50: | Line 50: | ||
<file> | <file> | ||
- | (get-men men-pref) | + | (get-men mpref) |
- | (get-women women-pref) | + | (get-women wpref) |
</file> | </file> | ||
* get-men primește o listă de preferințe masculine și determină lista tuturor bărbaților din problemă | * get-men primește o listă de preferințe masculine și determină lista tuturor bărbaților din problemă | ||
Line 60: | Line 60: | ||
(get-pref-list pref person) | (get-pref-list pref person) | ||
</file> | </file> | ||
- | * get-pref-list primește o listă de preferințe (masculine sau feminine) și o persoană person ale cărei preferințe apar (garantat) în listă și întoarce lista preferințelor lui person | + | * get-pref-list primește o listă de preferințe (masculine sau feminine) și o persoană person ale cărei preferințe apar (garantat) în listă și întoarce lista preferințelor lui person |
* ex: ''%%(get-pref-list women-preferences 'bia)%%'' => '''(adi cos bobo)'' | * ex: ''%%(get-pref-list women-preferences 'bia)%%'' => '''(adi cos bobo)'' | ||
Line 90: | Line 90: | ||
Scopul etapei este consolidarea cunoștințelor legate de: | Scopul etapei este consolidarea cunoștințelor legate de: | ||
- | * funcționale | + | * funcționale (faptul că funcțiile sunt valori de ordinul întâi oferă atât posibilitatea de a lucra cu funcționalele din limbaj, cât și pe aceea de a implementa propriile funcționale, pentru orice șablon util pe care îl observați - din acest motiv, aveți inclusiv sarcina de a implementa două funcționale și a le folosi ulterior) |
* funcții anonime | * funcții anonime | ||
* programare de tip “wishful thinking” - veți implementa funcția stable-match? folosindu-vă de funcția better-match-exists?, întrucât noțiunea de stabilitate este definită ca "nu există un partener mai potrivit pentru niciunul dintre soți"; dacă nu ați fi avut deja funcția better-match-exists?, ar fi fost o idee foarte bună să programați stable-match? ca și cum ați fi implementat deja conceptul de partener mai potrivit (wishful thinking), și apoi să aveți grijă chiar să implementați această funcție ajutătoare | * programare de tip “wishful thinking” - veți implementa funcția stable-match? folosindu-vă de funcția better-match-exists?, întrucât noțiunea de stabilitate este definită ca "nu există un partener mai potrivit pentru niciunul dintre soți"; dacă nu ați fi avut deja funcția better-match-exists?, ar fi fost o idee foarte bună să programați stable-match? ca și cum ați fi implementat deja conceptul de partener mai potrivit (wishful thinking), și apoi să aveți grijă chiar să implementați această funcție ajutătoare | ||
Line 142: | Line 142: | ||
</file> | </file> | ||
* get-unstable-couples primește o listă engagements de logodne (unde fiecare cuplu are pe prima poziție o femeie), respectiv două liste mpref/wpref de preferințe masculine/feminine și întoarce lista tuturor cuplurilor instabile din engagements | * get-unstable-couples primește o listă engagements de logodne (unde fiecare cuplu are pe prima poziție o femeie), respectiv două liste mpref/wpref de preferințe masculine/feminine și întoarce lista tuturor cuplurilor instabile din engagements | ||
- | * ex: ''%%(get-unstable-couples '((ana . cos) (bia . adi) (cora . bobo)) men-preferences women-preferences)%%'' => ''%%'((ana . cos) (bia . adi))%%'' (întrucât ana și adi se preferă reciproc în dauna partenerilor lor actuali) | + | * ex: ''%%(get-unstable-couples '((ana . cos) (bia . adi) (cora . bobo)) men-preferences women-preferences)%%'' => ''%%'((ana . cos) (bia . adi))%%'' (întrucât ana și adi se preferă reciproc în dauna partenerilor lor actuali) (ordinea cuplurilor în rezultat nu contează, checker-ul sortează singur returul funcției get-unstable-couples) |
<file> | <file> | ||
Line 182: | Line 182: | ||
În această etapă veți rezolva SMP pentru cazul în care preferințele evoluează în timp, așa cum se întâmplă adesea în realitate. Orice schimbare poate afecta stabilitatea căsătoriilor obținute anterior, dar - având în vedere că preferințele nu se schimbă radical de la un moment la altul - pare mai puțin costisitor ca în loc să rulăm algoritmul Gale-Shapley de la zero de fiecare dată când se schimbă ceva, să pornim de la soluția anterioară și să o actualizăm pe aceasta în cazul în care identificăm în ea cupluri instabile. | În această etapă veți rezolva SMP pentru cazul în care preferințele evoluează în timp, așa cum se întâmplă adesea în realitate. Orice schimbare poate afecta stabilitatea căsătoriilor obținute anterior, dar - având în vedere că preferințele nu se schimbă radical de la un moment la altul - pare mai puțin costisitor ca în loc să rulăm algoritmul Gale-Shapley de la zero de fiecare dată când se schimbă ceva, să pornim de la soluția anterioară și să o actualizăm pe aceasta în cazul în care identificăm în ea cupluri instabile. | ||
- | Veți exersa în continuare stilul funcțional de a programa studiat in săptămânile anterioare, plus conceptul de flux introdus la ultimul laborator. Întrucât o instanță SMP este reprezentată prin două liste de preferințe masculine, respectiv feminine, vom reprezenta SMP cu preferințe dinamice ca pe un flux de instanțe SMP, fiecare element din flux reprezentând preferințele la un anumit moment în timp. Soluția SMP cu preferințe dinamice trebuie calculată tot sub formă de flux, unde fiecare element este o listă de căsătorii stabile conform preferințelor la momentul respectiv. Veți obține primul element din fluxul rezultat aplicând algoritmul Gale-Shapley asupra primului element din fluxul de intrare, iar pe următoarele prin aplicarea succesivă a algoritmului de actualizare prezentat mai jos. | + | Observați că la începutul fișierului etapa4.rkt se solicită să aduceți în folderul curent rezolvările etapelor 2 și 3, pentru a beneficia de funcțiile implementate anterior. |
- | Algoritmul de actualizare este bazat pe o metodă introdusă de Roth și Vande, și functionează în felul următor: | + | Veți exersa în continuare stilul funcțional de a programa studiat în săptămânile anterioare, plus conceptul de flux introdus la ultimul laborator. Întrucât o instanță SMP este reprezentată prin două liste de preferințe masculine, respectiv feminine, vom reprezenta SMP cu preferințe dinamice ca pe un flux de instanțe SMP, fiecare element din flux reprezentând preferințele la un anumit moment în timp. Soluția SMP cu preferințe dinamice trebuie calculată tot sub formă de flux, unde fiecare element este o listă de căsătorii stabile conform preferințelor la momentul respectiv. Veți obține primul element din fluxul rezultat aplicând algoritmul Gale-Shapley asupra primului element din fluxul de intrare, iar pe următoarele prin aplicarea succesivă a algoritmului de actualizare prezentat mai jos. |
- | * pornește de la soluția anterioară (căsătoriile stabile la momentul anterior) | + | |
+ | Algoritmul de actualizare este bazat pe o metodă introdusă de Roth și Vande, și funcționează în felul următor: | ||
+ | * pornește de la soluția anterioară - căsătoriile stabile la momentul anterior | ||
* dintre acestea, elimină cuplurile care au devenit instabile în urma schimbărilor de preferințe | * dintre acestea, elimină cuplurile care au devenit instabile în urma schimbărilor de preferințe | ||
* consideră că toate cuplurile rămase (care sunt stabile între ele) se găsesc împreună într-o cameră, în timp ce toate celelalte persoane din problemă așteaptă la coadă la intrarea în cameră | * consideră că toate cuplurile rămase (care sunt stabile între ele) se găsesc împreună într-o cameră, în timp ce toate celelalte persoane din problemă așteaptă la coadă la intrarea în cameră | ||
Line 191: | Line 193: | ||
* repetă pasul anterior până când se termină coada iar în cameră sunt numai cupluri stabile, reprezentând noua soluție | * repetă pasul anterior până când se termină coada iar în cameră sunt numai cupluri stabile, reprezentând noua soluție | ||
- | Funcțiile pe care va trebui să le implementați sunt: | + | Toate funcțiile din această etapă întorc una sau mai multe liste de cupluri. Așa cum v-ați obișnuit în etapa anterioară, ordinea cuplurilor în listă nu contează (dar pe prima poziție a fiecărui cuplu se va găsi un bărbat/o femeie, în funcție de cum cere fiecare funcție în parte). Aveți de implementat următoarele funcții: |
<file> | <file> | ||
Line 206: | Line 208: | ||
* bia își consultă lista de preferințe - ''%%'(adi cos bobo)%%'' | * bia își consultă lista de preferințe - ''%%'(adi cos bobo)%%'' | ||
* ea încearcă pe rând să se cupleze cu adi, respectiv bobo (nu și cu cos, pentru că el nu este în cameră), dar atât adi cât și bobo își preferă partenerele actuale, așadar bia rămâne momentan singură, ceea ce înseamnă că o logodim fictiv cu valoarea false | * ea încearcă pe rând să se cupleze cu adi, respectiv bobo (nu și cu cos, pentru că el nu este în cameră), dar atât adi cât și bobo își preferă partenerele actuale, așadar bia rămâne momentan singură, ceea ce înseamnă că o logodim fictiv cu valoarea false | ||
- | * rezultatul final este ''%%'((#f . bia) (bobo . cora) (adi . ana))%%'' (ori aceleași cupluri în altă ordine) | + | * rezultatul final este ''%%'((#f . bia) (bobo . cora) (adi . ana))%%'' |
<file> | <file> | ||
Line 220: | Line 222: | ||
* întrucât toate persoanele au intrat în cameră, acesta este și rezultatul final | * întrucât toate persoanele au intrat în cameră, acesta este și rezultatul final | ||
- | Pentru exemplificarea următoarelor două funcții, vom folosi următoarele liste de preferințe reflectând situația la două momente de timp t0 și t1 (singura diferență apare la preferințele lui adi): | + | Pentru exemplificarea următoarelor două funcții, vom folosi următoarele liste de preferințe reflectând situația la două momente de timp t<sub>0</sub> și t<sub>1</sub> (singura diferență apare la preferințele lui adi): |
<file> | <file> | ||
(define men-preferences-0 (define men-preferences-1 | (define men-preferences-0 (define men-preferences-1 | ||
Line 234: | Line 236: | ||
<file> | <file> | ||
(update-stable-match engagements mpref wpref) | (update-stable-match engagements mpref wpref) | ||
- | </file> | + | </file> |
* update-stable-match primește o listă completă de logodne engagements (soluția SMP de la momentul anterior de timp), respectiv două liste mpref/wpref de preferințe masculine/feminine (de la momentul actual) și întoarce o nouă listă completă de logodne stabile (conform cu preferințele actuale) | * update-stable-match primește o listă completă de logodne engagements (soluția SMP de la momentul anterior de timp), respectiv două liste mpref/wpref de preferințe masculine/feminine (de la momentul actual) și întoarce o nouă listă completă de logodne stabile (conform cu preferințele actuale) | ||
* ex: ''%%(update-stable-match '((ana . adi) (bia . cos) (cora . bobo)) men-preferences-1 women-preferences-1)%%'' => ''%%'((ana . cos) (bia . adi) (cora . bobo))%%'' | * ex: ''%%(update-stable-match '((ana . adi) (bia . cos) (cora . bobo)) men-preferences-1 women-preferences-1)%%'' => ''%%'((ana . cos) (bia . adi) (cora . bobo))%%'' | ||
Line 248: | Line 250: | ||
</file> | </file> | ||
* build-stable-matches-stream primește un flux de instanțe SMP (reprezentând preferințele acelorași persoane la momente succesive de timp) și întoarce fluxul de soluții SMP corespunzătoare acestor instanțe | * build-stable-matches-stream primește un flux de instanțe SMP (reprezentând preferințele acelorași persoane la momente succesive de timp) și întoarce fluxul de soluții SMP corespunzătoare acestor instanțe | ||
- | * pentru exemplificare, considerăm că am definit fluxul pref-stream-a care are pe prima poziție perechea (cons men-preferences-0 women-preferences-0) și pe a doua (și ultima) poziție perechea (cons men-preferences-1 women-preferences-1) | + | * pentru exemplificare, considerăm că am definit fluxul pref-stream-a care are pe prima poziție perechea ''%%(cons men-preferences-0 women-preferences-0)%%'' și pe a doua (și ultima) poziție perechea ''%%(cons men-preferences-1 women-preferences-1)%%'' |
* ex: ''%%(build-stable-matches-stream pref-stream-a)%%'' => un flux care are pe prima poziție căsătoriile ''%%'((ana . adi) (bia . cos) (cora . bobo))%%'' și pe a doua poziție căsătoriile ''%%'((ana . cos) (bia . adi) (cora . bobo))%%'' | * ex: ''%%(build-stable-matches-stream pref-stream-a)%%'' => un flux care are pe prima poziție căsătoriile ''%%'((ana . adi) (bia . cos) (cora . bobo))%%'' și pe a doua poziție căsătoriile ''%%'((ana . cos) (bia . adi) (cora . bobo))%%'' | ||
- | * primul element Sol0 din fluxul rezultat se obține aplicând algoritmul Gale-Shapley asupra preferințelor de la momentul t0 | + | * primul element Sol<sub>0</sub> din fluxul rezultat se obține aplicând algoritmul Gale-Shapley asupra preferințelor de la momentul t<sub>0</sub> |
- | * al doilea element din fluxul rezultat se obține aplicând update-stable-match asupra lui Sol0 și a preferințelor de la momentul t1 | + | * al doilea element din fluxul rezultat se obține aplicând update-stable-match asupra lui Sol<sub>0</sub> și a preferințelor de la momentul t<sub>1</sub> |
+ | |||
+ | ===== Precizări ===== | ||
+ | |||
+ | * Exercițiile din fiecare etapă se rezolvă în fișierul care poartă numele etapei (**etapa1.rkt**, **etapa2.rkt**, etc.). Pentru testare, veți rula codul din fișierul **checker.rkt**. | ||
+ | * Fiecare etapă (o arhivă .zip cu fișierul care poartă numele etapei plus eventualele fișiere care sunt solicitate de acesta cu "require") se va încărca pe vmchecker. Testele de vmchecker sunt aceleași cu cele din checker.rkt. Pentru etapele 3 și 4 testele folosesc funcția stable-match? implementată în etapa 2. Pentru a preveni teste care trec sau nu trec din cauză că funcția stable-match? este implementată greșit, pe vmchecker vom folosi un stable-match? implementat de noi (deci în această situație puteți obține punctaje diferite local față de vmchecker). | ||
+ | * Dacă doriți să rezolvați exerciții din etapa curentă care depind de exerciții din etapele anterioare pe care nu le-ați rezolvat, puteți semnala acest lucru asistentului, care vă va pune la dispoziție o rezolvare pentru acele exerciții astfel încât să puteți continua tema. Odată ce alegeți această variantă, nu mai puteți primi punctaj pe exercițiile pentru care ați primit rezolvarea, chiar daca deadline-ul lor nu a expirat. Puteți solicita rezolvări doar pentru exercițiile din etapele anterioare, nu și pentru cele din etapa curentă. Dacă implementați un exercițiu din etapa curentă pe baza unui alt exercițiu din etapa curentă pe care nu l-ați rezolvat, se va lua în calcul punctajul dat de checker, chiar dacă implementarea ar funcționa în caz că exercițiul nerezolvat ar funcționa. | ||
+ | * Tema este în primul rând o temă de programare funcțională - pentru care folosim Racket. Racket este un limbaj multiparadigmă, care conține și elemente "ne-funcționale" (de exemplu proceduri cu efecte laterale), pe care **nu** este permis să le folosiți în rezolvare. | ||
+ | * Pentru fiecare etapă, checker-ul vă oferă un punctaj între 0 și 120 de puncte. Pentru a obține cele 1.33p din nota finală cu care este creditată tema de Racket, este suficient să acumulați 400 de puncte de-a lungul celor 4 etape. Un punctaj între 400 și 480 se transformă într-un bonus proporțional. | ||
+ | * Veți prezenta tema asistentului, care poate modifica punctajul dat de checker dacă observă nereguli precum răspunsuri hardcodate, proceduri cu efecte laterale, implementări neconforme cu restricțiile din enunț. | ||
+ | |||
+ | ===== Resurse ===== | ||
+ | |||
+ | ===== Changelog ===== | ||
+ | * 28.02 (ora 23:25) - Am publicat tema. | ||
+ | |||
+ | ===== Referinţe ===== | ||
+ | * [[https://www.ncbi.nlm.nih.gov/pmc/articles/PMC8871443/|Matching-Updating Mechanism: A Solution for the Stable Marriage Problem with Dynamic Preferences]] | ||