Supply argument to reporter - netlogo

The following might be a basic programming question for Netlogo.
I'd like to write generic reporters that I can supply arguments for what they should report on. Suppose the following program:
turtles-own [
houses
cars
]
to setup
clear-all
create-turtles 10
reset-ticks
end
to go
ask turtles [
set houses houses + random 2
set cars cars + random 5
]
tick
end
I can write a reporter on the mean of houses as such:
to-report mean-houses
report mean [ houses ] of turtles
end
But I'd like to have a generic reporter that I can also use to report the mean of cars, like so:
to-report means [ param ]
report mean [ param ] of turtles
end
However this does not work as intended:
setup
repeat 15 [go]
show means houses
> ERROR: You can't use HOUSES in an observer context, because HOUSES is turtle-only.*
How can I have Netlogo evealuate param in the context of turtles in such an instance? I am familiar with how to do this in R (e.g., via tidy evaluation masking with {{ x }}, or the earlier quoting mechanism), but unfamiliar with how to translate this to Netlogo.

As the error states, you are trying to pass a turtle-only variable (houses) to a procedure that is being used in observer context which doesn't work because Netlogo will try passing the variable to the procedure before actually running the procedure.
Instead, you could use the following code. With this example, you first use the "of"-primitive to extract the houses/cars variables as a list. Only then do you pass them to the "means"-procedure, which is being run by the observer.
to-report means [ param ]
report mean param
end
show means [houses] of turtles
show means [cars] of turtles

The NetLogo Way
<reporter> [ <expression> ] of <agentset>
Note: I use "agents" below, since this answer applies to any NetLogo agent, be it turtles, turtle breeds, patches, or links.
Rather than passing an agent variable (or expression) to a procedure and then somehow make the agents make a list and then act on the list, NetLogo makes it easy to first make the list from an expression evaluated individually by every agent in an agentset, so you can pass that list to some reporter. The syntax (as you know) is:
;; return list of <expression>
;; calculated by each member of agentset
[ expression ] of agentset
So, if this is your reporter:
to-report gini [ samples ]
;; samples will be sorted here, don't pre-sort!
;; best guess -- please correct if wrong
;; source:
;; https://en.wikipedia.org/wiki/Gini_coefficient#Calculation
let n length samples
let indexes (range 1 (n + 1))
let s1 2 * sum (map [[i y] -> i * y] indexes sort samples)
let s2 n * sum samples
let G (s1 / s2) - ((n + 1) / n)
report G
end
Then you might calculate the gini for your various measures like this:
print gini [ measure-1 ] of turtles
print gini [ measure-2 ] of turtles
print gini [ measure-3 ] of turtles
Which makes sense, since gini is a function that takes a set of samples. And this lets you easily use other sub-populations or breeds or whatever.
"Abbreviated" Syntax
I am about to lead you "down the garden path," so if you like what you've seen so far, you can stop here. If you want a little chuckle, read on.
Perhaps the above is just too verbose for you, and you really, really, want to get rid of "of turtles?" (even though you might later want to apply the generic function even more generically to sub-populations?)
Well, you could. We could write it using an "anonymous reporter":
print gini [-> houses ]
And then gini might look like this:
to-report gini [ sample-expression ]
let samples sort [ run-result sample-expression ] of turtles
;;; ... the rest of your gini function here
report G
end
OK, but you've embedded "of turtles" in your function. But what if later you want to evaluate this function for some sub-population or perhaps use patches instead of turtles?
You might fix that by taking the agentset as an input, as well.
to-report gini [ anon-reporter source ]
let samples [ run-result anon-reporter ] of source
;; etc
end
and then write:
print gini [-> measure-1 ] turtles
print gini [-> measure-2 ] turtles
print gini [-> measure-3 ] turtles
Ugh, a bit awkward. Let's add a little syntax candy:
to-report of_ [ agents ] report agents end
NOW we can write:
print gini [-> measure-1 ] of_ turtles
print gini [-> measure-2 ] of_ turtles
print gini [-> measure-3 ] of_ turtles
Oh, Dear. That looks rather familiar, doesn't it? But rather more verbose than when we started.
So now we are back to:
print gini [ measure-1 ] of turtles

