Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to compare two lists in Netlogo?

Tags:

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.

like image 226
ThomasC Avatar asked Aug 24 '17 09:08

ThomasC


1 Answers

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...)

like image 112
Nicolas Payette Avatar answered Jan 03 '23 11:01

Nicolas Payette