NetLogo: getting randomly chosen position of a repeated value in a list - netlogo

If I have the following: set list [8 1 0 3 4 2 0 1 2 4 25 0 3 3]. I would like to find a way to get, for example, a random item position for zero (2, 6 or 11) or for three (3, 12 or 13).
I have tried with:
let i (position (one-of list = 0) list )
print i
However, that only returns a boolean i. I know I could use position 0 list, but that gives priority to the first position (2, in the case of zero) while I would like it to randomly chosen from all values equal to zero on the list. I thought of using a while[], but I was wondering if there is a faster and simpler way.

In general, when you are working with lists, it is a good idea to familiarise yourself with anonymous procedures and some related primitives like map and filter.
I wrote a quick procedure, called positions that should be able to take care of this. First I create a list containing all the possible indexes: index-list.
Next, I use map to simultaneously go through the input-list and the index-list. It uses ifelse-value to check for each item of the input-list whether or not it corresponds to the input-item that you wanted to check it against. If they correspond, it returns the position of that item in the input-list. Otherwise it returns FALSE.
The final step is to filter out all the FALSE responses so that you are left with a list containing only the positions of your input-item in the input-list.
to-report positions [ input-item input-list ]
let index-list range length input-list
let position-list (map [ [list-item index] -> ifelse-value input-item = list-item [index][FALSE] ] input-list index-list)
report filter [index -> index != FALSE] position-list
end
Testing this gives [2 6 11] as a result, which corresponds with what you would expect
to test
let my-list [8 1 0 3 4 2 0 1 2 4 25 0 3 3]
show positions 0 my-list ;[2 6 11]
end

Related

Plotting elements of a list through time (ticks)