You can use runresult, provided you are happy to pass the procedure's argument as a string:
to-report means [varname]
report mean [runresult varname] of turtles
end
Trying it in the Command Center:
observer> setup
observer> repeat 15 [go]
observer> show means "houses"
observer: 7.4

Related

Different results of reporters turtles/turtle x

I have created an opinion dynamics model, that works just fine. But now I wanted to see, how the opinion of all of my turtles changes. So I created the reporter "report [opinion] of turtles". When I put this in behaviorspace I get wildly jumping results that do not correspond with what I observe. If I test this with individual turtles like "report [opinion] of turtle 0", I get the smooth curve progression that I expected to see.
Does anyone know why this is happening? I would find it rather unwieldy, if I had to put every turtle individually in my behaviorspace, because I have sliding Agentsnumbers.
You can let each turtle have a list variable, at the beginning of which each turtle will record its ID. At every step, each turtle will append its opinion value.
Then you can have a global variable, which you will use as a list of lists, to which at the end of the simulation each turtle will append its own list.
In BheaviorSpace, you will only need to use one reporter (the list of lists) at the end of each experiment's run.
See below for a working example:
globals [
results
]
turtles-own [
opinion
my-list
]
to setup
clear-all
reset-ticks
set results (list)
create-turtles 3 [
set opinion random 10
set my-list list self opinion
]
end
to go
if (ticks = 5) [
ask turtles [
set results lput my-list results
]
stop
]
ask turtles [
set opinion opinion + 1
set my-list lput opinion my-list
]
tick
end
At the end of each run, the results reporter will look like:
[[(turtle 2) 3 4 5 6 7 8] [(turtle 0) 0 1 2 3 4 5] [(turtle 1) 5 6 7 8 9 10]]
Note that, this way, the lists in results will always be in random order.
If you're interested in having them ordered according to some criterion, you can do it.
The example below changes the if (ticks = 5) statement to order results according to turtles' ID, but you can just use sort on whatever characteristic you're interested in.
if (ticks = 5) [
let sorted-turtles sort turtles
foreach sorted-turtles [this-turtle -> ask this-turtle [set results lput my-list results]]
stop
]

NetLogo: foreach syntax

Very basic question, I can't see why my foreach code doesn't do anything (no error message but no effect whatsoever). So my turtles have a 3-dimensionnal variable (intention) that is preset to [0 0 0]. My final problem is much more complex than this, but in simple terms I am now trying to get every dimension of this vector to change to one, that is [1 1 1].
I have created a procedure called change-intention that uses foreach to produce this, to no effect:
to change-intention
ask turtles [
(foreach intention [ x -> set x 1])
]
end
I have tried this on the observer & turtle command line as well as on individual turtles' to no results nor errors..
Thanks!
Several problems. The first is that lists are not mutable - if you want to change the value in a list, you have to create a new list with that value. The second is that you can't use set to do that, you have to use replace-item.
The code is self contained - open a new model and try it out, changing the call in the testme procedure to different implementations. The procedure change-intention1 is the way you are currently thinking about it (my interpretation anyway). The procedure change-interpretation2 is the way to implement your approach, replacing each item and creating the new list (addressing the problems identified).
However, a better way to do this is with the map procedure instead of foreach because all the values are changed at once rather than looping through the list and dealing with each. Of course, that may not be so easy to implement in your real model.
turtles-own [intention]
to testme
clear-all
create-turtles 1
[ set intention [0 0 0]
]
ask turtles [ type "before call:" print intention ]
change-intention2
ask turtles [ type "after call:" print intention ]
reset-ticks
end
to change-intention1
ask turtles
[ foreach intention
[ x ->
print "here"
set intention 1
]
]
end
to change-intention2
ask turtles
[ foreach intention
[ x ->
let pp position x intention
type "here:" print pp
set intention replace-item pp intention 1
]
]
end
to change-intention3
ask turtles
[ set intention map [ x -> 1 ] intention
]
end

