Differences

This shows you the differences between two versions of the page.

Link to this comparison view

pp:26:teme:racket-supermarket [2026/03/18 11:18]
mihaela.balint
pp:26:teme:racket-supermarket [2026/03/26 08:55] (current)
mihaela.balint
Line 1: Line 1:
-===== Etapa =====+===== Etapa =====
  
-Această etapă își propune să sublinieze importanțabstractizăriiVa trebui să vă definiți propriul ​TDA (tip de date abstract) și să oferiți o interfață completă (un set de constructori ​și operatori) prin care utilizatorul poate manipula valorile tipuluiindependent de implementarea din spate. Apoi, este esențial ca voi înșivă ​să folosiți TDA-ul doar prin intermediul interfeței (în etapa 4 veți înțelege și mai bine de ce este esențial)+Etapa 4 oferă un exemplu interesant de utilizare ​fluxurilorVeți reimplementa ​TDA-ul ''​queue''​ pentru a obține un plus de performanță și, cu condiția să fi respectat bariera de abstractizare ​în etapa 3, funcțiile implementate anterior vor funcționa fără modificări pe noua reprezentare
  
-Veți începe ​rezolvarea etapei ​prin a implementa ​TDA-ul ''​%%queue%%''​ în fișierul **queue.rkt**.+Din nou, rezolvarea etapei ​începe cu implementarea ​TDA-ului ''​queue''​ în fișierul **queue.rkt**.
  
-Acest tip reprezintă o coadă (first-in-first-out) ​ca pe o structură: +Din motive de performanță detaliate în schelet, reținem câmpul ''​left''​ al structurii ''​queue''​ ca flux (în contrast cu reprezentarea ​ca listă din etapa 3). Definiția structurii nu se modifică: 
-<​code ​lisp>+<​code ​scheme>
 (define-struct queue (left right size-l size-r)) (define-struct queue (left right size-l size-r))
 </​code>​ </​code>​
