Normal distribution for turtle at startup
I want to randomly place the turtles at some x and y coordinates, limited to a Gaussian distribution without two turtles in one patch.
Things I've tried: 1. There is http://ccl.northwestern.edu/netlogo/docs/dictionary.html#random-normal but how can I avoid turtles getting the same patch.
The previous code I used (randomly allocated only):
ask n-of population patches-in-box
[
sprout-inboxturtles 1
]
; population - the number of turtles; patches-in-box - where I want to place the turtles
source to share
There is no built-in equivalent n-of
for normal distributions (and it's not clear to me what it should be if there was one). Therefore, you will have to use random-normal
and adapt it for your special case:
to distribute-turtles [ pop box ]
if pop > count box [ error "Box can't hold all turtles!" ]
let ys [ pycor ] of box
let xs [ pxcor ] of box
let min-x min xs
let min-y min ys
let max-x max xs
let max-y max ys
let mid-x mean list min-x max-x
let mid-y mean list min-y max-y
let w max-x - min-x
let h max-y - min-y
crt pop [
loop [
let x random-normal mid-x (w / 6)
if x > max-x [ set x max-x ]
if x < min-x [ set x min-x ]
set xcor x
let y random-normal mid-y (h / 6)
if y > max-y [ set y max-y ]
if y < min-y [ set y min-y ]
set ycor y
if not any? other turtles-here [ stop ]
]
move-to patch-here ; to center in patch
]
end
And this is an example of how you call it:
to setup
ca
let population 100
let patches-in-box patches with [ abs pxcor < 10 and abs pycor < 10 ]
ask patches-in-box [ set pcolor black + 2 ]
distribute-turtles population patches-in-box
end
A few notes:
-
The code would be more effective if you pass it
min-x
,max-x
,min-y
andmax-y
chat, rather than calculate the value of a set of agentsbox
, but it should not be a huge difference if your box is really big. -
We need to make sure there are
pop
fewer patches or it will cycle forever because there would be no free patch to put the turtles on: that's why we throw an error when that happens. And the closerpop
tocount box
, even if it gives no errors, the longer it will take to complete, because it will be difficult for the last turtles to find a place. -
You can play with standard deviations (
w / 6
andh / 6
) to get the shape of the distribution that you want (which is basically a "steepness" bell curve). -
random-normal
theoretically unlimited, so it can give you coordinates that are out of the box. This is why we pinch the results to the lowest and highest possible coordinates. If your standard deviations are too high, you may find that many turtles end up "stuck" at the edges of the box.
source to share
I just figured out that you can work around the speed issue entirely by using the rnd:weighted-n-of
NetLogo Rnd Extension primitive ! Here's some revised code:
extensions [ rnd ]
to distribute-turtles [ pop box ]
if pop > count box [ error "Box can't hold all turtles!" ]
let ys [ pycor ] of box
let xs [ pxcor ] of box
let min-x min xs
let min-y min ys
let max-x max xs
let max-y max ys
let mid-x mean list min-x max-x
let mid-y mean list min-y max-y
let w max-x - min-x
let h max-y - min-y
ask rnd:weighted-n-of pop box [
[ (p (pxcor - mid-x) (w / 6)) * (p (pycor - mid-y) (h / 6)) ] of ?
] [ sprout 1 ]
end
to-report p [ x std-dev ]
report (1 / (std-dev * sqrt (2 * pi))) * e ^ (0 - ((x ^ 2) / (2 * (std-dev ^ 2))))
end
What rnd:weighted-n-of
it does is that it takes an agent set (or list) and a reporter task that should return a "weight" for each item. The heavier elements have the best chance of choosing. In our case, we assign these weights to the patches in the field using the normal propagation probability density function (which is the reporter p
in the code).
You can use the distribute-turtles
same as in my other answer:
to setup
ca
let patches-in-box patches with [ abs pxcor < 10 and abs pycor < 10 ]
let population (count patches-in-box - 10)
ask patches-in-box [ set pcolor black + 2 ]
distribute-turtles population patches-in-box
end
... but in this case the code is very fast, even if it is population
almost the same as count patches-in-box
. What for? Because it rnd:weighted-n-of
is smart enough to sometimes discard items that have already been picked and keep picking among those that havenβt been picked yet. (You can look at the basic Scala code if you are interested in the details.) In our case, this means that the patches at the center out of the box will not be badly picked over and over again: only loose spots will remain in the game towards the end.
source to share