Is there an equivlent of python unpacking or bash's indirect parameter expansion with Netlogo?

Background
I used this answer to select a turtle based on a probability distribution determined by the turtle's popularity or fitness.
Issue
I am trying to pass a parameter that determines which of the turtle's property the probability distribution is determined by.
Question
How can I perform an equivalent of a "python unpacking" of a parameter in netlogo?
Sample code
turtles-own
[
fitness
strength
degree ;;Node's Connectness
popularity
wealth
]
to-report pick-turtle-biased-by-property [turtle-list property-to-unpack]
let prob-list []
let turtle-list []
ask turtles [
set prob-list lput [[property-to-unpack] of self ] prob-list
set turtle-list lput self turtle-list
]
report first rnd:weighted-one-of-list (map list turtle_list prob-list) last
end
The key to what you're trying to do is to use "anonymous reporters" for passing the "property to unpack". See the Anonymous procedures section of the programming guide.
Here is a full example:
extensions [ rnd ]
turtles-own [
strength
wealth
]
to setup
clear-all
create-turtles 10 [
set strength random 100
set wealth random 100
]
end
to go
print pick-turtle-biased-by-property [ -> strength ]
print pick-turtle-biased-by-property [ -> wealth ]
end
to-report pick-turtle-biased-by-property [ property-to-unpack ]
let pairs [ (list self runresult property-to-unpack) ] of turtles
report first rnd:weighted-one-of-list pairs last
end

Netlogo - Sum of lists of turtles

I would like to sum several lists of turtles. Lets call each variable turtle-list. There is only one list per variable, each list has the same number of items. If I have n turtles, I know that I can write
show (map + [turtle-list] of turtle 0 [turtle-list] of turtle 1 ... [turtle-
list] of turtle n)
Nevertheless, it may be very long and does not work if the number of turtles changes.
Is it possible to do it without writing the variable of each turtle ? Thank you for your help
I think you want to use reduce and sentence to convert a list of lists (from [turtle-list] of turtles) to a single list of values, then just sum that list:
turtles-own [ turtle-list ]
to setup
ca
crt 5 [
set turtle-list map [ i -> ( who + 1 ) * i ] [ 1 2 3 ]
]
reset-ticks
end
to sum-turtle-lists
show sum reduce sentence [turtle-list] of turtles
end
Let me know if that's not quite what you're after.
Edit:
Based on your comment, try this version:
to sum-turtle-lists
show reduce [ [ i a ] -> ( map + i a ) ] [turtle-list] of turtles
end

Logical Statement Determining if the intersection between two agentsets is empty

I have seen on here how to create an intersection or union of two agentsets, but I am trying to say if any turtle in agentset a is in agentset b, return true. I was trying
ifelse (member? (one-of my-intersections) destination-intersections)
but I am pretty sure this is just testing if one element in my-intersections is in destination -intersections instead of testing every element. Is there some way to use a for each? Or is there another functionality I am unaware of?
Again, I have already referenced
NetLogo two agentsets operations
Thank you!!
The most straightforward way to write such a test is:
to-report test [ as bs ]
report any? as with [ member? self bs ]
end
To try it:
create-turtles 5
show test (turtle-set turtle 0 turtle 1 turtle 2) (turtle-set turtle 3 turtle 4)
show test (turtle-set turtle 0 turtle 1 turtle 2) (turtle-set turtle 0 turtle 3 turtle 4)
will show:
observer: false
observer: true
It's not the most efficient way, however, because the with clause builds an intermediate agentset that's not really needed.
A faster test would be:
to-report test [ as bs ]
let result false
ask as [
if member? self bs [
set result true
stop
]
]
report result
end
Edit:
I spoke too fast. As per the NetLogo wiki page on compiler architecture, the combination of any? and with does get optimized to exit early. Bottom line: you should use the first version (i.e., any? as with [ member? self bs ]).