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
Related
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
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
]
I would like to call a function within a function in netlogo and both functions take a number of arguments, how can I do that? before I even try runresult (from previous answers), the code syntax is giving me many errors.
Essentially, what the code is doing is driving a forward reaction: species1 + species 2 -> species 3 by doing the following:
asking species1 to scan the perimeter for species2, and if found, based on a an onrat (k-on) multiplied by a factor (alpha), make species 2 die and set the breed of species1 to species3. Now, second function (set-attributes2) will be called tos et certain attributes of the new species3, which takes many arguments too. How do I:
call a function2 (set-attributes2) within a function1(fwd-reaction)
pass arguments of function2 (for example )when doing the above?
to set-attributes2 [ x-occupiedepitopes x-size x-leader x-exempt_from_immobilisation x-aggregated x-color]
set occupiedepitopes x-occupiedepitopes
set size x-size
set leader x-leader
set aggregated x-aggregated
set exempt_from_immobilisation x-exempt_from_immobilisation
set color x-color
end
to fwd-reaction [#asking-species #species-to-scan #x-k_on #x-alpha #species-to-die #new-breed]
;let temp-list []
;set temp-list (list asking-species species-to-scan x-k_on x-alpha species-to-die new-breed )
let scanning #species-to-scan
ask #asking-species [
if (any? other (#species-to-scan) -here) and random-float 1000 < (#x-k_on * 2 * #x-alpha)
[
ask one-of other #species-to-die -here
[ die ]
set breed #new-breed
set-attributes2 0 2 self true false red
]
]
end
Right now, the error says I am missing a paranthesis after -here in this line of code:
if (any? other (#species-to-scan) -here) and random-float 1000 < (#x-k_on * 2 * #x-alpha)
I downloaded the modified random clusters code for generating neutral landscape models using the Millington's version of the modified random clusters approach in the NetLogo modeling commons. When I click the "generate-landscape" button, the "fill-landscape" procedure in the code causes a "Nothing named ? has been defined" error.
When I created the attached interface image and attempted to run the adjoining code below. The problem seems to be related to the question mark in the "occurrences" report function. The reduce function is not working as intended. Is there a work around for this? See interface, then code below:
ifelse ( any? neighbours with [ cluster != nobody ] ) ;; check if there are any assigned patches in neighbourhood
[
let covers []
ask neighbours with [ cluster != nobody ]
[
set covers fput cover covers ;;ask neighbours to add their covers to the list
]
let unique-covers remove-duplicates covers ;;create a list of unique covers
let max-cover-count -1 ;the number of neighbours with the maximum cover
let max-cover -1 ;the maximum cover
ifelse(length unique-covers > 1)
[
;if there is more than one unique-cover
foreach unique-covers ;for each of the unique covers
[
let occ occurrences ? covers ;count how many neighbours had this cover
ifelse(occ > max-cover-count) ;if the count is greater than the current maximum count
[
set max-cover ? ;set this as the dominant cover
set max-cover-count occ ;update the current maximum count
;---------------
to-report occurrences [x the-list]
report reduce
[ifelse-value (?2 = x) [?1 + 1] [?1]] (fput 0 the-list)
end
;---------------
The code is suppose to generate a neutral landscape model using the modified random clusters approach developed by Saura and Martinez-Millan (2000). However, the error "Nothing named ? has been defined" error the code from running smoothly. Looking forward to thoughts ...
The old ? syntax from NetLogo 5.x was replaced with the new -> syntax in NetLogo 6. See https://ccl.northwestern.edu/netlogo/docs/programming.html#anonymous-procedures
So, for example, in NetLogo 5, you would write:
foreach [0 1 2 3] [
print ?
]
in NetLogo 6, you write:
foreach [0 1 2 3] [ x ->
print x
]
A combination of Bryan's answer (first procedure) and the NetLogo Dictionary (second procedure) gives you the following. The comments indicate the new bits. Not tested.
ifelse ( any? neighbours with [ cluster != nobody ] )
[ let covers []
ask neighbours with [ cluster != nobody ]
[ set covers fput cover covers
]
let unique-covers remove-duplicates covers
let max-cover-count - 1 ; added a space around subtraction
let max-cover - 1 ; more spacing
ifelse(length unique-covers > 1)
[ foreach unique-covers
[ this-cover -> ; here's the new bit, calling ? 'this-cover'
let occ occurrences this-cover covers ; passes to the occurrences procedure
ifelse(occ > max-cover-count)
[ set max-cover this-cover ; using the name this-cover again
set max-cover-count occ
And for occurrences, you can take the procedure directly from the NetLogo Dictionary reduce example
to-report occurrences [#x #the-list]
report reduce
[ [occurrence-count next-item] -> ifelse-value (next-item = #x)
[occurrence-count + 1] [occurrence-count] ] (fput 0 #the-list)
end
I'm trying to have turtles match based on attraction parameters, however I only get either one match or one mismatch and won't count anymore turtles matching, as well as not moving the counter forward.
to new-couple
set countdown2 5
ask turtles [
;; CREATE NEW COUPLE
ifelse countdown2 <= 0
[ die ]
[ set countdown2 countdown2 - 1 ] ]
end
The code that you have provided does not have an error. Try this version of it and you will see that the new-couple code correctly reduces the countdown 5 times and then kills the rest of the turtles. So it's not producing the problem that you describe of things only happening once.
to testme
clear-all
create-turtles 10
type "Start turtles: " print count turtles
new-couple
type "End turtles: " print count turtles
end
to new-couple
let countdown2 5
ask turtles [
;; CREATE NEW COUPLE
ifelse countdown2 <= 0
[ die ]
[ set countdown2 countdown2 - 1 ] ]
end
Could you please provide more of your code. Also, an explanation of what the countdown is supposed to achieve could be useful. At the moment it basically selects the number of turtles that don't die and there are easier ways to achieve that.