How to retrieve multiple variables from NetLogo agentsets in the same (not random) order? - netlogo

I have a NetLogo model in which agents retrieve multiple lists of variables from other agents. The order in which these lists are returned is crucial, because variables in each list are associated with each other. However, I believe lists are returned from other agents in a random order each time. For example, take the following simplified test case:
turtles-own [testlist1 testlist2 testlist3 testlist4]
to setup
random-seed 1
clear-all
create-turtles 5
ask turtles [
create-links-with other turtles
set testlist1 []
set testlist2 []
set testlist3 []
set testlist4 []
set testlist1 lput [who] of self testlist1
set testlist2 lput [who] of self testlist2] ;identical to testlist1
end
to go
ask turtles[
set testlist3 reduce sentence [testlist1] of link-neighbors
show testlist3
set testlist4 reduce sentence [testlist2] of link-neighbors
show testlist4]
end
For my use case, values in testlist3 and testlist4 should be in the same order, but their orders differ at random. Output:
(turtle 2): [0 3 1 4]
(turtle 2): [3 4 1 0]
(turtle 3): [4 1 0 2]
(turtle 3): [1 0 2 4]
(turtle 0): [4 2 3 1]
(turtle 0): [3 4 2 1]
(turtle 1): [0 4 2 3]
(turtle 1): [4 2 3 0]
(turtle 4): [0 2 1 3]
(turtle 4): [0 3 2 1]
My question: What is the best way to return multiple lists (such as testlist and testlist2 above) from an agent-set in the same order in a given procedure?
Replacing link-neighbors with turtle-set sort link-neighbors doesn't work, because after converting the sorted list back to an agent-set, the agents in the agent-set are called in a random order. If at all possible, I'd prefer not to have to refactor the entire model from lists to matrices using the matrix extension.

You were on the right track with the idea of turning your agentset to a list. The only part missing was using map instead of turning it back into a turtle set and then using of again:
to go
ask turtles[
set testlist3 reduce sentence map [ t -> [ testlist1 ] of t ] sort link-neighbors
show testlist3
set testlist4 reduce sentence map [ t -> [ testlist2 ] of t ] sort link-neighbors
show testlist4
]
end
See this answer for a bit more detail about the parallel between list operations and agentset operations.

Related

How to speed up the creation of turtles by classes of a map using NetLogo 6.2?

