breeds [ philosophers forks ] globals [ HUNGRY EATING THINKING ;; these are constants for the states colors ;; this will be a list mapping states -> colors table-size turtle-size ;; constant sizes for things in the gw fork-offset ;; this is a heading offset used to place the forks fork-distance ;; this is a distance used to place the forks ] philosophers-own [ ;; how to draw the left fork when i'm holding it left-fork-xpos left-fork-ypos left-fork-heading ;; how to draw the right fork when i'm holding it right-fork-xpos right-fork-ypos right-fork-heading state ;; my current state left-fork right-fork ;; the forks on my right and left total-eaten ;; how much i've have to eat ] forks-own [ xpos ypos save-heading ;; where i belong when i'm on the table owner ;; the philosopher that currently owns me (if any) marked? ;; whether i'm currently marked ] to nastavi ca ; constants set HUNGRY 0 set EATING 1 set THINKING 2 set colors [ red green blue ] set table-size 0.6 set turtle-size 0.1 set fork-offset 10 set fork-distance 0.1 ; set up the model make-turtles recolor ; set up the plots setup-plots do-plots end ;; create all the turtles, place them, and associate forks with philosophers to make-turtles locals [ new-left previous-left current-turn ] set previous-left nobody set current-turn 0 set-default-shape philosophers "person" set-default-shape forks "fork" ;; the tactic is to create one fork and one philosopher at a time, ;; associating each new philosopher with the new fork and with the fork ;; we created last time (stored in previous-left). the direction each new ;; turtle faces is incremented as we go, and they're moved to the edge of ;; the table. repeat stevilo_filozofov [ create-custom-forks 1 [ set color 9 set size turtle-size set marked? false set owner nobody rt current-turn rt 360 / (2 * stevilo_filozofov) jump ((table-size - turtle-size) / 2) rt 180 ;; turn around so i look prettier. set new-left self ;; save my position and heading, so the philosophers can replace me later set xpos xcor set ypos ycor set save-heading heading ] create-custom-philosophers 1 [ set size turtle-size set state THINKING set right-fork previous-left set previous-left new-left set left-fork new-left rt current-turn jump ((table-size + turtle-size) / 2) calculate-fork-positions ] set current-turn (current-turn + 360 / stevilo_filozofov) ] ; assuming that ids are assigned to turtles monotonically, this ties the ; knot. set right-fork-of (min-one-of philosophers [ who ]) previous-left ask random-one-of forks [ set marked? true ] end to zacni ifelse menjavati_se? [ update-one ] [ update-all ] recolor do-plots end ;; here we figure out where to place the forks when we pick them up. basically ;; they go above the philosophers head, the left on the left side and the ;; right on the right side. fork-offset determines how far apart they are, and ;; fork-distance determines how far above the head. to calculate-fork-positions ;; philosopher procedure rt fork-offset set left-fork-xpos (xcor + dx * fork-distance) set left-fork-ypos (ycor + dy * fork-distance) set left-fork-heading heading lt fork-offset * 2 set right-fork-xpos (xcor + dx * fork-distance) set right-fork-ypos (ycor + dy * fork-distance) set right-fork-heading heading rt fork-offset end ;; everybody gets a new color. to recolor ask philosophers [ ;; look up the color in the colors list indexed by our current state set color (item state colors) ] ask forks [ ;; we'll indicate marked forks only if cooperation is on. ifelse sodelovanje? and marked? [ set color magenta ] [ set color 9 ] ] end to update-one ask random-one-of philosophers [ if state = THINKING [ if random-float 1.0 < verjetnost_lakote [ set state HUNGRY ] stop ] if state = EATING [ ;; keep track of how much we're eating. set total-eaten (total-eaten + 1) if random-float 1.0 < verjetnost_sitosti [ ;; put down forks ifelse sodelovanje? [ release-forks-smart ] [ release-forks-naive ] ;; continue thinking set state THINKING ] stop ] if state = HUNGRY [ ; try to pick up the forks. ifelse sodelovanje? [ acquire-forks-smart ] [ acquire-forks-naive ] ; if we've got both forks, eat. if got? left-fork and got? right-fork [ set state EATING ] stop ] ] end ;; here's where philosophers actually do their thing. note that a philosopher ;; can go through several states in the same call to update. to update-all ask philosophers [ ;; some thinking philosophers may get hungry. if state = THINKING [ if random-float 1.0 < verjetnost_lakote [ set state HUNGRY ] stop ] ;; some eating philosophers may get full. if state = EATING [ ;; keep track of how much we're eating. set total-eaten (total-eaten + 1) if random-float 1.0 < verjetnost_sitosti [ ;; put down forks ifelse sodelovanje? [ release-forks-smart ] [ release-forks-naive ] ;; continue thinking set state THINKING ] stop ] if state = HUNGRY [ ; try to pick up the forks. ifelse sodelovanje? [ acquire-forks-smart ] [ acquire-forks-naive ] ; if we've got both forks, eat. if got? left-fork and got? right-fork [ set state EATING ] stop ] ] end ;; a more sophisticated strategy for releasing the forks, which switches any ;; marks to the other fork. see the info tab for details. to release-forks-smart ;; philosopher procedure ;; check left fork ifelse marked?-of left-fork [ set marked?-of left-fork false set marked?-of right-fork true ] [ ;; otherwise, check right fork. if marked?-of right-fork [ set marked?-of right-fork false set marked?-of left-fork true ] ] ;; release the forks. release left-fork release right-fork end ;; just drop the forks. to release-forks-naive ;; philosopher procedure release left-fork release right-fork end ;; to release a fork, we set its owner to nobody and replace it on the table. to release [ fork ] ;; philosopher procedure without-interruption [ set owner-of fork nobody ask fork [ setxy xpos ypos set heading save-heading ] ] end ;; just try to pick each fork up. if i get only one, i'll just hold it ;; until i get the other one. to acquire-forks-naive ;; philosopher procedure ;; try left fork if owner-of left-fork = nobody [ acquire-left ] ;; try right fork if owner-of right-fork = nobody [ acquire-right ] end ;; a more sophisticated strategy for acquiring the forks. see the info tab ;; for details. to acquire-forks-smart ;; philosopher procedure ;; try left fork if owner-of left-fork = nobody [ if (not marked?-of left-fork) or got? right-fork [ acquire-left ] ] ;; try right fork if owner-of right-fork = nobody [ if (not marked?-of right-fork) or got? left-fork [ acquire-right ] ] end ;; grab the left fork to acquire-left ;; philosopher procedure acquire left-fork left-fork-xpos left-fork-ypos left-fork-heading end ;; grab the right fork to acquire-right ;; philosopher procedure acquire right-fork right-fork-xpos right-fork-ypos right-fork-heading end ;; pick up a fork by setting its owner to me and moving it to a new ;; location to acquire [ fork new-x new-y new-heading ] ;; philosopher procedure without-interruption [ set owner-of fork self ask fork [ setxy new-x new-y set heading new-heading ] ] end ;; i've got a fork if it's owned by me. to-report got? [ fork ] ;; philosopher procedure report (owner-of fork) = self end ;; set up the plots. our ranges are dynamic, so we need this. to setup-plots set-current-plot "Zaužiti špageti" set-plot-x-range 0 (count philosophers + 1) set-current-plot "Razporeditev stanj" set-plot-y-range 0 (count philosophers) end ;; do the plotting. to do-plots every 0.4 [ set-current-plot "Zaužiti špageti" set-current-plot-pen "default" plot-pen-reset ask philosophers [ plotxy (who / 2) total-eaten ] ] set-current-plot "Razporeditev stanj" set-current-plot-pen "Razmišljujoč" plot (count philosophers with [ state = THINKING ]) set-current-plot-pen "Lačen" plot (count philosophers with [ state = HUNGRY ]) set-current-plot-pen "Jedec" plot (count philosophers with [ state = EATING ]) end ; *** NetLogo Model Copyright Notice *** ; ; This model was created as part of the projects: ; PARTICIPATORY SIMULATIONS: NETWORK-BASED DESIGN FOR SYSTEMS LEARNING IN ; CLASSROOMS and INTEGRATED SIMULATION AND MODELING ENVIRONMENT. ; The project gratefully acknowledges the support of the ; National Science Foundation (REPP & ROLE programs) -- grant numbers ; REC #9814682 and REC-0126227. ; ; Copyright 2003 by Uri Wilensky. Updated 2003. All rights reserved. ; ; Permission to use, modify or redistribute this model is hereby granted, ; provided that both of the following requirements are followed: ; a) this copyright notice is included. ; b) this model will not be redistributed for profit without permission ; from Uri Wilensky. ; Contact Uri Wilensky for appropriate licenses for redistribution for ; profit. ; ; To refer to this model in academic publications, please use: ; Wilensky, U. (2003). NetLogo Dining Philosophers model. ; http://ccl.northwestern.edu/netlogo/models/DiningPhilosophers. ; Center for Connected Learning and Computer-Based Modeling, ; Northwestern University, Evanston, IL. ; ; In other publications, please use: ; Copyright 1998 by Uri Wilensky. All rights reserved. See ; http://ccl.northwestern.edu/netlogo/models/DiningPhilosophers ; for terms of use. ; ; *** End of NetLogo Model Copyright Notice *** @#$#@#$#@ GRAPHICS-WINDOW 354 10 764 441 0 0 400.0 1 10 1 1 1 CC-WINDOW 354 442 764 562 Command Center BUTTON 7 32 79 65 nastavi nastavi NIL 1 T OBSERVER T BUTTON 7 72 76 105 začni zacni T 1 T OBSERVER T SLIDER 172 44 345 77 stevilo_filozofov stevilo_filozofov 2 40 6 1 1 NIL SLIDER 172 85 345 118 verjetnost_lakote verjetnost_lakote 0 1.0 0.5 0.01 1 NIL SLIDER 172 125 345 158 verjetnost_sitosti verjetnost_sitosti 0 1.0 0.5 0.01 1 NIL PLOT 8 199 345 379 Zaužiti špageti Številka filozofa Špageti 0.0 100.0 0.0 25.0 true true PENS "default" 1.0 1 -16776961 false PLOT 8 382 345 562 Razporeditev stanj Čas Število filozofov 0.0 100.0 0.0 100.0 true true PENS "Razmišljujoč" 1.0 0 -16776961 true "Lačen" 1.0 0 -65536 true "Jedec" 1.0 0 -11352576 true SWITCH 8 112 159 145 sodelovanje? sodelovanje? 0 1 -1000 BUTTON 83 72 169 105 naslednji korak zacni NIL 1 T OBSERVER T SWITCH 8 152 159 185 menjavati_se? menjavati_se? 0 1 -1000 @#$#@#$#@ KAJ JE TO? Problem filozofov pri večerji je klasična študija primera sinhronizacije hkratnih procesov. Ta problem je znan študentom računalništva, uporaben pa je tudi za druge situacije, v katerih se mora več neodvisnih procesov uskladiti glede uporabe skupnega vira oz. pripomočka. Problem je precej enostaven. Predpostavimo, da skupina filozofov sedi za okroglo mizo in je špagete. Ti filozofi so dolgočasni. Ne delajo drugega kot da mislijo, postanejo lačni in jedo. Med seboj ne komunicirajo. Vilica leži na mizi med dvema filozofoma. Torej je na mizi natančno toliko vilic, kot je filozofov. Da lahko filozof je špagete, potrebuje dve vilici, vilico z leve in vilico z desne strani. Če želijo vsi filozofi dobiti kaj špagetov, si bodo morali vilice deliti. Na več načinov gre lahko kaj narobe. Nek filozof lahko vzame obe vilici in nikoli ne neha s hranjenjem. To pomeni, da njegova neposredna soseda ne bosta mogla nikoli jesti. (Čeprav bo vsaj nekdo jedel.) Kaj se zgodi, če vsak filozof takoj vzame vilico na svoji desni in čaka, da postane vilica na levi prosta? (Da to poskusiš, nastavi verjetnost_lakote na 1.0, sodelovanje? in menjavati_se? daj na OFF, nato klikni na nastavi in začni.) Ta situacija se imenuje »mrtva točka« in je poguba za oblikovalce konkurenčnih sistemov. Cilj tega problema je, da najdemo strategijo, ki jo lahko filozofi uporabijo in ki zagotavlja, da: 1. Najmanj en lačen filozof lahko vedno je. 2. V povprečju vsi filozofi dobijo enako količino hrane. Obstaja še ena značilnost sistema, ki pomaga pri iskanju rešitve: ko filozof drži vilico ima možnost, da jo označi ali pa, da odstrani oznako z vilice. Te oznake so vidne vsakemu filozofu, ki čaka na vilico. Ena naključna vilica bo vedno krenila na pot označena. Da pa se izognemo zmešnjavi, se označene vilice ne da vidno določiti, če ni vključeno sodelovanje. Če je sodelovanje vključeno, so označene vilice drugačne barve. Ali lahko najdeš način, da nahraniš vse filozofe? Ne pozabi, da filozofi v osnovi ne smejo komunicirati (razen z označevanjem vilic, čeprav to predstavlja komunikacijski kanal). To pomeni, da določanje globalnih značilnosti skupine (npr. sodo/liho število filozofov, prvi filozof) ni dovoljeno. Prebrisan bralec bo opazil, da začetno označevanje ene vilice krši to pravilo z dodeljevanjem globalno edinstveno značilnostjo enemu filozofu. Ali lahko najdeš način, da nahraniš vse filozofe, če odvzameš na začetku označeno vilico? KAKO DELUJE? Imamo dva tipa predstavnikov: filozofi in vilice. Filozofi vedo katera vilica je na njihovi levi in katera na njihovi desni. Vedo tudi v kakšni fazi so (razmišljujoči, lačni ali jedci) in koliko so v celoti pojedli. Vilice vedo, kdo jih trenutno drži (če jih sploh kdo) in če so označene. Če hoče filozof vzeti vilico, mora najprej preveriti, da vilice ne drži kak od sosedov. Nato nastavi, da je on lastnik vilice. V tem modelu je mogoče, da ukradeš vilice drugemu filozofu. Zato je od vsakega filozofa odvisno, da to ne naredi. Filozof spusti vilico, ko nastavi, da ni nihče njen lastnik. Vsi filozofi na začetku razmišljajo (so modre barve). V vsakem koraku lahko misleči filozof postane lačen (rdeče barve) z verjetnostjo verjetnost_lakote. Lačen filozof bo poskušal pridobiti obe vilici. Dokler tega ne naredi bo ostal lačen. Lačen filozof, ki ima obe vilici, bo takoj začel jesti (bo zelene barve). Filozof, ki se prehranjuje, bo postal sit z verjetnostjo verjetnost_sitosti. V tem trenutku bo spustil obe vilici in bo spet razmišljal (modra barva). Vrednost sodelovanje? določa katera strategija se uporablja za pridobivanje in spuščanje vilic. Če je sodelovanje izključeno (off), se uporablja naslednja enostavna strategija: 1. Če je na voljo leva vilica, jo vzemi. 2. Če je na voljo desna vilica, jo vzemi. 3. Če imaš obe vilici, začni s hranjenjem. Drugače poskusi še enkrat. Ko je filozof sit, se vilice enostavno izpustijo. Označevanje se popolnoma ignorira. Če je sodelovanje vključeno (on), se uporablja bolj prefinjena strategija z označevanjem. Za pridobivanje vilice: 1. Če je leva vilica na voljo, jo vzemi. 2. Če imaš levo vilico in je označena in še nimaš desne vilice, spusti levo vilico. 3. Če je desna vilica prosta, jo vzemi. 4. Če imaš desno vilico in je označena in še nimaš leve vilice, spusti desno vilico. 5. Če imaš obe vilici, začni s hranjenjem. Drugače poskusi še enkrat. Ko končaš s hranjenjem, za spustitev vilic: 1. Če je ena od vilic označena, zbriši oznako in označi drugo vilico. 2. Spusti vilici. KAKO UPORABLJATI? Začetne nastavitve: stavilo_filozofov: koliko filozof želiš nahraniti Gumb nastavi bo nastavil začetne pogoje. Gumb začni bo zagnal simulacijo in gumb »naslednji korak« bo naredil naslednji korak simulacije in ti omogočil, da bolj natančno vidiš kaj se dogaja. Druge nastavitve: verjetnost_lakote: Verjetnost, da v nekem koraku nek misleči filozof postane lačen. verjetnost_sitosti: Verjentost, da v nekem koraku filozof, ki se prehranjuje, postane sit. sodelovanje?: Če je izključeno, bodo filozofi uporabljali bolj enostavno strategijo za pridobivanje vilic; če pa je vključeno, bodo filozofi uporabljali bolj prefinjeno strategijo. (Zgoraj si lahko pogledaš kako deluje.) manjavati_se?: Če je vključeno, se bo lahko v enem trenutku premaknil samo en filozof (to vidiš z uporabo gumba naslednji korak); če je izključeno, ima vsak filozof možnost, da se premakne. Če je manjavati_se? vključeno, se bodo lahko nekateri filozofi premaknili dvakrat preden se bodo premaknili vsi filozofi. V povprečju se vsi filozofi premaknejo enakokrat. Grafa: Zaužiti špageti: grafično prikaže količino špagetov, ki jih je pojedel vsak filozof (glede na to koliko korakov je vsak filozof bil v fazi hranjenja) Razporeditev stanj: grafično prikazuje število filozofov v vsaki fazi skozi čas STVARI, KI JIH JE POTREBNO OPAZITI Poigraj se z menjavati_se? za različne vrednosti za verjetnost_lakote ter verjetnost_sitosti in za različna števila filozofov. Opaziš lahko, da menjavati_se? vpliva več kot samo na hitrost simulacije, ker ni vsem filozofom zagotovljeno, da se bodo prvič premaknili preden se bo kdorkoli drug premaknil drugič. Ali misliš, da bo to dolgoročno vplivalo na rezultate simulacije? Zakaj da oz. zakaj ne? Pod katerimi pogoji se to zgodi? Poigraj se z različnimi vrednostmi verjetnost_lakote in verjetnost_sitosti. Opazuj kako različne kombinacije na različne načine vplivajo na sistem. Opaziš lahko, da kljub temu, da sistem pod določenimi pogoji deluje dobro, lahko »težji« pogoji izpostavijo šibkosti. To dokazuje pomembnost »testiranja pod težjimi pogoji« za dosego dobrega sistema, posebno pri prosotnosti konkurence. STVARI, KI JIH JE VREDNO POSKUSITI Eksperimentiraj s sodelovanjem v kombinaciji z različnimi nastavitvami za verjetnost_lakote in verjetnost_sitosti. Poskušaj najti situacijo v kateri je očiten kontrast med obnašanjem filozofov, ki sodelujejo in filozofi, ke med seboj ne sodelujejo. Poskušaj zagnati sistem za dalj časa z različnimi nastavitvami. Ali opaziš, da se kdaj na začetku sistem obnaša dobro, toda sčasoma začne »propadato« (in lahko pride celo do mrtve točke)? Kaj pa obratno? Kaj lahko iz tega sklepaš o vrednosti »dolgoživosti testiranja« pri doseganju stabilnosti in učinka konkurenčnega sistema? RAZŠIRJANJE MODELA Poskušaj najti drugačno strategijo za filozofe in jo implementiraj in preveri kako dobro deluje! Verjetno boš želel uporabiti označevanje, zato ne pozabi, da označevanje ni vidno, če je sodelovanje onemogočeno; lahko boš želel tudi to spremeniti. Ali lahko najdeš enostavnejšo strategijo kot je ta, ki smo jo pravkar predstavili? @#$#@#$#@ default true 0 Polygon -7566196 true true 150 5 40 250 150 205 260 250 box true 0 Polygon -7566196 true true 45 255 255 255 255 45 45 45 circle false 0 Circle -7566196 true true 0 0 300 fork true 0 Polygon -7566196 true true 160 247 150 251 140 248 147 107 129 97 133 29 137 86 141 86 147 38 151 86 155 84 159 39 166 96 154 105 got-both true 0 Circle -7566196 true true 116 27 68 Polygon -7566196 true true 140 95 141 115 97 125 63 222 57 232 57 248 67 250 75 245 77 237 111 174 120 257 182 257 192 175 225 241 227 248 235 251 239 251 248 242 243 231 239 232 206 126 163 114 161 92 Polygon -7566196 true true 240 237 253 192 249 188 257 168 256 187 263 173 260 189 268 179 262 198 258 196 Polygon -7566196 true true 61 238 39 197 35 198 25 179 38 194 33 175 41 192 39 173 49 194 44 196 got-left true 0 Circle -7566196 true true 116 27 68 Polygon -7566196 true true 140 95 141 115 97 125 63 222 57 232 57 248 67 250 75 245 77 237 111 174 120 257 182 257 192 175 225 241 227 248 235 251 239 251 248 242 243 231 239 232 206 126 163 114 161 92 Polygon -7566196 true true 240 237 253 192 249 188 257 168 256 187 263 173 260 189 268 179 262 198 258 196 got-right true 0 Circle -7566196 true true 116 27 68 Polygon -7566196 true true 140 95 141 115 97 125 63 222 57 232 57 248 67 250 75 245 77 237 111 174 120 257 182 257 192 175 225 241 227 248 235 251 239 251 248 242 243 231 239 232 206 126 163 114 161 92 Polygon -7566196 true true 61 239 32 195 29 200 23 175 32 193 29 172 37 192 35 173 44 191 40 198 person true 0 Circle -7566196 true true 116 27 68 Polygon -7566196 true true 140 95 141 115 97 125 63 222 57 232 57 248 67 250 75 245 77 237 111 174 120 257 182 257 192 175 225 241 227 248 235 251 239 251 248 242 243 231 239 232 206 126 163 114 161 92 turtle true 0 Polygon -7566196 true true 138 75 162 75 165 105 225 105 225 142 195 135 195 187 225 195 225 225 195 217 195 202 105 202 105 217 75 225 75 195 105 187 105 135 75 142 75 105 135 105 @#$#@#$#@ NetLogo 2.0.2 @#$#@#$#@ @#$#@#$#@ @#$#@#$#@