-  * left, right +  * adăugare în coadă ​este o adăugare în stiva ''​right''​ (ca înainte
-    * sunt stive (last-in-first-out,​ implementate ca liste Racket)  +  o extragere ​din coadă ​este extragere ​din stiva ''​left'' ​(ca înainte
-    * fiecare ​adăugare în coadă ​va fi o adăugare în stiva right  +  după fiecare ​operație ''​enqueue'' ​sau ''​dequeue'' ​trebuie menținut invariantul  ​''​%%size(left) ≥ size(right)%%''​; astfelniciun ​''​dequeue'' nu va găsi stiva ''​left'' ​vidă  
-    * ex adăugare: \\ adaug 1 => ''​%%right '(1)%%'',​ \\ adaug 2 => ''​%%right = '(2 1)%%''​ +  * când o operație ​''​enqueue'' ​sau ''​dequeue'' ​produce situația ​''​%%size(leftsize(right- 1%%'', ​aplicăm o **rotație**:​  
-    fiecare scoatere ​din coadă ​va fi scoatere ​din stiva left (când left este vidă, va trebui mai întâi să mutăm toate elementele din right în left, apoi să scoatem din left)  +    * mutăm "în mod leneș"​ toate elementele din ''​right'' ​în ''​left''​ 
-    mutarea este rezultatul unor operații pop (din right) + push (în left) repetate +    * ce înseamnă "​leneș":​ elementele vor fi mutatede fapt, unul câte unul, pe măsură ce extragem elemente din ''​left'', ​nu toate deodată ​(dacă s-ar muta deodată nu am rezolva problema complexității, ci doar am deplasa-o asupra altor operații
-    * ex mutare: \\ mut în ''​%%left = '()%%'' ​din ''​%%right = '(2 1)%%''​ => \\ ''​%%left ​= '(2)%%'',​ ''​%%right = '(1)%%'' ​(primul pop din right îl extrage pe 2 și îi face push în left) => \\ ''​%%left = '(1 2)%%''​''​%%right = '()%%'' ​(apoi pop din right îl extrage pe 1 și îi face push în left) +   
-    * ex scoatere: \\ scot din coada cu ''​%%left = '()%%'',​ ''​%%right '(2 1)%%'' ​=> \\ ''%%left = '(1 2)%%'', ​''​%%right = '​()%%''​ (după mutarea elementelor) => \\ ''​%%left = '(2)%%'', ​''​%%right = '()%%''​ (după scoaterea primului element) +Veți redefini ​interfața ​din etapa 3. Noile implementări depind de implementarea funcției de rotație:
-    * observați că primul element adăugat este primul element scos (first-in-first-out+
-  ​* size-l, size-r +
-    * sunt numere naturale, reprezentând numărul de elemente din cele 2 stive +
-  +
-Sarcina voastră este să implementați interfața ​TDA-ului queue:+
 <​file>​ <​file>​
-  empty-queue ​ :              -> queue  ​(constructor nular pentru o coadă goală) +(rotate left right Acc)
-  queue-empty?​ :        queue -> Bool   ​(operator care verifică dacă o coadă este goală) +
-  enqueue ​     : Elem x queue -> queue  (operatorul de adăugare în coadă) +
-  dequeue ​     :        queue -> queue  (operatorul de scoatere din coadă) +
-  top          :        queue -> Elem   ​(operatorul de vizualizare a elementului din vârful cozii)+
 </​file>​ </​file>​
-  ​ +  ​* ''​rotate''​ calculează (cu evaluare întârziată) rezultatul ''​%%left ++ (reverse right)%%''​ 
-Această reprezentare pentru coadă asigură cost amortizat O(1pentru operațiile de enqueue ​și dequeue. Vom folosi această reprezentare pentru câmpul queue al structurii counterîntrucât este mai eficientă decât reprezentarea cu liste Racket ​din etapele ​1 și 2.+  * rotația se efectuează doar atunci când ''​%%size(left) = size(right) - 1%%'',​ așadar găsește un număr echilibrat ​de elemente în cele două stive 
 +  * la fiecare extragere din ''​left'',​ extragem ("​pop"​) ​și un element din ''​right''​ pe care îl adăugăm ("​push"​) în acumulatorul ''​Acc''​ 
 +  * când ''​left''​ devine goală, ''​right''​ conține un singur element (''​%%size(left) = size(right) - 1%%''​),​ iar ''​Acc''​ conține toate elementele aflate inițial în ''​right'',​ în ordine inversă; acum adăugăm elementul ​din ''​right''​ la începutul ''​Acc''​ (în timp ''​O(1)''​), ​și acesta este exact conținutul cu care trebuie să reinițializăm stiva ''​left''​
  
-După ce ați finalizat implementarea TDA-ului, continuați dezvoltarea simulatorului în fișierul **supermarket.rkt**. (Observație:​ pe vmchecker veți încărca o arhivă .zip cu fișierele queue.rkt și supermarket.rkt.) 
-   
-În primul rând, va trebui să adaptați o serie de funcții de la etapa 2 astfel încât ele să țină cont de noua reprezentare (în care câmpul queue din structura counter este de tip coadă (queue) - TDA-ul implementat de voi; este o coincidență că numele câmpului coincide cu numele tipului, în niciun caz nu era necesar acest lucru). 
- 
-În plus față de etapa anterioară,​ în această etapă simulatorul trebuie să modeleze trecerea timpului. Până acum, simulatorul trata așezările la cozi, întârzierile și deschiderile de noi case ca și cum s-ar produce în ordine, dar la un același moment de timp. Acest lucru nu corespunde realității - între diversele evenimente este firesc să treacă timp, timp în care clienții avansează la case și, la un moment dat, părăsesc supermarketul. 
- 
-Exceptând adaptările menționate,​ funcțiile principale pe care va trebui să le implementați sunt: 
-<​file>​ 
-(pass-time-through-counter minutes) 
-</​file>​ 
-  * este o funcție curry (aplicată doar pe un număr de minute, va aștepta un al doilea argument de tip counter) 
-  * odată ce și-a primit (pe rând) argumentele,​ pass-time-through-counter actualizează tt-ul și et-ul casei în tt-ul și et-ul pe care casa ar trebui să le aibă după trecerea numărului dat de minute 
-  * queue-ul casei nu se modifică, pentru că intenția este de a nu folosi niciodată această funcție pentru a avansa cu un număr de minute mai mare decât timpul până la ieșirea primului client din coadă 
-  ​ 
 Exemplu: ​ Exemplu: ​
-<​code ​lisp+<​code ​scheme
-((pass-time-through-counter 5)  +(rotate ​(stream-cons 1 (stream-cons 2 (stream-cons 3 empty-stream))) 
- ​(counter ​ +        ​'​(7 ​6 5 4) 
-          12  +        empty-stream)
-          7  +
-          ​(make-queue '() '((ada . 7)) 0 1)))+
 </​code>​ </​code>​
 => =>
-''​%%(counter ​2 (queue '​() ​'((ada . 7)) 0 1))%%'' ​+''​%%#<​stream>​%%''​ \\ 
 +Mai precis, rezultatul este de forma: 
 +<code scheme>​ 
 +(stream-cons ​ 
 +             ​(rotate (stream-cons ​2 (stream-cons 3 empty-stream)) 
 +                     '(6 5 4) 
 +                     (stream-cons ​empty-stream))
 +</​code>​ 
 +și, conform comportamentului constructorului ''​stream-cons'',​ apelul recursiv al funcției ''​rotate''​ este întârziat. 
 +Când accesăm restul acestui flux (de exemplu, la ''​dequeue''​),​ evaluăm apelul întârziat,​ obținând un rezultat de forma ''​%%(stream-cons 2 (rotate ....))%%''​, etc.  
 + 
 +După ce ați finalizat implementarea TDA-ului, continuați implementarea în fișierul **etapa4.rkt**. 
 +  
 +Față de etapa anterioară,​ simulatorul tratează două cereri noi: 
 +  * ''​(close index)''​ solicită închiderea casei cu indexul ''​index'',​ și redistribuirea clienților din coadă (cu excepția primului) 
 +  * ''​(open index)''​ solicită deschiderea casei cu indexul ''​index''​ 
 +Apare distincția între case deschise și case închise: în această etapă, cererile de tip "​așezare la o casă",​ respectiv "​ensure"​ iau în considerare doar casele deschise. Modul în care reprezentați starea caselor (deschisă/​închisă) este la alegerea voastră.
  
-<​file>​ 
-(serve requests fast-counters slow-counters) 
-</​file>​ 
-  * serve actualizează casele din fast-counters și slow-counters pe măsură ce situația lor evoluează, pe baza listei ''​%%requests%%''​ în care elementele sunt: 
-    * cereri (așezări la coadă, întârzieri,​ ajustări ale numărului de case) \\ sau  
-    * timpi care trec între cereri 
  
-Exemplu:  +Exemplu ​pentru ''​ITEMS = 5''​
-<​code ​lisp+<​code ​scheme
-(serve '​((ana ​14) (mia 2) 5 (ion 7) (delay 1 2) 7)+(serve '​((ana ​7) (mia 2) 5 (ion 8) (dan 6) (close 2) (delay 1 15) (ema 2) (open 2) 2 (geo 5) (close 1) (ensure ​7))
        (list (empty-counter 1))        (list (empty-counter 1))
        (list (empty-counter 2) (empty-counter 3)))        (list (empty-counter 2) (empty-counter 3)))
-</​code> ​pentru ITEMS = 5:  +</​code>​ 
-  * observăm că avem o casă fast (o vom numi C1) și case slow (le vom numi C2 și C3) +  * avem o casă fast (o numim ''​C1''​) și două case slow (le numim ''​C2'' ​și ''​C3''​) 
-  * primele ​cereri distribuie cei clienți astfel: +  * când ilustrăm starea caselor: 
-    * ana la C2 => ''​%%C2 = (counter 2 14 14 (queue ​'() '((ana . 14)) 0 1))%%''​ +    * o casă este o colecție de ''​index'',​ ''​tt'',​ ''​et''​ și ''​queue''​ (dar puteți modifica structura, dacă doriți) 
-    * mia la C1 => ''​%%C1 = (counter 1 2 2 (queue ​'() '((mia . 2)) 1))%%''​ +    * vizualizăm elementele fluxurilor între acolade (în loc să scriem ''#<​stream>'',​ ceea ce nu este tocmai informativ
-  * apoi trec 5 minute, după care situația ​trebuie să fie+  * primele ​două cereri distribuie cei doi clienți astfel: 
-    * mia a ieșit de la C1, care a rămas goală => ''​%%C1 = (counter 1 0 0 (queue ​'​() ​'() 0 0))%%''​ +    * ''​ana'' ​la ''​C2'' ​=> ''​%%C2 = (counter 2 7 7 (queue ​{(ana . 7)'​() ​0))%%''​  
-    * la C2 au trecut 5 minute => ''​%%C2 = (counter 2 9 9 (queue ​'() '((ana . 14)) 0 1))%%''​ +    * ''​mia'' ​la ''​C1'' ​=> ''​%%C1 = (counter 1 2 2 (queue ​{(mia . 2)} '() 1 0))%%''​ 
-    * C3 a rămas cum era: goală și neîntârziată => ''​%%C3 = (counter 3 0 0 (queue ​'​() ​'() 0 0))%%''​ +    * obs: în etapa trecută ''​ana''​ și ''​mia''​ apăreau ca elemente în stiva ''​right'';​ acum ele sunt în stiva ''​left'',​ deoarece s-a efectuat o rotație, necesară pentru menținerea invariantului ''​%%size(left) ≥ size(right)%%''​  
-    au părăsit supermarketul,​ în ordine: ''​%%'((mia))%%'' ​(mia de la C1+  * apoi trec ''​5'' ​minute, după care situația ​este
-  * ion se așază la C3 => ''​%%C3 = (counter ​3 7 7 (queue '() '((ion . 7)) 1))%%''​ +    * ''​mia'' ​a ieșit de la ''​C1''​, care a rămas goală => ''​%%C1 = (counter 1 0 0 (queue ​{} '() 0 0))%%''​ 
-  * C1 este întârziată cu minute => ''​%%C1 = (counter 1 2 2 (queue '() '​() ​0))%%''​ +    * la ''​C2'' ​au trecut ​''​5'' ​minute => ''​%%C2 = (counter 2 2 2 (queue ​{(ana . 7)'​() ​0))%%''​ 
-  * apoi trec minute, după care situația ​trebuie să fie+    * ''​C3'' ​a rămas cum era: goală și neîntârziată => ''​%%C3 = (counter 3 0 0 (queue ​{} '() 0 0))%%''​ 
-    * întârzierea de la C1 s-a consumat => ''​%%C1 = (counter 1 0 0 (queue ​'​() ​'() 0 0))%%''​ +  următoarele două cereri distribuie cei doi clienți astfel: 
-    * la C2 au trecut 7 minute ​=> ''​%%C2 = (counter 2 2 2 (queue '() '((ana 14)) 0 1))%%''​ +    * ''​ion''​ la ''​C3''​ => ''​%%C3 = (counter 3 8 8 (queue {(ion 8)} '() 1 0))%%''​ 
-    ion ieșit de la C3, care a rămas goală => ''​%%C3 = (counter ​3 0 0 (queue ​'() '​() ​0))%%''​ +    * ''​dan'' ​la ''​C2''​ => ''​%%C2 = (counter 2 8 2 (queue {(ana . 7)} '((dan . 6)) 1 1))%%''​ 
-    au părăsit supermarketul,​ în ordine:: ​''​%%'((1 . mia) (ion))%%'' ​+  * ''​C2'' ​se închide => ''​ana''​ rămâne la ''​C2'',​ iar ''​dan''​ se mută la ''​C3''​ 
 +    * => ''​%%C2 = (counter ​2 2 2 (queue ​{(ana . 7)} '​() ​1 0))%%'' și nu mai primește clienți 
 +    * => ''​%%C3 = (counter 3 14 8 (queue {(ion . 8)} '((dan . 6)) 1 1))%%''​ 
 +  * ''​C1'' ​este întârziată cu ''​15'' ​minute => ''​%%C1 = (counter 1 15 15 (queue ​{} '​() ​0 0))%%'
 +  * ''​ema''​ se așază la ''​C3''​ => ''​%%C3 = (counter 3 16 8 (queue {(ion . 8<​flux-neevaluat-care-va-produce-dan-și-ema>​} '() 3 0))%%''​ 
 +    * ''​C2''​ are ''​tt''​ mai mic, însă ''​C2''​ este închisă, deci se alege între ''​C1''​ și ''​C3''​ 
 +  * ''​C2''​ se deschide, fără să producă alte modificări 
 +  * apoi trec ''​2'' ​minute, după care situația ​este
 +    * întârzierea de la ''​C1'' ​s-a consumat ​parțial ​=> ''​%%C1 = (counter 1 13 13 (queue ​{} '() 0 0))%%''​ 
 +    * ''​ana''​ a ieșit de la ''​C2'' ​=> ''​%%C2 = (counter 2 0 0 (queue ​{} '​() ​0 0))%%'
 +    * la ''​C3''​ au trecut ''​2''​ minute => ''​%%C3 = (counter 3 14 6 (queue {(ion 8<​flux...>​} '(0))%%''​ 
 +  ''​geo''​ se ază la ''​C2'' ​=> ''​%%C2 = (counter ​2 5 5 (queue ​{(geo . 5)'​() ​0))%%''​ 
 +  ''​C1''​ se închide, fără să producă alte modificări 
 +  * ''​ensure''​ compară media timpilor totali ai caselor deschise cu ''​7''​ 
 +    * ''​tt2''​ + ''​tt3''​ = ''​5''​ + ''​14''​ = ''​19''​ => ''​tt-mediu = 19 / 2 > 7''​ 
 +    * ''​tt1''​ nu participă la medie întrucât ''​C1''​ este închisă 
 +    * se adaugă o casă slow goală (''​C4''​) => ''​tt-mediu = 19 / 3 ≤ 7''​ (deci ne oprim aici cu adăugarea) 
 +Rezultat final: 
 +<code scheme>​ 
 +(list 
 + '((1 . mia) (ana)) 
 + (cons 2 (queue #<​stream> ​'() 1 0)) 
 + (cons 3 (queue #<​stream> ​'() 3 0))) 
 +</​code>​
  
pp/26/teme/racket-supermarket.1773825505.txt.gz · Last modified: 2026/03/18 11:18 by mihaela.balint
CC Attribution-Share Alike 3.0 Unported
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0