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 12:06]
mihaela.balint
pp:26:teme:racket-supermarket [2026/03/26 08:55] (current)
mihaela.balint
Line 1: Line 1:
-===== Etapa =====+===== Etapa =====
  
-Etapa 3 subliniază importanțabstractizăriiVă veți defini propriul ​TDA (tip de date abstract) cu o interfață completă (un set de constructori ​și operatori) prin care utilizatorul poate manipula valorile tipuluiindependent ​de implementarea din spate. Apoivoi înșivă trebuie să folosiți TDA-ul doar prin intermediul interfeței (aspect esențial pentru o dezvoltare facilă în etapa 4)+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 3funcțiile implementate anterior vor funcționa fără modificări pe noua reprezentare
  
-Rezolvarea ​etapei începe cu implementarea TDA-ului ''​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 scheme> <code scheme>
 (define-struct queue (left right size-l size-r)) (define-struct queue (left right size-l size-r))
 </​code>​ </​code>​
-  ​* ''​left'',​ ''​right''​ +  * o 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 o extragere din stiva ''​left''​ (ca înainte
-    ​* o adăugare în coadă este 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**:​  
-    * o extragere din coadă este o extragere din stiva ''​left''​ (când ''​left''​ este vidă, mutăm toate elementele din right în left, apoi extragem 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 faptunul 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 extragere\\ extrag din coada cu ''​%%left = '​()%%''​''​%%right = '(2 1)%%''​ => \\ ''​%%left = '(1 2)%%''​''​%%right = '​()%%''​ (după mutarea elementelor) => \\ ''​%%left = '(2)%%'', ​''​%%right = '()%%''​ (după extragerea 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 extras (first-in-first-out+
-  ​* ''​size-l'',​ ''​size-r''​ +
-    * sunt numere naturale, reprezentând numărul de elemente din cele două 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 extragere 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 asigură cost amortizat ​''​O(1)'' ​pentru operațiile de ''​enqueue''​ și ''​dequeue''​. Vom folosi acest TDA pentru câmpul ​''​queue'' ​al structurii ​''​counter'', ​optimizând 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 implementarea în fișierul **etapa3.rkt**. ​ 
-   
-Mai întâi, adaptați funcțiile 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''​);​ este o coincidență că numele câmpului coincide cu numele tipului, nu o necesitate). 
- 
-În această etapă simulatorul modelează, în plus, trecerea timpului. Anterior, 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 evenimente este firesc să treacă timp, timp în care clienții avansează la case și, la un moment dat, părăsesc magazinul. 
- 
-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ă parțial 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 pentru a reflecta trecerea numărului dat de minute 
-  * câmpul ''​queue''​ nu se modifică, deoarece intenția este să folosim această funcție doar cu timpi mai mici sau egali cu timpul până la ieșirea primului client din coadă 
-  ​ 
 Exemplu: ​ Exemplu: ​
 <code scheme> <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>​
 => =>
 +''​%%#<​stream>​%%''​ \\
 +Mai precis, rezultatul este de forma:
 <code scheme> <code scheme>
-(counter ​2 (queue '​() ​'((ada . 7)) 0 1))+(stream-cons ​ 
 +             ​(rotate (stream-cons ​2 (stream-cons 3 empty-stream)) 
 +                     '(6 5 4) 
 +                     (stream-cons ​empty-stream)))
 </​code>​ </​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 pentru ''​ITEMS = 5'': ​+Exemplu pentru ''​ITEMS = 5'':​
 <code scheme> <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>​ </​code>​
-  +  ​* avem o casă fast (o numim ''​C1''​) și două case slow (le numim ''​C2''​ și ''​C3''​
-  ​observăm că avem o casă fast (o numim ''​C1''​) și două case slow (le numim ''​C2''​ și ''​C3''​)+  * când ilustrăm starea caselor: 
 +    * o casă este o colecție de ''​index'',​ ''​tt'',​ ''​et''​ și ''​queue''​ (dar puteți modifica structura, dacă doriți) 
 +    * vizualizăm elementele fluxurilor între acolade (în loc să scriem ''#<​stream>'',​ ceea ce nu este tocmai informativ)
   * primele două cereri distribuie cei doi clienți astfel:   * primele două cereri distribuie cei doi clienți astfel:
-    * ''​ana''​ la ''​C2''​ => ''​%%C2 = (counter 2 14 14 (queue ​'() '((ana . 14)) 0 1))%%''​ +    * ''​ana''​ la ''​C2''​ => ''​%%C2 = (counter 2 7 7 (queue ​{(ana . 7)'​() ​0))%%''​  
-    * ''​mia''​ la ''​C1''​ => ''​%%C1 = (counter 1 2 2 (queue ​'() '((mia . 2)) 1))%%''​+    * ''​mia''​ la ''​C1''​ => ''​%%C1 = (counter 1 2 2 (queue ​{(mia . 2)} '() 1 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)%%'' ​
   * apoi trec ''​5''​ minute, după care situația este:   * apoi trec ''​5''​ minute, după care situația este:
-    * ''​mia''​ a ieșit de la ''​C1'',​ care a rămas goală => ''​%%C1 = (counter 1 0 0 (queue ​'​() ​'() 0 0))%%''​ +    * ''​mia''​ a ieșit de la ''​C1'',​ care a rămas goală => ''​%%C1 = (counter 1 0 0 (queue ​{} '() 0 0))%%''​ 
-    * la ''​C2''​ au trecut ''​5''​ minute => ''​%%C2 = (counter 2 9 9 (queue ​'() '((ana . 14)) 0 1))%%''​ +    * la ''​C2''​ au trecut ''​5''​ minute => ''​%%C2 = (counter 2 2 2 (queue ​{(ana . 7)'​() ​0))%%''​ 
-    * ''​C3''​ a rămas cum era: goală și neîntârziată => ''​%%C3 = (counter 3 0 0 (queue ​'​() ​'() 0 0))%%''​ +    * ''​C3''​ a rămas cum era: goală și neîntârziată => ''​%%C3 = (counter 3 0 0 (queue ​{} '() 0 0))%%''​ 
-    au părăsit magazinul, în ordine: ''​%%'((1 . mia))%%''​  +  următoarele două cereri distribuie cei doi clienți astfel: 
-  * ''​ion''​ se așază la ''​C3''​ => ''​%%C3 = (counter ​3 7 7 (queue '() '((ion . 7)) 1))%%''​ +    * ''​ion''​ la ''​C3''​ => ''​%%C3 = (counter 3 8 8 (queue {(ion . 8)} '​() ​0))%%''​ 
-  * ''​C1''​ este întârziată cu ''​2''​ minute => ''​%%C1 = (counter 1 2 2 (queue '() '​() ​0))%%''​ +    * ''​dan''​ la ''​C2''​ => ''​%%C2 = (counter 2 8 2 (queue {(ana 7)} '((dan . 6)) 1 1))%%''​ 
-  * apoi trec ''​7''​ minute, după care situația este: +  * ''​C2''​ se închide => ''​ana''​ rămâne la ''​C2'',​ iar ''​dan''​ se mută la ''​C3''​ 
-    * întârzierea de la ''​C1''​ s-a consumat => ''​%%C1 = (counter 1 0 0 (queue '() '() 0 0))%%''​ +    * => ''​%%C2 = (counter ​2 2 2 (queue ​{(ana . 7)} '​() ​1 0))%%'' și nu mai primește clienți 
-    * la ''​C2''​ au trecut ''​7''​ minute => ''​%%C2 = (counter ​2 2 2 (queue ​'() '((ana . 14)) 0 1))%%''​ +    * => ''​%%C3 = (counter 3 14 8 (queue {(ion . 8)} '((dan . 6)) 1 1))%%''​ 
-    * ''​ion''​ a ieșit de la ''​C3''​, care a rămas goală ​=> ''​%%C3 = (counter ​3 0 0 (queue ​'() '​() ​0))%%''​ +  * ''​C1''​ este întârziată cu ''​15''​ minute => ''​%%C1 = (counter 1 15 15 (queue ​{} '​() ​0 0))%%'
-    au părăsit magazinul, în ordine:: ​''​%%'((1 . mia) (ion))%%'' ​+  * ''​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.1773828408.txt.gz · Last modified: 2026/03/18 12:06 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