Differences

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

Link to this comparison view

pp:26:teme:racket-supermarket [2026/03/12 09:48]
mihaela.balint
pp:26:teme:racket-supermarket [2026/03/26 08:55] (current)
mihaela.balint
Line 1: Line 1:
-===== Etapa =====+===== Etapa =====
  
-Etapa 2 își propune exploatarea faptului că funcțiile sunt valori ​de ordinul întâi. Veți defini funcții curry, veți abstractiza funcții cu implementări similare, ​și veți folosi funcționale - atât implementări propriicât și funcționalele predefinite în Racket. Vă încurajăm ​să valorificați oportunitățile ​de utilizare a funcțiilor anonime și funcționalelor, inclusiv când enunțul nu impune acest lucru.+Etapa 4 oferă un exemplu interesant ​de utilizare a fluxurilor. Veț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
  
-În această etapănumărul de case din magazin nu mai este fixatAvem: +Din nourezolvarea etapei începe cu implementarea TDA-ului ''​queue''​ în fișierul **queue.rkt**
-  * o listă fast-counters ​de case care acceptă doar clienți care au cumpărat maxim ITEMS produse + 
-  * o listă slow-counters de case deschise tuturor clienților +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ă:
-Pentru ​ca în viitor să putem determina ordinea ieșirii clienților din magazin, introducem un nou câmp în structura counter:+
 <code scheme> <code scheme>
-(define-struct ​counter (index tt et queue))+(define-struct queue (left right size-l size-r))
 </​code>​ </​code>​
