For this, I suggest using just a single random-float between 0 and 1, saving it and then evaluating every probability based on that single number. The trick here is summing up your probabilities. If it is not p(a), check if it is p(a) + p(b). If it is not p(b), check if it is p(a) + p(b) + p(c) etc. In using this method, each option will have its own probability chance of being the chosen option and since the sum of all probabilities is 1, there is always 1 probability that will be chosen.
I use ifelse to evaluate this so option 2 is only considered is option 1 is rejected, option 3 only if 1 and 2 are rejected and so on. Normally ifelse only has 2 options but by including brackets around the entire thing, you can give it as many options as you want.
to go
let options ["a" "b" "c" "d" "e" "f"]
let probabilities [0 0 0.3 0.5 0.1 0.1]
let the-number random-float 1
show the-number
(ifelse
the-number < sum sublist probabilities 0 1 [show item 0 options]
the-number < sum sublist probabilities 0 2 [show item 1 options]
the-number < sum sublist probabilities 0 3 [show item 2 options]
the-number < sum sublist probabilities 0 4 [show item 3 options]
the-number < sum sublist probabilities 0 5 [show item 4 options]
the-number < sum sublist probabilities 0 6 [show item 5 options]
)
end
In your case, this would result in:
to go-2
let x random-float 1
(ifelse
x < 0 [show "a"] ;p(a) = p(x < 0) = 0
x < 0 [show "b"] ;p(b) = p(0 =< x < 0) = 0
x < 0.3 [show "c"] ;p(c) = p(0 =< x < 0.3) = 0.3
x < 0.8 [show "d"] ;p(d) = p(0.3 =< x < 0.8) = 0.5
x < 0.9 [show "e"] ;p(e) = p(0.8 =< x < 0.9) = 0.1
x < 1.0 [show "f"] ;p(f) = p(0.9 =< x < 1.0) = 0.1
)
end
First Edit:
Autogenerating this cumulative lists can for example be done using a map procedure. Here each new value of incremented-probabilities is the sum of the probability and all those that came before it.
let probabilities n-values 20 [0.05]
let incremented-probabilities (map [[this-probability index] -> sum sublist probabilities 0 (index + 1) ] probabilities range length probabilities)
show incremented-probabilities
Second Edit:
Now if you have a variable/high number of different options, you might not want to manually write this entire ifelse structure. Luckily Netlogo has the run primitive which allows you to read the content of a string and treat is as a command.
In the following example, I use foreach and word to, one by one, add an ifelse condition for each different option.
to go-3
let outcomes range 20
let probabilities n-values 20 [0.05]
let additive-probabilities (map [[this-probability index] -> sum sublist probabilities 0 (index + 1) ] probabilities range length probabilities)
let the-number random-float 1
show the-number
; Create your big ifelse code block as a string
let ifelse-string "(ifelse"
(foreach outcomes additive-probabilities [ [outcome probability] ->
set ifelse-string (word
ifelse-string
"\n the-number < "
probability
" [show "
outcome
" ]"
)
])
set ifelse-string word ifelse-string "\n)"
print ifelse-string
; Now run the string as if it was code
run ifelse-string
end
Lastly, you can take a look at "Lottery Example" in the models library. It looks a lot simpler than what i did here.