I have a problem with accelerating a code in NetLogo. I tried a few things and they didn't work. The problem is in the "setup-patches" procedure that refers to the creation of turtles (please, see the code).
I have a map (I use the GIS extension, but to be a replicable example I didn't use it here) with 7 classes (which in the code is called habitatcover). 6 habitatcover have vegetation and therefore is used by turtles (mobile agent) and 1 class has no vegetation and therefore is not used by turtles (habitatcover 7). Turtles can born in the 6 types of habitatcover that have vegetation and their combinations result in 63 items (please, see the variable in the code called ValidHabs).
Also, I have 3 types of metabolism and 3 types of reproduction, which results in 9 combinations, that is, 9 types of turtles.
For each ValidHabs item (which has a total of 63 items) 50 individuals of each of the 9 types of turtles are born. Therefore, for item 0 of ValidHabs which is [1] 450 individuals will be born (= 9 * 50) it executes all the procedures and goes to the next item in the ValidHabs list until it goes through all the items in this list.
The problem is that as the world is 1000x1000 and 450 turtles are born per list item (which has 63 items in total), using GIS, as well, I have several maps to perform these procedures, in addition to having minimum 15 repetitions per map (using BehaviourSpace) takes a lot of time do execute one map (almost 5 days per map). I've already tried to make modifications to speed it up and haven't had much success. I know the problem is in the "setup-patches" procedure, but I'm not quite sure how to solve it. Can anybody help me?
Thanks in advance!
The code below:
globals
[
RandomSeeds
HotPatchSet
ValidHabs
ValidHabsItem
CurrentHotPatchSet
]
turtles-own
[
turtle-profiles-habitat
energy-reproduction
turtle-metabolism
turtle-profiles-code
turtle-profiles-reproduction-code
turtle-profiles-metabolism-code
turtle-profiles-habitat-code
]
patches-own
[
habitatcover
]
to setup
clear-all
set RandomSeeds 1
random-seed RandomSeeds
resize-world 999 * 0 ( 999 * 1 ) ( 999 * -1 ) 999 * 0 ;; defines the edge size of the world and location of origin: corner top left. The world is 1000x1000
read-legal-habs ;; create list of valid habitats for each turtle profile
set ValidHabsItem 0
setup-layers
setup-patches
reset-ticks
end
to read-legal-habs ;; create list of valid habitats for each turtle profile
set ValidHabs [[1] [2] [3] [4] [5] [6] [1 2] [1 3] [1 4] [1 5] [1 6] [2 3] [2 4] [2 5] [2 6] [3 4] [3 5] [3 6] [4 5] [4 6] [5 6] [1 2 3] [1 2 4] [1 2 5] [1 2 6] [1 3 4] [1 3 5] [1 3 6] [1 4 5] [1 4 6] [1 5 6] [2 3 4] [2 3 5] [2 3 6] [2 4 5] [2 4 6] [2 5 6] [3 4 5] [3 4 6] [3 5 6] [4 5 6] [1 2 3 4] [1 2 3 5] [1 2 3 6] [1 2 4 5] [1 2 4 6] [1 2 5 6] [1 3 4 5] [1 3 4 6] [1 3 5 6] [1 4 5 6] [2 3 4 5] [2 3 4 6] [2 3 5 6] [2 4 5 6] [3 4 5 6] [1 2 3 4 5] [1 2 3 4 6] [1 2 3 5 6] [1 2 4 5 6] [1 3 4 5 6] [2 3 4 5 6] [1 2 3 4 5 6]]
end
to setup-layers ;; the original code I use GIS. And depending on how the class distributions (habitatcover) are on the map, it takes longer to create the turtles
let pcolors [ ]
set pcolors [ 25 65 23 53 105 10 2 ]
ask patches
[
set pcolor item ( random 7 ) pcolors
]
ask patches
[
if pcolor = 25 [ set habitatcover 1 ]
if pcolor = 65 [ set habitatcover 2 ]
if pcolor = 23 [ set habitatcover 3 ]
if pcolor = 53 [ set habitatcover 4 ]
if pcolor = 105 [ set habitatcover 5 ]
if pcolor = 10 [ set habitatcover 6 ]
if pcolor = 2 [ set habitatcover 7 ]
]
end
to setup-patches
let list1 ( list 2 4 8 ) ;; metabolism types
let list2 ( list 10 15 20 ) ;; reproduction types
let n0 count turtles
set HotPatchSet patches with [ ( habitatcover != 7 ) ] ;; referring to all 6 habitatcovers that have some type of vegetation removing habitatcover 7 that has no vegetation
set CurrentHotPatchSet HotPatchSet with [ habitatcover = one-of item ValidHabsItem ValidHabs ] ;; CurrentHotPatchSet will be the HotPatchSet with the current habitatcover ;; ValidHabsItem is the item that goes from 0 to 62 since there are 63 habitacover combinations (see the list ValidHabs has 63 items)
let s ( length list1 ) * ( length list2 ) * 50 ;; 50 individuals per profile = 3 * 3 * 50 = 450 turtles
while [ n0 < s ]
[
(
foreach list1
[
this-metabolism ->
foreach list2
[
this-reproduction ->
let c count CurrentHotPatchSet
if c = 0 [ stop ]
ask one-of CurrentHotPatchSet
[
sprout 1
[
set turtle-profiles-habitat item ValidHabsItem ValidHabs ;; I need the ValidHabsItem and turtle-profiles-habitat, because in the "go" procedure I'm calling each item (ValidHabsItem) from the ValidHabs list to execute all the procedures
set turtle-metabolism this-metabolism
set energy-reproduction this-reproduction
setup-turtles
]
set CurrentHotPatchSet CurrentHotPatchSet with [ not any? turtles in-radius 3 ] ;; each turtle must be a minimum distance of 3 patches and can't have more than one turtle in each patch
]
]
]
)
set n0 count turtles
]
end
to setup-turtles
set turtle-profiles-habitat-code reduce_list turtle-profiles-habitat
(
ifelse
turtle-metabolism = 2 [ set turtle-profiles-metabolism-code "_M1" ]
turtle-metabolism = 4 [ set turtle-profiles-metabolism-code "_M2" ]
turtle-metabolism = 6 [ set turtle-profiles-metabolism-code "_M3" ]
)
(
ifelse
energy-reproduction = 5 [ set turtle-profiles-reproduction-code "_R1" ]
energy-reproduction = 10 [ set turtle-profiles-reproduction-code "_R2" ]
energy-reproduction = 15 [ set turtle-profiles-reproduction-code "_R3" ]
)
set turtle-profiles-code ( word turtle-profiles-habitat-code turtle-profiles-reproduction-code turtle-profiles-metabolism-code )
end
to-report reduce_list [ a_list ]
report read-from-string word reduce word a_list ""
end
Opening note: In no way I am assuming that my suggestions are exhaustive, as other people might see other things to improve.
I intend this question to be exclusively on code, i.e. assuming that it is not addressing non-code options such as computer cluster etc.
Eliminate the time needed to upload GIS data
Importing GIS data in NetLogo is a lengthy process. You can get rid of this process by using export-world and import-world (see here and here). These commands will let you export to a file the current state of your NetLogo world, and then import into NetLogo that state from the file. You can perform the export once when the GIS data has been loaded (so that the GIS information is stored in patches) and store the file somewhere: this means that you won't need to upload GIS data again but will only need to perform import-world.
My personal suggestion is that you create a separate NetLogo file to do this: only in this separate file you will have the GIS extension's procedures and the export-world command. In the file with your main model, you will only have the import-world part.
Of course you will need to create a new/different file for each new/different set of GIS files you use.
Reduce the amount of times you need to perform import-world
Your model is quite big, so it might be the case that import-world too takes some time. You can adjust your code such that, when using BeahviorSpace, you will only have to run import-world once.
See here for some previous discussion.
The idea is that in your setup, instead of using clear-all (which would also clear all of that imported data which is stored inside patches), you manually clear everything apart from patches (i.e. you use clear-globals, clear-ticks, clear-turtles, clear-drawing, clear-all-plots and clear-output). This will allow you to check if the data has already been imported: if not, then it means that this is the first run and you need to use import-world; if yes, it means that patches already have that information stored and thus import-world needs not to be performed.
I don't know if in your model the patch variables coming from GIS (i.e. coming from import-world) might be changed during the simulation. If this is the case, it means that you need to store the initial state of these variables as a special patch variable, which will be used to reset the initial state when you do not use import-world.
Some code will make all of this clearer. For example, in case the GIS information imported through import-world is stored as a vegetation patch variable, you can create an initial-vegetation variable for this purpose:
patches-own [
initial-vegetation
vegetation
]
to setup
clear-globals
clear-ticks
clear-turtles
clear-drawing
clear-all-plots
clear-output
ifelse (all? patches [initial-vegetation = 0])
[import-world "initial-state.csv"]
[ask patches [set vegetation initial-vegetation]]
end
Otherwise, if in your model the variable of interest can never be changed (following my example: if vegetation never changes during the simulation...) things are even simpler:
patches-own [
vegetation
]
to setup
clear-globals
clear-ticks
clear-turtles
clear-drawing
clear-all-plots
clear-output
ifelse (all? patches [initial-vegetation = 0])
[import-world "initial-state.csv"]
[]
end
Looking at your setup-patches procedure, I don't see any code that is obviously inefficient.
(probably set n0 n0 + 1 would be faster than set n0 count turtles - but this is just for the sake of noting it, as it surely has a negligible effect).
Possible unintended aspects in your code? (1)
ValidHabsItem is used twice but it is never set to anything different than zero. In setup there is set ValidHabsItem 0 (anyway note that this is superflous, as zero is the default value), and the value of ValidHabsItem is never changed. I don't know if this is used in some other way in the full version of your code (e.g. if the value of ValidHabsItem iterates from 0 to 62) but note that, looking exclusively at the code in your question, this means that item ValidHabsItem ValidHabs is always [1]. Which in turn, looking at the two instances where you use it in setup-patches, means that:
The statement:
set CurrentHotPatchSet HotPatchSet with [habitatcover = one-of item ValidHabsItem ValidHabs]
is equivalent to:
set CurrentHotPatchSet HotPatchSet with [habitatcover = 1]
The statement:
set turtle-profiles-habitat item ValidHabsItem ValidHabs
is equivalent to:
set turtle-profiles-habitat [1]
Overall this means that, by using the code in your question, turtles will only be born on orange patches (those with habitatcover = 1) and they will only have turtle-profiles-habitat = [1]. Is this intended? Is it not? I am not sure, but it looks peculiar enough for me to point it out.
Possible unintended aspects in your code? (2)
Let's imagine that ValidHabsItem is not constantly 0 but it goes from 0 to 62, with the effect that item ValidHabsItem ValidHabs is always a different list containing a varying number of numbers.
What do you want your code to do when you write:
set CurrentHotPatchSet HotPatchSet with [habitatcover = one-of item ValidHabsItem ValidHabs]
?
If you want to check that habitatcover of patches is one of the values in the current list of habitats, then this is not what your code is doing.
Let's take an example: the current list being represented by item ValidHabsItem ValidHabs is [2 4 5].
The one-of item ValidHabsItem ValidHabs statement is literally one of [2 4 5]. Given that one-of is a random reporter, let's say that in this occasion it extracts the value of 4. This means that your:
set CurrentHotPatchSet HotPatchSet with [habitatcover = one-of item ValidHabsItem ValidHabs]
is
set CurrentHotPatchSet HotPatchSet with [habitatcover = 4]
even if item ValidHabsItem ValidHabs = [2 4 5]; with the result that all patches having habitatcover = 2 or habitatcover = 5 will be excluded.
If it is correct to say that this is not what you wanted, it means that what you are looking for is the member? reporter (see here):
set CurrentHotPatchSet HotPatchSet with [member? (habitatcover) (item ValidHabsItem ValidHabs)]
In the example where item ValidHabsItem ValidHabs = [2 4 5], the code above will set CurrentHotPatchSet as every patch having habitatcover as either 2, 4 or 5.

How to extend neighbor function to 24 using code from Moore and Von Nuemman example

I am learning how to use net logo and one of the things I am trying to do is to create a larger neighborhood then the built in 8 that comes with the agent set "neighbor".
I want to use this extended neighborhood to run Conway's Game of Life with more neighbors.
I have used the built in function from the Game of Life available in the netlogo's model library.
to go
let neighbors24 [list pxcor pycor] of patches with [abs pxcor <= 2 and abs pycor <= 2]
ask patches
[ set live-neighbors count neighbors24 with [living?] ]
;; Starting a new "ask patches" here ensures that all the patches
;; finish executing the first ask before any of them start executing
;; the second ask. This keeps all the patches in synch with each other,
;; so the births and deaths at each generation all happen in lockstep.
ask patches
[ ifelse live-neighbors = 3
[ cell-birth ]
[ if live-neighbors != 2
[ cell-death ] ] ]
tick
end
I expect neighbors24 to increase the number of neighboring cells from 8 to 24, instead I am met with the following error.
"WITH expected input to be an agentset but got the list [[-2 -1] [0 0] [2 2] [-2 2] [-1 1] [2 -2] [0 2] [-1 -1] [-2 1] [-1 -2] [2 1] [1 0] [-1 0] [-1 2] [1 -1] [0 -1] [-2 0] [0 -2] [1 2] [-2 -2] [1 -2] [0 1] [2 0] [2 -1] [1 1]] instead."
NetLogo should tell you which line is giving you the error. Please include that in your future questions.
In this case, the error is (presumably) the line set live-neighbors count neighbors24 with [living?]. Your problem is that with selects those agents in the specified agentset that meet a condition. So patches with [pcolor = yellow] would get the yellow patches. However, neighbors24 is not an agentset, it's a list of patch coordinates.
It is a common NetLogo novice mistake to create lists, particularly if you have experience with other programming languages. If you are creating lists of agent identifiers (eg coordinates for patches, or who numbers for turtles) you almost certainly want an agentset instead.
The modified line let neighbors24 patches with [abs pxcor <= 2 and abs pycor <= 2] will create neighbors24 as an agentset.

How to store different list values for different turtles

Edited:
Each turtle has different values depending on its connections, I have several lists for different purposes. one of those lists seems to be stored once for all the turtles. My question is, how can I store values that are only related to each turtle in its list and not mix up all the values in one list.
I am getting something like this as a result:
(turtle 0): [3.1198376765467213 2.296024229601798 3.42548843517858 -1.259846009171373 -0.7503525744180024 0.8329075988682271 2.5179361772122446 2.499561039717374]
(turtle 1): [3.1198376765467213 2.296024229601798 3.42548843517858 -1.259846009171373 -0.7503525744180024 0.8329075988682271 2.5179361772122446 2.499561039717374]
(turtle 2): [3.1198376765467213 2.296024229601798 3.42548843517858 -1.259846009171373 -0.7503525744180024 0.8329075988682271 2.5179361772122446 2.499561039717374]
(turtle 3): [3.1198376765467213 2.296024229601798 3.42548843517858 -1.259846009171373 -0.7503525744180024 0.8329075988682271 2.5179361772122446 2.499561039717374]
when in fact the result should be like this
(turtle 0): [3.1198376765467213 2.296024229601798]
(turtle 1): [3.42548843517858 -1.259846009171373]
(turtle 2): [-0.7503525744180024 0.8329075988682271]
(turtle 3): [2.5179361772122446 2.499561039717374]
Here is the codes I tried: (please note that calc-payoff is a function that calculates the payoff values for each turtle and it works perfectly fine)
ask turtles [
calc-payoff
set p_list lput ([payoff] of self) p_list
reset]
AND
Added part:
the problem is that some of the turtles have turtle_list2 = 0 by the end since the if condition was not fulfilled for them. However, I want the round to keep going until all the turtles find their stable values. (this part is after the tick)
ask turtles [
calc-payoff
set p_list lput payoff p_list
reset]
ask turtles [create-links-to other turtles
calc-payoff2
set turtle_list lput payoff turtle_list
reset]
ask turtles [
ask one-of links [die]
calc-payoff2
set turtle_list lput payoff turtle_list
reset]
tick
set tickcount tickcount + 1
if tickcount >= 3[
ask turtles
[
let p1 item (length turtle_list - 3) turtle_list
let p2 item (length turtle_list - 2) turtle_list
let p3 item (length turtle_list - 1 ) turtle_list
if p1 < p2 [if p2 > p3 [ set turtle_list2 (list p2) ]]
set payoff_list lput (sum turtle_list2 ) payoff_list]
user-message (word "stability is reached at payoff = " sum payoff_list)]
end
Hard to say for sure without seeing your code, but my guess is that p_list is a globals variable instead of a turtles-own variable. Have a look at the variables section of the NetLogo user manual for some more details.
For an example, have a look at the following toy setup:
globals [ global-list ]
turtles-own [ turtle-list ]
to setup
ca
set global-list []
crt 10 [
move-to one-of patches
set global-list lput xcor global-list
set turtle-list ( list xcor )
]
reset-ticks
end
After running that setup, if you do print global-list, you should see output like:
[-14 4 -3 11 -16 -2 4 8 -1 -9]
If we ask the turtles to show their own list with
ask turtles [ show turtle-list ]
you should see something like:
observer> ask turtles [ show turtle-list ]
(turtle 3): [-14]
(turtle 5): [8]
(turtle 9): [4]
(turtle 7): [-16]
(turtle 2): [4]
(turtle 0): [11]
(turtle 6): [-3]
(turtle 8): [-9]
(turtle 1): [-1]
(turtle 4): [-2]
Where each turtle has their own version of that list.
Edit:
To have your turtles update their lists, you can use exactly the same lput syntax you used in your question- for example, the following loops until a randomly drawn float value is less than 0.25, then has turtles print out their turtle-list. For each iteration of the loop, the turtles will move, then add to their turtle-list:
to go
loop [
if random-float 1 < 0.25 [
ask turtles [ show turtle-list ]
stop
]
ask turtles [
fd 1
set turtle-list lput xcor turtle-list
]
]
end
You get an output like:
(turtle 2): [13 13 13 13]
(turtle 5): [-4 -4.3583679495453005 -4.716735899090601 -5.0751038486359015]
(turtle 9): [14 13.015192246987791 12.030384493975582 11.045576740963373]
(turtle 7): [-3 -2.5 -2 -1.5]
(turtle 3): [-2 -2.3420201433256693 -2.6840402866513386 -3.026060429977008]
(turtle 0): [7 7.951056516295154 8.902113032590307 9.853169548885461]
(turtle 4): [-14 -13.947664043757056 -13.895328087514113 -13.842992131271169]
(turtle 8): [12 11.35721239031346 10.71442478062692 10.071637170940381]
(turtle 1): [16 15.674431845542843 15.348863691085686 15.02329553662853]
(turtle 6): [-16 16.426423563648953 15.852847127297908 15.279270690946863]

agents sharing with each other their lists

I am making a NetLogo model. Each agent has a list of 5 integers (agent-list). On each tick, turtles create link with one other turtle, and share with each other their list.
turtles-own [ agent-list ]
.
.
.
ask turtles [
create-link-with one-of other turtles
set agent-list lput agent-list of link-neighbors agent-list
]
I know the code above doesn't work, how should I fix it?
The simplest way to combine the lists as you've described would probably be sentence:
turtles-own [ agent-list ]
to setup
ca
crt 3 [
set agent-list map [random 10] range 5
]
reset-ticks
end
to link-and-share
ask turtles [
let target one-of other turtles
create-link-with target
set agent-list sentence agent-list [agent-list] of target
show agent-list
]
end
However, you'll have do do some tweaking depending on what you're actually looking to do since that means that turtles linking later in the procedure are likely to pull the agent-list of turtles that have already modified their own agent-list. So, if turtle 0 grabs the agent-list of turtle 1, then later turtle 4 grabs the agent-list of turtle 0, turtle 4 would have an agent-list of 15 integers, not 10, similar to the output below:
(turtle 1): [6 1 5 4 7 3 9 8 1 1]
(turtle 0): [9 0 3 3 5 3 9 8 1 1]
(turtle 2): [3 9 8 1 1 9 0 3 3 5 3 9 8 1 1]

How to identify triangles in Netlogo

How can I find all triangles in an undirected network in Netlogo, that is, list all instances of A-B, B-C, C-A?
Thank you,
Thomas
Here is a fairly naive approach. If your network is not too big, it could be good enough:
to-report find-triangles
let triangles (list)
ask turtles [
let t1 self
; find all the triangles that the turtle is a part of
ask link-neighbors [
let t2 self
ask link-neighbors [
let t3 self
if link-with t1 != nobody [
set triangles lput (turtle-set t1 t2 t3) triangles
]
]
]
]
report remove-duplicates triangles
end
Let's test it with a simple network:
to setup
clear-all
create-turtles 4
ask turtle 0 [
create-link-with turtle 1
create-link-with turtle 2
]
ask turtle 1 [
create-link-with turtle 2
]
ask turtle 3 [
create-link-with turtle 1
create-link-with turtle 2
]
ask turtles [ set label who ]
repeat 30 [ layout-spring turtles links 0.2 5 1 ]
show map sort find-triangles
end
From the command center, the result is:
observer> setup
observer: [[(turtle 1) (turtle 2) (turtle 3)] [(turtle 0) (turtle 1) (turtle 2)]]