How can I record the identity of turtles another turtle interacts with? - netlogo

My model involves one turtle surveying the area and it should keep track of the ID/ 'who' of the turtles it bumps into. Importantly, the surveyor could potentially record the same ID/ 'who' twice but I'm not sure how to implement that memory side of things.
breed[boats boat]
boats-own [
my-neighbors
num-neighbors
count-neighbors]
to setup
clear-all
crt 100 [
move-to one-of patches with [ not any? turtles-here ]
]
crt 1 [set breed boats
set count-neighbors 0
]
reset-ticks
end
to go
ask turtles [
fd 1
]
ask boats [
survey
]
tick
end
to survey
set my-neighbors (other turtles) in-radius 3
set num-neighbors count my-neighbors
set count-neighbors [who] of my-neighbors
end
UPDATE
In light of the answer below I came up with the following which also records when the interaction took place by creating a new time variable.
breed[boats boat]
boats-own [
my-neighbors
num-neighbors
id-neighbors
survey-time]
turtles-own [
time
]
to setup
clear-all
crt 10 [
move-to one-of patches with [ not any? turtles-here ]
]
crt 1 [
set breed boats
set shape "circle"
set id-neighbors []
set survey-time []
]
reset-ticks
end
to go
ask turtles [
fd 1
set time ticks
]
ask boats [
survey
]
tick
end
to survey
set my-neighbors (other turtles-here )
set num-neighbors count my-neighbors
set id-neighbors (sentence id-neighbors [who] of my-neighbors )
set survey-time (sentence survey-time [time] of my-neighbors )
end

Currently, you are always setting count-neighbors to the list of all its current neighbors, but this list is cleared and made anew with each tick. Instead of that, you can use primitives like sentence to combine the old list of count-neighbors with the new list you are generating this iteration and set the new list of count-neighbors to be this combined list.
set count-neighbors (sentence count-neighbors [who] of my-neighbors )
I also initialised your count-neighbors as an empty list rather than as 0, since 0 is already a turtle who so that would give you false information
crt 1 [set breed boats
set count-neighbors []
]
To check if the memory is working as intended, you can use inspect one-of boats in the command center and see how each new entry gets added to the end of the list.
Edit for followup question
Your solution here definitely works. Allow me a few suggestions for it as well:
There is not need to create the time variable, each turtle can already access the ticks global variable
set id-neighbors (sentence id-neighbors [who] of my-neighbors )
set survey-time (sentence survey-time [ticks] of my-neighbors )
As an alternative, this one creates a list of lists, with each item containing the turtle that was encountered and the time when it was encountered. Slightly harder to work with but clear at a glance which values belong together.
set id-neighbors (sentence id-neighbors [list who ticks] of my-neighbors )

Related

Linking turtles to another turtle with highest value in NetLogo. Limit the number of links