I would need to study the distribution through time of items that are selected from a list, based on agent source’s breed (women and men).
At each tick, a breed woman or man creates a new object that is added in other turtles’lists. This/these objects can be selected at each step (ticks) by other turtles (women and/or men), spreading within the network.
In the plot, the y-axis should have the number of occurrences (frequency) of each object in the visited turtles (i.e. turtles that have selected that item from their lists).
Example:
object 3 is created by a man, object 5 is created by a woman.
man 2: count 1 object 3 (object 3 created) at tick 1
woman 4: count 1 object 5 (object 5 created) at tick 3
...
man 2: count 1 object 3 (object 3 picked) at tick 12
man 2: count 1 object 3 (object 3 picked) at tick 12
man 2: count 1 object 3 (object 3 picked) at tick 13
...
woman 31: count 1 object 5 (object 5 picked) at tick 21
Plots:
for object 3, I would have (dots in blue as it was created by a man)
x y
1 1
2 0
3 0
...
12 2
13 1
...
and for object 5 (dots in red as it was created by a woman):
x y
1 1
2 0
3 0
...
12 0
13 0
...
21 1
...
Do you have any suggestions on how I could plot over time items that are created, then picked by turtles and see, separately, the different distributions over time?
What you could do is using length filter in order to get the count of objects created by either men or women (if I understood well, this is item 2 in your list example):
let selected (list item 0 list_1 item 1 list_1 item 2 list_1)
ifelse item 2 list_1 = women [
set list_1_w fput selected list_1_w
print (word "List objects created by women: " list_1_w)
let list_count_w (length (filter [a -> item 2 a = women] list_1_w)) /* added */
]
[ set list_1_m fput selected list_1_m
print (word "List objects created by men: " list_1_m)
let list_count_m (length (filter [a -> item 2 a = men] list_1_m)) /* added */
]
The two letvariables above return a count of objects created by women or men. This count considers only breed women and men, not distinguishing between objects created by woman x and objects created by man x. About plotting them, probably you should count all of them at each tick in order to have a chronology of the number of events (objects) selected through time by agents.
To track each object, an idea would be to create a temporary plot pen that can track all objects:
ask turtles [ /* here you should distinguish between objects created by women and objects created by men */
create-temporary-plot-pen (word who)
set-plot-pen-color color
plotxy ticks ___ /* you should add here variable that you want to consider */
]
The code above can create a multiplot to track all objects (but you will need to label them and keep track when they're selected).
It's just an idea. You (or someone else in the community) should change accordingly the code above to consider the different breeds and how to track these objects through time.
I hope this can be of some help!
Since I can't seem to get you to understand my questions, I have a different suggestion. Stop trying to do a plot. Instead, do a monitor on the screen that does the calculation (at each tick) of whatever it is you are trying to plot. You can have one monitor for each breed. Once you have the monitor working, just use the same code as the pen in a plot.

Roulette Wheel Selection in Netlogo using Agent Variables, not Constants

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.

Applying Operations on each element of the list

I wish to divide each element in a list by a number, I have tried the following:
Approach 1:
set item 0 (new-vec item 0 vec / number)
set item 1 (new-vec item 1 vec / number)
gives error this isn't something you can use set on
Approach 2:
foreach new-vec
[ set ? ? / number]
doesn't seem to work.
Please help. Thanks in advance.
This is because NetLogo lists are immutable data structures.
If you really want mutability you can always use the array extension, but once you've learned to use NetLogo's immutable lists properly, this is almost never necessary: the lists primitives are usually all that you need.
To divide all the numbers in a list by some other number, use map:
let new-vec [10 50 100]
let number 10
let divided-vec map [ ? / number ] new-vec
will assign the list [1 5 10] to divided-vec.
The map operation builds a new list by applying an operation to each element of the list you pass to it. In the example above, I assigned the new list to a new variable (divided-vec), but if you wanted, you could also assign it back to new-vec:
set new-vec map [ ? / number ] new-vec
This will behave as if you modified new-vec in place, though it won't be the case.
If you want to apply an operation to just one item in a list, you can do it with a combination of replace-item and item:
let my-list [2 4 6 8 10]
show replace-item 1 my-list (item 1 my-list * 100)
will show: [2 400 6 8 10]
This is how to do it in NetLogo 6, which changed anonymous procedures and thus how this is done in map:
let new-vec [10 50 100]
let number 10
let divided-vec map [ i -> i / number ] new-vec

Calculate the number of common features an agent shares with an agentset

I would like to report a count of the number of common features (e.g. [1 8 4] is three features) an agent (target_turtle) shares with each agent in an agentset (neighbor_turtle). Any suggestions please?
For example: If the agent has the features [1 8 7] and an agent from the agent set has the features [1 7 8], they share one common feature i.e. 1 . The features 8 and 7 are not included as the order of the features is relevant.
The current error I get is: All the list arguments to FOREACH must be the same length.
Cheers,
Marshall
;; reporting overlap between two agents
to-report overlap_between [target_turtle neighbor_turtle]
let suma 0
ask neighbor_turtle
[
(foreach [feature] of target_turtle [Feature] of neighbor_turtle
[ if ?1 = ?2 [ set suma suma + 1] ]
)
report suma
]
end
Your code seems almost correct already, though the ask neighbor_turtle part isn't necessary; you're already using of to switch perspectives.
The error message you're getting seems to indicate that you need to somehow handle the case where the turtle's feature lists aren't the same length.
I'll assume you just want to ignore any trailing items in the longer of the two lists. Here's code that does that:
to-report overlap-between [target-turtle neighbor-turtle]
let features1 [feature] of target-turtle
let features2 [feature] of neighbor-turtle
ifelse length features1 > length features2
[ set features1 sublist features1 0 length features2 ]
[ if length features2 > length features1
[ set features2 sublist features2 0 length features1 ] ]
report sum (map [ifelse-value (?1 = ?2) [1] [0]]
features1 features2)
end
Note that it's idiomatic in NetLogo to name variables like-this not like_this.

NetLogo : How to do multiple operations on lists (find, get , replace, remove , search elements within lists , ....)

I am new to NetLogo and I was wondering if there is a complete reference to do operations on lists, I have read most of the posts here in addition to Netlogo dictionary but for example if I need a list of pairs of numbers like
[[1 2] [2 2] [2 3] ,,, ]
when I search
member? 3 thislist
Will I have the option to say which element of inner list I am considering for the search ? for instance I will get false if it search first element and true if I search second element.
Can anybody please clarify the use of lists in Netlogo?
map, filter, reduce, foreach, n-values, and sort-by provide customizable operations on lists, using tasks. See http://ccl.northwestern.edu/netlogo/docs/programming.html#tasks.
Here's your example using map:
observer> show member? 3 map first [[1 2] [2 2] [2 3]]
observer: false
observer> show member? 3 map last [[1 2] [2 2] [2 3]]
observer: true
It appears Seth answered your initial question. To answer your follow up question on changing an item, you can use replace-item See: http://ccl.northwestern.edu/netlogo/docs/dictionary.html#listsgroup
or use map. Below is an example replacing the first item with a -99 if the second item is 3:
let aList [[1 2] [2 2] [2 3] [4 4] [5 3]]
set aList map [(list ifelse-value (item 1 ? = 3) [-99][item 0 ?] item 1 ?)] aList