This is an old revision of the document!


Etapa 4

În această etapă veți observa 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 la etapa anterioară (folosind valorile de tip coadă doar prin intermediul interfeței), vă veți bucura de faptul că nu trebuie să modificați nimic în fișierul supermarket.rkt pentru a lucra cu această nouă reprezentare. Volumul de lucru este diminuat (relativ la etapele precedente), dar vă încurajăm să folosiți timpul suplimentar pentru a înțelege în profunzime felul în care ne ajută fluxurile.

Veți începe rezolvarea etapei prin a reimplementa TDA-ul queue în fișierul queue.rkt.

Din motive de performanță explicate în detaliu în schelet, vom reprezenta câmpul left al structurii queue ca flux (spre deosebire de reprezentarea ca listă din etapa anterioară). Reamintim definiția structurii (care nu s-a modificat):

(define-struct queue (left right size-l size-r))
  • în continuare, fiecare adăugare în coadă va fi o adăugare în stiva right
  • în continuare, fiecare scoatere din coadă va fi o scoatere din stiva left
  • după fiecare operație enqueue sau dequeue vom avea grijă să menținem invariantul |left| ≥ |right| (dimensiunea stivei left trebuie să fie mai mare sau egală decât dimensiunea stivei right); astfel, stiva left nu va fi niciodată găsită vidă de o operație de dequeue, și nu vom avea nevoie să facem un dequeue costisitor prin mutarea în timp O(n) a tuturor elementelor din right în left
  • de fiecare dată când o operație de enqueue sau dequeue ne aduce în situația |left| = |right| - 1, vom aplica o rotație: vom muta în acel moment toate elementele din right în left, însă, left fiind flux, elementele vor fi mutate, în fapt, unul câte unul, pe măsură ce avem nevoie să extragem elemente din left, nu toate deodată (dacă ar fi deodată nu am rezolva problema complexității, ci doar am muta-o asupra altor operații)

Sarcina voastră este să reimplementați interfața TDA-ului queue (aceleași funcții pe care le-ați implementat în etapa 3). Aceasta depinde de implementarea funcției de rotație:

(rotate left right Acc)
  • funcția calculează (cu evaluare întârziată) rezultatul left ++ (reverse right)
  • rotația se efectuează doar atunci când |left| = |right| - 1, așadar găsește un număr echilibrat de elemente în cele două stive
  • de fiecare dată când extragem un element din left, vom extrage (“pop”) și unul din right și îl vom adăuga (“push”) în acumulatorul Acc
  • când left devine goală, automat right conține un singur element (|left| = |right| - 1), iar toate celelalte elemente care au fost în right se găsesc în Acc, deja inversate; acum putem adăuga 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:

(rotate (stream-cons 1 (stream-cons 2 (stream-cons 3 empty-stream)))
        '(7 6 5 4)
        empty-stream)

#<stream>
Mai precis, rezultatul este de forma:

(stream-cons 1 
             (rotate (stream-cons 2 (stream-cons 3 empty-stream))
				         '(6 5 4)
							(stream-cons 7 empty-stream)))

și, după cum știm din comportamentul constructorului stream-cons, apelul recursiv al funcției rotate este întârziat. Dacă ulterior vom accesa restul acestui flux, vom evalua noul apel al lui rotate și vom obține un rezultat de forma (stream-cons 2 (rotate ....)), etc.

După ce ați finalizat implementarea TDA-ului, continuați dezvoltarea simulatorului în fișierul supermarket.rkt.

Simulatorul trebuie să modeleze toate situațiile de la etapa anterioară, plus situația în care o casă este închisă.

Exemplu:

(serve '((ana 7) (mia 2) 5 (ion 8) (close 2) (delay 1 10) (dan 2) 3 (ensure 5))
       (list (empty-counter 1))
       (list (empty-counter 2) (empty-counter 3)))

pentru ITEMS = 5:

  • observăm că avem o casă fast (o vom numi C1) și 2 case slow (le vom numi C2 și C3)
  • pentru a ilustra starea caselor vom folosi:
    • reprezentarea unui counter ca o colecție de index, tt, et și queue (deși în această etapă aveți libertatea să modificați structura, dacă doriți)
    • reprezentarea elementelor unui flux între acolade (altfel ar trebui să scriem #stream, ceea ce nu este tocmai informativ)
  • primele 2 cereri distribuie cei 2 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, dar aici sunt în stiva left pentru că s-a efectuat o rotație, necesară pentru menținerea invariantului |left| ≥ |right|
  • apoi trec 5 minute, după care situația caselor trebuie să fie:
    • 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))
  • ion se așază la C3 ⇒ C3 = (counter 3 8 8 (queue {(ion . 8)} '() 1 0))
  • C2 este închisă ⇒ nu poate primi clienți noi, dar funcționează normal până la golirea cozii
  • C1 este întârziată cu 10 minute ⇒ C1 = (counter 1 10 10 (queue {} '() 0 0))
  • dan se așază la C3 ⇒ C3 = (counter 3 10 8 (queue {(ion . 8)} '((dan . 2)) 1 1))
    • C2 avea tt-ul mai mic, însă C2 este închisă, deci s-a ales între C1 și C3
  • apoi trec 3 minute, după care situația caselor trebuie să fie:
    • întârzierea de la C1 s-a consumat parțial ⇒ C1 = (counter 1 7 7 (queue {} '() 0 0))
    • ana a ieșit de la C2, care a rămas goală ⇒ C2 = (counter 2 0 0 (queue {} '() 0 0))
    • la C3 au trecut 3 minute ⇒ C3 = (counter 3 7 5 (queue {(ion . 8)} '((dan . 2)) 1 1))
  • ensure compară media timpilor totali ai caselor deschise cu 5
    • tt1 + tt3 = 7 + 7 = 14 ⇒ ttmed = 14 / 2 > 5
    • tt2 nu participă la medie întrucât C2 este închisă
    • se adaugă o casă slow goală (C4) ⇒ ttmed = 14 / 3 ≤ 5 (deci ne oprim aici cu adăugarea)
pp/21/teme/racket-teste-enunt.1616622087.txt.gz · Last modified: 2021/03/24 23:41 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