I am a beginner with NetLogo and I am trying to ask some turtles (students from different social classes) to link to other turtles (schools). What I would like is for the working class students to look for the school with the highest achievement which is at the same not expensive and has not reached the max number of links allowed. If the desired school has reached the max number of links allowed I want the student to look for the next school with the highest achievement which has not reached the max number of links allowed and so on.
This is the code. I get the following message "ANY? expected input to be an agentset but got the turtle (school 1) instead."
breed [schools school]
breed [upperclass upperclass-student]
breed [workingclass workingclass-student]
upperclass-own [achievement enrolled? target]
workingclass-own [achievement enrolled? target]
schools-own [schoolachievement expensive? ]
to setup
clear-all
set-default-shape schools "house"
set-default-shape upperclass "person"
set-default-shape workingclass "person"
ask patches [ set pcolor 8 ]
create-schools num-of-schools [ setxy random-xcor random-ycor set schoolachievement random-normal 5 1
set expensive? one-of [ true false ] ]
create-upperclass num-of-upperclass [ set color white setxy random-xcor random-ycor set achievement
random-normal 5 1 ] ;Students from upper class have higher achievement
create-workingclass num-of-workingclass [ set color red setxy random-xcor random-ycor set achievement
random-normal 4 1 ]
end
to go
ask workingclass [
choose-school ]
end
to choose-school
if breed = workingclass [
set target one-of schools with-max [ schoolachievement ] with [ expensive? = false ] ]
if any? target with [ count link-neighbors < max-link-count ] [
create-link-with target ]
set enrolled? TRUE
end
Your problem is the difference between an agent and an agentset, which is a somewhat subtle problem. The with-max returns an agentset - a set of agents (in this case turtles). That agentset can have 0 members, 1 member, 2+ members but is a set even if it is empty. However, the one-of selects one agent from the agentset and returns it as an agent, not an agentset. That is, NetLogo knows anything that is returned by one-of must be exactly one agent. At this point, primitives that are for agentsets (like any?) will throw an error unless they can also be used on individual agents.
So, back to your code. I like the readability of checking whether there are viable schools and then selecting one, which is what I think you meant to do. That would be:
to choose-school
if breed = workingclass
[ set targets schools with-max [ schoolachievement ] with [ expensive? = false ]
set candidates targets with [ count link-neighbors < max-link-count ]
if any? candidates
[ create-link-with one-of candidates
set enrolled? TRUE
]
]
end
Note that I also changed to targets instead of target, which is one way to keep track of whether something is an agent or an agentset.
The other way you could do this and keep it as an agent is:
to choose-school
if breed = workingclass [
set target one-of schools with-max [ schoolachievement ] with [ expensive? = false ] ]
if target != nobody and [count link-neighbors] of target < max-link-count [
create-link-with target ]
set enrolled? TRUE
end
So you can use nobody instead of any? but you can't also use with in that line because the with is really a filter on a set.
I also think you have a bracketing issue - I assume you want set enrolled? TRUE inside the brackets. I left it in the second fix, but changed in the first error (as well as changing bracket position convention to make the code block structure more visible)

Create a new item and add it to my neighbours's lists

I would like to ask how I can add an element created by one turtle to its own list and its neighbour's lists.
I created a local variable, neighbours, defined as turtle-set in-link-neighbors with [breed=breed1]. Then I asked neighbours to add the element created (new_elem), following an answer provided me by an user in this forum.
The code is:
to create_elements
create-elements 1[
set person one-of turtles with [breed = breed1 or breed = breed2]
ifelse [breed = breed1] of person
[
set attribute1 random-float 1
set attribute2 random-float 1
set function1 (1 + attribute1)
]
[
set attribute1 random-float 1
set attribute2 random-float 1
set function2 (1 - attribute1)
]
let neighbours (turtle-set self in-link-neighbors with [breed = breed1] of person)
ask neighbours
[set my-list fput new_elem my-list]
]
]
end
I know that there is an error in let neighbours (turtle-set self in-link-neighbors with [breed = breed1] of person)..., but also in putting an element in the list, as I think the new element is defined in the breed elements. In fact, the error message says that
elements breed does not own variable my-list
Would it be possible to specify the breed of the turtle-set? What I would need is consider only breed1 and breed2, not elements breed.
For example, since I am considering person as creator of the element, is it right to write
let neighbours (turtle-set person in-link-neighbors with [breed = breed1] of person)
ask neighbours
[set my-list fput new_elem my-list]
And if it would be correct, how can I add a new element as "New element" to the list, taking into account its attribute for further consideration.
For example: set my-list fput (list attribute1 attribute2) of elements my-list) returns me list of values like (0.134531 0.14141) (0.91844 0.42176) ... Any suggestions to have something nicer to see but with the same information? I will need to keep track of this values in the next steps.
I hope you can shed some light on what I am doing incorrectly.
Thanks
Val, here's some working code that creates a new element and updates everyone's my-list.
It's probably not exactly what you wanted but I hope it provides some help anyway.
You didn't include all the info on breeds and who owns what so I punted.
I broke up more complex commands into multiple shorter ones in order to debug what was going on and where it was breaking down. I added some print statements.
If you load this up, run setup, and hit "go" once, you can see agents in a network linked up with their "who" numbers besides them so you can easily inspect the ones you
want. Values of my-list are also printed out in the command section.
Two more iterations of the "go" step should verify that they are outputting what you wanted.
I didn't know whether you wanted new_elem to be just local to the create_elements section, of if you wanted it globally available, so I put comments in both places.
I hope this helps! There are more comments in the code itself. Note especially that you must initialize my-list as an empty list, or it will default to the number zero, and your fput statement will fail with a comment about expecting a list and finding zero.
globals [
;;new_elem ;; might be needed as a global ??
]
;; ///////////////////// note that there is no breed required called "people"
breed [ elements element]
breed [ breed1 lion ]
breed [ breed2 tiger ]
;; ///////////////////// i punted on which entity owned "function1 and function2
breed1-own [ attribute function1 function2 my-list]
breed2-own [ attribute function1 function2 my-list]
to setup
clear-all
;; make some turtles with breed = breed1 (say, red lions)
create-breed1 2 [ set size 2 set shape "circle" set color red
setxy random-xcor random-ycor
]
;; make some turtles with breed = breed2 (say, green tigers)
create-breed2 2 [ set size 2 set shape "circle" set color green
setxy random-xcor random-ycor
]
;; //////////////////////////////////////////////////////////////////////////
;; NOTE!!! If you don't initialize my-list to an empty LIST type,
;; fput will generate an error when you try to fput a new element onto it
;; this is ugly but fast:
ask breed1 [create-links-with other breed1
set my-list [] ]
ask breed1 [create-links-with breed2
set my-list [] ]
ask breed2 [create-links-with other breed2
set my-list [] ]
ask breed2 [create-links-with breed1
set my-list [] ]
ask turtles [set label who] ;; ///////////////////////// for debugging
;; set new_elem nobody ;; this could be a global so it can persist
;; outside create_element, in which case
;; initilize it here
reset-ticks
end
to go
create_elements
tick
end
to create_elements
;; declare the local variables, all agent-sets of some type
let new_elem nobody ;; declare this locally if we don't need to persist it
;; outside the create_elements context
;; and remove the declaration in [ globals ]
;; and initializtion in setup
let personx nobody
let xx-neighbors nobody
;; do just this creation here in order to see what's going on more easily
;; than combining multiple operations into a long complex command
create-elements 1 [ set new_elem self ]
type "new element is this agentset " show new_elem
set personx one-of turtles with [breed = breed1 or breed = breed2]
ifelse [breed = breed1] of personx
[ ;; if it is breed1
ask personx [
set attribute random-float 1
set function1 (1 + attribute)
]
]
[ ;; else, it must be breed2
ask personx [
set attribute random-float 1
set function2 (1 - attribute)
]
]
;;//////////////////////////////////////// for debugging
type "the personx we defined above is " print personx
ask personx [set xx-neighbors (turtle-set self in-link-neighbors )]
if-else xx-neighbors != nobody ;; If it has any members, which should
;; always be true since we added self to the set
[
ask xx-neighbors
[
set my-list fput new_elem my-list
;; ////////////////////////////////////for debugging
type "here's the resulting my-list: " show my-list
]
]
[ print "ERROR didn't find any neighbors or self" ]
end

