How to compare two lists in Netlogo? - netlogo

I have two breeds, buyers and suppliers, and buyers are building a list (sup_list) of suppliers that have attributes stored in list 'att' that are greater than a list of criteria stored in list 'b'. The following line does this for the first criteria - is there an easy way to add in all the others?
ask buyers [set sup_list suppliers with [item 0 att > [item 0 b] of myself]]
So in English the criteria would be: item 0 > item 0 AND item 1 > item 1 AND item 2 > item 3 etc.
Thank you.

The expression you want is:
suppliers with [ reduce and (map > att [ b ] of myself) ]
This is a tricky bit of functional programming. Let's see how it works.
Our first goal is to take the two lists of numbers and turn it into a single list of boolean values, where each item will be true if the item at the same location in the buyer's list is greater than the item at the same location in the supplier's list. For example, if we have:
Buyer's list: [1 1 1 1]
Supplier's list: [2 1 1 1]
...only the first item in the supplier's list fits our criteria, so we want our resulting list to be:
[true false false false]
Whenever we want to turn one or more lists of things into a single list of things, the NetLogo primitive to use is map. The map primitive takes a reporter and one or more lists. It applies the reporter to item(s) taken from the list(s) and builds a new list out of that. This is exactly what we need. Try this in the NetLogo command center:
observer> show (map > [2 1 1 1] [1 1 1 1])
observer: [true false false false]
A couple of things to note:
Since we are passing more than one list to map, we need to put the whole expression inside parentheses.
We are using concise syntax for passing > as a reporter. This could also have been written [ [a b] -> a > b ].
Now that we have our list of boolean values, we want to check if all these values are true, i.e., if all supplier items fit the buyer's criteria. NetLogo has an all? primitive that does something like that for agentsets, but we cannot use it here since we are dealing with a list. We will have to use reduce instead.
The reduce primitive is the one to use whenever we want to turn a list into a single value. Here, we want to turn a list of booleans into a single boolean value, that will be true if all the values in the list are true and will be false otherwise.
As the NetLogo documentation says, "it can be difficult to develop an intuition about what reduce does". (I strongly urge you to read the documentation and try experimenting with the primitive.) In a nutshell, it traverses a list and applies a reporter to each item and an "accumulator" value, storing the result of that operation in the accumulator. The first item of the list is used to initialize the accumulator.
In our case, the reporter used with reduce will be and, since we want to check that the first item is true, and that the second item is true, and that the third item is true, etc.
Let's try to reduce our previously obtained list of booleans:
observer> show reduce and [true false false false]
observer: false
(Not that we're, again, using the concise syntax to pass and as a reporter. This could have been written [ [p q] -> p and q ].)
The end result is false, because not all values are true. Let's see how this works, step by step:
it stores the first item from the list in the accumulator, so the accumulator now holds the value true.
it passes the value of the accumulator and the value of the second item to the and reporter. The accumulator is true but the second item is false. The result of true and false is false, so it stores false in the accumulator.
it passes the value of the accumulator and the value of the third item to the and reporter. The accumulator is now false and the second item is also false. The result of false and false is false, so again, it stores false in the accumulator.
the fourth step is just like the third: the accumulator holds false and the fourth item is also false. The result of false and false is false, so again, it stores false in the accumulator.
Once we run out of list items, reduce reports the value of the accumulator, in this case false. The only case where it would report true is if all values in the list are true, leading to a sequence of true and true comparisons that all result in storing true in the accumulator. That's exactly what we want:
observer> show reduce and [true true true true]
observer: true
If you put all of this together, you should be able to see how:
suppliers with [ reduce and (map > att [ b ] of myself) ]
...gives you the agentset of suppliers that fit all criteria of the buyer!
(Note that with returns an agentset, not a list, so you should probably rename your sup_list variable...)

Related

Iterating over a list of booleans values

**I have a list called ( a) which holds booleans values thus I want to implement an if statement if each item value in the list ( a )is true and implement another if statement if each item value in list ( a) is false.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
I tried this but it does not work !!!
1- foreach a [ x -> if ( x = true) [ask pharmacists [ do the first if statment ]
2- foreach a [ x -> if ( x = false) [ask pharmacists [ do the second if statment ]
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
I want to cycle at each boolean value in list (a) and perform an if statement based on whether the value is true or false.**
I'm not sure I fully understand what you're trying to do- you may want to have a look at the Asking Help for some guidelines. Note the comment:
DO NOT post images of code, data, error messages, etc. - copy or type the text into the question. Please reserve the use of images for diagrams or demonstrating rendering bugs, things that are impossible to describe accurately via text.
Also, have a look at the section on making a Minimal, Complete, and Verifiable Example. This will help users provide you with a useful answer that is definitely applicable to your issue. If my answer below is not helpful, I suggest you make a toy model that acts as a working example of the problem you're running into.
If you just want to iterate over a list of true / false values, I think you're on the right track- have a look at the very simple example below which just prints a statement depending on whether the current iterated value is true or false:
to setup
ca
let boolean-list [ true true true false true false false false ]
foreach boolean-list [
i ->
ifelse i [
print "Current item is true!"
] [
print "Current item is false!"
]
]
reset-ticks
end

Get a count of turtles with a combination of values

I am trying to count the number of "buyer" type turtles, which have a certain surplus (turtle variable) greater than or equal to zero, and price (another turtle variable) greater than the current turtle's price (already grabbed in local variable myprice...although there may be a more direct way to put it in)
let countup count buyers with ([surplus >= 0] and [price > myprice])
NetLogo returns
Expected a TRUE/FALSE here, rather than a list or block.
let countup count buyers with (surplus >= 0 and price > myprice) returns
WITH expected this input to be a TRUE/FALSE block, but got a TRUE/FALSE instead
Close! You're looking for:
let countput count buyers with [ surplus >= 0 and price > myprice ]
with is a report that takes two arguments, like so
<turtleset> with <report block>
where the reporter block is a clump of code surrounded by [ ] that will result in either true or false. In general [ ] is netlogo's way of grouping together code so you can doing something special with it, such as having each agent in an agentset run it. Hope that helps!
Also, I assume you've got something like let myprice price on, say, the line above this one. You can combine those lines like so (not saying this code is the right way to do it, just wanted to show another option):
let countput count buyers with [ surplus >= 0 and price > [ price ] of myself ]
Checkout the docs for (the very poorly named) myself.

How to use add elements to a matrix?

I want to add multiple items from one list to another list, that is organized in one big list, like a matrix.
let targetlists (list firstlist seccondlist thirdlist)
So in my double while loop, I added this code;
set (item x targetlists) lput (item y sourcelist) (item x targetlists)
Sadly it gives me the following error:
This isn't something you can use "set" on.
I found out that it has to do with how I select the target list, as the following code does work, but doesn't do what I want:
set firstlist lput (item y sourcelist) firstlist
JenB is right that, in general, you use replace-item. However, replacing your while loops with map will be much more effective.
I'm not entirely sure what you're trying to do, but it looks like you're trying to put the elements of sourcelist onto the end of the lists in targetlists. Even if that's not what you're doing, this should point you in the right direction:
set targetlists (map [ [ source-item target-row ] ->
lput source-item target-row
] sourcelist targetlists)
This will iterate through the items of sourcelist and targetlists together, calling lput on the pairs.
Also, there's a handy shortcut where, if a reporter already does what you want, you can pass it directly to map. So you can condense this to:
set targetlists (map lput sourcelist targetlists)
Now, given that you mentioned nested whiles and you're indexing into the two lists with two different indices, you might be trying to put the entire contents of sourcelist onto the ends of each of the targetlists. If that's the case, you can just do
set targetlists map [ l -> (sentence l sourcelist) ] targetlists
If I'm totally off, and you're trying to do something completely different, just let me know in the comments and I'll update my answer.

How to compare two turtles in Netlogo by going through a list of their attributes?

My turtles have more than 30 attributes of boolean values and I would like to use a foreach loop to compare turtles and rank them based on their similarity without the need to compare each attribute individually. I might be missing an obvious point here, I have tried having a list of attributes, but it didn't work and all turtles got the maximum similarity score.
Here's some code that calculates the Hamming distance between two lists. Note that the very clever reduce code is taken directly from the NetLogo dictionary.
to testme
let ll1 (list TRUE TRUE FALSE FALSE)
let ll2 (list TRUE FALSE TRUE FALSE)
let ll3 ( map = ll2 ll1 )
show ll3
show reduce [ [occurrence-count next-item] ->
ifelse-value (next-item) [occurrence-count + 1] [occurrence-count] ] (fput 0 ll3)
end
If you were wanting to calculate the similarity score of a pair of turtles, you could turn this into a reporter that takes the two turtles as arguments. But it's not clear that comparing two turtles is what you want to do, so I haven't written code for that.

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.