Accessing owned traits in netlogo with nested ask - netlogo

This is what i want to do:
patches-own[
trait1
trait2
trait3
]
let similarityCounter 0
ask one-of patches[
ask one-of neighbors[
**for-each trait[
if neighborTrait = patchTrait**[
set similarityCounter (similarityCounter + 1)
]
]
]
]
The part between ** is what I'm unsure about. How does one iterate over the patch-own parameters and compare between patch and neighbor?

How about you create a list for each patch of their trait values and count matches in the two lists? It would looks something like this.
to testme
let similarityCounter 0
ask one-of patches
[ let mytraits (list trait1 trait2 trait3)
let theirtraits [(list trait1 trait2 trait3)] of one-of neighbors
set similarityCounter length filter [ xx -> xx ] (map = mytraits theirtraits)
]
end
The final line is a little dense. What it does is compare the two lists of traits using the map function with the = operator, which will return a list of true and false values indicating whether that specific trait matches. The filter then creates a list of just the true values and the length counts the number of those true values.
Unfortunately, NetLogo doesn't do the trick of treating a true as 1 and false as 0 that you see in some languages, so you can't simply sum the match results list.

I really like Jen's answer, but just for fun, I'd like to provide an alternative way to approach the problem that uses Jen's idea of treating true as 1 and false as 0.
But first, I think that, depending on the rest of your model, it could have been a good idea for you to store your traits directly in a list instead of separate variables. In programming, having variable names with a numeric suffix like trait1, trait2, etc. is usually a hint that a list should be used instead.
Nevertheless, we will leave your general design alone for now and just provide a small function that makes it easy to package your traits into a list:
to-report traits ; patch reporter
report (list trait1 trait2 trait3)
end
Once you have that, you can write something like [ traits ] of one-of patches to get a list of the patche's traits.
Now let's attack the problem of turning true and false into ones and zeros in a similar way. It's true that NetLogo doesn't provide that conversation automatically (which I think is a good thing) but it's easy to write our own function for that:
to-report bool-to-int [ yes? ]
report ifelse-value yes? [ 1 ] [ 0 ]
end
We are now ready to write our main function. We will use Jen's approach of mapping over the = operator to convert our lists of traits to a list of boolean (i.e., true/false) values, and we will then use map again to convert that list into a list of 1 and 0. Once we have that, all that is left is to sum it! Here we go:
to-report similarity-with [ other-patch ] ; patch reporter
report sum map bool-to-int (map = traits [ traits ] of other-patch)
end
Having that reporter makes it really easy to get the similarity between two patches. You can now say things like:
print [ similarity-with one-of neighbors ] of one-of patches
Notice how I have approached the problem by building small pieces that be combined together. I really like this way of proceeding: it allows me to concentrate on one part of the problem at a time, but it's also more easy to test and results in code that I find very readable. NetLogo's to-report procedures are a great tool to achieve that kind of modularity.

Related

Supply argument to reporter

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

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

Netlogo: How to compute sum of items of lists within a list?