Setting new target patch but excluding current in Netlogo

I am creating a simulation which copies shoplifter behaviour. Turtles are split between "professional" and "novice" shoplifters and if "professionals" are apprehended by store security they might (1/2) want to select a new store to target "new-store-required".
"professional" shoplifters target the store with the lowest "security" value in a certain radius, all values are set as they are created.
I am trying to set a new "target-store", a "store" in-radius 10 with the second lowest "security", i.e. excluding the current "target-store" but I am having difficulty.
So far I have attempted to made several additions to the following code to exclude the current target store, this includes variations of "member? my patches" as the "store" where the shoplifter has been apprehended is added to this "patch-set" which will inform a later command. Also I have made a list of ascending "security" values to tell the "shoplifter" to target the "store" with "security" (the value which determines store vulnerability) the same as item 1 on the list, but I fear this might not work because their original target-store might not necessarily be item 0 as they target the store with the lowest "security" in a 10 unit radius.
These are the lines of code I am working with at the moment, any suggestions would be greatly appreciated.
***Edit: I could ideally like the code to make use of "mypatches" so each time a professional shoplifter is apprehended at a store that store can be added to mypatches and the subsequent target-store can exclude all stores which are members of mypatches.
to new-target-store
ask turtles [ if
new-store-required = 1 and professional = 1 and (random-float 1 < 0.5) [
set target-store min-one-of store in-radius 10 [security]
]
]
end
Edit 2: I've fixed what was wrong.
You may want to include your setup code, or a stripped-down version of it if it's really long, to make sure that answers conform to the structure you've used. I would approach this by having a turtles-own variable to store their current target, which they can try to fill if it is empty (rather than using an extra boolean for that purpose). Also, you may want to convert your 1/0 options to true/false for cleaner code. Check out this example setup:
globals [ stores ]
patches-own [ security ]
turtles-own [
current-target
professional?
mypatches
]
to setup
ca
ask n-of 20 patches [
set pcolor green
set security 1 + random 10
]
set stores patches with [ pcolor = green ]
crt 5 [
setxy random-xcor random-ycor
pd
set professional? one-of [ true false ]
set current-target nobody
set mypatches ( patch-set )
]
reset-ticks
end
This sets up a world with some green patches that are grouped into the patch-set called stores. Also, you have some turtles that have the boolean professional? set to either true or false. They initialize with no current-target store, and an empty mypatches patch-set variable.
Now, you can have turtles check if their current-target exists. If it does not, they can assign a store to that variable from the set of stores (possible-targets, here) that are not equal to the patch-here of the asking turtle. Professional thieves can further refine possible-targets to exclude any stores at which they have been apprehended, by excluding any stores that are a member of their mypatches patch-set variable. More details in comments:
to go
ask turtles [
; if you have no target currently
if current-target = nobody [
; Create a temporary patch set made up of all stores except for
; the one that I'm currently in
let possible-targets stores with [ self != [patch-here] of myself ]
ifelse professional? [
; Have professional thieves revise their possible targets to exclude
; any in the patchset mypatches, then choose a possible target
set possible-targets possible-targets with [ not member? self [mypatches] of myself ]
set current-target min-one-of possible-targets in-radius 10 [ security ]
] [
; Have amateur thieves choose randomly from the possible targets
set current-target one-of possible-targets
]
]
; move closer to your current target, or
; move to it exactly if you're near enough
ifelse current-target != nobody [
face current-target
ifelse distance current-target > 1 [
fd 1
] [
move-to current-target
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; *** do your shoplifting attempt/check here ***
; For this example, just have professional thieves sometimes
; add this patch to their mypatches patchset
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
if professional? and random-float 1 < 0.5 [
set mypatches ( patch-set mypatches patch-here )
]
; Reset current-target to nobody
set current-target nobody
]
] [
; if no suitable nearby targets, wander randomly
rt random 61 - 30
fd 1
]
]
tick
end
If you run that long enough, eventually your professional thieves will stop being able to find target stores as they have added all stores to their mypatches variable.

