NetLogo Programming: An Introduction

Overview and Objectives

This appendix provides an introduction to programming in Netlogo 6.

Goals and Outcomes

Prerequisites

Before reading this appendix, please read the Introduction to NetLogo supplement.

NetLogo Models: Basic Structure

Building Models: First Steps

Steps toward Making Your Own Models

  1. Experiment with existing models via GUI

  2. Modify existing models

  3. Roll your own

Modifying Models

Find a model that does something close to what you want:

  • make sure your intended use complies with the copyright

  • save it under a new name

  • add appropriate attribution to the header

  • modify the model to suit your needs

  • update the model documentation to match your changes

  • make sure all borrowed code is clearly and appropriately attributed

Structured and Commented Code

  • use help names for variables and procedures

  • create a procedure for any repeated code blocks (DRY)

  • turn your procedures into pure functions when possible

  • structure and comment your code for readability

This will be:

– helpful to others who read your code – helpful to you in both writing and understanding your code

Simple Modifications: World Settings

You might want to change the World settings:

  • size

  • location of 0, 0

  • topology: torus or rectangle

  • patch size (this and size determine size of world screen)

The topology may be changed in the Interface tab or by means of __change-topology.

New Model: Key Decisions

  • system to be modeled

  • what do the agents represent?

  • what are the rules of action and interaction?

  • how will you approximate these rules in the modeling environment?

  • if your model repeatedly runs a schedule, how much time is represented by one iteration (e.g., by 1 tick)?

Code Tab

The Code tab can contain comments, declarations, and procedure definitions (command procedures and reporter procedures). Outside of code blocks, we should only find:

  • comments

  • NetLogo keywords (see below)

  • special declarations (e.g., <instances>-own; see below)

NetLogo Keywords

The NetLogo Dictionary includes a short list of NetLogo keywords. These are reserved words in the NetLogo language that can appear at the first level in the Code tab (i.e., outside of any procedure definition). Each has a special meaning that is defined in the NetLogo Dictionary. Among the most commonly used keywords, three are use to declare variables (globals, patches-own, and turtles-own) and three are use to define procedures (to, to-report, and end).

Declarations Section

The declarations section precedes the procedures section. The two most common declarations are global variables and agent attributes.

Global Variables

declared globals:

In the Code tab, globals [...] declares a list of global variables.

interface globals

Note: other variables with global scope may be declared in the GUI (e.g., in sliders).

  • each global variable must be declared

  • a global variable can be declared in the declarations section or in the GUI (e.g., in a slider or chooser)

  • every agent can access or set a global variable

  • to assign (or reassign) the value of a global variable, use the set command

Declaration of Instance Attributes

Use the patches-own, turtles-own, and links-own keywords to declare new instance attributes for patches, turtles, and links. (As we will see, we can also declare attributes for turtle breeds and link breeds.) Each of these requires a space-separated list of attribute names. For example,

turtles-own [income wealth]

Procedures Section

The procedures section only contains procedures (user-written commands and reporters). It comes after the declarations section.

command procedure

  • to my-procedure ... end

  • body contains NetLogo commands

reporter procedure

  • to-report my-reporter ... end

  • returns a value

  • must use the report command

Basic NetLogo Model

A basic model typically includes a setup procedure and a go procedure. The setup procedure typically initializes any global variables, initializes any plots, initializes any agents (e.g., by setting the values of patch and turtle properties), and initialize any output files. The go procedure tyypically runs one interation of the core model (by calling other procedures), updates any plots, and updates any output files.

Trivial Model

To produce a very simple example of a NetLogo model, open NetLogo and then enter the following code in the Code tab.

globals [ nHeads ]

to setup
  clear-all
end

to go
  set nHeads (nHeads + fairCoinFlip)
end

to-report fairCoinFlip
  report ifelse-value (random-float 1 < 0.5) [1] [0]
end

Using the Trivial Model

Next, return to the Command Center and enter the following lines, one at a time.

setup
show nHeads
go
show nHeads

Program Structure

Code Examples

The NetLogo Models Library includes a collection of code examples. Be sure to look at these for hints whenever you get stuck.

Basic Program Structure

Even the simplest NetLogo programs traditionally include the following structure:

globals

declaration of global variables using the globals keyword

setup

a procedure named setup that initializes the global varaibles and does other setup operations

go

a procedure that runs one iteration of the model; this holds the “schedule” for your program

Expressions and Statements

Programmers use the term expression for a piece of code that will produce a value. (An example is 1 + 2, an expression involving addition.) Programmers use the term statement to refers to an instruction telling a computer to carry our some action. A NetLogo statement will not return a value, but it will cause some action to take place. (An example is print "this", a print statement.)

We say an expression is evaluated. We say a statement is executed. The action produced by a statement is sometimes called a side effect of the statement.

We build statements from NetLogo command primitives, which are the basic verbs on the NetLogo language. We will be particularly interested in the ask command, which allows us to control our NetLogo agents.

Procedures: Review

Recall that there are two basic types of procedures: reporter procedures, and command procedures.

Reporter procedure stub:

to-report <reporter-name>
  <do-stuff>
  report <return-value>
end

Command procedure stub:

to <command-name>
  <do-stuff>
end

By convention, reporter names are nouns, and command names are verbs.

Documentation: https://ccl.northwestern.edu/netlogo/docs/programming.html#procedures

Reporter Procedures: Second Steps

A reporter procedure may be more complicated than the examples above. It may consumer more than a single argument. And it may have an elaborate procedure bod. The basic structure of a reporter procedure is the following.

to-report <reporter-name> [<parameters>]
  <reporter-body ...>
  report <result>
end

For example, define a bivariate function that returns the larger of two numbers. Here is a traditional approach.

