• Nenhum resultado encontrado

Servirea clienŃilor la o coadă

Sisteme expert în condi Ń ii de timp real

12.1. Servirea clienŃilor la o coadă

EnunŃul problemei este următorul: se doreşte simularea unei cozi de aşteptare la un ghişeu. Coada e formată din clienŃi iar la ghişeu există un funcŃionar care serveşte clienŃii. Pentru a servi un client, funcŃionarul consumă o cuantă de timp, întotdeauna aceeaşi. ApariŃia clienŃilor în coadă se face la momente aleatorii de timp. Cel servit este primul din coadă, iar ultimul venit intră la urma cozii.

Există două tipuri de evenimente externe în această problemă: intrarea clienŃilor în coadă şi tactul ceasului de timp real. Să numim evenimentele din prima categorie – evenimente client, şi pe cele din a doua – evenimente ceas. ApariŃia evenimentelor client e aleatorie în timp, pe când apariŃia evenimentelor ceas se face întotdeauna după acelaşi interval de timp – cuanta de timp pe care o considerăm propice problemei noastre. Pentru simularea activităŃii la o coadă secunda e o cuantă de timp prea fină iar ora prea grosieră. Cea care convine e minutul.

Într-o primă variantă, vom simula apariŃia evenimentelor client de o manieră statică, adică memorând în fapte apariŃia acestor evenimente. Dimpotrivă vom lăsa pe seama unei reguli simularea evenimentelor ceas.

Grupul de fapte evenimente memorează faptele ce descriu evenimentele externe: ceasul – în formatul (ceas <minut>) şi apariŃia clienŃilor în coadă – în formatul (client <nume> <momentul apariŃiei>). Ceasul este iniŃializat la momentul 0:

(deffacts evenimente (ceas 0)

(client Ion 0) (client Matei 1) (client Mircea 4)

Sisteme expert în condiŃii de timp real 167

(client Maria 11) )

Grupul parametri memorează parametrii simulării – în cazul de faŃă numai timpul de servire al unui client (presupus întotdeauna acelaşi):

(deffacts parametri (timp-servire 3) )

Grupul date conŃine alte fapte ce ajută la simulare: coada – iniŃial goală, un indicator care Ńine starea funcŃionarului (liber ori ocupat) şi un contor al timpului rămas pentru servirea unui client:

(deffacts date (coada)

(functionar liber) (trsc 0)

)

Regula de apariŃie în coadă a unui client se activează dacă ceasul ajunge la momentul în care trebuie luat în considerare un client pentru că acesta intră în coadă. AcŃiunile efectuate sunt: retragerea faptului ce memorează apariŃia clientului – consumat – şi introducerea numelui clientului în extremitatea dreaptă a cozii:

(defrule vine-client (ceas ?t)

?cl <- (client ?nume ?t) ?co <- (coada $?sir-clienti) =>

(retract ?cl ?co)

(assert (coada $?sir-clienti ?nume))

(printout t “vine clientul “ ?nume “ la momentul “ ?t crlf)

)

Regula ce marchează începerea servirii unui client este inc-serv-client: dacă funcŃionarul este liber şi în coadă se găseşte cel puŃin un client, atunci funcŃionarul devine ocupat cu servirea primului client aflat la rând.

Să notăm că dintre cele 5 condiŃii ale părŃii stângi a regulii, doar primele două sunt restrictive (ele testând respectiv funcŃionarul liber şi existenŃa cel puŃin a unui nume în coadă). Faptul (trsc ...) este iniŃializat la valoarea cuantei de timp alocate clientului:

Programarea bazată pe reguli 168

(defrule inc-serv-client

?func <- (functionar liber) (coada ?primul $?rest) (timp-servire ?ts) (ceas ?t)

?tr <- (trsc ?) =>

(retract ?func ?tr)

(assert (functionar ocupat ?primul)

(trsc ?ts)) (printout t “incepe servirea clientului “ ?primul “ la momentul “ ?t crlf)

)

Regula de terminare a servirii unui client: dacă funcŃionarul este ocupat cu servirea clientului aflat în faŃă la rând şi timpul de servire al acestuia a expirat, atunci funcŃionarul devine liber şi clientul iese din coadă:

(defrule termin-serv-client

?func <- (functionar ocupat ?nume) ?co <- (coada ?nume $?rest)

?tr <- (trsc 0) (ceas ?t)

=>

(retract ?func ?co)

(assert (functionar liber) (coada $?rest)) (printout t “termin servirea clientului “ ?nume “ la momentul “ ?t crlf) )

Următoarea regulă simulează ceasul: faptele care păstrează timpul şi numărul de minute rămase pentru servirea clientului aflat în faŃă sunt actualizate – primul incrementat, al doilea decrementat. Să observăm că prioritatea acestei reguli este cea mai mică dintre toate regulile simulării. Cum condiŃiile ei de aplicare sunt satisfăcute la orice pas al simulării (existenŃa faptelor ceas şi trsc), doar declaraŃia de prioritate minimă face ca regula să se activeze numai în cazul în care nici o altă regulă nu mai poate fi aplicată.

(defrule tact-ceas

(declare (salience -100))

Sisteme expert în condiŃii de timp real 169

?ce <- (ceas ?t) ?tr <- (trsc ?v) =>

(retract ?ce ?tr) (bind ?t (+ ?t 1)) (assert (ceas ?t)

(trsc =(- ?v 1)))

(printout t “minutul: “ ?t crlf) )

Oprirea simulării se face când coada este vidă şi nici un fapt client nu a mai rămas în bază. Maniera de oprire aleasă aici a fost prin retragerea unui fapt care este folosit în absolut toate regulile, cel conŃinând ceasul:

(defrule oprire

(declare (salience 10)) (coada)

(not (client $?)) ?ce <- (ceas ?) =>

(retract ?ce) )

Iată rezultatele rulării acestui program:

CLIPS> (load “Coada.clp”) TRUE

CLIPS> (reset) CLIPS> (run)

vine clientul Ion la momentul 0

incepe servirea clientului Ion la momentul 0 minutul: 1

vine clientul Matei la momentul 1 minutul: 2

minutul: 3

termin servirea clientului Ion la momentul 3 incepe servirea clientului Matei la momentul 3 minutul: 4

vine clientul Mircea la momentul 4 minutul: 5

minutul: 6

termin servirea clientului Matei la momentul 6 incepe servirea clientului Mircea la momentul 6 minutul: 7

minutul: 8 minutul: 9

Programarea bazată pe reguli 170

termin servirea clientului Mircea la momentul 9 minutul: 10

minutul: 11

vine clientul Maria la momentul 11

incepe servirea clientului Maria la momentul 11 minutul: 12

minutul: 13 minutul: 14

termin servirea clientului Maria la momentul 14 CLIPS>