Copy the link breed variable in the patch below

I have a network of nodes and links. This figure
is a capture of the world. The graph represents streets of a city. I have imported a shapefile with the gis extension. The gray lines are links, black dots are nodes and red dots represent people. The people move heading to the next node. In a street corner, the red dot chooses next street by examining the variable popularity owned by the link.
The links breed has a variable, popularity, whose value I would like to copy in the patches that are below.
If I try, for example, something like this to access patches under links will produce an error
ask links [show [(list pxcor pycor)] of patch-here]
Another approach can be to access links variable popularity from patches, but I do not know how to do it.
The reason why I want this is because I want to write in a file a matrix of popularity values and its position in the matrix should correspond with the position of the link in the world. Thus, the patches below the links would give me the matrix form. I have a procedure that for each patch writes the value of the patch in a file. However, I do not know how to pass the popularityvalue from the link to the patch below it.
Is there any way to copy a link owned variable to its patch?
Regards
If someone has a better way of doing this (or can simplify my code), feel free. Here is a complete working example. Copy it into an empty NetLogo model and run it to see it work.
The setup procedure just creates some nodes and links with appropriate test values and then calls the transfer-link-values procedure, which does what I think you want. The setup procedure then puts the values into the patch labels to display them and see the results.
The way the transfer-link-values procedure works is to create a turtle at one end of the link, and that turtle moves toward the other end of the link transferring the value as it goes. When it gets to the other end, the turtle dies.
patches-own [patch-popularity]
links-own [link-popularity]
to setup
clear-all
create-turtles 10 [ setxy random-xcor random-ycor]
while [ any? turtles with [not any? my-links] ]
[ let to-pair turtles with [not any? my-links]
let thisNode one-of to-pair
ask thisNode
[ create-link-with one-of other to-pair
[ set link-popularity 5 + random 5 ]
]
]
transfer-link-values
ask patches [ if patch-popularity != 0 [set plabel patch-popularity ] ]
end
to transfer-link-values
ask links
[ let start-node one-of both-ends
let this-link self
let end-node nobody
ask start-node [ set end-node [other-end] of this-link ]
let transfer-value link-popularity
ask start-node
[ hatch 1
[ face end-node
if transfer-value > patch-popularity
[ ask patch-here [ set patch-popularity transfer-value ] ]
while [ not member? end-node turtles-here ]
[ forward 1
if transfer-value > patch-popularity
[ ask patch-here [ set patch-popularity transfer-value ] ]
]
if transfer-value > patch-popularity
[ ask patch-here [ set patch-popularity transfer-value ] ]
die
]
]
]
end

