Net Logo
Net Logo
Steven O. Kimbrough
April 11, 2014
ii
Contents
Preface
ix
1 Starters
1.1 Starters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
1.1.1 NetLogo world view (main metaphors) . . . . . . . . .
1.2 The Interface Tab . . . . . . . . . . . . . . . . . . . . . . . .
1.2.1 The Observer . . . . . . . . . . . . . . . . . . . . . . .
1.2.2 Inspecting . . . . . . . . . . . . . . . . . . . . . . . . .
1.2.3 Editing the View (and the World) . . . . . . . . . . .
1.2.4 More on Editing the World . . . . . . . . . . . . . . .
1.2.5 Interface Widgets (on the Toolbar) . . . . . . . . . . .
1.2.5.1 NetLogo Interface Tab: The Interface Toolbar: Buttons . . . . . . . . . . . . . . . . . .
1.2.5.2 NetLogo Interface Tab: The Interface Toolbar: Sliders . . . . . . . . . . . . . . . . . . .
1.2.5.3 NetLogo Interface Tab: The Interface Toolbar: Switches . . . . . . . . . . . . . . . . . .
1.2.5.4 The Interface Toolbar: Choosers . . . . . . .
1.2.5.5 The Interface Toolbar: Input boxes . . . . .
1.2.5.6 The Interface Toolbar: Monitor . . . . . . .
1.2.5.7 The Interface Toolbar: Plot . . . . . . . . . .
1.2.5.8 The Interface Toolbar: Output . . . . . . . .
1.2.5.9 The Interface Toolbar: Note . . . . . . . . .
1.2.6 The Interface Toolbar: Plot . . . . . . . . . . . . . . .
1.2.7 Introduce a Bug . . . . . . . . . . . . . . . . . . . . .
1.3 The Info Tab . . . . . . . . . . . . . . . . . . . . . . . . . . .
1.4 The Code Tab . . . . . . . . . . . . . . . . . . . . . . . . . .
1.4.1 Commands and reporters . . . . . . . . . . . . . . . .
1.4.2 Global and local variables . . . . . . . . . . . . . . . .
iii
1
1
1
2
2
2
3
5
5
5
6
6
7
7
7
8
8
8
8
13
14
15
17
17
1.4.3
1.4.4
1.4.5
1.4.6
1.4.7
1.4.8
1.4.9
1.4.10
1.4.11
1.4.12
Games
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
18
18
19
20
21
22
23
23
24
25
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
27
28
28
29
29
29
29
30
30
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
33
34
34
35
36
36
37
39
.
.
.
.
.
.
.
.
.
43
43
44
44
45
45
45
45
46
48
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
4.4.1
4.4.2
Mutation . . . . . . . . . . . . . . . . . . . . . . . . .
Recombination . . . . . . . . . . . . . . . . . . . . . .
48
48
51
.
.
.
.
57
57
58
61
61
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
69
70
72
73
79
83
83
83
10 How Tos
89
10.1 Collect Agents in a Neighborhood . . . . . . . . . . . . . . . 89
10.2 Breeds Other than Me . . . . . . . . . . . . . . . . . . . . . . 89
11 Development Notes
91
References
92
Index
93
vi
List of Figures
1.1
1.2
1.3
1.4
.
.
.
.
4
11
14
16
2.1
2.2
27
28
4.1
47
7.1
60
8.1
8.2
8.3
64
67
68
9.1
9.2
78
9.3
9.4
vii
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
80
83
86
viii
Preface
Assumptions:
Previous exposure to NetLogo models. Previous exposure to programming. In either case exposure can be quite minimal.
Working with an open, new NetLogo model. Version: 5.X. These notes
separately.
Here, highlights only. These tutorials are just a beginning, to get you
started and to serve as notes and as a quick reference.
RTFM principle: read the manual, from NetLogo. Most important:
Programming Guide and NetLogo Dictionary. Read the Programming
Guide. Keep the NetLogo Dictionary to hand as you write code and
refer to it often. You can often find commands that will do exactly
what you need. But there are a lot of commands. Notice that they
are organized by category; see the top of the NetLogo Dictionary.
NetLogo demonstration files, written by me, can generally be downloaded (if available) at http://opim.wharton.upenn.edu/~sok/mandms/
nlogocode/ or perhaps more likely at http://opim.wharton.upenn.edu/
~sok/age/nlogo.
There isnt much in the way of a NetLogo textbook or instruction manual
at all, other than what is present on the NetLogo Web site
NetLogo home page: http://ccl.northwestern.edu/netlogo/.
NetLogo user manual: http://ccl.northwestern.edu/netlogo/docs/.
Note well: The user manual comes with three tutorials. I recommend
them, especially for beginners. Also, NetLogo comes with a models
library (under the File menu), which is full of interesting examples,
including code examples. Well worth rooting around in.
ix
Chapter 1
Starters
1.1
Starters
First of all, remember that NetLogo has a manual with lots of valuable
information. RTFM! For purposes of getting started you might consider
looking here and in the NetLogo manual. Here, begin immediately below. In
the NetLogo manual, begin with Introduction then move on to Learning
NetLogo. Skim the Interface Guide and the Programming Guide and
be prepared to consult them as you progress. The NetLogo Dictionary is
especially useful on a day-to-day basis.
1.1.1
The NetLogo program/application has a main window with three tabs, for
three different functions:
Interface
Info
Code
CHAPTER 1. STARTERS
ground over which turtles can move. Links are agents that
connect two turtles. The observer doesnt have a location
you can imagine it as looking out over the world of turtles
and patches.
The world: rectangular array of patches on which turtles may sit.
Patches are (like) geographic locations and are fixed. Turtles are
moveable entities. Both have properties. In addition, turtles may
be connected by links, which are also agents.
The observer: looks down at the world and what is in it.
From the Command Center. From the Procedures.
The View. A window onto the world of patches and turtles. By default,
a black window on the Interface Tab.
Well focus next on the Interface Tab.
1.2
1.2.1
The Observer
Again: The observer: looks down at the world and what is in it.
Can issue commands, from the Command Center. For example,
observer> create-turtles 1 creates a turtle at patch (0,0) or patch
0 0 as it is called in NetLogo.
Note: every patch has a planar or x-y coordinate address, measured
away from 0 0 in the cartesian plane.
observer> ask turtle 0 [fd 12] moves our turtle (ID is 0) forward
12 patches.
observer> ask turtle 0 [forward -12] puts it back at the origin.
1.2.2
Inspecting
1.2.3
CHAPTER 1. STARTERS
1.2.4
1.2.5
CHAPTER 1. STARTERS
print Mutation?
if-else (Mutation?)
[set Mutation? false]
[set Mutation? true]
Accept and try it out.
1.2.5.2
Slider: Sliders are global variables, which are accessible by all agents.
They are used in models as a quick way to change a variable without
having to recode the procedure every time. Instead, the user moves
the slider to a value and observes what happens in the model.
Click and draw a slider. Set Global variable to myFirstVariable,
leave Minimum at 0, set Increment to 0.1, Maximum to 10, and
Value to 7.3. Click OK. Move the slider to a new value.
Try observer> print Myfirstvariable. (We see that NetLogo is
not case-senstive.) Try observer> set myFirstVariable 9.9
then observer> set myFirstVariable 29,
and then observer> print myFirstVariable.
Note well
Chooser: Choosers let the user choose a value for a global variable
from a list of choices, presented in a drop down menu.
One per line. Put strings in double quotes. Numbers directly.
Click and draw a chooser. In the Global variable text area, type
person. In the Choices text area type:
"Bob"
"Carol"
"Ted"
"Alice"
9
23.34
Accept and try it out. Note: Choosers dont accept functions to evaluate. (Choosers cant be beggars?)
Right-click on the monitor and choose Edit. Insert person as the
global variable. Accept and try it out.
Comment: You can also use a chooser to control execution of the
program. Think of the choices as determining scenarios.
1.2.5.5
Input: Input Boxes are global variables that contain strings or numbers. The model author chooses what types of values the user can
enter. Input boxes can be set to check the syntax of a string for commands or reporters. Number input boxes read any type of constant
number expression which allows a more open way to express numbers
than a slider. Color input boxes offer a NetLogo color chooser to the
user.
Try one out. Use the variable name bob. Type print bob from the
command center.
1.2.5.6
Monitor: Monitors display the value of any expression. The expression could be a variable, a complex expression, or a call to a reporter.
Monitors automatically update several times per second.
CHAPTER 1. STARTERS
A reporter is a procedure that returns a value. Were not there yet
(but we will be).
Click and draw a monitor. In the Reporter text area, type Mutation?.
Accept and try it out.
1.2.5.7
Output: The output area is a scrolling area of text which can be used
to create a log of activity in the model. A model may only have one
output area.
Click and draw an output area. Edit the button and change the first
line from print Mutation? to output-print Mutation?.
Accept and try it out. You can essentially achieve this by writing to
the Command Center with print etc. However, clear-all clears the
output area, but not the command center output area.
See also: print, show, type, write.
1.2.5.9
Note: Notes lets [sic] you add informative text labels to the Interface
tab. The contents of notes do not change as the model runs.
Nor can your program modify them. Useful for giving basic directions
to users.
Click and draw a note. Insert Click here to initialize: in the text
area. Accept. Right-click and choose Select. Move (mouse down
and drag) the note to a point above the button. Click outside the note
to deselect it.
1.2.6
Were going to create a stream (eventually two streams) random walk data,
and plot the results. This will be a bit more complex than what we have
done so far.
1. Begin by creating two buttons: Setup and Random Walking. For now,
just give them display names only, with nothing to do.
10
CHAPTER 1. STARTERS
Walkingto run the model. You may find it useful to add other buttons. Especially during development, they can be useful for debugging.
5. Now create a plot. Click and drag the plot widget to an appropriate
spot. In the Name field, type:
My first plot
Set X min to 0, X max to 10.0, Y min to 20, and Y max to
30. Note: these settings are not crucial, because NetLogo will change
them dynamically as needed.
Click on the Create button and name the new plot pen daStreamAPen.
Select its color to be cyan.
Click Ok.
6. In the Commands text area of the Random Walking button, type:
print (word "streamA " streamA)
set daNewA ((random-float 1) - 0.5)
print (word "daNewA " daNewA)
set streamA (streamA + daNewA)
Click the Forever check box. Click Ok.
Note well: NetLogo now uses the reporter word to concatenate strings.
See the NetLogo Dictionary on word for details.
What this code does is the following. Weve initialized streamA to be
25.0. We draw a random number between 0 and 1 (with random-float
1) and add it to streamA, subtracting 0.5 at the same time. So, the
new value of streamA is the old value plus or minus a random amount
between 0 and 0.5. streamA will drift aimlessly, in what is called a
random walk. Note that step intervals other than (0, 0.5) are possible;
weve just chosen that one for convenience.
Another comment on the code. word in the first line is being used
as a string concatenator (concatenator = putter together). In
the third and fourth lines the plus sign is being used for numerical
addition. Notice especially that in NetLogo the operators must have
white space surrounding them. a + b is OK, but a+b is not.
Then click the Setup button followed by the Random Walking button.
11
You will see output scrolling by in the Command Center output window. After a short time, click on the Random Walking button again
to stop the run.
Now click on the double-headed arrow, next to the Clear button, at
the far right of the Command Center output window. See the image
that follows.
25.0
-0.082978
24.917022
-0.4998856316786342
24.417136368321366
-0.353244107423887
24.06389
-0.3137397857321689
23.75015
-0.10323251879902084
23.64692
-0.08080549071321619
12
CHAPTER 1. STARTERS
streamA
daNewA
streamA
daNewA
streamA
daNewA
streamA
23.566114509286784
-0.295548
23.270561999999998
-0.47261240282038
22.79795
-0.08269519422643179
22.71525480577357
Note again: Seeding the random number generator with 1 should produce these values reliably. (Actually, sometimes NetLogo seems to
round off the values. Im not clear why this seemingly irregular behavior occurs.)
Click the Clear button to remove the text from the Command Center
window. Click the double-headed arrow again to return the Command
Center window to its original and diminished position.
7. Now lets do some plotting. Add the following code to the code area
of the Random Walking button:
set-current-plot "My first plot"
set-current-plot-pen "daStreamAPen"
plot-pen-down
plot streamA
This snippet of code should be readily understandable. First, we tell
NetLogo which (of possibly many) plots we want to access. Next we
tell NetLogo which (of possibly many) pens (for distinct streams of
data) we wish to use. We place the pen down and we plot the current
value of our variable of interest, here streamA. And thats it.
Click the Ok button in the Random Walking dialog box. Click the
Setup button, then click Random Walking and watch the plot unfold!
8. Now well add a second random walk stream. First, add two new
sliders, for global variables daNewB and streamB, analogous to daNewA
and streamA. Second, edit (right-click then choose Edit) your plot,
creating a new pen called daStreamBPen and set its color to magenta.
Third, modify the code for the Setup button to read as follows:
clear-all
13
1.2.7
Introduce a Bug
The first line of the code for the Random Walking button is now
;print (word "streamA " streamA)
Change it to
14
CHAPTER 1. STARTERS
1.3
Not a lot to say here. A nice design. Two modes: view and edit. Go to edit
mode and notice the simple pattern.
[Later: Using the ODD protocol here for documentation: http://bio.
uib.no/te/papers/Grimm_2010_The_ODD_protocol_.pdf.
1. Purpose
2. State variables and scales
15
clear-all
set daNewA 0.0
set streamA 25.0
set daNewB 0.0
set streamB 25.0
random-seed 1
Notice that the shaded area uses typewriter font (conventional for code).
1.4
16
CHAPTER 1. STARTERS
The Find. . . function is for searching for text in the edit area (the
large white area extending below). The Check function is for validating
your code, looking for syntax errors. The Procedures function is a dropdown list that allows you to see, select, and go to a particular procedure.
The rest is the large white editing area extending below.
There are two types of procedures: commands (which correspond to subroutines in other languages or procedures with void returns) and reporters
(which in other languages are often called functions, or procedures that return values). Commands do things, but do not return values. Reporters
return values. NetLogo is not case-sensitive. Even so, Ill try to follow this
stylistic convention:
Procedurescommands and reportersbegin with an upper-case letter
Variables begin with a lower-case letter
After the first character, both procedures and variables UseTheCamelBackConvention.
1.4.1
17
To declare a reporter, call it SumOfTwoNumsSquared, that accepts one argument and returns the argument plus one squared, do this:
to-report SumOfTwoNumsSquared [daFirstNumber daSecondNumber]
report (daFirstNumber + daSecondNumber) * (daFirstNumber + daSecondNumber)
end
To declare a command, call it MyFirstCommand, use the following format:
to MyFirstCommand
print "Hello from MyFirstCommand."
print (word "The square of 3 + 2 is "
end
SumOfTwoNumsSquared(3)(2)
Try typing these into the procedures edit area. Then create a button and
call MyFirstCommand. Points arising:
1. Reporters and commands may or may not require accompanying arguments to be specified. If arguments are specified you show this as
in the declaration for the reporter SumOfTwoNumsSquared, with the
arguments specified between square brackets and separated by white
space if there is more one.
2. NetLogo uses square brackets, [. . . ], to indicate lists (of which more
later). Items in a list are separated by white space.
3. NetLogo supports various arithmetic and mathematical operators, e.g.,
+ for addition, * for multiplication, ^ for exponentiation, and so forth.
NetLogo requires that these operators be surrounded by white space.
So, 2*3 is not legal, but 2 * 3 is.
1.4.2
NetLogos variables are not typed, but they must be declared. NetLogo
supports both global and local variables. Global variables may be declared
in either of two ways. First, using a variable in a slider or switch on the
Interface Tab counts as declaring the variable as global. Second, at the top
of the procedures edit area, you can declare NetLogo global variables using
this format:
".")
18
CHAPTER 1. STARTERS
1.4.3
1.4.4
Assignment: Set
19
1.4.5
Turtles and patches are agents, objects with properties. By default every
patch has the properties: pxcor, pycor (its x and y coordinates on the
world grid), pcolor (its color), plabel, and plabel-color. You can see
the properties of a patch by right-clicking on it, then choosing to inspect it.
Turtles come by default with a longer list of properties. These, too, you can
see (and edit) by right-clicking on a turtle and choosing to inspect it.
Your program can alter any properties a patch or turtle has. In addition,
and most usefully, your program can add properties to turtles and to patches.
For example, placing
patches-own [ playerType ]
at the beginning of the procedures edit area, below globals and above the
first procedure will cause all patches to have a new property, playerType.
If you want more properties added, just add them to the list, which above
contains just playerType. Similarly, you can add properties to turtles with,
e.g.,
turtles-own [ speed availableEnergy]
If you want to set a property of a turtle or patch to a certain value, you
ask, e.g.,
ask turtle 0 [set shape "airplane"]
Note: every turtle has an ID number. Numbering is in sequence, beginning
with 0. There are a number of shapes that ship with NetLogo (ship shapes?).
You can see the current list by typing
show shapes
in the Command Center. Similarly, you can ask a patch to set one of its
properties, whether given by default or added by you, e.g.,
ask patch
20
CHAPTER 1. STARTERS
Note that every patch is identified uniquely by its x-y coordinate numbers
on the world grid.
If you want all the patches or turtles to do something, you just ask, e.g.,
ask patches [set pcolor "blue"]
And similarly for ask turtles. With these commands you exploit NetLogos simulation of parallel programming. NetLogo updates the agents in
random order.
NetLogos of and one-of mechanisms are also quite useful. -of is used
with a property, e.g.
set [color] of turtle 0 blue
Use of when dealing with one turtle or one patch. You can also use it for
agentsets, collections of NetLogo agents (see 1.4.6 below). See of in the
Dictionary.
You use with to select a set of turtles or patches from a larger group,
e.g.,
ask turtles with [shape = "default"] [set color green]
Again, see the Dictionary.
NetLogos one-of randomly selects one item from a list. For example,
print one-of ["Bob" "Carol" "Ted" "Alice"]
1.4.6
Agentsets
21
with
turtles-here
in-radius
at-points
neighbors4, neighbors
turtles-on
Useful built-in reporters taking agentsets as arguments:
max-one-of and min-one-of
one-of, n-of
values-from
1.4.7
Breeds of turtles
Turtles, but not patches, can be organized by breeds, which are classes
distinct agentsetsof turtles. Use breed at the top of the procedures edit
area, before the procedures, to declare new breeds, e.g.,
breed [ optimists optimist]
breed [ pessimists pessimist]
Then, where you might say turtles you can now say optimists or pessimists,
and where you might say turtle you can now say optimist or pessimist.
You can still write
create-turtles 17
and you can also write
create-optimists 23
22
1.4.8
CHAPTER 1. STARTERS
Lists
This adds "Bob" to the beginning (position 0) of daList, making it one item
longer. Use lput for adding to the end. Note well: In NetLogo lists are
naturally accessed from the front. If you need to access (add, delete, find
something in) a list towards the end, it will often be faster to reverse the
list, access it, and then reverse it again.
set daList but-first daList
This removes the first item in daList. Use but-last to remove the last
item.
List are used for controlling iteration. Example:
foreach [1 2 3]
[crt ?]
This does what in other languages might be done with
for i=1 to 3
crt(i)
next i
or with
for (int i=1; i < 4; i++) {
crt(i)
}
23
1.4.9
Character strings
Are indicated with double quotes, e.g., "Bob". Generally, if a built-in reporter works on a list it will work on a string, too. Example:
print length (list 2 4 6 8)
print length "Now is the time"
In addition there are string-specific built-ins: is-string?, substring, word.
Recall that string concatenation is done with word, e.g.,
print (word 17 " is " "an odd number").
1.4.10
I/O
You can read from and write to files, in simple ways. You can make QuickTime movies of the execution of your NetLogo program.
Here, too briefly, is example code for writing to a file. Its taken from
Chapter 9. NetLogos file handling capabilities are very basic (maybe primitive would be a better word). Anyway, only one file open at a time, be
sure to close files when youre done, and writing to a file appends to whats
there, so if you want a blank file, first check to see if it exists and if it does,
delete it.
4
5
6
18
19
20
24
CHAPTER 1. STARTERS
1.4.11
25
3. while
From the manual:
while [reporter] [ commands ]
If reporter reports false, exit the loop. Otherwise run commands and repeat.
The reporter may have different values for different agents,
so some agents may run commands a different number of times
than other agents.
while [any? other turtles-here]
[ fd 1 ]
;; turtle moves until it finds a patch that has
;; no other turtles on it
1.4.12
Two main command procedures: Setup and (then) Go, both called by buttons on the Interface tab, and Go a forever button. Setup initializes, Go
handles the main loop of execution. Both can (and usually should) call
various reporters and command procedures as subroutines.
26
CHAPTER 1. STARTERS
Chapter 2
27
2.1
2.1.1
Variables set on the Interface tab are global, as are variables declared with
globals (at the top of the Procedures window).
globals [Row ; the row player
Col ; the column player
]
To set a global variable, use set, e.g.,
set Row turtle 0
set Col turtle 1
All other variables are local. To declare a local variable use let and give
it a value, e.g.,
let carol 8
Once declared (assuming you are in its scope) you change the value of a
local variable with set, e.g.,
set carol (carol + 1)
Note: you need white space before and after arithmetic operations.
2.1.2
29
Reporters
to-report bob [x y]
report (list 3 4 x y)
end
to test
let carol bob ("hello")("there")
print first carol
print last carol
print carol
end
This code is in Simple2x2.nlogo. Try typing test in the command line (on
the interface tab). Note that using a test procedure like this is a good idea
during program development.
Note well: use of square and round brackets.
2.1.3
Lists
2.1.4
Random Numbers
2.1.5
Turtles
See the Turtle category in the Dictionary. Turtles (which can move) and
patches (which cannot move) are, with lists, the main data structures in
What this does is to define new attributes that all turtles will have. We
can define as many as we want. Our program will use this attributes as
turtle-specific variables, which will be set perhaps many times during a run.
2.2
Understanding Simple2x2.nlogo
2.3
Exercises
2.3. EXERCISES
31
(a) TitForTatComplement. Defaults to 1, after that, like TitForTat it mimics the play of the counter-player in the previous
round. (Also known as SuspiciousTitForTat.)
(b) 2 Tits for OneTat.
(c) Tit for Two Tats.
(d) All of the strategies used by Axelrod in his tournaments.
4. Add a feature to output the run information to a comma separated
file. Such files are easily read by R, Excel, and other data analysis
programs. See the Files category in the Dictionary. You should settle
on a name for your file, such as Simple2x2Output.txt. When you go to
write your data to your file for the first time, you will normally want
to see if the file already exists. If it does and you want to start anew,
then delete it.
Dont forget to close your file when you are done. Also, NetLogo really
only lets you deal with one open file at a time.
5. Add a slider to the Interface tab, named NumReplications. Then
make appropriate code changes so that that number of replications is
run for any given setting. Preferably, make this work with the file
logging feature so that results from each replication are stored (as
rows) in a comma separated file.
6. Add features to the program so that you can run tournaments, say one
strategy playing each strategy in a given list. Make sure the results
are properly recorded a log file.
7. Add features to the program so that you can do multiple runs for
sensitivity analysis. For example, you might vary the payoffs in a
game systematically, undertake multiple runs, record the data, and
see how the payoff changes affect the performance of a strategy.
Chapter 3
3.0.1
Exercise 1
We write two commands: Setup and Go. In Setup, create a single turtle,
and give it a name, say daTruck which should be global. Position the truck
at patch -10 0. Hint: Use setxy. Give the truck the shape "truck", set
its size to 4, and its heading to 90 (due east).
In Go, when the truck has the shape "truck" move it forward east
one patch per run of Go, until the truck is on patch 10 0. Then, set the
shape to "truck-west" and the heading to 270 (due west). If the shape is
"truck-west", move the truck forward west one patch at a time, until the
truck is on patch -10 0. Now, change its shape to "truck" again and its
heading to due east.
Create buttons for Setup and Go, making Go a forever button. Exercise
the code. Use the speed control slider at the top of the world window to
control the speed of the truck. Experiment with the code a bit to add
features, e.g., change the color of the truck depending on its direction.
3.0.2
Exercise 2
We write two commands: SetupPlus and GoPlus, and buttons to call them.
Now we declare delivery-trucks as a new breed with breed [delivery-trucks
delivery-truck] and we add loading-time as a property of delivery-trucks.
Do this with delivery-trucks-own [ loading-time ]. Our truck will
take some time to load and unload.
Write SetupPlus much as you did Setup, but use create-delivery-trucks
instead of create-turtles and set the loading-time of our truck to -1.
Write GoTruckPlus much as you did GoTruck, but when the truck arrives at the eastern terminus, set its loading-time to 4, then decrement
loading-time by 1 each time step until it equals 0. At that time, set the
shape and direction for heading west, and set loading-time to -1 again.
When the truck arrives at the western terminus, it should be handled
analogously to what was done at the eastern terminus.
35
Using buttons for SetupPlus and GoPlus, exercise the code and experiment with changing it.
3.0.3
Exercise 3
Now well create two delivery trucks and run them in parallel at different
speeds. We write two commands: SetupPlusArg and GoPlusArg, and buttons to call them. Well also write a command, GoTruckPlusArg that takes
a delivery truck as its calling argument and processes its activities.
There are one or two important issues here. First, we want different
trucks to do things at different, idiosyncratic speeds. Well facilitate this
by maintaining a global counter, mytick, which we increment each time
GoPlusArg is called. A particular truck will do things based on the value of
mytick. A truck that does something every 2 ticks, for example, will check
for mytick mod 2 = 0. A slower truck might act when mytick mod 5 = 0.
Note well: Consider how to do all of this more elegantly using the Note well
reserved words in NetLogo, tick and ticks.
The second important issue is that we want a single way to handle all
of the delivery trucks, even though they behave differently. We do this by
giving them different values for their properties and writing a command (here
GoTruckPlusArg) that handles any delivery truck based on its property
values.
So, GoTruckPlusArg is very like GoTruckPlus of exercise 2, except that
it takes a delivery truck as an input argument.
Delivery trucks now have more properties: delivery-trucks-own [
speed loading-time loading-flag loading-time-left].
In SetupPlusArg we create two delivery trucks. Call them daTruck,
as before, and daOtherTruck. Make one of the truck green and the other
yellow (or pick some other color scheme). Both trucks should have their
loading-flag set at -1. Let one have a speed of 2 and give the other
3. Have one truck go between patch -10 0 on the west to 10 0 on the
east, while the other has a route from -10 10 to 10 10. Finally, give one a
loading-time of 3 and give the other a 5.
The job of GoPlusArg is mainly to call GoTruckPlusArg. Here it is:
to GoPlusArg
set mytick mytick + 1
ask delivery-trucks [
if mytick mod speed = 0
[GoTruckPlusArg(self)]
3.0.4
Solutions
The NetLogo program is animation-1-truck.nlogo. When all three exercises are implemented the leading declarations are:
globals [ daTruck mytick
daOtherTruck ]
Exercise 1
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;; Exercise 1 ;;;;;;;;;;;;
to Setup
clear-all
create-turtles 1
set daTruck turtle 0
ask daTruck
[setxy -10 0
set shape "truck"
set size 4
set heading 90]
end
to Go
ask daTruck [
if (shape = "truck") [
37
ifelse (xcor < 9)
[fd 1]
[fd 1
set shape "truck-west"
; Note: the shape is defined in the library as "truck-west"
; Things dont work properly if you change capitalization at all,
; e.g., "truck-west". Its safest just to always use lower case.
set heading 270]
] ; end of if shape = truck
if (shape = "truck-west") [
ifelse (xcor > -9)
[fd 1]
[fd 1
set shape "truck"
set heading 90]
]
] ; end of ask daTruck
end ; of Go
3.0.4.2
Exercise 2
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;; Exercise 2 ;;;;;;;;;;
to SetupPlus
clear-all
create-delivery-trucks 1
set daTruck delivery-truck 0
ask daTruck
[setxy -10 0
set shape "truck"
set size 4
set speed 3
set heading 90
set loading-time -1]
end
to GoTruckPlus
ask daTruck [
if (shape = "truck") [
ifelse (xcor < 9)
[fd 1]
[if (loading-time < 0) [
set loading-time 4]
if (loading-time > 0) [
set loading-time loading-time - 1]
if (loading-time = 0) [
set shape "truck-west"
; Note: the shape is defined in the library as "truck-west"
; Things dont work properly if you change capitalization at all,
; e.g., "truck-west". Its safest just to always use lower case.
set heading 270
set loading-time -1]
]
] ; end of if shape = truck
if (shape = "truck-west") [
ifelse (xcor > -9)
[fd 1]
[if (loading-time < 0) [
set loading-time 4]
if (loading-time > 0) [
set loading-time loading-time - 1]
if (loading-time = 0) [
set shape "truck"
set heading 90
set loading-time -1]
] ; end of else in ifelse
] ; end of if shape = truck-west
] ; end of ask daTruck
end ; of GoTruckPlus command
to GoPlus
set mytick mytick + 1
ask daTruck [
if mytick mod speed = 0 [
39
GoTruckPlus
]
] ; end of ask daTruck
end
3.0.4.3
Exercise 3
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;; Exercise 3 ;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;
;;; SetupPlusArg ;;;;
;;;;;;;;;;;;;;;;;;;;;
to SetupPlusArg
clear-all
create-delivery-trucks 2
set daTruck turtle 0
set daOtherTruck turtle 1
ask daTruck
[setxy -10 0
set shape "truck"
set size 4
set speed 3
set heading 90
set color green
set loading-flag -1
set loading-time 3]
ask daOtherTruck
[setxy -10 10
set shape "truck"
set size 4
set speed 2
set heading 90
set color yellow
set loading-flag -1
41
if (shape = "truck-west") [
ifelse (xcor > -9)
[fd 1]
[ if (loading-flag > 0) [
set loading-time-left loading-time-left - 1]
if (loading-flag < 0) [
set loading-time-left loading-time
set loading-flag 1]
if (loading-time-left <= 0 and loading-flag > 0) [
set shape "truck"
set heading 90
set loading-flag -1
set loading-time-left 0]
] ; end of else in ifelse
] ; end of if shape = truck-west
] ; end of ask daTruck
end ; of GoTruckPlusArg command
Chapter 4
4.1
Basics
bob
first bob
but-first bob
reverse bob
item 3 bob
44
4.2
4.2.1
Exercise 1
4.2.2
45
Exercise 2
If your list contains elements other than numbers, for example strings or
other lists, then numerical operations performed while iterating on the list
(e.g., with map or sum) will cause an error condition.
The solution to this problem is to write a reporter that determines
whether or not everything in the list is in fact a number. NetLogo has
built-in reporters that find the types of objects. Specifically, is-number?
reports true if the argument is a number, and false otherwise.
Write a reporter that accepts a list as its argument and returns true
if every element is a number and false otherwise. Hint: member? xx yy
reports true if xx is a member of list yy and false otherwise.
See NetLogos manual for other is- reporters.
4.2.3
4.2.3.1
Solutions
Exercise 1
Exercise 2
46
4.3
Lists are often useful for remembering things. The agent observes something,
notes a value in a list (use fput for efficiency), . . . .
observer> set bob fput 6 bob
observer> print bob
[6 1 2 3 4 5]
. . . and after a time takes an action depending on the contents of the list,
i.e., the data collected and remembered. Then, typically, the agent will reset
the list, making it empty, [].
In this exercise we model a form of learning I call Probe and Adjust.
A source of data, puts out (to begin) a constant value. Our agent wants to
learn what that value is. The agent has an initial guess, currentValue. In
each tick, the agent uses its currentValue to make a guess. Specifically,
the agents guess is a uniformly random number between currentValue delta and currentValue + delta, where delta is a global variable (think:
slider) and is small compared to currentValue.
After the agent guesses, the data source returns to the agent the absolute
value of the difference between the guess and the sources value. The agent
maintains two lists: one for guesses above currentValue and one for guesses
below currentValue. The agent records the sources responses in whichever
list is appropriate. After a number of guesses, epochLength, another global
variable, the agent adjusts its currentValue. If the high guesses on average
produce smaller errors, then the agent adjust currentValue up by epsilon,
another global variable or parameter, one that should be smaller than delta.
And similarly if the low guesses do better.
You should plot both the sources value and the agents guesses. What
happens?
Now make the sources values a mild random walk. Can the agent track
the changes? Under what conditions?
See Figure 4.1, page 47, for pseudocode presenting Probe and Adjust.
47
4. returnsDown []
5. Do forever:
6. episodeCounter episodeCounter + 1
7. bidQuantity U [currentQuantity , currentQuantity + ]
(The agents bidQuantity is drawn from the uniform distribution
within the range currentQuantity .)
8. return Return-of bidQuantity
(The agent receives return from bidding bidQuantity.)
9. If (return currentQuantity) then:
returnsUp Append return to returnsUp
else:
returnsDown Append return to returnsDown
10. If (episodeCounter mod epochLength = 0) then:
(Epoch is over. Adjust episodeCounter and reset accumulators.)
(a) If (mean-of returnsUp mean-of returnsDown) then:
currentQuantity currentQuantity +
else:
currentQuantity currentQuantity
(b) returnsUp []
(c) returnsDown []
11. Loop back to step 5.
Figure 4.1: Pseudo code for basic Probe and Adjust
48
4.4
4.4.1
Mutation
4.4.2
Recombination
In recombination, two (or more, but well stick to two) solutions exchange
genetic material, at least metaphorically. A simple way to this is with singlepoint crossover. Two solutions are identified as well as a crossover point. If
our solutions are
[1 1 0 1 1 0 0 0]
and
49
[1 1 1 1 1 1 1 1]
and our crossover point is 3, then the two resulting solutions are
[1 1 0 1 1 1 1 1]
and
[1 1 1 1 1 0 0 0]
Write a reporter that accepts two solutions on input and a probability
of crossover, and returns two solutions, appropriately, using single-point
crossover.
The single-point crossover has a bias. It matters what the order is of
the meaning of the alleles. This can be overcome with two-point crossover.
Instead of one point of exchange, there are two. So, for example, if our
previous two solutions were instead crossed over at points 3 and 6, we would
get
[1 1 0 1 1 1 0 0]
and
[1 1 1 1 1 0 1 1]
Write a reporter that accepts two solutions on input and a probability of
crossover, and returns two solutions, appropriately, using two-point crossover.
50
Chapter 5
Programming exercise:
evo-dyna
In this chapter we present a programming exercise to develop a simple model
in NetLogo that exercises an evolutionary dynamic (evo-dyna) in a finite
population of players playing a 22 game. Here is a schematic for the game:
0
1
0
(row00, col00)
(row10, col10)
1
(row01, col01)
(row11, col11)
Each player, Row and Column, has two stage-game strategies, labeled
0 and 1. The payoffs are listed in the form rowXY and colXY. Row gets
rowXY if Row plays its strategy 0 and Column plays its strategy Y.
This is a discrete (finite population) version of the replicator dynamics,
which is modeled using differential equations. In our finite and discrete
model, we have a population of players represented as patches in the NetLogo
world. Each patch is a player and each player has a playerType.
We distinguish four types of players: "type00" players play strategy 0
as Row and 0 as Column; "type10" players play strategy 1 as Row and 0
as Column; "type01" players play strategy 0 as Row and 1 as Column; and
"type11" players play strategy 1 as Row and 1 as Column.
A run is organized by distinct generations. Each generation consists of a
number of rounds of play, that number being set by the RoundsPerGeneration
slider/global variable. A generation is run the command RunAGeneration.
At the heart of this command is the following mixture of code and pseudocode (indicated by < code goes here >):
51
52
53
RunAGeneration command needs to be developed as part of this exercise, although considerable structure is available for you there.
2. There are 8 sliders for setting the globals row00, row01, row10, row11,
col00, col01, col10, and col11. These are the payoffs to the Row
and Column players. So rowXY is the payoff to Row if Row plays
strategy X and Column plays strategy Y.
Note especially that this representation is quite general and in particular allows for non-symmetric 22 games.
Payoffs should not be negative.
3. There are 4 slides for setting the globals initialWeight00, initialWeight01,
initialWeight10, and initialWeight11. The program permits up
to 4 types of players. Players of typeXY play strategy X when they
are Row players and strategy Y when they are Column players.
The expected percentage of the various types in each generation is
determined from the weights. A types percentage is just its current
weight divided by the total weight of all the types. These four sliders
initialize the four weights. After that, returns from play are accumulated during a generation and used to determine the percentages for
the next generation.
4. There is a slider for the global variable roundsPerGeneration. During
each generation the number of rounds of play is roundsPerGeneration.
In a single round of play, two patches are randomly chosen, one to be
the Row player, the other to be the Column player. They play as specified and the resulting payoffs are accumulated during the generation.
Note that in the Test command there is some useful code for conducting a round of play:
set
set
set
set
54
Now, the best next step is probably to study Setup and understand how
it works. After that, you should be able to begin designing and coding for
this exercise.
Chapter 6
Diffusion
Use the diffuse command to create patches with different heights. Use
patches-own [height]
to give each patch a height. Pick one patch, say patch 0 0, to be the top of
a hill. Set its height to some reasonably large number, say 100. Now set the
pcolor of that patch to some extreme on the color table. See Programming
Guide and Colors within it. For example height = 100 might map to 69.9,
which is white. Height = 0 might map to 60, which is black, the default
patch color. And heights in between to colors between would be various
shades of green.
Now use diffuse to make neighboring patches have non-zero heights.
Do all of this so it displays nicely and the hill is visually evident.
6.2
Hill Climbing
Create a turtle that is able to climb the hill you just built. See uphill (and
downhill). You might also use neighbors.
These methods assume the agent, here a turtle, has a very short field
of vision, i.e., that he can see only his immediate neighbors. Redo the
procedures so that the turtle has a field of vision set by a parameter ( 1).
Hint: Look at the documentation for in-radius.
55
56
Chapter 7
7.1
File Output
58
Often, the file will exist, but you no longer want the data, you want to write
new data to an empty file. In that case, you need to check whether the file
exists and if so, delete it. Lines 24 from Figure 7.1 on page 60 show how
to do this:
; Delete the existing file if there is one.
if (file-exists? "data-dump-example.txt")
[file-delete "data-dump-example.txt"]
Now that the file is open, you can write to it. Line 7 from Figure 7.1 on
page 60 shows how to do this:
file-print "Bob,Carol,Ted,Alice"
file-print prints strings (as here) as well as numbers and even agents, and
then terminates the line, so that the next thing you output begins the next
line of the file. If you dont want to start a new line, use file-write.
To close a file, use file-close. Its important to do this, if only because
you cant open and opened file. Error!
7.2
Output format
Under the Tools menu in NetLogo you will find the BehaviorSpace option.
It is for parameter sweeping, that is, running a model multiple times with
different parameter values, and recording data. This is a fine thing to do
and we shall do it. But well do it without BehaviorSpace. Still, its worth
looking into.
The format for data from BehaviorSpace is idiosyncratic spreadsheet.
Much better is what Ill call R-tabular format (after R, the statistical
analysis package, http://www.r-project.org/, and what it likes), which I
define as follows.
1. The (text) file consists of rows of one or more items (or fields), with
each row having the same number of items.
2. The items are separated by a common symbol, which I shall take to
be the comma, ,.
3. The first row in the file contains headers for each of the columns, that
is, names for the data fields under them.
59
4. After the first row, all rows at data records. The records may mix data
types; specifically, they may include integers, floating point numbers,
and text. The text items should not have spaces in them; use a dash
or underscore if you want to preserve the appearance of a space.
The NetLogo code in Figure 7.1 on page 60 produces output files in
R-tabular format. Here is the top portion of one such file:
Bob,Carol,Ted,Alice
2,3,4,100
2,3,4,101
2,3,5,100
2,3,5,101
2,5,4,100
2,5,4,101
2,5,5,100
2,5,5,101
2,7,4,100
2,7,4,101
2,7,5,100
2,7,5,101
4,3,4,100
4,3,4,101
4,3,5,100
Note well: Although NetLogo has a file-close-all command, only one file
at a time can be available for writing (or for reading). So, if you open a file,
close it as soon as you are done writing. Dont rely on the file-close-all
command.
Study Figure 7.1 on page 60 to make sure you understand how it works.
60
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
to dump-em
; Delete the existing file if there is one.
if (file-exists? "data-dump-example.txt")
[file-delete "data-dump-example.txt"]
; Print the headers for the file. Assume CSV.
file-open "data-dump-example.txt"
file-print "Bob,Carol,Ted,Alice"
file-close
let firstLoopCounter 0
let secondLoopCounter 0
let thirdLoopCounter 0
let fourthLoopCounter 0
foreach [2 4 6] [
set firstLoopCounter ?
foreach [3 5 7] [
set secondLoopCounter ?
foreach [4 5] [
set thirdLoopCounter ?
foreach [100 101] [
set fourthLoopCounter ?
; Print the records to the file. Assume CSV.
file-open "data-dump-example.txt"
file-print (word firstLoopCounter "," secondLoopCounter ","
thirdLoopCounter "," fourthLoopCounter)
file-close
] ; end of fourth loop
] ; end of third loop
] ; end of second loop
] ; end of first loop
end ; end of to dump-em
Figure 7.1: Example procedure to write data to a file. Line numbers added.
Code is from Example-data-writing.nlogo.
7.3. EXERCISES
7.3
61
Exercises
7.3.1
62
Chapter 8
8.1
How It Works
There are two procedures: Setup and Go. Both have buttons on the Interface
tab, with Go being a forever button. You initialize the system by clicking on
the Setup button. You then run the system by clicking on the Go button.
You stop the run by clicking on the Go button again.
0. Time proceeds discretely by ticks (of the clock; tick in NetLogo).
1. The queue is represented by a list of turtles waiting to be served. Its
name in the program is customerQueue, a global variable. When a
new turtle arrives it is put at the end of the queue (under a presumed
first-come-first-served regime). In NetLogo
set customerQueue lput nextCustomerToArrive customerQueue
63
64
65
66
At this point, the end of Go, statistics, plots etc. may be updated. Monitors
on the Interface tab presently handle what is done directly.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
67
68
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
to Go
tick
if [arrivalTime] of nextCustomerToArrive <= ticks
[set customerQueue lput nextCustomerToArrive customerQueue
create-customers 1
ask customer max [who] of customers
[set arrivalTime (ticks + random-exponential
meanCustomerInterarrivaltime)]
set nextCustomerToArrive customer max [who] of customers
]
ask servers [
if idle = false and scheduledCompletion <= ticks
[let toDie [who] of processingCustomer
ask customer toDie [die]
set idle true
set scheduledCompletion -1
set processingCustomer []
]
; If you are idle and there is a customer to serve,
; dequeue it and start processing it.
if idle = true and length(customerQueue) > 0
[set processingCustomer first customerQueue
set customerQueue but-first customerQueue
set scheduledCompletion (ticks + random-exponential
meanCustomerServiceTime)
set idle false
set [deQueueTime] of processingCustomer ticks
]
]
end
Figure 8.3: Go procedure of SimpleQueuingModel.nlogo
Chapter 9
Doing Experiments
It is appropriate to think of an ABM, or indeed any computational model,
as calculating one or more functions. Given a setting of the parameters,
or more generally a configuration of the model, the model is executed and
produces results. We mayindeed shouldthink of the configuration of the
model as fixing predictor (exogenous) variables and the results produced as
response (exogenous) variables. The function computed is from the predictor variables to the response variables. To understand or investigate the
computational model is to understand or investigate this function.
At bottom, we investigate a computational model because we want to
describe it partially or in summary form, because we find this valuable.
We summarize the model with certain findings of interest or with a simpler
model, for example a low-order polynomial model, as would be generated
by a regression study.
Directly or indirectly we are presented with a number of issues associated
with any attempt to understand or investigate a computational model.
1. Model setup. Setting up, possibly reprogramming, the computational model so that it can be run in a way that collects the data we
wish to have.
2. Variable construction. Constructing, arranging to generate, the
appropriate response variables.
3. Response point estimation. Estimating the response variables for
a given configuration. Every ABM (or very nearly so) is a stochastic
computational model, so its outputs, the particular realizations of its
response variables, will vary from run to run. The results from any
single run are not likely to be credible unless supported by adequate
69
70
In this chapter I aim to illustrate the basics of, the first steps in, experimental
investigation of computational models. There is very much more to the
subject. Here we have only a beginning, but a useful one.
In addressing the issues, above, I shall work with a single example in this
chapter, the SimpleQueuingModel.nlogo, discussed in the previous chapter.
Readers should first be familiar with it. Here, we shall work with a descendant of that model, called SimpleQueuingModelExp.nlogo.
9.1
Model Setup
71
to Go
tick
Now it begins
to Go
while [ticks < maxTicks]
[
tick
and ends with an added ] to match the one added in line 3 of the
procedure. The former code is completely encompassed within the
body of this added while-loop.
Finally, we need to take care to clear or reset all of the appropriate variables
in globals. When we do this, Setup now begins as follows:
to Setup
clear-all-except-globals ; For a fresh start.
; Now clear the globals we need cleared:
set nextCustomerToArrive nobody
set customerQueue []
There is a third variable in globals, daVersion, which we do not need to
reset here. This solves our first problem.
Our second problem is that the Setup command procedure contains,
indeed begins with, the command clear-all, which (from the NetLogo
manual)
Resets all global variables to zero, and calls reset-ticks, clearturtles, clear-patches, clear-drawing, clear-all-plots, and clearoutput.
We want to do this sort of thing because we want a fresh start with every run.
If we didnt do it then, for example, we might begin a run with unwanted
stuff left over from the previous run. The problem with keeping clear-all
in Setup is that we want to do multiple runs and store the results. How
may runs? Where do the results go? This information is stored in program
variables which would be wiped out if we called clear-all for each new
run.
The solution to this problem is to eliminate the use of clear-all in
Setup, but clear everything except the global variables at the start of Setup.
To do that, we write a new command procedure, called clear-all-exceptglobals, and substitute it for clear-all in Setup. Here it is.
72
to clear-all-except-globals
reset-ticks
clear-turtles
clear-patches
clear-drawing
clear-all-plots
clear-output
end
MasterSetup #1
This doesnt quite give us the capability of doing multiple runs and
recording the data, but were getting close. We need a master setup procedure. It will call Setup and Go for us and wont forget why. Heres a
first version of MasterSetup, after declaring endingNumInQueue in globals.
Well call it MasterSetup #1.
to MasterSetup
; MasterSetup #1
clear-all
let endingNumInQueue []
foreach n-values numRunsToRun [?]
[set currentRunNumber ?
Setup
Go
set endingNumInQueue
lput length(customerQueue) endingNumInQueue
]
print (word "Mean=" mean(endingNumInQueue) ". "
"Variance=" variance(endingNumInQueue) ". Full list:"
endingNumInQueue ".")
print "All done."
end
And so our second problem is solved, at least tentatively.
9.2
Variable construction
73
9.3
We see that the queue lengths are not unduly long. What happens if we run
for more ticks? Here are the results when maxTicks = 1,000.
Mean=21.9. Variance=190.01010101010093. Full list:[
45 8 34 28 19 6 15 14 20 48 15 19 5 24 12 0 52 21 21 1 0
12 20 53 26 1 61 9 34 57 30 14 22 33 39 34 23 12 20 5 15
11 32 23 19 29 20 27 31 5 7 16 22 12 55 35 39 10 28 17 5
2 30 0 25 26 29 12 5 12 32 28 30 10 17 12 14 48 24 28 1
24 22 17 33 29 22 17 33 17 16 46 32 13 9 22 39 3 28 13].
All done.
And here 10,000:
Mean=185.69. Variance=2826.923131313131. Full list:[
145 210 201 219 175 189 177 224 115 189 210 216 57
104 126 109 169 274 322 234 211 103 181 150 186 180
199 186 128 199 122 139 170 150 201 164 211 267 170
191 295 167 182 212 303 174 196 176 192 232 195 139
74
293
208
150
110
All
MasterSetup #2
170
146
176
221
199
138
152
221
With these settings it is evident that the queue length will grow without
limit unless the system is stopped. What is perhaps most interesting is how
long it takes, how many customer arrivals it takes, starting from an empty
system (Good morning!) to have intolerable degradation of service. This is
something that simulation is well suited to investigate.
As we extend and deepening our investigations, however, it makes sense
to write the data to files, and then explore the data with a good statistical
analysis package, such as R, our tool of choice. To do that we begin with
version #2 of MasterSetup.
1 to MasterSetup
2
; MasterSetup #2
3
clear-all
4
; Delete the existing output file, if it exists.
5
if file-exists? "runsOutput.txt"
6
[file-delete "runsOutput.txt"]
7
; Print the data column headers to the output file,
8
; separated by commas.
9
file-open "runsOutput.txt"
10
file-print (word "runNumber,meanCustomerInterarrivalTime,"
11
"meanCustomerServiceTime,maxTicks,numInQueueAtEnd")
12
file-close
13
foreach n-values numRunsToRun [?]
14
[set currentRunNumber ?
15
Setup
16
Go
17
file-open "runsOutput.txt"
18
file-print (word currentRunNumber "," meanCustomerInterarrivalTime ","
19
meanCustomerServiceTime "," maxTicks "," length(customerQueue))
20
file-close
21
]
22
print "All done."
23 end
75
76
Max.
316.0
OK, now lets repeat the experiment with only 20,000 ticks, instead of
10,000.
> carol <- read.table(runsOutput.txt,header=T,sep=",")
> summary(carol$numInQueueAtEnd)
Min. 1st Qu. Median
Mean 3rd Qu.
Max.
199.0
316.5
355.0
357.5
401.8
645.0
> summary(carol)
runNumber
meanCustomerInterarrivalTime meanCustomerServiceTime
Min.
: 0.00
Min.
:4
Min.
:4.4
1st Qu.:24.75
1st Qu.:4
1st Qu.:4.4
Median :49.50
Median :4
Median :4.4
Mean
:49.50
Mean
:4
Mean
:4.4
3rd Qu.:74.25
3rd Qu.:4
3rd Qu.:4.4
Max.
:99.00
Max.
:4
Max.
:4.4
maxTicks
numInQueueAtEnd
Min.
:20000
Min.
:199.0
77
1st Qu.:316.5
Median :355.0
Mean
:357.5
3rd Qu.:401.8
Max.
:645.0
As we can see, the queue is lengthening, the server is falling farther and
farther behind. Of course, we can do statistical tests. Well use Wilcoxons
signed-rank test, which is non-parametric and does not require any assumption of a normal distribution. (See help(wilcox.test).)
> wilcox.test(bob$numInQueueAtEnd,carol$numInQueueAtEnd)
Wilcoxon rank sum test with continuity correction
data: bob$numInQueueAtEnd and carol$numInQueueAtEnd
W = 256, p-value < 2.2e-16
alternative hypothesis: true location shift is not equal to 0
We feel very safe in rejecting the null hypothesis that the means of these
two data sets are identical. And we can see it even better with
> boxplot(bob$numInQueueAtEnd,carol$numInQueueAtEnd)
See Figure 9.1 for the results.
100
200
300
400
500
600
78
Figure 9.1: Box plots of queue lengths. 1) 10,000 ticks. 2) 20,000 ticks.
9.4
79
So far weve had one setting of the predictor variables per data file, with
multiple runs in order to estimate a response variable. This is all well and
good, and it can take us far. Rs summary command (see above) is in fact
very useful and can often settle issues to hand.
But we want more. In particular it is very often important to understand
the joint effects of several predictor (exogenous) variables on a response
variable. So first we have to get the data, generate it and write it to a file,
then we need to analyze it. Well start with what needs to be done first. To
do that we begin with version #3 of MasterSetup.
MasterSetup #3
With maxTicks = 1000 and numRunsToRun=100, we get 900 data records.
As usual, summary is helpful, although not very on the overall data:
> ted <- read.table("runsOutput.txt",header=T,sep=",")
> summary(ted)
runNumber
meanCustomerInterarrivalTime meanCustomerServiceTime
Min.
: 1.0
Min.
:4
Min.
:4
1st Qu.:225.8
1st Qu.:4
1st Qu.:4
Median :450.5
Median :5
Median :5
Mean
:450.5
Mean
:5
Mean
:5
3rd Qu.:675.2
3rd Qu.:6
3rd Qu.:6
Max.
:900.0
Max.
:6
Max.
:6
maxTicks
numInQueueAtEnd
Min.
:1000
Min.
: 0.00
1st Qu.:1000
1st Qu.: 2.00
Median :1000
Median : 10.50
Mean
:1000
Mean
: 21.06
3rd Qu.:1000
3rd Qu.: 36.00
Max.
:1000
Max.
:116.00
We need to simplify. Our first and fourth columns contain data we do not
need for the present, so we extract the needed columns into a:
> a <- ted[,c(2,3,5)]
> summary(a)
meanCustomerInterarrivalTime
Min.
:4
1st Qu.:4
Median :5
meanCustomerServiceTime
Min.
:4
1st Qu.:4
Median :5
numInQueueAtEnd
Min.
: 0.00
1st Qu.: 2.00
Median : 10.50
80
1 to MasterSetup
2
; MasterSetup #3
3
clear-all
4
set currentRunNumber 0
5
; Delete the existing output file, if it exists.
6
if file-exists? "runsOutput.txt"
7
[file-delete "runsOutput.txt"]
8
; Print the data column headers to the output file,
9
; separated by commas.
10
file-open "runsOutput.txt"
11
file-print (word "runNumber,meanCustomerInterarrivalTime,"
12
"meanCustomerServiceTime,maxTicks,numInQueueAtEnd")
13
file-close
14
foreach [4.0 5.0 6.0]
15
[set meanCustomerInterarrivalTime ?
16
foreach [4.0 5.0 6.0]
17
[set meanCustomerServiceTime ?
18
foreach n-values numRunsToRun [?]
19
[set currentRunNumber (currentRunNumber + 1)
20
Setup
21
Go
22
file-open "runsOutput.txt"
23
file-print (word currentRunNumber ","
meanCustomerInterarrivalTime ","
24
meanCustomerServiceTime "," maxTicks ","
length(customerQueue))
25
file-close
26
] ; end of foreach n-values numRunsToRun [?]
27
] ; end of the second foreach
28
] ; end of the first (the outer-most) foreach
29
print "All done."
30 end
Figure 9.2: MasterSetup #3. Nested for loops for a factorial data collection.
Mean
:5
3rd Qu.:6
Max.
:6
81
Mean
: 21.06
3rd Qu.: 36.00
Max.
:116.00
Let us further restrict our attention to those records for which the meanCustomerServiceTime
is 6.0.
> b <- a[a$meanCustomerServiceTime == 6,]
> summary(b)
meanCustomerInterarrivalTime meanCustomerServiceTime
Min.
:4
Min.
:6
1st Qu.:4
1st Qu.:6
Median :5
Median :6
Mean
:5
Mean
:6
3rd Qu.:6
3rd Qu.:6
Max.
:6
Max.
:6
numInQueueAtEnd
Min.
: 0.0
1st Qu.: 13.0
Median : 30.0
Mean
: 37.4
3rd Qu.: 60.0
Max.
:116.0
82
Median
-0.280
3Q
5.507
Max
50.310
Coefficients:
Estimate
(Intercept)
-262.9100
meanCustomerInterarrivalTime
40.9667
meanCustomerServiceTime
75.4267
meanCustomerInterarrivalTime:meanCustomerServiceTime -11.9200
Std. Error t value
(Intercept)
15.6866 -16.76
meanCustomerInterarrivalTime
3.0963
13.23
meanCustomerServiceTime
3.0963
24.36
meanCustomerInterarrivalTime:meanCustomerServiceTime
0.6112 -19.50
Pr(>|t|)
(Intercept)
<2e-16 ***
meanCustomerInterarrivalTime
<2e-16 ***
meanCustomerServiceTime
<2e-16 ***
meanCustomerInterarrivalTime:meanCustomerServiceTime
<2e-16 ***
--Signif. codes: 0 *** 0.001 ** 0.01 * 0.05 . 0.1
1
Residual standard error: 12.22 on 896 degrees of freedom
Multiple R-squared: 0.7563,Adjusted R-squared: 0.7555
F-statistic: 926.9 on 3 and 896 DF, p-value: < 2.2e-16
which I think is not very helpful in this case.
83
meanCustomerServiceTime
4
5
6
14.4
43.71
71.65
2.98
11.25
31.39
1.08
3.14
10.11
6.153 19.366
37.716
Grand Total
43.25333333
15.20666667
4.776666667
21.079
9.4.1
9.5
Response Discovery
Just a word. This is a much larger topic and a difficult one. In a nutshell,
this is a kind of optimization problem: define an outcome region of interest,
then select decision variables in order to minimize the difference between
the response variable and the outcome region of interest.
9.6
Well now take a look at version #4 of MasterSetup. Having seen something MasterSetup #4
84
85
150
100
50
0
alice$meanLengthOfQueueAtEnd
200
86
10
20
30
40
50
60
Index
Figure 9.4: Queue length increases rapidly at 1000 ticks when arrival rate
exceeds service rate
87
88
Chapter 10
How Tos
10.1
neighbors and neighbors4 return AgentSets of turtles on the immediatelyadjacent patches. With in-radius we can collect (now in a list, not an
AgentSet) the turtles (breeds) within a given radius from the calling turtle.
See MatingGame.nlogo.
to-report ListNeighboringBreed[daBreed daRadius]
let toReturn []
ask daBreed in-radius daRadius [set toReturn fput who toReturn]
report toReturn
end
See also in-cone.
But, but, but . . .
The above reporter produces a list of neighbors. Generally better is to
have an AgentSet. Heres how:
let myNeighbors daBreed in-radius daRadius
Simple and elegant! Thats how to do it.
Both approaches assume that they are being called by some turtle.
10.2
90
to-report OppositeGender[MyBreed]
let toReturn XXs
if MyBreed = XYs [set toReturn XXs]
if MyBreed = XXs [set toReturn XYs]
report toReturn
end
Chapter 11
Development Notes
Creates a list and assigns it to bob.
let bob read-from-string (word "[" "1 2 3" "]")
print length bob
91
92
Bibliography
[Railsback and Grimm, 2012] Railsback, S. F. and Grimm, V. (2012).
Agent-Based and Individual-Based Modeling. Princeton University Press,
Princeton, NJ.
93
Index
assignment statement, 3, 6
print, 6, 8
random-seed, 9
button widget, 5
set, 3, 6, 9
set-current-plot, 12
chooser widget, 7
set-current-plot-pen, 12
Code tab, 1
setxy, 34
Command Center, 2
show, 8
Command Center output window, 11
show shapes, 19
commands, 16
sum, 44
ask, 2
turtles-own, 19
ask patch, 20
type, 8
ask patches, 20
with, 20
ask turtle, 2, 19
write, 8
ask turtles, 20
commenting code, 13
clear-all, 3, 8, 9
comments, 18
count, 3
csv files, 75
create-turtles, 2
debugging, 13
fd, 2
downhill, 55
forward, 2
if-else, 6
headed csv format, 75
inspect, 2
is-, 45
in-radius, 55
is-number?, 45
Info tab, 1
length, 44
Interface tab, 1
map, 44
interface widgets, 5
member?, 45
button, 5
mod, 35
chooser, 7
of, 20
monitor, 7
one-of, 20
note, 8
patches-own, 19
output, 8
plot, 12
plot, 8
selecting and deselecting, 8
plot-pen-down, 12
94
INDEX
slider, 6
switch, 6
line breaks, 18
links, 2
Lisp, 44
list commands
length, 44
map, 44
member?, 45
sum, 44
lists, 17, 22, 43
main window, 1
MasterSetup #2, 74
MasterSetup #3, 79, 83
MasterSetup #4, 83
MasterSetup #1, 72
mathematical commands
mod, 35
monitor widget, 7
neighbors, 55
NetLogo
version, ix
note widget, 8
observer, 2
output widget, 8
parallelism, 20
patches, 2
addresses, 2
coordinate system, 5
plot widget, 8
Probe and Adjust, 46
procedures
commands, 16
reporters, 16
QuickStart.nlogo, x
95
R
dataframe, 75
home page, x
summary, 79
wilcox.test, 77
random number generators, 9
reporter, 8
reporters, 16
RTFM principle, ix
self, 36
slider widget, 6
sorting, 43
string concatenation, 10, 23
style conventions, 16
switch widget, 6
ticks, 35
tick, 35
turtle commands
setxy, 34
turtles, 2
uphill, 55
variables
self, 36
View, 2
white space and operators, 10
wilcox.test, 77
world, 2