How to find the largest network cluster? - netlogo

"nw:weak-component-clusters" in the Networks extension will return a list of weakly connected agentsets. I would like to output the number of turtles in the biggest of these.
So
show nw:weak-component-clusters
observer: [(agentset, 15 turtles) (agentset, 20 turtles) (agentset, 16 turtles)]
would return 20.
Is there an easy way to do this please?

This isn't pretty but it will work:
to find_max
let my_list []
let my_max 0
let turt_list nw:weak-component-clusters
foreach turt_list [x -> ask x [set my_list lput count x my_list]]
set my_max max my_list
show my_max
end

There is a simpler approach using map:
to-report count-of-largest-cluster
report max (map count nw:weak-component-clusters)
end
map takes a reporter and a list as inputs, and reports a list whose items are the result of the input reporter being run for every item of the input list.
nw:weak-component-clusters is a list of agentsets, therefore map count nw:weak-component-clusters is a list of each agentset's count. Note that the parentheses in my solution are optional and only there for readability.

Related

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.

subsetting agentsets transforming a list of agents into an agentset

A toy example. There are two groups of people: A and B. Only A can say "hello" to people B. People walk around the world and meet each other. When people A meet people B, they say hello to them. Each person A record who was said hello to and the tick when that occurred. They cannot say hello to the same person until five new ticks happen. The procedures below only apply to people A.
Each time a person A say hello to a person B I define:
set tick-last-greeting lput ticks tick-last-greeting
set previous-person-b-greeted lput selected-person-b previous-person-b-greeted
Before the say-hello procedure happens again:
if (length tick-last-greeting != [] and previous-person-b-greeted != []) [
; wait 5 ticks
set temp (map [ticks - ? > 5] tick-last-greeting)
; filter the list, I don't know if there is a better way to do this
set previous-person-b-greeted (map last filter [first ? = false] (map list temp previous-person-b-greeted))
set tick-last-greeting (map last filter [first ? = false] (map list temp tick-last-greeting))
]
So, I get a list of people B that shouldn't be greeted by a person A but until five ticks happen. Here is my key problem: how to define an agentset that excludes the agents of the list previous-person-b-greeted.
set potential-persons-b targets-on (patch-set neighbors patch-here)
if (previous-person-b-greeted > 0) [
; Here, I get an error as expected
let who-previous-person-b [who] of previous-person-b-greeted
set potential-persons potential-persons with [who != who-previous-person-b]
]
A possible solution: transform the list previous-person-b-greeted into an agentset (I don't know if there is simple way to do this).
Any ideas?
To transform a list of agents into an agentset, use turtle-set or patch-set or link-set. So e.g.:
observer> create-turtles 5
observer> let mylist (list turtle 0 turtle 2 turtle 4) print turtle-set mylist
(agentset, 3 turtles)
I will assume that you're not using specific breeds for people A or people B.
Perhaps you could try using breeds, for example:
breed [personA peopleA]
breed [personB peopleB]
Will define 2 different agentsets and then you can use the <breeds>-own statement to define a list of recently greeted people.
peopleA-own [recently-greeted-people recently-greeted-people-time]
And then everytime that a personA has to greet someone your procedure could look like this:
to greet [personB-who]
if (not (and (member? personB-who recently-greeted-people)
(procedure-that-checks-ticks-less-than-5))
...ADD HERE OTHER LOGICAL CHECKS DEPENDING ON YOUR PROBLEM
)
[
fput personB-who recently-greeted-people
fput current-tick recently-greeted-people-time
]
end
Observe that for every personB greeted, the who and the id are added to different lists and then they must be removed at the same time to keep consistence.
You can read more about breeds in the NLogo dictionary.
Finally, following your suggestions, I ended up with this solution:
set potential-persons-b sort (targets-on (patch-set neighbors patch-here))
if (previous-person-b-greeted != [])
[
foreach previous-victimized-target
[ set potential-persons-b remove ? potential-persons-b]
set potential-persons-b turtle-set potential-persons-b
]
Here a more general solution using to-report:
to-report subsetting-agents [agent-set1 agent-set2]
set agent-set1 sort agent-set1
set agent-set2 sort agent-set2
foreach agent-set2
[ set agent-set1 remove ? agent-set1]
set agent-set1 turtle-set agent-set1
report agent-set1
end

Subtracting element of ith position from element at (i + 1)th position of any list in netlogo

I want to create a list of count values of some variable (tot-turtles) increasing with each tick. I tried the below code but all time list is having single element of length 1. neither i is getting incremented. please correct me.
set tot-turtles count turtles
to go
let mylist [ ]
set mylist lput tot-turtles mylist ; show mylist
set i 1
foreach mylist [ ; print ? ;show i
set x ? - i ; print x
set i (i + 1) ;show i
]
end
I want to subtract elements of list in the following fashion where the length of list depends on the number of simulation run or till simulation ends, then
i need subtraction of element as element at (i + 1)th - element at ith position till the end of the list.
In the above code i is 1 then increments by 1 ie 2 and then continue to 1 2 1 2 1 2. mylsit always shows single element. Confused with "?" , it gives element of current position if i am not wrong, but how we know the current position?
Please help me out of these doubts and code. thanks a lot.
Thank you sir, yes i was doing mistake with local and global variable i checkd it later. and the thing i wanted is as below.
to setup
set mylist [ 0]
set item-difference 0
end
to go
set tot-turtles count tutles set
mylist lput tot-turtles mylist
let _n (length mylist)
set item-difference (( item ( _n - 1 ) mylist - item ( _n - 2 ) mylist )
end
I hope you got Allan sir.
It's a bit difficult to tell what you are after, but it seems you are using a local variable when you want a global variable. See if this offers some help:
globals [mylist]
to setup
ca
set mylist []
crt 10
end
to go
crt 1
set mylist lput (count turtles) mylist ; show mylist
end
to test
let _n (length mylist)
(foreach mylist n-values _n [? + 1] [
print ?1 - ?2
])
end