Netlogo: ask turtle to reproduce after it completes a procedure, and ask new turtle to repeat that procedure for itself

I'm new to NetLogo and am attempting to model home range selection of subsequent colonizers. The model should follow simple steps:
Individual 1 picks a home range (a subset of patches).
When individual 1 is done picking its home range, it hatches new
individual 2.
Individual 2 picks a home range, then hatches individual 3.
Individual 3 picks a home range, and so on.
I'm having trouble figuring out how to get this to work. I can get the first turtle to pick a home range. But the offspring do not. Writing the code numerous ways has only accomplished two unintended outcomes. Either endless new individuals are hatched simultaneously, before the first turtle has a home range, and the new turtles fail to pick a home range. Or, the first turtle picks its home range and hatches a new turtle, but that new turtle doesn't pick a home range. Neither outcome is what I want.
How do I set this up to run as intended, so that hatchlings pick home ranges too? Here is one simplified version of my code:
to setup-turtles
crt 1
[setxy random-xcor random-ycor]
end
to go
ask turtles [pick-homerange]
tick
end
to pick-homerange
while [food-mine < food-required] ;; if not enough food, keep picking patches for home range
[;; code to pick home range until it has enough food; this is working okay
]
[;; when enough food, stop picking home range
hatch 1 fd 20 ;; now hatch 1, move new turtle slightly away
]
end
So it is at this last part, once the home range is built, that I want a new turtle to hatch from its parent. I then want that turtle to repeat the pick-homerange procedure. How could that be coded to happen? I've tried writing this every way I can think of; nothing is working. Thanks in advance for any assistance!
One way to do this is to have each patch equal one "food value", and have turtles grow their home range until their home range supplies them with enough food. I would set this up so that patches "know" to which turtle they belong, and so that turtles know how much food they need, which patches are part of their home range, and the food supplied by their homerange. Example patch and turtle variables would then be:
patches-own [
owned_by
]
turtles-own [
food_required
my_homerange
homerange_food
]
Then, your turtles can add patches into their home range until they hit their "food_required", whatever you set that as. For simplicity, in this example I assume that turtles are territorial and so won't "share" home ranges. Further explanation of steps is commented in the code below. This is intended just to get you started- for example, it will hang if you run pick-homerange too many times.
to setup-turtles
crt 1 [
set size 1.5
setxy random-xcor random-ycor
set food_required 5 + random 5
set homerange_food 0
set my_homerange []
]
end
to pick-homerange
ask turtles [
;; Check if the current patch is owned by anyone other than myself
if ( [owned_by] of patch-here != self ) and ( [owned_by] of patch-here != nobody ) [
;; if it is owned by someone else, move to a new patch that is not owned
let target one-of patches in-radius 10 with [ owned_by = nobody ]
if target != nobody [
move-to target
]
]
;; Now add the current patch into my homerange
ask patch-here [
set owned_by myself
]
set my_homerange patches with [ owned_by = myself ]
;; calculate the number of patches currently in my homerange
set homerange_food count patches with [owned_by = myself]
;; Now grow the homerange until there are enough patches in the homerange
;; to fulfill the "food_required" variable
while [ homerange_food < food_required ] [
let expander one-of my_homerange with [ any? neighbors with [ owned_by = nobody ] ]
if expander != nobody [
ask expander [
let expand_to one-of neighbors4 with [ owned_by = nobody ]
if expand_to != nobody[
ask expand_to [
set owned_by [owned_by] of myself
]
]
]
]
;; Reassess homerange food worth
set my_homerange patches with [ owned_by = myself ]
set homerange_food count patches with [owned_by = myself]
]
ask my_homerange [
set pcolor [color] of myself - 2
]
;; Now that my homerange has been defined, I will hatch a new turtle
hatch 1 [
set color ([color] of myself + random 4 - 2)
]
]
end