I would like to make the sum = the total of pollen recieved by a plant from other plants (Donnors) which is stored in a list of a list (own by each turtle = plant).
The following code make an error (when computing the sum):
OF expected input to be an agent or agentset but got the list
[[119.05593 50 50] [301.25853 50 50] [30.23906 50 50] [460.525845 50
50] [55.16717 50 50] [301.25853 50 50]] instead.
Does any one could help me about the mistake in the line "set Tot_pol sum ..." ?
Many thanks for your help.
to check-pol [m] ;; we check the pollen recieved by the two morphs
set Donnors [] ;; empty list of pollen donnors
ask zsps with [morph = m] ;; morph of the pollen reciever
[
set totpol 0
;; check for pollen donnors and morph for compatiblity within a radius :
ask zsps with[distance myself <= 20 and morph != m]
[
set totpol (NMaleFlowers * 100 * item round (distance myself) pollination-list) ;; the farther the less pollen
set Donnors lput [ (list totpol NMaleFlowers NFemFlowers)] of myself Donnors
]
set Tot_pol sum [ item (position 0 Donnors) Donnors ] of Donnors ;; total of pollen recieved
]
end
Luke's answer is good and should fix your problem. I suspect, however, that you are going to be doing lots of these types of sums. You may wish to set up a to-report that you can use for whichever item you want to sum over, just by passing the item number and the name of the list of lists. It would look like this:
to-report sum-item [#pos #listoflists ]
let items map [ x -> item #pos x ] #listoflists
report reduce [ [a b] -> a + b] items
end
The first line extracts the relevant item (remember index from 0) into a new list which the second line sums.
You would then use it with set Tot_pol sum-item 0 Donnors
Here's an answer that is not actually responding to your question. Instead, it is a more NetLogo-ish way of doing what I think you are trying to do with your code.
to check-pol [m]
ask zsps with [morph = m]
[ let senders zsps with [distance myself <= 20 and morph != m]
set totpol sum [NMaleFlowers * 100 * round (distance myself)] of senders
]
end
Your code gets into levels of ask that I think are unnecessary. What I think you are doing with your list is keeping track of the pollen donors. But an agentset is a cleaner approach and then you can simply pull out the information you want from the agentset using of.
Further, when you ask zsps with[distance myself <= 20 and morph != m] to set variable values in your code, then THOSE agents (not the receiving agent) are the ones having their variables changed. I think you are trying to take the perspective of the receiver of pollen, who looks around and received pollen from the other agents that are close enough. So the receiving agent should have the value changed.
This is not tested.
I'm not 100% sure what you're after here (you may want to look at the Minimum, Complete, and Verifiable Example guidelines), but if I'm reading you right you want the sum of the first item for each entry in the Donners list.
As to why your approach didn't work- NetLogo is telling you with that error that you've used of with a list, but of only works with agents or agentsets. Instead, you have to use a list processing approach. The simplest way might be to use sum in conjunction with map first in order to get what you need:
to sum-first-item
let example-list [ [ 1 2 3 ] [ 4 5 6 ] [ 7 8 9 ] ]
let sum-of-firsts sum map first example-list
print sum-of-firsts
end
To translate to Donnors, try:
set Tot_pol sum map first Donnors
That should work, but without reproducible a code example I can't check.

How to compare two turtles in Netlogo by going through a list of their attributes?

My turtles have more than 30 attributes of boolean values and I would like to use a foreach loop to compare turtles and rank them based on their similarity without the need to compare each attribute individually. I might be missing an obvious point here, I have tried having a list of attributes, but it didn't work and all turtles got the maximum similarity score.
Here's some code that calculates the Hamming distance between two lists. Note that the very clever reduce code is taken directly from the NetLogo dictionary.
to testme
let ll1 (list TRUE TRUE FALSE FALSE)
let ll2 (list TRUE FALSE TRUE FALSE)
let ll3 ( map = ll2 ll1 )
show ll3
show reduce [ [occurrence-count next-item] ->
ifelse-value (next-item) [occurrence-count + 1] [occurrence-count] ] (fput 0 ll3)
end
If you were wanting to calculate the similarity score of a pair of turtles, you could turn this into a reporter that takes the two turtles as arguments. But it's not clear that comparing two turtles is what you want to do, so I haven't written code for that.

Roulette Wheel Selection in Netlogo using Agent Variables, not Constants

I hope this is a simple solution, but I'm having a difficult time with it.
Problem:
I would like to weight the probability of something occurring by an variable not a constant
Setup
My agent is a farm.
Farms own four variables that represent the
number of cows, goats, pigs, and sheep on it.
When a farm wants to
remove an animal, I'd like the likelihood to remove a member of a
particular species to be directly proportional to quantity of each
species on the farm (i.e. if there are 7 goats, 2 cows, and 1 pig,
there is a 70% probability of taking a goat and a zero percent
probability of taking a sheep)
I have found formula like this for when you know the exact numerical weight that each value will have:
to-report random-weighted [values weights]
let selector (random-float sum weights)
let running-sum 0
(foreach values weights [
set running-sum (running-sum + ?2) ; Random-Weighted Created by NickBenn
if (running-sum > selector) [
report ?1
]
])
end
and the methods described in the rnd extension. But both of these throw the "expected a constant" error when i put "Cow" in instead of a constant.
Something like:
to example1
let values ["Cow" "Sheep" "Goat" "Pig"]
let probabilities [2 0 7 1]
let indices n-values length values [ ? ] ; Made by Nicolas Payette
let index rnd:weighted-one-of indices [ item ? probabilities ]
let loca item index values
end
works well, but if I were to replace it with:
to example1
let values ["Cow" "Sheep" "Goat" "Pig"]
let probabilities [Num-Cows Num-Sheep Num-Goats Num-Pigs]
let indices n-values length values [ ? ] ; Made by Nicolas Payette
let index rnd:weighted-one-of indices [ item ? probabilities ]
let loca item index values
end
it fails.
Alan is right: you need to use the list primitive (as opposed to just brackets) when you want to construct a list from anything else than constants.
I would add two things to that:
The latest version of the rnd extension has two sets of primitives: one for agentsets, and one for lists. So you should probably update and use the rnd:weighted-one-of-list primitive.
Your code is based around using indices to pick an item. That's fine, but that's not the only way to do it.
You could also have something like:
to example1
let values ["Cow" "Sheep" "Goat" "Pig"]
let probabilities (list Num-Cows Num-Sheep Num-Goats Num-Pigs)
let loca first rnd:weighted-one-of-list (map list values probabilities) last
end
This may be a bit trickier to understand, but here is the gist of it:
The (map list values probabilities) expression takes both your values list and your probabilities list and "zips" them together using the list primitive, resulting in a list of pairs: [["Cow" 2] ["Sheep" 0] ["Goat" 7] ["Pig" 1]].
We pass the last reporter to the rnd:weighted-one-of-list primitive to tell it that the last (i.e., second) item of each of these pairs should be used as the probability.
Since rnd:weighted-one-of-list operates on a list of pairs, the item it returns will be a pair (e.g., ["Goat" 7]). We are only interested in the first item of the pair, so we extract it with the first reporter.
Note that we use the NetLogo's concise syntax for tasks when passing list as an argument to map and last as an argument to rnd:weighted-n-of. You could replace list with [ (list ?1 ?2) ] and last with [ last ? ], but it would be uglier.