Conventional Programming 1
Do you have questions or comments about this model? Ask them here! (You'll first need to log in.)
WHAT IS IT?
This is a tutorial introduction to NetLogo as a conventional programming language. It is self-contained on the assumption that the user is passingly familiar with the NetLogo platform and its use for agent-based modeling. Before tackling this tutorial, users should at the very least read the tutorials in the NetLogo user manual and exercise some NetLogo programs. Readers should know about patches, turtles, and the world in NetLogo, although we will not discuss them in this tutorial. Readers should also know about the Interface tab and the things that can go on it, the Info tab (where you are now), and the fact that NetLogo code resides in the Code tab (as well as in some of the interface widgets).
CONTEXT
The NetLogo platform comes with a programming language, which we may as well call NetLogo. Together, the platform and the programming language, afford and have been designed for building agent-based models. Not every programming task, however, calls for an agent-based model. Most in fact do not and for these there are various other programming languages that, for a given task, will likely be more suitable than NetLogo. Important examples of such languages include (in no particular order) Python, PHP, C, Java, Ruby, and MATLAB. There are very many others as well.
With very few exceptions any programming language will have conventional or general programming capabilities, plus special features or capabilities that distinguish it for particular purposes. Programming languages, like all other cultural objects, must compete for acceptance and popularity. They do this largely through specialization combined with some degree or other of conventional programming capabilities. NetLogo is no exception.
NetLogo leaves much to be desired as a conventional programming language. (It is terrific in its specialization for "low floor, high ceiling" agent-based modeling.) Even so, there are a number of good reasons to explore this aspect of NetLogo.
- Programming novices can easily obtain skills for very many useful programming tasks, such as implementing mathematical functions and getting them to calculate useful results. If you are just starting to program and need a rudimentary conventional programming language, NetLogo may do you just fine.
- It is well known that learning one conventional programming language makes learning another much easier and faster. Having become familiar with NetLogo as a conventional programming language will help you a lot when you need to acquire facility with Python, PHP, C, Java, MATLAB, and so on.
- Experienced programmers, those with good knowledge of one or more conventional programming languages, will find that understanding NetLogo's treatment of conventional programming helps them ramp up quickly to NetLogo and provides useful insights into how it works.
- It will be very often the case that agents or patches in a particular model require services of a conventional programming nature. (Agents need to evaluate mathematical functions, too.) Understanding this aspect of NetLogo is essential for meeting these requirements.
Then here we go.
HELLO WORLD
It is a tradition and a fine one to begin instruction for any programming language by showing how to write a "Hello, world!" program. Why not?
There are a number of ways to do this in NetLogo. First, type
print "Hello, world!"
in the Command Center command line (with "observer>" to the left), and then press the Enter/Return key. You will see
Hello, world!
appear in the Command Center display window. Why does one expression have "Hello, world!" in quotes and the other not? Well, the print
command expects to receive a sequence of characters (called a string), which it will print. NetLogo indicates the extent of a string by enclosing it in double quote marks (characters). The output doesn't have quotes because they are not part of the string that print
was asked to print.
Suppose we want to include double quote characters in the print string, how do we do that? Answer: by escaping them with the backslash character: \
. Here's an example:
observer> print "\"Hello, world!\"" "Hello, world!"
OK, smart guy, now what if we want to include a backslash character in the output string, how do we do that? With another backslash:
observer> print "This is how you print a \\ character."
This is how you print a \ character.
And this, I submit, resolves the (apparent) paradox of using characters to delineate sequences of characters.
NetLogo also lets you print to the Interface output widget if it is present:
observer> output-print "You can print \"s and \\s to the output widget."
This yields
You can print "s and \s to the output widget.
in the output widget.
Output will accumulate unless you clear it with clear-output
or something stronger, such as a clear-all
command. There is a button for this on the Interface tab.
Finally, we can print from a command procedure stored in the Code tab:
to yo-button
output-print "Yo, world!"
end
Click the yo-button on the Interface tab and see the message printed in the output widget.
We see here the basic template for a command procedure in NetLogo:
to command name
[
NetLogo code]
end
Of which, much more as we proceed.
FRAMEWORK
Conventional programming languages, including NetLogo, will all (more or less) have similar or analogous features of seven kinds:
- variables
- operators and built-in functions
- procedures
- flow control
- data structures
- I/O (input and output)
- special libraries/functions
We'll now work through the framework in the context of NetLogo.
1. VARIABLES
Variables in a programming language are symbols that may be (and normally are) assigned values. For example, in (the NetLogo code)
let sara 23.4
the variable is sara
, the value it is assigned is 23.4 and let
instructs NetLogo to effect the assignment. Now let's consider this line of code in a command procedure, it's typical context. (You will find this procedure in the Code tab.)
to local-assignment
let sara 23.4
output-print (word "The value of sara is " sara ".")
set sara 43.2
output-print (word "Now the value of sara is " sara ".")
end
Try clicking the local-assignment button on the Interface tab. What's going on here is this. First, let sara 23.4
creates a local variable and assigns it the value 23.4. Next, output-print (word "The value of sara is " sara ".")
uses (word "The value of sara is " sara ".")
to create the string "The value of sara is 23.4." and then print it to the output widget. Next, set sara 43.2
assigns sara
a new value. Because sara
already exists (having been created with let sara 23.4
), NetLogo requires us to use set
instead of let
to assign values to variables. Finally, output-print (word "Now the value of sara is " sara ".")
uses (word "Now the value of sara is " sara ".")
to create the string "Now the value of sara is 43.2." and prints it to the output widget.
sara
in this example is a local variable, meaning that it was created with let
within a procedure and is only valid within that procedure. If we create another procedure and try to use sara
NetLogo will go into error mode. If we use let
in another procedure to declare a variable called sara
that variable is different than the one we declared and assigned in our other procedure, local-assignment
. Further, when we assign this new sara
a value, the old sara
is unaffected. They are two distinct entities having the same name. Think: Grace Lee who made an entire movie, "The Grace Lee Project," by interviewing other people named Grace Lee. Here's a link:
http://www.wmm.com/filmcatalog/pages/c646.shtml
(It's a fine movie and will help you remember how local variables work.)
Now, if we have local variables, do we also have variables that are not local? Definitely, and they are called global variables. There are two kinds in NetLogo. One kind is declared at the top of the Code tab using the NetLogo key word globals
. For example,
globals [bob carol ted alice]
declares the variables bob
, carol
, ted
, and alice
and makes them global. The effect of this is to make each of these variables available throughout the NetLogo program. Consider the following two command procedures, which you will find in the Code tab.
to bob-plus-one
set bob (bob + 1)
output-print (word "The value of bob is now " bob ".")
end
to bob-plus-two
set bob (bob + 2)
output-print (word "The value of bob is now " bob ".")
end
(Notice: (i) We have used the addition operator, +
, to add two numbers. In NetLogo, it is required that operators have spaces on either side, just as they do here. (ii) word
is also a kind of operator. It combines sequences of strings and/or numbers into a single string. We will have more to say below about operators.)
If you click the clear-all button on the Interface and then click
- bob-plus-one
- bob-plus-one
- bob-plus-two
- bob-plus-one
You will see displayed in the output widget the following.
The value of bob is now 1.
The value of bob is now 2.
The value of bob is now 4.
The value of bob is now 5.
Notice that the value of bob
before you first clicked on bob-plus-one must have been zero (why?). In general, variables declared with globals
are initialized to 0.
The second way to create a global variable is with a widget on the Interface. On the Interface tab you will find a slider called a-global-slider-variable and in the Code tab you will find this command procedure.
to show-global-slider-value
output-print (word "The value of a-global-slider-variable is "
a-global-slider-variable ".")
end
Move the slider to a convenient value then click the show-global-slider-value button. The value of a-global-slider-variable will be displayed in the output widget.
The following command procedure is also in the Code tab.
to set-global-slider-value-to-bob
set a-global-slider-variable bob
output-print (word "The value of a-global-slider-variable is "
a-global-slider-variable ".")
end
Click the show-global-slider-value button. The value of a-global-slider-variable will be set to whatever value the variable bob
and the new value of a-global-slider-variable will be displayed in the output widget. Notice that the slider will also change to its new value. Also notice that we broke the output-print
statement into two lines, breaking at a point between items in the word
list. In general, NetLogo is relaxed about formatting. Go ahead and break lines to keep everything visible in the window, but I recommend using indentation (as above), to maintain clarity.
Variable names in NetLogo should begin with alphabetic characters (a-z), may contain digits (0-9), and both the dash (-) and the underscore (_). Spaces are NOT allowed. Also, NetLogo is not case-sensitive, so BOB
and bob
and BoB
and so on are all equivalent and may be used interchangeably (although it would be ill-advised to do this).
2. OPERATORS AND BUILT-IN FUNCTIONS
You are familiar with the concept of a function from your acquaintance with mathematics. A function takes as input one or more values (or variables having values) and returns a value. The function concept in conventional programming languages is essentially the same.
NetLogo comes with a number of built-in functions, which you get to use at will. For example, there are trigonometric functions.
observer> print cos(12.3)
0.9770455744352636
Look, for other examples, under Math in the NetLogo Dictionary. Notice the syntax for our example. cos
is our function name (short for cosine). The function takes one input value, or argument, which in the example is 12.3. In general, function arguments should be individually enclosed in parentheses, as we see in this case.
An operator is just a function with a different syntax. +
as we saw above is an operator. In standard prefix notation, standard for functions, we might write +(3.4,6.7)
. Instead, using operator infix notation we write 3.4 + 6.7
. Any differences are entirely superficial. Again, see the Math section in the NetLogo Dictionary for examples of operators in NetLogo.
3. PROCEDURES
Procedures in a conventional, or general, programming language are distinct "chunks" of code that are named and may be run (executed) by "calling" them from another part of the program. Computer programs easily become very complicated and require ways to modularize them (break them into smaller, meaningful pieces) if they are to remain manageable and usable. Procedures are the most fundamental form of modularization.
NetLogo recognizes two kinds of procedures:
- command procedures (or just commands)
- reporter procedures (or just reporters)
The key difference between them is that reporters return values when they are called. There are very much like functions. Indeed that is how we should think of them. Commands, on the other hand do things (including calling reporters).
We have already seen several examples of command procedures, so here is a reporter procedure. You will find it in the Code tab.
to-report square-em-add-em [x y]
; This reporter takes two variables when called,
; x and y, and returns the value of x^2 + y^2.
let xx x * x
let yy y ^ 2
report xx + yy
end
This reporter illustrates the general pattern for reporters in NetLogo.
to-report <reporter name> [<optionally a series of variable names>]
<NetLogo code and comments.>
report <some value or variable>
end
The reporter name should follow the conventions for naming variables (as should the names of command procedures). The parameter list is set off between square brackets: [...] and is optional, although normally needed. Variable names, separated by spaces, go into the list. You should use names that are not otherwise used for global variables. These names will become local variables in the reporter procedure. In our present example, they are x
and y
. It is fine to use x
and y
as parameters in other procedures. Just remember that they are local variables. Remember: Grace Lee.
The first two lines of our procedure begin with semicolons: ;
. NetLogo uses the semicolon as a comment sign. Everything in a line after a semicolon (unless it appears in a quoted string, as in print "We can print ;s if they appear within strings"
) is considered to be a comment by NetLogo and is ignored. Comments are very handy things. Use them profusely.
let xx x * x
creates a new local variable, xx
and assigns it the value of x2. Similarly, let yy y ^ 2
creates a new local variable, yy
and assigns it the value of y2.
Finally, every reporter procedure requires at least one report
command. Notice that NetLogo allows complex expressions that get evaluated as part of the report
command.
In calling a reporter we recommend enclosing its arguments singly in parentheses. Here's an example, which you will find in the Code tab. There is also a button for it on the Interface tab.
to call-square-em-add-em
let x1 a-global-slider-variable
let x2 another-global-slider-variable
let daResult square-em-add-em(x1)(x2)
output-print (word "The result is " daResult ".")
end
Reporter procedures may be called from the command line of the Command Center, from command procedures, from reporter procedures, and indeed from buttons on the Interface tab.
4. FLOW CONTROL
Also known as control flow, and called Control Flow and Logic in NetLogo. See "Control/Logic" in the NetLogo Dictionary.
Absent flow control statements, execution of programming language statements proceeds sequentially, from top to bottom. The examples so far illustrate this. Very often, however, we wish to control the flow of execution, perhaps to re-execute a number of lines of code, perhaps to skip certain lines of code, and so on. Flow control statements let us do this. NetLogo supports versions of the basic flow control constructs found in conventional programming languages.
The if
statement has the following syntactic template.
if
condition[
commands]
where condition is a NetLogo expression that evaluates to true
or false
and commands indicates the NetLogo code that is to be executed if the condition evaluates to true
. Here's an example, which you will find in the Code tab.
to simple-if
if a-global-slider-variable > 17
[output-print "It's more than 17."
set a-global-slider-variable 17]
end
Try it out by clicking on the simple-if button on the Interface tab. Comments:
a-global-slider-variable > 17
evaluates totrue
orfalse
, depending on the current value ofa-global-slider-variable
, e.g.,observer> print a-global-slider-variable > 17 true
The
>
symbol is a NetLogo operator (that is it is a function presented in infix form) and it means just what you think it means: It corresponds to the mathematical "greater than" sign, so thatx > y
evaluates totrue
exactly when the values ofx
andy
are numeric (or can be interpreted as such) and the value ofx
is strictly larger than that ofy
.If
a-global-slider-variable > 17
evaluates tofalse
, then the associated code is skipped and execution continues after theif
statement.NetLogo requires that the associated code be enclosed in square brackeks,
[...]
, but it is very lenient regarding just where they are placed. The example shows a stylistically sound placement.You may put any number of lines of code, including flow control statements, within the square brackets.
to simple-ifelse ifelse a-global-slider-variable > 17 [output-print "It's more than 17." set a-global-slider-variable 17] [output-print "It's less than or equal to 17."] end
The ifelse
statement has the following syntactic template.
ifelse
reporter[
commands1]
[
commands2]
where reporter is a NetLogo expression that evaluates to true
or false
, commands1 indicates the NetLogo code that is to be executed if the reporter evaluates to true
, and commands2 indicates the NetLogo code that is executed if the reporter evaluates to false
. So, why reporter and condition earlier for the if
statement? The NetLogo document is simply confused here and the terminology is a bit confusing. We've seen how to write reporter procedures. Any such procedure counts as a reporter in NetLogo, but other things count as reporters as well. Expressions with relational operators, as in a-global-slider-variable > 17
, count as reporters. (See Math in the NetLogo Dictionary for the full list of relational operators in NetLogo.) NetLogo also has a number of built-in reporters that evaluate to true
or false
and are often very useful, including:
observer> print is-number? a-global-slider-variable true observer> print is-string? another-global-slider-variable false observer> print is-string? "carol" true observer> print is-string? carol false
The key thing to remember is that whether for condition in if
or reporter in ifelse
we need a reporter that evaluates to true
or false
.
Here's an example, which you will find in the Code tab.
to simple-ifelse
ifelse a-global-slider-variable > 17
[print "It's more than 17."
set a-global-slider-variable 17]
[print "It's less than or equal to 17."]
end
Try it out with the simple-ifelse button on the Interface tab.
The repeat
command
repeat
number[
commands]
runs commands number times.
Here's an example, which you will find in the Code tab.
to simple-repeat
let dacount 0
repeat a-global-slider-variable
[output-print dacount
set dacount (dacount + 1)]
end
Try it out with the simple-repeat button on the Interface tab. What happens if the number value is not an integer, say it's equal to 12.3? Well, edit the a-global-slider-variable widget and experiment.
With the while
statement
while [
reporter] [
commands]
if reporter reports false, we exit from the loop; we run commands and repeat. Unless you intend for while
to execute indefinitely (as an "infinite loop"), you will need to change the value of a variable that can affect whether reporter reports true
or false
. Here's an example.
to while-away
let dacount a-global-slider-variable
while [dacount >= 0] [
output-print dacount
set dacount (dacount - 1)
]
end
You will find it in the Code tab. Try it out with the while-away button on the Interface tab. Notice a slight change in formatting for this command procedure. This alternative is also fine and is in fact favored a bit by NetLogo. It's up to you.
Our final flow control statement, foreach
is in fact not listed by NetLogo in the Control/Logic category in the dictionary. Instead it appears in the Task category. Go figure. Anyway, here is the template.
foreach
list command-task
Here is NetLogo's explanation:
With a single list, runs the task for each item of list.
This isn't very helpful, but the following example is.
to simple-foreach
foreach [2 4 6 8] [
output-write ?
output-type " "
output-print ? * ?
]
end
You will find it in the Code tab. Try it out with the simple-foreach button on the Interface tab. Here's what's going on. foreach
iterates through its list, going item by item. In the example, the first item is the number 2, so the NetLogo special variable ?
is assigned the value 2. Then the code in command-task is executed once. (Notice output-write
to print without a new line, and output-type
to print a blank space. Look them up in the NetLogo Dictionary.) After the code in command-task is executed, control flows back to the start of the foreach
statement and ?
is assigned the value of the next item in list, which is 4 the second time through, and then the code in command-task is executed once with the new value of ?
. This continues until each item in list has been assigned in tern to ?
, after which the flow of control is passed to the next statement after the foreach
statement.
A problem with the foreach
construction we just looked at is that we explicitly state the list. This is fine for small lists, but what if we want to iterate over hundreds or thousands (or more) items? For this we can construct list using
n-values
size reporter-task
which reports "a list of length size containing values computed by repeatedly running the task." The NetLogo documentation isn't as articulate as one might hope. Here's an example showing how to do it.
to n-values-foreach
foreach n-values 4 [(1 + ?) * 2] [
output-write ?
output-type " "
output-print ? * ?
]
end
As usual, you will find it in the Code tab, should try it out with the n-values-foreach button on the Interface tab. Notice that n-values-foreach
and simple-foreach
have identical outputs. Note as well:
observer> print n-values 5 [?]
[0 1 2 3 4] observer> print n-values 5 [1 + ?]
[1 2 3 4 5]
observer> print n-values 5 [(1 + ?) * 2]
[2 4 6 8 10]
See the pattern?
Finally, the topic of nested loops. Flow control statements may, and often need to, appear within the scope of other flow control statements. This presents a problem in the case of NetLogo's foreach
because we only have the one iteration variable, ?
. In a nested foreach
, what does a particular ?
refer to? Is it the first foreach
? the second? the third? You see the point. NetLogo has a finesse for the problem, which you can read about in the documentation (and which will not work for the example I am giving). I'll show you the alternative I prefer, which in any case is fully general.
Suppose we want to print out something like a multiplication table, but one in which the row values are multiplied by the square roots of the column values. The resulting table will not be symmetric. Moreover, let us assume a table with 6 rows and 5 columns.
to nested-foreach
foreach n-values 6 [(1 + ?)] [
let x1 ?
foreach n-values 5 [(1 + ?) ^ 0.5] [
let x2 ?
output-write x1 * x2
output-type " "
]
output-print " "
]
end
As usual, you will find it in the Code tab, and you should try it out with the nested-foreach button on the Interface tab. The trick, or method, in nested-foreach
is to assign ?
to a local variable immediately after it is itself assigned a value. Then, with every instance of nesting, we assign a new local variable the value of ?
. And we do our computations in terms of these local variables---here x1
and x2
---instead of ?
which has no global unique interpretation.
5. DATA STRUCTURES
So far, we have worked with just two kinds of data: numbers and strings. NetLogo variables can hold either and a single variable can have the type of data assigned to it changed arbitrarily.
Think of a data structure as a complex of simpler data items, for which the programming language as commands for accessing it and manipulating it.
The primary data structure in NetLogo (aside from turtles and patches, which we ignore here) is the list. A list is simply an ordered sequence of items. These items may be of any sort, including numbers, strings, other lists. (And turtles and patches, but not now.) A given list may include any or all of these kinds of things. So lists are very flexible and hence powerful data structures.
See the List category in the NetLogo Dictionary for the commands associated with lists. Our treatment here is introductory.
The empty list---a list with nothing in it---is indicated by []
. You add something to the beginning of a list with the fput
command and to the end with lput
. Items in lists are separated by spaces (NOT commas).
observer> set bob [] observer> print bob [] observer> set bob fput 34.5 bob observer> print bob [34.5] observer> set bob lput "Carol" bob observer> print bob [34.5 Carol] observer> set bob fput bob bob observer> show bob observer: [[34.5 "Carol"] 34.5 "Carol"]
You can access items in a list, counting from 0, and you can retrieve the length of a list:
observer> print item 1 bob 34.5 observer> print item 0 bob [34.5 Carol] observer> print length bob 3
You can replace items in a list with other items. This creates a new list and leaves the original unaltered.
observer> set carol replace-item 2 bob "Alice" observer> show carol observer: [[34.5 "Carol"] 34.5 "Alice"] observer> show bob observer: [[34.5 "Carol"] 34.5 "Carol"]
Similarly, you can remove items from lists.
observer> set ted remove-item 2 carol observer> show ted observer: [[34.5 "Carol"] 34.5] observer> show carol observer: [[34.5 "Carol"] 34.5 "Alice"]
In a prototypical use of lists, we collect or create data, insert the data into a list, and return the list from a reporter. Also prototypically, we are given a list and we iterate through it, often with foreach
, in order to process each of its items. Here's an example.
to-report cubes [alist]
; Accepts a list, alist, presumed to be numbers, and
; reports a new list of the items in alist cubed.
let toreport []
foreach alist [
set toreport lput (? ^ 3) toreport
]
report toreport
end
observer> set bob n-values 9 [?] observer> show bob observer: [0 1 2 3 4 5 6 7 8] observer> print cubes(bob) [0 1 8 27 64 125 216 343 512]
6. I/O (INPUT AND OUTPUT)
We have seen a number of output commands, including print
, write
, type
, and their output-
analogs. See the NetLogo Dictionary for these as well as for show
. All of NetLogo's I/O commands are gathered in the Input/output and the File categories in the NetLogo Dictionary.
We'll finish our treatment of output with a discussion of writing to files from NetLogo.
NetLogo's file reading and writing capabilities are limited, but what is available is widely useful, so here we go.
We begin with the file-open
command. Here is the relevant passage from the NetLogo Dictionary.
file-open
stringThis command will interpret string as a path name to a file and open the file. You may then use the reporters
file-read
,file-read-line
, andfile-read-characters
to read in from the file, orfile-write
,file-print
,file-type
, orfile-show
to write out to the file.Note that you can only open a file for reading or writing but not both. The next file i/o primitive you use after this command dictates which mode the file is opened in. To switch modes, you need to close the file using file-close.
OK, here is a simple example.
to file-output-csv
if file-exists? "demo.csv"
[file-delete "demo.csv"]
file-open "demo.csv"
let data n-values 24 [5 + ?]
foreach [0 1 2 3 4 5] [
let row ?
let next item 0 data
file-write next
set data but-first data
foreach [0 1 2] [
let col ?
set next item 0 data
file-type ","
file-write next
set data but-first data
]
file-type "\n"
]
file-close
end
As usual, you will find it in the Code tab, and you should try it out with the file-output-csv button on the Interface tab. "csv" means "comma separated values", a common format for data in text files. Excel and indeed most statistical programs, such as R, will read it. Use this output format for your data so that these other programs can access it easily.
Here is what is in the resulting file, demo.csv:
5, 6, 7, 8 9, 10, 11, 12 13, 14, 15, 16 17, 18, 19, 20 21, 22, 23, 24 25, 26, 27, 28
Points arising:
- For simplicity's sake I am assuming that you want to write the file into the same directory that the NetLogo program is in. If this is not correct, provide the full or relative path name, suitable for your operating system, in quotes, e.g., "../data/demo.csv". If you don't know what this means, you can probably skip the point without loss. Just keep your data files in the same directory as your NetLogo file.
- If a file exists and has data in it when your program opens it, any data you write to the file will be appended to the end of the file. The new data will be placed after the old data. If you do not want this, then as in the example
file-output-csv
command procedure, first check to see whether your file exists and if it does, delete it. And then open the file. - The
file-type "\n"
line of code has the effect of inserting a new line character---\n
---at the end of each row. The difference betweenprint
andwrite
(in their various forms) is thatprint
inserts a new line character andwrite
does not. In code, we are outputting each line in pieces, sequentially, so we need to usewrite
. - Once you are done with a file, issue the
file-close
command. Not doing this invites trouble. - Only open one file at a time in NetLogo.
See the File Output Example.nlogo model in the NetLogo Models Library for more information.
Now, briefly, file input.
Assume we have a file, demo-space.txt in the same directory as our NetLogo program and that it looks just like demo.csv with spaces instead of commas:
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
Here is a simple example.
to load-input-data
ifelse ( file-exists? "demo-space.txt" )
[
let input-data []
;; This opens the file, so we can use it.
file-open "demo-space.txt"
while [ not file-at-end? ]
[
set input-data sentence input-data (list
(list file-read file-read file-read file-read))
]
output-print input-data
file-close
]
[user-message
"There is no demo-space.txt file in current directory!" ]
end
As usual, you will find it in the Code tab, and you should try it out with the load-input-data button on the Interface tab. Here is the output you will get:
[[5 6 7 8] [9 10 11 12] [13 14 15 16] [17 18 19 20] [21 22 23 24] [25 26 27 28]]
Points arising:
The NetLogo command sentence
is new for us. It appears in the List category of the NetLogo Dictionary. Here is the relevant explanation from the Dictionary:
sentence
value1 value2Makes a list out of the values. If any value is a list, its items are included in the result directly, rather than being included as a sublist. Examples make this clearer:
show sentence 1 2 => [1 2] show sentence [1 2] 3 => [1 2 3] show sentence 1 [2 3] => [1 2 3] show sentence [1 2] [3 4] => [1 2 3 4] show sentence [[1 2]] [[3 4]] => [[1 2] [3 4]] show (sentence [1 2] 3 4 5 7) => [1 2 3 4 5 6 7]
input-data
is defined as a local variable in this example. In any likely application you will want to access the data from the file with other parts of your program. To do this either (i) declareinput-data
as a global variable, or (ii) convertload-input-data
to a reporter and reportinput-data
upon completion.- The
file-read
reads the next item separated by white space in the file. (list file-read file-read file-read file-read)
reads the next for space-separated items from the file and puts them into a NetLogo list. This corresponds to a single row of the file, but we need to know this ahead of time. NetLogo does have aread-line
command, but does not have any commands for splitting lines with commas, or spaces, or whatever.- We use
file-read
because there is no built-in command for dealing with CSV files.
Check out the other commands in the Files category of the NetLogo Dictionary. user-file
and user-new-file
allow you to prompt the user for files, rather than "hardwiring" them into your code.
See the File Input Example.nlogo model in the NetLogo Models Library for more information.
And finally, NetLogo has an Interface widget for eliciting user input, called an input. There's one on the Interface tab which defines the global variable an-input-number
. The value is editable by the user.
observer> print an-input-number / cos(12) 101.98869774373532
Check it out, as well as the other capabilities of input widgets.
7. SPECIAL LIBRARIES/FUNCTIONS
NetLogo has a lot of these, many but hardly all of which pertain directly to agent-based modeling (think: create-turtles
and breeds
and so on).
Especially with the extensions (see the NetLogo User Manual), there are ample additional resources for the conventional programmer, particularly arrays, hashtables, and matrices. Discussion of these will occur in subsequent numbers of this conventional programming series. Stay tuned.
HOW TO CITE
If you mention this model in a publication, I ask that you include a citation for the model itself and for the NetLogo software:
- Kimbrough, Steven O. (2014). Conventional Programming 1 model. University of Pennsylvania, Philadelphia, PA. Conventional Programming 1.nlogo
COPYRIGHT AND LICENSE
Copyright 2014 Steven O. Kimbrough.
This work is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike 3.0 License. To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-sa/3.0/ or send a letter to Creative Commons, 559 Nathan Abbott Way, Stanford, California 94305, USA.
Commercial licenses are also available. To inquire about commercial licenses, please contact Steven O. Kimbrough at kimbrough@wharton.upenn.edu.
Version: $Id: Conventional Programming 1.nlogo 4368 2014-10-01 21:22:32Z sok $.
Comments and Questions
globals [bob carol ted alice] to yo-button output-print "Yo, world!" end to local-assignment let sara 23.4 output-print (word "The value of sara is " sara ".") set sara 43.2 output-print (word "Now the value of sara is " sara ".") end to bob-plus-one set bob (bob + 1) output-print (word "The value of bob is now " bob ".") end to bob-plus-two set bob (bob + 2) output-print (word "The value of bob is now " bob ".") end to show-global-slider-value output-print (word "The value of a-global-slider-variable is " a-global-slider-variable ".") end to set-global-slider-value-to-bob set a-global-slider-variable bob output-print (word "The value of a-global-slider-variable is " a-global-slider-variable ".") end to-report square-em-add-em [x y] ; This reporter takes two variables when called, ; x and y, and returns the value of x^2 + y^2. let xx x * x let yy y ^ 2 report xx + yy end to call-square-em-add-em let x1 a-global-slider-variable let x2 another-global-slider-variable let daResult square-em-add-em(x1)(x2) output-print (word "The result is " daResult ".") end to simple-if if a-global-slider-variable > 17 [output-print "It's more than 17." set a-global-slider-variable 17] end to simple-ifelse ifelse a-global-slider-variable > 17 [output-print "It's more than 17." set a-global-slider-variable 17] [output-print "It's less than or equal to 17."] end to simple-repeat let dacount 0 repeat a-global-slider-variable [output-print dacount set dacount (dacount + 1)] end to while-away let dacount a-global-slider-variable while [dacount >= 0] [ output-print dacount set dacount (dacount - 1) ] end to simple-foreach foreach [2 4 6 8] [ output-write ? output-type " " output-print ? * ? ] end to n-values-foreach foreach n-values 4 [(1 + ?) * 2] [ output-write ? output-type " " output-print ? * ? ] end to nested-foreach foreach n-values 6 [(1 + ?)] [ let x1 ? foreach n-values 5 [(1 + ?) ^ 0.5] [ let x2 ? output-write x1 * x2 output-type " " ] output-print " " ] end to file-output-csv if file-exists? "demo.csv" [file-delete "demo.csv"] file-open "demo.csv" let data n-values 24 [5 + ?] foreach [0 1 2 3 4 5] [ let row ? let next item 0 data file-write next set data but-first data foreach [0 1 2] [ let col ? set next item 0 data file-type "," file-write next set data but-first data ] file-type "\n" ] file-close end to load-input-data ifelse ( file-exists? "demo-space.txt" ) [ let input-data [] ;; This opens the file, so we can use it. file-open "demo-space.txt" while [ not file-at-end? ] [ set input-data sentence input-data (list (list file-read file-read file-read file-read)) ] output-print input-data file-close ] [user-message "There is no demo-space.txt file in current directory!" ] end to-report cubes [alist] ; Accepts a list, alist, presumed to be numbers, and ; reports a new list of the items in alist cubed. let toreport [] foreach alist [ set toreport lput (? ^ 3) toreport ] report toreport end
There are 2 versions of this model.
Attached files
No files
This model does not have any ancestors.
This model does not have any descendants.