;; globals [ k-version gv-lambda-next-transition ] breed [exceptions an-exch] breed [tokens a-colored-token] breed [philosophers philosopher] philosophers-own [ dm-andon ;; my current state total-eaten ;; how much I've had to eat ] ;; breed [forks fork] forks-own [ lambda-reset home-xpos home-ypos home-heading ;; so to restore my home position in the layout and reset attributes. total-busy-time ] ;; breed [places a-place] places-own [ dm-token-list ] ;; breed [transitions an-event] transitions-own [ lambda-enabled? lambda-firing ] ;; directed-link-breed [canvas-arcs a-canvas-arc] directed-link-breed [petri-arcs a-petri-arc] turtles-own [ dm-id dm-arrival dm-departure dm-remarks marked? ] patches-own [dm-zone] ;; to setup clear-all set k-version 4.05 show (word date-and-time " Info! ======================================= set up the model ============================== NETLOGO version: " netlogo-version " Project version: " k-version ) set-default-shape philosophers "person" set-default-shape forks "arrow" set-default-shape tokens "fish" set-default-shape places "circle" set-default-shape transitions "flag" ask patches [ ifelse (pycor < 0) [set pcolor yellow set dm-zone "Petri"] [set pcolor gray set dm-zone "canvas"] ] create-ordered-tokens (2 * bu-num-philosophers) [ set size 1.5 set color red set dm-id who set label dm-id ] layout-circle tokens 7 init-canvas-next-token one-of tokens init-petri-net foreach k-zones [ask rpt-banner-patch ? [set plabel ? set plabel-color black]] mt-visual-mngmt set gv-lambda-next-transition task [rpt-next-transition last k-transitions] reset-ticks reset-timer end ;; to go carefully [ show (word rpt-cron " Info! ==================================== step starts ==================================== version " k-version ) if (bu-horizon < ticks) [error (word "HALT condition raised because horizon " bu-horizon " is reached!")] ask transitions with [runresult gv-lambda-next-transition = label] [ if bu-debug-mode? [show (word label " DEBUG! checking enabled transition ...")] if runresult lambda-enabled? [ if not (is-command-task? lambda-firing) [error (word self " lambda-firing issue " lambda-firing)] if bu-debug-mode? [show (word label " DEBUG! go ... firing transition ...")] run lambda-firing ] ] ask philosophers with ["EATING" = dm-andon] [set total-eaten 1 + total-eaten] ask forks with [red = color] [set total-busy-time 1 + total-busy-time] mt-visual-mngmt ] [ show (word date-and-time " ======================== THE PETRI NET DINING PHILOSOPHERS EXPERIMENT IS OVER!!! ==================================== version " k-version ) ask one-of patches with ["Petri" = dm-zone] [sprout-exceptions 1 [ set shape ifelse-value (member? "HALT" error-message) ["flag"] ["bug"] set label-color black set label ifelse-value (member? "HALT" error-message) ["HALT!"] ["PANIC!"] set color violet set size 4 set dm-remarks error-message set dm-arrival ticks show (word label rpt-cron error-message k-delimiter " elapsed time: " precision timer 1 " secs." ) watch-me ]] stop ] tick end ;; to init-petri-net foreach k-places [ask rpt-place-patch ? [ sprout-places 1 [ set size 1 set color blue set label-color black set label ? set dm-token-list [] foreach n-values (3 + bu-num-philosophers) [-1 + (-1 * ?)] [ ask patch-at ? -1 [set dm-zone [label] of myself set pcolor orange] ] ] ]] ask philosophers [ mt-enqueue-token-at-place self "think" ] ask forks [ mt-enqueue-token-at-place self "free-forks" ] foreach k-transitions [ask rpt-transition-patch ? [ sprout-transitions 1 [set size 2 set label ? set lambda-enabled? rpt-def-lambda-enabled ? set color blue] ]] ask transitions with ["seize-forks" = label] [ create-a-petri-arc-to one-of places with ["eat" = label] [set color pink] ] ask places with ["eat" = label] [ create-a-petri-arc-to one-of transitions with ["release-forks" = label] [set color pink] ] ask transitions with ["release-forks" = label] [ create-a-petri-arc-to one-of places with ["think" = label] [set color pink] create-a-petri-arc-to one-of places with ["free-forks" = label] [set color pink] ] ask places with ["think" = label] [ create-a-petri-arc-to one-of transitions with ["seize-forks" = label] [set color pink] ] ask places with ["free-forks" = label] [ create-a-petri-arc-to one-of transitions with ["seize-forks" = label] [set color pink] ] show (word " Info! init-petri-net has created " count places " places; " count transitions " transitions; " count petri-arcs " arcs.") end ;; to init-canvas-next-token [#token] let lv-next-token rpt-conection-candidate-from #token if bu-debug-mode? [show (word " DEBUG! prepares the conection of " #token " to one of candidates " lv-next-token)] ifelse (nobody = lv-next-token) [ ask turtles [ if bu-debug-mode? [ show (word label " DEBUG! re-arranging items in canvas; in links: " count my-in-links ", out links: " count my-out-links " heading: " heading )] move-to patch-at 0 8 if not ( (count my-in-links = 1) and (count my-out-links = 1) ) [error (word " each philosopher must have a left and right fork!" )] if is-fork? self [set home-xpos xcor set home-ypos ycor set home-heading heading set lambda-reset task [set color pink set xcor home-xpos set ycor home-ypos set heading home-heading ] ] ] ] [ set lv-next-token rpt-cast-token-after-token lv-next-token #token ask #token [create-a-canvas-arc-to lv-next-token [set color yellow if bu-debug-mode? [ show (word " DEBUG! I am the arc from " #token lv-next-token)] ]] init-canvas-next-token lv-next-token ] end ;; to mt-visual-mngmt ask places [ let lv-my-lane patches with [[label] of myself = dm-zone] ask lv-my-lane [set plabel ""] foreach dm-token-list [ask one-of (lv-my-lane with ["" = plabel]) [set plabel-color runresult rpt-phenotype ? set plabel [dm-id] of ?] ] ask patch-at 1 0 [set plabel length [dm-token-list] of myself set pcolor orange] ] ask patch -4 -11 [set plabel-color black set plabel "colored tokens legend"] ask patch -4 -12 [set plabel-color black set plabel "black tokens are forks"] ask patch -4 -13 [set plabel-color white set plabel "white tokens are philosophers"] ask philosophers [ set color rpt-philosopher-andon-color ] end ;; to mt-enqueue-token-at-place [#token #place] if not (member? #place k-places) [error (word #place " invalid at mt-enqueue-token-at-place " #token)] ask one-of places with [#place = label] [ if not (pred-valid-token-here? #token) [error (word #token " not accepted mt-enqueue-token-at-place " #place)] set dm-token-list lput #token dm-token-list if bu-debug-mode? [show (word label " DEBUG! mt-enqueue-token-at-place inserts token " #token " updated token list " dm-token-list)] ] end ;; to pm-philosopher-ends-eating if not (is-an-event? self) [error (word self label " unexpected in pm-philosopher-ends-eating!")] let lv-my-places (list "eat" ) if bu-debug-mode? [show (word label " DEBUG! firing tokens from places " lv-my-places " in pm-philosopher-starts-eating " )] ask my-in-petri-arcs [ask end1 [ if not (is-a-place? self) [error (word self label " was expected to be a place in pm-philosopher-ends-eating ")] if not member? label lv-my-places [error (word self label " unexpected place in pm-philosopher-ends-eating ")] if bu-debug-mode? [show (word label " DEBUG! firing tokens from this place; in pm-philosopher-ends-eating" )] foreach filter [pred-is-marked? ?] dm-token-list [ set dm-token-list remove ? dm-token-list if bu-debug-mode? [show (word label " DEBUG! pm-philosopher-ends-eating removes token " ? " updated token list " dm-token-list)] ask ? [ set marked? false let sv-next-place ifelse-value (is-philosopher? self) ["think"] ["free-forks"] mt-enqueue-token-at-place self sv-next-place if (is-philosopher? self) [set dm-andon "THINKING" set color rpt-philosopher-andon-color] if (is-fork? self) [run lambda-reset] ] ] ]] end ;; to pm-philosopher-starts-eating if not (is-an-event? self) [error (word self label " unexpected in pm-philosopher-starts-eating!")] let lv-my-places (list "think" "free-forks") if bu-debug-mode? [show (word label " DEBUG! firing tokens from places " lv-my-places " in pm-philosopher-starts-eating " )] ask my-in-petri-arcs [ask end1 [ if not (is-a-place? self) [error (word self label " was expected to be a place in pm-philosopher-starts-eating ")] if not member? label lv-my-places [error (word self label " unexpected place in pm-philosopher-starts-eating ")] if bu-debug-mode? [show (word label " DEBUG! firing tokens from this place; in pm-philosopher-starts-eating " )] foreach filter [pred-is-marked? ?] dm-token-list [ set dm-token-list remove ? dm-token-list if bu-debug-mode? [show (word label " DEBUG! pm-philosopher-starts-eating removes token " ? " updated token list " dm-token-list)] ask ? [ set marked? false mt-enqueue-token-at-place self "eat" if (is-philosopher? self) [set dm-andon "EATING" set color rpt-philosopher-andon-color] if (is-fork? self) [set color red fd 4] ] ] ]] end ;; to-report k-places report (list "think" "eat" "free-forks") end ;; to-report k-zones report (list "canvas" "Petri") end ;; to-report k-philosopher-states report (list "THINKING" "EATING" "HUNGRY") end ;; to-report k-transitions report (list "seize-forks" "release-forks") end ;; to-report pred-are-my-forks-available? [#forks-needed #resources] if not (is-list? #forks-needed) [error (word self label " invalid arg " #forks-needed " in pred-are-my-forks-available?")] if bu-debug-mode? [show (word label " DEBUG! pred-are-my-forks-available? checking whether " #forks-needed " are available in " #resources " so to start to eat.")] foreach #resources [ if (member? ? #forks-needed) [set #forks-needed remove ? #forks-needed ] if (empty? #forks-needed) [ if bu-debug-mode? [show (word label " DEBUG! pred-are-my-forks-available? succeeds! she can seize her left and right forks from the available resources " #resources) ] report true ] ] report false end ;; to-report pred-seize-forks-enabled? if not ((is-an-event? self) and ("seize-forks" = label)) [error (word self label " is not expected to run pred-seize-forks-enabled? " )] set color red let sv-actors [] let sv-resources [] let lv-my-places (list "think" "free-forks") ask my-in-petri-arcs [ask end1 [ if not (is-a-place? self) [error (word self label " was expected to be a place in pred-seize-forks-enabled? ")] if not member? label lv-my-places [error (word self label " unexpected place in pred-seize-forks-enabled? ")] set lv-my-places remove label lv-my-places if "think" = label [set sv-actors dm-token-list ] if "free-forks" = label [set sv-resources dm-token-list] ]] if not (empty? lv-my-places) [error (word self label " mismatch in arcs with expectations in pred-seize-forks-enabled? ")] if bu-debug-mode? [show (word label " DEBUG! tokens in think place: " sv-actors " tokens in free-fork place: " sv-resources) ] foreach sv-actors [ if pred-are-my-forks-available? (rpt-my-forks ?) sv-resources [ if bu-debug-mode? [show (word label " DEBUG! pred-seize-forks-enabled? found " ? " who has both needed forks!")] ask ? [set color yellow set marked? true if bu-debug-mode? [show (word label " DEBUG! has been marked; pred-seize-forks-enabled? " )]] foreach rpt-my-forks ? [ask ? [set color yellow set marked? true] ] set lambda-firing task [pm-philosopher-starts-eating ] report true ] ] set color blue report false end ;; to-report pred-is-still-hungry? [#token] if not (is-philosopher? #token) [error (word #token " can not be asked pred-is-still-hungry?") ] report random-float 1.0 < bu-prob-still-hungry end ;; to-report pred-release-forks-enabled? if not ((is-an-event? self) and ("release-forks" = label)) [error (word self label " is not expected to run pred-release-forks-enabled? " )] set color red let sv-tokens [] let lv-my-places (list "eat" ) ask my-in-petri-arcs [ask end1 [ if not (is-a-place? self) [error (word self label " was expected to be a place in pred-release-forks-enabled? ")] if not member? label lv-my-places [error (word self label " unexpected place in pred-release-forks-enabled? ")] set lv-my-places remove label lv-my-places foreach dm-token-list [set sv-tokens lput ? sv-tokens] ]] if not (empty? lv-my-places) [error (word self label " mismatch in arcs with expectations in pred-release-forks-enabled? ")] if bu-debug-mode? [show (word label " DEBUG! tokens in eat place: " sv-tokens ) ] set color blue foreach sv-tokens [ if (is-philosopher? ?) and (not pred-is-still-hungry? ?) [ if bu-debug-mode? [show (word label " DEBUG! " ? " is marked; pred-release-forks-enabled? " )] ask ? [set color yellow set marked? true] foreach rpt-my-forks ? [ask ? [set color yellow set marked? true] ] set lambda-firing task [pm-philosopher-ends-eating ] report true ] ] report false end ;; to-report pred-is-marked? [#token] if not (is-turtle? self) [error (word #token " should be a turlte! issue raised in pred-is-marked? ")] report [marked?] of #token end ;; to-report pred-valid-token-here? [#token] if not (is-a-place? self) [error (word self label " unexpected to run pred-valid-token-here?" )] let lv-pos position label k-places let lv-pred (list task [is-philosopher? #token] task [is-philosopher? #token or is-fork? #token] task [is-fork? #token]) report runresult item lv-pos lv-pred end ;; to-report rpt-next-transition [#item] if not (member? #item k-transitions) [error (word #item " invalid in rpt-next-transition.")] let lv-pos position #item k-transitions set lv-pos (1 + lv-pos) mod length k-transitions set gv-lambda-next-transition task [rpt-next-transition item lv-pos k-transitions] report item lv-pos k-transitions end ;; to-report rpt-my-forks [#actor] if not (is-philosopher? #actor) [error (word #actor label " unexpected to run rpt-my-forks!" )] let lv-my-forks [] ask #actor [ ask my-out-canvas-arcs [ask end2 [set lv-my-forks lput self lv-my-forks]] ask my-in-canvas-arcs [ask end1 [set lv-my-forks lput self lv-my-forks]] if not (length lv-my-forks = 2) [error (word self label " expects to own - say have links to - her left and right forks")] ] report lv-my-forks end ;; to-report rpt-def-lambda-enabled [#event] if not (member? #event k-transitions) [error (word #event " not valid in rpt-def-lambda-enabled!")] let lv-lambda (list task [pred-seize-forks-enabled? ] task [pred-release-forks-enabled?] ) let lv-pos position #event k-transitions report item lv-pos lv-lambda end ;; to-report rpt-cast-token-after-token [#token-to #token-from] let lv-next-token nobody ask #token-to [ if bu-debug-mode? [show (word label " DEBUG! I will receive the conection from; but first I have to mutate.")] ifelse (is-fork? #token-from) [hatch-philosophers 1 [set lv-next-token self set label dm-id set dm-andon "THINKING" set marked? false if bu-debug-mode? [ show (word label " DEBUG! casted" )] set size 2.0 facexy 0 0 ]] [hatch-forks 1 [set lv-next-token self set label dm-id set color pink set marked? false if bu-debug-mode? [ show (word label " DEBUG! casted" )] set size 1.5 rt 180] ] ask my-out-canvas-arcs [ask end2 [ create-a-canvas-arc-from lv-next-token [set color yellow ] show (word label " WARNING! restore the arc that will be destroyed now in order to re-connect from node " [dm-id] of lv-next-token) ]] if bu-debug-mode? [ show (word label " DEBUG! I will die now.") ] die ] report lv-next-token end ;; to-report rpt-conection-candidate-from [#token] let lv-candidates nobody ask #token [ set lv-candidates other tokens with [(not any? my-in-canvas-arcs) and (not out-link-neighbor? #token )] ] if any? lv-candidates [report min-one-of lv-candidates [distance #token] ] report nobody end ;; to-report rpt-phenotype [#colored-token] report ifelse-value is-philosopher? #colored-token [task [white] ] [task [black]] end ;; to-report rpt-philosopher-andon-color if not is-philosopher? self [error (word self label " not a valid breed in rpt-philosopher-andon-color!" )] if not (member? dm-andon k-philosopher-states ) [error (word dm-andon " not found! rpt-philosopher-andon-color")] let lv-lambda-options (list task [blue] task [green] task [red]) let lv-pos position dm-andon k-philosopher-states report runresult item lv-pos lv-lambda-options end ;; to-report rpt-banner-patch [#zone] let lv-pos position #zone k-zones let lv-banner (list task [patch 0 8] task [patch 12 -2]) report runresult item lv-pos lv-banner end ;; to-report rpt-place-patch [#place] let lv-pos position #place k-places let lv-banner (list task [patch -6 -2] task [patch -3 -9 ] task [patch 14 -14 ]) report runresult item lv-pos lv-banner end ;; to-report rpt-transition-patch [#event] let lv-pos position #event k-transitions let lv-banner (list task [patch 5 -6] task [patch 5 -11 ]) report runresult item lv-pos lv-banner end ;; to-report rpt-cron report (word " timestamp:" precision ticks 1 k-delimiter) end ;; ========== sentinel END of PROGRAM ==================== @#$#@#$#@ GRAPHICS-WINDOW 210 10 649 470 16 16 13.0 1 10 1 1 1 0 0 0 1 -16 16 -16 16 1 1 1 ticks 30.0 SLIDER 12 17 197 50 bu-num-philosophers bu-num-philosophers 5 10 6 1 1 NIL HORIZONTAL BUTTON 13 174 79 207 NIL setup NIL 1 T OBSERVER NIL NIL NIL NIL 1 BUTTON 109 174 172 207 NIL go T 1 T OBSERVER NIL NIL NIL NIL 0 SWITCH 22 422 188 455 bu-debug-mode? bu-debug-mode? 1 1 -1000 MONITOR 669 92 764 137 version k-version 2 1 11 BUTTON 109 221 194 254 go-once go NIL 1 T OBSERVER NIL NIL NIL NIL 0 CHOOSER 25 364 163 409 k-delimiter k-delimiter "," ";" 0 SLIDER 15 67 192 100 bu-prob-still-hungry bu-prob-still-hungry 0.2 0.90 0.7 0.1 1 NIL HORIZONTAL PLOT 929 26 1338 241 Histogram - food consumption by philosophers philosopher-ID food 0.0 100.0 0.0 17.0 true false "set-plot-x-range 0 (1 + count philosophers)" "" PENS "food-pen" 1.0 1 -5298144 true "" "plot-pen-reset\nask philosophers [ plotxy who total-eaten ]" PLOT 853 290 1347 458 plot-resource-allocation NIL NIL 0.0 100.0 0.0 35.0 true true "set-plot-y-range 0 (1 + count philosophers)" "" PENS "thinking-pen" 1.0 0 -14070903 true "" "plot count philosophers with [\"THINKING\" = dm-andon]" "eating-pen" 1.0 0 -2674135 true "" "plot count philosophers with [\"EATING\" = dm-andon]" TEXTBOX 670 25 887 115 PLEASE READ THE 'INFO' TAB.\nThe five dining philosophers is a well known problem in computer science. 12 113.0 1 MONITOR 675 156 911 201 mean food eaten per philosopher and tick sum [total-eaten] of philosophers / (max (list 1 ticks) * count philosophers) 2 1 11 MONITOR 682 222 870 267 mean fork busy time per tick sum [total-busy-time] of forks / (max (list 1 ticks) * count forks) 2 1 11 SLIDER 18 118 190 151 bu-horizon bu-horizon 70 600 310 30 1 ticks HORIZONTAL @#$#@#$#@ ## BACKGROUND The Dining Philosophers problem is a classic case study in the synchronization of concurrent processes. It will be familiar to many students of Computer Science, but is applicable to many situations in which several independent processes must coordinate the use of shared resources [Wilensky, 2003] ## PROBLEM STATEMENT Consider the famous synchronization problem consisting of a group of N hungry philosophers who spend some time thinking between copious meals of spaghetti. There are only N forks on a circular table and there is a fork between two philosophers. These are boring philosophers: they do nothing but think, get hungry and eat. In particular, they do not communicate with one another. A fork sits on the table in between each pair of philosophers, so there are exactly as many forks as philosophers. However, the spaghetti is quite messy, so in order to eat, each philosopher needs to be holding two forks, both the fork to her left and the fork to her right. Clearly, if all the philosophers are to get some spaghetti, they'll have to share the forks. There are many ways that this can go wrong. A given philosopher can pick up both forks and begin eating, and never stop. This guarantees that (at least) her immediate neighbors will never get to eat. (Though at least SOMEONE gets to eat!) What would happen if every philosopher immediately picked up the fork to her right, then waited for the fork to her left to become available? This situation is called "deadlock," and it is the bane of designers of concurrent systems. The goal of the problem is to come up with a strategy that the philosophers can use to guarantee that: 1. At least one hungry philosopher can always eat. 2. On average, all the philosophers get the same amount to eat. There is one other feature of the system that aids in finding a solution: while a philosopher is holding a fork, she has the ability to place a mark on it or to remove an existing mark. These marks are visible to any philosopher who inspects the fork. One random fork will always start out marked, but in order to avoid confusion, marked forks are not visually distinguished unless cooperation is enabled (in which case they are a different color). Can you think of a way to feed the philosophers? Remember that the philosophers shouldn't, in principle, communicate (apart from marking forks, though that arguably constitutes a communication channel). This means that the assignment of global group properties (such as "even/odd-numbered philosophers" or "first philosopher") is not allowed. The astute reader will note that the initial marking of a single fork violates this rule by assigning a globally unique property to a single philosopher. In the absence of such an initially distinguished fork, can you think of a way to feed the philosophers? ## HOW IT WORKS (SYSTEM MODEL) The layout is split in two areas. The upper area, labelled as 'canvas' is where the observer can see the problem-world. The lower area, called 'Petri' contains the Petri net that rules the system. Philosopher agents know which fork is on their left and which fork is on their right. An arc connects a philosopher to her left fork. Another arc to her right fork. They also know what state they're in (thinking, hungry or eating) and how much they've eaten in total. Fork agents know they are busy when tehy leave from their home position. When a fork is at its home position, it can be seized by a philosopher in its neighbor. (arc-connected to) All the philosophers are initially thinking (blue). A thinking philosopher is always hungry. She will try to acquire both forks, and until she has done so will remain hungry. A hungry philosopher with both forks immediately begins eating (green). An eating philosopher may become full with probability full-chance, at which point she will release both forks and resume thinking (blue). This logic is supported by the Petri net (lower area in the layout). See the model section. ## HOW TO USE IT Initial settings: - num-philosophers: how many philosophers you'd like to feed. The setup button will set the initial conditions. The go button will run the simulation, and the "go once" button will run the simulation for just one step, allowing you to watch what happens in more detail. Other settings: - bu-prob-still-hungry: The probability of any eating philosopher to continue eating next period of time. Plots: - Spaghetti consumed: plots the amount of spaghetti each philosopher has consumed (based on how many time steps she has spent in the eating state). - Resource allocation: plots the number of philosophers in each state over time. ## THINGS TO NOTICE In the command center (console) the observer can see what the system is doing (trace). More detailed trace is shown when bu-debug-mode? is 'on'. ## THINGS TO TRY Play with different configurations of hungry-chance and full-chance and different numbers of philosophers. See how different combinations stress the system in different ways. ## MODEL In the model, there are three places; places contain two types of tokens, the first type is associated with the philosophers and the second is associated with forks. The arcs are labeled by the token variables. A token has a number of attributes. The tokens residing in both the places “think” and “free forks” have two attributes: the first attribute being its type and the second attribute being its identity, id. The tokens residing in the place “eat”, have four attributes: the first two ones are the same as in place “think”, and the last two ones are the ids of the forks currently used by the philosopher. The transition “take forks” is associated with the predicate which specifies the correct relation between a philosopher and the two forks used by him. The predicate inscribed on transition “take forks” as i = j is a concise form of expressing that the second attribute of a token should match the second attribute of the two tokens representing the forks. This means that a philosopher can eat only when the two adjacent forks are free. For example, the forks and must be free in order to allow the philosopher to move to the eating place. Note that a predicate expresses an imperative condition which must be met in order for a transition to fire. A predicate should not be used to express the result associated with transition “put down forks”, although there is a well-defined relationship between the attributes of the tokens released when “put down forks” fires. ## EXTENDING THE MODEL - MANAGING VERSIONS The current version (1.03) has 468 LOC (lines of code). Try to think of a different strategy for the philosophers, then implement it and see how well it works! Can you think of other configurations of processes and resources that might be interesting to experiment with? For example, suppose there is one salt shaker on the table where all the philosophers can reach it, and suppose that each time a philosopher has acquired both forks, she must acquire the salt shaker and salt her spaghetti before she begins eating. She can release the salt shaker after only one time step (i.e., before she finishes eating her pasta and releases the forks), so several philosophers can still eat at once. Can this modification lead to deadlock? What if there are both salt and pepper? Test your intuition! There are many, many other such possibilities, and many are directly analogous to situations that frequently arise in practical resource allocation problems. ## REFERENCES * 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. * Wilensky, U. (1999). NetLogo. http://ccl.northwestern.edu/netlogo/. Center for Connected Learning and Computer-Based Modeling, Northwestern University, Evanston, IL. * Wang, Jiacun. "Petri nets for dynamic event-driven system modeling." Handbook of Dynamic System Modeling (2007): 1-17. http://bluehawk.monmouth.edu/~jwang/Ch024.pdf * Zurawski, Richard, and MengChu Zhou. "Petri nets and industrial applications: A tutorial." Industrial Electronics, IEEE Transactions on 41.6 (1994): 567-583. http://www.stevens-tech.edu/wireless/research/petrinet/reading-petri-net-tutorial-zurawski-zhou.pdf * http://cpntools.org/_media/book/cpn.pdf ## CREDITS josegual@esce.ipvc.pt June 2015 @#$#@#$#@ default true 0 Polygon -7500403 true true 150 5 40 250 150 205 260 250 airplane true 0 Polygon -7500403 true true 150 0 135 15 120 60 120 105 15 165 15 195 120 180 135 240 105 270 120 285 150 270 180 285 210 270 165 240 180 180 285 195 285 165 180 105 180 60 165 15 arrow true 0 Polygon -7500403 true true 150 0 0 150 105 150 105 293 195 293 195 150 300 150 box false 0 Polygon -7500403 true true 150 285 285 225 285 75 150 135 Polygon -7500403 true true 150 135 15 75 150 15 285 75 Polygon -7500403 true true 15 75 15 225 150 285 150 135 Line -16777216 false 150 285 150 135 Line -16777216 false 150 135 15 75 Line -16777216 false 150 135 285 75 bug true 0 Circle -7500403 true true 96 182 108 Circle -7500403 true true 110 127 80 Circle -7500403 true true 110 75 80 Line -7500403 true 150 100 80 30 Line -7500403 true 150 100 220 30 butterfly true 0 Polygon -7500403 true true 150 165 209 199 225 225 225 255 195 270 165 255 150 240 Polygon -7500403 true true 150 165 89 198 75 225 75 255 105 270 135 255 150 240 Polygon -7500403 true true 139 148 100 105 55 90 25 90 10 105 10 135 25 180 40 195 85 194 139 163 Polygon -7500403 true true 162 150 200 105 245 90 275 90 290 105 290 135 275 180 260 195 215 195 162 165 Polygon -16777216 true false 150 255 135 225 120 150 135 120 150 105 165 120 180 150 165 225 Circle -16777216 true false 135 90 30 Line -16777216 false 150 105 195 60 Line -16777216 false 150 105 105 60 car false 0 Polygon -7500403 true true 300 180 279 164 261 144 240 135 226 132 213 106 203 84 185 63 159 50 135 50 75 60 0 150 0 165 0 225 300 225 300 180 Circle -16777216 true false 180 180 90 Circle -16777216 true false 30 180 90 Polygon -16777216 true false 162 80 132 78 134 135 209 135 194 105 189 96 180 89 Circle -7500403 true true 47 195 58 Circle -7500403 true true 195 195 58 circle false 0 Circle -7500403 true true 0 0 300 circle 2 false 0 Circle -7500403 true true 0 0 300 Circle -16777216 true false 30 30 240 cow false 0 Polygon -7500403 true true 200 193 197 249 179 249 177 196 166 187 140 189 93 191 78 179 72 211 49 209 48 181 37 149 25 120 25 89 45 72 103 84 179 75 198 76 252 64 272 81 293 103 285 121 255 121 242 118 224 167 Polygon -7500403 true true 73 210 86 251 62 249 48 208 Polygon -7500403 true true 25 114 16 195 9 204 23 213 25 200 39 123 cylinder false 0 Circle -7500403 true true 0 0 300 dot false 0 Circle -7500403 true true 90 90 120 face happy false 0 Circle -7500403 true true 8 8 285 Circle -16777216 true false 60 75 60 Circle -16777216 true false 180 75 60 Polygon -16777216 true false 150 255 90 239 62 213 47 191 67 179 90 203 109 218 150 225 192 218 210 203 227 181 251 194 236 217 212 240 face neutral false 0 Circle -7500403 true true 8 7 285 Circle -16777216 true false 60 75 60 Circle -16777216 true false 180 75 60 Rectangle -16777216 true false 60 195 240 225 face sad false 0 Circle -7500403 true true 8 8 285 Circle -16777216 true false 60 75 60 Circle -16777216 true false 180 75 60 Polygon -16777216 true false 150 168 90 184 62 210 47 232 67 244 90 220 109 205 150 198 192 205 210 220 227 242 251 229 236 206 212 183 fish false 0 Polygon -1 true false 44 131 21 87 15 86 0 120 15 150 0 180 13 214 20 212 45 166 Polygon -1 true false 135 195 119 235 95 218 76 210 46 204 60 165 Polygon -1 true false 75 45 83 77 71 103 86 114 166 78 135 60 Polygon -7500403 true true 30 136 151 77 226 81 280 119 292 146 292 160 287 170 270 195 195 210 151 212 30 166 Circle -16777216 true false 215 106 30 flag false 0 Rectangle -7500403 true true 60 15 75 300 Polygon -7500403 true true 90 150 270 90 90 30 Line -7500403 true 75 135 90 135 Line -7500403 true 75 45 90 45 flower false 0 Polygon -10899396 true false 135 120 165 165 180 210 180 240 150 300 165 300 195 240 195 195 165 135 Circle -7500403 true true 85 132 38 Circle -7500403 true true 130 147 38 Circle -7500403 true true 192 85 38 Circle -7500403 true true 85 40 38 Circle -7500403 true true 177 40 38 Circle -7500403 true true 177 132 38 Circle -7500403 true true 70 85 38 Circle -7500403 true true 130 25 38 Circle -7500403 true true 96 51 108 Circle -16777216 true false 113 68 74 Polygon -10899396 true false 189 233 219 188 249 173 279 188 234 218 Polygon -10899396 true false 180 255 150 210 105 210 75 240 135 240 house false 0 Rectangle -7500403 true true 45 120 255 285 Rectangle -16777216 true false 120 210 180 285 Polygon -7500403 true true 15 120 150 15 285 120 Line -16777216 false 30 120 270 120 leaf false 0 Polygon -7500403 true true 150 210 135 195 120 210 60 210 30 195 60 180 60 165 15 135 30 120 15 105 40 104 45 90 60 90 90 105 105 120 120 120 105 60 120 60 135 30 150 15 165 30 180 60 195 60 180 120 195 120 210 105 240 90 255 90 263 104 285 105 270 120 285 135 240 165 240 180 270 195 240 210 180 210 165 195 Polygon -7500403 true true 135 195 135 240 120 255 105 255 105 285 135 285 165 240 165 195 line true 0 Line -7500403 true 150 0 150 300 line half true 0 Line -7500403 true 150 0 150 150 pentagon false 0 Polygon -7500403 true true 150 15 15 120 60 285 240 285 285 120 person false 0 Circle -7500403 true true 110 5 80 Polygon -7500403 true true 105 90 120 195 90 285 105 300 135 300 150 225 165 300 195 300 210 285 180 195 195 90 Rectangle -7500403 true true 127 79 172 94 Polygon -7500403 true true 195 90 240 150 225 180 165 105 Polygon -7500403 true true 105 90 60 150 75 180 135 105 plant false 0 Rectangle -7500403 true true 135 90 165 300 Polygon -7500403 true true 135 255 90 210 45 195 75 255 135 285 Polygon -7500403 true true 165 255 210 210 255 195 225 255 165 285 Polygon -7500403 true true 135 180 90 135 45 120 75 180 135 210 Polygon -7500403 true true 165 180 165 210 225 180 255 120 210 135 Polygon -7500403 true true 135 105 90 60 45 45 75 105 135 135 Polygon -7500403 true true 165 105 165 135 225 105 255 45 210 60 Polygon -7500403 true true 135 90 120 45 150 15 180 45 165 90 sheep false 15 Circle -1 true true 203 65 88 Circle -1 true true 70 65 162 Circle -1 true true 150 105 120 Polygon -7500403 true false 218 120 240 165 255 165 278 120 Circle -7500403 true false 214 72 67 Rectangle -1 true true 164 223 179 298 Polygon -1 true true 45 285 30 285 30 240 15 195 45 210 Circle -1 true true 3 83 150 Rectangle -1 true true 65 221 80 296 Polygon -1 true true 195 285 210 285 210 240 240 210 195 210 Polygon -7500403 true false 276 85 285 105 302 99 294 83 Polygon -7500403 true false 219 85 210 105 193 99 201 83 square false 0 Rectangle -7500403 true true 30 30 270 270 square 2 false 0 Rectangle -7500403 true true 30 30 270 270 Rectangle -16777216 true false 60 60 240 240 star false 0 Polygon -7500403 true true 151 1 185 108 298 108 207 175 242 282 151 216 59 282 94 175 3 108 116 108 target false 0 Circle -7500403 true true 0 0 300 Circle -16777216 true false 30 30 240 Circle -7500403 true true 60 60 180 Circle -16777216 true false 90 90 120 Circle -7500403 true true 120 120 60 tree false 0 Circle -7500403 true true 118 3 94 Rectangle -6459832 true false 120 195 180 300 Circle -7500403 true true 65 21 108 Circle -7500403 true true 116 41 127 Circle -7500403 true true 45 90 120 Circle -7500403 true true 104 74 152 triangle false 0 Polygon -7500403 true true 150 30 15 255 285 255 triangle 2 false 0 Polygon -7500403 true true 150 30 15 255 285 255 Polygon -16777216 true false 151 99 225 223 75 224 truck false 0 Rectangle -7500403 true true 4 45 195 187 Polygon -7500403 true true 296 193 296 150 259 134 244 104 208 104 207 194 Rectangle -1 true false 195 60 195 105 Polygon -16777216 true false 238 112 252 141 219 141 218 112 Circle -16777216 true false 234 174 42 Rectangle -7500403 true true 181 185 214 194 Circle -16777216 true false 144 174 42 Circle -16777216 true false 24 174 42 Circle -7500403 false true 24 174 42 Circle -7500403 false true 144 174 42 Circle -7500403 false true 234 174 42 turtle true 0 Polygon -10899396 true false 215 204 240 233 246 254 228 266 215 252 193 210 Polygon -10899396 true false 195 90 225 75 245 75 260 89 269 108 261 124 240 105 225 105 210 105 Polygon -10899396 true false 105 90 75 75 55 75 40 89 31 108 39 124 60 105 75 105 90 105 Polygon -10899396 true false 132 85 134 64 107 51 108 17 150 2 192 18 192 52 169 65 172 87 Polygon -10899396 true false 85 204 60 233 54 254 72 266 85 252 107 210 Polygon -7500403 true true 119 75 179 75 209 101 224 135 220 225 175 261 128 261 81 224 74 135 88 99 wheel false 0 Circle -7500403 true true 3 3 294 Circle -16777216 true false 30 30 240 Line -7500403 true 150 285 150 15 Line -7500403 true 15 150 285 150 Circle -7500403 true true 120 120 60 Line -7500403 true 216 40 79 269 Line -7500403 true 40 84 269 221 Line -7500403 true 40 216 269 79 Line -7500403 true 84 40 221 269 wolf false 0 Polygon -16777216 true false 253 133 245 131 245 133 Polygon -7500403 true true 2 194 13 197 30 191 38 193 38 205 20 226 20 257 27 265 38 266 40 260 31 253 31 230 60 206 68 198 75 209 66 228 65 243 82 261 84 268 100 267 103 261 77 239 79 231 100 207 98 196 119 201 143 202 160 195 166 210 172 213 173 238 167 251 160 248 154 265 169 264 178 247 186 240 198 260 200 271 217 271 219 262 207 258 195 230 192 198 210 184 227 164 242 144 259 145 284 151 277 141 293 140 299 134 297 127 273 119 270 105 Polygon -7500403 true true -1 195 14 180 36 166 40 153 53 140 82 131 134 133 159 126 188 115 227 108 236 102 238 98 268 86 269 92 281 87 269 103 269 113 x false 0 Polygon -7500403 true true 270 75 225 30 30 225 75 270 Polygon -7500403 true true 30 75 75 30 270 225 225 270 @#$#@#$#@ NetLogo 5.2.0 @#$#@#$#@ @#$#@#$#@ @#$#@#$#@ @#$#@#$#@ @#$#@#$#@ default 0.0 -0.2 0 0.0 1.0 0.0 1 1.0 0.0 0.2 0 0.0 1.0 link direction true 0 Line -7500403 true 150 150 90 180 Line -7500403 true 150 150 210 180 @#$#@#$#@ 0 @#$#@#$#@