Hamda Binte Ajmal
Hamda Binte Ajmal

Reputation: 455

Multiple mutually exclusive events and probabilities in netlogo

consider the following 5 events that can occur in netlogo,

[a b c d e f] Each event has a specific probability of occurring. Say [0 0 0.3 0.5 0.1 0.1], that is, p(a) = 0, p(b) = 0, p (d) = 0.5

One (and only one event)must occur . How do I model it in Netlogo.

What i did:

ask turtles 
[
 if random-float 1 < 0
[EventA]
if random-float 1 < 0.5
[EventD] ; and so on 


]

But with this approach, sometimes no event will occur or sometimes more than 1.

Upvotes: 1

Views: 218

Answers (3)

Hamda Binte Ajmal
Hamda Binte Ajmal

Reputation: 455

Thank you for posting the answers. The solution i used was to use cumulative probabilities.


  let probabilities  [0 0 0.3 0.5 0.1 0.1]

  let cum-pmf partial-sums probabilities ; returns [0 0 0.3 0.8 0.9 1]


  let n random-float 1
  report length filter [ [?1] -> ?1 < n ] cum-pmf  ; indexing starts at 0

and the function partial-sums is

to-report partial-sums [lst]
report butfirst reduce [[result-so-far next-item] -> lput (next-item + last
result-so-far) result-so-far] fput [0] lst
end

Upvotes: 1

TurtleZero
TurtleZero

Reputation: 1064

Short answer: This is a classic use case for "roulette-wheel" selection.

You can use the NetLogo RND extension to do this, or roll your own following the Lottery example in the model library.

More:

The method abstracts the probabilities to weights, so any set of values from a list or from an agentset can be used; the probability of selection is the ratio of the individual value to the sum of all values in the set or list.

It does not require the set or lists to be sorted, and is scalable to any number of items.

You can write it to produce either the list index of the selected value, or a related value (like an agent or a value from another list).

It can be used for both with-replacement and without-replacement selection from the set.

Without-replacement can be done either by removing individuals from the selection list/set or by setting the selection weight/value of an individual to 0 once it is selected(use a copy of the real values if the selection is repeated.)

Link to NetLogo RND Extension

Simple roll-your-own example:

;; List weight has values to consider
;; Returns the index of the selected item
To RW-Select [ weight ]
  Let last-index length weight
  Let total sum weight
  Let index 0
  Let cumulative 0
  Let rnd random-float total
  While [cumulative <= rnd and index < last-index] 
  [ 
    Set cumulative cumulative + item index weight
    Set index index + 1
  ]
    Report (index - 1)
End

Upvotes: 5

LeirsW
LeirsW

Reputation: 2305

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.

Upvotes: 1

Related Questions