Assigning turtles a ranked number in netlogo - netlogo

I'm trying to assign turtles a number which I can tell them to move in order of. Using previous posts and some general playing around I've managed to create a ranked order list of the turtles, but now I want to assign turtles a number based on their relative position in that list.
Example:
current list: [(turtle 8) (turtle 1) (turtle 9) (turtle 0)]
desired turtle designation: turtle 8 = 1, turtle 1= 2, turtle 9 = 3, etc.
So far I've reached:
globals [rank_list]
turtles-own [var.
rank]
set rank_list sort-on [var.] turtles
create-turtles (50)
[setxy (random-float max-pxcor) (random-float max-pycor)
set var. random-normal 0.5 0.175
if var. > 1 [set sociability 0.99999999]
if var. < 0 [set sociability 0.00000001]
foreach rank_list ask ? [set rank ... ;this is where I get stumped
to go
ask turtles [foreach rank [ask ? [move]]]
end
any tips for assigning values based on the ranked order in a list would be very much appreciated!

You can use n-values to generate the ranks and the variadic version of foreach to loop through both the rank-list and the ranks at the same time:
turtles-own [ var rank ]
to setup
clear-all
create-turtles 50 [
setxy random-pxcor random-pycor
set var random-normal 0.5 0.175
]
let rank-list sort-on [ var ] turtles
let ranks n-values length rank-list [ ? ]
(foreach rank-list ranks [ ask ?1 [ set rank ?2 ] ])
end
But the question is: do you really need a rank variable? Why not use the rank-list directly:
foreach rank-lisk [ ask ? [ move ] ]
Or even just sort your turtles on var each time:
foreach (sort-on [ var ] turtles) [ ask ? [ move ] ]
The latter is not the most efficient, but if you have only 50 turtles and do this only once per tick, you'll never notice the difference.

Using Nicolas' answer above I've achieved the goal or ranked order movement. It's still a bit processing-power-intensive for the 2000 turtles I'm working with, but at least it runs!
turtles-own [var]
to ranking
let rank-list sort-on [var] turtles
let ranks n-values length rank-list [ ? ]
(foreach rank-list ranks [ask ?1 [set var ?2] ] )
end
to make_turtles
create-turtles (5)
[set var random-normal 0.5 0.2
set color scale-color blue var 0 1
set size 3]
ranking
ask turtles [set label var]
end
to move
let rank-list sort-on [var] turtles
ask turtles [foreach rank-list [ask ? [ forward random 9]]]
end
to setup
clear-all
make_turtles
end
to go
move
end

Related

Is there a possibility to have an ifelse statement with two conditions (ticks mod and probability)?

I'm fairly new to Netlogo but I want to build a model where an agent (a car driver) will leave his home at a certain hour with a certain probability. Let's say he leaves Monday morning at 1 am (if have linked the ticks to the time so one tick is one hour).
I tried to work with ifelse-statements combined with a second statement which has to be verified in order for the entire statement to become true. In the example below the car / agent should leave with a probability of 7.7% its house and drive to a patch called underway-patches. Since one week has 168 hours, I tried to link the hour via the mod ticks (hence, mod ticks = 1 is equal to 1 am on a Monday morning).
This alone works:
ifelse ticks mod 168 = 1 and random-float 100.0 < 7.7
[ ask turtles [ move-to one-of underway-patches ] ]
[ ask turtles [ move-to one-of home-patches] ]
This works fine. So I have always about 7 out of 100 turtles moving to the underway-patch.
But If I now add the second hour, so 2 am, the first function does not work anymore (there are no turtles moving at all at 1 am - only at 2 am). I expect about 7 out of 100 turtles to move at 1 am to the underway-patch and then I expect about 5 out of 100 turtles to move at 2 am to the underway-patch (and the other 7 of the first hour should go back to the home-patches).
This does not work anymore:
; Monday, 1 am
ifelse ticks mod 168 = 1 and random-float 100.0 < 7.7
[ ask turtles [ move-to one-of underway-patches ] ]
[ ask turtles [ move-to one-of home-patches] ]
; Monday, 2 am
ifelse ticks mod 168 = 2 and random-float 100.0 < 5.1
[ ask turtles [ move-to one-of underway-patches] ]
[ ask turtles [move-to one-of home-patches] ]
I appreciate every help! Thanks in advance.
First, congratulations on an extremely clear question despite your newness to the site.
The problem is not that you have multiple ifelse statements, that is fine. The issue is that your ifelse statement is applying a single test to all turtles. Just look at the first example with one statement:
ifelse ticks mod 168 = 1 and random-float 100.0 < 7.7
[ ask turtles [ move-to one-of underway-patches ] ]
[ ask turtles [ move-to one-of home-patches] ]
Imagine that it is tick number 1. The computer runs the random number generator and gets 2. Great, the condition is true so the first block gets run. That will have ALL turtles move to the underway-patches. Similarly, if the random number generator returns 10, then the condition is false and ALL turtles move to home-patches.
You probably want something more like (you don't have to do the brackets on multiple lines, I did it so you can see the logical blocks of the structure):
ifelse ticks mod 168 = 1
[ ask turtles-on home-patches
[ if random-float 100.0 < 7.7
[ move-to one-of underway-patches
]
]
]
[ ask turtles-on underway-patches [ move-to one-of home-patches] ]
Or if you want exactly the correct proportion of turtles to move:
ifelse ticks mod 168 = 1
[ let num-to-move 0.077 * count turtles-on home-patches
ask n-of num-to-move turtles-on home-patches
[ move-to one-of underway-patches
]
]
[ ask turtles-on underway-patches [ move-to one-of home-patches] ]
Just a general observation, if you are going to code this for every possible starting time, you are going to have a lot of code that is identical except for the tick and the proportion. You state that you are new to NetLogo, so I don't want to jump too quickly to more advanced concepts, but come back when you're a little further along with having thought through your model and we can probably help you create a procedure that reduces the need to duplicate code.
UPDATE: One approach to reusing the code
This isn't quite right because I'm not really clear what sort of movement you want, but here is a complete model where the proportions are stored in a list and ticks is used to identify the correct item in the list. That proportion is then passed to a piece of code that moves turtles.
globals
[ home-patches
underway-patches
proportions
]
to setup
clear-all
set proportions [0 0.077 0.05 0.15]
set home-patches patches with [abs pxcor <= 3 and abs pycor <= 3]
ask home-patches [ set pcolor white ]
set underway-patches patches with [not member? self home-patches]
ask underway-patches [ set pcolor yellow ]
create-turtles 100
[ set color red
]
reset-ticks
end
to go
move-turtles item (1 + ticks mod 3) proportions
tick
end
to move-turtles [#prop]
print #prop
ask turtles
[ ifelse member? patch-here home-patches
[ if random-float 1 < #prop
[ move-to one-of underway-patches
]
]
[ move-to one-of home-patches
]
]
end

Create a gradient for a turtle swarm

I created a rectangular turtle grid using a total of 1000 turtles.
let in-shape patches with [ pxcor >= -50 and pxcor <= 50 and pycor >= -5 and pycor <= 5 ]
ask in-shape [ sprout 1 ]
Now I need to create a sort of gradient, that will give a sense of distance to my turtle swarm. Given a "seed" with value 0, it emits a message with its value 0 in a certain talk_radius.
The turtles inside this talk_radius compute their distance to the seed. If the distance is less than a fixed value (called gradient_distance) the turtle will assume 1 as gradient_value, emitting a message with its value.
The other turtles do the same. So everyone will take the value x + 1, where x is the lowest value of the turtle within the gradient_distance, as shown in the picture
This is the relative algorithm in pseudo code:
loop
if gradient seed = TRUE then // check if robot is designated as gradient source
gradient value(self) = 0
else
gradient value(self) = GRADIENT MAX
for all neighbors n do
if measured distance(n) < G then // G represents the gradient-distance and GRADIENT MAX is infinity
if gradient value(n) < gradient value(self) then
gradient value(self) = gradient value(n)
gradient value(self) = gradient value(self) + 1
transmit gradient value(self)
And that's my implementation in netlogo:
globals [talk_radius gradient_max gradient_distance]
turtles-own [gradient_seed gradient_value]
to setup
ca
resize-world -60 60 -20 20
crt 1000
let in-shape patches with [ pxcor >= -50 and pxcor <= 50 and pycor >= -5 and pycor <= 5 ]
ask in-shape [ sprout 1 ]
set talk_radius 4
set gradient_max 100000
set gradient_distance 1
ask turtles
[set shape "circle"]
ask turtles-on patch -50 5
[set gradient_seed true]
end
to gradient-formation
while [true]
[
ask turtles
[
ifelse (gradient_seed = true)
[
set gradient_value 0
]
[
set gradient_value gradient_max
set color scale-color green gradient_value 0 120
ask (other turtles) in-radius talk_radius with [distance myself <= gradient_distance] ;; i consider all the turtle in talk_radius having the right gradient_distance
[
let a ([gradient_value] of self) ;; "of self" is not necessary but helped me for a better comprehension
if (a < ([gradient_value] of myself))
[
ask myself [set gradient_value a]
]
]
set gradient_value (gradient_value + 1)
]
set color scale-color green gradient_value 0 120
]
]
end
I used a scale-color in order to have a feedback of what i have done, as you can see in the image.
And now the problem: instead of let a ([gradient_value] of self), i tried set a ([gradient_value] of self) adding a to the turtle variable (I added a in the turtle-own list on top).
I thought the result would have been the same, but instead i got a constantly increasing gradient_value for every turtle as you can see in the image(the color white denotes a very high gradient_value).
Why this difference? Thank you in advance and sorry for the long question.
EDITED EXTENSIVELY in response to discussion that refined the problem
First, I would like to start with a simpler version of the code. I believe this is exactly the same as yours without the while[true]. I removed the extra 1000 turtles you are creating, and separated the ifelse on whether a seed into two separate ask statements, for clarity. I also moved the colouring until after the value calculation is complete.
globals [talk_radius gradient_max gradient_distance]
turtles-own [gradient_seed? gradient_value]
to setup
clear-all
resize-world -60 60 -20 20
let in-shape patches with [ pxcor >= -50 and pxcor <= 50 and pycor >= -5 and pycor <= 5 ]
ask in-shape
[ sprout 1
[ set shape "circle"
set gradient_seed? false
]
]
set talk_radius 4
set gradient_max 100000
set gradient_distance 1
repeat 10 [ gradient-formation ]
end
to gradient-formation
ask turtles-on patch -50 5
[ set gradient_seed? true
set gradient_value 0
]
ask turtles with [not gradient_seed?]
[ set gradient_value gradient_max
ask (other turtles) in-radius talk_radius with [distance myself <= gradient_distance]
[ let my-gradval ([gradient_value] of self)
if my-gradval < [gradient_value] of myself
[ ask myself [set gradient_value my-gradval]
]
]
set gradient_value (gradient_value + 1)
]
ask turtles [set color scale-color green gradient_value 0 120 ]
end
There is a conceptual issue here. Until a turtle has its gradient_value calculated, it is 0. This means a large number of turtles will have a 0 turtle nearby and then have their own gradient_value as 1. It does not produce a colour gradient. To get around this, you need to run the gradient-formation several times. The approach in your code of while [true] introduces an infinite loop. Instead, you can repeat an arbitrary number of times (10 in the code above).
The problem with let versus set + turtles-won is that the set with turtles-own creates 1000 copies of gradient_value - one for each turtle. The let version creates a (temporary) global variable that all turtles access. So when you use set, you are setting it for that turtle, not as a general access number. I think what is happening is that the line set gradient_value my-gradval is accessing the wrong turtle's copy of my-gradval.
But, from the discussion, the purpose of the code that is causing the problem is to find a local minimum. There is a much more direct way of doing that.
to gradient-formation
ask turtles-on patch -50 5
[ set gradient_seed? true
set gradient_value 0
]
ask turtles with [not gradient_seed?]
[ set gradient_value 1 + min [gradient_value] of
other turtles in-radius min (list talk_radius gradient_distance)
]
ask turtles [set color scale-color green gradient_value 0 120 ]
end
ADDED a minimum working example to show the differences.
This is the let (global variable) version
turtles-own [testval]
to testme
clear-all
create-turtles 500
[ setxy random-xcor random-ycor
set color blue
set testval 1 + random 10
]
ask one-of turtles
[ set color red
inspect self
type "testval of asking turtle is " print testval
ask turtles-on neighbors
[ set color yellow
let my-testval [testval] of self ;; creates a temp global variable
type "my-testval is " print my-testval
if my-testval < [testval] of myself
[ ask myself
[ set testval my-testval ;; copies the global variable value
]
]
]
]
end
This is the set (turtle attribute) version
turtles-own [testval my-testval]
to testme
clear-all
create-turtles 500
[ setxy random-xcor random-ycor
set color blue
set testval 1 + random 10
]
ask one-of turtles
[ set color red
inspect self
type "testval of asking turtle is " print testval
ask turtles-on neighbors
[ set color yellow
set my-testval [testval] of self
type "my-testval is " print my-testval
if my-testval < [testval] of myself
[ ask myself
[ set testval my-testval ;; copies value from one attribute to other
]
]
]
]
end

Netlogo: simulation of cellular differentiation pattern?

I am trying to simulate the differentiation pattern of a simple organism. This is how I'd like my breeds and variables to work:
Breeds: vegetatives and heterocysts. Vegetatives can divide, heterocysts can't. Vegetatives can become heterocysts. Ideally, once a heterocyst is formed, the closer a vegetative is to it, the less likely it is for it to become a heterocyst in turn.
Variables:
age: + 1 per tick, - 1 for newly-hatched turtles
bump: A means by which to displace all the turtles located 'ahead' of a newly-hatched turtle, so they don't overlap. I imagined the system a bit like a Newton's Cradle (http://s.hswstatic.com/gif/newtons-cradle-1.jpg)
pro: promoter. Accumulates partially randomly. Once it reaches a certain value ('concentration'), a vegetative would change breed to become a heterocyst. Value decreased by inh.
proL: label for pro, with rounded values.
inh: inhibitor. Ideally this value should form a 'gradient' (highest in turtles near heterocysts, lowest further away).
The obvious problem that I can see is that I get a lot of contiguous heterocysts. Which is sort of what I've been trying to avoid. But I can't see what went wrong...Please help?
to setup
clear-all
setup-turtles
reset-ticks
ask turtles [ set size 1 ]
end
to setup-turtles
create-vegetatives 1
ask turtles [
setxy random-xcor random-ycor
set shape "circle"
set color 65]
end
to go
divide
add-age
move
differentiate
tick
end
turtles-own [age
bump
inh
pro
proL]
breed [vegetatives vegetative]
breed [heterocysts heterocyst]
to add-age
ask turtles [
set age age + 1
ifelse show-age?
[ set label age ]
[ set label "" ]
]
end
to divide
ask vegetatives [
if random 100 < 2 [
hatch 1[
set bump 1
set age age - 1
set inh 0
]
]]
end
;;Trying to get only one turtle per patch, making the others move
to move
ask turtles[
while [bump = 1] [
ifelse not any? turtles-on patch-right-and-ahead 180 1[
rt 180
fd 1
set bump 0
if any? other turtles-here[
ask other turtles-here
[set bump 1]
]
]
[fd 1
set bump 0
if any? other turtles-here[
ask other turtles-here[
set bump 1]
]
]
]]
end
to differentiate
ask turtles[
set pro (pro - inh + (random 2))
set proL round pro
ifelse show-proL?
[ set label proL ]
[ set label "" ]
create-links-with other turtles-on patch-ahead 1
create-links-with other turtles-on patch-right-and-ahead 180 1
if breed = vegetatives [
if any? link-neighbors[
ifelse any? link-neighbors with [breed = heterocysts]
[]
[set inh mean [inh] of link-neighbors]
]
if any? vegetatives with [pro > 50]
[ask vegetatives with [pro > 50]
[set breed heterocysts
set color brown
set shape "circle"
if any? link-neighbors[
ask link-neighbors with [breed != heterocysts]
[set inh 2]]
]]
]]
clear-links
end

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)]]

Define home area-turtles?

I am very new to netlogo. I have searched every question here before I posted this.
I have the following code which sprouts a given number of horses:
ask n-of Number-horses patches with [grass? = "Yes"]
[sprout-horses 1 [set color 25 ]]
The person can change the number of horses using the slider but I would like each horse to have its own area/range/radius.
They can only move within this radius/area and they cannot meet each other.
From what I've read it's got something to do with the distance function?
You can find a similar problem here which has examples too :
Spacing agents in NetLogo based on territory size
There are several ways that you can assign a territory zone to each horse, but all methods that I know have two steps, first step is in order to make sure initial home area of horses are separated from each other , So we need to create horses only in patches which has a certain distance from another patch which has a horse on it,I did not follow your method that asked patches to sprout horses and instead I created them without asking patches.
I was not sure how you defined grass? Variable for each patch but I have assigned a number of patches with grass? = true and others false.
Second step is to set home-area property of each horse. If initially you moved them far away from each other they will have separate territories.
I have included a few examples here :
First to use in-radius for both steps:
Breed [Horses horse]
Horses-own [home-area]
patches-own [grass?]
globals [Zone-Radius]
to setup
clear-all
reset-ticks
set Zone-Radius 2
ask patches
[
ifelse pxcor mod 5 = 3
[ set Grass? true ]
[ set Grass? false ]
]
create-horses Number-horses
[ Move-to one-of patches with [Grass? and not any? other horses in-radius (Zone-Radius + 1)]
set home-area patches in-radius Zone-Radius
set color 25
]
end
to go
ask horses [
ifelse member? patch-ahead 1 home-area
[rt random 10 fd 1 ] ; move if next patch is in their zone
[rt random 180]
]
tick
end
In this example horses only move in the patches in their radius 2. But you can change that base on your model requirements.
In the second method you can use distance for the first step (finding empty patches with enough distance to current patch) and radius for second one (assigning home-area to each horse).
Move-to one-of patches with [Grass? and not any? other horses with [distance myself < (Zone-Radius + 1)]]
set home-area patches in-radius Zone-Radius
If you use higher distance for finding empty patches you will have completely seprated zones. Finally , you can use distance for both steps:
Move-to one-of patches with [Grass? and not any? other horses with [distance myself < (Zone-Radius + 1)]]
set home-area patches with [distance myself < Zone-Radius]
I just did it another way:
Breed [Horses horse]
Horses-own [home-area]
patches-own [ concession? forest? parks?]
globals [Zone-Radius]
to setup
clear-all
reset-ticks
set Zone-Radius 2
ask n-of 500 patches [ set concession? "No" ]
ask n-of 500 patches[ set forest? "Yes" ]
ask n-of 500 patches[ set parks? "Yes"]
let i 0
while [i < Number-horses]
[
ask one-of patches with [(concession? = "No" or forest? = "YES" or parks? = "YES" ) and (not any? horses in-radius (Zone-Radius + 2) )]
[
sprout-horses 1 [
set home-area patches with [distance myself < Zone-Radius]
let w who
ask home-area [set pcolor red]
set color 25 ]
]
set i (i + 1)
]
end
to go
ask horses [
ifelse member? patch-ahead 1 home-area [rt random 10 fd 1 ] [rt random 180]
]
tick
end
As you can see I used while and a condition to ask patches one by one, I might be mistaken but when I ask all the n-of Number-of-horses patches with [YourCondition][...] I get the wrong results and distance between horses is not effective, maybe they are created all at the same time and therefore upon creating a horse there was no horse nearby!? I am new to these concepts and might be wrong.
This is the code and view for the one which asks patches to create horses at once here :
Breed [Horses horse]
Horses-own [home-area]
patches-own [ concession? forest? parks?]
globals [Zone-Radius]
to setup
clear-all
reset-ticks
set Zone-Radius 2
ask n-of 500 patches [ set concession? "No" ]
ask n-of 500 patches[ set forest? "Yes" ]
ask n-of 500 patches[ set parks? "Yes"]
ask n-of number-horses patches with [(concession? = "No" or forest? = "YES" or parks? = "YES" ) and (not any? horses in-radius (Zone-Radius + 2) )]
[
sprout-horses 1 [
set home-area patches with [distance myself < Zone-Radius]
let w who
ask home-area [set pcolor red]
set color 25 ]
]
end
to go
ask horses [
ifelse member? patch-ahead 1 home-area [rt random 10 fd 1 ] [rt random 180]
]
tick
end