In NetLogo how do use random-float with known percentage chances? - netlogo

I'm getting a bit confused about the random-float function because it produces a value strictly less than the one you provide.
In my model I have 7 agents that I want to produce according to the following probabilities:
0.493 0.368 0.060 0.067 0.006 0.004 0.002
So I transform them into a cumulative sum giving:
0.493 0.861 0.921 0.988 0.994 0.998 1.000
Then I plug these into my code:
ask patches [
while [sum [energy] of turtles < 1000] [
let choose-size random-float 1
if choose-size < 0.493 [ sprout-ones 1 ]
if choose-size >= 0.493 and choose-size < 0.861 [ sprout-twos 1 ]
if choose-size >= 0.861 and choose-size < 0.921 [ sprout-threes 1 ]
if choose-size >= 0.921 and choose-size < 0.988 [ sprout-fours 1 ]
if choose-size >= 0.988 and choose-size < 0.994 [ sprout-fives 1 ]
if choose-size >= 0.994 and choose-size < 0.998 [ sprout-sixes 1 ]
if choose-size >= 0.998 [ sprout-sevens 1 ]
]]
Could some kind soul verify these, in particular because the last value will never actually hit one, am I underestimating it? Thanks!

What you have written is the correct way to go about it. While you can indeed never reach 1, a random-float outcome has 16 decimals so the difference is negligible. But even if that minuscule number matters your approach is correct.
Let's start with considering a random number X, that is generated by random-float 1. This number has a few properties
X is an element of [0,1[
X has a total of 16 decimals
X could be (0.0000000000000000, 0.0000000000000001, ... , 0.9999999999999999)
There are a total of 10^16 different options for X
Now if we want to use this number to calculate an easy probability, say a coinflip. For that we would want exactly half of the results for X to give one outcome, and half of the results for X to give another outcome.
For that we will need to compare X to 0.5000000000000000, or 0.5 for short.
If we check X <= 0.5, we will get
P(true) = (0.0000000000000000, 0.0000000000000001, ... ,
0.5000000000000000)
P(false) = (0.5000000000000001, 0.5000000000000002, ...
, 0.9999999999999999)
If you count all those together, the number of possible results for X that give true is 5 * 10^15 + 1, while the number of possible results for X that are false is 5 * 10^15 - 1. So this distribution is very close but slightly off.
If instead we check X < 0.5, we will get
P(true) = (0.0000000000000000, 0.0000000000000001, ... ,
0.4999999999999999)
P(false) = (0.5000000000000000, 0.5000000000000001, ...
, 0.9999999999999999)
If you count all those together, the number of possible results for X that give true is 5 * 10^15, while the number of possible results for X that are false is 5 * 10^15. A perfectly equal result.
You are basically always dividing your possible results into two groups and have to decide which of the two groups gets the border value. Since the lower of the two groups already includes 0, the value against which you are comparing should go to the other group. This even works with cumulative sum of your probabilities, since each subsequent group will contain their lower border but will not contain their upper border.
Also note that if random-float 1 actually included both 1 and 0, we would have 10^16 + 1 possible outcomes. This number is odd, so we could never perfectly split it into two equal groups.

Related

What is the most appropriate way to include randomness in the movement - NetLogo

First, let me describe what I am doing and why I am asking this question.
I have 74 cities included in the model and I want to simulate movement between them. I have an OD probability matrix where rows are origins and columns are destinations. Matrix looks like this:
0 1 ..... 73
----------------------
0 |0.5 0.1 .... 0.0
...| . . .. . .
73 | 0.1 0.2 .. 0.3
Please note: if we look at the first row, that means that an agent from the city with index 0 has the probability to stay in it 0.5, to move to the city with idx=1 0.1 and so on.. What I want to do is to on the best statistically speaking way distribute agents' destination. For the agents which origin is city 0 I want to stay approximately 50% of agents (not exact 50%), but also I want to give some chance to the cities that have 0% probability, like pair 0-73.
I already coded the randomness according to the answer to this question: Netlogo: How can send agents from "area x" to "area y" using an O/D matrix?
But the answer for me in this question is not logical, concretely this part:
ask turtles with [residency = "nw"]
[ let myrandom random-float 1
ifelse myrandom <= 0.5 [ set destination "nw" ] [
ifelse myrandom <= 0.8 [ set destination "ne" ] [
ifelse myrandom <= 0.0 [ set destination "sw" ] [
set destination "se" ]]]
If I understood well, myrandom would take a value in the range 0-1 and then it would go to check one by one condition whether its' value is smaller or equal than this constant values.
In that sense, myrandom wound never get to the "sw" part (0 would always be smaller than 0.5) and there is more chance to get the "nw" part where probability is 0.5 than the "ne" part where the probability is higher-0.8. And only because it's not listed first. I am no sure that this is the right way to go, and also I am not sure which is (I can't sort my probabilities because their position represents city-id(see below)). Or I understood wrong?
Here is presented the part of my code. I imported the matrix without the headings/cities ID because they are equivalent to NetLogo indexing. The cities with ID are already imported into the model. Also, in each point/city I created the corresponding number of agents that I read for each city from the CSV file. During the creation of the agents, I use the row from the matrix that corresponds to the current city/origin and go through the probabilities as JenB did in his answer above.
breed [city cities]
breed [inhabitant inhabitants]
;; part of the setup
;; open the csv file that contains population per city
file-open path
while [ not file-at-end? ] [
let data csv:from-row file-read-line
let city-id item 0 data
let population item 1 data
to add-inhabitants
create-inhabitants population [
set city-home one-of cities with [id = city-id] ;; set the origin
move-to city-home
set-destination(city-id) ;; for this origin chose the destination
]
]
to set-destination [row] ;; row from the matrix which represent the movement from the current city/origin to other cities
let row-probabilities matrix:get-row od-matrix row ;; use the row that correspondents to the city
let random-value random-float 1
let i 0 ;; index counter
foreach row-probabilities [ ;; for each probability in row
p ->
if random-value <= p ;; this part is coded as in the JenB's answer
[
set destination one-of cities with [id = i] ;; i is column index which is actually index of destination city
stop ;; if you set city -> stop
]
if i = 73 [set destination one-of cities with [id = i]
stop] ;; the last city -> there is no more option/reason to check
set i i + 1
]
end
I know it's a little bit longer, but I wanted to explain clearly. Some guidelines and explanations would be much appreciated!
Your question suggests that you don't understand what the code in that section is doing. This is the corrected code for that bit:
ask turtles with [residency = "nw"]
[ let myrandom random-float 1
ifelse myrandom <= 0.5 [ set destination "nw" ] [
ifelse myrandom <= 0.8 [ set destination "ne" ] [
ifelse myrandom <= 0.9 [ set destination "sw" ] [
set destination "se" ]]]
Yes, the first line in the block draws a random number in the range 0 to 1. Imagine that the draw gave 0.4. Then the first ifelse would be true and the destination would be set to "nw". Now imagine the draw was 0.6, then the first ifelse would be false and the code would go on to test the else part, which is true because 0.6 <= 0.8.
The code works because the initial draw is uniform. That is, 10% of the time (on average) it returns a number in the range 0 to 0.1, and 10% in the range 0.1 to 0.2 and so on. So 50% of the time it returns a number in the range 0 to 0.5, which returns true for the first line. 30% of the time it returns a number in the range 0.5 to 0.8, which is false for the first test and true for the second test. 10% of the time it returns a number in the range 0.8 to 0.9 and 10% of the time it returns a number in the range 0.9 to 1.
So breaking the interval with check points at 0.5, 0.8, 0.9 (and 1 for the remainder) gives you sections that are 0.5, 0.3 (=0.8-0.5), 0.1 (=0.9-0.8) and 0.1 (=1=0.9) in length. And a uniform random number will fall into those sections with probability distribution 50%, 30%, 10% and 10% of the draws.

NetLogo - Have one variable changed with a certain probability of a group of randomly chosen turtles

In NetLogo, I would like to have each round a likelihood of between 0 to 10 % turtles of the whole population to have a change of a variable. Within the chosen turtles, their variable can change between +1 and +4 by a certain likelihood.
breed [ humans human ]
humans-own [ var ]
to setup
create-humans(population) [ set var 0 ]
end
to go
ask humans [ var_change ]
end
to var_change [
let %draw (random-float 100)
let %strength 0 ;no eco loss
if (%draw < 50) [ set %strength (%strength + 1) ] ;1 little eco loss
if (%draw < 10) [ set %strength (%strength + 2) ] ;2 middle eco loss
if (%draw < 5) [ set %strength (%strength + 3) ] ;3 strong eco loss
if (%draw < 1) [ set %strength (%strength + 4) ] ;4 complete eco loss
[ ask one-of %strength patches [ set economic economic + 3 ]]; here I do not know how to continue(*)
]
end
*I do not know how to code that between 0 to 10 % of turtles can have with a certain probability have their variable var changed. How can I achieve that?
The way you have it set up, all turtles are sent to the var_change procedure. It would be easier to have the var_change procedure both select the turtles to change and assign the amount of change. Something like:
to go
var_change
end
to var_change
; choose proportion to change
let %draw-prop random-float 0.1
let n-changers round (%draw-prop * count turtles) + 1 ; +1 so at least one changes
; change by some amount
ask n-of n-changers turtles
[ let %draw-change random 100
set economic economic + 1 ;all get some eco loss
if (%draw-change < 10) [ set economic economic + 1 ] ;2 middle eco loss
if (%draw-change < 5) [ set economic economic + 1] ;3 strong eco loss
if (%draw-change < 1) [ set economic economic + 1 ] ;4 complete eco loss
]
end
Note that I changed all your + amounts to + 1. The way you had it written, drawing a number like 3 would have added 1 (as <50) then another 2 (as <10) then another 3 (as <5) for a total increase of 6. An if clause runs the code if the if condition is satisfied and skips over it if not satisfied. Either way, the next code always runs.

Create 1000 turtles near each others

I have to create a lot of turtles forming a compact group of any shape, a simple 10x100 rectangle is enough. The important thing is that they must be near each others.
In c i would do something like this:
for(x = 1; x <= rows; x++)
{
for(y = 1; y <= columns; y++)
{
create_turtle(x,y);
}
}
And the equivalent in netlogo would be:
crt 1000
let n 0
let x 1
let y 1
while[y <= 10]
[
set x 1
while[x <= 100]
[
ask turtle n
[move-to patch x y]
set x x + 1
set n n + 1
]
set y y + 1
]
But it's not an elegant solution. Any suggestion?
Edit: More precisely I have to reproduce what has been done in this article: http://science.sciencemag.org/content/345/6198/795.full
Every turtle is a little robot.
And here you can see one way turtles could be positioned turtles schema
I'm using circle turtles like the robots of the article.
One of the trickiest things for programmers from other languages to do when learning NetLogo is getting rid of all the loops. Iterating through the agents or patches is embedded in the ask primitive, you don't need to code the iteration. ask also iterates in a random order so that repeated processes don't lead to any advantage to whichever agent happens to be first in the loop.
Also, when you create turtles, you can immediately give them instructions. You can also place them initially in an arbitrary position rather than move them there. Here is one solution that places them all in a rectangle that is 5 patches to the left/right of centre (0,0) and occupies half the height of the world.
create-turtles 1000 [ setxy random-float 10 - 5 random-ycor * 0.5 ]
From the edit, I think you are wanting them to be created at gridpoints rather than randomly within the space. If that is true, then select the patches you want and ask them to sprout a turtle.
let in-shape patches with [ pxcor >= -10 and pxcor <= 10 and pycor >= -10 and pycor <= 10 ]
ask in-shape [ sprout 1 ]
You will need to work out your own values and make sure they are within the world dimension.

How to hatch turtles with probability

I'm trying to find a procedure to hatch a turtle based on random probability:
40% for A
30% for B
30% for C
How do you hatch a turtle depending on that probability? What procedure/s should I use?
It looks like A, B, and C are breeds? Then
to weighted-hatch ;; turtle-proc
let p random-float 100
if (p >= 60) [hatch-As 1 [init-A]]
if (if p >= 30 and p < 60) [hatch-Bs 1 [init-B]]
if (p < 30) [hatch-Cs 1 [init-C]]
end
to init-A
;;put any desired initializations here
end
Etc.
You could alternatively use the rnd extension; see NetLogo, weighted random draw from a list: how to use rnd-extension?
Throw a dice mate! : ) Generate a random number, since you have 3 probable options you can use something like random-float 1 this gives a number in [0,1).
Then, if 0>= number <=0.4 hatch A, else if 0.4< number <=0.7 hatch B and so on for C.
Happy coding!

Making box in the middle of the world by exact percentage from the overall space

I want to make box in the middle of the Netlogo world
I managed to make a box but in the corner of my space the location of the origin is corner and the max pxcor = 9 and the maxpycor = 9
The code for 25%
to setup-area-25%
ask patches with [pxcor >= 5 and pycor >= 5] [ set pcolor blue ]
end
and the other code for 50 %
to setup-area-50%
ask patches with [pxcor >= -5 and pycor >= 5] [ set pcolor blue ]
end
I want to make blue area represent 25 and 50 % of the world but in the middle of the world I tried to use in radius but it did not give me a right area.
Thanks in advance
Here is a quick and dirty way that won't necessarily give you the exact percentage that your looking for, but could be good enough, depending on what you are trying to do:
to make-box [ pct box-color ]
let side round sqrt (count patches * (pct / 100))
let x min-pxcor + ceiling ((world-width - side) / 2)
let y min-pycor + ceiling ((world-height - side) / 2)
ask patches with [
pxcor >= x and pxcor < x + side and
pycor >= y and pycor < y + side
] [
set pcolor box-color
]
end
Calling make-box 25 red should give you a red square that is about 25% of the overall area, calling make-box 50 blue should give a blue square that is about 50%, etc.
The code uses the square root of the desired box area as the side of the box to draw. Not all numbers are perfect squares, however, and this is why you don't always get the exact percentage that you are looking for. You could try to look for the closest factor pair instead, but in some cases, they're just not very square. For example, 50% of the default NetLogo world size is 544.5 patches. If we round this up, we get 545 patches: not a perfect square. The closest factor pair that will give you exactly 545 is 109 * 5, which is probably not what you want.
Edit:
Here is a version that uses the closest factor pair, thereby always giving an area equal to the desired percentage of the world (rounded to an integer number of patches, but that can't be avoided). Just be warned that the box may end up being much more rectangular than square; so much that it very well may wrap around the world. You'll have to vary world-size or requested percentage if you want to avoid that.
to make-box [ pct box-color ]
let n round (count patches * (pct / 100))
let h height (floor sqrt n) n
let w (n / h)
let x min-pxcor + ceiling ((world-width - w) / 2)
let y min-pycor + ceiling ((world-height - h) / 2)
ask patches with [
pxcor >= x and pxcor < x + w and
pycor >= y and pycor < y + h
] [
set pcolor box-color
]
end
to-report height [ h n ]
report ifelse-value (n mod h = 0) [ h ] [ height (h - 1) n ]
end
The algorithm for finding the closest factor pair loosely follows this answer.