-  * ''​et''​ +  * o adăugare în coadă este o adăugare în stiva ''​right'' ​(ca înainte) 
-    vine de la "exit time", și reprezintă timpul rămas până când primul client ​din coadă ​va părăsi această casă +  o extragere ​din coadă ​este o extragere din stiva ''​left''​ (ca înainte) 
-    depinde de numărul de produse cumpărate de acest client ​(1 produs = 1 minutși de eventualele întârzieri suferite de casă  +  după fiecare operație ''​enqueue''​ sau ''​dequeue''​ trebuie menținut invariantul ​ ''​%%size(left≥ size(right)%%'';​ astfel, niciun ''​dequeue''​ nu va găsi stiva ''​left''​ vidă  
- +  * când o operație ''​enqueue''​ sau ''​dequeue''​ produce ​situația ''​%%size(left) = size(right) - 1%%''​aplicăm o **rotație**:  
-Simulatorul trebuie să modeleze atât situațiile de la etapa anterioarăcât și două noi situații+    mutăm "în mod leneș" toate elementele din ''​right''​ în ''​left''​ 
-  când cel mai avansat client (din punct de vedere al exit time-ului) părăsește magazinul +    ce înseamnă "leneș": elementele vor fi mutate, de 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
-  când este necesară deschiderea unor noi case, pentru a micșora media timpilor totali de așteptare +   
- +Veți redefini interfața din etapa 3. Noile implementări depind de implementarea funcției de rotație:
-Inițialveți adapta o serie de funcții de la etapa 1 la noua reprezentare (adică la numărul variabil de case și la prezența câmpului ​''​et'' ​în structură). +
- +
-Apoi, funcțiile principale pe care va trebui să le implementați sunt: +
 <​file>​ <​file>​
-(update f counters index)+(rotate left right Acc)
 </​file>​ </​file>​
-  * update aplică transformarea ​''​f'' ​casei din ''​counters'' ​care are indexul ​''​index'',​ și întoarce lista ''​counters'' ​actualizată +  * ''​rotate''​ calculează (cu evaluare întârziată) rezultatul ​''​%%left ++ (reverse right)%%''​ 
-  ​+  * 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''​ 
 Exemplu: ​ Exemplu: ​
 <code scheme> <code scheme>
-(update ​(λ (C) (struct-copy counter C [tt 0])) +(rotate ​(stream-cons 1 (stream-cons 2 (stream-cons 3 empty-stream))) 
-        ​(list (counter 1 2 2 '()) (counter 2 5 '())+        '(7 6 4
-        ​2)+        ​empty-stream)
 </​code>​ </​code>​
-=> +=> 
 +''​%%#<​stream>​%%''​ \\ 
 +Mai precis, rezultatul este de forma:
 <code scheme> <code scheme>
-(list (counter 1 2 '()) (counter 2 0 '()))+(stream-cons 1  
 +             (rotate (stream-cons ​2 (stream-cons 3 empty-stream)) 
 +                     '​(4) 
 +                     (stream-cons 7 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>​ 
-(remove-first-from-counter C) 
-</​file>​ 
-  * remove-first-from-counter scoate prima persoană din coada casei ''​C''​ 
-  * ''​tt''​-ul și ''​et''​-ul casei ''​C''​ trebuie ajustate în consecință ​ 
-    * orice întârziere avea casa, ea dispare 
-    * dispar produsele clientului care pleacă (și minutele asociate acestora) 
-    * nicio altă casă nu este afectată (este ca și cum ar fi trecut timpul doar pe la casa ''​C'';​ acest lucru se va schimba în etapa 3) 
  
-Exemplu:+Exemplu ​pentru ''​ITEMS = 5''​:
 <code scheme> <code scheme>
-(remove-first-from-counter ​(counter ​50 '((ana . 3) (leo . 35) (mia . 10))))+(serve '((ana 7) (mia 2) 5 (ion 8) (dan 6) (close 2) (delay ​15) (ema 2) (open 2) 2 (geo 5(close 1) (ensure 7)) 
 +       (list (empty-counter 1)) 
 +       (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''​) 
 +  * 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: 
 +    * ''​ana''​ la ''​C2'' ​=> ''​%%C2 = (counter 2 7 7 (queue {(ana . 7)} '() 1 0))%%''​  
 +    * ''​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: 
 +    * ''​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 2 2 (queue {(ana . 7)} '() 1 0))%%''​ 
 +    * ''​C3''​ a rămas cum era: goală și neîntârziată => ''​%%C3 = (counter 3 0 0 (queue {} '() 0 0))%%''​ 
 +  * următoarele două cereri distribuie cei doi clienți astfel: 
 +    * ''​ion''​ la ''​C3''​ => ''​%%C3 = (counter 3 8 8 (queue {(ion . 8)} '() 1 0))%%''​ 
 +    * ''​dan''​ la ''​C2''​ => ''​%%C2 = (counter 2 8 2 (queue {(ana . 7)} '((dan . 6)) 1 1))%%''​ 
 +  * ''​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...>​} '() 3 0))%%''​ 
 +  * ''​geo''​ se așază la ''​C2''​ => ''​%%C2 = (counter 2 5 5 (queue {(geo . 5)} '() 1 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> <code scheme>
-(counter 1 45 35 '((leo 35) (mia 10)))+(list 
 + '((mia) (ana)) 
 + (cons 2 (queue #<​stream>​ '() 1 0)) 
 + (cons 3 (queue #<​stream>​ '() 3 0)))
 </​code>​ </​code>​
- 
-<​file>​ 
-(serve requests fast-counters slow-counters) 
-</​file>​ 
-  * serve primește o listă de cereri (așezări la coadă, întârzieri,​ ieșiri de la casă, ajustări ale numărului de case) și le tratează în ordine, în sensul că actualizează casele din ''​fast-counters''​ și ''​slow-counters''​ pe măsură ce situația lor evoluează 
- 
-Exemplu (pentru ''​ITEMS = 5''​): ​ 
-<code scheme> 
-(serve '((ana 8) (mia 2) (mara 14) (ion 7) (remove-first) (ensure 5) (remove-first)) 
-       (list (empty-counter 1) (empty-counter 2)) 
-       (list (empty-counter 3) (empty-counter 4))) 
-</​code>  ​ 
-        
-  * observăm că avem două case fast (pentru simplitate le numim ''​C1''​ și ''​C2''​) și două case slow (le numim ''​C3''​ și ''​C4''​) 
-  * primele 4 cereri distribuie cei 4 clienți astfel: 
-    * ''​ana''​ la ''​C3''​ (prima casă slow cu ''​tt=0''​) => ''​%%C3 = (counter 3 8 8 '((ana . 8)))%%''​ 
-    * ''​mia''​ la ''​C1''​ (prima casă fast cu ''​tt=0''​) => ''​%%C1 = (counter 1 2 2 '((mia . 2)))%%''​ 
-    * ''​mara''​ la ''​C4''​ (casa slow cu ''​tt''​ minim) ​ => ''​%%C4 = (counter 4 14 14 '​((mara . 14)))%%''​ 
-    * ''​ion''​ la ''​C3''​ (casa slow cu ''​tt''​ minim) ​  => ''​%%C3 = (counter 3 15 8 '((ana . 8) (ion . 7)))%%''​ 
-  * remove-first scoate cel mai avansat client: 
-    * cel mai avansat client este ''​mia''​ (''​et=2''​) 
-    * ea este scoasă de la ''​C1'' ​            => ''​%%C1 = (counter 1 0 0 '​())%%''​ (observați ''​tt''​ și ''​et''​) 
-  * ensure compară media timpilor totali cu ''​5'':​ 
-    * ''​tt1 + tt2 + tt3 + tt4 = 0 + 0 + 15 + 14 = 29''​ => ''​ttmed = 29 / 4 > 5''​ 
-    * se adaugă o casă slow goală (''​C5''​) => ''​ttmed = 29 / 5 > 5''​ 
-    * se adaugă o casă slow goală (''​C6''​) => ''​ttmed = 29 / 6 ≤ 5''​ (deci putem trece la cererea următoare) 
-  * remove-first scoate cel mai avansat client: 
-    * cel mai avansat client este ''​ana''​ (''​et=8''​)  ​ 
-    * ea este scoasă de la ''​C3'' ​            => ''​%%C3 = (counter 3 7 7 '((ion . 7)))%%''​ (observați ''​tt''​ și ''​et''​) 
  
pp/26/teme/racket-supermarket.1773301726.txt.gz · Last modified: 2026/03/12 09:48 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