to-report maxof2 [#x #y]
  let _result #x
  if (#y > #x) [
    set _result #y
  ]
  report _result
end

This example is more complicated: the procedure body comprises multiple commands. (Read about ifelse-value for another way to do this.) The let command introduces a new variable in the procedure body, along with its initial value. This example uses the first argument as the initial value. Then an if statement performs conditional branching, using set to change the value of _result if the second argument is the larger. The report command returns the result, which is the larger of the two values.

Local-Variable Naming Convention

Note the underscore beginning the name _result. When presenting NetLogo code, this course adopts a naming convention for the variables introduced in procedure bodies: they always begin with an underscore. No other names begin this way. This ensures that these name are never confused with other variables in our code.

Example: Minimal Program Structure

globals [ gvar01 gvar02 ]

to setup
  clear-all
end

to go
  do-stuff
end

to do-stuff
  ...
end

Program Structure: Setup

As soon as you add any complexity to your model, you will want to break the model set up into parts:

  • the global variables,

  • the patches

  • the turtles

So your model set up procedure will often look like:

to setup
  ca
  setupGlobals
  setupPatches
  setupTurtles
  reset-ticks
end

Note: NetLogo already has a setup-plots command, which in turn is called by reset-ticks. If you want to set up your plots in the Code tab, use the name setupPlots or init-plots instead.

Application: Minimal Program Structure

globals [ nHeads ]

to setup
  clear-all  ;sets nHeads to 0
end

to go
  repeat 50 [
    set nHeads (nHeads + fairCoinFlip02)
  ]
end

to-report fairCoinFlip02
  ;; fill in procedure body
end

Placeholders

When you are writing code, you may wish to refer to a procedure you have not written yet. If you do not define a procedure with this name, the NetLogo syntax checker will complain.

The solution is to define an empty procedure or a procedure that warns you that it needs to be written.

Such placeholders and warnings are sometimes called “scaffolding”. The idea is that assist you in construction of your model, but you intend to remove them from the final product.

Baseline Parameterization

Typically, a model should specify a default parameterization to serve as the baseline parameterization. Use the special startup procedure for this.

If you name a procedure startup, it will be run when your model first loads in the GUI. This is the right place to set default values for your sliders (and other interface globals). Do not set code-tab globals in startup: unlike interface globals, code-tab globals will be reset by clear-all.

Code Analysis

  • scaffolding (print statements)

  • inline tests (if tests with error statements)

  • test procedures (e.g., test-setup and test-go)

  • procedure timing (e.g., reset-timer myproc print timer)

  • profiling (see the profiler extension)

Parameters for Functions and Procedures

The defintions of functions (reporter procedures) and procedures (command procedures) may include parameters. Parameters are variables, not values. A parameter is an abstract representation of any possible input. To use it, function or procedure defined with a parameter must be applied to an input value. This actual input value is called an input argument, or just an argument.

NetLogo Functions

NetLogo offers two ways to create a function: as a reporter procedure, or as a function literal. (Function literals are also called anonymous functions, function expressions, lambdas, or tasks.) The present section focuses on reporter procedures. NetLogo programmers typically just call these reporters.

To create a reporter procedure, use the to-report and end primitives in the Code tab. (Procedure definitions must come after the declarations section.) The reporter name must immediately follow to-report, and the reporter body must come before end. The body of a reporter procedure must use the report primitive to return a value. (NetLogo uses report where other common languages use return.) Here is an example of a reporter procedure with no parameters.

to-report always0  ;reporter name is `always0`
  report 0         ;reporter body incldues `report`
end

This trivial function is considered nullary because it does not use any inputs. This course still calls it a function, because using it produces a value. It is more common, however, for a function to require an input to produce a value. For example, a unary function requires a single input value in order to produce an output value. (A unary function may also be called univariate or monadic.)

Functions and Parameters

In mathematics, a function is essentially a mapping of input values to output values. For example, the function expression \(x \mapsto x\) represents the identity function: for any input value, this function outputs the identical value. The name (x) used to abstractly represent an arbitrary input is a function parameter. This name has no meaning outside of the function expression. (Mathematicians say the name is bound by the expression.)

Similarly, a NetLogo function is a rule for transforming inputs into outputs. When defining a NetLogo procedure, we can provide a list of parameter names in brackets immediately after the procedure name. A unary function has a single parameter. The name used to abstractly represent any input is a function parameter (or formal parameter). This name has no meaning outside of the function definition; strictly local to the definition.

to-report identity [#param01]
  report #param01
end

Arity: Some Examples

The number of formal parameters in a function definition is the arity of the function. The arity of a function is therefore the number of arguments that the function consumes when executed. A function that consumes one argument is called a unary function. Here is an example.

to-report logistic375 [#x]
  report 3.75 * #x * (1 - #x)
end

A function that consumes two arguments is called a binary function.

to-report logistic [#r #x]
  report #r * #x * (1 - #x)
end

A function that consumes three arguments is called a ternary function.

to-report production [#a #x #y]
  report (#x ^ #a) * (#y ^ (1 - #a))
end

Note that each of these functions return a single value (a number). In every case, the names of these variables have meaning the is strictly internal to the procedure we are defining. We say that these variables are local to the procedure. There is no problem that we reused the name #x in the definitions of three different procedures. These uses are entirely independent. The use of this name in one procedure definition cannot in any way seen by any other procedure.

Partial Function Application

One user defined procedure can call another user defined procedure. For example, instead of defining logistic375 as above, we can use partial function application to define it in terms of logistic.

to-report logistic375 [#x]
  report logistic 3.75 #x
end

Partial Function Application (Redux)

One user defined procedure can call another user defined procedure. For example, we could define incremented in terms of added.

to-report added [#x #y]
  report (#x + #y)
end

to-report incremented [#x]
  report added #x 1
end

Similarly, we can turn a function of three variables into a function of two variable. Let us set the parameter in the production function (defined above) to 0.33, thereby producing a function of two variables.

to-report production33 [#x #y]
  report production 0.33 #x #y
end

In these two examples, we use a function of larger arity to produce use a function of smaller arity. This is called partial function application.

Write Once Use Anywhere

Here is a silly reporter that illustrates the use of parameters. This time, instead of returning a number, the function returns a boolean value (true or false).

to-report is-equal? [#x #y]
  report (#x = #y)
end

Copy is-equal? into your Code tab. You can use it elsewhere in your code. You can even use it in the Command Center. So, go to the Command Center and type in the following.

show is-equal? 2 3

The observer will show you the value false. Note how the reporter "consumes" two arguments (the 2 and the 3), because we defined it to do so.

Parameters for Procedures (another example)

Suppose we want to simulate a coin flip with a specified probability.

to-report bernoulli [#p]
  report ifelse-value (random-float 1 < #p) [1] [0]
end

Once you copy that to your Code tab, you can use it like this:

print bernoulli 0.3

This example is different than our earlier examples. This bernoulli function is not a pure function: even if you call it with the same argument, if produces a different output. The output is a random variable.

Procedures Calling Procedures

As before, new procedure definitions can depend on existing procedures. Here is a nullary reporter procedure defined in terms of a unary reporter procedure.

to-report fairCoinFlip02
  report bernoulli 0.5
end

Plotting: First Steps

Types of Plots

As discussed in the Introduction to NetLogo supplement, point-and-click addition of plot widgets to the Interface tab is particularly simple in NetLogo. As of NetLogo 6.1, there are three basic approaches to two-dimensional chart construction: plot, plotxy, and histogram. All use the same plot widget.

plot

Plots each point \((x,y)\) given just the \(y\) value; the x values are automatically incremented.

plotxy

Plots each point \((x,y)\) given two arguments, the \(x\) value and the \(y\) value.

histogram

Produces a histogram from a numerical list.

In the Interface tab, add a plot with the pen update command plot nHeads. In the Code tab, create a coin-flipping program that has the following go procedure:

to go
  set nHeads 0
  repeat 50 [set nHeads (nHeads + flipCoin)]
  update-plots
end

Clearly this is not the complete program: you need to declare nHeads as a global variable, define a flipCoin reporter procedure, and define an appropriate setup procedure. In the Command Center, run your setup procedure, and then use the repeat command to run your go procedure 100 times.

Basic Concepts: Plots

Review plots in the Introduction to NetLogo supplement. Then, in the NetLogo Models Library, review Code Examples » Plotting Example. For the moment, we will only change the pen update commands.

pen update commands

commands to be executed when the plot updates

setup-plots

NetLogo primitive to initialize all plots. Often comes at the end of our setup procedure. (However, it is more common to use reset-ticks, which calls setup-plots.) http://ccl.northwestern.edu/netlogo/docs/dictionary.html#reset-ticks

update-plots

NetLogo primitive to update all plots. Often comes at the enf of our go procedure. (However, it is more common to use tick, which calls update-plots.) http://ccl.northwestern.edu/netlogo/docs/dictionary.html#tick

Temporary Plot Pens

If you want to add background features (like a 45 degree line) to a plot, you can use a temporary plot pen <em>during setup</em>. For example, the following code add to the current plot a 45 degree line from the point \((0,0)\) to the point \((1,1)\).

;;plot 45 degree line from (0,0) to (1,1)
create-temporary-plot-pen "equal"
plotxy 0 0 plotxy 1 1

export-plot

The export-plot command writes a comma-separated values file. The data written includes the \(x\) and \(y\) coordinates of all the points plotted by all the plot pens in the plot.

The export-plot command takes two arguments: the plot name as a string, and a file name as a string. The plot name is the same as whatever you entered as the name in the plot dialogue (which is used as the title of your plot). Use forward slashes, not backslashes, to specify the file name. The data is written to an external file. (See the NetLogo Dictionary entry for details.)

Plot Commands

most-used plot commands:

histogram plot plotxy set-current-plot set-current-plot-pen set-plot-pen-mode

often-used plot commands:

set-histogram-num-bars set-plot-pen-color set-plot-x-range set-plot-y-range

autoplot (automatic axes range adjustemnts):

autoplot? auto-plot-off auto-plot-on

clear-plot related commands:

clear-all-plots clear-plot plot-pen-reset

other plot commands:

http://ccl.northwestern.edu/netlogo/docs/dictionary.html#plottinggroup

Simplest Histogram

A histogram plots the frequency of occurence of items in a list. Add a new plot in the Interface tab and replace the default pen update commands with histogram [1 2 2 3 3 3]. Click OK then then in the Command Center enter ca update-plots.

Note that by default histogram produces a line plot. For the corresponding bar chart, you need to change the pen-mode. At the Command Center, you can enter set-plot-pen-mode 1. But you can set the pen mode in NetLogo's plot dialogue.

Dynamic Histogram

If we have a histogram of turtle colors, we would like our histogram to be redrawn when our turtles change colors.

In the NetLogo Models Library, under Code Examples, see Histogram Example.

Note that the tick command calls update-plots. Note that the x-axis is not autoscaled; you must scale in appropriately be histogramming your data.

Simple Histogram

Suppose we have turtles classified by color: red, green, or blue. After using the GUI to create a plot titled "Class Histogram", we can:

to update-class-histogram
  set-current-plot "Class Histogram"
  histogram map
    [position ? [red green blue]]
    ([color] of turtles)
end

Custom Histogram

If we would like to color-code our bars, we cannot use histogram. Instead we plot a bar for each value.

to update-class-histogram
  set-current-plot "Class Histogram"
  plot-pen-reset
  set plot-pen-mode 1     ;; bar mode
  set-plot-pen-color red
  plot count turtles with [color = red]
  set-plot-pen-color green
  plot count turtles with [color = green]
  set-plot-pen-color blue
  plot count turtles with [color = blue]
end

Language Basics

Review of Language Basics

  • reassignment: set a b

  • use parentheses to control order of operations

  • use brackets [ ] for code blocks

  • white space ignored after initial space

  • procedures (commands and reporters; see above)

Basic Data Types

numbers

all numbers are floating point (as in Javascript)

lists

ordered, immutable collection of objects; concatenate with sentence

strings

immutable sequence of characters; create with double quotes; concatenate with word

booleans

true or false; reported by comparisons

Agentsets

  • turtlesets

  • patchsets

  • linksets

Extension Data Types

  • tables

  • arrays

Language Surprises

  • use (- numbername), not -numbername

  • case-insensitive

  • necessary white space: set a (3 * b)

Some Fairly Recent Changes

Transition Guide:

http://ccl.northwestern.edu/netlogo/docs/transition.html

initialization:

from version 5 onwards, you must explicitly call reset-ticks to initialize the ticks counter; it is no longer called by clear-all.

random choice

Use one-of (not the older random-one-of).

string concatenation:

From NetLogo 5 onwards, always use word to concatenate strings (not +).

If you assemble a string from more or less than two parts, remember to surround word and its arguments with parentheses. For example, (word "join " 3 " parts").

Language Conventions

  • Logical variables end in ?

  • procedure body indented

  • two semicolons to start comment ;;

Ticks

NetLogo includes a built-in tick counter:

print ticks  ;; display current value of ticks
tick         ;; increment ticks (by 1)
print ticks  ;; display current value of ticks
reset-ticks  ;; reset ticks to 0
print ticks  ;; display current value of ticks

Booleans and Comparisons: Numerical Issues

Be careful with numerical comparisons when you are not working with integers. Computers must work with approximations of fractions. The value of (0.1 + 0.2) is 0.30000000000000004, so the value of (0.1 + 0.2 = 0.3) is false, and the value of (0.1 + 0.2 > 0.3) is true.

Control Flow

Conditional Branching with if and ifelse

A boolean expression has a value of either true or false. Boolean expressions can provide conditions for the flow of control in a NetLogo program. This is called conditional branching. The basic constructs for conditional branching is the ifelse statement.

ifelse <condition> [<commands4true>] [<commands4false>]

Angle brackets indicate where NetLogo code must be substituted. For example, you need to replace <condition> with a boolean expression. (That is an expression that evaluates to either true or false). For example, we might condition what to print on a boolean expression.

ifelse (2 = 1 + 1) [print "success"] [print "failure"]

When the command block for a false condition is empty, we may use the simpler if statement. This provides commands only for the case where the boolean expression is true.

if (2 = 1 + 1) [print "success"] ; otherwise do nothing

Ternary Operator

The ifelse-value reporter primitive is a ternary operator. That is, it consumes three inputs and returns a value. The arguments are a boolean condition, a reporter block to evaluate when the condition is true, and a reporter block to evaluate when the condition is false. (A reporter block is an expression surrounded by brackets.) Once again using angle brackets to indicate the need to substitute actual code, charaterize the ifelse-value syntax as

ifelse-value <condition> [<trueExpression>] [<falseExpression>]

The condition is a boolean expression: it must evaluate to true or false. If the condition is true, NetLogo evaluates the first reporter block. If the condition is false, NetLogo evaluates the second reporter block. The value of the entire conditional expression is the value of the evaluated reporter block. To illustrate, enter the following two examples at NetLogo’s command line:

print ifelse-value true [1] [0]
print ifelse-value false [1] [0]

ifelse-value redux

The ifelse-value reporter primitive can handle additional conditions, if surrounded by parentheses. The following example uses this extended syntax to produce the sign of a number. The first boolean condition that evaluates to true determnes the result reported. If none are true, the default value is reported.

to-report sign [#x]
  report (ifelse-value
        (#x < 0) [-1]
        (#x > 0) [1]
        [0])
end

Booleans and Conditional Branching

E.g., noting that random-float 1 is between zero and one:

if (random-float 1 < 0.5) [show "heads"]

We might also like the observer to print “tails” for larger outcomes. We can use the ifelse construct to do this.:

ifelse (random-float 1 < 0.5)
  [show "heads"]
  [show "tails"]

Note that to create a string, we bracket a sequence of characters with double quotes.

Example: Conditional Setting of Global Variables

  • start NetLogo

  • In the Code window enter globals [nHeads nTails]

  • Go to the Command Center and enter the following code:

ifelse (random-float 1 < 0.5)
  [set nHeads (nHeads + 1)]
  [set nTails (nTails + 1)]
show nHeads
show nTails

ifelse-value

NetLogo also provides the unusual ifelse-value primitive, which allows condition determination of a value.

ask turtles [
  set color ifelse-value (wealth < 0) [red] [blue]
]

http://ccl.northwestern.edu/netlogo/docs/dictionary.html#ifelse

Example of Switching

We can nest ifelse-value expressions to discriminate between cases.

let x random 10000
show ifelse-value (x < 10) ["One digit"] [
     ifelse-value (x < 100) ["Two digits"] [
     ifelse-value (x < 1000) ["Three digits"] [
     "Many digits"
     ]]]

Looping: repeat

The repeat primitive allows you to repeat a command block as many times as you wish. E.g., enter the following at the Command Center.

let _ct 0 repeat 50 [show _ct set _ct (_ct + 1)]

In the Command Center, the observer shows you the whole numbers up 0-49. As another example, at the Command Center enter:

clear-all
repeat 50 [set nHeads (nHeads + fairCoinFlip) ]
show nHeads

Note: clear-all sets all global variables to their default value of 0.

Exiting a Loop: stop

At the Command Center enter:

let _ct 0 repeat 50 [show _ct set _ct (_ct + 1) stop]

The stop command exits the loop, so in the Command Center, the observer only shows 0.

Exiting a Procedure: stop

We can use stop to exit a procedure, but stop only exits the procedure that executes it. To illustrate, add the following to the Code tab:

to test
  show 0  stop-me  show 2
end

to stop-me
  stop  show 1
end

Go to the Command Center and enter test. You will see 0 and 2 printed.

Forever Buttons

NetLogo buttons include an unusual property: then may be forever buttons. When pressed, a forever button runs its code repeatedly, instead of just once. (Pressing it again terminates the repetition.) Turn any button into a forever button by selecting the Forever checkbox while editing the button.

Stopping Forever Buttons

NetLogo models often have a go command that is called by a forever button. If you want to stop on a condition, rather than by again clicking the button, use stop conditionally at the top of your procedure:

to go
  if (stopCondition) [ stop ]
  ...
end

This prevents the user from forcing additional step in the model by repeatedly pressing the button.

Looping: loop

Run a list of commands repeatedly (potentially forever):

loop [ commands ]

This is obviously a hazardous construct, but if one of the commands eventually calls stop, you will exit the loop.

loop [if (ticks > 100) [stop] tick]

Use of loop is not quite like use of a forever button. In NetLogo, we usually use a forever button in order to repeat something forever. We can click again on a forever button to exit the loop. If the button calls a procedure that executes the stop command, that will also exit the forever-button loop. However, procedures do not pass on the stop command to loop: to break out of loop, stop must be called by a command directly in the loop body.

Control Flow: Looping

ask <agentset> [<commands>]

Ask each agent in an agentset, in random order, to run commands.

foreach <list> <commands>

Run commands on each list element, sequentially.

repeat <number> <commands>

Repeat commands a set number of times.

loop [<commands>]

Repeat commands forever. (Dangerous.)

while [<condition>] [<commands>]

Run commands for a long as condition is true.

At this time (version 6), NetLogo does not offer a good way to break out of looping constructs. (E.g., there is nothing equivalent to C’s break statement.) NetLogo’s stop command does not serve this purpose. (Inside an ask, it is rather like C’s continue statement.) The best way to conditionally exit a loop is therefore to use that condition with a while loop.

Control Flow: Other

  • ask-concurrent

  • carefully (and error-message)

  • every

  • run

  • runresult

  • to

  • to-report

  • wait

  • with-local-randomness

  • without-interruption

Operators: Math, Logic and Comparison

math
  • +, -, /, ^

  • white space delimited (e.g., 3 + 2 not 3+2)

  • all are binary, but can write (- x) for 0 - x

logical operators (operate on booleans)
  • and, not, or, xor

comparison
  • >, >=, <, <=, =, !=

Operator Precedence (high to low)

  • with, at-points, in-radius, in-cone

  • (all other primitives and user-defined procedures)

  • eponentiation: ^

  • *, /, mod

  • +, -

  • inequality comparisons: <, >, <=, >=

  • equality comparisons: =, !=

  • logical operators: and, or, xor

Note that primitives have higher precedence than other operators. E.g., sin 0 + 1 evaluates to 1.

Documentation resource:

https://ccl.northwestern.edu/netlogo/docs/programming.html#syntax

Global Variables

  • have global scope (i.e., are available anywhere in the program)

  • must be declared before used

    • in the declarations section, or

    • by adding a button

  • use set a b to change the value of variable a

Local Variables

Local variable can be created with let inside a procedure body. They are invisible outside their code block. [1] Suppose that insider a procedure body, a and b have already been defined, but c has not. Then

  • let c a declares a new local variable c and assigns it the value of a.

  • set c b changes the value of c to be the value of b.

  • The scope of c is restricted to code block in which it was declared. In particular, the variable c is invisible outside of this procedure body.

A procedure’s formal parameters are also local to the procedure.

Tasks

Tasks vs. Procedures

NetLogo 6 introduces lambdas, which are also perhaps unfortunately called “anonymous procedures”. (This terminology is perhaps unfortunate, because a lambda can be named by assigning it to a variable.) This course calls these “tasks” (which was a more intuitive NetLogo 5 terminology).

We declare a task with the -> primitive. Like a procedure, a tasks may be a command task or a reporter task. (Determine which type a task is with the is-anonymous-command? and is-anonymous-reporter? primitives.) The syntax to create a reporter task or command task is:

[[<prms>] -> <reporter>]
[[<prms>] -> <commands>]

As usual, the angle-bracketed text needs to be replaced. For example, replace <prms> with a list of formal parameter names. Analogously to procedures, a task can accept arguments. The formal parameters are named in a block. If there is only one parameter, it need not be bracketed. If there are no parameters, use empty brackets (or omit them).

Like a procedure, a task stores code for later execution. Unlike procedures, tasks are values, and they can be passed around like any other values. This is a very powerful facility and can be quite useful. However, it means that we need a special syntax for apply a task to arguments. Use runresult to apply a reporter task to its arguments. Use run to apply a command task to its arguments.

Surprising Need for Parentheses

The parenthesis determine what is considered to be an input to the task. (Extra inputs are simply ignored.) For example,

print (runresult [x -> x * x] 2)

An Even More Surprising Need for Parentheses

let max2 [[?1 ?2] -> ifelse-value (?1 >= ?2) [?1] [?2]]
show reduce [[?1 ?2] -> (runresult max2 ?1 ?2)] [1 2 3 4 3 2 1]
show reduce max2 [1 2 3 4 3 2 1]  ;shorthand for the same thing

Reporter Tasks

A reporter task is used to run code and return a value. We use the runresult primitive to execute a reporter task. For example:

let square [[?] -> ? * ?] print (runresult square 5)

Again, tasks with arguments must be run with parentheses. While (runresult square 5) is correct, runresult square 5 (without the parentheses is an error.

Reporter Tasks as Function Literals

In NetLogo, there are two different ways to create functions. The traditional way is to declare a reporter procedure in the procedures section of a NetLogo Model. If we want to create a function elsewhere, such as inside a procedure or at the command line, we use a function literal, also called lambda expressions or tasks. Each approach can be useful.

A function literal is an expression whose value is a function. Here is an example of a function literal in NetLogo.

[?x -> ?x + 0.03 * ?x * (1 - ?x)]

The bracketed expression is a function literal; the brackets are required. Here we follow an optional NetLogo convention of beginning the parameter names with a question mark. It is worth noticing the close relationship between the syntax for function literals and the mathematical syntax \(x \mapsto x + 0.03 * x * (1 - x)\).

In NetLogo programming, function literals are often called anonymous reporters, since we need not associate them with a name. (For historical reasons, it is also common to refer to a function literal as a lambda expression.) Function literals enable us to create functions inside a NetLogo procedure or at the command line. As we will see, this can be very useful.

In NetLogo, function literals must be called with the help of the runresult command. For example, enter the following at the command line. (The parentheses are required.)

print (runresult [?x -> ?x + 0.03 * ?x * (1 - ?x)] 2)

Here, the print command needs a value to print. This value is provided by the runresult command, which applies our function literal (in brackets) to the value of our number literal (2).

Sometimes the use of anonymous functions can become hard to read. In this case, we may prefer to introduce a variable to refer to our function. In NetLogo, we may use the let command to introduce a new variable. For example, enter the following at the command line. (The parentheses are required.)

let f [?x -> ?x + 0.03 * ?x * (1 - ?x)] print (runresult f 2)

Tasks Are Closures

Tasks reported by procedures close over variables local to the procedure. For example, consider the following reporter procedure, which reports a task.

to-report modnum [#divisor]
  report [? -> ? mod #divisor]
end

Recall that NetLogo requires the use of runresult to invoke a reporter task. At the NetLogo command line, try the following.

let mod3 modnum 3 print (runresult mod3 17)
let mod4 modnum 4 print (runresult mod4 17)

We see that our modnum function returns a task that is a `function closure`_. That is, each task keeps track of its own value of #divisor (i.e., the value of #divisor when the task was created).

Command Tasks: Simple Example

A command task is used to run code without returning a value. We use the run primitive to run a command task. Consider the following.

globals [x xpp]

to setup
  set x 0
  set xpp [[] -> set x (x + 1)]
end

Here xpp is just an global-variable name, but we assign a command task to it. Now the execution run xpp to add 1 to x.

Command Tasks: Stack Example

A command task is used to run code without returning a value. Recall that we use the run primitive to execute a command task. Consider the following.

globals [stack push]

to setup
  set stack []
  set push  [[item] -> set stack lput item stack]
end

Now we can (run push 1) to push a 1 on our stack. Recall that the parentheses are required. The code (run push 1) is correct, but the code run push 1 (without parentheses) is an error.

Tasks in the Models Library

  • State Machine Example

  • Termites 3D

Lists

NetLogo lists can contain a variety of items in a fixed order. Lists are ordered, immutable, and may be heterogeneous. For example, a list may contain both numbers and strings. (At this point you may wish to review the introduction to lists in the Introduction to NetLogo supplement.)

Basic List Construction

NetLogo lists may be constructed by providing the list primitive, which can make a list out of any number of items. Try the following examples of list construction at the command line. (Be sure to use include the parentheses.)

print (list )                 ;; empty list
print (list 0 1)              ;; list of numbers
print (list "zero" "one")     ;; list of strings
print (list 0 1 "zero" "one") ;; list of numbers and strings

The printed results display in brackets. Since these example lists are constructed only from number literals and string literals, we may use this bracket notation for list construction. The following examples construct the same lists with this shorthand notation.

print []                 ;; empty list
print [0 1]              ;; list of numbers
print ["zero" "one"]     ;; list of strings
print [0 1 "zero" "one"] ;; list of numbers and strings

Do not use the bracket notation when creating a list from variables. For example, let x 0 print (list x) is perfectly legal, but let x 0 print [x] is an error.

first and but-first

The simplest list is the empty list, which contains no items. Any other list has a first item, sometimes called the head, and the rest of the list, sometimes called the tail. Access the head with the first reporter. Access the tail with the but-first reporter. A list with only one item has a head, which is the first item; its tail is the empty list.

print first [0]         ; 0
print but-first [0]     ; []
print first [1 2 3]     ; 1
print but-first [1 2 3] ; [2 3]

Any empty list has no head or tail. Using first or but-first on any empty list produces a runtime error.

List Length

The length of a list is the number of items in the list. The length of an empty list is \(0\).

length lst

reports the length of lst

empty? lst

reports true if lst is empty

Creating Arithmetic Sequences with range

The simplest way to create a long list of values is with range, which generates list of numbers from a starting point, an open stopping point, and a step size.

(range <start> <stop> <step>)

The step size may be omitted; its default value is \(1\). The starting point may additionally be omitted; its default value is \(0\).

(range <start> <stop>)
range <stop>

In this last case, parentheses become optional. So for example, range 10 is equivalent to (range 10). The other cases require parentheses.

Accessing List Items

Because lists are ordered, we may sensibly ask what item is at a particular location. The item primitive provides the most general way to access items by index. Indexing is zero-based, which means that the first index is 0. The expression (item n mylist) evaluates to the n-th item of the list mylist. For example, (item 0 [3 2 1]) evaluates to 3.

Convenient Reporters for Item Access

To make life easier for NetLogo programmers, NetLogo provides some convenient reporter primitives. Use first to access the first element, last to access the last element, and one-of to access a random element. This gives us four common ways to access list items.

item index list

Reports the list item at the (zero-based) index.

first list

Reports the first item of the list.

last

Reports the last item of the list.

one-of list

Reports a random item of the list.

Removing Items from a List

NetLogo lists are immutable, so each of the following commands reports a new list.

remove item list

Remove all instances of item from list.

remove-item int list

Remove the item in position int from list.

remove-duplicates lst

After the first occurence of any item in lst, remove duplicates of that item.

sublist list n1 n2

Remove items outside the integer range \([n_1,\dots,n_2]\). (Recall that indexing is zero-based.)

Missing from this collection is a way to remove only the first instance of an item. The position primitive makes it easy to fill this gap.

to-report remove-instance [#item #list]
  let _pos position #item #list
  report ifelse-value (_pos != false) [remove-item _pos #list] [#list]
end

Adding Items to a List

fput <item> <list>

prepends item to list (e.g., fput 1 [2 3])

lput <item> <list>

appends item to list (e.g., lput 3 [1 2])

sentence <list1> <list2>

concatenates list1 and list2 (e.g., (sentence [1 2] [3]))

Note: in each case, a new list is returned, which we can represent as [1 2 3].

Membership Testing

position item list

report the index of item in list

member? value list

report true if value is in list

Mapping over Ranges

Many of the needs for basic list creation can be met by mapping over ranges. For example,

map [?x -> ?x * ?x] (range 10)

Creating Lists with n-values

An alternative to mapping over ranges is to use n-values, which does not require buidling the range list.

Newcomers to NetLogo often find it puzzling to use n-values. Read the documentation carefully. The general syntax is

n-values <number> <reporter block>

The n-values primitive takes two inputs and produces one output. The inputs are the number of values to produce, and a reporter. The output is a list, where each item is a function of its index.

Remember that NetLogo indexes start at zero. Consider the command n-values 5 [? -> ?]. This say to produced a list of 5 values using the reporter [? -> ?]. The question mark is just an ordineary variable name, which stands for the index. (You can use any other valid name.) The result is therefore [0 1 2 3 4]: a list of 5 successive values, starting at 0.

Note again that n-values takes two arguments: an integer size (here 5), and a “reporter block” (here [? -> ?]).

Documentation Resource:

http://ccl.northwestern.edu/netlogo/docs/dictionary.html#n-values

Question Mark: n-values

The question mark in the reporter is an ordinary NetLogo variable name used by convention. (NetLogo allows many names that would be illegal in other languages.) The values taken by this variable depend on the command.

When we use the n-values command, the variable will take on successive integer values, starting at 0. (The number of values is determined by the size argument.) That is, when we use n-values, the reporter parameter stands for the index of the list item.

For example, to produce a list of 5 items where each item equals its index, we can use

n-values 5 [? -> ?]
n-values 5 [x -> x]
n-values 5 [any-name -> any-name]

As another example, to produce a list of 5 items where each item equals half of its index, we can use

n-values 5 [? -> ? / 2]

Here is another example: to produce a list of the squares of \(0\) through \(9\), we can use

n-values 10 [? -> ? * ?]

You are not required to use a reporter parameter if you do not need it. For example,

n-values 5 [random 2]

Iteration over Lists

Use foreach to run commands for each item of a list. (Read the documentation very carefully.) The general syntax is:

foreach <list> <command>

As usual, in this example the angle brackets indicate a needed substitution. The command may be any builtin or user-defined command that expects a single argument. Here is a simple concrete example, which provides foreach with actual arguments: a short list and the print command.

foreach [0 1 2] print

Often there is no suitable builtin command, so that it is desirable to create a command on the fly. Use a command task for this. (NetLogo also call this an anonymous command or arrow command.) Here a concrete example, where the arguments are a short list and a command task.

foreach [0 1 2] [? -> print ? * ?]

The square brackets and the arrow are crucial to the definition of an arrow command. Note that the ? is an ordinary name that is a somewhat common convention for naming parameters in arrow commands. In NetLogo, the question mark is just a normal variable name, which happens to be conventional when defining arrow commands. (Any valid identifier may be used instead: you could use x or ?x or ?1, etc.) The name is local to the task for which it is a parameter, so using the same name in two different tasks do not create a name collision.

Iteration over Lists of Lists

Lists can contain lists. Here is a slightly more complicated example, which iterates over a list of pairs. Each pair is a list, so we can extract its first and list member.

foreach [[0 1] [2 3] [4 5]] [? -> print first ? print last ?]

The foreach command iterates over a list, which may be created in all the usual ways. For example, use range to generate a list, and then use foreach to process that list item by item.

foreach (range 3) [[?] -> print ? * ?]

Or, produce the list with n-values. (Note that n-values requires a reporter as its second argument, supplied here as a reporter task (i.e., function literal).

foreach (n-values 3 [? -> ?]) [[?] -> print ? * ?]

The n-values reporter provides sequential nonnegative integers to its reporter task. The foreach command provides sequential elements of its list to its command task.

Cumulative Sum using foreach

to-report partialSums [#nums]
  let total 0
  let result []
  foreach #nums [[?] ->
    set total total + ?
    set result lput total result
  ]
  report result
end

First Function Plot with foreach

To plot a function \(f[x]\), we need to decide which \(x\) values to consider. Then we need to pair each \(x\) value with a \(y\) value. Then we can use plotxy to do the actual plotting.

Suppose we have a set of \(x\) values named domain and a function (of a single input) named f. Then we can use foreach to plot the \((x,y)\) pairs as follows:

foreach domain [[?] -> plotxy ? f ?]

Exercise: Explain how the following code works:

foreach [1 2 3] [[?] -> plotxy ? (? * ?)]

Note how a straight line is drawn between each specified point \((x,f[x])\).

Second Function Plot with foreach

Suppose we want to plot \(f[x]\) on the interval \([0,1]\). To get a smooth looking curve often requires a It takes 101 points to delimit 100 equal sized intervals. So we can proceed as follows:

let domain n-values 101 [? -> ? / 100]
foreach domain [[?] -> plotxy ? f ?]

Exercise: Enter the following function in your Code tab and plot it.

to-report f [#x]
  report 3.75 * #x * (1 - #x)
end

Creating a Domain for Function Plotting

To plot a function \(f[x]\), we need to decide on a domain over which to plot it. Commonly, we choose an interval \([x_\text{min},x_\text{max}]\). But of course, we cannot literally plot every point in an interval, which contains an infinity of points. So we create a subset of these points on which to actually evaluate our function. Commonly, we do this by deciding how many points we wish to plot and then dividing the interval up evenly.

to-report linspace [#xmin #xmax #npts]
  let _len (#xmax - #xmin)
  report n-values #npts [? -> #xmin + _len * (? / (#npts - 1))]
end

Basic Function Plot

Add a plot named Function Plot to your Interface tab. Add the following command procedure to your Code tab (along with the linspace function defined above).

to plotFunction [
  #f    ;(task)   : the function to be plotted (as a task)
  #xmin ;(float)  : the first domain point to plot
  #xmax ;(float)  : the last domain point to plot
  #npts ;(int)    : the number of points to plot
  ]
  ;create the domain of function application:
  let _domain linspace #xmin #xmax #npts
  ;plot the points of the function:
  foreach _domain [?x ->
    plotxy ?x (runresult #f ?x)
  ]
end

This plotfunction command takes four arguments: a reporter task that accepts one argument, the left and right boundaries of the plot domain, and the number of points to plot. This code depends on the linspace utility, which is presented above.

On the interval [0,1], plot the logistic map with an amplitude parameter of 3.5. (As background, consider the Wikipedia artice on the Logistic Map.)

foreach Example: Multiple Lists

The foreach command can be used with multiple lists of identical length. The first result is computed from the first elements of the arguments. The second result is computed from the second elements of the arguments. For example:

(foreach [1 2] [3 4] [5 6] [[?1 ?2] -> print ?1 + ?2 + ?3])

Note the required parentheses.

Note: ?1, ?2, and ?3 are ordinary names that are sequentially assigned to each item in the first, second, and third foreach sequence.

Operating on Lists

sublists
  • sublist, remove-duplicates

  • remove item list, remove-item int list

  • but-first, but-last

  • n-of int list

new lists
  • replace-item int list

  • fput, lput, sentence

  • n-values int [reporter]

rearranged lists
  • reverse, shuffle

  • sort, sort-by

Immutability

  • NetLogo lists are immutable: you construct new lists based on old lists.

  • if you want an extant variable to refer to a new list, use set.

set mylist replace-item 0 mylist 99
; mylist's first element is now 99
set mylist lput 100 mylist
; appends the value 100 to mylst
set mylist fput -1 mylist
; mylist now has a new first element

Creating Lists from Agentsets with of

use of with an agentset:

[color] of turtles

[pcolor] of patches

[(list self pcolor)] of patches

[(list self color size)] of turtles

Note that lists can contain lists!

Lists to Agentsets

patch-set lst

creats a patch set from any patches in lst (or its sublists) http://ccl.northwestern.edu/netlogo/docs/dictionary.html#patch-set

turtle-set lst

creats a turtle set from any turtles in lst (or its sublists) http://ccl.northwestern.edu/netlogo/docs/dictionary.html#turtle-set

Basic Functional Programming with Lists

Remember that a question mark (?) is an ordinary variable name in NetLogo.

map reporter list

Apply a reporter to a list and produce a new list.

E.g., map [? -> ? * ?] [0 1 2] reports [0 1 4].

filter boolean-reporter list

Report a list of criterion-satsifying members of the input list. (See discussion below.)

E.g., filter [? -> ? > 0] [0 1 2] reports [1 2].

reduce two-input-reporter list

Combine the items of a list into a single result by repeatedly applying a binary operation.

Suppose op is an infix binary operation then reduce op [a b c] will report ((a op b) op c)

E.g., reduce + [1 2 3] reports 6 while reduce - [1 2 3] reports -4.

sort-by reporter list

Sort a list based on pairwise comparisons.

E.g., sort-by > [3 1 4 2] reports [4 3 2 1]

Filtering

Sometimes we want a sublist of elements that meet a certain criterion. We can use filter for this. E.g.,

filter [[?] -> ? < 3] [1 2 1 3]

reports [1 2 1].

Using Filter to Count Occurences

The following is a somewhat inefficient way to tally, because it constructs a list instead of just the count. (A good way to tally all items is to use table:counts, provided by the table extension.) Nevertheless, it provides a simple example of the use of filter.

to-report countx [
  #lst ;the list of items
  #x   ;the item to search for
  ] ;-> (int): the frequency of #x in #lst
  report length filter [? -> ? = #x] #lst
end

Filtering Agentsets

If you want to filter an agentset s based on an attribute w, you would have to convert it to a list ([self] of myagentset) before your could apply filter. E.g.,

filter [? -> [w] of ? < 3] [self] of patches

However, the better way is usually to use with to create an agentset.

patches with [w < 3]

Note that filter consumes and list and reports a list, while with requires an agentset and a reporter block, and reports an agentset. It follows that with can remove an agent a from an agentset:

set myset myset with [self != a]
Documentation resources:

Set Operations with Agentsets

Here are example for patches. Handle turtles and links similarly.

subsetting

with (e.g., patches with [pcolor = red])

union

patch-set (e.g., (patch-set set1 set2))

intersection

member? (e.g., set1 with [member? set2])

set difference

member? (e.g., set1 with [not member? set2])

Lists: Contrast with Agentsets

agentset

  • an unordered, mutable, homogeneous collection of agents

  • traverse with ask

    • ask agentset [ list of commands ]

list

  • an ordered, immutable, possibly heterogeneous collection of objects

  • traverse the list items sequentially with foreach

    E.g., foreach [1.1 2.2 2.6] [[?] -> print round ?]

Patches at-points

Produce agentsets of patches a given relative positions with at-points.

clear-patches
ask patch 5 5
  [ask patches at-points [[-1 -1] [1 1]]
    [set pcolor blue]]

Note: we specified a list of offset pairs, relative to patch 5 5. http://ccl.northwestern.edu/netlogo/docs/dictionary.html#at-points

Advanced List Use

Some example of advanced list use:

nested foreach

Here we illustrate nested foreach loops by producing the two-dimensional offsets needed to construct a box (Moore) neighborhood of arbitrary radius.

to-report moore-offsets [#r]
  let _dxdy (list )  ;; empty list
  let offsets (range (- #r) (1 + #r) 1)
  foreach offsets [?dy ->
    foreach offsets [?dx ->
      set _dxdy lput (list ?dx ?dy) _dxdy
    ]
  ]
  report _dxdy
end

nested map

Here we illustrate nested map loops by producing the two-dimensional offsets needed to construct a box (Moore) neighborhood of arbitrary radius.

to-report box-offsets [#r]
  let _offsets (range (- #r) (1 + #r) 1)
  let _dxdys map [?dy -> map [?dx -> (list ?dx ?dy)] _offsets] _offsets
  report reduce sentence _dxdys
end

Permutations via Nested foreach

NetLogo supports recursion, which we use here to produce all the permutations of a list.

to-report permutations [#lst] ;Return all permutations of `lst`
  let n length #lst
  if (n = 0) [report #lst]
  if (n = 1) [report (list #lst)]
  if (n = 2) [report (list #lst reverse #lst)]
  let result []
  let idxs n-values n [? -> ?]
  ;use each item as a first item, permuting remaining items
  foreach idxs [[?] ->
    let xi item ? #lst
    foreach (permutations remove-item ? #lst) [[?] ->
      set result lput (fput xi ?) result
    ]
  ]
  report result
end

reduce

Simple Reduction of a List

reduce reporter list

repeatedly apply a binary operation to a list from left to right, using the binary operation supplied by reporter.

A common convention uses ?1 and ?2 in the reporter task to refer to the two objects being combined. For example, sum the items in [1 2 3] as follows:

reduce [?1 ?2] -> ?1 + ?2] [1 2 4]
reduce + [1 2 4]  ;; short form

How reduce Works

Consider the following:

reduce [[?1 ?2] -> ?1 + ?2] [1 2 4]

Remember, reduce works through the list from left to right. Here ?1 refers to the first argument, and ?2 refers to the second argument.

Step 1:

set ?1 to the first item (e.g., 1) and set ?2 to the second item (e.g., 2)

Step 2:

add ?1 and ?2; if there are any more list items go to Step 3, otherwise report the result of the addition.

Step 3:

set ?1 to the result of addition (e.g., 3), and then set ?2 to the next item in the list (e.g., 4). Go to Step 2.

So the following would produce the same result:

to-report sum-list [lst]
  let arg1 first lst
  foreach butfirst lst [[?] ->
    let arg2 ?
    set arg1 (arg1 + arg2)
  ]
  report arg1
end

Factorial via reduce

We can use reduce with n-values to produce the factorial of a positive integer. (Be careful; the factorial grows very quickly.)

to-report factorial [#n]
  report reduce * n-values #n [? -> ? + 1]
end

Binary to Integer via reduce

Suppose we have a list of zeros and ones representing a binary number.

to-report binary-to-integer [bits]
  report reduce [[?1 ?2] -> ?1 * 2 + ?2] bits
end

Item Count via reduce

to-report countx [
  #lst ;Number[0..*], list of items
  #x   ;the item whose occurences we tally
  ] ;-> (int): the multiplicity of #x in #lst
  let _f [[?acc ?x] -> ifelse-value (?x = #x) [?acc + 1] [?acc]]
  report reduce _f (fput 0 #lst)
end
;Attribution: see NetLogo documentation of `reduce`

All and Any

NetLogo does not provide all and any for lists. But they are easily implemented for list of booleans with reduce. For example:

to-report allTrue [#lst]
  report reduce and #lst
end

to-report anyTrue [#lst]
  report reduce or #lst
end

With just a little more effort, we can improve these functions so that they appropriately handle empty lists.

to-report allTrue [#lst]
  report ifelse-value (empty? #lst) [true] [reduce and #lst]
end

to-report anyTrue [#lst]
  report ifelse-value (empty? #lst) [false] [reduce or #lst]
end

flatten via reduce

The sentence primitive concatenates lists. Therefore reduce combined with sentence can concatenate all the sublists in a list of lists. To illustrate, enter reduce sentence [[0] [1 1] [2 2 2]] at the command line.

to-report catenate [#lstlst]
  report reduce sentence #lstlst
end

Reversing a List with reduce

Since NetLogo has a reverse primitive, the following exercise is simply to illustrate the capabilities of reduce. Reversing a list using reduce uses a useful trick: modify the input list by inserting an empty list at the front (with fput). This becomes the first value seen by reduce, so we can use it to successively accumulate items. We cannot simply reduce with fput however, because we must first reverse the order in which it takes its arguments. Fortunately, reduce works with binary reporter tasks (i.e., function literals).

to-report reversed [#lst]
  report reduce [[?list ?item] -> fput ?item ?list] (fput [] #lst)
end

Partial Sums via reduce

The \(n\)-th partial sum of a numerical list is the sum of its first \(n\) elements. A list of the partial sums is often called the cumulative sum. To produce these partial sums, reuse the trick of modifying the input list (with fput) before applying reduce. This time however, insert a single-element list containing the first element of the input list. Now reduce can build up a new list by repeatedly appending a new partial sum.

to-report partialSums [
  #lst ;list of numbers
  ]; -> list of the cumulative sums
  ;prepare for reduce by turning [x1 ... xn] into [[x1] x2 ... xn]
  let _lst (fput (list (first #lst)) butfirst #lst)
  report reduce [[?1 ?2] -> lput (?2 + last ?1) ?1] _lst
end

List to CSV Row with reduce

The reduce primitive can readily do list concatenation while adding an item separator such as a comma or a space.

to-report stringRiffle [
  #lst  ;list, the values to join in a string
  #sep  ;string, the separator to put between values
  ]
  report (reduce [[?x ?y] -> (word ?x #sep ?y)] #lst)
end

This stringRiffle function can readily produce a CSV row from a list of values. (NetLogo’s csv extension also provides this functionality.) For example,

stringRiffle [1 2 3] ","

Four Different Implementations of countBy

Traditional:

to-report countBy [#lst #pred]
  let _ct 0
  foreach #lst [? ->
  if (runresult #pred ?) [set _ct (1 + _ct)]
  ]
  report _ct
end

Map:

to-report countBy [#lst #pred]
  let _bin map [? -> ifelse-value (runresult #pred ?) [1] [0]] #lst
  report sum _bin
end

Filter:

to-report countBy [#lst #pred]
  let _pass filter #pred #lst
  report length _pass
end

Reduce:

to-report countBy [#lst #pred]
  ;convert boolean to int
  let _f [[?acc ?val] ->
           ifelse-value (runresult #pred ?val) [1 + ?acc] [?acc]]
  report reduce _f (fput 0 #lst)
end

Strings

As in many other languages, string literals in NetLogo use double quotes "like this". If you need a string that will print with quotes, escape them with a backslash "\"like this\"". NetLogo strings have good multi-language support; they can contain any Unicode characters. Many list operations also work on strings. (A single character is represented as a string of length one.)

Using n-values for Mapping Across a String

to-report string-to-digits [#s]
  report n-values (length #s) [? -> read-from-string item ? #s]
end

File-Based IO

Preliminaries

Before experimenting with the file commands, create a new NetLogo model instance and save it to a directory where it is safe to overwrite and delete files.

Open and Close File

When doing modeling and simulation, we often export some of the data produced by our simulations to files. At times, we also read into our simulations data that is stored in files. In this section we explore how to read and write text files with NetLogo.

Before we can write to or read from a file, we must open it. We use file-open <string> to open a file, where you substitute a file path for <string>. Once finished with an open file, you should always close it with file-close.

file-open "temp.txt"
file-close  ;;close the last opened file

The the argument to file-open is a string; it must be in quotes. In contrast, file-close does not take an argument; it will close the last opened file.

Open a File

Unlike many languages, NetLogo does not ask you to specify upon opening whether you will read from or write to the file. That is determined by the first file primitive you use after opening the file.

For example, if you use file-read then the file can only be read. On the other hand, if you use file-write then it can only be written.

file-open "temp.txt"     ;open the file for reading or writing
file-print "output text" ;file can now be written, NOT read
file-close               ;close the last opened file

file-open "temp.txt"     ;open the file for reading or writing
print file-read-line     ;file can now be read, NOT written
file-close               ;close the last opened file

Open a File for Writing

If you open an existing file and write to it, you will append to that file. If you want to replace the content of an existing file, you will have start with a file-delete. In order to open a file for writing and close it afterwards, you need the following commands:

file-delete <string>

delete the file designated by <string>

file-open <string>

open a file for reading or appending (but not both)

file-close

close an open file

Using carefully with file-delete

To replace the content of a file, begin by deleting the existing file. However, trying to delete a file that does not exist is a runtime error. Suppose you do not know ahead of time whether the file exists? Here are two solutions. (Caution: these will delete temp.txt if it exists!) The first is to use an if statement to condition on the value of file-exists?.

if (file-exists? "temp.txt") [file-delete "temp.txt"]

A more idiomatic solution is to use carefully to ignore any file-deletion error. (See the NetLogo Dictionary for details.)

carefully [file-delete "temp.txt"] []

For example, try the following at the command line.

carefully [file-delete "temp.txt"] []
file-open "temp.txt"
file-print "write this line to temp.txt"
file-close

Caution: Ask Before Using file-delete

If you are absolutely sure that it is safe to delete an existing file, you can use carefully with file-delete. However, you can never be sure it is ok to delete a file that someone else might have created. So models that you might ever share should not use this approach. Instead, you should check whether the file exists with file-exists, which returns a boolean. (See the NetLogo Dictionary for details.)

If the file does not exist, then you may consider writing a file, although it is polite to ask. You can ask for permission with NetLogo’s user-yes-or-no? primitive. (See the NetLogo Dictionary entry for details.) It would be even more polite to ask the user to suggest a filename, which can be done with user-new-file. (See the NetLogo Dictionary entry for details.)

If the file already exists, can then ask the user of your code whether it is acceptible to delete the file. Here we use NetLogo’s user-yes-or-no? primitive.

if (file-exists? "temp.txt") [
  ifelse (user-yes-or-no? "OK to delete temp.txt?") [
    file-delete "temp.txt"
  ][
    error "temp.txt already exists"
  ]
]

If the user says not to delete a file, this code provides a pretty primitive response: it raises an error, so that program execution stops. A better approach is to ask the user to suggest a filename, which as before can be done with user-new-file.

File Output Commands

NetLogo provides an unusual collection of commands for writing to files. Note that file-print and file-show append a carriage return (CR).

file-type value

write value to file

strings are written without quotes; backslashes escape control characters

file-write value

write a space, and then write value,

strings are written quote delimited; backslashes are literal

file-print value

write value, followed by a newline.

file-show value

first write the agent description, then write value, followed by CR

Example: Export List

In oder to illustrate these concepts, consider the following utility to export a list to a file. Warning: this simplified approach will overwrite an existing file without asking permission. (See the Export List exercise in the NetLogo Exercises supplement.)

;WARNING: riskyExportList overwrites #filename without asking permission!
to riskyExportList [
  #filename ;String, the full name of the file
  #header   ;String, the header (or "")
  #items    ;List, the values to be written
  ]
  carefully [file-delete #filename] []
  file-open #filename
  if "" != #header [file-print #header]
  foreach #items [?item -> file-print ?item]
  file-close
end

Try out this procedure on a simple list, such as [1 2 3]. For example:

riskyExportList "/temp/temp.csv" [1 2 3]

Open the resulting file with a text editor to view the result. You should find a single column of output in the target file.

Example: Export Attribute (Agentset)

The following produces a single column of output in the file named temp.csv.

carefully [file-delete "temp.csv"] []
file-open "temp.csv"
ask patches [
  file-print pcolor   ;NetLogo colors are numbers
]
file-close

Recall that [pcolor] of patches produces a list of colors (as numbers). So you can alternatively:

riskyExportList ([pcolor] of patches)

Example: Write Space-Separated Values (SSV)

Try this in the command center:

carefully [file-delete "temp.txt"] []
file-open "temp.txt"
file-print "minimum mean maximum"
file-type 10 file-write 15 file-write 20
file-print ""  ;;terminate line with CR
file-close

Example: Write Comma-Separated Values (CSV)

Ordinarily we use the csv extension to write CSV files. However, we can do it by hand. In the Code tab, create the following command procedure:

to writeCSVrow [#fname #vals]
  file-open #fname
  file-type first #vals
  foreach but-first #vals [[?] ->
    file-type "," file-type ?
  ]
  file-print ""  ;;terminate line with CR
  file-close
end

Here we illustrate how to write a header line and a line of data. At the command center, enter the following:

carefully [file-delete "temp.csv"] []
writeCSVrow "temp.csv" ["minimum" "mean" "maximum"]
writeCSVrow "temp.csv" [10 15 10]

Writing subsequent lines is identical.

Multiple Open Files

You must always use file-open to specify what file you want to interact with. E.g.,

file-open "log1.txt"
file-open "log2.txt"
file-write "this goes in log2.txt"
file-close
file-open "log1.txt"  ;;required!
file-write "this goes in log1.txt"
file-close

File-Based Input

In order to read external information into a program, the following commands are often useful.

file-read-line:

read the next line and return it as a string (without terminators)

file-read:

read the next "constant" (e.g., number, list, or string) and return it

file-at-end?:

report true if last character of file has been read

Of course we will still need to open and close our files.

file-open string:

open a file for reading or appending (but not both)

file-close:

close an open file

Example: file-read-line

Try this in the command center:

file-open "temp.txt"
print file-read-line
file-close

Note use forward slashes in your paths.

Example: File-Based Input

Suppose the nldata01.txt looks like:

pxcor pycor n-turtles
0 0 5
1 0 3

You could handle this (in a procedure, in the Code tab) as follows:

file-open "nldata01.txt"
let trash file-read-line ;; discard header line
while [not file-at-end?] [
  ask patch file-read file-read [sprout file-read]
]
file-close

Example: More File-Based Input

Assume a 20x10 world of patches.

Suppose patches have a foo attribute. Suppose you have created foo.txt as:

1 2 3 4 ... 200

Suppose patches also have a bar attribute. Suppose you have created bar.txt as:

200 199 198 197 ... 1

Give each patch one of these values for its foo and bar attributes as follows:

to setupPatches
  let patch-list sort patches
  file-open "foo.txt"
  foreach patch-list [[?] ->ask ? [set foo file-read]]
  file-close
  file-open "bar.txt"
  foreach patch-list [[?] ->ask ? [set bar file-read]]
  file-close
end

Comment: patches are sorted in a fixed order: left to right, top to bottom.

Example: File-Based Input (Python)

fin = open('nldata01.txt', 'r')
trash = next(fin)
data = dict()
for line in fin:
    x, y, n = map(int, line.split())
    data[(x,y)] = n
fin.close()

CSV Extension

The NetLogo CSV extension simplifies reading and writing data in the CSV format. CSV stands for comma-separated values. The CSV extension accommodates some common deviations from the CSV standard. For example, it allows specification of a different delimiter than the comma. However, the standard for scientific data exchange is a comma as the field delimiter and a point as the decimal separator.

Declaring and Using the CSV Extension

You must declare your intention to use the csv extension at the top of your Code tab.

extensions [csv]

You can write a list of lists to myFile.csv like this:

csv:to-file "myFile.csv" [[1 2] [3 4] [5 6]]

Try this at the command line. (Warning: this will overwrite any existing file named myFile.csv!) You can append a row to myFile.csv like this:

file-open "myFile.csv"
file-print csv:to-row [7 8]
file-close

Example: File-Based Input (CSV)

extensions [csv]

to setup
  file-close-all
  ca
  file-open "c:/temp/temp.csv"
  ;;if there is a header line, use it or discard it
  let _trash file-read-line
end

to get-one-line
  file-open "c:/temp/temp.csv"
  if file-at-end? [ stop ]
  let _line file-read-line      ;; read the line into a string
  let _data csv:from-row _line  ;; convert the string to a list of numbers
  ;;now do whatever you want with the data
end

Example: File-Based Output (CSV)

extensions [csv]

to setup
  ca
  file-close-all
  carefully [file-delete "temp.csv"] []
  file-open "c:/temp/temp.csv"
  file-print "x,y,z"
  file-close
end

to write-one-line
  let _mylist (list x y z)
  file-open "c:/temp/temp.csv"
  let _mystr csv:to-row _mylist
  file-print _mystr
  file-close
end

BehaviorSpace and File Output

If you want to make a unique output file for each BehaviorSpace run, use the behaviorspace-run-number primitive to make a unique filename. Alternatively, produce filenames based on parameter values.

For example, suppose that in BehaviorSpace you specify the parameter sweep:

["globalA" 1 2 3]
["gloablB" 4 5 6]

Then you can

file-open (word "myfile-" globalA "-" globalB ".txt")

Of course you can combine these two approaches. And if a need for even more flexibility arises, consider Charles Staelin's pathdir extension (on GitHub).

Table Extension

NetLogo ship with a number of extensions, which are imported with the extensions keyword. Tables are provided by the table extension, so we must add the following near the top of the Code tab.

extensions [table]

What is a Table?

Fundamentally, a NetLogo table is a mapping from keys to values. (See the documentation for details.) The lookup of the value of a key is very fast—much faster than iterating through a list of key-value pairs.

Create a new table with table:make. Tables are mutable: Add a new key-value pair with table:put. Get the value associated with an existing key with table:get. For example:

to xmplTable
  let tbl table:make
  table:put tbl "test" "this"
  print table:get tbl "test"
end

Frequency Tables via the table Extension

One of the most useful features of the table extension is the table:counts primitive. This converts a list into a frequency table, using the list items as keys and providing the counts as values. Try the following at the command line.

print table:counts ["a" "b" "c" "b" "a"]

Note the special formatting of the printed result ({{table: [["a" 2] ["b" 2] ["c" 1]]}}), which appears to hold a list of ordered pairs. The first item in each pair is a key; each key appears only once. The second item in each pair is the associated value—in this case, the associated count. For example, the pair ["c" 1] means that the string "c" was counted once.

In sum, producing a frequency table in NetLogo is very simple. First, import that table extension, and then use its counts primitive to produce a table of counts. The resulting table displays very similarly to a list of two-item lists, which are the key-value pairs. The keys can be numerical. For example, a gambling simulation with patch agents may produce a list of integer wealth values, retrievable as [wealth] of patches. Produce the associated frequency table as table:counts ([wealth] of patches).

Frequency Tables as Plot Coordinates

A frequency plot includes one point for each key-value pair in the resulting frequency table. (See the discussion in the Basic Statistics supplement for details.) When a simulation produces clustered integer data (e.g., as in the Gift World lecture), NetLogo’s plotting facilities can produce a nice frequency plot. First of all, table:counts will nicely assemble the plot data. Iterate over the key-value pairs in order to do the plotting.

Frequency Plots via the table Extension

As discussed above, the foreach command iterates over NetLogo lists. However, NetLogo does not currently allow iteration over a table. Fortunately, the table:to-list function can convert a table to a list of key-value pairs. This command converts a frequency table to a list of lists, where each inner list of the result holds two items. When the keys are numerical, each inner list can representing the two coordinates of a single point. E.g.,

table:to-list (table:counts [wealth] of patches)

Plotting a single key-value pair is easy. Use NetLogo’s first primitive to extract the first coordinate. Use NetLogo’s last primitive to extract the second coordinate. Then provide the first and second coordinates to NetLogo’s plotxy primitive, which will plot a point. In sum, plot each point \((x,y)\) by extracting \(x\) and \(y\) values from a key-value pair.

For example, create data by rolling a die \(100\) times, recording a list of the rolls (i.e., of the number of pips on the upward face of each roll). Use table:counts to produce a frequency table, and use table:to-list to extract the list of \((x,y)\) coordinates. Finally, use plotxy to plot each of these points.

let data n-values 100 [one-of [1 2 3 4 5 6]]
let t table:counts data
let pts table:to-list t
foreach pts [
  [xy] -> plotxy (first xy) (last xy)
]

Given data, the following more compactly accomplishes the same plotting goal.

foreach table:to-list table:counts data [
  [xy] -> plotxy (first xy) (last xy)
]

Missing Outcomes

Naturally, table:counts only counts observed outcomes. It is often desirable for a frequency table or frequency plot to show the zero count for outcomes that were not realized. Fortunately, the table entension includes the table:get-or-default command, which may be used to retrieve values for a list of keys with a default of \(0\).

Table Manipulation Example

This following example shows how to make a frequency table without table:counts. This is just as an exercise to illustrate features of a NetLogo table and the use of foreach.

to-report counts [#lst]
  let _t table:make
  foreach #lst [[?] ->
    let _k ?
    ifelse table:has-key? _t _k [
      table:put _t _k (1 + table:get _t _k)
    ][
      table:put _t _k 1
    ]
  ]
  report _t
end

Array Extension

What is an Array?

A NetLogo array is a fixed-length collection of objects, such as a collection of 100 numbers. Let us make an array of length 100, full of zeros.

array:from-list n-values 100 [0]

Indexing is zero-based. That is, as with lists, the first item has index 0. The second item has index 1. And so on.

Documentation: http://ccl.northwestern.edu/netlogo/5.0/docs/arraystables.html

Arrays Are Mutable

School-Lockers Analogy:

You can think of an array as a bit like a row of school lockers. Each student has an assigned locker, where s/he stores stuff. The stuff in a locker can change. Similarly, we can change the corresponding item in the array. Let us change the first value of myarray to 999.

array:set myarray 0 999

Increment a Single Item

Let us increment the first value of myarray by 1.

array:set myarray 0 (array:item myarray 0 + 1)

Let us decrement the second value of myarray by 1.

array:set myarray 1 (array:item myarray 1 - 1)

When array items represent the values of an attribute of agents, then a transfer can be represented as a decrement of one item combined with an increment in another.

This is a bit like taking something out of one student's locker and putting it in another student's locker.

Arrays vs Lists

NetLogo uses the term "array" substantially differently than many languages. In particular, a NetLogo array is a fixed length container of objects, which need not be of a common type. (E.g., they need not all be numbers.) Array items can be quickly accessed or replaced, using their indexes.

array:set myarr 0 (array:item myarr 0 + 1)

Since lists are immutable, the equivalent operation on lists is a bit more awkward.

set mylst replace-item 0 mylst (item 0 mylst + 1)

Array Limitations

While arrays can be useful when one needs a fixed-length container with changing contents, they are limited. For example, to copy an array, you need a list intermediary:

let acopy array:from-list array:to-list myarr

(See http://ccl.northwestern.edu/netlogo/docs/arraystables.html for details on array:to-list.)

Similarly, max and min work only on lists, so you will again have to use array:to-list if you want to use these commands.

Array Limitations: Filtering

We can only apply filter to lists. So if you want to filter an array a, you need to convert it first:

filter [? < 3] array:to-list a

Other Extensions

Bundled Extensions

See: Help > NetLogoUser Manual > Extensions

A standard NetLogo installation bundles a few extensions, which are located in Extensions subfolder of the NetLogo installation folder. These include:

For most users the two most important extensions are csv and table. Advanced users often require nw and matrix and profiler.

vid Extension

Record 100 ticks of a simulation:

vid:start-recorder
vid:record-view
repeat 100 [
  go
  vid:record-view
]
vid:save-recorder "my-movie.mp4"

Documentation: https://ccl.northwestern.edu/netlogo/docs/vid.html

Alternatives to vid Extension

There have been reports that the vid extensions produces videos that do not play reliably under Windows.

An alternative is to export the view every tick and then combine the exported .png files into a movie.

to make-frames
  setup  ;must call reset-ticks
  repeat 100 [
    go  ; (must call tick)
    export-view (word "frame" (1000 + ticks) ".png")
  ]
end

This will produce 100 files with names frame1001.png to frame1100.png.

To combine the PNG files, use any software capable of doing so. For example,

  • ffmpeg -f image2 -r 1/5 -i frame%04d.png -vcodec mpeg4 -y movie.mp4

  • avconv -f image2 -i frame%04d.png -r 76 -s 800x600 foo.avi

  • Mathematica's Export function.

  • Python's pillow library.

  • GIF Construction Set Professional.

Other Important Extensions

See https://github.com/NetLogo/NetLogo/wiki/Extensions

shell

https://github.com/NetLogo/Shell-Extension/

stats
R
numanal

Numerical Analysis (roots and optima) http://sophia.smith.edu/~cstaelin/NetLogo.html http://sophia.smith.edu/~cstaelin/NetLogo/numanal.html

web

https://github.com/NetLogo/Web-Extension/wiki/Primitives

Example of retrieving stock market data in real time:

web:make-request
  "http://download.finance.yahoo.com/d/quotes.csv"
  "GET" [["s" "GOOG"] ["f" "l1"] ["e" ".csv"]]

Odds and Ends

Colors Are Numbers

When we show the color of an agent, the result is a number. NetLogo represents colors by numbers in [0 .. 140). http://ccl.northwestern.edu/netlogo/5.0/docs/programming.html#colors

The command random-float 140 picks a random number in this range.

As a matter of convenience, NetLogo also defines named aliases for some colors. (E.g., white = 9.9.)

So the following are equivalent:

ask mypatch [set pcolor white]
ask mypatch [set pcolor 9.9]

(You can see this equivalent by entering show white at the command line.)

scale-color

For useful examples (including shading and tinting), see http://ccl.northwestern.edu/papers/ABMVisualizationGuidelines/palette/doc/NetLogo%20Color%20Howto%201.htm

Advanced Topics

NetLogo Source (.nls) Files

In support of DRY programming, NetLogo allows a model to load a .nls file declaring variables, breeds, and (most importantly) procedure definitions.

https://ccl.northwestern.edu/netlogo/docs/programming.html#multiple-source-files

The process for creating a new .nls file in the Code tab is a bit awkward.

  • at the top of the Code tab add __includes [], and then press Check.

  • a new chooser named Included Files appears; from it pick New Source File

  • add some code and then File » Save As, being sure to include the .nls extension!

  • note this this does not save your model file; it just saves your .nls file. To save your model file, first return to one of the three main tabs.

NetLogo APIs

NetLogo can interface with the outside world via its:

Extensions allow to add new primitives to NetLogo, written in any language that runs on the JVM (Java, Scala, Simula, etc.)

For example, interface with an agent written in a language that the JVM can interface with (possibly by using the JNI) by writing a NetLogo extension with a command that calls the agent. A NetLogo model could then use your new command to let the external agent report an action.

The controlling API allows a NetLogo model to be externally controlled by any program that can interact with the JVM. Use the controlling API to send commands to a NetLogo model and to report the results back to your external program.

Using Mathematica link is somewhat like using the controlling API except that all interactions over the link are interpreted by NetLogo.

The GoGo Extension interfaces with GoGo boards running the Human Interface Driver (HID) firmware. The GoGo Board connects with the computer via the USB port and supports sensors and motors. The NetLogo Models Library includes the Robotic Factory model, which demonstrates this capability.

Summary and Conclusions

Resources

See the NetLogo Programming Guide for the definitive documentation of procedure defintion.

Programming Style

Currently there is no official NetLogo style guide. The NetLogo Models Library is stylistically fairly consistent, so it can serve as a guide by example.

Here are some style guidelines that reflect some fairly common practices.

  • declare variables (globals, patches-own, etc.) one per line, with an explanatory comment for each variable

  • breed names should be obviously plural

  • name command procedures with nouns and reporter procedures with verbs

  • indent code blocks by 2 spaces per level, including procedure and reporter bodies;

  • do not use tab characters (except possibly in output)

  • identify procedure context with a comment, e.g.,

    to move ;; turtle procedure
      right random-float 360
      forward 1
    end
  • avoid using who numbers

  • put branching conditions in parentheses

Here are two addition common practices that this course violates on a regular basis.

do not use underscores in names

but, this course begins local variable names with an underscore

name boolean variables with a question mark, as in attempted-task?

but, this course instead begins boolean variable names with is or has, as in hasAttemptedTask

Additionally, this course adopts the following nonstandard conventions.

  • start parameter names with a hash and local variable names with an underscore.

    to-report sq [#x]
      let _xsq (#x * #x)
      report _xsq
    end
  • open code-block brackets at the end of a line; close them on their own line, except between the if and else clauses, e.g.,

    ifelse (this = that) [
      do-A
    ][
      do-B
    ]

Contrary to common practices, I recommend:

  • use upper camel case for file names, with no spaces

  • for variable long names, use camel-case instead of hyphenation, beginning with a lower-case letter

While hyphenated names are a convention in Lisp derived languages, they are not possible in many other languages. Avoiding them makes it a bit easier to port models to other languages.

NetLogo File Format

NetLogo files use a plain text file format. This means that all the widgets in the Interface tab can be edited with a text editor. Ordinarily you will adjust the locations of widgets (such as sliders, monitors, or plots) with a mouse in the Interface GUI. However, sometimes finer adjusted is desirable. In this case, since the file format is plain text, we can simply edit the .nlogo file directly. There is helpful informal file-format documentation online.

For example, defining a monitor takes 10 lines, as follows. First comes the new MONITOR declaration, on its own line. Next comes a specification of the top left \((x1,y1)\) and bottom right \((x2,y2)\) corners of the monitor, measured in pixel offsets from the top left of your graphic window. Unfortunately, y2 is ignored: the monitor height depends of the font-size you specify in the tenth line. Next you specify the display name for your monitor and the reporter expression (e.g., global variable name) you are monitoring. The next line specifies the precision of the numer displayed (i.e., the number of decimal places). The ninth line appears to be reserved for future use, and the last line specifies the font-size (in points).

MONITOR
x1
y1
x2
y2
Display Name
reporter-expression
precision
1
font-size

References

[Axtell.Axelrod.Epstein.Cohen-1996-CMOT]

Axtell, Robert, et al. (1996) Aligning Simulation Models: A Case Study and Results. Computational and Mathematical Organization Theory 1, 123--141. https://doi.org/10.1007/BF01299065

[Railsback.Grimm-2011-PrincetonUP]

Railsback, Steven F., and Volker Grimm. (2011) Agent-Based and Individual-Based Modeling: A Practical Introduction. Princeton, NJ: Princeton University Press.

[Resnick-1997-MIT]

Resnick, Mitchel. (1997) Turtles, Termites, and Traffic Jams: Explorations in Massively Parallel Microworlds. Cambridge, MA: MIT Press.

[thiele.grimm-2010-envsoft]

Thiele, Jan C., and Volker Grimm. (2010) NetLogo meets R: Linking Agent-based Models with a Toolbox for their Analysis. Environmental Modeling and Software , 972--974.

[Wilensky-2017-CCL]

Wilensky, Uri. (2017) NetLogo 6.01 User Manual.

[Wilensky.Rand-2015-MIT]

Wilensky, Uri, and William Rand. (2015) An Introduction to Agent-Based Modeling: Modeling Natural, Social, and Engineered Complex Systems with NetLogo. Cambridge, MA: MIT Press.


version:

2023-08-09