I hope this is a simple solution, but I'm having a difficult time with it.
Problem:
I would like to weight the probability of something occurring by an variable not a constant
Setup
My agent is a farm.
Farms own four variables that represent the number of cows, goats, pigs, and sheep on it.
When a farm wants to remove an animal, I'd like the likelihood to remove a member of a particular species to be directly proportional to quantity of each species on the farm (i.e. if there are 7 goats, 2 cows, and 1 pig, there is a 70% probability of taking a goat and a zero percent probability of taking a sheep)
I have found formula like this for when you know the exact numerical weight that each value will have:
to-report random-weighted [values weights]
let selector (random-float sum weights)
let running-sum 0
(foreach values weights [
set running-sum (running-sum + ?2) ; Random-Weighted Created by NickBenn
if (running-sum > selector) [
report ?1
]
])
end
and the methods described in the rnd extension. But both of these throw the "expected a constant" error when i put "Cow" in instead of a constant.
Something like:
to example1
let values ["Cow" "Sheep" "Goat" "Pig"]
let probabilities [2 0 7 1]
let indices n-values length values [ ? ] ; Made by Nicolas Payette
let index rnd:weighted-one-of indices [ item ? probabilities ]
let loca item index values
end
works well, but if I were to replace it with:
to example1
let values ["Cow" "Sheep" "Goat" "Pig"]
let probabilities [Num-Cows Num-Sheep Num-Goats Num-Pigs]
let indices n-values length values [ ? ] ; Made by Nicolas Payette
let index rnd:weighted-one-of indices [ item ? probabilities ]
let loca item index values
end
it fails.
Alan is right: you need to use the list
primitive (as opposed to just brackets) when you want to construct a list from anything else than constants.
I would add two things to that:
The latest version of the rnd
extension has two sets of primitives: one for agentsets, and one for lists. So you should probably update and use the rnd:weighted-one-of-list
primitive.
Your code is based around using indices to pick an item. That's fine, but that's not the only way to do it.
You could also have something like:
to example1
let values ["Cow" "Sheep" "Goat" "Pig"]
let probabilities (list Num-Cows Num-Sheep Num-Goats Num-Pigs)
let loca first rnd:weighted-one-of-list (map list values probabilities) last
end
This may be a bit trickier to understand, but here is the gist of it:
The (map list values probabilities)
expression takes both your values
list and your probabilities
list and "zips" them together using the list
primitive, resulting in a list of pairs: [["Cow" 2] ["Sheep" 0] ["Goat" 7] ["Pig" 1]]
.
We pass the last
reporter to the rnd:weighted-one-of-list
primitive to tell it that the last (i.e., second) item of each of these pairs should be used as the probability.
Since rnd:weighted-one-of-list
operates on a list of pairs, the item it returns will be a pair (e.g., ["Goat" 7]
). We are only interested in the first item of the pair, so we extract it with the first
reporter.
Note that we use the NetLogo's concise syntax for tasks when passing list
as an argument to map
and last
as an argument to rnd:weighted-n-of
. You could replace list
with [ (list ?1 ?2) ]
and last
with [ last ? ]
, but it would be uglier.